aboutsummaryrefslogtreecommitdiff
path: root/examples/example3a_spi_wasm/instructions.wat
blob: f09e080e34d3f56221149f540b587aa4c52250a3 (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
111
112
113
114
115
;; 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), SPI memory (0x13FC00),
;; SPI bytes_to_output reg (0x13FE00), SPI bytes_to_receive reg (0x13FE02)
;; and SPI operating reg (0x13FE04).

(module
 (memory 0 2)
 (func $main
       (local $transfers i32)
       (local $offset i32)
       (local $address i32)
       (local $index i32)

       ;; power up flash chip
       ;; set bytes_to_output to 1
       (i32.store16 offset=0 align=2
		    (i32.const 0x13FE00) (i32.const 1))
       ;; set bytes_to_receive to 0
       (i32.store16 offset=0 align=2
		    (i32.const 0x13FE02) (i32.const 0))
       ;; release power-down SPI command
       (i32.store8 offset=0 align=1
		   (i32.const 0x13FC00) (i32.const 0xAB))
       ;; start SPI operation
       (i32.store16 offset=0 align=2
		    (i32.const 0x13FE04) (i32.const 0x1))

       ;; wait for at least 3000 ns after command gets sent
       ;; reset the timer
       (i32.store16 offset=0x0 align=2
		    (i32.const 0x1BFC08) (i32.const 0x0))

       ;; loop until 45 ticks pass; 45 ticks is 3600 ns; additional 600ns
       ;; is enough for power-up command to be sent
       (loop $again
	     (br_if $again (i32.lt_u
			    (i32.load16_u offset=0x0 align=2
					  (i32.const 0x1BFC08))
			    (i32.const 45))))

       ;; we'll transfer 2400 bytes by making 5 transfers of 480 bytes;
       ;; our SPI peripheral can transfer at most 511 bytes in one SPI command
       (set_local $transfers (i32.const 0))

       (loop $outer
	     ;; set bytes_to_output to 5
	     (i32.store16 offset=0 align=2
			  (i32.const 0x13FE00) (i32.const 5))
	     ;; set bytes_to_receive to 480
	     (i32.store16 offset=0 align=2
			  (i32.const 0x13FE02) (i32.const 480))
	     ;; fast read SPI command
	     (i32.store8 offset=0 align=1
			 (i32.const 0x13FC00) (i32.const 0x0B))
	     ;; prepare address - first, compute current offset
	     (set_local $offset (i32.mul (get_local $transfers)
					 (i32.const 480)))
	     ;; then, add computed offset to base address of 135100
	     (set_local $address (i32.add (get_local $offset)
					  (i32.const 135100)))
	     ;; store the address in big endian
	     (i32.store16 offset=0 align=2
			  (i32.const 0x13FC02)
			  (i32.div_u (get_local $address)
				     (i32.const 256)))
	     (i32.store8 offset=0 align=1
			 (i32.const 0x13FC03) (get_local $address))
	     (i32.store8 offset=0 align=1
			 (i32.const 0x13FC01)
			 (i32.div_u (get_local $address)
				    (i32.const 65536)))
	     ;; start SPI operation
	     (i32.store16 offset=0 align=2
			  (i32.const 0x13FE04) (i32.const 0x1))
	     ;; force wait for operation completion
	     (i32.store16 offset=0 align=2
			  (i32.const 0x13FE00) (i32.const 0))

	     ;; assume transferred data to be ascii text and print it to screen
	     ;; initialize index to 0
	     (set_local $index (i32.const 0))
	     ;; copy characters in a loop
	     (loop $inner
		   ;; copy 4 characters to VGA memory
		   (i32.store offset=0xFFC00 align=4
			      (i32.add (get_local $index)
				       (get_local $offset))
			      (i32.load offset=0x13FC00 align=4
					(get_local $index)))
		   ;; increase index
		   (set_local $index (i32.add (get_local $index)
					      (i32.const 4)))
		   ;; loop condition
		   (br_if $inner (i32.lt_u
				  (get_local $index)
				  (i32.const 480))))

	     ;; increase transfers count
	     (set_local $transfers (i32.add (get_local $transfers)
					    (i32.const 1)))

	     ;; switch LED2
	     (i32.store16 offset=0x0 align=2
			  (i32.const 0x1BFC06)
			  (i32.rem_u (get_local $transfers) (i32.const 2)))

	     ;; if less than 5 transfers were done, continue with another one
	     (br_if $outer (i32.lt_u (get_local $transfers) (i32.const 5))))

       ;; write a non-zero value to the VGA power-on reg at 0x100600 (0x100A00)
       (i32.store16 offset=0x0 align=2
		    (i32.const 0x100600) (i32.const 0x1)))
 (export "main" (func $main)))