mirror of
https://github.com/deater/dos33fsprogs.git
synced 2024-09-26 05:54:45 +00:00
e7f1907f38
using PRORWTS seek now also fixed subtle bug in qboot when loading partial tracks also a bunch of movement in the demo stuff by accident, oops but it's 2am and I'm too lazy to back that out
633 lines
11 KiB
ArmAsm
633 lines
11 KiB
ArmAsm
; the following lives on sectors $0E and $0D
|
|
; why?
|
|
; request sector 2 and 4, and the interleave is
|
|
|
|
; beneath apple dos (3-23)
|
|
; Physical (firmware) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
|
; DOS33 mapping : 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15
|
|
|
|
|
|
; Beneath Apple DOS
|
|
; p86 (dos reference)
|
|
;
|
|
|
|
;WAIT = $FCA8 ;; delay 1/2(26+27A+5A^2) us
|
|
|
|
.org $900
|
|
|
|
code_begin:
|
|
|
|
.byte version
|
|
|
|
readnib:
|
|
slotpatch1: ; smc
|
|
lda $c0d1 ; gets set to C08C (Q6L) read
|
|
bpl readnib
|
|
rts
|
|
|
|
;===============================
|
|
;===============================
|
|
;===============================
|
|
; seek then read
|
|
;===============================
|
|
;===============================
|
|
;===============================
|
|
; Y = starting sector
|
|
; A = page to read into
|
|
; X = number of sectors to read
|
|
|
|
;fill address array for one track
|
|
seekread:
|
|
sty startsec+1
|
|
sta tmpadr_smc+1
|
|
stx total+1
|
|
|
|
inittrk:
|
|
sec
|
|
lda #$10
|
|
sbc startsec+1
|
|
cmp total+1
|
|
bcs it_skip
|
|
|
|
tax
|
|
|
|
it_skip:
|
|
stx partial1
|
|
stx partial2
|
|
jsr seek
|
|
|
|
startsec:
|
|
ldy #$d1
|
|
|
|
;===========================================
|
|
; fill in table of addresses we want to read
|
|
; corresponding to sectors on the track
|
|
; if they are 0, it means we don't need it
|
|
|
|
tmpadr_loop:
|
|
|
|
tmpadr_smc:
|
|
lda #$d1
|
|
sta addrtbl, y
|
|
inc tmpadr_smc+1
|
|
iny
|
|
dec partial1
|
|
bne tmpadr_loop
|
|
|
|
;====================================
|
|
; read a sector
|
|
;====================================
|
|
; first address field
|
|
;====================================
|
|
; starts with $D5 $AA $96
|
|
; then XX YY volume
|
|
; then XX YY track
|
|
; then XX YY sector
|
|
; then XX YY checksum
|
|
; then ends with $DE $AA $EB
|
|
;====================================
|
|
; data field
|
|
;====================================
|
|
; starts with $D5 $AA $AD
|
|
; 342 bytes of data
|
|
; XX checksum
|
|
; ends with $DE $AA $EB
|
|
read:
|
|
|
|
ldx #0 ; if we don't set this, bad things can happen
|
|
; if we start on a data field w/o setting
|
|
; the sector first
|
|
outer_read:
|
|
jsr readnib
|
|
inner_read:
|
|
cmp #$d5 ; look for $D5 part of addr field
|
|
bne outer_read
|
|
|
|
jsr readnib ; look for $D5 $AA
|
|
cmp #$aa
|
|
bne inner_read
|
|
|
|
; look for $D5 $AA $AD
|
|
|
|
tay ; we need Y=#$AA later
|
|
jsr readnib
|
|
eor #$ad ; zero A if match
|
|
beq check_mode ; WHY?
|
|
|
|
; if not #$AD, then #$96 is assumed
|
|
; so in address field
|
|
|
|
; following are volume, track, sector
|
|
|
|
ldy #2 ; volume, track, sector
|
|
another:
|
|
|
|
; these are stored in a weird 4+4 format and this is how
|
|
; you decode them
|
|
|
|
jsr readnib
|
|
rol
|
|
sta sector_smc+1
|
|
jsr readnib
|
|
and sector_smc+1 ; now A has the value
|
|
|
|
dey ; work through the values
|
|
bpl another
|
|
|
|
tay ; A should be sector#?
|
|
; Y is now sector # VMW
|
|
ldx addrtbl, Y ; fetch corresponding address
|
|
; in table.
|
|
|
|
beq outer_read ; if address 0, not valid, try again
|
|
|
|
sta sector_smc+1 ; store sector for later
|
|
|
|
stx adrpatch1+2 ; store address to all of these
|
|
stx adrpatch8+2
|
|
stx adrpatch2+2
|
|
stx adrpatch3+2
|
|
stx adrpatch5+2
|
|
stx adrpatch7+2
|
|
|
|
inx
|
|
stx adrpatch9+2 ; store address+1 here
|
|
dex
|
|
|
|
dex
|
|
stx adrpatch4+2 ; store address-1 here?
|
|
stx adrpatch6+2
|
|
|
|
ldy #$fe ; Y=-2
|
|
|
|
loop2:
|
|
adrpatch1:
|
|
lda $d102, Y
|
|
pha
|
|
iny
|
|
bne loop2
|
|
|
|
branch_read:
|
|
bcs outer_read ; branch always
|
|
|
|
check_mode:
|
|
cpx #0
|
|
beq outer_read ; loop if not expecting #$AD
|
|
|
|
loop33:
|
|
sta tmpval_smc+1 ; zero rolling checksum
|
|
slotpatch2:
|
|
loop4:
|
|
ldx $c0d1
|
|
bpl loop4
|
|
lda preshift-$96, X
|
|
adrpatch2:
|
|
sta $d102, Y ; store 2-bit array
|
|
|
|
tmpval_smc:
|
|
eor #$d1
|
|
iny
|
|
bne loop33
|
|
ldy #$aa
|
|
slotpatch3:
|
|
loop5:
|
|
ldx $c0d1
|
|
bpl loop5
|
|
eor preshift-$96, X
|
|
adrpatch3:
|
|
ldx $d102, Y ; bit2tbl
|
|
eor grouped+2, X ; first 86 nibbles use group bits 0-1
|
|
adrpatch4:
|
|
sta $d156, y
|
|
iny
|
|
bne loop5
|
|
and #$fc
|
|
ldy #$aa
|
|
slotpatch4:
|
|
loop6:
|
|
ldx $c0d1
|
|
bpl loop6
|
|
eor preshift-$96, X
|
|
adrpatch5:
|
|
ldx $d102, Y ; bit2tbl
|
|
eor grouped+1, X ; second 86 nibbles use group bits 2-3
|
|
adrpatch6:
|
|
sta $d1ac, Y
|
|
iny
|
|
bne loop6
|
|
and #$fc
|
|
ldx #$ac
|
|
slotpatch5:
|
|
loop7:
|
|
ldy $c0d1
|
|
bpl loop7
|
|
eor preshift-$96, Y
|
|
adrpatch7:
|
|
ldy $d100, X ; bit2tbl
|
|
eor grouped, Y ; last 84 nibbles use group bits 4-5
|
|
adrpatch8:
|
|
sta $d100, x
|
|
inx
|
|
bne loop7
|
|
and #$fc
|
|
slotpatch6:
|
|
loop8:
|
|
ldy $c0d1
|
|
bpl loop8
|
|
eor preshift-$96, Y
|
|
cmp #1 ; carry = !zero
|
|
ldy #1
|
|
loop9:
|
|
pla
|
|
adrpatch9:
|
|
sta $d100, Y
|
|
dey
|
|
bpl loop9
|
|
branch_read2:
|
|
bcs branch_read ; branch if checksum failure
|
|
|
|
sector_smc:
|
|
ldy #$d1
|
|
txa
|
|
sta addrtbl, Y ; zero corresponding address
|
|
dec total+1
|
|
dec partial2 ; adjust remaining count
|
|
; (faster than looping over array)
|
|
sec
|
|
bne branch_read2 ; read all requested sectors in one track
|
|
|
|
sta startsec+1 ; this was missing from original code
|
|
; leading to trouble on wrap around
|
|
; it not starting at sector0
|
|
total:
|
|
ldx #$d1
|
|
beq driveoff
|
|
inc phase_smc+1
|
|
inc phase_smc+1 ; update current track
|
|
jmp inittrk
|
|
|
|
driveoff:
|
|
slotpatch7:
|
|
lda $c0d1
|
|
|
|
rts
|
|
|
|
|
|
;=================================
|
|
;=================================
|
|
; seek, SEEK!
|
|
;=================================
|
|
;=================================
|
|
; phase_smc+1 = track*2 to seek to
|
|
; curtrk+1 = current track
|
|
|
|
|
|
; due to problems when switching drive1/drive
|
|
; we include here instead the larger but less fancy
|
|
; seek from PRORWTS
|
|
|
|
; "no tricks here, just the regular stuff" -- qkumba
|
|
|
|
step = $CC ;(internal) state for stepper motor
|
|
;tmptrk = $CD ;(internal) temporary copy of current track
|
|
;phase = $CE ;(internal) current phase for seek
|
|
;tmpsec = $3c
|
|
|
|
; X = destination track
|
|
; Y = 0
|
|
|
|
;cu;rtrk_smc:
|
|
; lda #0
|
|
|
|
seek:
|
|
|
|
;p;hase_smc:
|
|
; lda #0
|
|
; sta phase
|
|
|
|
curtrk_smc:
|
|
lda #0
|
|
|
|
ldy #0 ; added
|
|
sty step
|
|
; asl phase
|
|
|
|
; txa ; get destination in A
|
|
; asl ; multiply to get half track
|
|
copy_cur:
|
|
tax ; current track
|
|
sta tmpval_smc+1 ;tmptrk ; save current track for later
|
|
|
|
; calculate direction to seek
|
|
|
|
sec
|
|
phase_smc:
|
|
sbc #$d1 ; track *2 to seek to?
|
|
beq done_seek ; if match, we're there
|
|
|
|
; update direction
|
|
|
|
bcs seeking_out ; if positive, seeking out toward T34
|
|
|
|
seeking_in:
|
|
eor #$ff ; negate the result?
|
|
inx ; move current track inward
|
|
bcc seek_dir_done
|
|
|
|
seeking_out:
|
|
sbc #1 ; difference -1 (carry is set here)
|
|
dex ; move current track outward
|
|
|
|
seek_dir_done:
|
|
cmp step ; compare to step
|
|
bcc skip_set_step ; if below minimum, don't change?
|
|
|
|
lda step ; load step value
|
|
|
|
skip_set_step:
|
|
|
|
; set acceleration/momentum
|
|
|
|
cmp #8 ; see if > 8
|
|
; our momentum table is 8
|
|
; (DOS3.3 it's 12)
|
|
; Y maxes out if over 8
|
|
|
|
bcs skip_update_momentum
|
|
tay ; acceleration offset in Y
|
|
sec ; carry set is phase on
|
|
skip_update_momentum:
|
|
|
|
txa ; current track in A
|
|
pha ; save for later
|
|
ldx phase_on_time, Y ; load on time from table
|
|
|
|
done_seek: ; +++
|
|
php ; save flags(?)
|
|
bne skip_p ; bra?
|
|
loop_mmm:
|
|
clc ; set phase off
|
|
lda tmpval_smc+1 ;tmptrk ; restore saved track
|
|
ldx phase_off_time, Y ; get off time from table
|
|
skip_p:
|
|
stx sector_smc+1 ;tmpsec ; why
|
|
and #3 ; mask to 1 of 3 phases
|
|
rol ; multiply by 2, set low bit to carry
|
|
; carry holds on/off
|
|
tax
|
|
lsr ; get low bit in carry for later
|
|
; but must do before A destroyed
|
|
;unrseek=unrelocdsk+(*-reloc)
|
|
|
|
slotpatch8:
|
|
lda $C0D1, X
|
|
|
|
seek_delay:
|
|
|
|
; delay 2+(19*5)-1 = 97 cycles, + 6+2 = 105 cycles = ~100us
|
|
|
|
seek_delay_outer:
|
|
ldx #$13 ; 2
|
|
seek_delay_inner:
|
|
dex ; 2
|
|
bne seek_delay_inner ; 2/3
|
|
|
|
dec sector_smc+1 ;tmpsec ; 6 holds on/off delay time
|
|
bne seek_delay_outer ; 2/3
|
|
seek_delay_end:
|
|
|
|
; C is from the LSR previously? so phase bit
|
|
|
|
bcs loop_mmm ; if carry set, try again phase off
|
|
plp ; restore?
|
|
|
|
beq seekret ; if zero we were done
|
|
|
|
pla ; restore current track
|
|
inc step ; increment step count
|
|
bne copy_cur ; (bra) try again
|
|
|
|
seekret:
|
|
; update current track
|
|
ldx phase_smc+1
|
|
stx curtrk_smc+1
|
|
; the DOS3.3 RWTS waits 25ms after seeking for things to settle
|
|
|
|
rts
|
|
|
|
|
|
;curtrk_smc: ; FIXME
|
|
; lda #0
|
|
|
|
|
|
.if 0
|
|
seek:
|
|
ldx #0 ; reset acceleration count?
|
|
stx step_smc+1
|
|
|
|
copy_cur:
|
|
|
|
curtrk_smc:
|
|
lda #0 ; current track
|
|
sta tmpval_smc+1 ; save current track for later
|
|
|
|
; calculate direction to seek
|
|
|
|
sec
|
|
phase_smc:
|
|
sbc #$d1 ; track*2 to seek to
|
|
beq seekret ; if equal, we are already there
|
|
; so we are done
|
|
|
|
; A is distance, update direction
|
|
|
|
bcs seeking_out ; if positive, seeking out to 34
|
|
|
|
seeking_in:
|
|
eor #$ff ; negate the result? (why?)
|
|
inc curtrk_smc+1 ; move track counter inward
|
|
bcc ssback ; bra
|
|
|
|
seeking_out:
|
|
adc #$fe ; difference -=1 (carry always 1)
|
|
dec curtrk_smc+1 ; move track counter outward
|
|
|
|
ssback:
|
|
cmp step_smc+1 ; compare to step
|
|
bcc skip_set_step ; if below minimum, don't change?
|
|
|
|
;================================
|
|
; step the proper length of time
|
|
; taking into account momentum?
|
|
|
|
step_smc:
|
|
lda #$d1 ; load step value
|
|
|
|
skip_set_step:
|
|
|
|
; set acceleration (???)
|
|
|
|
cmp #8 ; see if >8
|
|
; our on/off
|
|
; tables only 8 bytes long
|
|
; (dos33 they are 12?)
|
|
|
|
; what is Y in that case?
|
|
; apparently in maxes out
|
|
|
|
bcs skip11
|
|
|
|
tay ; acceleration offset in Y
|
|
|
|
do_phase_on:
|
|
sec ; carry set is phase on
|
|
|
|
skip11:
|
|
lda curtrk_smc+1 ; current track in A
|
|
ldx phase_on_time, Y ; get phase on time in X
|
|
bne do_phase_common ; (bra?)
|
|
|
|
do_phase_off:
|
|
clc ; carry set, phase off
|
|
lda tmpval_smc+1 ; restore original track
|
|
ldx phase_off_time, Y ; get phase off time in X
|
|
|
|
do_phase_common:
|
|
stx sector_smc+1
|
|
; A is the track?
|
|
and #3 ; mask to 1 of 4 phases
|
|
rol ; double to the 8 phase on/off
|
|
; with carry the on/off
|
|
tax
|
|
slotpatch8:
|
|
sta $c0d1, X ; flip the phase
|
|
; C080...C087 seeks inward (toward 34)
|
|
; C087...C080 seeks outward (to 0)
|
|
|
|
|
|
seek_delay:
|
|
|
|
seek_delay_outer:
|
|
|
|
; inner delay
|
|
; delay 2+(19*5)-1 = 97 cycles, + 6+2 = 105 cycles = ~100us
|
|
|
|
ldx #$13 ; 2
|
|
seek_delay_inner:
|
|
dex ; 2
|
|
bne seek_delay_inner ; 2/3
|
|
|
|
|
|
dec sector_smc+1 ; 6 holds the on/off delay time
|
|
bne seek_delay_outer ; 2/3
|
|
|
|
seek_delay_end:
|
|
|
|
lsr ; bottom bit of A here
|
|
; is the carry bit
|
|
; from phase on/off
|
|
|
|
bcs do_phase_off ; repeat, this time off
|
|
|
|
inc step_smc+1 ; increment step count
|
|
bne copy_cur ; bra(?) back to beginning
|
|
|
|
.endif
|
|
|
|
; phase on/off tables, in 100us multiples
|
|
|
|
phase_on_time: .byte $01, $30, $28, $24, $20, $1e, $1d, $1c
|
|
phase_off_time: .byte $70, $2c, $26, $22, $1f, $1e, $1d, $1c
|
|
|
|
|
|
addrtbl: .res 16
|
|
|
|
partial1: .byte $00
|
|
partial2: .byte $00
|
|
|
|
|
|
;==========================
|
|
; enable drive motor
|
|
;==========================
|
|
|
|
driveon:
|
|
|
|
slotpatch9:
|
|
lda $c0d1 ; turn drive on first
|
|
; then you select drive
|
|
|
|
|
|
driveon_disk1:
|
|
|
|
slotpatch10:
|
|
lda $C0d1 ; drive 1 select
|
|
; jmp done_drive_select
|
|
|
|
|
|
; this could be more compact
|
|
|
|
lda CURRENT_DRIVE
|
|
cmp #2
|
|
bne done_drive_select
|
|
|
|
|
|
driveon_disk2:
|
|
|
|
slotpatch11:
|
|
lda $C0d1 ; drive 2 select
|
|
|
|
done_drive_select:
|
|
|
|
|
|
; wait 1s
|
|
|
|
; WAIT takes 1/2(26+27A+5A^2) us
|
|
; so for A=255 = (26+6885 +325125)*1/2 = 166018s *6 = ~1s
|
|
|
|
; 6, 5, 4, 3, 2, 1
|
|
wait_1s:
|
|
ldx #6 ; 2
|
|
wait_1s_loop:
|
|
lda #255 ; 2
|
|
jsr wait ; 6
|
|
dex ; 2
|
|
bne wait_1s_loop
|
|
|
|
rts
|
|
|
|
load_new:
|
|
|
|
jsr driveon
|
|
|
|
lda load_track
|
|
asl ; track to start*2
|
|
sta phase_smc+1
|
|
|
|
lda load_sector
|
|
tay ; sector to start
|
|
|
|
lda load_length ; length
|
|
tax
|
|
|
|
lda load_address ; address to load
|
|
|
|
jsr seekread
|
|
|
|
rts
|
|
|
|
load_address:
|
|
.byte $00
|
|
load_track:
|
|
.byte $00
|
|
load_sector:
|
|
.byte $00
|
|
load_length:
|
|
.byte $00
|
|
|
|
.include "wait.s"
|
|
|
|
|
|
code_end:
|
|
|
|
.assert (>seek_delay_end - >seek_delay) < 1 , error, "seek delay spans page"
|