;*************************************************************
; 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
;
; MODIFIED TO ASSEMBLE WITH INTEL 8080 CROSS ASSEMBLER
; AND PRETTIFIED SOURCE
;           UDO MUNK
;           1/3/2017
;**************************************************************
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
USRCTR: DW   0          ;USER CTR TBLE PTR, NON ZERO
USRESC: 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      ;CONTROL 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   BMPC1      ;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
BMPC1:  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   SCR3       ;WRAP AROUND
        CPI  0CH        ;GRAPHICS MODE
        JNZ  SCR1       ;NO, ALLOW SCROLL
SCR3:   XRA  A
        MOV  M,A        ;HOME CURSOR FOR WRAP AROUND
        INX  H
        MOV  M,A
        RET
SCR1:   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
SCR2:   JMP  DLN1       ;ERASE CURRENT LINE AND RETURN
;******************************
;PROCESS CONTROL CODES
;******************************
CONTROL:XCHG            ;D,E=CCHR PTR
        LHLD USRCTR     ;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  ESC1       ;ESCCNT>1
        MOV  M,A        ;SAVE ESCAPE CODE
ESC1:   LHLD USRESC     ;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
BLNK1:  LDA  PRTMD      ;IN PROTECTED MODE?
        ANI  80H
        ANA  M          ;PROTECTED?
        JM   BLNK2      ;IS PROTECTED, DO NOT BLANK
        MVI  M,' '
BLNK2:  INX  H
        DCX  D
        MOV  A,D
        ORA  E          ;DONE YET?
        JNZ  BLNK1      ;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
BLAN3:  LDA  PRTMD      ;PROTECTED MODE?
        ORA  A
        JZ   BLAN1      ;NOT PROTECTED,SKIP CHECK
        MOV  A,M        ;GET CHAR
        ORA  A
        JM   BLAN1+3    ;IS PROTECTED,DO NOT BLANK
BLAN1:  MVI  A,' '
        MOV  M,A        ;INSERT BLANK
        INX  H          ;NEXT CHAR
        DCR  C          ;COUNT
        JNZ  BLAN3
        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
CHRL1:  LDA  CLINE      ;COLS/LINE
        SUB  E
        INR  E
        INX  H
        INR  C          ;COUNT INCREASED
        DCR  A          ;DNE YET WITH LINE
        JZ   CHRL2      ;END OF LINE RETURN
        MOV  A,M        ;H,L=END +1
        ANA  D          ;PROTECTED?
        JP   CHRL1      ;NO, KEEP GOING
CHRL2:  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
DLN1:   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
FNDT1:  MVI  C,8        ;BIT COUNTER
        DCR  H
        JZ   FNDTDN     ;FOUND IT
        DCR  C          ;BIT COUNTER
        JNZ  FNDT1+2
        INX  D          ;PT AT NEXT BYTE
        JMP  FNDT1
FNDTDN: LDAX D          ;GET TAB BYTE BITS
        MOV  B,C        ;SAVE COUNT OF BITS
FNDT2:  RLC
        DCR  C
        JNZ  FNDT2      ;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   SCR3       ;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
CALP1:  DCR  B          ;DONE YET
        JZ   CALP2      ;YES
        DAD  D          ;ADD ANOTHER LINE OF CHARS
        JMP  CALP1
CALP2:  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
;*********************************
ESCCO:  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 PSW
        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  PSW
        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  SRCP1      ;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
CMPB1:  LDAX D          ;DEST BYTE
        CMP  M          ;SAME AS SOURCE BYTE?
        INX  H
        INX  D
        JZ   CMPB2      ;YES, NO PRINT
        CALL PNTMEM     ;PRINT ADDR,SOURCE DEST
        XCHG
        CALL PNTMEM+3   ;NO CRLF
        XCHG
CMPB2:  DCX  B
        MOV  A,B
        ORA  C
        RZ              ;YES,RETURN
        IN   3
        ANI  2
        RNZ             ;BAIL OUT
        JMP  CMPB1
;*****************************************
;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
SEAR1:  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  SEAR1
        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 OBJECT
        POP  PSW
        POP  PSW
        POP  PSW        ;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
RDRCO:  CALL CASIN      ;TYPE CODE
RDRC1:  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 CAINCK     ;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  RDRCO      ;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 CAINIT     ;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
;**********************************************
;CAINIT READ CASETTE UNTIL 32 SYNC BYTES READ
;**********************************************
CAINIT: CALL BYTESET    ;READ FIRST SYNC
        MVI  B,31
CAIN2:  CALL CASIN
        CPI  0E6H
        MVI  A,'I'
        JNZ  ERR1
        DCR  B
        JNZ  CAIN2
        RET
;*******************************
;CASETTE OUTPUT BYTE
;*******************************
CASOUT: PUSH PSW        ;SAVE IT
        IN   3
        ANI  4
        JZ   CASOUT+1
        POP  PSW
        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
;*****************************************
;CAINCK- READ BYTE WITH CHECKSUM
;*****************************************
CAINCK: 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 PSW
        CALL ASBI       ;CONVERT TO BIBARY
        JNC  IHEX1
        POP  PSW
        RET
IHEX1:  DAD  H
        DAD  H
        DAD  H
        DAD  H          ;ADD NEW DIGIT
        ADD  L
        MOV  L,A
        POP  PSW
        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
SRCP1:  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   ESCCO
        DB   0
        END
