blob: 49ae980949915ec3eb338bba6fbb31939bb0b219 (
about) (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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 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)))
|