MEMSZ	EQU	64		  ;
BIOSSZ	EQU	01C00H		  ; ncr biossz = 8 k
VERS	EQU	04		  ;
;****************************************************************
;*
;* module name = ncrbios.asm
;* descriptive name = ncr bios for sb/80 os
;* copyright (c) = 1982, lifeboat associates, inc.
;* author = mark l. rollins, emil sturniolo
;*	    marty gindi, bob halsall,Seth Goldstein, Jethro Wright, III
;* date written = 15/dec/80
;*
;* change activity =
;*   11/30/82 JW3    v.05	chg tot dsk space from 486k -> 481k per NCR req 24 nov 82
;*   10/14/82 ES,JW3 v.04	fix biosfun,read after write,spmode
;*   08/05/82 scg		put in interupt driven serial printer
;*   06/16/82 mlr    v.03	put in intvctr
;*   04/26/82 mlr,es v.02	make it work in germany
;*   03/06/82 mlr    v.01	setup for sb80
;*   03/06/82 rh,mg  v.00	make it work
;*
;*   release = r.04
;*   date = 16/jun/82
;*
;* environment =
;*   processor = mac (dig.rsrch)
;*
;****************************************************************

	PAGE
;****************************************************************
;*								*
;*			SWITCHES				*
;*								*
;****************************************************************


MSIZE	EQU	00 		  
OVHD	EQU	0800H		; DIFF TO MDS
MEAT	EQU	0680H		; LENGTH OF BIOS CODE
USRSIZ	EQU	0200H		; LENGTH OF USER AREA
CRAM	EQU	0		; CP/M RAM BASE
CPVER	EQU	2		; DIGITAL RESEARCH VERS
SBVER	EQU	6
RELEASE	EQU	0		




	MACLIB	DISKDEF		; LOAD THE DISK DEFINITION LIBRARY



;****************************************************************
;*								*
;*		RELOCATION PARAMETERS				*
;*								*
;****************************************************************


;REL1	ORG	0		;NEEDED FOR MAC $+R
;BIAS	SET	(MSIZE-20)*1024+CRAM-OVHD
;	IF MSIZE EQ 0
;BIAS	SET -3400H+REL1+CRAM	;REL0 BIAS
;	ENDIF

	PAGE
;****************************************************************
;*								*
;*			SB/80 EQUATES				*
;*								*
;****************************************************************


FALSE	EQU	0
TRUE	EQU	NOT FALSE

BKPRT	EQU	TRUE		  ;
NOBKP	EQU	NOT BKPRT

TOFMEM	EQU	MEMSZ*1024	  ;
BIOS	EQU	TOFMEM-BIOSSZ	  ;

	IF	BKPRT
DOSSZ	EQU	1400H		  ; THIS IS CONDITIONAL
	ELSE
DOSSZ	EQU	1000H		  ; THIS IS CONDITIONAL
	ENDIF


CLISZ	EQU	1000H

DOS	EQU	BIOS-DOSSZ	  ;
CLI	EQU	DOS-CLISZ	  ;


DOSNTRY	EQU	DOS+6
DOSTBL	EQU	DOSNTRY+3

CLISTB	EQU	CLI+3		  ; NO AUTO LD ENTRY TO CLI

CLIVAD	EQU	CLI+8AH		  ; ADDR OF CLI VERS STRING
DOSVAD	EQU	DOSTBL+2	  ; ADDR OF DOS VERS STRING

USER	EQU	BIOS+MEAT	  ;
OFFST	EQU	1100H-CLI	  ; SYSGEN OFFSET

INIBPFN	EQU	136
LDCLIFN	EQU	137

	PAGE
;****************************************************************
;*								*
;*		MISCELLAENOUS EQUATES				*
;*								*
;****************************************************************


TESTING	EQU	FALSE
BDOS$RESET	EQU	TRUE
IOBYTE	EQU	CRAM+3		;INTEL I/O BYTE
CDISK	EQU	CRAM+4		;CURRENT DISK NUMBER
CR	EQU	0DH
LF	EQU	0AH
BS	EQU	08H
FF	EQU	0CH
TOF	EQU	0CH
ESC	EQU	1BH
CLRSCN	EQU	01AH
PARAMS	EQU	FALSE		; NO PARAMETER TABLE


;****************************************************************
;*
;*	NCR EQUATES
;*
;****************************************************************


NCRKBDI	EQU	0FC2BH			; ADDR OF KEYBD DISABLE INTERRUPTS


	PAGE
;****************************************************************
;*
;*	PUT SIGNON MSG & TEXT IN DOS AT BIOS-80H
;*
;****************************************************************


SOMSG:
	DB	CLRSCN
	DB	CR,LF
	DB	'SB-80 for NCR 9010'
	DB	CR,LF
	DB	(MEMSZ/10)+'0',(MEMSZ MOD 10)+'0','K Version '
	DB	CPVER+'0','.',SBVER+'0',RELEASE+'0'
	DB	CR,LF
	DB	'Fix Disk Version 1.8 WF 1985 '
	DB	CR,LF,'$'

SIGNON:
	LXI	H,SOMSG
TEXT:
	MOV	A,M
	CPI	'$'
	RZ
	MOV	C,A
	PUSH	H
	CALL	VCONOUT
	POP	H
	INX	H
	JMP	TEXT

SOFILL	EQU	80H-($-SOMSG)	  ; SIGNON FILL FOR RELOCATION
	DS	SOFILL

	PAGE
;****************************************************************
;*								*
;*		BIOS BEGINS HERE				*
;*								*
;****************************************************************





JCBOTE:	JMP	KCBOTE
JWBOTE:	JMP	KWBOTE
	JMP	VCONST
	JMP	VCONIN
	JMP	KCONOUT
	JMP	VLIST
	JMP	VPUNCH
	JMP	VREADER
	JMP	KHOME
	JMP	KSELDSK
	JMP	KSETTRK
	JMP	KSETSEC
	JMP	KSETDMA
	JMP	KREAD
	JMP	KWRITE
	JMP	VLISTST
	JMP	KSECTRAN
	JMP	BIOSFUN
BIORES:	DB	0000H		; RESULT OF STATUS FROM DISK
				; CMD TO BE PASSED BACK TO THE 
				; FORMAT PROGRAM


	PAGE
;****************************************************************
;*								*
;*	INITIALIZE SB/80 DOS RESET FN INTERCEPT			*
;*								*
;****************************************************************

INITRST:
	LHLD	DOSTBL		; GET ADDR OF BEG OF DOS FN TBL
	LXI	D,(13*2)	; OFFSET TO FN 13 (DISK RESET)
	DAD	D		; <DE> NOW PTS TO FN 13 ADDR
	PUSH	H		; SAVE PTR FOR LATER
	MOV	E,M		; GET ACTUAL ADDR,
	INX	H
	MOV	D,M
	XCHG			;   & PUT IN <HL>
	SHLD	DRSADR		; STORE IN OUR DOS RST ADDR IN WS
	LXI	D,BRESET	; THEN PT TO OUR EQUIV ROUTINE
	POP	H
	MOV	M,E
	INX	H
	MOV	M,D
	RET


;****************************************************************
;*								*
;*	SB/80 DOS RESET FUNCTION INTERCEPT
;*								*
;****************************************************************

BRESET:
	CALL	WRESET		; PERFORM WARM RESET
	LHLD	DRSADR		; GET DOS RESET FN ADDR,
	PCHL			;   & EXECUTE

DRSADR:	DW	00		; WS WORD FOR DOS RESET FN ADDR

	PAGE
;****************************************************************
;*								*
;*	KCBOTE	COLD START					*
;*								*
;****************************************************************


KCBOTE:				; COLD BOOT ENTRY
	XRA	A
	STA	NCRKBDI		; DISABLE KEYBOARD INTERRUPTS
	DI
	LXI	SP,100H

	CALL	RESET		; INITIALIZE RAM

	CALL	INITMDSK	; INITIALIZE MEMORY DISK

	CALL	READDOS		; READ IN SB/80 DOS

	CALL	INITRST		; INITIALIZE DOS RESET FN

	CALL	VCINIT		; INITIALIZE I/O
	CALL	SIGNON

	MVI	C,INIBPFN	; INITIALIZE BACKGROUND PRINT
	CALL	DOSNTRY
	XRA	A		; INIT CURDRV & ACCUMULATOR FOR COLD BOOT
	STA	CDISK
	JMP	GOSB80



;****************************************************************
;*								*
;*	KWBOTE	WARM START					*
;*								*
;****************************************************************


KWBOTE:				; WARM BOOT ENTRY
	LXI	SP,100H
	CALL	WRESET
	MVI	A,0FFH		; INIT ACCUMULATOR FOR WARM BOOT,
				;   & FALL THRU
	PAGE
;****************************************************************
;*								*
;*	GOSB80	PAGE 0 INITIALIZATION				*
;*								*
;****************************************************************


GOSB80:
	ORA	A		; SET Z FLAG IF COLD START
	PUSH	PSW		; SAVE Z FLAG

	MVI	A,0C3H		; <JMP> OPCODE
	STA	CRAM		; STORE
	STA	CRAM+5		;  JMP

	LXI	H,BIOS+3	; STORE ADDR OF
	SHLD	CRAM+1		;  WARM BOOT ENTRY

	LXI	H,DOSNTRY	; STORE ADDR OF
	SHLD	CRAM+6		;  DOSNTRY

	LDA	CDISK
	MOV	E,A 		; LOGGED-IN DISK
	MVI	C,LDCLIFN	; FN TO LOAD CLI
	CALL	DOSNTRY		;   (RETURNS W/DRV IN <C>)

	POP	PSW		; RESTORE Z FLAG
	LDA	MODE1		; GET MODE BYTE
	RRC			; AUTO ON COLD BOOT
	JZ	GOC2		; COLD BOOT JUMP AND USE PREVIOUS BIT
	RRC			
GOC2:	JNC	CLI+3		; CLEAR AUTO ( AUTO NOT SET FOR EITHER IF NC)
	JMP	CLI		; IS A CARRY SO DO AUTO BOOT

	PAGE
;****************************************************************
;*								*
;*	 READDOS	READ DOS IN				*
;*								*
;*		NOTE:	DOS STARTS AT TRK 2, SCTR 1 FOR 30	*
;*			SECTORS, AND CONTINUES AT TRK 2, SCTR	*
;*			33 FOR 10 SECTORS, FOR A TOTAL LENGTH	*
;*			OF 1400H (40 CPM SECTORS).  (NCR ROM	*
;*			REQUIRES TRK 2, SCTRS 31,32 FOR IPL	*
;*			CHECKSUM PROCESSING.)			*
;*								*
;****************************************************************

READDOS:
	MVI	C,0		; SELECT
	CALL	KSELDSK		; DRIVE 0

	MVI	C,2		; READ TRACK 1
	CALL	KSETTRK
	LXI	B,(30 SHL 8) + 1
	LXI	H,DOS			; READ IN DOS1
	CALL	CPRD1

	LXI	B,(10 SHL 8) + 33
	LXI	H,DOS+(30 * 80H)	; READ IN DOS2

	; FALL THRU TO CPRD1

CPRD1:	PUSH	B
	PUSH	H
	SHLD	DMAADR		; SET DMA ADDRESS
	CALL	KSETSEC		; SETUP SECTOR
	CALL	KREAD		; READ SECTOR
	POP	H
	POP	B
	INR	C		; BUMP SECTOR COUNT
	LXI	D,80H
	DAD	D		; BUMP DMA ADDRESS
	DCR	B
	JNZ	CPRD1
	RET

	PAGE
;****************************************************************
;*								*
;*	BIOS FUNCTION DISPATCHER				*
;*								*
;****************************************************************


BIOSFUN:
	MOV	A,C
	ADD	A
	LXI	H,BFNTBL	; POINT TO FUNCTION ADDRESS TABLE
	CALL	OFFSET		; OFFSET INTO TABLE
	MOV	A,M		; GET LO BYTE
	INX	H
	MOV	H,M		; GET HI BYTE
	MOV	L,A		; LO BYTE TO [A]
	PCHL

;
; NOTE:  BFNTBL CAN BE FOUND JUST AFTER TABLES FOLLOWING MAREA
;

	PAGE
;****************************************************************
;*								*
;*		PARAMETER PASSING ROUTINES			*
;*								*
;****************************************************************


KSELDSK:
	MOV	A,C		; GET DRIVE #
	STA	CLRFLG
	ANI	07FH		; NO CLRFLG
	LXI	H,NUMMDSK
	CMP	M
	JNC	SELERR
	STA	SEKDSK		; SAVE SELECTED DISK
	CPI	2
	JNC	KSELDSK1
	CALL	MOUNT		; MOUNT DISK
	JNZ	SELERR
GETDPH:	LDA	SEKDSK
	ADD	A		; * 2
	ADD	A		; * 4
	ADD	A		; * 8
	ADD	A		; * 16
	LXI	H,DPBASE
	JMP	OFFSET		; GET OFFSET INTO [HL]
KSELDSK1:
	CPI	4
	JZ	KSELDSK2
	CALL	MOUNTH
	JMP	GETDPH
KSELDSK2:
	CALL	MOUNTM
	JMP	GETDPH

SELERR:				; SELECT ERROR
	LXI	H,0		;RET ERROR CODE
	XRA	A
	STA	CDISK
	RET

;****************************************************************
;*
;*	NOTE:	THE REST OF THE PARAMETER PASSING ROUTINES CAN
;*		BE FOUND JUST AFTER THE TABLES FOLLOWING MAREA
;*		IN THIS LISTING

	PAGE
;****************************************************************
;*								*
;*	MAREA:	       MODE AREA				*
;*								*
;****************************************************************

MAREA	EQU	$		  ; MODE AREA

NUMDVS:	DB	2		; NUMBER OF DRIVES ON THE SYSTEM
IOCONF:	DB	10$01$01$01B	; SET INITIAL IOBYT FOR LST:=LPT:
DTRIES:	DB	5		; 5 RETRIES/LOOP
DLOOPS:	DB	5		; 5 LOOPS (RESTORE PERFORMED AFTER EA LOOP)

BPIOB:	DB	00$00$00$10B	; SET INITIAL BKPRT:=UL1: (USING BITS 0/1)
	;		 00B = SERIAL PRINTER
	;		 01B = UNUSED
	;		 10B = P1 PARALLEL PRINTER
	;		 11B = P2 PARALLEL PRINTER
		; PRINTER PORT ADDRS MAY BE EXCHANGED BETW 0FC30H & 0FDD0H
P1PORT:	DW	0FC30H		; PRINTER 1 (6441) PORT ADDR // P1-P2 ADDRS MAY
P2PORT:	DW	0FC30H		; PRINTER 2 (4504) PORT ADDR //  BE XCHANGED

P2DREG:	DB	0B5H		; P2 DATA REG (B5=CONT FORM FEED; B6=CUT FORM;
				;	       B7=BAR CODE)
BCNCHR:	DB	0		; BAR CODE NUMBER OF CHARACTERS

LFTMRG:	DB	1
RTMRG:	DB	145
PITCH:	DB	10		; CAN ALSO BE 12
LPI:	DB	6		; LINES PER INCH
LOGTOP:	DB	6		; # LINES AT TOP OF PG
LINEMAX: DB	60		; MAX # PRINTABLE LINES ON PG
LOGBOP:	DB	6		; # LINES AT BOTTOM OF PG
SPINST:	DB	000H		; SER PORT INSTALLATION CONDITIONAL
SPMODE:	DB	08AH		; SERIAL PORT PARAMETERS (FUNC 1 )
VERIFY:	DB	1		; READ AFTER WRITE SELECT VARIABLE
MAFILL	EQU	20H-($-MAREA)-1   ; FILL FOR 32 BYTES(-1 FOR MODE1)
	DS	MAFILL
NOTUSED EQU	0		;CODE FOR UNUSED TABLE ENTRY
MODE1:	DB	1		  ; SET TO AUTO ON COLD BOOT
NUMHDSK	DB	4
NUMMDSK	DB	5
	PAGE
;****************************************************************
;*								*
;*		  KEYBOARD TRANSLATE TABLE			*
;*								*
;****************************************************************


KEYTBL:
	DB	00H		; 
	DB	01H		; 
	DB	02H		; 
	DB	03H		; 
	DB	04H		; 
	DB	05H		; 
	DB	06H		; 
	DB	07H		; 
	DB	08H		; 
	DB	09H		; 
	DB	0AH		; 
	DB	0BH		; 
	DB	0CH		; 
	DB	0DH		; 
	DB	0EH		; 
	DB	0FH		; 
	DB	10H		; 
	DB	11H		; 
	DB	12H		; 
	DB	13H		; 
	DB	14H		; 
	DB	15H		; 
	DB	16H		; 
	DB	17H		; 
	DB	18H		; 
	DB	19H		; 
	DB	1AH		; 
	DB	1BH		; 
	DB	1CH		; 
	DB	1DH		; 
	DB	1EH		; 
	DB	1FH		; 

	DB	20H		; 
	DB	21H		; 
	DB	22H		; 
	DB	23H		; 
	DB	24H		; 
	DB	25H		; 
	DB	26H		; 
	DB	27H		; 
	DB	28H		; 
	DB	29H		; 
	DB	2AH		; 
	DB	2BH		; 
	DB	2CH		; 
	DB	2DH		; 
	DB	2EH		; 
	DB	2FH		; 
	DB	30H		; 
	DB	31H		; 
	DB	32H		; 
	DB	33H		; 
	DB	34H		; 
	DB	35H		; 
	DB	36H		; 
	DB	37H		; 
	DB	38H		; 
	DB	39H		; 
	DB	3AH		; 
	DB	3BH		; 
	DB	3CH		; 
	DB	3DH		; 
	DB	3EH		; 
	DB	3FH		; 

	DB	40H		; 
	DB	41H		; 
	DB	42H		; 
	DB	43H		; 
	DB	44H		; 
	DB	45H		; 
	DB	46H		; 
	DB	47H		; 
	DB	48H		; 
	DB	49H		; 
	DB	4AH		; 
	DB	4BH		; 
	DB	4CH		; 
	DB	4DH		; 
	DB	4EH		; 
	DB	4FH		; 
	DB	50H		; 
	DB	51H		; 
	DB	52H		; 
	DB	53H		; 
	DB	54H		; 
	DB	55H		; 
	DB	56H		; 
	DB	57H		; 
	DB	58H		; 
	DB	59H		; 
	DB	5AH		; 
	DB	5BH		; 
	DB	5CH		; 
	DB	5DH		; 
	DB	5EH		; 
	DB	5FH		; 

	DB	60H		; 
	DB	61H		; 
	DB	62H		; 
	DB	63H		; 
	DB	64H		; 
	DB	65H		; 
	DB	66H		; 
	DB	67H		; 
	DB	68H		; 
	DB	69H		; 
	DB	6AH		; 
	DB	6BH		; 
	DB	6CH		; 
	DB	6DH		; 
	DB	6EH		; 
	DB	6FH		; 
	DB	70H		; 
	DB	71H		; 
	DB	72H		; 
	DB	73H		; 
	DB	74H		; 
	DB	75H		; 
	DB	76H		; 
	DB	77H		; 
	DB	78H		; 
	DB	79H		; 
	DB	7AH		; 
	DB	7BH		; 
	DB	7CH		; 
	DB	7DH		; 
	DB	7EH		; 
	DB	7FH		; 


	DB	1BH		; 80H
	DB	12H		; 81H
        DB	13H		; 82H
	DB	18H		; 83H
	DB	05H		; 84H
	DB	04H		; 85H
	DB	09H		; 86H
	DB	NOTUSED		; 87H
	DB	0DH		; 88H
	DB	2CH		; 89H
	DB	2EH     	; 8AH
	DB	08H		; 8BH
	DB	03H		; 8CH
	DB	NOTUSED		; 8DH
	DB	NOTUSED		; 8EH
	DB	NOTUSED		; 8FH

	DB	NOTUSED		; 90H      USED FOR UPPER LOWER CASE
	DB	8CH		; 91H
	DB	8DH		; 92H
	DB	8EH		; 93H
	DB	8FH		; 94H
	DB	90H		; 95H
	DB	03H		; 96H
	DB	NOTUSED		; 97H
	DB	0DH		; 98H
	DB	92H		; 99H
	DB	NOTUSED		; 9AH
	DB	92H		; 9BH
	DB	NOTUSED		; 9CH
	DB	NOTUSED		; 9DH
	DB	93H		; 9EH
	DB	94H		; 9FH

	DB	NOTUSED		; A0H
	DB	NOTUSED		; A1H
	DB	NOTUSED		; A2H
	DB	95H		; A3H
	DB	96H		; A4H
	DB	97H		; A5H
	DB	NOTUSED		; A6H
	DB	98H		; A7H
	DB	99H		; A8H
	DB	9AH		; A9H
	DB	9BH		; AAH
	DB	9CH		; ABH
	DB	9DH		; ACH
	DB	9EH		; ADH
	PAGE
;****************************************************************
;*
;*	BFNTBL		BIOS FUNCTION TABLE
;*
;****************************************************************

BFNTBL:				; BIOS FUNCTION TABLE

	DW	BRESET		; RESET DISK STUFF
	DW	CWRTRAK		; WRITE TRACK
	DW	CRDTRAK		; READ TRACK
	DW	PSDMA		; PHYSICAL SET DMA
	DW	PSDSK		; PHYSICAL SET DISK
	DW	PSTRK		; PHYSICAL SET TRK
	DW	PSSEC		; PHYSICAL SET SECTOR
	DW	PSREAD		; PHYSICAL READ
	DW	PSWRITE		; PHYSICAL WRITE
	DW	PHOME		; HOME the drive


;****************************************************************
;*								*
;*	KHOME	SEEK TRACK 0					*
;*								*
;****************************************************************

KHOME:
	MVI	C,0		; SELECT TRACK 0


;****************************************************************
;*								*
;*	KSETTRK	SELECT TRACK IN [C]				*
;*								*
;****************************************************************

KSETTRK:
	MOV	A,C
	STA	SEKTRK
	RET


;****************************************************************
;*								*
;*	KSETSEC	SET SECTOR IN [C]				*
;*								*
;****************************************************************

KSETSEC:
	MOV	A,C
	DCR	A
	STA	SEKSEC		;SECTOR TO SEEK
	RET

	PAGE
;****************************************************************
;*								*
;*	KSETDMA	SET DMA ADDRESS	IN [BC]				*
;*								*
;****************************************************************

KSETDMA:
	MOV	H,B
	MOV	L,C
	SHLD	DMAADR
	RET


;****************************************************************
;*								*
;*	KSECTRAN	SECTOR TRANSLATE			*
;*								*
;****************************************************************

KSECTRAN:
	MOV	L,C
	MOV	H,B
	INX	H
	RET


;****************************************************************
;*								*
;*	KCONOUT	FLUSH PENDING DISK WRITE BEFORE CONSOLE 	*
;*		OUTPUT						*
;*								*
;****************************************************************

KCONOUT:
	PUSH	B		; SAVE CHAR TO OUTPUT
	CALL	FLUSH		; YES, WRITE TO DISK
	POP	B
	JMP	VCONOUT

	PAGE
;****************************************************************
;*								*
;*	KREAD		LOGICAL READ ROUTINE			*
;*								*
;****************************************************************

KREAD:
	CALL	CKSINGLE	; CHECK FOR 128 BYTE SECTOR
	JZ	RDSINGLE	; DO SD READ
	CALL	FLUSH		; WRITE IF ACTIVE BUFFER
	RNZ			; ERROR
	CALL	DIRCHK		; FORCE READ ON DIRECTORY SECTOR
	CZ	CLOSE		; FORCE READ ON DIR SECTOR
	CALL	ALLOC		; RETURN 1 IN [A] FOR NEXT INSTR.
	STA	READOP		; SET READ OPERATION
	JMP	RWOPER		; AND DO BUFFERED READ


;****************************************************************
;*								*
;*	KWRITE		LOGICAL WRITE ROUTINE			*
;*								*
;****************************************************************


KWRITE:
	MOV	A,C		; GET WRITE TYPE
	STA	WRTYPE		; AND SAVE IT
	CALL	CKSINGLE	; CHECK FOR TRACK ZERO 
	JZ	WRTSINGLE
	XRA	A		; 0 TO ACCUMULATOR
	STA	READOP		; SET WRITE OPERATION
	CALL	DEBLOCK		; SET UP DEBLOCKING
	JMP	RWOPER		; DO THE WRITE

	PAGE
;****************************************************************
;*								*
;*	DIRCHK	CHECK FOR DISK OPERATION TO 1ST DIRECTORY 	*
;*								*
;****************************************************************

DIRCHK:
	LDA	SEKDSK
	CPI	2
	JNC	DIRCHK1
	LDA	SEKTRK		; GET TRACK NUMBER
	CPI	3		; IS IT DIRECTORY TRACK
	RNZ			; NO, NOT DIRECTORY
	LDA	SEKSEC		; GET SECTOR
	ORA	A
	RET			; RETURN WITH FLAGS SET
DIRCHK1:
	CPI	4
	JZ	DIRCHK2
	LDA	SEKTRK		; GET TRACK NUMBER
	CPI	1		; IS IT DIRECTORY TRACK
	RNZ			; NO, NOT DIRECTORY
	LDA	SEKSEC		; GET SECTOR
	ORA	A
	RET			; RETURN WITH FLAGS SET

DIRCHK2:
	LDA	SEKTRK
	CPI	0
	RNZ
	LDA	SEKSEC
	ORA	A
	RET


CKSINGLE:
	LDA	SEKDSK
	CPI	4
	LDA	SEKSEC
	JZ	CKSN1
				; CHECK FOR 128 BYTE SECTORS
	LDA	SEKTRK		; GET TRACK 0
	ORA	A
	LDA	SEKSEC		; GET  REQUESTED SECTOR
	JNZ	CKSN1		; NOT 128 BYTE
	INR	A		; BUMP SECTOR NUMBER
	STA	SEKHST		; MAY BE 128 BYTE SECTORS
	XRA	A
	RET

CKSN1:	CALL	CONVT		; CONVERT TO PHYSICAL
	STA	SEKHST		; SAVE 
	XRA	A
	INR	A		; SET NON ZERO
	RET



RDSINGLE:
	MVI	A,1		; DISK COMMAND
	DB	06H		; MVI B-ENABLE FALL THRU TO SINGLE OP
WRTSINGLE:
	XRA	A
	STA	DSKCMD
	LXI	H,SEKDSK
	CALL	MOVEDA
	LHLD	DMAADR		; GET DMA ADDRESS
	JMP	DSKOP1

	PAGE
;****************************************************************
;*								*
;*	SECTOR DEBLOCKING ALGORITHMS FOR CPM 2.0		*
;*	N.B.	THESE ROUTINES REQUIRE THE FOLLOWING DATA AREA	*
;*		STRUCTURE:					*
;*			SEKDSK	DS	1			*
;*			SEKTRK	DS	1			*
;*			SEKHST	DS	1			*
;*			SEKSEC	DS	1			*
;*								*
;****************************************************************


;****************************************************************
;*		DISK DEFINITIONS				*
;****************************************************************

DPBASE:

	DISKS	5			;FOUR DISKS


	DISKDEF	 0,1,52,0,2048,480,128,128,3,0	;DD DS 8"

	PAGE
	DISKDEF	 1,1,52,0,2048,480,128,128,3,0	;DD DS 8"


	DISKDEF	 2,1,96,0,4096,1200,512,0,1


	DISKDEF	 3,1,96,0,4096,1200,512,0,1

	DISKDEF  4,1,32,0,2048,96,128,0,0	;MEMORY DISK

	DISKDEF  8,1,26,0,1024,243,64,64,2	;STD 8"


	PAGE
;****************************************************************
;*		DISK DEBLOCKING MACROS				*
;****************************************************************

;	UTILITY MACRO TO COMPUTE SECTOR MASK

SMASK	MACRO	HBLK		;; COMPUTE LOG2(HBLK) RETURN @X
@Y	SET	HBLK
@X	SET	0
	REPT	8
	IF	@Y = 1
	EXITM
	ENDIF
;;	@Y IS NOT 1, SHIFT RIGHT ONE POSITION
@Y	SET	@Y SHR 1
@X	SET	@X + 1
	ENDM
	ENDM


;****************************************************************
;*								*
;*	CP/M TO HOST DISK CONSTANTS				*
;*								*
;****************************************************************


HSTSIZD	EQU	256		;HOST DISK SECTOR SIZE
HSTSPTD	EQU	26		;HOST DISK SECTORS/TRK
HSTBLKD	EQU	HSTSIZD/128	;CP/M SECTS/HOST BUFF
CPMSPTD	EQU	HSTBLKD * HSTSPTD	;CP/M SECTORS/TRACK
SECMSKD	EQU	HSTBLKD-1	;SECTOR MASK
	SMASK	HSTBLKD		;COMPUTE SECTOR MASK
SECSHFD	EQU	@X		;LOG2(HSTBLK)


;****************************************************************
;*								*
;*	WRITE ENTRY PARAMETERS					*
;*								*
;****************************************************************

WRALL	EQU	0		;WRITE TO ALLOCATED
WRDIR	EQU	1		;WRITE TO DIRECTORY
WRUAL	EQU	2		;WRITE TO UNALLOCATED

	PAGE
;****************************************************************
;*								*
;*	DEBLOCK							*
;*								*
;****************************************************************


DEBLOCK:
	LDA	WRTYPE		; GET TYPE OF WRITE
	ORA	A		; TYPE0 NORMAL WRITE?
	JZ	CHKUNA		; CHECK FOR PREV UNALLOC

	CPI	WRUAL		; TYPE2 WRITE UNALLOCATED?
	LDA	CXTRA		; ##NEXT UNALLOC RECS
	JZ	SETCNT		; SET REC COUNT
	XRA	A		; TYPE1 DIR AND ALL ELSE
				; MUST PRE-READ
SETCNT:
				; INITIALIZE COUNT AND UNA BLOCK
	STA	UNACNT
	LXI	H,SEKDSK	; MOVE SEK INFO
	LXI	D,UNADSK	; TO UNA BLOCK
	CALL	MOVE4

CHKUNA:
				; CHECK FOR WRITE TO UNALLOCATED SECTOR
	LXI	H,UNACNT	; ANY UNALLOC REMAIN?
	DCR	M		; UNACNT = UNACNT-1
	JM	ALLOC		; SKIP IF NOT

				; MORE UNALLOCATED RECORDS REMAIN
	LXI	D,SEKDSK
	LXI	H,UNADSK
	CALL	COMPARE		; COMPARE DISK AND TRK
	JNZ	ALLOC		
	INX	H		; [HL] POINTS TO UNASEC
	INX	D		; [DE] POINTS TO SEKSEC
	LDAX	D		; REQUESTED CPM SECTOR TO [A]
	CMP	M		; EXPECTED CPM SECTOR?
	JNZ	ALLOC		; NOT SAME
	INR	A		; MATCH, BUMP FOR NEXT SECTOR
	MOV	B,A		; NEXT EXPECTED SECTOR TO [B]
	LDA	CSCMAX		; GET MAXIMUM SECTOR ON A TRACK+1
	CMP	B		; HAVE SECTOR NUMBERS OVERFLOWED
	JNC	NOOVF		; NO
	LXI	H,UNATRK	; BUMP EXPECTED TRACK ON SECTOR OVERFLOW
	INR	M
	MVI	B,0		; NEXT EXPECTED SECTOR IS 0
NOOVF:	MOV	A,B		; GET NEXT ANTICIPATED SECTOR
	STA	UNASEC		; AND SAVE IT
	XRA	A		; 0 TO ACCUMULATOR
	STA	RSFLAG		; SET NO PREREAD
	RET			; READY FOR RWOPER


ALLOC:
				; ALLOCATED RECORD, REQUIRES PRE-READ
	XRA	A		; 0 TO ACCUM
	STA	UNACNT		; UNACNT = 0
	INR	A		; 1 TO ACCUM
	STA	RSFLAG		; SET PREREAD REQUIRED
	RET			; READY FOR RWOPER



	PAGE
;****************************************************************
;*								*
;*	RWOPER	BUFFERED READ/WRITE				*
;*		ENTER WITH READOP	1=READ,0=WRITE		*
;*			   RSFLAG	1=MUST PRE-READ		*
;*			   WRTYPE	1=FORCE WRITE		*
;*								*
;****************************************************************


RWOPER:
	LXI	H,HSTACT	; HOST ACTIVE FLAG
	MOV	A,M
	MVI	M,1		; ALWAYS BECOMES 1
	ORA	A		; WAS IT ALREADY?
	JZ	FILHST		; FILL HOST IF INACTIVE

				; HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
	LXI	H,HSTDSK
	LXI	D,SEKDSK
	CALL	COMPARE		; CHECK DISK,TRACK
	JNZ	NOMATCH
	LDAX D ! CMP M		; CHECK FOR SAME HOST SECTOR
	JZ	MATCH

NOMATCH:
				;NOT CORRECT PHYSICAL SECTOR (SEKHST)
	LDA	HSTWRT		;WRITE PENDING?
	ORA	A
	CNZ	WRITEHST	;CLEAR HOST BUFF
	RNZ			;ERROR

FILHST:
				; MAY HAVE TO FILL THE HOST BUFFER
	XRA	A		; 0 TO ACCUM
	STA	HSTWRT		; NO PENDING WRITE
	LXI	H,SEKDSK	; MOVE SEK INFO
	LXI	D,HSTDSK	; TO HST BLOCK
	CALL	MOVE4
	LDA	RSFLAG		; NEED TO READ?
	ORA	A
	CNZ	READHST		; YES, PRE-READ
	RNZ			; ERROR

MATCH:				; CORRECT PHYSICAL SECTOR IS IN BUFFER
	LDA	CMSK		; FIND OFFSET INTO BUFFER
	MOV	B,A		; GET MASK(VARIABLE)
	LDA	SEKSEC		; GET REQUESTED SECTOR
	ANA	B		; MASK FOR PROPER SECTION & RESET CARRY
	RAR			; 9 BIT SHIFT RIGHT
	MOV	H,A		; FOR MULTIPLY BY 128
	MVI	A,0		; PREPARE LO-BYTE
	RAR			; SHIFT CARRY TO BIT 7
	MOV	L,A		; [HL] IS NOW [A]*128
	LXI	D,HSTBUF	; ADD BUFFER BASE ADDRESS
	DAD	D		; [HL] POINTS TO PROPER BUFFER
	XCHG			; TO [DE] FOR XFER
	LHLD	DMAADR		; GET/PUT CP/M DATA
	LDA	READOP		; WHICH WAY?
	ORA	A
	JNZ	RWMOVE		; SKIP IF READ

	MVI	A,1		; WRITE OPERATION, MARK AND SWITCH DIRECTION
	STA	HSTWRT		; HSTWRT = 1
	XCHG			; SOURCE/DEST SWAP
RWMOVE:
	XCHG			; DE=DEST, HL=SOURCE
	CALL	MOVE80

				; DATA HAS BEEN MOVED TO/FROM HOST BUFFER
	LDA	READOP		; READ?
	DCR	A		; 1 BECOMES 0
	RZ			; EXIT IF READ
	LDA	WRTYPE		; WRITE TYPE
	CPI	WRDIR		; TO DIRECTORY?
	JZ	FLUSH		; FLUSH NOW
	XRA	A
	RET			; NO FURTHER PROCESSING



FLUSH:	LDA	HSTWRT		; SEE IF WRITE PENDING
	ORA	A
	RZ			; NO WRITE PENDING
	CALL	CLOSE
	JMP	WRITEHST

CLOSE:	XRA	A
	STA	UNACNT
	STA	HSTACT
	STA	HSTWRT
	RET



	PAGE
;****************************************************************
;*								*
;*		MOUNT	SETUP TABLE FOR SELECTED DRIVE		*
;*								*
;****************************************************************


MOUNT:				; TEST DENSITY OF NEWLY SELECTED DISK
	LDA	CLRFLG		; CHECK FOR FORCED MOUNT
	ANI	80H
	JNZ	MOUNT1		; FLAG SET, DO READ AND TABLE SETUP
	CALL	SEKTYP		; GET POINTER TO TYPE FLAG
	MOV	A,M		; GET TABLE ENTRY
	ANI	RDYBIT		; CHECK MOUNT BIT
	JZ	MOUNT1		; DO READ AND TABLE SETUP
	LDA	SEKDSK		; SEE IF CURRENT TABLE
	LXI	H,MONDSK	; BELONGS TO THIS DISK
	CMP	M		; SET FLAGS
	RZ			; TABLE ALREADY SETUP
	JMP	MOUNT2		; JUST SETUP NEW TABLE

MOUNT1:	CALL	FLUSH		; WRITE OUT BUFFER IF PENDING 
	CALL	CLOSE		; AND CLOSE IF READ
	LDA	SEKDSK		; GO READ ID
	CALL	READID		; READ ID
	RNZ
	PUSH	PSW
	CALL	SEKTYP
	POP	PSW
	ORI	RDYBIT
	MOV	M,A

MOUNT2:
	CALL	SEKTYP
	MOV	A,M
	CALL	CHKLGL		; SEE IF LEGAL SPEC AND XLATE TO TABLE ENTRY
	RNZ			; ILLEGAL SPEC
	LXI	H,MTABL		; POINT TO MOUNT PARAMETER TABLE
	ADD	A		; *2
	MOV	B,A		; SAVE *2 RESULT
	ADD	A		; *4
	ADD	A		; *8
	ADD	B		; * 10
	CALL	OFFSET		; BUMP HL BY A
MOUNT3:
	LXI	D,CTTABL	; PLACE TO PUT DISK DATA FOR SELECTED DRIVE
	MVI	B,10		; MOVE 10 BYTES
	CALL	MOVELP
	CALL	GETDPH		; GET THE PARM HEADER TO SET
	PUSH	H
 	LHLD	CPBLK		; GET PAR-BLOCK TO [BC]
	MOV	C,L
	MOV	B,H		; PARAM BLOCK TO BC
	POP	H		; DP HEADER ADRS TO HL
	LXI	D,10
	DAD	D
	MOV	M,C
	INX	H
	MOV	M,B		; SET DISK PARMS ADDRESS
	LDA	SEKDSK
	STA	MONDSK
	XRA	A		; SET Z FOR NO ERROR
	RET
MOUNTH:				; TEST DENSITY OF NEWLY SELECTED DISK
	LDA	CLRFLG		; CHECK FOR FORCED MOUNT
	ANI	80H
	JNZ	MOUNTH1		; FLAG SET, DO READ AND TABLE SETUP
	CALL	SEKTYP		; GET POINTER TO TYPE FLAG
	MOV	A,M		; GET TABLE ENTRY
	ANI	RDYBIT		; CHECK MOUNT BIT
	JZ	MOUNTH1		; DO READ AND TABLE SETUP
	LDA	SEKDSK		; SEE IF CURRENT TABLE
	LXI	H,MONDSK	; BELONGS TO THIS DISK
	CMP	M		; SET FLAGS
	RZ			; TABLE ALREADY SETUP
	JMP	MOUNTH2		; JUST SETUP NEW TABLE

MOUNTH1:
	CALL	FLUSH
	CALL	CLOSE
	LDA	SEKDSK
	CALL	READID
	RNZ
	CALL	SEKTYP
	ORI	RDYBIT
	MOV	M,A

MOUNTH2:
	LXI	H,MTABLH	; POINT TO MOUNT PARAMETER TABLE
	LXI	D,CTTABL	; PLACE TO PUT DISK DATA FOR SELECTED DRIVE
	MVI	B,10		; MOVE 10 BYTES
	CALL	MOVELP
	LDA	SEKDSK
	STA	MONDSK
	XRA	A		; SET Z FOR NO ERROR
	RET
MOUNTM:				; TEST DENSITY OF NEWLY SELECTED DISK
	LDA	CLRFLG		; CHECK FOR FORCED MOUNT
	ANI	80H
	JNZ	MOUNTM1		; FLAG SET, DO READ AND TABLE SETUP
	CALL	SEKTYP		; GET POINTER TO TYPE FLAG
	MOV	A,M		; GET TABLE ENTRY
	ANI	RDYBIT		; CHECK MOUNT BIT
	JZ	MOUNTM1		; DO READ AND TABLE SETUP
	LDA	SEKDSK		; SEE IF CURRENT TABLE
	LXI	H,MONDSK	; BELONGS TO THIS DISK
	CMP	M		; SET FLAGS
	RZ			; TABLE ALREADY SETUP
	JMP	MOUNTM2		; JUST SETUP NEW TABLE

MOUNTM1:
	CALL	SEKTYP
	ORI	RDYBIT
	MOV	M,A

MOUNTM2:
	LXI	H,MTABLH	; POINT TO MOUNT PARAMETER TABLE
	LXI	D,CTTABL	; PLACE TO PUT DISK DATA FOR SELECTED DRIVE
	MVI	B,10		; MOVE 10 BYTES
	CALL	MOVELP
	LDA	SEKDSK
	STA	MONDSK
	XRA	A		; SET Z FOR NO ERROR
	RET


	PAGE
;****************************************************************
;*								*
;*	CHKLGL	CHECK FOR LEGAL SIZE DENSITY COMBINATION	*
;*		ENTER WITH DRIVE TYPE IN [A]			*
;*		RETURN TABLE POS IN [A]				*
;*		Z SET IF LEGAL, NZ IF ILLEGAL			*
;*								*
;****************************************************************


CHKLGL:	PUSH	H
	LXI	H,LGLTBL	; POINT TO TABLE
	ANI	7		; MASK DRIVE READY BIT
	ADD	A		; 2 BYTE TABLE ENTRIES
	CALL	OFFSET		; FIND TABLE POS
	MOV	A,M		; GET FLAG
	ORA	A		; SET FLAGS
	INX	H		; BUMP COUNTER
	MOV	A,M		; GET TABLE CODE
	POP H
	RET


;****************************************************************
;*								*
;*			LEGALITY TABLE				*
;*								*
;****************************************************************


;		LEGALITY	TABLE CODE	  DEN SID SIZ0
LGLTBL:
	DB	0   		,0		;  0   0   0
	DB	0FFH		,0		;  0   0   1
	DB	0FFH		,0		;  0   1   0 	
	DB	0FFH		,0		;  0   1   1
	DB	0FFH		,0		;  1   0   0 
	DB	0   		,1		;  1   0   1
	DB	0FFH   		,0		;  1   1   0
	DB	0   		,2		;  1   1   1





	PAGE

MTABL:
	DW	DPB8
	DB	8
	DB	0
	DB	26	
	DW	128
	DW	XLTS
	DB	8

MTABLH:
	DW	0
	DB	2
	DB	3
	DB	24*4
	DW	512
	DW	XLTH
	DB	32

	DW	DPB0
	DB	SECSHFD
	DB	SECMSKD
	DB	CPMSPTD
	DW	HSTSIZD
	DW	XLTD
	DB	16
MTABLM:
	DW	0
	DB	2
	DB	3
	DB	32
	DW	512
	DW	XLTM
	DB	32

XLTS:	DB	 1, 7,13,19,25, 5,11,17,23
	DB	 3, 9,15,21, 2, 8,14,20,26
	DB	 6,12,18,24, 4,10,16,22

XLTD:	DB	 1,10,19, 2,11,20, 3,12,21
	DB	 4,13,22, 5,14,23, 6,15,24
	DB	 7,16,25, 8,17,26, 9,18

XLTH:	DB	 1,2,3,4,5,6,7,8,9,10,11
	DB	12,13,14,15,16,17,18,19,20,21,22,23,24
XLTM:	DB	1,2,3,4,5,6,7,8

CTTABL:
CPBLK:	DS	2	; PARAMETER BLOCK POINTER
CSHF:	DS	1	; SHIFT FACTOR
CMSK:	DS	1	; SECTOR MASK
CSCMAX:	DS	1	; MAXIMUM SECTOR
CSIZ:	DS	2	; SECTOR SIZE
CTRANS:	DW	2	; PHYSICAL SECTOR TRANSLATE TABLE ADDRESS
CXTRA:	DB	1	; SPARE BYTE






	PAGE
;****************************************************************
;*								*
;*		UTILITY SUBROUTINES				*
;*								*
;****************************************************************


COMPARE:			;2 BYTE COMPARE
	LDAX D ! CMP M ! RNZ	; DSK
	INX H  ! INX D
	LDAX D ! CMP M ! RNZ	; LOW BYTE OF TRK
	INX H  ! INX D		; POINT TO CPM SECTOR
	RET			; Z SET IF MATCH



NXTTYP:	LDA	NXTDSK
	JMP	GETTYP
SEKTYP:	LDA	SEKDSK
GETTYP:	LXI	H,DRVTYP
	CALL	OFFSET
	MOV	A,M
	ANI	7
	RET



	PAGE
;****************************************************************
;*								*
;*	CONVT	ENTER WITH CPM SECTOR NUMBER IN [A]		*
;*		EXPECTS REQUESTED TRACK				*
;*		RETURN PHYSICAL SECTOR IN [A]			*
;*								*
;****************************************************************


CONVT:
	MOV	B,A		; CPM SECTOR TO [B]
	LDA	CMSK		; GET CURRENT MASK
	CMA			; INVERT
	ANA	B		; AND ZERO LO ORDER SUB-BLOCK BITS
	MOV	C,A		; SAVE PHYSICAL BITS
	LDA	CSHF		; GET SHIFT NUMBER
	ORA	A
	MOV	B,A		; SHIFT FACTOR TO [B]
	MOV	A,C		; SECTOR BITS TO [A]
	JZ	CON2		; 128 BYTE SECTORS
CON1:	RRC			; DIV BY 2
	DCR	B		; COUNTDOWN
	JNZ	CON1		; THE PRESCRIBED # OF TIMES
CON2:	LHLD	CTRANS		; GET TRANSLATE TABLE
XL1:	CALL	OFFSET
	MOV	A,M		; GET TRANSLATED SECTOR
	RET




MOVEDA:	LXI	D,NXTDSK	; DESTINATION NXT PARAMETERS
MOVE4:	MVI	B,4		;4 BYTE MOVE
	JMP	MOVELP
MOVE80:	MVI	B,80H		;128 BYTE MOVE
MOVELP:				;B BYTE HL TO DE MOVE
	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVELP
	RET




	PAGE
;****************************************************************
;*								*
;*	HOST DISK OPERATIONS					*
;*								*
;****************************************************************


WRITEHST:			; PHYSICAL BIG SECTOR WRITE
	XRA	A
	DB	21H		; LXI H- ENABLE FALL THRU TO DISKIO
READHST:			; PHYSICAL BIG SECTOR READ
	MVI	A,1		; FALL INTO DISKIO
DISKIO:
				; SETUP DISK FROM HST PARAMETER BLOCK
	STA	DSKCMD
	LXI	H,HSTDSK
	CALL	MOVEDA
	LXI	H,HSTBUF
DSKOP1:	SHLD	PMAADR		; SAVE IN PHYSICAL DMAADRS
	LDA	DSKCMD
	ORA	A
	JNZ	CREAD
	JMP	CWRITE





	PAGE
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;+****************************************************************+
;+*								 *+
;+*	  PHYSICAL ROUTINES FOR NCR 9010 FLEX CONTROLLER	 *+
;+*								 *+
;+****************************************************************+
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++




;****************************************************************
;*								*
;*		DISK CONTROLLER EQUATES				*
;*								*
;****************************************************************


DCOMD	EQU	0FD01H		; DISK COMMAND PORT
DSTAT	EQU	0FD01H		; DISK STATUS PORT
DSTAT2	EQU	0FD02H		; DISK STATUS PORT # 2
DINTON	EQU	0FD02H		; INTERRUPT CONTROL PORT
DINTOFF	EQU	0FD03H		; INTERRUPT CONTROL PORT
RSTSERV	EQU	0FD04H		; RESET SERVICE REQUEST
DRESET	EQU	0FD07H		; RESET DISK CONTROLLER



DMALO	EQU	0FC8CH		; DMA ADDRESS LO
DMAHI	EQU	0FC8DH		; DMA ADDRESS HI
DMASIZL	EQU	0FC8EH		; DMA COUNT LO
DMASIZH	EQU	0FC8FH		; DMA COUNT HI AND COMMAND PORT

DMAWRT	EQU	0C0H		; DMA WRITE COMMAND
DMAREAD	EQU	080H		; DMA READ COMMAND




	PAGE
;****************************************************************
;*								*
;*		DISK CONTROL BITS				*
;*								*
;****************************************************************


SIDE1	EQU	01H		; SIDE SELECT BIT
UNITLO	EQU	02H		; LO UNIT BIT
UNITHI	EQU	04H		; HI UNIT BIT

DDEN	EQU	080H		; DOUBLE DENSITY BIT

	PAGE
;****************************************************************
;*								*
;*		DISK CONTROLLER COMMANDS			*
;*								*
;****************************************************************


RESTORE	EQU	00H		; RESTORE COMMAND
WRITFMT	EQU	01H		; WRITE FORMAT COMMAND
READFMT	EQU	02H		; READ FORMAT COMMAND
WRITDAT	EQU	03H		; WRITE DATA COMMAND
READDAT	EQU	04H		; READ DATA COMMAND
WRITDEL	EQU	05H		; WRITE DELETED DATA COMMAND
WRTFMTD	EQU	06H		; FORMAT DEFECTIVE TRACK COMMAND
VERI	EQU	07H		; VERIFY COMMAND
DMABOUT	EQU	08H		; DMA BYTE OUT COMMAND
DMABIN	EQU	09H		; DMA BYTE IN COMMAND
BTURN	EQU	0AH		; BYTE TURNAROUND COMMAND
DTURN	EQU	0BH		; DATA TURNAROUND COMMAND


ATOE	EQU	080H		; ASCII TO EBCDIC CONVERSION
ETOA	EQU	0C0H		; EBCDIC TO ASCII CONVERSION

	PAGE
;****************************************************************
;*								*
;*	CREAD		READ SECTOR				*
;*								*
;****************************************************************

CREAD:	
	LDA	DLOOPS		; GET THE NUMBER OF RESTORE LOOPS
	MOV	C,A		;   INTO <C>, AS OUTER LOOP COUNTER
CREAD1:
	LDA	DTRIES		; GET THE NUMBER OF RETRIES
	MOV	B,A		;   INTO <B>, AS INNER LOOP COUNTER
CREAD2:
	CALL	DREAD		; DO PRIMITIVE READ
	RZ			; RET IF ZERO, NO ERROR
	DCR	B		; ELSE, COUNT DOWN INNER LOOP
	JNZ	CREAD2		; LOOP TIL DONE

	CALL	RECAL		; RESTORE EA OUTER LOOP ITERATION BY HOMING
	DCR	C		; COUNT DOWN OUTER LOOP
	JNZ	CREAD1		; LOOP TIL DONE

	JMP	DRVERR		; IF WE GET HERE, REPORT ERROR



;****************************************************************
;*								*
;*	CWRITE		WRITE SECTOR				*
;*								*
;****************************************************************

CWRITE:
	LDA	DLOOPS		; GET THE NUMBER OF RESTORE LOOPS
	MOV	C,A		;   INTO <C>, AS OUTER LOOP COUNTER
CWRIT1:
	LDA	DTRIES		; GET THE NUMBER OF RETRIES
	MOV	B,A		;   INTO <B>, AS INNER LOOP COUNTER
CWRIT2:
	CALL	DWRITE		; DO PRIMITIVE WRITE
	PUSH	PSW		; SAVE FLAGS
	LDA	NXTDSK
	CPI	2
	JNC	CWRIT3
	LDA	VERIFY		; SEE IF READ AFTER WRITE IS SELECTED
	ORA	A		; SET FLAGS
	CNZ	CREAD		; REREAD SECTOR
CWRIT3:
	POP	PSW		; RESTORE FLAGS
	RZ			; RET IF ZERO, NO ERROR
	DCR	B		; ELSE, COUNT DOWN INNER LOOP
	JNZ	CWRIT2		; LOOP TIL DONE

	CALL	RECAL		; RESTORE EA OUTER LOOP ITERATION BY HOMING
	DCR	C		; COUNT DOWN OUTER LOOP
	JNZ	CWRIT1		; LOOP TIL DONE

	JMP	DRVERR		; ERROR	




DRVERR:
	POP	PSW		; STACK CLEANUP
	MVI	A,1		; ERROR CODE
	ORA	A
	RET

	PAGE
;****************************************************************
;*								*
;*	CWRTRAK	WRITE OUT A TRACK				*
;*		ENTER [E] BIT 7 = DDEN, BIT 0 = SIDE		*
;*								*
;****************************************************************



CWRTRAK:
	PUSH	D		; SAVE THE WHALES (DENSITY. SIDE)

	LXI	H,CMDSTG	; SETUP THE COMMAND STRING FOR THE CONTROLLER
	MVI	M,WRITFMT	; FIRST PUT IN THE WRITE TRACK COMMAND
	INX	H		; POINT TO NEXT ONE
	LDA	NXTDSK		; SET DISK BITS
	CALL	FORMDISK	
	POP	D		; GET DENSITY BITS BACK
	ORA	E		; MIX THEM WITH DISK BITS
	MOV	M,A		; SAVE SECOND PRT OF CMD STRING
	LDA	NXTTRK		; GET THE TRACK
	INX	H		; POINT TO THIRD CMD STRING
	MOV	M,A		; PUT IT IN
	INX	H		; POINT TO FOURTH PART OF CMD STRING
	MVI	M,0		; SET IT TO ZERO

	LXI	H,26*4		; SETUP DMA FOR TRKWRT SECTOR DATA
	CALL	WRTDMA
	CALL	XWAIT		; SEND OUT THE COMMAD AND WAIT FOR COMPLETION
	RET


	PAGE

;****************************************************************
;*								*
;*	CRDTRAK	READ A TRACK		 			*
;*		ENTER [E] BIT 7 = DDEN, BIT 0 = SIDE		*
;*								*
;****************************************************************



CRDTRAK:
	PUSH	D		; SAVE THE WHALES (DENSITY. SIDE)

	LXI	H,CMDSTG	; SETUP THE COMMAND STRING FOR THE CONTROLLER
	MVI	M,READFMT	; FIRST PUT IN THE READ TRACK COMMAND
	INX	H		; POINT TO NEXT ONE
	LDA	NXTDSK		; SET DISK BITS
	CALL	FORMDISK	
	POP	D		; GET DENSITY BITS BACK
	ORA	E		; MIX THEM WITH DISK BITS
	MOV	M,A		; SAVE SECOND PRT OF CMD STRING
	LDA	NXTTRK		; GET THE TRACK
	INX	H		; POINT TO THIRD CMD STRING
	MOV	M,A		; PUT IT IN
	INX	H		; POINT TO FOURTH PART OF CMD STRING
	MVI	M,0		; SET IT TO ZERO

	LXI	H,26*4		; SETUP DMA FOR TRKREAD SECTOR DATA
	CALL	RDDMA
	CALL	XWAIT		; SEND OUT THE COMMAD AND WAIT FOR COMPLETION
	RET


	PAGE
;****************************************************************
;*								*
;*	PSDMA	SET PHYSICAL DMA. DMA IN [DE]			*
;*								*
;****************************************************************



PSDMA:	XCHG			; GET DMA TO [HL]
	SHLD	PMAADR		; SAVE IN PHYSICAL LOC
	RET



;****************************************************************
;*								*
;*	PSDSK	SET PHYSICAL DISK. DISK IN [E]			*
;*								*
;****************************************************************



PSDSK:	MOV	A,E		; GET DISK TO [A]
	STA	NXTDSK		; SAVE IT
	RET



;****************************************************************
;*								*
;*	PSTRK	SET PHYSICAL TRACK. TRACK IN [E]		*
;*								*
;****************************************************************



PSTRK:	MOV	A,E		; GET TRACK TO [A]
	STA	NXTTRK		; SAVE IT
	RET



;****************************************************************
;*								*
;*	PSSEC	SET PHYSICAL SECTOR. SECTOR IN [E]		*
;*								*
;****************************************************************



PSSEC:	MOV	A,E		; GET SECTOR TO [A]
	STA	NXTHST		; SAVE IT
	RET


;****************************************************************
;*								*
;*	PHOME	DO A HOME TO SELECTED DRIVE			*
;*								*
;****************************************************************


PHOME:
	LDA	NXTDSK		; GET THE DISK SET
	CALL	DHOME
	RET

	PAGE
;****************************************************************
;*								*
;*		PSREAD						*
;*								*
;****************************************************************

PSREAD:
	PUSH	D		; SAVE THE WHALES (DENSITY. SIDE)

	LXI	H,CMDSTG	; SETUP THE COMMAND STRING FOR THE CONTROLLER
	MVI	M,READDAT	; FIRST PUT IN THE READ DATA  COMMAND
	INX	H		; POINT TO NEXT ONE
	LDA	NXTDSK		; SET DISK BITS
	CALL	FORMDISK	
	POP	D		; GET DENSITY BITS BACK
	ORA	E		; MIX THEM WITH DISK BITS
	MOV	M,A		; SAVE SECOND PRT OF CMD STRING
	LDA	NXTTRK		; GET THE TRACK
	INX	H		; POINT TO THIRD CMD STRING
	MOV	M,A		; PUT IT IN
	INX	H		; POINT TO THIRD PARD OF CMD STRING
	LDA	NXTHST		; GET HOST SECTOR
	MOV	M,A		; SAVE AS FOURTH PART OF STRING

	MOV	A,E		; GET DENSITY STUFF BACK
	RLC			; ROTATE BIT 7 ROUND TO CARRY
	LXI	H,80H		; ASSUME SINGLE DENSITY SIZE
	JNC	PSRD1		; JUMP IF IT IS
	LXI	H,100H		; OTHERWISE SET TO DOUBLE DENSITY SIZE
PSRD1:	CALL	RDDMA
	CALL	XWAIT		; SEND OUT THE COMMAND AND WAIT FOR COMPLETION
	RET

	PAGE
;****************************************************************
;*								*
;*		PSWRITE						*
;*								*
;****************************************************************

PSWRITE:
	PUSH	D		; SAVE THE WHALES (DENSITY. SIDE)

	LXI	H,CMDSTG	; SETUP THE COMMAND STRING FOR THE CONTROLLER
	MVI	M,WRITDAT	; FIRST PUT IN THE WRITE DATA  COMMAND
	INX	H		; POINT TO NEXT ONE
	LDA	NXTDSK		; SET DISK BITS
	CALL	FORMDISK	
	POP	D		; GET DENSITY BITS BACK
	ORA	E		; MIX THEM WITH DISK BITS
	MOV	M,A		; SAVE SECOND PRT OF CMD STRING
	LDA	NXTTRK		; GET THE TRACK
	INX	H		; POINT TO THIRD CMD STRING
	MOV	M,A		; PUT IT IN
	INX	H		; POINT TO THIRD PARD OF CMD STRING
	LDA	NXTHST		; GET HOST SECTOR
	MOV	M,A		; STORE ARE FOURTH PART OF STRING

	MOV	A,E		; GET DENSITY STUFF BACK
	RLC			; ROTATE BIT 7 ROUND TO CARRY
	LXI	H,80H		; ASSUME SINGLE DENSITY SIZE
	JNC	PSWR1		; JUMP IF IT IS
	LXI	H,100H		; OTHERWISE SET TO DOUBLE DENSITY SIZE
PSWR1:	CALL	WRTDMA
	CALL	XWAIT		; SEND OUT THE COMMAND AND WAIT FOR COMPLETION
	RET

	PAGE
;****************************************************************
;*								*
;*	DREAD	LOW LEVEL READ					*
;*								*
;****************************************************************

DREAD:	PUSH	B		; SAVE [B]
	LDA	NXTDSK
	CPI	2
	JNC	DREADH
	CALL	SSIZE		; CALCULATE SECTOR SIZE
	CALL	RDDMA		; SETUP DMA FOR READ(PASS SECTOR SIZE IN [HL])
	MVI	C,READDAT	; READ DATA COMMAND
	CALL	SETUP		; SET UP COMMAND STRING
	CALL	XWAIT		; SEND COMMAND STRING
	POP	B		; RESTORE [B]
	RET			; RETURN STATUS
DREADH:
	CPI	4
	JZ	DREADM
	LXI	H,512
	CALL	RDDMAH		; SETUP DMA FOR READ(PASS SECTOR SIZE IN [HL])
	MVI	C,05		; READ DATA COMMAND
	CALL	SETUPH		; SET UP COMMAND STRING
	CALL	XWAITH		; SEND COMMAND STRING
	POP	B		; RESTORE [B]
	RET			; RETURN STATUS

DREADM:
	CALL	SETUPM
	CALL	MOVE
	CALL	CMMDRAM
	CALL	XWATXTH
	POP	B
	RET

;****************************************************************
;*								*
;*	DWRITE	LOW LEVEL WRITE					*
;*								*
;****************************************************************

DWRITE:	PUSH	B		; SAVE [B]
	LDA	NXTDSK
	CPI	2
	JNC	DWRITEH
	CALL	SSIZE		; CALCULATE SECTOR SIZE
	CALL	WRTDMA		; SETUP DMA FOR WRITE(PASS SECTOR SIZE IN [HL])
	MVI	C,WRITDAT	; WRITE DATA COMMAND
	CALL	SETUP		; SET UP COMMAND STRING
	CALL	XWAIT		; SEND COMMAND STRING
	POP	B		; RESTORE [B]
	RET			; RETURN STATUS

DWRITEH:
	CPI	4
	JZ	DWRITEM
	LXI	H,512
	CALL	WRTDMAH		; SETUP DMA FOR WRITE(PASS SECTOR SIZE IN [HL])
	MVI	C,04		; WRITE DATA COMMAND
	CALL	SETUPH		; SET UP COMMAND STRING
	CALL	XWAITH		; SEND COMMAND STRING
	POP	B		; RESTORE [B]
	RET			; RETURN STATUS

DWRITEM:
	CALL	SETUPM
	XCHG
	CALL	MOVE
	CALL	CMMDRAM
	CALL	XWATXTH
	POP	B
	RET

;****************************************************************
;*								*
;*	SSIZE	CALCULATE SECTOR SIZE				*
;*		RETURN SIZE IN [HL]				*
;*								*
;****************************************************************

SSIZE:	LDA	NXTTRK		; GET TRACK NUMBER
	ORA	A		; TEST FOR TRACK 0
	JZ	SSIZ1		; TRACK 0 IS 128 BYTES
	CALL	NXTTYP		; ELSE GET DRIVE TYPE
SSIZ1:	ANI	1		; MASK SIZE BIT
	ADI	1		; INSURE 1 GO AROUND
	MOV	B,A		; TO B FOR COUNTER
	LXI	H,40H		; BASE SECTOR SIZE/2
SSIZ2:	DAD	H		; DOUBLE
	DCR	B		; COUNT DOWN
	JNZ	SSIZ2		; LOOP TILL DONE
	RET

	PAGE
;****************************************************************
;*								*
;*	SETUP	SETUP CONTROLLER				*
;*								*
;****************************************************************


SETUP:
	LXI	H,CMDSTG	; POINT TO DISK COMMAND STRING
	MOV	M,C		; SEND COMMAND
	INX	H		; BUMP COMMAND POINTER
	LDA	NXTDSK		; GET REQUESTED DRIVE
	CALL	FORMDISK	; FORM PROPER DISK BIT
	MOV	B,A		; DISK BIT IN [B]
	CALL	FORMSIDE	; FORM SIDE BIT
	MOV	C,A		; SIDE TO [C]
	CALL	FORMDENS	; FORM DENSITY BIT
	ORA	B		; OR IN DISK NUMBER 
	ORA	C		; OR IN SIDE NUMBER
	MOV	M,A		; INSERT UNIT/SIDE/DENS BYTE
	INX	H		; BUMP POINTER
	CALL	FORMCYL		; FORM CYLINDER NUMBER
	MOV	M,A		; INSERT CYL NUMBER
	INX	H		; BUMP POINTER
	LDA	NXTHST		; GET SECTOR NUMBER
	MOV	M,A		; INSERT SECTOR NUMBER INTO STRING
	RET			; ALL DONE

SETUPH:
	LXI	H,CMDSTG	; POINT TO DISK COMMAND STRING
	MOV	M,C		; SEND COMMAND
	INX	H		; BUMP COMMAND POINTER
	LDA	NXTDSK		; GET REQUESTED DRIVE
	DCR	A
	DCR	A
	MOV	M,A		; INSERT UNIT/SIDE/DENS BYTE
	INX	H		; BUMP POINTER
	LDA	NXTTRK		; GET TRACK NUMBER
	PUSH	H
	LXI	H,24
	CALL	MULT
	CALL	TESTALT		; TEST ALTERNATE TRACK TABLE
	POP	H
	DCX	D
	MOV	M,E
	INX	H
	MOV	M,D
	RET			; ALL DONE
SETUPM:
	LDA	NXTTRK		;GET TEACK NUMBER
	CALL	CMMERAM		;ENABLE CMM RAM
	LDA	NXTHST		;GET SECTOR NUMBER
	DCR	A
	LXI	H,512		;SECTOR SIZE
	CALL	MULT
	LXI	D,7000H		;POINTER TO TRACK
	DAD	D		;POINTER TO SECTOR
	XCHG
	LHLD	PMAADR
	XCHG
	LXI	B,512		;SIZE
	RET
CMMERAM:
	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	ORA	A
	RLC
	RLC
	ADI	040H
	CMA
	MOV	C,A
	MVI	B,071H
	MVI	A,4
	STA	0FC04H
	STAX	B
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
CMMDRAM:
	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	MVI	B,071H
	MVI	C,0E3H
	MVI	A,4
	STA	0FC04H
	STAX	B
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET


TESTALT:
	LDA	NXTHST		; GET NUMBER OF SECTORS
;	CPI	12
;	JC	TESTALT1	; JUMP IF NXTHST < 12
;	SUI	12
;	MVI	E,12
;	MVI	D,0
;	DAD	D
TESTALT1:
;	CALL	CHECK		; CHECK ALTERNATE TRACK TABLE
	MOV	E,A
	MVI	D,0
	DAD	D
	XCHG
	RET
CHECK:
	PUSH	PSW
	XCHG
	LXI	H,ALTTAB
	MVI	B,6		; NUMBER OF ALTERNATE TRACKS
CHECK3:
	XRA	A
	CMP	M		; TEST FOR NO ALTERNATE TRACKS
	JNZ	CHECK1
	INX	H
	CMP	M
	DCX	H
	JZ	CHECKE		; JUMP IF NO ALTERNATE TRACK ASSIGNED
CHECK1:
	MOV	A,E
	CMP	M
	INX	H
	JNZ	CHECK2
	MOV	A,D
	CMP	M
	JZ	CHECKF		; JUMP IF ALTERNATE TRACK FOUND
CHECK2:
	INX	H
	INX	H
	INX	H
	DCR	B
	JNZ	CHECK3		; NEXT TABLE ENTRY
CHECKE:
	XCHG
	POP	PSW
	RET
CHECKF:
	INX	H
	MOV	E,M
	INX	H
	MOV	D,M
	JMP	CHECKE
ALTTAB:
	DW	0,0
	DW	0,0
	DW	0,0
	DW	0,0
	DW	0,0
	DW	0,0
				
	PAGE
;****************************************************************
;*								*
;*		FORMDENS	FORM DENSITY BIT		*
;*								*
;****************************************************************


FORMDENS:	
	PUSH	H
	LDA	NXTTRK		; GET NEXT TRACK
	ORA	A		;
	JZ	FDENS1		; TRACK ZERO IS ALWAYS SINGLE
	CALL	NXTTYP		; GET TYPE 
	ANI	DENBIT
	JZ	FDENS1
	MVI	A,DDEN		; SETUP DOUBLE DENSITY
FDENS1:	POP	H
	RET




;****************************************************************
;*								*
;*	FORMDISK	ENTER WITH DRIVE # IN [A]		*
;*			RETURNS PROPER DRIVE BITS IN [A]	*
;*								*
;****************************************************************


FORMDISK:
	RLC			; ROTATE 1 LEFT
	ANI	0000$0110B
	RET

	PAGE
;****************************************************************
;*								*
;*	FORMSIDE	FORM SIDE BIT				*
;*			RETURNS SIDE BIT IN [A]			*
;*								*
;****************************************************************

FORMSIDE:
	PUSH	H
	CALL	NXTTYP		; SEE IF DOUBLE SIDED
	ANI	SIDBIT		; 
	JZ	FMSID1		; DONE IF SINGLE SIDED
	LDA	NXTTRK		; GET TRACK NUMBER
	CALL	DSTRKTRN	; DO TRACK TRANSLATION(LOGICAL TO PHYSICAL)
	ANI	1		; EVEN TRACKS ARE SIDE 0
FMSID1:	POP	H		; RESTORE [HL]
	RET			; RETURNS SIDE NUMBER IN BIT 0


;****************************************************************
;*								*
;*	FORMCYL		FORM CYLINDER NUMBER			*
;*			RETURNS CYLINDER IN [A]			*
;*								*
;****************************************************************

FORMCYL:
	PUSH	H
	CALL	NXTTYP		; GET DISK TYPE
	ANI	DENBIT		; CHECK FOR DOUBLE DENSITY
	JNZ	FCYL1		; DOUBLE, DO TRANSLATION
	LDA	NXTTRK		; GET TRACK NUMBER
	JMP	FCYL4		; AND RETURN

FCYL1:	PUSH	B		; SAVE [BC]
	CALL	NXTTYP		; GET TYPE
	ANI	SIDBIT		; TEST FOR DOUBLE SIDED
	JNZ	FCYL2		; DOUBLE SIDED
	LDA	NXTTRK		; 
	CALL	SSTRKTRN	; SINGLE SIDED TRACK TRANSLATION
	JMP	FCYL3		; BIG FINISH

FCYL2:	LDA	NXTTRK		; GET TRACK #
	CALL	DSTRKTRN	; DOUBLE SIDED TRACK TRANSLATION
	RRC			; ROTATE RIGHT FOR CYLINDER NUMBER
	ANI	0111$1111B	; AND MASK
FCYL3:	POP	B		; RESTORE [BC]
FCYL4:	POP	H
	RET

	PAGE
;****************************************************************
;*								*
;*	SSTRKTRN	SINGLE SIDED TRACK TRANSLATION		*
;*		ENTER WITH LOGICAL TRACK # IN [A]		*
;*		RETURNS PHYSICAL TRACK NUMBER IN [A]		*
;*								*
;****************************************************************


SSTRKTRN:
	CPI	0		; TEST FOR TRACK 0
	RZ			; DONE IF 0
	CPI	3		; SEE IF TRACK 3
	JNC	SSTKT1
	ADI	71		; ADD 71
	RET

SSTKT1:	CPI	74
	JNC	SSTKT2
	SUI	2
	RET

SSTKT2:	RET



	PAGE
;****************************************************************
;*								*
;*	DSTRKTRN	DOUBLE SIDED TRACK TRANSLATION		*
;*		ENTER WITH LOGICAL TRACK # IN [A]		*
;*		RETURNS PHYSICAL TRACK NUMBER IN [A]		*
;*								*
;****************************************************************


DSTRKTRN:
	CPI	0		; TEST FOR TRACK 0
	RZ			; =0 DO NOTHING
	CPI	3		; SEE IF .GE. TRK 3
	JNC	DSTKT1		; YES THEN JUMP
	CPI	1		; TEST FOR TRACK 1
	JNZ	DSTKT4		; JUMP IF NOT
	ADI	143		; 1 ==> 144
	RET

DSTKT4:	ADI	144		; =2, 2==> 146
	RET

DSTKT1:	CPI	146		; .GE. 3 SEE IF .LT. 146
	JNC	DSTKT2		; .GE. 146 SO JUMP
	SUI	2		; 3 THRU 145 BECOMES 1 THRU 144 (SUB 2)
	RET

DSTKT2:	CPI	147		
	JNC	DSTKT3		; .GE. 147 DONT DO ANYTING
	SUI	1		; 146 ==> 145
	RET

DSTKT3:	RET

	PAGE
;****************************************************************
;*								*
;*	RECAL	RECALIBRATE TRACK REGISTER			*
;*								*
;****************************************************************

RECAL:
	PUSH	B		; SAVE <B> TO USE AS LOCAL REGISTER
	LDA	NXTDSK		; GET DRIVE NUMBER
	CALL	DHOME		; JUST OHM
	POP	B		; RESTORE <B>
	RET


;****************************************************************
;*								*
;*	DHOME	PHYSICAL HOME DRIVE				*
;*		ENTER WITH DRIVE NUMBER IN [A]			*
;*								*
;****************************************************************

DHOME:	
	PUSH	PSW
	LDA	DTRIES		; SETUP RETRI COUNT
	MOV	B,A
	POP	PSW
DHM1:
	PUSH	B		; SAVE COUNT
	PUSH	PSW
	LXI	H,CMDSTG	; POINT TO COMMAND STRING

	MVI	M,RESTORE	; RESTORE COMMAND
	INX	H
	CPI	2
	JNC	DHM2
	CALL	FORMDISK	; FORM PROPER DISK 

	MOV	M,A
	INX	H

	MVI	M,0		; FORCE CYL # TO 0
	INX	H

	MVI	M,1
	CALL	XWAIT		; SEND COMMAND STRING
DHM3:
	POP	B		; GET BACK COUNT
	MOV	A,B
	POP	B
	RZ			; RETURN IF OK (FROM XWAIT)

	DCR	B		; DEC COUNTER
	JNZ	DHM1

	MVI	A,1		; SAY ERROR
	ORA	A
	RET
DHM2:
	CPI	4
	JZ	DHM4
	DCR	A
	DCR	A
	MOV	M,A
	INX	H
	MVI	M,0
	INX	H
	MVI	M,0
	CALL	XWAITH
	JMP	DHM3
DHM4:
	CALL	XWATXTH
	JMP	DHM3

	PAGE
;****************************************************************
;*								*
;*	READID	READ ID BLOCK OF DISK				*
;*		ENTER WITH DISK NUMBER IN [A]			*
;*		RETURNS ID BYTE IN [A]				*
;*								*
;****************************************************************

READID:
	STA	IDDISK		; SAVE DRIVE NUMBER TO TEST
	LDA	DTRIES		; SET UP RETRY COUNTER
	MOV	B,A		;   IN <B>
RDID1:
	LDA	IDDISK
	PUSH	B		; SAVE COUNTER
	CALL	DHOME		; RESTORE DISK
	POP	B		; RESTORE COUNTER
	LDA	IDDISK
	CPI	2
	JNC	RDID6
	CALL	IDSETUP		; SETUP COMMAND STRING FOR TK 0 READ
	CALL	IDDMA		; SETUP DMA FOR ID READ
	CALL	XWAIT		; SEND COMMAND AND WAIT FOR RESULT
RDID5:
	JZ	RDID2		; XWAIT RETURNS NZ IF ERR (SUCH AS SOFT ERR)
	DCR	B		; AT THIS POINT, WE HAVE AN ERROR
	JNZ	RDID1		;   LOOP ON COUNTER
	JMP	RDID3		;   IF COUNTER GETS TO 0, FORCE NON-TRK 0 READS
RDID2:
	CALL	IDCHECK		; CHECK FOR VALID ID
	RZ			; DONE IF VALID ID
RDID3:
	MVI	A,1		; PHYSICAL TRACK 1
	STA	TRKBYTE		; INTO COMMAND STRING

	MVI	A,1		; SECTOR 1
	STA	SECBYTE		; INTO COMMAND STRING

;
; TRY TO DETERMINE DENSITY BY PERFORMING NON-TRK 0 READS:
;
;   TRY SINGLE SIDED, SINGLE DENSITY
;
	LDA	IDDISK		; GET DRIVE # TO ID
	CALL	FORMDISK	; FORM DRIVE NUMBER, SINGLE SIDE, SD
	STA	DSKBYTE		;  FORCE DRIVE TYPE
	CALL	IDDMA		; SETUP DMA FOR ID READ
	CALL	XWAIT		; TEST READ TRACK 1
	MVI	A,0		; SINGLE DENSITY ID VALUE
	JZ	RDIDXT1		; RETURN ID CODE

	PAGE
;
;   THEN TRY SINGLE SIDED, DOUBLE DENSITY
;
	LDA	IDDISK		; GET DRIVE # TO ID
	CALL	FORMDISK	; FORM DRIVE NUMBER
	ORI	DDEN		; OR IN DOUBLE DENSITY
	STA	DSKBYTE		; FORCE DRIVE TYPE	
	CALL	IDDMA		; SETUP DMA FOR ID READ
	CALL	XWAIT		; TEST READ TRACK 1
	JNZ	RDIDXT2		; ERROR, RETURN ID ERROR
;
;   FINALLY, TRY DOUBLE SIDED, DOUBLE DENSITY
;
	LDA	IDDISK		; GET DRIVE # TO ID
	CALL	FORMDISK	; FORM DRIVE NUMBER
	ORI	DDEN		; OR IN DOUBLE DENSITY
	ORI	SIDE1		; OR IN DOUBLE SIDED
	STA	DSKBYTE		; FORCE DRIVE TYPE
	CALL	IDDMA		; SETUP DMA FOR READ
	CALL	XWAIT		; TEST READ TRACK 1 SIDE 1
	MVI	A,0000$0111B	; ID CODE FOR DOUBLE SIDED DOUBLE DENSITY
	JZ	RDIDXT1
	MVI	A,0000$0101B	; ID CODE FOR DOUBLE DENSITY

RDIDXT1:
	MOV	B,A		; SAVE CODE IN [B]
	XRA	A		; RESET FLAGS
	MOV	A,B		; RETURN CODE TO [A]
	RET

RDIDXT2:
	MVI	A,0FFH
	ORA	A		; SET NON ZERO FOR ERROR
	RET
RDID6:
	CALL	ALSETUP
	CALL	IDDMAH
	CALL	XWAITH
	JZ	BUILDALT
	DCR B
	JNZ	RDID1
	JMP	RDIDXT2
BUILDALT:
	LXI	H,HSTBUF
	LXI	D,13
	DAD	D
	LXI	D,ALTTAB
	LXI	B,24
	CALL	MOVE
	XRA	A
	RET

	PAGE
;****************************************************************
;*								*
;*	IDSETUP	SETUP COMMAND STRING FOR ID READ		*
;*		ENTER WITH DRIVE # IN [A]			*
;*								*
;****************************************************************


IDSETUP:
	LXI	H,CMDSTG

	MVI	M,READDAT	; SEND READ DATA COMMAND
	INX	H

	CALL	FORMDISK	; FORM DRIVE NUMBER
	MOV	M,A		; SAVE DRIVE NUMBER (SIDE 0, SINGLE DENSITY)
	INX	H

	MVI	M,0		; TRACK 0
	INX	H

	MVI	M,1		; SECTOR 1
	RET
ALSETUP:
	LXI	H,CMDSTG

	MVI	M,05		; SEND READ DATA COMMAND
	INX	H
	DCR	A
	DCR	A
	MOV	M,A		; SAVE DRIVE NUMBER (SIDE 0, SINGLE DENSITY)
	INX	H

	MVI	M,11		; SECTOR LOW
	INX	H

	MVI	M,0		; SECTOR HIGH
	RET


;****************************************************************
;*								*
;*	IDDMA	SETUP DMA CONTROLLER FOR ID READ		*
;*								*
;****************************************************************


IDDMA:
	LXI	H,HSTBUF
	SHLD	PMAADR

	LXI	H,128		; JUST READ FIRST 128 BYTES OF SECTOR
	JMP	RDDMA	
IDDMAH:
	LXI	H,HSTBUF
	SHLD	PMAADR
	LXI	H,128
	JMP	RDDMAH

	PAGE
;****************************************************************
;*								*
;*	IDCHECK READ BUFFER FOR VALID ID BLOCK			*
;*		RETURN Z SET IF VALID ID BLOCK			*
;*		RETURNS ID CODE IN [A]				*
;*								*
;****************************************************************


IDCHECK:
	LXI	H,HSTBUF	; POINT TO ID BUFFER
	LXI	D,CHKMSG	; AND CHECKSUM MESSAGE	
	MVI	B,8		; CHECK 1ST 8 BYTES
IDCK1:	LDAX	D		; GET BYTE TO CHECK
	CMP	M		; COMPARE
	JNZ	IDCK3		; NO COMPARE
	INX	H		; BUMP
	INX	D		; BUMP
	DCR	B		; COUNT DOWN
	JNZ	IDCK1		; LOOP TILL DONE

	LDA	HSTBUF+8	; GET ID BYTE
	MOV	B,A
	ANI	1111$1000B	; TEST FOR ZERO BITS
	JNZ	IDCK3		; INVALID ID CODE
	MOV	A,B		; RETURN ID CODE IN [A]
	RET			; AND Z SET

IDCK3:	MVI	A,0FFH		; BAD ID
	ORA	A
	RET


CHKMSG:	DB	'NCR FMT-'	; FORMAT BLOCK MSG



	PAGE
;****************************************************************
;*								*
;*	DMA ROUTINES						*
;*		ENTER WITH SECTOR SIZE IN [HL]			*
;*								*
;****************************************************************

WRTDMA:
	MVI	A,DMAWRT	; WRITE DMA COMMAND
	JMP	DMA1		; 

RDDMA:
	MVI	A,DMAREAD	; READ DMA COMMAND
DMA1:
	PUSH	PSW		; SAVE DMA COMMAND CODE
	PUSH	H		; SAVE SECTOR SIZE
	LHLD	PMAADR		; GET DMA ADDRESS
	MOV	A,L		; GET LO BYTE
	STA	DMALO		; SEND ADDRESS
	MOV	A,H		; 
	STA	DMAHI		; 
	POP	H		; RESTORE SECTOR SIZE
	MOV	A,L		; GET LO BYTE OF DMA COUNT
	STA	DMASIZL		; SEND LO BYTE OF COUNT
	POP	PSW		; GET COMMAND TO [A]
	ORA	H		; OR IN HI BYTE OF DMA COUNT
	STA	DMASIZH		; SEND HI BYTE OF COUNT AND COMMAND
	RET
WRTDMAH:
	MVI	A,DMAWRT	; WRITE DMA COMMAND
	JMP	DMA1H		; 

RDDMAH:
	MVI	A,DMAREAD	; READ DMA COMMAND
DMA1H:
	PUSH	PSW
	PUSH	H		; SAVE SECTOR SIZE
	LHLD	PMAADR		; GET DMA ADDRESS
	MOV	A,L		; GET LO BYTE
	STA	0FCA4H		; SEND ADDRESS
	MOV	A,H		; 
	STA	0FCA5H		; 
	POP	H		; RESTORE SECTOR SIZE
	MOV	A,L		; GET LO BYTE OF DMA COUNT
	STA	0FCA6H		; SEND LO BYTE OF COUNT
	POP	PSW		; GET COMMAND TO [A]
	ORA	H		; OR IN HI BYTE OF DMA COUNT
	STA	0FCA7H		; SEND HI BYTE OF COUNT AND COMMAND
	RET

	PAGE
;****************************************************************
;*								*
;*	XWAIT		SEND COMMAND        AND WAIT		*
;*			FOR STATUS				*
;*								*
;*	  RETURNS:	Z IF OK, NZ IF NOT OK			*
;*								*
;****************************************************************

XWAIT:
	LXI	H,CMDSTG	; POINT TO COMMAND STRING
	MVI	B,4		; 4 BYTES LONG
XWAT1:
	MOV	C,M		; GET A COMMAND BYTE
	CALL	SENCOM		; SEND TO CONTROLLER
	INX	H		; BUMP COMMAND POINTER
	DCR	B		; AND COUNT DOWN
	JNZ	XWAT1		; LOOP TILL DONE
XWAT2:
	LDA	DSTAT		; GET STATUS
	ANI	0C0H		; MASK OUT ALL BUT CONTROLLER BUSY &
				;   POLL RQST BITS
	CPI	80H		; THEN TEST FOR CONTROLLER BUSY
	JZ	XWAT2		; WAIT UNTIL CONTROLLER NOT BUSY

	STA	RSTSERV		; & THEN MAKE SERVICE REQUEST
	LDA	DSTAT		; GET DISK STATUS
	ANI	0FH
	CPI	2
	STA	BIORES		; SAVE STATUS OF CONTROLLER
				; NOT 0 = ERROR
	JZ 	XWATXT		; IT'S OK
	RET			; IT'S NOT OK

XWATXT:
	XRA	A
	STA	BIORES		; THIS IS TO STORE A ZERO TO
				; FLAG A GOOD OP
	RET


;****************************************************************
;*								*
;*	SENCOM	SEND COMMAND TO DISK CONTROLLER			*
;*		ENTER WITH COMMAND IN [C]			*
;*								*
;****************************************************************

SENCOM:	LDA	DSTAT		; GET STATUS BYTE
	ANI	80H		; MASK BUSY BIT
	JNZ	SENCOM		; LOOP TILL NOT BUSY
	MOV	A,C		; GET COMMAND
	STA	DCOMD		; AND SEND IT
	RET			; DONE

XWAITH:	
	LXI	D,CMDSTG	; POINT TO COMMAND STRING
	LXI	H,0FC61H
	CALL	CNTRLS
	CALL	RSRQP
	ANI	01FH
	CPI	2
	STA	BIORES		; SAVE STATUS OF CONTROLLER
				; NOT 0 = ERROR
	JZ 	XWATXTH		; IT'S OK
	RET			; IT'S NOT OK

XWATXTH:
	XRA	A
	STA	BIORES		; THIS IS TO STORE A ZERO TO
				; FLAG A GOOD OP
	RET
CNTRLS:
	LDAX	D
	MOV	M,A
	CALL	ACTIVE
	INX	D
	LDAX	D
	MOV	M,A
	CALL	ACTIVE
	INX	D
	LDAX	D
	MOV	M,A
	CALL	ACTIVE
	INX	D
	LDAX	D
	MOV	M,A
CNTRLS1:
	MOV	A,M
	ANI	40H
	JZ	CNTRLS1
	RET
RSRQP:
	INX	H
	INX	H
	INX	H
	MOV	M,A
	DCX	H
	DCX	H
	DCX	H
	MOV	A,M
	RET
ACTIVE:
	PUSH	B
	MVI	B,0FFH
ACTIVE1:
	DCR	B
	MOV	A,M
	RAL
	JC	ACTIVE1
	POP	B
	RET

	PAGE
;****************************************************************
;*								*
;*	RESET:	INITIALIZE PARAMETERS				*
;*								*
;****************************************************************


RESET:
	LXI	H,0100H		; RAM INIT OF TPA
	LXI	B,0DEFFH
	
CLR$LOOP:
	XRA	A
	MOV	M,A
	DCX	B
	INX	H
	ORA	C
	ORA	B
	JNZ	CLR$LOOP
	LXI	H,0707H
	SHLD	DRVTYP
	SHLD	DRVTYP+2

WRESET:
	MVI	A,0FFH
	STA	MONDSK
	MVI	B,4
	LXI	H,DRVTYP
RESET1:
	MOV	A,M
	ANI	NOT RDYBIT
	MOV	M,A
	INX	H
	DCR	B
	JNZ	RESET1
	LXI	H,0FFFFH		;SET TRK 0FFH
	SHLD	TKTBL
	SHLD	TKTBL+2
	CALL	CLOSE
	RET
INITMDSK:
	MVI	A,0
MDSK1:
	PUSH	PSW
	CALL	CMMERAM
	LXI	H,07000H
	LXI	B,1000H
	MVI	D,0E5H
MDSK2:
	MOV	M,D
	INX	H
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MDSK2
	POP	PSW
	INR	A
	CPI	48
	JNZ	MDSK1
	CALL	CMMDRAM
	RET

	


;****************************************************************
;*								*
;*	OFFSET	ADD [A] TO [HL] RESULT IN [HL]			*
;*								*
;****************************************************************

OFFSET:	ADD	L
	MOV	L,A
	RNC
	INR	H
	RET

	PAGE
;****************************************************************
;*								*
;*			USER AREA				*
;*								*
;****************************************************************

SUSER	EQU	$		  ; START OF USER AREA



VCINIT:		JMP	UCINIT
VWINIT:		JMP	UWINIT
VCONST:		JMP	UCONST
VCONIN:		JMP	UCONIN
VCONOUT:	JMP	UCONOT
VLIST:		JMP	ULIST
VPUNCH:		JMP	UPUNCH
VREADER:	JMP	UREADER
VLISTST:	JMP	ULISTST




UCINIT:	
	LDA	IOCONF
	STA	IOBYTE
	CALL	P1INIT
UWINIT:	RET


UCONST:
	LDA	IOBYTE
	CALL	DSPACH
	DW	KEYST
	DW	KEYST
	DW	KEYST
	DW	KEYST


UCONIN:
	LDA	IOBYTE
	CALL	DSPACH
	DW	KEYIN
	DW	KEYIN
	DW	KEYIN
	DW	KEYIN

	PAGE
UCONOT:
	LDA	IOBYTE
	CALL	DSPACH
	DW	VIDOUT
	DW	VIDOUT
	DW	VIDOUT
	DW	VIDOUT


UPUNCH:	LDA	IOBYTE
	RRC ! RRC ! RRC ! RRC
	CALL	DSPACH
	DW	VIDOUT
	DW	VIDOUT
	DW	P1CHROUT
	DW	VIDOUT


UREADER:	
	LDA	IOBYTE
	RRC ! RRC 
	CALL	DSPACH
	DW	KEYIN
	DW	KEYIN
	DW	KEYIN
	DW	KEYIN

ULIST:
	INR	B		; DOS SETS <B> TO 0FFH FOR BKPRNT
	JZ	BPLIST

	LDA	IOBYTE
	RLC ! RLC
ULIST1:
	CALL	DSPACH
	DW	VIDOUT
	DW	VIDOUT
	DW	P1CHROUT
	DW	VIDOUT

BPLIST:
	LDA	BPIOB		; GET BPKPRNT IOBYT INSTEAD OF REGULAR IOBYT
	JMP	ULIST1		; LST: BITS ARE ALREADY IN 0/1 POSITION


ULISTST:
	INR	B		; DOS SETS <B> TO 0FFH FOR BKPRNT
	JZ	BPLISTST

	LDA	IOBYTE
	RLC ! RLC
ULISTST1:
	CALL	DSPACH
	DW	KEYST
	DW	KEYST
	DW	P1STATUS
	DW	KEYST

BPLISTST:
	LDA	BPIOB		; GET BPKPRNT IOBYT INSTEAD OF REGULAR IOBYT
	JMP	ULISTST1	; LST: BITS ARE ALREADY IN 0/1 POSITION

	PAGE
DSPACH:
	ANI	3
	ADD	A		; 2 BYTE TABLES
	POP	H		; RETURN ADDRESS IS REALLY TABLE BASE
	ADD	L
	MOV	L,A
	JNC	DSP1
	INR	H
DSP1:
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A
	PCHL

	PAGE
;****************************************************************
;*								*
;*			CRT EQUATES				*
;*								*
;****************************************************************


WXPOS	EQU	0C0H		; WRITE CURSOR X
RXPOS	EQU	0C0H		; READ CURSOR X
WYPOS	EQU	0C1H		; WRITE CURSOR Y
RYPOS	EQU	0C1H		; READ CURSOR Y
WDCHR	EQU	0C2H		; WRITE DISPLAY CHARACTER
RDCHR	EQU	0C2H		; READ DISPLAY CHARACTER
WCCHR	EQU	0C3H		; WRITE CONTROL CHARACTER
RCCHR	EQU	0C3H		; READ CONTROL CHARACTER
HSYNEN	EQU	0C4H		; HORIZ. SYNC ENABLE

MWXPOS	EQU	0FCC0H		; WRITE CURSOR X
MRXPOS	EQU	0FCC0H		; READ CURSOR X
MWYPOS	EQU	0FCC1H		; WRITE CURSOR Y
MRYPOS	EQU	0FCC1H		; READ CURSOR Y
MWDCHR	EQU	0FCC2H		; WRITE DISPLAY CHARACTER
MRDCHR	EQU	0FCC2H		; READ DISPLAY CHARACTER
MWCCHR	EQU	0FCC3H		; WRITE CONTROL CHARACTER
MRCCHR	EQU	0FCC3H		; READ CONTROL CHARACTER
MHSYNEN	EQU	0FCC4H		; HORIZ. SYNC ENABLE


SCWID	EQU	80
ROWS	EQU	24




	PAGE
;****************************************************************
;*								*
;*	VIDOUT		SCREEN DRIVER				*
;*								*
;****************************************************************


VIDOUT:	PUSH	B
	PUSH	D
	PUSH	H
	LDA	ESCFLG		; SEE IF
	ORA	A		; ESCAPE SEQUENCE IN PROGRESS
	JNZ	DOESC		; YES, DO IT.
	LDA	DRQ		; SEE IF SOMEBODY
	ORA	A		; WANTS DATA
	JZ	VID1		; NO, JUST DO VIDEO
	LHLD	DRQADR		; ELSE GET ADDRESS OF REQUESTEE
	PCHL			; AND HOP TO IT


VID1:	MOV	A,C		; GET CHARACTER
	CPI	' '		; CHECK FOR CONTROL CHARACTER
	JC	SEARCHC		; CHECK CONTROL CHAR LIST
PUTCHR:
	LDA	INVFLG		; GET INVERSE VIDEO FLAG
	ADD	C		; GET CHARACTER
	STA	MWDCHR		; PLACE CHAR INTO MEMORY
	CALL	BUMPCUR		; BUMP CURSOR POSITION

NULL:
;
	POP	H		; RESTORE ENVIRONMENT
	POP	D		; 
	POP	B		; 
	RET			; AND RETURN



	PAGE
;****************************************************************
;*								*
;*	BUMPCUR	BUMP CURSOR POSITION				*
;*								*
;****************************************************************


BUMPCUR:
	LDA	CURCOL		; GET CURRENT COLUMN NUMBER
	INR	A
	CPI	SCWID		; SEE IF = WIDTH
	JNC	BMPCR1		; BEYOND LAST COLUMN
	STA	CURCOL		; SAVE NEW COLUMN
	RET

	
BMPCR1:
	LDA	CURROW		; GET CURRENT ROW
	CPI	ROWS-1		; SEE IF ON LAST ROW
	JNZ	BMPCR2		; NOT ON LAST ROW
	LDA	RAPFLG		; GET 
	ORA	A		; SEE IF SET
	RZ			; WRAP AROUND NOT SET
	XRA	A
	STA	CURCOL
;	LDA	CURROW
	CALL	SCROLLUP
	RET	


BMPCR2:	XRA	A		; ZERO
	STA	CURCOL		; COLUMN
	LDA	CURROW
	INR	A
	STA	CURROW
	RET








	PAGE
;****************************************************************
;*								*
;*	DOESC	PROCESS ESCAPE SEQUENCE				*
;*		ENTER WITH CONTROL CHAR IN [C]			*
;*								*
;****************************************************************


DOESC:	XRA	A		; ZERO OUT
	STA	ESCFLG		; ESCAPE FLAG
	MOV	A,C		; CHARACTER TO [A] FOR LOOKUP
	LHLD	CURPOS		; GET CURRENT CURSOR POSITION
	PUSH	H		; WILL WIND UP IN [HL]
	LXI	H,ESCTBL	; POINT TO ESCAPE TABLE
	JMP	LOOKUP		; LOOKUP PROPER ROUTINE


ESCSEQ:	MVI	A,0FFH
	STA	ESCFLG
	JMP	NULL

ESCTBL:	DB	58
	DW	VCLEAR		; CLEAR SCREEN
	DB	2AH
	DW	VCLEAR
	DB	29H
	DW	SETINV		; SET INVERSE VIDEO
	DB	28H
	DW	RESINV		; RESET INVERSE VIDEO
	DB	'L'
	DW	GRAPH		; ENTER GRAPHICS CHARACTER
	DB	'Y'
	DW	EEOS		; ERASE TO END OF SCREEN
	DB	'y'
	DW	EEOS		; ERASE TO END OF SCREEN
	DB	'T'
	DW	EEOL		; ERASE TO END OF LINE
	DB	'E'
	DW	INSLIN		; INSERT LINE
	DB	'R'
	DW	DELLIN		; DELETE LINE
	DB	'Q'
	DW	INSCHR		; INSERT CHARACTER
	DB	'W'
	DW	DELCHR		; DELETE CHARACTER
	DB	'='
	DW	POSCUR		; POSITION CURSOR
	DB	'G'
	DW	REVERSE		;REVERSE VIDEO ON OFF
	DB	0FFH
	DW	NULL



	PAGE
;****************************************************************
;*								*
;*	POSCUR	POSITION CURSOR					*
;*								*
;****************************************************************


POSCUR:	
	MVI	A,0FFH		; SETUP 
	STA	DRQ		; DATA REQUEST FLAG
	LXI	H,GETY		; Y ACQUISITION ROUTINE
	SHLD	DRQADR		; SAVE DRQ ADDRESS
	JMP	NULL		; RESET CURSOR


GETY:
	MOV	A,C		; GET DATA
	SUI	' '		; SUBTRACT OFFSET
	STA	YPOS		; SAVE ROW NUMBER
	LXI	H,GETX		; GET ADDRESS OF NEXT ROUTINE
	SHLD	DRQADR		; WHICH NEEDS DATA
	JMP	NULL


GETX:	MOV	A,C		; GET DATA
	SUI	' '		; SUBTRACT OFFSET
	STA	XPOS		; SAVE X POSITION

	XRA	A		; RESET
	STA	DRQ		; DATA REQUEST FLAG

	LDA	YPOS		; GET ROW NUMBER
	MOV	H,A		; INTO [H]
	LDA	XPOS		; GET COLUMN NUMBER
	MOV	L,A		; INTO [L]
	SHLD	CURXY		; SAVE NEW POSITION
	CALL	WRITEPOS	; WRITE NEW POSITION
	JMP	NULL		; [HL] IS NOW CURSOR POSITION



	PAGE
;****************************************************************
;*								*
;*	SETINV	SET INVERSE VIDEO				*
;*								*
;****************************************************************

REVERSE:
	MVI	A,0FFH
	STA	DRQ		;SET DATA REQUEST FLAG
	LXI	H,REVERS1
	SHLD	DRQADR		;SAVE DRQ ADDRESS
	JMP	NULL
REVERS1:
	MOV	A,C
	CPI	'4'
	MOV	A,0
	STA	DRQ
	JNZ	RESINV
SETINV:	
	MVI	A,00H		;SET INVERSFLAG
	STA	INVFLG
	JMP	NULL



;****************************************************************
;*								*
;*	RESINV	RESET INVERSE VIDEO				*
;*								*
;****************************************************************


RESINV:	
	XRA	A		; RESET INVERS FLAG
	STA	INVFLG
	JMP	NULL



	PAGE
;****************************************************************
;*								*
;*	GRAPH		SETUP GRAPHICS CHARACTER REQUEST	*
;*								*
;****************************************************************


GRAPH:
	MVI	A,0FFH		; SET DATA
	STA	DRQ		; REQUEST FLAG
	LXI	H,PUTGRC	; GET ADDRESS OF NEXT ROUTINE
	SHLD	DRQADR		; WHICH NEEDS DATA
	JMP	NULL



;****************************************************************
;*								*
;*	PUTGRC		PLACE GRAPHICS CHARACTER		*
;*								*
;****************************************************************


PUTGRC:	XRA	A			; RESET
	STA	DRQ			; DATA REQUEST FLAG
	JMP	PUTCHR			; AND PLACE CHARACTER ON SCREEN




	PAGE
;****************************************************************
;*								*
;*	INSLIN	INSERT LINE AT CURSOR POSITION			*
;*		CURSOR REMAINS STATIONARY, REST OF SCREEN MOVES	*
;*		DOWN 1 LINE					*
;*								*
;****************************************************************


INSLIN:	LDA	CURROW		; GET ROW NUMBER
	CALL	SCROLLDN	; SCROLL SCREEN DOWN
	JMP	NULL



;****************************************************************
;*								*
;*	DELLIN	DELETE LINE AT CURSOR POSITION			*
;*		CURSOR REMAINS STATIONARY, REST OF SCREEN MOVES	*
;*		UP 1 LINE					*
;*								*
;****************************************************************


DELLIN:
	LDA	CURROW		; GET ROW NUMBER
	CALL	SCROLLUP	; SCROLL SCREEN UP
	JMP	NULL		; AND RESTORE IT


	PAGE
;****************************************************************
;*								*
;*	INSCHR	INSERT CHARACTER AT CURSOR POSITION		*
;*		REST OF LINE MOVES OUT 1 CHAR, LAST FALLING OFF	*
;*		THE END OF THE LINE				*
;*								*
;****************************************************************


INSCHR:
	LDA	CURCOL			; GET NUMBER OF COL POSITIONS TO MOVE
	MOV	C,A
	MVI	A,SCWID-1
	SUB	C
	JZ	INSCH2			; IF NONE TO MOVE THEN JUMP OUT

	MOV	C,A			; SAVE IN [C] AS COUNT

	LHLD	CURXY			; GET CURRENT POSITION
	MVI	L,SCWID-2		; START MOVING FROM CHAR BEFORE LAST

INSCH1:
	CALL	WRHLPOS			; GET CHAR POINTED IN HL
	LDA	MWCCHR			; RECYCLE THE ATTRIBUTE
	MOV	B,A			; SAVE IT
	LDA	MRDCHR			; READ THE CHAR
	INR	L			; POINT TO NEXT CHAR

	CALL	WRHLPOS			
	MOV	D,A			; SAVE THE CHR A BIT
	MOV	A,B			; RESTORE THE ATTRIBUTE
	STA	MWCCHR			; AND PUT IT IN NEW POS
	MOV	A,D			; RESTORE THE CURSOR
	STA	MWDCHR			; MOVE IN NEXT CHAR

	DCR	L			; SET TO MOVE NEXT CHAR
	DCR	L
	DCR	C			; DEC THE COUNTER
	JNZ	INSCH1			; LOOP TILL DONE

INSCH2:	
	CALL	WRITEPOS		; RESTORE THE CURSOR
	MVI	C,' '			; PUT A SPACE AT CUR LOC
	LDA	INVFLG			; SET IN INVERS STUFF
	STA	MWCCHR			; SAVE AS ATTRIBUTE
	MOV	A,C			; GET CHAR BACK
	STA	MWDCHR			; SAVE IT
	CALL	WRITEPOS		; MOVE IT BACK
	JMP	NULL
	
	PAGE
;****************************************************************
;*								*
;*	DELCHR	DELETE CHARACTER AT CURSOR POSITION		*
;*		REST OF LINE MOVES IN 1 CHAR, LEAVING A SPACE	*
;*		AT THE END OF THE LINE				*
;*								*
;****************************************************************

DELCHR:	
	LDA	CURCOL			; GET NUMBER OF COL POSITIONS TO MOVE
	MOV	C,A
	MVI	A,SCWID-1
	SUB	C
	JZ	DELCH2			; IF NONE TO MOVE THEN JUMP OUT

	MOV	C,A			; SAVE IN [C] AS COUNT

	LHLD	CURXY			; GET CURRENT POSITION
	LDA	CURCOL			; MOVE IN AS FROM LOCATION
	INR	A			; START AT PRES + 1
	MOV	L,A			; MOVE IN AS START LOCATION

DELCH1:
	CALL	WRHLPOS			; GET CHAR POINTED IN HL
	LDA	MRCCHR			; MOVE ATTRIBUTE
	MOV	B,A			; SAVE IT
	LDA	MWDCHR			; READ THE CHAR
	DCR	L			; POINT TO NEXT CHAR
	CALL	WRHLPOS			
	MOV	D,A			; SAVE CHAR A BIT
	MOV	A,B			; GET BACK ATTRIBUTE
	STA	MWCCHR
	MOV	A,D			; RESETORE CHAR
	STA	MWDCHR			; MOVE IN NEXT CHAR
	INR	L			; SET TO MOVE NEXT CHAR
	INR	L
	DCR	C			; DEC THE COUNTER
	JNZ	DELCH1			; LOOP TILL DONE

DELCH2:	
	LHLD	CURXY			; PUT A SPACE AT THE END OF THE LINE
	MVI	L,SCWID-1
	CALL	WRHLPOS
	MVI	C,' '			; PUT A SPACE AT CUR LOC
	LDA	INVFLG			; SET IN INVERSFLAG
	STA	MWCCHR
	MOV	A,C			; GET CHAR TO [A]
	STA	MWDCHR			; SAVE IT
	CALL	WRITEPOS		; MOVE IT BACK
	JMP	NULL

	PAGE
;****************************************************************
;*								*
;*	EEOL	ERASE TO END OF LINE				*
;*								*
;****************************************************************


EEOL:	CALL	ICLEOL		; CLEAR TO END OF ROW
	JMP	NULL		; AND DONE



;****************************************************************
;*								*
;*	EEOS	ERASE TO END OF SCREEN				*
;*								*
;****************************************************************


EEOS:
	JMP	CLEOS		; 




	PAGE
;****************************************************************
;*								*
;*	NDFS	NON DESTRUCTIVE FORWARD SPACE			*
;*								*
;****************************************************************

NDFS:
	LDA	CURCOL		; GET CURRENT COLUMN
	INR	A		; BUMP IT
	STA	CURCOL
	CPI	SCWID		; SEE IF OVERFLOW
	JC	NDFS1		; DONE IF NO OVERFLOW
	CALL	COLUM0		; RETURN TO COLUMN 0
	CALL	ILF		; DO LINEFEED
NDFS1:	CALL	WRITEPOS
	JMP	NULL		; 



;****************************************************************
;*								*
;*	ILF	INTERNAL LINE FEED				*
;*								*
;****************************************************************

ILF:
	LDA	CURROW		; GET CURRENT ROW NUMBER
	INR	A		; BUMP IT
	CPI	ROWS
	JNC	ILF1		; SCOLL IF CARRY
	STA	CURROW
	CALL	WRITEPOS	; UPDATE CUR CURSOR POSITION
	RET
ILF1:
	MVI	A,0
	JMP	SCROLLUP



;****************************************************************
;*								*
;*	LINEFD	DO LINEFEED					*
;*								*
;****************************************************************


LINEFD:
	CALL	ILF
	JMP	NULL


	PAGE
;****************************************************************
;*								*
;*	CARRET	CARRIAGE RETURN					*
;*								*
;****************************************************************

CARRET:
	CALL	COLUM0		; GET CURSOR POS FOR COLUMN 0
	JMP	NULL		; AND DONE



;****************************************************************
;*								*
;*	BACKSP	BACKSPACE CURSOR				*
;*								*
;****************************************************************

BACKSP:
	LDA	CURCOL		; GET COLUMN NUMBER
	DCR	A		; BUMP DOWN COLUMN
	JP	BKSP1		; NOT PAST COLUMN 0
	LDA	CURROW		; 
	DCR	A		; 
	JP	BKSP2		; 
	MVI	A,0		; 
BKSP2:
	STA	CURROW		;
	MVI	A,SCWID-1	; 
BKSP1:
	STA	CURCOL		; SAVE NEW COLUMN
	CALL	WRITEPOS	;   & WRITE THE NEW POSITION
	JMP	NULL		; DONE

	PAGE
;****************************************************************
;*								*
;*	RLF	REVERSE LINE FEED				*
;*								*
;****************************************************************

RLF:
	LDA	CURROW		; GET CURRENT ROW
	DCR	A		; BUMP DOWN
	JM	RLF1
	STA	CURROW		; SAVE NEW ROW
RLF1:
	CALL	WRITEPOS
	JMP	NULL



;****************************************************************
;*								*
;*	BELL	RING THE BELL					*
;*								*
;****************************************************************

BELL:
	STA	KBELL
	JMP	NULL

	PAGE
;****************************************************************
;*								*
;*	VHOME	HOME CURSOR					*
;*								*
;****************************************************************

VHOME:
	CALL	IHOME		; DO HOME
	JMP	NULL		; DONE


;****************************************************************
;*								*
;*	IHOME	PHYSICAL INTERNAL HOME CURSOR			*
;*								*
;****************************************************************

IHOME:
	LXI	H,0		; CURSOR POSITION
	SHLD	CURXY		; ESTABLISH CURSOR POSITION
	CALL	WRITEPOS	; WRITE NEW CURSOR POSITION
	RET



;****************************************************************
;*								*
;*	VCLEAR	CLEAR SCREEN, HOME CURSOR			*
;*								*
;****************************************************************


VCLEAR:
	CALL	IHOME		; HOME CURSOR
	LXI	B,ROWS*SCWID	; # OF SPACES TO CLEAR
	CALL	SPCLEAR		; CLEAR TO SPACES
	JMP	NULL		; CURSOR WILL HAVE WRAPPED AROUND TO 
				; TOP OF PAGE





	PAGE
;****************************************************************
;*								*
;*	CLEOS	CLEAR FROM CURRENT ROW TO END OF SCREEN		*
;*								*
;****************************************************************


CLEOS:
	LDA	CURROW		;FIND LINES TO DO
	MOV	C,A
	MVI	A,ROWS-1
	SUB	C
	JZ	CLEOS1		; IF 0, JUST CLEAR CURRENT ROW

	MVI	L,0		; SET  COL TO 0
	MOV	H,C		; GET CURROW TO H
	INR	H		; BUMP ROW NUMBER
	CALL	WRHLPOS		; WRITE CURSOR POSITION
	LXI	H,SCWID		; CALCULATE # OF BYTES TO CLEAR
	CALL	MULT		; 
	MOV	C,L		; # OF BYTES TO [BC]
	MOV	B,H
	CALL	SPCLEAR		; CLEAR TO SPACES
	CALL	WRITEPOS	; RESTORE CURRENT POS

CLEOS1:
	CALL	ICLEOL
	JMP	NULL

	PAGE
;****************************************************************
;*								*
;*	ICLEOL	CLEAR FROM CURRENT CURSOR TO END OF LINE	*
;*								*
;****************************************************************

ICLEOL:
	LDA	CURCOL		; GET CURRENT COLUMN NUMBER
	MOV	B,A		; CURSOR TO [B]
	MVI	A,SCWID		; MAX CLEAR 80 BYTES
	SUB	B
	RZ			; DONE IF NO BYTES TO CLEAR
	MVI	B,0		; 
	MOV	C,A		; NUMBER OF BYTES TO CLEAR IN [BC]
	CALL	SPCLEAR		; CLEAR TO SPACES
	CALL	WRITEPOS	; RE-ESTABLISH OLD CURSOR POSITION
	RET



;****************************************************************
;*								*
;*	CLRLIN	CLEAR ROW IN <A> TO SPACES			*
;*								*
;****************************************************************

CLRLIN:
	MOV	H,A		; PUT ROW IN <H>,
	MVI	L,0		;   & SET COLUMN TO 0
	CALL	WRHLPOS		; POSITION CURSOR TO BEG OF LINE
	LXI	B,SCWID		; GET SCREEN WIDTH
	CALL	SPCLEAR		; & CLEAR THE LINE
	CALL	WRITEPOS	; REESTABLISH CUR CURSOR POSITION
	RET



;****************************************************************
;*								*
;*	SPCLEAR	CLEAR [BC] BYTES TO SPACES			*
;*								*
;****************************************************************


SPCLEAR:
	PUSH	B		; SAVE [BC]
	MVI	C,' '		; GET A SPACE
	MOV	E,C		; CLEAR CHARACTER TO [E]
	POP	B		; RESTORE [BC]
	LXI	H,MWDCHR	; POINT TO WRITE DATA CHAR PORT
	LDA	INVFLG		; GET INVLG TO D
	MOV	D,A
SPCL1:
	MOV	A,B		; TEST FOR 0
	ORA	C
	RZ			; DONE IF 0
	INX	H		; BUMP POUNTER TO ATTRIBUTE WINDOW
	MOV	M,D		; PUT IN
	DCX	H		; PUT POINTER BACK
	MOV	M,E		; WRITE A SPACE
	DCX	B		; COUNT DOWN
	JMP	SPCL1


	
	PAGE
;****************************************************************
;*								*
;*	COLUM0	ZERO CURRENT COLUMN				*
;*								*
;****************************************************************

COLUM0:
	XRA	A		; ZERO
	STA	CURCOL		; CURRENT COLUMN
	CALL	WRITEPOS	; WRITE CURSOR POSITION
	RET




	PAGE
;****************************************************************
;*								*
;*	SCROLLUP	SCROLLS UP 1 LINE			*
;*		ENTER WITH [A] = ROW NUMBER FOR START OF SCROLL	*
;*								*
;****************************************************************


SCROLLUP:
	MOV	B,A		; STARTING ROW TO [B]
	MVI	A,ROWS-1	; FIND NUMBER OF TABLE ENTRIES TO MOVE
	SUB	B		; CALC # OF LINES TO ACTUALLY SCROLL
	JZ	SCLUP2		; IF NON TO MOVE JUMP
	MOV	C,A		; NUMBER OF ROWS TO MOVE IN [C]
SCLUP1:
	CALL	MUROW		; AND MOVE ROW UP
	INR	B
	DCR	C
	JNZ	SCLUP1
;
SCLUP2:
	MVI	A,ROWS-1	; CLEAR THE BOTTOM LINE
	CALL	CLRLIN
	LHLD	CURXY		; SET CURRENT LINE TO COL 0
	MVI	L,0
	SHLD	CURXY
	CALL	WRITEPOS
	RET


;****************************************************************
;*								*
;*	SCROLLDN	SCROLLS DOWN 1 LINE			*
;*		ENTER WITH [A] = ROW NUMBER FOR START OF SCROLL	*
;*								*
;****************************************************************


SCROLLDN:
	PUSH	PSW		; SAVE ENTRY ROW
	MOV	B,A		; STARTING ROW TO [B]
	MVI	A,ROWS-1	; FIND NUMBER OF TABLE ENTRIES TO MOVE
	SUB	B		; CALC # OF LINES TO ACTUALLY SCROLL
	JZ	SCLDN2		; IF NONE TO MOCE JUMP
	MOV	C,A		; NUMBER OF ROWS TO MOVE IN [C]
	MVI	B,ROWS-2	; START AT ROW BEFORE FIRST
SCLDN1:
	CALL	MDROW		; AND MOVE ROW UP
	DCR	B
	DCR	C
	JNZ	SCLDN1
;
SCLDN2:
	POP	PSW		; GET ROW THAT ENTERED WITH
	CALL	CLRLIN		; AND CLEAR IT
	LHLD	CURXY		; SET CURRENT LINE TO COL 0
	MVI	L,0
	SHLD	CURXY
	CALL	WRITEPOS
	RET

	PAGE
;****************************************************************
;*								*
;*	MDROW	MOVE ROW IN [B] TO ROW B+1			*
;*								*
;****************************************************************

MDROW:
	PUSH	B		; 
	PUSH	D		; 
	PUSH	H		; 
	MVI	C,SCWID		; GET COLUMN COUNTER
	MOV	H,B		; ROW NUMBER TO [H]
	MVI	L,0		; STARTING COLUMN NUMBER
MDROW1:
	CALL	WRHLPOS		; SET CURSOR
	LDA	MRCCHR		; GET ATTRIBUTE
	MOV	B,A		; SAVE IT
	LDA	MRDCHR		; GET CHARACTER

	INR	H		; BUMP ROW NUMBER
	CALL	WRHLPOS		; SET CURSOR
	MOV	D,A		; SAVE THE CHAR A BIT
	MOV	A,B		; GET IN ATTRIBUT
	STA	MWCCHR		; WHITE THE ATTRIBUTE
	MOV	A,D		; RESTORE THE CURSOR
	STA	MWDCHR		; WRITE DATA CHARACTER

	DCR	H		; RESTORE SOURCE ROW
	INR	L		; BUMP COLUMN NUMBER
	DCR	C		; COUNT DOWN
	JNZ	MDROW1		; LOOP TILL DONE
	POP	H		; 
	POP	D		; 
	POP	B		; RESTORE REGS
	RET



	PAGE
;****************************************************************
;*								*
;*	MUROW	MOVE ROW IN [B+1] TO ROW B			*
;*								*
;****************************************************************

MUROW:
	PUSH	B		; 
	PUSH	D		; 
	PUSH	H		; 
	MVI	C,SCWID		; GET COLUMN COUNTER
	MOV	H,B		; ROW NUMBER TO [H]
	INR	H
	MVI	L,0		; STARTING COLUMN NUMBER
MUROW1:
	CALL	WRHLPOS		; SET CURSOR
	LDA	MRCCHR		; GET THE CURSOR
	MOV	B,A		; SAVE A BIT
	LDA	MRDCHR		; GET CHARACTER

	DCR	H		; BUMP ROW NUMBER
	CALL	WRHLPOS		; SET CURSOR
	MOV	D,A		; SAVE THE CHAR
	MOV	A,B		; GET BACK THE ATTRIBUTE
	STA	MWCCHR		; AND PUT IT IN
	MOV	A,D		; GET BACK THE CHAR
	STA	MWDCHR		; WRITE DATA CHARACTER

	INR	H		; RESTORE SOURCE ROW
	INR	L		; BUMP COLUMN NUMBER
	DCR	C		; COUNT DOWN
	JNZ	MUROW1		; LOOP TILL DONE
	POP	H		; 
	POP	D		; 
	POP	B		; RESTORE REGS
	RET

	PAGE
;****************************************************************
;*								*
;*	WRITEPOS	WRITE CURRENT ROW/COL TO CRT		*
;*								*
;****************************************************************


WRITEPOS:
	LDA	CURROW		; GET CURRENT ROW
	STA	MWYPOS		; SEND TO CRT
	LDA	CURCOL		; GET CURRENT COLUMN
	STA	MWXPOS		; SEND TO CRT
	RET



;****************************************************************
;*								*
;*	WRHLPOS		WRITE CURRENT ROW/COL TO CRT		*
;*		ENTER WITH COLUMN IN [L], ROW IN [H]		*
;*								*
;****************************************************************


WRHLPOS:
	PUSH	PSW
	MOV	A,H		; GET CURRENT ROW
	STA	MWYPOS		; SEND TO CRT
	MOV	A,L		; GET CURRENT COLUMN
	STA	MWXPOS		; SEND TO CRT
	POP	PSW
	RET

	PAGE
;****************************************************************
;*								*
;*		MISC. SUBROUTINES				*
;*								*
;****************************************************************


;****************************************************************
;*								*
;*	MULT		MULTIPLY [A] BY [HL] 			*
;*		RETURNS PRODUCT IN[HL]				*
;*								*
;****************************************************************


MULT:	XCHG
	LXI	H,0
	LXI	B,800H		; B IS LOOP COUNTER, C IS OVERFLOW INDICATOR
MUL1:	DAD	H
	JNC	MUL2
	INR	C		; BUMP OVERFLOW
MUL2:	RLC			; ROTATE NEXT BIT OF MULTIPLICAND INTO CARRY
	JNC	MUL3
	DAD	D
	JNC	MUL3
	INR	C
MUL3:	DCR	B
	JNZ	MUL1
	MOV	A,C		; SEE IF OVERFLOW
	ORA	A		; TEST ZERO FLAG AND RESET CARRY
	RZ
	STC			; CARRY INDICATES OVERFLOW
	RET




;****************************************************************
;*								*
;*	MUL128	MULTIPLY [A] BY 128				*
;*		RESULT IN [HL]					*
;*								*
;****************************************************************


MUL128:	ORA	A		; RESET CARRY
	RAR			; CARRY TO BIT 7 ETC.
	MOV	H,A		; RESTORE NEW HI BYTE
				; BYTE 0 OF [L] IS IN CARRY
	MVI	A,0		; ZER0 TO [A]
	RAR			; ROTATE
	MOV	L,A		; LO BYTE OF PRODUCT BACK TO [L]
	RET			;



;****************************************************************
;*								*
;*	SCTOBU	MOVE SCREEN WIDTH BYTES FROM [HL] TO [DE]	*
;*								*
;****************************************************************


;****************************************************************
;*								*
;*	MOVWID	MOVE SCREEN WIDTH BYTES FROM [HL] TO [DE]	*
;*								*
;****************************************************************


MOVWID:	LXI	B,SCWID		; NUMBER OF BYTES TO MOVE
MOVE:	MOV	A,M		; GET BYTE FROM SOURCE
	STAX	D		; AND STUFF AT DEST
	INX	H		; BUMP SOURCE
	INX	D		; AND DEST
	DCX	B		; COUNT DOWN
	MOV	A,B
	ORA	C		; TEST FOR ZERO
	JNZ	MOVE		; LOOP TILL DONE
	RET



	PAGE
;****************************************************************
;*								*
;*	SEARCHC	SEARCH FOR CHARACTER IN LOOKUP TABLE		*
;*								*
;****************************************************************



SEARCHC:
	LHLD	CURPOS		; CURSOR POSITION TO TOS
	PUSH	H		; 
	LXI	H,COMTBL	; POINT TO COMMAND TABLE



;****************************************************************
;*								*
;*	LOOKUP	FIND ROUTINE ADDRESS IN TABLE			*
;*		ENTER WITH CHAR TO MATCH IN [A]			*
;*		      [HL] ON TOS				*
;*		LAST TABLE ENTRY MUST BE FF AND DEFAULT ROUTINE	*
;*								*
;****************************************************************


LOOKUP:
	CMP	M		; CHECK FOR MATCH
	JZ	LOOKF		; YES, FOUND IT
	MOV	B,M		; GET CHAR FROM TABLE INTO [B]
	INR	B		; IS IT LAST CH
	JZ	LOOKF		; UNDEFINED CONTROL CHARACTER, DO NULL ROUTINE
	INX	H
	INX	H
	INX	H		; BUMP TO NEXT ENTRY
	JMP	LOOKUP		; KEEP LOOKING
;
LOOKF:
	INX	H		; BUMP TO ADDRESS
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG			; ADDRESS TO [HL]
	XTHL			; SWAP [HL] AND TOS
	RET			; GO TO TARGET ADDRESS



	PAGE
;****************************************************************
;*								*
;*	COMTBL	COMMAND TABLE FOR LOOKUP			*
;*								*
;****************************************************************


COMTBL:
	DB	0
	DW	NULL
	DB	7
	DW	BELL	; RING THE BELL
	DB	8
	DW	BACKSP
	DB	10
	DW	LINEFD	; LINE FEED
	DB	0BH
	DW	RLF	; REVERSE LINE FEED
	DB	0CH
	DW	NDFS	; NON DESTRUCTIVE FORWARD SPACE
	DB	0DH	
	DW	CARRET	; CARRIAGE RETURN
	DB	17H
	DW	EEOL	; ERASE TO END OF LINE
	DB	1AH
	DW	VCLEAR	; CLEAR SCREEN
	DB	1BH
	DW	ESCSEQ	; ESCAPE SEQUENCES
	DB	1EH
	DW	VHOME	; HOME CURSOR
	DB	0FFH	; END OF TABLE
	DW	NULL	; DO NUTTIN ROUTINE



	PAGE
;****************************************************************
;*								*
;*		VIDEO DATA AREA					*
;*								*
;****************************************************************


CURXY	EQU	$
CURCOL:	DB	$-$		; CURRENT COLUMN NUMBER
CURROW:	DB	$-$		; CURRENT ROW NUMBER

TMPXY	EQU	$		; TEMPORARY ROW/COL STORAGE
TMPCOL:	DB	$-$
TMPROW:	DB	$-$

OLDROW:	DW	$-$		; OLD ROW/COLUMN POSITION

CURPOS:	DW	$-$		; CURSOR POSITION IN RAM
DRQ:	DB	$-$		; DATA REQUEST FLAG
ESCFLG:	DB	$-$		; ESCAPE FLAG
INVFLG:	DB	$-$		; INVERSE VIDEO FLAG
RAPFLG:	DB	$-$		; WRAP AT END OF PAGE
DRQADR:	DW	$-$		; DATA REQUEST ADDRESS POINTER
DCBYTE:	DB	$-$		; CURRENT DISPLAY CONTROL BYTE
SCROW:	DB	$-$		; SCROLLING ROW NUMBER

XPOS:	DB	$-$		; 
YPOS:	DB	$-$		; CURSOR CONTROL DATA


ENVID	EQU	$		  ; END OF VIDEO DRIVER





	PAGE
;*****************************************************************
;*****************************************************************
;**								**
;**		      KEYBOARD ROUTINES				**
;**								**
;*****************************************************************
;*****************************************************************



;****************************************************************
;*								*
;*		      KEYBOARD EQUATES				*
;*								*
;****************************************************************


KEYBASE	EQU	0FC28H		; BASE ADDRESS OF KEYBOARD

WDKEY	EQU	KEYBASE		; WRITE DATA TO KEYBOARD
RDKEY	EQU	KEYBASE		; READ DATA FROM KEYBOARD
CLKENA	EQU	KEYBASE+1	; CLEAR KEYBOARD ENA
RSKEY	EQU	KEYBASE+1	; READ KEYBOARD STATUS
KEYEI	EQU	KEYBASE+2	; ENABLE KEYBOARD INTERRUPTS
KEYDI	EQU	KEYBASE+3	; DISABLE KEYBOARD INTERRUPTS
RSKSRQ	EQU	KEYBASE+4	; RESET KEYBOARD SERVICE REQUEST
KDIAGC	EQU	KEYBASE+5	; DIAGNOSTIC CLEAR
KBELL	EQU	KEYBASE+6	; RING BELL
KEYRES	EQU	KEYBASE+7	; RESET KEYBOARD INTERFACE


KBDAT	EQU	10H		; DATA READY BIT
KBENA	EQU	20H		; ENTRY NOT ACCEPTED BIT
KBBRK	EQU	40H		; KEYBOARD BREAK BIT




	PAGE
;****************************************************************
;*								*
;*		   KEYBOARD BIOS ROUTINES			*
;*								*
;*	USER CALLABLE KEYBOARD INPUT ROUTINES			*
;*								*
;****************************************************************




;****************************************************************
;*								*
;*	KEYINIT	KEYBOARD INITIALIZATION				*
;*								*
;****************************************************************


KEYINIT:
	STA	CAPLOCK		; CLEAR CAPS LOCK MODE
	CALL	PKEYINIT	; DO PHYSICAL INITIALIZATION
	RET






	PAGE
;****************************************************************
;*								*
;*	KEYST	KEYBOARD SYSTEM STATUS				*
;*		RETURNS 0FFH IF CHARACTER READY			*
;*			0 IF CHARACTER NOT READY		*
;*								*
;****************************************************************


KEYST:
	LDA	FUNACT		; CHECK IF FUNCTION EXPANSION IS ACTIVE
	ORA	A
	RNZ			; IF IT IS IT IS PRIORITY SO RETURN STAT SET
	CALL	PKEYST		; CHECK PHYSICAL KEY STATUS
	RET			; RETURN STATUS



	PAGE
;****************************************************************
;*								*
;*	KEYIN	KEYIN SYSTEM. INCLUDES EXPANDING FUNCTIONS	*
;*		AS WELL AS RETURNING NORMAL KEY STUFF. 		*
;*								*
;****************************************************************


KEYIN:
	CALL	PKEYST		; CHECK PHYSICAL
	JZ	KEYIN		; LOOP TILL KEY PRESSED
	CALL	PKEYIN		; GET THE KEY FROM THE BUFFER TO [A]
	CPI	090H
	JZ	XCHGKEY		;CHANGE UPPER AND LOWER CASE
	LXI	H,KEYTBL
	CALL	OFFSET
	MOV	A,M
	RET
XCHGKEY:
	LXI	H,KEYTBL+41H
	LXI	D,KEYTBL+61H
	MVI	B,1AH
XCHGKE1:
	MOV	A,M
	MOV	C,A
	LDAX	D
	MOV	M,A
	MOV	A,C
	STAX 	D
	INX	H
	INX	D
	DCR	B
	JNZ	XCHGKE1
	JMP 	KEYIN	




;****************************************************************
;*								*
;*	TOUPPER	SET CHAR IN [C] TO UPPER CASE (IF IT WAS LOWER	*
;*		CASE ALPHABETIC	. RETURN CHAR IN [C]		*
;*								*
;****************************************************************


TOUPPER:
	MOV	A,C		; GET CHAR
	CPI	'a'		; CHECK LOWER BOUND
	RC			; RETURN IF LESS
	CPI	'z'+1		; CHECK UPPER BOUND
	RNC			; RETURN IF MORE
	ANI	05FH		; MAKE TO UPPER CASE
	MOV	C,A		; RETURN IN [C]
	RET






	PAGE
;****************************************************************
;*								*
;*	PKEYST	RETURN PHYSICAL KEYBOARD STATUS			*
;*								*
;****************************************************************


PKEYST:
	LDA	RSKEY		; READ STATUS
	ANI	KBDAT		; MASK DATA AVAILABLE BIT
	RZ			; DONE IF NO DATA READY
	MVI	A,0FFH		; 
	ORA	A		; 
	RET



;****************************************************************
;*								*
;*	PKEYIN	RETURN KEYBOARD CHARACTER IN [A]		*
;*								*
;****************************************************************


PKEYIN:
	CALL	PKEYST		; GET STATUS
	JZ	PKEYIN		; LOOP TILL READY
	LDA	RDKEY		; GET DATA
	RET


;****************************************************************
;*								*
;*	PKEYINIT	PHYSICAL KEYBOARD INITIALIZATION	*
;*								*
;****************************************************************



PKEYINIT:
	XRA	A		; RESET
	STA	KEYDI		; DISABLE KEYBOARD INTERRUPTS
	STA	CLKENA		; AND ERROR STATUS
	RET



	PAGE	
;****************************************************************
;*								*
;*		     KEYBOARD DATA AREA				*
;*								*
;****************************************************************


CAPLOCK:	DB	$-$	; CAPS LOCK MODE STATUS
FUNACT:		DB	$-$	; FUNCTION EXPANSION ACTIVE FLAG
FCHARCNT:	DB	$-$	; FUNCTION CHAR COUNT
FPOINTER:	DW	$-$	; POINTER INTO CHARSTRING






	PAGE
;****************************************************************
;*								*
;*		PHYSICAL SERIAL DEVICE ROUTINES			*
;*								*
;****************************************************************
;
;	NOT USED ANY LONGER
;
;
SPAIST:
SPAOUT:
SPAIN:
	RET
	PAGE
;****************************************************************
;*								*
;*	NCR LIST ROUTINES					*
;*								*
;****************************************************************


P1DTOFF	EQU	0		; P1 DATA OFFSET
P1STOFF	EQU	1		; P1 STAT OFFSET
P1DIOFF	EQU	3		; P1 DISABLE INTERRUPTS OFFSET
P1RSOFF	EQU	7		; P1 RESET OFFSET

P1DATA	DW	00
P1STAT	DW	00
P1DI	DW	00
P1RESET	DW	00

EXTON	EQU	1FH		; TURN EXTENDED ON
EXTOFF	EQU	1EH		; TURN EXTENDED OFF
P1ERRMSK EQU	0C6H		; PARALELLEL PRINTER ERROR MASK

P1INIT:
	CALL	STPP1AD		; SETUP PORT ADDR'S
	XRA	A
	LHLD	P1RESET		; RESET PARALLEL PRINTER 1
	MOV	M,A
	LHLD	P1DI		; DISABLE INTERRUPTS
	MOV	M,A
	RET


STPP1AD:
	LHLD	P1PORT
	SHLD	P1DATA		; DATA OFFSET ALWAYS 0
	XCHG			; PUT P1PORT ADDR IN <DE> FOR DAD
	LXI	H,P1STOFF
	DAD	D
	SHLD	P1STAT
	LXI	H,P1DIOFF
	DAD	D
	SHLD	P1DI
	LXI	H,P1RSOFF
	DAD	D
	SHLD	P1RESET
	RET


P1CHROUT:
	CALL	STPP1AD
	MOV	A,C		; GET CHAR FROM DOS
	JMP	P1OUT

P1CTLCHR:
	LXI	H,P1CTBL
P1CTLLP:
	CMP	M
	JZ	P1OUT
	INX	H
	MOV	B,M
	INR	B
	JZ	P1EXIT
	JMP	P1CTLLP

P1OUT:
	PUSH	PSW
	CALL	P1WAIT
	POP	PSW
	LHLD	P1DATA
	MOV	M,A
	RET

P1WAIT:
	CALL	P1STATUS
	JZ	P1WAIT
	RET

P1STATUS:
	CALL	STPP1AD
	LHLD	P1STAT
P1STAT1:
	MOV	A,M
	ANI	P1ERRMSK	; CHECK ANY OF THE ACTIVE ERROR BITS
	JZ	P1STATX
	XRA	A
	RET
P1STATX:
	MVI	A,0FFH
	ORA	A
	RET

P1CTBL:
	DB	LF
	DB	FF
	DB	CR
	DB	EXTON
	DB	EXTOFF
	DB	0FFH

P1EXIT:
	RET

	PAGE
;****************************************************************
;*								*
;*	NCR SERIAL A PORT ROUTIINES				*
;*								*
;****************************************************************
;****************************************************************
;*			MACRO DEFS				*
;****************************************************************
SAVE	MACRO
	PUSH	PSW
	PUSH	H
	PUSH	D
	PUSH	B
	ENDM

RETURN	MACRO	ENAB
	POP	B
	POP	D
	POP	H
	POP	PSW
	IF	ENAB
	EI
	ENDIF
	RET
	ENDM

;****************************************************************
;*								*
;*		         DISK DATA				*
;*								*
;****************************************************************


SEKDSK	DB	0
SEKTRK	DB	0
SEKHST	DB	0
SEKSEC	DB	0

UNADSK	DB	0
UNATRK	DB	0
UNAHST	DB	0
UNASEC	DB	0

HSTDSK	DB	0
HSTTRK	DB	0
HSTHST	DB	0
HSTSEC	DB	0

NXTDSK	DB	0
NXTTRK	DB	0
NXTHST	DB	0
NXTSEC	DB	0



	PAGE
;****************************************************************
;*								*
;*		      DRIVE PARAMETERS				*
;*								*
;****************************************************************


SIZBIT	EQU	1		; SECTOR SIZE
SIDBIT	EQU	2		; SIDEDNESS
DENBIT	EQU	4		; DOUBLE DENSITY
RDYBIT	EQU	8		; MARK AS DRIVE READY

DRVTYP:	DS	5		; STORAGE FOR 4 DRIVES






;****************************************************************
;*								*
;*		    DISK COMMAND STRING				*
;*								*
;****************************************************************


CMDSTG	EQU	$

CMDBYTE	DB	0
DSKBYTE	DB	0
TRKBYTE	DB	0
SECBYTE	DB	0




;****************************************************************
;*								*
;*		       MISC DATA				*
;*								*
;****************************************************************


MONDSK	DB	0
CLRFLG	DB	0
DSKCMD	DB	0
UNACNT	DB	0
DMAADR	DW	0
PMAADR	DW	0
TKTBL	DW	0,0
RSFLAG	DB	0
READOP	DB	0
WRTYPE	DB	0
HSTACT	DB	0
HSTWRT	DB	0
IDDISK	DB	0


BEGDAT	EQU	$
DIRBUF:	DS	128
ALV0:	DS	60
CSV0:	DS	32
ALV1:	DS	60
CSV1:	DS	32
ALV2:	DS	150
CSV2:	DS	0
ALV3:	DS	150
CSV3:	DS	0
ALV4:	DS	25
CSV4:	DS	0
ENDDAT	EQU	$
DATSIZ	EQU	$-BEGDAT
		


;****************************************************************
;*								*
;*		       DISK BUFFER				*
;*								*
;****************************************************************


HSTBUF:	DS	512



TOPRAM	EQU	$		  ; HIGH RAM REQUIRED




	END
