blob: 01e081a252dba9a0e360032ea06be00c63f7445e (
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
;; See instructions.wat of soc_print_number test. A lot has been taken from
;; there.
;; Relevant addresses are VGA text memory (0xFFC00), VGA regs (0x100600),
;; lower half of timer reg (0x1BFC08) and led2 reg (0x1BFC06).
(module
(memory 0 2)
;; print number in decimal at address $dest, return address after
;; the last digit
(func $print (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 $counter i32)
(local $adr i32)
;; reset the timer (although it should already be resetted, anyway...)
(i32.store16 offset=0x1BFC08 align=2
(i32.const 0x0) (i32.const 0x0))
;; initialize counter
(set_local $counter (i32.const 0))
;; add numbers from 1 to 100
(i32.const 0)
(loop $again (param i32) (result i32)
(set_local $counter (i32.add
(get_local $counter)
(i32.const 1)))
(i32.add (get_local $counter))
(br_if $again (i32.lt_u
(get_local $counter)
(i32.const 100))))
;; we now leave sum on the stack for later
;; light led2
(i32.store16 offset=0x1BFC06 align=2
(i32.const 0x0) (i32.const 0x1))
;; print timer value
(set_local $adr (call $print
;; read timer value
(i32.load16_u offset=0x1BFC08 align=2
(i32.const 0x0))
(i32.const 0xFFC00)))
;; print ascii underscore '_'
(i32.store8 offset=0x0 align=1
(get_local $adr) (i32.const 0x5F))
;; print computed sum
(set_local $adr (call $print
;; sum's already on the stack
(i32.add (get_local $adr) (i32.const 1))))
;; 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)))
|