; ;================================================================================================== ; MD DISK DRIVER (MEMORY DISK) ;================================================================================================== ; ; MD DEVICE CONFIGURATION ; MD_DEVCNT .EQU 2 ; NUMBER OF MD DEVICES SUPPORTED MD_CFGSIZ .EQU 6 ; SIZE OF CFG TBL ENTRIES ; MD_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE) MD_STAT .EQU 1 ; OFFSET OF STATUS (BYTE) MD_LBA .EQU 2 ; OFFSET OF LBA (DWORD) ; ; DEVICE CONFIG TABLE (RAM DEVICE FIRST TO MAKE IT ALWAYS FIRST DRIVE) ; MD_CFGTBL: ; DEVICE 1 (RAM) .DB 1 ; DRIVER DEVICE NUMBER .DB 0 ; DEVICE STATUS .DW 0,0 ; CURRENT LBA ; DEVICE 0 (ROM) .DB 0 ; DEVICE NUMBER .DB 0 ; DEVICE STATUS .DW 0,0 ; CURRENT LBA ; #IF ($ - MD_CFGTBL) != (MD_DEVCNT * MD_CFGSIZ) .ECHO "*** INVALID MD CONFIG TABLE ***\n" #ENDIF ; .DB $FF ; END MARKER ; ; ; MD_INIT: CALL NEWLINE ; FORMATTING PRTS("MD: UNITS=2 $") PRTS("ROMDISK=$") LD HL,ROMSIZE - 128 CALL PRTDEC PRTS("KB RAMDISK=$") LD HL,RAMSIZE - 128 CALL PRTDEC PRTS("KB$") ; ; SETUP THE DIO TABLE ENTRIES ; LD BC,MD_FNTBL LD DE,MD_CFGTBL PUSH BC CALL DIO_ADDENT POP BC LD DE,MD_CFGTBL + MD_CFGSIZ CALL DIO_ADDENT ; XOR A ; INIT SUCCEEDED RET ; RETURN ; ; ; MD_FNTBL: .DW MD_STATUS .DW MD_RESET .DW MD_SEEK .DW MD_READ .DW MD_WRITE .DW MD_VERIFY .DW MD_FORMAT .DW MD_DEVICE .DW MD_MEDIA .DW MD_DEFMED .DW MD_CAP .DW MD_GEOM #IF (($ - MD_FNTBL) != (DIO_FNCNT * 2)) .ECHO "*** INVALID MD FUNCTION TABLE ***\n" #ENDIF ; ; ; MD_VERIFY: MD_FORMAT: MD_DEFMED: CALL PANIC ; INVALID SUB-FUNCTION ; ; ; MD_STATUS: XOR A ; ALWAYS OK RET ; ; ; MD_RESET: XOR A ; ALWAYS OK RET ; ; ; MD_CAP: LD A,(IY+MD_DEV) ; GET DEVICE NUMBER OR A ; SET FLAGS JR Z,MD_CAP0 ; UNIT 0 DEC A ; TRY UNIT 1 JR Z,MD_CAP1 ; UNIT 1 CALL PANIC ; PANIC ON INVALID UNIT MD_CAP0: LD A,(HCB + HCB_ROMBANKS) ; POINT TO ROM BANK COUNT JR MD_CAP2 MD_CAP1: LD A,(HCB + HCB_RAMBANKS) ; POINT TO RAM BANK COUNT MD_CAP2: SUB 4 ; SUBTRACT OUT RESERVED BANKS LD H,A ; H := # BANKS LD E,64 ; # 512 BYTE BLOCKS / BANK CALL MULT8 ; HL := TOTAL # 512 BYTE BLOCKS LD DE,0 ; NEVER EXCEEDS 64K, ZERO HIGH WORD XOR A RET ; ; ; MD_GEOM: ; RAM/ROM DISKS ALLOW CHS STYLE ACCESS BY EMULATING ; A DISK DEVICE WITH 1 HEAD AND 16 SECTORS / TRACK. CALL MD_CAP ; HL := CAPACITY IN BLOCKS LD D,1 | $80 ; HEADS / CYL := 1 BY DEFINITION, SET LBA CAPABILITY BIT LD E,16 ; SECTORS / TRACK := 16 BY DEFINTION LD B,4 ; PREPARE TO DIVIDE BY 16 MD_GEOM1: SRL H ; SHIFT H RR L ; SHIFT L DJNZ MD_GEOM1 ; DO 4 BITS TO DIVIDE BY 16 XOR A ; SIGNAL SUCCESS RET ; DONE ; ; ; MD_DEVICE: LD D,DIODEV_MD ; D := DEVICE TYPE LD A,(IY+MD_DEV) ; GET DEVICE NUMBER LD E,A ; PUT IN E FOR RETURN OR A ; SET FLAGS LD C,%00100000 ; ASSUME ROM DISK ATTRIBUTES JR Z,MD_DEVICE1 ; IF ZERO, IT IS ROM DISK, DONE LD C,%00101000 ; USE RAM DISK ATTRIBUTES MD_DEVICE1: XOR A ; SIGNAL SUCCESS RET ; ; ; MD_MEDIA: LD A,(IY+MD_DEV) ; GET DEVICE NUM ADD A,MID_MDROM ; OFFSET BY MD ROM LD E,A ; RESULTANT MEDIA ID TO E LD D,0 ; D:0=0 MEANS NO MEDIA CHANGE XOR A ; SIGNAL SUCCESS RET ; ; ; MD_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+MD_LBA+0),L ; SAVE NEW LBA LD (IY+MD_LBA+1),H ; ... LD (IY+MD_LBA+2),E ; ... LD (IY+MD_LBA+3),D ; ... XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; ; MD_READ: CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR LD BC,MD_RDSEC ; GET ADR OF SECTOR READ FUNC LD (MD_RWFNADR),BC ; SAVE IT AS PENDING IO FUNC JR MD_RW ; CONTINUE TO GENERIC R/W ROUTINE ; ; ; MD_WRITE: CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR LD BC,MD_WRSEC ; GET ADR OF SECTOR WRITE FUNC LD (MD_RWFNADR),BC ; SAVE IT AS PENDING IO FUNC LD A,(IY+MD_DEV) ; GET DEVICE NUMBER OR A ; SET FLAGS TO TEST FOR ROM (UNIT 0) JR NZ,MD_RW ; NOT ROM, SO OK TO WRITE, CONTINUE LD E,0 ; UNIT IS READ ONLY, ZERO SECTORS WRITTEN OR $FF ; SIGNAL ERROR RET ; AND DONE ; ; ; MD_RW: LD (MD_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 MD_RW1: PUSH BC ; SAVE COUNTERS LD HL,(MD_RWFNADR) ; GET PENDING IO FUNCTION ADDRESS CALL JPHL ; ... AND CALL IT JR NZ,MD_RW2 ; IF ERROR, SKIP INCREMENT ; INCREMENT LBA LD A,MD_LBA ; LBA OFFSET IN CFG ENTRY CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL INC32HL ; INCREMENT THE VALUE ; INCREMENT DMA LD HL,MD_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR INC (HL) ; BUMP DMA BY INC (HL) ; ... 512 BYTES XOR A ; SIGNAL SUCCESS MD_RW2: POP BC ; RECOVER COUNTERS JR NZ,MD_RW3 ; IF ERROR, BAIL OUT INC C ; BUMP COUNT OF SECTORS READ DJNZ MD_RW1 ; LOOP AS NEEDED MD_RW3: LD E,C ; SECTOR READ COUNT TO E LD HL,(MD_DSKBUF) ; CURRENT DMA TO HL OR A ; SET FLAGS BASED ON RETURN CODE RET ; AND RETURN, A HAS RETURN CODE ; ; ; MD_RDSEC: CALL MD_IOSETUP ; SETUP FOR MEMORY COPY #IF (MDTRACE >= 2) LD (MD_SRC),HL LD (MD_DST),DE LD (MD_LEN),BC #ENDIF PUSH BC LD C,A ; SOURCE BANK LD B,BID_BIOS ; DESTINATION BANK IS RAM BANK 1 (HBIOS) #IF (MDTRACE >= 2) LD (MD_SRCBNK),BC CALL MD_PRT #ENDIF LD A,C ; GET SOURCE BANK LD (HB_SRCBNK),A ; SET IT LD A,B ; GET DESTINATION BANK LD (HB_DSTBNK),A ; SET IT POP BC #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY ; DO THE INTERBANK COPY #IF (INTMODE == 1) EI #ENDIF XOR A RET ; ; ; MD_WRSEC: CALL MD_IOSETUP ; SETUP FOR MEMORY COPY EX DE,HL ; SWAP SRC/DEST FOR WRITE #IF (MDTRACE >= 2) LD (MD_SRC),HL LD (MD_DST),DE LD (MD_LEN),BC #ENDIF PUSH BC LD C,BID_BIOS ; SOURCE BANK IS RAM BANK 1 (HBIOS) LD B,A ; DESTINATION BANK #IF (MDTRACE >= 2) LD (MD_SRCBNK),BC CALL MD_PRT #ENDIF LD A,C ; GET SOURCE BANK LD (HB_SRCBNK),A ; SET IT LD A,B ; GET DESTINATION BANK LD (HB_DSTBNK),A ; SET IT POP BC #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY ; DO THE INTERBANK COPY #IF (INTMODE == 1) EI #ENDIF XOR A RET ; ; SETUP FOR MEMORY COPY ; A=BANK SELECT ; BC=COPY SIZE ; DE=DESTINATION ; HL=SOURCE ; ; ASSUMES A "READ" OPERATION. HL AND DE CAN BE SWAPPED ; AFTERWARDS TO ACHIEVE A WRITE OPERATION ; ; ON INPUT, WE HAVE LBA ADDRESSING IN HSTLBAHI:HSTLBALO ; BUT WE NEVER HAVE MORE THAN $FFFF BLOCKS IN A RAM/ROM DISK, ; SO THE HIGH WORD (HSTLBAHI) IS IGNORED ; ; EACH RAM/ROM BANK IS 32K BY DEFINITION AND EACH SECTOR IS 512 ; BYTES BY DEFINITION. SO, EACH RAM/ROM BANK CONTAINS 64 SECTORS ; (32,768 / 512 = 64). THEREFORE, YOU CAN THINK OF LBA AS ; 00000BBB:BBOOOOOO IS WHERE THE 'B' BITS REPRESENT THE BANK NUMBER ; AND THE 'O' BITS REPRESENT THE SECTOR NUMBER WITHIN THE BANK. ; ; TO EXTRACT THE BANK NUMBER, WE CAN LEFT SHIFT TWICE TO GIVE US: ; 000BBBBB:OOOOOOOO. FROM THIS WE CAN EXTRACT THE MSB ; TO USE AS THE BANK NUMBER. NOTE THAT THE "RAW" BANK NUMBER MUST THEN ; BE OFFSET TO THE START OF THE ROM/RAM BANKS. ; ALSO NOTE THAT THE HIGH BIT OF THE BANK NUMBER REPRESENTS "RAM" SO THIS ; BIT MUST ALSO BE SET ACCORDING TO THE UNIT BEING ADDRESSED. ; ; TO GET THE BYTE OFFSET, WE THEN RIGHT SHIFT THE LSB BY 1 TO GIVE US: ; 0OOOOOOO AND EXTRACT THE LSB TO REPRESENT THE MSB OF ; THE BYTE OFFSET. THE LSB OF THE BYTE OFFSET IS ALWAYS 0 SINCE WE ARE ; DEALING WITH 512 BYTE BOUNDARIES. ; MD_IOSETUP: LD L,(IY+MD_LBA+0) ; HL := LOW WORD OF LBA LD H,(IY+MD_LBA+1) ; ... ; ALIGN BITS TO EXTRACT BANK NUMBER FROM H SLA L ; LEFT SHIFT ONE BIT RL H ; FULL WORD SLA L ; LEFT SHIFT ONE BIT RL H ; FULL WORD LD C,H ; BANK NUMBER FROM H TO C ; GET BANK NUM TO A AND SET FLAG Z=ROM, NZ=RAM LD A,(IY+MD_DEV) ; DEVICE TO A AND $01 ; ISOLATE LOW BIT, SET ZF LD A,C ; BANK VALUE INTO A PUSH AF ; SAVE IT FOR NOW ; ADJUST L TO HAVE MSB OF OFFSET SRL L ; ADJUST L TO BE MSB OF BYTE OFFSET LD H,L ; MOVE MSB TO H WHERE IT BELONGS LD L,0 ; AND ZERO L SO HL IS NOW BYTE OFFSET ; LOAD DESTINATION AND COUNT LD DE,(MD_DSKBUF) ; DMA ADDRESS IS DESTINATION LD BC,512 ; ALWAYS COPY ONE SECTOR ; FINISH UP POP AF ; GET BANK AND FLAGS BACK JR Z,MD_IOSETUP2 ; DO ROM DRIVE, ELSE FALL THRU FOR RAM DRIVE ; MD_IOSETUP1: ; RAM ADD A,BID_RAMD0 RET ; MD_IOSETUP2: ; ROM ADD A,BID_ROMD0 RET ; ; ; MD_PRT: PUSH AF PUSH BC PUSH DE PUSH HL CALL NEWLINE LD DE,MDSTR_PREFIX CALL WRITESTR CALL PC_SPACE LD DE,MDSTR_SRC CALL WRITESTR LD A,(MD_SRCBNK) CALL PRTHEXBYTE CALL PC_COLON LD BC,(MD_SRC) CALL PRTHEXWORD CALL PC_SPACE LD DE,MDSTR_DST CALL WRITESTR LD A,(MD_DSTBNK) CALL PRTHEXBYTE CALL PC_COLON LD BC,(MD_DST) CALL PRTHEXWORD CALL PC_SPACE LD DE,MDSTR_LEN CALL WRITESTR LD BC,(MD_LEN) CALL PRTHEXWORD POP HL POP DE POP BC POP AF RET ; ; ; MD_RWFNADR .DW 0 ; MD_DSKBUF .DW 0 ; MD_SRCBNK .DB 0 MD_DSTBNK .DB 0 MD_SRC .DW 0 MD_DST .DW 0 MD_LEN .DW 0 ; MDSTR_PREFIX .TEXT "MD:$" MDSTR_SRC .TEXT "SRC=$" MDSTR_DST .TEXT "DEST=$" MDSTR_LEN .TEXT "LEN=$"