-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcasloader.asm
353 lines (309 loc) · 13 KB
/
casloader.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
341
342
343
344
345
346
347
348
349
350
351
352
353
;===============================================================================
;TURGEN SYSTEM - STDBLOAD 2a, modified by Jacek Kuczera
;Binary loader for standard (FSK) tape records
;The author has placed this work in the Public Domain, thereby relinquishing all
;copyrights. Everyone is free to use, modify, republish, sell or give away this
;work without prior consent from anybody.
;This loader uses the "trailing EOF record trick" - Last 128 bytes of the
;loader are in the EOF block. These 128 bytes are moved from the cassette
;buffer to the intended memory location. The trick allows this loader to be
;only 4 records long
;The loader is ROM OS agnostic
;U̶s̶i̶n̶g̶ ̶t̶h̶e̶ ̶L̶D̶R̶T̶Y̶P̶E̶ ̶s̶y̶m̶b̶o̶l̶,̶ ̶t̶h̶i̶s̶ ̶l̶o̶a̶d̶e̶r̶ ̶c̶a̶n̶ ̶b̶e̶ ̶a̶s̶s̶e̶m̶b̶l̶e̶d̶
;t̶o̶ ̶e̶i̶t̶h̶e̶r̶ ̶b̶o̶o̶t̶ ̶(̶L̶D̶R̶T̶Y̶P̶E̶=̶0̶)̶ ̶o̶r̶ ̶b̶i̶n̶a̶r̶y̶ ̶(̶L̶D̶R̶T̶Y̶P̶E̶=̶1̶)̶ ̶f̶i̶l̶e̶.̶
;===============================================================================
LDR_START = $7100
CASBLOCKS = 5
CIO1_OP = $0342+16
CIO1_STAT = $0343+16
CIO1_BUFLO = $0344+16
CIO1_BUFHI = $0345+16
CIO1_LENLO = $0348+16
CIO1_LENHI = $0349+16
CIO1_AUX1 = $034A+16
CIO1_AUX2 = $034B+16
CIO0_OP = $0342
CIO0_STAT = $0343
CIO0_BUFLO = $0344
CIO0_BUFHI = $0345
CIO0_LENLO = $0348
CIO0_LENHI = $0349
CIO0_AUX1 = $034A
CIO0_AUX2 = $034B
opt h-
org LDR_START
;-------------------------------------------------------------------------------
; Boot header
;-------------------------------------------------------------------------------
BOOTHEAD dta 0
dta CASBLOCKS-1 ;number of cassette blocks (not counting the EOF block)
dta a(LDR_START)
dta a(FAKEINIT)
lda #60 ;Motor off
sta PACTL
ldx #255 ;Clear pushdown store
txs
;-------------------------------------------------------------------------------
; Move last portion of the loader code from cassette buffer
;-------------------------------------------------------------------------------
RELO_P2 ldx #128 ;Move 128 bytes of the EOF block
RELO_P2_L lda 1024-1,X ;from cassette buffer
sta LDR_START+((CASBLOCKS-1)*128)-1,X ;to the intended place
dex
bne RELO_P2_L
;-------------------------------------------------------------------------------
; Loader mainline code
;-------------------------------------------------------------------------------
BL000 jsr STARTUP ;Display program name
BLTOP lda #1 ;Rest flags (first segment + no binary header)
sta BLF_FIRST
sta BLF_NOBIN
jsr FCLOSE
jsr FOPEN ;Call subroutine that opens C: file
lda CIO1_STAT ;Check for error
bpl GETSEG ;No error, continue
jsr ERRHNDL ;If error occured, go to handle it
jmp BLTOP ;Then start again
;-------------------------------------------------------------------------------
; Read a segment
;-------------------------------------------------------------------------------
GETSEG lda #<FAKEINIT ;Set fake INIT vector to RTS
sta INITAD
lda #>FAKEINIT
sta INITAD+1
;-------------------------------------------------------------------------------
; Get segment header
;-------------------------------------------------------------------------------
GS_STRTA lda #<BLSEGHEAD ;Read first two bytes of segment header
sta CIO1_BUFLO
lda #>BLSEGHEAD
sta CIO1_BUFHI
lda #2
sta CIO1_LENLO
lda #0
sta CIO1_LENHI
jsr GETBLK
lda #255 ;Check for 255 255
cmp BLSEGHEAD
bne GS_ENDA
cmp BLSEGHEAD+1
bne GS_ENDA ;If 255 255 not found, continue
lda #0
sta BLF_NOBIN
jmp GS_STRTA ;And then start over
GS_ENDA lda #<(BLSEGHEAD+2) ;Get rest of the segment header
sta CIO1_BUFLO
lda #>(BLSEGHEAD+2)
sta CIO1_BUFHI
lda #2
sta CIO1_LENLO
lda #0
sta CIO1_LENHI
jsr GETBLK
;-------------------------------------------------------------------------------
; Processing specific for the first segment
; 255 255 header check
; RUNAD is set to point to the first segment
;-------------------------------------------------------------------------------
lda BLF_NOBIN ;Check if 255 255 header was found
beq GS_FSRUN ;It was, we can continue
jmp ERRNOBIN ;If not, we signalize an error and continue
GS_FSRUN lda BLF_FIRST ;Is this the first segment
beq GS_CALCLN ;No, just continue
lda #0 ;Reset first segment indication
sta BLF_FIRST ;RUNAD points to this segment
lda BLSEGHEAD
sta RUNAD
lda BLSEGHEAD+1
sta RUNAD+1
;-------------------------------------------------------------------------------
; Calculate length of the segment
;-------------------------------------------------------------------------------
GS_CALCLN sec ;Subtract start address from end address
lda BLSEGHEAD+2
sbc BLSEGHEAD+0
sta CIO1_LENLO
bcs GS_LENHI
dec BLSEGHEAD+3
GS_LENHI sec
lda BLSEGHEAD+3
sbc BLSEGHEAD+1
sta CIO1_LENHI
clc ;Increase the difference by 1 to get length
lda CIO1_LENLO
adc #1
sta CIO1_LENLO
bcc GS_GETD
inc CIO1_LENHI
;-------------------------------------------------------------------------------
;Read segment data
;-------------------------------------------------------------------------------
GS_GETD lda BLSEGHEAD
sta CIO1_BUFLO
lda BLSEGHEAD+1
sta CIO1_BUFHI
jsr GETBLK
;-------------------------------------------------------------------------------
; INIT segment handling
;-------------------------------------------------------------------------------
lda INITAD ;Check if there was real INIT segment
cmp #<FAKEINIT
bne REALINI
lda INITAD+1
cmp #>FAKEINIT
beq POSTINI
REALINI lda #60 ;Switch off the motor
sta PACTL
jsr DOINIT ;Execute INIT segment code
lda #52 ;Switch on the motor
sta PACTL
POSTINI jmp GETSEG ;Get another segment
;===============================================================================
;Subroutine that gets a blocks using CIO. Buffer address and length of
;the block must be set by the caller.
;===============================================================================
GETBLK ldx #16 ;Channel 1
lda #7 ;Requesting CIO READ operation
sta CIO1_OP
jsr CIOV ;Call CIO
lda CIO1_STAT ;Check for error
bmi GBERR ;Error occured - handle it
rts
GBERR cmp #136 ;Is this EOF ?
bne GBERR_S ;No - handle error
ldx #255 ;Yes, this is EOF
txs ;Clear stack
jsr FCLOSE ;Close file
jmp (RUNAD) ;Run the program
GBERR_S jmp ERRHNDL
;===============================================================================
;Emulation of JSR(738)
;===============================================================================
DOINIT jmp (INITAD)
FAKEINIT rts
;===============================================================================
;Main data area
;===============================================================================
BLSEGHEAD dta 0,0,0,0 ;Segment header and position pointer
BLF_FIRST dta 0 ;First segment to be loaded
BLF_NOBIN dta 0 ;No binary file header found yet
CDEV dta c'C:',155 ;File name
;===============================================================================
;Subroutine that closes file
;===============================================================================
FCLOSE ldx #16
lda #12 ;Requesting CIO CLOSE operation with code 12
sta CIO1_OP
jsr CIOV ;Call CIO
rts
;===============================================================================
;Subroutine that opens file
;===============================================================================
FOPEN ldx #16 ;IOCB 1
lda #3 ;Requesting CIO OPEN operation with code 3
sta CIO1_OP
lda #4 ;Auxiliary value 4 - open for reading
sta CIO1_AUX1
lda #12 ;And also simulate key press
sta CH
lda #128 ;Auxiliary value 128 - short IRGs
sta CIO1_AUX2
lda #<CDEV ;Buffer- DEVICE:FILENAME ("C:")
sta CIO1_BUFLO
lda #>CDEV
sta CIO1_BUFHI
jsr CIOV ;Call CIO
rts
;===============================================================================
;Error handling
;===============================================================================
ERRHNDL lda #$24 ;I/O error - red background
jsr ERRSIG
jmp COLDSV ;Cold start
ERRNOBIN lda #$0E ;Not a binary file - white background
jsr ERRSIG
jmp WARMSV ;Warm start
;===============================================================================
; Auxiliary routines for error handling
;===============================================================================
ERRSIG sta COLOR4 ;Signalize error by changing background
sta COLOR2
sta COLBK
sta COLPF2
lda #60 ;Switch off the motor
sta PACTL
jsr WFORKEY
rts
WFORKEY lda #255 ;Wait for any key
sta CH
WFORKEYL lda CH
cmp #255
beq WFORKEYL
rts
;===============================================================================
; Loader startup
;===============================================================================
STARTUP lda #0 ;Reset cold start flag
sta COLDST
lda #1 ;Indicate disk boot succeded
sta BOOT
jsr DINI
lda #<DINI
sta DOSINI
lda #>DINI
sta DOSINI+1
lda #1 ;Turn off cursor
sta CRSINH
lda #$E ;White letters
sta COLOR1
lda #$0 ;Black playfield
sta COLOR2
lda #0 ;Black backround
sta COLOR4
ldx #0 ;Channel 0
lda #9 ;Requesting PRINT
sta CIO0_OP
lda #<PROGTITLE
sta CIO0_BUFLO
lda #>PROGTITLE
sta CIO0_BUFHI
lda #<[PROGNEND-PROGTITLE]
sta CIO0_LENLO
lda #>[PROGNEND-PROGTITLE]
sta CIO0_LENHI
jsr CIOV ;Call CIO
lda #<LINE1
sta CIO0_BUFLO
lda #>LINE1
sta CIO0_BUFHI
PRLINE lda CIO0_BUFLO
clc
adc #(LINE2-LINE1)
sta CIO0_BUFLO
bcc @+
inc CIO0_BUFHI
@ lda #<[PROGNEND-PROGTITLE]
sta CIO0_LENLO
lda #>[PROGNEND-PROGTITLE]
sta CIO0_LENHI
jsr CIOV
dec LINECNT
bne PRLINE
DINI lda #<BLTOP
sta DOSVEC
lda #>BLTOP
sta DOSVEC+1
rts
LINECNT dta 3
PROGTITLE dta 125 ;Clear screen
LINE1 dta c' ------------------',155
LINE2 dta c' -- Atari Bird --',155
LINE3 dta c' ------------------',155
LINE4 dta c' JK 2017',155
PROGNEND
.IF (*-LDR_START > CASBLOCKS*128)
.ERROR "Exceeded CASBLOCKS"
.ENDIF
.align LDR_START+CASBLOCKS*128,$00 ;fill the rest of last cassette block
dta $FF,$FF ;output binary header
opt h+