; Disk routine (pinched from Agile – sorry guys)
CIAAPRA EQU $bfe001 Cia A port register A
CIABPRB EQU $bfd100 Cia B port register B
CIABICR EQU $bfdd00 Cia B interrupt control register
CUSTOM EQU $dff000 Custom hardware
INTREQR EQU $1e Read interrupt request
DSKPTH EQU $20 Disk buffer pointer
DSKLEN EQU $24 Disk access length
DSKSYNC EQU $7e Disk sync word
DMACON EQU $96 Write DMA control
INTREQ EQU $9c Write interrupt request
ADKCON EQU $9e Write audio and disk controller
StepDel EQU $bb7 Step delay (dbf, naughty!)
; a0 is address to load file at, d0 is no. of file
FileRead
movem.l d0-d7/a0-a6,-(sp) Store registers
move.l a0,a1 Copy addr. to load into a1
lea Filename(pc),a0 Get filename in a0
bsr MkName Put d0 (hex) into filename string
lea Variables(pc),a6 a6 = Variables base
lea CIABPRB,a5 a5 = CIA base (CIABPRB)
lea CUSTOM,a4 a4 = custom hardware base
move.l a1,20(a6) Store addr. to load in vars
clr.w 10(a6) Set ‘no track in buffer’
move.b #%11111111,(a5) All CIABPRB high
move.b #%10000111,(a5) SEL0-3 low (all motors now off)
move.b #%01111111,(a5) Ready for motors on again
bclr #3,(a5) Select drive 0, motor on
tst.w 0(a6) }
nop } blowed if I know why
not.w 0(a6) }
clr.l 2(a6) Clear current track and ?
clr.l 6(a6) Clear sec. to load, sec.no on track
btst #4,CIABICR-CIABPRB(a5) Test index (pointlessly)
.wtindx btst #4,CIABICR-CIABPRB(a5) Test index
beq.s .wtindx Repeat until one occurs
bset #1,(a5) Dir = out towards edge
.gttk0 btst #4,CIAAPRA-CIABPRB(A5) Are we at track 0?
beq.s .gottk0
.wtrdy BTST #5,CIAAPRA-CIABPRB(A5) Drive ready?
bne.s .wtrdy Wait until it is
bclr #0,(a5) Set step
nop
nop
nop Wait a few cycles
bset #0,(a5) Clear step
move.w #StepDel,D0 NAUGHTY – should use CIAs!
.stpdel dbf d0,.stpdel Step delay
bra.s .gttk0 Repeat until we get to track 0
.gottk0 bsr GetHash Calculate filename’s hash value
move.w #880,d0 Root block no. in d0
bsr ReadSec
tst.l d7 Was there an error?
bne DoneAll Clear up and return if so
move.w 18(a6),d0 Filename’s hash offset into d0
move.l (a3,d0.w),d0 Get no. of file header block
beq DoneAll If no file, clear up and return
.hshchn bsr ReadSec Read sector
tst.l d7 Was there an error?
bne.s DoneAll If so clear up, return
lea $1B0(a3),a2 a2 = pointer to filename in block
moveq #0,d0 Byte -> word
move.b (a2)+,d0 Get name length byte
cmp.w 16(a6),d0 Compare with wanted filename length
beq.s .sameln Go on if same lengths
.wrongF move.l $1F0(A3),d0 Get next hash chain
beq.s DoneAll If none, file not found – return
bra.s .hshchn Otherwise follow down the hash chain
.sameln subq.w #1,d0 Length -1 for dbf
move.l 12(a6),a1 Required filename ptr. in a1
.letlop move.b (a2)+,d1 Get byte from current file’s name
cmp.b #”a”-1,d1 Test case (badly)
ble.s .isupr Go on if upper case
sub.b #32,d1 Else convert to upper case
.isupr cmp.b (a1)+,d1 Compare with required filename
bne.s .wrongF If different, wrong file
dbf d0,.letlop Repeat to compare all letters
.loadlp move.l $10(a3),d0 Get first/next data block
beq.s DoneAll If none, clean up and return
cmp.w #1759,d0 Above valid range?
bgt.s DoneAll If so, clean up and return
bsr.s ReadSec Otherwise load it
tst.l d7 If there was an error
bne.s DoneAll then clear up and return
lea $200(a3),a0 Get end-of-block pointer in a0
move.l $14(a3),d1 Get checksum long
clr.l $14(a3) Clear same long in block
move.l a3,a1 Copy block pointer to a1
moveq #0,d0 Clear sum
.sumlop add.l (a1)+,d0 Add long to sum
cmp.l a0,a1 At end of block
blt.s .sumlop Sum all longs
neg.l d0 Negate sum
eor.l d0,d1 Compare with stored sum
bne.s DoneAll If checksum fails, clean up and return
move.l $c(a3),d0 Get no. of bytes in this block in d0
subq.w #1,d0 Prepare for dbf
lea $18(a3),a1 Get pointer to data in a1
move.l 20(a6),a0 Get address to load at in a0
.cpbyte move.b (a1)+,(a0)+ Copy data as bytes
dbf d0,.cpbyte Repeat
move.l a0,20(a6) Store new load address
bra.s .loadlp Carry on loading
; Routine to switch off motors and return
DoneAll move.b #%11111111,(a5) Select everything
move.b #%10000111,(a5) All motors off
move.b #%11111111,(a5) Left off
movem.l (sp)+,d0-d7/a0-a6 Restore registers
rte Return
; Routine to read a sector (in d0) from the disk
; Pointer to the loaded sector is returned in a3
ReadSec tst.w 10(a6) Check buffer status
bmi.s L701E6 Leave alone if negative
move.w #1,10(A6) Otherwise set to 1 (pointless)
L701E6 moveq #0,d7 d7 is error flag, none yet
move.w d0,6(a6) Store sector to load in vars
ext.l d0 word -> long
divu #11,d0 sector number…
swap d0 …mod 11
move.w d0,8(a6) gives sector on track, store in vars
swap d0 recover division result
move.l d0,d1 Copy to d1
lsr.w #1,d1 Get cylinder no. in d1.w
tst.w 10(a6) Is there a track in the buffer?
bpl.s .nedred If not, will have to read one
cmp.w 2(a6),d1 Is it the right cylinder?
bne.s .nedred If not, will have to read one
move.w d0,d2 Copy track no. to d2
and.w #1,d2 Mask to get side
cmp.w 4(a6),d2 Is the right side in the buffer?
beq L7036E If so, buffer is prepared
.nedred bset #2,(a5) Select side 0
clr.w 4(a6) Flag side 0 in vars
btst #0,d0 See which side is required
beq.s .sideok Go on if 0; side is correct
move.w #1,4(a6) Flag side 1 in vars
bclr #2,(a5) Select side 1
.sideok move.w d1,d0 Copy d0 to d1
bsr GetTkd0 Go to that track
move.w #$7F00,ADKCON(a4) Clear top byte of ADKCON
move.w #$9500,ADKCON(a4) MFM, no precomp, wordsync, FAST(MFM)
move.w #$4489,DSKSYNC(a4) Standard sync
move.l #$23600,a3 Get buffer pointer
move.l #$55555555,d6 Get clock value in d6
.fndlst move.l a3,a1 Copy buffer pointer to a1
move.w #2,INTREQ(a4) Clear disk interrupt request
move.l a3,DSKPTH(a4) Set disk buffer
.watrdy btst #5,CIAAPRA-CIABPRB(a5) Disk ready?
bne.s .watrdy Wait until it is
move.w #$8210,DMACON(a4) Disk DMA on
move.w #$8008,DSKLEN(a4)
move.w #$8008,DSKLEN(a4) Read len = sector info only
.wtdkdn btst #1,INTREQR+1(a4) Disk DMA done interrupt?
beq.s .wtdkdn Wait until one occurs
.skpsnc cmp.w #$4489,(a1)+ Compare syncs at (buffer+)
beq.s .skpsnc Keep going until past
subq.l #2,a1 a1 points to last sync
move.l (a1),d0
move.l 4(a1),d1 Get longs of sector info
and.l d6,d0
and.l d6,d1 Mask with clock
add.l d0,d0 Shift first one left
or.l d0,d1 Recombine
cmp.b #1,d1 Just before track gap?
bne.s .fndlst If not keep looking for last sector
move.l a3,DSKPTH(a4) Set buffer pointer again
move.w #$8210,DMACON(a4) Ensure disk DMA is still on
move.w #$9770,DSKLEN(a4)
move.w #$9770,DSKLEN(a4) Now read whole track
move.w #2,INTREQ(a4) Clear disk DMA done int. request
move.l #$186A0,d1 d1 = quite a long time
.wtdmad subq.l #1,d1 Count down
bne.s .notstk Go on if not end of count
not.l d7 Else flag an error
move.w #$4000,DSKLEN(a4) Stop disk DMA
rts Return
.notstk btst #1,INTREQR+1(A4) Disk DMA done interrupt?
beq.s .wtdmad If not, keep counting
move.w #$4000,DSKLEN(a4) Stop disk DMA
moveq #10,d5 11 sectors to decode
move.l a3,a2 Put them back over the buffer
move.l a3,a1 Save buffer pointer for later
.seclop move.w #$3ff,d0 Amount of space to look for sync in
.fndsnc cmp.w #$4489,(a3)+ Look for sync
beq.s .gotsc Go on if found it
dbf d0,.fndsnc Keep trying
not.l d7 If sync missing, flag error
rts and return
.gotsc cmp.w #$4489,(a3) Looking at sync?
bne.s .skpsnk If not, have passed it
addq.l #2,a3 Otherwise skip over it
.skpsnk movem.l (a3)+,d0-d1 Get two longs
and.l d6,d0
and.l d6,d1 And them with clock
add.l d0,d0 Shift first one left
or.l d1,d0 Recombine
lsr.w #8,d0 Shift right for sector number
move.w d0,(a2)+ Store sector number over buffer
lea $30(a3),a3 Skip sector info; a3 points to data
moveq #$7f,d2 128 longs of data to decode
.decdat move.l $200(a3),d1 Get second long of data
move.l (a3)+,d0 Get first long of data
and.l d6,d0
and.l d6,d1 And them with clock
add.l d0,d0 Shift first one left
or.l d1,d0 Recombine
move.l d0,(a2)+ Store over buffer again
dbf d2,.decdat Repeat for all data
dbf d5,.seclop Repeat for all sectors
; Track is now decoded as sectorno.w, data.b repeated 11 times
; Now bubblesort the sectors into order
.bubble move.l a1,a2 Get buffer pointer again
moveq #9,d0 10 (sector and next sector)s to compare
moveq #0,d1 d1 is count of sectors swapped
.cmpsec move.w (a2),d2 Get no. of current sector in d2
cmp.w $202(a2),d2 Compare with no. of next sector
blt.s .sortok If less, go on
move.l a2,a3 Copy current sec. pointer to a3
move.w #$100,d2 One sector + sector no. words to swap
.swpwrd move.w $202(a3),d3
move.w (a3),$202(a3)
move.w d3,(a3)+ Swap a word of sector data
dbf d2,.swpwrd Repeat
addq.w #1,d1 Inc. no. of sectors swapped
.sortok lea $202(a2),a2 Get next sector
dbf d0,.cmpsec Repeat for 10 (sector and next sector)s
tst.w d1 Did we have to swap anything?
bne.s .bubble If so, try again
lea 2(a1),a2 a2 is pointer to first sector data
moveq #10,d0 11 sectors to shift back
.seccpy moveq #$7f,d1 128 longs of data in each sector
.cpydat move.l (a2)+,(a1)+ Copy longs of data back down buffer
dbf d1,.cpydat Repeat for all data
addq.l #2,a2 Skip sector no., no longer needed
dbf d0,.seccpy Copy other sectors directly after
; At this point, the track is prepared in the buffer, so we just need
; to return a pointer to the sector in a3
L7036E move.l #$23600,a3 Get buffer pointer
moveq #9,d0 Constant for shift
moveq #0,d1 word -> long
move.w 8(a6),d1 Sector no. on track .w into d1
asl.l d0,d1 d1 $xx ones
; stores result in variables
GetHash move.l a0,12(a6) Store filename in vars
move.l a0,a1 Copy to a1
moveq #0,d0 Clear length counter
.getlen tst.b (a1)+ End of filename?
beq.s .gotlen Go on if so
addq.w #1,d0 Else increase length counter,
bra.s .getlen repeat
.gotlen move.w d0,d1 Copy filename length to d1
move.w d0,16(a6) Store filename length in vars
subq.w #1,d1 Prepare d1 (filename len) for dbf
.hshlop mulu #13,d0 d0 = filename length * 13
moveq #0,d2 Clear d2 for byte -> word
move.b (a0),d2 Get letter of filename
cmp.b #”a”-1,d2 Test case (badly)
ble.s .letok If less or equal, is upper case
sub.b #32,d2 Otherwise sub 32 to make it upper case
.letok move.b d2,(a0)+ Store back in filename
add.w d2,d0 Add to hash total in d0
and.w #$7ff,d0 Keep d0 in range
dbf d1,.hshlop Repeat for all bytes of filename
divu #72,D0 Hash total…
swap d0 …mod 72…
addq.w #6,d0 …plus 6…
asl.w #2,D0 …times 4
move.w d0,18(a6) store in variables
rts
; Routine to put the number in d0 into the filename at a0 (“$xx”)
MkName move.w d0,d1 Copy fileno. to d1
move.w d1,d2 and d2
lsr.w #4,d2 d2 is upper nibble
bsr.s D2toHex convert to hex ascii
move.b d2,1(a0) store as first digit of filename
move.w d1,d2 move lower nibble into d2
bsr.s D2toHex convert to hex
move.b d2,2(a0) store as second nibble
rts return
; Routine to convert d2 into hex ascii
D2toHex and.w #$f,d2 Only numbers from 0-15
add.w #”0″,d2 Convert to ascii
cmp.w #”9″,D2 letter or number?
ble.s .digit return if number
addq.w #7,d2 else add 7 to convert to letter
.digit rts return
Variables: dc.w 0 0 = .w
dc.w 0 2 = Current track .w
dc.w 0 4 = Side in buffer (0/1) .w
dc.w 0 6 = sector to load .w
dc.w 0 8 = sector no. on track .w
dc.w 0 10 = Valid track in buffer .w
dc.l 0 12 = Pointer to filename .l
dc.w 0 16 = Length of filename in bytes .w
dc.w 0 18 = filename’s hash offset .w
dc.l 0 20 = Address to load at .l
Filename dc.b “$00″,0 Filename to load
Agile File Loader
; Disk routine (pinched from Agile – sorry guys)
<-- Spiv’s File Loader | [ Code ]
<-- Spiv’s File Loader | [ Code ] | Alpha One’s Track loader -->