;__________________________________________________________________________________________________ ; ; CBIOS FOR N8VEM ; ; BY ANDREW LYNCH, WITH INPUT FROM MANY SOURCES ; ROMWBW ADAPTATION BY WAYNE WARTHEN ;__________________________________________________________________________________________________ ; ; The std.asm file contains the majority of the standard equates ; that describe data structures, magic values and bit fields used ; by the CBIOS. ; #INCLUDE "std.asm" ; .ORG CBIOS_LOC ; DEFINED IN STD.ASM ; STACK .EQU CBIOS_END ; USE SLACK SPACE FOR STACK AS NEEDED ; ;================================================================================================== ; CP/M JUMP VECTOR TABLE FOR INDIVIDUAL SUBROUTINES ;================================================================================================== ; These jumps are defined in the CP/M-80 v2.2 system guide and comprise ; the invariant part of the BIOS. ; JP BOOT ; #0 - COLD START WBOOTE JP WBOOT ; #1 - WARM START JP CONST ; #2 - CONSOLE STATUS JP CONIN ; #3 - CONSOLE CHARACTER IN JP CONOUT ; #4 - CONSOLE CHARACTER OUT JP LIST ; #5 - LIST CHARACTER OUT JP PUNCH ; #6 - PUNCH CHARACTER OUT JP READER ; #7 - READER CHARACTER IN JP HOME ; #8 - MOVE HEAD TO HOME POSITION JP SELDSK ; #9 - SELECT DISK JP SETTRK ; #10 - SET TRACK NUMBER JP SETSEC ; #11 - SET SECTOR NUMBER JP SETDMA ; #12 - SET DMA ADDRESS JP READ ; #13 - READ DISK JP WRITE ; #14 - WRITE DISK JP LISTST ; #15 - RETURN LIST STATUS JP SECTRN ; #16 - SECTOR TRANSLATE ; ;================================================================================================== ; CBIOS STAMP FOR ROMWBW ;================================================================================================== ; ; RomWBW CBIOS places the following stamp data into page zero ; at address $40. The address range $40-$4F is reserved by CP/M ; as a scratch area for CBIOS. This data below is copied there at ; every warm start. It allows applications to identify RomWBW CBIOS. ; Additionally, it contains a pointer to additional CBIOS extension ; data (CBX) specific to RomWBW CBIOS. ; ; RomWBW CBIOS page zero stamp starts at $40 ; $40-$41: Marker ('W', ~'W') ; $42-$43: Version bytes: major/minor, update/patch ; $44-$45: CBIOS Extension Info address ; STPLOC .EQU $40 STPIMG: .DB 'W',~'W' ; MARKER .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO .DW CBX ; ADDRESS OF CBIOS EXT DATA STPSIZ .EQU $ - STPIMG ; ; The following section contains key information and addresses for the ; RomWBW CBIOS. A pointer to the start of this section is stored with ; with the ZPX data in page zero at $44 (see above). ; CBX: .DW DEVMAP ; DEVICE MAP ADDRESS .DW DRVMAP ; DRIVE MAP ADDRESS .DW DPBMAP ; DPB MAP ADDRESS ; CBXSIZ .EQU $ - CBX .ECHO "CBIOS extension info occupies " .ECHO CBXSIZ .ECHO " bytes.\n" ; ;================================================================================================== ; CHARACTER DEVICE MAPPING ;================================================================================================== ; ; MAP LOGICAL CHARACTER DEVICES TO PHYSICAL CHARACTER DEVICES ; #IF (PLATFORM == PLT_UNA) LD_TTY .EQU 0 LD_CRT .EQU 0 LD_BAT .EQU CIODEV_BAT LD_UC1 .EQU 0 LD_PTR .EQU 0 LD_UR1 .EQU 0 LD_UR2 .EQU 0 LD_PTP .EQU 0 LD_UP1 .EQU 0 LD_UP2 .EQU 0 LD_LPT .EQU 0 LD_UL1 .EQU 0 #ELSE #IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4)) TTYDEV .EQU CIODEV_ASCI #ELSE TTYDEV .EQU CIODEV_UART #ENDIF ; LD_TTY .EQU TTYDEV LD_CRT .EQU TTYDEV LD_BAT .EQU CIODEV_BAT LD_UC1 .EQU TTYDEV LD_PTR .EQU TTYDEV LD_UR1 .EQU TTYDEV LD_UR2 .EQU TTYDEV LD_PTP .EQU TTYDEV LD_UP1 .EQU TTYDEV LD_UP2 .EQU TTYDEV LD_LPT .EQU TTYDEV LD_UL1 .EQU TTYDEV ; #IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4)) LD_UC1 .SET CIODEV_ASCI + 1 LD_PTR .SET CIODEV_ASCI + 1 LD_PTP .SET CIODEV_ASCI + 1 #ENDIF ; #IF (UARTENABLE & (UARTCNT >= 2)) LD_UC1 .SET CIODEV_UART + 1 LD_PTR .SET CIODEV_UART + 1 LD_PTP .SET CIODEV_UART + 1 #ENDIF ; #IF (VDUENABLE | CVDUENABLE | N8VENABLE) LD_CRT .SET CIODEV_CRT #ENDIF #IF (PRPENABLE & PRPCONENABLE) LD_CRT .SET CIODEV_PRPCON #ENDIF #IF (PPPENABLE & PPPCONENABLE) LD_CRT .SET CIODEV_PPPCON #ENDIF #ENDIF ; .DB DEVCNT DEVMAP: ; ; CONSOLE .DB LD_TTY ; CON:=TTY: (IOBYTE XXXXXX00) .DB LD_CRT ; CON:=CRT: (IOBYTE XXXXXX01) .DB LD_BAT ; CON:=BAT: (IOBYTE XXXXXX10) .DB LD_UC1 ; CON:=UC1: (IOBYTE XXXXXX11) ; READER .DB LD_TTY ; RDR:=TTY: (IOBYTE XXXX00XX) .DB LD_PTR ; RDR:=PTR: (IOBYTE XXXX01XX) .DB LD_UR1 ; RDR:=UR1: (IOBYTE XXXX10XX) .DB LD_UR2 ; RDR:=UR2: (IOBYTE XXXX11XX) ; PUNCH .DB LD_TTY ; PUN:=TTY: (IOBYTE XX00XXXX) .DB LD_PTP ; PUN:=PTP: (IOBYTE XX01XXXX) .DB LD_UP1 ; PUN:=UP1: (IOBYTE XX10XXXX) .DB LD_UP2 ; PUN:=UP2: (IOBYTE XX11XXXX) ; LIST .DB LD_TTY ; LST:=TTY: (IOBYTE 00XXXXXX) .DB LD_CRT ; LST:=CRT: (IOBYTE 01XXXXXX) .DB LD_LPT ; LST:=LPT: (IOBYTE 10XXXXXX) .DB LD_UL1 ; LST:=UL1: (IOBYTE 11XXXXXX) ; DEVCNT .EQU ($ - DEVMAP) .ECHO DEVCNT .ECHO " Input/Output devices defined.\n" ; ;================================================================================================== ; DISK MAPPING TABLE ;================================================================================================== ; ; This table maps logical CP/M drive letters to the physical device, ; unit, and slice within the HBIOS. Additionally, each entry is mapped ; to a dedicated CP/M DPH structure for the drive. ; ; The position of the entry in the table determines the CP/M drive being ; mapped. First entry is A:, second entry is B:, etc. ; ; Note that this table is intended to be modified dynamically to allow ; user remapping of drives. Warning: BDOS drives must be reset and ; warm start performed if this table is changed dynamically. The application ; making changes to this table is responsible for ensuring the changes ; are valid and appropriate or very bad things will happen. ; #IF (PLATFORM == PLT_UNA) DRVMAP .EQU 0 ; MANAGED DYNAMICALLY FOR UNA #ELSE ; #DEFINE DRVENT(DEV,UNIT,SLICE,DPHADR) \ #DEFCONT .DB DEV | UNIT \ #DEFCONT .DB SLICE \ #DEFCONT .DW DPHADR ; .DB DRVCNT DRVMAP: DRVLST ; DRVCNT .EQU ($ - DRVMAP) / 4 .ECHO DRVCNT .ECHO " drive letters defined.\n" ; #ENDIF ; ;================================================================================================== ; DPB MAPPING TABLE ;================================================================================================== ; ; MAP MEDIA ID'S TO APPROPRIATE DPB ADDRESSEES ; THE ENTRIES IN THIS TABLE MUST CONCIDE WITH THE VALUES ; OF THE MEDIA ID'S (SAME SEQUENCE, NO GAPS) ; .DB DPBCNT ; DPBMAP: .DW 0 ; MID_NONE (NO MEDIA) .DW DPB_ROM ; MID_MDROM .DW DPB_RAM ; MID_MDRAM .DW DPB_RF ; MID_RF .DW DPB_HD ; MID_HD .DW DPB_FD720 ; MID_FD720 .DW DPB_FD144 ; MID_FD144 .DW DPB_FD360 ; MID_FD360 .DW DPB_FD120 ; MID_FD120 .DW DPB_FD111 ; MID_FD111 ; DPBCNT .EQU ($ - DPBMAP) / 2 ; ;================================================================================================== ; BIOS FUNCTIONS ;================================================================================================== ; ;__________________________________________________________________________________________________ BOOT: ; STANDARD BOOT INVOCATION DI IM 1 LD SP,STACK ; STACK FOR INITIALIZATION ; CALL INIT ; EXECUTE COLD BOOT CODE ROUTINE ; LD SP,$100 ; MOVE STACK SO WE CAN INIT BUFFER AREA ; LD HL,BUFFERS ; INIT BUFFERS AREA LD HL,INIT ; INIT BUFFERS AREA ; LD BC,CBIOS_END - BUFFERS ; SIZE OF BUFFER SPACE LD BC,CBIOS_END - INIT ; SIZE OF BUFFER SPACE CALL FILL ; DO IT ; LD SP,STACK ; PUT STACK BACK WHERE IT BELONGS JR GOCPM ; THEN OFF TO CP/M WE GO... ; ;__________________________________________________________________________________________________ WBOOT: DI IM 1 ; LD SP,STACK ; STACK FOR INITIALIZATION ; #IF (PLATFORM == PLT_UNA) ; RESTORE COMMAND PROCESSOR FROM UNA BIOS CACHE LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$800D ; UBIOS_PAGE (SEE PAGES.INC) RST 08 ; DO IT PUSH DE ; SAVE PREVIOUS BANK LD HL,(CCPBUF) ; ADDRESS OF CCP BUF IN BIOS MEM LD DE,CPM_LOC ; ADDRESS IN HI MEM OF CCP LD BC,CCPSIZ ; SIZE OF CCP LDIR ; DO IT LD BC,$01FB ; UNA FUNC = SET BANK POP DE ; RECOVER OPERATING BANK RST 08 ; DO IT #ELSE ; RESTORE COMMAND PROCESSOR FROM CACHE IN HB BANK LD B,BID_USR ; B = DEST BANK = USR BANK = TPA LD C,BID_HB ; C = SRC BANK = HB BANK CALL HB_XCOPY ; SET BANKS FOR INTERBANK COPY LD HL,$800 ; COPY FROM FIXED LOCATION IN HB BANK LD DE,CPM_LOC ; TO CCP LOCATION IN USR BANK LD BC,CCPSIZ ; COPY CONTENTS OF COMMAND PROCESSOR CALL HB_COPY ; DO IT #ENDIF ; ; FALL THRU TO INVOKE CP/M ; ;__________________________________________________________________________________________________ GOCPM: #IF (PLATFORM == PLT_UNA) ; USE A DEDICATED BUFFER FOR UNA PHYSICAL DISK I/O LD HL,SECBUF ; ADDRESS OF PHYSICAL SECTOR BUFFER LD (BUFADR),HL ; SAVE IT IN BUFADR FOR LATER #ELSE ; GET AND SAVE PHYSICAL DISK XFR BUFFER LOCATION ; ASSUMED TO BE IN HBIOS BANK (BID_HB) LD B,BF_DIOGETBUF ; GET DISK BUFFER ADR IN HBIOS DRIVER BANK RST 08 ; MAKE HBIOS CALL LD (BUFADR),HL ; RECORD THE BUFFER ADDRESS #ENDIF ; LD A,$C3 ; LOAD A WITH 'JP' INSTRUCTION (USED BELOW) ; ; CPU RESET / RST 0 / JP 0 -> WARM START CP/M LD ($0000),A ; JP OPCODE GOES HERE LD HL,WBOOTE ; GET WARM BOOT ENTRY ADDRESS LD ($0001),HL ; AND PUT IT AT $0001 ; ; INT / RST 38 -> INVOKE MONITOR ; LD ($0038),A ; LD HL,GOMON ; LD ($0039),HL ; ; INT / RST 38 -> PANIC ; LD ($0038),A ; LD HL,PANIC ; PANIC ROUTINE ADDRESS ; LD ($0039),HL ; POKE IT ; CALL 5 -> INVOKE BDOS LD ($0005),A ; JP OPCODE AT $0005 LD HL,BDOS ; GET BDOS ENTRY ADDRESS LD ($0006),HL ; PUT IT AT $0006 ; ; INSTALL ROMWBW CBIOS PAGE ZERO STAMP AT $40 LD HL,STPIMG ; FORM STAMP DATA IMAGE LD DE,STPLOC ; TO IT'S LOCATION IN PAGE ZERO LD BC,STPSIZ ; SIZE OF BLOCK TO COPY LDIR ; DO IT ; ; RESET (DE)BLOCKING ALGORITHM CALL BLKRES ; ; DEFAULT DMA ADDRESS LD BC,$80 ; DEFAULT DMA ADDRESS IS $80 CALL SETDMA ; SET IT ; ; ENSURE VALID DISK AND JUMP TO CCP LD A,(CDISK) ; GET CURRENT USER/DISK AND $F ; ISOLATE DISK PART LD C,A ; SETUP C WITH CURRENT USER/DISK, ASSUME IT IS OK CALL DSK_STATUS ; CHECK DISK STATUS JR Z,CURDSK ; ZERO MEANS OK LD A,(DEFDRIVE) ; CURRENT DRIVE NOT READY, USE DEFAULT JR GOCCP ; JUMP TO COMMAND PROCESSOR CURDSK: LD A,(CDISK) ; GET CURRENT USER/DISK GOCCP: LD C,A ; SETUP C WITH CURRENT USER/DISK, ASSUME IT IS OK JP CCP ; JUMP TO COMMAND PROCESSOR ; ;__________________________________________________________________________________________________ GOMON: CALL PANIC ; ; DI ; IM 1 ; ; LD SP,STACK ; ; ; RELOAD MONITOR INTO RAM (IN CASE IT HAS BEEN OVERWRITTEN) ; CALL ROMPGZ ; LD HL,MON_IMG ; LD DE,MON_LOC ; LD BC,MON_SIZ ; LDIR ; CALL RAMPGZ ; ; JUMP TO MONITOR WARM ENTRY ; JP MON_UART ; ; ;================================================================================================== ; CHARACTER BIOS FUNCTIONS ;================================================================================================== ; ;__________________________________________________________________________________________________ ; ;__________________________________________________________________________________________________ CONST: ; CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT ; LD B,BF_CIOIST ; B = FUNCTION LD HL,CIOST ; HL = ADDRESS OF COMPLETION ROUTINE JR CONIO ; ;__________________________________________________________________________________________________ CONIN: ; CONSOLE CHARACTER INTO REGISTER A ; LD B,BF_CIOIN ; B = FUNCTION LD HL,CIOIN ; HL = ADDRESS OF COMPLETION ROUTINE JR CONIO ;__________________________________________________________________________________________________ CONOUT: ; CONSOLE CHARACTER OUTPUT FROM REGISTER C ; LD B,BF_CIOOUT ; B = FUNCTION POP HL ; NO COMPLETION ROUTINE, SETUP DIRECT RETURN TO CALLER LD E,C ; E = CHARACTER TO SEND ; JR CONIO ; COMMENTED OUT, FALL THROUGH OK ; ;__________________________________________________________________________________________________ CONIO: ; LD A,(IOBYTE) ; GET IOBYTE AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR CONSOLE ; OR $00 ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0C JR CIO_DISP ; ;__________________________________________________________________________________________________ LIST: ; LIST CHARACTER FROM REGISTER C ; LD B,BF_CIOOUT ; B = FUNCTION POP HL ; NO COMPLETION ROUTINE, SETUP DIRECT RETURN TO CALLER LD E,C ; E = CHARACTER TO SEND JR LISTIO ; ;__________________________________________________________________________________________________ LISTST: ; RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) ; LD B,BF_CIOOST ; B = FUNCTION LD HL,CIOST ; HL = ADDRESS OF COMPLETION ROUTINE ; JR LISTIO ; COMMENTED OUT, FALL THROUGH OK ; ;__________________________________________________________________________________________________ LISTIO: ; LD A,(IOBYTE) ; GET IOBYTE RLCA ; SHIFT RELEVANT BITS TO BITS 0-1 RLCA AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR LST: OR $0C ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0C JR CIO_DISP ; ;__________________________________________________________________________________________________ PUNCH: ; PUNCH CHARACTER FROM REGISTER C ; LD B,BF_CIOOUT ; B = FUNCTION POP HL ; NO COMPLETION ROUTINE, SETUP DIRECT RETURN TO CALLER LD E,C ; E = CHARACTER TO SEND ; JR PUNCHIO ; COMMENTED OUT, FALL THROUGH OK ; ;__________________________________________________________________________________________________ PUNCHIO: ; LD A,(IOBYTE) ; GET IOBYTE RLCA ; SHIFT RELEVANT BITS TO BITS 0-1 RLCA RLCA RLCA AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR PUN: OR $08 ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0C JR CIO_DISP ; ;__________________________________________________________________________________________________ READER: ; READ CHARACTER INTO REGISTER A FROM READER DEVICE ; LD B,BF_CIOIN ; B = FUNCTION LD HL,CIOIN ; HL = ADDRESS OF COMPLETION ROUTINE JR READERIO ; ;__________________________________________________________________________________________________ READERST: ; RETURN READER STATUS (0 IF NOT READY, 1 IF READY) ; LD B,BF_CIOIST ; B = FUNCTION LD HL,CIOST ; HL = ADDRESS OF COMPLETION ROUTINE ; JR READERIO ; COMMENTED OUT, FALL THROUGH OK ; ;__________________________________________________________________________________________________ READERIO: ; LD A,(IOBYTE) ; GET IOBYTE RRCA ; SHIFT RELEVANT BITS TO BITS 0-1 RRCA AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR RDR: OR $04 ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0C JR CIO_DISP ; ;__________________________________________________________________________________________________ CIOIN: ; COMPLETION ROUTINE FOR CHARACTER INPUT FUNCTIONS ; LD A,E ; MOVE CHARACTER RETURNED TO A RET ; FALL THRU ;; ;;__________________________________________________________________________________________________ ;CIOOUT: ;; COMPLETION ROUTINE FOR CHARACTER OUTPUT FUNCTIONS ;; RET ; ;__________________________________________________________________________________________________ CIOST: ; COMPLETION ROUTINE FOR CHARACTER STATUS FUNCTIONS (IST/OST) ; #IF (PLATFORM == PLT_UNA) LD A,E #ENDIF OR A ; SET FLAGS RET Z ; NO CHARACTERS WAITING (IST) OR OUTPUT BUF FULL (OST) OR $FF ; $FF SIGNALS READY TO READ (IST) OR WRITE (OST) RET ; ;================================================================================================== ; CHARACTER DEVICE INTERFACE ;================================================================================================== ; ; ROUTING FOR CHARACTER DEVICE FUNCTIONS ; A = INDEX INTO DEVICE MAP BASED ON IOBYTE BIOS REQUEST ; B = FUNCTION REQUESTED: BF_CIO(IN/OUT/IST/OST) ; E = CHARACTER (IF APPLICABLE TO FUNCTION) ; HL = ADDRESS OF COMPLETION ROUTINE ; CIO_DISP: PUSH HL ; PUT COMPLETION ROUTINE ON STACK ; LOOKUP IOBYTE MAPPED DEVICE CODE AND 0FH ; ISOLATE INDEX INTO DEVICE MAP LD HL,DEVMAP ; HL = ADDRESS OF DEVICE MAP CALL ADDHLA ; ADD OFFSET LD A,(HL) ; LOOKUP DEVICE CODE #IF (PLATFORM == PLT_UNA) LD C,B ; MOVE FUNCTION TO C LD B,A ; DEVICE GOES IN B #ELSE LD C,A ; SAVE IN C FOR BIOS USAGE #ENDIF CP CIODEV_BAT ; CHECK FOR SPECIAL DEVICE (BAT, NUL) JR NC,CIO_DISP1 ; HANDLE SPECIAL DEVICE RST 08 ; RETURN VIA COMPLETION ROUTINE SET AT START RET CIO_DISP1: ; HANDLE SPECIAL DEVICES AND 0F0H ; ISOLATE DEVICE CP CIODEV_BAT ; BAT: ? JR Z,CIO_BAT ; YES, GO TO BAT DEVICE HANDLER CP CIODEV_NUL ; NUL: ? JR Z,CIO_NUL ; YES, GO TO NUL DEVICE HANDLER CALL PANIC ; SOMETHING BAD HAPPENED ; ; BAT: IS A PSEUDO DEVICE REDIRECTING INPUT TO READER AND OUTPUT TO LIST ; CIO_BAT: LD C,E ; PUT CHAR BACK IN C LD A,B ; GET REQUESTED FUNCTION CP BF_CIOIN ; INPUT? JR Z,READER ; -> READER CP BF_CIOIST ; INPUT STATUS? JR Z,READERST ; -> READER CP BF_CIOOUT ; OUTPUT? JR Z,LIST ; -> LIST CP BF_CIOOST ; OUTPUT STATUS? JR Z,LISTST ; -> LIST CALL PANIC ; SOMETHING BAD HAPPENED ; ; NUL: IS A DUMMY DEVICE THAT DOES NOTHING ; CIO_NUL: LD A,B ; FUNCTION CP BF_CIOIN JR Z,NUL_IN CP BF_CIOIST JR Z,NUL_IST CP BF_CIOOUT JR Z,NUL_OUT CP BF_CIOOST JR Z,NUL_OST CALL PANIC ; NUL_IN: LD E,$1B ; RETURN EOF NUL_OUT: RET ; NUL_IST: NUL_OST: OR $FF ; A=$FF & NZ SET RET ; ;================================================================================================== ; DISK BIOS FUNCTIONS ;================================================================================================== ; ;__________________________________________________________________________________________________ SELDSK: ; SELECT DISK NUMBER FOR SUBSEQUENT DISK OPS #IF DSKTRACE CALL PRTSELDSK ; *DEBUG* #ENDIF ; JP DSK_SELECT ; ;__________________________________________________________________________________________________ HOME: ; SELECT TRACK 0 (BC = 0) AND FALL THRU TO SETTRK #IF DSKTRACE CALL PRTHOME ; *DEBUG* #ENDIF ; LD A,(HSTWRT) ; CHECK FOR PENDING WRITE OR A ; SET FLAGS JR NZ,HOMED ; BUFFER IS DIRTY LD (HSTACT),A ; CLEAR HOST ACTIVE FLAG ; HOMED: LD BC,0 ; ;__________________________________________________________________________________________________ SETTRK: ; SET TRACK GIVEN BY REGISTER BC LD (SEKTRK),BC RET ; ;__________________________________________________________________________________________________ SETSEC: ; SET SECTOR GIVEN BY REGISTER BC LD (SEKSEC),BC RET ; ;__________________________________________________________________________________________________ SECTRN: ; SECTOR TRANSLATION FOR SKEW, HARD CODED 1:1, NO SKEW IMPLEMENTED LD H,B LD L,C RET ; ;__________________________________________________________________________________________________ SETDMA: LD (DMAADR),BC RET ; ;__________________________________________________________________________________________________ READ: LD A,DOP_READ JR READWRITE ; ;__________________________________________________________________________________________________ WRITE: LD A,C LD (WRTYPE),A ; SAVE WRITE TYPE LD A,DOP_WRITE JR READWRITE ; ;__________________________________________________________________________________________________ READWRITE: LD (DSKOP),A ; SET THE ACTIVE DISK OPERATION JR BLKRW ; ;================================================================================================== ; BLOCKED READ/WRITE (BLOCK AND BUFFER FOR 512 BYTE SECTOR) ;================================================================================================== ; ;__________________________________________________________________________________________________ ; ; RESET (DE)BLOCKING ALGORITHM - JUST MARK BUFFER INVALID ; NOTE: BUFFER CONTENTS INVALIDATED, BUT RETAIN ANY PENDING WRITE ; BLKRES: XOR A LD (HSTACT),A ; BUFFER NO LONGER VALID LD (UNACNT),A ; CLEAR UNALLOC COUNT RET ;__________________________________________________________________________________________________ ; ; FLUSH (DE)BLOCKING ALGORITHM - DO PENDING WRITES ; BLKFLSH: ; CHECK FOR BUFFER WRITTEN (DIRTY) LD A,(HSTWRT) ; GET BUFFER WRITTEN FLAG OR A RET Z ; NOT DIRTY, RETURN WITH A=0 AND Z SET ; CLEAR THE BUFFER WRITTEN FLAG (EVEN IF A WRITE ERROR OCCURS) XOR A ; Z = 0 LD (HSTWRT),A ; SAVE IT ; DO THE WRITE AND RETURN RESULT JP DSK_WRITE #IF WRTCACHE WRT_ALC .EQU 0 ; WRITE TO ALLOCATED WRT_DIR .EQU 1 ; WRITE TO DIRECTORY WRT_UNA .EQU 2 ; WRITE TO UNALLOCATED ; ;__________________________________________________________________________________________________ ; ; (DE)BLOCKING READ/WRITE ROUTINE. MANAGES PHYSICAL DISK BUFFER AND CALLS ; PHYSICAL READ/WRITE ROUTINES APPROPRIATELY. ; BLKRW: #IF DSKTRACE CALL PRTDSKOP ; *DEBUG* #ENDIF ; FIX!!! WE ABORT ON FIRST ERROR, DRI SEEMS TO PASS ERROR STATUS TO THE END!!! ; IF WRITE OPERATION, GO TO SPECIAL WRITE PROCESSING LD A,(DSKOP) ; GET REQUESTED OPERATION CP DOP_WRITE ; WRITE JR Z,BLKRW1 ; GO TO WRITE PROCESSING ; OTHERWISE, CLEAR OUT ANY SEQUENTIAL, UNALLOC WRITE PROCESSING ; AND GO DIRECTLY TO MAIN I/O XOR A ; ZERO TO A LD (WRTYPE),A ; SET WRITE TYPE = 0 (WRT_ALC) TO ENSURE READ OCCURS LD (UNACNT),A ; SET UNACNT TO ABORT SEQ WRITE PROCESSING JR BLKRW4 ; GO TO I/O BLKRW1: ; WRITE PROCESSING ; CHECK FOR FIRST WRITE TO UNALLOCATED BLOCK LD A,(WRTYPE) ; GET WRITE TYPE CP WRT_UNA ; IS IT WRITE TO UNALLOC? JR NZ,BLKRW2 ; NOPE, BYPASS ; INITIALIZE START OF SEQUENTIAL WRITING TO UNALLOCATED BLOCK ; AND THEN TREAT SUBSEQUENT PROCESSING AS A NORMAL WRITE CALL UNA_INI ; INITIALIZE SEQUENTIAL WRITE TRACKING XOR A ; A = 0 = WRT_ALC LD (WRTYPE),A ; NOW TREAT LIKE WRITE TO ALLOCATED BLKRW2: ; IF WRTYPE = WRT_ALC AND SEQ WRITE, GOTO BLKRW7 (SKIP READ) OR A ; NOTE: A WILL ALREADY HAVE THE WRITE TYPE HERE JR NZ,BLKRW3 ; NOT TYPE = 0 = WRT_ALC, SO MOVE ON CALL UNA_CHK ; CHECK FOR CONTINUATION OF SEQ WRITES TO UNALLOCATED BLOCK JR NZ,BLKRW3 ; NOPE, ABORT ; WE MATCHED EVERYTHING, TREAT AS WRITE TO UNALLOCATED BLOCK LD A,WRT_UNA ; WRITE TO UNALLOCATED LD (WRTYPE),A ; SAVE WRITE TYPE CALL UNA_INC ; INCREMENT SEQUENTIAL WRITE TRACKING JR BLKRW4 ; PROCEED TO I/O PROCESSING BLKRW3: ; NON-SEQUENTIAL WRITE DETECTED, STOP ANY FURTHER CHECKING XOR A ; ZERO LD (UNACNT),A ; CLEAR UNALLOCATED WRITE COUNT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; IS A FLUSH NEEDED HERE??? ; FLUSH CURRENT BUFFER CONTENTS IF NEEDED ;CALL BLKFLSH ; FLUSH PENDING WRITES ;RET NZ ; ABORT ON ERROR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BLKRW4: ; START OF ACTUAL I/O PROCESSING CALL BLK_XLT ; DO THE LOGICAL TO PHYSICAL MAPPING: SEK... -> XLT... CALL BLK_CMP ; IS THE DESIRED PHYSICAL BLOCK IN BUFFER? JR Z,BLKRW6 ; BLOCK ALREADY IN ACTIVE BUFFER, NO READ REQUIRED ; AT THIS POINT, WE KNOW WE NEED TO READ THE TARGET PHYSICAL SECTOR ; IT MAY ACTUALLY BE A PREREAD FOR A SUBSEQUENT WRITE, BUT THAT IS OK ; FIRST, FLUSH CURRENT BUFFER CONTENTS CALL BLKFLSH ; FLUSH PENDING WRITES RET NZ ; ABORT ON ERROR ; IMPLEMENT THE TRANSLATED VALUES CALL BLK_SAV ; SAVE XLAT VALUES: XLT... -> HST... ; IF WRITE TO UNALLOC BLOCK, BYPASS READ, LEAVES BUFFER UNDEFINED LD A,(WRTYPE) CP 2 JR Z,BLKRW6 ; DO THE ACTUAL READ CALL DSK_READ ; READ PHYSICAL SECTOR INTO BUFFER JR Z,BLKRW6 ; GOOD READ, CONTINUE ; IF READ FAILED, RESET (DE)BLOCKING ALGORITHM AND RETURN ERROR PUSH AF ; SAVE ERROR STATUS CALL BLKRES ; INVALIDATE (DE)BLOCKING BUFFER POP AF ; RECOVER ERROR STATUS RET ; ERROR RETURN BLKRW6: ; CHECK TYPE OF OPERATIONS, IF WRITE, THEN GO TO WRITE PROCESSING LD A,(DSKOP) ; GET PENDING OPERATION CP DOP_WRITE ; IS IT A WRITE? JR Z,BLKRW7 ; YES, GO TO WRITE PROCESSING ; THIS IS A READ OPERATION, WE ALREADY DID THE I/O, NOW JUST DEBLOCK AND RETURN CALL BLK_DEBLOCK ; EXTRACT DATA FROM BLOCK XOR A ; NO ERROR RET ; ALL DONE BLKRW7: ; THIS IS A WRITE OPERATION, INSERT DATA INTO BLOCK CALL BLK_BLOCK ; INSERT DATA INTO BLOCK ; MARK THE BUFFER AS WRITTEN LD A,TRUE ; BUFFER DIRTY = TRUE LD (HSTWRT),A ; SAVE IT ; CHECK WRITE TYPE, IF WRT_DIR, FORCE THE PHYSICAL WRITE LD A,(WRTYPE) ; GET WRITE TYPE CP WRT_DIR ; 1 = DIRECTORY WRITE ; JR Z,BLKFLSH ; FLUSH PENDING WRITES AND RETURN STATUS JP Z,BLKFLSH ; FLUSH PENDING WRITES AND RETURN STATUS XOR A ; ALL IS WELL, SET RETURN CODE 0 RET ; RETURN ; ;__________________________________________________________________________________________________ ; ; INITIALIZE TRACKING OF SEQUENTIAL WRITES INTO UNALLOCATED BLOCK ; SETUP UNA... VARIABLES ; UNA_INI: ; COPY SEKDSK/TRK/SEC TO UNA... LD HL,SEK LD DE,UNA LD BC,UNASIZ LDIR ; SETUP UNACNT AND UNASPT LD HL,(SEKDPH) ; HL POINTS TO DPH LD DE,10 ; OFFSET OF DPB ADDRESS IN DPH ADD HL,DE ; DPH POINTS TO DPB ADDRESS LD A,(HL) INC HL LD H,(HL) LD L,A ; HL POINTS TO DPB LD C,(HL) INC HL LD B,(HL) ; BC HAS SPT LD (UNASPT),BC ; SAVE SECTORS PER TRACK DEC HL DEC HL ; HL POINTS TO RECORDS PER BLOCK (BYTE IN FRONT OF DPB) LD A,(HL) ; GET IT LD (UNACNT),A ; SAVE IT RET ; ;__________________________________________________________________________________________________ ; ; CHECK FOR CONTINUATION OF SEQUENTIAL WRITES TO UNALLOCATED BLOCK ; SEE IF UNACNT > 0 AND UNA... VARIABLES MATCH SEK... VARIABLES ; UNA_CHK: LD A,(UNACNT) ; GET THE COUNTER OR A JR NZ,UNA_CHK1 ; IF NOT DONE WITH BLOCK, KEEP CHECKING ; CNT IS NOW ZERO, EXHAUSTED RECORDS IN ONE BLOCK! DEC A ; HACK TO SET NZ RET ; RETURN WITH NZ UNA_CHK1: ; COMPARE UNA... VARIABLES WITH SEK... VARIABLES LD HL,SEK LD DE,UNA LD B,UNASIZ JR BLK_CMPLOOP ; ;__________________________________________________________________________________________________ ; ; INCREMENT THE SEQUENTIAL WRITE TRACKING VARIABLES ; TO REFLECT THE NEXT RECORD (TRK/SEC) WE EXPECT ; UNA_INC: ; DECREMENT THE BLOCK RECORD COUNT LD HL,UNACNT DEC (HL) ; INCREMENT THE SECTOR LD DE,(UNASEC) INC DE LD (UNASEC),DE ; CHECK FOR END OF TRACK LD HL,(UNASPT) XOR A SBC HL,DE RET NZ ; HANDLE END OF TRACK LD (UNASEC),HL ; SECTOR BACK TO 0 (NOTE: HL=0 AT THIS POINT) LD HL,(UNATRK) ; GET CURRENT TRACK INC HL ; BUMP IT LD (UNATRK),HL ; SAVE IT RET #ELSE ; ;__________________________________________________________________________________________________ ; ; (DE)BLOCKING READ/WRITE ROUTINE. MANAGES PHYSICAL DISK BUFFER AND CALLS ; PHYSICAL READ/WRITE ROUTINES APPROPRIATELY. ; BLKRW: #IF DSKTRACE CALL PRTDSKOP ; *DEBUG* #ENDIF CALL BLK_XLT ; SECTOR XLAT: SEK... -> XLT... CALL BLK_CMP ; IN BUFFER? JR Z,BLKRW1 ; YES, BYPASS READ CALL BLK_SAV ; SAVE XLAT VALUES: XLT... -> HST... LD A,FALSE ; ASSUME FAILURE, INVALIDATE BUFFER LD (HSTACT),A ; SAVE IT CALL DSK_READ ; READ PHYSICAL SECTOR INTO BUFFER RET NZ ; BAIL OUT ON ERROR BLKRW1: LD A,(DSKOP) ; GET PENDING OPERATION CP DOP_WRITE ; IS IT A WRITE? JR Z,BLKRW2 ; YES, GO TO WRITE ROUTINE CALL BLK_DEBLOCK ; EXTRACT DATA FROM BLOCK XOR A ; NO ERROR RET ; ALL DONE BLKRW2: CALL BLK_BLOCK ; INSERT DATA INTO BLOCK CALL DSK_WRITE ; WRITE PHYSICAL SECTOR FROM BUFFER RET NZ ; BAIL OUT ON ERROR LD A,TRUE ; BUFFER IS NOW VALID LD (HSTACT),A ; SAVE IT XOR A ; ALL IS WELL, SET RETURN CODE 0 RET ; RETURN #ENDIF ; ;__________________________________________________________________________________________________ ; ; TRANSLATE FROM CP/M DSK/TRK/SEC TO PHYSICAL ; SEK... -> XLT... ; BLK_XLT: ; FIRST, DO A BYTE COPY OF SEK... TO XLT... LD HL,SEK LD DE,XLT LD BC,XLTSIZ LDIR ; NOW UPDATE XLTSEC BASED ON (DE)BLOCKING FACTOR (ALWAYS 4:1) LD BC,(SEKSEC) ; SECTOR IS FACTORED DOWN (4:1) DUE TO BLOCKING SRL B ; 16 BIT RIGHT SHIFT TWICE TO DIVIDE BY 4 RR C SRL B RR C LD (XLTSEC),BC RET ; ;__________________________________________________________________________________________________ ; ; SAVE RESULTS OF TRANSLATION: XLT... -> HST... ; IMPLICITLY SETS HSTACT TO TRUE! ; BLK_SAV: LD HL,XLT LD DE,HST LD BC,XLTSIZ LDIR RET ; ;__________________________________________________________________________________________________ ; ; COMPARE RESULTS OF TRANSLATION TO CURRENT BUF (XLT... TO HST...) ; NOTE THAT HSTACT IS COMPARED TO XLTACT IMPLICITLY! XLTACT IS ALWAYS TRUE, SO ; HSTACT MUST BE TRUE FOR COMPARE TO SUCCEED. ; BLK_CMP: LD HL,XLT LD DE,HST LD B,XLTSIZ BLK_CMPLOOP: LD A,(DE) CP (HL) RET NZ ; BAD COMPARE, RETURN WITH NZ INC HL INC DE DJNZ BLK_CMPLOOP RET ; RETURN WITH Z ; ;__________________________________________________________________________________________________ ; ; BLOCK DATA - INSERT CPM DMA BUF INTO PROPER PART OF PHYSICAL SECTOR BUFFER ; BLK_BLOCK: #IF (PLATFORM == PLT_UNA) CALL BLK_SETUP EX DE,HL LD BC,128 LDIR RET #ELSE LD C,BID_USR ; C=SRC=USER BANK=TPA LD B,BID_HB ; B=DEST=HBIOS CALL HB_XCOPY ; HB_XCOPY CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION EX DE,HL ; SWAP HL/DE FOR BLOCK OPERATION LD BC,128 ; DMA BUFFER SIZE CALL HB_COPY ; HB_COPY (INTERBANK COPY) RET #ENDIF ; ;__________________________________________________________________________________________________ ; ; DEBLOCK DATA - EXTRACT DESIRED CPM DMA BUF FROM PHYSICAL SECTOR BUFFER ; BLK_DEBLOCK: #IF (PLATFORM == PLT_UNA) CALL BLK_SETUP LD BC,128 LDIR RET #ELSE LD C,BID_HB ; C=SRC=HBIOS LD B,BID_USR ; B=DEST=USER BANK=TPA CALL HB_XCOPY ; HB_XCOPY CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION LD BC,128 ; DMA BUFFER SIZE CALL HB_COPY ; HB_COPY (INTERBANK COPY) RET #ENDIF ; ;__________________________________________________________________________________________________ ; ; SETUP SOURCE AND DESTINATION POINTERS FOR BLOCK COPY OPERATION ; AT EXIT, HL = ADDRESS OF DESIRED BLOCK IN SECTOR BUFFER, DE = DMA ; BLK_SETUP: LD BC,(SEKSEC) LD A,C AND 3 ; A = INDEX OF CPM BUF IN SEC BUF RRCA ; MULTIPLY BY 64 RRCA LD E,A ; INTO LOW ORDER BYTE OF DESTINATION LD D,0 ; HIGH ORDER BYTE IS ZERO LD HL,(BUFADR) ; HL = START OF SEC BUF ADD HL,DE ; ADD IN COMPUTED OFFSET ADD HL,DE ; HL NOW = INDEX * 128 (SOURCE) LD DE,(DMAADR) ; DE = DESTINATION = DMA BUF RET ; ;================================================================================================== ; PHYSICAL DISK INTERFACE ;================================================================================================== ; ; LOOKUP DISK INFORMATION BASED ON CPM DRIVE IN C ; ON RETURN, D=DEVICE/UNIT, E=SLICE, HL=DPH ADDRESS ; DSK_GETINF: #IF (PLATFORM == PLT_UNA) LD HL,(UNA_DRVMAP) ; HL := START OF UNA DRIVE MAP #ELSE LD HL,DRVMAP ; HL := START OF DRIVE MAP #ENDIF DEC HL ; POINT TO DRIVE COUNT LD A,C ; A := CPM DRIVE CP (HL) ; COMPARE TO NUMBER OF DRIVES CONFIGURED JR NC,DSK_GETINF1 ; IF OUT OF RANGE, GO TO ERROR RETURN INC HL ; POINT TO START OF DRIVE MAP ; RLCA ; MULTIPLY A BY 4... RLCA ; TO USE AS OFFSET INTO ???? MAP CALL ADDHLA ; ADD OFFSET LD D,(HL) ; D := DEVICE/UNIT INC HL ; BUMP TO SLICE LD E,(HL) ; E := SLICE INC HL ; POINT TO DPH LSB LD A,(HL) ; A := DPH LSB INC HL ; POINT TO DPH MSB LD H,(HL) ; H := DPH MSB LD L,A ; L := DPH LSB LD A,H ; TEST FOR INVALID DPH OR L ; ... BY CHECKING FOR ZERO VALUE JR Z,DSK_GETINF1 ; HANDLE ZERO DPH, DRIVE IS INVALID XOR A ; SET SUCCESS RET ; DSK_GETINF1: ; ERROR RETURN XOR A LD H,A LD L,A LD D,A LD E,A INC A RET ; ; ; DSK_SELECT: LD B,E ; SAVE E IN B FOR NOW CALL DSK_GETINF ; GET D=DEVICE/UNIT, E=SLICE, HL=DPH ADDRESS RET NZ ; RETURN IF INVALID DRIVE (A=1, NZ SET, HL=0) PUSH BC ; WE NEED B LATER, SAVE ON STACK ; ; SAVE ALL THE NEW STUFF LD A,C ; A := CPM DRIVE NO LD (SEKDSK),A ; SAVE IT LD A,D ; A := DEVICE/UNIT LD (SEKDU),A ; SAVE DEVICE/UNIT LD (SEKDPH),HL ; SAVE DPH POINTER ; ; UPDATE OFFSET FOR ACTIVE SLICE ; A TRACK IS ASSUMED TO BE 16 SECTORS ; THE OFFSET REPRESENTS THE NUMBER OF BLOCKS * 256 ; TO USE AS THE OFFSET LD H,65 ; H = TRACKS PER SLICE, E = SLICE NO CALL MULT8 ; HL := H * E (TOTAL TRACK OFFSET) LD (SEKOFF),HL ; SAVE NEW TRACK OFFSET ; ; CHECK IF THIS IS LOGIN, IF NOT, BYPASS MEDIA DETECTION ; FIX: WHAT IF PREVIOUS MEDIA DETECTION FAILED??? POP BC ; GET ORIGINAL E INTO B BIT 0,B ; TEST DRIVE LOGIN BIT #IF (PLATFORM == PLT_UNA) JR DSK_SELECT2 ; NO MEDIA DETECTION FOR UNA #ENDIF JR NZ,DSK_SELECT2 ; BYPASS MEDIA DETECTION ; ; DETERMINE MEDIA IN DRIVE LD A,(SEKDU) ; GET DEVICE/UNIT LD C,A ; STORE IN C LD B,BF_DIOMED ; DRIVER FUNCTION = DISK MEDIA RST 08 OR A ; SET FLAGS LD HL,0 ; ASSUME FAILURE RET Z ; BAIL OUT IF NO MEDIA ; ; A HAS MEDIA ID, SET HL TO CORRESPONDING DPBMAP ENTRY LD HL,DPBMAP ; HL = DPBMAP RLCA ; DPBMAP ENTRIES ARE 2 BYTES EACH CALL ADDHLA ; ADD OFFSET TO HL ; ; LOOKUP THE ACTUAL DPB ADDRESS NOW LD E,(HL) ; DEREFERENCE HL... INC HL ; INTO DE... LD D,(HL) ; DE = ADDRESS OF DESIRED DPB ; ; PLUG DPB INTO THE ACTIVE DPH LD HL,(SEKDPH) LD BC,10 ; OFFSET OF DPB IN DPH ADD HL,BC ; HL := DPH.DPB LD (HL),E ; SET LSB OF DPB IN DPH INC HL ; BUMP TO MSB LD (HL),D ; SET MSB OF DPB IN DPH ; DSK_SELECT2: LD HL,(SEKDPH) ; HL = DPH ADDRESS FOR CP/M XOR A ; FLAG SUCCESS RET ; NORMAL RETURN ; ; ; DSK_STATUS: #IF (PLATFORM == PLT_UNA) XOR A ; ASSUME OK FOR NOW RET ; RETURN #ENDIF ; C HAS CPM DRIVE, LOOKUP DEVICE/UNIT AND CHECK FOR INVALID DRIVE CALL DSK_GETINF ; B = DEVICE/UNIT RET NZ ; INVALID DRIVE ERROR ; VALID DRIVE, DISPATCH TO DRIVER LD C,D ; C := DEVICE/UNIT LD B,BF_DIOST ; B := FUNCTION: STATUS RST 08 RET ; ; ; DSK_READ: ; SET B = FUNCTION: READ LD B,BF_DIORD JR DSK_IO ; ; ; DSK_WRITE: ; SET B = FUNCTION: WRITE LD B,BF_DIOWR JR DSK_IO ; ; ; #IF (PLATFORM == PLT_UNA) DSK_IO: DSK_IO1: PUSH BC LD DE,(HSTTRK) ; GET TRACK INTO HL LD B,4 ; PREPARE TO LEFT SHIFT BY 4 BITS DSK_IO2: SLA E ; SHIFT DE LEFT BY 4 BITS RL D DJNZ DSK_IO2 ; LOOP TILL ALL BITS DONE LD A,(HSTSEC) ; GET THE SECTOR INTO A AND $0F ; GET RID OF TOP NIBBLE OR E ; COMBINE WITH E LD E,A ; BACK IN E LD HL,0 ; HL:DE NOW HAS SLICE RELATIVE LBA ; APPLY OFFSET NOW ; OFFSET IS EXPRESSED AS NUMBER OF BLOCKS * 256 TO OFFSET! LD A,(HSTOFF) ; LSB OF SLICE OFFSET TO A ADD A,D ; ADD WITH D LD D,A ; PUT IT BACK IN D LD A,(HSTOFF+1) ; MSB OF SLICE OFFSET TO A CALL ADDHLA ; ADD OFFSET POP BC ; RECOVER FUNCTION IN B LD A,(HSTDU) ; GET THE DEVICE/UNIT VALUE LD C,A ; PUT IT IN C ; DISPATCH TO DRIVER PUSH BC EX DE,HL ; DE:HL NOW HAS LBA LD B,C ; UNIT TO B LD C,$41 ; UNA SET LBA RST 08 ; CALL UNA CALL NZ,PANIC POP BC ; RECOVER B=FUNC, C=UNIT LD E,C ; UNIT TO E LD C,B ; FUNC TO C LD B,E ; UNIT TO B LD DE,(BUFADR) ; SET BUFFER ADDRESS LD HL,1 ; 1 SECTOR ;CALL PC_SPACE ;LD A,B ;CALL PRTHEXBYTE RST 08 CALL NZ,PANIC XOR A ; SET FLAGS BASED ON RESULT RET #ELSE DSK_IO: LD A,(HSTDU) ; GET ACTIVE DEVICE/UNIT BYTE AND $F0 ; ISOLATE DEVICE PORTION CP DIODEV_FD ; FLOPPY? JR NZ,DSK_IO1 ; NO, USE LBA HANDLING ; SET HL=TRACK (ADD IN TRACK OFFSET) LD DE,(HSTOFF) ; DE = TRACK OFFSET FOR LU SUPPORT LD HL,(HSTTRK) ; HL = TRACK # ADD HL,DE ; APPLY OFFSET FOR ACTIVE SLICE ; SET DE=SECTOR LD DE,(HSTSEC) ; DE = SECTOR # ; SET C = DEVICE/UNIT LD A,(HSTDU) ; LOAD DEVICE/UNIT VALUE LD C,A ; SAVE IN C ; DISPATCH TO DRIVER RST 08 OR A ; SET FLAGS BASED ON RESULT RET ; NEW LBA HANDLING ; COERCE TRACK/SECTOR INTO HL:DE AS 0000:TTTS DSK_IO1: PUSH BC LD DE,(HSTTRK) ; GET TRACK INTO HL LD B,4 ; PREPARE TO LEFT SHIFT BY 4 BITS DSK_IO2: SLA E ; SHIFT DE LEFT BY 4 BITS RL D DJNZ DSK_IO2 ; LOOP TILL ALL BITS DONE LD A,(HSTSEC) ; GET THE SECTOR INTO A AND $0F ; GET RID OF TOP NIBBLE OR E ; COMBINE WITH E LD E,A ; BACK IN E LD HL,0 ; HL:DE NOW HAS SLICE RELATIVE LBA ; APPLY OFFSET NOW ; OFFSET IS EXPRESSED AS NUMBER OF BLOCKS * 256 TO OFFSET! LD A,(HSTOFF) ; LSB OF SLICE OFFSET TO A ADD A,D ; ADD WITH D LD D,A ; PUT IT BACK IN D LD A,(HSTOFF+1) ; MSB OF SLICE OFFSET TO A CALL ADDHLA ; ADD OFFSET POP BC ; RECOVER FUNCTION IN B LD A,(HSTDU) ; GET THE DEVICE/UNIT VALUE LD C,A ; PUT IT IN C ; DISPATCH TO DRIVER RST 08 OR A ; SET FLAGS BASED ON RESULT RET #ENDIF ; ;================================================================================================== ; UTILITY FUNCTIONS ;================================================================================================== ; #DEFINE CIOMODE_CBIOS ORG_UTIL .EQU $ #INCLUDE "util.asm" SIZ_UTIL .EQU $ - ORG_UTIL .ECHO "UTIL occupies " .ECHO SIZ_UTIL .ECHO " bytes.\n" ; ;================================================================================================== ; DIAGNOSTICS ;================================================================================================== ; #IF DSKTRACE ;__________________________________________________________________________________________________ PRTSELDSK: CALL NEWLINE PUSH BC PUSH DE LD B,E LD DE,STR_SELDSK CALL WRITESTR CALL PC_SPACE LD DE,STR_DSK LD A,C CALL PRTHEXBYTE CALL PC_SPACE CALL PC_LBKT LD A,B CALL PRTHEXBYTE CALL PC_RBKT POP DE POP BC RET ; ;__________________________________________________________________________________________________ PRTHOME: CALL NEWLINE LD DE,STR_HOME CALL WRITESTR RET ; ;__________________________________________________________________________________________________ PRTDSKOP: LD (XSTKSAV),SP LD SP,XSTK CALL NEWLINE LD A,(DSKOP) LD DE,STR_READ CP DOP_READ CALL Z,WRITESTR LD DE,STR_WRITE CP DOP_WRITE CALL Z,WRITESTR LD A,C CALL Z,PRTHEXBYTE LD DE,STR_DSK CALL WRITESTR LD A,(SEKDSK) CALL PRTHEXBYTE LD DE,STR_TRK CALL WRITESTR LD BC,(SEKTRK) CALL PRTHEXWORD LD DE,STR_SEC CALL WRITESTR LD BC,(SEKSEC) CALL PRTHEXWORD LD SP,(XSTKSAV) RET RET XSTKSAV .DW 0 .FILL $20 XSTK .EQU $ ; STR_SELDSK .DB "SELDSK$" STR_HOME .DB "HOME$" STR_READ .DB "READ$" STR_WRITE .DB "WRITE$" STR_DSK .DB " DSK=$" STR_TRK .DB " TRK=$" STR_SEC .DB " SEC=$" ; #ENDIF ; ;================================================================================================== ; DATA ;================================================================================================== ; ;STR_READONLY .DB "\r\nCBIOS Err: Read Only Drive$" ;STR_STALE .DB "\r\nCBIOS Err: Stale Drive$" ; SECADR .DW 0 ; ADDRESS OF SECTOR IN ROM/RAM PAGE DEFDRIVE .DB 0 ; DEFAULT DRIVE CCPBUF .DW 0 ; ADDRESS OF CCP BUF IN UNA BIOS ; ; DOS DISK VARIABLES ; DSKOP: .DB 0 ; DISK OPERATION (DOP_READ/DOP_WRITE) WRTYPE: .DB 0 ; WRITE TYPE (0=NORMAL, 1=DIR (FORCE), 2=FIRST RECORD OF BLOCK) DMAADR: .DW 0 ; DIRECT MEMORY ADDRESS HSTWRT: .DB 0 ; TRUE = BUFFER IS DIRTY BUFADR: .DW $8000-$400 ; ADDRESS OF PHYSICAL SECTOR BUFFER (DEFAULT MATCHES HBIOS) ; ; DISK I/O REQUEST PENDING ; SEK: SEKDSK: .DB 0 ; DISK NUMBER 0-15 SEKTRK: .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL) SEKSEC: .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL) SEKDU: .DB 0 ; DEVICE/UNIT SEKDPH: .DW 0 ; ADDRESS OF ACTIVE (SELECTED) DPH SEKOFF: .DW 0 ; TRACK OFFSET IN EFFECT FOR LU SEKACT: .DB TRUE ; ALWAYS TRUE! ; ; RESULT OF CPM TO PHYSICAL TRANSLATION ; XLT: XLTDSK .DB 0 XLTTRK .DW 0 XLTSEC .DW 0 XLTDU .DB 0 XLTDPH .DW 0 XLTOFF: .DW 0 XLTACT .DB TRUE ; ALWAYS TRUE! ; XLTSIZ .EQU $ - XLT ; ; DSK/TRK/SEC IN BUFFER (VALID WHEN HSTACT=TRUE) ; HST: HSTDSK .DB 0 ; DISK IN BUFFER HSTTRK .DW 0 ; TRACK IN BUFFER HSTSEC .DW 0 ; SECTOR IN BUFFER HSTDU .DB 0 ; DEVICE/UNIT IN BUFFER HSTDPH .DW 0 ; CURRENT DPH ADDRESS HSTOFF .DW 0 ; TRACK OFFSET IN EFFECT FOR LU HSTACT .DB 0 ; TRUE = BUFFER HAS VALID DATA ; ; SEQUENTIAL WRITE TRACKING FOR UNALLOCATED BLOCK ; UNA: UNADSK: .DB 0 ; DISK NUMBER 0-15 UNATRK: .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL) UNASEC: .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL) ; UNASIZ .EQU $ - UNA ; UNACNT: .DB 0 ; COUNT DOWN UNALLOCATED RECORDS IN BLOCK UNASPT: .DW 0 ; SECTORS PER TRACK ; #IF (PLATFORM == PLT_UNA) UNA_DRVMAP .DW 0 #ENDIF ; ;================================================================================================== ; DISK CONTROL STRUCTURES (DPB, DPH) ;================================================================================================== ; RAMBLKS .EQU (((BID_RAMDN - BID_RAMD + 1) * 32) / 2) CKS_RAM .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA ALS_RAM .EQU ((RAMBLKS + 7) / 8) ; ALS: BLKS / 8 (ROUNDED UP) ; ROMBLKS .EQU (((BID_ROMDN - BID_ROMD + 1) * 32) / 2) CKS_ROM .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA ALS_ROM .EQU ((ROMBLKS + 7) / 8) ; ALS: BLKS / 8 (ROUNDED UP) ; CKS_FD .EQU 64 ; CKS: DIR ENT / 4 = 256 / 4 = 64 ALS_FD .EQU 128 ; ALS: BLKS / 8 = 1024 / 8 = 128 ; CKS_HD .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA ALS_HD .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) ; ; ; DISK PARAMETER BLOCKS ; ; BLS BSH BLM EXM (DSM<256) EXM (DSM>255) ; ---------- --- --- ------------- ------------- ; 1,024 3 7 0 N/A ; 2,048 4 15 1 0 ; 4,096 5 31 3 1 ; 8,192 6 63 7 3 ; 16,384 7 127 15 7 ; ; AL0/1: EACH BIT SET ALLOCATES A BLOCK OF DIR ENTRIES. EACH DIR ENTRY ; IS 32 BYTES. BIT COUNT = (((DRM + 1) * 32) / BLS) ; ; CKS = (DIR ENT / 4), ZERO FOR NON-REMOVABLE MEDIA ; ; ALS = TOTAL BLKS (DSM + 1) / 8 ;__________________________________________________________________________________________________ ; ; ROM DISK: 64 SECS/TRK (LOGICAL), 128 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 ; ROM DISK SIZE = TOTAL ROM - 32K RESERVED FOR SYSTEM USE ; .DW CKS_ROM .DW ALS_ROM .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_ROM: .DW 64 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK #IF ((ROMBLKS - 1) < 256) .DB 1 ; EXM: EXTENT MASK #ELSE .DB 0 ; EXM: EXTENT MASK #ENDIF .DW ROMBLKS - 1 ; DSM: TOTAL STORAGE IN BLOCKS - 1 .DW 255 ; DRM: DIR ENTRIES - 1 = 255 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA .DW 0 ; OFF: ROM DISK HAS NO SYSTEM AREA ;__________________________________________________________________________________________________ ; ; RAM DISK: 64 SECS/TRK, 128 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 ; RAM DISK SIZE = TOTAL RAM - 64K RESERVED FOR SYSTEM USE ; .DW CKS_RAM .DW ALS_RAM .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_RAM: .DW 64 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK #IF ((RAMBLKS - 1) < 256) .DB 1 ; EXM: EXTENT MASK #ELSE .DB 0 ; EXM: EXTENT MASK #ENDIF .DW RAMBLKS - 1 ; DSM: TOTAL STORAGE IN BLOCKS - 1 .DW 255 ; DRM: DIR ENTRIES - 1 = 255 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA .DW 0 ; OFF: RESERVED TRACKS = 0 TRK ;__________________________________________________________________________________________________ ; ; 4MB RAM FLOPPY DRIVE, 32 TRKS, 1024 SECS/TRK, 128 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 ; SEC/TRK ENGINEERED SO THAT AFTER DEBLOCKING, SECTOR NUMBER OCCUPIES 1 BYTE (0-255) ; .DW CKS_HD .DW ALS_HD .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_RF: .DW 1024 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK .DB 0 ; EXM: EXTENT MASK .DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = (4MB / 2K BLS) - 1 = 2047 .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA .DW 0 ; OFF: RESERVED TRACKS = 0 TRK ;__________________________________________________________________________________________________ ; ; GENERIC HARD DISK DRIVE (8MB DATA SPACE + 128K RESERVED SPACE) ; LOGICAL: 1040 TRKS (16 RESERVED), 64 SECS/TRK, 128 BYTES/SEC ; PHYSICAL: 65 CYLS (1 RESERVED), 16 HEADS/CYL, 16 SECS/TRK, 512 BYTES/SEC ; BLOCKSIZE (BLS) = 4K, DIRECTORY ENTRIES = 512 ; .DW CKS_HD .DW ALS_HD .DB (4096 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_HD: .DW 64 ; SPT: SECTORS PER TRACK .DB 5 ; BSH: BLOCK SHIFT FACTOR .DB 31 ; BLM: BLOCK MASK .DB 1 ; EXM: EXTENT MASK .DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 = (8MB / 4K BLS) - 1 = 2047 .DW 511 ; DRM: DIR ENTRIES - 1 = 512 - 1 = 511 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 0 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 .DW 16 ; OFF: RESERVED TRACKS = 16 TRKS * (16 TRKS * 16 HEADS * 16 SECS * 512 BYTES) = 128K ;__________________________________________________________________________________________________ ; ; IBM 720KB 3.5" FLOPPY DRIVE, 80 TRKS, 36 SECS/TRK, 512 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 128 ; .DW CKS_FD .DW ALS_FD .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_FD720: .DW 36 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK .DB 0 ; EXM: EXTENT MASK .DW 350 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((720K - 18K OFF) / 2K BLS) - 1 = 350 .DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127 .DB 11000000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4 .DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K ;__________________________________________________________________________________________________ ; ; IBM 1.44MB 3.5" FLOPPY DRIVE, 80 TRKS, 72 SECS/TRK, 512 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 ; .DW CKS_FD .DW ALS_FD .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_FD144: .DW 72 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK .DB 0 ; EXM: EXTENT MASK .DW 710 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,440K - 18K OFF) / 2K BLS) - 1 = 710 .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 72 SEC/TRK) = 18K ;__________________________________________________________________________________________________ ; ; IBM 360KB 5.25" FLOPPY DRIVE, 40 TRKS, 9 SECS/TRK, 512 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 128 ; .DW CKS_FD .DW ALS_FD .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_FD360: .DW 36 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK .DB 1 ; EXM: EXTENT MASK .DW 170 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((360K - 18K OFF) / 2K BLS) - 1 = 170 .DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4 .DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K ;__________________________________________________________________________________________________ ; ; IBM 1.20MB 5.25" FLOPPY DRIVE, 80 TRKS, 15 SECS/TRK, 512 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 ; .DW CKS_FD .DW ALS_FD .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_FD120: .DW 60 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK .DB 0 ; EXM: EXTENT MASK .DW 591 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,200K - 15K OFF) / 2K BLS) - 1 = 591 .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K ;__________________________________________________________________________________________________ ; ; IBM 1.11MB 8" FLOPPY DRIVE, 77 TRKS, 15 SECS/TRK, 512 BYTES/SEC ; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 ; .DW CKS_FD .DW ALS_FD .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) DPB_FD111: .DW 60 ; SPT: SECTORS PER TRACK .DB 4 ; BSH: BLOCK SHIFT FACTOR .DB 15 ; BLM: BLOCK MASK .DB 0 ; EXM: EXTENT MASK .DW 569 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,155K - 15K OFF) / 2K BLS) - 1 = 569 .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K ; #IF (PLATFORM == PLT_UNA) SECBUF .FILL 512,0 ; PHYSICAL DISK SECTOR BUFFER #ENDIF ; ;================================================================================================== ; CBIOS BUFFERS ;================================================================================================== ; ;BUFFERS: ; BUFPOOL .EQU $ ; START OF BUFFER POOL ; ;================================================================================================== ; COLD BOOT INITIALIZATION ; ; THIS CODE IS PLACED IN THE BDOS BUFFER AREA TO CONSERVE SPACE. SINCE ; COLD BOOT DOES NO DISK IO, SO THIS IS SAFE. ; ;================================================================================================== ; ; .ORG BUFFERS .FILL 16 * 4,0 ; RESERVED FOR DRVMAP TABLE .FILL 16 * 16,0 ; RESERVED FOR DPH TABLE ; INIT: ; THIS INIT CODE WILL BE OVERLAID, SO WE ARE GOING ; TO MODIFY THE BOOT ENTRY POINT TO CAUSE A PANIC ; TO EASILY IDENTIFY IF SOMETHING TRIES TO INVOKE ; THE BOOT ENTRY POINT AFTER INIT IS DONE. LD A,$CD ; "CALL" INSTRUCTION LD (BOOT),A ; STORE IT BOOT ENTRY POINT LD HL,PANIC ; ADDRESS OF PANIC ROUTINE LD (BOOT+1),HL ; STORE IT AT BOOT ENTRY + 1 #IF (PLATFORM == PLT_UNA) ; MAKE SURE UNA EXEC PAGE IS ACTIVE LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$800E ; SWITCH BACK TO EXEC BANK CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE) ; INSTALL UNA INVOCATION VECTOR FOR RST 08 LD A,$C3 ; JP INSTRUCTION LD (8),A ; STORE AT 0x0008 LD HL,($FFFE) ; UNA ENTRY VECTOR LD (9),HL ; STORE AT 0x0009 #ENDIF ; PARAMETER INITIALIZATION LD A,DEFIOBYTE ; LOAD DEFAULT IOBYTE LD (IOBYTE),A ; STORE IT #IF ((PLATFORM != PLT_N8) & (PLATFORM != PLT_MK4) & (PLATFORM != PLT_S100) & (PLATFORM != PLT_UNA)) IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE LD A,DEFIOBYTE ; ASSUME WE WANT DEFAULT IOBYTE VALUE JR NZ,INIT1 ; IF BIT6=1, NOT SHORTED, CONTINUE WITH DEFAULT LD A,ALTIOBYTE ; LOAD ALT IOBYTE VALUE INIT1: LD (IOBYTE),A ; SET THE ACTIVE IOBYTE #ENDIF ; DEFAULT DRIVE XOR A ; ZERO LD (DEFDRIVE),A ; STORE IT LD (CDISK),A ; SETUP CDISK ; STARTUP MESSAGE CALL NEWLINE ; FORMATTING LD DE,STR_BANNER ; POINT TO BANNER CALL WRITESTR ; DISPLAY IT CALL NEWLINE ; FORMATTING #IF (PLATFORM == PLT_UNA) ; SAVE COMMAND PROCESSOR IMAGE TO MALLOCED CACHE IN UNA BIOS PAGE LD C,$F7 ; UNA MALLOC LD DE,CCPSIZ ; SIZE OF CCP RST 08 ; DO IT CALL NZ,PANIC ; BIG PROBLEM LD (CCPBUF),HL ; SAVE THE ADDRESS (IN BIOS MEM) LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$800D ; UBIOS_PAGE (SEE PAGES.INC) RST 08 ; DO IT PUSH DE ; SAVE PREVIOUS BANK LD HL,CPM_LOC ; ADDRESS IN HI MEM OF CCP LD DE,(CCPBUF) ; ADDRESS OF CCP BUF IN BIOS MEM LD BC,CCPSIZ ; SIZE OF CCP LDIR ; DO IT LD BC,$01FB ; UNA FUNC = SET BANK POP DE ; RECOVER OPERATING BANK RST 08 ; DO IT #ELSE ; SAVE COMMAND PROCESSOR TO DEDICATED CACHE IN RAM BANK 1 LD C,BID_USR ; B = SRC BANK = USR BANK = TPA LD B,BID_HB ; C = DEST BANK = HB BANK CALL HB_XCOPY ; SET BANKS FOR INTERBANK COPY LD HL,CPM_LOC ; COPY FROM CCP LOCATION IN USR BANK LD DE,$800 ; TO FIXED LOCATION IN HB BANK LD BC,CCPSIZ ; COPY CONTENTS OF COMMAND PROCESSOR CALL HB_COPY ; DO IT #ENDIF ; SYSTEM INITIALIZATION CALL BLKRES ; RESET DISK (DE)BLOCKING ALGORITHM CALL MD_INIT ; INITIALIZE MEMORY DISK DRIVER (RAM/ROM) #IF (PLATFORM == PLT_UNA) CALL UNA_INIT #ENDIF CALL DPH_INIT ; INITIALIZE DPH TABLE AND BUFFERS CALL NEWLINE ; FORMATTING ; ; DISPLAY FREE MEMORY LD DE,STR_LDR ; FORMATTING CALL WRITESTR ; AND PRINT IT LD HL,CBIOS_END ; SUBTRACT HIGH WATER LD DE,(BUFTOP) ; ... FROM TOP OF CBIOS OR A ; ... WITH CF CLEAR SBC HL,DE ; ... SO HL GETS BYTES FREE CALL PRTDEC ; PRINT IT LD DE,STR_MEMFREE ; ADD DESCRIPTION CALL WRITESTR ; AND PRINT IT ; ; SETUP AUTOSTART COMMAND LD HL,CMD ; ADDRESS OF STARTUP COMMAND LD DE,CCP+7 ; START OF COMMAND BUFFER IN CCP LD BC,CMDLEN ; LENGTH OF AUTOSTART COMMAND LDIR ; INSTALL IT ; RET ; CMD .DB CMDLEN - 1 #IFDEF AUTOCMD .TEXT AUTOCMD #ENDIF .DB 0 CMDLEN .EQU $ - CMD ; STR_BANNER .DB OSLBL, " for ", PLATFORM_NAME, ", CBIOS v", BIOSVER, "$" STR_MEMFREE .DB " Disk Buffer Bytes Free\r\n$" ; ; ;__________________________________________________________________________________________________ MD_INIT: #IF (PLATFORM == PLT_UNA) ; ; INITIALIZE RAM DISK BY FILLING DIRECTORY WITH 'E5' BYTES ; FILL FIRST 8K OF RAM DISK TRACK 1 WITH 'E5' ; #IF (CLRRAMDISK != CLR_NEVER) LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$8000 ; FIRST BANK OF RAM DISK CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE) #IF (CLRRAMDISK == CLR_AUTO) ; CHECK FIRST 32 DIRECTORY ENTRIES. IF ANY START WITH AN INVALID ; VALUE, INIT THE RAM DISK. VALID ENTRIES ARE E5 (EMPTY ENTRY) OR ; 0-15 (USER NUMBER). LD HL,0 LD DE,32 LD B,32 CLRRAM0: LD A,(HL) CP 0E5H JR Z,CLRRAM1 ; E5 IS VALID CP 16 JR C,CLRRAM1 ; 0-15 IS ALSO VALID JR CLRRAM2 ; INVALID ENTRY! JUMP TO INIT CLRRAM1: ADD HL,DE ; LOOP FOR 32 ENTRIES DJNZ CLRRAM0 ; JR CLRRAM2 ; *DEBUG* JR CLRRAM3 ; ALL ENTRIES VALID, BYPASS INIT CLRRAM2: #ENDIF ; LD A,BID_USR ; SWITCH BACK TO USR BANK ; CALL HB_SETBNK ; .. SO WRITESTR WILL WORK LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$800E ; SWITCH BACK TO EXEC BANK FOR WRITESTR CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE) LD DE,STR_INITRAMDISK ; RAM DISK INIT MESSAGE CALL WRITESTR ; DISPLAY IT ; LD A,BID_RAMD ; SWITCH BACK TO FIRST BANK ; CALL HB_SETBNK ; .. OF RAM DISK LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$8000 ; FIRST BANK OF RAM DISK CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE) LD HL,0 ; SOURCE ADR FOR FILL LD BC,$2000 ; LENGTH OF FILL IS 8K LD A,$E5 ; FILL VALUE CALL FILL ; DO IT CLRRAM3: ; LD A,BID_USR ; USR BANK (TPA) ; CALL HB_SETBNK ; SELECT IT LD BC,$01FB ; UNA FUNC = SET BANK LD DE,$800E ; SWITCH BACK TO EXEC BANK CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE) #ENDIF #ELSE ; ; INITIALIZE RAM DISK BY FILLING DIRECTORY WITH 'E5' BYTES ; FILL FIRST 8K OF RAM DISK TRACK 1 WITH 'E5' ; #IF (CLRRAMDISK != CLR_NEVER) LD A,BID_RAMD ; FIRST BANK OF RAM DISK CALL HB_SETBNK ; SELECT IT #IF (CLRRAMDISK == CLR_AUTO) ; CHECK FIRST 32 DIRECTORY ENTRIES. IF ANY START WITH AN INVALID ; VALUE, INIT THE RAM DISK. VALID ENTRIES ARE E5 (EMPTY ENTRY) OR ; 0-15 (USER NUMBER). LD HL,0 LD DE,32 LD B,32 CLRRAM0: LD A,(HL) CP 0E5H JR Z,CLRRAM1 ; E5 IS VALID CP 16 JR C,CLRRAM1 ; 0-15 IS ALSO VALID JR CLRRAM2 ; INVALID ENTRY! JUMP TO INIT CLRRAM1: ADD HL,DE ; LOOP FOR 32 ENTRIES DJNZ CLRRAM0 ; JR CLRRAM2 ; *DEBUG* JR CLRRAM3 ; ALL ENTRIES VALID, BYPASS INIT CLRRAM2: #ENDIF LD A,BID_USR ; SWITCH BACK TO USR BANK CALL HB_SETBNK ; .. SO WRITESTR WILL WORK LD DE,STR_INITRAMDISK ; RAM DISK INIT MESSAGE CALL WRITESTR ; DISPLAY IT LD A,BID_RAMD ; SWITCH BACK TO FIRST BANK CALL HB_SETBNK ; .. OF RAM DISK LD HL,0 ; SOURCE ADR FOR FILL LD BC,$2000 ; LENGTH OF FILL IS 8K LD A,$E5 ; FILL VALUE CALL FILL ; DO IT CLRRAM3: LD A,BID_USR ; USR BANK (TPA) CALL HB_SETBNK ; SELECT IT #ENDIF #ENDIF RET ; ; ;__________________________________________________________________________________________________ #IF (PLATFORM == PLT_UNA) ; UNA_INIT: ; ; PERFORM UNA BIOS SPECIFIC INITIALIZATION ; UPDATE DRVMAP BASED ON AVAILABLE UNA UNITS ; ; SETUP THE DRVMAP STRUCTURE LD HL,(BUFTOP) ; GET CURRENT BUFFER TOP ; LD (UNA_DRVCNT),HL ; SAVE POINTER TO DRIVE COUNT INC HL ; SKIP 1 BYTE FOR ENTRY COUNT PREFIX LD (UNA_DRVMAP),HL ; SAVE AS UNA DRIVE MAP LD (BUFTOP),HL ; ... AND AS NEW BUFTOP ; ; PUSH HL ; *DEBUG* ; POP BC ; *DEBUG* ; CALL PRTHEXWORD ; *DEBUG* ; EX DE,HL ; DE := UNA DRIVE MAP PTR LD HL,CBX ; HL := CBX INC HL ; BUMP TO INC HL ; ... DRVMAP ENTRY OF CBX LD (HL),E ; RECORD ADDRESS INC HL ; ... OF DRVMAP LD (HL),D ; ... IN CBX ; LD B,0 ; START WITH UNIT 0 ; UNA_INIT1: ; LOOP THRU ALL UNITS AVAILABLE LD C,$48 ; UNA FUNC: GET DISK TYPE LD L,0 ; PRESET UNIT COUNT TO ZERO CALL $FFFD ; CALL UNA, B IS ASSUMED TO BE UNTOUCHED!!! LD A,L ; UNIT COUNT TO A OR A ; PAST END? JR Z,UNA_INIT2 ; WE ARE DONE PUSH BC ; SAVE UNIT CALL UNA_INIT3 ; PROCESS THE UNIT POP BC ; RESTORE UNIT INC B ; NEXT UNIT JR UNA_INIT1 ; LOOP ; UNA_INIT2: ; FINALIZE THE DRIVE MAP RET ; DONE ; UNA_INIT3: ; PROCESS CURRENT UNIT (SEE UNA PROTOIDS.INC) LD A,D ; MOVE DISK TYPE TO A ; CALL PC_LBKT ; *DEBUG* ; CALL PRTHEXBYTE ; *DEBUG* ; CALL PC_RBKT ; *DEBUG* ; CALL UNA_INIT4 ; MAKE A DRIVE MAP ENTRY LD A,D ; LOAD DRIVE TYPE CP $40 ; RAM/ROM? RET Z ; DONE IF SO ; CP $?? ; FLOPPY DRIVE? ; RET Z ; DONE IF SO CALL UNA_INIT4 ; ANOTHER ENTRY FOR HARD DISK LD A,1 ; BUT WITH SLICE VALUE OF 1 INC HL ; BUMP TO SLICE POSITION LD (HL),A ; SAVE IT RET ; DONE ; UNA_INIT4: ; ALLOCATE SPACE IN DRVMAP PUSH BC ; SAVE INCOMING UNIT NUM LD BC,4 ; 4 BYTES PER ENTRY CALL ALLOC ; ALLOCATE CALL NZ,PANIC ; SHOULD NEVER ERROR HERE ; CALL PC_LBKT ; *DEBUG* ; CALL PRTHEXWORD ; *DEBUG* ; CALL PC_RBKT ; *DEBUG* PUSH BC ; MOVE MEM PTR POP HL ; ... TO HL POP BC ; RECOVER UNIT NUM LD (HL),B ; SAVE IT IN FIRST BYTE OF DRV MAP ENTRY PUSH HL ; SAVE HL LD HL,(UNA_DRVMAP) ; POINT TO DRIVE MAP DEC HL ; BACK TO ENTRY COUNT INC (HL) ; INCREMENT THE ENTRY COUNT ; LD A,(HL) ; *DEBUG* ; CALL PRTHEXBYTE ; *DEBUG* POP HL ; RECOVER HL RET ; DONE ; #ENDIF ; ; ;__________________________________________________________________________________________________ ; DPH_INIT: ; ; ITERATE THROUGH DRIVE MAP TO BUILD DPH ENTRIES DYNAMICALLY ; LD DE,STR_DPHINIT ; POINT TO MSG CALL WRITESTR ; DISPLAY IT CALL NEWLINE ; FORMATTING ; ; ALLOCATE DPH POOL SPACE BASED ON DRIVE COUNT #IF (PLATFORM == PLT_UNA) LD HL,(UNA_DRVMAP) ; LOAD DRIVE MAP POINTER #ELSE LD HL,DRVMAP ; LOAD DRIVE MAP POINTER #ENDIF DEC HL ; BACKUP TO ENTRY COUNT LD A,(HL) ; GET THE ENTRY COUNT LD L,A ; PUT DRIVE COUNT LD H,0 ; ... INTO HL ADD HL,HL ; MULTIPLY ADD HL,HL ; ... BY SIZE ADD HL,HL ; ... OF DPH (16) ADD HL,HL ; ... FOR TOTAL SIZE PUSH HL ; MOVE POOL SIZE POP BC ; ... INTO BC FOR MEM ALLOC CALL ALLOC ; ALLOCATE THE SPACE CALL NZ,PANIC ; SHOULD NEVER ERROR ; ; SET DPHTOP TO START OF ALLOCATED SPACE PUSH BC ; MOVE MEM POINTER POP HL ; ... TO HL LD (DPHTOP),HL ; ... AND SAVE IN DPHTOP ; ; ALLOCATE DIRECTORY BUFFER LD BC,128 ; SIZE OF DIRECTORY BUFFER CALL ALLOC ; ALLOCATE THE SPACE CALL NZ,PANIC ; SHOULD NEVER ERROR PUSH BC ; MOVE MEM POINTER POP HL ; ... TO HL LD (DIRBUF),HL ; ... AND SAVE IN DIRBUF ; ; SETUP FOR DPH BUILD LOOP #IF (PLATFORM == PLT_UNA) LD HL,(UNA_DRVMAP) ; POINT TO DRIVE MAP #ELSE LD HL,DRVMAP ; POINT TO DRIVE MAP #ENDIF DEC HL ; BACKUP TO ENTRY COUNT LD B,(HL) ; LOOP DRVCNT TIMES LD C,0 ; DRIVE INDEX INC HL ; BUMP TO START OF DRIVE MAP ; DPH_INIT1: ; DISPLAY DRIVE LETTER LD A,C ; LOAD DRIVE INDEX ADD A,'A' ; MAKE IT A DISPLAY LETTER LD DE,STR_LDR ; LEADER STRING CALL WRITESTR ; DISPLAY IT CALL COUT ; DISPLAY DRIVE LETTER CALL PC_COLON ; DISPLAY COLON LD A,'=' ; SEPARATOR CALL COUT ; DISPLAY IT ; SETUP FOR DPH BUILD ROUTINE INCLUDING DPH BLOCK ALLOCATION LD D,(HL) ; D := DEV/UNIT INC HL ; BUMP LD E,(HL) ; E := SLICE INC HL ; BUMP CALL PRTDUS ; PRINT DEVICE/UNIT/SLICE LD A,D ; A := DEV/UNIT PUSH HL ; SAVE IT LD DE,(DPHTOP) ; GET ADDRESS OF NEXT DPH PUSH DE ; SAVE IT ; INVOKE THE DPH BUILD ROUTINE PUSH BC ; SAVE LOOP CONTROL CALL MAKDPH ; MAKE THE DPH AT DE, DEV/UNIT IN A ;CALL NZ,PANIC ; FOR NOW, PANIC ON ANY ERROR POP BC ; RESTORE LOOP CONTROL ; STORE THE DPH POINTER IN DRIVE MAP POP DE ; RESTORE DPH ADDRESS POP HL ; RESTORE HL := DPH PTR LOC ;RET NZ ; ABORT ON ERROR JR Z,DPH_INIT2 ; IF OK, CONTINUE LD DE,0 ; ... OTHERWISE ZERO OUT THE DPH POINTER DPH_INIT2: LD (HL),E ; SAVE DPH POINTER INC HL ; ... IN LD (HL),D ; ... DRIVE MAP INC HL ; AND BUMP TO START OF NEXT ENTRY ; UPDATE DPH ALLOCATION TOP LD A,16 ; SIZE OF A DPH ENTRY EX DE,HL ; HL := DPH POINTER CALL ADDHLA ; CALC NEW DPHTOP LD (DPHTOP),HL ; SAVE IT ; HANDLE THE NEXT DRIVE MAP ENTRY EX DE,HL ; HL := NEXT DRIVE MAP ENTRY INC C ; NEXT DRIVE DJNZ DPH_INIT1 ; LOOP AS NEEDED RET ; DONE ; MAKDPH: ; ; MAKE A DPH AT ADDRESS IN DE FOR DEV/UNIT IN A ; PUSH DE ; SAVE INCOMING DPH ADDRESS ; #IF (PLATFORM == PLT_UNA) ; LD B,A ; UNIT NUM TO B LD C,$48 ; UNA FUNC: GET DISK TYPE CALL $FFFD ; CALL UNA LD A,D ; MOVE DISK TYPE TO A ; ; DERIVE DPB ADDRESS BASED ON DISK TYPE CP $40 ; RAM/ROM DRIVE? JR Z,MAKDPH0 ; HANDLE RAM/ROM DRIVE IF SO ; CP $?? ; FLOPPY DRIVE? ; JR Z,XXXXX ; HANDLE FLOPPY LD DE,DPB_HD ; ASSUME HARD DISK JR MAKDPH1 ; CONTINUE ; MAKDPH0: ; HANDLE RAM/ROM LD C,$45 ; UNA FUNC: GET DISK INFO LD DE,$9000 ; 512 BYTE BUFFER *** FIX!!! *** CALL $FFFD ; CALL UNA BIT 7,B ; TEST RAM DRIVE BIT LD DE,DPB_ROM ; ASSUME ROM JR Z,MAKDPH1 ; NOT SET, ROM DRIVE, CONTINUE LD DE,DPB_RAM ; OTHERWISE, MUST BE RAM DRIVE JR MAKDPH1 ; CONTINUE ; #ELSE ; ; DETERMINE APPROPRIATE DPB LD DE,DPB_ROM ; ASSUME ROM CP DIODEV_MD+0 ; ROM? JR Z,MAKDPH1 ; YES, JUMP AHEAD LD DE,DPB_RAM ; ASSUME ROM CP DIODEV_MD+1 ; ROM? JR Z,MAKDPH1 ; YES, JUMP AHEAD AND $F0 ; IGNORE UNIT NIBBLE NOW LD DE,DPB_FD144 ; ASSUME FLOPPY CP DIODEV_FD ; FLOPPY? JR Z,MAKDPH1 ; YES, JUMP AHEAD LD DE,DPB_RF ; ASSUME RAM FLOPPY CP DIODEV_RF ; RAM FLOPPY? JR Z,MAKDPH1 ; YES, JUMP AHEAD LD DE,DPB_HD ; EVERYTHING ELSE IS ASSUMED TO BE HARD DISK JR MAKDPH1 ; JUMP AHEAD ; #ENDIF ; MAKDPH1: ; ; BUILD THE DPH POP HL ; HL := START OF DPH LD A,8 ; SIZE OF DPH RESERVED AREA CALL ADDHLA ; LEAVE IT ALONE (ZERO FILLED) LD BC,(DIRBUF) ; ADDRESS OF DIRBUF LD (HL),C ; PLUG DIRBUF INC HL ; ... INTO DPH LD (HL),B ; ... AND BUMP INC HL ; ... TO NEXT DPH ENTRY LD (HL),E ; PLUG DPB ADDRESS INC HL ; ... INTO DPH LD (HL),D ; ... AND BUMP INC HL ; ... TO NEXT ENTRY DEC DE ; POINT DEC DE ; ... TO START DEC DE ; ... OF DEC DE ; ... DPB DEC DE ; ... PREFIX DATA (CKS & ALS BUF SIZES) CALL MAKDPH2 ; HANDLE CKS BUF, THEN FALL THRU FOR ALS BUF RET NZ ; BAIL OUT ON ERROR MAKDPH2: EX DE,HL ; POINT HL TO CKS/ALS SIZE ADR LD C,(HL) ; BC := CKS/ALS SIZE INC HL ; ... AND BUMP LD B,(HL) ; ... PAST INC HL ; ... CKS/ALS SIZE EX DE,HL ; BC AND HL ROLES RESTORED LD A,B ; CHECK TO SEE OR C ; ... IF BC IS ZERO JR Z,MAKDPH3 ; IF ZERO, BYPASS ALLOC, USE ZERO FOR ADDRESS CALL ALLOC ; ALLOC BC BYTES, ADDRESS RETURNED IN BC JR NZ,ERR_BUFOVF ; HANDLE OVERFLOW ERROR MAKDPH3: LD (HL),C ; SAVE CKS/ALS BUF INC HL ; ... ADDRESS IN LD (HL),B ; ... DPH AND BUMP INC HL ; ... TO NEXT DPH ENTRY XOR A ; SIGNAL SUCCESS RET ; ALLOC: ; ; ALLOCATE BC BYTES FROM BUF POOL, RETURN STARTING ; ADDRESS IN BC. LEAVE ALL OTHER REGS ALONE EXCEPT A ; Z FOR SUCCESS, NZ FOR FAILURE ; PUSH DE ; SAVE ORIGINAL DE PUSH HL ; SAVE ORIGINAL HL LD HL,(BUFTOP) ; HL := CURRENT BUFFER TOP PUSH HL ; SAVE AS START OF NEW BUFFER PUSH BC ; GET BYTE COUNT POP DE ; ... INTO DE ADD HL,DE ; ADD IT TO BUFFER TOP LD A,$FF ; ASSUME OVERFLOW FAILURE JR C,ALLOC1 ; IF OVERFLOW, BYPASS WITH A == $FF PUSH HL ; SAVE IT LD DE,$10000 - CBIOS_END ; SETUP DE FOR OVERFLOW TEST ADD HL,DE ; CHECK FOR OVERFLOW POP HL ; RECOVER HL LD A,$FF ; ASSUME FAILURE JR C,ALLOC1 ; IF OVERFLOW, CONTINUE WITH A == $FF LD (BUFTOP),HL ; SAVE NEW TOP INC A ; SIGNAL SUCCESS ; ALLOC1: POP BC ; BUF START ADDRESS TO BC POP HL ; RESTORE ORIGINAL HL POP DE ; RESTORE ORIGINAL DE OR A ; SIGNAL SUCCESS RET ; ERR_BUFOVF: LD DE,STR_BUFOVF JR ERR ; ERR_INVMED: LD DE,STR_INVMED JR ERR ; ERR: CALL WRITESTR OR $FF RET ; DPHTOP .DW 0 ; CURRENT TOP OF DPH POOL DIRBUF .DW 0 ; DIR BUF POINTER BUFTOP .DW BUFPOOL ; CURRENT TOP OF BUF POOL ; PRTDUS: ; ; PRINT THE DEVICE/UNIT/SLICE INFO ; ON INPUT D HAS DEVICE/UNIT, E HAS SLICE ; DESTROY NO REGISTERS OTHER THAN A ; #IF (PLATFORM == PLT_UNA) ; PUSH BC ; PRESERVE BC PUSH DE ; PRESERVE DE PUSH HL ; PRESERVE HL LD B,D ; B := UNIT LD C,$48 ; UNA FUNC: GET DISK TYPE CALL $FFFD ; CALL UNA LD A,D ; DISK TYPE TO A CP $40 JR Z,PRTDUS1 ; IF SO, HANDLE RAM/ROM LD DE,DEVIDE ; IDE STRING CP $41 ; IDE? JR Z,PRTDUSX ; IF YES, PRINT LD DE,DEVSD ; SD STRING CP $43 ; SD? JR Z,PRTDUSX ; IF YES, PRINT LD DE,DEVUNK ; OTHERWISE, UNKNOWN JR PRTDUSX ; PRINT IT PRTDUS1: LD C,$45 ; UNA FUNC: GET DISK INFO LD DE,$9000 ; 512 BYTE BUFFER *** FIX!!! *** CALL $FFFD ; CALL UNA BIT 7,B ; TEST RAM DRIVE BIT LD DE,DEVROM ; ASSUME ROM JR Z,PRTDUSX ; IF SO, DISPLAY ROM LD DE,DEVRAM ; ELSE RAM JR Z,PRTDUSX ; DO IT PRTDUSX: CALL WRITESTR ; PRINT DEVICE NAME POP HL ; RECOVER HL POP DE ; RECOVER DE POP BC ; RECOVER BC LD A,D ; LOAD DEVICE/UNIT CALL PRTDECB ; PRINT IT CALL PC_COLON ; FORMATTING LD A,E ; LOAD SLICE CALL PRTDECB ; PRINT IT RET ; DEVRAM .DB "RAM$" DEVROM .DB "ROM$" DEVIDE .DB "IDE$" DEVSD .DB "SD$" DEVUNK .DB "UNK$" ; #ELSE ; PUSH DE ; PRESERVE DE PUSH HL ; PRESERVE HL LD A,D ; LOAD DEVICE/UNIT RRCA ; ROTATE DEVICE RRCA ; ... BITS RRCA ; ... INTO RRCA ; ... LOWEST 4 BITS AND $0F ; ISOLATE DEVICE BITS ADD A,A ; MULTIPLE BY TWO FOR WORD TABLE LD HL,DEVTBL ; POINT TO START OF DEVICE NAME TABLE CALL ADDHLA ; ADD A TO HL TO POINT TO TABLE ENTRY LD A,(HL) ; DEREFERENCE HL TO LOC OF DEVICE NAME STRING INC HL ; ... LD D,(HL) ; ... LD E,A ; ... CALL WRITESTR ; PRINT THE DEVICE NMEMONIC POP HL ; RECOVER HL POP DE ; RECOVER DE LD A,D ; LOAD DEVICE/UNIT AND $0F ; ISOLATE UNIT CALL PRTDECB ; PRINT IT CALL PC_COLON ; FORMATTING LD A,E ; LOAD SLICE CALL PRTDECB ; PRINT IT RET ; DEVTBL: ; DEVICE TABLE .DW DEV00, DEV01, DEV02, DEV03 .DW DEV04, DEV05, DEV06, DEV07 .DW DEV08, DEV09, DEV10, DEV11 .DW DEV12, DEV13, DEV14, DEV15 ; DEVUNK .DB "???$" DEV00 .DB "MD$" DEV01 .DB "FD$" DEV02 .DB "RAMF$" DEV03 .DB "IDE$" DEV04 .DB "ATAPI$" DEV05 .DB "PPIDE$" DEV06 .DB "SD$" DEV07 .DB "PRPSD$" DEV08 .DB "PPPSD$" DEV09 .DB "HDSK$" DEV10 .EQU DEVUNK DEV11 .EQU DEVUNK DEV12 .EQU DEVUNK DEV13 .EQU DEVUNK DEV14 .EQU DEVUNK DEV15 .EQU DEVUNK ; #ENDIF ; STR_INITRAMDISK .DB "\r\nFormatting RAMDISK...$" STR_LDR .DB "\r\n $" STR_DPHINIT .DB "\r\n\r\nConfiguring Drives...$" STR_BUFOVF .DB " *** Insufficient Memory ***$" STR_INVMED .DB " *** Invalid Device ID ***$" ; ;================================================================================================== ; ;================================================================================================== ; .FILL CBIOS_END - $,$00 ; SLACK .EQU (CBIOS_END - BUFPOOL) .ECHO "CBIOS buffer space: " .ECHO SLACK .ECHO " bytes.\n" ; .ECHO "CBIOS total space used: " .ECHO $ - CBIOS_LOC .ECHO " bytes.\n" ; .END