; "ICRT"; Rev 0; Written by Ben L Gee; Dec 9, 1979 ; Modified by Dan Fischler for use with the CP/M ; Assembler-- August 20, 1980 ; ICRT is a driver for the SSM VB3 video board. ICRT will allow ; the VB3 to replace most any intelligent crt terminal. ; ; This software has been used successfully with UCSD Pascal and ; MicroPro Wordstar. ; DEFINE SOME SYSTEM EQUATES ROM EQU 0E400H ;Beginning of ROMmable code FALSE EQU 0 TRUE EQU NOT FALSE ; DEFINE THE VB3 PARAMETERS VIDEO EQU 0C000H ;Address of video memory OFFSET EQU 01000H ;Relative offset to attribute field VTAC EQU 0D0H ;I/O address of CRT Controller KSTAT EQU 0E0H ;Keyboard Status/Board Enable Port KDATA EQU 0E1H ;Keyboard Data/Board Disable Port NCOLS EQU 80 ;Number of columns NROWS EQU 24 ;Number of rows SKEW EQU 0 SCANF EQU 525 ;Scans per frame SCANR EQU 11 ;Scans per data row HCOUNT EQU 113 ;Character times in 1 horiz scan line INTERL EQU TRUE ;Dispay is interlaced CODE EQU 5 ;80 columns NORMAL EQU 3 ;Attribute for alphanumerics REVERS EQU 4 ;Attribute for reverse video BLANK EQU 8 ;Attribute for blank video UNDRLN EQU 16 ;Attribute for underline BLINK EQU 32 ;Attribute for blinking character STRIKE EQU 64 ;Attribute for strike-thru REDUCE EQU 128 ;Attribute for reduced intensity MAXESC EQU 32 ;Max size of an escape sequence ; DEFINE SOME ASCII VALUES BS EQU 08H ;Back space HT EQU 09H ;Horizontal Tab LF EQU 0AH ;Line Feed VT EQU 0BH ;Vertical Tab CR EQU 0DH ;Cursor Return ESC EQU 1BH ;Escape Character ICH EQU 40H ;Insert Character CUU EQU 41H ;Cursor Up CUD EQU 42H ;Cursor Down CUF EQU 43H ;Cursor Forward CUB EQU 44H ;Cursor Backward CNL EQU 45H ;Cursor Next Line CPL EQU 46H ;Cursor Preceding Line CHA EQU 47H ;Cursor Horizontal Absolute CUP EQU 48H ;Cursor Position CHT EQU 49H ;Cursor Horizontal Tab ED EQU 4AH ;Erase In Display EL EQU 4BH ;Erase In Line IL EQU 4CH ;Insert Line DL EQU 4DH ;Delete Line DCH EQU 50H ;Delete Character SU EQU 53H ;Scroll Up SD EQU 54H ;Scroll Down CTC EQU 57H ;Cursor Tab Control CVT EQU 59H ;Cursor Vertical Tab CBT EQU 5AH ;Cursor Backward Tab CVA EQU 5BH ;Cursor Vertical Absolute SGR EQU 6DH ;Select Graphic Rendition ; VIDEO DRIVER SUBROUTINES ; ENTRIES POINTS ARE: ; ; VBINIT - To initialize the hardware and software ; VBIN - To get a keystroke from the keyboard ; VBOUT - To output a character to the display ; VBSTAT - To check the keyboard status ; ; CALLING SEQUENCES: ; ; CALL VBINIT ; ; CALL VBIN ; STA KEYSTROKE ;Result in Register A ; ; ; MVI C,DATA ;Output character in Register C ; MOV C,A ; CALL VBOUT ; ; CALL VBSTAT ;Returns Register A=0 if ; ;No keystroke is available, else ; ;Returns Register A=0FFH ; ORG ROM JMP VBINIT JMP VBIN JMP VBOUT JMP VBSTAT VBINIT: OUT KSTAT ;Enable the VB3 Board MVI A,NORMAL STA ATTRIB ;Set default attribute MVI A,NROWS-1 STA LSTROW ;InitializeLASTROW to NROWS-1. XRA A STA MODE ;Not in Escape mode CALL CTC5 ;Clear all horizontal tab stops CALL CTC6 ;Clear all vertical tab stops LXI H,0 CALL EEOS ;Clear the screen CALL CURON ;Put the cursor on the screen ; INITALIZE ALL OF THE CONTROL REGISTERS OUT VTAC+14 OUT VTAC+10 ;Reset the VTAC MVI A,HCOUNT-1 OUT VTAC+0 IF NOT INTERL MVI A,03CH ENDIF IF INTERL MVI A,0BCH ENDIF OUT VTAC+1 IF NOT INTERL MVI A,(SCANR-1)*8+CODE ENDIF IF INTERL MVI A,(SCANR-2)*8+CODE ENDIF OUT VTAC+2 MVI A,SKEW*64+NROWS-1 OUT VTAC+3 IF INTERL MVI A,(SCANF-513)/2 ENDIF IF NOT INTERL MVI A,(SCANF-256)/2 ENDIF OUT VTAC+4 MVI A,(SCANF-NROWS*SCANR)/4+8 OUT VTAC+5 ;Try to center the data on the screen MVI A,NROWS-1 OUT VTAC+6 OUT VTAC+14 ;Start the timing chain OUT KDATA ;Disable the VB3 board RET VBSTAT: IN KSTAT ;Check keyboard status CMA ANI 1 RZ ;Return a zero if no data MVI A,0FFH RET ;Else return a 0FFH VBIN: CALL VBSTAT ;Return the next key JZ VBIN ;Wait until one is available IN KDATA ;Get it RET ;And return ; VBOUT IS THE MAIN DISPLAY DRIVER FOR THE VB3 BOARD VBOUT: PUSH H ;First, save all registers PUSH D PUSH B OUT KSTAT ;And enable the VB3 board CALL CUROFF ;Then, turn off the cursor CALL PROCES ;And process the character CALL CURON ;Now, turn the cursor back on OUT KDATA ;Disable the VB3 board POP B ;And restore the registers POP D POP H RET ; ON ENTRY, REG HL = LOGICAL CURSOR ADDRESS AND REG C = DATA. PROCES: LDA MODE ;See if we received an ESC character ORA A JNZ PESCSE ;JIF we are in an escape sequence MOV A,C ;Move the data to register A CPI 80H ;Check for range of 80 to FF JNC PESC ;It is an ESC sequence if >7FH CPI ESC ;Check for control characters JZ DOESC ;If match, then do control character CPI CR JZ DOCR CPI LF JZ DOLF CPI HT JZ DOHT CPI BS JZ DOBS CPI VT JZ DOVT CPI ' ' RC ;Skip other control characters JMP DODAT ;Must be a data character DOESC: MVI A,1 STA MODE ;We are now reading an ESC sequence XRA A STA COUNT ;Init the CRT for the sequence STA POINT RET PESC: CALL DOESC PESCSE: LDA COUNT CPI MAXESC ;Check for buffer overflow JZ ABORT XCHG ;Save HL MOV L,A ;Index into buffer goes to HL MVI H,0 INR A STA COUNT ;Increment pointer MOV A,C ;Get data ANI 7FH ;7 bits only LXI B,ESCSEQ ;Get base of buffer DAD B ;Compute current cell MOV M,A ;Save data XCHG ;Restore HL CPI '@' ;Not a terminator if < 40H RC MOV C,A ;Save the data XRA A STA MODE ;ESC seq done, now process it MOV A,C ;Get the data again CPI ICH JZ DOICH ;JIF Insert Character CPI CUU JZ DOCUU ;JIF Cursor Up CPI CUD JZ DOCUD ;JIF Cursor Down CPI CUF JZ DOCUF ;JIF Cursor Forward CPI CUB JZ DOCUB ;JIF Cursor Back CPI CNL JZ DOCNL ;JIF Cursor Next Line CPI CPL JZ DOCPL ;JIF Cursor Preceding Line CPI CHA JZ DOCHA ;JIF Cursor Horizontal Absolute CPI CUP JZ DOCUP ;JIF Cursor Position CPI CHT JZ DOCHT ;JIF Cursor Horizontal Tab CPI ED JZ DOED ;JIF Erase in Display CPI EL JZ DOEL ;JIF Erase in Line CPI IL JZ DOIL ;JIF Insert Line CPI DL JZ DODL ;JIF Delete Line CPI DCH JZ DODCH ;JIF Delete Character CPI SU JZ DOSU ;JIF Scroll Up CPI SD JZ DOSD ;JIF Scroll Down CPI CTC JZ DOCTC ;JIF Cursor Tab Control CPI CVT JZ DOCVT ;JIF Cursor Vertical Tab CPI CBT JZ DOCBT ;JIF Cursor Backward Tab CPI CVA JZ DOCVA ;JIF Cursor Vertical Absolute CPI SGR JZ DOSGR ;JIF Select Graphic Rendition CPI 7FH JZ DODEL RET ;None of the above, so skip it DOICH: MVI A,1 ;Insert Character CALL GET1P RZ MOV B,A ICH1: PUSH B CALL INCHAR POP B DCR B JNZ ICH1 RET DOCUU: MVI A,1 ;Cursor Up CALL GET1P ;Get a parameter, 1 is default RZ ;If value is zero, then done MOV B,A CUU1: PUSH B ;Repeat till count is zero CALL UP POP B DCR B JNZ CUU1 RET DOCUD: MVI A,1 ;Cursor Down CALL GET1P RZ MOV B,A CUD1: PUSH B CALL DOWN POP B DCR B JNZ CUD1 RET DOCUF: MVI A,1 CALL GET1P RZ MOV B,A CUF1: PUSH B CALL RIGHT POP B DCR B JNZ CUF1 RET DOCUB: MVI A,1 CALL GET1P RZ MOV B,A CUB1: PUSH B CALL LEFT POP B DCR B JNZ CUB1 RET DOCNL: MVI A,1 ;Cursor Next Line CALL GET1P RZ MOV B,A CNL1: PUSH B CALL NEXTLN POP B DCR B JNZ CNL1 RET DOCPL: MVI A,1 ;Cursor Preceding Line CALL GET1P RZ MOV B,A CPL1: PUSH B CALL PREVLN POP B DCR B JNZ CPL1 RET DOCHA: MVI A,1 ;Cursor Horizontal Absolute CALL GET1P DCR A CPI NCOLS RNC MOV L,A ;Put the cursor on that column RET DOCUP: CALL DOCHA ;Cursor position (Goto XY) JMP DOCVA DOCHT: MVI A,1 ;Cursor Horizontal Tabulation CALL GET1P RZ MOV B,A CHT1: PUSH B CALL DOHT POP B DCR B JNZ CHT1 RET DOED: MVI A,0 ;Erase in Display CALL GET1P JZ EEOS PUSH H CPI 1 JNZ ED1 XCHG LXI H,0000H LXI B,NORMAL*256+' ' CALL FILLS ;Erase from start to cursor JMP ED2 ED1: CPI 2 JNZ ED2 LXI H,0 CALL EEOS ;Erase entire display ED2: POP H ;Restore cursor address RET DOEL: MVI A,0 ;Erase in Line CALL GET1P JZ EEOL ;Erase from cursor to end of line PUSH H CPI 1 JNZ EL1 XCHG MOV H,D MVI L,0 LXI B,NORMAL*256+' ' CALL FILLS ;Erase from the start of line to cursor JMP EL2 EL1: CPI 2 JNZ EL2 MVI L,0 CALL EEOL ;Erase the entire line EL2: POP H RET DOIL: MVI A,1 ;Insert Line CALL GET1P RZ MOV B,A IL1: PUSH B CALL INSELN POP B DCR B JNZ IL1 RET DODL: MVI A,1 ;Delete Line CALL GET1P RZ MOV B,A DL1: PUSH B CALL DELLN POP B DCR B JNZ DL1 RET DODCH: MVI A,1 ;Delete Character CALL GET1P RZ MOV B,A DCH1: PUSH B CALL DLCHAR POP B DCR B JNZ DCH1 RET DOSU: MVI A,1 ;Scroll Up CALL GET1P RZ MOV B,A SU1: PUSH B CALL RLUP POP B DCR B JNZ SU1 RET DOSD: MVI A,1 ;Scroll Down CALL GET1P RZ MOV B,A SD1: PUSH B CALL RLDWN POP B DCR B JNZ SD1 RET DOCTC: XRA A ;Cursor Tab Control CTCA: CALL GET1P INR A RZ MOV C,A PUSH H CALL PCTC POP H MVI A,255 JMP CTCA PCTC: DCR C JZ CTC0 DCR C JZ CTC1 DCR C JZ CTC2 DCR C JZ CTC3 DCR C JZ CTC4 DCR C JZ CTC5 DCR C JZ CTC6 RET CTC0: MVI H,0 LXI D,HTABS DAD D MVI M,255 RET CTC1: MOV L,H MVI H,0 LXI D,VTABS DAD D MVI M,255 RET CTC2: MVI H,0 LXI D,HTABS DAD D MVI M,0 RET CTC3: MOV L,H MVI H,0 LXI D,VTABS DAD D MVI M,0 RET CTC4: CTC5: LXI H,HTABS MVI B,NCOLS CTC5A: MVI M,0 INX H DCR B JNZ CTC5A RET CTC6: LXI H,VTABS MVI B,NROWS CTC6A: MVI M,0 INX H DCR B JNZ CTC6A RET DOCVT: MVI A,1 ;Cursor Vertical Tabulation CALL GET1P RZ MOV B,A CVT1: PUSH B CALL DOVT POP B DCR B JNZ CVT1 RET DOCBT: MVI A,1 ;Cursor Backward Tabulation CALL GET1P RZ MOV B,A CBT1: PUSH B CALL DOBT POP B DCR B JNZ CBT1 RET DOCVA: MVI A,1 ;Cursor Vertical Absolute CALL GET1P DCR A CPI NROWS RNC MOV H,A RET DOSGR: XRA A ;Select Graphic Rendition SGRA: CALL GET1P MOV C,A LDA ATTRIB INR C RZ CALL PSGR STA ATTRIB MVI A,255 JMP SGRA PSGR: DCR C JZ SGR0 DCR C DCR C JZ SGR2 DCR C DCR C JZ SGR4 DCR C JZ SGR5 DCR C DCR C JZ SGR7 DCR C JZ SGR8 DCR C JZ SGR9 DCR C JZ SGR10 DCR C JZ SGR11 DCR C JZ SGR12 DCR C JZ SGR13 RET SGR0: MVI A,3 RET SGR2: ORI REDUCE RET SGR4: ORI UNDRLN RET SGR5: ORI BLINK RET SGR7: ORI REVERS RET SGR8: ORI BLANK RET SGR9: ORI STRIKE RET SGR10: ORI 3 RET SGR11: ANI 0FCH ORI 2 RET SGR12: ANI 0FCH ORI 1 RET SGR13: ANI 0FCH RET DODEL: PUSH H LXI H,VIDEO LXI B,NROWS*NCOLS DODEL1: MOV M,L INX H DCX B MOV A,C ORA B DCR B JNZ DODEL1 RET GET1P: MOV D,A ;Save the default value MVI E,0 ;Zero the accumulator LXI B,ESCSEQ-1 ;Point to the escape string PUSH H ;Save the cursor address MORE: NOGOOD: LDA POINT INR A ;Compute the index for the next byte LXI H,COUNT CMP M ;See if there is any more JZ NOMORE ;JIF None STA POINT ;Update the pointer MOV L,A MVI H,0 DAD B ;Point to the next char to come out MOV A,M ;Get it CPI ';' ;Check for a seperator JZ NOMORE ;JIF number is done SUI '0' JC NOGOOD CPI 10 JNC NOGOOD ;JIF char is not from 0 to 9 MOV D,A ;Save the value MOV A,E ;Multiply the accumulated value by 10 ADD A ;*2 MOV E,A ADD A ;*4 ADD A ;*8 ADD E ;*10 Done! ADD D ;Add in new digit MOV E,A ;Return it to the accumulator MOV D,A ;Wipe out old value JMP MORE ;Go for the next digit NOMORE: MOV A,D ;Get the value ORA A ;Set flags POP H ;Restore cursor address RET ABORT: XRA A STA MODE ;Reset the escape flag RET ; PUT A DATA CHAR ON THE SCREEN AND ADVANCE THE CURSOR. PUTCHAR:PUSH H ;Save the logical cursor address CALL GETBA ;Get the physical cursor address LXI D,OFFSET MOV M,C ;Put the data there DAD D ;Compute the address of the governing attribute MOV M,B ;Put the attribute here POP H ;Get the logical cursor address back RET DODAT: LDA ATTRIB ;Get the current attribute MOV B,A ;Set it up for PUTCHAR CALL PUTCHAR CALL RIGHT ;Move the cursor right RNZ ;Done if the cursor didn't wrap around ;Else, we must move the cursor to the next line ; PUT THE CURSOR ON COLUMN 1 OF THE NEXT LINE. SCROLL THE SCREEN ; IF THE CURSOR WAS ON THE LAST LINE. NEXTLN: MVI L,0 ;Put the cursor on coumn 1 of the next line ;And do a line feed ; MOVE THE CURSOR DOWN ONE LINE. SCROLL THE SCREEN ; IF THE CURSOR WAS ON THE LAST LINE. DOLF: CALL DOWN RNZ MVI H,NROWS-1 PUSH H CALL RLUP LXI H,(NROWS-1)*256 CALL EEOL POP H RET ; MOVE THE CURSOR TO COL 1 OF THE CURRENT LINE. DOCR: MVI L,0 RET ; BACK THE CURSOR BY ONE POSITION. DOBS: CALL LEFT CZ UP PUSH H CALL GETBA MVI M,' ' POP H RET ; DO A HORIZONTAL TABULATION DOHT: MOV C,L ;Save the column number LXI D,HTABS ;Point to the horizontal tab table DOHT1: CALL RIGHT ;Move right PUSH H XRA A ;Get a zero MOV H,A DAD D ;Point to HTABS[COL] ORA M ;See if true POP H RNZ ;Done if found a tab stop MOV A,L CMP C RZ ;Done if no tab stops JMP DOHT1 ;Continue looking for tab stops ; DO A VERTICAL TABULATION DOVT: MOV C,H ;Save the row number LXI D,VTABS ;Point to the vertical tab table DOVT1: CALL DOWN ;Move down PUSH H XRA A ;Get a zero MOV L,H MOV H,A DAD D ;Point to VTABS[ROW] ORA M ;See if true POP H RNZ ;Done if found a tab stop MOV A,H CMP C RZ ;Done if not tab stops JMP DOVT1 ;Continue looking for tab stops ; DO A BACKWARD TABULATION DOBT: MOV C,L ;Save the column number LXI D,HTABS ;Point to the horizontal tab table DOBT1: CALL LEFT ;Move left PUSH H XRA A ;Get a zero MOV H,A DAD D ;Point to HTABS[COL] ORA M ;See if true POP H RNZ ;Done if found a tab stop MOV A,L CMP C RZ ;Done if no tab stops JMP DOBT1 ;Continue looking for tab stops ; MOVE THE CURSOR UP. UP: MOV A,H DCR H ORA A RNZ MVI H,NROWS-1 RET ; MOVE THE CURSOR DOWN. DOWN: INR H MVI A,NROWS CMP H RNZ MVI H,0 RET ; MOVE THE CURSOR LEFT. LEFT: MOV A,L DCR L ORA A RNZ MVI L,NCOLS-1 RET ; MOVE THE CURSOR RIGHT. RIGHT: INR L MVI A,NCOLS CMP L RNZ MVI L,0 RET ; MOVE THE CURSOR TO THE BEGINNING OF THE PREVIOUS LINE PREVLN: MVI L,0 CALL UP RNZ MVI H,0 PUSH H CALL RLDWN LXI H,0 CALL EEOL POP H RET ; ERASE FROM THE CURSOR POSITION TO THE END OF THE SCREEN. EEOS: LXI D,((NROWS-1)*256)+NCOLS-1 LXI B,NORMAL*256+' ' JMP FILLS ; ERASE FROM THE CURSOR TO THE END OF THE CURRENT LINE. EEOL: MOV D,H MVI E,NCOLS-1 LXI B,NORMAL*256+' ' JMP FILLS ; FILL THE SCREEN WITH THE DATA IN REG C, THE ATTRIB IN REG B ; FROM X,Y LOCATION HL TO DE. FILLS: PUSH H CALL GETBA ;Get address of start XCHG CALL GETBA ;Get address of finish MOV A,H ;Compare finish and start CMP D JNZ CMPD1 MOV A,L CMP D+1 CMPD1: XCHG JNC FILLS1 ;JIF area to fill does not wrap PUSH D ;Save finish address PUSH B LXI D,VIDEO + NROWS * ((NCOLS + 15) AND 0FFF0H) - 1 CALL FILLS2 ;Fill from start to end of screen POP B POP D LXI H,VIDEO ;Fill from start of screen to finish address FILLS1: CALL FILLS2 ;Fill the screen POP H RET FILLS2: PUSH B PUSH H PUSH D CALL FILL ;Fill in the data POP H POP D LXI B,OFFSET DAD B XCHG DAD B POP B MOV C,B CALL FILL ;Fill in the attributes RET FILL: MOV M,C INX H MOV A,H CMP D JNZ CMPD2 MOV A,L CMP D+1 CMPD2: JC FILL JZ FILL RET ; SCROLL THE SCREEN UP BY ONE LINE. RLUP: LDA LSTROW INR A CPI NROWS JNZ RLUP1 XRA A RLUP1: OUT VTAC+6 STA LSTROW RET ; SCROLL THE SCREEN DOWN ONE LINE RLDWN: LDA LSTROW ORA A JNZ RLDWN1 MVI A,NROWS RLDWN1: DCR A OUT VTAC+6 STA LSTROW RET ; TURN THE CURSOR ON. ; THE LOGICAL ADDRESS OF THE CURSOR MUST BE IN REG HL. CURON: SHLD CURADR MOV A,L OUT VTAC+12 LDA LSTROW INR A ADD H CPI NROWS JC CURON1 SUI NROWS CURON1: OUT VTAC+13 RET ; TURN THE CURSOR OFF. ; THE LOGICAL ADDRESS OF THE CURSOR IS RETURNED IN REG HL. CUROFF: LHLD CURADR MVI A,0FFH OUT VTAC+12 RET ; THE INTERNAL DESCRIPTION OF THE NEXT FOUR PROCEDURES ARE ; THEIR PASCAL COUNTERPARTS. THE PROCEDURES WERE FIRST WRITTEN ; IN PASCAL AND THEN TRANSLATED INTO ASSEMBLY. IN EACH CASE I ; HAVE ASSUMED THAT THE FOLLOWING DECLARATIONS HAVE BEEN MADE. ; CONST ; NCOLS = 80; (* OR WHATEVER *) ; NROWS = 24; (* OR WHATEVER *) ; ; TYPE ; COLS = 0..NCOLS-1; ; ROWS = 0..NROWS-1; ; LINE = RECORD OF ; COL : ARRAY[COLS] OF CHAR ; END; ; SCREEN = ARRAY [ROWS] OF LINE; ; ; VAR ; R : ROWS; (* THE CURRENT CURSOR ROW ADDRESS *) ; C : COLS; (* THE CURRENT CURSOR COLUMN ADDRESS *) ; ROW : SCREEN; (* THIS IS THE VB3 MEMORY MAPPED SCREEN *) ; RI : ROWS; (* A COUNTER FOR ROWS *) ; CI : COLS; (* A COUNTER FOR COLUMNS *) ; BLANK_LINE : LINE; (* ASSUMED TO BE A BLANK LINE *) ; TO REFERENCE A CHARACTER ON THE SCREEN, SAY: ; ; ROW[RI].COL[CI] ; ; FOR SOME VALUES OF RI AND CI. ; ; TO REFERENCE A ENTIRE LINE OF THE SCREEN, SAY: ; ; ROW[RI] ; ; FOR SOME VALUE OF RI. ; PROCEDURE INSELN; ; BEGIN ; FOR RI := NROWS-1 TO R+1 DO ; ROW[RI] := ROW[RI-1]; ; ROW[R] := BLANK_LINE; ; END; INSELN: PUSH H MOV C,H INR C LXI H,(NROWS-1)*256 LXI D,(NROWS-1)*256 ILLOOP: MOV A,H CMP C JC ILEXIT DCR H CALL MVLINE DCR D JMP ILLOOP ILEXIT: CALL EEOL POP H RET ; PROCEDURE DELLN; ; BEGIN ; FOR RI := R TO NROWS-2 DO ; ROW[RI] := ROW[RI+1]; ; ROW[NROWS-1] := BLANK_LINE; ; END; DELLN: PUSH H MVI L,0 MOV D,H MOV E,L DLLOOP: MVI A,NROWS-2 CMP D JC DLEXIT INR H CALL MVLINE INR D JMP DLLOOP DLEXIT: CALL EEOL POP H RET ; PROCEDURE INCHAR; ; BEGIN ; FOR CI := NCOLS-1 DOWNTO C+1 DO ; ROW[R].COL[CI] := ROW[R].COL[CI-1]; ; ROW[R].COL[C] := ' '; ; END; INCHAR: PUSH H MOV C,L INR C MVI L,NCOLS-1 MOV D,H MOV E,L ICHLOP: MOV A,L CMP C JC ICHEXT DCR L CALL MVCHAR DCR E JMP ICHLOP ICHEXT: LXI B,NORMAL*256+' ' CALL PUTCHAR POP H RET ; PROCEDURE DLCHAR; ; BEGIN ; FOR CI := C TO NCOLS-2 DO ; ROW[R].COL[CI] := ROW[R].COL[CI+1]; ; ROW[R].COL[NCOLS-1] := ' '; ; END; DLCHAR: PUSH H MOV D,H MOV E,L DCHLOP: MVI A,NCOLS-2 CMP E JC DCHTXT INR L CALL MVCHAR INR E JMP DCHLOP DCHTXT: LXI B,NORMAL*256+' ' CALL PUTCHAR POP H RET MVLINE: PUSH H PUSH D PUSH B LXI B,OFFSET CALL GETBA PUSH H DAD B XCHG CALL GETBA PUSH H DAD B XCHG LXI B,NCOLS INR B HERE1: MOV A,M STAX D INX H INX D DCR C JNZ HERE1 DCR B JNZ HERE1 POP D POP H LXI B,NCOLS INR B HERE2: MOV A,M STAX D INX H INX D DCR C JNZ HERE2 DCR B JNZ HERE2 POP B POP D POP H RET MVCHAR: PUSH H PUSH D PUSH B CALL GETBA XCHG CALL GETBA LDAX D MOV M,A LXI B,OFFSET DAD B XCHG DAD B MOV A,M STAX D POP B POP D POP H RET ; CONVERT A LOGICAL ADDRESS TO A PHYSICAL ADDRESS. ; ON ENTRY, HL CONTAINS THE LOGICAL ADDRESS. ; ON EXIT, HL CONTAINS THE PHYSICAL ADDRESS. ; A LOGICAL ADDRESS IS IN THE FORM (ROW, COLUMN) WITH ROW IN REG H AND COLUMN ; IN REG L. ROW MUST BE IN THE RANGE OF 0 TO NROWS-1 AND COLUMN MUST BE IN ; THE RANGE OF 0 TO NCOLS-1. ; A PHYSICAL ADDRESS IS THE ACTUAL MEMORY ADDRESS IN THE VIDEO MEMORY. GETBA: PUSH B LDA LSTROW INR A ADD H CPI NROWS JC GETBA1 SUI NROWS GETBA1: MOV C,A MVI B,0 MOV A,L LXI H,MAPPER DAD B DAD B MOV C,A MOV A,M INX H MOV H,M MOV L,A DAD B POP B RET ; The following section (MAPPER) saves space for a mapping ; table. ; The number of DW's should be equal to the number of lines. MAPPER: J SET (NCOLS+15) AND 0FFF0H DW VIDEO+J*0 DW VIDEO+J*1 DW VIDEO+J*2 DW VIDEO+J*3 DW VIDEO+J*4 DW VIDEO+J*5 DW VIDEO+J*6 DW VIDEO+J*7 DW VIDEO+J*8 DW VIDEO+J*9 DW VIDEO+J*10 DW VIDEO+J*11 DW VIDEO+J*12 DW VIDEO+J*13 DW VIDEO+J*14 DW VIDEO+J*15 DW VIDEO+J*16 DW VIDEO+J*17 DW VIDEO+J*18 DW VIDEO+J*19 DW VIDEO+J*20 DW VIDEO+J*21 DW VIDEO+J*22 DW VIDEO+J*23 DW VIDEO+J*24 ENDROM EQU $ ORG VIDEO+NCOLS*NROWS ATTRIB: DS 1 ;THE CURRENT SCREEN ATTRIB CURADR: DS 2 ;THE LOGICAL CURSOR ADDRESS LSTROW: DS 1 ;THE LAST ROW DISPLAYED ON THE SCREEN MODE: DS 1 ;BOOLEAN, TRUE IF RECEIVING AN ESCAPE SEQUENCE COUNT: DS 1 ;INDEX INTO ESCSEQ POINT: DS 1 ;SAME AS ABOVE EXCEPT USED FOR READING ESCSEQ: DS MAXESC ;HOLDS THE ESCAPE SEQUENCE HTABS: DS NCOLS ;USED FOR SETTING HORIZONTAL TABS VTABS: DS NROWS ;SAME FOR VERTICAL TABS ENDRAM EQU $ ORG ENDROM ;This address will appear on the console ;after the assembly END ROM