	TITLE	CUSTOMIZED BIOS FOR M5B
	LIST	NOCOND
BOOT	EQU	10H		;10H: HARD DISK, 3: 8" FLOPPY, 20H: 5" FLOPPY
;****************************************************************************
;
;	CUSTOMIZED BIOS FOR M5B
;	   (c) 1981   GRH Electronics, CUPERTINO, CA
;
;****************************************************************************
;
;	CONFIGURATION:
;
; CPM
; DRIVE	USAGE
   IF	BOOT = 10H		;HARD DISK BOOT CONFIG.
;   A	SIDE 0 & 1 OF HARD DISK PHYSICAL DRIVE 0
;   B	SIDE 2 & 3 OF HARD DISK PHYSICAL DRIVE 0
;   C	SIDE 0 & 1 OF HARD DISK PHYSICAL DRIVE 1
;   D	SIDE 2 & 3 OF HARD DISK PHYSICAL DRIVE 1
;   E	JADE 8" FLOPPY PHYSICAL DRIVE 0
;   F	JADE 8" FLOPPY PHYSICAL DRIVE 1
   ENDIF
   IF	BOOT = 3
;   A	JADE 8" FLOPPY PHYSICAL DRIVE 0
;   B	JADE 8" FLOPPY PHYSICAL DRIVE 1
;   C	SIDE 0 & 1 OF HARD DISK PHYSICAL DRIVE 0
;   D	SIDE 2 & 3 OF HARD DISK PHYSICAL DRIVE 0
;   E	SIDE 0 & 1 OF HARD DISK PHYSICAL DRIVE 1
;   F	SIDE 2 & 3 OF HARD DISK PHYSICAL DRIVE 1
   ENDIF
   IF	BOOT = 20H
;   A	JADE 5" FLOPPY PHYSICAL DRIVE 0
;   B	JADE 5" FLOPPY PHYSICAL DRIVE 1
;   C	SIDE 0 & 1 OF HARD DISK PHYSICAL DRIVE 0
;   D	SIDE 2 & 3 OF HARD DISK PHYSICAL DRIVE 0
;   E	SIDE 0 & 1 OF HARD DISK PHYSICAL DRIVE 1
;   F	SIDE 2 & 3 OF HARD DISK PHYSICAL DRIVE 1
;   G	JADE 8" FLOPPY PHYSICAL DRIVE 0
;   H	JADE 8" FLOPPY PHYSICAL DRIVE 1
   ENDIF
;
;*************************************************************
;
;   REVISION HISTORY:
;
; 3.00 - 26 JAN 87   GRH
;	Implemented new common IOPB code & Jade floppy firmware support.
;	Implemented disk drive driver tables and new function to return
;	 a ptr to a drive table.
;	Removed init of IOBYTE.
;	Implemented 5" floppy driver.
;	Implemented use of ROM primitives.
;	Moved system down to 60k.
; 3.01 	26 JUN 88 GRH
;	Remove 5" floppy support. Implement in CP/M-86 BIOS.
;	Change single function to return drive table ptr into a BIOS function
;	  call using restart instruction.
;	Change LOGON to specify the ID sector & track. At same time, fix bug
;	  which did not specify the logon track.
; 3.02	7 JUL 88   GRH
;	Add '?' to include file names.
;	Change hard disk system tracks directory reference to new format.
;	Correct bug in drivers which caused retry to fail. (sector remained
;	  corrupted)
;	Stubbed out new Clock routines for present.
; 3.03	31 JUL 88   GRH
;	Unstub Clock routines.
; 3.04	6 AUG 88   GRH
;	Remove floppy side select from BIOS & move to controller.
;	Implement new ID sector format.
;	Implement CP/M 3.0 DPB structure in preparation for deblocking.
; 3.05	11-3-88   GRH
;	Change included data to update IOPB.PBSTAT to new configuration.
; 3.06	1-28-89   GRH
;	Revised primitive calling procedures to use the monitor rom function
;	 rather than swapping Roms itself.
; 3.07	11-25-90   GRH
;	Modify for Ver. 1.22 Monitor.
;	Fix bug in 8" Hard Disk table which benignly (at current level)
;	 caused the drive table to have bad data (default table was missing
;	 the 2 deblocking extension bytes).
;	Implement data xfer inhibit schemes with PB_FLG & PB_BCNT.
;	Add pick-up of THIS_BNK data in all iopb cases.
;	Remove clock buffer set/read system calls.
;	12-5-90  GRH
;	Remove IX IOPB ptr passing to disk drivers.
;	1-13-91   GRH
;	Fix bug which corrupted PB_FLG.
; 3.08	2-22-91   GRH
;	Remove references to THIS_BNK & use monitor function #7 instead.
;	Add track-head shift factor to DPBs for future use.
; 3.09	5-15-91   GRH
;	Change 8" floppy side select to track bit 0. Move calculation from
;	 DCM8 to CBIOS.
;	Remove IOPB ptr passing in IX redundancy.
;	Change DPB track-head shift factor to Sector Offset like track
;	 offset. Disk partitioning will add this value to sector word. It
;	 will be stored in the ID sector data to be dynamic.
;
; 3.10	5-20-91   GRH
;	Change LOGON to attempt to recover from old disks better, using
;	 DCM8301 version controller firmware.
;
; 3.11	9-2-91   GRH
;	Add redlines & change for M5ZMON v.2.00.
;
; 3.12	9-11-91   GRH
;	Add deblocking code.
;	9-17-91   GRH		Add r/ls & move to 59k system.
;	9-19-91   GRH		Fix bug which destroyed my root directories!
;	  BUF_RD was writing.
;	  Patch problems with partitioning until 20MB drive installed.
;	  Fix TPA corruption by LOGON problem by using ROMBNK sector buffer for
;	   ID sector read.
;	9-20-91   GRH		Fold in redlines.
;	10-21-91   GRH		Fix bugs
;	10-22-91   GRH		Fix bugs
;	10-23-91   GRH		Fix bugs
;
VERSN	EQU	312
;
;****************************************************************************

	SUBTTL	SYSTEM DECLARATIONS
;============================================================================
;
;	ASSEMBLY PARAMETERS
;
;============================================================================
;
FALSE	EQU	0
TRUE	EQU	NOT FALSE


;============================================================================
;
;	CONDITIONAL ASSEMBLY FLAGS
;
;============================================================================
;
INTCPTS	EQU	TRUE		;ENABLE SYSTEM CALL INTERCEPT WHISTLE


;============================================================================
;
; INCLUDE   COMIOPB3.DEF
; INCLUDE     DISKS3.DEF
; INCLUDE       BDIR.DEF
; INCLUDE      M5ZF2.DEF
;
;============================================================================
;
	LIST	OFF
*INCLUDE   COMIOPB3.DEF
*INCLUDE     DISKS3.DEF
*INCLUDE       BDIR.DEF
*INCLUDE      M5ZF2.DEF
	LIST	ON


;============================================================================
;
;   DISK OPERATING SYSTEM ADDRESSES
;
;============================================================================
;
SYS	EQU	2	;CP/M VERSION {2,3}
;
NKSYS:	EQU	59			;SYSTEM SIZE IN K BYTES
KBYTE:	EQU	1024
CPMSZ:	EQU	KBYTE * NKSYS
CPMBS:	EQU	CPMSZ - (20 * KBYTE) 	;CP/M BIAS VALUE
CCP:	EQU	CPMBS + 3400H		;ADDR OF CCP
BDOS:	EQU	CPMBS + 3C00H		;ADDRESS OF BDOS
BIOS:	EQU	CPMBS + 4A00H		;ADDRESS OF BDOS
BIOSR:	EQU	1000H - BIOS
;
;   PAGE 0 LOCATIONS
;
PAGE0:	EQU	0		;START OF CP/M RAM
DEFDRV:	EQU	PAGE0 + 4	;DEFAULT DRIVE PARAM ADDR
BDOSJV	EQU	PAGE0 + 5	;BDOS SYSTEM CALL ENTRY
THIS_STK EQU	PAGE0 + 1CH	;CURRENT STACK FRAME PTR
DK_BDRV	EQU	0041H		;BOOT DRIVE # FROM PROM
DEFBFR	EQU	PAGE0 + 80H	;DEFAULT BUFFER
;
;   BIOS FUNCTION CALL RESTART VECTOR
;
BFUNRST	EQU	28H
BFUNRSV	EQU	PAGE0 + BFUNRST
BFUNRSI	EQU	0C7H + BFUNRST


;============================================================================
;
;	OTHER DECLARATIONS
;
;============================================================================
;
SECSZ:	EQU	128
NDRVS:	EQU	6
   IF	BOOT = 10H
;
;   8" HARD DISK BOOT DATA
;
STHD	EQU	0		;START LOGICAL DRIVE OF HARD DISK
NDHD	EQU	3		;LAST LOGICAL DRIVE OF HARD DISK
ST8FD	EQU	4		;START LOGICAL DRIVE OF 8" FLOPPY
ND8FD	EQU	5		;LAST LOGICAL DRIVE OF 8" FLOPPY
   ENDIF
   IF	BOOT = 3
;
;   8" FLOPPY BOOT DATA
;
STHD	EQU	2		;START LOGICAL DRIVE OF HARD DISK
NDHD	EQU	5		;LAST LOGICAL DRIVE OF HARD DISK
ST8FD	EQU	0		;START LOGICAL DRIVE OF 8" FLOPPY
ND8FD	EQU	1		;LAST LOGICAL DRIVE OF 8" FLOPPY
   ENDIF


;============================================================================
;
;        BDOS CONSTANTS ON ENTRY TO WRITE
;
;============================================================================
;
WRALL	EQU	0	;WRITE TO ALLOCATED
WRDIR	EQU	1	;WRITE TO DIRECTORY
WRUAL	EQU	2	;WRITE TO UNALLOCATED


;============================================================================
;
;	ASCII CHARS
;
;============================================================================
;
LF:	EQU	0AH
CR:	EQU	0DH
CTRLZ:	EQU	1AH


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	GENERATE THE TRANSLATION TABLE MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
GXLATE	MACRO	#SECTORS, #SKEW
	LIST	OFF
NXTSEC	DL	1		;;START WITH SECTOR 1
LOWEST	DL	1
;;
	REPT	#SECTORS
	LIST	ON
	DB	NXTSEC
	LIST	OFF
NXTSEC	DL	NXTSEC + #SKEW	;ADD SKEW FACTOR
;;
   IF	NXTSEC > #SECTORS	;CHECK FOR OVERFLOW
NXTSEC	DL	NXTSEC - #SECTORS
;;
   IF	NXTSEC <= LOWEST	;CHECK FOR REPEAT
NXTSEC	DL	LOWEST + 1
LOWEST	DL	NXTSEC
   ENDIF
   ENDIF
;;
	ENDM
	LIST	ON
	ENDM


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	INITIALIZE VERSION TEXT IN RAM MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
PVERS	MACRO	#VERS
DD	DL	#VERS
   IF	DD > 9999
	DB	(DD / 10000) + '0'
DD	DL	DD % 10000
   ENDIF
   IF	DD > 999
	DB	(DD / 1000) + '0'
DD	DL	DD % 1000
   ENDIF
	DB	(DD / 100) + '0'
	DB	'.'
	DB	((DD % 100) / 10) + '0'
	DB	(DD % 10) + '0'
	ENDM


	SUBTTL	BIOS CODE
	ORG	BIOS
;----------------------------------------------------------------------------
;
;   BIOS JUMP VECTOR TABLE
;
;----------------------------------------------------------------------------
;
	JP	INIT1		;COLD START ENTRY
	JP	WARM		;RELOAD CCP/BDOS
	JP	CNSCK		;GET CONSOLE STATUS
	JP	CI		;CONSOLE INPUT
	JP	COC		;CONSOLE OUTPUT
	JP	LO		;PRINTER OUTPUT
	JP	PUNCH
	JP	READER
	JP	HOME		;HOME SELECTED DRIVE
	JP	SELDSK		;SELECT DISK DRIVE
	JP	SETTRK		;SET TRACK #
	JP	SETSEC		;SET SECTOR #
	JP	SETDMA		;SET TRANSFER ADDR
	JP	DISKRD		;PERFORM DISK READ
	JP	DISKWR		;PERFORM DISK WRITE
	JP	LISTST		;RETURN LIST STATUS
	JP	SECTRN		;TRANSLATE SECTOR
	JP	BIOFUNC		;EXECUTE FUNCTION CALL


;############################################################################
;
;	THE FOLLOWING BOOT DATA MUST RESIDE AS DEFINED RIGHT BEFORE THE COLD
; INIT ROUTINE START AND MUST BE IN THE 1ST SECTOR. THESE 2 WORDS ARE
; REFERENCED BY THE BOOT LOADER CODE IN ORDER TO DETERMINE THE LOAD ADDRESS
; AND LENGTH OF THE BIOS.
;
;############################################################################
;
	DB	0		;Z80 CPU
	DB	0		;SPARE
BIOSSZ:	DW	BIOSND - BIOS	;BIOS MODULE SIZE IN BYTES
BIOSST:	DW	BIOS		;BIOS MODULE LOAD ADDR FOR SBD
;
;   CONTINUE ON WITH INIT
;
INIT1:	JR	INIT


;############################################################################
;
;	DIRECTORY SECTOR BUFFER STARTS HERE AFTER CRUNCHING COLD START
;  CODE. THIS BUFFER IS USED BY THE CP/M DIRECTORY CHECK ROUTINES THAT
;  CHECK FOR DISK CHANGE.
;
;############################################################################
;
DIRBF:	EQU	$		;BUFFER BEGINNING


;----------------------------------------------------------------------------
;
;    INIT  - COLD START ENTRY FROM BOOT MUST SET ALL BIOS PARAMS
;
;----------------------------------------------------------------------------
;
INIT:
;
;   SET TEMPORARY STACK
;
	DI
	LD	SP,DEFBFR	;USE PAGE 0 FOR STACK
	LD	(THIS_STK),SP
	EI
;
;   INIT DEFAULT DRIVE
;
	LD	A,(DK_BDRV)	;USE DRIVE # PASSED IN PAGE 0
	AND	A,3
	LD	(DEFDRV),A
;
;   SEND SYSTEM SIGN-ON
;
	LD	HL,MSGSO
	CALL	EDITOR
;
;   MODIFY COLD START VECTOR TO WARM START
;
	LD	HL,(BIOS+4)
	LD	(BIOS+1),HL
;
;   INIT OUR STUFF
;
	CALL	GETBNK
	LD	(BUF_DMAB),A
;
;   INITIALIZE CLOCK VECTORS IF CLOCK INSTALLED
;
	LD	A,MF_CSYN	;TEST FOR BOARD PRESENT
	CALL	XMROM
;
;   IF CLOCK PRESENT THEN TURN ON CLOCK DRIVE
;
	OR	A,A
	LD	A,38H		;COND. JR (ON)
	JR	Z,CLKON
;
;   ELSE TURN OFF CLOCK DRIVE
;
	LD	A,18H		;UNCOND. JR (OFF) (CAUSES JUMP TO ILLEGAL)
;
CLKON:	LD	(INHCLK),A
;
;   BOOT CCP & BDOS
;
	JR	WARM


;############################################################################
;
;	SIGN-ON MESSAGE
;
;############################################################################
;
MSGSO:	DB	CR,LF
	DB	CPMSZ / (KBYTE * 10) + '0'
	DB	(CPMSZ MOD (KBYTE * 10)) / KBYTE + '0'
	DB	'K CP/M-80  Vers 2.2',CR,LF
	DB	'M5b CBIOS    Vers '
	PVERS	VERSN
	DM	CR,LF


   IF	$ > (DIRBF + SECSZ)
	CONMSG	**** WARNING!  COLD INIT CODE BIGGER THAN DIR BUFFER ****
   ELSE
	DS	DIRBF+SECSZ-$	;FILL OUT DIRECTORY BUFFER TO 1 SECTOR SIZE
   ENDIF


;----------------------------------------------------------
;
;	WARM REBOOT ENTRY LOADS CCP,BDOS FROM DISK &
; SETS UP VARIABLES
;
;----------------------------------------------------------
;
WARM:
;
;   SET TEMPORARY STACK
;
	DI
	LD	SP,DEFBFR
	LD	(THIS_STK),SP
	EI
;
;   INIT OUR STUFF
;
	XOR	A,A
	LD	(BUF_ACT),A	;ASSUME NO DATA IN BUFFER
;
	LD	(UNA_CNT),A	;CLEAR UNALLOCATED SECTOR COUNT
;
	LD	(BUF_MOD),A	;CLEAN BUFFER
;
	LD	HL,BLKBUF	;INIT BUFFER PTR
	LD	(BUF_DMA),HL
;
;   LOG ON DRIVE TO INIT TABLES
;
	LD	A,(DK_BDRV)
	AND	A,3		;MODULO 4
	LD	C,A
	LD	E,0
	CALL	SELDSK
	LD	A,L		;IF ERROR THEN ABORT
	OR	A,H
	JR	Z,WEROR
;
;   READ BOOT DIRECTORY
;

	LD	BC,DEFBFR	;SET XFER ADDRESS (USE DEFAULT BUFFER)
	CALL	SETDMA
;
	LD	BC,BD_SEC	;SET DIRECTORY SECTOR
	CALL	SETSEC
;
	LD	BC,0		;SET TRACK TO 0
	CALL	SETTRK
;
	CALL	DISKRD
	JR	NZ,WEROR
;
;   CHECK FOR VALID BOOT DIRECTORY
;
	LD	A,(DEFBFR)
	CP	A,86H
	JR	C,WEROR
;
;   SET UP TO LOAD CCP/BDOS
;
	LD	HL,(DEFBFR + BD_SBDSS)	;PREFETCH BDOS TRK/SECTOR
	PUSH	HL
;
	LD	HL,(DEFBFR + BD_SCCPS) ;FETCH CCP TRK/SECTOR
	LD	C,L
	LD	B,0
	CALL	SETSEC
;
	LD	C,H
	CALL	SETTRK
;
	LD	BC,CCP
	CALL	SETDMA
;
;   READ CCP/BDOS
;
WREAD:	CALL	DISKRD
	JR	NZ,WEROR	;IF ERROR THEN EXIT
;
;   NEXT SECTOR
;
	LD	HL,CPM_SEC
	INC	(HL)
;
	LD	DE,128		;DMA += SECTOR SIZE
	LD	HL,(CPM_DMA)
	ADD	HL,DE
	LD	(CPM_DMA),HL
;
;   IF NOT INTO BDOS THEN READ NEXT SECTOR
;
	LD	DE,BDOS
	XOR	A,A
	SBC	HL,DE
	JR	C,WREAD
;
;   ELSE IF AT BEGINNING OF BDOS THEN SET UP NEW TRACK & SECTOR
;
	JR	Z,RDBDOS
;
;   ELSE IF NOT AT BIOS THEN READ NEXT SECTOR
;
	LD	DE,BIOS - BDOS
	SBC	HL,DE
	JP	C,WREAD
;
;   ELSE DONE READING SYSTEM
;
	JR	WZRPG
;
;
;   ELSE SET UP & READ BDOS
;
RDBDOS:	POP	HL		;RESTORE BDOS TRK/SECTOR FROM DIRECTORY
	LD	C,L
	LD	B,A		;A STILL CONTAINS 0
	CALL	SETSEC
;
	LD	C,H
	CALL	SETTRK
;
	JR	WREAD
;
;
;   WARM BOOT ERROR, OUTPUT MSG & GO TO DEBUGGER
;
WEROR:	LD	HL,MSGLE	;OUTPUT ERROR MESSAGE
	CALL	EDITOR
	CALL	MR_BRK
	HALT
;
;
;   BOOT OK, INIT PAGE 0
;
WZRPG:
;
;   INIT BIOS WARM START IN PAGE 0
;
	LD	A,0C3H
	LD	HL,BIOS + 3
	LD	(PAGE0),A
	LD	(PAGE0 + 1),HL
;
;   INIT BDOS CALL VECTOR IN PAGE 0
;
	LD	HL,BDOS + 6
	LD	(BDOSJV),A
	LD	(BDOSJV + 1),HL
;
;   INIT BIOS CALL VECTOR IN PAGE 0
;
	LD	HL,BIOFUNC
	LD	(BFUNRSV),A
	LD	(BFUNRSV + 1),HL
;
;   SET DEFAULT SECTOR BUFFER
;
	LD	BC,DEFBFR
	CALL	SETDMA
;
  IF	INTCPTS
;
;   PUT BDOS VECTOR INTO INTERCEPT CODE
;
	LD	HL,(BDOS + 7)
	LD	(BDOSV),HL
;
;   NOW PUT INTERCEPT VECTOR INTO BDOS CODE
;
	LD	HL,INTCPT
	LD	(BDOS + 7),HL
  ENDIF
;
;   PASS DEFAULT DISK TO CCP
;
	LD	A,(DEFDRV)
	LD	C,A
	JP	CCP


	SUBTTL	BIOS DISK FUNCTION ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	READ A DISK SECTOR
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
DISKRD:
;
;   SET UP DATA TABLE PTRS
;
	PUSH	IX
	LD	IX,(CUR_DDT)
;
	PUSH	IY
	LD	IY,(CUR_DPB)
;
;   IF NOT BLOCKED THEN USE CPM READ
;
	LD	A,(IY + DPB_PSH)	;0= 128-BYTE SECTORS
	OR	A,A
	JP	Z,DISKRDN
;
;   READS DON'T NEED ALLOCATION
;
	XOR	A,A
	LD	(UNA_CNT),A
;
;   READ_OPERATION_FLAG = TRUE (1)
;
	INC	A
	LD	(READOP),A
;
;   PRE-READ_OF_DATA_FLAG = TRUE
;
	LD	(RSFLAG),A
;
;   TREAT AS UNALLOCATED BLOCK
;
	LD	A,WRUAL
	LD	(WRTYPE),A
;
	JP	RWOPER		;TO PERFORM THE READ
;
;
;   NORMAL NON-BLOCKED READ
;
DISKRDN:
	CALL	CPM_RD
	JP	RW_RET


;****************************************************************************
;
;	WRITE DISK SECTOR FUNCTION
;	ENTRY- C= WRITE TYPE:
;			0: WRITE TO ALLOCATED BLOCK (UPDATE)
;			1: WRITE TO DIRECTORY BLOCK (ALLWAYS WRITE)
;			2: WRITE TO UNALLOCATED BLOCK (NO NEED TO PRE-READ)
;
;****************************************************************************
;
DISKWR:
;
;   REMOVE BOOT WRITE PROTECTION
;
	XOR	A,A
	LD	(WR_PROT),A
;
;   SET PTRS TO DISK DATA
;
	PUSH	IX
	LD	IX,(CUR_DDT)
;
	PUSH	IY
	LD	IY,(CUR_DPB)
;
;   IF NOT BLOCKED THEN USE CPM WRITE
;
	LD	A,(IY + DPB_PSH)	;0= 128-BYTE SECTORS
	OR	A,A
	JP	Z,DISKWRN
;
;   READ_OP_FLAG = FALSE
;
	XOR	A,A
	LD	(READOP),A
;
;   SAVE WRITE TYPE
;
	LD	A,C
	LD	(WRTYPE),A
;
;   IF 1ST WRITE TO UNALLOCATED (NEW, UNUSED) BLOCK THEN SET PARAMETERS
;
	CP	A,WRUAL
	JP	NZ,CHKUNA
;
;   COUNT = NUMBER_OF_SECTORS_IN_BLOCK
;
	LD	A,(IY + DPB_BLM)	;CUR_DPB.DPBBLM + 1 ::= (BLKSIZ/128)
	INC	A
	LD	(UNA_CNT),A
;
;   SET DISK TO SEEK
;
	LD	A,(CPM_DSK)
	LD	(UNA_DSK),A
;
;   SET TRACK TO SEEK
;
	LD	HL,(CPM_TRK)
	LD	(UNA_TRK),HL
;
;   SET SECTOR TO SEEK
;
	LD	HL,(CPM_SEC)
	LD	(UNA_SEC),HL
;
;   IF NO UNALLOCATED SECTORS REMAIN THEN PREREAD
;
CHKUNA:	LD	A,(UNA_CNT)
	OR	A,A
	JP	Z,ALLOC
;
;   ELSE MORE UNALLOCATED RECORDS REMAIN, COUNT--
;
	DEC	A
	LD	(UNA_CNT),A
;
;   IF REQUESTED SECTOR != UNALLOCATED SECTOR THEN PURGE
;
	LD	A,(CPM_DSK)	;SAME DISK?
	LD	HL,UNA_DSK
	CP	A,(HL)
	JR	NZ,ALLOC
;
	LD	HL,(UNA_TRK)	;SAME TRACK?
	LD	DE,(CPM_TRK)
	SBC	HL,DE
	JR	NZ,ALLOC
;
	LD	HL,(CPM_SEC)
	LD	DE,(UNA_SEC)
	SBC	HL,DE
	JR	NZ,ALLOC
;
;   MATCH, MOVE TO NEXT SECTOR FOR FUTURE REF
;
	EX	DE,HL		;UNASEC += 1
	INC	HL
	LD	(UNA_SEC),HL
;
;   IF PAST LAST SECTOR ON TRACK THEN USE 1ST SECTOR OF NEXT TRACK
;
	LD	E,(IY + DPB_SPT)
	LD	D,(IY + DPB_SPT +1)
	SBC	HL,DE
	JP	C,NOOVF
;
	LD	HL,0		;SECTOR = 1
	LD	(UNA_SEC),HL
;
	LD	HL,(UNA_TRK)	;TRACK++
	INC	HL
	LD	(UNA_TRK),HL
;
NOOVF:
;
;   MATCH FOUND, MARK AS UNNECESSARY READ
;
	XOR	A,A		;PREREAD FLAG = FALSE
	LD	(RSFLAG),A
	JP	RWOPER
;
;
;   NORMAL NON-BLOCKED WRITE
;
DISKWRN:
	CALL	CPM_WR
	JP	RW_RET
;
;
;   NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ
;
ALLOC:
	XOR	A,A		;COUNT = 0
	LD	(UNA_CNT),A
;
	INC	A		;PREREAD FLAG = TRUE
	LD	(RSFLAG),A
;
;
;
;   COMMON CODE FOR READ AND WRITE FOLLOWS
;
RWOPER:
;
;   ASSUME NO ERRORS
;
	XOR	A,A
	LD	(IOPB + PB_STATO),A
;
;   COMPUTE BUFFER SECTOR
;
	LD	HL,(CPM_SEC)
	DEC	HL			;CONVERT PHYSICAL SECTOR TO LOGICAL
;
	LD	A,(IY + DPB_PSH)	;USE PHYSICAL SHIFT FACTOR (CP/M 3.X)
	AND	A,3			;LIMIT TO 1024 BYTE SECTORS
	JP	Z,NOSECSHF		;IF ALREADY 0 THEN SECTOR SIZE IS 128
;
SECSHFLP:
	SRL	H			;ELSE SHIFT OVER TO PHYSICAL SECTOR
	RR	L
	DEC	A
	JP	NZ,SECSHFLP
;
NOSECSHF:
	INC	HL		;SET BACK TO PHYSICAL SECTOR
	LD	(BUF_PSEC),HL	;BUFFER PHYSICAL SECTOR TO ACCESS
;
;   IF BUFFER == EMPTY THEN READ THE PHYSICAL SECTOR
;
	LD	HL,BUF_ACT
	LD	A,(HL)
;
	LD	(HL),1		;BUFFER = ACTIVE IN ANY CASE
;
	OR	A,A
	JR	Z,FILHST
;
;   HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
;
	LD	A,(CPM_DSK)
	LD	HL,BUF_DSK	;SAME DISK?
	CP	A,(HL)
	JR	NZ,NOMATCH
;
	LD	HL,(BUF_TRK)	;SAME TRACK?
	LD	DE,(CPM_TRK)
	SBC	HL,DE
	JR	NZ,NOMATCH
;
	LD	DE,(BUF_PSEC)	;SAME SECTOR?
	LD	HL,(BUF_SEC)
	SBC	HL,DE
	JR	Z,MATCH		;SKIP IF MATCH
;
NOMATCH:
;
;   IF BUFFER == DIRTY THEN WRITE IT OUT BEFORE READING NEW ONE
;
	CALL	BUF_FLSH	;CLEAR HOST BUFF
;
	JR	NZ,RW_RET	;IF ERROR THEN ABORT
;
FILHST:
;
;   READ THE SECTOR BUFFER
;
	LD	A,(CPM_DSK)	;BUFFER SECTOR = PHYSICAL SECTOR
	LD	(BUF_DSK),A
;
	LD	HL,(CPM_TRK)
	LD	(BUF_TRK),HL
;
	LD	HL,(BUF_PSEC)
	LD	(BUF_SEC),HL
;
;   IF REQUIRED TO READ THEN READ
;
	LD	A,(RSFLAG)		;NEED TO READ?
	OR	A,A
	CALL	NZ,BUF_RD		;YES, IF 1
;
;   BUFFER = CLEAN
;
	XOR	A,A
	LD	(BUF_MOD),A
;
MATCH:
;
;   COPY DATA TO OR FROM BUFFER
;
	LD	HL,(CPM_SEC)	;CALCULATE INDEX INTO BUFFER
	DEC	HL		;CONVERT TO LOGICAL SECTOR (0..N-1)
	LD	A,L
;
	AND	A,(IY + DPB_PHM)   ;USE PHYSICAL RECORD MASK DATA (CP/M 3.X)
;
	RRA			;BITS <7..1> -> BITS <14..8>
	LD	H,A
;
	LD	A,0		;BIT 0 -> BIT 7
	RRA
	LD	L,A
;
;   HL HAS RELATIVE HOST BUFFER ADDRESS
;
	LD	DE,BLKBUF
	ADD	HL,DE		;HL = HOST ADDRESS
;
	LD	DE,(CPM_DMA)	;GET/PUT CP/M DATA
	LD	BC,128		;LENGTH OF MOVE
;
	LD	A,(READOP)	;WHICH WAY?
	OR	A,A
	JP	NZ,RWMOVE	;SKIP IF READ
;
;   WRITE OPERATION, MARK AND SWITCH DIRECTION
;
	LD	A,1		;BUFFER = DIRTY
	LD	(BUF_MOD),A
;
;   SAVE BUFFER DATA PTRS FOR LATER FLUSHES
;
	LD	(BUF_DDT),IX
	LD	(BUF_DPB),IY
;
	EX	DE,HL		;SOURCE/DEST SWAP
;
RWMOVE:
;
;   BC INITIALLY 128, DE IS SOURCE, HL IS DEST
;
	LDIR
;
;   DATA HAS BEEN MOVED TO/FROM HOST BUFFER, IF NOT DIRECTORY THEN DELAY WRITE
;
	LD	A,(WRTYPE)		;IF NOT DIRECTORY THEN DELAY WRITE
	CP	A,WRDIR
	LD	A,(IOPB + PB_STATO)	;RETURN ANY ERRORS ANYWAY
	JR	NZ,RW_RET
;
;   IF ERROR THEN ABORT
;
	OR	A,A
	JR	NZ,RW_RET
;
;   NO ERROR/DIRECTORY WRITE
;
	XOR	A,A			;BUFFER = CLEAN
	LD	(BUF_MOD),A
;
	CALL	BUF_WR			;WRITE TO DISK
;
	LD	A,(IOPB + PB_STATO)	;RETURN ANY ERRORS
;
;   DONE, RESTORE & RETURN
;
RW_RET:	OR	A,A	;SET RESULT STATUS FLAG
	POP	IY
	POP	IX
;
	RET


;****************************************************************************
;
;	CPM_WR PERFORMS THE PHYSICAL WRITE FROM CPM_DMA TO THE DISK.
;	ENTRY-	(CPM_DSK)= DISK # TO WRITE TO
;		(CPM_TRK)= TRACK # TO WRITE TO
;		(CPM_SEC)= SECTOR # TO WRITE TO
;		(CPM_DMA)= XFER ADDRESS
;		IX= DDT PTR
;		IY= DPB PTR
;	EXIT -	(IOPB.PB_STATO)= 0: OK, /0: ERROR
;
;****************************************************************************
;
CPM_WR:
;
	LD	HL,LL_WRIT
	JP	CPM_RW


;****************************************************************************
;
;	CPM_RD2 PERFORMS THE PHYSICAL READ FROM THE DISK INTO CPM_DMA,
; WITHOUT BLOCKING.
;	ENTRY-	(CPM_DSK)= DISK # TO READ FROM
;		(CPM_TRK)= TRACK # TO READ FROM
;		(CPM_SEC)= SECTOR # TO READ FROM
;		(CPM_DMA)= XFER ADDRESS
;	EXIT -	(IOPB.PB_STATO)= 0: OK, /0: ERROR
;
;****************************************************************************
;
CPM_RD2:
;
;   SET UP PTRS
;
	PUSH	IX
	PUSH	IY
	LD	IX,(CUR_DDT)
	LD	IY,(CUR_DPB)
;
;   EXECUTE READ SECTOR
;
	CALL	CPM_RD
;
;   RESTORE PTRS & RETURN
;
	POP	IY
	POP	IX
	RET


;****************************************************************************
;
;	CPM_RD PERFORMS THE PHYSICAL READ FROM THE DISK INTO CPM_DMA.
;	ENTRY-	(CPM_DSK)= DISK # TO READ FROM
;		(CPM_TRK)= TRACK # TO READ FROM
;		(CPM_SEC)= SECTOR # TO READ FROM
;		(CPM_DMA)= XFER ADDRESS
;		IX= DDT PTR
;		IY= DPB PTR
;	EXIT -	(IOPB.PB_STATO)= 0: OK, /0: ERROR
;
;****************************************************************************
;
CPM_RD:
;
	LD	HL,LL_READ
;
;   COMMON CODE
;
CPM_RW:	PUSH	HL
	LD	HL,CPM_TRK
;
;   FALL INTO COMMON XFER CODE
;


;****************************************************************************
;
;	SET UP IOPB FOR EXECUTION
;	ENTRY-	HL= PTR TO IOPB IMAGE TRACK DATA
;		IX= DDT PTR
;		IY= DPB PTR
;		(SP)= ADDRESS {LL_READ, LLWRIT} OF EXECUTOR
;
;****************************************************************************
;
RD_WR:	LD	DE,IOPB + PB_TRKO
	LD	BC,PB_BCNTO - PB_TRKO
	LDIR
;
;   EXECUTE LOW LEVEL READ OR WRITE (ON STACK)
;
	RET


;****************************************************************************
;
;	BUF_FLSH FLUSHES THE BUFFER DATA IF MODIFIED
;	ENTRY-	(BUF_DSK)= DISK # TO WRITE TO
;		(BUF_TRK)= TRACK # TO WRITE TO
;		(BUF_PSEC)= SECTOR # TO WRITE TO
;		(BUF_DDT)= DDT PTR
;		(BUF_DPB)= DPB PTR
;	EXIT -	(IOPB.PB_STATO)= 0: OK, /0: ERROR
;
;****************************************************************************
;
BUF_FLSH:
;
;   IF UNMODIFIED THEN RETURN
;
	LD	A,(BUF_MOD)
	OR	A,A
	RET	Z
;
;   ELSE SET PTRS TO BUFFER DATA
;
	PUSH	IX
	PUSH	IY
	LD	IX,(BUF_DDT)
	LD	IY,(BUF_DPB)
;
;   WRITE THE BUFFER DATA
;
	CALL	BUF_WR
;
;   RESTORE THE PTRS
;
	POP	IY
	POP	IX
;
;   IF ERROR THEN RETURN IT
;
	OR	A,A
	RET	NZ
;
;   ELSE CLEAN BUFFER
;
	LD	(BUF_MOD),A
	RET


;****************************************************************************
;
;	BUF_WR PERFORMS THE PHYSICAL WRITE FROM BLKBUF TO THE HOST DISK.
;	ENTRY-	(BUF_DSK)= DISK # TO WRITE TO
;		(BUF_TRK)= TRACK # TO WRITE TO
;		(BUF_SEC)= SECTOR # TO WRITE TO
;		IX= DDT PTR
;		IY= DPB PTR
;	EXIT -	(IOPB.PB_STATO)= 0: OK, /0: ERROR
;
;****************************************************************************
;
BUF_WR:
;
	LD	HL,LL_WRIT
	JP	BUF_RW


;****************************************************************************
;
;	RDBUF PERFORMS THE PHYSICAL READ FROM THE HOST DISK INTO BLKBUF.
;	ENTRY-	(BUF_DSK)= DISK # TO READ FROM
;		(BUF_TRK)= TRACK # TO READ FROM
;		(BUF_SEC)= SECTOR # TO READ FROM
;		IX= DDT PTR
;		IY= DPB PTR
;	EXIT -	(IOPB.PB_STATO)= 0: OK, /0: ERROR
;
;****************************************************************************
;
BUF_RD:
;
	LD	HL,LL_READ
;
;   COMMON CODE
;
BUF_RW:	PUSH	HL
	LD	HL,BUF_TRK
	JP	RD_WR


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	SELECT DRIVE FUNCTION
;	LOG-ON - SET DISK PARAMETER BLOCK
;	ENTRY-	C= DRIVE #
;		E= 0 IF NEW SELECT
;	EXIT -	HL= PTR TO DPT OR 0 FOR ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
SELDSK:
;
;   STORE DRIVE # FOR FUTURE USE
;
	LD	A,C
	LD	(CPM_DSK),A
;
;   SAVE LOGON REQUEST FLAG
;
	LD	A,E
	LD	(LOGRQ),A
;
;   COMPUTE DISK DRIVER TABLE PTR
;
	CALL	RETDVRT		;DRIVE IS STILL IN C REGISTER
;
;   IF DRIVE ERROR THEN RETURN (HL= 0)
;
	RET	NZ
;
;   ELSE SAVE PTR
;
	LD	(CUR_DDT),HL
;
;   FETCH FLAGS
;
	INC	HL		;EXE +1
	INC	HL		;FLGS
	LD	C,(HL)
;
;   FETCH DISK PARAMETER BLOCK ADDRESS
;
	INC	HL		;DRV
	INC	HL		;DPB_PTR
	LD	E,(HL)
	INC	HL
	LD	D,(HL)
	LD	(CUR_DPB),DE
;
;   FETCH DISK PARAMETER HEADER ADDRESS
;
	INC	HL		;DPH PTR
	LD	E,(HL)
	INC	HL
	LD	D,(HL)
	LD	(CUR_DPH),DE
	EX	DE,HL		;PUT DPH PTR IN HL FOR RETURN
;
;   IF NOT FIRST SELECT OR LOGON INHIBITED THEN RETURN TABLE PTR
;
	LD	A,(LOGRQ)	;0: LOGON, 1:INHIBIT
	OR	A,C		;0: NORMAL, 1: INHIBIT
	CPL
	AND	A,1
	RET	Z
;
;   ELSE LOG ON DRIVE
;
	PUSH	IX		;SAVE REGS
	PUSH	IY
;
	LD	IX,(CUR_DDT)	;SET REGS
	LD	IY,(CUR_DPB)
;
;   ATTEMPT TO READ ID SECTOR
;
	CALL	BUF_FLSH	;FLUSH BUFFER 1ST
	JR	NZ,LOGERR
;
	CALL	DISKLOG
	JR	NZ,LOGERR
;
;   IF NO ID SECTOR THEN USE DEFAULT DPB
;	(NOTE: CONTROLLER HAS SET IT'S DISK DEFAULTS IN DEFBFR IN ALL CASES)
;
	LD	A,(IOPB + PB_ST2O)
	CP	A,-1		;-1:NONE, 0:JADE, 1:DESCRIPTOR, 2: EXTENDED,
;				  3: PARTITIONED, ID
	JR	Z,LGDEF
;
;   ELSE IF OLD FORMATS THEN PAD DPB DATA
;
	CP	A,3
	JR	NC,IDOK
;
	LD	HL,BLKBUF + ID_PSHO	;FILL DATA WITH 0S
	LD	B,ID_FLGO - ID_PSHO
;
PADIDL:	LD	(HL),0
	INC	HL
	DJNZ	PADIDL
;
;   ELSE XFER ID SECTOR DATA TO TABLES
;
IDOK:	CALL	TRNONE		;ASSUME NO TRANSLATION
;
;   IF HARD DISK OR DOUBLE DENSITY THEN NO TRANSLATION
;
	LD	A,(BLKBUF + ID_FLGO)
	AND	A,[1 SHL DF_DTDB] OR [1 SHL DF_HARDB]
;
;   ELSE SET TRANSLATION
;
	CALL	Z,TR8
;
;   XFER DISK DATA TO DPB
;
	LD	DE,(CUR_DPB)		;GET ADDR OF DPB
	LD	HL,BLKBUF + ID_SPTO
	LD	BC,DPB_SZ
	LDIR
;
;   XFER DISK PHYSICAL DATA TO TABLE
;
	LD	A,(BLKBUF + ID_HEADS)
;
SEL1:	LD	(IX + DDT_HDS),A
;
;   RETURN DRIVE TABLE PTR
;
	LD	HL,(CUR_DPH)
	XOR	A,A		;RETURN NO-ERROR
	JR	LGDONE
;
;
;   IF NOT HARD DISK THEN GO DO FLOPPY TEST
;
LGDEF:	BIT	4,(IX + DDT_FLG)
	JR	Z,LGCKFD
;
;   ELSE USE HARD DISK DEFAULTS
;
	CALL	TRNONE		;  NO XLATE
	LD	HL,HDPBK
;
;   XFER DATA TO TABLES
;
SEL2:	LD	DE,(CUR_DPB)	;  USE DEFAULT TABLE
	LD	BC,DPB_SZ
	LDIR
;
	LD	A,(HL)		;HEADS VALUE
	JR	SEL1
;
;
;   USE 8" FLOPPY DEFAULTS
;
LGCKFD:	CALL	TR8
	LD	HL,SD8PBK
	JR	SEL2
;
;   ERROR EXIT
;
LOGERR:	LD	HL,0
;
;   DONE
;
LGDONE:	POP	IY	;RESTORE REGS
	POP	IX
	RET


;****************************************************************************
;
;   HOME DRIVE - TREAT AS SEEK TRK 0
;	EXIT -	BC= 0
;
;****************************************************************************
;
HOME:
;
;   IF PENDING WRITE (BUFFER DIRTY) THEN IGNORE
;
	LD	A,(BUF_MOD)
	OR	A,A
	JR	NZ,HOME2
;
;   ELSE PURGE BUFFER
;
	LD	(BUF_ACT),A
;
HOME2:
;
;   JUST SET TRACK TO 0
;
	LD	BC,0
;
;   FALL INTO SET TRACK
;


;****************************************************************************
;
;	SET TRACK #
;	ENTRY-	BC= TRACK #
;
;****************************************************************************
;
SETTRK:
	LD	(CPM_TRK),BC
	RET


;****************************************************************************
;
;	SET SECTOR
;	ENTRY-	BC= SECTOR #
;
;****************************************************************************
;
SETSEC:
	LD	(CPM_SEC),BC
	RET


;****************************************************************************
;
;	SET TRANSFER ADDR
;	ENTRY-	BC= ADDRESS
;	EXIT -	A= ?
;
;****************************************************************************
;
SETDMA:	LD	(CPM_DMA),BC
;
	LD	A,(BUF_DMAB)	;FETCH BANK ADDRESS SET BY COLD START
	LD	(CPM_DMAB),A
;
;   DONE
;
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	SECTOR TRANSLATION FUNCTION
;	ENTRY-	DE= 0: NO XLATE, ELSE PTR TO XLATE TABLE
;		BC= SECTOR # TO XLATE
;	EXIT -	HL= XLATED SECTOR OR BC + 1
;		BC= UNCHANGED
;		A, DE= ?
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
SECTRN:
;
;   IF NO TRANSLATION THEN RETURN SECTOR++
;
	LD	A,D	;IF TABLE ADDR = 0 THEN NO TRANSLATION
	OR	A,E
	JP	Z,NOTRAN
;
;   ELSE CALCULATE NEW SECTOR FROM TABLE
;
	EX	DE,HL
	ADD	HL,BC
	LD	L,(HL)
;
	LD	H,0
	RET
;
;
;   CONVERT FROM CP/M'S LOGICAL SECTOR {0..N-1} TO PHYSICAL SECTOR {1..N}
;   
NOTRAN:	LD	HL,1
	ADD	HL,BC
	RET


	SUBTTL	DISK SUPPORT ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	LOGON DISK FUNCTION
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
DISKLOG:
;
;   SET UP READ IOPB
;
	LD	A,(BUF_DMAB)
	LD	(LOGIOPB + PB_DMAXO),A
;
	LD	HL,LOGIOPB
	LD	DE,IOPB
	LD	BC,PB_STATO
	LDIR
;
;   EXECUTE WITHOUT COMPENSATION
;
	JR	LL_DO


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	LOW LEVEL READ
;	ENTRY-	IX= DDT PTR
;		IY= DPB PTR
;	EXIT -	IOPB.PB_STATO, A= STATUS
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
LL_READ:
;
;   ENABLE UPLOAD
;
	XOR	A,A
	LD	(IOPB + PB_FLGO),A
;
;   DISABLE DOWNLOAD
;
	LD	HL,0
	LD	(IOPB + PB_BCNTO),HL
;
;   PASS READ SECTOR COMMAND
;
	LD	A,PB_READC
	JP	LL_RW


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	LOW LEVEL WRITE
;	ENTRY-	IX= DDT PTR
;		IY= DPB PTR
;	EXIT -	IOPB.PB_STATO, A= STATUS
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
LL_WRIT:
;
;   IF STILL PROTECTED THEN ERROR
;
	LD	A,(WR_PROT)
	OR	A,A
	JR	NZ,DO_ERR
;
;   INHIBIT UPLOAD
;
	LD	A,1 SHL PB_INHX
	LD	(IOPB + PB_FLGO),A
;
;   CALCULATE DOWNLOAD BYTE COUNT
;
	LD	A,(IY + DPB_PSH) ;USE SHIFT FACTOR {0:128, 1:256, 2:512, 3:1024}
	LD	HL,128		;START WITH 128 BYTES
;
	AND	A,3		;LIMIT TO 1024-BYTE SECTORS
;
	JR	Z,LL_WR2	;IF SHIFT_FACTOR == 0 THEN DONE
;
LL_WR3:	ADD	HL,HL		;DOUBLE COUNT
	DEC	A
	JP	NZ,LL_WR3
;
LL_WR2:	LD	(IOPB + PB_BCNTO),HL
;
;   PASS WRITE COMMAND
;
	LD	A,PB_WRITC
;
;   FALL INTO COMMON CODE
;


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	COMMON IOPB EXECUTER
;	ENTRY-	A= COMMAND
;		IX= DRIVE TABLE PTR
;		IY= DPB PTR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
LL_RW:	LD	(IOPB + PB_CMDO),A
;
;   OFFSET SECTOR
;
	LD	HL,(IOPB + PB_SECO)
	LD	A,L
	ADD	A,(IX + DDT_SOF)
	LD	L,A
	LD	A,H
	ADC	A,(IX + DDT_SOF + 1)
	LD	H,A
	LD	(IOPB + PB_SECO),HL
;
;   SET PHYSICAL DRIVE
;
LL_DO:	LD	A,(IX + DDT_DRV)
	LD	(IOPB + PB_DRVO),A
;
;   FETCH DRIVER VECTOR & EXECUTE DISK DRIVER
;
LL_OPLP:
	LD	HL,LL_OPRET		;PUT RETURN ADDRESS ON STACK
	PUSH	HL
;
	LD	L,(IX + DDT_EXE)	;FETCH DRIVER ADDRESS FROM TABLE
	LD	H,(IX + DDT_EXE + 1)
	JP	(HL)
;
;   DRIVER RETURNS HERE
;
LL_OPRET:
;
;   IF NO ERRORS THEN RETURN ZF
;
	RET	Z	;IF NO_ERROR THEN RETURN
;
;   PRINT ERROR
;
IOPBDMP:
	LD	A,(BUF_DMAB)	;SET BANK
	LD	E,A
;
	LD	HL,IOPB
	LD	A,MF_DIOB	;USE DISPLAY IOPB DATA FUNCTION
	CALL	XMROM
;
;   QUERY USER FOR OPTION
;
	LD	HL,DSKEB
	CALL	EDITOR
;
;   GET USER RESPONSE
;
	CALL	CI		;GET USER RESPONSE
;
	PUSH	AF		;SAVE CHAR
	LD	C,A		;ECHO CHAR
	CALL	COC
	CALL	CRLF		;NEW LINE
	POP	AF
;
	AND	A,5FH		;INSURE UPPER CASE
;
;   IF RETRY THEN TRY AGAIN
;
	CP	A,'R'		;IF RETRY THEN RETURN TO CALLER
	JR	Z,LL_OPLP
;
;   ELSE IF ABORT THEN DO WARM BOOT
;
	CP	A,'A'		;IF ABORT THEN RE-BOOT
	JP	Z,0
;
;   ELSE IF DEBUGGER THEN EXECUTE IT
;
	CP	A,'M'
	JP	Z,MR_BRK
;
;   ELSE IF IGNORE THEN RETURN NO ERROR
;
	SUB	A,'I'		;IF IGNORE THEN RETURN NO ERROR
	RET	Z
;
;   ELSE RETURN ERROR TO BDOS
;
	LD	A,-1		;RETURN -1 TO BDOS
	OR	A,A
	RET
;
;
;   DISPLAY WRITE PROTECT ERROR MESSAGE
;
DO_ERR:	LD	HL,WP_ERM
	CALL	EDITOR
	JR	IOPBDMP


;****************************************************************************
;
;	SET 3740 SECTOR TRANSLATION PROCEDURE
;	ENTRY-	(CUR_DPH)= MUST BE PTR TO DPH
;	EXIT -	DE, HL= ?
;
;****************************************************************************
;
TR8:
	LD	DE,SDTRAN
;
SETTR:	LD	HL,(CUR_DPH)
	LD	(HL),E
	INC	HL
	LD	(HL),D
	RET


;****************************************************************************
;
;	SET NO SECTOR TRANSLATION PROCEDURE
;	EXIT -	HL, DE= ?
;
;****************************************************************************
;
TRNONE:	LD	DE,0
	JR	SETTR


	SUBTTL	HARD DISK ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	EXECUTE THE IOPB PRIMITIVE
;	EXIT - A= 0: OK, /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
XPRIM:
;
;   EXECUTE THE PRIMITIVE IN ROM
;
	LD	A,(BUF_DMAB)	;PRESET IOPB BANK
	LD	E,A
;
	LD	HL,IOPB
	CALL	MR_XIOB		;EXECUTE THE FUNCTION
;
	OR	A,A		;FUNCTION ERR?
	RET	NZ
;
;   RETURN THE COMMAND RESULTS STATUS
;
	LD	A,(IOPB + PB_STATO)
	OR	A,A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	HARD DISK DRIVER FUNCTION
;	ENTRY-	IX= DRIVER TABLE PTR
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
HDEXEC:	EQU	XPRIM


	SUBTTL	JADE FLOPPY DRIVER ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	JADE 8" FLOPPY DISK DRIVER FUNCTION
;	ENTRY-	IY= DRIVER TABLE PTR
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
FD8EXEC:
;
;   IF HEADS == 1 THEN EXECUTE IOPB
;
	LD	A,(IX + DDT_HDS)
	DEC	A
	JP	Z,XPRIM
;
;   ELSE SELECT SIDE FROM TRACK BIT 0
;
	LD	HL,(IOPB + PB_TRKO)
	PUSH	HL			;SAVE ORIGINAL DATA
;
	LD	A,(IOPB + PB_SECO + 1)
	ADD	A,A			;BIT 15 -> BIT_BUCKET
;
	SRL	H
	RR	L
	RRA				;TRK BIT 0 -> SECTOR BIT 15
	LD	(IOPB + PB_SECO + 1),A
;
	LD	(IOPB + PB_TRKO),HL	;TRACK = RESIDUAL
;
;   EXECUTE THE IOPB
;
	CALL	XPRIM
;
;   RESTORE THE MODIFIED IOPB SO RETRY WILL WORK
;
	POP	HL			;TRACK
	LD	(IOPB + PB_TRKO),HL
;
	LD	HL,IOPB + PB_SECO +1	;CLEAR BIT 15
	RES	7,(HL)
;
;   DONE
;
	RET


	SUBTTL	BIOS FUNCTION CALLS
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	FUNCTION DISPATCHER
;	ENTRY-	C= FUNCTION #
;	EXIT -	A= -1: ERROR, 0: OK
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
BIOFUNC:
;
;   IF FUNCTION # NOT IN TABLE THEN RETURN -1
;
	LD	A,C
	CP	A,MAXFUNCS
	LD	A,-1
	RET	NC
;
;   ELSE COMPUTE TABLE ENTRY
;
	PUSH	HL		;SAVE POSSIBLE DATA
;
	LD	HL,BFUNTBL
	LD	A,C
	ADD	A,A
	ADD	A,L
	LD	L,A
	LD	A,0
	ADC	A,H
	LD	H,A
;
;   EXECUTE TABLE ADDRESS
;
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A
;
	EX	(SP),HL		;PUT CALLER'S DATA IN HL, FUNCTION ADDR ON
	RET			; STACK, EXECUTE FUNCTION ADDRESS ON STACK


;############################################################################
;
;	BIOS FUNCTION TABLE
;
;############################################################################
;
BFUNTBL:
	DW	RETVERS		;0:RETURN VERSION #
	DW	RETDVRTF	;1:RETURN DISK PHYSICAL CONFIGURATION TABLE PTR
MAXFUNCS EQU	($ - BFUNTBL) / 2


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN BIOS VERSION # FUNCTION #0
;	EXIT -	HL= VERSION # IN BINARY {0.00,..655.35}
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
RETVERS:
	LD	HL,VERSN
	XOR	A,A		;RETURN NO ERROR
	RET
	

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN DRIVER TABLE PTR FUNCTION #1
;	ENTRY-	E= DRIVE #
;	EXIT -	E:HL= DRIVER TABLE BASE PTR
;		NZ= ILLEGAL DRIVE REQUESTED (HL=0)
;		A, B, C= ?
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
RETDVRTF:
;
;   ADJUST REGISTER
;
	LD	C,E
;
;   FALL INTO LOCAL ENTRY
;


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN DRIVER TABLE PTR FUNCTION
;	ENTRY-	C= DRIVE #
;	EXIT -	E:HL= DRIVER TABLE BASE PTR
;		NZ= ILLEGAL DRIVE (HL= 0)
;		A, B, C= ?
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
RETDVRT:
;
;   ASSUME DRIVE 0
;
	LD	HL,DDT_0	;START AT 1ST TABLE
;
;   IF DRIVE == 0 THEN ALREADY THERE
;
	LD	A,C
	OR	A,A
	RET	Z
;
;   ELSE IF ILLEGAL DRIVE THEN RETURN ERROR
;
	CP	A,NDRVS
	JR	C,RETDV2
;
	LD	HL,0
	OR	A,A		;SET NZ
	RET
;
;
;   ELSE COMPUTE TABLE PTR
;
RETDV2:	LD	B,C
	LD	DE,DDT_SIZ
;
RETDVL:	ADD	HL,DE
	DJNZ	RETDVL
;
	LD	A,(BUF_DMAB)
	LD	E,A
;
;   RETURN NO ERROR
;
	XOR	A,A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	GET BANK NUMBER FUNCTION
;	EXIT -	A= BANK #
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
GETBNK:
	LD	A,MF_GBNK
	JP	MR_FUN
	

	SUBTTL	NON-DISK PROCEDURES
;***************************************************************************
;
;	NEWLINE PROCEDURE
;
;***************************************************************************
;
CRLF:	LD	C,CR
	CALL	COC
	LD	C,LF
	JP	COC


  IF	INTCPTS
	SUBTTL	ADDITIONAL FUNCTIONS TO SUPPORT CDOS PROGRAMS
;***************************************************************************
;
;	SYSTEM CALL INTERCEPT ROUTINE CHECKS FOR ILLEGAL BDOS CALLS &
;  PRINTS MESSAGE IF ILLEGAL. ALSO IMPLEMENTS CDOS CLOCK/CALENDAR
;  SYSTEM CALLS FOR ASMB.
;
;***************************************************************************
INTCPT:	LD	A,C		;CHECK CALL VALIDITY
	CP	A,41		;IF <= 40 THEN OK
;
BDOSV	EQU	$ + 1
	JP	C,BDOS + 11H	;THIS ADDR MODIFIED BY WARM BOOT RTN
;
;  THE FOLLOWING CONDITIONAL JUMP IS MODIFIED TO AN UNCONDITIONAL JUMP BY
;  THE WARM BOOT ROUTINE IF THE CLOCK/CALENDAR BOARD IS NOT PRESENT
;  IF NOT MODIFIED, THEN IT IS ALLWAYS FALSE (NOP).
;
INHCLK:	JR	C,ILLEGC
;
;  NOW CHECK FOR EXTENDED CALLS
;
	CP	A,8DH		;IF RETURN VERSION THEN RETURN IT
	JR	Z,RETCVER
;
	CP	A,90H		;IF NOT CLOCK THEN ERR
	JR	C,ILLEGC
;
	JR	Z,CLKCAL	;IF CALENDAR THEN GET IT
;
	CP	A,92H
	JR	Z,CLKTIM	;IF TIME THEN GET IT
;
;  ILLEGAL SYSTEM CALL
;
ILLEGC:	PUSH	BC		;SAVE FUNCTION #
;
;   OUTPUT WARNING MESSAGE
;
	LD	HL,ISCMSG	;OUTPUT WARNING
	CALL	EDITOR
;
;   OUTPUT FUNCTION #
;
	POP	BC
	LD	A,MF_PHXB
	CALL	XMROM
;
;   OUTPUT NEW LINE
;
	CALL	CRLF
;
;   RETURN NULLS
;
	XOR	A,A		;BC = HL = A = 0
	LD	L,A
	LD	H,A
	LD	C,A
	LD	B,A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	CDOS RETURN VERSION FUNCTION
;  MAKES CLOCK/CALENDAR WORK.
;	EXIT -	B= 1
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
RETCVER:
	LD	B,1
	RET

	SUBTTL	CLOCK ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN CALENDAR FUNCTION 90H
;	EXIT -	A= DAY
;		B= MONTH
;		C= YEAR
;		L= DAY OF WEEK
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
CLKCAL:
	LD	A,MF_GCAL
	JP	XMROM


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN TIME FUNCTION 92H
;	EXIT -	A= SECONDS
;		B= MINUTES
;		C= HOURS
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
CLKTIM:
	LD	A,MF_GTIM
	JP	XMROM

   ENDIF

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	MONITOR ROM EXECUTER
;	ENTRY-	A= FUNCTION #
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
XMROM:	EQU	MR_FUN


	SUBTTL	CHAR I/O ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	CONSOLE INPUT
;	EXIT -	A= CHAR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
CI:
	LD	A,MF_CI
	JP	XMROM


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN CONSOLE STATUS
;	EXIT -	A= 0: NOT READY
;		   FFH: CHAR READY
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
CNSCK:
	LD	A,MF_CIS
	JP	XMROM


;****************************************************************************
;
;	CONSOLE OUTPUT
;	ENTRY-	C= CHAR TO OUTPUT
;
;****************************************************************************
;
COC:
	LD	A,MF_CO
	JP	XMROM


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	READER DRIVER - DUMMY
;	EXIT -	A= CTRL-Z
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
READER:	LD	A,CTRLZ		;FAKE EOF
;
;   FALL INTO PUNCH RETURN
;


;****************************************************************************
;
;	PUNCH DRIVER
;	ENTRY-	C= CHAR TO OUTPUT
;
;****************************************************************************
;
PUNCH:	RET


;****************************************************************************
;
;	PRINTER DRIVER
;	ENTRY-	C= CHAR TO OUTPUT
;
;****************************************************************************
;
LO:
	LD	A,MF_LO
	JP	XMROM


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN LIST DEVICE STATUS
;	EXIT -	A= 0: BUSY, FFH:READY
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
LISTST:
	LD	A,MF_LOS
	JP	XMROM


;****************************************************************************
;
;	MESSAGE EDITOR
;	ENTRY-	HL= TEXT PTR (BIT 7= 1: TERMINATOR)
;	EXIT -	REGS= ?
;
;****************************************************************************
;
EDITOR:
	CALL	GETBNK
	LD	E,A
	LD	A,MF_PUTS
	JP	XMROM


	SUBTTL	INITIALIZED DATA
;############################################################################
;
;	3740 SECTOR TRANSLATION TABLE
;	**** CP/M SINGLE DENSITY ****
;
;############################################################################
;
SDTRAN:	GXLATE	26,6


;############################################################################
;
;	COMMON I/O PARAMETER BLOCK
;
;############################################################################
;
IOPB:	REPT	PB_SIZE
	LIST	OFF
	DB	0
	LIST	ON
	ENDM


;############################################################################
;
;	DISK DRIVER TABLES (DDT)
;
;############################################################################
;
	STRUCT	0
DDT_EXE	DS	2	;START ADDRESS OF DISK DRIVER
DDT_FLG	DS	1	;FLAGS 	BIT	DEF.
;				0	1: INHIBIT LOGON
;				1..3	PARTITION # {0,..7}
;				4	1: HARD DISK DRIVE
;				
DDT_DRV	DS	1	;PHYSICAL DRIVE #
DDT_DPB	DS	2	;DPB ADDRESS FOR THIS DRIVE
DDT_DPH	DS	2	;DPH ADDRESS FOR THIS DRIVE
;
;   THE FOLLOWING MAY BE BROUGHT OFF DISK DESCRIPTOR OR FROM DEFAULT TABLES
;
DDT_HDS	DS	1	;HEADS
DDT_SOF DS	2	;SECTOR OFFSET
;
;   DEFINE THE STRUCTURE SIZE
;
DDT_SIZ	DS	0
	ENDM


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	MACRO TO DEFINE THE DRIVER TABLE RECORD
;	ENTRY-	#DADD= DRIVER ADDRESS
;		#PD= PHYSICAL DRIVE #
;		#FLG= DRIVE FLAGS
;		#DPB= DPB ADDRESS
;		#DPH= DPH ADDRESS
;		#HDS= HEADS
;		#SOF= SECTOR OFFSET
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
ALLDRV	MACRO	#DADD,#PD,#FLG,#DPB,#DPH,#HDS,#SOF
	DW	#DADD		;DRIVER EXECUTION ADDR
	DB	#FLG		;FLAGS
	DB	#PD		;MONITOR PHYSICAL DRIVE #
	DW	#DPB		;DISK PARAMETER BLOCK PTR
	DW	#DPH		;DISK PARAMETER HEADER PTR
	DB	#HDS		;HEADS
	DW	#SOF		;SECTOR OFFSET
;
	ENDM

   IF	BOOT = 10H
;   A
DDT_0:	ALLDRV	HDEXEC,6,10H,D0DPB,D0DPH,4,0
;   B
DDT_1:	ALLDRV	HDEXEC,6,12H,D1DPB,D1DPH,4,8000H
;   C
DDT_2:	ALLDRV	HDEXEC,7,10H,D2DPB,D2DPH,4,0
;   D
DDT_3:	ALLDRV	HDEXEC,7,12H,D3DPB,D3DPH,4,8000H
;   E
DDT_4:	ALLDRV	FD8EXEC,0,0,D4DPB,D4DPH,1,0
;   F
DDT_5:	ALLDRV	FD8EXEC,1,0,D5DPB,D5DPH,1,0
   ENDIF
   IF	BOOT = 3
;   A
DDT_0:	ALLDRV	FD8EXEC,0,0,D0DPB,D0DPH,1,0
;   B
DDT_1:	ALLDRV	FD8EXEC,1,0,D1DPB,D1DPH,1,0
;   C
DDT_2:	ALLDRV	HDEXEC,4,10H,D2DPB,D2DPH,4,0
;   D
DDT_3:	ALLDRV	HDEXEC,4,12H,D3DPB,D3DPH,4,8000H
;   E
DDT_4:	ALLDRV	HDEXEC,7,10H,D4DPB,D4DPH,4,0
;   F
DDT_5:	ALLDRV	HDEXEC,7,12H,D5DPB,D5DPH,4,8000H
   ENDIF


;############################################################################
;
;			MESSAGES
;
;############################################################################
;
MSGLE:	DM	CR,LF,'LOAD ERROR'
;
DSKEB:	DM	CR,LF,'Abort, Ignore, Retry, (BDOS) - '
;
WP_ERM:	DM	CR,LF,'W-PROT Error!'
;
   IF	INTCPTS
ISCMSG:	DM	CR,LF,'ILL SYS CALL, #= '
   ENDIF


;############################################################################
;
;	DEFAULT 8" FLOPPY DISK PARAMETER BLOCK
;	IBM 3740 SINGLE DENSITY FORMAT
;
;############################################################################
;
SD8PBK:	DW	26		;SECTORS PER TRACK
	DB	3		;BLOCK SHIFT FACTOR
	DB	7		;BLOCK MASK
	DB	0		;NULL MASK
	DW	242		;DISK SIZE -1
	DW	63		;DIRECTORY MAX
	DB	11000000B	;ALLOC 0
	DB	0		;ALLOC 1
	DW	16		;CHECK SIZE
	DW	2		;TRACK OFFSET
	DB	0		;PHYSICAL RECORD SHIFT FACTOR
	DB	0		;PHYSICAL RECORD MASK
	DW	0		;LOGICAL DRIVE SECTOR OFFSET
;
;   DEFAULT DISK PHYSICAL PARAMETERS
;
	DB	1		;HEADS


;############################################################################
;
;	DEFAULT 8" HARD DISK PARAMETER BLOCK
;
;############################################################################
;
HDPBK:	DW	128		;SECTORS PER TRACK (LOGICAL)	(SPT)
	DB	5		;BLOCK SHIFT FACTOR		(BSH)
	DB	31		;BLOCK MASK			(BLM)
	DB	1		;NULL MASK			(EXM)
	DW	1015		;DISK SIZE (CLUSTERS -1)	(DSM)
	DW	1152 / 2	;DIRECTORY MAX			(DRM)
	DB	0FFH		;ALLOCATION 0			(AL0)
	DB	10000000B	;ALLOCATION 1			(AL1)
	DW	0		;CHECK SIZE			(CKS)
	DW	2		;TRACK OFFSET			(OFF)
	DB	1		;PHYSICAL RECORD SHIFT FACTOR	(PSH)
	DB	1		;PHYSICAL RECORD MASK		(PRM)
	DW	0		;LOGICAL DRIVE SECTOR OFFSET	(SOF)
;
;
;
	DB	4		;HEADS


;############################################################################
;
;	DRIVE PARAMETER HEADER AREA
;	1 PER DRIVE
;
;############################################################################
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	GENERATE A DISK PARAMETER TABLE MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
ALLDPH:	MACRO	#D
	LIST	ON
D#D(DD)DPH:			;DRIVE PARAMETER HEADER FOR DRIVE #D(DD)
	DW	0		;;SECTOR TRAN TBL (OR 0 IF NO XLATE)
	DW	0		;;SCRATCH AREA
	DW	0		;;"
	DW	0		;;"
	DW	DIRBF		;;DIRECTORY BUFFER PTR
	DW	D#D(DD)DPB	;;DRIVE PARAMETER BLK PTR
   IF	((DD - 1) <= NDHD) AND ((DD - 1) >= STHD)
	DW	0		;;NO CHECKS ON HARD DISK
   ELSE
	DW	D#D(DD)CHK	;;DRIVE DISK CHECKSUMS ARRAY PTR
   ENDIF
	DW	D#D(DD)ALL	;;DRIVE CLUSTER ALLOCATION BIT MAP PTR
	LIST	OFF
	ENDM
;
;   DEFINE THE DATA
;
DD	DL	1
	REPT	NDRVS
	LIST	OFF
	ALLDPH	0123456789ABCDEF
DD	DL	DD + 1
	LIST	ON
	ENDM


;############################################################################
;
;	LOGON IOPB OVERLAY
;
;############################################################################
;
LOGIOPB:
	DB	PB_LOGC	;COMMAND
	DB	0	;DRIVE
	DW	0	;TRACK
	DW	ID_SECT	;SECTOR
	DB	0	;FLAGS
	DW	BLKBUF	;DMA
	DB	0	;BANK
	DW	0	;COUNT

;
WR_PROT DB	-1	;/0: WRITE PROTECTION ENABLED

;
;   LAST OF INITIALIZED CODE READ FROM DISK
;
BIOSND	EQU	$

	SUBTTL	UNINITIALIZED DATA AREA
;############################################################################
;
;   THE FOLLOWING DATA MUST RESIDE IN THIS ORDER TO MATCH THE IOPB DATA
;
;############################################################################
;
;   CP/M IOPB OVERLAY
;
CPM_DSK DS	1	;LOGICAL DRIVE
CPM_TRK DS	2	;LOGICAL TRACK NUMBER
CPM_SEC DS	2	;LOGICAL SECTOR NUMBER
	DS	1	;FLAGS
CPM_DMA DS	2	;XFER ADDR
CPM_DMAB DS	1	;XFER BANK
;
;
;   BUFFER IOPB OVERLAY
;
BUF_DSK DS	1	;BUFFER DISK NUMBER
BUF_TRK DS	2	;BUFFER TRACK NUMBER
BUF_SEC DS	2	;BUFFER SECTOR NUMBER
	DS	1	;FLAGS
BUF_DMA	DS	2
BUF_DMAB DS	1	;BANK #
;
;
;   BLOCKING BUFFER MAINTENANCE
;
BUF_PSEC DS	2	;BUFFER PHYSICAL SECTOR
BUF_ACT DS	1	;0: BUFFER FLUSHED, /0: DATA IN BUFFER
BUF_MOD	DS	1	;0: BUFFER CLEAN, /0: BUFFER DIRTY (MODIFIED)
;
BUF_DDT	DS	2	;BUFFER DDT PTR
BUF_DPB	DS	2	;BUFFER DPB PTR
;
RSFLAG:	DS	1	;0: NO PREREAD REQ'D, /0: PREREAD REQ'D
READOP:	DS	1	;0: WRITE OPERATION, 1: READ OPERATION
WRTYPE:	DS	1	;WRITE OPERATION TYPE FROM BDOS:
;			 0: WRITE TO ALLOCATED (USED) BLOCK (PREREAD)
;			 1: WRITE TO DIRECTORY (PREREAD & WRITE)
;			 2: WRITE TO UNALLOCATED (UNUSED) BLOCK (NO
;				PREREAD REQ'D)
;
;
UNA_CNT: DS	1	;# SECTORS REMAINING IN BLOCK (CLUSTER)
UNA_DSK: DS	1	;LAST UNALLOC DISK
UNA_TRK: DS	2	;LAST UNALLOC TRACK
UNA_SEC: DS	2	;LAST UNALLOC SECTOR


;############################################################################
;
;   VARIABLES
;
;############################################################################
;
CUR_DPB DS	2	;DRIVE TABLE PTR
CUR_DDT	DS	2	;DRIVE DRIVER TABLE BASE ADDRESS PTR
CUR_DPH	DS	2	;DPH PTR
;
LOGRQ:	DS	1	;LOG ON REQUEST REG.


;############################################################################
;
;   DRIVE ALLOCATION AREAS
;
;############################################################################
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	MACRO TO DEFINE THE DRIVE ALLOCATION & CHECKSUMS AREA
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	ALL = (DSM / 8) + 1
;	CHK = DPB.CKS
;
ALLDAL:	MACRO	#D
	LIST	ON
   IF	((DD - 1) >= STHD) AND ((DD - 1) <= NDHD)
D#D(DD)ALL:	DS	128	;ALLOCATION BIT MAP FOR 8" HARD DRIVE #D(DD)
   ENDIF
   IF	((DD - 1) >= ST8FD) AND ((DD - 1) <= ND8FD)
D#D(DD)ALL:	DS	57	;ALLOCATION BIT MAP FOR 8" DRIVE #D(DD)
D#D(DD)CHK	DS	32    ;DIRECTORY CHECKSUMS STORAGE (1 BYTE PER SECTOR)
   ENDIF
	LIST	OFF
	ENDM
;
;   RESERVE THE DATA SPACE
;
DD	DL	1
	REPT	NDRVS
	LIST	OFF
	ALLDAL	0123456789ABCDEF
DD	DL	DD + 1
	LIST	ON
	ENDM


;############################################################################
;
;   RESERVE DRIVE PARAMETER BLOCKS
;
;############################################################################
;
	STRUCT	0
DPB_SPT	DS	2	;SPT- SECTORS/TRACK
DPB_BSH	DS	1	;BSH- BLOCK SHIFT FACTOR DETERMINED BY CLUSTER SIZE
			;	1K= 3, 2K= 4, 4K= 5, 8K= 6, 16K= 7
DPB_BLM	DS	1	;BLM- BLOCK MASK
			;	1K = 7, 2K= 15, 4K= 31, 8K= 63, 16K= 127
DPB_EXM	DS	1	;EXM- EXTENT MASK
			;	DSM < 256 : 1K= 0, 2K= 1, 4K= 3, 8K= 7, 16K= 15
			;	DSM > 255 : 2K= 0, 4K= 1, 8K= 3, 16K= 7
DPB_DSM	DS	2	;DSM- DRIVE STORAGE SIZE (IN CLUSTERS)
	;  INT(((#_TRACKS - OFF) * SPT * BYTES PER SECTOR) / CLUSTER SIZE) -1
DPB_DRM	DS	2	;DRM- DIRECTORY SIZE -1
DPB_AL0	DS	2	;AL0,1- DIRECTORY ALLOCATION
			;	1 MSB PER DIRECTORY CLUSTER ALLOCATED
DPB_CKS	DS	2	;CKS- # DIRECTORY SECTORS CHECKED
			;	(DRM +1) / 4
DPB_OFF	DS	2	;OFF- # RESERVED TRACKS (USUALLY 2)
;
;   ADDITIONAL CP/M 3.0 DATA (ALSO COULD BE USED BY CP/M 2.2 DEBLOCKING)
;
DPB_PSH	DS	1	;PSH- PHYSICAL RECORD SHIFT FACTOR BASED ON BYTES/SEC
			;	0: 128, 1: 256, 2: 512, 3: 1024
DPB_PHM	DS	1	;PHM- PHYSICAL RECORD MASK BASED ON BYTES/SEC
			;	0: 128, 1: 256, 3: 512, 7: 1024
;
;   ADDITIONAL DISK PARTITIONING DATA FOR THE LOGICAL DRIVE SELECTION.
;	PARTITIONING BY TRACKS ARE IMPLIMENTED THRU BDOS USING DPBOFF ABOVE.
;	PARTITIONING BY HEADS ARE IMPLIMENTED BY USING THE FOLLOWING DATA.
;	  (HEAD BITS ARE INCLUDED IN SECTOR WORD UPPER BITS)
;
DPB_SECO DS	2	;SOF- SECTOR OFFSET (FOR LOGICAL DRIVE)
;				0: NONE, 1..65535: OFFSET
DPB_SZ	DS	0
	ENDM
;
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	GENERATE THE DPB FOR DRIVE MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
ALLDPB:	MACRO	#D
	LIST	ON
D#D(DD)DPB:	DS	DPB_SZ		;ALLOCATION FOR DRIVE #D(DD)
	LIST	OFF
	ENDM
;
;   RESERVE THE DATA SPACE
;
DD	DL	1
	REPT	NDRVS
	LIST	OFF
	ALLDPB	0123456789ABCDEF
DD	DL	DD + 1
	LIST	ON
	ENDM

;
;   BLOCKING BUFFER
;
BLKBUF:	DS	1024		;HOST BUFFER


   IF	(($ - 8000H) > 07700H) OR ($ < 8000H)
	CONMSG	**** BIOS TOO BIG, USE MOVCPM & RE-ADJUST! ****
   ENDIF

	END
