; "ICRT"; Rev 0; Written by Ben L Gee; Dec 9, 1979 ; Modified by Dan Fischler for use with a Z80 ; 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. ; All mnemonics are in Z80 assembly language ; 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 REVERSE 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 IF INTERL VFILL EQU SCANF-513 ENDIF IF NOT INTERL VFILL EQU SCANF-256 ENDIF VMARG EQU (SCANF-NROWS*SCANR)/4+8 ; 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 JP VBINIT JP VBIN JP VBOUT JP VBSTAT VBINIT: OUT KSTAT,A ;Enable the VB3 Board LD A,NORMAL LD (ATTRIB),A ;Set default attribute LD A,NROWS-1 LD (LSTROW),A ;Initialize LASTROW to NROWS-1. XOR A LD (MODE),A ;Not in Escape mode CALL CTC5 ;Clear all horizontal tab stops CALL CTC6 ;Clear all vertical tab stops LD HL,0 CALL EEOS ;Clear the screen CALL CURON ;Put the cursor on the screen ; INITALIZE ALL OF THE CONTROL REGISTERS OUT VTAC+14,A OUT VTAC+10,A ;Reset the VTAC LD A,HCOUNT-1 OUT VTAC+0,A IF NOT INTERL LD A,03CH ENDIF IF INTERL LD A,0BCH ENDIF OUT VTAC+1,A IF NOT INTERL LD A,SCANR*8-8+CODE ENDIF IF INTERL LD A,SCANR*8-16+CODE ENDIF OUT VTAC+2,A LD A,SKEW*64+NROWS-1 OUT VTAC+3,A LD A,VFILL/2 OUT VTAC+4,A LD A,VMARG OUT VTAC+5,A ;Try to center the data on the screen LD A,NROWS-1 OUT VTAC+6,A OUT VTAC+14,A ;Start the timing chain OUT KDATA,A ;Disable the VB3 board RET VBSTAT: IN A,KSTAT ;Check keyboard status CPL AND 1 RET Z ;Return a zero if no data LD A,0FFH RET ;Else return a 0FFH VBIN: CALL VBSTAT ;Return the next key JR Z,VBIN ;Wait until one is available IN A,KDATA ;Get it RET ;And return ; VBOUT IS THE MAIN DISPLAY DRIVER FOR THE VB3 BOARD VBOUT: PUSH HL ;First, save all registers PUSH DE PUSH BC OUT KSTAT,A ;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,A ;Disable the VB3 board POP BC ;And restore the registers POP DE POP HL RET ; ON ENTRY, REG HL = LOGICAL CURSOR ADDRESS AND REG C = DATA. PROCES: LD A,(MODE) ;See if we received an ESC character OR A JP NZ,PESCSE ;JIF we are in an escape sequence LD A,C ;Move the data to register A CP 80H ;Check for range of 80 to FF JP NC,PESC ;It is an ESC sequence if >7FH CP ESC ;Check for control characters JP Z,DOESC ;If match, then do control character CP CR JP Z,DOCR CP LF JP Z,DOLF CP HT JP Z,DOHT CP BS JP Z,DOBS CP VT JP Z,DOVT CP ' ' RET C ;Skip other control characters JP DODAT ;Must be a data character DOESC: LD A,1 LD (MODE),A ;We are now reading an ESC sequence XOR A LD (COUNT),A ;Init the CRT for the sequence LD (POINT),A RET PESC: CALL DOESC PESCSE: LD A,(COUNT) CP MAXESC ;Check for buffer overflow JP Z,ABORT EX DE,HL ;Save HL LD L,A ;Index into buffer goes to HL LD H,0 INC A LD (COUNT),A ;Increment pointer LD A,C ;Get data AND 7FH ;7 bits only LD BC,ESCSEQ ;Get base of buffer ADD HL,BC ;Compute current cell LD (HL),A ;Save data EX DE,HL ;Restore HL CP '@' ;Not a terminator if < 40H RET C LD C,A ;Save the data XOR A LD (MODE),A ;ESC seq done, now process it LD A,C ;Get the data again CP ICH JP Z,DOICH ;JIF Insert Character CP CUU JP Z,DOCUU ;JIF Cursor Up CP CUD JP Z,DOCUD ;JIF Cursor Down CP CUF JP Z,DOCUF ;JIF Cursor Forward CP CUB JP Z,DOCUB ;JIF Cursor Back CP CNL JP Z,DOCNL ;JIF Cursor Next Line CP CPL JP Z,DOCPL ;JIF Cursor Preceding Line CP CHA JP Z,DOCHA ;JIF Cursor Horizontal Absolute CP CUP JP Z,DOCUP ;JIF Cursor Position CP CHT JP Z,DOCHT ;JIF Cursor Horizontal Tab CP ED JP Z,DOED ;JIF Erase in Display CP EL JP Z,DOEL ;JIF Erase in Line CP IL JP Z,DOIL ;JIF Insert Line CP DL JP Z,DODL ;JIF Delete Line CP DCH JP Z,DODCH ;JIF Delete Character CP SU JP Z,DOSU ;JIF Scroll Up CP SD JP Z,DOSD ;JIF Scroll Down CP CTC JP Z,DOCTC ;JIF Cursor Tab Control CP CVT JP Z,DOCVT ;JIF Cursor Vertical Tab CP CBT JP Z,DOCBT ;JIF Cursor Backward Tab CP CVA JP Z,DOCVA ;JIF Cursor Vertical Absolute CP SGR JP Z,DOSGR ;JIF Select Graphic Rendition CP 7FH JP Z,DODEL RET ;None of the above, so skip it DOICH: LD A,1 ;Insert Character CALL GET1P RET Z LD B,A ICH1: PUSH BC CALL INCHAR POP BC DEC B JP NZ,ICH1 RET DOCUU: LD A,1 ;Cursor Up CALL GET1P ;Get a parameter, 1 is default RET Z ;If value is zero, then done LD B,A CUU1: PUSH BC ;Repeat till count is zero CALL UP POP BC DEC B JP NZ,CUU1 RET DOCUD: LD A,1 ;Cursor Down CALL GET1P RET Z LD B,A CUD1: PUSH BC CALL DOWN POP BC DEC B JP NZ,CUD1 RET DOCUF: LD A,1 CALL GET1P RET Z LD B,A CUF1: PUSH BC CALL RIGHT POP BC DEC B JP NZ,CUF1 RET DOCUB: LD A,1 CALL GET1P RET Z LD B,A CUB1: PUSH BC CALL LEFT POP BC DEC B JP NZ,CUB1 RET DOCNL: LD A,1 ;Cursor Next Line CALL GET1P RET Z LD B,A CNL1: PUSH BC CALL NEXTLN POP BC DEC B JP NZ,CNL1 RET DOCPL: LD A,1 ;Cursor Preceding Line CALL GET1P RET Z LD B,A CPL1: PUSH BC CALL PREVLN POP BC DEC B JP NZ,CPL1 RET DOCHA: LD A,1 ;Cursor Horizontal Absolute CALL GET1P DEC A CP NCOLS RET NC LD L,A ;Put the cursor on that column RET DOCUP: CALL DOCHA ;Cursor position (Goto XY) JP DOCVA DOCHT: LD A,1 ;Cursor Horizontal Tabulation CALL GET1P RET Z LD B,A CHT1: PUSH BC CALL DOHT POP BC DEC B JP NZ,CHT1 RET DOED: LD A,0 ;Erase in Display CALL GET1P JP Z,EEOS PUSH HL CP 1 JP NZ,ED1 EX DE,HL LD HL,0000H LD BC,NORMAL*256+' ' CALL FILLS ;Erase from start to cursor JP ED2 ED1: CP 2 JP NZ,ED2 LD HL,0 CALL EEOS ;Erase entire display ED2: POP HL ;Restore cursor address RET DOEL: LD A,0 ;Erase in Line CALL GET1P JP Z,EEOL ;Erase from cursor to end of line PUSH HL CP 1 JP NZ,EL1 EX DE,HL LD H,D LD L,0 LD BC,NORMAL*256+' ' CALL FILLS ;Erase from the start of line to cursor JP EL2 EL1: CP 2 JP NZ,EL2 LD L,0 CALL EEOL ;Erase the entire line EL2: POP HL RET DOIL: LD A,1 ;Insert Line CALL GET1P RET Z LD B,A IL1: PUSH BC CALL INSELN POP BC DEC B JP NZ,IL1 RET DODL: LD A,1 ;Delete Line CALL GET1P RET Z LD B,A DL1: PUSH BC CALL DELLN POP BC DEC B JP NZ,DL1 RET DODCH: LD A,1 ;Delete Character CALL GET1P RET Z LD B,A DCH1: PUSH BC CALL DLCHAR POP BC DEC B JP NZ,DCH1 RET DOSU: LD A,1 ;Scroll Up CALL GET1P RET Z LD B,A SU1: PUSH BC CALL RLUP POP BC DEC B JP NZ,SU1 RET DOSD: LD A,1 ;Scroll Down CALL GET1P RET Z LD B,A SD1: PUSH BC CALL RLDWN POP BC DEC B JP NZ,SD1 RET DOCTC: XOR A ;Cursor Tab Control CTCA: CALL GET1P INC A RET Z LD C,A PUSH HL CALL PCTC POP HL LD A,255 JP CTCA PCTC: DEC C JP Z,CTC0 DEC C JP Z,CTC1 DEC C JP Z,CTC2 DEC C JP Z,CTC3 DEC C JP Z,CTC4 DEC C JP Z,CTC5 DEC C JP Z,CTC6 RET CTC0: LD H,0 LD DE,HTABS ADD HL,DE LD (HL),255 RET CTC1: LD L,H LD H,0 LD DE,VTABS ADD HL,DE LD (HL),255 RET CTC2: LD H,0 LD DE,HTABS ADD HL,DE LD (HL),0 RET CTC3: LD L,H LD H,0 LD DE,VTABS ADD HL,DE LD (HL),0 RET CTC4: CTC5: LD HL,HTABS LD B,NCOLS CTC5A: LD (HL),0 INC HL DEC B JP NZ,CTC5A RET CTC6: LD HL,VTABS LD B,NROWS CTC6A: LD (HL),0 INC HL DEC B JP NZ,CTC6A RET DOCVT: LD A,1 ;Cursor Vertical Tabulation CALL GET1P RET Z LD B,A CVT1: PUSH BC CALL DOVT POP BC DEC B JP NZ,CVT1 RET DOCBT: LD A,1 ;Cursor Backward Tabulation CALL GET1P RET Z LD B,A CBT1: PUSH BC CALL DOBT POP BC DEC B JP NZ,CBT1 RET DOCVA: LD A,1 ;Cursor Vertical Absolute CALL GET1P DEC A CP NROWS RET NC LD H,A RET DOSGR: XOR A ;Select Graphic Rendition SGRA: CALL GET1P LD C,A LD A,(ATTRIB) INC C RET Z CALL PSGR LD (ATTRIB),A LD A,255 JP SGRA PSGR: DEC C JP Z,SGR0 DEC C DEC C JP Z,SGR2 DEC C DEC C JP Z,SGR4 DEC C JP Z,SGR5 DEC C DEC C JP Z,SGR7 DEC C JP Z,SGR8 DEC C JP Z,SGR9 DEC C JP Z,SGR10 DEC C JP Z,SGR11 DEC C JP Z,SGR12 DEC C JP Z,SGR13 RET SGR0: LD A,3 RET SGR2: OR REDUCE RET SGR4: OR UNDRLN RET SGR5: OR BLINK RET SGR7: OR REVERS RET SGR8: OR BLANK RET SGR9: OR STRIKE RET SGR10: OR 3 RET SGR11: AND 0FCH OR 2 RET SGR12: AND 0FCH OR 1 RET SGR13: AND 0FCH RET DODEL: PUSH HL LD HL,VIDEO LD BC,NROWS*NCOLS DODEL1: LD (HL),L INC HL DEC BC LD A,C OR B DEC B JP NZ,DODEL1 RET GET1P: LD D,A ;Save the default value LD E,0 ;Zero the accumulator LD BC,ESCSEQ-1 ;Point to the escape string PUSH HL ;Save the cursor address MORE: NOGOOD: LD A,(POINT) INC A ;Compute the index for the next byte LD HL,COUNT CP (HL) ;See if there is any more JP Z,NOMORE ;JIF None LD (POINT),A ;Update the pointer LD L,A LD H,0 ADD HL,BC ;Point to the next char to come out LD A,(HL) ;Get it CP ';' ;Check for a seperator JP Z,NOMORE ;JIF number is done SUB '0' JP C,NOGOOD CP 10 JP NC,NOGOOD ;JIF char is not from 0 to 9 LD D,A ;Save the value LD A,E ;Multiply the accumulated value by 10 ADD A ;*2 LD E,A ADD A ;*4 ADD A ;*8 ADD E ;*10 Done! ADD D ;Add in new digit LD E,A ;Return it to the accumulator LD D,A ;Wipe out old value JP MORE ;Go for the next digit NOMORE: LD A,D ;Get the value OR A ;Set flags POP HL ;Restore cursor address RET ABORT: XOR A LD (MODE),A ;Reset the escape flag RET ; PUT A DATA CHAR ON THE SCREEN AND ADVANCE THE CURSOR. PUTCHAR:PUSH HL ;Save the logical cursor address CALL GETBA ;Get the physical cursor address LD DE,OFFSET LD (HL),C ;Put the data there ADD HL,DE ;Compute the address of the governing attribute LD (HL),B ;Put the attribute here POP HL ;Get the logical cursor address back RET DODAT: LD A,(ATTRIB) ;Get the current attribute LD B,A ;Set it up for PUTCHAR CALL PUTCHAR CALL RIGHT ;Move the cursor right RET NZ ;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: LD 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 RET NZ LD H,NROWS-1 PUSH HL CALL RLUP LD HL,(NROWS-1)*256 CALL EEOL POP HL RET ; MOVE THE CURSOR TO COL 1 OF THE CURRENT LINE. DOCR: LD L,0 RET ; BACK THE CURSOR BY ONE POSITION. DOBS: CALL LEFT CALL Z,UP PUSH HL CALL GETBA LD (HL),' ' POP HL RET ; DO A HORIZONTAL TABULATION DOHT: LD C,L ;Save the column number LD DE,HTABS ;Point to the horizontal tab table DOHT1: CALL RIGHT ;Move right PUSH HL XOR A ;Get a zero LD H,A ADD HL,DE ;Point to HTABS[COL] OR (HL) ;See if true POP HL RET NZ ;Done if found a tab stop LD A,L CP C RET Z ;Done if no tab stops JP DOHT1 ;Continue looking for tab stops ; DO A VERTICAL TABULATION DOVT: LD C,H ;Save the row number LD DE,VTABS ;Point to the vertical tab table DOVT1: CALL DOWN ;Move down PUSH HL XOR A ;Get a zero LD L,H LD H,A ADD HL,DE ;Point to VTABS[ROW] OR (HL) ;See if true POP HL RET NZ ;Done if found a tab stop LD A,H CP C RET Z ;Done if not tab stops JP DOVT1 ;Continue looking for tab stops ; DO A BACKWARD TABULATION DOBT: LD C,L ;Save the column number LD DE,HTABS ;Point to the horizontal tab table DOBT1: CALL LEFT ;Move left PUSH HL XOR A ;Get a zero LD H,A ADD HL,DE ;Point to HTABS[COL] OR (HL) ;See if true POP HL RET NZ ;Done if found a tab stop LD A,L CP C RET Z ;Done if no tab stops JP DOBT1 ;Continue looking for tab stops ; MOVE THE CURSOR UP. UP: LD A,H DEC H OR A RET NZ LD H,NROWS-1 RET ; MOVE THE CURSOR DOWN. DOWN: INC H LD A,NROWS CP H RET NZ LD H,0 RET ; MOVE THE CURSOR LEFT. LEFT: LD A,L DEC L OR A RET NZ LD L,NCOLS-1 RET ; MOVE THE CURSOR RIGHT. RIGHT: INC L LD A,NCOLS CP L RET NZ LD L,0 RET ; MOVE THE CURSOR TO THE BEGINNING OF THE PREVIOUS LINE PREVLN: LD L,0 CALL UP RET NZ LD H,0 PUSH HL CALL RLDWN LD HL,0 CALL EEOL POP HL RET ; ERASE FROM THE CURSOR POSITION TO THE END OF THE SCREEN. EEOS: LD DE,((NROWS-1)*256)+NCOLS-1 LD BC,NORMAL*256+' ' JP FILLS ; ERASE FROM THE CURSOR TO THE END OF THE CURRENT LINE. EEOL: LD D,H LD E,NCOLS-1 LD BC,NORMAL*256+' ' JP FILLS ; FILL THE SCREEN WITH THE DATA IN REG C, THE ATTRIB IN REG B ; FROM X,Y LOCATION HL TO DE. FILLS: PUSH HL CALL GETBA ;Get address of start EX DE,HL CALL GETBA ;Get address of finish LD A,H ;Compare finish and start CP D JP NZ,CMPD1 LD A,L CP E CMPD1: EX DE,HL JP NC,FILLS1 ;JIF area to fill does not wrap PUSH DE ;Save finish address PUSH BC LD DE,VIDEO + NROWS * ((NCOLS + 15) AND 0FFF0H) - 1 CALL FILLS2 ;Fill from start to end of screen POP BC POP DE LD HL,VIDEO ;Fill from start of screen to finish address FILLS1: CALL FILLS2 ;Fill the screen POP HL RET FILLS2: PUSH BC PUSH HL PUSH DE CALL FILL ;Fill in the data POP HL POP DE LD BC,OFFSET ADD HL,BC EX DE,HL ADD HL,BC POP BC LD C,B CALL FILL ;Fill in the attributes RET FILL: LD (HL),C INC HL LD A,H CP D JP NZ,CMPD2 LD A,L CP E CMPD2: JP C,FILL JP Z,FILL RET ; SCROLL THE SCREEN UP BY ONE LINE. RLUP: LD A,(LSTROW) INC A CP NROWS JP NZ,RLUP1 XOR A RLUP1: OUT VTAC+6,A LD (LSTROW),A RET ; SCROLL THE SCREEN DOWN ONE LINE RLDWN: LD A,(LSTROW) OR A JP NZ,RLDWN1 LD A,NROWS RLDWN1: DEC A OUT VTAC+6,A LD (LSTROW),A RET ; TURN THE CURSOR ON. ; THE LOGICAL ADDRESS OF THE CURSOR MUST BE IN REG HL. CURON: LD (CURADR),HL LD A,L OUT VTAC+12,A LD A,(LSTROW) INC A ADD H CP NROWS JP C,CURON1 SUB NROWS CURON1: OUT VTAC+13,A RET ; TURN THE CURSOR OFF. ; THE LOGICAL ADDRESS OF THE CURSOR IS RETURNED IN REG HL. CUROFF: LD HL,(CURADR) LD A,0FFH OUT VTAC+12,A 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 HL LD C,H INC C LD HL,(NROWS-1)*256 LD DE,(NROWS-1)*256 ILLOOP: LD A,H CP C JP C,ILEXIT DEC H CALL MVLINE DEC D JP ILLOOP ILEXIT: CALL EEOL POP HL RET ; PROCEDURE DELLN; ; BEGIN ; FOR RI := R TO NROWS-2 DO ; ROW[RI] := ROW[RI+1]; ; ROW[NROWS-1] := BLANK_LINE; ; END; DELLN: PUSH HL LD L,0 LD D,H LD E,L DLLOOP: LD A,NROWS-2 CP D JP C,DLEXIT INC H CALL MVLINE INC D JP DLLOOP DLEXIT: CALL EEOL POP HL 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 HL LD C,L INC C LD L,NCOLS-1 LD D,H LD E,L ICHLOP: LD A,L CP C JP C,ICHEXT DEC L CALL MVCHAR DEC E JP ICHLOP ICHEXT: LD BC,NORMAL*256+' ' CALL PUTCHAR POP HL 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 HL LD D,H LD E,L DCHLOP: LD A,NCOLS-2 CP E JP C,DCHTXT INC L CALL MVCHAR INC E JP DCHLOP DCHTXT: LD BC,NORMAL*256+' ' CALL PUTCHAR POP HL RET MVLINE: PUSH HL PUSH DE PUSH BC LD BC,OFFSET CALL GETBA PUSH HL ADD HL,BC EX DE,HL CALL GETBA PUSH HL ADD HL,BC EX DE,HL LD BC,NCOLS INC B HERE1: LD A,(HL) LD (DE),A INC HL INC DE DEC C JP NZ,HERE1 DEC B JP NZ,HERE1 POP DE POP HL LD BC,NCOLS INC B HERE2: LD A,(HL) LD (DE),A INC HL INC DE DEC C JP NZ,HERE2 DEC B JP NZ,HERE2 POP BC POP DE POP HL RET MVCHAR: PUSH HL PUSH DE PUSH BC CALL GETBA EX DE,HL CALL GETBA LD A,(DE) LD (HL),A LD BC,OFFSET ADD HL,BC EX DE,HL ADD HL,BC LD A,(HL) LD (DE),A POP BC POP DE POP HL 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 BC LD A,(LSTROW) INC A ADD H CP NROWS JP C,GETBA1 SUB NROWS GETBA1: LD C,A LD B,0 LD A,L LD HL,MAPPER ADD HL,BC ADD HL,BC LD C,A LD A,(HL) INC HL LD H,(HL) LD L,A ADD HL,BC POP BC RET ; The following section (MAPPER) saves space for a mapping ; table. ; The number of DEFW's should be equal to the number of lines. MAPPER: J DEFL (NCOLS+15) AND 0FFF0H DEFW VIDEO+J*0 DEFW VIDEO+J*1 DEFW VIDEO+J*2 DEFW VIDEO+J*3 DEFW VIDEO+J*4 DEFW VIDEO+J*5 DEFW VIDEO+J*6 DEFW VIDEO+J*7 DEFW VIDEO+J*8 DEFW VIDEO+J*9 DEFW VIDEO+J*10 DEFW VIDEO+J*11 DEFW VIDEO+J*12 DEFW VIDEO+J*13 DEFW VIDEO+J*14 DEFW VIDEO+J*15 DEFW VIDEO+J*16 DEFW VIDEO+J*17 DEFW VIDEO+J*18 DEFW VIDEO+J*19 DEFW VIDEO+J*20 DEFW VIDEO+J*21 DEFW VIDEO+J*22 DEFW VIDEO+J*23 DEFW VIDEO+J*24 ENDROM EQU $ ORG VIDEO+NCOLS*NROWS ATTRIB: DEFS 1 ;THE CURRENT SCREEN ATTRIBUTE CURADR: DEFS 2 ;THE LOGICAL CURSOR ADDRESS LSTROW: DEFS 1 ;THE LAST ROW DISPLAYED ON THE SCREEN MODE: DEFS 1 ;BOOLEAN, TRUE IF RECEIVING AN ESCAPE SEQUENCE COUNT: DEFS 1 ;INDEX INTO ESCSEQ POINT: DEFS 1 ;SAME AS ABOVE EXCEPT USED FOR READING ESCSEQ: DEFS MAXESC ;HOLDS THE ESCAPE SEQUENCE HTABS: DEFS NCOLS ;USED FOR SETTING HORIZONTAL TABS VTABS: DEFS NROWS ;SAME FOR VERTICAL TABS ENDRAM EQU $ ORG ENDROM ;This address will appear on the console ;after the assembly END ROM