-
Notifications
You must be signed in to change notification settings - Fork 1
/
prodos.a
737 lines (656 loc) · 27.8 KB
/
prodos.a
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
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
phaseoff = $c080 ;stepper phase off.
unitnum = $43
drvindx pha ;preserve acc.
lda unitnum ; for example : 0 (drive 1) 110 (slot 6) 0000
lsr
lsr
lsr
lsr
cmp #$8
and #$7 ; drive-slot -> slot-drives
rol
tax ;into x for index to table
pla ;restore acc.
rts
; ====================================================================
myseek asl ;assume two phase stepper.
sta track ;save destination track(*2)
jsr alloff ;turn all phases off to be sure.
jsr drvindx ;get index to previous track for current drive
lda drv0trk,x
sta curtrk ;this is where i am
lda track ;and where i'm going to
sta drv0trk,x
jsr seek ;go there!
alloff ldy #3 ;turn off all phases before returning
nxoff tya ;(send phase in acc.)
jsr clrphase ;carry is clear, phases shold be turned off
dey
bpl nxoff
lsr curtrk ;divide back down
clc
rts ;all off... now it's dark
; **************************
; * *
; * fast seek subroutine *
; **************************
; * *
; * on entry ---- *
; * *
; * x-reg holds slotnum *
; * times $10. *
; * *
; * a-reg holds desired *
; * halftrack. *
; * (single phase) *
; * *
; * curtrk holds current *
; * halftrack. *
; * *
; * on exit ----- *
; * *
; * a-reg uncertain. *
; * y-reg uncertain. *
; * x-reg undisturbed. *
; * *
; * curtrk and trkn hold *
; * final halftrack. *
; * *
; * prior holds prior *
; * halftrack if seek *
; * was required. *
; * *
; * montimel and montimeh *
; * are incremented by *
; * the number of *
; * 100 usec quantums *
; * required by seek *
; * for motor on time *
; * overlap. *
; * *
; * --- variables used --- *
; * *
; * curtrk, trkn, count, *
; * prior, slottemp *
; * montimel, montimeh *
; * *
; **************************
ibtrk !byte $00
ibsect !byte $00
ibstat !byte $00
iobpdn !byte $00
curtrk !byte $00
drv0trk = *-2
!byte 0,0,0,0,0,0,0 ;for slots 1 thru 7
!byte 0,0,0,0,0,0,0 ;drives 1 & 2
retrycnt !fill 1,0
seekcnt !fill 1,0
; *
; ************************
; * *
; * readadr---- *
; * *
; ************************
count = * ;'must find' count.
last !fill 1,0 ;'odd bit' nibls.
csum !fill 1,0 ;used for address header cksum
csstv !fill 4,0 ;four bytes,
; * checksum, sector, track, and volume.
sect = csstv+1
track = csstv+2
volume = csstv+3
; *
trkcnt = count ;halftrks moved count.
prior !fill 1,0
trkn !fill 1,0
; **************************
; * *
; * phase on-, off-time *
; * tables in 100-usec *
; * intervals. (seek) *
; * *
; **************************
ontable !byte 1,$30,$28
!byte $24,$20,$1e
!byte $1d,$1c,$1c
offtable !byte $70,$2c,$26
!byte $22,$1f,$1e
!byte $1d,$1c,$1c
seek sta trkn ;save target track
cmp curtrk ;on desired track?
beq setphase ;yes,energize phase and return
lda #$0
sta trkcnt ;halftrack count.
seek2 lda curtrk ;save curtrk for
sta prior ;delayed turnoff.
sec
sbc trkn ;delta-tracks.
beq seekend ;br if curtrk=destination
bcs out ;(move out, not in)
eor #$ff ;calc trks to go.
inc curtrk ;incr current track (in).
bcc mintst ;(always taken)
out adc #$fe ;calc trks to go.
dec curtrk ;decr current track (out).
mintst cmp trkcnt
bcc maxtst ; and 'trks moved'.
lda trkcnt
maxtst cmp #$9
bcs step2 ;if trkcnt>$8 leave y alone (y=$8).
tay ;else set acceleration index in y
sec
step2 jsr setphase
lda ontable,y ;for 'ontime'.
jsr mswait ;(100 usec intervals)
lda prior
clc ;for phaseoff
jsr clrphase ;turn off prior phase
lda offtable,y ; then wait 'offtime'.
jsr mswait ;(100 usec intervals)
inc trkcnt ; 'tracks moved' count.
bne seek2 ;(always taken)
seekend jsr mswait ;settle 25 msec
clc ;set for phase off
setphase lda curtrk ;get current track
clrphase and #3 ;mask for 1 of 4 phases
rol ;double for phaseon/off index
ora slotz
tax
lda phaseoff,x ;turn on/off one phase
ldx slotz ;restore x-reg
rts ;and return
; *
; **************************
; * *
; * mswait subroutine *
; * *
; **************************
; * *
; * delays a specified *
; * number of 100 usec *
; * intervals for motor *
; * on timing. *
; * *
; * on entry ---- *
; * *
; * a-reg: holds number *
; * of 100 usec *
; * intervals to *
; * delay. *
; * *
; * on exit ----- *
; * *
; * a-reg: holds $00. *
; * x-reg: holds $00. *
; * y-reg: unchanged. *
; * carry: set. *
; * *
; * montimel, montimeh *
; * are incremented once *
; * per 100 usec interval*
; * for moton on timing. *
; * *
; * assumes ---- *
; * *
; * 1 usec cycle time *
; * *
; **************************
montimel = csstv+2 ;motor-on time
montimeh = montimel+1 ;counters.
mswait ldx #$11
msw1 dex ;delay ; 86 usec.
bne msw1
inc montimel
bne msw2 ;double-byte
inc montimeh ;increment.
msw2 sec ;s
sbc #$1 ;done 'n' intervals?
bne mswait ;(a-reg counts)
rts
!align 255, 0
; ****************************
; * *
; * read address field *
; * subroutine *
; * (16-sector format) *
; * *
; ****************************
; * *
; * reads volume, track *
; * and sector *
; * *
; * on entry ---- *
; * *
; * xreg: slotnum times $10 *
; * *
; * read mode (q6l, q7l) *
; * *
; * on exit ----- *
; * *
; * carry set if error. *
; * *
; * if no error: *
; * a-reg holds $aa. *
; * y-reg holds $00. *
; * x-reg unchanged. *
; * carry clear. *
; * *
; * csstv holds chksum, *
; * sector, track, and *
; * volume read. *
; * *
; * uses temps count, *
; * last, csum, and *
; * 4 bytes at csstv. *
; * *
; * expects ---- *
; * *
; * original 10-sector *
; * normal density nibls *
; * (4-bit), odd bits, *
; * then even. *
; * *
; * caution ---- *
; * *
; * observe *
; * 'no page cross' *
; * warnings on *
; * some branches!! *
; * *
; * assumes ---- *
; * *
; * 1 usec cycle time *
; * *
; ****************************
q6l = $c08c
;; Read here https://www.bigmessowires.com/2015/08/27/apple-ii-copy-protection/
;; Every three bytes read, there's an additional one for disk encoding reason
;; So if I read 768 times, that's 768 nibbles => 576 bytes => this can read up to two consecutive sectors I guess
; d = count - $FC gives number of wait loops before finding signature $D5 $AA $96
; if d == 0; then less than $FF - $FC (4) loops
; if d == 1 : between 4 and 256+4 loops
; A sector takes 12500 usec, a frame is 100000 usec => I should be able to read 8 sectors in one frame
rdadr16 ldy #$fc ; will count -4,-3,-2,-1,0 (three times) then three (count) times 256 => 768+3 = 771 counts
sty count ;'must find' count.
lda sect
sta old_sect
rdasyn iny
bne rda1 ;low order of count.
inc count ;(2k nibls to find
beq rderr ; adr mark, else err)
rda1 lda q6l,x ;read nibl.
bpl rda1 ;*** no page cross! ***
rdasn1 cmp #$d5 ;adr mark 1?
bne rdasyn ;(loop if not)
nop ;added nibl delay.
rda2 lda q6l,x
bpl rda2 ;*** no page cross! ***
cmp #$aa ;adr mark 2?
bne rdasn1 ; (if not, is it am1?)
ldy #$3 ;index for 4-byte read. WIZ!!! checksum, sector, track, and volume.
; * (added nibl delay)
rda3 lda q6l,x
bpl rda3 ;*** no page cross! ***
cmp #$96 ;adr mark 3?
bne rdasn1 ; (if not, is it am1?)
;sty count2 ; WIZ !!!
;ldy #$3 ;index for 4-byte read. WIZ!!!
sei ;no interupts until address is tested.(carry is set)
lda #$0 ;init checksum.
rdafld sta csum
rda4 lda q6l,x ;read 'odd bit' nibl.
bpl rda4 ;*** no page cross! ***
rol ;align odd bits, '1' into lsb.
sta last ; (save them)
rda5 lda q6l,x ;read 'even bit' nibl.
bpl rda5 ;*** no page cross! ***
and last ;merge odd and even bits.
sta csstv,y ;store data byte.
eor csum
dey
bpl rdafld ;loop on 4 data bytes.
tay ;if final checksum
bne rderr ;nonzero, then error.
rda6 lda q6l,x ;first bit-slip nibl.
bpl rda6 ;*** no page cross! ***
cmp #$de
bne rderr ;error if nonmatch.
nop ;delay
rda7 lda q6l,x ;second bit-slip nibl.
bpl rda7 ;*** no page cross! ***
cmp #$aa
beq rdgood ;error if nonmatch.
rderr sec
rts
rdgood:
lda old_sect
cmp sect ; compare A (old_sect) to sect | 0 to 9
beq rdsuccess
bmi .ok ; old_sect (A) < sect
lda sect ; old_sect > sect
clc
adc #SECTORS_PER_TRACK
sec
sbc old_sect ; A = sect - old_sect
clc
adc sectors_passed
sta sectors_passed
clc
rts
.ok:
lda sect
sec
sbc old_sect ; A = sect - old_sect
clc
adc sectors_passed
sta sectors_passed
rdsuccess:
clc ;clear carry on
rts ; normal read exits.
!align 255, 0
; **************************
; * *
; * read subroutine *
; * (16-sector format) *
; * *
; **************************
; * *
; * reads encoded bytes *
; * into nbuf1 and nbuf2 *
; * *
; * first reads nbuf2 *
; * high to low, *
; * then reads nbuf1 *
; * low to high. *
; * *
; * on entry ---- *
; * *
; * x-reg: slotnum *
; * times $10. *
; * *
; * read mode (q6l, q7l) *
; * *
; * on exit ----- *
; * *
; * carry set if error. *
; * *
; * if no error: *
; * a-reg holds $aa. *
; * x-reg unchanged. *
; * y-reg holds $00. *
; * carry clear. *
; * caution ----- *
; * *
; * observe *
; * 'no page cross' *
; * warnings on *
; * some branches!! *
; * *
; * assumes ---- *
; * *
; * 1 usec cycle time *
; * *
; **************************
dnibl = *-$96
!byte $00,$04
!byte $ff,$ff,$08,$0c
!byte $ff,$10,$14,$18
twobit3 !byte $00,$80,$40,$c0 ;used in fast prenib as lookup for 2-
; bit quantities.
!byte $ff,$ff,$1c,$20
!byte $ff,$ff,$ff,$24
!byte $28,$2c,$30,$34
!byte $ff,$ff,$38,$3c
!byte $40,$44,$48,$4c
!byte $ff,$50,$54,$58
!byte $5c,$60,$64,$68
twobit2 !byte $00,$20,$10,$30 ;used in fast prenib.
endmrks !byte $de,$aa,$eb,$ff ;table using 'unused' nibls
; ($c4,$c5,$c6,$c7)
!byte $ff,$ff,$ff,$6c
!byte $ff,$70,$74,$78
!byte $ff,$ff,$ff,$7c
!byte $ff,$ff,$80,$84
!byte $ff,$88,$8c,$90
!byte $94,$98,$9c,$a0
twobit1 !byte $00,$08,$04,$0c ;used in fast prenib.
!byte $ff,$a4,$a8,$ac
!byte $ff,$b0,$b4,$b8
!byte $bc,$c0,$c4,$c8
!byte $ff,$ff,$cc,$d0
!byte $d4,$d8,$dc,$e0
!byte $ff,$e4,$e8,$ec
!byte $f0,$f4,$f8,$fc
dnibl2 !byte 0
dnibl3 !byte 0
dnibl4 !byte 0
nibl !byte $96,2,0,0,$97
!byte 1,0,0,$9a,3,0,0,$9b
!byte 0,2,0,$9d,2,2,0,$9e
!byte 1,2,0,$9f,3,2,0,$a6
!byte 0,1,0,$a7,2,1,0,$ab
!byte 1,1,0,$ac,3,1,0,$ad
!byte 0,3,0,$ae,2,3,0,$af
!byte 1,3,0,$b2,3,3,0,$b3
!byte 0,0,2,$b4,2,0,2,$b5
!byte 1,0,2,$b6,3,0,2,$b7
!byte 0,2,2,$b9,2,2,2,$ba
!byte 1,2,2,$bb,3,2,2,$bc
!byte 0,1,2,$bd,2,1,2,$be
!byte 1,1,2,$bf,3,1,2,$cb
!byte 0,3,2,$cd,2,3,2,$ce
!byte 1,3,2,$cf,3,3,2,$d3
!byte 0,0,1,$d6,2,0,1,$d7
!byte 1,0,1,$d9,3,0,1,$da
!byte 0,2,1,$db,2,2,1,$dc
!byte 1,2,1,$dd,3,2,1,$de
!byte 0,1,1,$df,2,1,1,$e5
!byte 1,1,1,$e6,3,1,1,$e7
!byte 0,3,1,$e9,2,3,1,$ea
!byte 1,3,1,$eb,3,3,1,$ec
!byte 0,0,3,$ed,2,0,3,$ee
!byte 1,0,3,$ef,3,0,3,$f2
!byte 0,2,3,$f3,2,2,3,$f4
!byte 1,2,3,$f5,3,2,3,$f6
!byte 0,1,3,$f7,2,1,3,$f9
!byte 1,1,3,$fa,3,1,3,$fb
!byte 0,3,3,$fc,2,3,3,$fd
!byte 1,3,3,$fe,3,3,3,$ff
; *
nbuf2 !fill $56,0 ;nibl buffer for read/write of low 2-
!align 255, 0
read16 txa ;get slot #.
ora #$8c ;prepare mods to read routine.
sta rd4+1 ;warning: the read routine is self modified!!!
sta rd5+1
sta rd6+1
sta rd7+1
sta rd8+1
lda buf ;modify storage addresses also.
ldy buf+1
sta ref3+1
sty ref3+2
sec
sbc #$54
bcs rd16b ;branch if no borrow.
dey
rd16b sta ref2+1
sty ref2+2
sec
sbc #$57
bcs rd16c ;branch if no borrow.
dey
rd16c sta ref1+1
sty ref1+2
ldy #$20 ;'must find count'
rsync dey
beq rderr2 ;branch if can't find data header
; marks.
rd1 lda q6l,x
bpl rd1
rsync1 eor #$d5 ;first data mark.
bne rsync
nop ;waste a little time...
rd2 lda q6l,x
bpl rd2
cmp #$aa ;data mark 2
bne rsync1 ;if not, check for first again.
nop
rd3 lda q6l,x
bpl rd3
cmp #$ad ;data mark 3
bne rsync1 ;if not, check for data mark 1 again.
ldy #$aa
lda #0
rdata1 sta wtemp ;use zpage for checksum keeping.
rd4 ldx $c0ec ;warning: self modified.
bpl rd4
lda dnibl,x
sta nbuf2-$aa,y ;save the two-bit groups in nbuf.
eor wtemp ;update checksum.
iny ;bump to next nbuf position.
bne rdata1 ;loop for all $56 two-bit groups.
ldy #$aa ;now read directly into user buffer.
bne rd5 ;branch always taken!!!
; *
rderr2 sec
rts
; *
ref1 sta $1000,y ;warning: self modified!
; *
rd5 ldx $c0ec
bpl rd5
eor dnibl,x ;get actual 6-bit data from dnib table.
ldx nbuf2-$aa,y ;get associated two-bit pattern.
eor dnibl2,x ;and combine to form whole byte.
iny
bne ref1 ;loop for $56 bytes.
pha ;save this byte for now, no time to
; store...
and #$fc ;strip low bits...
ldy #$aa ;prepare for next $56 bytes.
rd6 ldx $c0ec
bpl rd6
eor dnibl,x
ldx nbuf2-$aa,y
eor dnibl3,x
ref2 sta $1000,y ;warning: self modified.
iny
bne rd6 ;loop until this group of $56 read in.
; *
rd7 ldx $c0ec
bpl rd7
and #$fc
ldy #$ac ;last group is $54 long.
rdata2 eor dnibl,x
ldx nbuf2-$ac,y
eor dnibl4,x ;combine to form full byte.
ref3 sta $1000,y
rd8 ldx $c0ec ;warning: self modified.
bpl rd8
iny
bne rdata2
and #$fc
eor dnibl,x ;check sum ok?
bne rderr1 ;branch if not.
ldx slotz ;test end marks.
rd9 lda q6l,x
bpl rd9
cmp #$de
clc
beq rdok ;branch if good trailer...
rderr1 sec
rdok pla ;place last byte into user buffer.
ldy #$55
sta (buf),y
rts
sector_zero:
!zone {
STA slotz
ldx slotz
LDA MOTOR_ON, x
LDA #$FF
JSR mswait
;; On which track are we right now ?
ldx slotz
.retry_locate:
jsr rdadr16
bcs .retry_locate
;; Inform 'seek' of the current sector
lda track ; set by rdadr16
asl
sta curtrk ; half track
ldx slotz
lda #0
asl
jsr seek
LDA #$FF
JSR mswait
rts
}
; ----------------------------------------------------------------------------
advance_drive_latch:
LDA curtrk
CMP #((TRACKS_PER_SIDE-1)*2) ; Are we on the last track
BEQ .disk_end ; yes, don't go any further
CLC
ADC #2 ; A = desired halftrack; curtrk = current track
ldx #SLOT_SELECT
JSR seek
.disk_end:
CLC
RTS
rs_sectors_to_read !byte 104
target_track !byte 28
target_sector !byte 0
target_bank !byte $40
read_sect:
LDA #SLOT_SELECT
STA slotz
ldx #SLOT_SELECT
LDA MOTOR_ON, X
LDA #$FF
JSR mswait
;; On which track are we right now ?
ldx #SLOT_SELECT
.retry_locate:
jsr rdadr16
bcs .retry_locate
;; Inform 'seek' of the current sector
lda track ; set by rdadr16
asl
sta curtrk ; half track
ldx #SLOT_SELECT
lda target_track
asl
jsr seek
LDA #$FF
JSR mswait
;; Find the sector on the track
read_sect1:
ldx #SLOT_SELECT
jsr rdadr16
bcs read_sect1
lda sect ;set by rdadr16
cmp target_sector
bne read_sect1
lda #0
sta buf
lda target_bank
sta buf + 1
ldx #SLOT_SELECT
jsr read16
bcs early_out
inc target_bank
inc target_sector
lda target_sector
cmp #SECTORS_PER_TRACK
bne no_next_track
jsr advance_drive_latch
lda #0
sta target_sector
no_next_track:
dec rs_sectors_to_read
bne read_sect1
early_out:
rts