;*********************************;
;     SECTOR PATCH UTILITY        ;
;*********************************;
	ORG	100H
 
;****
; MISC. EQUATES
;****
 
TBUF	EQU	0080H
VDMLC	EQU	0CC00H
VDMLN	EQU	64
VDMPG	EQU	4
;****
; GENERALIZED A BIT; jtb
;****
SOL	EQU	1	;set to 1 for SOL behavior
NSTAR	EQU	1	;set to 1 for nortstar behavior

	IF	SOL
VDM$SCL	EQU	0FEH	;VDM scrollbase register
	ELSE
VDM$SCL	EQU	0C8H	;VDM scrollbase register
	ENDIF

	IF	NSTAR
SEC$TRK EQU	40	;sectors per track
TRK$DSK	EQU	35	;tracks/disk
NUM$DSK	EQU	4	;number of disk drives
	ELSE
SEC$TRK EQU	26	;  \
TRK$DSK	EQU	77	;   >-- original values from CPMUG001
NUM$DSK	EQU	2	;  /
	ENDIF
;*****
; OBTAIN BIOS VECTORS
;*****
VECTRS:	JMP	GETVEC
	DS	42
WBOOTE	EQU	VECTRS+3
CSTS	EQU	VECTRS+6
CI	EQU	VECTRS+9
CO	EQU	VECTRS+12
LO	EQU	VECTRS+15
PO	EQU	VECTRS+18
RI	EQU	VECTRS+21
HOME	EQU	VECTRS+24
SELDSK	EQU	VECTRS+27
SETTRK	EQU	VECTRS+30
SETSEC	EQU	VECTRS+33
SETDMA	EQU	VECTRS+36
READ	EQU	VECTRS+39
WRITE	EQU	VECTRS+42
GETVEC:	LXI	D,WBOOTE
	LHLD	1
	MVI	B,42
GETVE1:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	GETVE1
;
 
;****
; MAIN PROGRAM
;****

MAIN:	LXI	SP,STACK	;SET STACK
	LXI	H,VDMLC	;POINT TO VDM MEMORY
	MVI	B,VDMPG	;# PAGES IN VDM
	MVI	A,' '
CLR:	MVI	C,00
CL2:	MOV	M,A
	INX	H
	DCR	C
	JNZ	CL2
	DCR	B
	JNZ	CLR
	LXI	H,TBUF	;CLEAR BUFFER TO SPACES
	MVI	B,128	;BUFFER SIZE
	MVI	A,' '
CL3:	MOV	M,A
	INX	H
	DCR	B
	JNZ	CL3
	LXI	D,MSG1
	LXI	H,VDMLC+VDMLN
	MVI	B,64
	CALL	MOVTG	;MOV MSG1 TO SCREEN
	MVI	A,00	;CLEAR VDM I/O PORT
	OUT	VDM$SCL
	STA	CURDK	;SET DISK TO DRIVE 0
	CALL	HOME	;RESTORE HEAD
	XRA	A
	STA	CURTK	;SET CURTK BYTE
	INR	A
	STA	CURSC	;SET CURRENT SECTOR
	LXI	H,VDMLC+(2*VDMLN)
	LXI	D,MSG2
	MVI	B,64
	CALL	MOVTG
	JMP	LOOP1
LOOP:	CALL	DSPLY	;DISPLAY PARAMETERS
LOOP1:	CALL	CONIN	;READ CONSOLE
	CPI	'A'
	JC	LOOP2
	ANI	5FH
LOOP2:	LXI	H,2020H ;CLEAR ERROR FLAG
	SHLD	VDMLC+(15*VDMLN)
	LXI	H,CMDTB	;POINT TO COMMAND TABLE
	MVI	C,NCMDS	;NUMBER OF COMMANDS
CMLP:	CMP	M	;COMMAND FOUND?
	JZ	CMOK
	INX	H
	INX	H
	INX	H
	DCR	C	;ANY COMMANDS LEFT?
	JNZ	CMLP	;YES, KEEP LOOKING
ERR:	LXI	H,VDMLC+(15*VDMLN)
	MOV	M,A
	INX	H
	MVI	M,'?'
	JMP	LOOP
CMOK:	INX	H
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG
	LXI	D,LOOP
	PUSH	D
	PCHL
 
CONIN:	CALL	CI
	ANI	7FH
	CPI	3
	JZ	0
	RET
 
;****
; DISPLAY ROUTINE
;****
DSPLY:	LXI	D,TBUF
	LXI	H,VDMLC+(4*VDMLN)
	MVI	B,80H
	CALL	MOVE
	LXI	H,VDMLC+(2*VDMLN)
	LXI	D,MSG2
	MVI	B,64	;MOVE MESSAGE TO SCREEN
	CALL	MOVTG
	LXI	H,VDMLC+(2*VDMLN)+OF1	;OFFSET TO FIELD1
	LDA	CURSC
	CALL	HXO	;DISPLAY SECTOR NUMBER
	LXI	H,VDMLC+(2*VDMLN)+OF2	;OFFSET TO FIELD2
	LDA	CURTK
	CALL	HXO	;DISPLAY CURTK NUMBER
	LXI	H,VDMLC+(2*VDMLN)+OF3	;OFFSET TO FIELD3
	LDA	CURDK
	CALL	HXO	;DISPLAY DISK NUMBER
	LXI	H,VDMLC+(2*VDMLN)+OF4
	CALL	STAT
	CALL	HXO
	LXI	H,VDMLC+(8*VDMLN)
	LXI	D,TBUF	;POINT TO BUFFER
	MVI	C,128	;BUFFER SIZE
DL3:	LDAX	D	;GET BYTE FROM BUFFER
	CALL	HXO	;DISPLAY BYTE
	INX	D	;BUMP BUFFER POINTER
	DCR	C	;DECREMENT BYTE COUNT
	JNZ	DL3	;LOOP
	LXI	H,VDMLC+(14*VDMLN)
	MVI	B,64
	CALL	BLANKIT
	RET
 
BLANKIT:MVI	M,' '
	INX	H
	DCR	B
	JNZ	BLANKIT
	RET

;****
; READ ROUTINE
;****
 
READR:	CALL	SETUP
	CALL	READ
	RET

SETUP:	LXI	B,TBUF
	CALL	SETDMA
	LDA	CURDK
	MOV	C,A
	CALL	SELDSK
	LDA	CURSC
	MOV	C,A
	CALL	SETSEC
	LDA	CURTK
	MOV	C,A
	CALL	SETTRK
	RET
 
WRITR:	CALL	SETUP
	CALL	WRITE
	RET

NEXTR:	CALL	NXSEC	;BUMP TO NEXT SECTOR
	CC	NXTRK	;BUMP TO NEXT CURTK
	MVI	A,'+'
	JC	ERR	;ERROR
	CALL	READR
	RET

PREVR:	CALL	PVSEC	;BUMP TO PREV. SECTOR
	CC	PVTRK
	MVI	A,'-'
	JC	ERR
	CALL	READR
	RET

HDOUT:	CALL	PVTRK	;DECREMENT CURTK
	CALL	READR	;READ SECTOR
	RET		;EXIT

HDIN:	CALL	NXTRK	;INCREMENT CURTK
	CALL	READR	;READ SECTOR
	RET		;MOVE HEAD

NXSEC:	LDA	CURSC
	CPI	SEC$TRK	;END OF CURTK
	JNC	NXS2	;YES
	INR	A
	STA	CURSC
	XRA	A
	RET
NXS2:	MVI	A,01
	STA	CURSC
	STC
	RET

NXTRK:	LDA	CURTK
	CPI	TRK$DSK-1
	CMC
	RC		;ERROR
	INR	A
	STA	CURTK
	RET

PVSEC:	LDA	CURSC
	CPI	01+1
	JC	PVS2
	DCR	A
	STA	CURSC
	XRA	A
	RET
PVS2	MVI	A,SEC$TRK
	STA	CURSC
	STC
	RET

PVTRK:	LDA	CURTK
	CPI	00+1
	RC
	DCR	A
	STA	CURTK
	RET

MOVTG:	LDAX	D
	ORI	80H
	MOV	M,A
	DCR	B
	INX	H
	INX	D
	JNZ	MOVTG
	RET
 
HXO:	MOV	B,A	;SAVE BYTE IN B
	RRC
	RRC
	RRC
	RRC		;GET HI ORDER 4 BITS
	CALL	HXN	;CONVERT TO HEX ASCII
	INX	H	;BUMP MEM ADDRESS
	MOV	A,B	;GET BYTE AGAIN
	CALL	HXN	;CONVERT
	INX	H	;BUMP MEM ADDRESS
	RET

HXN:	ANI	0FH	;GET 4 BITS
	ORI	30H	;CONVERT TO ASCII
	CPI	3AH	;A-F?
	JC	HXN1	;NO, CONTINUE
	ADI	07	;COMPENSATE
HXN1:	MOV	M,A	;STORE BYTE
	RET

MOVE:	LDAX	D
	MOV	M,A
	INX	H
	INX	D
	DCR	B
	JNZ	MOVE
	RET
 
HXI:	LXI	B,0
	CALL	HXC
	RC
	MOV	B,A
HXI1:	CALL	HXC
	CMC
	RNC
	MOV	C,A
	MOV	A,B
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	ADD	C
	MOV	B,A
	JMP	HXI1

HXC:	CALL	CONIN
	MOV	C,A
	CPI	'0'
	RC
	CPI	'9'+1
	JNC	HXA
	ORI	80H
	MOV	C,M
	DCX	H
	MOV	M,C
	INX	H
	MOV	M,A
	ANI	0FH
	RET
HXA:	ANI	5FH
	CPI	'A'
	JC	HXC
	CPI	'F'+1
	JNC	HXC
	ORI	80H
	MOV	C,M
	DCX	H
	MOV	M,C
	INX	H
	MOV	M,A
	SUI	37H
	ANI	0FH
	RET

GETEM:	MVI	M,'?'+80H
	INX	H
	MVI	M,'?'+80H
	CALL	HXI
	RC
	MOV	A,B
	ANA	A
	RET

NWDSK:	LXI	H,VDMLC+(2*VDMLN)+OF3
	CALL	GETEM
	JC	NWDS1
	MOV	A,B
	CPI	NUM$DSK
	JNC	NWDSK
	STA	CURDK
NWDS1:	LDA	CURDK
	DCX	H
	CALL	HXO
	CALL	READR
	RET

NWTRK:	LXI	H,VDMLC+(2*VDMLN)+OF2
	CALL	GETEM
	JC	NWTR2
	MOV	A,B
	CPI	TRK$DSK
	JNC	NWTRK
	STA	CURTK
NWTR2:	LDA	CURTK
	DCX	H
	CALL	HXO
	MOV	A,C
	CPI	20H
	JZ	NWDSK
	CALL	READR
	RET

NWSEC:	LXI	H,VDMLC+(2*VDMLN)+OF1
	CALL	GETEM
	JC	NWSC2
	XRA	A
	ADD	B
	JZ	NWSEC
	CPI	SEC$TRK+1
	JNC	NWSEC
	STA	CURSC
NWSC2:	LDA	CURSC
	DCX	H
	CALL	HXO
	MOV	A,C
	CPI	20H
	JZ	NWTRK
	CALL	READR
	RET

GETBNO:	LXI	H,VDMLC+(14*VDMLN)
	LXI	D,MSGI
	MVI	B,MSGILEN
	CALL	MOVTG
	CALL	GETEM
	RC
	MOV	A,B
	CPI	129
	JNC	GETBNO
	DCR	A
	JM	GETBNO
	STA	BYTENO
	MVI	B,MSGILEN+3
	LXI	H,VDMLC+(14*VDMLN)
	CALL	BLANKIT
	ANA	A
	RET

HEXPAT:	CALL	GETBNO
	RC
	LDA	BYTENO
	MOV	C,A
	MVI	B,0
	LXI	H,TBUF
	DAD	B
	XCHG
	ADD	A
	MOV	C,A
	LXI	H,VDMLC+(8*VDMLN)
	DAD	B
HEXPA1:	CALL	GETEM
	JC	HEXPA2
	MOV	A,B
	STAX	D
HEXPA2:	LDAX	D
	DCX	H
	CALL	HXO
	MOV	A,C
	CPI	' '
	RNZ
	INX	D
	LDA	BYTENO
	INR	A
	CPI	128
	RNC
	STA	BYTENO
	JMP	HEXPA1

ASCPAT:	CALL	GETBNO
	RC
	LDA	BYTENO
	MOV	C,A
	MVI	B,0
	LXI	H,TBUF
	DAD	B
	XCHG
	LXI	H,VDMLC+(4*VDMLN)
	DAD	B
ASCPA1:	MVI	M,'?'+80H
	CALL	CONIN
	CPI	20H
	RC
	MOV	M,A
	STAX	D
	INX	H
	INX	D
	LDA	BYTENO
	INR	A
	CPI	128
	RNC
	STA	BYTENO
	JMP	ASCPA1

CMDTB:	DB	'R'
	DW	READR
	DB	'W'
	DW	WRITR
	DB	'A'
	DW	ASCPAT
	DB	'H'
	DW	HEXPAT
	DB	'+'	;READ NEXT SECTOR
	DW	NEXTR
	DB	0AH
	DW	NEXTR
	DB	'-'	;READ PREV SECTOR
	DW	PREVR
	DB	'D'	;SELECT DISK DRIVE
	DW	NWDSK
	DB	'I'	;STEP HEAD IN
	DW	HDIN
	DB	'O'	;STEP HEAD OUT
	DW	HDOUT
	DB	'Q'	;QUIT (EXIT TO CP/M)
	DW	0
	DB	'S'	;SPECIFIC SECTOR
	DW	NWSEC
	DB	'T'
	DW	NWTRK	;SPECIFIC TRACK
	DB	'C'	;CLEAR ALL AND RESTART EXAM
	DW	MAIN
NCMDS	EQU	($-CMDTB)/3
 
MSG1:	DB	' SPAT VERSION 1.0   '
	DB	'                       '
	DB	'                       '
MSG2:	DB	'SECTOR    '
MSG2A:	DB	'TRACK    '
MSG2B:	DB	'DRIVE    '
MSG2C:	DB	'STATUS    '
MSG2D:	DB	'                              '
	DB	'                    '
MSGI:	DB	' BYTE # '
MSGILEN	EQU	$-MSGI
OF1	EQU	(MSG2A-MSG2)-3
OF2	EQU	(MSG2B-MSG2)-3
OF3	EQU	(MSG2C-MSG2)-3
OF4	EQU	(MSG2D-MSG2)-3
 
	DS	64
STACK	EQU	$
CURSC:	DB	00	;CURRENT SECTOR
CURTK:	DB	00	;CURRENT TRACK
CURDK:	DB	00	;CURRENT DISK
BYTENO:	DB	0


;*********************************
;	GET DISK STATUS
;*********************************

STAT:	SUB	A
	IF	NOT NSTAR
	OUT	0C0H	;REQUEST STATUS FROM CONTROLLER
	IN	0C0H	;GET STATUS
	ENDIF
	RET		;AND RETURN

	END

