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.
 
 
 
 
 
 

2850 lines
83 KiB

;__________________________________________________________________________________________________
;
; CBIOS FOR SBC
;
; BY ANDREW LYNCH, WITH INPUT FROM MANY SOURCES
; ROMWBW ADAPTATION BY WAYNE WARTHEN
;__________________________________________________________________________________________________
;
FALSE .EQU 0
TRUE .EQU ~FALSE
;
; DEFINE PLATFORM STRING
;
#IFDEF PLTWBW
#DEFINE PLTSTR "WBW"
#ENDIF
#IFDEF PLTUNA
#DEFINE PLTSTR "UNA"
#ENDIF
;
; RAM DISK INITIALIZATION OPTIONS
;
CLR_NEVER .EQU 0 ; NEVER CLEAR RAM DISK
CLR_AUTO .EQU 1 ; CLEAR RAM DISK IF INVALID DIR ENTRIES
CLR_ALWAYS .EQU 2 ; ALWAYS CLEAR RAM DISK
;
; DISK OPERATION CONSTANTS
;
DOP_READ .EQU 0 ; READ OPERATION
DOP_WRITE .EQU 1 ; WRITE OPERATION
;
; SPECIAL CHARACTER DEVICES IMPLEMENTED INTERNALLY
;
DEV_BAT .EQU $FE ; BAT:
DEV_NUL .EQU $FF ; NUL:
;
#INCLUDE "../HBIOS/ver.inc"
;
#INCLUDE "config.asm"
;
; MEMORY LAYOUT
;
IOBYTE .EQU 3 ; LOC IN PAGE 0 OF I/O DEFINITION BYTE
CDISK .EQU 4 ; LOC IN PAGE 0 OF CURRENT DISK NUMBER 0=A,...,15=P
;
CCP_LOC .EQU CPM_LOC
CCP_SIZ .EQU $800
;
BDOS_LOC .EQU CCP_LOC + CCP_SIZ
BDOS_SIZ .EQU $E00
;
CBIOS_LOC .EQU BDOS_LOC + BDOS_SIZ
CBIOS_END .EQU CPM_END
;
MEMTOP .EQU $10000
;
#IFDEF PLTWBW
#INCLUDE "../HBIOS/hbios.inc"
#ENDIF
;
#IFDEF PLTUNA
#INCLUDE "../UBIOS/ubios.inc"
#ENDIF
;
.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:
DEVMAPADR .DW DEVMAP ; DEVICE MAP ADDRESS
DRVMAPADR .DW 0 ; DRIVE MAP ADDRESS (FILLED IN LATER)
DPBMAPADR .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
;
; IOBYTE (0003H)
; ==============
;
; Device LST: PUN: RDR: CON:
; Bit positions 7 6 5 4 3 2 1 0
;
; Dec Binary
;
; 0 00 TTY: TTY: TTY: TTY:
; 1 01 CRT: PTP: PTR: CRT:
; 2 10 LPT: UP1: UR1: BAT:
; 3 11 UL1: UP2: UR2: UC1:
;
; TTY: Teletype device (slow speed console)
; CRT: Cathode ray tube device (high speed console)
; BAT: Batch processing (input from RDR:, output to LST:)
; UC1: User-defined console
; PTR: Paper tape reader (high speed reader)
; UR1: User-defined reader #1
; UR2: User-defined reader #2
; PTP: Paper tape punch (high speed punch)
; UP1: User-defined punch #1
; UP2: User-defined punch #2
; LPT: Line printer
; UL1: User-defined list device #1
;
#IFDEF PLTUNA
LD_TTY .EQU 0 ; -> COM0:
LD_CRT .EQU 0 ; -> CRT:
LD_BAT .EQU DEV_BAT
LD_UC1 .EQU 0 ; -> COM1:
LD_PTR .EQU 0 ; -> COM1:
LD_UR1 .EQU 0 ; -> COM2:
LD_UR2 .EQU 0 ; -> COM3:
LD_PTP .EQU 0 ; -> COM1:
LD_UP1 .EQU 0 ; -> COM2:
LD_UP2 .EQU 0 ; -> COM3:
LD_LPT .EQU 0 ; -> LPT0:
LD_UL1 .EQU 0 ; -> LPT1:
#ELSE
LD_TTY .EQU CIODEV_CONSOLE ; -> COM0:
LD_CRT .EQU CIODEV_CONSOLE ; -> CRT:
LD_BAT .EQU DEV_BAT
LD_UC1 .EQU CIODEV_CONSOLE ; -> COM1:
LD_PTR .EQU CIODEV_CONSOLE ; -> COM1:
LD_UR1 .EQU CIODEV_CONSOLE ; -> COM2:
LD_UR2 .EQU CIODEV_CONSOLE ; -> COM3:
LD_PTP .EQU CIODEV_CONSOLE ; -> COM1:
LD_UP1 .EQU CIODEV_CONSOLE ; -> COM2:
LD_UP2 .EQU CIODEV_CONSOLE ; -> COM3:
LD_LPT .EQU CIODEV_CONSOLE ; -> LPT0:
LD_UL1 .EQU CIODEV_CONSOLE ; -> LPT1:
#ENDIF
;
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)
;
;==================================================================================================
; DRIVE MAPPING TABLE (DRVMAP)
;==================================================================================================
;
; Disk mapping is done using a drive map table (DRVMAP) which is built
; dynamically at cold boot. See the DRV_INIT routine. This table is
; made up of entries as documented below. The table is prefixed with one
; byte indicating the number of entries. The index of the entry indicates
; the drive letter, so the first entry is A:, the second entry is B:, etc.
;
; BYTE: UNIT
; BYTE: SLICE
; WORD: DPH ADDRESS
;
;==================================================================================================
; 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 ROUTINE
;
; CLEAR BUFFER SPACE STARTING AT DIRBUF TO TOP OF CBIOS
; INIT SETS UP HL AND BC SO WE ARE READY TO CALL FILL
LD SP,$100 ; MOVE STACK OUT OF THE WAY TEMPORARILY
CALL FILL ; CLEAR DISK BUFFER AREA
;
LD SP,STACK ; PUT STACK BACK WHERE IT BELONGS
JR GOCPM ; THEN OFF TO CP/M WE GO...
;
;__________________________________________________________________________________________________
REBOOT:
; REBOOT FROM ROM, REPLACES BOOT AFTER INIT
#IFDEF PLTUNA
LD BC,$01FB ; UNA FUNC = SET BANK
LD DE,0 ; ROM BOOT BANK
CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE)
#ENDIF
#IFDEF PLTWBW
LD A,0 ; ROM BOOT BANK
CALL HB_BNKSEL ; SELECT IT INTO LOW MEMORY
#ENDIF
;
; JUMP TO RESTART ADDRESS
JP 0
;
;__________________________________________________________________________________________________
WBOOT:
DI
IM 1
;
LD SP,STACK ; STACK FOR INITIALIZATION
;
#IFDEF PLTUNA
; RESTORE COMMAND PROCESSOR FROM UNA BIOS CACHE
LD BC,$01FB ; UNA FUNC = SET BANK
LD DE,BID_BIOS ; 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,CCP_LOC ; ADDRESS IN HI MEM OF CCP
LD BC,CCP_SIZ ; 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,BF_SYSXCPY ; HBIOS FUNC: SYSTEM EXTENDED COPY
LD DE,(BNKBIOS) ; D = DEST (USER BANK), E = SRC (BIOS BANK)
RST 08 ; SET BANKS FOR INTERBANK COPY
LD B,BF_SYSCPY ; HBIOS FUNC: SYSTEM COPY
LD HL,(CCPBUF) ; COPY FROM FIXED LOCATION IN HB BANK
LD DE,CCP_LOC ; TO CCP LOCATION IN USR BANK
LD IX,CCP_SIZ ; COPY CONTENTS OF COMMAND PROCESSOR
RST 08 ; DO IT
#ENDIF
;
; SOME APPLICATIONS STEAL THE BDOS SERIAL NUMBER STORAGE
; AREA (FIRST 6 BYTES OF BDOS) ASSUMING IT WILL BE RESTORED
; AT WARM BOOT BY RELOADING OF BDOS. WE DON'T WANT TO RELOAD
; BDOS, SO INSTEAD THE SERIAL NUMBER STORAGE IS FIXED HERE
; SO THAT THE DRI SERIAL NUMBER VERIFICATION DOES NOT FAIL
LD HL,BDOS_LOC
LD BC,6
XOR A
CALL FILL
;
; FALL THRU TO INVOKE CP/M
;
;__________________________________________________________________________________________________
GOCPM:
#IFDEF PLTUNA
; USE A DEDICATED BUFFER FOR UNA PHYSICAL DISK I/O
LD HL,SECBUF ; ADDRESS OF PHYSICAL SECTOR BUFFER
LD (DSKBUF),HL ; SAVE IT IN DSKBUF FOR LATER
#ELSE
; ALLOCATE A SINGLE SECTOR DISK BUFFER ON THE HBIOS HEAP
LD B,BF_SYSALLOC ; BIOS FUNC: ALLOCATE HEAP MEMORY
LD HL,512 ; 1 SECTOR, 512 BYTES
RST 08 ; DO IT
CALL NZ,PANIC ; HANDLE ERROR
LD (DSKBUF),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_LOC + 6 ; 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 $0F ; 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_LOC ; 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 $FF IF CHARACTER READY, $00 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)
;
#IFDEF PLTUNA
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 $0F ; ISOLATE INDEX INTO DEVICE MAP
LD HL,DEVMAP ; HL = ADDRESS OF DEVICE MAP
CALL ADDHLA ; ADD OFFSET
LD A,(HL) ; LOOKUP DEVICE CODE
#IFDEF PLTUNA
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 DEV_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
CP DEV_BAT ; BAT: ?
JR Z,CIO_BAT ; YES, GO TO BAT DEVICE HANDLER
CP DEV_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 ; SWALLOW CHARACTER
;
NUL_IST:
NUL_OST:
OR $FF ; A=$FF & NZ (READY)
RET
;
;==================================================================================================
; DISK BIOS FUNCTIONS
;==================================================================================================
;
;__________________________________________________________________________________________________
SELDSK:
; SELECT DISK NUMBER FOR SUBSEQUENT DISK OPS
#IF DSKTRACE
CALL PRTSELDSK
#ENDIF
;
JP DSK_SELECT
;
;__________________________________________________________________________________________________
HOME:
; SELECT TRACK 0 (BC = 0) AND FALL THRU TO SETTRK
#IF DSKTRACE
CALL PRTHOME
#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
#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
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 ; HL PIONTS TO DPB ENTRY IN DPH
LD A,(HL) ; DEREFERENCE HL
INC HL ; ... TO GET
LD H,(HL) ; ... DPB ADDRESS
LD L,A ; ... SO HL NOW POINTS TO DPB ADDRESS
LD C,(HL) ; DEREFERENCE HL
INC HL ; ... INTO BC SO THAT
LD B,(HL) ; ... BC NOW HAS SPT
LD (UNASPT),BC ; SAVE SECTORS PER TRACK
DEC HL ; BACKUP TO START OF DPB
DEC HL ; BACKUP ONE BYTE FOR 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
#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:
#IFDEF PLTUNA
CALL BLK_SETUP
EX DE,HL
LD BC,128
LDIR
RET
#ELSE
LD B,BF_SYSXCPY ; HBIOS FUNC: SYSTEM EXTENDED COPY
LD A,(BNKUSER) ; GET USER BANK
LD E,A ; E = SOURCE (USER BANK)
LD A,(BNKBIOS) ; GET DEST BANK
LD D,A ; D = DEST (BIOS BANK)
RST 08 ; SET BANKS FOR INTERBANK COPY
CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION
LD B,BF_SYSCPY ; HBIOS FUNC: SYSTEM COPY
EX DE,HL ; SWAP HL/DE FOR BLOCK OPERATION
PUSH IX ; SAVE IX
LD IX,128 ; DMA BUFFER SIZE
RST 08 ; DO IT
POP IX ; RESTORE IX
RET
#ENDIF
;
;__________________________________________________________________________________________________
;
; DEBLOCK DATA - EXTRACT DESIRED CPM DMA BUF FROM PHYSICAL SECTOR BUFFER
;
BLK_DEBLOCK:
#IFDEF PLTUNA
CALL BLK_SETUP
LD BC,128
LDIR
RET
#ELSE
LD B,BF_SYSXCPY ; HBIOS FUNC: SYSTEM EXTENDED COPY
LD DE,(BNKBIOS) ; E = SOURCE (BIOS BANK), D = DEST (USER BANK)
RST 08 ; DO IT
CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION
LD B,BF_SYSCPY ; HBIOS FUNC: SYSTEM COPY
PUSH IX ; SAVE IX
LD IX,128 ; DMA BUFFER SIZE
RST 08 ; DO IT
POP IX ; RESTORE IX
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 A,(SEKSEC) ; GET LOW BYTE OF SECTOR
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,(DSKBUF) ; 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=UNIT, E=SLICE, HL=DPH ADDRESS
;
DSK_GETINF:
LD HL,(DRVMAPADR) ; HL := START OF UNA DRIVE MAP
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 DRVMAP
CALL ADDHLA ; ADD OFFSET
LD D,(HL) ; D := 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=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 := UNIT
LD (SEKUNIT),A ; SAVE UNIT
LD (SEKDPH),HL ; SAVE DPH ADDRESS
;
; 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
;
; RESTORE DE TO BC (FOR ACCESS TO DRIVE LOGIN BIT)
POP BC ; GET ORIGINAL E INTO B
;
#IFDEF PLTWBW
;
; CHECK IF THIS IS LOGIN, IF NOT, BYPASS MEDIA DETECTION
; FIX: WHAT IF PREVIOUS MEDIA DETECTION FAILED???
BIT 0,B ; TEST DRIVE LOGIN BIT
JR NZ,DSK_SELECT2 ; BYPASS MEDIA DETECTION
;
; DETERMINE MEDIA IN DRIVE
LD A,(SEKUNIT) ; GET UNIT
LD C,A ; STORE IN C
LD B,BF_DIOMEDIA ; DRIVER FUNCTION = DISK MEDIA
LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY
RST 08 ; DO IT
LD A,E ; RESULTANT MEDIA ID TO ACCUM
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
#ENDIF
;
DSK_SELECT2:
LD HL,(SEKDPH) ; HL = DPH ADDRESS FOR CP/M
XOR A ; FLAG SUCCESS
RET ; NORMAL RETURN
;
;
;
DSK_STATUS:
#IFDEF PLTUNA
XOR A ; ASSUME OK FOR NOW
RET ; RETURN
#ELSE
; C HAS CPM DRIVE, LOOKUP UNIT AND CHECK FOR INVALID DRIVE
CALL DSK_GETINF ; B := UNIT
RET NZ ; INVALID DRIVE ERROR
; VALID DRIVE, DISPATCH TO DRIVER
LD C,D ; C := UNIT
LD B,BF_DIOSTATUS ; B := FUNCTION: STATUS
RST 08
RET
#ENDIF
;
;
;
DSK_READ:
; SET B = FUNCTION: READ
LD B,BF_DIOREAD
JR DSK_IO
;
;
;
DSK_WRITE:
; SET B = FUNCTION: WRITE
LD B,BF_DIOWRITE
JR DSK_IO
;
;
;
#IFDEF PLTUNA
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 ADCHLA ; ADD OFFSET
POP BC ; RECOVER FUNCTION IN B
LD A,(HSTUNIT) ; GET THE 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,(DSKBUF) ; SET BUFFER ADDRESS
LD HL,1 ; 1 SECTOR
; DISPATCH TO UBIOS
RST 08
OR A ; SET FLAGS BASED ON RESULT
RET
#ELSE
DSK_IO:
;
; TRANSLATE CP/M TRACK/SECTOR -> HBIOS TRACK/HEAD/SECTOR
; NEEDS TO HANDLE FLOPPY SEPARATE FROM HARD DISK
;
CHS:
LD A,(HSTUNIT) ; GET UNIT
LD C,A ; UNIT -> C
PUSH BC ; SAVE FUNC/UNIT
LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO
RST 08 ; GET UNIT INFO, DEVICE TYPE IN D
POP BC ; GET FUNC/UNIT BACK TO BC
LD A,D ; DEVICE TYPE -> A
AND $F0 ; ISOLATE HIGH BITS
CP DIODEV_FD ; FLOPPY?
JR NZ,CHSHD ; IF NOT, DO HD CHS XLAT
;
; FLOPPY SPECIFIC TRANSLATION
; CURRENTLY LEAVES HEAD VALUE IMBEDDED IN
; TRACK WHICH HBIOS FD DRIVER HANDLES
;
LD DE,(HSTSEC) ; SECTOR DE, HEAD(D) BECOMES ZERO
LD HL,(HSTTRK) ; TRACK -> TRACK (LOW BIT HAS HEAD)
JR CHS2
;
; HARD DISK SPECIFIC TRANSLATION
; ASSUMES 16 HEADS PER CYLINDER AND 16 SECTORS PER TRACK
;
CHSHD:
LD HL,(HSTTRK) ; GET TRACK VALUE
LD A,L ; LSB OF TRACK TO A
AND $0F ; ISOLATE HEAD IN LOW 4 BITS
LD D,A ; STUFF IT IN D
LD A,(HSTSEC) ; GET SECTOR
LD E,A ; STUFF IT IN E
LD A,B ; SAVE B (HBIOS FUNC)
LD B,4 ; PREPARE TO SHIFT OUT 4 BIT HEAD VALUE
CHSHD1:
SRL H ; SHIFT ONE BIT OUT
RR L ; ... OF HL
DJNZ CHSHD1 ; DO ALL 4 BITS
LD B,A ; RESTORE B (HBIOS FUNC)
; FALL THRU TO CHS2
;
; ALL TYPES OF TRANSLATION WIND UP HERE TO
; MAKE THE ACTUAL HBIOS CALL
;
CHS2:
PUSH DE ; SAVE HEAD/SECTOR + COULD MOVE
LD DE,(HSTOFF) ; NOW GET SLICE OFFSET | TO CHSHD,
ADD HL,DE ; ADD IT TO TRACK VALUE | NO SLICES
POP DE ; RECOVER HEAD/SECTOR + FOR FLOPPY
;
; MAKE HBIOS CALL
; HBIOS FUNC SHOULD STILL BE IN B
; UNIT SHOULD STILL BE IN C
;
PUSH BC ; SAVE INCOMING FUNCTION, DEVICE/UNIT
LD B,BF_DIOSEEK ; SETUP FOR NEW SEEK CALL
RST 08 ; DO IT
POP BC ; RESTORE INCOMING FUNCTION, DEVICE/UNIT
RET NZ ; ABORT IF SEEK RETURNED AN ERROR W/ ERROR IN A
LD HL,(DSKBUF) ; GET BUFFER ADDRESS
LD DE,1 ; TRANSFER ONE SECTOR
RST 08 ; DO IT
OR A ; SET FLAGS
RET ; DONE
#ENDIF
;
;==================================================================================================
; UTILITY FUNCTIONS
;==================================================================================================
;
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:
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
RET
;
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 BIOS BANK
;
#IFDEF PLTWBW
BNKBIOS .DB 0 ; BIOS BANK ID
BNKUSER .DB 0 ; USER BANK ID
#ENDIF
;
; 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
DSKBUF .DW 0 ; ADDRESS OF PHYSICAL SECTOR BUFFER
;
; LOGICAL 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)
SEKUNIT .DB 0 ; DISK UNIT
SEKDPH .DW 0 ; ADDRESS OF ACTIVE (SELECTED) DPH
SEKOFF .DW 0 ; TRACK OFFSET IN EFFECT FOR SLICE
SEKACT .DB TRUE ; ALWAYS TRUE!
;
; RESULT OF CPM TO PHYSICAL TRANSLATION
;
XLT:
XLTDSK .DB 0
XLTTRK .DW 0
XLTSEC .DW 0
XLTUNIT .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
HSTUNIT .DB 0 ; DISK UNIT IN BUFFER
HSTDPH .DW 0 ; CURRENT DPH ADDRESS
HSTOFF .DW 0 ; TRACK OFFSET IN EFFECT FOR SLICE
HSTACT .DB 0 ; TRUE = BUFFER HAS VALID DATA
;
; SEQUENTIAL WRITE TRACKING FOR (UNA)LLOCATED 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
;
;==================================================================================================
; DISK CONTROL STRUCTURES (DPB, DPH)
;==================================================================================================
;
CKS_RAM .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA
ALS_RAM .EQU 24 ; ALS: BLKS / 8 = 192 / 8 = 24 (ASSUMES 512K DISK)
;
CKS_ROM .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA
ALS_ROM .EQU 24 ; ALS: BLKS / 8 = 192 / 8 = 24 (ASSUMES 512K DISK)
;
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 - 128K RESERVED FOR SYSTEM USE
;
; ALS_ROM, EXM, DSM MUST BE FILLED DYNAMICALLY:
; - ALS_ROM := (BANKS * 2)
; - EXM := (BANKS <= 16) ? 1 : 0
; - DSM := (BANKS * 16)
;
; DEFAULT VALUES BELOW ARE FOR 512K ROM
;
.DW CKS_ROM ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW ALS_ROM ; ALS: BLKS / 8
.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
.DB 1 ; EXM: (BLKS <= 256) ? 1 : 0
.DW 192 - 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 - 128K RESERVED FOR SYSTEM USE
;
; ALS_RAM, EXM, DSM MUST BE FILLED DYNAMICALLY:
; - ALS_RAM := (BANKS * 2)
; - EXM := (BANKS <= 16) ? 1 : 0
; - DSM := (BANKS * 16)
;
; DEFAULT VALUES BELOW ARE FOR 512K RAM
;
.DW CKS_RAM ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW ALS_RAM ; ALS: BLKS / 8
.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
.DB 1 ; EXM: (BLKS <= 256) ? 1 : 0
.DW 192 - 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
;
.DW CKS_HD
.DW ALS_HD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_RF:
.DW 64 ; 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
;
#IFDEF PLTUNA
SECBUF .FILL 512,0 ; PHYSICAL DISK SECTOR BUFFER
#ENDIF
;
;==================================================================================================
; CBIOS 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, THIS IS SAFE.
;
;==================================================================================================
;
HCB .EQU $8000 ; LOCATION OF TEMP COPY OF HCB DURING INIT (256 BYTES)
INIBUF .EQU $8800 ; LOCATION OF TEMP WORK BUF DURING INIT (512 BYTES)
;
HEAPEND .EQU CBIOS_END - 64 ; TOP OF HEAP MEM, END OF CBIOS LESS 32 ENTRY STACK
;
.FILL 16 * 4,0 ; SKIP DRVMAP TABLE AREA
.FILL 16 * 16,0 ; SKIP DPH TABLE AREA
;
INIT:
; ADJUST BOOT VECTOR TO REBOOT ROUTINE
LD HL,REBOOT ; GET REBOOT ADDRESS
LD (CBIOS_LOC + 1),HL ; STORE IT IN FIRST ENTRY OF CBIOS JUMP TABLE
#IFDEF PLTUNA
; MAKE SURE UNA EXEC PAGE IS ACTIVE
LD BC,$01FB ; UNA FUNC = SET BANK
LD DE,BID_USR ; SWITCH BACK TO EXEC BANK
CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED)
; 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
#ELSE
LD B,BF_SYSGET ; HBIOS FUNC=GET SYS INFO
LD C,BF_SYSGET_BNKINFO ; HBIOS SUBFUNC=GET BANK ASSIGNMENTS
CALL $FFF0 ; CALL HBIOS, RST 08 NOT YET INSTALLED
LD A,D ; GET HBIOS BANK RETURNED IN D
LD (BNKBIOS),A ; ... AND SAVE IT
LD A,E ; GET USER BANK RETURNED IN E
LD (BNKUSER),A ; ... AND SAVE IT
; MAKE SURE USER BANK IS ACTIVE
LD B,BF_SYSSETBNK ; HB FUNC: SET BANK
LD A,(BNKUSER) ; SELECT USER BANK
LD C,A ; PUT IN C
CALL $FFF0 ; RST 8 IS NOT YET INSTALLED
; INSTALL HBIOS INVOCATION VECTOR FOR RST 08
LD A,$C3 ; JP INSTRUCTION
LD (8),A ; STORE AT 0x0008
LD HL,($FFF1) ; HBIOS ENTRY VECTOR
LD (9),HL ; STORE AT 0x0009
; CREATE A TEMP COPY OF THE HBIOS CONFIG BLOCK (HCB)
; FOR USE DURING INIT
LD B,BF_SYSXCPY ; HBIOS FUNC: SYSTEM EXTENDED COPY
LD DE,(BNKBIOS) ; D = DEST (USER BANK), E = SOURCE (BIOS BANK)
RST 08 ; SET BANKS FOR INTERBANK COPY
LD B,BF_SYSCPY ; HBIOS FUNC: SYSTEM COPY
LD HL,HCB_LOC ; COPY FROM FIXED LOCATION IN HB BANK
LD DE,HCB ; TO TEMP LOCATION IN USR BANK
LD IX,HCB_SIZ ; COPY CONTENTS OF HCB
RST 08 ; DO IT
; CAPTURE RAM DRIVE STARTING BANK
LD A,(HCB + HCB_BIDRAMD0)
LD (BNKRAMD),A
#ENDIF
; PARAMETER INITIALIZATION
XOR A ; LOAD DEFAULT IOBYTE
LD (IOBYTE),A ; STORE IT
; INIT DEFAULT DRIVE TO A: FOR NOW
XOR A ; ZERO
LD (DEFDRIVE),A ; STORE IT
; CBIOS BANNER
CALL NEWLINE ; FORMATTING
LD DE,STR_BANNER ; POINT TO BANNER
CALL WRITESTR ; DISPLAY IT
#IFDEF PLTUNA
; SAVE COMMAND PROCESSOR IMAGE TO MALLOCED CACHE IN UNA BIOS PAGE
LD C,$F7 ; UNA MALLOC
LD DE,CCP_SIZ ; 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,BID_BIOS ; UBIOS_PAGE (SEE PAGES.INC)
RST 08 ; DO IT
PUSH DE ; SAVE PREVIOUS BANK
LD HL,CCP_LOC ; ADDRESS IN HI MEM OF CCP
LD DE,(CCPBUF) ; ADDRESS OF CCP BUF IN BIOS MEM
LD BC,CCP_SIZ ; 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 B,BF_SYSALLOC ; HBIOS FUNC: ALLOCATE HEAP MEMORY
LD HL,CCP_SIZ ; SIZE TO ALLOC (SIZE OF CCP)
RST 08 ; DO IT
CALL NZ,PANIC ; BIG PROBLEM
LD (CCPBUF),HL ; SAVE THE ADDRESS (IN BIOS MEM)
LD B,BF_SYSXCPY ; HBIOS FUNC: SYSTEM EXTENDED COPY
LD A,(BNKUSER) ; GET USER BANK
LD E,A ; E = SOURCE (USER BANK)
LD A,(BNKBIOS) ; GET BIOS BANK
LD D,A ; D = DEST (BIOS BANK)
RST 08 ; DO IT
LD B,BF_SYSCPY ; HBIOS FUNC: SYSTEM COPY
LD HL,CCP_LOC ; COPY FROM CCP LOCATION IN USR BANK
LD DE,(CCPBUF) ; TO ALLOCATED LOCATION IN HB BANK
LD IX,CCP_SIZ ; COPY CONTENTS OF COMMAND PROCESSOR
RST 08 ; DO IT
#ENDIF
; DISK SYSTEM INITIALIZATION
CALL BLKRES ; RESET DISK (DE)BLOCKING ALGORITHM
CALL DEV_INIT ; INITIALIZE CHARACTER DEVICE MAP
CALL MD_INIT ; INITIALIZE MEMORY DISK DRIVER (RAM/ROM)
CALL DRV_INIT ; INITIALIZE DRIVE MAP
CALL DPH_INIT ; INITIALIZE DPH TABLE AND BUFFERS
;
; DISPLAY FREE MEMORY
LD DE,STR_LDR2 ; FORMATTING
CALL WRITESTR ; AND PRINT IT
LD HL,CBIOS_END ; SUBTRACT HIGH WATER
LD DE,(HEAPTOP) ; ... 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
;
LD A,(DEFDRIVE) ; GET DEFAULT DRIVE
LD (CDISK),A ; ... AND SETUP CDISK
;
; SETUP AUTOSTART COMMAND
LD HL,CMD ; ADDRESS OF STARTUP COMMAND
LD DE,CCP_LOC + 7 ; START OF COMMAND BUFFER IN CCP
LD BC,CMDLEN ; LENGTH OF AUTOSTART COMMAND
LDIR ; INSTALL IT
;
; OS BANNER
CALL NEWLINE2 ; FORMATTING
LD DE,STR_CPM ; DEFAULT TO CP/M LABEL
LD A,(BDOS_LOC) ; GET FIRST BYTE OF BDOS
CP 'Z' ; IS IT A 'Z' (FOR ZSDOS)?
JR NZ,INIT2 ; NOPE, CP/M IS RIGHT
LD DE,STR_ZSDOS ; SWITCH TO ZSDOS LABEL
INIT2:
CALL WRITESTR ; DISPLAY OS LABEL
LD DE,STR_TPA1 ; TPA PREFIX
CALL WRITESTR
LD A,BDOS_LOC / 1024 ; TPA SIZE IS START OF BDOS
CALL PRTDECB ; PRINT IT
CALL PC_PERIOD ; DECIMAL POINT
LD A,0 + (((BDOS_LOC % 1024) * 100) / 1024)
CALL PRTDECB ; MANTISSA
LD DE,STR_TPA2 ; AND TPA SUFFIX
CALL WRITESTR
CALL NEWLINE ; FORMATTING
;
; SETUP HL & DE TO CLEAR BUFFER AFTER RETURN (VIA CALL TO FILL)
; HL: START OF BUFFER AREA TO CLEAR (DIRBUF)
; BC: LENGTH OF BUFFER AREA TO CLEAR CBIOS_END - (DIRBUF)
; CLEAR BUFFER SPACE STARTING AT DIRBUF TO TOP OF CBIOS
LD HL,CBIOS_END ; CALC SIZE TO CLEAR BY
LD DE,(DIRBUF) ; ... SUBTRACTING DIRBUF START
SBC HL,DE ; ... FROM TOP OF CBIOS
PUSH HL ; MOVE SIZE
POP BC ; ... TO BC
LD HL,(DIRBUF) ; START OF AREA TO CLEAR -> HL
XOR A ; FILL WITH ZEROES
;
RET ; DONE
;
;
;__________________________________________________________________________________________________
DEV_INIT:
;
#IFDEF PLTWBW
;
; PATCH IN CRT: DEVICE
LD A,(HCB + HCB_CRTDEV) ; GET CONSOLE DEVICE
CP $FF ; NUL MEANS NO CRT DEVICE
JR Z,DEV_INIT00 ; IF SO, LEAVE IT ALONE
LD (DEVMAP + 1),A ; CONSOLE CRT
LD (DEVMAP + 13),A ; LIST CRT
;
; UPDATE IOBYTE IF CRT DEVICE IS ACTIVE
LD A,(HCB + HCB_CRTDEV) ; GET CRT DEVICE
LD B,A ; SAVE IN B
LD A,(HCB + HCB_CONDEV) ; GET CONSOLE DEVICE
CP B ; COMPARE
JR NZ,DEV_INIT00 ; IF DIFFERENT (CRT NOT ACTIVE), LEAVE IOBYTE ALONE
LD A,1 ; IF SAME (CRT ACTIVE), SET IOBYTE FOR CON: = CRT:
LD (IOBYTE),A ; STORE IN IOBYTE
;
DEV_INIT00:
; LOOP THRU DEVICES ADDING NON-CRT DEVICES TO DEVMAP
LD B,BF_SYSGET ; HBIOS FUNC: GET SYS INFO
LD C,BF_SYSGET_CIOCNT ; SUBFUNC: GET CIO UNIT COUNT
RST 08 ; E := SERIAL UNIT COUNT
LD B,E ; COUNT TO B
LD C,0 ; UNIT INDEX
LD HL,DEV_INIT1 ; POINTER FOR FIRST ENTRY FOUND
DEV_INIT0:
PUSH BC ; SAVE LOOP CONTROL
PUSH HL ; SAVE TARGET
LD B,BF_CIODEVICE ; HBIOS FUNC: GET DEVICE INFO
RST 08 ; D := DEVICE TYPE, E := PHYSICAL UNIT NUMBER
POP HL ; RESTORE TARGET
LD A,D ; DEVICE TYPE TO A
CP CIODEV_VDU ; COMPARE TO FIRST VIDEO DEVICE
POP BC ; RESTORE LOOP CONTROL
LD A,C ; UNIT INDEX TO ACCUM
;CALL C,JPHL ; DO IT IF DEVICE TYPE < VDU
CALL JPHL ; DO FOR ANY CHARACTER DEVICE TYPE
INC C ; NEXT UNIT
DJNZ DEV_INIT0 ; LOOP TILL DONE
RET ; ALL DONE
;
DEV_INIT1:
; PATCH IN COM0: DEVICE ENTRIES
LD (DEVMAP + 0),A ; CONSOLE TTY
LD (DEVMAP + 4),A ; READER TTY
LD (DEVMAP + 8),A ; PUNCH TTY
LD (DEVMAP + 12),A ; LIST TTY
LD HL,DEV_INIT2 ; HL := CODE FOR NEXT DEVICE
RET
;
DEV_INIT2:
; PATCH IN COM1: DEVICE ENTRIES
LD (DEVMAP + 3),A ; CONSOLE UC1
LD (DEVMAP + 5),A ; READER PTR
LD (DEVMAP + 9),A ; PUNCH PTP
LD HL,DEV_INIT3 ; HL := CODE FOR NEXT DEVICE
RET
;
DEV_INIT3:
; PATCH IN COM2: DEVICE ENTRIES
LD (DEVMAP + 6),A ; READER UR1
LD (DEVMAP + 10),A ; PUNCH PT1
LD HL,DEV_INIT4 ; HL := CODE FOR NEXT DEVICE
RET
;
DEV_INIT4:
; PATCH IN COM3: DEVICE ENTRIES
LD (DEVMAP + 7),A ; READER UR2
LD (DEVMAP + 11),A ; PUNCH PT2
LD HL,DEV_INIT5 ; HL := CODE FOR NEXT DEVICE
RET
;
DEV_INIT5:
RET ; FAILSAFE IN CASE MORE THAN 4 COM DEVICES
;
#ENDIF
RET
;
;
;
;__________________________________________________________________________________________________
MD_INIT:
;
; UDPATE THE RAM/ROM DPB STRUCTURES BASED ON HARDWARE
;
#IFDEF PLTWBW
LD A,(HCB + HCB_ROMBANKS) ; ROM BANK COUNT
LD IX,DPB_ROM ; ADDRESS OF DPB
CALL MD_INIT1 ; FIX IT UP
;
LD A,(HCB + HCB_RAMBANKS) ; RAM BANK COUNT
LD IX,DPB_RAM ; ADDRESS OF DPB
CALL MD_INIT1 ; FIX IT UP
;
JR MD_INIT4 ; DONE
;
MD_INIT1:
;
; PUT USABLE BANK COUNT IN HL
SUB 4 ; REDUCE BANK COUNT BY RESERVED PAGES
LD L,A ; PUT IN LSB OF HL
LD H,0 ; MSB IS ALWAYS ZERO
;
; UPDATE ALS FIELD
LD A,L ; LSB OF PAGE COUNT
RLCA ; DOUBLE IT
LD (IX - 3),A ; SAVE IT AS LSB OF ALS
;
; UDPATE EXM FIELD
LD A,L ; LSB OF PAGE COUNT
CP 16 + 1 ; COMPARE TO EXM THRESHOLD
LD A,1 ; ASSUME <= 16 BANKS, EXM := 1
JR C,MD_INIT2
XOR A ; > 16 BANKS, EXM := 0
MD_INIT2:
LD (IX + 4),A ; SAVE EXM VALUE
;
; UPDATE DSM FIELD
LD B,4 ; ROTATE 4 TIMES TO MULTIPLY BY 16
MD_INIT3:
SLA L ; SHIFT LSB
RL H ; SHIFT MSB W/ CARRY
DJNZ MD_INIT3 ; REPEAT AS NEEDED
DEC HL ; SUBTRACT 1 FOR PROPER DSM VALUE
LD (IX+5),L ; SAVE UPDATED
LD (IX+6),H ; ... DSM VALUE
RET
;
MD_INIT4:
;
#ENDIF
;
#IFDEF PLTUNA
;
; 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,BID_RAMD0 ; 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 $E5
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 BC,$01FB ; UNA FUNC = SET BANK
LD DE,BID_USR ; SWITCH BACK TO EXEC BANK FOR WRITESTR
CALL $FFFD ; DO IT (RST 08 NOT SAFE HERE)
CALL NEWLINE2 ; FORMATTING
LD DE,STR_INITRAMDISK ; RAM DISK INIT MESSAGE
CALL WRITESTR ; DISPLAY IT
LD BC,$01FB ; UNA FUNC = SET BANK
LD DE,BID_RAMD0 ; 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 BC,$01FB ; UNA FUNC = SET BANK
LD DE,BID_USR ; 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 B,BF_SYSSETBNK ; HBIOS FUNC: SET BANK
LD A,(BNKRAMD) ; FIRST BANK OF RAM DISK
LD C,A ; ... TO C
CALL $FFF0 ; DO IT (RST 08 NOT SAFE)
#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 $E5
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 B,BF_SYSSETBNK ; HBIOS FUNC: SET BANK
LD A,(BNKUSER) ; SWITCH BACK TO USER BANK
LD C,A ; ... TO REG C
CALL $FFF0 ; DO IT (RST 08 NOT SAFE)
LD DE,STR_INITRAMDISK ; RAM DISK INIT MESSAGE
CALL WRITESTR ; DISPLAY IT
LD B,BF_SYSSETBNK ; HBIOS FUNC: SET BANK
LD A,(BNKRAMD) ; SWITCH BACK TO FIRST BANK
LD C,A ; ... TO REG C
CALL $FFF0 ; DO IT (RST 08 NOT SAFE)
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 B,BF_SYSSETBNK ; HBIOS FUNC: SET BANK
LD A,(BNKUSER) ; USR BANK (TPA)
LD C,A ; ... TO REG C
CALL $FFF0 ; DO IT (RST 08 NOT SAFE)
#ENDIF
;
#ENDIF
;
RET
;
;
;__________________________________________________________________________________________________
#IFDEF PLTUNA
;
DRV_INIT:
;
; PERFORM UBIOS SPECIFIC INITIALIZATION
; BUILD DRVMAP BASED ON AVAILABLE UBIOS DISK DEVICE LIST
;
; GET BOOT UNIT/SLICE INFO
LD BC,$00FC ; UNA FUNC: GET BOOTSTRAP HISTORY
RST 08 ; CALL UNA
LD D,L ; SAVE L AS UNIT
LD E,0 ; SLICE IS ZERO
LD (BOOTVOL),DE ; D -> UNIT, E -> SLICE
;
; SETUP THE DRVMAP STRUCTURE
LD HL,(HEAPTOP) ; GET CURRENT HEAP TOP
INC HL ; SKIP 1 BYTE FOR ENTRY COUNT PREFIX
LD (DRVMAPADR),HL ; SAVE AS DRIVE MAP ADDRESS
LD (HEAPTOP),HL ; ... AND AS NEW HEAP TOP
;
; LOOP THRU DEVICES TO COUNT TOTAL HARD DISK VOLUMES
LD B,0 ; START WITH UNIT 0
LD L,0 ; INIT HD VOL COUNT
;
DRV_INIT2: ; LOOP THRU ALL UNITS AVAILABLE
PUSH HL ; SAVE HD VOL COUNT
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
POP HL ; RESTORE HD VOL COUNT
OR A ; PAST END?
JR Z,DRV_INIT4 ; WE ARE DONE, MOVE ON
CALL DRV_INIT3 ; PROCESS THE UNIT
INC B ; NEXT UNIT
JR DRV_INIT2 ; LOOP
;
DRV_INIT3:
LD A,D ; DRIVER TYPE TO A
CP $40 ; RAM/ROM?
RET Z ; DO NOT COUNT
;CP $?? ; FLOPPY?
;RET Z ; DO NOT COUNT
INC L ; INCREMENT HARD DISK COUNT
RET ; DONE
;
DRV_INIT4: ; SET SLICES PER VOLUME (HDSPV) BASED ON HARD DISK VOLUME COUNT
LD A,L ; HARD DISK VOLUME COUNT TO A
LD E,8 ; ASSUME 8 SLICES PER VOLUME
DEC A ; DEC ACCUM TO CHECK FOR COUNT = 1
JR Z,DRV_INIT5 ; YES, SKIP AHEAD TO IMPLEMENT 8 HDSPV
LD E,4 ; NOW ASSUME 4 SLICES PER VOLUME
DEC A ; DEC ACCUM TO CHECK FOR COUNT = 2
JR Z,DRV_INIT5 ; YES, SKIP AHEAD TO IMPLEMENT 4 HDSPV
LD E,2 ; IN ALL OTHER CASES, WE USE 2 HDSPV
;
DRV_INIT5:
LD A,E ; SLICES PER VOLUME VALUE TO ACCUM
LD (HDSPV),A ; SAVE IT
;
; SETUP TO ENUMERATE DEVICES TO BUILD DRVMAP
LD B,0 ; START WITH UNIT 0
;
DRV_INIT6: ; 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?
RET Z ; WE ARE DONE
PUSH BC ; SAVE UNIT
CALL DRV_INIT7 ; PROCESS THE UNIT
POP BC ; RESTORE UNIT
INC B ; NEXT UNIT
JR DRV_INIT6 ; LOOP
;
DRV_INIT7: ; PROCESS CURRENT UNIT (SEE UNA PROTOIDS.INC)
LD A,D ; DRIVE TYPE TO ACCUM
LD D,B ; UNIT TO D
LD E,0 ; INIT SLICE INDEX
LD B,1 ; DEFAULT LOOP COUNTER (1 SLICE)
CP $40 ; RAM/ROM?
JR Z,DRV_INIT8 ; SINGLE SLICE, DO IT
;CP $?? ; FLOPPY?
;JR Z,DRV_INIT8 ; SINGLE SLICE, DO IT
LD A,(HDSPV) ; GET SLICES PER VOLUME TO ACCUM
LD B,A ; MOVE TO B FOR LOOP COUNTER
;
DRV_INIT8: ; SLICE CREATION LOOP
;
; INC DRVMAP ENTRY COUNT AND CHECK FOR 16 ENTRY MAXIMUM
LD HL,(DRVMAPADR) ; POINT TO DRIVE MAP
DEC HL ; BACKUP TO POINT TO ENTRY COUNT
LD A,(HL) ; CURRENT COUNT TO ACCUM
CP 16 ; AT MAX?
RET NC ; IF >= MAX, JUST BAIL OUT
INC (HL) ; INCREMENT THE ENTRY COUNT
;
; ALLOCATE ENTRY AND FILL IN UNIT, SLICE
LD HL,4 ; 4 BYTES PER ENTRY
CALL ALLOC ; ALLOCATE SPACE
CALL NZ,PANIC ; SHOULD NEVER ERROR HERE
LD (HL),D ; SAVE UNIT IN FIRST BYTE OF DRVMAP ENTRY
INC HL ; POINT TO NEXT BYTE OF DRVMAP ENTRY
LD (HL),E ; SAVE SLICE NUM IN SECOND BYTE OF DRVMAP ENTRY
;
INC E ; INCREMENT SLICE INDEX
DJNZ DRV_INIT8 ; LOOP AS NEEDED
RET ; DONE
;
#ELSE
;
DRV_INIT:
;
; PERFORM HBIOS SPECIFIC INITIALIZATION
; BUILD DRVMAP BASED ON AVAILABLE HBIOS DISK DEVICE LIST
;
; GET BOOT UNIT/SLICE INFO
LD DE,(HCB + HCB_BOOTVOL) ; BOOT VOLUME (UNIT, SLICE)
LD (BOOTVOL),DE ; D -> UNIT, E -> SLICE
;
; SETUP THE DRVMAP STRUCTURE
LD HL,(HEAPTOP) ; GET CURRENT HEAP TOP
INC HL ; SKIP 1 BYTE FOR ENTRY COUNT PREFIX
LD (DRVMAPADR),HL ; SAVE AS DRVMAP ADDRESS
LD (HEAPTOP),HL ; AND AS NEW HEAP TOP
;
; SETUP TO LOOP THROUGH AVAILABLE DEVICES
LD B,BF_SYSGET
LD C,BF_SYSGET_DIOCNT
RST 08 ; E := DISK UNIT COUNT
LD B,E ; COUNT TO B
LD A,B ; COUNT TO A
OR A ; SET FLAGS
RET Z ; HANDLE ZERO DEVICES (ALBEIT POORLY)
;
; LOOP THRU DEVICES TO COUNT TOTAL HARD DISK VOLUMES
PUSH BC ; SAVE THE DEVICE COUNT
LD C,0 ; USE C AS DEVICE LIST INDEX
LD E,0 ; INIT E FOR HARD DISK VOLUME COUNT
;
DRV_INIT2:
PUSH BC ; SAVE LOOP CONTROL
CALL DRV_INIT3 ; CHECK DRIVE
POP BC ; RESTORE LOOP CONTROL
INC C ; NEXT UNIT
DJNZ DRV_INIT2 ; LOOP
POP BC ; RESTORE UNIT COUNT IN B
JR DRV_INIT4 ; CONTINUE
;
DRV_INIT3:
PUSH DE ; SAVE DE (HARD DISK VOLUME COUNTER)
LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO
RST 08 ; CALL HBIOS, UNIT TO C
LD A,D ; DEVICE TYPE TO A
POP DE ; RESTORE DE
CP DIODEV_IDE ; HARD DISK DEVICE?
RET C ; NOPE, RETURN
INC E ; INCREMENT HARD DISK COUNT
RET ; AND RETURN
;
DRV_INIT4: ; SET SLICES PER VOLUME (HDSPV) BASED ON HARD DISK VOLUME COUNT
LD A,E ; HARD DISK VOLUME COUNT TO A
LD E,8 ; ASSUME 8 SLICES PER VOLUME
DEC A ; DEC ACCUM TO CHECK FOR COUNT = 1
JR Z,DRV_INIT5 ; YES, SKIP AHEAD TO IMPLEMENT 8 HDSPV
LD E,4 ; NOW ASSUME 4 SLICES PER VOLUME
DEC A ; DEC ACCUM TO CHECK FOR COUNT = 2
JR Z,DRV_INIT5 ; YES, SKIP AHEAD TO IMPLEMENT 4 HDSPV
LD E,2 ; IN ALL OTHER CASES, WE USE 2 HDSPV
;
DRV_INIT5:
LD A,E ; SLICES PER VOLUME VALUE TO ACCUM
LD (HDSPV),A ; SAVE IT
;
; SETUP TO ENUMERATE DEVICES TO BUILD DRVMAP
LD B,BF_SYSGET
LD C,BF_SYSGET_DIOCNT
RST 08 ; E := DISK UNIT COUNT
LD B,E ; COUNT TO B
LD C,0 ; USE C AS DEVICE LIST INDEX
;
DRV_INIT6: ; LOOP THRU ALL UNITS AVAILABLE
PUSH BC ; PRESERVE LOOP CONTROL
LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO
RST 08 ; CALL HBIOS, D := DEVICE TYPE
POP BC ; GET UNIT INDEX BACK IN C
PUSH BC ; RESAVE LOOP CONTROL
CALL DRV_INIT7 ; MAKE DRIVE MAP ENTRY(S)
POP BC ; RESTORE LOOP CONTROL
INC C ; INCREMENT LIST INDEX
DJNZ DRV_INIT6 ; LOOP AS NEEDED
RET ; FINISHED
;
DRV_INIT7: ; PROCESS UNIT
LD E,0 ; INITIALIZE SLICE INDEX
LD B,1 ; DEFAULT LOOP COUNTER
LD A,D ; DEVICE TYPE TO ACCUM
LD D,C ; UNIT NUMBER TO D
CP DIODEV_IDE ; HARD DISK DEVICE?
JR C,DRV_INIT8 ; NOPE, LEAVE LOOP COUNT AT 1
LD A,(HDSPV) ; GET SLICES PER VOLUME TO ACCUM
LD B,A ; MOVE TO B FOR LOOP COUNTER
;
DRV_INIT8: ; SLICE CREATION LOOP
;
; INC DRVMAP ENTRY COUNT AND ENFORCE FOR 16 ENTRY MAXIMUM
LD HL,(DRVMAPADR) ; POINT TO DRIVE MAP
DEC HL ; BACKUP TO POINT TO ENTRY COUNT
LD A,(HL) ; CURRENT COUNT TO ACCUM
CP 16 ; AT MAX?
RET NC ; IF >= MAX, JUST BAIL OUT
INC (HL) ; INCREMENT THE ENTRY COUNT
;
; ALLOCATE ENTRY AND FILL IN UNIT, SLICE
LD HL,4 ; 4 BYTES PER ENTRY
CALL ALLOC ; ALLOCATE SPACE
CALL NZ,PANIC ; SHOULD NEVER ERROR HERE
LD (HL),D ; SAVE UNIT IN FIRST BYTE OF DRVMAP ENTRY
INC HL ; POINT TO NEXT BYTE OF DRVMAP ENTRY
LD (HL),E ; SAVE SLICE NUM IN SECOND BYTE OF DRVMAP ENTRY
;
INC E ; INCREMENT SLICE INDEX
DJNZ DRV_INIT8 ; LOOP AS NEEDED
RET ; DONE
;
#ENDIF
;
;
;__________________________________________________________________________________________________
;
DPH_INIT:
;
; ITERATE THROUGH DRIVE MAP TO BUILD DPH ENTRIES DYNAMICALLY
;
CALL NEWLINE2 ; FORMATTING
LD DE,STR_DPHINIT ; POINT TO MSG
CALL WRITESTR ; DISPLAY IT
CALL NEWLINE ; FORMATTING
;
; ALLOCATE DPH POOL SPACE BASED ON DRIVE COUNT
LD HL,(DRVMAPADR) ; LOAD DRIVE MAP POINTER
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
CALL ALLOC ; ALLOCATE THE SPACE
CALL NZ,PANIC ; SHOULD NEVER ERROR
;
; SET DPHTOP TO START OF ALLOCATED SPACE
LD (DPHTOP),HL ; ... AND SAVE IN DPHTOP
;
; ALLOCATE DIRECTORY BUFFER
LD HL,128 ; SIZE OF DIRECTORY BUFFER
CALL ALLOC ; ALLOCATE THE SPACE
CALL NZ,PANIC ; SHOULD NEVER ERROR
LD (DIRBUF),HL ; ... AND SAVE IN DIRBUF
;
; SETUP FOR DPH BUILD LOOP
LD HL,(DRVMAPADR) ; POINT TO DRIVE MAP
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 := UNIT
INC HL ; BUMP
LD E,(HL) ; E := SLICE
INC HL ; BUMP
CALL PRTDRV ; PRINT DRIVE INFO
LD A,D ; A := UNIT
PUSH HL ; SAVE DRIVE MAP POINTER
PUSH AF ; SAVE UNIT
; MATCH AND SAVE DEFAULT DRIVE BASED ON BOOT UNIT/SLICE
LD HL,BOOTVOL + 1 ; POINT TO BOOT UNIT
LD A,D ; LOAD CURRENT UNIT
CP (HL) ; MATCH?
JR NZ,DPH_INIT1A ; BYPASS IF NOT BOOT UNIT
DEC HL ; POINT TO BOOT SLICE
LD A,E ; LOAD CURRENT SLICE
CP (HL) ; MATCH?
JR NZ,DPH_INIT1A ; BYPASS IF NOT BOOT SLICE
LD A,C ; LOAD THE CURRENT DRIVE NUM
LD (DEFDRIVE),A ; SAVE AS DEFAULT
DPH_INIT1A:
POP AF ; RESTORE UNIT
LD DE,(DPHTOP) ; GET ADDRESS OF NEXT DPH
PUSH DE ; ... AND SAVE IT
; INVOKE THE DPH BUILD ROUTINE
PUSH BC ; SAVE LOOP CONTROL
CALL MAKDPH ; MAKE THE DPH AT DE, 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 TO DE
POP HL ; RESTORE DRIVE MAP POINTER TO HL
JR Z,DPH_INIT2 ; IF MAKDPH 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 UNIT IN A
;
PUSH DE ; SAVE INCOMING DPH ADDRESS
;
#IFDEF PLTUNA
;
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,INIBUF ; 512 BYTE BUFFER
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 (UNIT NUMBER IN A)
; GET DEVICE INFO
LD C,A ; UNIT NUMBER TO C
LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO
RST 08 ; CALL HBIOS, RET W/ DEVICE TYPE IN D, PHYSICAL UNIT IN E
LD A,D ; DEVICE TYPE TO A
CP DIODEV_MD ; RAM/ROM DISK?
JR Z,MAKDPH0 ; HANDLE SPECIAL
LD DE,DPB_FD144 ; PRELOAD FLOPPY DPB
CP DIODEV_FD ; FLOPPY?
JR Z,MAKDPH1 ; IF SO, PROCEED TO DPH CREATION
LD DE,DPB_RF ; PRELOAD RAM FLOPPY DPB
CP DIODEV_RF ; RAM FLOPPY?
JR Z,MAKDPH1 ; IF SO, PROCEED TO DPH CREATION
; EVERYTHING ELSE IS A HARD DISK
LD DE,DPB_HD ; PRELOAD HARD DISK DPB
JR MAKDPH1 ; PROCEED TO DPH CREATION
;
MAKDPH0:
; RAM/ROM DISK DPB DERIVATION
; TYPE OF MEMORY DISK (RAM/ROM) DETERMINED BY PHYSICAL UNIT NUMBER
LD A,E ; LOAD PHYSICAL UNIT NUMBER
LD DE,DPB_ROM ; PRELOAD ROM DISK DPB
OR A ; UNIT=0 (ROM)?
JR Z,MAKDPH1 ; IF UNIT=0, IT IS ROM, PROCEED TO DPH CREATION
LD DE,DPB_RAM ; PRELOAD RAM DISK DPB
CP $01 ; UNIT=1 (RAM)?
JR Z,MAKDPH1 ; IF UNIT=0, IT IS ROM, PROCEED TO DPH CREATION
CALL PANIC ; OTHERWISE UNKNOWN, NOT POSSIBLE, JUST PANIC
;
#ENDIF
;
MAKDPH1:
;
; BUILD THE DPH (DE POINTS TO DPB)
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
; FALL THRU FOR ALS BUF
MAKDPH2:
PUSH HL ; SAVE DPH PTR
EX DE,HL ; USE HL AS DPB PTR, DE IS NOW SCRATCH
LD E,(HL) ; DE := CKS/ALS SIZE
INC HL ; ... AND BUMP
LD D,(HL) ; ... PAST
INC HL ; ... CKS/ALS SIZE
EX DE,HL ; DPB PTR BACK TO DE, ALLOC SIZE TO HL
LD A,H ; CHECK TO SEE
OR L ; ... IF HL (ALLOC SIZE) IS ZERO
CALL NZ,ALLOC ; ALLOC BC BYTES, ADDRESS RETURNED IN BC
PUSH HL ; MOVE ALLOC RESULT PTR
POP BC ; ... TO BC
POP HL ; RECOVER DPH PTR TO HL
JR NZ,ERR_HEAPOVF ; HANDLE POSSIBLE ALLOC OVERFLOW HERE
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 HL BYTES FROM HEAP, RETURN STARTING
; ADDRESS IN HL. LEAVE ALL OTHER REGS ALONE EXCEPT A
; Z FOR SUCCESS, NZ FOR FAILURE
;
PUSH BC ; SAVE ORIGINAL BC
LD BC,(HEAPTOP) ; BC := CURRENT HEAP TOP
PUSH BC ; SAVE AS START OF REQUESTED BUFFER
ADD HL,BC ; HL := NEW HEAP TOP
LD A,$FF ; ASSUME OVERFLOW FAILURE
JR C,ALLOC1 ; IF MEMTOP OVERFLOW, EXIT WITH A == $FF
PUSH HL ; OTHERWISE, SAVE NEW HEAP TOP VALUE
LD BC,MEMTOP - HEAPEND ; SETUP BC FOR HEAP OVERFLOW TEST
ADD HL,BC ; CHECK FOR HEAP OVERFLOW
POP HL ; RECOVER HL (NEW HEAP TOP VALUE)
JR C,ALLOC1 ; IF HEAP OVERFLOW, EXIT WITH A == $FF
LD (HEAPTOP),HL ; SAVE NEW HEAP TOP
INC A ; SIGNAL SUCCESS
;
ALLOC1:
POP HL ; ALLOCATED BUF START ADDRESS TO HL
POP BC ; RESTORE BC
OR A ; SET ZF TO SIGNAL RESULT
RET
;
ERR_HEAPOVF:
LD DE,STR_HEAPOVF
JR ERR
;
ERR_INVMED:
LD DE,STR_INVMED
JR ERR
;
ERR:
CALL WRITESTR
OR $FF
RET
;
PRTDRV:
;
; PRINT THE UNIT/SLICE INFO
; ON INPUT D HAS UNIT, E HAS SLICE
; DESTROY NO REGISTERS OTHER THAN A
;
#IFDEF PLTUNA
;
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,PRTDRV1 ; IF SO, HANDLE RAM/ROM
LD DE,DEVIDE ; IDE STRING
CP $41 ; IDE?
JR Z,PRTDRVX ; IF YES, PRINT
LD DE,DEVPPIDE ; PPIDE STRING
CP $42 ; PPIDE?
JR Z,PRTDRVX ; IF YES, PRINT
LD DE,DEVSD ; SD STRING
CP $43 ; SD?
JR Z,PRTDRVX ; IF YES, PRINT
LD DE,DEVDSD ; DSD STRING
CP $44 ; DSD?
JR Z,PRTDRVX ; IF YES, PRINT
LD DE,DEVUNK ; OTHERWISE, UNKNOWN
JR PRTDRVX ; PRINT IT
PRTDRV1:
LD C,$45 ; UNA FUNC: GET DISK INFO
LD DE,INIBUF ; 512 BYTE BUFFER
CALL $FFFD ; CALL UNA
BIT 7,B ; TEST RAM DRIVE BIT
LD DE,DEVROM ; ASSUME ROM
JR Z,PRTDRVX ; IF SO, DISPLAY ROM
LD DE,DEVRAM ; ELSE RAM
JR Z,PRTDRVX ; DO IT
PRTDRVX:
CALL WRITESTR ; PRINT DEVICE NAME
POP HL ; RECOVER HL
POP DE ; RECOVER DE
POP BC ; RECOVER BC
LD A,D ; LOAD 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$"
DEVPPIDE .DB "PPIDE$"
DEVSD .DB "SD$"
DEVDSD .DB "DSD$"
DEVUNK .DB "UNK$"
;
#ELSE
;
PUSH BC ; PRESERVE BC
PUSH DE ; PRESERVE DE
PUSH HL ; PRESERVE HL
LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO
LD C,D ; UNIT TO C
RST 08 ; CALL HBIOS
LD A,D ; RESULTANT DEVICE TYPE
PUSH DE ; NEED TO SAVE UNIT NUMBER (IN E)
RRCA ; ROTATE DEVICE
RRCA ; ... BITS
RRCA ; ... INTO
RRCA ; ... LOWEST 4 BITS
AND $0F ; ISOLATE DEVICE BITS
ADD A,A ; MULTIPLY 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 DE ; RECOVER UNIT (IN E)
LD A,E ; LOAD UNIT
AND $0F ; ISOLATE UNIT
CALL PRTDECB ; PRINT IT
POP HL ; RECOVER HL
POP DE ; RECOVER DE
POP BC ; RECOVER BC
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
;
DPHTOP .DW 0 ; CURRENT TOP OF DPH POOL
DIRBUF .DW 0 ; DIR BUF POINTER
HEAPTOP .DW BUFPOOL ; CURRENT TOP OF HEAP
BOOTVOL .DW 0 ; BOOT VOLUME, MSB=BOOT UNIT, LSB=BOOT SLICE
BNKRAMD .DB 0 ; STARTING BANK ID FOR RAM DRIVE
HDSPV .DB 2 ; SLICES PER VOLUME FOR HARD DISKS (MUST BE >= 1)
;
CMD .DB CMDLEN - 1
#IFDEF AUTOCMD
.TEXT AUTOCMD
#ENDIF
.DB 0
CMDLEN .EQU $ - CMD
;
STR_BANNER .DB "CBIOS v", BIOSVER, " [", PLTSTR, "]$"
STR_INITRAMDISK .DB "Formatting RAMDISK...$"
STR_LDR2 .DB "\r\n"
STR_LDR .DB "\r\n $"
STR_DPHINIT .DB "Configuring Drives...$"
STR_HEAPOVF .DB " *** Insufficient Memory ***$"
STR_INVMED .DB " *** Invalid Device ID ***$"
STR_MEMFREE .DB " Disk Buffer Bytes Free$"
STR_CPM .DB "CP/M-80 v2.2$"
STR_ZSDOS .DB "ZSDOS v1.1$"
STR_TPA1 .DB ", $"
STR_TPA2 .DB "K TPA$"
;
;==================================================================================================
;
;==================================================================================================
;
SLACK .EQU (CBIOS_END - $)
.ECHO "INIT code slack space: "
.ECHO SLACK
.ECHO " bytes.\n"
.FILL SLACK,$00
;
HEAPS .EQU (CBIOS_END - BUFPOOL)
.ECHO "HEAP space: "
.ECHO HEAPS
.ECHO " bytes.\n"
;
.ECHO "CBIOS total space used: "
.ECHO $ - CBIOS_LOC
.ECHO " bytes.\n"
;
; PAD OUT AREA RESERVED FOR HBIOS PROXY
.FILL MEMTOP - $
;
.END