#TITLE "NEC-APC Smart Screen Driver Interface" #SUBTTL "For the TurboDOS operating system" #PAGE 132,66 ; ; SCRAPC.A ; ; Version date: 8/18/84 ; ; Edit History: ; 7/12/84 jl - Module Created. ; 8/18/84 jl - Added cursor delayed enable feature ; MODULE "SCRAPC" ; module ID ; #INCLUDE "DREQUATE" ; common driver equivalences #INCLUDE "APCEQU" ; common NEC-APC equivalences ; PEEKNG == 00 ; if desperation debugging SCRTST == 00 ; if screen test version ; ; Some screen parameters ; NMBROWS == 25 ; number of user rows NMBCOLS == 80 ; number of user columns STATROW == 25 ; status row CSRCNT == 2 ; delay in ticks for cursor displaying ; DEFATTR == 0X80 ; green with no special attr ALTFONT == 0X89 ; alternate character set ATTROFF == 0X1000 ; attribute memory offset constant ; A0 == 0X30 ; constant 0 A1 == 0X31 ; constant 1 A9 == 0X39 ; constant 9 ASC == 0X3B ; constant ; ; ; GDC status register definition ; DR == 1<<0 ; data ready in FIFO FF == 1<<1 ; FIFO full FE == 1<<2 ; FIFO empty DW == 1<<3 ; drawing in progress DMA == 1<<4 ; DMA execute VS == 1<<5 ; vertical sync active HB == 1<<6 ; horizontal blank active ; ; GDC commands ; RESET == 0X00 ; reset controller SYNC == 0X0E ; SYNC format specify VSYNC == 0X6E ; vertical SYNC mode CCHAR == 0X4B ; cursor and char characteristics START == 0X6B ; start display and end idle mode BCTRL == 0X0C ; display blanking control ZOOM == 0X46 ; zoom factor control CURS == 0X49 ; cursor position specify PRAM == 0X70 ; parameter RAM load PITCH == 0X47 ; pitch specification WDAT == 0X20 ; write DATA into display memory MASK == 0X4A ; mask register load FIGS == 0X4C ; figure drawing parameters specify FIGD == 0X6C ; figure draw start RDAT == 0XA0 ; data read commands CURD == 0XE0 ; cursor address read DMAR == 0XA4 ; DMA read request DMAW == 0X24 ; DMA write request ; ; LOC Data# ; locate in data segment ; ; Bell status --- 00 = sound the bell, 01 = show a bell when ; an ASCII 07 is received ; SHOBELL::BYTE 0 ; bell status ; ; User defined tab size. ; NOTE: Set to desired tab size 2 through 16. ; TABSIZ::BYTE 8 ; default tab size ; ; User defined start up cursor mode. ; NOTE: 0 = non-displayed, 1&2 = blinking block, 3&4= blinking underline. ; CURSOR::BYTE 2 ; default cursor mode ; ; User defined status line enable. ; NOTE: Set to 0XFF for enable and 0 for disable. ; SLFLAG::BYTE 0XFF ; default status line enable ; FLAGS: BYTE CSRFL ; driver flag byte (def follows) INIT == 1<<0 ; initialization flag WRPFL == 1<<1 ; write protected flag ANSFL == 1<<2 ; ANSII mode flag ULRFL == 1<<6 ; user line load (reverse) flag CSRFL == 1<<7 ; cursor display flag ; CURSCR: BYTE 1 ; current screen number SAVSCR: BYTE 0 ; save screen variable ROWCOL: WORD 0 ; current row/column (low/high) NXTSEQ: WORD 0 ; next routine in escape sequence BEGROW: BYTE 0 ; beginning row number ENDROW: BYTE NMBROWS-1 ; ending row number TOPROW: BYTE 0 ; current top row number TMPROW: BYTE 0 ; temp row storage area CSRDLY: BYTE 0 ; cursor delayed enable counter CURTROW:BYTE 0 ; Current TeleVideo row CURTCOL:BYTE 0 ; Current TeleVideo column TVMODE: BYTE 0 ; TeleVideo mode = 1 if TV950 ; = 0 if no TV ; SMXSPH::WORD 1 ; screen mutual exclusion semaphore WORD . WORD .-2 ; ; ANSII sequence variables ; ASCSIZ == 32 ; number of bytes to buffer ASCBP: WORD 0 ; index of next char to store ASCADR: WORD 0 ; address of cursor move rtn ASCOPT: BYTE 0 ; True if in ANSII option mode ASCBUF: RES ASCSIZ ; buffer for ANSII sequences ASCBUFE == . ; end of ANSII buffer ACSPRM == 0X05 ; cursor option parameter # ; ; ; ; ASCII control code lookup table. ; CTLTBL == . ; base of the lookup table BYTE 0X07 ; #1 BYTE 0X08 ; #2 BYTE 0X09 ; #3 BYTE 0X0A ; #4 BYTE 0X0B ; #5 BYTE 0X0C ; #6 BYTE 0X0D ; #7 BYTE 0X1A ; #8 BYTE 0X1B ; #9 BYTE 0X1E ; #10 CTBLEN == .-CTLTBL ; length of lookup table ; ; ASCII control code branch table. ; CTBLXEC == . ; base of execution table WORD BELL ; #1 ring the terminal bell WORD BACKSP ; #2 back space WORD HZTAB ; #3 horizontal tab WORD LINE ; #4 line feed WORD RLINE ; #5 reverse line feed WORD TNFSP ; #6 non-destructive forward space WORD RETURN ; #7 carrige return WORD CUPSCR ; #8 clear unprotected screen WORD ENAESC ; #9 enable escape sequence WORD HOME ; #10 home cursor ; ; ESCAPE sequence lookup table. ; ESCTBL == . ; base of the lookup table BYTE "=" ; #1 direct cursor addressing BYTE "*" ; #2 clear unprot screen BYTE "T" ; #3 clear unprot, end of line BYTE "Y" ; #4 clear unprot, end of page BYTE "C" ; #5 set terminal display color BYTE "j" ; #6 begin reverse video fields BYTE "k" ; #7 end reverse video fields BYTE "^" ; #8 begin blinking fields BYTE "_" ; #9 begin blank fields BYTE "q" ; #10 end blink/blank fields BYTE "l" ; #11 begin underline fields BYTE "m" ; #12 end underline fields BYTE "." ; #13 set cursor attribute BYTE "[" ; #14 begin of ANSII sequence BYTE "(" ; #15 enable alternate font BYTE 0X01 ; #16 set attribute directly BYTE "A" ; #17 Televideo up arrow BYTE "B" ; #18 Televideo down arrow BYTE "D" ; #19 Televideo left arrow BYTE "H" ; #20 Televideo home BYTE "I" ; #21 Televideo erase eol BYTE "J" ; #22 Televideo erase eos BYTE "K" ; #23 Televideo clearscreen BYTE "X" ; #24 Televideo row position BYTE "u" ; #25 Reset Televideo mode BYTE "v" ; #26 Set Televideo mode ETBLEN == .-ESCTBL ; length of lookup table ; ; ESCAPE sequence branch table. ; ETBLXEC == . ; base of execution table WORD SETXY ; #1 WORD CUPSCR ; #2 WORD CUPEOL ; #3 WORD TCUPEOP ; #4 WORD TBEGCOLR ; #5 WORD BEGRV ; #6 WORD ENDRV ; #7 WORD BEGBLINK ; #8 WORD BEGBLANK ; #9 WORD ENDBB ; #10 WORD BEGUND ; #11 WORD ENDUND ; #12 WORD SETCSRA ; #13 WORD BEGANS ; #14 WORD SETFONT ; #15 WORD ATTDIR ; #16 WORD RLINE ; #17 WORD LINE ; #18 WORD BACKSP ; #19 WORD HOME ; #20 WORD CUPEOL ; #21 WORD CUPEOP ; #22 WORD CUPSCR ; #23 WORD TCURROW ; #24 WORD RESTV ; #25 WORD SETTV ; #26 ; ; ANSII command lookup table ; ANSTBL == . ; Base of lookup table BYTE "f" ; #1 BYTE "H" ; #2 BYTE "C" ; #3 BYTE "A" ; #4 BYTE "B" ; #5 BYTE "D" ; #6 BYTE "J" ; #7 BYTE "K" ; #8 BYTE "m" ; #9 BYTE "M" ; #10 BYTE "h" ; #11 BYTE ">" ; #12 ATBLEN == .-ANSTBL ; Length of lookup table ; ; ANSII command branch table ; ATBLXEC == . ; Base of execution table WORD ASETXY ; #1 direct cursor addressing WORD ASETXY ; #2 direct cursor addressing WORD ARIGHT ; #3 move cursor right WORD AUP ; #4 move cursor up WORD ADOWN ; #5 move cursor down WORD ALEFT ; #6 move cursor left WORD APAGE ; #7 clear page WORD ALINE ; #8 clear line WORD AATTR ; #9 set attribute WORD AATTR ; #10 set attribute WORD ASETXY ; #11 direct cursor addressing WORD ASETOPT ; #12 set options ; ; ANSII option sequence lookup table ; OPTTBL == . ; Base of lookup table BYTE "h" ; #1 BYTE "L" ; #2 BYTE "l" ; #3 OPTLEN == .-OPTTBL ; Length of lookup table ; ; ANSII option branch table ; OPTXEC == . ; Base of execution table WORD ADISABLE ; #1 disable mode WORD AENABLE ; #2 enable mode WORD AENABLE ; #3 enable mode ; ; ANSII page command branch table ; APGEXEC == . ; Base of execution table WORD CUPEOP ; #0 erase to end of page WORD CUPEOP1 ; #1 erase from begin of page WORD CUPSCR1 ; #2 erase entire page ; ; ANSII line command branch table ; ALNEXEC == . ; Base of execution table WORD CUPEOL ; #0 erase to end of line WORD CUPEOL1 ; #1 erase from begin of line WORD CUPEOL2 ; #2 erase entire line ATTRTBL == . ; Base of attribute table BYTE 0X00 ; ANSII attribute 0 -- default BYTE 0X00 ; ANSII attribute 1 -- default BYTE 0X04 ; ANSII attribute 2 -- vertline BYTE 0X02 ; ANSII attribute 3 -- overline BYTE 0X01 ; ANSII attribute 4 -- undrline BYTE 0X08 ; ANSII attribute 5 -- blink BYTE 0X00 ; ANSII attribute 6 -- unused BYTE 0X10 ; ANSII attribute 7 -- inverse ; ; NITCMD: BYTE __LEN ; CRT initialization command BYTE SYNC|0X01,CRT_CMD ; Character display mode '0': no BYTE 0X10,CRT_PARM ; interlace, flashless drawing, static BYTE 0X4E,CRT_PARM ; RAM, 80 character per row. BYTE 0X52,CRT_PARM BYTE 0X0E,CRT_PARM BYTE 0X06,CRT_PARM BYTE 0X13,CRT_PARM BYTE 0XEE,CRT_PARM BYTE 0X45,CRT_PARM BYTE VSYNC|0X01,CRT_CMD ; master video sync BYTE ZOOM,CRT_CMD ; zooming disabled BYTE 0X00,CRT_PARM BYTE PITCH,CRT_CMD ; 80 character per row BYTE 0X50,CRT_PARM BYTE MASK,CRT_CMD BYTE 0XFF,CRT_PARM BYTE 0XFF,CRT_PARM __LEN == (.-NITCMD-1)/2 ; CCHRCMD:BYTE CCHRCLN ; cursor char command BYTE CCHAR,CRT_CMD CCHRP1: BYTE 0X12,CRT_PARM BYTE 0X21,CRT_PARM BYTE 0X8A,CRT_PARM CCHRCLN == (.-CCHRCMD-1)/2 ; CSRCMD: BYTE CSRCLN ; specify cursor command BYTE CURS,CRT_CMD CSRLOW: BYTE 0X00,CRT_PARM CSRHI: BYTE 0X00,CRT_PARM CSRCLN == (.-CSRCMD-1)/2 ; WDATCMD: ; write single char command BYTE WDATCLN BYTE WDAT,CRT_CMD FONT: BYTE 0X00,CRT_PARM CHAR: BYTE 0X00,CRT_PARM WDATCLN == (.-WDATCMD-1)/2 ; WATTCMD: ; write attribute command BYTE WATTCLN BYTE WDAT|0X10,CRT_CMD CURATTR:BYTE DEFATTR,CRT_PARM WATTCLN == (.-WATTCMD-1)/2 ; RDATCMD: BYTE RDATCLN BYTE RDAT|0X10,CRT_CMD RDATCLN == (.-RDATCMD-1)/2 ; PRAMCMD: ; Write parameter RAM command BYTE PRAMCLN BYTE PRAM,CRT_CMD BYTE (NMBROWS*80+80)%0X100,CRT_PARM BYTE (NMBROWS*80+80)/0X100,CRT_PARM BYTE 0X30,CRT_PARM BYTE 0X01,CRT_PARM PRAM1: BYTE 0X00,CRT_PARM PRAM2: BYTE 0X00,CRT_PARM PRAM3: BYTE 0X00,CRT_PARM PRAM4: BYTE 0X00,CRT_PARM PRAM5: BYTE 0X00,CRT_PARM PRAM6: BYTE 0X00,CRT_PARM PRAM7: BYTE 0X00,CRT_PARM PRAM8: BYTE 0X00,CRT_PARM PRAMCLN == (.-PRAMCMD-1)/2 ; ; FIGSCMD: BYTE FIGSCLN BYTE FIGS,CRT_CMD BYTE 0X02,CRT_PARM FIGSP2: BYTE 0X00,CRT_PARM FIGSP3: BYTE 0X00,CRT_PARM FIGSCLN == (.-FIGSCMD-1)/2 ; ; ; Cursor character table. ; CCHRTBL: BYTE 0X12,0X01,0X8A ; blinking block BYTE 0X12,0X21,0X8A ; steady block BYTE 0X12,0X0E,0X8A ; blinking underline BYTE 0X12,0X2E,0X8A ; steady underline ; ; ; Melody commands and constants ; MELREADY== 0X80 ; Ready to accept command BELCMDS:DB 0X31,0X63,0X3C,0X39 ; List of melody commands ; ; LOC Code# ; locate in code segment ; ; Screen entry point. Output char passed in CL register. ; SCREEN:: PUSH SI PUSH DI ; save regs PUSH CX ; save output char MOV BX,&SMXSPH ; get exclusion semaphore addr CALL WAIT# ; dispatch if neccessary POP CX ; restore output char CALL __SCR ; call the driver MOV BX,&SMXSPH ; get exclusion semaphore addr CALL SIGNAL# ; signal process completed OR AL,=0XFF ; set status POP DI POP SI ; restore regs RET ; and exit ; __SCR: CLD ; set direction = increment MOV AX,DS MOV ES,AX ; copy DS into ES seg reg TEST FLAGS,=INIT ; test initialization flag JNZ __C1 ; if done, continue PUSH CX ; save output char MOV BX,&NITCMD ; get init table addr CALL GDCOUT ; and output it CALL SLINIT ; initialize status line CALL CUPSCR ; clear user screen area OR FLAGS,=INIT ; set init flag for further entry POP CX ; restore output char __C1: MOV CSRDLY,=CSRCNT ; pre-set cursor delay count AND CCHRP1,=~0X80 ; reset cursor display bit MOV BX,&CCHRCMD CALL GDCOUT ; disable cursor display MOV DX,ROWCOL ; load current row/column address MOV AX,NXTSEQ ; get possible next escape sequence MOV NXTSEQ,=0 ; always clear it TEST AX,AX ; sequence present? JNZ SEQCOM ; if so, continue CMP FONT,=00 ; Is this alternate font mode? JNE DISPLAY ; If so, display regardless CMP CL,=ASP ; displayable char? JNB DISPLAY ; if so, continue #IF PEEKNG ; Desperation debugging PUSH CX MOV CL,=0X7E CALL DISPLAY POP CX JMP DISPLAY #ENDIF MOV DI,&CTLTBL ; get control char lookup table MOV AL,CL ; load char MOV CX,=CTBLEN ; get table length REPNZ SCAS BYTE ; look for a match JNZ __X ; if not found, cont MOV BX,=CTBLEN-1 SUB BX,CX ; calc length into table ADD BX,BX ; time 2 for execute table CALLI CTBLXEC[BX] ; execute the function __X: CALL UPDCSR ; do cursor update stuff RET ; and exit ; SEQCOM: CALLI AX ; continue escape sequence JMPS UPDCSR ; do cursor update stuff ; DISPLAY: MOV CHAR,CL ; set char in command string CALL PNTCHAR ; point cursor at char memory MOV BX,&WDATCMD CALL GDCOUT ; write single char CALL PNTATTR MOV BX,&WATTCMD CALL GDCOUT ; write single attribute MOV FONT,=00 ; Cancel alternate font CALL NFSP ; do non-destructive forword space ; UPDCSR: MOV ROWCOL,DX ; update current row/column CALL PNTCHAR ; point cursor at character memory ; #IF SCRTST ; if screen test version JMPS CSRENA ; enable cursor #ELSE RET ; and exit #ENDIF ; ; The following routine is called from the real-time-clock driver to ; check for the cursor enable delay count. When count of zero is reached, ; the cursor is re-enabled. ; CSRCHK:: CMP CSRDLY,=0 ; check for count reached JZ _X1 ; if so, continue DEC CSRDLY ; decrement the count JNZ _X1 ; if count still going ; ; This entry is called from the keyboard input routine to enable the cursor ; unconditionally when waiting on a character. ; CSRENA:: MOV CSRDLY,=0 ; force count to zero TEST FLAGS,=CSRFL ; cursor enabled? ; JZ _X1 ; if not, continue OR CCHRP1,=0X80 ; set cursor display bit MOV BX,&CCHRCMD CALL GDCOUT ; re-enable the cursor _X1: RET ; exit ; ; ; CONTROL CHARACTER FUNCTIONS. ; ENAESC: ; start escape sequence. CONTROL-[ MOV NXTSEQ,&BEGESC ; set sequence function number RET ; and exit ; BELL: ; ring the terminal bell. CONTROL-G TEST SHOBELL,=1 ; Visually show the bell ? JNZ BELL1 LEA BX,BELCMDS ; Setup sound chip for bell CALL MELOUT CALL MELOUT CALL MELOUT MOV CX,=0X1F35 ; Wait for a while LOOP $ ; This should take 250 ms CALL MELOUT ; Issue click RET MELOUT: MOV CX,=10 ; Clear counters __1: IN AL,MEL_STAT ; Get melody status PUSH [BX] POP [BX] MOV AH,AL ; Compare current status IN AL,MEL_STAT ; ..to new status until PUSH [BX] POP [BX] CMP AH,AL ; ..status is stable JNE __0 CMP AL,=MELREADY ; Is the command register ready? JE __2 __0: LOOP __1 ; No, try again ; JMP MELOUT RET __2: MOV AL,[BX] ; Get melody command INC BX ; Move to next command OUT MEL_CMD,AL RET BELL1: MOV CHAR,=ABEL CALL PNTCHAR ; point cursor at char memory MOV BX,&WDATCMD CALL GDCOUT ; write single char CALL PNTATTR MOV BX,&WATTCMD CALL GDCOUT ; write single attribute JMP UPDCSR ; HOME: ; home cursor function. CONTROL-^ MOV DL,=0 ; get starting row number JMPS RETCOM ; and join common ; RETURN: ; carrige return function. CONTROL-M CMP CURSCR,=0 ; screen = user line load? JNZ RETCOM ; if not, continue common MOV CL,SAVSCR ; get restore screen number ;;; CALL SETULS ; and do user line stuff RET ; and exit ; RETCOM: XOR DH,DH ; cursor to starting column JMPS FCKWP ; check write protect stuff ; BACKSP: ; back space function. CONTROL-H DEC DH ; decrement column number JNS __C ; Did we go off left margin ? TEST FLAGS,=ANSFL ; Yes, are we in ANSII mode ? JZ __C OR DL,DL ; Yes, and is this line 0 ? JNZ __C XOR DH,DH ; Yes, so freeze cursor pos __C: CMP DH,=NMBCOLS ; cursor column wrap? JC BCKWP ; if not, continue MOV DH,=NMBCOLS-1 ; cursor back to last column ; drop into reverse line feed function RLINE: ; reverse line feed function. CONTROL-K DEC DL ; decrement row number JNS __C0 ; Did we just go negative ? TEST FLAGS,=ANSFL ; Yes, must we hold here ? JZ __C0 XOR DL,DL ; Yes, stay right here __C0: CMP DL,BEGROW ; cursor reverse row wrap? JC __C1 ; if so, continue CMP DL,ENDROW ; check upper boundry JBE BCKWP ; if not, continue __C1: MOV DL,ENDROW ; cursor wrap to last row ; BCKWP: TEST FLAGS,=WRPFL ; write protect mode? JZ __X ; if not, continue CALL RETATTR ; get the attribute byte TEST AL,=1<<5 ; protected field? JNZ BACKSP ; if so, try last field __X: RET ; else exit ; TNFSP: TEST TVMODE,=01 ; Is this Televideo mode ? JZ NFSP JMP CUPSCR ; Yes, go clear screen NFSP: ; non-dest forward space. CONTROL-L INC DH ; increment column number CMP DH,=NMBCOLS ; cursor column wrap? JC FCKWP ; if not, continue XOR DH,DH ; cursor to starting column CMP CURSCR,=0 ; screen = user line load? JNZ LINE ; if not, continue with line feed TEST FLAGS,=ULRFL ; user load reverse flag set? JZ __C1 ; if not, continue CALL DELCHAR ; delete the char at column 0 __C1: MOV DH,=NMBCOLS-1 ; else, reset to last column RET ; and exit ; LINE: ; line feed function. CONTROL-J INC DL ; increment row number CMP DL,ENDROW ; cursor row wrap? JBE FCKWP ; if not, continue TEST FLAGS,=WRPFL ; write protect mode on? JZ SCROLL ; if not, continue MOV DL,BEGROW ; reset to first row FCKWP: TEST FLAGS,=WRPFL ; write protect mode? JZ __X ; if not, continue CALL RETATTR ; return attribute byte TEST AL,=1<<5 ; protected field? JNZ NFSP ; if so, continue __X: RET ; else exit ; ; Scroll the screen. ; SCROLL: DEC DL ; restore last row on screen INC TOPROW ; bump current top row CMP TOPROW,=NMBROWS ; and load the value JB __C1 ; if not, continue MOV TOPROW,=0 ; reset top row __C1: CALL PRAMOUT ; send scrolling command PUSH DX ; SAVE CURRENT ROW/COLUMN MOV DH,=0 ; SET COLUMN ONE CALL CUPEOL ; clear unprotected end of line POP DX ; RESTORE ROW/COLUMN RET ; all done ; HZTAB: ; horizontal tab. CONTROL-I MOV AL,DH ; get current column XOR AH,AH ; make double length MOV CL,TABSIZ ; get the tab size DIV CL ; calc last tab column MOV AL,TABSIZ SUB AL,AH ; calc length to next stop ADD AL,DH ; calc next tab stop CMP AL,=NMBCOLS ; test against number of columns JNC __X ; if over limit, continue, no change MOV DH,AL ; set new column number __X: RET ; all done ; ; BEGESC: MOV DI,&ESCTBL ; get control char lookup table MOV SI,&ETBLXEC ; get pointer to execution tbl MOV BX,=ETBLEN-1 ; get length of excape table TBLOOKX: MOV AL,CL ; load char MOV CX,BX ; get table length INC CX REPNZ SCAS BYTE ; look for a match JZ __C ; if found, continue RET ; else just exit ; __C: SUB BX,CX ; calc length into table ADD BX,BX ; time 2 for execute table JMPI [BX+SI] ; execute the function ; ; ;+--------------------------------+ ;| Special TeleVideo 950 functions| ;+--------------------------------+ RESTV: MOV TVMODE,=00 ; Return to normal mode RET SETTV: MOV TVMODE,=01 ; Set into Televideo mode RET TCURROW: MOV NXTSEQ,&SETTROW ; Start TeleVideo row sequence RET TCURCOL: MOV NXTSEQ,&SETTCOL ; Start TeleVideo col sequence RET SETTROW: MOV CH,=NMBROWS ; Check validity of row char CALL CKBIASA JC _XTV MOV CURTROW,CL ; Good value, go set cursor TVC: MOV DL,CURTROW MOV DH,CURTCOL JMP FCKWP _XTV: RET SETTCOL: MOV CH,=NMBCOLS ; Check validity of col char CALL CKBIASA JC _XTV MOV CURTCOL,CL ; Good value, go set cursor JMP TVC ; ; ; +-----------------------------------+ ; | ANSII SEQUENCE FUNCTIONS | ; +-----------------------------------+ ; ; Start up ANSII sequence ; BEGANS: MOV NXTSEQ,&ANSPARS ; setup ANSII buffer routine MOV ASCBP,&ASCBUF ; initialize ANSII buffer MOV ASCOPT,=0 ; clear ANSII option boolean RET ; ; Buffer characters in ANSII buffer ; ANSPARS: CMP CL,=A0 ; Is the character < 0 ? JB __X1 CMP CL,=ASC ; No, is it a ";" ? JE __X CMP CL,=A9 ; No, is it > 9 ? JA __X1 __X: MOV BX,ASCBP ; No, it's in [0..9, ;] CMP BX,&ASCBUFE ; Is there room in buffer ? JE __X2 MOV [BX],CL ; Yes, store char INC BX ; Move to next buffer pos MOV ASCBP,BX MOV NXTSEQ,&ANSPARS ; Continue to accumulate chars __X2: RET ; ; Process ANSII command in CL ; __X1: TEST ASCOPT,=1 ; Is this an option command ? JZ __X3 MOV DI,&OPTTBL ; Yes, look for char in OPTTBL MOV SI,&OPTXEC ; Execute off OPTXEC MOV BX,=OPTLEN-1 ; OPTTBL length JMP TBLOOKX __X3: MOV SI,&ATBLXEC ; Execute off of ATBLXEC MOV DI,&ANSTBL ; Look for char in ANSTBL MOV BX,=ATBLEN-1 ; ANSTBL length JMP TBLOOKX ; ; Convert ASCII parameter to binary ; ; Assume SI = ^Buffer, BX = Default value, DX = Minimum value ; Return CX = binary value ; ASCTOBIN: XOR AX,AX ; Clear out high byte for later MOV CX,BX ; Setup default value CALL ATBGET ; Get first character into AL JE __X ; IS there a character ? XOR CX,CX ; No, start accumulating __X0: MOV DI,CX ; Multiply accumulator by 10 SHL CX,=1 SHL CX,=1 JC __X1 ; Overflow ? ADD CX,DI JC __X1 ; Overflow ? SHL CX,=1 JC __X1 ; Overflow ? SUB AL,=A0 ; Convert ASCII to binary ADD CX,AX ; Add in new digit JC __X1 ; Is this an overflow ? CALL ATBGET ; Get new character into AL JNZ __X0 ; Is there a valid character ? CMP CX,DX ; No, is return > minimum ? JAE __X MOV CX,DX ; No, return minimum __X: RET __X1: MOV CX,BX ; Overflow, flush parameter __X2: CALL ATBGET ; Get next parameter char JNE __X2 ; End of parameter ? RET ATBGET: ; Get char in AL, return Z set ; if character invalid CMP SI,ASCBP ; Is the buffer empty ? JE __X LODS BYTE ; Get character into AX CMP AL,=ASC ; Is it a ";" ? __X: RET ; ; Get a 1-based parameter and return it in CX ; GET1PRM: PUSH DX ; Save current cursor position MOV SI,&ASCBUF ; Start at beginning of buffer MOV DX,BX ; Set default to minimum CALL ASCTOBIN ; Get parameter value POP DX ; Recover cursor position RET ; ; Multiple parameter read and dispatch ; Assume AX = ^handler routine ; ADISP: MOV ASCADR,AX ; Save parameter handler addr MOV SI,&ASCBUF ; Get pointer to param buffer PUSH DX ; Save current position XOR DX,DX ; Set minimum parameter __C: CMP SI,ASCBP ; Are there any parameters left? JE __X MOV BX,DX ; Make default parameter 0 CALL ASCTOBIN ; Get parameter value CALLI ASCADR ; Call handler routine JMP __C ; Go get next parameter __X: POP DX ; Recover cursor position RET ; ; ANSII Set attribute ; AATTR: MOV CURATTR,=DEFATTR ; Set attribute to green MOV AX,&AATRHAN ; Get address of attr handler JMP ADISP ; Go handle attributes AATRHAN: TEST CX,=0XFFE8 ; Is this a valid parameter ? JNZ __C TEST CL,=0X10 ; Yes, is the color bit set ? JNZ __CLR MOV BX,CX ; No, assemble special attrib. MOV AL,ATTRTBL[BX] ; Get attribute bit OR CURATTR,AL ; Include it in new attribute __C: RET ; Get another attribute __CLR: AND CURATTR,=0X1F ; Clear out old color SHL CL,=1 ; Shift new color into position SHL CL,=1 SHL CL,=1 SHL CL,=1 SHL CL,=1 OR CURATTR,CL ; Include new color RET ; Get another attribute ; ; ANSII option set ; ASETOPT: MOV ASCOPT,=1 ; Set ANSII option mode MOV NXTSEQ,&ANSPARS ; Continue parsing parameters RET AENABLE: MOV AX,&AENHAN ; Setup to handle option #'s JMP ADISP ; Start parsing parameters AENHAN: CMP CX,=ACSPRM ; Is this a cursor enable ? JNE __X OR FLAGS,=CSRFL ; Yes, enable the cursor __X: RET ADISABLE: MOV AX,&ADISHAN ; Setup to handle option #'s JMP ADISP ; Start parsing parameters ADISHAN: CMP CX,=ACSPRM ; Is this a cursor disable ? JNE __X AND FLAGS,=~CSRFL ; Yes, disable the cursor __X: RET ; ; ANSII Set X-Y coordinate ; ASETXY: MOV SI,&ASCBUF ; Get pointer to param buffer PUSH DX ; Save current position MOV DX,=0X0001 ; Minimum line number to 1 MOV BX,DX ; Default line number to 1 CALL ASCTOBIN ; Convert parameter to binary CMP CX,=NMBROWS ; Is this beyond last row ? JA __X PUSH CX ; No, save this for later CALL ASCTOBIN ; Convert next parameter POP DX ; Get row back into DL CMP CX,=NMBCOLS ; Is this beyond last column ? JA __X MOV DH,CL ; Get column in DH SUB DX,=0X0101 ; Convert to 0-based coords POP AX ; Trash old position JMP FCKWP ; Go set position __X: POP DX ; Return with old position RET ; ; ANSII Cursor right ; ARIGHT: MOV AX,&NFSP ; Get address of cursor mover JMP ANSCSR ; Go move cursor ; ; ANSII Cursor left ; ALEFT: MOV AX,&BACKSP ; Get address of cursor mover JMP ANSCSR ; Go move cursor ; ; ANSII Cursor down ; ADOWN: MOV AX,&LINE ; Get address of cursor mover JMP ANSCSR ; Go move cursor ; ; ANSII Cursor up ; AUP: MOV AX,&RLINE ; Get address of cursor mover ANSCSR: MOV ASCADR,AX ; Save address of cursor mover MOV BX,=0X0001 ; Set minimum and default to 1 CALL GET1PRM ; Get move count into CX PUSH FLAGS ; Save flags OR FLAGS,=ANSFL ; Set ANSII mode __X: PUSH CX ; Save count just in case CALLI ASCADR ; Move cursor up POP CX ; Get count back LOOP __X ; Go as many times as specified POP FLAGS ; Restore flags RET ; ; ANSII Line clear sequences ; ALINE: MOV SI,&ALNEXEC ; Get jump table for line code JMP APLXEC ; Get param and execute ; ; ANSII Page clear sequences ; APAGE: MOV SI,&APGEXEC ; Get jump table for page code APLXEC: XOR BX,BX ; Set minimum and default to 0 PUSH SI ; Save jump table address CALL GET1PRM ; Get operation parameter POP SI ; Restore jump table address CMP CL,=02 ; Is operation greater than 2? JBE __C XOR CX,CX ; Yes, use default __C: MOV BX,CX ; Transfer to appropriate code ADD BX,BX ; Convert to table index JMPI [BX+SI] ; Transfer to appropriate code ; ; ; +------------------------------------+ ; | TERMINAL ESCAPE SEQUENCE FUNCTIONS | ; +------------------------------------+ ; ; Set cursor X-Y address. ; SETXY: MOV NXTSEQ,&SETROW ; next char should be the row RET ; done ; SETROW: MOV CH,=NMBROWS ; get number of valid rows CALL CKBIASA ; remove ASCII bias JC _X2 ; if invalid, exit MOV TMPROW,CL ; store in temp variable MOV NXTSEQ,&SETCOL ; next char should be the column _X2: RET ; done ; SETCOL: MOV CH,=NMBCOLS ; get number of valid columns CALL CKBIASA ; remove ASCII bias JC _X2 ; if invalid, exit MOV DH,CL ; move to reg MOV DL,TMPROW ; get temp stored row JMP FCKWP ; check forward movement and exit ; ; Set attribute directly ; ATTDIR: MOV NXTSEQ,&ATTSET ; Set attribute directly RET ATTSET: MOV CURATTR,CL ; Yes, ... we mean DIRECTLY RET ; ; Set alternate font ; SETFONT: MOV NXTSEQ,&FONTCHK ; Set font from RAM RET FONTCHK: CMP CL,=A1 ; Is this an ASCII "1"? JNE __X MOV FONT,=ALTFONT ; Yes, set alternate font __X: RET ; ; Set display colors if normal mode, right cursor if Televideo mode. ; TBEGCOLR: TEST TVMODE,=01 ; Is this Televideo mode ? JZ BEGCOLOR JMP NFSP ; Yes, go do right arrow ; ; Set display colors. ; BEGCOLOR: ; set colors attribute MOV NXTSEQ,&SETCOLOR RET ; SETCOLOR: MOV CH,=8 ; set upper limit CALL CKBIAS0 JC __X ; if invalid, continue MOV AL,CL ; move to reg MOV CL,=5 ; get shift factor SHL AL,CL ; move bits AND CURATTR,=~0XE0 ; strip old attributes OR CURATTR,AL ; add new ones __X: RET ; done ; ; Begin reverse video fields. ; BEGRV: OR CURATTR,=0X10 ; set attribute bit RET ; done ; ; End reverse video fields. ; ENDRV: AND CURATTR,=~0X10 ; clear attribute bit RET ; done ; ; Begin blinking fields. ; BEGBLINK: OR CURATTR,=0X08 ; set attribute bit RET ; done ; ; Begin blank fields. ; BEGBLANK: AND CURATTR,=~0XE0 ; set secret color code RET ; done ; ; End blink/blank fields. ; ENDBB: AND CURATTR,=~0X08 ; clear attribute bit OR CURATTR,=0X80 ; set display GR attribute RET ; done ; ; Begin underline fields. ; BEGUND: OR CURATTR,=0X01 ; set attribute bit RET ; ; End underline fields. ; ENDUND: AND CURATTR,=~0X01 ; clear attribute bit RET ; ; Set cursor attribute. ; SETCSRA: MOV NXTSEQ,&SETCSR1 ; set code expected next RET ; and exit ; SETCSR1: MOV CH,=5 ; get upper limit on code CALL CKBIAS0 ; check ASCII bias JC __X ; if invalid, continue AND FLAGS,=~CSRFL ; clear cursor display flag DEC CL ; code = 0? JC __X ; if so, continue OR FLAGS,=CSRFL ; set cursor display flag MOV BL,CL ; move to reg ADD BL,BL ; times 2 ADD BL,CL ; times 3 XOR BH,BH ; make double length ADD BX,&CCHRTBL ; add table base MOV AX,&CCHRCMD ; point at command table too MOV CX,=3 ; get loop count __LP: MOV AL,[BX] ; get first parm XCHG AX,BX MOV [BX],AL ; substitute XCHG AX,BX INC BX ; bump table pointer ADD AX,=2 ; and command table pointer LOOP __LP ; continue for the count __X: RET ; all done ; ; ; Check ASCII BIAS. Limit in CH reg, Base is ASCII SPACE. ; CKBIASA: SUB CL,=ASP ; remove bias, check lower limit JC _BX ; if invalid, exit CKBCOM: CMP CL,CH ; check upper limit CMC ; invert logic _BX: RET ; all done, exit ; ; Check ASCII BIAS. Limit in CH reg, Base is ASCII 0. ; CKBIAS0: SUB CL,='0' ; remove bias, check lower limit JC _BX ; if under, exit JMPS CKBCOM ; join common code ; ; Clear screen and leave cursor in original location ; CUPSCR1: PUSH DX ; Save original coordinates CALL CUPSCR ; Go clear screen POP DX ; Restore original coordinates RET ; ; ; Clear unprotected screen. ; CUPSCR: MOV TOPROW,=0 ; reset top row CALL PRAMOUT ; send PRAM values XOR DX,DX ; reset row/column register MOV ROWCOL,DX ; and storage location CALL PNTCHAR ; point cursor at screen memory MOV AL,=NMBROWS ; get number of rows MOV CL,=NMBCOLS ; get column size MUL CL ; calc screen positions DEC AX ; adjust for DC variable MOV FIGSP2,AL MOV FIGSP3,AH ; set DC variable MOV BX,&FIGSCMD ; get figs command addr CALL GDCOUT ; and send it MOV CHAR,=ASP MOV BX,&WDATCMD CALL GDCOUT CALL PNTATTR ; point to attribute memory MOV BX,&FIGSCMD CALL GDCOUT AND CURATTR,=0XE0 ; reset non-color attributes MOV BX,&WATTCMD JMP GDCOUT ; send write data command ; ; Clear entire line and leave cursor in original location ; CUPEOL2: PUSH DX ; Save original cursor location XOR DH,DH ; Go to beginning of line CALL CUPEOL ; Clear line POP DX ; Restore original cursor RET ; ; Clear from beginning of line to cursor position, inclusive ; CUPEOL1: PUSH DX ; Save current cursor position MOV AL,DH ; Get # of chars - 1 XOR AH,AH XOR DH,DH ; Start at left margin CALL CLRCHR ; Clear the characters POP DX ; Restore cursor position RET ; ; Clear unprotected to end of line. ; CUPEOL: MOV AX,=NMBCOLS ; get number of columns SUB AL,DH ; calc remaining columns DEC AL ; adjust for DC write CLRCHR: MOV FIGSP2,AL MOV FIGSP3,AH ; set figs parameters CALL PNTCHAR ; point to char memory MOV BX,&FIGSCMD CALL GDCOUT ; send figs command MOV CHAR,=ASP MOV BX,&WDATCMD CALL GDCOUT ; write data and exit CALL PNTATTR ; point to attribute memory MOV BX,&FIGSCMD CALL GDCOUT ; send figs command MOV BX,&WATTCMD JMP GDCOUT ; ; Clear from beginning of screen to current cursor position ; CUPEOP1: CALL CUPEOL1 ; Clear begin line to cursor PUSH DX ; Save current cursor position __C: DEC DL ; Move to prior line JS __X ; Are we off the display ? CALL CUPEOL2 ; No, clear entire line JMP __C ; Loop until done __X: POP DX ; Restore cursor position RET ; ; Clear end of page in normal mode, or set column address in ; Televideo mode. ; TCUPEOP: TEST TVMODE,=01 ; Is this Televideo mode ? JZ CUPEOP JMP TCURCOL ; Yes, interpret column pos ; ; ; Clear unprotected to end of page. ; CUPEOP: PUSH DX ; save current row/col __1: CALL CUPEOL ; clear current row to end of line XOR DH,DH ; force first column INC DL ; select next row CMP DL,=NMBROWS ; test against max rows JB __1 ; if still on screen POP DX ; restore row/col RET ; and done ; ; DELCHAR: RET ; ; INSCHAR: RET ; ; ; +----------------------+ ; | STATUS LINE ROUTINES | ; +----------------------+ ; ; Initialize the status line. ; SLINIT: MOV DX,=2*NMBROWS+1 ; Fudge position to line 26 CALL CUPEOL ; Clear line RET ; all done ; ; ; +----------------------------------+ ; | SCREEN DRIVER COMMON SUBROUTINES | ; +----------------------------------+ ; ; Point cursor at current DX specified row/column. ; PNTCHAR: CALL SCRADDR ; calc screen address MOV CSRLOW,AL MOV CSRHI,AH ; load command variables MOV BX,&CSRCMD JMP GDCOUT ; send command and exit ; ; Point cursor at current DX specified attribute field. ; PNTATTR: CALL SCRADDR ; calc screen address ADD AX,=ATTROFF MOV CSRLOW,AL MOV CSRHI,AH MOV BX,&CSRCMD JMP GDCOUT ; ; Return the current attribute byte. ; RETATTR: CALL PNTATTR ; point to attribute memory CALL GDCFE ; wait for fifo to empty MOV BX,&RDATCMD ; load read command addr CALL GDCOUT ; and issue it JMP GDCIN ; read returned value and exit ; ; Calc physical screen address from row/column. ; On entry: DL=row, DH=column. ; On exit: AX=screen address. ; SCRADDR: MOV CL,DL ; mov current row to reg ADD CL,TOPROW ; add in the top row base CMP CL,=NMBROWS ; check for max row wrap JB __C1 ; if no wrap, continue SUB CL,=NMBROWS ; wrap screen memory __C1: MOV AL,=NMBCOLS ; get constant MUL CL ; calc beginning row addr MOV CL,DH ; get current column XOR CH,CH ; make double length ADD AX,CX ; calc distance into row RET ; all done ; ; ; PRAM output subroutine. This routine calculates the PRAM values ; based on the current top row (TOPROW) and number of user rows (NMBROW). ; PRAMOUT: MOV AL,TOPROW ; get current top row MOV CL,=NMBCOLS ; get number of columns MUL CL ; calc starting address MOV PRAM1,AL MOV PRAM2,AH ; set start addr, ptn 1 MOV AL,=NMBROWS ; get max row number SUB AL,TOPROW ; calc rows to ent of ptn MOV CL,=19 MUL CL ; times line size MOV CL,=4 SHL AX,CL ; adjust field MOV PRAM3,AL MOV PRAM4,AH ; set length, ptn 1 XOR AX,AX MOV PRAM5,AL MOV PRAM6,AH ; set start addr, ptn 2 MOV AL,TOPROW ; get rows to end of ptn MOV CL,=19 MUL CL ; times line size MOV CL,=4 SHL AX,CL ; adjust field MOV PRAM7,AL MOV PRAM8,AH ; set length, ptn 2 CALL GDCFE ; wait for fifo empty MOV BX,&PRAMCMD ; get parameter ram command CALL GDCOUT ; send to device JMP GDCFE ; wait fifo empty and exit ; ; ; GDC command output subroutine. ; On entry: [BX]=length of command, [BX]+1=Commands/Parameters word list. ; GDCOUT: PUSHF ; save flags CLI ; and disable interrupts PUSH DX ; save regs MOV AH,[BX] ; load command length INC BX ; bump pointer XOR DH,DH ; clear reg __LOOP: TEST AH,AH ; any bytes left? JZ __X ; if not, exit loop ; __C1: IN AL,CRT_STAT ; read GDC status TEST AL,=FF ; fifo full? JNZ __C1 ; if so, wait MOV DL,1[BX] ; load port (command or parm) MOV AL,0[BX] ; load value OUT DX,AL ; and send it INC BX INC BX DEC AH ; count words down JMPS __LOOP ; and continue loop ; __X: POP DX POPF ; restore interrupt status RET ; else, exit ; ; ; Wait for GDC fifo empty out. ; GDCFE: IN AL,CRT_STAT ; read GDC status TEST AL,=FE ; fifo empty? JZ GDCFE ; if so, continue loop RET ; else, exit ; ; ; Read a GDC returned parameter. ; GDCIN: IN AL,CRT_STAT ; read status TEST AL,=DR ; data ready? JZ GDCIN ; if not, loop IN AL,CRT_PARM ; read the data RET ; and return it ; END