-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathloader.asm
340 lines (314 loc) · 10.6 KB
/
loader.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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
;
; This loader will be contained within a REM statement in
; a BASIC program created using bin2rem.
;
defc MEM_BANK_ROM=0x10
defc IO_BORDER=0xfe
defc IO_BANK=0x7ffd
defc MIC_OUTPUT=8
defc FLD_BYTES=+($c000-160)
defc LD_BYTES=0x556
defc ERR_SP=0x5c3d
; Screen memory addresses and dimensions
defc SCREEN_START=0x4000
defc SCREEN_LENGTH=0x1800
defc SCREEN_END=SCREEN_START+SCREEN_LENGTH
defc SCREEN_ATTR_START=SCREEN_START+SCREEN_LENGTH
defc SCREEN_ATTR_LENGTH=0x300
defc SCREEN_ATTR_END=SCREEN_ATTR_START+SCREEN_ATTR_LENGTH
defc BORDCR=0x5c48
;
; ROM routine addresses
;
ROM_CLS EQU 0x0DAF ; Clears the screen and opens channel 2
ROM_OPEN_CHANNEL EQU 0x1601 ; Open a channel
ROM_PRINT EQU 0x203C ; Print a string
ATTR_P EQU 0x5C8D
;
; PRINT control codes - work with ROM_PRINT and RST 0x10
;
INK EQU 0x10
PAPER EQU 0x11
FLASH EQU 0x12
BRIGHT EQU 0x13
INVERSE EQU 0x14
OVER EQU 0x15
AT EQU 0x16
TAB EQU 0x17
CR EQU 0x0C
; Start address used by bin2rem 23766
org 0x5cd6
start:
jr start1
dw blocks
dw loadBlock
dw version
version:
ds 32
start1:
di
ld sp, stack
xor a
ld (ATTR_P), a
call ROM_CLS
; Copy LD_BYTES to a non-contended bank
ld bc, 160
ld hl, LD_BYTES_START
ld de, FLD_BYTES
ldir
; Detect 128K/48K
detect48K:
ld de, $c000
ld bc, IO_BANK ; Memory bank port
xor a
out (c), a ; Select bank 0
ld (de), a ; Write 0 to bank 0
inc a
out (c), a ; Select bank 1
ld (de), a ; Write 1 to bank 1
dec a
out (c), a ; Select bank 0
ld a, (de) ; Read value from bank 0
; a = 0 (128K)
; a = 1 (48K)
or a
jr z, fullLoad
; Prevent 128K banks from loading
; on 48K systems
ld b, 9
ld hl, blocks
ld de, 7
testBlock:
ld a, $15
cp (hl)
jr z, loadIt
ld a, $12
cp (hl)
jr z, loadIt
ld a, $10
cp (hl)
jr z, loadIt
; Prevent block from loading by setting back
; to -1
set 7, (hl)
loadIt:
add hl, de
djnz testBlock
fullLoad:
ld b, 9
ld hl, blocks
nextBlock:
call loadBlock
djnz nextBlock
ld a, MEM_BANK_ROM
ld bc, IO_BANK ; Memory bank port
out (c), a ; Select bank 0
; Exec address is stored directly above stack
; we can simply return to the execAddr
ret
;
; Load and decompress a block from tape
;
; Input:
; a - bank
; hl - Pointer to block data
;
loadBlock:
push bc
push hl
; Set the bank to load
ld bc, IO_BANK
ld a, (hl)
or a
jp m, loadBlockDone
inc hl
out (c), a
ld e, (hl)
inc hl
ld d, (hl)
inc hl
push de ; loadSize
ld c, (hl)
inc hl
ld b, (hl)
inc hl
push bc ; loadAddr
push bc
pop ix
ld c, (hl)
inc hl
ld b, (hl)
inc hl
push bc ; destAddr
ld a, 0xff ; Data block
scf ; Load not verify
ld hl, tapeError ; Address to jump to on error
push hl
ld (ERR_SP), sp
tapeLoader equ $+1
call LD_BYTES ; Do the load
di
ret nc
pop hl ; Error handler address
ld a, MIC_OUTPUT
out (IO_BORDER), a
pop de ; destAddr
pop hl ; loadAddr
pop bc ; loadSize
ld a, d
cp $40 ; Check for $40xx (screen memory)
jr nz, reverse ; if not, use reverse decompression
call dzx0_standard ; else, decompress forwards
jr loadBlockDone
reverse:
add hl, bc
dec hl ; Last byte of loaded data
call dzx0_standard_back ; Decompress backwards
loadBlockDone:
pop hl
ld bc, $7
add hl, bc
pop bc
ret
; -----------------------------------------------------------------------------
; ZX0 decoder by Einar Saukas
; "Standard" version (69 bytes only) - BACKWARDS VARIANT
; -----------------------------------------------------------------------------
; Parameters:
; HL: last source address (compressed data)
; DE: last destination address (decompressing)
; -----------------------------------------------------------------------------
dzx0_standard_back:
ld bc, 1 ; preserve default offset 1
push bc
ld a, $80
dzx0sb_literals:
call dzx0sb_elias ; obtain length
lddr ; copy literals
inc c
add a, a ; copy from last offset or new offset?
jr c, dzx0sb_new_offset
call dzx0sb_elias ; obtain length
dzx0sb_copy:
ex (sp), hl ; preserve source, restore offset
push hl ; preserve offset
add hl, de ; calculate destination - offset
lddr ; copy from offset
inc c
pop hl ; restore offset
ex (sp), hl ; preserve offset, restore source
add a, a ; copy from literals or new offset?
jr nc, dzx0sb_literals
dzx0sb_new_offset:
inc sp ; discard last offset
inc sp
call dzx0sb_elias ; obtain offset MSB
dec b
ret z ; check end marker
dec c ; adjust for positive offset
ld b, c
ld c, (hl) ; obtain offset LSB
dec hl
srl b ; last offset bit becomes first length bit
rr c
inc bc
push bc ; preserve new offset
ld bc, 1 ; obtain length
call c, dzx0sb_elias_backtrack
inc bc
jr dzx0sb_copy
dzx0sb_elias_backtrack:
add a, a
rl c
rl b
dzx0sb_elias:
add a, a ; inverted interlaced Elias gamma coding
jr nz, dzx0sb_elias_skip
ld a, (hl) ; load another group of 8 bits
dec hl
rla
dzx0sb_elias_skip:
jr c, dzx0sb_elias_backtrack
ret
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
; ZX0 decoder by Einar Saukas & Urusergi
; "Standard" version (68 bytes only)
; -----------------------------------------------------------------------------
; Parameters:
; HL: source address (compressed data)
; DE: destination address (decompressing)
; -----------------------------------------------------------------------------
dzx0_standard:
ld bc, $ffff ; preserve default offset 1
push bc
inc bc
ld a, $80
dzx0s_literals:
call dzx0s_elias ; obtain length
ldir ; copy literals
add a, a ; copy from last offset or new offset?
jr c, dzx0s_new_offset
call dzx0s_elias ; obtain length
dzx0s_copy:
ex (sp), hl ; preserve source, restore offset
push hl ; preserve offset
add hl, de ; calculate destination - offset
ldir ; copy from offset
pop hl ; restore offset
ex (sp), hl ; preserve offset, restore source
add a, a ; copy from literals or new offset?
jr nc, dzx0s_literals
dzx0s_new_offset:
pop bc ; discard last offset
ld c, $fe ; prepare negative offset
call dzx0s_elias_loop ; obtain offset MSB
inc c
ret z ; check end marker
ld b, c
ld c, (hl) ; obtain offset LSB
inc hl
rr b ; last offset bit becomes first length bit
rr c
push bc ; preserve new offset
ld bc, 1 ; obtain length
call nc, dzx0s_elias_backtrack
inc bc
jr dzx0s_copy
dzx0s_elias:
inc c ; interlaced Elias gamma coding
dzx0s_elias_loop:
add a, a
jr nz, dzx0s_elias_skip
ld a, (hl) ; load another group of 8 bits
inc hl
rla
dzx0s_elias_skip:
ret c
dzx0s_elias_backtrack:
add a, a
rl c
rl b
jr dzx0s_elias_loop
tapeError:
di
call ROM_CLS
ld de, tapeErrorMsg
ld bc, tapeErrorMsgEnd-tapeErrorMsg
call ROM_PRINT
jr $
tapeErrorMsg:
db AT, 11, 6, INK, 2, PAPER, 0, FLASH, 1, "Tape loading error!!"
tapeErrorMsgEnd:
; -----------------------------------------------------------------------------
ds 32, $55
stack:
ds 2
blocks:
REPT 9
db $ff
ds 6
ENDR
; The below is overwritten with the tape loader
LD_BYTES_START:
ds 160, $55