aboutsummaryrefslogtreecommitdiff
path: root/fendersdbl.dasm
blob: cb6ea3ffb6488723bd363e4f2562f64acef89e2a (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
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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
; Fenders "3-sector" loader disassembly, 20070526 bkw
; Double-density version

; Note: the double-density loader doesn't actually fit in 3 sectors.
; It uses sectors 1-3 and 720.
; First 3 sectors of a DD disk are still only 128 bytes/sector.

; At boot, the OS boot code loads the first 3 sectors and jumps to
; the loaded code... which then loads sector 720 (a proper 256-byte DD
; sector), which contains the rest of the code.

; I haven't done a very thorough job of reverse-engineering the DD
; version of the loader. Its structure is similar to that of the SD
; loader (fenders.dasm).

 processor 6502

;;; Equates:

;; OS ROM entry points
SIOV        .equ  $e459
COLDSV      .equ  $e477
KEYBDV      .equ  $e420 ; K: handler device table
keyb_get_lo .equ  KEYBDV+4 ; pointer to "get byte" routine, minus 1
keyb_get_hi .equ  KEYBDV+5 ; (used by get_key)

;; OS zero page
BOOTQ       .equ   $09
SAVMSC      .equ   $58
ZROFRE      .equ   $80

;; OS and FMS page 2 RAM variables
COLDST      .equ   $0244
SDMCTL      .equ   $022f
SDLSTL      .equ   $0230
SDLSTH      .equ   $0231
RUNAD       .equ   $02e0
INITAD      .equ   $02e2

;; DCB, used for sector I/O parameters by SIOV (called by read_sector)
DDEVIC      .equ   $0300
DUNIT       .equ   $0301
DCOMND      .equ   $0302
DSTATS      .equ   $0303
DBUFLO      .equ   $0304
DBUFHI      .equ   $0305
DTIMLO      .equ   $0306
DBYTLO      .equ   $0308
DBYTHI      .equ   $0309
DAUX1       .equ   $030a
DAUX2       .equ   $030b

;; Hardware registers
COLPF1      .equ   $d017
VCOUNT      .equ   $d40b

;; Local variables (zero page)
end_address         .equ   $45
save_pos            .equ   $49
menu_counter        .equ   $b0
dir_sector_lo       .equ   $b1
tmp_dlistl          .equ   $b2
tmp_dlisth          .equ   $b3
menu_ptr_lo         .equ   $b4
menu_ptr_hi         .equ   $b5
dest_ptr            .equ   $43
start_sector_lo_tbl .equ   $c0
start_sector_hi_tbl .equ   $e0

;; Local variables (non zero page)
buffer              .equ   $0b10
sector_link_hi      .equ   $0c0d ; buffer + $fd
sector_link_lo      .equ   $0c0e ; buffer + $fe
sector_byte_count   .equ   $0c0f ; buffer + $ff

;;; Bootable disk image starts here:
   .org   $0700

;;; Standard Atari boot disk header (6 bytes)
boot_record:
   .byte $00         ; ignored
   .byte $03         ; number of sectors to read
   .word boot_record ; load address
   .word COLDSV      ; init address, don't think this gets used

;;; Actual code starts here:
boot_continuation:
OFFSET_COLDST_1_DD .equ *-boot_record+1
OFFSET_COLDST_2_DD .equ *-boot_record+5
   LDY   #$00   ; 0 .
   STY   COLDST
   INY
   STY   BOOTQ
   STY   DUNIT
   DEC   DTIMLO
set_dbl_density:
   LDA   #$4e   ; 78 N
   STA   DCOMND
   LDA   #$40   ; 64 @
   STA   DSTATS
   LDA   #$0c   ; 12 .
   STA   DBYTLO
   LDA   #$00   ; 0 .
   STA   DBYTHI
   LDA   #<buffer
   STA   DBUFLO
   LDA   #>buffer
   STA   DBUFHI
   JSR   SIOV
   BMI   set_dbl_density
   LDA   #$04   ; 4 .
   STA   buffer+5
   LDA   #$01   ; 1 .
   STA   buffer+6
   LDA   #$00   ; 0 .
   STA   buffer+7
   LDA   #$4f   ; 79 O
   STA   DCOMND
   LDA   #$80   ; 128 .
   STA   DSTATS
   JSR   SIOV
   BMI   set_dbl_density

; The bootloader code is 640 bytes long. First 384 bytes were loaded
; from the 3 boot sectors already; the rest lives in sector 720, which
; we have to load before running it:
read_sec_720:
   LDA   #$52   ; 82 R
   STA   DCOMND
   LDA   #$40   ; 64 @
   STA   DSTATS
   LDA   #$80   ; 128 .
   STA   DBUFLO
   LDA   #$08   ; 8 .
   STA   DBUFHI
   LDA   #$00   ; 0 .
   STA   DBYTLO
   LDA   #$01   ; 1 .
   STA   DBYTHI
   LDA   #$d0   ; 208 .
   STA   DAUX1
   LDA   #$02   ; 2 .
   STA   DAUX2
   JSR   SIOV
   BMI   read_sec_720

   ; setup display list
   LDA   SDLSTL
   STA   tmp_dlistl
   LDA   SDLSTH
   STA   tmp_dlisth
   LDA   #$00   ; 0 .
   STA   SDMCTL
   LDA   #<display_list   ; 58 :
   STA   SDLSTL
   LDA   #>display_list   ; 9 .
   STA   SDLSTH

   ; init menu
   LDA   #$6c   ; 108 l
   STA   menu_ptr_lo
   LDA   #$09   ; 9 .
   STA   menu_ptr_hi
   LDA   #$69   ; 105 i
   STA   dir_sector_lo

read_dir_sector:
   LDA   dir_sector_lo
   STA   DAUX1
   LDA   #$01   ; 1 .
   STA   DAUX2
   JSR   read_sector
   INC   dir_sector_lo
   DEX

do_dirent:
   LDA   buffer,X
   BEQ   dir_done
   BMI   next_dirent
   AND   #$01   ; 1 .
   BNE   next_dirent
   INC   menu_counter
   LDY   menu_counter
   LDA   buffer+3,X
   STA   start_sector_lo_tbl,Y
   LDA   buffer+4,X
   STA   start_sector_hi_tbl,Y
   TYA
   CLC
   ADC   #$a0   ; 160 .
   LDY   #$03   ; 3 .
   STA   (menu_ptr_lo),Y
   INY
   LDA   #$8e   ; 142 .
   STA   (menu_ptr_lo),Y
   INY
next_char:
   INY
   LDA   buffer+5,X
   INX
   SEC
   SBC   #$20   ; 32  
   STA   (menu_ptr_lo),Y
   CPY   #$10   ; 16 .
   BNE   next_char
   CLC
   LDA   menu_ptr_lo
   ADC   #$14   ; 20 .
   STA   menu_ptr_lo
   BCC   skip_ptr_hi
   INC   menu_ptr_hi
skip_ptr_hi:
   LDA   menu_counter
   CMP   #$14   ; 20 .
   BEQ   dir_done
next_dirent:
   TXA
   AND   #$f0   ; 240 .
   CLC
   ADC   #$10   ; 16 .
   TAX
   ASL
   BCC   do_dirent
   BCS   read_dir_sector
dir_done:
   LDA   #$22   ; 34 "
   STA   SDMCTL
wait_vcount_0:
   LDA   VCOUNT
   BNE   wait_vcount_0
wait_for_input:
   JSR   get_key
   SEC
   SBC   #$40   ; 64 @
   CMP   menu_counter
   BEQ   load_file
   BCS   wait_for_input
load_file:
   TAX
   LDA   start_sector_lo_tbl,X
   STA   DAUX1
   LDA   start_sector_hi_tbl,X
   STA   DAUX2
   LDA   #$68   ; 104 h
   STA   menu_ptr_lo
   LDA   #$09   ; 9 .
   STA   menu_ptr_hi
L0834:
   DEX
   BEQ   print_loading_msg
   CLC
   LDA   menu_ptr_lo
   ADC   #$14   ; 20 .
   STA   menu_ptr_lo
   BCC   L0834
   INC   menu_ptr_hi
   BNE   L0834
print_loading_msg:
   LDY   #$00   ; 0 .
next_msg_byte:
   LDA   loading_msg,Y
   STA   (SAVMSC),Y
   INY
   CPY   #$09   ; 9 .
   BNE   next_msg_byte
print_filename:
   LDA   (menu_ptr_lo),Y
   STA   (SAVMSC),Y
   INY
   CPY   #$15   ; 21 .
   BNE   print_filename
   LDA   #$00   ; 0 .
   STA   SDMCTL
   LDA   tmp_dlistl
   STA   SDLSTL
   LDA   tmp_dlisth
   STA   SDLSTH
   LDA   #$22   ; 34 "
   STA   SDMCTL
wait_vcount_again:
   LDA   VCOUNT
   BNE   wait_vcount_again
   LDY   #$00   ; 0 .
   TYA
clear_zp:
   STA   ZROFRE,Y
   INY
   BPL   clear_zp

; the "JSR try_read" below MUST be located at $087f.
; The JSR opcode is the last byte loaded in the 3-sector boot loader,
; and its operand is the first 2 bytes loaded from sector 720!
 .if *<>$087f
   .echo "Code offsets have changed, fix me (", *, "should be $087f)"
   .err
 .endif
   JSR   try_read ; cut here!

   DEX

read_segment:
   JSR   get_next_byte
   STA   dest_ptr
   JSR   get_next_byte
   STA   dest_ptr+1
   AND   dest_ptr
   CMP   #$ff   ; 255 .
   BEQ   read_segment
   JSR   get_next_byte
   STA   end_address
   JSR   get_next_byte
   STA   end_address+1
load_byte:
   JSR   get_next_byte
   STA   (dest_ptr),Y
   INC   dest_ptr
   BNE   check_seg_done
   INC   dest_ptr+1
   BEQ   check_for_init
check_seg_done:
   LDA   end_address
   CMP   dest_ptr
   LDA   end_address+1
   SBC   dest_ptr+1
   BCS   load_byte
check_for_init:
   LDA   INITAD
   ORA   INITAD+1
   BEQ   read_segment
   STX   save_pos
   JSR   do_init
   LDX   save_pos
   LDY   #$00   ; 0 .
   STY   INITAD
   STY   INITAD+1
   BEQ   read_segment

do_init:
   JMP   (INITAD)

get_next_byte:
   ; self-modifying code changes immediate CPX operand
   CPX   #$fd   ; 253 .
   BNE   return_next_byte
   LDA   DAUX1
   ORA   DAUX2
   BNE   try_read
OFFSET_SCREENOFF_DD .equ *-boot_record
   LDA   SDMCTL
   JMP   (RUNAD)

read_sector:
   LDA   #$31   ; 49 1
   STA   DDEVIC
   LDA   #$52   ; 82 R
   STA   DCOMND
   LDA   #<buffer   ; 16 .
   STA   DBUFLO
   LDA   #>buffer   ; 11 .
   STA   DBUFHI
   LDA   #$00   ; 0 .
   STA   DBYTLO
   LDA   #$01   ; 1 .
   STA   DBYTHI

try_read:
   LDA   #$40   ; 64 @
   STA   DSTATS
   JSR   SIOV
   BMI   try_read
   LDA   sector_link_hi
   AND   #$03   ; 3 .
   STA   DAUX2
   LDA   sector_link_lo
   STA   DAUX1
OFFSET_ROTCOLOR_DD .equ *-boot_record
   LDA   COLPF1
   LDA   sector_byte_count
   STA   get_next_byte+1
   LDY   #$00   ; 0 .
   LDX   #$00   ; 0 .
return_next_byte:
   LDA   buffer,X
   INX
   RTS

get_key:
   LDA   keyb_get_hi
   PHA
   LDA   keyb_get_lo
   PHA
   RTS

loading_msg:
   .byte   $00,$00,$2c,$6f,$61,$64,$69,$6e   ; "..,oadin"
   .byte   $67,$00,$00                       ; "g.."
display_list:
   .byte   $70,$70,$70,$47                   ; "pppG"
   .byte   <screen,>screen
   .byte   $70,$06,$06,$06,$06,$06,$06       ; "p......"
   .byte   $06,$06,$06,$06,$06,$06,$06,$06   ; "........"
   .byte   $06,$06,$06,$06,$06,$06,$41       ; "......A"
   .byte   <display_list,>display_list
OFFSET_TITLE_DD .equ *-boot_record
screen:
   .byte   $00,$00,$00,$00,$61,$74,$61       ; ".....ata"
   .byte   $72,$69,$00,$61,$72,$63,$61,$64   ; "ri.arcad"
   .byte   $65,$00,$00,$00,$00,$00,$00,$00   ; "e......."
   .byte   $00,$00,$00,$00,$00,$00,$00,$00   ; "........"
   .byte   $00,$00,$00,$00,$00,$00,$00,$00   ; "........"
   .byte   $00                               ; "."