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.
 
 
 
 
 
 

350 lines
8.2 KiB

;
;==================================================================================================
; RAM FLOPPY DISK DRIVER
;==================================================================================================
;
;
;
RF_U0IO .EQU $A0 ; BASED ADDRESS OF RAMFLOPPY 1
RF_U1IO .EQU $A4 ; BASED ADDRESS OF RAMFLOPPY 2
RF_U2IO .EQU $A8 ; BASED ADDRESS OF RAMFLOPPY 3
RF_U3IO .EQU $AC ; BASED ADDRESS OF RAMFLOPPY 4
;
; IO PORT OFFSETS
;
RF_DAT .EQU 0 ; DATA IN/OUT ONLY TO SRAM - R/W
RF_AL .EQU 1 ; ADDRESS LOW FOR RAMF MEMORY - W/O
RF_AH .EQU 2 ; ADDRESS HIGH FOR RAMF MEMORY - W/O
RF_ST .EQU 3 ; STATUS PORT - R/O
;
; RF DEVICE CONFIGURATION
;
RF_DEVCNT .EQU RFCNT ; NUMBER OF RF DEVICES SUPPORTED
RF_CFGSIZ .EQU 8 ; SIZE OF CFG TBL ENTRIES
RF_MAXRF .EQU 4 ; MAXIMUM NUMBERS OF DEVICES SUPPORTED
;
RF_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
RF_STAT .EQU 1 ; OFFSET OF STATUS (BYTE)
RF_LBA .EQU 2 ; OFFSET OF LBA (DWORD)
RF_IOAD .EQU 7 ; OFFSET OF DEVICE IO ADDRESS
#IF ($RF_DEVCNT > RF_MAXRF)
.ECHO "*** ONLY 4 RAM FLOPPY DEVICES SUPPORTED ***\n"
RF_DEVCNT .SET RF_MAXRF
#ENDIF
;
; DEVICE CONFIG TABLE (RAM DEVICE FIRST TO MAKE IT ALWAYS FIRST DRIVE)
;
RF_CFGTBL:
; DEVICE 0
.DB 0 ; DRIVER DEVICE NUMBER
.DB 0 ; DEVICE STATUS
.DW 0,0 ; CURRENT LBA
.DB 0 ; UNUSED
.DB RF_U0IO ; DEVICE BASE ADDR
#IF (RF_DEVCNT > 1)
; DEVICE 1
.DB 1 ; DEVICE NUMBER
.DB 0 ; DEVICE STATUS
.DW 0,0 ; CURRENT LBA
.DB 0 ; UNUSED
.DB RF_U1IO ; DEVICE BASE ADDR
#ENDIF
#IF (RF_DEVCNT > 2)
; DEVICE 2
.DB 2 ; DRIVER DEVICE NUMBER
.DB 0 ; DEVICE STATUS
.DW 0,0 ; CURRENT LBA
.DB 0 ; UNUSED
.DB RF_U2IO ; DEVICE BASE ADDR
#ENDIF
; ; DEVICE 3
#IF (RF_DEVCNT > 3)
.DB 3 ; DEVICE NUMBER
.DB 0 ; DEVICE STATUS
.DW 0,0 ; CURRENT LBA
.DB 0 ; UNUSED
.DB RF_U3IO ; DEVICE BASE ADDR
#ENDIF
;
#IF ($ - RF_CFGTBL) != (RF_DEVCNT * RF_CFGSIZ)
.ECHO "*** INVALID RF CONFIG TABLE ***\n"
#ENDIF
;
.DB $FF ; END MARKER
;
;
;
RF_INIT:
CALL NEWLINE ; FORMATTING
PRTS("RF:$")
LD B,RF_DEVCNT ; LOOP CONTROL
LD IY,RF_CFGTBL ; START OF CFG TABLE
RF_INIT0:
CALL RF_UNIT
PUSH BC ; SAVE LOOP CONTROL
LD BC,RF_FNTBL ; BC := FUNC TABLE ADR
PUSH IY ; CFG ENTRY POINTER
POP DE ; COPY TO DE
CALL DIO_ADDENT ; ADD ENTRY, BC IS NOT DESTROYED
LD BC,RF_CFGSIZ ; SIZE OF CFG ENTRY
ADD IY,BC ; BUMP IY TO NEXT ENTRY
POP BC ; RESTORE BC
DJNZ RF_INIT0 ; LOOP AS NEEDED
PRTS(" DEVICES=$") ; DISPLAY NUMBER
LD A,RF_DEVCNT ; OF DEVICES
CALL PRTDECB
;
XOR A ; INIT SUCCEEDED
RET ; RETURN
;
RF_UNIT:
PRTS(" IO=0x$") ; DISPLAY
LD A,(IY+RF_IOAD) ; PORT AND
CALL PRTHEXBYTE ; WRITE
PRTS(" WP=$") ; PROTECT
ADD A,RF_ST ; STATUS OF
LD C,A ; THIS DEVICE
IN A,(C)
AND 1
JR Z,RF_NO_WP1
PRTS("ON$")
RET
RF_NO_WP1:
PRTS("OFF$")
RET
;
;
;
RF_FNTBL:
.DW RF_STATUS
.DW RF_RESET
.DW RF_SEEK
.DW RF_READ
.DW RF_WRITE
.DW RF_VERIFY
.DW RF_FORMAT
.DW RF_DEVICE
.DW RF_MEDIA
.DW RF_DEFMED
.DW RF_CAP
.DW RF_GEOM
#IF (($ - RF_FNTBL) != (DIO_FNCNT * 2))
.ECHO "*** INVALID MD FUNCTION TABLE ***\n"
#ENDIF
;
RF_VERIFY:
RF_FORMAT:
RF_DEFMED:
CALL SYSCHK ; INVALID SUB-FUNCTION
LD A,ERR_NOTIMPL
OR A
RET
;
;
;
RF_STATUS:
XOR A ; STATUS ALWAYS OK
RET
;
;
;
RF_RESET:
XOR A ; ALWAYS OK
RET
;
;
;
RF_CAP:
LD DE,0
LD HL,$2000 ; 8192 BLOCKS OF 512 BYTES
XOR A
RET
;
;
;
RF_GEOM:
; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS
; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE
CALL RF_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
LD L,H ; DIVIDE BY 256 FOR # TRACKS
LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL
LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT
LD E,16 ; SECTORS / TRACK = 16
RET ; DONE, A STILL HAS RF_CAP STATUS
;
;
;
RF_DEVICE:
LD D,DIODEV_RF ; D := DEVICE TYPE
LD E,(IY+RF_DEV) ; E := PHYSICAL DEVICE NUMBER
LD C,%00110000 ; C := ATTRIBUTES, NON-REMOVABLE RAM FLOPPY
LD H,0 ; H := 0, DRIVER HAS NO MODES
LD L,(IY+RF_IOAD) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
;
;
RF_MEDIA:
LD E,MID_RF ; RAM FLOPPY MEDIA
LD D,0 ; D:0=0 MEANS NO MEDIA CHANGE
XOR A ; SIGNAL SUCCESS
RET
;
;
;
RF_SEEK:
BIT 7,D ; CHECK FOR LBA FLAG
CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA
RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA)
LD (IY+RF_LBA+0),L ; SAVE NEW LBA
LD (IY+RF_LBA+1),H ; ...
LD (IY+RF_LBA+2),E ; ...
LD (IY+RF_LBA+3),D ; ...
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
;
;
RF_READ:
CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR
LD BC,RF_RDSEC ; GET ADR OF SECTOR READ FUNC
LD (RF_RWFNADR),BC ; SAVE IT AS PENDING IO FUNC
JR RF_RW ; CONTINUE TO GENERIC R/W ROUTINE
;
;
;
RF_WRITE:
CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR
LD BC,RF_WRSEC ; GET ADR OF SECTOR WRITE FUNC
LD (RF_RWFNADR),BC ; SAVE IT AS PENDING IO FUNC
CALL RF_CHKWP ; WRITE PROTECTED?
JR Z,RF_RW ; IF 0, NOT WP, CONTINUE WITH GENERIC R/W ROUTINE
LD E,0 ; ZERO SECTORS WRITTEN
LD A,ERR_READONLY ; SIGNAL ERROR
OR A ; SET FLAGS
RET ; AND DONE
;
;
;
RF_RW:
LD (RF_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
LD A,E ; BLOCK COUNT TO A
OR A ; SET FLAGS
RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0
LD B,A ; INIT SECTOR DOWNCOUNTER
LD C,0 ; INIT SECTOR READ/WRITE COUNT
CALL RF_SETIO ; SET BASE PORT IO ADR FOR SELECTED UNIT
RF_RW1:
PUSH BC ; SAVE COUNTERS
LD HL,(RF_RWFNADR) ; GET PENDING IO FUNCTION ADDRESS
CALL JPHL ; ... AND CALL IT
JR NZ,RF_RW2 ; IF ERROR, SKIP INCREMENT
; INCREMENT LBA
LD A,MD_LBA ; OFFSET OF LBA VALUE
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL INC32HL ; INCREMENT THE VALUE
; INCREMENT DMA
LD HL,RF_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
INC (HL) ; BUMP DMA BY
INC (HL) ; ... 512 BYTES
XOR A ; SIGNAL SUCCESS
RF_RW2:
POP BC ; RECOVER COUNTERS
JR NZ,RF_RW3 ; IF ERROR, BAIL OUT
INC C ; BUMP COUNT OF SECTORS READ
DJNZ RF_RW1 ; LOOP AS NEEDED
RF_RW3:
LD E,C ; SECTOR READ COUNT TO E
LD HL,(RF_DSKBUF) ; CURRENT DMA TO HL
OR A ; SET FLAGS BASED ON RETURN CODE
RET Z ; RETURN SUCCESS
LD A,ERR_IO ; SIGNAL IO ERROR
OR A ; SET FLAGS
RET ; AND DONE
;
; READ SECTOR
;
RF_RDSEC:
CALL RF_SETADR ; SEND SECTOR STARTING ADDRESS TO CARD
LD HL,(RF_DSKBUF) ; HL := DISK BUFFER ADDRESS
LD A,(RF_IO) ; GET IO PORT BASE
#IF (DMAENABLE & (DMAMODE=DMAMODE_ECB))
LD BC,512 ; READ 512 BYTES
CALL DMAINIR ; USING DMA
#ELSE
OR RF_DAT ; OFFSET TO DAT PORT
LD C,A ; PUT IN C FOR PORT IO
LD B,0 ; INIT BYTE COUNTER
INIR ; READ 256 BYTES
INIR ; AND ANOTHER 256 BYTES FOR 512 TOTAL
XOR A ; SIGNAL SUCCESS
#ENDIF
RET ; AND DONE
;
; WRITE SECTOR
;
RF_WRSEC:
CALL RF_SETADR ; SEND SECTOR STARTING ADDRESS TO CARD
LD HL,(RF_DSKBUF) ; HL := DISK BUFFER ADDRESS
LD A,(RF_IO) ; GET IO PORT BASE
OR RF_DAT ; OFFSET TO DAT PORT
#IF (DMAENABLE & (DMAMODE=DMAMODE_ECB))
LD BC,512 ; WRITE 512 BYTES
CALL DMAOTIR ; USING DMA
#ELSE
LD C,A ; PUT IN C FOR PORT IO
LD B,0 ; INIT BYTE COUNTER
OTIR ; WRITE 256 BYTES
OTIR ; AND ANOTHER 256 BYTES FOR 512 TOTAL
XOR A ; SIGNAL SUCCESS
#ENDIF
RET ; AND DONE
;
;
;
RF_SETIO:
LD A,(IY+RF_IOAD) ; GET THE IO PORT
LD (RF_IO),A ; OF THE DEVICE WE
RET ; ARE WORKING ON
;
;
;
RF_SETADR:
;
#IF (DSKYENABLE)
LD A,RF_LBA
CALL LDHLIYA
CALL HB_DSKACT ; SHOW ACTIVITY
#ENDIF
;
LD A,(RF_IO) ; OUTPUT THE LOGICAL BLOCK
OR RF_AL ; ADDRESS TO THE
LD C,A ; TO THE MSB AND
LD A,(IY+RF_LBA+0) ; LSB SECTRK
OUT (C),A ; REGISTERS.
LD A,(IY+RF_LBA+1) ; BYTE COUNTER
INC C ; IS RESET
OUT (C),A
RET
;
;
;
RF_CHKWP:
CALL RF_SETIO ; SET BASE PORT IO ADR FOR SELECTED UNIT
LD A,(RF_IO) ; GET IO PORT BASE
OR RF_ST ; OFFSET TO ST PORT
LD C,A ; PUT PORT ADR IN C FOR IO
IN A,(C) ; READ ST PORT
BIT 0,A ; CHECK WRITE PROTECT (BIT 0)
RET ; RET WP STATUS IN ZF, NZ=WP
;
;
;
RF_IO .DB 0 ; PORT ADDRESS OF ACTIVE DEVICE
RF_RWFNADR .DW 0
;
RF_DSKBUF .DW 0