aboutsummaryrefslogtreecommitdiff
;; 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)))