Files
RomWBW/Source/CBIOS/cbios.asm
Wayne Warthen 99ec7049f7 Implement Auto PROFILE.SUB Execution on Boot
Updated CBIOS to look for PROFILE.SUB on the boot drive and SUBMIT it
automatically at cold boot if it exists.  Also patched SUBMIT.COM to
force temporary file onto A: to ensure immediate execution of SUBMITed
files.
2017-12-03 15:17:44 -08:00

2936 lines
87 KiB
NASM

;__________________________________________________________________________________________________
;
; CBIOS FOR SBC
;
; BY ANDREW LYNCH, WITH INPUT FROM MANY SOURCES
; ROMWBW ADAPTATION BY WAYNE WARTHEN
;__________________________________________________________________________________________________
;
; TODO:
; 1) STACK LOCATION DURING BOOT OR WBOOT???
; 2) REVIEW USE OF DI/EI IN INIT
;
FALSE .EQU 0
TRUE .EQU ~FALSE
;
BDOS .EQU 5 ; BDOS FUNC INVOCATION VECTOR
;
; 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 postion of the entry indicates
; the drive letter, so the first entry is A:, the second entry is B:, etc.
;
; UNIT: BIOS DISK UNIT # (BYTE)
; SLICE: DISK SLICE NUMBER (BYTE)
; DPH: DPH ADDRESS OF DRIVE (WORD)
;
; DRVMAP --+
; | DRIVE A | DRIVE B | | DRIVE N |
; +-----V------+-------+-----+--------------------+ +--------------------+
; | N | UNIT | SLICE | DPH | UNIT | SLICE | DPH | ... | UNIT | SLICE | DPH |
; +----8+-----8+------8+-+-16+-----8+------8+-+-16+ +-----8+------8+-+-16+
; | | |
; +--------------------+ +-> [DPH] +-> [DPH]
; |
; V-----+-------+-------+-------+--------+-----+-----+-----+
; DPH: | XLT | 0000H | 0000H | 0000H | DIRBUF | DPB | CSV | ALV |
; +---16+-----16+-----16+-----16+------16+-+-16+-+-16+-+-16+
; (ONE DPH PER DRIVE) | | |
; | | +----------+
; | | |
; +----------------------+ V-------------+ V-------------+
; | | CSV BUF | | ALV BUF |
; | +-------------+ +-------------+
; | (CSZ BYTES) (ASZ BYTES)
; |
; +-----+-----+-----V-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
; DPB: | CSZ | ASZ | BLS | SPT | BSH | BLM | EXM | DSM | DRM | AL0 | AL1 | CKS | OFF |
; +---16+---16+----8+---16+----8+----8+----8+---16+---16+----8+----8+---16+---16+
; |<--- PREFIX ---->|<------------------- STANDARD CP/M DPB ------------------->|
;
;==================================================================================================
; 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
LD SP,STACK ; STACK FOR INITIALIZATION
;
; COPY INITIALIZATION CODE TO RUNNINT LOCATION $8000
LD HL,BUFPOOL
LD DE,$8000
LD BC,CBIOS_END - BUFPOOL
PUSH HL ; SAVE START ADR FOR BELOW
PUSH HL ; SAVE START ADR AGAIN FOR BELOW
PUSH BC ; SAVE LENGTH FOR BELOW
LDIR ; COPY THE CODE
;
; CLEAR BUFFER
POP BC ; RECOVER LENGTH
POP HL ; RECOVER START
POP DE ; RECOVER START AS DEST
LD (HL),0 ; SET FIRST BYTE TO ZERO
INC DE ; OFFSET DEST
DEC BC ; REDUCE LEN BY ONE
LDIR ; USE LDIR TO FILL
;
CALL INIT ; PERFORM COLD BOOD ROUTINE
CALL RESCPM ; RESET CPM
CALL AUTOSUB ; PREP AUTO SUBMIT, IF APPROPRIATE
;
JR GOCPM ; THEN OFF TO CP/M WE GO...
;
;__________________________________________________________________________________________________
REBOOT:
; REBOOT FROM ROM, REPLACES BOOT AFTER INIT
#IFDEF PLTUNA
DI ; NO INTERRUPTS
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
DI ; NO INTERRUPTS
LD A,0 ; ROM BOOT BANK
CALL HB_BNKSEL ; SELECT IT INTO LOW MEMORY
#ENDIF
;
; JUMP TO RESTART ADDRESS
JP 0
;
;__________________________________________________________________________________________________
WBOOT:
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_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY
LD DE,(BNKBIOS) ; D = DEST (USER BANK), E = SRC (BIOS BANK)
LD HL,CCP_SIZ ; HL = COPY LEN = SIZE OF COMMAND PROCESSOR
RST 08 ; DO IT
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY
LD HL,(CCPBUF) ; COPY FROM FIXED LOCATION IN HB BANK
LD DE,CCP_LOC ; TO CCP LOCATION IN USR BANK
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
;
CALL RESCPM ; RESET CPM
JR GOCPM ; THEN OFF TO CP/M WE GO...
;
;__________________________________________________________________________________________________
RESCPM:
;
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
;
RET
;
;__________________________________________________________________________________________________
GOCPM:
;
; 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_SYSSETCPY ; HBIOS FUNC: SETUP BANK 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)
LD HL,128 ; HL = COPY LEN = DMA BUFFER SIZE
RST 08 ; DO IT
CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY
EX DE,HL ; SWAP HL/DE FOR BLOCK OPERATION
RST 08 ; DO IT
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_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY
LD DE,(BNKBIOS) ; E = SOURCE (BIOS BANK), D = DEST (USER BANK)
LD HL,128 ; HL = COPY LEN = DMA BUFFER SIZE
RST 08 ; DO IT
CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY
RST 08 ; DO IT
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:
PUSH BC
LD DE,(HSTTRK) ; GET TRACK INTO HL
LD B,4 ; PREPARE TO LEFT SHIFT BY 4 BITS
DSK_IO1:
SLA E ; SHIFT DE LEFT BY 4 BITS
RL D
DJNZ DSK_IO1 ; 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 ASSUMES FLOPPY IS DOUBLE-SIDED AND
; USES LOW ORDER BIT OF TRACK AS HEAD VALUE
;
; HBIOS SEEK: HL=CYLINDER, D=HEAD, E=SECTOR
;
LD DE,(HSTSEC) ; SECTOR -> DE, HEAD(D) BECOMES ZERO
LD HL,(HSTTRK) ; TRACK -> HL (LOW BIT HAS HEAD)
SRL H ; SHIFT HEAD BIT OUT OF HL
RR L ; ... AND INTO CARRY
RL D ; CARRY BIT (HEAD) INTO D
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.
;
;==================================================================================================
;
.ORG $8000 ; INIT CODE RUNS AT $8000
;
HEAPEND .EQU CBIOS_END - 64 ; TOP OF HEAP MEM, END OF CBIOS LESS 32 ENTRY STACK
;
INIT:
DI ; NO INTERRUPTS FOR NOW
; 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)
; COPY BIOS PAGE ZERO TO USER BANK
LD BC,$01FB ; UNA FUNC = SET BANK
LD DE,BID_BIOS ; UBIOS_PAGE (SEE PAGES.INC)
CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED)
PUSH DE ; SAVE PREVIOUS BANK
LD HL,0 ; FROM ADDRESS 0 (PAGE ZERO)
LD DE,SECBUF ; USE SECBUF AS BOUNCE BUFFER
LD BC,256 ; ONE PAGE IS 256 BYTES
LDIR ; DO IT
LD BC,$01FB ; UNA FUNC = SET BANK
POP DE ; RECOVER OPERATING BANK
CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED)
LD HL,SECBUF ; FROM SECBUF (BUNCE BUFFER)
LD DE,0 ; TO PAGE ZERO OF OPERATING BANK
LD BC,256 ; ONE PAGE IS 256 BYTES
LDIR ; DO IT
; 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
; GET CRITICAL BANK ID'S
LD B,BF_SYSGET ; HBIOS FUNC=GET SYS INFO
LD C,BF_SYSGET_BNKINFO ; HBIOS SUBFUNC=GET BANK ASSIGNMENTS
RST 08 ; CALL HBIOS
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
; SOFT RESET HBIOS
LD B,BF_SYSRESET ; HB FUNC: RESET
RST 08 ; DO IT
; CREATE A TEMP COPY OF THE HBIOS CONFIG BLOCK (HCB)
; FOR REFERENCE USE DURING INIT
LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY
LD DE,(BNKBIOS) ; D = DEST (USER BANK), E = SOURCE (BIOS BANK)
LD HL,HCB_SIZ ; HL = COPY LEN = SIZE OF HCB
RST 08 ; DO IT
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY
LD HL,HCB_LOC ; COPY FROM FIXED LOCATION IN HB BANK
LD DE,HCB ; TO TEMP LOCATION IN USR BANK
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 NEWLINE2 ; 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 ALLOCATED 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 B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK 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)
LD HL,CCP_SIZ ; HL = COPY LEN = SIZE OF COMMAND PROCESSOR
RST 08 ; DO IT
;LD B,BF_SYSCPY ; HBIOS FUNC: SYSTEM COPY
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK 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
;
#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
;
; DISPLAY FREE MEMORY
LD DE,STR_LDR2 ; FORMATTING
CALL WRITESTR ; AND PRINT IT
;LD HL,CBIOS_END ; SUBTRACT HIGH WATER
LD HL,HEAPEND ; 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
;
; 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
RET ; DONE
;
;
;__________________________________________________________________________________________________
AUTOSUB:
;
; SETUP AUTO SUBMIT COMMAND (IF REQUIRED FILES EXIST)
LD A,(DEFDRIVE) ; GET DEFAULT DRIVE
INC A ; CONVERT FROM DRIVE NUM TO FCB DRIVE CODE
LD (FCB_SUB),A ; SET DRIVE OF SUBMIT.COM FCB
LD (FCB_PRO),A ; SET DRIVE OF PROFILE.SUB FCB
;
LD C,17 ; BDOS FUNCTION: FIND FIRST
LD DE,FCB_SUB ; CHECK FOR SUBMIT.COM
CALL BDOS ; INVOKE BDOS TO LOOK FOR FILE
INC A ; CHECK FOR ERR, $FF --> $00
RET Z ; ERR, DO NOT ATTEMPT AUTO SUBMIT
;
LD C,17 ; BDOS FUNCTION: FIND FIRST
LD DE,FCB_PRO ; CHECK FOR PROFILE.SUB
CALL BDOS ; INVOKE BDOS TO LOOK FOR FILE
INC A ; CHECK FOR ERR, $FF --> $00
RET Z ; ERR, DO NOT ATTEMPT AUTO SUBMIT
;
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 ; PATCH COMMAND LINE INTO CCP
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
; FIX: BELOW SHOULD TEST THE "TERMINAL" BIT INSTEAD OF CHECKING DEVICE NUMBER
CP CIODEV_TERM ; 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)
DI ; NO INTERRUPTS
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)
EI ; RESUME INTERRUPTS
#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)
DI ; NO INTERRUPTS
LD A,(BNKRAMD) ; FIRST BANK OF RAM DISK
CALL HB_BNKSEL ; SELECT BANK
#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 A,(BNKUSER) ; SWITCH BACK TO USER BANK
CALL HB_BNKSEL ; SELECT BANK
CALL NEWLINE2 ; FORMATTING
LD DE,STR_INITRAMDISK ; RAM DISK INIT MESSAGE
CALL WRITESTR ; DISPLAY IT
LD A,(BNKRAMD) ; SWITCH BACK TO FIRST BANK
CALL HB_BNKSEL ; SELECT BANK
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,(BNKUSER) ; USR BANK (TPA)
CALL HB_BNKSEL ; SELECT BANK
EI ; RESUME INTRRUPTS
#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
CALL C,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
CALL C,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
CALL C,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
CALL C,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
JR C,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
;
; ALLOCATE HL BYTES FROM HEAP
; RETURN POINTER TO ALLOCATED MEMORY IN HL
; ON OVERFLOW ERROR, C SET
;
ALLOC:
PUSH DE ; SAVE DE SO WE CAN USE IT FOR WORK REG
LD DE,(HEAPTOP) ; GET CURRENT HEAP TOP
PUSH DE ; AND SAVE FOR RETURN VALUE
ADD HL,DE ; ADD REQUESTED SPACE, HL := NEW HEAP TOP
JR C,ALLOCX ; TEST FOR CPU MEMORY SPACE OVERFLOW
;LD DE,(HEAPLIM) ; LOAD DE WITH HEAP LIMIT
LD DE,HEAPEND ; LOAD DE WITH HEAP LIMIT
EX DE,HL ; DE=NEW HEAPTOP, HL=HEAPLIM
SBC HL,DE ; HEAPLIM - HEAPTOP
JR C,ALLOCX ; C SET ON OVERFLOW ERROR
; ALLOCATION SUCCEEDED, COMMIT NEW HEAPTOP
LD (HEAPTOP),DE ; SAVE NEW HEAPTOP
ALLOCX:
POP HL ; RETURN VALUE TO HL
POP DE ; RECOVER DE
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 - 2
.TEXT "SUBMIT PROFILE"
.DB 0
CMDLEN .EQU $ - CMD
;
FCB_SUB .DB '?' ; DRIVE CODE, 0 = CURRENT DRIVE
.DB "SUBMIT " ; FILE NAME, 8 CHARS
.DB "COM" ; FILE TYPE, 3 CHARS
.FILL 36-($-FCB_SUB),0 ; ZERO FILL REMAINDER OF FCB
;
FCB_PRO .DB '?' ; DRIVE CODE, 0 = CURRENT DRIVE
.DB "PROFILE " ; FILE NAME, 8 CHARS
.DB "SUB" ; FILE TYPE, 3 CHARS
.FILL 36-($-FCB_PRO),0 ; ZERO FILL REMAINDER OF FCB
;
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$"
#IFDEF PLTUNA
INIBUF .FILL 512,0 ; LOCATION OF TEMP WORK BUF DURING INIT (512 BYTES)
#ELSE
HCB .FILL HCB_SIZ,0 ; LOCATION OF TEMP COPY OF HCB DURING INIT (256 BYTES)
#ENDIF
;
;==================================================================================================
; END OF COLD BOOT INITIALIZATION
;==================================================================================================
;
.ORG BUFPOOL + ($ - $8000)
;
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