;********************************************************
;*							*
;*	--  CUSTOM BIOS FOR CP/M VERSION 2.2  --	*
;*							*
;*	Russell Smith       7-October-1980		*
;*							*
;*	LIST DEVICE ADDED 6-DEC-81 BY HERB KOEHL        *
;*							*
;*	LIST DEVICE INITIALIZATION CHANGE TO INCLUDE	*
;*	SIO AUTO ENABLE 27-FEB-82 BY HERB KOEHL		*
;*							*
;*	LIST STATUS CHANGED TO TAKE ADVANTAGE OF 	*
;*	SIO AUTO ENABLE MODE 27-FEB-82 BY HERB KOEHL	*
;*							*
;********************************************************
;
	PSECT	ABS
;
MSIZE	EQU	60		;MEMORY CAPACITY IN KBYTES
MONITR	EQU	0F000H		;BASE OF SYSTEM MONITOR
	
EXTRA	EQU	MSIZE-20
BASE	EQU	.RES.EXTRA*1024-0200H	;BIOS START IS E800 NOW
	
CCP	EQU	.RES.3400H+BASE	;CONSOLE COMMAND PROCESSOR
BDOS	EQU	.RES.3C06H+BASE	;OPERATING SYSTEM ENTRY POINT
CBIOS	EQU	.RES.4A00H+BASE	;BASE OF CUSTOM BIOS
BDOS2	EQU	05H		;I/O FUNCTION VECTOR
	
;
;
;
	ORG	CBIOS
;
	JP	BOOT		;STANDARD JUMP TABLE TO
BVECTR:	JP	WBOOT		;THE SUBROUTINES OF CBIOS
SVECTR:	JP	CONST
IVECTR:	JP	CONIN
OVECTR:	JP	CONOUT
	JP	LIST  		;LIST DEVICE VECTOR
	JP	CONOUT		;PUNCH DEVICE VECTOR
	JP	CONIN		;READER DEVICE VECTOR
	JP	HOME
	JP	SELECT
	JP	SEEK
	JP	SETSEC
	JP	SETPTR
	JP	READ
	JP	WRITE
	JP	LISTST		;LIST DEVICE STATUS VECTOR
	JP	TRANS
;
;
;
BOOT:	CALL	LSTINIT		;INITIALIZE THE LIST DEVICE
	LD	A,080H		;SET IOBYTE TO ALL TTY: EXECPT LST:
	LD	(0003H),A	; IOBYTE 
	LD	HL,SIGNON
	CALL	PMSG		;PRINT SIGNON MESSAGE
	JR	GOCPM-$
;
;
WBOOT:	LD	SP,STACK
	LD	C,0
	CALL	SELECT		;SELECT UNIT 0
	CALL	HOME		;SEEK TRACK ZERO
	LD	HL,.RES.3400H+BASE
	LD	BC,0D02H
	CALL	RDLOOP		;READ EVEN SECTORS ON TRK 0
	LD	HL,.RES.3480H+BASE
	LD	BC,0C03H
	CALL	RDLOOP		;READ ODD SECTORS ON TRK 0
	LD	C,1
	CALL	SEEK		;SEEK TO TRACK 1
	JR	NZ,BOMB-$
	LD	HL,.RES.4080H+BASE
	LD	BC,0A01H	
	CALL	RDLOOP		;READ ODD SECTORS ON TRK 1
	LD	HL,.RES.4100H+BASE
	LD	BC,0902H
	CALL	RDLOOP		;READ EVEN SECTORS ON TRK 1
GOCPM:	LD	A,0C3H		;STORE JUMP VECTORS IN RAM
	LD	(00H),A
	LD	HL,CBIOS+3	;JUMP TO CBIOS WARM BOOT AT 00H
	LD	(01H),HL
	LD	(05H),A
	LD	HL,BDOS		;JUMP TO BDOS GOES AT 05H
	LD	(06H),HL
	LD	(38H),A
	LD	HL,MONITR	;JUMP TO MONTR GOES AT 38H
	LD	(39H),HL
	LD	BC,0080H
	CALL	SETPTR		;MAKE DISK BUFFER=0080H
	LD	C,0
	JP	CCP
;
;
RDLOOP:	LD	(POINTR),HL	;STORE ADDR. PASSED IN HL
	LD	A,C
	LD	(SECTOR),A	;STORE SECT# PASSED IN C
	PUSH	HL
	PUSH	BC
	CALL	READ		;READ THE SPECIFIED SECTOR
	POP	BC
	POP	HL
	JR	NZ,BOMB-$
	INC	H		;BUMP LOAD ADDRESS BY 256
	INC	C
	INC	C		;BUMP SECTOR# BY 2
	DJNZ	RDLOOP-$
	RET
;
;
BOMB:	LD	HL,DEAD
	CALL	PMSG
LOOP:	JP	LOOP

DEAD:	DEFB	CR,LF
	DEFM	'cannot boot CP/M $'
;
;
;
CONST:	JP	MONITR+6	;MONITOR CONSOLE STATUS RTN.
;
;
CONIN:	JP	MONITR+9	;MONITOR CONSOLE INPUT RTN.
;
;
CONOUT:	LD	A,C
	JP	MONITR+12	;MONITOR CONSOLE OUTPUT RTN.
;
;	**** CPM LIST DEVICE INITIALIZATION AND HANDELER **** 12/05/81
;
;
;		SPECIAL PARAMETERS
;
BAUD	EQU	00H		;CHANNEL A BAUD RATE GENERATOR PORT NUMBER
SPEED	EQU	07H		;1200 BAUD
;
ASIDAT	EQU	04H		;SERIAL CHANNEL A DATA
ASICON	EQU	06H		;SERIAL CHANNEL B CONTROL
;
;

LSTINI:	EQU	$
	LD	A,SPEED		;FIRST SET THE BAUD RATE GENERATOR!!
	OUT	(BAUD),A

	LD	HL,LSTTAB	;POINT TO LIST SIO INITIALIZATION TABLE
	LD	B,08		;LOAD THE LENGHT OF THE BLOCK INTO B
	LD	C,ASICON	;REG. C POINTS TO THE PORT.
	OTIR

	RET			;INITILIZATION IS FINISHED RETURN TO WHO CALLED
;
;
;	***** LIST DEVICE STATUS ROUTINE ****
;

LISTST:	EQU	$
	IN	A,(ASICON)	;CHECK THE STATUS OF THE FLAGS IN READ REG. 0
	BIT	2,A		;TRANSMITTER BUFFER READY??
	JR	Z,LSTST2	;JUMP IF XMITTER BUFFER NOT READY

	XOR	A
	JR	LSTST3

LSTST2:	EQU	$
	LD	A,0FFH		;MAKE STATUS BUSY...

LSTST3:	EQU	$
	LD	B,A
	LD	A,010H		;RESET THE SIO FLAGS
	OUT	(ASICON),A
	LD	A,B
	RET


;
;
;
;
;	***** SIO LIST DRIVER *****
;

LIST:	EQU	$
	CALL	LISTST		;GET THE LIST STATUS
	AND	A		;UPDATE PROCESSOR FLAGS
	JR	NZ,LIST		;CALL AGAIN IF NOT READY

	LD	A,C		;MOVE THE CHARACTER FOR C TO A
	OUT	(ASIDAT),A	;SEND IT......
	RET
;
;
;
;	***** SIO INITIALIZATION TABLE ****
;
;
LSTTAB:	EQU	$
	DEFB	04H		;WRITE REG. 4
	DEFB	44H		;16X CLOCK, ONE STOP BIT, NO PARITY
	DEFB	01H		;WRITE REG. 1
	DEFB	00H		;ZERO IT
	DEFB	03H		;WRITE REG. 3
	DEFB	0E1H		;ENABLE 8 BITS / WORD AND AUTO ENABLES
	DEFB	05H		;WRITE REG. 5
	DEFB	0EAH		;DTR, 8 BITS / WORD, XMIT,RTS : ENABLED

;
;
;
;********************************************************
;*							*
;*	DISK I/O SUBROUTINES FOR CP/M CBIOS		*
;*							*
;********************************************************
;
;
;	SECTOR TRANSLATE TABLE FOR STANDARD
;	1 IN 6 INTERLEAVE FACTOR
;
SECTAB:	DEFB	1,7,13,19
	DEFB	25,5,11,17
	DEFB	23,3,9,15
	DEFB	21,2,8,14
	DEFB	20,26,6,12
	DEFB	18,24,4,10
	DEFB	16,22
;
;
;	DISK PARAMETER BLOCK FOR STANDARD 8" FLOPPY
;
DPBLK:	DEFW	26		;SECTORS PER TRACK
	DEFB	3		;BLOCK SHIFT CONST.
	DEFB	7		;BLOCK MASK CONST.
	DEFB	0		;EXTENT MASK CONST.
	DEFW	242		;MAX BLOCK#
	DEFW	63		;MAX DIRECTORY ENTRY#
	DEFB	11000000B	;ALLOCATION MASK MSB
	DEFB	00000000B	;'             ' LSB
	DEFW	16		;CHECK SIZE
	DEFW	2		;RESERVED TRACKS
;
;
;	DISK PARAMETER HEADERS FOR A 4 DISK SYSTEM
;
DPHTAB:	DEFW	SECTAB,0000H	;DPH FOR UNIT 0
	DEFW	0000H,0000H
	DEFW	DIRBUF,DPBLK
	DEFW	CHK0,ALL0
 
	DEFW	SECTAB,0000H	;DPH FOR UNIT 1
	DEFW	0000H,0000H
	DEFW	DIRBUF,DPBLK
	DEFW	CHK1,ALL1
 
	DEFW	SECTAB,0000H	;DPH FOR UNIT 2
	DEFW	0000H,0000H
	DEFW	DIRBUF,DPBLK
	DEFW	CHK2,ALL2
 
	DEFW	SECTAB,0000H	;DPH FOR UNIT 3
	DEFW	0000H,0000H
	DEFW	DIRBUF,DPBLK
	DEFW	CHK3,ALL3
;
;
;
;
SETSEC:	LD	A,C
	LD	(SECTOR),A	;STORE SECTOR NUMBER PASSED
	RET			; VIA BC
;
;
TRANS:	EX	DE,HL		;ADD TRANSLATION TABLE ADDRESS
	ADD	HL,BC		; PASSED IN DE TO SECTOR# IN BC
	LD	L,(HL)
	LD	H,0		;LOOKUP PHYSICAL SECTOR NUMBER
	RET			; AND RETURN IT IN HL
;
;
SETPTR:	LD	(POINTR),BC	;STORE DATA POINTER PASSED
	RET			; VIA BC
;
;
;
SELECT:	LD	HL,0		;PREP TO CHECK FOR MAX UNIT#
	LD	A,C
	CP	4
	RET	NC		;RETURN WITH HL=0 IF C > 3
	LD	(UNIT),A	;STORE C AS NEW DRIVE UNIT#
	LD	L,A
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL		;MULTIPLY UNIT# BY 16
	LD	DE,DPHTAB
	ADD	HL,DE		;ADD START ADDRESS OF DHP BLOCK
	PUSH	HL
	LD	C,A		;LOAD C WITH DISK DRIVE NUMBER
	LD	B,0		;LOAD B WITH SEEK SPEED FOR THIS DRIVE
	CALL	MONITR+27	;CALL SELECT ROUTINE IN MONITOR
	POP	HL
	RET	Z		;EXIT IF SELECTED SUCCESSFULY
	LD	C,1
	CALL	REPORT
	JR	NZ,SEL2-$	;JUMP IF COMMAND ABORT INDICATED
	LD	A,(UNIT)	;ELSE TRY TO SELECT THE DRIVE AGAIN
	LD	C,A
	JR	SELECT-$

SEL2:	LD	HL,0		;DISABLE FURTHER BIOS CALLS BY
	RET			; INDICATING SELECT ERROR TO BDOS
;
;
;
HOME:	CALL	MONITR+30	;CALL HOME ROUTINE IN MONITOR
	RET	Z		;RETURN IF ALL WENT WELL
	LD	C,2
	CALL	REPORT
	JR	Z,HOME-$	;RE-TRY HOME IF ERROR INDICATED
	RET
;
;
SEEK:	LD	A,C		;GET TRACK # FROM C
	LD	(TRACK),A
	CALL	MONITR+33	;CALL SEEK ROUTINE IN MONITOR
	RET	Z		;EXIT IF NO ERRORS INDICATED
	LD	C,2
	CALL	REPORT		;REPORT SEEK ERROR TO CONSOLE
	RET	NZ		;RETURN PERMANENT ERROR UNLESS
	LD	A,(TRACK)	; RE-TRY REQUEST IS INDICATED
	LD	C,A
	JR	SEEK-$
;
;
;
READ:	LD	HL,(POINTR)
	LD	A,(SECTOR)
	LD	C,A
	CALL	MONITR+36	;CALL READ ROUTINE IN MONITOR
	RET	Z		;RETURN IF NO ERRORS
	LD	C,3		;INDICATE READ ERROR TO HANDLER
	CALL	REPORT		;REPORT DISK ERROR TO CONSOLE
	JR	Z,READ-$	;RE-TRY READ IF INDICATED
	RET
;
;
;
WRITE:	LD	HL,(POINTR)
	LD	A,(SECTOR)
	LD	C,A
	CALL	MONITR+39	;CALL WRITE ROUTINE IN MONITOR
	RET	Z		;RETURN IF NO ERRORS
	LD	C,4		;INDICATE WRITE ERROR TO HANDLER
	CALL	REPORT		;REPORT DISK ERROR TO CONSOLE
	JR	Z,WRITE-$	;RE-TRY WRITE IF INDICATED
	RET			;ELSE RETURN PERMANENT ERROR
;
;
REPORT:	LD	(FLAGS),A	;STORE 1771 I/O STATUS FLAGS
	LD	A,C
	LD	(CLASS),A	;STORE COMMAND CLASS OF ERROR
	LD	HL,DSKMSG
	CALL	PMSG		;PRINT OUT START OF MESSAGE
	DEC	HL
	LD	A,(CLASS)
	LD	B,A
REP1:	CALL	SKIP		;SKIP TO NEXT '$' IN STRING @ HL
	DJNZ	REP1-$
	CALL	PMSG		;PRINT STRING NOW POINTED TO BY HL
	LD	HL,ERRMSG
	CALL	PMSG		;PRINT 'error  ' AFTER TYPE
	LD	A,(FLAGS)
	RLA			;TEST FIRST FOR DRIVE-NOT-READY ERROR
	JR	C,REP8-$	; AND JUMP IF THAT IS THE PROBLEM
	LD	E,A		;GET REMAINING 1771 ERROR BITS INTO E
	LD	HL,RWERRS
	LD	A,(CLASS)
	CP	3		;DETERMINE IF SELECT/SEEK OF R/W ERROR
	JR	NC,REP2-$
	LD	HL,SKERRS	;POINT HL TO PROPER SET OF MESSAGES
REP2:	LD	B,5
	RES	0,D
REP4:	SLA	E		;SHIFT OUT A 1771 STATUS REG BIT
	JR	NC,REP5-$
	LD	C,','
	BIT	0,D
	CALL	NZ,OVECTR	;PRINT COMMA BETWEEN STRINGS IF D=1
	CALL	PMSG		;THEN PRINT ERROR MESSAGE @ HL
	SET	0,D		;FLAG THAT A STRING WAS PRINTED
	JR	REP6-$

REP5:	CALL	SKIP		;SKIP TO NEXT STRING @ HL
	RES	0,D		;FLAG THAT A STRING WAS SKIPPED
REP6:	DJNZ	REP4-$		;REPEAT FOR ALL 5 POSSIBLE ERRORS
	LD	HL,TSMSG
	CALL	PMSG		;PRINT TRACK/SECTOR# HEADER
	LD	A,(TRACK)
	CALL	PUT2HX		;PRINT TRACK# IN HEX
	LD	C,'/'
	CALL	OVECTR
	LD	A,(SECTOR)
	CALL	PUT2HX
REP7:	LD	A,1
	OR	A		;RETURN PERM ERROR INDICATION IN A
	RET
;
REP8:	LD	HL,RDYMSG
	CALL	PMSG		;PRINT DISK-NOT-READY MESSAGE
	CALL	IVECTR		; AND WAIT FOR CONSOLE INPUT
	CP	'C'-64
	JR	Z,REP7-$
	XOR	A		;RETURN A=0 IF SOMETHING OTHER THAN
	RET			; CONTROL-C WAS TYPED AT THE CONSOLE
;
SKIP:	PUSH	BC		;SAVE BC
	LD	B,255
	LD	A,'$'
	CPIR			;SCAN MEMORY LOOKING FOR '$'
	POP	BC
	RET
;
;
;
;	CHARACTER STRING OUTPUT ROUTINE. PRINTS ASCII DATA
;	POINTED TO BY HL UNTIL A DOLLAR SIGN IS ENCOUNTERED

PMSG:	EQU	$
	LD	A,(HL)		;PRINT MESSAGE POINTED TO BY HL...
	CP	'$'		;IF THE CHARACTER IS A DOLLER THEN WE ARE AT THE END
	INC	HL
	RET	Z
	LD	C,A		;PRINT CHARACTER
	CALL	OVECTR
	JR	PMSG-$


;****** NOTE! I TRYED TO MAKE PMSG MORE EFFICIENT BY CALLING
;       A CPM ROUTINE BUT IT DOESN'T SEEM TO WORK HERE
;       EX	DE,HL		;GET MESSAGE VECTOR IN DE FOR CPM CALL
;	LD	C,09H		;BDOS FUNCTION 9 IS PRINT STRING
;	CALL	BDOS2
;	RET



PUT2HX:	PUSH	AF
	RRA
	RRA
	RRA
	RRA
	CALL	PUTNIB
	POP	AF
PUTNIB:	AND	00001111B
	ADD	A,90H
	DAA
	ADC	A,40H
	DAA
	LD	C,A
	CALL	OVECTR		;PRINT A HEX-ASCII CHARACTER
	RET
;
;
;	
LF	EQU	0AH		;LINE FEED
CR	EQU	0DH		;CARRIAGE RETURN
	
DSKMSG:	DEFB	CR,LF
	DEFM	'bios $'
	DEFM	'select $'
	DEFM	'seek $'
	DEFM	'read $'
	DEFM	'write $'

ERRMSG:	DEFM	'error  $'
	
SKERRS:	DEFM	'$'
	DEFM	'$'
	DEFM	'cannot seek$'
	DEFM	'bad crc$'
	DEFM	'cannot restore$'

RDYMSG:	DEFM	'drive not ready -$'

RWERRS:	DEFM	'write protected$'
	DEFM	'write fault$'
	DEFM	'record not found$'
	DEFM	'bad crc$'
	DEFM	'data overrun$'

TSMSG:	DEFM	'  trk/sect = $'

SIGNON:	DEFB	CR,LF
	DEFM	'60K CP/M 2.2'
	DEFB	CR,LF
	DEFM	'|LIST: 0.2|  27-FEB-82'
CRLF:	DEFB	CR,LF
	DEFM	'$'
;
;
UNIT:	DEFS	1
TRACK:	DEFS	1
SECTOR:	DEFS	1
POINTR:	DEFS	1
FLAGS:	DEFS	1
CLASS:	DEFS	1
	DEFS	32
STACK:	DEFS	1		;LOCAL STACK FOR WARM BOOT
;
;********************************************************
;*							*
;*	DISK I/O BUFFERS FOR BDOS FILE HANDLER		*
;*							*
;********************************************************
;
;
;
DIRBUF:	DEFS	128		;SCRATCH DIRECTORY BUFFER
;
ALL0:	DEFS	32		;UNIT 0 ALLOCATION BUFFER
CHK0:	DEFS	16		;UNIT 0 CHECK VECTOR
ALL1:	DEFS	32		;UNIT 1 ALLOCATION VECTOR
CHK1:	DEFS	16		;UNIT 1 CHECK VECTOR
ALL2:	DEFS	32		;UNIT 2 ALLOCATION VECTOR
CHK2:	DEFS	16		;UNIT 2 CHECK VECTOR
ALL3:	DEFS	32		;UNIT 3 ALLOCATION VECTOR
CHK3:	DEFS	16		;UNIT 3 CHECK VECTOR
;
;
;
;
;
	END
