-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbootloader.asm
284 lines (248 loc) · 10.1 KB
/
bootloader.asm
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
; Bootloader Console
; Simon Kirkby
; 20190822
; obeygiantrobot@gmail.com
; automatic gizmo headers
;.equ blinky,0
;.equ user_led,1
;.equ tx_status,2
;.equ tx_data,3
;.equ rx_status,4
;.equ rx_data,5
;.equ image,6
;.equ boot,7
base: .window ; todo this macro needs to align to 8 word boundary
win: .window ; named window , this is hand aligned to *8
J init ; jump to init
reboot: ; label for rebooting into
; pad itself is declared at the bottom so it does not overwrite code
; blinky holding program
;.equ timer, 65000
;blinkInit: ; start here
; MOVI R0,0 ; move zero into R0
; MOVI R1,0 ; move zero into R1
;blinkEntry:
; ADDI R0,R0, 1 ; add one to R0 ( increment the leds )
; STXA R0, blinky ; write to the leds
;blinkWait:
; ADDI R1,R1,1 ; add 1 to the counter
; CMPI R1,timer ; is the counter equal to timer ?
; JNE blinkWait ; not there yet jump back
; MOVI R1,0 ; reset R1 to zero
; J blinkEntry ; start again , increment the leds
spacer: .alloc 512 ; spacer for the new program , asm needs to be able to link to the bottom
; accumulate and execute a char pad.
init: ; initialize the program all the registers.
MOVI R0,base
STW R0 ; set the register window at zero
MOVI R0,0 ; working register
MOVI R1,0 ; working address
MOVI R2,0 ; holding data
MOVI R3,0 ; device status
MOVI R4,0 ; current bootloader write data
MOVI R5,0 ; end of string address
MOVI R6,0 ; jump2 return address , no return stack , careful with the return registers
MOVI R7,0 ; jump return address
;write the greet string
MOVR R1,nl ; newline
JAL R6,dumpstring
MOVR R1,greet ; greetings string
JAL R6,dumpstring
MOVR R1,pwd ; prompt
JAL R6,dumpstring
MOVR R1,pad ; load the pad address
MOVI R0,0 ; load a zero
ST R0,R1,0 ; store the zero in the pad length cell
MOVR R1,padStatus ; reset the pad status
MOVI R0,0
ST R0,R1,0
run: ; main loop
JAL R7,checkrx ; get a char from the serial port
JAL R7,txchar ; write R2 ( holding ) to the serial port
J procpad ; check pad active and process
J run
warmboot:
MOVR R1,wb ; write the warmboot string to the console
JAL R6,dumpstring
MOVI R0,0 ; set boot image to 0
STXA R0,image ; write to the image external register
MOVI R0,1 ; write one into regiters
STXA R0,boot ; reboot the FPGA into the boot loader
warmme:
MOVI R0,1 ; set boot image to 1
STXA R0,image ; write to the image external register
MOVI R0,1 ; write one into regiters
STXA R0,boot ; reboot the FPGA into the boot loader
checkrx: ; get a char off the serial port
LDXA R3,rx_status ; load the RX status from the serial port
CMPI R3,1 ; compare the register to 1
BEQ addtopad ; if it is equal to one , add it to the pad
J checkrx
addtopad: ; get the data and acknowledge
LDXA R2,rx_data ; load the RX data from the serial port
MOVI R3,1 ; load 1 into to R3
STXA R3,rx_status ; acknowledge the char in the serial port
MOVI R3,0 ; load 0 into to R3
STXA R3,rx_status ; acknowledge the char in the serial port
CMPI R2,4 ; check if it is ^D , warmboot
BEQ warmboot
CMPI R2,3 ; check ^C restart processor
BEQ init
; check if it is a CR and set the padstatus to 1
CMPI R2,13 ; is a CR
BNE padContinue
; update the pad status to 1
MOVR R1,padStatus
MOVI R0,1
ST R0,R1,0
JR R7,0
padContinue:
; put the incoming char into the pad
MOVR R1,pad ; move pad into the working address
LD R0,R1,0 ; load the length into the working register
ADDI R0,R0,1 ; increment to pad count
AND R5,R1,R1 ; copy the pad address into holding
ADD R5,R5,R0 ; add the current pad length to holding
ST R2,R5,0 ; store the word into to address in holding
ST R0,R1,0 ; store the value back into the pad counter
JR R7,0 ; jump to main
txchar: ; put a char into the serial port
STXA R2,tx_data ; put the holding data into the serial port
STXA R2,blinky ; into blinky
MOVI R3,1 ; set status to one
STXA R3,tx_status ; write to tx status
MOVI R3,0 ; set the status to zero
STXA R3,tx_status ; acknowledge the write
waitup: ; TODO , this should be a fifo in the serial port
LDXA R3,tx_status ; wait for tx status to go high
CMPI R3,1
BEQ waitup
waitdown:
LDXA R3,tx_status ; wait for the status to go low
CMPI R3,0
BEQ waitdown
JR R7,0
; strings are pascal style strings, first word is the length of the string.
dumpstring:
LD R0,R1,0 ; load the length of the string into R0
CMPI R0,0 ; empty string , go back
BEQ exitdump
AND R5,R1,R1 ; copy address into temp
ADD R5,R5,R0 ; add the length to the address
; R1 is the current address
; R5 is the end of the string
nextchar:
ADDI R1,R1,1 ; increment the pointer
LD R2,R1,0 ; load the data at working address into holding
JAL R7,txchar ; write the char
CMP R1,R5 ; compare current with end of string
BLTU nextchar ; not there yet, get next char
exitdump:
JR R6,0 ; return with jump2
; Process the pad
procpad:
MOVR R1,padStatus ; load the pad status address into R1
LD R0,R1,0 ; load the pad status into R0
CMPI R0,1 ; is the pad active
BEQ procPadContinue ; continue
J run ; return to run
procPadContinue:
; process the pad here
; just dump to console for now
;MOVR R1,nl ; write a newline
;JAL R6,dumpstring
;MOVR R1,pad ; write the pad
;JAL R6,dumpstring
; read HEX number and write to memory
MOVR R1,pad ; load pad address
J hexread ; read hex
; next command ...
nextcommand:
;MOVR R1,nl ; write a newline
;JAL R6,dumpstring
;MOVR R1,pwd ; write the console prompt
;JAL R6,dumpstring
MOVR R1,padStatus ; reset pad status
MOVI R0,0
ST R0,R1,0
MOVR R1,pad ; reset pad counter
MOVI R0,0
ST R0,R1,0
J run ; back to main loop
greet: .string "Boneless-v3-zignig-bootloader\r\n"
nl: .string "\r\n"
pwd: .string "$"
wb: .string "!warmboot"
next: .string "..."
error: .string "\r\n!Error"
boottext: .string "\r\nbooting..."
; add strings various here
; some variables
padStatus: .alloc 1 ; is the pad ready to go ?
addr: .word 8 ; current address of the write bootloader writer
jump: .alloc 1 ; address to boot into
length: .alloc 1 ; length of the new firmware
mode: .word 0 ; the current mode of the bootloader
; TODO what to do with the pad ?
; get read hex running
; convert to number and write to memory
; jump to start
hexread:
LD R0,R1,0 ; load the length of the string into R0
CMPI R0,4 ; is the length of the pad 4 ?
BEQ hexcont ; yes , continue
J hexerror ; no , write error and reset program
hexcont:
MOVI R4,0 ; zero out the data
AND R5,R1,R1 ; copy address into temp
ADD R5,R5,R0 ; add the length to the address
hexnext:
ADDI R1,R1,1 ; increment the pointer to the next char
LD R0,R1,0 ; load the data at working address into holding
CMPI R0,70 ; is it above F , error
BGTU hexerror
CMPI R0,65 ; is it above A , must be a letter
BGEU letter
CMPI R0,57
BGTU hexerror ; gap between 9 and A , error
CMPI R0,48 ; greater than digit 0
BGEU number ; it's a number
J hexerror ; nope , an error
continue:
CMP R1,R5 ; compare current with end of string
BEQ copytomem
J hexnext
copytomem:
; R4 should contain the decoded hex value
CMPI R4,0xFFFF ; if the string is FFFF boot into it
BEQ bootinto
MOVR R1,addr ; load the working address
LD R0,R1,0 ; load the value
ST R4,R0,0 ; store the working data into the address
ADDI R0,R0,1 ; increment the pointer
ST R0,R1,0 ; put it back into addr
;AND R2,R0,R0
; debug
;ADDI R2,R2,57
;JAL R7,txchar
J nextcommand
letter: ; process a hex letter
SUBI R0,R0,55 ; subtract to get the ordinal value of the letter
J nextnibble
number:
SUBI R0,R0,48 ; subtract 40 to get the ordinal of a number
nextnibble:
SLLI R4,R4,4 ; shift left 4 bits
OR R4,R4,R0 ; OR the nibble
J continue ; next char
bootinto:
MOVR R1,boottext
JAL R6,dumpstring ; write the boot string
MOVI R0,win
STW R0 ; set the register window at zero
J reboot
hexerror:
MOVR R1,error ; set error
JAL R6,dumpstring ; write the string
J init
pad: .alloc 32 ; the pad itself