aboutsummaryrefslogtreecommitdiff
path: root/tests/soc_print_number/instructions.wat
diff options
context:
space:
mode:
Diffstat (limited to 'tests/soc_print_number/instructions.wat')
-rw-r--r--tests/soc_print_number/instructions.wat83
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)))