(module ;; Run with Wasmtime from a directory containing ilo.rom and ilo.blocks: ;; XDG_CACHE_HOME=/tmp /home/crc/.wasmtime/bin/wasmtime --dir=$PWD::. extras/ilo-wasm.wat ;; ;; The module uses WASI preview1 and fixed guest paths "ilo.rom" and ;; "ilo.blocks", matching the default names used by ilo.c. (import "wasi_snapshot_preview1" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32))) (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) (import "wasi_snapshot_preview1" "fd_close" (func $fd_close (param i32) (result i32))) (import "wasi_snapshot_preview1" "fd_seek" (func $fd_seek (param i32 i64 i32 i32) (result i32))) (import "wasi_snapshot_preview1" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) (memory 5) (export "memory" (memory 0)) (export "_start" (func $_start)) ;; Memory map: ;; 0..262143 ilo memory: 65,536 signed 32-bit cells ;; 262144..262275 data stack: 33 signed 32-bit cells ;; 262276..263303 address stack: 257 signed 32-bit cells (global $DS i32 (i32.const 262144)) (global $AS i32 (i32.const 262276)) (global $OPENED i32 (i32.const 263304)) (global $NIO i32 (i32.const 263308)) (global $IOV i32 (i32.const 263312)) (global $SEEKED i32 (i32.const 263320)) (global $BYTE i32 (i32.const 263328)) (global $NUMBUF i32 (i32.const 263336)) (global $ROM i32 (i32.const 263384)) (global $BLOCKS i32 (i32.const 263392)) (data (i32.const 263384) "ilo.rom\00") (data (i32.const 263392) "ilo.blocks\00") (global $ip (mut i32) (i32.const 0)) (global $sp (mut i32) (i32.const 0)) (global $rp (mut i32) (i32.const 0)) (func $cell (param $a i32) (result i32) local.get $a i32.const 2 i32.shl) (func $ds_addr (param $a i32) (result i32) global.get $DS local.get $a i32.const 2 i32.shl i32.add) (func $as_addr (param $a i32) (result i32) global.get $AS local.get $a i32.const 2 i32.shl i32.add) (func $t_addr (result i32) global.get $sp call $ds_addr) (func $n_addr (result i32) global.get $sp i32.const 1 i32.sub call $ds_addr) (func $r_addr (result i32) global.get $rp call $as_addr) (func $t (result i32) call $t_addr i32.load) (func $n (result i32) call $n_addr i32.load) (func $set_t (param $v i32) call $t_addr local.get $v i32.store) (func $set_n (param $v i32) call $n_addr local.get $v i32.store) (func $push (param $v i32) global.get $sp i32.const 1 i32.add call $ds_addr local.get $v i32.store global.get $sp i32.const 1 i32.add global.set $sp) (func $pop (result i32) (local $a i32) global.get $sp i32.const 1 i32.sub global.set $sp global.get $sp i32.const 1 i32.add local.tee $a call $ds_addr i32.load) (func $open_ro (param $path i32) (param $len i32) (result i32) (local $err i32) i32.const 3 ;; cwd preopen i32.const 0 local.get $path local.get $len i32.const 0 i64.const 6 ;; FD_READ | FD_SEEK i64.const 0 i32.const 0 global.get $OPENED call $path_open local.tee $err if i32.const -1 return end global.get $OPENED i32.load) (func $open_rw (param $path i32) (param $len i32) (result i32) (local $err i32) i32.const 3 i32.const 0 local.get $path local.get $len i32.const 0 i64.const 70 ;; FD_READ | FD_SEEK | FD_WRITE i64.const 0 i32.const 0 global.get $OPENED call $path_open local.tee $err if i32.const -1 return end global.get $OPENED i32.load) (func $load_image (local $fd i32) global.get $ROM i32.const 7 call $open_ro local.set $fd local.get $fd i32.const 0 i32.lt_s if i32.const 0 global.set $ip i32.const 0 global.set $sp i32.const 0 global.set $rp return end global.get $IOV i32.const 0 i32.store global.get $IOV i32.const 4 i32.add i32.const 262144 i32.store local.get $fd global.get $IOV i32.const 1 global.get $NIO call $fd_read drop local.get $fd call $fd_close drop i32.const 0 global.set $ip i32.const 0 global.set $sp i32.const 0 global.set $rp) (func $save_image (local $fd i32) global.get $ROM i32.const 7 call $open_rw local.set $fd local.get $fd i32.const 0 i32.lt_s if return end global.get $IOV i32.const 0 i32.store global.get $IOV i32.const 4 i32.add i32.const 262144 i32.store local.get $fd global.get $IOV i32.const 1 global.get $NIO call $fd_write drop local.get $fd call $fd_close drop) (func $read_block (local $fd i32) (local $block i32) (local $buffer i32) call $pop local.set $buffer call $pop local.set $block global.get $BLOCKS i32.const 10 call $open_ro local.set $fd local.get $fd i32.const 0 i32.lt_s if return end local.get $fd local.get $block i64.extend_i32_s i64.const 4096 i64.mul i32.const 0 global.get $SEEKED call $fd_seek drop global.get $IOV local.get $buffer call $cell i32.store global.get $IOV i32.const 4 i32.add i32.const 4096 i32.store local.get $fd global.get $IOV i32.const 1 global.get $NIO call $fd_read drop local.get $fd call $fd_close drop) (func $write_block (local $fd i32) (local $block i32) (local $buffer i32) call $pop local.set $buffer call $pop local.set $block global.get $BLOCKS i32.const 10 call $open_rw local.set $fd local.get $fd i32.const 0 i32.lt_s if return end local.get $fd local.get $block i64.extend_i32_s i64.const 4096 i64.mul i32.const 0 global.get $SEEKED call $fd_seek drop global.get $IOV local.get $buffer call $cell i32.store global.get $IOV i32.const 4 i32.add i32.const 4096 i32.store local.get $fd global.get $IOV i32.const 1 global.get $NIO call $fd_write drop local.get $fd call $fd_close drop) (func $save_ip global.get $rp i32.const 1 i32.add global.set $rp call $r_addr global.get $ip i32.store) (func $li global.get $ip i32.const 1 i32.add global.set $ip global.get $ip call $cell i32.load call $push) (func $du call $t call $push) (func $dr call $t_addr i32.const 0 i32.store global.get $sp i32.const 1 i32.sub global.set $sp) (func $sw (local $a i32) call $t local.set $a call $n call $set_t local.get $a call $set_n) (func $pu global.get $rp i32.const 1 i32.add global.set $rp call $r_addr call $pop i32.store) (func $po call $r_addr i32.load call $push global.get $rp i32.const 1 i32.sub global.set $rp) (func $ju call $pop i32.const 1 i32.sub global.set $ip) (func $ca call $save_ip call $pop i32.const 1 i32.sub global.set $ip) (func $cc (local $a i32) call $pop local.set $a call $pop if call $save_ip local.get $a i32.const 1 i32.sub global.set $ip end) (func $cj (local $a i32) call $pop local.set $a call $pop if local.get $a i32.const 1 i32.sub global.set $ip end) (func $re call $r_addr i32.load global.set $ip global.get $rp i32.const 1 i32.sub global.set $rp) (func $eq call $n call $t i32.eq i32.const -1 i32.mul call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $ne call $n call $t i32.ne i32.const -1 i32.mul call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $lt call $n call $t i32.lt_s i32.const -1 i32.mul call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $gt call $n call $t i32.gt_s i32.const -1 i32.mul call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $fe call $t call $cell i32.load call $set_t) (func $st call $t call $cell call $n i32.store global.get $sp i32.const 2 i32.sub global.set $sp) (func $ad call $n call $t i32.add call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $su call $n call $t i32.sub call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $mu call $n call $t i32.mul call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $di (local $a i32) (local $b i32) call $t local.set $a call $n local.set $b local.get $b local.get $a i32.div_s call $set_t local.get $b local.get $a i32.rem_s call $set_n local.get $b i32.const 0 i32.ge_s call $n i32.const 0 i32.lt_s i32.and if call $t i32.const 1 i32.add call $set_t call $n local.get $a i32.sub call $set_n end) (func $an call $t call $n i32.and call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $or call $t call $n i32.or call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $xo call $t call $n i32.xor call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $sl call $n call $t i32.shl call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $sr call $n call $t i32.shr_s call $set_n global.get $sp i32.const 1 i32.sub global.set $sp) (func $cp (local $l i32) (local $d i32) (local $s i32) call $pop local.set $l call $pop local.set $d call $t local.set $s i32.const -1 call $set_t block $done loop $again local.get $l i32.eqz br_if $done local.get $d call $cell i32.load local.get $s call $cell i32.load i32.ne if i32.const 0 call $set_t end local.get $l i32.const 1 i32.sub local.set $l local.get $s i32.const 1 i32.add local.set $s local.get $d i32.const 1 i32.add local.set $d br $again end end) (func $cy (local $l i32) (local $d i32) (local $s i32) call $pop local.set $l call $pop local.set $d call $pop local.set $s block $done loop $again local.get $l i32.eqz br_if $done local.get $d call $cell local.get $s call $cell i32.load i32.store local.get $l i32.const 1 i32.sub local.set $l local.get $s i32.const 1 i32.add local.set $s local.get $d i32.const 1 i32.add local.set $d br $again end end) (func $write_bytes (param $ptr i32) (param $len i32) global.get $IOV local.get $ptr i32.store global.get $IOV i32.const 4 i32.add local.get $len i32.store i32.const 1 global.get $IOV i32.const 1 global.get $NIO call $fd_write drop) (func $write_byte (param $b i32) global.get $BYTE local.get $b i32.store8 global.get $BYTE i32.const 1 call $write_bytes) (func $read_byte (result i32) global.get $IOV global.get $BYTE i32.store global.get $IOV i32.const 4 i32.add i32.const 1 i32.store i32.const 0 global.get $IOV i32.const 1 global.get $NIO call $fd_read drop global.get $NIO i32.load i32.eqz if i32.const 32 return end global.get $BYTE i32.load8_u) (func $io (local $dev i32) call $pop local.set $dev local.get $dev i32.eqz if call $pop call $write_byte return end local.get $dev i32.const 1 i32.eq if call $read_byte call $push return end local.get $dev i32.const 2 i32.eq if call $read_block return end local.get $dev i32.const 3 i32.eq if call $write_block return end local.get $dev i32.const 4 i32.eq if call $save_image return end local.get $dev i32.const 5 i32.eq if call $load_image i32.const -1 global.set $ip return end local.get $dev i32.const 6 i32.eq if i32.const 65536 global.set $ip return end local.get $dev i32.const 7 i32.eq if global.get $sp call $push global.get $rp call $push end) (func $process (param $o i32) local.get $o i32.const 1 i32.eq if call $li return end local.get $o i32.const 2 i32.eq if call $du return end local.get $o i32.const 3 i32.eq if call $dr return end local.get $o i32.const 4 i32.eq if call $sw return end local.get $o i32.const 5 i32.eq if call $pu return end local.get $o i32.const 6 i32.eq if call $po return end local.get $o i32.const 7 i32.eq if call $ju return end local.get $o i32.const 8 i32.eq if call $ca return end local.get $o i32.const 9 i32.eq if call $cc return end local.get $o i32.const 10 i32.eq if call $cj return end local.get $o i32.const 11 i32.eq if call $re return end local.get $o i32.const 12 i32.eq if call $eq return end local.get $o i32.const 13 i32.eq if call $ne return end local.get $o i32.const 14 i32.eq if call $lt return end local.get $o i32.const 15 i32.eq if call $gt return end local.get $o i32.const 16 i32.eq if call $fe return end local.get $o i32.const 17 i32.eq if call $st return end local.get $o i32.const 18 i32.eq if call $ad return end local.get $o i32.const 19 i32.eq if call $su return end local.get $o i32.const 20 i32.eq if call $mu return end local.get $o i32.const 21 i32.eq if call $di return end local.get $o i32.const 22 i32.eq if call $an return end local.get $o i32.const 23 i32.eq if call $or return end local.get $o i32.const 24 i32.eq if call $xo return end local.get $o i32.const 25 i32.eq if call $sl return end local.get $o i32.const 26 i32.eq if call $sr return end local.get $o i32.const 27 i32.eq if call $cp return end local.get $o i32.const 28 i32.eq if call $cy return end local.get $o i32.const 29 i32.eq if call $io return end) (func $process_bundle (param $opcode i32) local.get $opcode i32.const 255 i32.and call $process local.get $opcode i32.const 8 i32.shr_u i32.const 255 i32.and call $process local.get $opcode i32.const 16 i32.shr_u i32.const 255 i32.and call $process local.get $opcode i32.const 24 i32.shr_u i32.const 255 i32.and call $process) (func $execute block $done loop $again global.get $ip i32.const 65536 i32.ge_s br_if $done global.get $ip call $cell i32.load call $process_bundle global.get $ip i32.const 1 i32.add global.set $ip br $again end end) (func $print_i32 (param $v i32) (local $u i32) (local $p i32) (local $end i32) local.get $v i32.eqz if i32.const 48 call $write_byte return end local.get $v i32.const 0 i32.lt_s if i32.const 45 call $write_byte i32.const 0 local.get $v i32.sub local.set $u else local.get $v local.set $u end global.get $NUMBUF i32.const 31 i32.add local.tee $p local.set $end block $done loop $digits local.get $p local.get $u i32.const 10 i32.rem_u i32.const 48 i32.add i32.store8 local.get $u i32.const 10 i32.div_u local.set $u local.get $u i32.eqz br_if $done local.get $p i32.const 1 i32.sub local.set $p br $digits end end local.get $p local.get $end local.get $p i32.sub i32.const 1 i32.add call $write_bytes) (func $dump_stack block $done loop $again global.get $sp i32.eqz br_if $done i32.const 32 call $write_byte call $t call $print_i32 global.get $sp i32.const 1 i32.sub global.set $sp br $again end end i32.const 10 call $write_byte) (func $_start call $load_image call $execute call $dump_stack))