#include <m68k/asm.h>
#include <mac68k/obio/iwmreg.h>
#define USE_DELAY 0
.extern _C_LABEL(TimeDBRA) | in mac68k/macrom.c
.extern _C_LABEL(Via1Base) | in mac68k/machdep.c
.extern _C_LABEL(IWMBase) | in iwm_fd.c
.data
diskTo:
.byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01
.byte 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, 0x05, 0x06
.byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x08
.byte 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D
.byte 0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13
.byte 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A
.byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
.byte 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, 0x1D, 0x1E
.byte 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x20, 0x21
.byte 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28
.byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, 0x2A, 0x2B
.byte 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32
.byte 0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38
.byte 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
hdrLeadIn:
.byte 0xD5, 0xAA, 0x96
hdrLeadOut:
.byte 0xDE, 0xAA, 0xFF
dataLeadIn:
.byte 0xD5, 0xAA, 0xAD
dataLeadOut:
.byte 0xDE, 0xAA, 0xFF, 0xFF
toDisk:
.byte 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6
.byte 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3
.byte 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC
.byte 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3
.byte 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE
.byte 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC
.byte 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xf5, 0xF6
.byte 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
syncPattern:
.byte 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF
.byte 0xD5, 0xAA, 0xAD
.text
ENTRY(iwmQueryDrvFlag)
link %a6,#0
moveml %d1/%a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
movel %a6@(8),%d0 | Get drive #
beq quDrv00
cmpl #1,%d0
beq quDrv01
bra quDone | Invalid drive #
quDrv00:
tstb %a0@(intDrive) | SELECT; choose drive #0
bra queryDrv
quDrv01:
tstb %a0@(extDrive) | SELECT; choose drive #1
queryDrv:
movel %a6@(12),%d0 | Get register #
bsr driveStat
quDone:
moveml %sp@+,%d1/%a0-%a1
unlk %a6
rts
ENTRY(iwmReadSectHdr)
link %a6,#0
moveml %d1-%d5/%a0-%a4,%sp@-
movel %a6@(0x08),%a4 | Get param block address
bsr readSectHdr
moveml %sp@+,%d1-%d5/%a0-%a4
unlk %a6
rts
ENTRY(iwmInit)
link %a6,#0
moveml %d2/%a0,%sp@-
movel _C_LABEL(IWMBase),%a0
tstb %a0@(ph0L) | CA0
tstb %a0@(ph1L) | CA1
tstb %a0@(ph2L) | CA2
tstb %a0@(ph3L) | LSTRB
tstb %a0@(mtrOff) | ENABLE; make sure drive is off
tstb %a0@(intDrive) | SELECT; choose drive 1
moveq #0x1F,%d0 | XXX was 0x17 -- WHY!?
tstb %a0@(q6H)
andb %a0@(q7L),%d0 | status register
tstb %a0@(q6L)
cmpib #iwmMode,%d0 | all is well??
beq initDone
movel #0x00080000,%d2 | ca. 500,000 retries = 1.5 sec
initLp:
moveq #initIWMErr,%d0 | Initialization error
subql #1,%d2
bmi initErr
tstb %a0@(mtrOff) | disable drive
tstb %a0@(q6H)
moveq #0x3F,%d0
andb %a0@(q7L),%d0
bclr #5,%d0 | Reset bit 5 and set Z flag
| according to previous state
bne initLp | Loop if drive still on
cmpib #iwmMode,%d0
beq initDone
moveb #iwmMode,%a0@(q7H) | Init IWM
tstb %a0@(q7L)
bra initLp
initDone:
tstb %a0@(q6L) | Prepare IWM for data
moveq #0,%d0 | noErr
initErr:
moveml %sp@+,%d2/%a0
unlk %a6
rts
ENTRY(iwmCheckDrive)
link %a6,#0
moveml %d1/%a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
moveq #-1,%d1 | no drive
movel %a6@(0x08),%d0 | check drive #
beq chkDrv00
cmpl #1,%d0
beq chkDrv01
bra chkDone | invalid drive #
chkDrv00:
tstb %a0@(intDrive) | SELECT; choose drive #0
bra chkDrive
chkDrv01:
tstb %a0@(extDrive) | SELECT; choose drive #1
chkDrive:
moveq #-2,%d1 | error code
moveq #drvInstalled,%d0 | Drive installed?
bsr driveStat
bmi chkDone | no drive
moveq #0,%d1 | Drive found
tstb %a0@(mtrOn) | ENABLE; activate drive
moveq #singleSided,%d0 | Drive is single-sided?
bsr driveStat
bpl chkHasDisk
bset #0,%d1 | 1 = no.
chkHasDisk:
moveq #diskInserted,%d0 | Disk inserted?
bsr driveStat
bpl chkMotorOn
bset #1,%d1 | 1 = No.
bra chkDone
chkMotorOn:
moveq #drvMotorState,%d0 | Motor is running?
bsr driveStat
bpl chkWrtProt
bset #2,%d1 | 1 = No.
chkWrtProt:
moveq #writeProtected,%d0 | Disk is write protected?
bsr driveStat
bpl chkDD_HD
bset #3,%d1 | 1 = No.
chkDD_HD:
moveq #diskIsHD,%d0 | Disk is HD? (was "drive installed")
bsr driveStat
bpl chkDone
bset #4,%d1 | 1 = No.
chkDone:
movel %d1,%d0
moveml %sp@+,%d1/%a0-%a1
unlk %a6
rts
ENTRY(iwmDiskEject)
link %a6,#0
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
movel %a6@(0x08),%d0 | Get drive #
beq ejDrv00
cmpw #1,%d0
beq ejDrv01
bra ejDone | Invalid drive #
ejDrv00:
tstb %a0@(intDrive) | SELECT; choose drive #0
bra ejDisk
ejDrv01:
tstb %a0@(extDrive) | SELECT; choose drive #1
ejDisk:
tstb %a0@(mtrOn) | ENABLE; activate drive
moveq #motorOffCmd,%d0 | Motor off
bsr driveCmd
moveq #diskInserted,%d0 | Disk inserted?
bsr driveStat
bmi ejDone
moveq #ejectDiskCmd,%d0 | Eject it
bsr selDriveReg
tstb %a0@(ph3H) | LSTRB high
#if USE_DELAY
movel #1000,%sp@- | delay 1 ms
jsr _C_LABEL(delay)
addqw #4,%sp | clean up stack
#else
movew #1,%d0
bsr iwmDelay
#endif
tstb %a0@(ph3L) | LSTRB low
moveq #0,%d0 | All's well...
ejDone:
unlk %a6
rts
ENTRY(iwmSelectDrive)
link %a6,#0
moveml %a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
movel %a6@(8),%d0 | Get drive #
bne extDrv
tstb %a0@(intDrive)
bra sdDone
extDrv:
tstb %a0@(extDrive)
sdDone:
moveml %sp@+,%a0-%a1
unlk %a6
rts
ENTRY(iwmMotor)
link %a6,#0
moveml %a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
movel %a6@(8),%d0 | Get drive #
bne mtDrv1
tstb %a0@(intDrive)
bra mtSwitch
mtDrv1:
tstb %a0@(extDrive)
mtSwitch:
movel #motorOnCmd,%d0 | Motor ON
tstl %a6@(12)
bne mtON
movel #motorOffCmd,%d0
mtON:
bsr driveCmd
moveml %sp@+,%a0-%a1
unlk %a6
rts
ENTRY(iwmSelectSide)
link %a6,#0
moveml %d1/%a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
moveq #0x0B,%d0 | Drive ready for reading?
bsr selDriveReg | (undocumented)
ss01:
bsr dstatus
bmi ss01
moveq #rdDataFrom0,%d0 | Lower head
movel %a6@(0x08),%d1 | Get side #
beq ssSide0
moveq #rdDataFrom1,%d0 | Upper head
ssSide0:
bsr driveStat
moveml %sp@+,%d1/%a0-%a1
unlk %a6
rts
ENTRY(iwmTrack00)
link %a6,#0
moveml %d1-%d4/%a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
moveq #motorOnCmd,%d0 | Switch drive motor on
bsr driveCmd
moveq #stepOutCmd,%d0 | Step out
bsr driveCmd
movew #100,%d2 | Max. tries
t0Retry:
moveq #atTrack00,%d0 | Already at track 0?
bsr driveStat
bpl isTrack00 | Track 0 => Bit 7 = 0
moveq #doStepCmd,%d0 | otherwise step
bsr driveCmd
movew #80,%d4 | Retries
t0Still:
moveq #stillStepping,%d0 | Drive is still stepping?
bsr driveStat
dbmi %d4,t0Still
cmpiw #-1,%d4
bne t002
moveq #cantStepErr,%d0 | Not ready after many retries
bra t0Done
t002:
#if USE_DELAY
movel #15000,%sp@-
jsr _C_LABEL(delay) | in mac68k/clock.c
addqw #4,%sp
#else
movew #15,%d0
bsr iwmDelay
#endif
dbra %d2,t0Retry
moveq #tk0BadErr,%d0 | Can't find track 00!!
bra t0Done
isTrack00:
moveq #0,%d0
t0Done:
moveml %sp@+,%d1-%d4/%a0-%a1
unlk %a6
rts
ENTRY(iwmSeek)
link %a6,#0
moveml %d1-%d4/%a0-%a1,%sp@-
movel _C_LABEL(IWMBase),%a0
movel _C_LABEL(Via1Base),%a1
moveq #motorOnCmd,%d0 | Switch drive motor on
bsr driveCmd
moveq #stepInCmd,%d0 | Set step IN
movel %a6@(8),%d2 | Get # of steps from stack
beq stDone | 0 steps? Nothing to do.
bpl stepOut
moveq #stepOutCmd,%d0 | Set step OUT
negl %d2 | Make # of steps positive
stepOut:
subql #1,%d2 | Loop exits for -1
bsr driveCmd | Set direction
stLoop:
moveq #doStepCmd,%d0
bsr driveCmd | Step one!
movew #80,%d4 | Retries
st01:
moveq #stillStepping, %d0 | Drive is still stepping?
bsr driveStat
dbmi %d4,st01
cmpiw #-1,%d4
bne st02
moveq #cantStepErr,%d2 | Not ready after many retries
bra stDone
st02:
#if USE_DELAY
movel #30,%sp@-
jsr _C_LABEL(delay) | in mac68k/clock.c
addqw #4,%sp
#else
movew _C_LABEL(TimeDBRA),%d4 | dbra loops per ms
lsrw #5,%d4 | DIV 32
st03: dbra %d4,st03 | makes ca. 30 us
#endif
dbra %d2,stLoop
moveq #0,%d2 | All is well
stDone:
movel %d2,%d0
moveml %sp@+,%d1-%d4/%a0-%a1
unlk %a6
rts
ENTRY(iwmReadSector)
link %a6,#-8
moveml %d1-%d7/%a0-%a5,%sp@-
movel _C_LABEL(Via1Base),%a1
movel %a6@(o_hdr),%a4 | Addr of sector header struct
moveb %a4@+,%a6@(-3) | Save side bit,
moveb %a4@+,%a6@(-4) | track#,
moveb %a4@,%a6@(-5) | sector#
moveb #2*maxGCRSectors,%a6@(-6) | Max. retry count
movew %sr,%a6@(-2) | Save CPU status register
oriw #0x0600,%sr | Block all interrupts
rsNextSect:
movel %a6@(o_hdr),%a4 | Addr of sector header struct
bsr readSectHdr | Get next available SECTOR header
bne rsDone | Return if error
movel %a6@(o_hdr),%a4 | Sector header struct
moveb %a4@(o_side),%d1 | Get actual side
lsrb #3,%d1 | "Normalize" side bit (to bit 0)
andb #1,%d1
moveb %a6@(-3),%d2 | Get wanted side
eorb %d1,%d2 | Compare side bits
bne rsSeekErr | Should be equal!
moveb %a6@(-4),%d1 | Get track# we want
cmpb %a4@(o_track),%d1 | Compare to the header we've read
beq rsGetSect
rsSeekErr:
moveq #seekErr,%d0 | Wrong track or side found
bra rsDone
rsGetSect:
moveb %a4@(2),%a6@(-7) | save sector number
lea %a4@(3),%a4 | Beginning of tag buffer
moveq #50,%d3 | Max. retries for sector lookup
rsLeadIn:
lea dataLeadIn,%a3 | Sector data lead-in
moveq #0x03,%d4 | is 3 bytes long
rsLI1:
moveb %a0@,%d2 | Get next byte
bpl rsLI1
dbra %d3,rsLI2
moveq #noDtaMkErr,%d0 | Can't find a data mark
bra rsDone
rsLI2:
cmpb %a3@+,%d2
bne rsLeadIn | If ne restart scan
subqw #1,%d4
bne rsLI1
rsTagNyb0:
moveb %a0@,%d3 | Get a char,
bpl rsTagNyb0
moveb %a2@(0,%d3),%a4@+ | remap and store it
moveq #0,%d5 | Clear checksum registers
moveq #0,%d6
moveq #0,%d7
moveq #10,%d4 | Loop counter
moveq #0,%d3 | Data scratch reg
rsTags:
rsTagNyb1:
moveb %a0@,%d3 | Get 2 bit nibbles
bpl rsTagNyb1
moveb %a2@(0,%d3),%d1 | Remap disk byte
rolb #2,%d1
moveb %d1,%d2
andib #0xC0,%d2 | Get top 2 bits for first byte
rsTagNyb2:
moveb %a0@,%d3 | Get first 6 bit nibble
bpl rsTagNyb2
orb %a2@(0,%d3),%d2 | Remap it and complete first byte
moveb %d7,%d3 | The X flag bit (a copy of the carry
addb %d7,%d3 | flag) is added with the next addx
rolb #1,%d7
eorb %d7,%d2
moveb %d2,%a4@+ | Store tag byte
addxb %d2,%d5 | See above
rolb #2,%d1
moveb %d1,%d2
andib #0xC0,%d2 | Get top 2 bits for second byte
rsTagNyb3:
moveb %a0@,%d3 | Get second 6 bit nibble
bpl rsTagNyb3
orb %a2@(0,%d3),%d2 | remap it and complete byte
eorb %d5,%d2
moveb %d2,%a4@+ | Store tag byte
addxb %d2,%d6
rolb #2,%d1
andib #0xC0,%d1 | Get top 2 bits for third byte
rsTagNyb4:
moveb %a0@,%d3 | Get third 6 bit nibble
bpl rsTagNyb4
orb %a2@(0,%d3),%d1 | remap it and complete byte
eorb %d6,%d1
moveb %d1,%a4@+ | Store tag byte
addxb %d1,%d7
subqw #3,%d4 | Update byte counter (four 6&2 encoded
bpl rsTags | disk bytes make three data bytes).
movew #0x01FE,%d4 | Loop counter
moveq #0,%d1 | Clear %d1
moveb %a6@(-7),%d1 | Get sector# we have read
cmpb %a6@(-5),%d1 | Compare to the sector# we want
bne rsToCache
movel %a6@(o_buf),%a4 | Sector data buffer
bra rsData
rsToCache:
movel %a6@(o_rslots),%a4 | Base address of slot array
lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
movel #-1,%a4@(o_valid,%d1)
movel %a4@(o_secbuf,%d1),%a4 | and get its buffer ptr
rsData:
rsDatNyb1:
moveb %a0@,%d3 | Get 2 bit nibbles
bpl rsDatNyb1
moveb %a2@(0,%d3),%d1 | Remap disk byte
rolb #2,%d1
moveb %d1,%d2
andib #0xC0,%d2 | Get top 2 bits for first byte
rsDatNyb2:
moveb %a0@,%d3 | Get first 6 bit nibble
bpl rsDatNyb2
orb %a2@(0,%d3),%d2 | Remap it and complete first byte
moveb %d7,%d3 | The X flag bit (a copy of the carry
addb %d7,%d3 | flag) is added with the next addx
rolb #1,%d7
eorb %d7,%d2
moveb %d2,%a4@+ | Store data byte
addxb %d2,%d5 | See above
rolb #2,%d1
moveb %d1,%d2
andib #0xC0,%d2 | Get top 2 bits for second byte
rsDatNyb3:
moveb %a0@,%d3 | Get second 6 bit nibble
bpl rsDatNyb3
orb %a2@(0,%d3),%d2 | Remap it and complete byte
eorb %d5,%d2
moveb %d2,%a4@+ | Store data byte
addxb %d2,%d6
tstw %d4
beq rsCkSum | Data read, continue with checksums
rolb #2,%d1
andib #0xC0,%d1 | Get top 2 bits for third byte
rsDatNyb4:
moveb %a0@,%d3 | Get third 6 bit nibble
bpl rsDatNyb4
orb %a2@(0,%d3),%d1 | Remap it and complete byte
eorb %d6,%d1
moveb %d1,%a4@+ | Store data byte
addxb %d1,%d7
subqw #3,%d4 | Update byte counter
bra rsData
rsCkSum:
rsCkS1:
moveb %a0@,%d3 | Get 2 bit nibbles
bpl rsCkS1
moveb %a2@(0,%d3),%d1 | Remap disk byte
bmi rsBadCkSum | Fault! (Bad read)
rolb #2,%d1
moveb %d1,%d2
andib #0xC0,%d2 | Get top 2 bits for first byte
rsCkS2:
moveb %a0@,%d3 | Get first 6 bit nibble
bpl rsCkS2
moveb %a2@(0,%d3),%d3 | and remap it
bmi rsBadCkSum | Fault! ( > 0x3f is bad read)
orb %d3,%d2 | Merge 6&2
cmpb %d2,%d5 | Compare first checksum to %D5
bne rsBadCkSum | Fault! (Checksum)
rolb #2,%d1
moveb %d1,%d2
andib #0xC0,%d2 | Get top 2 bits for second byte
rsCkS3:
moveb %a0@,%d3 | Get second 6 bit nibble
bpl rsCkS3
moveb %a2@(0,%d3),%d3 | and remap it
bmi rsBadCkSum | Fault! (Bad read)
orb %d3,%d2 | Merge 6&2
cmpb %d2,%d6 | Compare second checksum to %D6
bne rsBadCkSum | Fault! (Checksum)
rolb #2,%d1
andib #0xC0,%d1 | Get top 2 bits for second byte
rsCkS4:
moveb %a0@,%d3 | Get third 6 bit nibble
bpl rsCkS4
moveb %a2@(0,%d3),%d3 | and remap it
bmi rsBadCkSum | Fault! (Bad read)
orb %d3,%d1 | Merge 6&2
cmpb %d1,%d7 | Compare third checksum to %D7
beq rsLdOut | Fault! (Checksum)
rsBadCkSum:
moveq #badDCkSum,%d0 | Bad data mark checksum
bra rsDone
rsBadDBtSlp:
moveq #badDBtSlp,%d0 | One of the data mark bit slip
bra rsDone | nibbles was incorrect
rsLdOut:
moveq #1,%d4 | Is two bytes long {1,0}
rsLdOut1:
moveb %a0@,%d3 | Get token
bpl rsLdOut1
cmpb %a3@+,%d3
bne rsBadDBtSlp | Fault!
dbra %d4,rsLdOut1
moveq #0,%d0 | OK.
rsDone:
movel %a6@(o_hdr),%a4 | Addr of sector header struct
moveb %a4@(o_sector),%d1 | Get # of sector we have just read
cmpb %a6@(-5),%d1 | Compare to the sector we want
beq rsAllDone
tstb %d0 | Any error? Simply ignore data
beq rsBufValid
lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
movel %a6@(o_rslots),%a4
clrl %a4@(o_valid,%d1) | Mark buffer content "invalid"
rsBufValid:
subqb #1,%a6@(-6) | max. retries
bne rsNextSect
| Sector not found, but
tstb %d0 | don't set error code if we
bne rsAllDone | already have one.
moveq #sectNFErr,%d0
rsAllDone:
movew %a6@(-2),%sr | Restore interrupt mask
moveml %sp@+,%d1-%d7/%a0-%a5
unlk %a6
rts
ENTRY(iwmWriteSector)
link %a6,#-10
moveml %d1-%d7/%a0-%a5,%sp@-
movel _C_LABEL(Via1Base),%a1
movel %a6@(o_hdr),%a4 | Addr of sector header struct
moveb %a4@+,%a6@(-3) | Save side bit,
moveb %a4@+,%a6@(-4) | track#,
moveb %a4@,%a6@(-5) | sector#
moveb #maxGCRSectors,%a6@(-6) | Max. retry count
movew %sr,%a6@(-2) | Save CPU status register
oriw #0x0600,%sr | Block all interrupts
wsNextSect:
movel %a6@(o_hdr),%a4
bsr readSectHdr | Get next available sector header
bne wsAllDone | Return if error
movel %a6@(o_hdr),%a4 | Sector header struct
moveb %a4@(o_side),%d1 | Get side#
lsrb #3,%d1 | "Normalize" side bit...
andb #1,%d1
moveb %a6@(-3),%d2 | Get wanted side
eorb %d1,%d2 | Compare side bits
bne wsSeekErr
moveb %a6@(-4),%d1 | Get wanted track#
cmpb %a4@(o_track),%d1 | Compare to the read header
beq wsCompSect
wsSeekErr:
moveq #seekErr,%d0 | Wrong track or side
bra wsAllDone
wsCompSect:
moveq #0,%d1 | Clear register
moveb %a4@(o_sector),%d1 | get the # of header read
lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
movel %a6@(o_wslots),%a4
tstl %a4@(o_valid,%d1) | Sector dirty?
bne wsBufDirty
moveq #maxGCRSectors-1,%d2 | Any dirty sectors left?
wsChkDty:
movew %d2,%d1
lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
tstl %a4@(o_valid,%d1)
bne wsNextSect | Sector dirty?
dbra %d2,wsChkDty
bra wsAllDone | We are through with this track.
wsBufDirty:
movel _C_LABEL(IWMBase),%a0
lea %a4@(0,%d1),%a3
movel %a3,%a6@(-10) | Save ptr to current slot
tstb %a0@(q6H) | Enable writing to disk
movel %a6@(o_hdr),%a4 | Sector header struct
lea %a4@(o_Tags),%a3 | Point %a3 to tags buffer
lea syncPattern,%a4
moveb %a4@+,%a0@(q7H) | Write first sync byte
lea %a0@(q6L),%a2 | Point %a2 to handshake register
lea %a0@(q6H),%a0 | Point %a0 to IWM data register
moveq #6,%d0 | Loop counter for sync bytes
moveq #0,%d2
moveq #0,%d3
movel #0x02010009,%d4 | Loop counters for tag/sector data
wsLeadIn:
moveb %a4@+,%d1 | Get next sync byte
wsLI1:
tstb %a2@ | IWM ready?
bpl wsLI1
moveb %d1,%a0@ | Write it to disk
subqw #1,%d0
bne wsLeadIn
moveb %a4@+,%d1 | Write 2nd byte of sector lead-in
lea toDisk,%a4 | Point %a4 to nibble translation table
wsLI2:
tstb %a2@ | IWM ready?
bpl wsLI2
moveb %d1,%a0@ | Write it to disk
moveq #0,%d5 | Clear checksum registers
moveq #0,%d6
moveq #0,%d7
moveq #0x0B,%d1 | 3rd byte of sector data lead-in
| (Gets translated to 0xAD)
moveb %a3@+,%d2 | Get 1st byte from tags buffer
bra wsDataEntry
wsSD1:
movel %a6@(-10),%a3 | Get ptr to current slot
movel %a3@(o_secbuf),%a3 | Get start of sector data buffer
wsData:
addxb %d2,%d7
eorb %d6,%d2
moveb %d2,%d3
lsrw #6,%d3 | Put 2 bit nibbles into place
wsRDY01:
tstb %a2@ | IWM ready?
bpl wsRDY01
moveb %a4@(0,%d3),%a0@ | Translate nibble and write
subqw #3,%d4 | Update counter
moveb %d7,%d3
addb %d7,%d3 | Set X flag (Why?)
rolb #1,%d7
andib #0x3F,%d0
wsRDY02:
tstb %a2@ | IWM ready?
bpl wsRDY02
moveb %a4@(0,%d0),%a0@ | Translate nibble and write
wsDataEntry:
moveb %a3@+,%d0 | Get first byte
addxb %d0,%d5
eorb %d7,%d0
moveb %d0,%d3 | Keep top two bits
rolw #2,%d3 | by shifting them to MSByte
andib #0x3F,%d1
wsRDY03:
tstb %a2@ | IWM ready?
bpl wsRDY03
moveb %a4@(0,%d1),%a0@ | Translate nibble and write
moveb %a3@+,%d1 | Get second byte
addxb %d1,%d6
eorb %d5,%d1
moveb %d1,%d3 | Keep top two bits
rolw #2,%d3 | by shifting them to MSByte
andib #0x3F,%d2
wsRDY04:
tstb %a2@ | IWM ready?
bpl wsRDY04
moveb %a4@(0,%d2),%a0@ | Translate nibble and write
tstl %d4 | Last loop cycle?
beq wsSDDone | Then get out while we can.
moveb %a3@+,%d2 | Get third byte
tstw %d4 | First write tag buffer,...
bne wsData
swap %d4 | ...then write data buffer
bne wsSD1
wsSDDone:
clrb %d3 | No 513th byte
lsrw #6,%d3 | Set up 2 bit nibbles
wsRDY05:
tstb %a2@ | IWM ready?
bpl wsRDY05
moveb %a4@(0,%d3),%a0@ | Write fragments
moveb %d5,%d3
rolw #2,%d3
moveb %d6,%d3
rolw #2,%d3
andib #0x3F,%d0
wsRDY06:
tstb %a2@ | IWM ready?
bpl wsRDY06
moveb %a4@(0,%d0),%a0@ | Write 511th byte
andib #0x3F,%d1
wsRDY07:
tstb %a2@ | IWM ready?
bpl wsRDY07
moveb %a4@(0,%d1),%a0@ | write 512th byte
moveb %d7,%d3
lsrw #6,%d3 | Get fragments ready
wsRDY08:
tstb %a2@ | IWM ready?
bpl wsRDY08
moveb %a4@(0,%d3),%a0@ | Write fragments
andib #0x3F,%d5
wsRDY09:
tstb %a2@ | IWM ready?
bpl wsRDY09
moveb %a4@(0,%d5),%a0@ | Write first checksum byte
andib #0x3F,%D6
wsRDY10:
tstb %a2@ | IWM ready?
bpl wsRDY10
moveb %a4@(0,%d6),%a0@ | Write second checksum byte
andib #0x3F,%d7
wsRDY11:
tstb %a2@ | IWM ready?
bpl wsRDY11
moveb %a4@(0,%d7),%a0@ | Write third checksum byte
lea dataLeadOut,%a4 | Sector data lead-out
moveq #3,%d2 | Four bytes long {3,2,1,0}
wsLeadOut:
moveb %a2@,%d1 | IWM ready?
bpl wsLeadOut
moveb %a4@+,%a0@ | Write lead-out
dbf %d2,wsLeadOut
moveq #0,%d0
btst #6,%d1 | Check IWM underrun bit
bne wsNoErr
moveq #wrUnderRun,%d0 | Could not write
| fast enough to keep up with IWM
wsNoErr:
tstb %a0@(0x0200) | q7L -- Write OFF
wsDone:
tstb %d0 | Any error? Simply retry
bne wsBufInvalid
movel %a6@(-10),%a4 | Else, get ptr to current slot
clrl %a4@(o_valid) | Mark current buffer "clean"
bra wsNextSect
wsBufInvalid:
subqb #1,%a6@(-6) | retries
bne wsNextSect
| Sector not found, but
tstb %d0 | don't set error code if we
bne wsAllDone | already have one.
moveq #sectNFErr,%d0
wsAllDone:
movew %a6@(-2),%sr | Restore interrupt mask
moveml %sp@+,%d1-%d7/%a0-%a5
unlk %a6
rts
iwmDelay:
id00: movew _C_LABEL(TimeDBRA),%d1 | dbra loops per ms
id01: dbra %d1,id01 |
dbra %d0,id00
rts
selDriveReg:
tstb %a0@(ph0H) | default CA0 to 1 (says IM III)
tstb %a0@(ph1H) | default CA1 to 1
btst #0,%d0 | bit 0 set => CA2 on
beq se00
tstb %a0@(ph2H)
bra se01
se00:
tstb %a0@(ph2L)
se01:
btst #1,%d0 | bit 1 set => SEL on (VIA 1)
beq se02
bset #vHeadSel,%a1@(vBufA)
bra se03
se02:
bclr #vHeadSel,%a1@(vBufA)
se03:
btst #2,%d0 | bit 2 set => CA0 on
bne se04
tstb %a0@(ph0L)
se04:
btst #3,%d0 | bit 3 set => CA1 on
bne se05
tstb %a0@(ph1L)
se05:
rts
dstatus:
tstb %a0@(q6H)
moveb %a0@(q7L),%d0
tstb %a0@(q6L) | leave in "read data reg"
tstb %d0 | state for safety
rts
driveStat:
tstb %a0@(mtrOn) | ENABLE; turn drive on
bsr selDriveReg
bsr dstatus
rts
dtrigger:
tstb %a0@(ph3H) | LSTRB high
moveb %a1@(vBufA),%a1@(vBufA) | intelligent nop seen in q700 ROM
tstb %a0@(ph3L) | LSTRB low
rts
driveCmd:
bsr selDriveReg
bsr dtrigger
rts
readSectHdr:
moveq #3,%d4 | Read 3 chars from IWM for sync
movew #1800,%d3 | Retries to sync to disk
moveq #0,%d2 | Clear scratch regs
moveq #0,%d1
moveq #0,%d0
movel _C_LABEL(IWMBase),%a0 | IWM base address
tstb %a0@(q7L)
lea %a0@(q6L),%a0 | IWM data register
shReadSy:
moveb %a0@,%d2 | Read char
dbra %d3,shSeekSync
moveq #noNybErr,%d0 | Disk is blank?
bra shDone
shSeekSync:
bpl shReadSy | No char at IWM, repeat read
subqw #1,%d4
bne shReadSy
movew #1500,%d3 | Retries to seek header
shLeadIn:
lea hdrLeadIn,%a3 | Sector header lead-in bytes
moveq #0x03,%d4 | is 3 bytes long
shLI1:
moveb %a0@,%d2 | Get next byte
dbra %d3,shLI2
moveq #noAdrMkErr,%d0 | Can't find an address mark
bra shDone
shLI2:
bpl shLI1 | No char at IWM, repeat read
cmpb %a3@+,%d2
bne shLeadIn | If ne restart scan
subqw #1,%d4
bne shLI1
lea diskTo-0x90,%a2 | Translate disk bytes -> 6&2
shHdr1:
moveb %a0@,%d0 | Get 1st char
bpl shHdr1
moveb %a2@(0,%d0),%d1 | and remap it
moveb %d1,%d4
rorw #6,%d1 | separate 2:6, drop hi bits
shHdr2:
moveb %a0@,%d0 | Get 2nd char
bpl shHdr2
moveb %a2@(0,%d0),%d2 | and remap it
eorb %d2,%d4
shHdr3:
moveb %a0@,%d0 | Get 3rd char
bpl shHdr3
moveb %a2@(0,%d0),%d1 | and remap it
eorb %d1,%d4
rolw #6,%d1 |
shHdr4:
moveb %a0@,%d0 | Get 4th char
bpl shHdr4
moveb %a2@(0,%d0),%d3 | and remap it
eorb %d3,%d4
shHdr5:
moveb %a0@,%d0 | Get checksum byte
bpl shHdr5
moveb %a2@(0,%d0),%d5 | and remap it
eorb %d5,%d4
bne shCsErr | Checksum ok?
moveq #1,%d4 | is 2 bytes long
shHdr6:
moveb %a0@,%d0 | Get token
bpl shHdr6
cmpb %a3@+,%d0 | Check
bne shLOErr | Fault!
dbra %d4,shHdr6
movew %d1,%d0 | Isolate side bit
lsrw #8,%d0
moveb %d0,%a4@+ | and store it
moveb %d1,%a4@+ | Store track number
moveb %d2,%a4@+ | and sector number
moveq #0,%d0 | All is well
bra shDone
shCsErr:
moveq #badCkSmErr,%d0 | Bad sector header checksum
bra shDone
shLOErr:
moveq #badBtSlpErr,%d0 | Bad address mark (no lead-out)
shDone:
tstl %d0 | Set flags
rts