;; 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 to take 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)))