-
Notifications
You must be signed in to change notification settings - Fork 7
/
bootrom-debug.s
306 lines (249 loc) · 6 KB
/
bootrom-debug.s
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# SCAMP bootloader
# The first 3 words from the disk device should be:
# 1. magic number (0x5343)
# 2. start address
# 3. length
# Once the given number of words have been loaded into memory at the
# given address, the address will be jumped to.
# Apart from the loaded code and the program counter, all machine state is
# undefined, including flags, contents of X, and all pseudo-registers including sp
.at 0
.def CFDATAREG 264
.def CFERRREG 265
.def CFBLKCNTREG 266
.def CFBLKNUMREG 267
.def CFCYLLOREG 268
.def CFCYLHIREG 269
.def CFHEADREG 270
.def CFSTATUSREG 271
.def CFREADCMD 0x20
.def SERIALREG0 136
.def SERIALREG1 137
.def SERIALREG3 139
.def SERIALREG5 141
.def SERIALCLKDIV 1 # 115200/1 = 115200 baud
.def START 0xff01 # r1
.def POINT 0xff02 # r2
.def LENGTH 0xff03 # r3
ld sp, 0x8000
call serial_init
# 1. print hello
ld r0, welcome_s
call print
call storage_init
# 2. read magic from disk
.def MAGIC 0x5343
call inword
#ld r11, r0
#ld r0, wrongmagic_s
#sub r11, MAGIC
#jnz error
# 3. read start address from disk
call inword
ld (START), r0
ld (POINT), r0
ld x, r0
ld r0, startinrom_s
#and x, 0xff00
#jz error
# 4. read length from disk
call inword
ld r11, r0
ld r0, zerolength_s
ld (LENGTH), r11
#jz error
# 5. read data from disk
read_data:
call inword
ld x, r0
ld ((POINT)++), x
dec (LENGTH)
jnz read_data
ld r0, ok_s
call print
# 6. jump to the loaded code
jmp (START)
# error message pointer in r0
#error:
# ld r1, r0
# ld r0, diskerror_s
# call print
# ld r0, r1
# call print
# jr- 1
# print the nul-terminated string pointed to by r0
print:
# wait for uart to be ready
# TODO: [bug] why are the nops necessary?
nop
in x, SERIALREG5 # line status register
nop
and x, 0x20 # test for "Transmitter Holding Register Empty"
nop
jz print # loop again if it's not ready
ld x, (r0++)
test x
jz printdone
# output the character
out SERIALREG0, x
jmp print
printdone:
ret
# r10 = value
# r15 = first bit to test (gets shifted-left 4)
test4bits:
ld r8, 1 # r8 = bit to set
ld r0, 0 # r0 = result
ld r9, 4
test4bits_loop:
ld x, r10
and x, r15
jz test4bits_dontset
or r0, r8
test4bits_dontset:
shl r8
shl r15
dec r9
jnz test4bits_loop
ret
# print hex of the word in r10, followed by '\r\n'
alphabet: .str "0123456789abcdef"
printhex:
ld x, r254
push x
ld r15, 1 # bit to test
ld r16, 0xff15 # address (start at r21 and work down)
printhex_loop:
call test4bits
add r0, alphabet
ld x, (r0)
ld (r16--), x
test r15
jnz printhex_loop
ld r22, 0x0d
ld r23, 0x0a
ld r24, 0
ld r0, 0xff12
call print
pop x
ld r254, x
serial_init:
# select divisor latches:
# write 0x80 to line control register
ld x, 0x80
out SERIALREG3, x
# set high byte of divisor latch = 0
ld x, 0
out SERIALREG1, x
# set low byte of divisor latch = SERIALCLKDIV
ld x, SERIALCLKDIV
out SERIALREG0, x
# select data register instead of divisor latches, and set 8-bit words, no parity, 1 stop:
# write 0x03 to line control register (addr 3)
ld x, 0x03
out SERIALREG3, x
ret
.def BLKNUM 0xff04 # r4
.def BLKIDX 0xff05 # r5
storage_init:
ld x, r254
push x
# initialise LBA address to 0 by writing 0 to Sector Number, Cylinder Low,
# and Cylinder High Registers, and 224 ("enable LBA") to the Drive/Head
# Register
ld r22, 0
call cfwait
ld x, 0
out CFBLKNUMREG, x
#call cfwait
ld x, 0
out CFCYLLOREG, x
#call cfwait
ld x, 0
out CFCYLHIREG, x
#call cfwait
ld x, 224
out CFHEADREG, x
# ask for 1 block
ld r22, 0x40
call cfwait
ld x, 1
out CFBLKCNTREG, x
# issue "read" command
#call cfwait
ld x, CFREADCMD
out CFSTATUSREG, x
ld (BLKIDX), 0
ld (BLKNUM), 0
pop x
ld r254, x
ret
# spin until card status matches mask in r22
# status flags are:
# 0x01 - ERR - the previous command ended in some time of error (see the Error Register)
# 0x02 - 0 - always 0
# 0x04 - CORR - a correctable error has occurred and the data has been corrected
# 0x08 - DRQ - the card requires information transferred to or from the host via the Data Register
# 0x10 - DSC - the card is ready
# 0x20 - DWF - a write fault has occurred
# 0x40 - RDY - the device is capable of performing card operations
# 0x80 - BUSY - the host is locked out from accessing the command register and buffer
cfwait:
in x, CFSTATUSREG
# first check if card is BUSY: if so, the other bits are undefined
ld r11, x
and x, 0x80
jnz cfwait
# now test whether the bits from the mask are all set
ld x, r11
and x, r22
sub x, r22
jnz cfwait
ret
# read the next 1 word from the disk device and return it in r0
inword:
ld x, r254
push x
ld r22, 0x48 # RDY | DRQ
call cfwait
# TODO: [bug] for some reason, trying to do:
# in r0, CFDATAREG
# results in corrupting the state of the UART, so we instead
# input into x and then load r0 from x
in x, CFDATAREG
ld r0, x
ld r10, x
call printhex
ld r0, r10
inc (BLKIDX)
# do we need to go to the next block?
ld x, (BLKIDX)
and x, 0xff00 # x&0xff00 == 0 except when we need the next block
jz inword_ret
nextblk:
ld r22, 0x40
call cfwait
inc (BLKNUM)
ld (BLKIDX), 0
# ask for the new block number
out CFBLKNUMREG, (BLKNUM)
call cfwait
# ask for 1 block
ld x, 1
out CFBLKCNTREG, x
call cfwait
# issue "read" command
ld x, CFREADCMD
out CFSTATUSREG, x
ld x, 0x2e # '.'
out SERIALREG0, x
inword_ret:
pop x
ld r254, x
ret
welcome_s: .str "SC b...\r\n\0"
ok_s: .str "K\r\n\0"
diskerror_s: .str "disk error: \0"
wrongmagic_s: .str "bad magic\0"
startinrom_s: .str "start in ROM\0"
zerolength_s: .str "0 length\0"