; ;================================================================================================== ; HDSK DISK DRIVER ;================================================================================================== ; HDSK_UNITCNT .EQU 2 ; TWO VIRTUAL HARD DISKS ; ; IO PORT ADDRESSES ; HDSK_IO .EQU $FD ; HDSK_CMDNONE .EQU 0 HDSK_CMDRESET .EQU 1 HDSK_CMDREAD .EQU 2 HDSK_CMDWRITE .EQU 3 HDSK_CMDPARAM .EQU 4 ; ; STATUS ; HDSKRC_OK .EQU 0 ; ; ; HDSK_INIT: CALL NEWLINE ; FORMATTING PRTS("HDSK: UNITS=$") LD A,HDSK_UNITCNT CALL PRTDECB ; ; SETUP THE DISPATCH TABLE ENTRIES ; LD B,HDSK_UNITCNT ; LOOP CONTROL LD C,0 ; PHYSICAL UNIT INDEX HDSK_INIT0: PUSH BC ; SAVE LOOP CONTROL LD B,C ; PHYSICAL UNIT LD C,DIODEV_HDSK ; DEVICE TYPE LD DE,0 ; UNIT DATA BLOB ADDRESS CALL DIO_ADDENT ; ADD ENTRY, BC IS NOT DESTROYED POP BC ; RESTORE LOOP CONTROL INC C ; NEXT PHYSICAL UNIT DJNZ HDSK_INIT0 ; LOOP UNTIL DONE ; XOR A DEC A ; INITIAL STATUS IS NOT READY $FF LD (HDSK_STAT),A ; SAVE IT XOR A ; INIT SUCCEEDED RET ; RETURN ; ; ; HDSK_DISPATCH: ; SAVE THE TARGET DEVICE/UNIT LOCALLY IN DRIVER LD A,C ; DEVICE/UNIT FROM C AND $0F ; ISOLATE UNIT NUM CP 2 ; CHECK FOR MAX UNIT EXCEEDED LD (HDSK_UNIT),A ; SAVE IT CALL NC,PANIC ; PANIC IF TOO HIGH ; ; DISPATCH ACCORDING TO DISK SUB-FUNCTION LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JP Z,HDSK_STATUS ; SUB-FUNC 0: STATUS DEC A JP Z,HDSK_RESET ; SUB-FUNC 1: RESET DEC A JP Z,HDSK_SEEK ; SUB-FUNC 2: SEEK DEC A JP Z,HDSK_READ ; SUB-FUNC 3: READ SECTORS DEC A JP Z,HDSK_WRITE ; SUB-FUNC 4: WRITE SECTORS DEC A JP Z,HDSK_VERIFY ; SUB-FUNC 5: VERIFY SECTORS DEC A JP Z,HDSK_FORMAT ; SUB-FUNC 6: FORMAT TRACK DEC A JP Z,HDSK_DEVICE ; SUB-FUNC 7: DEVICE REPORT DEC A JP Z,HDSK_MEDIA ; SUB-FUNC 8: MEDIA REPORT DEC A JP Z,HDSK_DEFMED ; SUB-FUNC 9: DEFINE MEDIA DEC A JP Z,HDSK_CAP ; SUB-FUNC 10: REPORT CAPACITY DEC A JP Z,HDSK_GEOM ; SUB-FUNC 11: REPORT GEOMETRY ; HDSK_VERIFY: HDSK_FORMAT: HDSK_DEFMED: CALL PANIC ; INVALID SUB-FUNCTION ; ; ; HDSK_STATUS: LD A,(HDSK_STAT) ; LOAD STATUS OR A ; SET FLAGS RET ; ; ; HDSK_RESET: XOR A ; ALWAYS OK RET ; ; GET DISK CAPACITY ; RETURN DE:HL=BLOCK COUNT, BC=BLOCK SIZE ; SLICE C/H/S = 65/16/16 OR 16,640 TOTAL SECTORS ; ASSUME 8 SLICES, SO 16640 X 8 = 133,120 TOTAL SECTORS ; HDSK_CAP: LD DE,133120 >> 16 ; BLOCK COUNT MSW LD HL,133120 & $FFFF ; BLOCK COUNT LSW LD BC,512 ; 512 BYTE SECTOR XOR A ; SIGNAL SUCCESS RET ; ; ; HDSK_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 HDSK_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,$80 | 16 ; HEADS / CYL = 16, SET LBA BIT LD E,16 ; SECTORS / TRACK = 16 XOR A ; SIGNAL SUCCESS RET ; ; ; HDSK_DEVICE: LD D,DIODEV_HDSK ; D := DEVICE TYPE LD E,C ; E := PHYSICAL UNIT LD C,%00000000 ; C := ATTRIBUTES, NON-REMOVABLE HARD DISK XOR A ; SIGNAL SUCCESS RET ; ; ; HDSK_MEDIA: LD E,MID_HD ; HARD DISK MEDIA LD D,0 ; D:0=0 MEANS NO MEDIA CHANGE XOR A ; SIGNAL SUCCESS RET ; ; ; HDSK_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 BC,HSTLBA ; POINT TO LBA STORAGE CALL ST32 ; SAVE LBA ADDRESS XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; ; HDSK_READ: LD (HDSK_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS LD A,HDSK_CMDREAD JR HDSK_RW ; ; ; HDSK_WRITE: LD (HDSK_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS LD A,HDSK_CMDWRITE JR HDSK_RW ; ; ; HDSK_RW: LD (HDSK_CMD),A ; CLEAR RESULTS XOR A ; A = 0 LD (HDSK_RC),A ; CLEAR RETURN CODE ; INIT IF NEEDED LD A,(HDSK_STAT) ; GET CURRENT STATUS OR A ; SET FLAGS CALL NZ,HDSK_DSKRESET ; RESET IF NOT READY ; SET DEVICE LD A,(HDSK_UNIT) ;AND $0F LD (HDSK_DEV),A ; ; INCOMING TRK:SEC ACTUALLY REPRESENTS 32 BIT LBA ; ; MAP TRK:SEC TO HDSK DRIVER AS TTSS:SS ; ; LD A,(HSTTRK) ; LSB OF TRACK ; LD (HDSK_TRK + 1),A ; MAPS TO MSB OF HDSK TRK ; LD A,(HSTSEC + 1) ; MSB OF SECTOR ; LD (HDSK_TRK),A ; MAPS TO LSB OF HDSK TRK ; LD A,(HSTSEC) ; LSB OF SECTOR ; LD (HDSK_SEC),A ; MAPS TO LSB OF HDSK SEC ; INCOMING ADDRESS IS LBA ; MAP HHHH:LLLL TO HDSK DRIVER AS HHLL:LL LD A,(HSTLBAHI) ; LSB OF LBA HIGH LD (HDSK_TRK + 1),A ; MAPS TO MSB OF HDSK TRK LD A,(HSTLBALO + 1) ; MSB OF LBA LOW LD (HDSK_TRK),A ; MAPS TO LSB OF HDSK TRK LD A,(HSTLBALO) ; LSB OF LBA LOW LD (HDSK_SEC),A ; MAPS TO LSB OF HDSK SEC ; SET TRANSFER ADDRESS LD BC,(HDSK_DSKBUF) LD (HDSK_DMA),BC ; EXECUTE COMMAND LD B,7 ; SIZE OF PARAMETER BLOCK LD HL,HDSK_PARMBLK ; START ADDRESS OF PARAMETER BLOCK HDSK_RW1: LD A,(HL) ; GET BYTE OF PARAMETER BLOCK OUT ($FD),A ; SEND IT TO PORT INC HL ; POINT TO NEXT BYTE DJNZ HDSK_RW1 IN A,($FD) ; GET RESULT CODE LD (HDSK_RC),A OR A JR Z,HDSK_OK JR HDSK_ERR HDSK_ERR: XOR A DEC A ; A=$FF TO SIGNAL ERROR LD (HDSK_STAT),A ; SAVE IT #IF (HDSKTRACE >= 1) PUSH AF CALL HDSK_PRT POP AF #ENDIF RET HDSK_OK: #IF (HDSKTRACE >= 2) CALL HDSK_PRT #ENDIF XOR A RET ; ; ; HDSK_DSKRESET: LD B,32 LD A,HDSK_CMDRESET HDSK_DSKRESET1: OUT ($FD),A DJNZ HDSK_DSKRESET1 XOR A ; STATUS = OK LD (HDSK_STAT),A ; SAVE IT #IF (HDSKTRACE >= 2) CALL NEWLINE LD DE,HDSKSTR_PREFIX CALL WRITESTR CALL PC_SPACE LD DE,HDSKSTR_RESET CALL WRITESTR #ENDIF RET ; ; ; HDSK_PRT: CALL NEWLINE LD DE,HDSKSTR_PREFIX CALL WRITESTR CALL PC_SPACE LD DE,HDSKSTR_CMD CALL WRITESTR LD A,(HDSK_CMD) CALL PRTHEXBYTE CALL PC_SPACE CALL PC_LBKT LD A,(HDSK_CMD) LD DE,HDSKSTR_NONE CP HDSK_CMDNONE JP Z,HDSK_PRTCMD LD DE,HDSKSTR_RESET CP HDSK_CMDRESET JP Z,HDSK_PRTCMD LD DE,HDSKSTR_READ CP HDSK_CMDREAD JP Z,HDSK_PRTCMD LD DE,HDSKSTR_WRITE CP HDSK_CMDWRITE JP Z,HDSK_PRTCMD LD DE,HDSKSTR_PARAM CP HDSK_CMDPARAM JP Z,HDSK_PRTCMD LD DE,HDSKSTR_UNKCMD HDSK_PRTCMD: CALL WRITESTR CALL PC_RBKT LD A,(HDSK_CMD) CP HDSK_CMDREAD JR Z,HDSK_PRTRW CP HDSK_CMDWRITE JR Z,HDSK_PRTRW RET HDSK_PRTRW: CALL PC_SPACE LD A,(HDSK_DEV) CALL PRTHEXBYTE CALL PC_SPACE LD BC,(HDSK_TRK) CALL PRTHEXWORD CALL PC_SPACE LD A,(HDSK_SEC) CALL PRTHEXBYTE CALL PC_SPACE LD BC,(HDSK_DSKBUF) CALL PRTHEXWORD CALL PC_SPACE LD DE,HDSKSTR_ARROW CALL WRITESTR CALL PC_SPACE LD DE,HDSKSTR_RC CALL WRITESTR LD A,(HDSK_RC) CALL PRTHEXBYTE CALL PC_SPACE CALL PC_LBKT LD A,(HDSK_RC) LD DE,HDSKSTR_RCOK CP HDSKRC_OK JP Z,HDSK_PRTRC LD DE,HDSKSTR_RCUNK HDSK_PRTRC: CALL WRITESTR CALL PC_RBKT RET ; ; ; HDSKSTR_PREFIX .TEXT "HDSK:$" HDSKSTR_CMD .TEXT "CMD=$" HDSKSTR_RC .TEXT "RC=$" HDSKSTR_ARROW .TEXT "-->$" HDSKSTR_NONE .TEXT "NONE$" HDSKSTR_RESET .TEXT "RESET$" HDSKSTR_READ .TEXT "READ$" HDSKSTR_WRITE .TEXT "WRITE$" HDSKSTR_PARAM .TEXT "PARAM$" HDSKSTR_UNKCMD .TEXT "UNKCMD$" HDSKSTR_RCOK .TEXT "OK$" HDSKSTR_RCUNK .TEXT "UNKNOWN ERROR$" ; ;================================================================================================== ; HDSK DISK DRIVER - DATA ;================================================================================================== ; HDSK_STAT .DB 0 HDSK_RC .DB 0 ; HDSK_UNIT .DB 0 HDSK_DSKBUF .DW 0 ; HDSK_PARMBLK: HDSK_CMD .DB 0 ; COMMAND (HDSK_READ, HDSK_WRITE, ...) HDSK_DEV .DB 0 ; 0..7, HARD DISK UNIT HDSK_SEC .DB 0 ; 0..255 SECTOR HDSK_TRK .DW 0 ; 0..2047 TRACK HDSK_DMA .DW 0 ; DEFINES WHERE RESULT IS PLACED IN MEMORY