diff options
Diffstat (limited to 'tests/soc_print_number/instructions.wat')
-rw-r--r-- | tests/soc_print_number/instructions.wat | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/tests/soc_print_number/instructions.wat b/tests/soc_print_number/instructions.wat new file mode 100644 index 0000000..c6029bc --- /dev/null +++ b/tests/soc_print_number/instructions.wat @@ -0,0 +1,83 @@ +;; VGA memory is at address 0x100000 from stack machine's point of view. +;; Here, however, we reserve first 1024 bytes for program code, so +;; all memory accesses here also have an additional offset of 0x400, +;; which we have tot ake into account. 0x100000 translates to 0xFFC00 +;; and 0x100A00 to 0x100600. +(module + (memory 0 2) + ;; print number in decimal at address $dest, return address after + ;; the last digit + (func $sub (param $number i32) (param $dest i32) (result i32) + (local $adr1 i32) + (local $adr2 i32) + ;; remember the initial address to write at + (set_local $adr1 (get_local $dest)) + (loop $again + ;; prepare address for store operation later + (get_local $dest) + ;; compute the last digit of number + (i32.rem_u (get_local $number) + (i32.const 10)) + ;; 0x30 is ASCII encoding of digit 0 + (i32.add (i32.const 0x30)) + ;; write digit's ASCII char to memory + (i32.store8 offset=0x0 align=1) + ;; increment the pointer + (set_local $dest (i32.add (i32.const 1) + (get_local $dest))) + ;; divide our number by 10 + (set_local $number (i32.div_u (get_local $number) + (i32.const 10))) + ;; break the loop, if number is 0 + (br_if $again (get_local $number))) + + ;; digit chars are now in the reverse order - swap them in a loop + (set_local $adr2 (i32.sub (get_local $dest) + (i32.const 1))) + (loop $again + ;; prepare address for later store operation + (get_local $adr2) + ;; load value on the left + (i32.load8_u offset=0x0 align=1 + (get_local $adr1)) + ;; prepare address for later store operation + (get_local $adr1) + ;; load value on the right + (i32.load8_u offset=0x0 align=1 + (get_local $adr2)) + ;; write value on the left + (i32.store8 offset=0x0 align=1) + ;; write value on the right + (i32.store8 offset=0x0 align=1) + + ;; increase $adr1 + (set_local $adr1 (i32.add (get_local $adr1) + (i32.const 1))) + ;; decrease $adr2 + (set_local $adr2 (i32.sub (get_local $adr2) + (i32.const 1))) + ;; loop until adr1 and adr2 cross/meet + (br_if $again (i32.lt_u (get_local $adr1) + (get_local $adr2)))) + ;; return the address we finished at + (get_local $dest)) + + (func $main + (local $adr i32) + ;; print number 9487462 as ASCII to address 0xFFC00 (0x100000); + ;; this is the address of VGA memory and will cause the number + ;; to be displayed on the screen + (set_local $adr (call $sub (i32.const 9487462) (i32.const 0xFFC00))) + ;; fill the rest of the screen with ASCII underscore + ;; (loop $again + ;; (i32.store8 offset=0x0 align=1 + ;; (get_local $adr) (i32.const 0x2D)) + ;; (set_local $adr (i32.add (get_local $adr) + ;; (i32.const 1))) + ;; (br_if $again (i32.lt_u (get_local $adr) + ;; (i32.const 0x100A00)))) + ;; write a non-zero value to the VGA power-on reg at 0x100600 (0x100A00) + (i32.store16 offset=0x100600 align=2 + (i32.const 0) (i32.const 1))) + + (export "main" (func $main))) |