;  INTELLIGENT TERMINAL PROGRAM VERSION 16.0
; DATE: 01/18/79 
;  OPERATIONAL ON THE INTEL 8080 MICRO COMPUTER 
;  THIS VERSION COMMUNICATES WITH TERMINAL, DTV, AND 2 TIME 
;  SHARING COMPUTERS
;    TITLE ' INTELLIGENT TERMINAL PROGRAM - IMSAI VERS 16.0'
; I-O CONTROL TABLE 
;*************************** EQUATES *****************************  
WIDTH   EQU     80         ; WIDTH OF LINE  
LINES   EQU     24         ; NUMBER OF LINES
SIZE    EQU     80      ; WIDTH OF SCREEN   
SIZEM1  EQU     SIZE-1  ; WIDTH MINUS ONE   
MIO     EQU     051H           ; MODEM I/O CHANNEL  
MRSET	EQU	52H		; MODEM RESET
MINTR	EQU	53H		; MODEM INTERRUPTS
NEDITB  EQU     1               ; NUMBER OF EDIT BUFFER LINES   
NSCRL   EQU     LINES-NEDITB-1  
MSTAT   EQU     050H           ; MODEM 1 STATUS 
IPS	EQU	20H		; INTERRUPT PENDING STATUS
RDA     EQU     040H           ; DATA AVAILIABLE FLAG   
TTYBE   EQU     080H           ; UART TRANSMISSION BUFFER EMPTY FLAG
KEYS    EQU     0   
KEYI    EQU     1   
KEYR	EQU	2		; IO PORT RESET
KEYP	EQU	3		; INTERRUPT ADDRESS
KEYPD	EQU	4		; PARALLEL INPUT PORT
BLK     EQU     020H
WBLK    EQU     0A0H
TOP     EQU     0F000H         ; TOP OF TV SCREEN   
WORDS   EQU     TOP+(LINES-1)*WIDTH   ; BEGINNING OF EDIT BUFFER
WORDEN	EQU	(WORDS+SIZEM1) AND 0FFH	; END OF EDIT BUFFER
WORDLO  EQU     WORDS AND 0FFH  
SIZED   EQU     SIZE*NEDITB          ; NUMBER OF CHARS IN EDIT BUFFER   
EOFED   EQU      WORDS+SIZED-1            ; POINTER TO END OF EDIT BUFFER   
EOEDLO  EQU     EOFED AND 0FFH; LOW ORDER EOFED 
OULINE  EQU      WORDS-SIZE           ; POINTER TO OUTPUT BUFFER
CR      EQU     13             ;
LF      EQU     10             ;
        ORG     100H          ;START PROGRAM HERE   
;   
;     TERMINAL CONTROL FUNCTIONS
 ;  
        JMP     BEGIN          ;
CTAB:   DW      BREAK          ; NULL - (OR BREAK KEY)  
        DW      MONTR          ; CTL-A 1 DISPLAY/TTY 
        DW      SUPS           ; CTL-B 2 OUTPUT @@SUPS   
	DW	RTCPM		; CTL-C 3 RETURN TO CPM
        DW      CHDEL          ; CTL-D DELETE FROM TEXT 
        DW      STAT           ; CTL-E 5 OUTPUT @@STAT  
        DW      LEFT           ; CTL-F 6 MOVE CURSOR LEFT   
        DW      RIGHT          ; CTL-G 7 MOVE CURSOR RIGHT  
        DW      CHOME          ; CTL-H 8 HOME CURSOR
        DW      MOVE           ; CTL-I 9 INSERT BLANK INTO TEXT 
        DW      GETM           ; CTL-J 10 GET STORED MESSAGE - 
        DW      UP             ; CTL-K 11 SCROLL UP
        DW      DOWN           ; CTL-L 12 SCROLL DOWN  
        DW      SAVCR          ; CTL-M 13 CARRIAGE RETURN  
        DW      GSTAR           ; CTL-N 14 1108- TO- BASIC  
        DW      RUNST          ; CTL-O 15 @RUN STATEMENT
        DW      XFDISK         ; CTL-P 20 - DISK TO TSC 
        DW      TAB            ; CTL-Q 17 TABS  
        DW      REPET          ; CTL-R 18 REPRINT LINE  
        DW      FIND           ; CTL-S FIND STRING IN EDIT BUFFER   
        DW      GSTAR          ; CTL-T 16 - TSC TO DISK 
        DW      HELP           ; CTL-U 21 - HELP
        DW      GSTAR          ; CTL-V GO READ HEX  
        DW      SKIP           ; CTL-W SKIP OVER WORD   
        DW      SENDM          ; CTL-X TRANSMIT SAVED IMAGE 
        DW      ERASE          ; CTL-Y ERASE TO LINE OF LINE
        DW      SAVEM          ; CTL-Z 19 SAVE EDIT BUFFER  
        DW      REPLACE        ; ESC
        DW      FLIP           ; 28 FS  
        DW      BAUD           ; 29-GS  300-1200 BAUD TOGGLE
        DW      GSTAR          ; 30 RS -  COPY FROM COMPUTER A TO B 
        DW      CLEAR          ; 31 US -  CLEAR SRCREEN  
;   
;*************************** BEGIN *****************************
BEGIN:  LXI     SP,STACK       ; SET STACK POINTER  
        LXI     D,MASK         ; INITIALIZE RAM AREA
        LXI     H,EBUF         ; POINT TO FIFO  RAM 
	MVI	B,MASKQ-MASK+2
;   
LOOP:   LDAX    D              ;
        MOV     M,A            ;
        INX     H              ;
        INX     D              ;
	DCR	B		; END OF MASK
	JNZ	LOOP		; IF NOT LOOP
	CALL	CRLF		; DO CARRIAGE RETURN
	LDA	1		; SET DISPLAY TO SCREEN
	STA	SENFLG
	JMP	RESTAR
;
;  CLEAR TV SCREEN
CLEAR:	LXI	H,TOP		; SET POINTER TO BEGINNING
	MVI	B,LINES		; SET UP LINE COUNTER
	MVI	C,WIDTH		; SET WIDTH COUNTER
	MVI	A,BLK		; FILL WITH BLANK
CLR1:	MOV	M,A		; STUFF ONE
	INX	H		; NEXT ADDR
	DCR	C		; ONE LESS TO DO
	JNZ	CLR1		;
	MVI	C,WIDTH		; NEW LINE
	DCR	B
	JNZ	CLR1
	CALL	BLANK		; FORM EDIT BUFFER
	RET
;
RESTAR:
	MVI	A,84H		; SET IO PORT BAUD RATE
	OUT	KEYS
	LDA	BRATE		; PICK-UP CURRENT MODEM BAUD RATE
	OUT	MSTAT
	MVI	A,1
	OUT	KEYR		; RESET IO PORT
	OUT	MRSET		; RESET MODEM
	CALL	CRLF
	MVI	A,08H		; SET MODE 2 FOR DTV
        STA    TOP+7FFH        ; INITIALIZE IMSAI BOARD 
	XRA	A
	OUT	MINTR		; MASK OUT DEV B INTERRUPTS
;   
; BLANK OUT EDIT BUFFER 
NEWL:   CALL    BLANK          ; BLANK OUT EDIT LINE
        LXI     H,WORDS        ; POINT TO BEGINNING OF EDIT BUFFER  
        MVI     B,0            ; ZERO OUT CHARACTER COUNT   
NEW1:   SHLD    POINT          ;  SAVE CURSOR POINTER   
;   
;   CHECK FOR MODEM INPUT   
;   
START:  CALL    MINP           ;  0330 CHECK MODEM STATUS   
        JC      IN6            ;IF NOT GO CHECK TTY INPUT STATUS
        JZ      START          ; REJECT 'EM 
ST1:    CALL    OUTC           ;OUTPUT TO TV/TTY
        JMP     START          ;
;   
;   MODEM INPUT ROUTINE 
;   
MINP:   PUSH    H              ; SAVE HL
        LHLD    MIBUF          ; POINT TO MODEM INPUT BUFFER
        LDA     MIPT           ; TOP OF MODEM INPUT FIFO BUFFER 
        CMP     L   
        JZ      MINP2          ; JUMP, IF NO CHARACTERS 
        MOV     L,A            ;MOVE TO STARTING ADDRESS
        INR     A              ; INCREMENT FIRST CHAR POINTER   
        STA     MIPT
        MOV     A,M            ; GET THE CHARACTER BACK TO AREG 
MINP1:  POP     H   
        JMP     MINP4   
;   
;   NOTHING IN FIFO BUFFER - CHECK MODEM FOR INPUT  
;     CARRY SET ON RET = NO DATA
;   
MINP2:  POP     H   
MINP3:	XRA	A
        IN      MSTAT          ; CHECK STATUS   
        ANI     RDA 
        STC 
        RZ  
        IN      MIO 
        ANI     7FH 
MINP4:  STC     ; TURN OFF CARRY
        CMC 
        RET 
;   
CHKMOD: CALL    MINP3          ; CHECK FOR INPUT
        RC      ; RETURN, IF NOT
        PUSH    H   
        LHLD    MIBUF   
        MOV     M,A 
        INR     L   
        SHLD    MIBUF   
        POP     H   
        RET 
;   
;  ANY INPUT FROM PARALLEL KEY BOARD ?
;
IN6:	MVI	A,04H		; GET INT. MASK FOR SENS
	OUT	KEYP		; OUTPUT IT
	IN	KEYS		; GET STATUS
	STA	STATIN		; SAVE STATUS
	ANI	IPS		; ISOLATE INT. PENDING BIT
	JZ	IN61		; IF NOT, GO CHECK TTY INPUT STATUS
	IN 	KEYP		; GET INT. ADDR.
	IN	KEYPD		; GET DATA FROM PARALLEL PORT
	JMP	IN81
IN61:	LDA	STATIN		; RESTORE STATUS
	JMP	IN8		; GO CHECK TTY INPUT STATUS
;
;      ANY INPUT FROM THE KEYBOARD? 
;   
IN8:    IN      KEYS           ; 0390 INPUT FROM TTY?   
        ANI     RDA            ;
        JZ      CHKT           ;IF NOT, GO CHECK TTY OUTPUT STATUS  
        IN      KEYI           ; 0420 ACCEPT INPUT FROM TTY 
IN81:
        ANI     7FH            ;STRIP OFF PARITY BIT
        CPI     BLK            ; IS IT CTL CHARACTER?   
;   
; CHECK CONTROL COMMAND TABLE   
;   
        LXI     H,START        ; SAVE RET ADDR ON STACK 
        PUSH    H   
        JNC     NOCTL          ; IF NOT GO STORE IT 
        LXI     H,CTAB         ; ADDR OF CMD TABLE  
        ADD     A              ; MULTIPLY BY 2  
        ADD     L   
        MOV     L,A            ; AND ADD TO HL  
        MOV     A,M            ; PICK UP LOWER ADDR 
        INX     H   
        MOV     H,M            ; PICK UP HIGH ADDR  
        MOV     L,A            ;HL CONTAIN JUMP ADDRESS 
        PCHL
;   
NOCTL:  CPI     94             ;UP ARROW: DELETE LINE   
        JZ      DELET          ;
        CPI     127            ;DELETE CHARACTER (RUBOUT)   
        LHLD    POINT   
        JNZ     SAVE           ;GO SAVE CHARACTER IN EDIT BUFFER
        CALL    WOB 
        MOV     A,L            ;
        DCX     H              ;DELETE CHARACTER
        CPI     WORDLO            ; AT BEGINNING OF LINE?   
        SHLD    POINT   
        MVI     M,BLK          ;BLANK IT OUT
        JZ      DELET          ;IF ZERO, DELETE LINE
        MVI     A,95           ;OUTPUT UNDERSCORE   
        CALL    OUTD           ;GO OUTPUT CHARACTER 
        RET                    ;
;   
;   SAVE CHARACTER  
;   
SAVE:   ORI     80H            ;
        MOV     M,A            ;STORE CHARACTER IN EDIT BUFFER  
        CALL    OUTD           ;
INVRH:  INX     H              ;BUMP MEMORY POINTER 
;   
;   SET UP CURSOR   
;   
INVRC:  MOV     A,M            ;TURN ON CURSOR  
        ANI     7FH            ;
        MOV     M,A            ;
        SHLD    POINT          ;
        RET                    ;
;   
;  TEXT EDITOR COMMAND  
;  *ESC* - INSERT 'R ' IN FRONT OF IMAGE TO REPLACE CURRENT 
;        IMAGE WITH CONTENTS OF EDIT BUFFER 
;   
REPLACE:
        MVI     A,'R'   
        CALL    OUT7           ; OUTPUT 'R '
        MVI     A,' '   
        CALL    OUT7
;   
;  CTL-M 
;  COME HERE FOR CRLF   
;   
SAVCR:  CALL    LENG           ;FIND LENGTH 
        MVI     M,CR           ;
;   
;   OUTPUT TO 1108  
;   
OUTI:   LXI     H,WORDS        ;YES, OUTPUT LINE TO BIG COMPUTER
OUTX:   MOV     A,M            ;PICK UP CHARACTER   
        ANI     7FH            ;
        CALL    OUT7           ;TRANMIT IT  
        CPI     CR             ; END OF LINE?   
        INX     H              ;INCREMENT EDIT BUFFER POINTER   
        JNZ     OUTX           ;LAST CHARACTER? 
;   
;   DELETE LINE 
;   
DELET:  CALL    CRLF           ;CLEAR EDIT BUFFER   
NEW:    POP     PSW 
        JMP     NEWL           ;
;   
;  CTL-R
; REPRINT THE LINE  
;   
REPET:                         ;REPRINT LINE WHEN CTL-R IS ENTERED  
        CALL    LENG           ;GET LENGTH OF LINE  
        MOV     A,B            ;
        ORA     A              ;IS EDIT BUFFER EMPTY?   
        STA     COUNT          ;NO  
        RZ                     ;IF SO,  GO TO START 
        LXI     H,WORDS        ;ELSE, POINT TO BEGINNING OF BUFFER  
        CALL    CRLF           ;OUTPUT CARRIAGE RETURN-LINE FEED
REPA:   MOV     A,M            ;REPRINT WHOLE LINE  
        ANI     7FH            ;
        CALL    OUTC           ;
        INX     H              ;BUMP POINTER
        DCR     B              ;DECREMENT CHARACTER COUNT   
        JNZ     REPA           ;LOOP
        RET 
;   
;  OUTPUT CARRIAGE RETURN -- LINE FEED (AND NULLS)  
;   
CRLF:   MVI     C,CR           ;OUTPUT CARRIAGE RETURN LINE FEED
        JMP     OUTCR          ;
;   
;  OUTPUT TO CONSOLE
;   
OUTD:   MOV     C,A            ;MORE CRLF KLUDGE
        LDA     SENFLG         ; 1040 CHECK SENSE SWITCHES  
        ANI     1              ;IS S/W 8 ON?
        MOV     A,C            ;
        RNZ                    ;IF NOT,  RETURN OUTPUT NO CHARACTER 
;   
;    OUTPUT ONE CHARACTER   
;   
OUTC:   ANI     7FH            ;
        CPI     7FH            ;DEL?
        RZ                     ;
        MOV     C,A            ;
        CPI     BLK            ;CR? 
        JNC     NOCR           ;NO CTL BUT COULD BE CR  
        CPI     CR             ;IS IT CR?   
        RNZ                    ;NOPE, THEN IGNORE   
OUTCR:  LDA     LASTC          ;OUTPUT CARRIAGE ROUTINE 
        CMP     C              ;IF PREVIOUS CHARACTER WAS NOT CARRI 
        RZ                     ;RETURN IF LAST CHAR WAS CR  
NOCR:   
        LDA     SENFLG         ;
        ANI     1              ;SW-8 ON?
        MOV     A,C            ;
        STA     LASTC          ;SAVE IN 'LAST' CHARACTER BUFFER 
        JNZ     CHOUT   
        CZ      TOUT           ;IF S-W 8 IS OFF, THEN OUTPUT TO TTY 
        CPI     CR             ;
        RNZ                    ;IF NOT CR, RETURN   
        MVI     A,LF           ;ELSE, OUTPUT LINE-FEED AND 6 NULLS  
        CALL    TOUT1          ;
        MVI     A,0            ;NULL IS ZERO
        MVI     C,5            ;LIKE 6 TIMES
NULL:   CALL    TOUT1          ;
        DCR     C              ;
        JNZ     NULL           ;
        MVI     A,CR           ;RESTORE CR TO A-REG 
GSTAR:  RET                    ;(JUMP HERE FOR UNDEFINED CMDS)  
;   
;    BUFFER OUTPUT ROUTINE  
;   
TOUT:   MOV     A,C            ;
        STA     LASTC          ;SAVE IN 'LAST' CHARACTER BUF
TOUT1:                         ;NOW, OUTPUT TO TTY  
        XCHG
        LHLD    EBUF           ;LOAD D-REG WITH POINTER TO LAST CHA 
        MOV     M,A            ;SAVE CHARACTER IN TTY OUTPUT BUFFER 
        CALL    LIMCHK  
        SHLD    EBUF
        XCHG
        RET                    ;
;   
;  CHECK LIMITS OF OUTPUT BUFFER
;  VARIES FROM FIFO  TO 9FFFH   
;   
LIMCHK: INX     H   
        PUSH    PSW 
        MOV     A,H 
	CPI	FIFOM SHR 8	; DON'T LET IT EXCEED XFFF
        JNZ     LIM1
        LXI     H,FIFO         ; RESET 4096 BYTE CIRCULAR BUFFER
LIM1:   POP     PSW            ; RESTORE A  
        RET 
;   
;   IF TBE AND TTY BUFFER NOT EMPTY, THEN OUTPUT A CHARACTER TO TTY 
;   
CHKT:   IN      KEYS           ; 1450 IS TTY TRANSMISSION BUFFER EMPTY (
        ANI     TTYBE          ;(TBE STATUS = 00000010B)
        JZ      MOUT           ;NO, THEN GO CHECK MODEM OUTPUT STAT 
        LDA     SBUF           ;START OF TTY OUTPUT BUF 
        LHLD    EBUF           ;LOAD H-L REG WITH POINTER TO TTY OU 
        CMP     L              ;DOES LAST CHAR. POINT TO FIRST CHAR 
        JNZ     CHKT1          ;IF SO, THEN THERE IS NO CHAR TO BE  
        LDA     SBUF+1         ;
        CMP     H   
        JZ      MOUT
CHKT1:  LHLD    SBUF
        MOV     A,M            ;PICK UP CHARACTER FROM BUFFER   
        OUT     KEYI           ;OUTPUT IT TO TTY
        CALL    LIMCHK         ;INCREMENT STARTING CHARACTER BUFFER 
        SHLD    SBUF
        JMP     START          ;
;   
;  CTL-E
; OUTPUT @@STAT 
;   
STAT:   LXI     D,SMSG         ;OUTPUT CANNED MESSAGE: @@STAT   
        JMP     OUTMG          ;
;
;  SET DISPLAY FLAG
MONTR:	LDA	SENFLG		; LOAD SENSE FLAG
	ADI	1
	CPI	2
	JC	MONT1
	XRA	A
MONT1:	STA	SENFLG		; TOGGLE FLAG
	RET
;
;  RETURN TO CPM
RTCPM:	LXI	D,CPMSG
	PUSH 	B		; DUMMY PUSH
	MVI	B,1		; OUTPUT ONE LINE
	MVI	C,WIDTH		; SET WIDTH COUNTER
	LXI	H,WORDS		; OUTPUT IN EDIT BUFFER
	CALL	TVMGA
	CALL	CRLF
	LHLD	JMPCON		; JMP CONOT ADDR
	MOV	A,H
	CMP	L		; CHECK IF  ZERO
	JZ	0		; RETURN TO CP/M
	LDA	CONINF		; RESTORE JMP CONOT
	MOV	M,A
	INX	H
	LDA	CONINF+1
	MOV	M,A
	JMP	0
;   
;  CTL-O
;   OUTPUT @RUN STATEMENT   
;   
RUNST: LXI      D,RMSG         ; OUTPUT 
        JMP     OUTMG   
;   
;  CTL-B
;   OUTPUT SUPS MESSAGE 
;   
SUPS:   LXI     D,UMSG         ;OUTPUT @@SUPS   
        JMP     OUTMG          ;
OUTMG:  IN      MSTAT          ; 1670 ROUTINE TO OUTPUT MESSAGE AT ADDRE
        ANI     TTYBE          ;CHECK STATUS
        JZ      OUTMG          ;LOOP IF TRANSMISSION BUF NOT EMPTY  
        LDAX    D              ;PICK UP CHARACTER   
        CALL    JOUT           ;AND OUTPUT IT   
        ANI     7FH            ;
        CPI     CR             ;IS IT A CARRIAGE RETURN?
        INX     D              ;INCREMENT CHAR POINTER  
        RZ                     ;
        JMP     OUTMG          ;OUTPUT NEXT CHARACTER   
;   
;  SCROLL UP ONE LINE   
;   
SCRL:   MVI     B,LINES-1-NEDITB     ;SCROLL UP ONE LINE
SCRLX:  LXI     H,TOP          ;TO ADDRESS  
        LXI     D,TOP+SIZE      ;FROM ADDRESS   
        CALL    SCUP           ;SCROLL UP ONE LINE  
        CALL    ZERO           ;BLANK OUT LINE 3
        RET                    ;
;   
;  SCROLL UP
;   
SCUP:   MVI     C,WIDTH           ;SCROLL UP ONE LINE   
SCUP2:  LDAX    D              ;PICK UP CHARACTER   
        ANI     7FH            ;STRIP OFF WHITE BACKGROUND  
        MOV     M,A            ;STORE IT IN NEW LOCATION
        INX     H              ;ADJUST POINTERS 
        INX     D              ;
        DCR     C              ;DECREMENT CHARACTER COUNTER 
        JNZ     SCUP2          ;LOOP
        CALL CHKMOD            ; CHECK FOR MODEM INPUT  
        DCR     B              ;DECREMENT LINE COUNTER  
        JNZ     SCUP           ;
        RET                    ;
;   
;    SCROLL DOWN ONE LINE   
;   
SCDN:   MVI     C,WIDTH           ;SCROLL DOWN ONE LINE 
SCDN2:  LDAX    D              ;PICK UP CHARACTER   
        ANI     7FH            ;REMOVE WHITE BACKGROUND 
        MOV     M,A            ;STORE CHARACTER IN NEW LOCATION 
        DCX     H              ;DECREMENT POINTERS  
        DCX     D              ;
        DCR     C              ;AND CHARACTER COUNTER   
        JNZ     SCDN2          ;LOOP FOR ALL WIDTH CHARACTERS   
        DCR     B              ;DECREMENT LINE COUNTER  
        JNZ     SCDN           ;
        RET                    ;
;   
;   BLANK OUT ONE LINE  
;   
ZERO:   MVI     A,BLK          ;LOAD A-REG WITH BLANK CHARACTER 
        MVI     C,WIDTH           ;LINE CHARACTER COUNT 
SC3:    MOV     M,A            ;STORE BLANK 
        INX     H              ;
        DCR     C              ;
        JNZ     SC3            ;LOOP FOR ALL WIDTH CHARACTERS   
        RET                    ;
;   
;  CTL-Y
;  ERASE TO END OF LINE 
;   
ERASE:  LHLD    POINT          ; PICK UP POINTER TO CURSOR  
        INX     H   
        JMP     BLKA
;   
;   BLANK OUT LINE  
;   
BLANK:  LXI     H,WORDS        ; POINT TO BEGINNING OF EDIT BUF 
BLKA:   MVI     A,WBLK         ;WHITE BACKGROUND TYPE   
        MVI     C,SIZE*NEDITB  ;BLANK OUT LOWER TWO LINES   
        JMP     SC3            ;
;   
;  PERFORM IMMEDIATE BREAK FUNCTION 
;   
BREAK:  XRA     A   
;   
; SET PARITY EVEN AND OUTPUT TO MODEM   
;   
JOUT: ORA       A              ; SET 8080 FLAGS 
        JPE     JOUTA          ; IS PARITY EVEN?
        ORI     80H            ; IF NOT SET PARITY BIT EVEN 
JOUTA:  OUT     MIO            ; OUTPUT TO MODEM
        RET 
;   
;  OUTPUT BUFFER TO MODEM   
;   
MOUT:   IN      MSTAT          ; CHECK STATUS BIT   
        ANI     TTYBE          ;
        JZ      START          ;GO CHECK FOR INPUT FROM BIG COMPUTE 
        LDA     NBUF           ;CURRENT CHARACTER POINTER   
        LHLD    MBUF           ;LAST CHARACTER OUTPUT POINTER   
        CMP     L              ;
        JZ      START          ; RETURN IF THERE ARE NO CHARACTERS  
        MOV     L,A            ; 250  TO BE OUTPUT; ELSE OUTPUT CHARACTE
        MOV     A,M            ;
        CALL    JOUT           ;
        INR     L              ;INCREMENT CURRENT CHAR POINTR   
        MOV     A,L            ;
        STA     NBUF           ;
        JMP     START          ; 2310   
;   
;    OUTPUT TO MODEM
;   
OUT7:                          ;
        PUSH    H   
        LHLD    MBUF           ;POINTER TO LAST CHAR OUTPUT 
        ANI     7FH            ;
        MOV     M,A            ;SAVE CHARACTER IN OUTPUT BUFFER 
        INR     L              ;
        SHLD    MBUF           ;
        POP     H   
;   
CHOUT:  PUSH    H   
        MOV     C,A            ; SAVE CHARACTER 
        PUSH    B              ;
        LHLD    TVBUF          ;TV BUFFER CURRNET CHARACTER POINTER 
        ANI     7FH            ;
        CPI     CR             ;IS IT CR?   
        JZ      TVCR           ;IF SO, THEN SCROLL UP   
        CPI     95             ;ELSE CHECK FOR DELETE   
        JNZ     CH0            ;
        DCX     H              ;IF CHAR IS DELETE, MOVE POINTER BA  
        JMP     CH2            ;
CH0:    CPI     BLK            ;IS CHAR CONTROL TYPE?   
        JC      CHEND          ;IF NOT, OUTPUT CHARACTER TO TV  
        MOV     A,L            ;ELSE, RETURN IF NOT CR  
        CPI     WORDLO      ; AT BEGINNING OF LINE? 
        JNZ     CH1            ;
        PUSH    B   
        CALL    SCRL
        POP     B   
        LXI     H,OULINE     ;RESET EDIT BUFFER 
        JMP     CH1 
TVCR:    PUSH B 
        CALL    SCRL           ;SCROLL UP ONE LINE  
        POP B   
        LXI     H,OULINE     ;RESET EDIT BUFFER 
        JMP     CH2            ;
CH1:    MOV     M,C            ;NOW, FINALLY, SAVE CHAR IN  
        INX     H              ;IN BUFFER AND BUMP POINTER  
CH2:    SHLD    TVBUF          ;SAVE POINTER
CHEND:  POP     B              ;
        POP     H              ; RESTORE H AND L
        MOV     A,C            ;
        RET                    ;
;   
; RESET CURRENT CURSOR POSITION 
WOB:    LHLD    POINT          ; MODIFY CURSOR  
        MOV     A,M            ;ERASE CURSOR
        ORI     80H            ;
        MOV     M,A            ;
        RET 
;   
;  CTL-G
; MOVE CURSOR RIGHT 
;   
RIGHT:  CALL    WOB            ;MOVE CURSOR RIGHT   
        JMP     INVRH          ;V7 GO INX H AND TURN ON CURSOR  
;   
;  CTL-F
;  MOVE EDIT BUFFER LEFT
;   
LEFT:   CALL    WOB            ;MOVE LEFT ONE POSITION  
        DCX     H   
        MOV     A,L            ; AT BEGINNING OF LINE?  
        CPI     WORDLO  
        JC      HOME           ; RESET TO BEGINNING OF BUF  
        JMP     INVRC          ;
;   
;  CTL-H
;   MOVE CURSOR TO BEGINNING OF EDIT BUFFER 
;   
CHOME:  CALL    WOB 
HOME:   LXI     H,WORDS        ;HOME CURSOR 
        JMP     INVRC          ;
;   
; ROUTINE TO FIND END OF STRING 
;   
LENG:   MVI     B,SIZE*NEDITB  ;START AT END OF EDIT BUFFER 
        LXI     H,EOFED        ; END OF EDIT BUFFER 
LENGA:  MOV     A,M            ;
        CPI     WBLK           ;IS IT BLANK?
        JZ      LENGC          ;
        CPI     BLK            ;
        JNZ     LENGB          ;
LENGC:  DCX     H              ;LOOK AT NEXT CHARACTER  
        DCR     B              ;
        JNZ     LENGA          ;
LENGB:  INX     H              ;END OF IMAGE HAS BEEN FOUND 
        MVI     M,BLK          ;SET CURSOR  
        RET                    ;
;   
;  CTL-I  INSERT INTO TEXT  
;   
MOVE:   CALL    WOB 
        MVI     A,EOEDLO-1 ; END OF EDIT LINE         ; 
        MVI     D,BLK          ;
MOVEL:  MOV     C,M            ;PICK UP  CHARACTER  
        MOV     M,D            ;STORE PREVIOUS CHARACTER
        MOV     D,C            ;
        INX     H              ;POINT TO NEXT CHARACTER 
        CMP     L              ;END OF EDIT BUFFER? 
        RZ                     ;
        JMP     MOVEL          ;IF NOT, THEN CONTINUE   
;   
;   DELETE IN  TEXT CTL-D   
;   
CHDEL:  LHLD    POINT   
        MOV     A,L            ;
        MVI     D,WBLK         ;
        MVI     L,EOEDLO-1         ;
CHDHL:  MOV     C,M            ;PICK UP CHARACTER   
        MOV     M,D            ;STORE LAST CHARACTER
        MOV     D,C            ;
        CMP     L              ;LAST CHARACTER IN EDIT BUFFER?  
        DCX     H              ;NO, THEN LOOP   
        JNZ     CHDHL          ;
        INX     H              ;YES, THEN SET CURSOR AND RETURN 
        JMP     INVRC          ;
;   
;  CTL-K  MOVE CURSOR UP
;   
UP:     MVI     B,1            ;
        LXI     D,TOP          ;MOVE TOP LINE TO TEMP BUFFER
        LXI     H,XBUF         ;
        CALL    SCUP           ;
        MVI     B,LINES-NEDITB  ;NOW, SCROLL 14 LINES UP ONE
        CALL    SCRLX          ;
        LXI     D,XBUF         ;MOVE TEMP LINE TO EDIT BUFFER   
        LXI     H,WORDS        ;
        MVI     B,1            ;
        CALL    SCUP           ;
ENDSC:  MVI     C,WIDTH           ; 
        LXI     H,WORDS        ;
INVRT:  MOV     A,M            ;TURN ON WHITE BACKGROUND
        ORI     80H            ;
        MOV     M,A            ;
        INX     H              ;
        DCR     C              ;
        JNZ     INVRT          ;LOOP FOR ALL CHARACTERS IN LINE 
        CALL    LENG           ;GO COMPUTE IMAGE LENGTH 
        JMP     NEW1          ; 
;   
;  CTL-L  MOVE CURSOR DOWN  
;   
DOWN:   MVI     B,1            ;
        LXI     D,WORDS+SIZEM1     ;3   
        LXI     H,XBUF+SIZEM1      ;
        CALL    SCDN           ;MOVE EDIT BUFFER TO TEMPORARY BUFFE 
        LXI     D,WORDS-1      ;
        LXI     H,WORDS+SIZEM1     ;3   
        MVI     B,LINES-NEDITB  ;NOW, SCROLL 14 LINES   
        CALL    SCDN           ;NOW, SCROLL DOWN 14 LINES   
        LXI     D,XBUF+SIZEM1      ;
        LXI     H,TOP+SIZEM1       ;
        MVI     B,1            ;
        CALL    SCDN           ;NOW MOVE TEMPORARY BUFFER TO TOP LI 
        JMP     ENDSC          ;
;   
;  CTL-V
;   READ HEX INPUT INTO MEMORY  
;   
;   
; LOAD INTEL HEX OBJECT FROM TSC TO MEMORY  
;   
READ:   
        LXI     H,0            ;SET BIAS ADDRESS TO ZERO
        PUSH    H   
READ0:  POP     H   
        PUSH    H   
        CALL    MOINP          ; INPUT CHARACTER FROM TSC   
        MVI     B,':'          ; IS IT A COLON? 
        SUB     B   
        JNZ     READ0          ;SEARCH FOR COLON
        MOV     D,A            ;ZERO OUT CHECKSUM   
        CALL    BYTE
        JZ      RED2           ;ZERO RECORD LENGTH, ALL DONE
        MOV     E,A            ;E (- RECORD LENGTH  
        CALL    BYTE           ;GET MSB OF LOAD ADDRESS 
        PUSH    PSW            ;SAVE IT 
        CALL    BYTE           ;GET LSB OF LOAD ADDRESS 
        POP     B              ;RETRIEVE MSB, PUT IN B  
        MOV     C,A 
        DAD     B              ;BIAS ADDRESS + LOAD ADDRESS -) HL   
        CALL    BYTE           ;RECORD TYPE 
RED1:   
        CALL    BYTE           ;READ DATA   
        MOV     M,A            ;PUT IN MEMORY   
        INX     H   
        DCR     E   
        JNZ     RED1           ;LOOP UNTIL DONE 
        CALL    BYTE           ;READ CHECKSUM   
        JNZ     CHKERR         ;CHECKSUM ERROR  
        JMP     READ0          ;GET ANOTHER RECORD  
RED2:   
        CALL    BYTE           ;GET MSB OF TRANSFER ADDRESS 
        MOV     H,A 
        CALL    BYTE
        MOV     L,A 
        ORA     H   
        JZ      RED3           ;IF TRANSFER ADDRESS = 0, RETURN TO KB   
        PCHL
RED3:   
        POP     H   
        JMP     READ4   
;   
BYTE:   
        CALL    MOINP          ;READ CHAR FROM TAPE 
        CALL    DIGIT         ;CONVERT ASCII TO HEX 
        RLC 
        RLC 
        RLC 
        RLC                    ;SHIFT FOUR PLACES   
        MOV     C,A 
        CALL    MOINP   
        CALL    DIGIT         ;GET LOWER NIBBLE 
        ORA     C   
        MOV     C,A 
        ADD     D              ;UPDATE CHECKSUM 
        MOV     D,A 
        MOV     A,C 
        RET                    ;RETURN  
;   
; CONVERT ASCII CHARACTER TO HEX DIGIT  
;   
DIGIT:  
        SUI     '0' 
        RC                     ; FILTER OUT 0-2FH   
        ADI     0E9H 
        RC                     ; FILTER OUT 47H-0FFH
        ADI     6   
        JP      NI0            ; TAKE BRANCH FOR A-F
        ADI     7   
        RC                     ; FILTER OUT 3AH-40H 
NI0:
        ADI     10  
        ORA     A              ; ZERO OUT ERROR FLAG
        RET                    ; RETURN 
;   
;  OUTPUT FINISHED MESSAGE  
;   
READ4:  LXI     D,FINMSG
        JMP     READ5   
;   
; OUTPUT ERROR MESSAGE  
;   
CHKERR: LXI     D,CKMSG 
READ5:  CALL    TVMSG   
        LXI     SP,STACK
        JMP     NEWL
;   
;       MODEM TO INPUT ROUTINE  
;   
MOINP:  
        IN      MSTAT          ;
        ANI     1              ;
        JZ      KEYIN          ;  GO CHECK KEYBOARD 
        IN      MIO            ;
        ANI     7FH            ; STRIP OFF PARITY   
        RET 
;   
KEYIN:                         ;  CHECK FOR KEYIN   
        IN      KEYS
        ANI     1              ;
        JZ      MOINP          ;  NO INPUT -- GO CHECK MODEM
        IN      KEYI           ;
        ANI     7FH            ;  STRIP OFF PARITY  
        CPI     1              ;  CHECK FOR CTL-A   
        JNZ     MOINP   
        JMP     BEGIN   
;   
;  CTL-S
;    FIND VALUE ON SCREEN   
;   
FIND:   CALL    LENG           ; GET IMAGE LENGTH   
        LXI     H,TOP          ;
        SHLD    XBUF           ; XBUF CONTAINS ADDRESS OF TV SCREEN 
FINDA:  MOV     C,B            ; SAVE CHARACTER COUNT   
        LXI     D,WORDS        ; POINT D-REG TO START OF EDIT BUF   
FINDB:  LDAX    D              ; COMPARE EB STRING CHARACTER
        ANI     7FH            ;
        CMP     M              ; WITH CHARACTER ON SCREEN   
        JNZ     FINDC          ; IF NOT FOUND, LOOK AT NEXT TV BUF C
        INX     H              ; ELSE, COMPARE NEXT TWO CHARACTERS  
        INX     D              ;
        DCR     C              ; IF LAST CHAR IN  EB, THEN SEARCH SU
        JZ      FOUND          ; AND JUMP TO FOUND  
        JMP     FINDB          ; ELSE, COMPARE NEXT TWO CHARACTERS  
FINDC:  LHLD    XBUF           ; CONTINUE SEARCH
        INX     H              ;
        SHLD    XBUF           ;
        MOV     A,H            ;
        CPI     WORDS SHR 8         ;   
        JC      FINDA          ;
        MOV     A,L            ;
        CPI     WORDLO        ; AT BEGINNING OF THE LINE?   
        JC      FINDA          ;
        JMP     NEW            ;
FOUND:  XCHG                   ; SEARCH SUCCESSFUL.  MOVE LINE  
        LXI     H,TOP         ; POINT HL TO TOP OF CRT  
        LXI     B,WIDTH      ; BC WILL CONTAIN LINE WIDTH   
FOUN1:  DAD     B             ; POINT TO NEXT LINE  
        MOV     A,H           ; DOES HL POINT PAST LOCATED TEXT?
        CMP     D   
        JC      FOUN1         ; IF NOT, CONTINUE LOOP   
        MOV    A,L            ; NOW CHECK LOWER ORDER ADDRESS   
        CMP    E
        JC      FOUN1         ; IF NOT , LOOP   
        LXI     B,-WIDTH      ; MOVE TO BEGINNING OF LINE   
        DAD     H   
        XCHG                   ;
FOUN2:  LXI     H,WORDS        ;
        MVI     B,1            ;
        CALL    SCUP           ;
        JMP     ENDSC          ;
;   
;  CTL-J
; GET STORED MESSAGE
;   
;   
GETM:   LXI     D,TBUF          ; POINT DE TO STORED LINE   
        JMP     FOUN2   
;  SEND TBUF MESSAGE TO MODEM   
;  CTL-X
;   
SENDM:  LXI     D,TBUF         ;
        JMP     OUTMG          ;
;   
;  CTL-Z  SAVE EDIT BUFFER  
SAVEM:  LXI     H,TBUF         ;
        LXI     D,WORDS        ;
        MVI     B,1            ;
        CALL    SCUP           ;
        MVI     M,CR           ;
        JMP     LENG           ;
;   
;  CTL-W = SKIP TO NEXT WORD
;   
SKIP:   LHLD    POINT   
SKIPA:  MOV     A,M            ;
        ORI     80H            ;
        MOV     M,A            ;
        INX     H              ;
;  TOP OF CRT
	PUSH 	H
	PUSH	D
	LXI	D,0-WORDS
	DAD	D		; CARRY AFFECTED
	POP	D
	POP	H
        JNC     HOME           ;
        MOV     A,M            ;
        CPI     BLK            ;
        JZ      INVRC          ;
        CPI     WBLK           ;
        JNZ     SKIPA          ;
        JMP     INVRC          ;
;   
; DO TAB THING (CTL-Q)  
;   
TAB:    CALL    WOB            ; LOAD CURSOR POINTER
	MOV	A,L		; NEXT COL MOD 8
	ADI	08H		; OVER 8
	ANI	0F8H		; AND BACK TO LAST MOD 8
	CPI	WORDEN		; END OF EDIT BUFFER
	JC	TABA
	MVI	A,WORDEN+1		; MAX LENGTH
TABA:	MOV	L,A		; SET CURSOR POINTER
	JMP	INVRC		; TURN-ON CURSOR
;   
;   FS - CHANGE OUTPUT PORT FLIP-FLOP   
;   
FLIP:   LXI     D,MODA         ; PORT A 
        LDA     MFLIP          ; LOAD MODEM FLAG
        CMA                    ; INVERT A-REG   
        STA     MFLIP          ; SAVE IT
        ORA     A              ; SET 8080 FLAGS 
        MVI     A,MSTAT        ; SET FOR MODEM A
        JZ      SETPORT        ;TURN ON OUTPUT TO MODEM A   
        DCR     A   
        DCR     A              ; SET TO OUTPUT TO MODEM B   
        LXI     D,MODB         ; POINT TO PORT B MESSAGE
;   
; SET PORT FOR COMPUTER A OR B COMMUNICATION
;  A-REG POINTS TO PORT; DE POINT  TO TV MSG ADDRESS
;   
SETPORT:STA     JOUT+1         ; SET STATUS PORT
        INR     A              ; POINT TO DATA PORT 
        STA     JOUTA+1        ; SET DATA OUTPUT PORT   
        JMP     TVMSG   
;   
;    GS - FLIP BAUD RATE TO EITHER 1200 OR 300 BAUD 
;   
BAUD:   LDA     BRATE          ; PICK UP CURRENT SIO CTL WORD   
        CPI     08H            ; IS IT 1200 BAUD 8-DATA BITS; 2-STOP BIT
        JZ      BAUD1          ; YES, CHANGE TO 12  
        MVI     A,08H   
        LXI     D,M1200        ; 1200-BAUD MSG  
        JMP     BAUD2          ;
BAUD1:  MVI     A,84H          ; MAKE 300-BAUD; ETC 
        LXI     D,M300         ; 300-BAUD MSG   
BAUD2:  STA     BRATE   
	OUT	MSTAT		; SET BAUD RATE
        CALL    TVMSG          ; OUTPUT MSG TO TV   
        JMP     RESTAR  
;   
;  CTL-U GIVE USER HELP 
;   
HELP:   LXI     D,HMSG         ; OUTPUT TO TV USER MSG  
TVMSG:  LXI     H,TOP          ; POINT TO TOP OF TV BUFFER  
TVMGA:  LDAX    D              ; PICK UP CHAR TO BE OUTPUT  
        CPI     '$'            ; ENDING?
        RZ                     ; FINISHED WHEN $ ENCOUNTERED
        MOV     M,A            ; OUTPUT IT  
        INX     H   
        INX     D   
        JMP     TVMGA   
;   
; CTL-P  OUTPUT CP/M DISK TO 1108   
;   
;  SET CP/M OUTPUT ADDR
XFDISK: CALL    SIOAD           ; PICK UP OUTPUT ADDRESS
        LXI     D,PMSG        ; SEND @@PTI  
        CALL    OUTMG         ; TO MODEM
        JMP     0            ; GO TO CP/M DISK OPERATING SYS 
;
;  SET CP/M OUTPUT ADDR
SIOAD:	LHLD	1		; ADDR OF WBOOTE:  JMP WBOOT
	LXI	D,10		; OFFSET TO JMP CONOT
	DAD	D
	SHLD	JMPCON		; SAVE JMP CONOT ADDR
	XCHG			; DE ADDR OF LO BYTE
	LXI	H,DTOU
	LDAX	D
	STA	CONINF
	MOV	A,L
	STAX	D
	INX	D
	LDAX	D
	STA	CONINF+1
	MOV	A,H
	STAX	D
	RET
;   
DTOU:   IN      MSTAT         ; CHECK MODEM STATUS  
        ANI     TTYBE         ; UART BUF EMPTY BIT  
        JZ      DTOU          ; LOOP IF NOT EMPTY   
        MOV     A,C 
        OUT     MIO           ; AND OUTPUT CHARACTER
        PUSH    D   
        CALL    CHOUT   
        POP     D   
        RET 
;   
;     STORAGE ALLOCATION
;   
MASK:   DW       FIFO          ;
	DW	FIFO
	DB	0		; COUNT
	DB	0		; MFLIP
	DB	0		; LASTC
	DB	08H		; BRATE
        DB     0              ; NBUF
        DW      WORDS          ; POINTER TO BEGINNING OF EDIT BUFFER
        DW      WORDS-WIDTH       ;TVBUF LOCATION   FOR OUTPUT  
MASKQ:	DW	MOBU1
;   
RMSG:    DB    '@RUN  CHINA,      ,38130,50,500,,125-1' 
        DB    CR
UMSG:   DB '@@SUPS' 
        DB    CR
SMSG:   DB '@@STAT' 
        DB    CR
PMSG:   DB '@@PTI'  
        DB  CR  
CPMSG:	DB	' ** RETURN TO CP/M ** $'
M300:   DB    '****** BAUD RATE 300 ********$'  
M1200:   DB    '****** BAUD RATE 1200 ********$'
FINMSG: DB     '***** HEX OBJECT IS LOADED ****$'   
CKMSG:  DB     '***** CHECK SUM ERROR *****$'   
MODA:   DB    '** OUTPUT TO PORT 51 **$' 
MODB:   DB    '** OUTPUT TO PORT 71 **$' 
HMSG:	DB	'*** TERMINAL CONTROL FUNCTIONS CTL-(?) ***          '
	DB	'                              '
	DB	'(A) DISPLAY/TTY TOGGLE     (B) SEND @@SUPS          '
	DB	'(C) RETURN TO CP/M          '
	DB	'(D) DELETE IN TEXT         (E) SEND @@STAT          '
	DB	'                            '
	DB	'(F) CURSOR LEFT            (G) CURSOR RIGHT         '
	DB	'(H) CURSOR HOME             '
	DB	'(I) INSERT IN TEXT         (J) GET STORED MESSAGE   '
	DB	'                            '
	DB	'(K) SCROLL UP              (L) SCROLL DOWN          '
	DB	'                            '
	DB	'(P) DISK TO TSC            (Q) TAB                  '
	DB	'(R) REPRINT                 '
	DB	'(U) HELP                   (W) WORD SKIP OVER       '
	DB	'(X) SEND BUF                '
	DB	'(Y) ERASE TO EOL           (Z) STORE IN BUF         '
	DB	'(GS) 300/1200 BAUD TOGGLE   '
	DB	'(US) CLEAR SCREEN $                                 '
  ******** FROM THIS POINT TO END MUST BE IN RAM ********
MIBUF:  DW      MIBU1          ; MODEM INPUT BUFFER 
MIPT:   DB      0              ; TOP OF INPUT FIFO BUFFER   
;  COPIED FROM MASK
EBUF:   DW    FIFO  
SBUF:   DW    FIFO  
COUNT:  DB    0 
MFLIP:  DB    0                ; MODEM OUTPUT FLAG  
LASTC:  DB    0                ; ST CHARACTER OUTPUT
BRATE:  DB    08H              ; 1200-300 BAUD TOGGLE   
NBUF:   DB    0                ; POINTER TO BEGINNING OF FIFO FO
POINT:  DW    WORDS            ; CURSOR POINTER 
TVBUF:  DW    WORDS-WIDTH        ; LINE 14  
MBUF:   DW    MOBU1            ; MODEM OUTPUT BUFFER ADDRESS
;  END OF COPY
SENFLG:	DB	0		; DISPLAY FLAG
STATIN:	DB	0		; KEYBOARD STATUS
XBUF:   DS    WIDTH               ; TEMPORARY LINE BUFFER   
TBUF:   DS    WIDTH               ; BUFFER FOR SAVING EDIT BUFFER CONTENTS (CTL-
JMPCON	DW	0		; ADDR OF JMP CONOT
CONINF	DW	0		; CONTENT OF JMP CONOT
	DS	128		; PROGRAM STACK AREA
STACK:	DS	2
;  ********BUFFERS ********
PREND:	DS	1		; MUST BE AT PROGRAM END
FIFO	EQU	(PREND+0FFFH) AND 0F000H  ; X000H TO XFFFH
FIFOM	EQU	FIFO+1000H
MIBU1	EQU	FIFOM		; MODEM INPUT BUFFER  XX00-XXFF
MOBU1	EQU	MIBU1+100H	; MODEM OUTPUT BUFFER  XX00-XXFF
        END