	TITLE	CUSTOMIZED BIOS FOR M5B
	LIST	NOCOND
;============================================================================
;
;	ASSEMBLY PARAMETERS
;
;============================================================================
FALSE	EQU	0
TRUE	EQU	NOT FALSE

;============================================================================
;
;	CONDITIONAL ASSEMBLY FLAGS
;
;============================================================================
SHORT	EQU	FALSE		;SHORT BIOS (REMOVES UNESENTIAL CODE)
LSTINC	EQU	FALSE		;LIST INCLUDE FILES
USEMON	EQU	TRUE		;USE MONITOR ROM I/O ROUTINES IF TRUE
INTRPTS	EQU	TRUE		;ENABLE INTERRUPT PROCESSING WHISTLE
INTCPTS	EQU	TRUE		;ENABLE SYSTEM CALL INTERCEPT WHISTLE
BOOT	EQU	3		;10H: HARD DISK, 3: 8" FLOPPY, 20H: 5" FLOPPY
DEBUG	EQU	FALSE		;TRUE TO DUMP THE IOPB DATA TO PRINTER
;
;   LISTING INCLUDE CONDITIONALS
;
P_ALL	EQU	FALSE		;TRUE TO PRINT ALL CODE
P_DISK	EQU	TRUE		;TRUE TO PRINT DISK CODE
P_CHAR	EQU	FALSE		;TRUE TO PRINT CHAR I/O CODE
P_CLK	EQU	FALSE		;TRUE TO PRINT CLOCK I/O CODE
P_INT	EQU	FALSE		;TRUE TO PRINT INTERRUPT CODE
P_BFUN	EQU	FALSE		;TRUE TO PRINT BIOS FUNCTION CODE
P_CDOS	EQU	FALSE		;TRUE TO PRINT CDOS FUNCTION CODE

	FORM
;****************************************************************************
;
;	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:
;
; 2.2.0 - RELEASE
;
; 2.2.3 - SWAPPED DCM & BIOS SECTORS ON DISK, ALLOWING A
;	    LARGER BIOS ALLOCATION ON THE DISK.
;
; 2.2.4 - ADDED NAKED TERMINAL DRIVERS & IOBYTE IN
;	    ANTICIPATION OF THE MONITOR. ALSO, ALL REFERENCES
;	    REQUIRING THE I/O PROMS TO BOOT HAS BEEN REMOVED.
;
; 2.2.5 - RECONFIGURE FOR 62K SYSTEM.
;
; 2.2.6 - 20 FEB 83
;	DOUBLE D REV C UPGRADE. CHANGE BOARD STATUS PORT BITS.
;
; 2.2.7 - 8 MAR 83 GRH
;	ADDED CLOCK/CALENDAR DRIVER, SYSTEM CALL INTERCEPT,
;	ILLEGAL SYSTEM CALL MESSAGE, CHANGED BIOS SIZE TO END
;	OF INITIALIZED DATA AREA. RESTRUCTURE MODULES.
;
; 2.28 - 22 APR 83   GRH
;	CHANGED DEFINITIONS TO ALLOW BIG DIRECTORIES.
;	DISALLOWED DRIVES C & D.
;
; 2.29 - 3 SEP 83   GRH
;	Changed Rev # for blocked DCM. Enables IBM system 34
;	256 bytes per sector disks to be read.
;
; 1.10 - 23 SEP 83   GRH
;	Move clock-calendar routines to ROM. Add Interrupt handler
;	(Mode 2). Change Revision display of sign-on (separate CBIOS rev).
;
; 2.00 - 24 MAR 84   GRH
;	Modify for hard disk
;
; 2.01 - 28 APR 84   GRH
;	Change hard disk DPB to reflect half size directory, but keep
;	allocation for 1k directory
;
; 2.02 - 2 JUN 84   GRH
;	Change floppy disk drivers to relate to ISASI control of JADE
;	   FDC.
;	Change IOPB sector value from physical sector (1..n) to logical
;	   sector value (0..n-1). This maintains more uniformity in
;	   parameter passing between hard disk & JADE floppy IOPBs.
;	Vector I/O routines to monitor rom routines.
;
; 2.03 - 4 JUN 84   GRH
;	Add bells & whistles again.
;	Move to 61k system.
;
; 2.04 - 30 MAR 85   GRH
;	Implemented hard disk drive 1 as C: & D:.
;	Implemented the Logon function for the hard disk.
;	Implemented user friendly disk error options: Abort, Retry, Ignore.
;	Solved warm boot hang problem by reseting host adapter if busy.
;
; 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	12-12-88   GRH
;	Add dynamic deblocking algorithms and CP/M 3.x data tables.
;
VERSN	EQU	305
;
;****************************************************************************


	SUBTTL	SYSTEM DECLARATIONS
;============================================================================
;
; INCLUDE JDDCONT.DEF
; INCLUDE COMIOPB.DEF
; INCLUDE DISKS.DEF
; INCLUDE MONBOARD.DEF
; INCLUDE ZMONROM.DEF
; INCLUDE DKBTROM.DEF
; INCLUDE NAKEDT.DEF
; INCLUDE ISHA.DEF
; INCLUDE CLOKROM.DEF
;
;============================================================================
	LIST	OFF
*INCLUDE JDDCONT.DEF
*INCLUDE COMIOPB.DEF
*INCLUDE DISKS.DEF
*INCLUDE MONBOARD.DEF
*INCLUDE ZMONROM.DEF
*INCLUDE DKBTROM.DEF
*INCLUDE NAKEDT.DEF
*INCLUDE ISHA.DEF
*INCLUDE CLOKROM.DEF
	LIST	ON


;============================================================================
;
;   DISK OPERATING SYSTEM ADDRESSES
;
;============================================================================
OP_SYS	EQU	2		;CP/M VERSION
;
NKSYS:	EQU	60		;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
IOBYTE:	EQU	PAGE0 + 3	;IOBYTE ADDR
DEFDRV:	EQU	PAGE0 + 4	;DEFAULT DRIVE PARAM ADDR
BDOSJV	EQU	PAGE0 + 5	;BDOS SYSTEM CALL ENTRY
DEFBFR	EQU	PAGE0 + 80H	;DEFAULT BUFFER
;
;   BIOS FUNCTION CALL RESTART VECTOR
;
BFUNRST	EQU	28H
BFUNRSV	EQU	PAGE0 + BFUNRST
BFUNRSI	EQU	0C7H + BFUNRST
;
TPA:	EQU	100H


;============================================================================
;
;	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


;============================================================================
;
;	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


;############################################################################
;
;	THESE BOOT PARAMS 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 CODE IN ORDER TO FIND THE LOAD ADDRESS FOR THE BIOS & IT'S
;  LENGTH.
;
;############################################################################
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
;
	LD	SP,DEFBFR	;USE PAGE 0 FOR STACK
;
;   MAKE SURE ROM IS ENABLED
;
	CALL	GETMON
;
;   INIT DEFAULT DRIVE
;
	LD	A,(DK_PROM + 1)	;USE DRIVE # PASSED IN PAGE 0
	AND	A,3
	LD	(DEFDRV),A
;
;   INIT DEBLOCKING DATA
;
	XOR	A,A		;ASSUME NO DATA IN BUFFER
	LD	(HST_ACT),A
;
	LD	(UNA_CNT),A	;CLEAR UNALLOCATED SECTOR COUNT
;
;   SEND SYSTEM SIGN-ON
;
CLOGO:	LD	HL,MSGSO
	CALL	EDITOR
;
;   MODIFY COLD START VECTOR TO WARM START
;
	LD	HL,(BIOS+4)
	LD	(BIOS+1),HL
;
;   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:
  IF	INTRPTS
;
;   SET INTERRUPT VECTOR TABLE BASE
;
	LD	A,HIGH INTABL
	LD	I,A
;
;   SET INTERRUPT MODE TO 2
;
	IM	2
;
;   ENABLE INTERRUPT VECTOR 7
;
	IN	A,(M2_IMASK)
	AND	A,7FH
	OUT	(M2_IMASK),A
;
;   FINALLY ENABLE VECTORED INTERRUPTS
;
	IN	A,(M2_STAT)
	OR	A,M2_IEN
	OUT	(M2_STAT),A
	EI
  ENDIF
;
;   SET TEMPORARY STACK
;
	LD	SP,DEFBFR
;
;   INSURE MONITOR ROM STILL ENABLED
;
	CALL	GETMON
;
   IF	BOOT = 10H
;   TEST ISHA HOST ADAPTER FOR A HUNG CONDITION AND CLEAR IF TRUE
;
	IN	A,(ISH_STATUS)	;IF HOST ADAPTER BUSY THEN
	BIT	ISH_BSYB,A
	JR	Z,NTHUNG
;
	LD	A,PB_CLRC
	LD	(IOPB + PB_CMDO),A
	CALL	XPRIM
;
NTHUNG:
   ENDIF
;
;   LOG ON DRIVE TO INIT TABLES
;
	LD	A,(DK_PROM + 1)
	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,(SEK_SEC)
	INC	HL
	LD	(SEK_SEC),HL
;
	LD	DE,SECSZ	;DMA := DMA + SECTOR SIZE
	LD	HL,(DMA_ADR)
	ADD	HL,DE
	LD	(DMA_ADR),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
;
	JP	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 & HALT
;
WEROR:	LD	HL,MSGLE	;OUTPUT ERROR MESSAGE
	CALL	EDITOR
	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
;
;   INITIALIZE CLOCK VECTORS IF CLOCK INSTALLED
;
	LD	C,CLK_F7	;TEST FOR BOARD PRESENT
	CALL	CLK1
;
;   IF CLOCK PRESENT THEN TURN ON CLOCK DRIVE
;
	OR	A,A
	LD	A,38H		;COND. JR (ON)
	JR	NZ,CLKON
;
;   ELSE TURN OFF CLOCK DRIVE
;
	LD	A,18H		;UNCOND. JR (OFF) (CAUSES JUMP TO ILLEGAL)
;
CLKON:	LD	(INHCLK),A
;
  ENDIF
;
;   PASS DEFAULT DISK TO CCP
;
	LD	A,(DEFDRV)
	LD	C,A
	JP	CCP


   IF	P_DISK OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
	SUBTTL	BIOS DISK FUNCTION ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	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:
;
;   ASSUME ERROR
;
	LD	HL,0
;
;   IF UNSUPPORTED DRIVE REQUESTED THEN RETURN 0 (ERROR)
;
	LD	A,C
	CP	A,NDRVS
	RET	NC
;
;   STORE DRIVE # FOR FUTURE USE
;
	LD	(SEK_DSK),A
;
;   LOOK UP DRIVE IN TABLES
;
	ADD	A,A
	LD	HL,DRV_PTRS
	ADD	A,L
	LD	L,A
	LD	A,0
	ADC	A,H
	LD	H,A
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A
	LD	(CUR_DPH),HL
;
;   FETCH OTHER PTRS
;
	PUSH	IX		;SAVE CURRENT IX
	PUSH	HL
	POP	IX
;
	LD	L,(IX+ DPHDPBO)
	LD	H,(IX+ DPHDPBO +1)
	LD	(CUR_DPB),HL
;
	LD	L,(IX+ DPHDTABO)
	LD	H,(IX+ DPHDTABO +1)
	LD	(CUR_BCB),HL
;
	LD	L,(IX+ DPHWRTO)
	LD	H,(IX+ DPHWRTO +1)
	LD	(CUR_WR),HL
;
	LD	L,(IX+ DPHRDO)
	LD	H,(IX+ DPHRDO +1)
	LD	(CUR_RD),HL
;
	LD	L,(IX+ DPHSOFO)
	LD	H,(IX+ DPHSOFO +1)
	LD	(CUR_SOFF),HL
;
	LD	A,(IX+ DPHDRVO)
	LD	(CUR_DRV),A
;
	POP	IX		;RESTORE IX BEFORE RETURNING
;
;   SAVE LOGON REQUEST FLAG
;
	LD	A,E
	LD	(LOGRQ),A
;
;   FETCH DISK PARAMETER HEADER TABLE ADDRESS
;
	LD	HL,(CUR_DPH)
;
;   IF NOT FIRST SELECT OR LOGON INHIBITED THEN RETURN TABLE PTR
;
	CPL
	AND	A,1
	RET	Z
;
;   ELSE LOG ON DRIVE
;
;   ATTEMPT TO READ ID SECTOR
;
	XOR	A,A		;INIT FLAG BYTE UNTIL FIRMWARE REVISED
	LD	(IOPB + PB_ST2O),A
;
	CALL	DISKLOG
	JP	NZ,FDSKER
;
;   IF NO ID SECTOR THEN USE DEFAULTS
;
	LD	A,(IOPB + PB_ST2O)
	CP	A,-2		;0: NO ID, -1: JADE ID, -2: EXTENDED ID
	JR	NZ,LGDEF
;
;   ELSE XFER ID SECTOR DATA TO TABLES
;
	LD	HL,DEFBFR + ID_SPTO
;
;   XFER DISK DATA TO DPB
;
LG_XDPB:
	LD	DE,(CUR_DPB)			;GET ADDR OF DPB
	LD	BC,DPBSZ
	LDIR
;
;   IF PSH > 3 THEN SET TO 0 (NO DEBLOCK)
;
	DEC	HL		;SKEW
	DEC	HL		;PHM
	DEC	HL		;PSH
	LD	A,(HL)
	CP	A,4
	JR	C,PSHOK
;
	LD	(HL),0		;PSH = 0
	INC	HL		;PHM = 0
	LD	(HL),0
	INC	HL		;SKEW = 0
	LD	(HL),0
	JR	DPBSET
;
PSHOK:
;   FETCH SKEW INDEX
;
	INC	HL		;PHM
	INC	HL		;SKEW
;
DPBSET:	LD	A,(HL)
;
;   CALCULATE SKEW TABLE TO USE
;
	OR	A,A		;IF 0 THEN NO XLATION
	JR	NZ,LG_X1
;
LG_NOX:	LD	HL,0
;
LG_X:	LD	(CUR_XLAT),HL
	JR	LG_DONE
;
;
;   IF SKEW > LAST THEN NONE
;	
LG_X1:	CP	A,4
	JR	C,LG_NOX
;
;   ELSE IF SKEW == 1 THEN IBM 3740 FORMAT
;
	LD	HL,X3740
	CP	A,2
	JR	C,LG_X
;
;   ELSE IF SKEW == 2 THEN IBM 3740 DOUBLE SIDED
;
	LD	HL,X3740D
	JR	Z,LG_X
;
;   ELSE IF SKEW == 3 THEN CCS SINGLE SIDED
;
	LD	HL,XCCS
	CP	A,4
	JR	C,LG_X
;
;   ELSE IF SKEW == 4 THEN CCS DOUBLE SIDED
;
	LD	HL,XCCSD
	JR	LG_X
;
;
;   RETURN DRIVE TABLE PTR
;
LG_DONE:
	LD	HL,(CUR_DPH)
	XOR	A,A
	RET
;
;
;   SELECT DEFAULT DPB FROM TABLES BASED ON DRIVE TYPE
;
LGDEF:	LD	HL,(CUR_DPH)
	DEC	HL		;POINT TO DRIVE TYPE BYTE
;
;   IF HARD DISK THEN USE HARD DISK TABLE
;
	LD	A,(HL)
	CP	A,10H
	JR	C,LG_DEFF
;
	LD	HL,HDPBK
	JR	LG_XDPB
;
;
;   USE 8" FLOPPY DEFAULTS
;
LG_DEFF:
	LD	HL,SD8PBK
	JR	LG_XDPB


;****************************************************************************
;
;   HOME DRIVE - TREAT AS SEEK TRK 0
;	EXIT -	BC= 0
;
;****************************************************************************
HOME:
;
;   IF PENDING WRITE (BUFFER DIRTY) THEN IGNORE
;
	LD	A,(HST_WRT)
	OR	A,A
	RET	NZ
;
;   ELSE PURGE BUFFER
;
	LD	(HST_ACT),A
	RET


;****************************************************************************
;
;	SET TRACK #
;	ENTRY-	BC= TRACK #
;
;****************************************************************************
SETTRK:
	LD	(SEK_TRK),BC
	RET


;****************************************************************************
;
;	SET SECTOR
;	ENTRY-	BC= SECTOR #
;
;****************************************************************************
SETSEC:
	LD	(SEK_SEC),BC
	RET


;****************************************************************************
;
;	SET TRANSFER ADDR
;	ENTRY-	BC= ADDRESS
;	EXIT -	A= 0
;
;****************************************************************************
SETDMA:	LD	(DMA_ADR),BC
	XOR	A,A
	LD	(DMA_BNK),A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	SECTOR TRANSLATION BDOS FUNCTION DOES NOTHING IN DEBLOCKING MODE
;	ENTRY-	BC= SECTOR # TO XLATE
;	EXIT -	HL= BC
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SECTRN:
	LD	H,B
	LD	L,C
	RET


;****************************************************************************
;
;	THE READ FUNCTION READS THE REQUESTED SECTOR
;	EXIT -	A= 0: OK, /0: ERROR CODE
;
;****************************************************************************
DISKRD:
;
;   IF SECTOR SIZE == 128 THEN USE UNBLOCKED ROUTINES & SAVE BUFFER
;
	LD	HL,(CUR_DPB)
	LD	DE,DPBPSHO
	ADD	HL,DE
	LD	A,(HL)
	OR	A,A
	JP	Z,UB_READ
;
;   SET UP DATA TABLE PTR
;
	PUSH	IX
	LD	IX,(CUR_DPB)
;
;   READ_OPERATION_FLAG = TRUE (1)
;
	LD	A,1
	LD	(READ_OP),A
;
;   PRE-READ_OF_DATA_FLAG = TRUE
;
	LD	(RS_FLAG),A
;
;   TREAT AS UNALLOCATED BLOCK
;
	LD	A,WR_UAL
	LD	(WR_TYPE),A
;
	JP	RWOPER		;TO PERFORM THE READ


;****************************************************************************
;
;	THE WRITE ENTRY POINT TAKES THE PLACE OF THE PREVIOUS BIOS DEFINTION
; FOR WRITE.
;	ENTRY- C= WRITE TYPE:
WR_ALL	EQU	0	;WRITE TO ALLOCATED BLOCK (UPDATE)
WR_DIR	EQU	1	;WRITE TO DIRECTORY BLOCK (ALLWAYS WRITE)
WR_UAL	EQU	2	;WRITE TO UNALLOCATED BLOCK (NO NEED TO PRE-READ)
;
;****************************************************************************
DISKWR:
;
;   IF SECTOR SIZE == 128 THEN USE UNBLOCKED ROUTINES
;
	LD	HL,(CUR_DPB)
	LD	DE,DPBPSHO
	ADD	HL,DE
	LD	A,(HL)
	OR	A,A
	JP	Z,UB_WRITE
;
;   SET PTR TO DISK DATA
;
	PUSH	IX
	LD	IX,(CUR_DPB)
;
;   READ_OP_FLAG = FALSE
;
	XOR	A,A
	LD	(READ_OP),A
;
;   SAVE WRITE TYPE
;
	LD	A,C
	LD	(WR_TYPE),A
;
;   IF 1ST WRITE TO UNALLOCATED (NEW, UNUSED) BLOCK THEN SET PARAMETERS
;
	CP	A,WR_UAL
	JP	NZ,CHKUNA
;
;   COUNT = NUMBER_OF_SECTORS_IN_BLOCK
;
	LD	A,(IX+ DPBBLMO)	;CUR_DPB.DPBBLM + 1 ::= (BLKSIZ/128)
	INC	A
	LD	(UNA_CNT),A
;
;   SET DISK TO SEEK
;
	LD	A,(SEK_DSK)
	LD	(UNA_DSK),A
;
;   SET TRACK TO SEEK
;
	LD	HL,(SEK_TRK)
	LD	(UNA_TRK),HL
;
;   SET SECTOR TO SEEK
;
	LD	HL,(SEK_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,(SEK_DSK)	;SAME DISK?
	LD	HL,UNA_DSK
	CP	A,(HL)
	JP	NZ,ALLOC
;
	LD	HL,(UNA_TRK)	;SAME TRACK?
	LD	DE,(SEK_TRK)
	SBC	HL,DE
	JP	NZ,ALLOC
;
	LD	HL,(SEK_SEC)
	LD	DE,(UNA_SEC)
	SBC	HL,DE
	JP	NZ,ALLOC
;
;   MATCH, MOVE TO NEXT SECTOR FOR FUTURE REF
;
	INC	HL		;UNASEC = UNASEC+1
	LD	(UNA_SEC),HL
;
;   IF PAST LAST SECTOR ON TRACK THEN USE 1ST SECTOR OF NEXT TRACK
;
	LD	E,(IX+ DPBSPTO)
	LD	D,(IX+ DPBSPTO +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	(RS_FLAG),A
	JP	RWOPER
;
;
;   NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ
;
ALLOC:
	XOR	A,A		;COUNT = 0
	LD	(UNA_CNT),A
;
	INC	A		;PREREAD FLAG = TRUE
	LD	(RS_FLAG),A
;
;
;
;   COMMON CODE FOR READ AND WRITE FOLLOWS
;
RWOPER:
;
;   ASSUME NO ERRORS
;
	XOR	A,A
	LD	(ER_FLAG),A
;
;   COMPUTE BUFFER SECTOR
;
	LD	BC,(SEK_SEC)
;
	LD	A,(IX+ DPBPSHO)		;USE PHYSICAL SHIFT FACTOR (CP/M 3.X)
	OR	A,A			;IF ALREADY 0 THEN SECTOR SIZE IS 128
	JR	Z,NOSECSHF
;
SECSHFLP:
	SRL	B			;ELSE SHIFT OVER TO PHYSICAL SECTOR
	RR	C
	DEC	A
	JR	NZ,SECSHFLP
;
NOSECSHF:
	LD	(SEK_HST),BC	;BUFFER SECTOR TO SEEK
;
;   IF BUFFER EMPTY THEN READ THE PHYSICAL SECTOR
;
	LD	HL,HST_ACT
	LD	A,(HL)
;
	LD	(HL),1		;BUFFER FULL IN ANY CASE
;
	OR	A,A
	JP	Z,FILHST
;
;   HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
;
	LD	A,(SEK_DSK)
	LD	HL,HST_DSK	;SAME DISK?
	CP	A,(HL)
	JP	NZ,NOMATCH
;
	LD	HL,(HST_TRK)	;SAME TRACK?
	LD	DE,(SEK_TRK)
	SBC	HL,DE
	JP	NZ,NOMATCH
;
	LD	DE,(SEK_HST)	;SAME SECTOR?
	LD	HL,(HST_SEC)
	SBC	HL,DE
	JP	Z,MATCH		;SKIP IF MATCH
;
NOMATCH:
;
;   IF CURRENT BUFFER DIRTY THEN WRITE IT OUT BEFORE READING NEW ONE
;
	LD	A,(HST_WRT)
	OR	A,A
	CALL	NZ,WRITEHST	;CLEAR HOST BUFF
;
FILHST:
;
;   READ THE SECTOR BUFFER
;
	LD	A,(SEK_DSK)	;BUFFER SECTOR = PHYSICAL SECTOR
	LD	(HST_DSK),A
;
	LD	HL,(SEK_TRK)
	LD	(HST_TRK),HL
;
	LD	HL,(SEK_HST)
	LD	(HST_SEC),HL
;
;   IF REQUIRED TO READ THEN READ
;
	LD	A,(RS_FLAG)		;NEED TO READ?
	OR	A,A
	CALL	NZ,READHST		;YES, IF 1
;
;   BUFFER = CLEAN
;
	XOR	A,A
	LD	(HST_WRT),A
;
MATCH:
;
;   COPY DATA TO OR FROM BUFFER
;
	LD	HL,(SEK_SEC)	;CALCULATE INDEX INTO BUFFER
	LD	A,L
;
	AND	A,(IX+ DPBPHMO)	;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,HST_BUF
	ADD	HL,DE		;HL = HOST ADDRESS
;
	LD	DE,(DMA_ADR)	;GET/PUT CP/M DATA
	LD	BC,128		;LENGTH OF MOVE
;
	LD	A,(READ_OP)	;WHICH WAY?
	OR	A,A
	JP	NZ,RWMOVE	;SKIP IF READ
;
;   WRITE OPERATION, MARK AND SWITCH DIRECTION
;
	LD	A,1		;BUFFER = DIRTY
	LD	(HST_WRT),A
;
	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,(WR_TYPE)	;IF NOT DIRECTORY THEN DELAY WRITE
	CP	A,WR_DIR
	LD	A,(ER_FLAG)	;RETURN ANY ERRORS ANYWAY
	JR	NZ,RW_RET
;
;   IF ERROR THEN ABORT
;
	OR	A,A
	RET	NZ
;
;   NO ERROR/DIRECTORY WRITE
;
	XOR	A,A		;BUFFER = CLEAN
	LD	(HST_WRT),A
;
	CALL	WRITEHST	;WRITE TO DISK
;
	LD	A,(ER_FLAG)	;RETURN ANY ERRORS
;
;   DONE, RESTORE & RETURN
;
RW_RET:
	POP	IX
;
	RET


	SUBTTL	DISK SUPPORT ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	UNBLOCKED READ FUNCTION
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
UB_READ:
;
;   SET COMMAND TO READ
;
	LD	A,PB_READC
;
;   COMMON UNBUFFERED R/W
;
UB_COMM:
	LD	(IOPB + PB_CMDO),A
;
;   SET DRIVE
;
	LD	A,(CUR_DRV)
	LD	(IOPB + PB_DRVO),A
;
;   SET DESCRIPTOR SECTOR TRACK
;
	LD	HL,(SEK_TRK)
	LD	(IOPB + PB_TRKO),HL
;
;   SET DESCRIPTOR SECTOR SECTOR
;
	LD	BC,(SEK_SEC)		;MUST TRANSLATE
	LD	DE,(CUR_XLAT)
	CALL	SEC_TRN
	LD	(IOPB + PB_SECO),HL
;
;   NO FLAGS
;
	XOR	A,A
	LD	(IOPB + PB_FLGO),A
;
;   128 BYTES
;
	LD	HL,128
	LD	(IOPB + PB_BCNTO),HL
;
;   SET DESCRIPTOR SECTOR XFER ADDRESS TO DATA
;
	LD	HL,(DMA_ADR)
	LD	(IOPB + PB_DMAO),HL
	LD	A,(DMA_BNK)
	LD	(IOPB + PB_DMAXO),A
;
;   EXECUTE THE IOPB
;
	JP	EX_IOPB


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	UNBLOCKED WRITE FUNCTION
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
UB_WRITE:
;
;   SET COMMAND TO WRITE
;
	LD	A,PB_WRITC
	JP	UB_COMM


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	LOGON DISK FUNCTION
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DISKLOG:
;
;   SET DESCRIPTOR SECTOR XFER ADDRESS TO DEFAULT BUFFER
;
	LD	HL,DEFBFR
	LD	(IOPB + PB_DMAO),HL
	XOR	A,A
	LD	(IOPB + PB_DMAXO),A
;
;   SET DESCRIPTOR SECTOR SECTOR
;
	LD	HL,ID_SECT
	LD	(IOPB + PB_SECO),HL
;
;   SET DESCRIPTOR SECTOR TRACK
;
	LD	L,H		;H == 0 FROM LAST OPERATION (HL= 0)
	LD	(IOPB + PB_TRKO),HL
;
;   PASS COMMAND TO EXECUTOR
;
	LD	A,PB_LOGC
	LD	(IOPB + PB_CMDO),A
;
;   EXECUTE THE IOPB
;
	JP	EX_IOPB


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	READ A DISK SECTOR INTO SECTOR DEBLOCKING BUFFER FUNCTION
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
READHST:
;
;   SET PTR TO EXECUTION ROUTINE
;
	LD	HL,(CUR_RD)
	PUSH	HL
;
;   SET DMA TO SECTOR BUFFER
;
	LD	HL,HST_BUF
	LD	(IOPB + PB_DMAO),HL
;
	XOR	A,A
	LD	(IOPB + PB_DMAXO),A
;
	LD	A,PB_READC	;SELECT READ OP
	JP	DISKOP


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	WRITE A DISK SECTOR FROM SECTOR DEBLOCKING BUFFER FUNCTION
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
WRITEHST:
;
;   SET PTR TO EXECUTION ROUTINE
;
	LD	HL,(CUR_WR)
	PUSH	HL
;
;   SET DMA TO SECTOR BUFFER
;
	LD	HL,HST_BUF
	LD	(IOPB + PB_DMAO),HL
;
	XOR	A,A
	LD	(IOPB + PB_DMAXO),A
;
	LD	A,PB_WRITC	;SELECT WRITE OP
;
;   FALL INTO COMMON DISK I/O
;


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	COMMON DISK I/O CODE
;	ENTRY-	A= IOPB COMMAND
;		(SP)= DRIVER ADDRESS
;		(IOPB.PB_DMA= SET
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DISKOP:
;
;   SET IOPB COMMAND
;
	LD	(IOPB + PB_CMDO),A
;
;   DRIVE
;
	LD	A,(CUR_DRV)
	LD	(IOPB + PB_DRVO),A
;
;   TRACK
;
	LD	HL,(HST_TRK)
	LD	(IOPB + PB_TRKO),HL
;
;   SECTOR
;
	LD	BC,(HST_SEC)		;XLATE POSSIBLE
	LD	DE,(CUR_XLAT)
	CALL	SEC_TRN
;
	LD	DE,(CUR_SOFF)		;ADD IN SECTOR OFFSET
	ADD	HL,DE
	LD	(IOPB + PB_SECO),HL
;
;   EXECUTE DRIVER ADDRESS ON STACK
;
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	EXECUTE IOPB FUNCTION
;	ENTRY-	IOPB ALL SET UP
;	EXIT -	A= 0: OK; /0: ERROR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
F8_RD:
F8_WR:
H8_RD:
H8_WR:
EX_IOPB
;
;   EXECUTE DISK DRIVER
;
DKOPLP:
;
;   EXECUTE THE PRIMITIVE IN ROM
;
	PUSH	IX
	LD	IX,IOPB		;PASS PTR TO IOPB
	LD	HL,DK_DSKX	;PRIMITIVE ENTRY
	LD	A,(DK_PROM)	;FETCH PROM #
	CALL	EXROM		;EXECUTE THE PRIMITIVE
	POP	IX
;
;   IF NO ERRORS THEN RETURN THE COMMAND RESULTS STATUS
;
	LD	A,(IOPB + PB_STATO)
	OR	A,A
	RET	Z
;
;   PRINT ERROR
;
	LD	HL,DSKEM	;OUTPUT PREFIX
	CALL	EDITOR
;
	LD	DE,IOPB
	LD	B,PB_SIZE
DSKER1:
	LD	A,(DE)		;FETCH BYTE
	PUSH	DE		;SAVE REGS
	PUSH	BC
	CALL	PRHEX		;OUTPUT ERROR CODE
;
	LD	C,' '
	CALL	COC
;
	POP	BC		;RESTORE REGS
	POP	DE
	INC	DE		;NEXT ERROR BYTE
	DJNZ	DSKER1		;IF NOT DONE THEN LOOP
;
	LD	HL,DSKEB	;OUTPUT ERROR MESSAGE
	CALL	EDITOR
;
;   GET USER RESPONSE
;
	CALL	CI
;
	PUSH	AF		;SAVE CHAR
	LD	C,A		;ECHO CHAR
	CALL	COC
	POP	AF
;
	AND	A,5FH		;INSURE UPPER CASE
;
;   IF RETRY THEN RETURN TO CALLER
;
	CP	A,'R'
	JR	Z,DKOPLP
;
;   ELSE IF ABORT THEN DO WARM BOOT
;
	CP	A,'A'
	JP	Z,0
;
;   ELSE IF IGNORE THEN RETURN NO ERROR
;
	SUB	A,'I'
	RET	Z
;
;   ELSE RETURN ERROR TO BDOS
;
FDSKER:	LD	HL,0		;RETURN DPB_PTR = 0 FOR SELECT FUNCTION
	LD	A,-1		;RETURN -1 TO BDOS
	OR	A,A
	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= ?
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SEC_TRN:
;
;   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


   IF	P_BFUN OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
	SUBTTL	BIOS FUNCTION CALLS
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	FUNCTION DISPATCHER
;	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
	DW	EXIOPB		;2:EXECUTE THE IOPB
MAXFUNCS EQU	($ - BFUNTBL) / 2


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN BIOS VERSION #
;	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
;	ENTRY-	C= DRIVE # (E FOR FUNCTION CALL)
;	EXIT -	HL= DRIVER TABLE BASE PTR
;		A, C= 0
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   BIOS CALL ENTRY (E= DRIVE #)
;
RETDVRTF:
;
;   IF ILLEGAL DRIVE THEN RETURN ERROR
;
	LD	A,E
	CP	A,NDRVS
;
	LD	A,-1
	RET	NC
;
;   ELSE RETURN PTR TO DPH
;
	LD	HL,DRV_PTRS	;POINT TO BASE OF TABLE
	LD	D,0		;ADD OFFSET TWICE FOR WORD PTRS
	ADD	HL,DE
	ADD	HL,DE
;
	LD	E,(HL)		;FETCH DPH PTR
	INC	HL
	LD	D,(HL)
;
	EX	DE,HL		;RETURN IN HL
;
;   RETURN NO ERROR
;
	XOR	A,A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	EXECUTE IOPB FUNCTION
;	ENTRY-	IX= IOPB PTR
;	EXIT -	A= 0: OK
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EXIOPB:
;
;   SET UP FOR CALL
;
	LD	HL,DK_DSKX
	LD	A,(DK_PROM)
	CALL	EXROM
;
;   FETCH & RETURN RESULT STATUS
;
	LD	A,(IX + PB_STATO)
	OR	A,A		;TEST RESULT FOR RETURN
	RET
	

	LIST	ON
	SUBTTL	NON-DISK PROCEDURES
;****************************************************************************
;
;	OUTPUT HEX DATA TO CONSOLE SUBR
;	ENTRY-	A= DATA
;	EXIT -	A, C= ?
;
;****************************************************************************
PRHEX:
;
;   PROCESS HIGH NIBBLE 1ST
;
	CALL	PRDIG
;
;   SWAP HIGH & LOW NIBBLES
;
PRDIG:	RLCA
	RLCA
	RLCA
	RLCA
;
;   SAVE DATA FOR RETURN
;
	PUSH	AF
;
;   CONVERT TO ASCII USING DAA TRICK
;
	AND	A,0FH
	ADD	A,90H
	DAA
	ADC	A,40H
	DAA
;
;   OUTPUT CHAR TO CONSOLE
;
	LD	C,A
	CALL	COC
;
;   RETURN DATA
;
	POP	AF
	RET


;***************************************************************************
;
;	NEWLINE PROCEDURE
;
;***************************************************************************
CRLF:	LD	C,CR
	CALL	COC
	LD	C,LF
	JP	COC


   IF	INTCPTS
   IF	P_CDOS OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
	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	C,CLKSET	;IF SET FUNCTION THEN SET CLOCK
;
	JR	Z,CLKTIM	;IF TIME THEN GET IT
;
	CP	A,93H
	JR	Z,CLKRDC	;IF READ CLOCK THEN GET IT
;
;  ILLEGAL SYSTEM CALL
;
ILLEGC:	PUSH	BC		;SAVE FUNCTION #
;
;   OUTPUT WARNING MESSAGE
;
	LD	HL,ISCMSG	;OUTPUT WARNING
	CALL	EDITOR
;
;   OUTPUT FUNCTION #
;
	POP	HL
	LD	A,L
	CALL	PRHEX
;
;   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

   IF	P_CLK OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
	SUBTTL	CLOCK ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN CALENDAR FUNCTION 90H
;	EXIT -	A= DAY
;		B= MONTH
;		C= YEAR
;		L= DAY OF WEEK
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CLKCAL:
	LD	HL,CLK_CAL	;ROM ENTRY POINT
	JR	CLK2


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN TIME FUNCTION 92H
;	EXIT -	A= SECONDS
;		B= MINITS
;		C= HOURS
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CLKTIM:
	LD	HL,CLK_TIM
	JR	CLK2
	

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	READ CLOCK TIME FUNCTION 93H
;	ENTRY-	DE= PTR TO 13 BYTE BUFFER FOR CLOCK DATA
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CLKRDC:
	LD	C,CLK_F1
	JR	CLK1


;****************************************************************************
;
;	CLOCK SET FUNCTION 91H
;	ENTRY-	DE= CLOCK IMAGE BUFR PTR (13 BYTES LONG)
;
;****************************************************************************
CLKSET:
	LD	C,CLK_F2
;
CLK1:	LD	HL,CLK_FUN
;
CLK2:	LD	A,CLK_ROM
;
;   FALL INTO ROM EXECUTER
;
   ENDIF


	LIST	ON
;****************************************************************************
;
;	EXECUTE ROM ROUTINE
;	ENTRY-	HL= ENTRY ADDRESS
;		A= ROM #
;	EXIT -	?
;
;****************************************************************************
EXROM:
	AND	A,M2_RSMK	;MASK OUT UNUSED BITS
	OUT	(M2_RSEL),A
;
	PUSH	HL		;SAVE ROM ENTRY VECTOR
;
	LD	HL,EXROMR	;PUT RETURN ADDR ON STACK
	EX	(SP),HL		;SWAP RETURN ADDRESS WITH ROM ENTRY VECTOR
	JP	(HL)		;EXECUTE ROM
;
;   ROM PROCEDURE RETURNS HERE
;
EXROMR:	PUSH	AF		;SAVE RETURN VALUE
	CALL	GETMON		;RESELECT MONITOR ROM
;
	POP	AF		;RETURN VALUE
	RET

   IF	P_CHAR OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
	SUBTTL	CHAR I/O ROUTINES
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	CONSOLE INPUT
;	EXIT -	A= CHAR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CI:
   IF	USEMON
	CALL	GETMON		;SWITCH IN MONITOR ROM
	JP	MR_CONIN	;USE MONITOR
   ELSE
	CALL	CNSCK		;IF NO CHAR RDY THEN WAIT
	JR	Z,CI
	IN	A,(NT_DATA)	;ELSE RETURN CHAR
	RET
   ENDIF


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN CONSOLE STATUS
;	EXIT -	A= 0: NOT READY
;		   FFH: CHAR READY
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CNSCK:
   IF	USEMON
	CALL	GETMON
	JP	MR_CONSTS
   ELSE
	IN	A,(NT_STAT)	;IF DATA NOT READY THEN RETURN 0
	AND	A,1 SHL NT_READY
TTOST1:	RET	Z
	LD	A,-1		;ELSE RETURN -1
	RET
   ENDIF


;****************************************************************************
;
;	CONSOLE OUTPUT
;	ENTRY-	C= CHAR TO OUTPUT
;
;****************************************************************************
COC:
   IF	USEMON
	CALL	GETMON
	JP	MR_CONOUT
   ELSE
	CALL	NTOST		;IF BUSY THEN WAIT
	OR	A,A
	JR	Z,COC

	LD	A,C
	OUT	(NT_DATA),A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN CONSOLE OUTPUT READY STATUS
;	EXIT -	A= 0: BUSY, FFH: READY
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NTOST:	IN	A,(NT_STAT)
	CPL			;REVERSE SENSE
	AND	A,1 SHL NT_BUSY
	JR	TTOST1
   ENDIF


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	READER DRIVER - DUMMY
;	EXIT -	A= CTRL-Z
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
READER:	LD	A,CTRLZ		;FAKE EOF


;****************************************************************************
;
;	PUNCH DRIVER
;	ENTRY-	C= CHAR TO OUTPUT
;
;****************************************************************************
PUNCH:	RET


;****************************************************************************
;
;	PRINTER DRIVER
;	ENTRY-	C= CHAR TO OUTPUT
;
;****************************************************************************
LO:
   IF	USEMON
	CALL	GETMON
	JP	MR_LSTOUT
   ELSE
	RET
   ENDIF


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN LIST DEVICE STATUS
;	EXIT -	A= 0: BUSY, FFH:READY
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LISTST:
   IF	USEMON
	CALL	GETMON
	JP	MR_LSTSTS
   ELSE
	LD	A,-1
	RET
   ENDIF


	LIST	ON
;****************************************************************************
;
;	GET MONITOR PROM SUBR
;	EXIT -	A= ?
;
;****************************************************************************
GETMON:
	LD	A,MR_RNUM
	OUT	(M2_RSEL),A
	RET


;****************************************************************************
;
;	MESSAGE EDITOR
;	ENTRY-	HL= TEXT PTR (BIT 7= 1: TERMINATOR)
;	EXIT -	REGS= ?
;
;****************************************************************************
EDITOR:	LD	C,(HL)		;MESSAGE EDIT LOOP
	PUSH	HL		;SAVE PTR
	RES	7,C		;CLEAR BIT 7 FOR OUTPUT
	CALL	COC
;
	POP	HL
	BIT	7,(HL)		;IF BIT 7 SET THEN RETURN
	RET	NZ
;
	INC	HL		;ELSE PRINT NEXT CHAR
	JR	EDITOR

  IF	INTRPTS
   IF	P_INT OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
	SUBTTL	INTERRUPTS
;----------------------------------------------------------------------------
;
;	USER INTERRUPT
;
;----------------------------------------------------------------------------
ITRAP:
;
;   SAVE REGS FIRST
;
	PUSH	AF
	PUSH	HL
	PUSH	BC
;
;   SAVE CURRENT ROM & GET MONITOR ROM
;
	IN	A,(M2_RSEL)
	LD	(ROMSAV),A
	CALL	GETMON
;
;   PRINT PROMPT
;
	LD	HL,ITMSG
IQCONT:	CALL	EDITOR
;
	LD	HL,IQMSG	;QUERY USER
	CALL	EDITOR
;
;   GET & ECHO USER INPUT
;
	CALL	CI
;
	PUSH	AF
	LD	C,A
	CALL	COC
	POP	AF
;
;   IF OPTION IS CTRL-C THEN WARM BOOT
;
	CP	A,3		;IF CTRL-C THEN WARM BOOT
	JP	Z,PAGE0
;
;   IF OPTION IS YES THEN WARM BOOT
;
	AND	A,5FH		;IGNORE CASE
;
	CP	A,'Y'
	JP	Z,PAGE0
;
;   IF OPTION IS INTERRUPT THEN EXECUTE RESTART 7
;
	CP	A,'I'
	JR	NZ,ITRAP1
;
	POP	BC		;RESTORE REGS 1ST
	POP	HL
	POP	AF
	JP	0038H
;
;   IF OPTION IS MONITOR THEN EXECUTE MONITOR TRAP
;
ITRAP1:	CP	A,'M'
	JR	NZ,ITRAPR
;
	POP	BC
	POP	HL
	POP	AF
	JP	0F824H
;
;   ELSE RESTORE REGS & RETURN
;
ITRAPR:
	LD	A,(ROMSAV)	;RESTORE ROM #
	OUT	(M2_RSEL),A
;
	POP	BC
	POP	HL
	POP	AF
	EI			;RE-ENABLE INTERRUPTS
	RET


;----------------------------------------------------------------------------
;
;	UNSUPPORTED INTERRUPT
;
;----------------------------------------------------------------------------
ILLINT:
	PUSH	AF		;SAVE ALL 8080 REGS
	PUSH	HL
	PUSH	BC
	LD	HL,ILLIM	;NOTIFY USER OF INT
	JR	IQCONT


	SUBTTL	INITIALIZED DATA
   IF	P_DISK OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
;############################################################################
;
;	3740 SECTOR TRANSLATION TABLE
;	**** CP/M SINGLE DENSITY ****
;
;############################################################################
X3740:	GXLATE	26,6
X3740D:	GXLATE	26,6
XCCS:	GXLATE	8,3
XCCSD:	GXLATE	8,3


;############################################################################
;
;	COMMON I/O PARAMETER BLOCK
;
;############################################################################
IOPB:	REPT	PB_SIZE
	LIST	OFF
	DB	0
	LIST	ON
	ENDM


;############################################################################
;
;	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
	DB	1		;SKEW INDEX


;############################################################################
;
;	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	0		;PHYSICAL RECORD SHIFT FACTOR	(PSH)
	DB	0		;PHYSICAL RECORD MASK		(PHM)
	DB	0		;SKEW INDEX (NONE)


   IF	P_INT OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
;############################################################################
;
;	MODE 2 INTERRUPT VECTOR TABLE
;
;############################################################################
;
;   START ON AN EVEN PAGE BOUNDARY
;
	IF	$ AND 0FFH
	DS	100H - ($ AND 0FFH)
	ENDIF
INTABL:
	REPT	7		;1ST 7 ARE UNSUPPORTED
	LIST	OFF
	DW	ILLINT
	LIST	ON
	ENDM
   IF	P_INT OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
;
	DW	ITRAP		;INT 8 IS USER INTERRUPT


	LIST	ON
;############################################################################
;
;			MESSAGES
;
;############################################################################
MSGLE:	DM	CR,LF,'LOAD ERROR'
;
DSKEM:	DB	CR,LF,'Disk Error Status:'
	DM	CR,LF,'CM DR TL TH SL SH FG AL AH AX CL CH ST S1 S2 S3',CR,LF
DSKEB:	DM	CR,LF,'Abort, Ignore, Retry, (BDOS) - '
;
   IF	INTCPTS
ISCMSG:	DM	CR,LF,'ILL SYS CALL, #= '
   ENDIF
   IF	INTRPTS
ITMSG	DM	CR,LF,'User'
ILLIM	DM	CR,LF,'Ill.'
IQMSG	DM	' Int. Abort? (Y/N/I/M) - '
   ENDIF


   IF	P_DISK OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF
;############################################################################
;
;	DRIVE DATA STRUCTURES POINTER TABLE
;
;############################################################################
DRV_PTRS:
;
ALL_DPHP MACRO	#D
	LIST	ON
	DW	D#D(DD)DPH
	LIST	OFF
	ENDM
;
DD	DL	1
;
	REPT	NDRVS
	ALL_DPHP 0123456789ABCDEF
DD	DL	DD +1
	ENDM
   IF	P_DISK OR P_ALL
	LIST	ON
   ELSE
	LIST	OFF
   ENDIF


;############################################################################
;
;	DRIVE PARAMETER HEADER AREA
;	1 PER DRIVE
;
;############################################################################
;
;   DPH STRUCTURE
;
	STRUCT	-12
;
;   EXTENDED DPH DATA
;
DPHSOFO	DS	2	;SECTOR OFFSET FOR THIS DRIVE
DPHWRTO	DS	2	;ADDRESS OF SECTOR WRITE DRIVER
DPHRDO	DS	2	;ADDRESS OF SECTOR READ DRIVER
DPHLOGO	DS	2	;ADDRESS OF LOGIN DRIVER (NOT USED AT THIS TIME)
DPHINO	DS	2	;ADDRESS OF INIT DRIVER
DPHDRVO	DS	1	;PHYSICAL DRIVE # ASSOCIATED WITH THIS LOGICAL DRIVE
DPHTYPO	DS	1	;DRIVE TYPE BYTE
;
;   REQUIRED (NORMAL) DPH DATA
;
DPHXLTO	DS	2	;ADDRESS OF SECTOR TRANSLATION TABLE (0 FOR DEBLOCKING)
	DS	6	;SCRATCH
   IF	OP_SYS = 2
DPHDIRBO DS	2	;ADDRESS OF DIRECTORY BUFFER
DPHDPBO	DS	2	;ADDRESS OF DPB
DPHCSVO	DS	2	;ADDRESS OF DIRECTORY CHECKSUMS BUFFER
DPHALVO	DS	2	;ADDRESS OF CLUSTER ALLOCATION BIT MAP BUFFER
   ENDIF
   IF	OP_SYS = 3
	DS	3	;ADDITIONAL SCRATCH
DPHMFO	DS	1	;MEDIA FLAG
DPHDPBO	DS	2	;ADDRESS OF DPB
DPHCSVO	DS	2	;ADDRESS OF DIRECTORY CHECKSUMS BUFFER
DPHALVO	DS	2	;ADDRESS OF CLUSTER ALLOCATION BIT MAP BUFFER
DPHDIRBO DS	2	;ADDRESS OF DIRECTORY BUFFER
DPHDTABO DS	2	;ADDRESS OF DATA BUFFER CONTROL BLOCK
DPHHSHO	DS	2	;ADDRESS OF DIRECTORY HASH TABLE BUFFER
DPHHBNKO DS	1	;BANK # OF DIRECTORY HASH TABLE BUFFER
   ENDIF
;
DPHSIZE	EQU	-DPHSOFO + $
	ENDM


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	GENERATE A DISK PARAMETER TABLE MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ALLDPH:	MACRO	#N,#SOFF,#WD,#RD,#LD,#ID,#PD,#DT,#CKS
	LIST	ON
	DW	#SOFF		;;SECTOR OFFSET
	DW	#WD		;;WRITE DRVR
	DW	#RD		;;READ DRVR
	DW	#LD		;;LOGIN DRVR
	DW	#ID		;;INIT DRVR
	DB	#PD		;;PHYSICAL DRIVE #
	DB	#DT
D#NDPH:				;;DRIVE PARAMETER HEADER FOR DRIVE #D(DD)
	DW	0		;;SECTOR TRAN TBL (OR 0 IF NO XLATE)
	DW	0,0,0		;;SCRATCH AREA
	DW	DIRBF		;;DIRECTORY BUFFER PTR
	DW	D#DDPB		;;DRIVE PARAMETER BLK PTR
	DW	#CKS		;;NO CHECKS ON HARD DISK
	DW	D#DALL		;;DRIVE CLUSTER ALLOCATION BIT MAP PTR
	LIST	OFF
	ENDM

;
;   DEFINE THE DATA
;
   IF	BOOT < 10H		;8" FLOPPY BOOT
	ALLDPH	0,0,F8_WR,F8_RD,0,0,0,0,D0CHK
	ALLDPH	1,0,F8_WR,F8_RD,0,0,1,0,D1CHK
	ALLDPH	2,0,H8_WR,H8_RD,0,0,4,10H,0
	ALLDPH	3,80H,H8_WR,H8_RD,0,0,4,10H,0
	ALLDPH	4,0,H8_WR,H8_RD,0,0,5,10H,0
	ALLDPH	5,80H,H8_WR,H8_RD,0,0,5,10H,0
   ELSE
   IF	BOOT < 20H		;8" HARD DISK BOOT
	ALLDPH	0,0,H8_WR,H8_RD,0,0,4,10H,0
	ALLDPH	1,80H,H8_WR,H8_RD,0,0,4,10H,0
	ALLDPH	2,0,H8_WR,H8_RD,0,0,5,10H,0
	ALLDPH	3,80H,H8_WR,H8_RD,0,0,5,10H,0
	ALLDPH	4,0,F8_WR,F8_RD,0,0,0,0,D4CHK
	ALLDPH	5,0,F8_WR,F8_RD,0,0,1,0,D5CHK
   ELSE
   IF	BOOT < 30H		;5" FLOPPY BOOT
	ALLDPH	0,0,F8_WR,F8_RD,0,0,0,0,D0CHK
	ALLDPH	1,0,F8_WR,F8_RD,0,0,1,0,D1CHK
	ALLDPH	2,0,H8_WR,H8_RD,0,0,4,10H,0
	ALLDPH	3,80H,H8_WR,H8_RD,0,0,4,10H,0
	ALLDPH	4,0,H8_WR,H8_RD,0,0,5,10H,0
	ALLDPH	5,80H,H8_WR,H8_RD,0,0,5,10H,0
   ENDIF
   ENDIF
   ENDIF
	LIST	ON

;
;   LAST OF INITIALIZED CODE READ FROM DISK
;
BIOSND	EQU	$

	SUBTTL	UNINITIALIZED DATA AREA
;############################################################################
;
;   VARIABLES
;
;############################################################################
;
;   THE FOLLOWING ITEMS ARE SET BY THE BIOS FUNCTIONS
;
SEK_DSK: DS	1		;LOGICAL DRIVE
SEK_TRK: DS	2		;LOGICAL TRACK NUMBER
SEK_SEC: DS	2		;LOGICAL SECTOR NUMBER

;
;   THE FOLLOWING ARE SET BY THE BUFFER READ/WRITE
;
HST_DSK: DS	1		;BUFFER DISK NUMBER
HST_TRK: DS	2		;BUFFER TRACK NUMBER
HST_SEC: DS	2		;BUFFER SECTOR NUMBER
;
;
SEK_HST: DS	2		;PHYSICAL SECTOR TO XFER

;
;   FLAGS
;
HST_ACT: DS	1		;0: BUFFER FLUSHED, /0: DATA IN BUFFER
HST_WRT: DS	1		;0: BUFFER CLEAN, /0: BUFFER DIRTY (MODIFIED)

;
;   THE FOLLOWING USED BY THE UNALLOCATED BLOCK ALGORITHMS
;
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

;
;
ER_FLAG: DS	1		;ERROR REPORTING 0: OK, /0: ERROR
RS_FLAG: DS	1		;0: NO PREREAD REQ'D, /0: PREREAD REQ'D
READ_OP: DS	1		;0: WRITE OPERATION, 1: READ OPERATION
WR_TYPE: 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)
DMA_ADR: DS	2		;LAST DMA ADDRESS
DMA_BNK DS	1		;LAST DMA BANK
;
HST_BUF: DS	1024		;HOST BUFFER

LOGRQ:	DS	1	;LOG ON REQUEST REG.
ROMSAV	DS	1	;ROM SWAP SAVE OF ORIGINAL ROM

;
;   CURRENT DRIVE DATA
;
CUR_DPH	DS	2	;DPH PTR
CUR_DPB	DS	2	;DPB PTR
CUR_BCB	DS	2	;BCB PTR
CUR_RD	DS	2	;READ DRIVER PTR
CUR_WR	DS	2	;WRITE DRIVER PTR
CUR_XLAT DS	2	;XLATION TABLE PTR (0: NONE)
CUR_SOFF DS	2	;SECTOR OFFSET FOR DRIVE
CUR_DRV	DS	1	;CURRENT PHYSICAL DRIVE #


;############################################################################
;
;   DRIVE ALLOCATION AREAS
;
;############################################################################

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	MACRO TO DEFINE THE DRIVE ALLOCATION & CHECKSUMS AREA
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ALLDAL:	MACRO	#D
	LIST	ON
   IF	((DD - 1) >= STHD) AND ((DD - 1) <= NDHD)
D#D(DD)ALL:	DS	127	;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
DPBSPTO	DS	2	;SPT- SECTORS/TRACK
DPBBSHO	DS	1	;BSH- BLOCK SHIFT FACTOR DETERMINED BY CLUSTER SIZE
			;	1K= 3, 2K= 4, 4K= 5, 8K= 6, 16K= 7
DPBBLMO	DS	1	;BLM- BLOCK MASK
			;	1K = 7, 2K= 15, 4K= 31, 8K= 63, 16K= 127
DPBEXMO	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
DPBDSMO	DS	2	;DSM- DRIVE STORAGE SIZE (IN CLUSTERS)
	;  INT(((#_TRACKS - OFF) * SPT * BYTES PER SECTOR) / CLUSTER SIZE) -1
DPBDRMO	DS	2	;DRM- DIRECTORY SIZE -1
DPBAL0O	DS	2	;AL0,1- DIRECTORY ALLOCATION
			;	1 MSB PER DIRECTORY CLUSTER ALLOCATED
DPBCKSO	DS	2	;CKS- # DIRECTORY SECTORS CHECKED
			;	(DRM +1) / 4
DPBOFFO	DS	2	;OFF- # RESERVED TRACKS (USUALLY 2)
;
;   ADDITIONAL CP/M 3.0 DATA (ALSO COULD BE USED BY CP/M 2.2 DEBLOCKING)
;
DPBPSHO	DS	1	;PSH- PHYSICAL RECORD SHIFT FACTOR BASED ON BYTES/SEC
			;	0: 128, 1: 256, 2: 512, 3: 1024
DPBPHMO	DS	1	;PHM- PHYSICAL RECORD MASK BASED ON BYTES/SEC
			;	0: 128, 1: 256, 3: 512, 7: 1024
;
;   ADDITIONAL UNIQUE DATA. HOPE CP/M 4.X DOES NOT NEED THIS BYTE
;
DPBSKWO	DS	1	;SKW- SKEW INDEX
;				0: NONE, 1:3740, 2:DS3740, 3:CCS1K, 4:DSCCS1K
;
DPBSZ	DS	0
	ENDM
;
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	GENERATE THE DPB FOR DRIVE MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ALLDPB:	MACRO	#D
	LIST	ON
D#D(DD)DPB:	DS	DPBSZ		;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


   IF	$ >= 0F800H
	CONMSG	**** BIOS TOO BIG, USE MOVCPM & RE-ADJUST! ****
   ENDIF

	END
