.PAGE 80,63
;DISK EXAMINE/MODIFY UTILITY.
;	This utility allows the user to examine absolute
;addresses on a disk.  Additionally he may alter, character by
;charater, the contents of any given sector.  Entire sectors
;may be moved from the bufer onto the disk.
;	All I/O is done through the BIOS for CPM.  There are
;no calls made to the BDOS.
;
;D.A. BARKER, January 1980.
; 
.PABS
.SALL
.OPSYN	.BLKB,DS
.OPSYN	.BYTE,DB
.OPSYN	.WORD,DW
;
.IDENT	LOOK
.PROGID	EXAM,1,2
;
;
;		*****************
;		* MISC. EQUATES *
;		*****************
;
TEST	=	0
CR	=	0DH
LF	=	0AH
DMADD	=	80H
QUIT	=	0	;USE CPM ENTRY
ESC	=	1BH
MAXDRV	=	2
NSECS	=	26
MAXGP	=	243
;
;		*************************
;		* I/0 ENTRY DEFINITIONS *
;		*************************
;
COUT	=	12	;THE FOLLOWING ARE BIOS JUMP TABLE
KEYIN	=	9	; ENTRY POINTS FOR THE VARIOUS
.SETDMA	=	36	; ROUTINES
.SELDSK	=	27
.SETTRK	=	30
.SETSEC	=	33
.READ	=	39
.WRITE	=	42
;
;		**********************
;		* STRING DEFINITIONS *
;		**********************
;
.DEFINE	ST1	=[     -- LOOK -- VERSION 1.3 -- D. A. BARKER  OCT. 21, 1980    ]
.DEFINE	ST2	=[ Drive:]
.DEFINE	ST3	=[         Track:]
.DEFINE ST4	=[          Sector:]
.DEFINE ST4.5	=[          Group:]
.DEFINE	ST5	=[ Display is from:]
.DEFINE	ST6	=[                 Auto-read is:]

;
;		*********************
;		* MACRO DEFINITIONS *
;		*********************
;
;	CURSOR ADDRESSING
;	This routine should produce the sequence of characters
;necessary to position the cursor.  The third parameter should
;not require alteration.
;
.DEFINE		XY [ROW,COL,Z(0)]  =
		[
		DB	ROW,COL
		.IFE Z, DB 0
		]
;
;	INVERTING A STRING VALUE
;	This routine sets the MSB of each character of the
;argument string.  This is used for inverse video when the
;IObyte has been altered to accept inverse video rather than
;xy-addressing
;
;	I/O FUNCTIONS
;	Setup and do a BIOS function (FUNC).
;
.DEFINE		GODO [FUNC]  =
		[
		PUSH	H
		PUSH	D
		LXI	D,FUNC
		CALL	IOCALL
		POP	D
		POP	H
		]
;
.DEFINE		TYPE  =  [CALL TYPEX]
;		
.DEFINE		PRINT  =  [CALL PRNTMSG]
;
.DEFINE		XYPR	=  [CALL POSPR]
;
;	GETKEY will set the zero flag if an Escape is typed.
;
.DEFINE		GETKEY	=  [CALL GK]
;
;  THE MAIN PROGRAM BEGINS
;
.LOC	0100H	;MAKE IT A CPM TRANSIENT
;
EXAM:
INIT:	LXI	B,DMADD	;THIS WILL NEVER CHANGE
	GODO .SETDMA
	LXI	H,100H
	SHLD	DSKTBL
	LXI	D,DSKTBL+2
	LXI	H,DSKTBL
	LXI	B,10
	LDIR		;INITIALIZE VARIOUS POINTERS
;
	LXI	H,DMADD
	MVI	M,0
	LXI	D,DMADD+1
	LXI	B,127
	LDIR		;CLEAR THE BUFFER AREA
;
CLEAR:	CALL	CLRSC
;
	CALL	WHITE	;INVERT THE VIDEO
	PRINT
	.ASCII	ST1		;PRINTING THE HEADER
	DB	CR,LF		;BLOCK AND STATUS DISPLAYS
	.ASCII	ST2
	.ASCII	ST3
	.ASCII	ST4
	.ASCII	ST4.5
	.ASCII	/       /
	DB	CR,LF
	.ASCII	ST5
	.ASCII	ST6
	.ASCII	/               /
	DB	0
	CALL	BLACK	
REENT:	LXI	SP,STACK	;ENTRY HERE WILL UPDATE ALL
	XYPR			; STATUS DISPLAYS
	XY [1,@ST2]
	LHLD	DRIVE
	MVI	A,'A'
	ADD	L
	TYPE
	XYPR
	XY [1,@ST2+@ST3]
	MVI	H,0
	DAD	H
	LXI	D,DSKTBL
	DAD	D
	MOV	A,M
	CALL	HEXOUT
	XYPR
	XY [1,@ST2+@ST3+@ST4]
	INX	H
	MOV	A,M
	CALL	HEXOUT
;
	XYPR
	XY [1,@ST2+@ST3+@ST4+@ST4.5]
	PUSH	H
	MOV	A,M
	LXI	H,GPTBL+NSECS
	LXI	B,NSECS
	CCDR		;BC NOW CONTAINS LOGICAL SECTOR #
	POP	H
	DCX	H
	MOV	L,M
	MVI	H,0
	DCR	L
	DCR	L	;TRACK-2
	JP	.VALID	;JMP IF TRACK > 1
	PRINT
	.ASCIZ /SYS*/
	JMPR	.NTV
; NOW MULTIPLY HL BY 26
.VALID:	DAD	H	;X2
	PUSH	H
	POP	D
	DAD	H	;X4
	DAD	H	;X8
	XCHG
	DAD	D
	XCHG		;DE IS NOW X10
	DAD	H	;X16
	DAD	D	;X26
	DAD	B	;HL NOW THE TOTAL SECTOR NUMBER
			;NOW DIVIDE BY 8
	MOV	A,L
	ANI	0F8H
	ORA	H
	RRC
	RRC
	RRC
	CALL	HEXOUT
	MVI	A,':'
	TYPE
	MOV	A,L	;GET REMAINDER
	ANI	7
	ADI	'1'	;ADD ASCII BIAS & INCREMENT
	TYPE
;
.NTV:	LDA	AUTONO
	ORA	A	;CHECK FOR AUTO-READ
	JNZ	RDSK	;JUMP IF AUTO-READ
;
	XYPR
	XY [2,@ST5,1]
	.ASCIZ	/ BUFFER/
	JMPR	LP
RDRTN:	XYPR			;EVERY DISK READ OR WRITE WILL
	XY [2,@ST5,1]		; RETURN HERE AND UPDATE THE 
	.ASCIZ	/ DISK  /	; SECOND STATUS LINE
LP:	LXI	H,AUTONO
	XYPR
	XY [2,@ST5+@ST6]
	MOV	A,M
	ORA	A
	JRZ	..OFF
	PRINT
	.ASCIZ	/ ON /
	JMPR	..ON
..OFF:	PRINT
	.ASCIZ	/ OFF/
..ON:	CALL	SPIT 	;SPIT THE BUFFER ONTO THE SCREEN
;
;		*********************
;		* COMMAND PROCESSOR *
;		*********************
;
GETCOM:	XYPR
	XY [15,0]
	CALL	ERAL	;ERASE THE PROMPT LINE
	GETKEY		;GET THE COMMAND CHARACTER
	LXI	H,CMDADD-1
	LXI	B,CMDADD-CMDTBL+1
	CCDR		;SCAN THE TABLE BACKWARDS
	LXI	H,CMDADD
	DAD	B
	DAD	B	;HL NOW POINTS TO THE ROUTINE'S ADDRESS
	MOV	E,M
	INX	H
	MOV	D,M
	PUSH	D	;SO A 'RET' WILL GO TO THE ROUTINE
SETUP:	LHLD	DRIVE
	MOV	C,L
	MVI	H,0
	DAD	H
	LXI	D,DSKTBL
	DAD	D	;HL POINT TO CURRENT DISK'S TRACK LOC.
	LXI	D,0
	RET		;GO EXECUTE THE CHOSEN ROUTINE
;
;		*********************
;		* THE COMMAND TABLE *
;		*********************
;
CMDTBL:	.ASCII	/DTSIO+-GNLRWAHCQM?/[3]
CMDADD:	DW	INFO,SELDRV,SELTRK,SELSEC,STPIN
	DW	STPOUT,NXSEC,LSTSEC,GROUP,NXGP
	DW	LSTGP,READ,WRITE,ASC,HXCMD
	DW	CLEAR,QUIT,MODE,INFO,QUIT
;
SELDRV:	CALL	ERAL
	PRINT
	.ASCIZ /DRIVE NUMBER?/
	MVI	E,0	;FOR THE GHX ROUTINE
	CALL	GHX
	CPI	MAXDRV
	JRNC	SELDRV
	STA	DRIVE
	JMP	REENT
;
SELTRK:	CALL	ERAL
	PRINT
	.ASCIZ	/DESIRED TRACK?/
	CALL	GETHEX
	CPI	77	;MAXIMUM TRACK NUMBER + 1
	JRNC	SELTRK
	MOV	M,A
	JMP	REENT
;
SELSEC:	CALL	ERAL
	PRINT
	.ASCIZ	/DESIRED SECTOR?/
	CALL	GETHEX
	ORA	A
	JRZ	SELSEC
	CPI	NSECS+1
	JRNC	SELSEC
	INX	H	;POINT TO CURRENT DRIVE'S SECTOR LOC.
	MOV	M,A
	JMP	REENT
;
NXSEC:	INX	H
	MOV	A,M
	INR	A
	CPI	NSECS+1
	JRNC	..NXT
	MOV	M,A
	JMP	REENT	;STAY ON SAME TRACK
..NXT:	MVI	A,1
	MOV	M,A
	DCX	H	;POINT TO CURRENT TRACK LOCATION
	JMPR	STPIN
;
LSTSEC:	INX	H
	MOV	A,M
	DCR	A
	ORA	A
	JRZ	..LST
	MOV	M,A
	JMP	REENT	;STAY ON THE SAME TRACK
..LST:	ADI	26
	MOV	M,A
	DCX	H	;POINT TO CURRENT TRACK LOCATION
	JMPR	STPOUT
;
NXGP:	INX	H	;GET PRESENT SECTOR #
	MOV	A,M	
	LXI	B,NSECS
	XCHG		;PUT SECTOR TABLE POINTER IN DE
	LXI	H,GPTBL+1 ;POINT TO 2ND ENTRY OF THIS TABLE
	CCIR		;SEARCH FOR THE PRESENT SECTOR
	MOV	A,M	;GET THE NEXT SECTOR
	XCHG		;POINT HL TO THE TABLE
	MOV	M,A
	JPE	REENT	;ODD PARITY MEANS END OF TABLE
	DCX	H
STPIN:	MOV	A,M
	CPI	76	;MAXIMUM TRACK NUMBER
	JNC	REENT
	INR	M
	JMP	REENT
;
LSTGP:	INX	H
	MOV	A,M
	LXI	B,NSECS
	XCHG
	LXI	H,GPTBL+NSECS
	CCDR
	MOV	A,M
	XCHG
	MOV	M,A
	JPE	REENT
	DCX	H
STPOUT:	MOV	A,M
	ORA	A
	JZ	REENT
	DCR	M
	JMP	REENT
;
;		*********************
;		* SECTOR SKEW TABLE *
;		*********************
;	Assuming a sector interleave of 6 sectors
;
GPTBL:	DB	22,1,7,13,19,25,5,11,17
	DB	23,3,9,15,21,2,8,14,20
	DB	26,6,12,18,24,4,10,16,22,1
;
GROUP:	CALL	ERAL
	PRINT
	.ASCIZ	/GROUP NUMBER?/
	CALL	GETHEX
	CPI	MAXGP+1
	JRNC	GROUP
	MVI	A,0FFH
	XCHG		;HL CONTAIN THE GROUP NUMBER
	DAD	H	;MULTIPLY # BY 8
	DAD	H
	DAD	H
	LXI	B,-NSECS
..AGN:	INR	A	;DIVIDE THE # BY NSECS
	DAD	B
	JRC	..AGN
	ADI	2	;QUOTIENT PLUS 2 IS NEW TRACK #
	STAX	D	
	DSBC	B	;HL IS THE LOGICAL SECTOR NUMBER
	LXI	B,GPTBL+1
	DAD	B	;(HL) IS NOW THE PHYSICAL SECTOR #
	MOV	A,M
	INX	D
	STAX	D
	JMP	REENT
;
MODE:	LDA	AUTONO	;TOGGLE THE AUTO-READ MODE
	INR	A
	ANI	1
	STA	AUTONO
	JNZ	RDSK
	JMP	RDRTN
;
ASC:	CALL	ERAL
	PRINT
	.ASCIZ	/ASCII BYTE NUMBER?/
	CALL	GETHEX
	CPI	80H
	JRNC	ASC
..AGN:	CALL	MCUR	;Position the cursor on the screen.
	CALL	ACUR
	CALL	MCUR0
	JRNC	..AGN
	MOV	M,A	;Update the DMA buffer.
	MVI	C,1	;Ready to advance by one.
	CALL	RESTO
	JMPR	..AGN
;
HXCMD:	CALL	ERAL
	PRINT
	.ASCIZ	/HEX BYTE NUMBER?/
	CALL	GETHEX
	CPI	80H
	JRNC	HXCMD
..AGN:	CALL	MCUR
	CALL	HCUR
	CALL	MCUR0
	JRNC	..AGN
	CALL	HEXFIL
	MVI	C,0
	JRZ	..FWD
	MOV	M,A
	INR	C
..FWD:	CALL	RESTO
	JMPR	..AGN
;
MCUR:	MOV	E,A	;THE CURSOR POINTER
	MVI	D,0
	LXI	H,DMADD
	DAD	D	;HL TO THE CP IN THE BUFFER
	CALL	HCUR	;POSITION THE HEX CURSOR
	CALL	BTYPE
	CALL	BTYPE
	CALL	ACUR	;THE ASCII CURSOR
	JMP	BTYPE
MCUR0:	GETKEY
	JZ	GIT	;LEAVE ON AN 'ESC'
	MVI	C,-1
	CPI	'H'-40H	;MOVE LEFT?
	RC
	JRZ	RESTO
	MVI	C,10H
	CPI	'J'-40H
	RC
	JRZ	RESTO
	MVI	C,1
	CPI	'L'-40H
	JRZ	RESTO
	CMC
	RC
	MVI	C,-10H
RESTO:	PUSH	B
	CALL	RS
	POP	B
	MOV	A,E
	ADD	C
	ANI	7FH	;INSURE IN SECTOR
	RET
;
RS:	CALL	HCUR
	MOV	A,M
	CALL	HEXOUT
	CALL	ACUR
	MOV	A,M
	ANI	7FH
	CPI	20H
	JRNC	..FW
	MVI	A,'.'
..FW:	CPI	0FFH
	JRNZ	..AGN
	MVI	A,'.'
..AGN:	TYPE
	RET
;
HCUR:	PUSH	D
	MOV	A,E
	RRC
	RRC
	RRC
	RRC
	ANI	0FH
	ADI	5
	MOV	D,A
	MOV	A,E
	ANI	0FH
	RLC
	MOV	E,A
	CALL	DEXY
	MOV	A,D
	POP	D
	MOV	D,A
	RET
ACUR:	PUSH	D
	MOV	A,E
	ANI	0FH
	ADI	24H
	MOV	E,A
	CALL	DEXY
	POP	D
	RET
;
GIT:	CALL	RS
	LXI	H,0
	SHLD	AUTONO
	JMP	REENT
;
HEXFIL:	CALL	HEXIT
	RZ
	MOV	B,A
..AGN:	GETKEY
	RZ
	CPI	CR
	JRZ	..XIT
	CALL	HEXIT
	JRC	..AGN
	RLCR	B
	RLCR	B
	RLCR	B
	RLCR	B
	ORA	B
	MOV	B,A
	XRA	A
	INR	A	;JUST TO CLEAR Z-FLAG
..XIT:	MOV	A,B
	RET
;
RDSK:	CALL	SETUP
READ:	CALL	IOSET
	XYPR
	XY [13,0]
	GODO	.READ
.IFN	TEST,	[
	ORA	A
	JZ	RDRTN
	XYPR
	XY [15,0,1]
	.ASCIZ / ERROR ON READ!! /
	GETKEY ]
	JMP	RDRTN
WRITE:	CALL	IOSET
	XYPR
	XY [13,0]
	GODO	.WRITE
	JMP	RDRTN

IOSET:	GODO	.SELDSK
	MOV	C,M
	GODO	.SETTRK
	INX	H
	MOV	C,M
	GODO	.SETSEC
	RET
;
INFO:	CALL	CLRSC		;SPLASH THE HELP TEXT TO THE SCREEN
	XYPR
	XY	[0,24,1]
	.ASCII	/COMMAND SUMMARY/[CR][LF]
	.ASCII	/D: select Drive (0,1,2,3)	   /
	.ASCII	/R: Read the current sector/[CR][LF]
	.ASCII	/T: select Track (0 - 4C)	   /
	.ASCII	/W: Write buffer to disk/[CR][LF]
	.ASCII	/S: select Sector (1 - 26)	   /
	.ASCII	/M: toggle the auto-read Mode/[CR][LF]
	.ASCII	/I: step In			   /[CR][LF]
	.ASCII	/O: step Out   			   /
	.ASCII	/A: ASCII fill the buffer/[CR][LF]
	.ASCII	/				   /
	.ASCII	/H: Hex fill the buffer/[CR][LF]
	.ASCII	/+: next physical sector	   /[CR][LF]
	.ASCII	/-: last physical sector 	   /
	.ASCII	/^H: move cursor left/[CR][LF]
	.ASCII	/				   /
	.ASCII	/^L: move cursor right	/[CR][LF]
	.ASCII	/The following 3 commands	   /
	.ASCII	/^J: move cursor down	/[CR][LF]
	.ASCII	/assume sector interleave of 6	   /
	.ASCII	/^K: move cursor up	/[CR][LF]
	.ASCII	/G: Group selection		   /
	.ASCII	/C: re-initialize the screen	/[CR][LF]
	.ASCII	/N: Next logical sector		   /
	.ASCII	/Q: exit to CPM/[CR][LF]
	.ASCII	/L: Last logical sector		   /
	.ASCII	/^C:  "   "  "/[CR][LF][0]
	XYPR
	XY [15,17,1]
	.ASCIZ	/Esc: general command Escape./
	GETKEY
	JMP	CLEAR

;
;		*********************
;		* MISC. SUBROUTINES *
;		*********************
;
;
IOCALL:	LHLD	1	;PICK UP THE BASE OF THE BIOS
	MVI	L,0
	DAD	D
	PCHL		;GO TO THE REQUESTED ROUTINE
;
BTYPE:	MVI	A,'_'
TYPEX:	MOV	C,A
	GODO [COUT]
	RET
;
POSPR:	XTHL
	MOV	D,M
	INX	H
	MOV	E,M
	CALL	DEXY
	JMPR	POSPR1
PRNTMSG: XTHL
	MOV	A,M
ZAGN:	TYPE
POSPR1:	INX	H
	MOV	A,M
	ORA	A
	JRNZ	ZAGN
	INX	H
	XTHL
	RET
;
HEXOUT:	PUSH	B	;SAVE BC
	MVI	B,1	;ITERATION COUNT
	MOV	C,A
	RAR
	RAR
	RAR
	RAR
..AGN:	ANI	0FH
	PUSH	B
	ADI	'0'
	CPI	'9'+1
	JRC	..OUT
	ADI	7
..OUT:	TYPE
	POP	B
	DCR	B
	JRNZ	..DUN
	MOV	A,C
	JMPR	..AGN
..DUN:	POP	B
	RET
;
;	READ HEX VALUES IN FROM THE KEYBOARD
;
GETHEX:	GETKEY
	JZ	REENT
	CALL	HEXIT
	JRC	GETHEX
	MOV	E,A
	MOV	A,C
	TYPE
GHX:	GETKEY
	JZ	REENT
	CPI	CR
	JRZ	..EX
	CALL	HEXIT
	JRC	GHX
	RLCR	E
	RLCR	E
	RLCR	E
	RLCR	E
	ORA	E
	MOV	E,A
	MOV	A,C
	TYPE
..EX:	MOV	A,E
	RET
;
;	CONVERT THE CONTENTS OF THE ACCUMULATOR TO
;	HEXIDECIMAL. SET CARRY ON ILLEGAL CHARACTERS
;
HEXIT:	MOV	C,A
	SUI	30H
	RC
	CPI	0AH
	CMC
	RNC
	SUI	7
	CPI	0AH
	RC
	CPI	10H
	CMC
	RET 
GK:	GODO	KEYIN
	CPI	ESC
	RET
;
;		**************************************
;		* DISPLAY THE CONTENTS OF THE BUFFER *
;		**************************************
;
SPIT:	XYPR
	XY	[5,0]
	LXI	H,DMADD
	MVI	B,8	;FOR 8 ROWS OF INFO
	PUSH	H
..BGN:	MVI	C,10H	;FOR 16 COLUMNS OF INFO
	LXI	H,..BUF
	XTHL		;HL TO BUFFER AND STACK TO ..BUF
..AGN:	MOV	A,M
	CALL	HEXOUT  
	MOV	A,M
	ANI	7FH
	CPI	7FH
	JRZ	..BD
	CPI	' '
	JRNC	..OK
..BD:	MVI	A,'.'
..OK:	XTHL		;GET THE ..BUF POSITION.
	MOV	M,A
	INX	H
	XTHL
	INX	H	;ADVANCE IN THE BUFFER
	DCR	C	;SEE IF THERE IS MORE ON THIS LINE
	JRNZ	..AGN
	XTHL
	PRINT
	.ASCII	/    /
..BUF:	DS	10H
	DB	CR,LF,0
	DCR	B	;MORE FROM THIS SECTOR?
	JRNZ	..BGN
	POP	H
	RET
DSKTBL:	DS	8	;ROOM ENOUGH FOR 4 DRIVES
DRIVE:	DS	1	;CURRENT DRIVE
AUTONO:	DS	1	;AUTO OR MANUAL READ
	DS	32
STACK:	DS	1
CLRSC:	PRINT
	.ASCIZ	[ESC]/E/[0][0]
	RET
BLACK:	PRINT
	.ASCIZ	[ESC]/q/[0][0]
	RET
WHITE:	PRINT
	.ASCIZ	[ESC]/p/[0][0]
	RET
ERAL:	PRINT
	.ASCIZ	[CR][ESC]/l/[0][0]
	RET
DEXY:	MVI	A,ESC
	TYPE
	MVI	A,'Y'
	TYPE
	MOV	A,D	;THE ROW NUMBER
	ADI	20H
	TYPE
	MOV	A,E	;THE COLUMN NUMBER
	ADI	20H
	TYPE
	RET
.END	EXAM

