Skip to content

Instantly share code, notes, and snippets.

@Two9A
Created September 5, 2023 14:10
Show Gist options
  • Save Two9A/427985064d360342caaf4f7d5769aeef to your computer and use it in GitHub Desktop.
Save Two9A/427985064d360342caaf4f7d5769aeef to your computer and use it in GitHub Desktop.
WASM definition macro preprocessor
(module (func $io_r (import "func" "io_r") (param i32) (result i32)) (func $io_w (import "func" "io_w") (param i32) (param i32)) (memory (import "buffers" "mem") 2) (table 16 anyfunc) (elem (i32.const 0) $r_ram $r_ram $r_ram $r_ram $r_ram $r_ram $r_ram $r_ram $r_ram $r_ram $r_basic $r_basic $r_ram $r_char $r_kernal $r_kernal) (func $r_ram (param $addr i32) (result i32) (i32.load8_u (i32.and (get_local $addr) (i32.const 0xFFFF)))) (func $r_basic (param $addr i32) (result i32) (i32.load8_u (if (result i32) (i32.eq (i32.and (i32.load (i32.const 0x0001)) (i32.const 3)) (i32.const 3)) (then (i32.add (i32.and (get_local $addr) (i32.const 0xFFFF)) (i32.const 0x10000))) (else (i32.and (get_local $addr) (i32.const 0xFFFF)))))) (func $r_kernal (param $addr i32) (result i32) (i32.load8_u (if (result i32) (i32.and (i32.load (i32.const 0x0001)) (i32.const 2)) (then (i32.add (i32.and (get_local $addr) (i32.const 0xFFFF)) (i32.const 0x10000))) (else (i32.and (get_local $addr) (i32.const 0xFFFF)))))) (func $r_char (param $addr i32) (result i32) (i32.and (i32.const 0xFF) (if (result i32) (i32.gt_u (i32.and (i32.load (i32.const 0x0001)) (i32.const 7)) (i32.const 4)) (then (call $io_r (get_local $addr))) (else (i32.load8_u (if (result i32) (i32.and (i32.gt_u (i32.and (i32.load (i32.const 0x0001)) (i32.const 7)) (i32.const 0)) (i32.lt_u (i32.and (i32.load (i32.const 0x0001)) (i32.const 7)) (i32.const 4))) (then (i32.add (i32.and (get_local $addr) (i32.const 0xFFFF)) (i32.const 0x10000))) (else (i32.and (get_local $addr) (i32.const 0xFFFF))))))))) (type $readfunc (func (param i32) (result i32))) (func $r (param $addr i32) (result i32) (call_indirect (type $readfunc) (get_local $addr) (i32.shr_u (i32.and (get_local $addr) (i32.const 0xF000)) (i32.const 12)))) (func $w (param $addr i32) (param $val i32) (if (i32.and (i32.and (i32.load (i32.const 0x0001)) (i32.const 4)) (i32.eq (i32.and (get_local $addr) (i32.const 0xF000)) (i32.const 0xD000))) (then (call $io_w (get_local $addr) (get_local $val))) (else (i32.store8 (i32.and (get_local $addr) (i32.const 0xFFFF)) (i32.and (get_local $val) (i32.const 0xFF)))))) (export "r" (func $r)) (export "w" (func $w)))
(module
(define CPUPORT (i32.const 0x0001))
(define LORAM (i32.const 1))
(define HIRAM (i32.const 2))
(define CHAREN (i32.const 4))
(define ROM_START (i32.const 0x10000))
(func $io_r (import "func" "io_r") (param i32) (result i32))
(func $io_w (import "func" "io_w") (param i32) (param i32))
(memory (import "buffers" "mem") 2)
(table 16 anyfunc)
(elem (i32.const 0)
$r_ram
$r_ram
$r_ram
$r_ram
$r_ram
$r_ram
$r_ram
$r_ram
$r_ram
$r_ram
$r_basic
$r_basic
$r_ram
$r_char
$r_kernal
$r_kernal
)
(func $r_ram (param $addr i32) (result i32)
(i32.load8_u
(i32.and (get_local $addr) (i32.const 0xFFFF))
)
)
(func $r_basic (param $addr i32) (result i32)
(define BOTHRAM (i32.const 3))
(i32.load8_u
;; If LORAM is high and HIRAM is high, ROM is swapped in
(if (result i32)
(i32.eq (i32.and (i32.load CPUPORT) BOTHRAM) BOTHRAM)
(then
(i32.add (i32.and (get_local $addr) (i32.const 0xFFFF)) ROM_START)
)
(else
(i32.and (get_local $addr) (i32.const 0xFFFF))
)
)
)
)
(func $r_kernal (param $addr i32) (result i32)
(i32.load8_u
;; If HIRAM is high, ROM is swapped in
(if (result i32)
(i32.and (i32.load CPUPORT) HIRAM)
(then
(i32.add (i32.and (get_local $addr) (i32.const 0xFFFF)) ROM_START)
)
(else
(i32.and (get_local $addr) (i32.const 0xFFFF))
)
)
)
)
(func $r_char (param $addr i32) (result i32)
(i32.and
(i32.const 0xFF)
(if (result i32)
;; If CHAREN is on and either LORAM or HIRAM is on, read I/O
(i32.gt_u (i32.and (i32.load CPUPORT) (i32.const 7)) CHAREN)
(then
(call $io_r (get_local $addr))
)
(else
(i32.load8_u
;; If CHAREN is off and either LORAM or HIRAM is on, read char ROM
(if (result i32)
(i32.and
(i32.gt_u (i32.and (i32.load CPUPORT) (i32.const 7)) (i32.const 0))
(i32.lt_u (i32.and (i32.load CPUPORT) (i32.const 7)) CHAREN)
)
(then
(i32.add (i32.and (get_local $addr) (i32.const 0xFFFF)) ROM_START)
)
(else
(i32.and (get_local $addr) (i32.const 0xFFFF))
)
)
)
)
)
)
)
(type $readfunc (func (param i32) (result i32)))
(func $r (param $addr i32) (result i32)
(call_indirect (type $readfunc)
(get_local $addr)
(i32.shr_u
(i32.and (get_local $addr) (i32.const 0xF000))
(i32.const 12)
)
)
)
(func $w (param $addr i32) (param $val i32)
(if
(i32.and
;; If CHAREN is high, 0xDxxx maps to I/O on write
(i32.and (i32.load CPUPORT) CHAREN)
(i32.eq (i32.and (get_local $addr) (i32.const 0xF000)) (i32.const 0xD000))
)
(then
(call $io_w (get_local $addr) (get_local $val))
)
(else
(i32.store8
(i32.and (get_local $addr) (i32.const 0xFFFF))
(i32.and (get_local $val) (i32.const 0xFF))
)
)
)
)
(export "r" (func $r))
(export "w" (func $w))
)
#!/usr/bin/env python3
# WAT preprocessor to add "define" support
# Imran Nazar, 2023
import sys
import numpy as np
from sexpdata import load, dumps, Symbol
def sscalar(i):
return np.isscalar(i) or isinstance(i, Symbol)
def tr(sexp, defines):
# First pass: Find immediate descendent s-exp's which define macros
new_defines = {}
for i in sexp:
if not sscalar(i):
if i[0] == Symbol('define'):
new_defines[i[1]] = i[2]
# Macros defined at this level override any of the same name higher up
merged_defines = defines.copy() | new_defines
# Second pass: Replace at this level, recurse if deeper levels encountered
return [
merged_defines[i] if (sscalar(i) and merged_defines.get(i))
else i if sscalar(i)
else tr(i, merged_defines)
for i in sexp
if sscalar(i) or i[0] != Symbol('define')
]
def main():
assert len(sys.argv) == 2, 'Filename not provided'
filename = sys.argv[1]
print(dumps(tr(load(open(filename)), {})))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment