mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1275 lines
39 KiB
1275 lines
39 KiB
;::::::::::::::::::::::::::::::::::::::::::::******************************
|
|
; Floppy Disk Routines ***** Hardware Dependent *****
|
|
; - D-X Designs Pty Ltd P112 - ******************************
|
|
;
|
|
; 1.3 - 26 Aug 01 - Cleaned up for GPL Release. HFB
|
|
; 1.2c- 12 May 97 - Cleaned up source, modified STSIZE Code (again). HFB
|
|
; 1.2b- 22 Apr 97 - Changed 5.25" Hi/Lo Speed controls. HFB
|
|
; 1.0a- 23 Mar 97 - (test) fixes. HFB
|
|
; 1.0 - 13 Aug 96 - Initial Release for P112 from YASMIO. HFB
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Floppy Units are accessed on the P112 using the on-board SMC FDC37C665.
|
|
; An optional assembly flag controls whether Polled or DMA-controlled IO is
|
|
; used in operation. The DMA mode does not use any Interrupts in this
|
|
; preliminary version, but instead polls the INT1* line as Bit 6 on Port C
|
|
; of the Z182.
|
|
; This software uses the following registers:
|
|
|
|
; 0DE - Port C, Bit 6=INT1*, Bit 7=INT2* (DRC)
|
|
|
|
; 090 - Configuration Control Port (CFCNTL)
|
|
; 091 - Configuration Data Port (CFDATA)
|
|
|
|
; The Chip configuration must be altered only to change the polarity on the
|
|
; Density signal applied to Pin 2 on the Floppy Connectors. Optional code
|
|
; which may be used forces this lead Hi/Lo as required for different formats
|
|
; using two bits of Configuration Register #5.
|
|
|
|
CR5 EQU 5 ; FDC/IDE setups
|
|
;Bit 7 6 5 4 3 2 1 0
|
|
; | | | | | +-+-+- unused
|
|
; | | | +-+------- 00 = Density Normal (tracks Data Rate)
|
|
; | | | 01 = (reserved), 10 = Force "1", 11 = Force "0"
|
|
; +-+-+----------- unused
|
|
|
|
; 092 - Drive Control Register (Write Only)
|
|
; 7 6 5 4 3 2 1 0
|
|
; | | | | | | +-+-- Drive (00=0, 01=1, 10=2, 11=3)
|
|
; | | | | | +------ 1 = Normal Opn, 0 = Reset Controller
|
|
; | | | | +-------- 1 = Enable DMA Pins, 0 = Disable DRQ,DAK,INT pins
|
|
; | | | +---------- 1 = Enable Drive 0 Motor
|
|
; | | +------------ 1 = Enable Drive 1 Motor
|
|
; | +-------------- 1 = Enable Drive 2 Motor
|
|
; +---------------- 1 = Enable Drive 3 Motor
|
|
; 093 - (Not Used)
|
|
; 094 - Data-Rate Select (Write) / Main Status Register (Read)
|
|
; 7 6 5 4 3 2 1 0 (Write)
|
|
|
|
; 7 6 5 4 3 2 1 0 (Read)
|
|
; | | | | +-+-+-+-- Drives Seeking (0=B0 Set, 1=B1 Set,.. 3=B3 Set)
|
|
; | | | +---------- 1 = Command In Progress, 0 = Command Ended
|
|
; | | +------------ 1 = Non-DMA Execution, 0 = DMA Execution
|
|
; | +-------------- 1 = Read, 0 = Write
|
|
; +---------------- 1 = Request for Master, 0 = Internal Execution
|
|
;
|
|
; 095 - Data/Command Register (Read/Write)
|
|
; (Byte Writes/Reads)
|
|
; 096 - (Not Used)
|
|
; 097 - Data Rate Register (Write) / Disk Changed Bit (Read)
|
|
; 7 6 5 4 3 2 1 0 (Write)
|
|
; | | | | | | +-+-- 00=500 kb/s, RPM/LC Hi, 01=250/300 kb/s (RPM/LC Lo)
|
|
; | | | | | | 10=250 kb/s, RPM/LC Lo, 11=1000 kb/s (RPM/LC Hi/Lo)
|
|
; +-+-+-+-+-+------ (Not Used)
|
|
;
|
|
; 7 6 5 4 3 2 1 0 (Read)
|
|
; | +-+-+-+-+-+-+-- (Tri-State, used for HD Controller)
|
|
; +---------------- 1 = Disk Changed (latched complement of DSKCHG inp)
|
|
;
|
|
; 0A0 - DMA I/O Select Port (DMA configuration Only)
|
|
|
|
IF BANKED
|
|
COMMON /BANK2/
|
|
ELSE
|
|
CSEG
|
|
ENDIF
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; STMODE (Function 0) - Set the FDC mode for Read/Write operations.
|
|
;
|
|
; Enter : A = Single-Density Flag (0 = Double Dens, 0FFH = Single Dens)
|
|
; Return: Nothing
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STSIZE and STSECT called first
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
STMODE: PUSH BC ; Save Regs
|
|
PUSH HL
|
|
CPL ; Flip Bits so 1=MFM, 0=FM
|
|
AND 01000000B ; keep only bit of interest
|
|
LD (MODE),A ; Set MT, MF, SK for Commands
|
|
LD B,A ; (for later)
|
|
LD A,(DRVSIZ)
|
|
DEC A ; becomes: 8"=0, 5"=1, 3"=2
|
|
LD L,2 ; (prepare for 8")
|
|
JR Z,STMOD2 ; ..jump if 8" (same as HD)
|
|
DEC L ; Else set to 3/5" Low Speed (1)
|
|
LD A,(DRVSPD)
|
|
OR A ; Low Speed?
|
|
JR Z,STMOD2 ; ..jump if So
|
|
INC L ; Else bump to 2 for Hi-Speed
|
|
LD A,(DRVSIZ)
|
|
SUB 2 ; 5.25" Hi-Density?
|
|
JR Z,STMOD2 ; ..jump if So pointing to 8"/5.25"HD
|
|
LD L,8+GAP3HD-FM5G3 ; Else Offset to 3.5" HD Gaps
|
|
JR STMOD4 ; ..and set SecSize
|
|
|
|
STMOD2: BIT 6,B ; MFM Set?
|
|
JR Z,STMOD3 ; ..jump if Not
|
|
SCF ; Else Set Carry if MFM
|
|
STMOD3: RL L ; Shift into LSB, Size * 2
|
|
ADD HL,HL
|
|
ADD HL,HL ; Size * 8, MFM * 4 (only 1 matters)
|
|
STMOD4: LD A,(RSZ)
|
|
LD (NBYTS),A ; save in Comnd Blk
|
|
OR A
|
|
PUSH AF
|
|
ADD A,L ; Add Sector Size to computation
|
|
LD L,A ; and Store
|
|
POP AF
|
|
LD A,129 ; (Prepare default)
|
|
JR Z,STMOD1 ; ..jump if 128-byte Sectors (DTL=128)
|
|
XOR A ; Else DTL is 0FFH (0-->FF)
|
|
STMOD1: DEC A ; Correct DTL Value
|
|
LD (DTL),A ; set
|
|
LD A,L ; Xfer index to A
|
|
LD HL,FM5G3-8 ; No low speed on 8"
|
|
CALL ADDAHL ; Index into gap 3 table
|
|
LD A,(HL)
|
|
LD (GPL),A ; store Gap Length
|
|
POP HL
|
|
POP BC
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; STSIZE (Function 1) - Set Drive Size (3.5", 5.25", 8"), Drive Speed
|
|
; (High/Low) Capability, and a Boolean flag for whether Motor Control is
|
|
; needed by the Drive.
|
|
;
|
|
; Enter : A = Hi Speed Flag ( 0 = Normal, 0FFH = High Speed Capable)
|
|
; D = Motor Flag (0 = No Motor Control, 0FFH = Motor needed)
|
|
; E = Drive Size (0 = Hard, 001 = 8", 010 = 5.25", 011 = 3.5")
|
|
; Return: Nothing
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STHDRV Called Previously. Call before calling STMODE.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
STSIZE: LD (DRVSPD),A ; Save Drive Speed Flag
|
|
OR A ; (set flag, 0=Normal, FF=Hi-Speed/Density)
|
|
LD A,E
|
|
LD (DRVSIZ),A ; Save Drive Size Byte
|
|
LD A,D
|
|
LD (FDMOT),A ; Set Drive Motor Needed flag
|
|
PUSH DE ; (Save Regs)
|
|
LD A,00000000B ; (Preset Hi 500 kbps, 3.5 & 5.25" Rate)
|
|
JR NZ,STSIZ2 ; ..jump if Hi-Density/Speed to Set
|
|
DEC E
|
|
DEC E ; 5.25" (010B -> 00)?
|
|
LD A,00000010B ; (Prepare for 250 kbps)
|
|
JR NZ,STSIZ2 ; ..jump if Not 5.25" w/Rate Set
|
|
PUSH HL
|
|
LD A,(HDR) ; Else use a routine from FLOPPY.Z80 to
|
|
CALL PHYSCL ; point to Physical Drive Byte (ICFG-xx)
|
|
BIT 6,(HL) ; Hi-Density capable?
|
|
POP HL
|
|
LD A,00000010B ; (Prepare for 250 kbps)
|
|
JR Z,STSIZ2 ; ..jump if No
|
|
LD A,00000001B ; Else set to 300 kbps (@360 rpm = 250kbps)
|
|
STSIZ2: OUT (DRR),A ; Set Rate in FDC Reg
|
|
LD D,A ; preserve Rate bits
|
|
IN0 A,(1FH) ; Read Cntrl Reg (B7=1 if Hi Speed)
|
|
RLA ; Speed to Bit Carry..Turbo?
|
|
LD A,(SPEED) ; (Get Processor Rate in MHz)
|
|
JR C,STSIZ8 ; ..jump if Turbo for longer delay
|
|
SRL A ; Else divide rate by 2
|
|
STSIZ8: INC D
|
|
DEC D ; 500 kb/s (Hi-Speed) Rate (D=0)?
|
|
JR NZ,STSIZ9 ; ..jump if Not
|
|
LD A,1 ; Else minimum delay for "High-Speed"
|
|
STSIZ9: LD (DLYCNT),A ; save delay count
|
|
POP DE
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; STHDRV (Function 2) - Set Head and Drive for Disk Operations.
|
|
;
|
|
; Enter : A = Unit # in D0-D1, Head in D2
|
|
; Return: Nothing
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
STHDRV: LD (HDR),A ; Save the Combined Head/Drive Byte
|
|
PUSH BC ; Save Regs
|
|
LD B,A ; and the HDR byte
|
|
SRL A ; Move
|
|
SRL A ; Head to B0
|
|
LD (HD),A ; and Save
|
|
LD A,(ACTIVE) ; Get current Activation Byte
|
|
IF FDDMA
|
|
AND 11111000B ; keep only motors and DMA Bit
|
|
ELSE
|
|
AND 11110000B ; If Polled, keep only motors
|
|
ENDIF
|
|
OR B ; add drive bit
|
|
POP BC ; Restore Regs
|
|
JP ACTIV8 ; ..exit saving new byte and activating FDC
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; STSECT (Function 3) - Set Sector Number, Sector Size and Last Sector #
|
|
;
|
|
; Enter : A = Physical Sector Number
|
|
; D = Sector Size (0=128, 1=256, 2=512, 3=1024)
|
|
; E = Last Physical Sector # on Side
|
|
; Return: Nothing
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
STSECT: LD (SECT),A ; Set Sector Number
|
|
LD A,D ; Get sector size
|
|
LD (RSZ),A ; save for commands
|
|
LD A,E ; Get last sector number
|
|
LD (EOT),A ; save in Command Block
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; SPEC (Function 4) - Do a Specify Command, setting Step Rate and Head
|
|
; Load/Unload Time. Values are rounded up if not even increments.
|
|
;
|
|
; Enter : A = Step Rate (in mS; Bit 7 = 1 for 8" drive
|
|
; D = Head Unload Time (in mS)
|
|
; E = Head Load Time (in mS)
|
|
; Return: Nothing
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STSIZE called previously to set DRVSPD variable.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
SPEC: PUSH BC ; Save Regs
|
|
PUSH DE
|
|
AND 7FH ; Strip 8" Bit from Step Rate
|
|
|
|
; At 250 kb/s MFM (125 kb/s FM), the times are doubled, so we must
|
|
; Divide the delays by two, else leave alone for 500 kb/s
|
|
|
|
LD B,A ; Save the Step Rate
|
|
LD A,(DRVSPD) ; Get Speed (Data Rate)
|
|
OR A ; High Speed?
|
|
LD A,B ; (restore Step Rate)
|
|
JR NZ,SPEC0 ; ..jump if 500 kb/s (High Density)
|
|
|
|
SRL A ; Divide Step Rate by 2
|
|
ADC A,0 ; round Up for partial
|
|
SRL D ; Divide Head Unload Time by 2
|
|
JR NC,SPEC11 ; ..jump if No Rounding Corr.
|
|
INC D
|
|
SPEC11: SRL E ; Divide Head Load Time by 2
|
|
JR NC,SPEC0 ; ..jump if No Rounding Corr.
|
|
INC E ; Else Round
|
|
SPEC0: NEG ; Get 2's Complement of Step Rate
|
|
AND 0FH ; mask
|
|
LD B,A ; (save)
|
|
LD A,D ; Get Head Unload Time in mS
|
|
ADD A,0FH ; force Rounding up
|
|
JR C,SPEC00 ; ..jump if Overflow to Max
|
|
AND 0F0H ; Keep Time MOD 16
|
|
JR NZ,SPEC3 ; ..jump if Not Zero
|
|
SPEC00: LD A,0F0H ; Else go to Maximum allowed
|
|
SPEC3: OR B ; Add in Step Rate
|
|
RLCA
|
|
RLCA
|
|
RLCA
|
|
RLCA ; Swap Nibbles
|
|
LD D,A ; put combined byte back in D
|
|
CALL WRDY ; Wait for RQM (hope DIO is Low!), retain Ints
|
|
LD A,03H ; Do an FDC Specify Command
|
|
OUT (DR),A
|
|
CALL WRDY
|
|
LD A,D ; first Rate Byte (Step Rate, HUT)
|
|
OUT (DR),A
|
|
CALL WRDY
|
|
LD A,E ; Get Head Load Time
|
|
ADD A,A ; Shift rate to B7..1
|
|
IF NOT FDDMA ; (Bit 0 = 0 for DMA)
|
|
OR 1 ; Insure Non-DMA Operation
|
|
ENDIF
|
|
OUT (DR),A
|
|
POP DE ; Restore Regs
|
|
POP BC
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; RECAL (Function 5) - Recalibrate Drive (moves heads to track 0).
|
|
;
|
|
; Enter : Nothing
|
|
; Return: A = 0 if Ok, NZ if Error. Flags reflect A
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;
|
|
; NOTE: BC Must be preserved by this routine.
|
|
; Assumes STHDRV, SPEC, STSIZE and STMODE called first.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
RECAL: LD A,3 ; Give this 3 chances to Home
|
|
RECAL1: LD (RETRYS),A
|
|
PUSH BC ; Save needed regs
|
|
LD BC,2*256+7 ; Two bytes, Recalibrate = 7
|
|
PUSH HL
|
|
CALL FDCMD ; execute Recalibrate
|
|
POP HL
|
|
IF NOT FDDMA
|
|
CALL FDCDN ; Clear Pending Ints, Wait for Seek Complete
|
|
AND 00010000B ; Homed? (B4=1 if No Trk0 found)
|
|
ENDIF
|
|
POP BC ; (restore regs)
|
|
JR Z,RECOK ; ..jump to Store if Ok
|
|
|
|
LD A,(RETRYS)
|
|
DEC A ; Any trys left?
|
|
JR NZ,RECAL1 ; ..loop if So
|
|
DEC A ; Else set Error Flag (0-->FF)
|
|
RET
|
|
|
|
RECOK: PUSH HL ; Save Regs
|
|
CALL IDXTRK ; Point to Current Drive in Track Array
|
|
XOR A ; get a Zero
|
|
LD (HL),A ; set Drive's Trk to 0
|
|
POP HL ; Restore regs
|
|
RET ; and return
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; SEEK (Function 6) - Set the Track for disk operations and seek to it.
|
|
;
|
|
; Enter : A = Desired Track Number
|
|
; D = Verify flag (0=No, FF=Yes)
|
|
; E = Double-step Flag (E <> 0 for Double-step)
|
|
; Return: A = 0, Zero Flag Set (Z) if Ok, A <> 0 Zero Clear (NZ) if Error
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STHDRV, SPEC, STSIZE and STMODE are called first.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
SEEK: LD (TTRK),A ; Save Track to Seek
|
|
PUSH HL ; Save Regs used here
|
|
PUSH DE
|
|
PUSH BC
|
|
|
|
CALL IDXTRK ; Point to Current Trk for Selected Drive
|
|
CP (HL) ; Is desired Track same as last logged?
|
|
JR NZ,SEEKNV ; ..jump if Not Same
|
|
INC D ; Else Set to No Verify (FF->0)
|
|
SEEKNV: LD A,E ; Get Double-step flag
|
|
LD (STEP2),A ; ..and save locally
|
|
|
|
LD A,(MXRTRY) ; Get the maximum Count
|
|
SEEK1: LD (RETRYS),A ; save remaining Retry Count
|
|
LD A,E
|
|
OR A ; Double Step?
|
|
LD A,(TTRK) ; Restore Track #
|
|
JR Z,SEEK2 ; ..jump if No Double Step
|
|
ADD A,A ; Else double Track #
|
|
SEEK2: LD (TRK),A ; Save the Track # in Comnd Block
|
|
LD BC,3*256+0FH ; (3-byte Seek Command = 0FH)
|
|
PUSH HL
|
|
CALL FDCMD ; Execute the Seek
|
|
POP HL
|
|
IF FDDMA
|
|
OR A ; Insure flags set
|
|
ELSE
|
|
CALL FDCDN ; Clear Pending Int, wait for Seek Complete
|
|
AND 01000000B ; Set NZ if Abnormal Termination
|
|
ENDIF
|
|
JR NZ,SEEKER ; ..jump if Error Seeking
|
|
INC D ; Are we Verifying (FF -> 0)?
|
|
DEC D ; (Correct for Test, 0 -> FF)
|
|
CALL NZ,READID ; Read next ID Mark if So
|
|
JR Z,SEEKX ; ..exit if Ok
|
|
|
|
SEEKER: LD A,(RETRYS) ; Else get trys remaining
|
|
DEC A ; Any left (80-track could need two)?
|
|
JR NZ,SEEK1 ; ..loop to try again if More
|
|
DEC A ; Else set Error Flag (0->FF)
|
|
SEEKX: LD E,A ; (Save status byte)
|
|
LD A,(TTRK)
|
|
LD (TRK),A ; Restore "Real" Track Number
|
|
JR NZ,SEEKXX ; ..jump if Error
|
|
LD (HL),A ; Else update Track in Index
|
|
SEEKXX: LD A,E ; Restore Status
|
|
OR A ; set flags
|
|
POP BC ; Restore Regs
|
|
POP DE
|
|
POP HL
|
|
RET
|
|
|
|
;.........................................................................
|
|
; Actual Read or Write
|
|
|
|
ACTRW: LD HL,(ACTDMA) ; Get actual DMA Addr
|
|
LD A,(RDOP)
|
|
OR A ; Read operation?
|
|
JR Z,SWRITE ; No, must be Write
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; SREAD (Function 7) - Read a Sector from the Floppy Disk. The Mode,
|
|
; Head/Drive, Track, and Sector must have already been set.
|
|
;
|
|
; Enter : HL --> Read Buffer
|
|
; Return: A = 0, Zero Set (Z) if Ok, A <> 0, Zero Clear (NZ) if Error.
|
|
; Uses : AF,HL. All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STMODE, STHDRV, STSECT, SPEC and SEEK Called First.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
SREAD: LD A,0110B ; Load 765 Read Command (06H)
|
|
IF FDDMA
|
|
PUSH AF ; Save Command
|
|
LD A,11001101B ; Set DMA Direction
|
|
; |||||||+- ?
|
|
; ||||||+-- MOD = Cycle Steal (ignored in I/O)
|
|
; ||||++--- Source = I/O (fixed)
|
|
; ||++----- Dest = Memory (Auto-Inc)
|
|
; ++------- ?
|
|
ENDIF
|
|
JR RW ; ..and continue below
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; SWRITE (Function 8) - Write a Sector to the Floppy Disk. The Mode,
|
|
; Head/Drive, Track, and Sector must have already been set.
|
|
;
|
|
; Enter : HL --> Write Buffer
|
|
; Return: A = 0, Zero Flag Set (Z) if Ok, A <> 0 Zero Clear (NZ) if Errors
|
|
; Uses : AF,HL. All other registers Preserved/Not Affected.
|
|
; Assumes STMODE, STHDRV, STSECT, SPEC and SEEK Called First.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
SWRITE: LD A,0101B ; Load 765 Write Command (05H)
|
|
IF FDDMA
|
|
PUSH AF ; Save Command
|
|
LD A,11110001B ; Set DMA Direction
|
|
; |||||||+- ?
|
|
; ||||||+-- MOD = Cycle Steal (ignored in I/O)
|
|
; ||||++--- Source = Memory (Auto-Inc)
|
|
; ||++----- Dest = I/O (fixed)
|
|
; ++------- ?
|
|
RW: OUT0 (DMODE),A ; Set DMA Channel #0 direction
|
|
POP AF ; restore Rd/Wr Comnd
|
|
ELSE
|
|
RW:
|
|
ENDIF ;fddma
|
|
PUSH BC ; Save Regs
|
|
PUSH DE
|
|
IF FDDMA
|
|
CALL SFDMA ; Set DMA Transfer Regs
|
|
LD HL,MODE ; Pt to Mode Flag
|
|
OR (HL) ; add to Command
|
|
ELSE
|
|
LD C,A ; (Save Command)
|
|
LD A,(MODE) ; Get Mode Flag
|
|
OR C ; add Read/Write Command to Mode Flag
|
|
ENDIF ;fddma
|
|
LD C,A ; to Reg
|
|
LD B,9 ; Read/Write Comnds are 9 bytes
|
|
|
|
LD A,(TSBSCF) ; Get Special Format Flag
|
|
OR A ; Special?
|
|
JR NZ,RW0 ; ..jump if Not
|
|
LD (HD),A ; Else Side 1 coded with Hd # 0
|
|
RW0: LD A,(RSZ) ; Get Sector Size Code
|
|
LD (NBYTS),A ; and Set in Comnd Blk
|
|
|
|
LD A,(EOT) ; Get Last Sctr #
|
|
PUSH AF ; (save for Exit)
|
|
LD A,(SECT) ; Get Desired Sector #
|
|
LD (EOT),A ; make last to Read only one Sector
|
|
|
|
PUSH HL
|
|
CALL FDCMD ; Execute Read/Write
|
|
POP HL
|
|
|
|
POP AF ; Restore Last Sctr #
|
|
LD (EOT),A ; to Comnd Blk
|
|
LD A,(ST1) ; Get Status Reg 1
|
|
AND 34H ; Return Any Error Bits
|
|
POP DE ; Restore Regs
|
|
POP BC
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; READID (Function 9) - Read the first Valid Address Mark on a track.
|
|
;
|
|
; Enter : Nothing
|
|
; Return: A = 0 if Ok, NZ if Error. Flags reflect A
|
|
; Uses : AF All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STHDRV, SPEC, STSIZE and STMODE called first.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
READID: LD A,(MODE) ; Get Command byte from block
|
|
OR 0AH ; or in Command
|
|
PUSH BC ; Save regs
|
|
LD B,2 ; two bytes in ReadID Command
|
|
LD C,A ; move Command to C
|
|
PUSH HL
|
|
CALL FDCMD ; Activate Controller
|
|
POP HL
|
|
LD A,(ST1) ; Get Status Reg 1
|
|
AND 25H ; Keep only Error Bits
|
|
POP BC ; Restore regs
|
|
RET ; ..and quit
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; RETDST (Function 10) - Return the status of a drive.
|
|
; This routine reports a "765" Controller type instead of actual number.
|
|
;
|
|
; Enter : Nothing
|
|
; Return: A = Status byte
|
|
; BC = 765 (FDC Controller Type)
|
|
; HL = Address of Status Byte
|
|
; Uses : AF,BC,HL All other Registers Preserved/Not Affected
|
|
;
|
|
; Assumes STHDRV called first
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
RETDST:
|
|
IF FDDMA
|
|
CALL WRDY ; Wait for RQM to be Set
|
|
LD A,0100B ; Load Return Drive Status Command (04H)
|
|
OUT0 (DR),A ; send to FDC
|
|
CALL WRDY
|
|
LD A,(HDR) ; Get Drive and Head
|
|
OUT (DR),A ; send it too
|
|
CALL FDCIN0 ; Read Stat at Command End
|
|
ELSE
|
|
LD BC,2*256+04H ; 2-byte Return Drive Status Command
|
|
CALL FDCMD
|
|
ENDIF ;fddma
|
|
LD HL,ST0 ; Point to Status Byte (Reg 3 contents)
|
|
LD A,(HL) ; fetch it
|
|
LD BC,765 ; load Controller ID
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; FMTTRK (Function 11) - Format a complete track on one side of a Floppy
|
|
; Disk. The Mode, Head/Drive, Track, and Sector must have been set.
|
|
;
|
|
; NOTE: The contents of the Format Data Block varies between controllers,
|
|
; so RETDST should be called to determine the controller type before
|
|
; setting up data structures.
|
|
;
|
|
; Enter : D = Formatting Sctrs/Track value
|
|
; E = Formatting Gap 3 Byte Count
|
|
; HL = Pointer to Controller-dependent Format Data block
|
|
; Return: A = 0, Zero Flag Set (Z) if Ok, A <> 0 Zero Clear (NZ) if Errors
|
|
; Uses : All Primary Registers
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
FMTTRK: PUSH DE ; Save for Later
|
|
IF FDDMA
|
|
LD A,11110001B ; Set DMA Direction
|
|
; |||||||+- ?
|
|
; ||||||+-- MOD = Cycle Steal (ignored in I/O)
|
|
; ||||++--- Source = Memory (Auto-Inc)
|
|
; ||++----- Dest = I/O (fixed)
|
|
; ++------- ?
|
|
OUT0 (DMODE),A ; Set DMA Channel #0 direction
|
|
LD A,(TPABNK) ; Format Data comes from TPA Bank
|
|
IF BANKED
|
|
RL H ; Eliminate the MSB of DMA Addr
|
|
ADC A,0 ; offset bank # by 32k banks
|
|
RRA ; shift Bank LSB to Carry
|
|
RR H ; Move Bank # LSB (Carry) to Address MSB
|
|
ENDIF ;banked
|
|
LD (FDMAB+2),A ; Set the Bank Value
|
|
LD (FDMAB),HL ; and DMA Address for Bank in DMA Comnd Block
|
|
LD HL,_DMA ; Get DMA IO Port addr
|
|
LD (FDMAB+3),HL ; place in DMA Comnd Block
|
|
XOR A
|
|
LD (FDMAB+5),A ; and Null out rest of Dest
|
|
CALL STFDMA ; Set DMA for Format
|
|
|
|
ELSE ;~fddma
|
|
IF BANKED
|
|
LD BC,(TPABNK) ; Get Source and Dest Banks
|
|
CALL XMOVE ; set them up
|
|
ENDIF
|
|
LD DE,HSTBUF ; Move the data to Host Buffer
|
|
LD BC,256 ; Two Sector's worth should be enough
|
|
CALL MOVE ; and move it
|
|
POP DE ; Restore SPT (D) and Gap3 (E)
|
|
ENDIF ;~fddma
|
|
LD A,(MODE)
|
|
OR 1101B ; set command to Format
|
|
LD C,A ; and place in Reg
|
|
LD HL,TRK
|
|
LD A,(RSZ)
|
|
LD (HL),A ; Place values in Command Block
|
|
INC HL
|
|
LD (HL),D
|
|
INC HL
|
|
LD (HL),E
|
|
INC HL
|
|
LD (HL),0E5H ; Set byte to write as Data
|
|
LD B,6 ; Six bytes in Format Command
|
|
IF NOT FDDMA
|
|
LD HL,HSTBUF
|
|
ENDIF
|
|
CALL FDCMD ; Execute !
|
|
LD A,(ST1) ; Get Status
|
|
AND 92H ; Return Error bits in A
|
|
RET
|
|
|
|
;=============================================================================
|
|
; FDCMD - Send Command to FDC
|
|
; Enter: B = # of Bytes in Command, C = Command Byte
|
|
; HL -> Buffer for Read/Write Data (If Needed)
|
|
; Exit : AF = Status byte
|
|
; Uses : AF,BC
|
|
|
|
FDCMD: PUSH HL ; save regs
|
|
CALL MOTOR ; Insure motors are On
|
|
LD HL,COMND ; Point to Command Block
|
|
LD (HL),C ; command passed in C
|
|
LD C,DR ; Set Data Port Addr
|
|
OTLOOP: CALL WRDY ; Wait for RQM (hoping DIO is Low) (No Ints)
|
|
OUTI ; Output Command bytes to FDC
|
|
JR NZ,OTLOOP ; ..loop til all bytes sent
|
|
|
|
POP HL ; Restore Transfer Addr
|
|
DI ; No Ints during IO to avoid data loss
|
|
FDCI1:
|
|
IF FDDMA
|
|
CALL FDCINT ; "Call" the Interrupt handler instead of Int
|
|
RET C ; ..quit if Timeout Error (C, A=FF)
|
|
LD A,(ST0) ; Else get first byte of Status
|
|
AND 0C0H ; check for Normal termination
|
|
RET ; ..return w/Error Flags set
|
|
ELSE
|
|
CALL WRDY
|
|
BIT 5,A ; In Execution Phase?
|
|
JR Z,FDCRES ; ..jump if Not to check result
|
|
BIT 6,A ; Write?
|
|
JR NZ,FDCI2 ; ..jump if Not to Read
|
|
OUTI ; Else Write a Byte from (HL) to (C)
|
|
JR FDCI1 ; and check for next
|
|
|
|
FDCI2: INI ; Read a byte from (C) to (HL)
|
|
JR FDCI1 ; and check for next
|
|
|
|
; Enter the Result Phase of the Command. Gather returned bytes
|
|
|
|
FDCRES: EI ; Interrupts Ok now if in Result Phase
|
|
LD HL,ST0 ; Point to Status Result area
|
|
ISGO: CALL WRDY
|
|
BIT 4,A ; End of Status/Result?
|
|
RET Z ; ..return if So
|
|
BIT 6,A ; Another byte Ready?
|
|
RET Z ; ..return if Not
|
|
INI ; Else Read Result/Status Byte
|
|
JR ISGO ; ..loop for next
|
|
|
|
;.....
|
|
; Check for Proper Termination of Seek/Recalibrate Actions by
|
|
; executing a Check Interrupt Command returning ST0 in A.
|
|
|
|
FDCDN: PUSH HL ; Don't alter regs
|
|
EI ; (Ints Ok Now)
|
|
FDCDN0: CALL WRDY ; Ready? (leave Ints alone)
|
|
LD A,08H ; Else Issue Sense Interrupt Status Comnd
|
|
OUT0 (DR),A
|
|
CALL WRDY
|
|
IN0 A,(DR) ; Get first Result Byte (ST0)
|
|
LD L,A
|
|
CP 80H ; Invalid Command?
|
|
JR Z,FDCDN0 ; ..jump to exit if So
|
|
CALL WRDY
|
|
IN0 A,(DR) ; Read Second Result Byte (Trk #)
|
|
LD A,L
|
|
BIT 5,A ; Command Complete?
|
|
JR Z,FDCDN0 ; ..loop if Not
|
|
POP HL
|
|
RET
|
|
ENDIF ;~fddma
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; MOTOR CONTROL. This routine performs final selection of the drive control
|
|
; latch and determines if the Motors are already spinning. If they are off
|
|
; and Motor control is needed, then the Motors are activated and the spinup
|
|
; delay time in tenths-of-seconds is performed before returning.
|
|
;
|
|
; Enter : Command byte in A
|
|
; Return: Head Delay bit set in Command in A if needed
|
|
; Uses : None. All Registers Preserved/Not Affected
|
|
|
|
MOTOR: PUSH AF ; Save Reg
|
|
LD A,(FDMOT)
|
|
OR A ; Need Motor?
|
|
JR Z,MOTORX ; ..jump to exit if Not
|
|
|
|
LD A,(MOTIM) ; Get remaining seconds
|
|
OR A ; Already On?
|
|
LD A,(MONTIM) ; (get Default On Time)
|
|
LD (MOTIM),A ; always reset
|
|
EI ; Insure Ints are Active
|
|
JR NZ,MOTORX ; ..exit if Motors On..they will stay On
|
|
|
|
LD A,(HDR) ; Get current Drive
|
|
IF FDDMA
|
|
OR 11111100B ; Set All Motors and DMA On, Cntrlr Active
|
|
ELSE
|
|
OR 11110100B ; Set All Motors On, DMA Off, Cntrlr Active
|
|
ENDIF
|
|
CALL ACTIV8 ; Do It!
|
|
LD A,(SPINUP) ; Get Spinup Time
|
|
LD (MTM),A ; to GP Counter
|
|
MOTOLP: LD A,(MTM)
|
|
OR A ; Up to Speed?
|
|
JR NZ,MOTOLP ; ..loop if Not
|
|
MOTORX: POP AF ; Restore Reg
|
|
RET
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Hardware-Dependent Host Read/Write Routine linked to from FLOPPY module.
|
|
; This routine Reads/Writes data from HSTBUF trying up to MXRTRY times
|
|
; before giving up. If an error occurs after the next-to-last try, the
|
|
; heads are homed to force a re-seek.
|
|
;
|
|
; Enter: (RDOP Set for desired operation)
|
|
; Exit : A = 0, Zero Set if Ok, A <> 0, Zero Reset if Errors
|
|
; Uses : AF,HL
|
|
;
|
|
; RDOP is set to 1 for Read, 0 for Write, TTRK set with desired Track
|
|
; number, STHDRV, STSECT, STMODE, SPEC all called previously.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
FHDRW: LD HL,HSTBUF ; Point to the host buffer
|
|
LD (ACTDMA),HL ; and set Memory Pointer
|
|
|
|
LD (FRWSTK),SP
|
|
LD SP,FRWSTK ; Use Local Stack
|
|
LD A,(MXRTRY) ; Get the maximum retry count
|
|
RWF2: LD (RWRTRY),A
|
|
PUSH DE ; (Save Regs)
|
|
LD A,(STEP2) ; Get double-Step flag
|
|
LD E,A
|
|
LD D,0FFH ; (Verify needed)
|
|
LD A,(TTRK) ; and track
|
|
CALL SEEK ; Try to seek to the desired track
|
|
POP DE ; (Restore Regs)
|
|
CALL Z,ACTRW ; Call R/W if Seek succeeded
|
|
LD (ERFLAG),A ; Save error code in any case
|
|
JR Z,FHDRX ; ..jump to return if No Errors
|
|
|
|
LD A,(RWRTRY) ; Get retry count
|
|
CP 2 ; Are we on Next to last try?
|
|
CALL Z,RECAL ; Return to Track 0 if so
|
|
LD A,(RWRTRY) ; and re-fetch try count
|
|
DEC A ; Do we have more retries left?
|
|
JR NZ,RWF2 ; ..jump to try again if more tries remain
|
|
|
|
CALL ERROR ; Else print Error Bios Message
|
|
FHDRX: LD SP,(FRWSTK) ; Restore Entry Stack
|
|
RET ; and Exit
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Gap 3 Length Table
|
|
; Index is: ((Drive_Factor * 8) + (MFM * 4) + RSZ) - 8
|
|
; Where Drive_Factor is based on Size and Speed as:
|
|
; 5.25"/3.5" Low Speed = 1
|
|
; 8" (Speed Ignored) = 2
|
|
; 3.5" High-Density Disks use special GAP3 Table, while 5.25" High-
|
|
; Density disks use 8" DD GAP3 values.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; 5.25"/3.5" Single-Density GAP3. 300 rpm, 125 kbps, FM
|
|
|
|
FM5G3: DEFB 7 ; 128
|
|
DEFB 5 ; 256
|
|
DEFB 20 ; 512
|
|
DEFB 27 ; 1024
|
|
|
|
; 5.25"/3.5" Double-Density GAP3. 300 rpm, 250 kbps, MFM
|
|
|
|
DEFB 0 ; 128
|
|
DEFB 9 ; 256
|
|
DEFB 13 ; 512
|
|
DEFB 27 ; 1024
|
|
|
|
; 8" Single-Density / 5.25" High-Speed GAP3. 360 rpm, 250 kbps, FM
|
|
|
|
DEFB 7 ; 128
|
|
DEFB 5 ; 256
|
|
DEFB 27 ; 512
|
|
DEFB 27 ; 1024
|
|
|
|
; 8" Double-Density / 5.25" High-Speed GAP3. 360 rpm, 500 kbps, MFM
|
|
|
|
GAP5HD: DEFB 0 ; 128
|
|
DEFB 15 ; 256
|
|
DEFB 11 ; 512
|
|
DEFB 17 ; 1024
|
|
|
|
; 3.5" Hi-Density GAP3. 300 rpm, 500 kbps, MFM
|
|
|
|
GAP3HD: DEFB 0 ; 128
|
|
DEFB 27 ; 256
|
|
DEFB 27 ; 512
|
|
DEFB 17 ; 1024 (27 if 10 spt)
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Error Printing Routine. This routine prints Error messages from the
|
|
; High-level Sector Read/Write routine when detected based on various
|
|
; parameters in the BIOS.
|
|
; Entering a Control-C after the message will cause a warm boot, anything
|
|
; else will ignore the error and return status to the caller.
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
ERROR:
|
|
IF BIOERM
|
|
PUSH BC
|
|
PUSH DE
|
|
CALL PRINT
|
|
DEFB BELL,CR,LF
|
|
DEFC 'FDC Error, U'
|
|
LD A,(HDR) ; Get unit number
|
|
AND 3
|
|
CALL PDEC ; ..in decimal
|
|
CALL PRINT
|
|
DEFC ' '
|
|
|
|
LD A,(COMND) ; Get the command byte
|
|
AND 3FH ; Else Mask Command
|
|
CP 0FH ; 765 type Seek?
|
|
JR NZ,ERR0 ; ..jump if Not
|
|
|
|
CALL PRINT
|
|
DEFC 'Seek'
|
|
JR ERR4
|
|
|
|
ERR0: CP 05H ; 765 type Write?
|
|
JR NZ,ERR1 ; ..jump if Not
|
|
CALL PRINT
|
|
DEFC 'Wr'
|
|
JR ERR4
|
|
|
|
ERR1: CP 06H ; 765 type Read?
|
|
JR NZ,ERR2 ; ..jump if Not
|
|
CALL PRINT
|
|
DEFC 'Rd'
|
|
JR ERR4
|
|
|
|
ERR2: CALL PRINT
|
|
DEFC 'Comnd = '
|
|
LD A,(COMND)
|
|
CALL PHEX
|
|
|
|
ERR4: CALL PRINT
|
|
DEFC ', '
|
|
LD HL,ST0 ; Point to Status Bytes
|
|
BIT 7,(HL) ; Abnormal Termination?
|
|
JR Z,ERR5
|
|
CALL PRINT
|
|
DEFC 'AT'
|
|
JR ERR13
|
|
|
|
ERR5: BIT 4,(HL) ; Equipment Check?
|
|
JR Z,ERR6
|
|
CALL PRINT
|
|
DEFC 'EC'
|
|
JR ERR13
|
|
|
|
ERR6: BIT 3,(HL) ; Not Ready?
|
|
JR Z,ERR7
|
|
CALL PRINT
|
|
DEFC 'NR'
|
|
JR ERR13
|
|
|
|
ERR7: INC HL ; Point to ST1
|
|
BIT 5,(HL) ; Data Error?
|
|
JR Z,ERR8
|
|
CALL PRINT
|
|
DEFC 'DE'
|
|
ERR8: BIT 2,(HL) ; No Data?
|
|
JR Z,ERR9
|
|
CALL PRINT
|
|
DEFC ' ND'
|
|
ERR9: BIT 1,(HL) ; Write Protect?
|
|
JR Z,ERR10
|
|
CALL PRINT
|
|
DEFC ' NW'
|
|
ERR10: BIT 0,(HL) ; Missing Address Mark?
|
|
JR Z,ERR11
|
|
CALL PRINT
|
|
DEFC ' MA'
|
|
ERR11: INC HL ; Point to ST2
|
|
BIT 4,(HL) ; Wrong Cylinder?
|
|
JR Z,ERR12
|
|
CALL PRINT
|
|
DEFC ' WC'
|
|
ERR12: CALL PRINT
|
|
DEFC ' (T='
|
|
LD A,(TTRK) ; Get Track (Cyl)
|
|
CALL PDEC ; Print cylinder (track)
|
|
CALL PRINT
|
|
DEFC ' H='
|
|
LD A,(HDR)
|
|
RRCA
|
|
RRCA
|
|
AND 0001B
|
|
CALL PDEC ; Print head
|
|
CALL PRINT
|
|
DEFC ' S='
|
|
LD A,(SECT)
|
|
CALL PDEC ; Print sector
|
|
CALL PRINT
|
|
DEFC ')'
|
|
|
|
ERR13: POP DE ; Restore Regs
|
|
POP BC
|
|
CALL CONIN ; Wait for any key
|
|
SUB 3 ; ^C (reboot)?
|
|
PUSH AF
|
|
CALL PRINT
|
|
DEFB CR,LF+80H ; Always echo crlf
|
|
POP AF
|
|
LD A,0FFH
|
|
RET NZ ; ..Return Bad Status if Not user abort
|
|
IF BANKED
|
|
JP ABORT
|
|
ELSE
|
|
RST 0 ; Vector thru loc 0 so wboot may be
|
|
ENDIF ; Intercepted by NZCOM, BGii, etc.
|
|
|
|
;.....
|
|
; Print value in A as a Decimal number (0-99)
|
|
|
|
PDEC: LD DE,10 ; We work in decimal
|
|
PD0: INC D
|
|
SUB E
|
|
JR NC,PD0
|
|
LD E,A
|
|
LD A,D
|
|
DEC A ; Is the first digit a Zero?
|
|
JR Z,PD1 ; ..jump if so and Don't Print
|
|
ADD A,'0'
|
|
CALL OUTCHR
|
|
PD1: LD A,E
|
|
ADD A,'0'+10
|
|
JR OUTCHR
|
|
|
|
;.....
|
|
; Print value in A as two Hex digits
|
|
|
|
PHEX: PUSH AF ; Print value in A as 2 Hex digits
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
CALL PHEX0
|
|
POP AF
|
|
PHEX0: AND 0FH
|
|
ADD A,90H
|
|
DAA
|
|
ADC A,40H
|
|
DAA
|
|
;..if Bioerm, fall thru to Outchr..
|
|
ELSE
|
|
OR 0FFH ; Insure NZ
|
|
RET
|
|
ENDIF ;Bioerm
|
|
|
|
OUTCHR: PUSH HL ; Print char in A to Console
|
|
PUSH DE
|
|
PUSH BC
|
|
LD C,A
|
|
CALL CONOUT
|
|
POP BC
|
|
POP DE
|
|
POP HL
|
|
RET
|
|
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Point to Last Track Storage Location for the Current Drive
|
|
; Enter: None
|
|
; Exit : HL -> Last track storage for this drive
|
|
; Uses : HL
|
|
|
|
IDXTRK: PUSH AF ; Save regs
|
|
LD A,(HDR) ; Get current drive/head
|
|
AND 0011B ; mask off head
|
|
LD HL,TRKARY ; Point to track storage block
|
|
CALL ADDAHL ; Point to the byte
|
|
POP AF ; restore regs
|
|
RET ; and return to caller
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Wait for FDC RQM to become Ready, and return DIO status in Zero Flag
|
|
; Pause before reading status port based on CPU Speed and Data Rate.
|
|
|
|
WRDY: LD A,(DLYCNT) ; Get computed delay count
|
|
WRDY0: DEC A ; Done?
|
|
JR NZ,WRDY0 ; ..loop if Not
|
|
WRDYL: IN A,(MSR) ; Read Main Status Register
|
|
BIT 7,A ; Interrupt Present?
|
|
RET NZ ; Return if So
|
|
JR WRDYL ; Else Loop
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; D M A S U P P O R T R O U T I N E S
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
IF FDDMA
|
|
; Set DMA Channel #0 for Format
|
|
|
|
STFDMA: PUSH AF ; Save regs
|
|
XOR A
|
|
OUT0 (DSTAT),A ; (No DMA or Interrupts)
|
|
LD L,D ; Get SPT value
|
|
LD H,0 ; extend to Word value
|
|
LD B,2 ; Multiply by 4 for Number of bytes
|
|
STDMA2: ADD HL,HL ; * 2
|
|
STDMA3: DJNZ STDMA2 ; ..looping til done
|
|
LD (FDMAB+6),HL ; Save Number of bytes to transfer
|
|
LD HL,FDMAB ; Point to DMA Control block
|
|
LD BC,8*256+SAR0L ; 8 bytes from (HL)..
|
|
OTIMR ; to DMA Ch #0 Registers
|
|
LD A,01100011B ; Enable DMA on Ch #0
|
|
; |||||||+- DME
|
|
; ||||||+-- ?
|
|
; ||||++--- DMA Ints (Ch1, Ch0)
|
|
; ||++----- Bit Write En * (Ch1, Ch0)
|
|
; ++------- DMA Enable (Ch1, Ch0)
|
|
OUT0 (DSTAT),A ; Command!
|
|
POP AF ; Restore regs
|
|
RET
|
|
|
|
;.....
|
|
; SFDMA - Set up DMA Channel #0 for Read/Write Operation.
|
|
; Number of sectors in Reg E is multiplied by Base Sector size to obtain
|
|
; the full number of bytes to transfer.
|
|
; Enter: HL -> Read/Write Buffer
|
|
; A = Read/Write Command
|
|
|
|
SFDMA: PUSH AF ; Save Rd/Wr Command
|
|
XOR A
|
|
OUT0 (DSTAT),A ; Disable DMA/DMA Ints
|
|
IF BANKED
|
|
LD A,(SYSBNK) ; Set System Bank #
|
|
ELSE
|
|
LD A,(TPABNK) ; If Not Banked, Load TPA Bank #
|
|
ENDIF
|
|
RL H ; Place Address MSB in Carry
|
|
ADC A,0 ; offset Bank # by 32k banks
|
|
RRA ; shift Bank LSB to Carry
|
|
RR H ; Move Bank # LSB (Carry) to Addr MSB
|
|
LD C,A ; Save Bank #
|
|
LD DE,_DMA ; Get Floppy DMA IO Port Address
|
|
LD B,0 ; and Dummy Bank #
|
|
POP AF
|
|
PUSH AF ; Restore Rd/Wr Command
|
|
AND 00001111B ; keeping only low nibble
|
|
CP 0101B ; Write?
|
|
JR Z,SFDMA0 ; ..jump if So; CHL = Source, BDE = Dest
|
|
EX DE,HL ; Else
|
|
LD A,B ; Swap Source
|
|
LD B,C ; w/Dest
|
|
LD C,A
|
|
SFDMA0: LD (FDMAB),HL ; Save Source
|
|
LD A,C ; in Block
|
|
LD (FDMAB+2),A
|
|
LD (FDMAB+3),DE ; and Dest
|
|
LD A,B
|
|
LD (FDMAB+5),A
|
|
LD HL,0080H ; Set 1 Logical Sector Size for Calcs
|
|
LD A,(RSZ) ; Get Physical Sector Size (in 128-byte recs)
|
|
LD B,A
|
|
INC B ; (compensate for first DJNZ)
|
|
JR STDMA3 ; ..compute, set and activate
|
|
ENDIF ;fddma
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; FDCINT - Used in the P112 as a polled routine in default configuration
|
|
; with Interrupts disabled. This code is assembled if the FDDMA equate
|
|
; is set TRUE. If your system uses Interrupts, add any additional code
|
|
; to save Stack pointer and AF, and insure that it is in the CODE segment.
|
|
; NOTE: that the service routine MUST be in the Common Memory if Interrupts
|
|
; (instead of polling ) are used to prevent problems when banked.
|
|
;
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
;;-- CSEG <Place the following in CSEG if "TRUE" Interrupts used>
|
|
IF FDDMA
|
|
FDCINT: ; Set local stack if Needed, Disable Interrupts for local calls
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD BC,0000 ; Inner loop timeout
|
|
LD D,30 ; Outer loop timeout
|
|
LD HL,ST0 ; Point to Status Area
|
|
Int00: IN0 A,(DRC) ; Read Port C
|
|
BIT 6,A ; Int1* active?
|
|
JR Z,Int01 ; ..jump if So
|
|
DEC BC ; Else count down
|
|
LD A,B
|
|
OR C
|
|
JR NZ,Int00 ; ..loop if Not timed out
|
|
DEC D ; Outer loop done?
|
|
JR NZ,Int00 ; ..loop if Not
|
|
SUB 1 ; Else set Carry, A=FF
|
|
LD (ST1),A ; Save Bad Status
|
|
CALL FDRst ; Reset the Controller
|
|
JR Int0X ; ..and Quit
|
|
|
|
Int01: LD BC,DR ; Else Point BC to Data Port
|
|
CALL WRDYw0
|
|
JR C,Int03 ; ..jump if Timeout
|
|
Int02: CALL WRDY
|
|
BIT 6,A ; Result phase over?
|
|
JR Z,Int03 ; ..jump if So to Exit
|
|
INI ; Read a byte from (C) to (HL)
|
|
INC B ; (correct B for above dec)
|
|
JR Int02 ; and check for next
|
|
|
|
Int03: CALL WRDY
|
|
LD A,08H ; Sense Interrupt Status Comnd
|
|
OUT (DR),A
|
|
CALL WRDY
|
|
IN A,(DR) ; Get first Result Byte (ST0)
|
|
CP 80H ; Invalid Command?
|
|
JR Z,Int0X ; ..jump to exit if So
|
|
LD (ST0),A ; Else save Status Byte 0
|
|
CALL WRDY
|
|
IN A,(DR) ; Read Second Result Byte (Trk #)
|
|
JR Int03 ; ..and loop
|
|
|
|
Int0X: POP HL ; Restore Regs
|
|
POP DE
|
|
POP BC
|
|
; Restore Stack if Needed
|
|
EI ; Insure Interrupts are Enabled
|
|
RET
|
|
|
|
;.....
|
|
; Alternate entry for code that generates no "Interrupt"
|
|
|
|
FDCIN0: PUSH BC ; Save regs
|
|
PUSH DE
|
|
PUSH HL
|
|
LD HL,ST0 ; Put Status bytes here
|
|
JR Int01 ; ..and continue mainline code
|
|
ENDIF ;fddma
|
|
|
|
; Wait for Interrupt maintaining watchdog timer
|
|
|
|
WRDYw0: PUSH BC ; Save Regs
|
|
LD BC,0 ; Set Maximum count
|
|
WRDYw1: IN A,(MSR) ; Get Status
|
|
RLA ; Int bit to Carry
|
|
JR C,WRDYw2 ; ..quit if Int
|
|
DEC BC ; Else count down
|
|
LD A,B
|
|
OR C ; Timed Out?
|
|
JR NZ,WRDYw1 ; ..loop if Not
|
|
CALL FDRst ; Else Reset Controller
|
|
WRDYw2: CCF ; Set Carry appropriately
|
|
POP BC ; restore regs
|
|
RET
|
|
|
|
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
CSEG ;*** Remainder of Code MUST be in Main Memory ***
|
|
|
|
;========================================================================
|
|
; Reset the Floppy Disk Controller. Called from CBOOT in case of Hard
|
|
; Disk Boot which leaves the controller in a "hung" state, and locally
|
|
; if the Controller times out (often due to changing diskettes).
|
|
|
|
FDRst: PUSH AF ; Save any status
|
|
XOR A
|
|
OUT (DCR),A ; Place Controller in Reset state
|
|
LD A,(ACTIVE) ; get current settings
|
|
AND 0FCH ; keep only motors, DMA and Ready
|
|
OUT (DCR),A ; and Restore
|
|
POP AF ; Restore Status
|
|
RET
|
|
|
|
;========================================================================
|
|
; Motor Off routine. Called from TIM-DX and SELFLP2 which forces
|
|
; Motors/Timer to be Off state so spinup delay is forced on next selection.
|
|
|
|
;;ChgSpd: ; <<-- Required label for SELFLP2. Activate
|
|
; label here if switching motor speed
|
|
MOTOFF: XOR A
|
|
LD (MOTIM),A ; Insure Motors Timed Out and show OFF
|
|
LD A,(ACTIVE) ; Get current settings
|
|
IF FDDMA ;
|
|
AND 00001111B ; strip of Motor bits
|
|
ELSE
|
|
AND 00000111B ; strip off Motor bits and DMA
|
|
ENDIF
|
|
ACTIV8: OR 00000100B ; (insure FDC out of Reset)
|
|
LD (ACTIVE),A ; save
|
|
OUT (DCR),A ; and Command!
|
|
ChgSpd: RET ; <<-- Activate label here if using 300 kb
|
|
; for constant 360 rpm on 5.25" Drives
|
|
|
|
;======================== RAM Storage Area ==============================
|
|
|
|
IF BANKED
|
|
COMMON /B2RAM/ ; If banked, Local stack in Bank
|
|
ELSE
|
|
DSEG ; ..otherwise in Data Segment
|
|
ENDIF ;
|
|
|
|
DEFS 30 ; Bios R/W Entry 15-level Local Stack
|
|
FRWSTK: DEFS 2 ; Storage for Entry Stack Pointer
|
|
|
|
DSEG ; Place in Common memory
|
|
|
|
; Add storage for DMA Control Block if using DMA Transfers
|
|
IF FDDMA
|
|
FDMAB: DEFS 2 ; Source Addr (16-bits)
|
|
DEFS 1 ; Source Bank
|
|
DEFS 2 ; Dest Addr (16-bits)
|
|
DEFS 1 ; Dest Bank
|
|
DEFS 2 ; Byte Count of transfer
|
|
ENDIF ;fddma
|
|
|
|
; NOTE: Variables listed as (** Global **) are accessed by other modules and
|
|
; MUST exist as defined.
|
|
|
|
COMND: DEFS 1 ; Storage for Command in execution
|
|
HDR: DEFS 1 ; Head (B2), Drive (B0,1) (** Global **)
|
|
TRK: DEFS 1 ; Track (t)
|
|
HD: DEFS 1 ; Head # (h)
|
|
SECT: DEFS 1 ; Physical Sector Number
|
|
NBYTS: DEFS 1 ; Bytes/Sector (n)
|
|
EOT: DEFS 1 ; End-of-Track Sect #
|
|
GPL: DEFS 1 ; Gap Length
|
|
DTL: DEFS 1 ; Data Length
|
|
|
|
RSZ: DEFS 1 ; Bytes/Sector. Must be placed outside of the
|
|
; Comnd Blk for FMTTRK to work.
|
|
; FDC Operation Result Storage Area
|
|
|
|
ST0: DEFS 1 ; Status Byte 0
|
|
ST1: DEFS 1 ; Status Byte 1 (can also be PCN)
|
|
ST2: DEFS 1 ; Status Byte 2
|
|
RC: DEFS 1 ; Track # (** Global **)
|
|
RH: DEFS 1 ; Head # (0/1)
|
|
RR: DEFS 1 ; Sector # (** Global **)
|
|
RN: DEFS 1 ; Sector Size (** Global **)
|
|
|
|
ACTDMA: DEFS 2 ; 16-bit DMA Address
|
|
|
|
;-->>> Do NOT re-order the following two bytes !! <<<--
|
|
|
|
MTM: DEFS 1 ; Floppy Time down-counter
|
|
MOTIM: DEFS 1 ; Motor On Time Counter
|
|
|
|
; DISK Subsystem Variable Storage
|
|
|
|
FDMOT: DEFS 1 ; Motor on required flag
|
|
RDOP: DEFS 1 ; Read/write flag
|
|
RETRYS: DEFS 1 ; Number of times to try Opns
|
|
RWRTRY: DEFS 1 ; Number of read/write tries
|
|
DRVSPD: DEFS 1 ; Drive Speed
|
|
DRVSIZ: DEFS 1 ; Drive Size
|
|
STEP2: DEFS 1 ; <> 0 for Double Step (** Global **)
|
|
MODE: DEFS 1 ; Bit 6 = 1 if MFM, 0 = FM
|
|
ACTIVE: DEFS 1 ; Current bits written to Dev Contr Reg (DCR)
|
|
DLYCNT: DEFS 1 ; Delay value reading Main Status Reg
|
|
FSPT: DEFS 1 ; Format Sectors/Track value
|
|
TSBSCF: DEFS 1 ; 0=Hd always 0 (TSBSC) (** Global **)
|
|
|
|
TTRK: DEFS 1 ; Storage for Track (** Global **)
|
|
TRKARY: DEFS 4 ; Track storage locations for four drives
|
|
|
|
;=========================== End of FDC-DX ==============================
|
|
|