; ;IMSAI VIDEO DISPLAY DRIVER & SMP-80 MONITOR FOR VIO-C ;AS DIS-ASSEMBLED BY BARRY WATZMAN 7/17/78 ; ORG 0F000H VIDBF DS 1920 ;SCREEN BUFFERR LF780 DS 1 ;CURSOR ROW (0-23) LF781 DS 1 ;CURSOR COLUMN (0-79) LF782 DS 1 ;INVERSE VIDEO FLAG LF783 DS 1 ;INVERTED COPY OF STATUS MODE BYTES LF784 DS 1 ;INSERT MODE TOGGLE LF785 DS 1 ;ESCAPE FLAG LF786 DS 1 ;STORAGE FOR 2ND CHAR OF ESC SEQ LF787 DS 2 ;ADDR OF ALT CTL CHAR TABLE LF789 DS 2 ;ADDR OF ALT ESC CHAR TABLE LF78B DS 2 ;ADDR OF ALT MONITOR CMD TABLE LF78D DS 2 ;ADDR OF RAM FOR I/O CMDS LF78F DS 2 ;ABSOLUTE CURSOR ADDRESS LF791 DS 1 ;0FFH HERE ==> BIT 80H=PROTECT LF792 DS 1 ;STORE CHAR UNDER CURSOR LF793 DS 1 ;STORE CHAR TO BE DISPLAYED LF794 DS 1 ;COPY OF STATUS W/EXTRA BITS LF795 DS 10 ;TAB STORAGE (BIT MAPPED) LF79F DS 2 ;STORE MAX ALLOWED COL LF7A1 DS 1 ;STORE MAX ALLOWED ROW LF7A2 DS 2 ;NO OF CHARS IN CUR SCRN FORMAT LF7A4 DS 1 ;PROT FLD ENCOUNTERED FLAG FOR TAB FNCT DS 1 LF7A6 DS 2 ;ABS. ADDR OF END OF SCREEN STACK DS 87 ;RESERVED FOR MONITOR STACK STATS DS 1 ;HARDWARE COMMAND BYTE ; ;PROGRAM ENTRY POINTS ; START: JMP INITL ;INITIALIZATION ENTRY JMP CHROT ;CHARACTER DISPLAY ENTRY JMP MONTR ;MONITOR ENTRY POINT LXI SP,STATS-1 ;SELF TEST PROGRAM ENTRY CALL INITL ;INITIALIZE VIO BOARD LF80F: CALL GTCHR ;GET CHAR FM KEYBD & PUT ON SCRN JMP LF80F ;DO IT FOREVER ; ;INITIALIZATION ROUTINE ; INITL: PUSH H ;SAVE REGISTERS PUSH D ; PUSH B ; PUSH PSW ; LXI H,VIDBF+1920 ;POINT TO START OF VAR. STORAGE MVI B,1FH ;LENGTH OF STORAGE AREA XRA A ;GET A ZERO LF81F: MOV M,A ;CLEAR STORAGE INX H ;POINT TO NEXT DCR B ;DECR. COUNT JNZ LF81F ;MORE IF NOT DONE LXI H,VIDBF ;GET 1ST CHAR ADDRESS SHLD LF78F ;SAVE ABSOLUTE CURSOR ADDR LXI H,1920 ;NO OF CHARS IN 80 X 24 SCRN SHLD LF7A2 ;SAVE NO CHRS IN CURRENT FORMAT CALL CLEAR ;CLEAR SCREEN MVI A,8 ;ASCII TEXT MODE, POS VID, 80X24 LXI D,LF8DF ;RETURN ADDR FOR ALL COMMANDS PUSH D ;PUT IT ON STACK TOP LF83A: STA LF794 ;SOFTWARE'S STATUS BYTE STA STATS ;HARDWARE'S STATUS BYTE CMA ;REVERSE BITS ANI 03H ;MASK SCRN SIZE BITS RRC ;CARRY = CHRS/LINE BIT INVERTED LXI H,40 ;ASSUME 40 CHRS/LINE JNC LF84B ;SKIP NEXT STEP IF REALLY 40 DAD H ;ELSE H,L = 80 LF84B: SHLD LF79F ;SAVE MAX PERMITTED COL. LXI H,LF7A1 ;POINT TO MAX. PERMITTED LINE # MVI M,11 ;ASSUME 12 LINES/PAGE RAR ;CARRY = INVERTED LINES/PG BIT JNC LF859 ;SKIP NEXT INST. IF REALLY 12 MVI M,23 ;ELSE STORE MAX FOR 24 LINES/PG LF859: LXI H,480 ;ASSUME 12 X 40 SCRN JNC LF860 ;IF ONLY 12 LINES, SKIP NXT INST DAD H ;ELSE AT LEAST 960 CHARS/SCRN LF860: ORA A ;SET FLAGS JZ LF865 ;SKIP NEXT INST IF ONLY 40 COLS DAD H ;ELSE 80 COLS, DOUBLE SCRN SIZE LF865: SHLD LF7A2 ;SAVE AS CHARS/SCRN LXI D,VIDBF ;LOAD D,E WITH START OF SCRN DAD D ;ADD NO CHRS/SCRN SHLD LF7A6 ;TO GET ABS. SCRN ADDRESS LDA LF794 ;GET CURRENT EXTENDED MODE ANI 0CH ;MASK MODE BITS XRI 0CH ;INVERT THEM STA LF783 ;AND SAVE ; ;COME HERE AFTER PROCESSING AN ESCAPE SEQ. ; LF879: XRA A ;GET A ZERO STA LF785 ;CLEAR ESCAPE OUTSTANDING FLAG RET ;DONE ; ;CHARACTER OUTPUT ENTRY POINT ; CHROT: PUSH H ;SAVE ALL REGISTERS PUSH D ; PUSH B ; PUSH PSW ; STA LF793 ;SAVE CHAR TO DISPLAY LHLD LF78F ;GET ABS. CURSOR ADDR LDA LF792 ;GET CHAR UNDER CURSOR MOV M,A ;PUT IT BACK LXI H,LF793 ;POINT AT CURRENT CHAR MOV A,M ;GET IT BACK CPI 1BH ;ESCAPE ? JZ LF94D ;YES - PROCESS ESCAPE LDA LF785 ;NO - PREV ESC OUTSTANDING ? ORA A ;SET FLAGS JNZ LF94D ;YES - PROCESS ESCAPE MOV A,M ;GET CHAR AGAIN CPI 7FH ;DELETE ? JZ LF93C ;YES - PROCESS LDA LF783 ;GET INVERTED STATUS ORA A ;ZERO - E.G. USING ALL 256 CHARS JZ LF8D6 ;YES - HANDLE SEPARATELY MOV A,M ;GET CHAR AGAIN CPI 0FFH ;PAD CHARACTER ? JZ LF8DF ;SKIP PROCESSING ANI 7FH ;MASK PARITY MOV M,A ;SAVE IT THAT WAY SBI 20H ;SEE IF CNTL CHAR JM LF929 ;WE DON'T DISPLAY CNTL CHARS LDA LF794 ;GET EXTENDED STATUS BYTE MOV B,A ;SAVE IN B ANI 0CH ;MASK TWO MODE BITS CPI 8 ;USING STD CHAR SET (0-7F) JNZ LF8D6 ;DISPLAY CHAR IF NOT MOV A,B ;ELSE GET STATUS BACK ANI 20H ;MASK UPPPER CASE ONLY BIT JNZ LF8D6 ;DISPLAY IF USING LOWER CASE MOV A,M ;ELSE GET CHAR AGAIN SBI 61H ;SEE IF UPPER CASE JM LF8D6 ;YES, PROCESS SBI 26 ;NO, CONVERT TO UPPER CASE JP LF8D6 ;DISPLAY UPPER CASE LETTERS ADI 5BH ;CONVERT 7B-7F CNTL CHRS BACK MOV M,A ;AND LEAVE THEM ALONE IN MEMORY ; ;GET HERE TO DISPLAY CHARS ; LF8D6: CALL LFB63 ;PUT CHARACTER ON SCREEN CALL RIGHT ;MOVE CURSOR RIGHT 1 POSITION LF8DC: CALL LFB0C ;CALC ABS CUR ADDR FROM ROW, COL LF8DF: CALL LFA95 ;TURN CURSOR BACK ON POP PSW ;RESTORE REGISTERS POP B ; POP D ; POP H ; RET ;AND GO HOME ; ;ROUTINE TO MOVE CURSOR RIGHT ; RIGHT: CALL LFB26 ;ADV. COL. NO. CZ LF8F9 ;UPDATE ROW ON OVERFLOW LDA LF791 ;GET PROTECT ON/OFF FLAG XCHG ;NEW CUR ADDR TO H,L ANA M ;SEE IF THIS CHAR PROT. JM RIGHT ;CUR CAN'T STOP ON PROT. FIELD RET ;DONE, CUR ON UPPROT. FIELD ; ;ROUTINE TO DO LINE-FEED (CURSOR DOWN) ; LINFD: LXI H,LF780 ;POINT TO CURRENT ROW LF8F9: INR M ;INCREMENT IT LDA LF7A1 ;GET MAX ALLOWED ROW CMP M ;OVERFLOW ? RP ;NO-DONE DCR M ;OVERFLOW - DCR ROW LDA LF794 ;GET EXTENDED STATUS BYTE ANI 8CH ;MASK MODE & SCROLL/PG BITS JM LF90D ;JUMP IF IN PAGE MODE CPI 0CH ;SEE IF IN GRAPHICS OPT. JNZ LF912 ;SCROLL UNLESS IN GRAPHICS LF90D: XRA A ;GET A ZERO MOV M,A ;MAKE IT THE NEW ROW INX H ;POINT TO COLUMN MOV M,A ;GET IT RET ;RETURN W/COLUMN IN ACC ; ;COME HERE TO SCROLL SCREEN UP 1 LINE ; LF912: LHLD LF79F ;GET MAX ALLOWED COLUMN PUSH H ;SAVE IT XCHG ;AND MOVE TO D,E LHLD LF7A2 ;GET NO. CHRS IN CUR FORMAT MOV A,L ;LOW ORDER BYTE TO A SUB E ;SUBTRACT CHARS/LINE MOV C,A ;PUT NO. CHRS - 1 LINE IN B,C MOV B,H ; XCHG ;H,L = CHARS/SCREEN LXI D,VIDBF ;GET ADDR OF VIDEO BUFFER DAD D ;H,L = ADDRESS OF SCREEN END CALL LFDDD ;BLOCK MOV BC CHRS FROM HL TO DE JMP LFA31 ;CLEAR LAST LINE AND RETURN ; ;PROCESS CONTROL CHARS -- H,L=POINTER TO CURRENT CHARACTER ; LF929: XCHG ;CHAR POINTER TO D,E LHLD LF787 ;GET ADDR OF ALT. TABLE MOV A,H ;GET HIGH BYTE ORA A ;SET FLAGS LDAX D ;GET CHAR IN ACCUM. JZ LF939 ;SKIP NEXT IF USING STD. TABLE CALL LFA11 ;ELSE DO SEARCH OF ALT. TABLE JNZ LF945 ;AND DISPATCH IF MATCH FOUND LF939: LDA LF793 ;GET CURRENT CHARACTER LF93C: LXI H,LFB92 ;POINT TO STD. TABLE CALL LFA11 ;SEARCH IT JZ LF8DF ;IF NO MATCH FOUND LF945: LXI D,LF8DC ;GET RET POINT FOR CNTL CHR ROUTINES PUSH D ;AND PUT IT ON STACK TOP LXI D,LF781 ;LET D,E POINT TO CURSOR COLUMN PCHL ;AND DISPATCH TO ROUTINE ; ;COME HERE TO PROCESS ESCAPE SEQUENCE, BOTH ON ;ESC. ITSELF & SUBSEQUENT CHARS. H,L POINTS A LF793. ; LF94D: LXI D,LF8DC ;GET RETURN ADDR FOR WHEN DONE PUSH D ;PUSH IT ON STACK XCHG ;SAVE CURRENT CHAR ADDR IN D,E LXI H,LF785 ;POINT TO ESCAPE FLAG MOV A,M ;GET IT INR M ;INCREMENT IT IN MEMORY ONLY ORA A ;SET FLAGS RZ ;NO ESC WAS OUTSTANDING, NOW IS DCR A ;ESC WAS OUTSTANDING, DCR OLD FLAG INX H ;POINT TO 2ND CHAR OF ESC. SEQ LDAX D ;GET CHAR UNDER CURSOR JNZ LF960 ;SKIP NXT IF ON 3RD OR 4TH CHAR (DCA) MOV M,A ;ALL OTHERS, SAVE 2ND ESC. SEQ CHAR LF960: LHLD LF789 ;POINT TO ALT. ESC. TABLE MOV A,H ;GET HIGH ADDRESS BYTE ORA A ;SET FLAGS LDAX D ;GET ESC. SEQ 2ND CHAR JZ LF96F ;USE STD. TABLE CALL LFA11 ;ELSE SEARCH ALT. TABLE JNZ LF97D ;EXEC. ROUTINE IF MATCH FOUND LF96F: LDA LF786 ;ELSE RESTORE 2ND CHAR OF ESC. SEQ ANI 0DFH ;MASK OUT 20H BIT LXI H,ESCTB ;POINT TO ESCAPE TABLE CALL LFA11 ;SEARCH IT JZ LF879 ;NO MATCH FOUND, CLR ESC. FLAG LF97D: LDA LF794 ;GET EXTENDED STATUS BYTE LXI D,LF83A ;RET ADDR TO UPDATE STATUS BYTES PCHL ;EXECUTE ESCAPE SUBROUTINE ; ;ROUTINES TO MOVE CURSOR UP/LEFT ONE POSITION ; UP: DCX D ;POINT AT ROW INSTEAD OF COL LEFT: LDAX D ;GET COLUMN (ROW) ORA A ;SET FLAGS RZ ;CAN'T BE LESS THAN ZERO, DONE DCR A ;ELSE DECREMENT LF989: STAX D ;AND PUT BACK RET ;THEN RETURN ; ;ROUTINE TO DO A CARRIAGE RETURN ; CRET: XRA A ;GET A ZERO STA LF784 ;CLEAR INSERT MODE JMP LF989 ;STORE ZERO AS COLUMN & RET. ; ;ROUTINES TO TOGGLE THE PROTECT AND INSERT MODES ; PROT: LXI H,LF791 ;POINT AT PROTECT ON/OFF FLAG JMP LF99B ;COMPLEMENT IT & RETURN INTOG: LXI H,LF784 ;POINT AT INSERT MODE FLAG LF99B: MOV A,M ;GET IT CMA ;COMPLEMENT IT MOV M,A ;PUT IT BACK RET ;DONE ; ;ROUTINE TO CLEAR SCREEN ; CLEAR: LHLD LF7A2 ;GET NO CHRS ON SCREEN XCHG ;TO D,E LXI H,VIDBF ;POINT TO START OF BUFFER LF9A6: LDA LF791 ;GET PROTECT FLAG ANI 80H ;MASK HIGH ORDER BIT ANA M ;AND WITH CHAR JM LF9B1 ;DON'T CLEAR PROTECTED MVI M,' ' ;ELSE REPLACE WITH SPACE LF9B1: INX H ;INCREMENT POINTER DCX D ;DECR. COUNT OF CHARS TO CLEAR MOV A,D ;SEE IF COUNT IS 0 ORA E ; JNZ LF9A6 ;NO - DO MORE,ELSE HOME CURSOR ; ;ROUTINE TO HOME CURSOR ; HOME: LXI H,0 ;MAKE H,L ZERO SHLD LF780 ;SAVE 0 AS BOTH ROW & COL RET ;DONE ; ;ROUTINE TO ERASE TO END OF LINE OR FIELD ; EREOF: CALL LF9EE ;GET COUNT OF CHRS TO CLEAR IN C LF9C2: LDA LF791 ;GET PROTECT FLAG ORA A ;ZERO ? JZ LF9CE ;YES - CLEAR TO END OF LINE MOV A,M ;NO - GET CHAR ORA A ;SET FLAGS JM LF9D1 ;DON'T CLEAR IF PROTECTED LF9CE: MVI A,' ' ;ELSE GET SPACE MOV M,A ;AND REPLACE CHAR WITH IT LF9D1: INX H ;INCREMENT POINTER DCR C ;DECR. COUNT JNZ LF9C2 ;CONTINUE IF NOT DONE RET ;ELSE RETURN ; ;CONTROL-V (TOGGLE INVERSE VIDEO) ROUTINE ; LF9D7: LXI H,LF782 ;POINT TO INVERSE VIDEO FLAG JMP LF99B ;TOGGLE IT & RETURN ; ;ROUTINE TO DELETE A CHAR & CLOSE UP LINE ; CHDEL: CALL LF9EE ;SPACES TO END OF FIELD IN C LHLD LF78F ;GET CURRENT CURSOR ADDR MOV D,H ;DUPLICATE IN D,E MOV E,L ; INX H ;POINT TO NEXT CHAR CALL LFDDD ;MOVE LINE UP MVI A,' ' ;GET SPACE DCX D ;POINT TO LAST POS. IN FIELD STAX D ;PUT SPACE THERE RET ;DONE ; ;ROUTINE TO COMPUTE NO. OF SPACES TO END OF LINE OR ;START OF NEXT PROTECTED FIELD & LEAVE ANS. IN REG. C ; LF9EE: LDA LF791 ;GET PROTECT STATUS ANI 80H ;MASK 80H BIT MOV D,A ;SAVE IN D LHLD LF78F ;GET CURSOR ADDRESS PUSH H ;SAVE ON STACK LDA LF781 ;GET CURRENT COLUMN MOV E,A ;SAVE IN E. LXI B,0 ;MAKE B,C ZERO LF9FF: LDA LF79F ;GET MAX ALLOWED COLUMN SUB E ;SUBTRACT CUR COLUMN INR E ;INR CUR COLUMN INX H ;INR CURSOR ADDR INR C ;INR COUNT OF SPACES TO CLR DCR A ;DCR COUNT SPACES LEFT THIS LINE JZ LFA0F ;DONE IF WENT TO END OF LINE MOV A,M ;ELSE GET CHAR AT CUR POSITION ANA D ;SEE IF PROTECTED JP LF9FF ;CONTINUE IF NOT PROTECTED LFA0F: POP H ;RESTORE CUR CURSOR ADDR TO H,L RET ;DONE ; ;COMMAND TABLE SEARCH ROUTINE FOR SINGLE CHAR COMMANDS ; LFA11: MOV B,A ;SAVE COMMAND TO LOOK UP IN B LFA12: MOV A,M ;GET TABLE ENTRY LXI D,LF780 ;LET D POINT TO ROW,COL ORA A ;SET FLAGS RZ ;END OF TABLE, RETN W/ZERO SET CMP B ;ELSE CHECK FOR MATCH JNZ LFA23 ;AND INR. PAST ADDR. IF NO MATCH INX H ;MATCH - POINT AT ADDR MOV E,M ;GET LOW ADDR IN E INX H ;POINT TO HIGH MOV D,M ;GET IT IN D XCHG ;XCHG - ADDR TO H,L ORA A ;SET FLAGS NON-ZERO RET ;AND RETURN LFA23: INX H ;POINT TO LOW ADDR INX H ;POINT TO HIGH ADDR INX H ;POINT TO NEXT TABLE ENTRY JMP LFA12 ;AND TEST IT ; ;ROUTINE TO DELETE A LINE ; DELIN: CALL LFA4D ;PUT CUR AT COL. 0 OF CUR LINE PUSH H ;NO. OF COLS. PER LINE DAD D ;H,L POINTS TO 1ST CHAR NEXT LINE CALL LFDDD ;BLK MOVE BC CHARS FROM HL TO DE LFA31: POP B ;RESTORE LINE SIZE TO B,C XCHG JMP LFA45 ;FILL WITH SPACES INLIN: CALL LFA4D ;B,C = NO CHRS AFTER CURSOR - 1 LINE PUSH H ;MAX COL SIZE DAD D ;ADD LINE LEN TO CURSOR DAD B ;ADD IN NO CHARS AFTR CUR - 1 LINE = END SCRN XCHG ;TO D,E (END OF SCREEN) DAD B ;H,L=CUR, B,C=NO CHR AFTER - 1 LINE DCX H ;DCR BY 1 FOR EA CHAR DCX D CALL LFB87 ;BLOCK MOVE POP B ;MAX COL SIZE INX H ;POINT TO 1ST CHAR OF "NEW" LINE LFA45: MVI M,20H ;BLANK OUT CHAR INX H ;INR POINTER DCR C ;DCR COUNT JNZ LFA45 ;DO TILL DONE RET ; LFA4D: XRA A ;GET A ZERO STAX D ;NEW COLUMN CALL LFA5D ;BC=NO CHARRS AFTER CURSOR, DE=-CUR, HL=CUR XCHG ;DE = CUR LHLD LF79F ;MAX ALLOWED COL. MOV A,L ;TO A LFA57: DCX B ;DCR B, NO CHRS DCR A ;CONTINUE TILL B,C REDUCED BY 1 LINE JNZ LFA57 RET ; LFA5D: CALL LFB0C ;UPDATE ABS CURR ADDR PUSH H ;SAVE ON STACK XCHG ;AND IN D,E LHLD LF7A6 ;GET END OF SCRN ADDR MOV A,D ;NEGATE CURSOR CMA MOV D,A MOV A,E CMA MOV E,A INX D DAD D ;HL = NO CHARS AFTER CURSOR PUSH H ;SAVE ON STACK POP B ;RESTORE BC (NO CHARS AFTER CUR) POP H ;CURSOR IN HL RET ; ;EXTENDED TEXT MODE (UPPER CHAR SET) ; EXTXT: ANI 0F3H ;CLEAR MODE BITS ORI 04H ;SET TO EXTENDED TEXT XCHG PCHL ; ;GRAPHICS MODE (ALL 256 BYTES AVAIL) ; GRAPH: ORI 0CH ;SET GRAPHICS BITS XCHG PCHL ; ;ASCII TEXT MODE (LOWER CHAR SET) ; TXT: ANI 0F3H ;CLEAR MODE BITS ORI 08H ;SET TO TEXT MODE XCHG PCHL ; ;TOGGLE SCROLL/PAGE MODE ; SCTOG: XRI 80H ;INVERT SCROLL BIT XCHG PCHL ; ;TOGGLE UPPER CASE ONLY/UPPER-LOWER CASE MODE ; ULTOG: XRI 20H ;INVERT U/L CASE TOGGLE XCHG PCHL ; ;TOGGLE INVERSE VIDEO BIT ; INVRT: XRI 10H ;INVERT POLARITY BIT XCHG PCHL ; ;TOGGLE PAGE LENGTH BETWEEN 12/24 LINES ; PGLEN: XRI 02H XCHG PCHL ; ;TOGGLE WIDTH BETWEEN 40/80 CHARS ; WIDTH: XRI 01H XCHG PCHL ; LFA95: LHLD LF78F ;GET CURSOR ADDRESS MOV A,M ;GET CHAR STA LF792 ;SAVE IT ORI 80H ;TURN CURSOR ON MOV M,A ;PUT IT BACK LDA LF783 ;GET STATUS BYTE ORA A ;SET FLAGS RNZ MVI M,7FH ;IN GRAPHICS MODE, DEL IS CURSOR RET ; ;CLEAR ALL TABS ; CATAB: LXI H,LF795 ;POINT TO 80 BIT TAB TABLE MVI B,0AH ;10 BYTES OF 8 TAB STOPS EA. XRA A ;GET ZERO LFAAD: MOV M,A ;CLEAR 8 TABS INX H ;POINT TO NEXT BLOCK OF 8 TABS DCR B ;DCR COUNT JNZ LFAAD ;CONTINUE TILL DONE JMP LF879 ;THEN CLR ESC FLAG & GO HOME ; ;SET OR CLEAR TAB STOPS ; SCTAB: CALL LFAC4 ;GET TAB BYTE, BIT NO. & BYTE COUNT XRI 80H ;CHANGE 80H BIT LFABB: RRC DCR B ;DCR COUNT OF BIT OFFSET JNZ LFABB ;KEEP ROTATING IF NOT DONE STAX D ;PUT BYTE BACK JMP LF879 ;CLEAR ESC. FLAG & GO HOME ; LFAC4: LDA LF781 ;GET CURRENT COLUMN TO H MOV H,A ;TO H INR H ;INITIALIZATION FOR FOLLOWING ROUTINE LXI D,LF795 ;POINT TO TAB TABLE LFACC: MVI C,8 ;NO TAB STOPS PER BYTE IN TABLE LFACE: DCR H ;POINT TO PREV. COLUMN JZ LFADA ;JUMP IF COL. EQ. ZERO DCR C ;ELSE DCR. BIT COUNT JNZ LFACE ;AND REPEAT IF NOT ZERO INX D ;BIT COUNT = 0, GET NEXT BYTE JMP LFACC ;GO UNTIL COL. EQ. ZERO LFADA: LDAX D ;GET TAB TABLE BYTE MOV B,C ;SAVE BIT COUNT LFADC: RLC DCR C ;DCR BIT COUNT JNZ LFADC ;DO UNTIL BIT COUNT EQ. ZERO RET ; ;TAB TO NEXT TAB STOP OR UNPROTECTED FIELD ; TAB: XRA A ;GET A ZERO STA LF7A4 ;CLEAR PROT. FIELD ENCOUNTERED FLAG LFAE6: CALL LFB26 ;ADVANCE 1 POSITION JNZ LFAF1 ;JUMP IF NOT ON LAST COL. OF LINE INR M ;ELSE INR. ROW CMP M ;ROW = MAX. ALLOWED ROW ? JM LF90D ;YES, OFF SCREEN, DO HOME LFAF1: LDA LF791 ;GET PROTECT FIELD ON-OFF FLAG XCHG ANA M ;SET SIGN FLAG MOV A,M ;GET CHAR UNDER CURSOR LXI D,LF7A4 ;POINT TO PROTECTED FIELD ENCOUNTERED FLAG JP LFB01 ;IF CURRENT POSITION NOT PROTECTED STAX D ;ELSE SET PROT. FIELD ENCOUNTERED FLAG JMP LFAE6 ;AND TRY NEXT COL. LFB01: LDAX D ;SEE IF PROT FIELD PREV. ENCOUNTERED ORA A RM ;YES, NOW ON 1ST UNPROT AFTER PROTECTED FIELD CALL LFAC4 ;SEE IF TAB STOP AT CUR. POSITION ORA A ;SET FLAGS RM ;DONE IF TAB STOP SET JMP LFAE6 ;TAB STOP NOT SET & STILL IN UNPROT FIELD ; ;UPDATE ABSOLUTE CURSOR ADDR ; LFB0C: LHLD LF79F ;MAX. ALLOWED COLUMN XCHG LHLD LF780 ;CUR ROW, COLUMN MOV C,H ;DUPE IN B,C MOV B,L LXI H,VIDBF ;POINT TO DISPLAY BUFFER INR B ;INITIALIZE LOOP LFB19: DCR B ;FOR EA. ROW AFTER FIRST JZ LFB21 DAD D ;ADD NO. OF COLS/ROW TO SCREEN JMP LFB19 ;UNTIL DONE LFB21: DAD B ;THEN ADD CURRENT COL. NO SHLD LF78F ;AND SAVE RESULT = NEW CURSOR ADDR RET ; ;BUMP CURSOR POSITION BY 1 ; LFB26: LHLD LF78F ;GET CUR ADDR INX H ;INCREMENT IT SHLD LF78F ;PUT IT BACK XCHG LXI H,LF781 ;POINT TO CUR. COL. NO INR M ;INCREMENT IT LDA LF79F ;GET MAX ALLOWED COL. SUB M ;COMPARE TO NEW COLUMN RNZ MOV M,A ;GONE OFF LINE, MAKE COL=0 DCX H ;POINT TO CURRENT ROW LDA LF7A1 ;GET MAX ALLOWED ROW IN A RET ; ;DIRECT CURSOR ADDRESSING ; LFB3D: LXI H,LF785 ;ESCAPE SEQ. FLAG LXI D,LF780 ;CURSOR ROW LDA LF793 ;CUR. CHAR SUI 20H MOV B,A ;SAVE CURRENT CHAR MOV A,M ;GET ESC. FLAG SUI 3 ;3RD CHAR OF ESC. SEQ ? RM ;NO, 1ST OR 2ND JNZ LFB59 ;IF 4TH CHAR OF ESC SEQ LDA LF7A1 ;MAX ALLOWED ROW LFB53: STAX D ;SAVE AS CURRENT ROW CMP B ;SEE IF SAME AS STRED CHAR RM ;DONE IF STORED CHAR > MAX. ROW MOV A,B ;ELSE GET STORED CHAR STAX D ;MAKE IT CUR ROW RET ;DONE ; LFB59: MVI M,0 ;CLEAR ESC FLAG LDA LF79F ;GET MAX ALLOWED COL INX D ;POINT TO CUR COL DCR A ;DCR MAX ALLOWED COL JMP LFB53 ;UPDATE COL ; ;PUT CHAR ON SCREEN ; LFB63: LHLD LF78F ;GET CUR ADDR PUSH H ;SAVE ON STACK LDA LF784 ;GET INSERT MODE SWITCH ORA A ;SET FLAGS JZ LFB7A ;IF NOT USING INSERT CALL LF9EE ;COMPUTE SPACES TO END OF FIELD DCX B ;DCR BY 1 DAD B ;ADD TO H,L = END ADDR MOV D,H ;DUPE H,L IN D,E MOV E,L DCX D ;DCR D,E BY 1 XCHG CALL LFB87 ;MOVE RIGHT LFB7A: POP H ;RESTOR CURSOR ADDR LDA LF782 ;GET CURSOR ON-OFF FLAG ANI 80H ;MASK REV. VIDEO BIT MOV B,A ;SAVE IN B LDA LF793 ;GET CHAR ORA B ;TURN CURSOR ON (MAYBE) MOV M,A ;STORE CHAR RET ; ;BLOCK MOVE B,C CHARS FROM H,L TO D,E ; LFB87: MOV A,C ORA B RZ MOV A,M STAX D DCX H DCX D DCX B JMP LFB87 ; ;CONTROL CODE TABLE FOR VIDEO DISPLAY ; LFB92: DB 0DH DW CRET DB 0AH DW LINFD DB 0BH DW UP DB 0CH DW RIGHT DB 08H DW LEFT DB 1EH DW HOME DB 1AH DW CLEAR DB 15H DW EREOF DB 16H DW LF9D7 DB 09H DW TAB DB 7FH DW CHDEL DB 14H DW INTOG DB 04H DW DELIN DB 05H DW INLIN DB 10H DW PROT DB 0 ; ;ESCAPE SEQUENCE TABLE FOR VIDEO DISPLAY ; ESCTB: DB 1DH DW LFB3D DB 'I' DW SCTAB DB 09H DW CATAB DB 'T' DW TXT DB 'E' DW EXTXT DB 'G' DW GRAPH DB 'S' DW SCTOG DB 'U' DW ULTOG DB 'V' DW INVRT DB 'L' DW PGLEN DB 'C' DW WIDTH DB 0 MONTR: LXI SP,STATS MVI A,0AAH ;INITIALIZATION FOR 8251 IN SIO CARD OUT 3 CMA OUT 3 CMA OUT 3 MVI A,27H OUT 3 CALL INITL ;INITIALIZE VIO LXI H,LFC29 ;SIGNON MESSAGE CALL LFFB6 ;PRINT IT LFBFC: LXI SP,STATS CALL CRLF ;DO CR/LF MVI A,'?' ;PROMPT CALL CHROT CALL GTCHR ;WAIT FOR INPUT MOV B,A ;SAVE CHAR IN B LXI D,LFBFC ;PUSH RETURN ADDR ON STACK PUSH D LHLD LF78B ;ADDR OF ALTERNATE COMMAND TABLE MOV A,H ORA A ;SEE IF IN USE MOV A,B ;RESTORE INPUT CHAR TO A JZ LFC1E ;USE STD. TABLE CALL LFA11 ;USE ALT. TABLE JNZ LFC28 ;EXECUTE CMD IF MATCH FOUND LFC1E: MOV A,B ;ELSE RESTORE CHAR LXI H,LFFC0 ;AND NOW TRY STD. TABLE CALL LFA11 RZ ;NO MATCH MVI B,1 LFC28: PCHL ;GO TO ROUTINE ; ;SIGN-ON MESSAGE & COPYRIGHT NOTICE ; LFC29: DB 'IMSAI SMP/80.0' DB 0 DB 'COPYRIGHT 6/77' ; ;JUMP COMMAND - JUMPS TO MEMORY ADDRESS ; JUMP: POP D ;REMOVE RET. ADDR FROM STACK CALLM: CALL LFF5B ;GET ADDR TO JMP TO IN H,L PCHL ;GO TO IT ENTR: CALL LFF5B ;GET ADDR IN H,L LFC4E: CALL CRLF ;START ON NEW LINE CALL LFCB6 ;OUTPUT ADDR IN H,L TO SCREEN MOV A,M ;GET CHAR MOV E,A ;SAVE IN A CALL LFCAD ;DUMP IT FOLLOWED BY A SPACE XCHG CALL LFF5E ;GET HEX VALUE IN H,L XCHG MOV M,E ;STORE NEW VALUE IN MEMORY DCX H ;POINT TO PREV. LOCATION CPI 0AH ;CR/LF TYPED ? RZ ;YES, DONE CPI '-' ;'-' TYPED ? JZ LFC4E ;YES, DO PREV. LOCATION INX H ;POINT TO ORIG. LOCATION INX H ;POINT TO NEXT LOCATION JMP LFC4E ;DO IT DUMP: CALL LFD20 ;GET STARTING ADDR IN H,L LFC70: LDA LF794 ;GET STATUS BYTE RRC ;SHIFT NO LINES/SCREEN INTO CARRY RRC MVI D,0CH ;ASSUME 12 JC LFC7C ;WAS INDEED 12 MVI D,18H ;WAS 24 LFC7C: CALL CRLF ;DO CR/LF IN 3 ;TERMINATE ON ANY CHAR ANI 02H RNZ MVI E,8 ;ASSUME 8 BYTES/LINE LDA LF794 ;GET STATUS RRC ;SHIFT WIDTH INTO CARRY JC LFC8F ;JUMP IF 40 COL. SCREEN MVI E,16 ;80 COLS, USE 16 BYTES/LINE LFC8F: CALL LFCB6 ;WRITE ADDR FOLLOWED BY SPACE LFC92: MOV A,M ;GET BYTE CALL LFCAD ;DUMP BYTE FOLLOWED BY SPACE INX H ;INR POINTER DCX B ;DCR COUNT MOV A,B ;TEST FOR DONE ORA C RZ ;DONE DCR E ;DCR BYTES THIS LINE JNZ LFC92 ;MORE IF NOT DONE DCR D ;DCR LINES THIS PAGE JNZ LFC7C ;MORE LINES IF NOT DONE CALL GTCHR ;ELSE PAUSE FOR ANY CHAR JMP LFC70 ;THEN DO NEXT PAGE ESCAP: CALL GTCHR RET LFCAD: CALL LFF9A ;MOVE H TO A MVI A,' ' CALL CHROT RET LFCB6: MOV A,H ;MOV H TO A CALL LFF9A ;OUTPUT AS HEX ASCII MOV A,L ;MOVE L TO A CALL LFCAD ;OUTPUT AS HEX ASCII RET PROTM: INR B UNPRT: CALL LFF3A MOV A,D ANI 0FCH ORA B MOV D,A MOV A,H ANI 0FCH ORA B LFCCC: OUT 0FEH CMP D RZ ADI 4 JMP LFCCC HEXLD: CALL GTCHR SBI ':' JNZ HEXLD MOV D,A CALL LFD04 ORA A RZ MOV B,A CALL LFD04 MOV H,A CALL LFD04 MOV L,A CALL LFD04 LFCEF: CALL LFD04 MOV M,A INX H DCR B JNZ LFCEF CALL LFD04 JZ HEXLD MVI A,'C' CALL CHROT RET LFD04: CALL GTCHR CALL LFF74 JC LFE07 ADD A ADD A ADD A ADD A MOV E,A CALL GTCHR CALL LFF74 JC LFE07 ADD E MOV E,A ADD D MOV D,A RET LFD20: CALL LFF3A PUSH PSW MOV A,E SUB L MOV C,A MOV A,D SBB H MOV B,A INX B POP PSW RET MOVEM: CALL LFDD7 LFD30: CALL LFDDD RET FILL: CALL LFDD7 MOV A,E MOV M,A DCX B MOV D,H MOV E,L INX D JMP LFD30 MEMCK: CALL LFD20 DCX B LFD44: XRA A MOV D,M LFD46: MOV M,A CMP M JNZ LFD5D DCR A JNZ LFD46 MOV M,D IN 3 ANI 02H RNZ INX H DCX B MOV A,B ORA C JNZ LFD44 RET LFD5D: INX H MOV E,A CALL LFF8D MOV A,E JMP LFF89 INPUT: DCR B OUTPT: CALL LFF3A MOV A,B RLC RLC RLC XRI 08H ORI 0D3H MOV D,L LHLD LF78D MOV M,A CMP M RNZ PUSH H INX H MOV M,D INX H MVI M,0C9H LXI H,LFD87 XTHL MOV A,B ORA A MOV A,E PCHL LFD87: RNZ CALL LFCAD RET LFD8C: CALL LFF5B SHLD LF78D RET MEMCP: CALL LFDD7 LFD96: LDAX D CMP M INX H INX D JZ LFDA5 CALL LFF8D XCHG CALL LFF90 XCHG LFDA5: DCX B MOV A,B ORA C RZ IN 3 ANI 02H RNZ JMP LFD96 SERCH: CALL LFDD7 PUSH H LXI H,0FFFFH CPI 0AH CNZ LFF5B XTHL LFDBE: MOV A,M XTHL ANA H CMP D XTHL INX H JNZ LFDCF MOV A,M XTHL ANA L CMP E XTHL CZ LFF85 LFDCF: DCX B MOV A,B ORA C JNZ LFDBE POP B RET LFDD7: CALL LFD20 JMP LFF4A LFDDD: MOV A,B ORA C RZ MOV A,M STAX D DCX B INX H INX D JMP LFDDD GOXEQ: DCR B LDTAP: PUSH B CALL LFF3A MOV A,D ORA E JZ LFE04 PUSH H PUSH D CALL LFF5B PUSH H CALL LFE66 JNZ LFE12 POP PSW POP PSW POP PSW JMP LFE12 LFE04: CALL LFE66 LFE07: MVI A,'T' JZ LFE12 LFE0C: CALL CHROT JMP LFBFC LFE12: POP B POP H POP D PUSH B PUSH H PUSH D MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A DAD H MOV C,H INR C LFE21: CALL LFEC2 CPI 81H JNZ LFE07 CALL LFEC2 MOV B,A LXI H,0 LFE30: CALL LFED0 STAX D INX D DCR B JNZ LFE30 PUSH D XCHG CALL LFF07 MOV H,L MOV L,A DAD D MOV A,H ORA L MVI A,'C' CNZ CHROT JNZ LFE50 MVI A,'*' CALL CHROT LFE50: POP D DCR C JNZ LFE21 CALL CRLF MVI C,3 LFE5A: POP H CALL LFCB6 DCR C JNZ LFE5A POP PSW RAR RC PCHL LFE66: CALL LFE8E CALL LFEC2 CPI 1 RNZ CALL LFEC2 MVI C,5 LFE74: CALL LFEC2 CALL CHROT DCR C JNZ LFE74 MVI C,3 LFE80: CALL LFF07 XTHL PUSH H DCR C JNZ LFE80 CALL LFF07 XRA A RET LFE8E: CALL LFEF6 MVI B,1FH LFE93: CALL LFEC2 CPI 0E6H MVI A,'I' JNZ LFE0C DCR B JNZ LFE93 RET LFEA2: PUSH PSW LFEA3: IN 3 ANI 04H JZ LFEA3 POP PSW OUT 0 RET GNSYN: CALL LFF5B MVI A,10H OUT 3 LFEB5: MVI A,0E6H CALL LFEA2 IN 3 ANI 02H RNZ JMP LFEB5 LFEC2: IN 3 RRC RRC JC LFBFC RRC JNC LFEC2 IN 0 RET LFED0: CALL LFEC2 PUSH B MOV C,A MVI B,0 DAD B POP B RET ALIGN: CALL GTCHR CALL LFEF6 LFEE0: LXI H,VIDBF LXI D,01E1H LFEE6: DCX D MOV A,D ORA E JZ LFEE0 MVI M,7FH CALL LFEC2 MOV M,A INX H JMP LFEE6 LFEF6: MVI A,60H OUT 3 LFEFA: CALL LFEC2 CPI 0E6H JNZ LFEFA MVI A,' ' OUT 3 RET LFF07: CALL LFEC2 MOV L,A CALL LFEC2 MOV H,A RET GTCHR: CALL KEYIN CPI 3 JZ MONTR CALL CHROT CPI 0DH CZ CRLF RET KEYIN: IN 3 ANI 02H JZ KEYIN IN 2 ANI 7FH RET NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP LFF3A: CALL LFF5B MOV D,H MOV E,L CPI 0AH RZ CPI ',' JZ LFF4A CPI ' ' RNZ LFF4A: XCHG CALL LFF5B XCHG RET ; ;CARRIAGE RETURN/LINFEED ROUTINE ; CRLF: MVI A,0DH CALL CHROT MVI A,0AH CALL CHROT RET LFF5B: LXI H,0 LFF5E: CALL GTCHR PUSH PSW CALL LFF74 JNC LFF6A POP PSW RET LFF6A: DAD H DAD H DAD H DAD H ADD L MOV L,A POP PSW JMP LFF5E LFF74: SUI 30H RC CPI 0AH JC LFF83 SUI 11H RC ADI 0AH CPI 10H LFF83: CMC RET LFF85: CALL LFF8D MOV A,M LFF89: CALL LFF9A RET LFF8D: CALL CRLF LFF90: DCX H CALL LFCB6 MOV A,M CALL LFCAD INX H RET LFF9A: PUSH PSW RRC RRC RRC RRC CALL LFFA7 POP PSW CALL LFFA7 RET LFFA7: ANI 0FH ADI 90H DAA ACI 40H DAA CALL CHROT RET CALL CRLF LFFB6: MOV A,M ORA A RZ CALL CHROT INX H JMP LFFB6 LFFC0: DB 'H' DW HEXLD DB 'R' DW LFD8C DB 'G' DW GNSYN DB 'A' DW ALIGN DB 'V' DW MEMCP DB 'I' DW INPUT DB 'O' DW OUTPT DB 'T' DW MEMCK DB 'J' DW JUMP DB 'C' DW CALLM DB 'D' DW DUMP DB 'E' DW ENTR DB 'M' DW MOVEM DB 'F' DW FILL DB 'U' DW UNPRT DB 'P' DW PROTM DB 'L' DW LDTAP DB 'S' DW SERCH DB 'X' DW GOXEQ DB 1BH ;1BH = ESCAPE DW ESCAP DB 0 DB 'VI0'