From e5d42b8dd840b920e980a523c22974b94e8ce6b6 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 26 Aug 2018 16:07:25 +0100 Subject: [PATCH] 9266 fdc driver for RBC style systems Could do with the data loops optimizing a bit more. They should be good for high density at 6MHz but we ought to be able to do HD at 4Mhz with some loop unrolling and repeat check tricks. --- Kernel/dev/rbcfd9266_hw.s | 705 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 705 insertions(+) create mode 100644 Kernel/dev/rbcfd9266_hw.s diff --git a/Kernel/dev/rbcfd9266_hw.s b/Kernel/dev/rbcfd9266_hw.s new file mode 100644 index 00000000..35591a51 --- /dev/null +++ b/Kernel/dev/rbcfd9266_hw.s @@ -0,0 +1,705 @@ +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; D-X Designs Pty Ltd P112 Floppy disk Routines +; Copyright (C) 1998 by Harold F. Bower +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; 2015-01-17 Will Sowerbutts: Ported to sdas/Fuzix from UZI-180 +; 2017-01-21 Will Sowerbutts: Improvements for reliable operation at 6MHz +; +; Reworked a bit for the FDC9266 and latch on the RBC/N8VEM hardware + + .module devfd_hw + +CPU_Z180 .equ Z80_TYPE-2 +.ifeq CPU_Z180 + .z180 +.endif + + ; imported symbols + .globl map_kernel + .globl map_process_always + .globl _devfd_dtbl + .globl _platform_idle + + ; exported sybols + .globl _devfd_init + .globl _devfd_read + .globl _devfd_write + .globl _devfd_track + .globl _devfd_sector + .globl _devfd_error + .globl _devfd_buffer + .globl _devfd_userbuf + .globl _fd_tick + + .include "../platform/kernel.def" + .include "../kernel.def" + + +;------------------------------------------------------------------------------ + .area _CODE + +; FDC_MSR - 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 +; +; FDC_DATA - Data/Command Register (Read/Write) +; (Byte Writes/Reads) +; +; FDC_DOR (write) - Latch +; 7 6 5 4 3 2 1 0 +; | | | | | | | +------- TC +; | | | | | | +---------- 1 = Motor on +; | | | | | +------------ 1 = 3.5/5.25" disk 2 = 8" (or high density) +; | | +-+-+-------------- P2-P0 (Precomp - set 125ns 100) +; | +-------------------- 1 = high density 0 = low density +; +---------------------- 1 = active, 0 = in reset +; +; FDC_DOR (read) +; 7 6 5 4 3 2 1 0 +; | | | | | | | +-------- DC +; +-+-+-+-+-+-+---------- 0 +; +;------------------------------------------------------------- +MONTIM .equ 250 ; Motor On time (Seconds * TICKSPERSEC) + +; Offsets into _devfd_dtbl +oFLG .equ 0 ; logged: 0 = Not Logged, 1 = Drive Logged +oPRM1 .equ 1 ; cbyte0: Step Rate (B7-4), HUT (3-0) +oPRM2 .equ 2 ; cbyte1: Hd Load in 4mS steps (0=infinite) +oGAP3 .equ 3 ; gap3: Gap 3 Length for Read +oSPT .equ 4 ; spt: Sectors-per-Track +oSEC1 .equ 5 ; sector1: First Sector Number +oFMT .equ 6 ; format: Bit-mapped Format byte +oSPIN .equ 7 ; spinup: Spinup delay (1/20-secs) +oTRK .equ 8 ; curtrk: Current Head Position (Track) +oNCYL .equ 9 ; ncyl: Number of cylinders +TBLSIZ .equ 10 ; sizeof() entry in _devfd_dtbl + +;------------------------------------------------------------- +; Determine if the controller exists and a drive is attached +; fdInit (int minor); +; Enter: Drive Minor # is on Stack +; Exit : HL = 0 if All is Ok, Non-Zero if Error + +_devfd_init: + XOR A + LD (motim),A ; Mark Motors as initially OFF + LD (hd),A ; and initially Head #0 + + LD A, #0x20 ; increase delay time for init + LD (dlyCnt),A + + POP HL ; Return Addr + POP BC ; minor (in C) + PUSH BC ; Keep on Stack for Exit + PUSH HL + PUSH IY ; Must be saved for the C caller + LD A,C + LD (drive),A ; Save Desired Device + CP #4 ; Legal? + JR NC,NoDrv ; ..Exit if Error + CALL ActivA ; Else force Reset (B2=0) + LD B,#0 +indel1: DJNZ indel1 ; (settle) + CALL Activ8 ; then bring out of Reset +indel2: DJNZ indel2 ; (settle, B already =0) + IN A,(FDC_MSR) + CP #0x80 ; Do we have correct Ready Status? + JR NZ,NoDrv ; ..exit Error if Not + + LD A,(drive) + CALL GetPrm ; Pt to this drive's table entry + PUSH HL + POP IY + LD oFLG(IY), #0 ; Ensure drive is Unlogged + CALL Spec ; Set Controller Params + JR C,NoDrv ; ..Error if TimeOut, Else.. + CALL Recal ; Recalibrate (home) Drive + JR NZ,NoDrv ; ..Error if it failed + LD oFLG(IY), #1 ; Mark drive as active + LD HL,#0 ; Load Ok Status + POP IY + RET + +NoDrv: LD HL,#0xFFFF ; Set Error Status + POP IY + RET + +;------------------------------------------------------------- +; This routine Reads/Writes data from buffer trying up to 15 times +; before giving up. If an error occurs after the next-to-last +; try, the heads are homed to force a re-seek. +; +; Enter: Drive Minor # is on Stack. Entry Point sets Read/Write Flag +; Exit : A = 0, Zero Set if Ok, A <> 0, Zero Reset if Errors +; (also returns H = 0 and L set to A for compatibilty with C code) +; Uses : AF,HL + +_devfd_read: + LD A,#1 + .db 0x21 ;..Trash HL, fall thru.. +_devfd_write: + LD A,#0 ; has to be two bytes -- do not optimise to xor a! + LD (rdOp),A + + POP HL ; Return Addr + POP BC ; minor (->C) + PUSH BC ; Keep on Stack for Exit + PUSH HL + + PUSH IY + + LD A,C + LD (drive),A ; Save Desired Device + + CALL Setup ; Set up subsystem + + LD A,#15 ; Get the maximum retry count +Rwf1: LD (rwRtry),A + LD D,#0xFF ; (Verify needed) + CALL SEEK ; Try to seek to the desired track + JR NZ,Rwf2 ; ..jump if No Good + + LD A,(rdOp) + OR A ; Read operation? + LD A,#0x05 ; Load DP8473 Write Command + JR Z,SWrite ; No, must be Write + INC A ; (A=06H) Load DP8473 Read Command +SWrite: OR #0x40 ; Set MFM Mode Bit + PUSH BC ; Save Regs + LD C,A ; Save + LD B,#9 ; Read/Write Comnds are 9 bytes + + 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 + + ld hl,(_devfd_buffer) + CALL FdCmd ; Execute Read/Write + + POP AF ; Restore Last Sctr # + LD (eot),A ; to Comnd Blk + + LD A,(st1) ; Get Status Reg 1 + AND #0x34 ; Return Any Error Bits + POP BC ; Restore Regs + LD (_devfd_error),A ; (store Error bits) + JR Z,FhdrX ; ..jump to return if No Errors + +Rwf2: 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,Rwf1 ; ..jump to try again if more tries remain + + OR #0xFF ; Else show Error +FhdrX: LD L,A + LD H,#0 + POP IY + RET ; and Exit + +;------------------------------------------------------------- +; SPEC - Do a Specify Command, setting Step Rate and Head +; Load/Unload Time. Settings require tailoring to Drive. +; +; Enter: IY -> Drive Table entry for current drive +; Exit : Nothing +; Uses : AF,BC + +Spec: CALL WRdyT ; Wait for RQM (hope DIO is Low!), Disable Ints + RET C ; ..Error if Timed Out + LD A,#0x03 ; Do an FDC Specify Command + OUT (FDC_DATA),A + + CALL WRdyT + RET C ; ..Error if Timed Out + LD A,oPRM1(IY) ; first Rate Byte (Step Rate, HUT) + OUT (FDC_DATA),A + + CALL WRdyT + RET C ; ..Error if Timed Out + LD A,oPRM2(IY) ; Get Head Load Time + ADD A,A ; Shift value left (doubles count) + INC A ; Set LSB for Non-DMA Operation + OUT (FDC_DATA),A + XOR A ; Return Ok Flag + RET + +;------------------------------------------------------------- +; RECAL Recalibrate Current "drive" (moves heads to track 0). +; Enter : IY -> Current Drive Table Entry +; Variable "drive" set to desired floppy unit +; 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. + +Recal: LD A,(hd) ; Get head # + ADD A,A + ADD A,A ; Shift to B3 + PUSH HL ; (preserve regs) + LD HL,#drive + OR (HL) ; add Drive bits + POP HL ; (restore regs) + + LD (hdr),A ; in Command Block + LD A,#3 ; Give this 3 chances to Home +Recal1: LD (retrys),A + PUSH BC ; Save needed regs + PUSH HL + LD BC,#(2*256+7) ; (2-byte Recalibrate Comnd = 07H) + CALL FdCmd ; execute Recalibrate + CALL FdcDn ; Clear Pending Ints, Wait for Seek Complete + POP HL ; (restore regs) + POP BC + AND #0x10 ; Homed? (B4=1 if No Trk0 found) + 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: XOR A ; Get a Zero (track / flag) + LD oTRK(IY),A ; Set in Table + RET ; and return + +;------------------------------------------------------------- +; READID - Read the first Valid Address Mark on a track. +; +; Enter : "hdr" byte set in Command Blk +; Return: A = 0 if Ok, NZ if Error. Flags reflect A +; Uses : AF All other Registers Preserved/Not Affected + +ReadID: LD A,#0x4a ; Load ReadID Command + MFM Mode byte + PUSH BC ; Save regs + LD B,#2 ; two bytes in ReadID Command + LD C,A ; move Command to C + CALL FdCmd ; Activate DP8473 FDC + + LD A,(st1) ; Get Status Reg 1 + AND #0x25 ; Return Any Error Bits + POP BC ; Restore regs + RET ; ..and quit + +;------------------------------------------------------------- +; SETUP - Set parameters necessary to Read/Write from Active Drive +; Enter: Variable "drive" set to current Drive (0..3) +; Variables _devfd_track and _devfd_sector set to desired block address +; Exit : IY -> Drive's Table entry +; Uses : AF,BC,HL + +Setup: LD A,(drive) + PUSH AF + CALL GetPrm ; Pt to Current Drive's Table + PUSH HL + POP IY + POP BC + LD A,(active) ; Get current Activation Byte + AND #0x80 ; keep reset bit + OR #0x20 ; 125ns precomp + PUSH AF ; Save the work so far +; CALL Activ8 ; save new byte and activate FDC + LD A,(_devfd_track) ; Get Host Track # + SRL A ; Div by 2 (LSB to Carry) + LD (trk),A ; Physical Track # to Comnd Blk + LD A,#0 + ADC A,A ; LSB becomes Head # + LD (hd),A ; save in Comnd Blk + ADD A,A + ADD A,A ; Shift to B3 + LD HL,#drive + OR (HL) ; add Drive bits + LD (hdr),A ; Save in Comnd Blk + LD A,oGAP3(IY) + LD (gpl),A ; Set Gap3 Length + LD A,oSPT(IY) + LD (eot),A ; Final Sector # on Trk + LD A,oFMT(IY) + AND #3 ; B0/1 of Format byte is Sector Size + LD (rsz),A ; save in Comnd Blk + LD A,#0xFF + LD (dtl),A ; Set Data Length code + LD A,(_devfd_sector) + ADD A,oSEC1(IY) ; Offset Sector # (base 0) by 1st Sector # + LD (sect),A ; set in Comnd Blk + XOR A ; (Preset Hi 500 kbps, 3.5 & 5.25" Rate) + BIT 7,oFMT(IY) ; Hi (500 kbps) Speed? + JR NZ,StSiz0 ; ..jump if Hi-Density/Speed to Set if Yes + LD A,oFMT(IY) + AND #0x0c ; Else Get Drive size + CP #0x08 ; 5.25"? + LD A,#0x44 ; (Prepare for 250 kbps) + JR NZ,StSiz0 ; ..jump if Not 5.25" w/Rate Set + BIT 4,oFMT(IY) ; Hi-Density capable drive? + LD A,#0x44 ; (Prepare for 250 kbps) + JR Z,StSiz0 ; ..jump if No + LD A,#0x44 ; Else set to 300 kbps (@360 rpm = 250kbps) + ; Mini, high density. +StSiz0: + POP BC ; Get bits back + OR B ; Merge in the rates + CALL Activ8 ; Set them all + + LD D,A ; preserve Rate bits +.ifeq CPU_Z180 + IN0 A,(0x1F) ; Read Z80182 CPU Cntrl Reg (B7=1 if Hi Speed) + RLA ; Speed to Bit Carry..Turbo? + LD A,#(CPU_CLOCK_KHZ/1000) ; (Get Processor Rate in MHz) + JR C,StSiz1 ; ..jump if Turbo for longer delay +.else + LD A,#(CPU_CLOCK_KHZ/1000) ; (Get Processor Rate in MHz) +.endif + SRL A ; Divide rate by 2 +StSiz1: BIT 2,D ; 500 kb/s (Hi-Speed) Rate (D=0)? + JR NZ,StSiz2 ; ..jump if Not + LD A,#1 ; Else minimum delay for "High-Speed" +StSiz2: LD (dlyCnt),A ; save delay count + RET + +;------------------------------------------------------------- +; SEEK - Set the Track for disk operations and seek to it. +; +; Enter : A = Desired Track Number +; D = Verify flag (0=No, FF=Yes) +; Return: A = 0, Zero Flag Set (Z) if Ok, A <> 0 Zero Clear (NZ) if Error +; Uses : AF All other Registers Preserved/Not Affected + +SEEK: PUSH HL ; Save Regs used here + PUSH DE + PUSH BC + + LD A,(trk) ; Get Track # + CP oTRK(IY) ; Is desired Track same as last logged? + LD oTRK(IY),A ; (set as if we made it there) + JR NZ,SEEKNV ; ..jump if Not Same + INC D ; Else Set to No Verify (FF->0) +SEEKNV: LD A,#4 ; Get the maximum Retry Count +SEEK1: LD (retrys),A ; save remaining Retry Count + LD BC,#(3*256+0x0F); (3-byte Seek Command = 0FH) + CALL FdCmd ; Execute the Seek + CALL FdcDn ; Clear Pending Int, wait for Seek Complete + + AND #0xE0 + CP #0x20 + JR NZ,SEEK2 ;; + + AND #0x40 ; Set NZ if Abnormal Termination + + LD B,A ;; Save Seek Status + LD A,(trk) ;; Check track # + CP C ;; Same track? + JR NZ,SEEK2 ;; Jump to Retry if NOT + LD A,B ;; Restore Seek Status + + INC D ; Are we Verifying (FF -> 0)? + CALL Z,ReadID ; Read next ID Mark if So + DEC D ; (Correct for Test, 0 -> FF) + + OR A ; Set Status (Seek Status if No ReadID) + JR Z,SEEKX ; ..exit if Ok + +SEEK2: 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: POP BC ; Restore Regs + POP DE + POP HL + RET + + +;------------------------------------------------------------- +; Check for Proper Termination of Seek/Recalibrate Actions by +; executing a Check Interrupt Command returning ST0 in A. +; Enter: None. Used after Seek/Recalibrate Commands +; Exit : A = ST0 Result Byte, C = PCN result byte +; Uses : AF and C. All other registers preserved/unused + +FdcDn: PUSH HL ; Don't alter regs +FdcDn0: CALL WRdy1 + LD A,#8 ; Sense Interrupt Status Comnd + OUT (FDC_DATA),A + CALL WRdy1 + IN A,(FDC_DATA) ; Get first Result Byte (ST0) + LD L,A + CP #0x80 ; Invalid Command? + JR Z,FdcDn0 ; ..jump to exit if So + CALL WRdy1 + IN A,(FDC_DATA) ; Read Second Result Byte (Trk #) + LD C,A ; ..into C + LD A,L + BIT 5,A ; Command Complete? + JR Z,FdcDn0 ; ..loop if Not + POP HL + RET + +;------------------------------------------------------------- +; MOTOR CONTROL. This routine performs final selection of +; the drive control latch and determines if the Motors are +; already spinning. If they are off, then the Motors are +; activated and the spinup delay time in tenths-of-seconds +; is performed before returning. +; +; Enter : None +; Return: None +; Uses : HL. Remaining Registers Preserved/Not Affected + +Motor: PUSH AF ; Save Regs + PUSH BC + LD A,#MONTIM ; Get motor timeout + LD (motim),A ; Reset the countdown timer + LD A,(active) ; Load current DOR contents + BIT 1,A ; Check motor on ? + JR NZ,MotorX ; If so no wait + OR #2 ; Motor on + CALL Activ8 ; Send to FDC DOR, update active + ; TODO this is a busy loop -- we should set a timer and yield + LD A,(drive) ; Get Current drive + CALL GetPrm ; Pt to Param table + LD BC,#oSPIN + ADD HL,BC ; offset to Spinup Delay + LD A,(HL) ; Get value + LD (mtm),A ; to GP Counter + EI ; Ensure Ints are ABSOLUTELY Active.. +; +; FIXME: this is wrong on two levels +; #1 We shouldn't rely upon an IRQ (we can busy wait too) +; #2 The timers are set in 1/20ths but it's not clear everyone is +; using 1/20ths for the IRQ call (See p112) +; +MotoLp: PUSH DE + CALL _platform_idle + POP DE + LD A,(mtm) ; ..otherwise, loop never times out! + OR A ; Up to Speed? + JR NZ,MotoLp ; ..loop if Not + DI ; No Ints now.. +MotorX: POP BC + POP AF ; Restore Reg + RET + +;------------------------------------------------------------- +; Wait for FDC RQM to become Ready with Timeout indicator. +; Timeout Length is arbitrary and depends on CPU Clock Rate. + +WRdyT: ;DI ; No Ints while we are doing I/O + LD BC,#30000 ; << Arbitrary >> +WRdyT0: DEC BC + LD A,B + OR C ; Timed Out? + SCF ; (set Error Flag in case) + RET Z ; ..return Error Flag if Yes + IN A,(FDC_MSR) ; Read Status Reg + AND #0x80 ; Interrupt Present (also kill Carry)? + RET NZ ; ..return Ok if Yes + JR WRdyT0 ; ..else loop to try again + +;------------------------------------------------------------- +; Return Pointer to Parameters of selected Drive +; Enter: A = Drive (0..3) +; Exit : HL -> Parameter entry of drive +; Uses : AF,HL + +GetPrm: PUSH DE + LD DE,#TBLSIZ ; Entry Size + LD HL,#_devfd_dtbl ; Init to table start + INC A +GetPr0: DEC A ; End? + JR Z,GetPrX ; ..quit if Yes, Ptr set + ADD HL,DE ; Else step to next + JR GetPr0 ; ..loop til found + +GetPrX: POP DE + RET + +;------------------------------------------------------------- +; This routine called at each Clock Interrupt. It is used +; to provide any necessary timer/timeout functions. +; Enter: None. +; Exit : HL -> mtm byte variable +; AF - destroyed +; Uses : AF,HL + +_fd_tick: + LD HL,#motim ; Point to FDC Motor-On timer + LD A,(HL) + OR A ; Already Timed out? + JR Z,TDone ; ..jump if Yes + DEC (HL) ; Else count down + CALL Z,MotOff ; stop motors if timed out +TDone: INC HL ; Advance ptr to watchdog/spinup timer (mtm) + LD A,(HL) + OR A ; Timed out? + RET Z ; ..quit if Yes + DEC (HL) ; Else count down + RET ; exit + +;------------------------------------------------------------- +; Motor Off routine. Force Off to delay on next select +; Enter: None. (Motoff) +; A = FDC Device Control Reg bits (Activ8/ActivA) +; Exit : A = Current FDC_DOR Register / "active" byte settings +; Uses : AF + +MotOff: XOR A + LD (motim),A ; Ensure Motors Marked as OFF + LD A,(active) ; Get current settings + AND #0x7D ; strip out motor bit + OR #0x80 ; out of reset +Activ8: +ActivA: LD (active),A ; save + OUT (FDC_DOR),A ; and Command! + RET + +;------------------------------------------------------------- +; FDCMD - Send Command to 9266 FDC +; Enter: B = # of Bytes in Command, C = Command Byte +; HL -> Buffer for Read/Write Data (If Needed) +; Exit : AF = Status byte +; Uses : AF. All other registers preserved/unused + +FdCmd: PUSH HL ; Save regs (for Exit) + PUSH BC + PUSH DE + + ; rewrite FdCmdXfer code so data flows in the correct direction + LD A,(rdOp) + OR A + LD A,#0xA2 ; Load second byte of INI opcode (doesn't update flags) + JR NZ,FdCiUpd ; ... if read, skip increment + INC A ; ... if write, A=0xA3, second byte of OUTI opcode +FdCiUpd:LD (FdCiR1+1),A ; update second byte of INI/OUTI instruction + + ; is the buffer in user memory? + LD A,(_devfd_userbuf) + LD D,A ; store userbuf flag in D + + ; prepare the drive + CALL Motor ; Ensure motors are On + + CALL FdCmdXfer ; Do the data transfer (using code in _COMMONMEM) + + LD HL,#st0 ; Point to Status Result area +IsGo: CALL WRdy + BIT 4,A ; End of Status/Result? + JR Z,FdcXit ; ..exit if So + BIT 6,A ; Another byte Ready? + JR Z,FdcXit ; ..exit if Not + INI ; Else Read Result/Status Byte + JR IsGo ; ..loop for next +FdcXit: + POP DE ; Restore Regs + POP BC + POP HL + RET + +;------------------------------------------------------------ +; COMMON MEMORY +;------------------------------------------------------------ + .area _COMMONMEM + +; inner section of FdCmd routine, has to touch buffers etc +FdCmdXfer: + BIT 0,D ; Buffer in user memory? + CALL NZ, map_process_always + + ; send the command (length is in B, command is in C) + PUSH HL ; save pointer for possible Transfer + LD HL,#comnd ; Point to Command Block + LD (HL),C ; command passed in C + LD C,#FDC_DATA ; FDC Data Port +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 Possible Transfer Addr + JR FdCiR2 ; start sampling MSR + +; transfer loop +; +; +FdCiR1: INI ; *** THIS INSTRUCTION IS MODIFIED IN PLACE to INI/OUTI + ; INI = ED A2 + ; OUTI = ED A3 +FdCiR2: IN A,(FDC_MSR) ; Read Main Status Register + ADD A + JR NC, FdCiR2 ; loop until interrupt requested + ADD A ; are we still in the Execution Phase? + JP M, FdCiR1 ; if so, next byte! + +; tidy up and return +FdCmdXferDone: + BIT 0,D ; Buffer in user memory? + RET Z ; done if not + JP map_kernel ; else remap kernel and return + +;------------------------------------------------------------- +; Wait for FDC RQM to become Ready, return DIO status in +; Zero Flag. Pause before reading status port (~12 mS +; specified, some assumed in code). + +WRdy: +WRdy1: LD A,(dlyCnt) ; Get delay count +WRdy0: DEC A ; count down + JR NZ,WRdy0 ; for ~6 uS Delay + +WRdyL: IN A,(FDC_MSR) ; Read Main Status Register + BIT 7,A ; Interrupt Present? + RET NZ ; Return if So + JR WRdyL ; Else Loop + +dlyCnt: .db (CPU_CLOCK_KHZ/1000) ; Delay to avoid over-sampling status register + +; FDC command staging area +comnd: .ds 1 ; Storage for Command in execution +hdr: .ds 1 ; Head (B2), Drive (B0,1) +trk: .ds 1 ; Track (t) +hd: .ds 1 ; Head # (h) +sect: .ds 1 ; Physical Sector Number +rsz: .ds 1 ; Bytes/Sector (n) +eot: .ds 1 ; End-of-Track Sect # +gpl: .ds 1 ; Gap Length +dtl: .ds 1 ; Data Length + +;------------------------------------------------------------ +; DATA MEMORY +;------------------------------------------------------------ + .area _DATA + +drive: .ds 1 ; (minor) Currently Selected Drive +active: .ds 1 ; Current bits written to FDC_DOR + +_devfd_sector: .ds 1 +_devfd_track: .ds 1 ; LSB used as Head # in DS formats +_devfd_error: .ds 1 +_devfd_buffer: .ds 2 +_devfd_userbuf: .ds 1 + +; DISK Subsystem Variable Storage +; FDC Operation Result Storage Area +st0: .ds 1 ; Status Byte 0 +st1: .ds 1 ; Status Byte 1 (can also be PCN) + .ds 1 ; ST2 - Status Byte 2 + .ds 1 ; RC - Track # + .ds 1 ; RH - Head # (0/1) + .ds 1 ; RR - Sector # + .ds 1 ; RN - Sector Size + +; -->>> NOTE: Do NOT move these next two variables out of sequence !!! <<<-- +motim: .ds 1 ; Motor On Time Counter <<<-- +mtm: .ds 1 ; Floppy Spinup Time down-counter <<<-- + +rdOp: .ds 1 ; Read/write flag +retrys: .ds 1 ; Number of times to try Opns +rwRtry: .ds 1 ; Number of read/write tries +DRVSPD: .ds 1 ; Drive Speed +DRVSIZ: .ds 1 ; Drive Size -- 2.34.1