;*************************************************************
;VIO TERMINAL FIRMWARE  REQUIRES REFRESH MEMORY TO BE AT
;F000 AND FIRMWARE ITSELF AT F800
; COPYRIGHT IMSAI MANUFACTURING COMPANY
;	    SAN LEANDRO, CALIFORNIA
;	    6/1/77
;**************************************************************
REFRESH	EQU 0F000H		;REFRESH MEMORY ON VIO
SYSRAM	EQU 0F780H		;SYSTEM RAM
VIOFM	EQU 0F800H		;FIRMWARE BEGINNING
	ORG VIOFM+7FDH
	DB 'VI0'	;SYSTEM IDENTIFIER
CTRPORT	EQU REFRESH+7FFH	;HARDWARE CONTROL WORD
	ORG SYSRAM
CURLIN	DB 0		;CURRENT LINE # 0-23
CURCOL	DB 0		;CURRENT COL # 0-79
INVIDIO	DB 0		;INVERSE VIDIO MODE(BY CHAR)
VDIMDE	DB 0		;MODE 0=GRAPHICS, NOT 0= TEXT
INSRT	DB 0		;INSERTING CHARS MODE
ESCCNT	DB 0		;ESCAPE CHAR COUNT
ESCCDE	DB 0		;ESCAPE CODE LAST USED
USERCTR	DW 0		;USER CTR TBLE PTR, NON ZERO
USERESC	DW 0		;USER ESCAPE TBLE PTR,NON ZERO
USERCMD DW 0		;USER MONITOR COMMAND TABLE
RAMPTR	DW 0		;RAM SPACE PTR WITH DIRECT I/O
CURPTR	DW 0		;CURSOR ADDRESS
PRTMD	DB 0		;PROTECTED MODE 0=NO
CCUR	DB 0		;CHAR UNDER CURSOR(FOR GRAPHICS MODE)
CCHAR	DB 0		;CURRENT CHARACTER TO DISPLAY
CTRLC	DB 0		;CONTROL WORD AS FOLLOWS
;				7 SCROLL MODE 0=SCROLL,1=WRAP
;				6 UNUSED
;				5 UP/LOW        0=UP,1=UP+LOW
;				4 1=INVERSE VIDIO SCREEN
;				3 00=BLANK,01=LOW128+INV,10=HIGH128+INV
;				2 11=256 CHAR GRAPHICS
;				1 #LINES 0=24,1=12
;				0 #CHARS 0=80,1=40
TAB	EQU $
	ORG $+10		;80 BITS FOR TAB CONTROL
CLINE	DW 0		;CHARS/LINE
LPAGE	DB 0		;LINES/PAGE-1
NCHARS	DW 0		;#CHARS ON DISPLAY
PRUPRF	DB 0		;TRANSITION PROTECT FLAG
USERF	DB	0	;ENTRY POINT FLAG 0=INIT48,1=CHAR48,2=USER
LASTC	DW 0		;LAST CHAR ON SCREEN PTR+1
;***********************************
; USER ENTRY POINTS
;**********************************
	ORG VIOFM
	JMP INIT		;INITIALIZATION POINT
	JMP CHAROUT		;CHARACTER OUTPUT
	JMP MONT		;MONITOR ENTRY POINT
VIOTEST	LXI SP,SYSRAM+7EH
	CALL INITŠ	CALL CHIN
	JMP VIOTEST+6		;DEMO TESTER
;**********************************************
INIT	PUSH H
	PUSH D
	PUSH B
	PUSH PSW
	LXI H,CURLIN		;START OF ZEROED AREA
	MVI B,CLINE-CURLIN AND 0FFH
	XRA A
INIT1	MOV M,A			;ZERO AREA
	INX H
	DCR B
	JNZ INIT1
	LXI H,REFRESH	;BEGIN CURSOR POS
	SHLD CURPTR
	LXI H,1920	;DEFAULT CHARS/SCREEN
	SHLD NCHARS
	CALL BLNKS	;CLEAR SCREEN AND HOME
	MVI A,8H	;DEFAULT 80X24 SCREEN TEXT MODE
	LXI D,BMP1	;SET UP RETURN ADDR
	PUSH D
;SUBROUTINE TO SET HARDWARE CONTROL PORT
SETCMD	STA CTRLC
	STA CTRPORT	;HARDWARE CONTROL PORT
	CMA
	ANI 3
	RRC		;FINDING NCHARS ON SCREEN
	LXI H,40	;COLS/LINE
	JNC $+4		;ENOUGH
	DAD H		;COLS/LINE=80
	SHLD CLINE
	LXI H,LPAGE	;PT AT LINES/PAGE
	MVI M,11
	RAR
	JNC $+5
	MVI M,23
	LXI H,480	;COUNT FOR 12 X 40 SCREEN
	JNC $+4
	DAD H
	ORA A		;SET FLAGS
	JZ $+4
	DAD H
	SHLD NCHARS
	LXI D,REFRESH
	DAD D
	SHLD LASTC	;LAST CHAR ON SCREEN PTR+1
	LDA CTRLC		;CONTOL CODE
	ANI 0CH		;MODE BITS ONLY
	XRI 0CH
	STA VDIMDE	;0=GRAPHICS
;CHECK CURSOR WITHIN POSSIBLE NEW BOUNDS
ESCRET	XRA A
	STA ESCCNT	;COUNT=0
	RETŠ;****************************************************************
; THIS IS THE NORMAL ENTRY POINT FOR COMMUNICATING WITH THE
; VIDIO MONITOR AS YOU WOULD A CRT.
;*****************************************************************
CHAROUT	PUSH H
	PUSH D
	PUSH B
	PUSH PSW
	STA CCHAR
	LHLD CURPTR	;CURSOR POSITION
	LDA CCUR	;CHAR UNDER CURSOR
	MOV M,A		;REMOVE CURSOR
	LXI H,CCHAR	;PT AT CURRENT CHAR
	MOV A,M	;GET CHAR
	CPI 1BH		;ESCAPE CHAR?
	JZ ESCAPE
	LDA ESCCNT	;ARE WE IN ESCAPE SEQ ALREADY?
	ORA A
	JNZ ESCAPE	;YES
	MOV A,M		;CURRENT CHAR
	CPI 7FH		;DELETE CHAR (RUBOUT)?
	JZ NOUSER+3	;YES
	LDA VDIMDE	;GRAPHICS MODE?
	ORA A
	JZ CHAR1	;YES
	MOV A,M
	CPI 0FFH	;DUMMY PAD FROM USER?
	JZ BMP1		;YES
	ANI 7FH		;STRIP PARITY BIT
	MOV M,A
	SBI 20H		;CONTROL CODE?
	JM CONTROL	;YES
	LDA CTRLC	;CONTROL WORD
	MOV B,A		;TMP SAVE
	ANI 0CH	;MODE ONLY
	CPI 08H	;LOW HALF OF CHAR GEN ROM?
	JNZ CHAR1	;NO,UPPER HALF
	MOV A,B		;CONTROL WORD
	ANI 20H		;UP/LOW CASE
	JNZ CHAR1	;LOWER OK AS IS
	MOV A,M		;CURRENT CHAR
	SBI 61H		;LOWER CASE A
	JM CHAR1	;NOT ALPHA
	SBI 7BH-61H
	JP CHAR1	;NOT ALPHA
	ADI 7BH-20H	;RESTORE AND CONVERT TO UPPER CASE
	MOV M,A
CHAR1	CALL INSCHR	;INSERT CCHAR AT CURSOR POS
	CALL BMPCUR
BMP10	CALL CALPOS		;CURSOR POS
BMP1	CALL INSCURS		;INSERT CURSOR
	POP PSW
	POP B
	POP D
	POP HŠ	RET
BMPCUR	EQU $
	CALL BMPC	;BUMP CURSOR CHAR POSITION
	CZ BMPCUR1	;DO LINE FEED
	LDA PRTMD	;PROTECT MODE?
	XCHG		;H,L=CURRENT CURSOR PTR
	ANA M		;IS IT PROTECTED?
	JM BMPCUR	;YES,SKIP PROTECTED FIELD
	RET		;GO INSERT CURSOR
LFEED	LXI H,CURLIN
BMPCUR1	INR M
	LDA LPAGE	;MAX LINES/PAGE
	CMP M		;EXCEED MAX?
	RP
	DCR M		;LEAVE AT LAST LINE
;********************************
;SCROLL UP OR WRAP AROUND AS SET BY CTRLC
;********************************************
SCROLL	LDA CTRLC	;KIND OF SCROLL?
	ANI 8CH		;LEAVE SCROLL AND MODE BITS
	JM SCROLL3	;WRAP AROUND
	CPI 0CH		;GRAPHICS MODE
	JNZ SCROLL1	;NO, ALLOW SCROLL
SCROLL3	XRA A
	MOV M,A		;HOME CURSOR FOR WRAP AROUND
	INX H
	MOV M,A
	RET
SCROLL1	LHLD CLINE	;COLS/LINE
	PUSH H		;SAVE COLS/LINE
	XCHG
	LHLD NCHARS	;# CAHRS PER PAGE
	MOV A,L
	SUB E
	MOV C,A
	MOV B,H
	XCHG
	LXI D,REFRESH
	DAD D		;HL=SOURCE,DE=DEST.
	CALL MVCUP
SCROLL2	JMP DLINE1	;ERASE CURRENT LINE AND RETURN
;******************************
;PROCESS CONTROL CODES
;************************
CONTROL	XCHG		;D,E=CCHR PTR
	LHLD USERCTR	;USER TABLE IF ANY
	MOV A,H
	ORA A
	LDAX D		;CCHAR IN A
	JZ NOUSER	;NO TABLE USER DEFINED
	CALL LOOKUP
	JNZ FNDCTRL	;FOUND TABLE ENTRY
NOUSER	LDA CCHAR
	LXI H,CTRTBL
	CALL LOOKUPŠ	JZ BMP1		;NOT FOUND
FNDCTRL	LXI D,BMP10	;RETURN ADDRESS
	PUSH D		;ON STACK
	LXI D,CURCOL
	PCHL
;
;****************************************
;PROCESS ESCAPE SEQUENCES
;**************************
ESCAPE	LXI D,BMP10	;RETURN ADDR
	PUSH D
	XCHG
	LXI H,ESCCNT
	MOV A,M		;ESCCAPE COUNT
	INR M		;ESCCNT=ESCCNT+1
	ORA A
	RZ
	DCR A
	INX H
	LDAX D		;GET CCHAR
	JNZ ESCAP1	;ESCCNT>1
	MOV M,A		;SAVE ESCAPE CODE
ESCAP1	LHLD USERESC	;USER ESCAPE TABLE PTR
	MOV A,H
	ORA A
	LDAX D		;ESCCODE
	JZ NUESC	;NO USER DEFINED TABLE
	CALL LOOKUP	;LOOKUP IN USERS TABLE
	JNZ FNDESC	;FOUND ESCAPE SEQ IN USER
NUESC	LDA ESCCDE	;TRY AGAIN IN VIO TABLE
	ANI 0DFH	;REMOVE LOWER CASE BIT
	LXI H,ESCTBL
	CALL LOOKUP
	JZ ESCRET	;NOT FOUND
FNDESC	LDA CTRLC
	LXI D,SETCMD
	PCHL
;
;************************
;CURSOR CONTROL
;********************
UPLINE	DCX D		;D,E=CURLIN PTR
BCKLNE	LDAX D		;D,E=CURLIN OR CURCOL
	ORA A		;SET FLAGS
	RZ
	DCR A		;BACK UP 1
BCKL1	STAX D
	RET
CRET	XRA A
	STA INSRT	;REMOVE INSERT MODE
	JMP BCKL1
;**********************************
;TOGGLE PROTECTED MODE FLAG
;*********************************
PRTECT	LXI H,PRTMD		;PT AT FLAGŠ	JMP INSMDE+3		;GO TOGGLE IT
;*************************************
;TOGGLE INSERT MODE FLAG
;************************************
INSMDE	LXI H,INSRT
	MOV A,M
	CMA
	MOV M,A
	RET
;***********************
;BLANK SCREEN AND HOME
;***********************
BLNKS	LHLD NCHARS	;#CHARS ON SCREEN
	XCHG
	LXI H,REFRESH
BLNKS1	LDA PRTMD	;IN PROTECTED MODE?
	ANI 80H
	ANA M		;PROTECTED?
	JM BLNKS2	;IS PROTECTED, DO NOT BLANK
	MVI M,' '
BLNKS2	INX H
	DCX D
	MOV A,D
	ORA E		;DONE YET?
	JNZ BLNKS1	;NO
HOME	LXI H,0
	SHLD CURLIN
	RET
;**********************************************
;BLANK FROM CURSOR TO END OF UNPROTECTED FIELD
;***********************************************
BLANKL	CALL CHARLN	;CALC # CHARS TO END OF FIELD
BLANKL3	LDA PRTMD	;PROTECTED MODE?
	ORA A
	JZ BLANKL1	;NOT PROTECTED,SKIP CHECK
	MOV A,M		;GET CHAR
	ORA A
	JM BLANKL1+3	;IS PROTECTED,DO NOT BLANK
BLANKL1	MVI A,' '
	MOV M,A		;INSERT BLANK
	INX H		;NEXT CHAR
	DCR C		;COUNT
	JNZ BLANKL3
	RET
;*********************************
;TURN ON PROTECTED FIELD/TURN OFF PROT FIELD
;**********************************************
PROTC	LXI H,INVIDIO		;PT AT INVERTED VIDIO FLAG
	JMP INSMDE+3
;*********************************************
;DELETE CHAR AND SHIFT PROTECTED FIELD LEFT ONE PLACE
;***********************************************
DELETE	CALL CHARLN
	LHLD CURPTR	;CURSOR POSITION
	MOV D,HŠ	MOV E,L
	INX H
	CALL MVCUP	;SHIFT LINE LEFT ONE PLACE
	MVI A,' '
	DCX D		;BACK UP ONE
	STAX D		;INSERT FINAL BLANK
	RET
;
;****************************************************
;CALC # CHARS FROM CURSOR TO END OF UNPROT FIELD INCLUSIVE
; RETURN H,L=CURSOR PTR
;**********************************************************
CHARLN	LDA PRTMD	;PROTECT MODE FLAG
	ANI 80H
	MOV D,A		;SAVE PROTECT MODE BIT
	LHLD CURPTR	;CURSOR POSITION
	PUSH H
	LDA CURCOL
	MOV E,A		;E=CURRENT COLUMN
	LXI B,0		;# CHARS TO END
CHARLN1	LDA CLINE	;COLS/LINE
	SUB E
	INR E
	INX H
	INR C		;COUNT INCREASED
	DCR A		;DNE YET WITH LINE
	JZ CHARLN2	;END OF LINE RETURN
	MOV A,M		;H,L=END +1
	ANA D		;PROTECTED?
	JP CHARLN1	;NO, KEEP GOING
CHARLN2	POP H		;CURSOR POSITION
	RET
;****************************************************************
;TABLE LOOK UP ROUTINE. SEARCHES FIRST BYTE OF THREE BYTE TABLE OF
;RECORDS FOR A MATCH OR ZERO. ZERO INDICATES END OF TABLE WITH NO
;MATCH, RETURNED IN A REG.H,L LOADED WITH SECOND TWO BYTES OF TABLE
;IF MATCH FOUND.
;*******************************************************************
LOOKUP	MOV B,A		;SAVE
	MOV A,M		;GET FIRST BYTE OF RECORD
	LXI D,CURLIN
	ORA A
	RZ		;DONE,NO MATCH
	CMP B		;SAME AS REQUESTED?
	JNZ TBLUP1	;NO
	INX H
	MOV E,M
	INX H
	MOV D,M
	XCHG
	ORA A		;SET FLAGS
	RET
TBLUP1	INX H
	INX H
	INX H		;BUMP TO NEXT RECORDŠ	JMP LOOKUP+1	;
;*************************************************
;DELETE CURRENT LINE AND RETURN CURSOR
;**********************************************
DLINE	CALL NMCHM	;SET UP FOR MOVE
	PUSH H		;SAVE COLS/LINE
	DAD D		;H,L=SOURCE BEGIN
	CALL MVCUP
DLINE1	POP B		;COLS/LINE
	XCHG
	JMP EN1		;ERASE LINE
;
;***********************************************
;ENTER NEW LINE AT CURSOR LINE,PUSH BOTTOM DOWN
;***********************************************
ENLINE	CALL NMCHM		;SET UP FOR MOVE
	PUSH H		;SAVE COLS/LINE
	DAD D		;H,L=SOURCE BEGIN
	DAD B		;H,L=END OF DEST+1
	XCHG
	DAD B		;H,L=END OF SOURCE+1
	DCX H
	DCX D
	CALL MVCDN	;MOVE DOWN 1 LINE
	POP B
	INX H
EN1	MVI M,' '
	INX H
	DCR C
	JNZ EN1
	RET
NMCHM	XRA A
	STAX D		;COL=0
	CALL CHARSN	;#CHARS TO END OF SCREEN
	XCHG		;D,E=DEST.
	LHLD CLINE	;COLS/LINE
	MOV A,L		;COLS/LINE
	DCX B
	DCR A
	JNZ $-2		;DECREASE COUNT BY ONE LINES WORTH
	RET
;******************************************
;CALC # CHARS TO END OF SCREEN FROM CURSOR
;********************************************
CHARSN	CALL CALPOS
	PUSH H		;SAVE
	XCHG		;D,E=CURSOR POS
	LHLD LASTC	;LAST CHAR POSITION+1
	MOV A,D
	CMA
	MOV D,A
	MOV A,E
	CMA
	MOV E,A
	INX D		;COMPLIMENT D,EŠ	DAD D		;H,L=# CHARS TO END-1
	PUSH H
	POP B		;B,C=#CHARS TO END
	POP H		;CURRENT POSITION CURSOR
	RET
;***********************
;ESCAPE CODE PROCESSING
;************************
HIGH128	ANI 0F3H
	ORI 4H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;GRAPHIC MODE 256 CHAR ROM,NO INVERSE VIDIO
GRAPHIC	ORI 0CH
	XCHG	;H,L=SETCMD ADDR
	PCHL
;LOWER HALF OF ROM+REVERSE VIDIO
LOW128	ANI 0F3H
	ORI 8H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;SCROLL TOGGLE
SCRL	XRI 80H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;UPPER LOWER CASE TOGGLE
UPLOW	XRI 20H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;INVERSE VIDIO TOGGLE
VIDIO	XRI 10H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;# LINES PER PAGE SWITCH
LINES	XRI 02H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;#COLS/LINE TIGGLE
COLS	XRI 01H
	XCHG	;H,L=SETCMD ADDR
	PCHL
;**************************************
;INSERT CURSOR CHAR AT PROPER POSITION
;*************************************
INSCURS	LHLD CURPTR
	MOV A,M
	STA CCUR	;SAVE CHAR UNDER CURSOR FOR GRAPHICS MODE

	ORI 80H		;BIT 7 FOR INVERSE VIDIO
	MOV M,A		;STORE BACK
	LDA VDIMDE
	ORA A
	RNZ		;NO GRAPHICS
	MVI M,7FH	;BLOCK FOR GRAPHICS MODE
	RETŠ;
;****************************************
;CLEAR TABS
;*****************************************
CLRTBS	LXI H,TAB		;TABS BITS
	MVI B,10		;#BYTES FOR TABS
	XRA A
CLRT1	MOV M,A
	INX H
	DCR B
	JNZ CLRT1
	JMP ESCRET		;PUT IN CURSOR
;***********************************
;SET OR CLEAR TAB TOGGLE BIT
;**********************************
SETTAB	CALL FNDTB
	XRI 80H		;INVERT TAB BIT
SETD2	RRC
	DCR B
	JNZ SETD2
	STAX D		;STORE TAB BYTE
	JMP ESCRET	;DO CURSOR
;FIND TAB BIT, LEAVE IN A REG BIT 7
FNDTB	LDA CURCOL	;COL #
	MOV H,A
	INR H
	LXI D,TAB	;WORD PTR
FNDTB1	MVI C,8		;BIT COUNTER
	DCR H
	JZ FNDTDN	;FOUND IT
	DCR C		;BIT COUNTER
	JNZ FNDTB1+2
	INX D		;PT AT NEXT BYTE
	JMP FNDTB1
FNDTDN	LDAX D		;GET TAB BYTE BITS
	MOV B,C		;SAVE COUNT OF BITS
FNDTB2	RLC
	DCR C
	JNZ FNDTB2	;ROTATE UNTIL FOUND
	RET
;
;***************************************************************
;TAB TO BEGINNING OF NEXT UNPROTECTED FIELD OR TAB OR HOME IF NONE
;*****************************************************************
TABB	XRA A
	STA PRUPRF	;PROTECT/UNPROTECT TRANSITION FLAG
TAB3	CALL BMPC	;BUMP CURSOR POSITION
	JNZ TAB1	;NO LINE FEED NECESSARY
	INR M		;BUMP LINE #
	CMP M		;EXCEED LPAGE?
	JM SCROLL3	;YES,HOME AND RETURN
TAB1	LDA PRTMD	;PROTECT MODE FLAG
	XCHG		;H,L PTS AT CHAR
	ANA M		;PROTECTED?
	MOV A,M		;GET CHARŠ	LXI D,PRUPRF	;TRANSITION FLAG
	JP TAB2		;NO PROTECTED FIELD
	STAX D		;SET TRANSITION FLAG
	JMP TAB3
TAB2	LDAX D		;GET TRANSITION FLAG
	ORA A
	RM		;UNPROT FIELD WITH TRANSITION
	CALL FNDTB	;FIND TAB POSITION BIT
	ORA A		;SET FLAGS
	RM		;TAB IS SET
	JMP TAB3
;************************************************
;CALCULATE CURSOR POSITION FROM CURLIN AND CURCOL
;**************************************************
CALPOS	LHLD CLINE	;CHARS/LINE-1
	XCHG
	LHLD CURLIN	;L=CURLIN,H=CURCOL
	MOV C,H
	MOV B,L
	LXI H,REFRESH	;BOTTOM OF REFRESH MEMORY
	INR B
CALPOS1	DCR B		;DONE YET
	JZ CALPOS2	;YES
	DAD D		;ADD ANOTHER LINE OF CHARS
	JMP CALPOS1
CALPOS2	DAD B		;ADD CURRENT COL
	SHLD CURPTR	;SAVE
	RET
;**************************
;BMPC BUMP CURSOR 1 PLACE. ON RETURN
; D,E=CURSOR POSITION
; H,L=CURCOL PTR OR CURLIN PTR DEPENDING ON Z FLAG
; Z FLAG=0 IF NO LINE FEED NEEDED,1 IF LINE FEED NEEDED
; CURLIN AND CURCOL AND CURPTR ARE UPDATED AS IF LINE FEED
; A REG =LPAGE IF LINE FEED NEEDED
;**********************************************************
BMPC	LHLD CURPTR
	INX H
	SHLD CURPTR	;UPDATE ABS CURSOR ADDRESS
	XCHG		;D,E=PTR
	LXI H,CURCOL
	INR M		;BUMP COLUMN
	LDA CLINE	;MAX COLS/LINE
	SUB M		;ZERO IF EXCEED LINE
	RNZ		;OK AS IS
	MOV M,A		;COL=0
	DCX H
	LDA LPAGE	;MAX LINES/PAGE
	RET
;************************************************
;ADDRESSABLE CURSOR FUNCTION
;********************************
ADDCURS	LXI H,ESCCNT	;PT AT ESCAPE COUNT
	LXI D,CURLIN	;PT AT CURRENT LINE COUNT
	LDA CCHARŠ	SUI 20H		;REMOVE OFFSET FOR COUNT
	MOV B,A
	MOV A,M	;GET COUNT
	SUI 3
	RM		;NO VALID NUMBS YET
	JNZ XADD	;X AXIS VALUE
;Y-AXIS VALUE
	LDA LPAGE
XADD3	STAX D		;MAX LINE #
	CMP B
	RM
	MOV A,B
	STAX D
	RET
XADD	MVI M,0		;ESCCNT=0
	LDA CLINE	;MAX COL/LINE
	INX D
	DCR A
	JMP XADD3
;
;********************************************************
;INSERT CHAR AT CURSOR POSITION.EITHER WRITES OVER PREVIOS
;CHAR OR PUSHES ENTIRE FIELD OVER ONE CHAR BEFORE INSERTING.
;************************************************************
INSCHR	LHLD CURPTR	;CURSOR ADDRESS
	PUSH H		;SAVE
	LDA INSRT	;INSERT FLAG
	ORA A
	JZ INSC3	;OVERWRITE
	CALL CHARLN
	DCX B		;3CHARS-1 TO END
	DAD B		;H,L PTS AT LAST CHAR ON LINE
	MOV D,H
	MOV E,L
	DCX D		;D,E PTS AT SOURCE
	XCHG		;H,L=SOURCE,D,E=DEST
	CALL MVCDN	;MOVE CHARS RIGHT
INSC3	POP H	;CURSOR POSITION
	LDA INVIDIO
	ANI 80H
	MOV B,A		;INVERT BIT
	LDA CCHAR
	ORA B		;MERGE WITH INVERT BIT
INSC4	MOV M,A
	RET
;********************************************************
;SHIFT CHARS RIGHT FROM D,E TO H,L,  B,C CHARS FROM RIGHT
;********************************************************
MVCDN	MOV A,C
	ORA B
	RZ		;DONE
	MOV A,M
	STAX D
	DCX H
	DCX DŠ	DCX B
	JMP MVCDN
;
;	CONTROL FUNCTION JUMP TABLE
CTRTBL	EQU $
	DB 0DH		;CARRIAGE RETURN
	DW CRET
	DB 0AH		;LINE FEED
	DW LFEED
	DB 0BH		;UP CURSOR (CTRL K)
	DW UPLINE
	DB 0CH		;FORWARD CURSOR (CTRL L)
	DW BMPCUR
	DB 08H		;BACK CURSOR (CTRL H)
	DW BCKLNE
	DB 1EH		;HOME CURSOR (CTRL ^)
	DW HOME
	DB 1AH		;SCREEN ERASE (CTRL Z)
	DW BLNKS
	DB 15H		;CLEAR TO EOL (CTRL U)
	DW BLANKL
	DB 16H		;PROTECTED FIELDS (CTRL V)
	DW PROTC
	DB 09H		;TAB (CTRL I)
	DW TABB
	DB 7FH		;DELETE CHAR (RUBOUT)
	DW DELETE
	DB 14H		;INSERT MODE (CTRL T)
	DW INSMDE
	DB 04H		;DELETE LINE CTRL D
	DW DLINE
	DB 05H		;INSERT LINE (CTRL E)
	DW ENLINE
	DB 10H		;PROTECTED MODE TOGGLE (CTRL P)
	DW PRTECT
	DB 0		;TERMINATOR
;	ESCAPE FUNCTION JUMP TABLE
ESCTBL	EQU $
	DB 1DH		;CURSOR CONTROL ('=' LESS BIT 5 LOWER CASE)
	DW ADDCURS
	DB 49H		;SET TAB
	DW SETTAB
	DB 09H		;CLEAR TABS
	DW CLRTBS
	DB 'T'		;LOWER 128 BYTES OF ROM
	DW LOW128
	DB 'E'		;EXTENDED MODE UPPER 128
	DW HIGH128
	DB 'G'		;GRAPHIC SET
	DW GRAPHIC
	DB 'S'		;SCROLL TOGGLE
	DW SCRL
	DB 'U'		;UPPER/LOWER CASE
	DW UPLOW
	DB 'V'		;INVERSE VIDIO TOGGLEŠ	DW VIDIO
	DB 'L'		;LINES/PAGE
	DW LINES
	DB 'C'		;COLS/LINE
	DW COLS
	DB 0		;TERMINATOR
;
;*******************************************************
;8085 MONITOR PROGRAM USING THE VIO FIRMWARE
; COPYRIGHT IMSAI MANUFACTURING COMPANY, INC.
; SAN LEANDRO,CALIFORNIA
; 6/7/77
;*******************************************************
MONT	LXI SP,REFRESH+7FFH	;TOP OF MEMORY
	MVI A,0AAH
	OUT 3
	CMA
	OUT 3
	CMA
	OUT 3
	MVI A,27H
	OUT 3		;SET UP USART
	CALL INIT	;INIT VIO
	LXI H,SIGNON
	CALL MSGNC		;SIGNON MSG
PRMPT	LXI SP,REFRESH+7FFH
	CALL CRLF
	MVI A,'?'
	CALL CHAROUT
	CALL CHIN	;GET COMMAND
	MOV B,A		;SAVE IT
	LXI D,PRMPT
	PUSH D		;RETURN ADDRESS
	LHLD USERCMD	;USER COMMAND TABLE
	MOV A,H
	ORA A		;SET FLAGS
	MOV A,B		;RETRIEVE CODE
	JZ NUCMD	;NO USER COMMAND TABLE
	CALL LOOKUP	;LOOKUP IN USER TABLE
	JNZ FNDCMD	;FOUND COMMAND
NUCMD	MOV A,B		;GET COMMAND AGAIN
	LXI H,CMDTBL	;COMAND TABLE PTR
	CALL LOOKUP
	RZ		;NO  ENTRY,PROMPT AGIN
	MVI B,1		;FOR PROT/UNPROT
FNDCMD	PCHL		;GO TO ROUTINE
SIGNON	DB 'IMSAI SMP/80.0',0
	DB 'COPYRIGHT 6/77'
;
;*************************************************
;JUMP TO MEMORY "JAAAA"
;CALL MEMORY WITH RETURN TO MONITOR
;***********************
JUMP	POP D		;REMOVE RETURN ADDRESS
CALL1	CALL IHEX	;GET JUMP ADDRESSŠ	PCHL		;DO IT
;***************************************
;ENTER BYTE INTO MEMORY AND MODIFY IF DESIRED
;******************************************************
ENTR	CALL IHEX	;START ADDR
	CALL CRLF
	CALL OHEXHL	;DISPLAY ADDRESS
	MOV A,M		;GET BYTE IN MEMORY
	MOV E,A		;PRESET FOR IHEX
	CALL OHEXB	;DISPLAY BYTE
	XCHG		;D,E=ADDRESS,L=DEFAULT CHAR
	CALL IHEX+3	;GET MODIFIER OR DEFAULT
	XCHG		;H,L=ADDR,E=BYTE
	MOV M,E
	DCX H
	CPI 0AH		;DONE?
	RZ		;YES
	CPI '-'		;BACKWARD
	JZ ENTR+3	;YES
	INX H
	INX H		;DEFAULT FORWARD
	JMP ENTR+3
;*****************************************************
;DISPLAY MEMORY "D,START,END CR"
;*************************************
DISP	CALL SIZE	;H,L=START,B,C=SIZE
	LDA CTRLC	;#LINES/COLS
	RRC		;#LINES BIT IN CARRY
	RRC
	MVI D,12
	JC $+5
	MVI D,24
DISP2	CALL CRLF
	IN 3
	ANI 2		;ANY INPUT
	RNZ		;YES,INTERRRUPT
	MVI E,8
	LDA CTRLC
	RRC
	JC $+5
	MVI E,16
	CALL OHEXHL	;OUTPUT ASCII H,L REG
DISP1	MOV A,M		;GET DATA BYTE
	CALL OHEXB	;OUTPUT WITH TRAIL BLANK
	INX H
	DCX B
	MOV A,B
	ORA C
	RZ		;DONE
	DCR E
	JNZ DISP1	;KEEP WITH CURRENT LINE
	DCR D		;FILLED PAGE YET?
	JNZ DISP2
	CALL CHIN	;WAIT FOR PAGE PROMT
	JMP DISP+3Š;****************************
;ALLOW ESCAPE SEQUENCES TO CONTROL
;*********************************
ESCAP	CALL CHIN	;READ ESCAPE SEQUENCE CODE
	RET
;********************************
;OUTPUT HEX WITH TRAILING BYTE
;******************************
OHEXB	CALL OHEX
	MVI A,' '
	CALL CHAROUT
	RET
;********************************
;OUTPUT 16 BIT ASCII HEX FROM H,L
;*********************************
OHEXHL	MOV A,H
	CALL OHEX
	MOV A,L
	CALL OHEXB
	RET
;*******************************************
;PROTECT /UNPROTECT RAM4A-4 MEMORY
;******************************************
PROT	INR B		;PROTECT/UNPROTECT FLAG
UNPRT	CALL PARM2	;GET START,END ADDRESSES IN H,L D,E
MEMP	MOV A,D
	ANI 0FCH	;GET 1K OFFSET ONLY
	ORA B
	MOV D,A
	MOV A,H
	ANI 0FCH
	ORA B
PROT1	OUT 0FEH	;DO IT
	CMP D		;DONE?
	RZ		;YES
	ADI 4		;SET FOR NEXT 1K BLOCK
	JMP PROT1
;**************************************************
;INTEL LOADER LOADS INTEL FORMAT TAPES FROM
;TELETYPE (PORT 2,3) 
;***********************************************
INTEL	CALL CHIN	;READ WITHOUT ECHO
	SBI ':'		;RCORD MARKER?
	JNZ INTEL	;NO
	MOV D,A		;ZERO CHECKSUM
	CALL IBYTE	;INPUT 2 HEX CHARS
	ORA A		;SET FLAGS
	RZ		;COUNT =0 MEANS END
	MOV D,A		;BYTE COUNT
	CALL IBYTE
	MOV H,A
	CALL IBYTE
	MOV L,A
	CALL IBYTE	;DUMMY RECORD TYPE IGNORED
DATA	CALL IBYTEŠ	MOV M,A
	INX H
	DCR D
	JNZ DATA
	CALL IBYTE	;READ AND ADD CHECKSUM
	JZ INTEL	;OK AS IS
	MVI A,'C'
	CALL CHAROUT	;ERROR MESSAGE
	RET
;*************************
;READ 2 ASCII HEX BYTES AND CONVERT TO BINARY
;********************************************
IBYTE	CALL CHIN	;READ CHAR
	CALL ASBI	;CONVERT TO BINARY
	JC ERR2
	ADD A
	ADD A
	ADD A
	ADD A
	MOV E,A		;SAVE
	CALL CHIN
	CALL ASBI
	JC ERR2		;INVALID ASCII HEX CHAR
	ADD E
	MOV E,A		;SAVE CHAR
	ADD D		;ADD TO CHECKSUM
	MOV D,A
	RET
;*************************************************
;SIZE INPUTS START,END ADDR AND CONVERTS TO START
;  AND SIZE IN H,L AND B,C
;*************************************************
SIZE	CALL PARM2	;H,L=START D,E=END
	PUSH A
	MOV A,E
	SUB L		;LOW BYTE SIZE
	MOV C,A
	MOV A,D
	SBB H		;HIGH BYTE SIZE
	MOV B,A
	INX B		;ADD 1
	POP A
	RET
;********************************************
;MEMORY MOVE "M SOURCE BEG,SOURCE END,DEST BEG"
;***********************************************
MOVE	CALL PARM4	;START,END,DEST
MOVE1	CALL MVCUP	;DO MOVE
	RET
;******************************
;FILL MEMORY WITH CHAR
;****************************
FILL	CALL PARM4	;START,END,FILL CHAR IN L
	MOV A,E		;FILL CHAR
	MOV M,A		;STORE IN FIRST LOCATIONŠ	DCX B
	MOV D,H
	MOV E,L		;DEST ADDR
	INX D		;=START ADDR+1
	JMP MOVE1
;*******************************
;MEMORY TEST ROUTINE
;****************************
MEMTEST	CALL SIZE	;H,L=START,B,C=SIZE
	DCX B		;B,C=SIZE-1 OR 0
MEM2	XRA A
	MOV D,M			;SAVE CELL
MEM1	MOV M,A
	CMP M
	JNZ MEMERR	;NOT GOOD
	DCR A		;NEXT PATTERN
	JNZ MEM1
	MOV M,D		;RESTORE MEMORY
	IN 3
	ANI 2		;BAIL OUT?
	RNZ		;YES
	INX H
	DCX B
	MOV A,B
	ORA C
	JNZ MEM2
	RET
MEMERR	INX H		;ADJUST FOR PRNMEM
	MOV E,A		;SAVE
	CALL PNTMEM	;PRINT ADDR,CONTENTS
	MOV A,E		;RESTORE
	JMP SRCPNT1	;PRINT SOULD BE
;**********************************
;DO DIRECT INPUT/OUTPUT FROM SPECIFIED PORT
;*************************************
INPORT	DCR B		;B=0=INPUT,B=1=OUTPUT
OUTPORT	CALL PARM2	;INPUT PORT,VALUE IN H,L AND D,E
	MOV A,B		;FLAG
	RLC
	RLC
	RLC
	XRI 08H		;INVERT BIT 3
	ORI 0D3H	;FORM I/O INST
	MOV D,L
	LHLD RAMPTR	;GET AVAIL RAM PTR
	MOV M,A
	CMP M
	RNZ		;INVALID RAM
	PUSH H
	INX H
	MOV M,D		;PORT #
	INX H
	MVI M,0C9H	;RETURN
	LXI H,IORET
	XTHL		;PUT RETURN ADDRESS,GET START ADDRŠ	MOV A,B
	ORA A		;SET FLAG FOR IN OR OUT
	MOV A,E		;OUTPUT BYTE
	PCHL
IORET	RNZ		;DONE IF OUTPUT INST
	CALL OHEXB	;PRINT VALUE IF INPUT
	RET
;********************************
;SET FREE RAM PTR FOR DIRECT IO INSTS
;***********************************
RAMFND	CALL IHEX	;GET RAM ADDR
	SHLD RAMPTR	;SAVE IN VIO RAM
	RET
;************************************************
;COMPARE MEMORY BLOCKS AND PRINT DIFFERENCES
;**********************************************
CMPBLK	CALL PARM4	;START,SIZE,DEST IN HL BC,DE
CMPBLK1	LDAX D		;DEST BYTE
	CMP M		;SAME AS SOURCE BYTE?
	INX H
	INX D
	JZ CMPB1	;YES, NO PRINT
	CALL PNTMEM	;PRINT ADDR,SOURCE DEST
	XCHG
	CALL PNTMEM+3	;NO CRLF
	XCHG
CMPB1	DCX B
	MOV A,B
	ORA C
	RZ		;YES,RETURN
	IN 3
	ANI 2
	RNZ		;BAIL OUT
	JMP CMPBLK1
;****************************************
;SEARCH MEMORY FOR MASKED 16 BIT VALUE
;S,FROM,TO,16BIT VALUE,16 BIT MASK
;*****************************************
SEARCH	CALL PARM4	;START,SIZE,VALUE IN H,L B,C D,E
	PUSH H		;SAVE
	LXI H,-1	;DEFAULT MASK ALL
	CPI 0AH		;USER SPECIFIED MASK?
	CNZ IHEX	;YES,READ IT INTO H,L
	XTHL		;MASK ON STACK,START IN H,L
SEARCH1	MOV A,M		;LOW BYTE
	XTHL		;H,L=MASK VALUE
	ANA H		;MASK HIGH BYTE
	CMP D		;IS IT CORRECT VALUE?
	XTHL		;RESTORE START PTR
	INX H		;BUMP PTR
	JNZ CMP16	;NO MATCH
	MOV A,M		;LOW BYTE
	XTHL		;GET MASK IN H,L
	ANA L
	CMP EŠ	XTHL		;H,L=START,STACK=MASK
	CZ SRCPNT	;PRINT MATCH IF FOUND
CMP16	DCX B
	MOV A,B
	ORA C
	JNZ SEARCH1
	POP B		;REMOVE MASK VALUE
	RET
;*******************************
;PARM4 INPUTS START,END,VALUE AND
;CONVERTS TO START,SIZE,VALUE IN H,L B,C AND D,E
;RESPECTIVELY
;**************************************************
PARM4	CALL SIZE
	JMP PARM3
;**************************************
;MVCUP MOVE B,C CHARS FROM H,L TO D,E FROM BOTTOM
;************************************************
MVCUP MOV A,B
	ORA C
	RZ
	MOV A,M
	STAX D		;MOVE IT
	DCX B
	INX H
	INX D
	JMP MVCUP	;KEEP GOING
;*************************************************
;LOAD OR EXECUTE CASETTE FILE USING HEADER OR
;USER SPECIFIED START,END,EXEC ADDRESSES
;**************************************************
EXEC	DCR B		;EXECUTE FLAG
LOAD	PUSH B		;SAVE EXEC/LOAD FLAG
	CALL PARM2	;ANY PARMS SPECIFIED?
	MOV A,D
	ORA E
	JZ HEADER	;NO PARMS,OR NOT ENOUGH PARMS
;SKIP HEADER IF PRESENT
	PUSH H		;START
	PUSH D		;END
	CALL IHEX	;GET EXEC IF ANY
	PUSH H		;EXEC ADDR
	CALL RDHEAD	;READ HEADER IF THERE
	JNZ RDRCRDS	;NOT THERE DO OBLECT
	POP A
	POP A
	POP A		;REMOVE HEADER PARMS
	JMP RDRCRDS	;DO OBJECT
HEADER	CALL RDHEAD	;READ HEADER
ERR2	MVI A,'T'	;TYPE CODE ERROR
	JZ RDRCRDS	;NO ERROR
ERR1	CALL CHAROUT
	JMP PRMPT	;BAIL OUT
RDRCRDS	POP B		;EXEC
	POP H		;ENDŠ	POP D		;START
	PUSH B		;RETURN EXEC ADDR
	PUSH H		;END
	PUSH D		;START
	MOV A,L
	SUB E
	MOV L,A
	MOV A,H
	SBB D
	MOV H,A
	DAD H
	MOV C,H
	INR C		;RECORD COUNT TO READ
RDRCRD	CALL CASIN	;TYPE CODE
RDRCRD1	CPI 81H		;ABS BINARY?
	JNZ ERR2	;TYPE CODE ERROR
	CALL CASIN	;BYTE COUNT
	MOV B,A		;SAVE RECORD BYTE COUNT
	LXI H,0		;0 CHECKSUM
RDATA	CALL CASINCK	;READ DATA BYTE
	STAX D		;STORE IT
	INX D
	 DCR B
	JNZ RDATA	;CONTINUE IF NOT DONE
	PUSH D		;SAVE MEMORY PTR
	XCHG		;DE=CHECKSUM
	CALL CASWD	;READ TAPE CHECKSUM
	MOV H,L
	MOV L,A		;REVERSE BYTES
	DAD D	;ADD TO COMPUTED CHECKSUM
	MOV A,H
	ORA L
	MVI A,'C'	;CHECKSUM ERROR
	CNZ CHAROUT	;TYPE 'C'
	JNZ $+8
	MVI A,'*'
	CALL CHAROUT	;TYPE * FOR GOOD RECORD
	POP D		;RETRIEVE MEMORY PTR
	DCR C		;ALL RECORDS READ YET
	JNZ RDRCRD	;NO READ ANOTHER
	CALL CRLF
	MVI C,3
LP2	POP H
	CALL OHEXHL
	DCR C
	JNZ LP2
	POP PSW		;EXEC/LOAD FLAG
	RAR
	RC		;DONE
	PCHL
;******************************
;READ HEADER RECORD
;**********************
RDHEAD	CALL CASINIT	;INIT CASETTE
	CALL CASIN	;READ TYPE CODEŠ	CPI 1		;HEADER RECORD?
	RNZ		;NO
	CALL CASIN	;RECORD LENGTH
	MVI C,5		;NAME SIZE
NM1	CALL CASIN	;NAME BYTE
	CALL CHAROUT	;DISPLAY IT
	DCR C
	JNZ NM1		;DO IT TILL DONE
	MVI C,3
ADDRS	CALL CASWD	;INPUT START,END,EXEC
	XTHL		;EXCH RETURN ADDR WITH PARM
	PUSH H		;PUSH RETURN ADDR AGAIN
	DCR C
	JNZ ADDRS
	CALL CASWD	;DUMMY CHECKSUM
	XRA A		;ZER FLAGS FOR NORMAL RETURN
	RET
;*******************************************
;CASINIT READ CASETTE UNTIL 32 SYNC BYTES READ
;**********************************************
CASINIT	CALL BYTESET	;READ FIRST SYNC
	MVI B,31
CASIN2	CALL CASIN
	CPI 0E6H
	MVI A,'I'
	JNZ ERR1
	DCR B
	JNZ CASIN2
	RET
;*******************************
;CASETTE OUTPUT BYTE
;**************************
CASOUT	PUSH A	;SAVE IT
	IN 3
	ANI 4
	JZ CASOUT+1
	POP A
	OUT 0		;WRITE BYTE
	RET
;*****************************
;GENERATE SYNC STREAM
;***************************
GEN	CALL IHEX	;WAIT FOR RETURN
	MVI A,10H
	OUT 3		;WRITE ENABLE MIO
GEN1	MVI A,0E6H
	CALL CASOUT
	IN 3
	ANI 2
	RNZ
	JMP GEN1
;****************************************
;READ BYTE FROM CASETTE WITHOUT CHECKSUM
;************************************************
CASIN	IN 3Š	RRC
	RRC		;C=SERIAL READY
	JC PRMPT	;BAIL OUT
	RRC		;C=CASETTE READY
	JNC CASIN	;KEEP TRYING
	IN 0		;DATA PORT
	RET
;*****************************************
;CASINCK- READ BYTE WITH CHECKSUM
;**************************************
CASINCK	CALL CASIN
CHKSUM	PUSH B
	MOV C,A		;NEW CHAR IN LOW BYTE
	MVI B,0
	DAD B		;ADD TO CHECKSUM
	POP B		;RESTORE
	RET
;****************************
;ALLIGN CASETTE BY READING AND DISPLAYING BYTES
;*******************************************
ALIGN	CALL CHIN	;WAIT FOR CR
	CALL BYTESET
ALL4	LXI H,REFRESH
	LXI D,481	;FILL SMALLEST SCREEN
ALL3	DCX D
	MOV A,D
	ORA E
	JZ ALL4		;START AGAIN EVERY 256 CHARS
	MVI M,7FH
	CALL CASIN	;READ NEXT CHAR
	MOV M,A		;PUT IN SCREEN
	INX H
	JMP ALL3
;*******************************
;GET CASETTE IN BYTE MODE IE READ FIRST 0E6H
;*******************************************
BYTESET	MVI A,60H	;BIT MODE
	OUT 3
BYTE1	CALL CASIN	;READ BYTE EVERY BIT TIME
	CPI 0E6H	;SYNC YET
	JNZ BYTE1	;NO
	MVI A,20H	;BYTE MODE
	OUT 3
	RET
;*******************************
;CASWD-INPUT WORD TO H,L ADD FIRST BYTE ONLY
;TO CHECKSUM
;*******************************************
CASWD	CALL CASIN	;READ LOW BYTE
	MOV L,A
	CALL CASIN	;READ HIGH BYTE
	MOV H,A
	RET
;********************************
;CHARACTER INPUT ROUTINESŠ;****************************
CHIN	CALL CHIN1
	CPI 03		;CRTL C?
	JZ MONT		;YES,RESET AND PROMPT
	CALL CHAROUT
	CPI 0DH
	CZ CRLF	;ADD LINE FEED
	RET
CHIN1	IN 3
	ANI 2
	JZ CHIN1
	IN 2		;READ PORT 2
	ANI 7FH		;MASK PARITY
	RET
	DB 0,0,0,0,0,0,0,0,0,0,0,0,0
;**********************************
;PARM2 READ 2 PARAMATERS 16 BITS EACH INTO H,L AND D,E
;********************************************************
PARM2	CALL IHEX
	MOV D,H
	MOV E,L
	CPI 0AH		;TERMINATED?
	RZ		;YES,USE SAME VALUE
	CPI ','
	JZ PARM3
	CPI ' '
	RNZ		;INVALID
PARM3	XCHG
	CALL IHEX	;GET SECOND PARM
	XCHG
	RET
;***********************
;CRLF DO CARRIAGE RETURN/LINE FEED
;*********************************
CRLF	MVI A,0DH
	CALL CHAROUT
	MVI A,0AH
	CALL CHAROUT
	RET
;:************************************************
;INPUT CHARS ASSUMED HEX AND CONVERT TO BINARY
;TERMINATES ON FIRST NO HEX CHAR WHICH IS LEFT
;IN A REG. H,L RETURNS WITH VALUE
;*************************************************
IHEX	LXI H,0
	CALL CHIN	;READ CHAR
	PUSH A
	CALL ASBI	;CONVERT TO BIBARY
	JNC IHEX1
	POP A
	RET
IHEX1	DAD H
	DAD H
	DAD H
	DAD H		;ADD NEW DIGITŠ	ADD L
	MOV L,A
	POP A
	JMP IHEX+3
;************************************************
;CONVERT ASCII HEX CHAR IN A-REG TO BINARY IN A REG
;RETURN WITH CARRY SET IF INVALID CHAR,RESET OTHERWISE
;********************************************************
ASBI	SUI 30H		;REMOVE ASCII BIAS
	RC		;INVALID <0
	CPI 10
	JC ASBI1	;VALID 0-9
	SUI 17
	RC		;INVALID
	ADI 10
	CPI 16		;SET CARRY IF <0FH
ASBI1	CMC
	RET
;*****************************************
;PRINT H,L AND 16 BIT MEMORY AT H,L
;**************************************
SRCPNT	CALL PNTMEM
	MOV A,M	;BYTE 2
SRCPNT1	CALL OHEX
	RET
PNTMEM	CALL CRLF
	DCX H		;BACK UP 1
	CALL OHEXHL
	MOV A,M
	CALL OHEXB
	INX H
	RET
;**********************************************
;OUTPUT HEX CHARS TO VIDIO FROM A REG
;*********************************************
OHEX	PUSH PSW	;SAVE CHAR
	RRC 
	RRC
	RRC
	RRC
	CALL BIAS	;BINARY TO ASCII AND OUT

	POP PSW
	CALL BIAS
	RET
;****************************
;CONVERT BINARY TO ASCII
;***************************
BIAS	ANI 0FH		;MASK NIBBLE
	ADI 90H
	DAA
	ACI 40H
	DAA
	CALL CHAROUT
	RETŠ;*********************************************
;OUTPUT MESSAGE PTED TO BY H,L AND TERMINATED
;BY ONE BYTE OF BINARY ZEROS
;********************************************
MSG	CALL CRLF
MSGNC	MOV A,M
	ORA A
	RZ
	CALL CHAROUT
	INX H
	JMP MSGNC
CMDTBL	EQU $
	DB 'H'
	DW INTEL	;INTEL HEX LOADS
	DB 'R'		;FREE RAM LOCATION
	DW RAMFND
	DB 'G'
	DW GEN		;GENERATE SYNC STREAM
	DB 'A'
	DW ALIGN	;ALLIGN CASETTE ON MIO
	DB 'V'
	DW CMPBLK	;COMPARE MEMORY BLOCKS
	DB 'I'
	DW INPORT	;INPUT FROM SPECIFIED PORT
	DB 'O'
	DW OUTPORT	;OUPUT TO SPECIFIED PORT
	DB 'T'
	DW MEMTEST
	DB 'J'
	DW JUMP		;JUMP TO ADDRESS
	DB 'C'
	DW CALL1	;CALL MEMORY WITH RETURN
	DB 'D'		;DISPLAY MEMORY
	DW DISP
	DB 'E'
	DW ENTR		;ENTER INTO MEMORY
	DB 'M'
	DW MOVE		;MOVE MEMORY BLOCK
	DB 'F'		;FILL MEMORY
	DW FILL
	DB 'U'
	DW UNPRT	;UNPROTECT MEMORY
	DB 'P'
	DW PROT		;PROTECT MEMORY
	DB 'L'
	DW LOAD		;LOAD CASETTE
	DB 'S'
	DW SEARCH	;16 BIT MASKED SEARCH
	DB 'X'
	DW EXEC		;EXECUTE FROM CASETTE
	DB 1BH		;ESCAPE CODE
	DW ESCAP
	DB 0
	END
