VTEmulator#
General Information
Author: Charles Green
Language: ACTION!
Compiler/Interpreter: ACTION!
Published: usenet
Well, I've gotten enough responses that I'd annoy my UUCP neighbor by mailing this file out that many times, so I guess it'll be better to post it.
A couple of things I never got around to doing:
- Adding a character count to the data in each line, maybe in the byte just before the 320-byte area where the characters for each line are "stenciled" in for display. This count could be used to speed up the insert-character and clear-to-end-of-line operations; they'd no longer have to go all the way out to column 80 if there was no data displayed out that far.
- Adding a single graphics-0 display line, either at the top or bottom of the screen, which could hold the current baud rate, parity, etc. (assuming that someone adds the code to change them, in addition to maybe brightness). (P.S. - I've since discovered that luminance values of 0 for brightness, 2 or 4 for cursor, and 6 for the characters works better than the values in this program. You also probably want to put the contrast at a minimum.)
- Smooth scrolling.
Enjoy, Charles Green char...@c3.COM
;'''''''''''''''''''''''''''''''''''' ; "TVI925.ACT" - A display-list based ; terminal emulator by Charles Green. ; ; Derived from the public domain VT52+ ; emulator written by Michael Jenkin. ;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, MODULE ;A: handler, originally by Jenkin. DEFINE LDY = "$A0", RTS = "$60", JMP = "$4C", PLA="$68", GR8 = "$0F", SKIP8 = "$70", JVP = "$41", LMS = "$40", RTI="$40", ESC = "1", CUP = "2", SGR = "3", PHA= "$48", TAX= "$AA", TXA= "$8A", TAY="$A8",TYA="$98", CMO = "4", XITVBV = "$E462" TYPE line = [BYTE mode CARD adrs] BYTE ARRAY display(8831) ;data+dlist BYTE ARRAY enhance(8), cursor(4) line POINTER dlist BYTE POINTER curln ;current line data BYTE pmbase = $D407, gractl=$D01D, lmargin = $52, rmargin = $53, rowcrs = $54, colcrs = $55, brkcnt, gprior = $26F, pcolr0 = $2C0, audc1 =$D201, hposm0 = $D004, sdmctl = $22F, soundr = $41, saudc1, ; audf1 = $D200, ; sskctl = $232, skctl = $D20F, state, need, needx, ins_mode, curcnt CARD ; savmsc = $58, sdlist = $230,cursad,keydef = $79, vvblkd = $224, brkky = $236 BYTE ARRAY xlate = [ ; New kbd map $6C $6A $3B $80 $80 $6B $2B $2A $6F $80 $70 $75 $0D $69 $2D $3D $76 $FF $63 $80 $80 $62 $78 $7A $34 $80 $33 $36 $1B $35 $32 $31 $2C $20 $2E $6E $80 $6D $2F $7E $72 $80 $65 $79 $09 $74 $77 $71 $39 $80 $30 $37 $08 $38 $3C $3E $66 $68 $64 $80 $82 $67 $73 $61 ;lowr $4C $4A $3A $80 $80 $4B $5C $5E $4F $80 $50 $55 $0D $49 $5F $7C $56 $FF $43 $80 $80 $42 $58 $5A $24 $80 $23 $26 $1B $25 $22 $21 $5B $20 $5D $4E $80 $4D $3F $60 $52 $80 $45 $59 $FE $54 $57 $51 $28 $80 $29 $27 $7F $40 $7B $7D $46 $48 $44 $80 $82 $47 $53 $41 ;uper $0C $0A $F0 $80 $80 $0B $1C $1E $F0 $80 $10 $15 $0A $09 $1F $F0 $16 $FF $03 $80 $80 $02 $18 $1A $F0 $80 $F0 $F0 $1B $F0 $F0 $F0 $1B $00 $1D $0E $80 $0D $7F $F0 $12 $80 $05 $19 $FD $14 $17 $11 $F0 $80 $F0 $F0 $7F $00 $F0 $F0 $06 $08 $04 $80 $82 $07 $13 $01 ;ctrl ] PROC vbi() IF curcnt = 0 THEN pcolr0 ==! 5 ;invert cursor curcnt = 15 ELSEIF curcnt < 255 THEN curcnt ==- 1 FI IF saudc1 > $E0 THEN saudc1 ==- 1 audc1 = saudc1 ; SOUND(2,100,14,bel) FI IF brkcnt THEN brkcnt ==- 1 IF brkcnt = 0 THEN ; sskctl ==& $7F ;remove force space ; skctl = sskctl skctl = $73 FI FI [JMP XITVBV] PROC brk() ;break interrupt handler ; [TYA PHA TXA PHA] brkcnt = 15; ; sskctl ==% $80 ;force serial space ; skctl = sskctl skctl = $F3 ; [PLA TAX PLA TAY] [PLA RTI] PROC del_ch(BYTE POINTER adr, BYTE col) BYTE POINTER badr,wadr BYTE x, y, bcount bcount = (80-col) RSH 1 FOR y = 1 TO 7 DO adr ==+ 40 wadr = adr + (col RSH 1) - 1 badr = wadr + 1 IF col & 1 THEN badr ==+ 1 wadr ==+ 1 wadr^ =(wadr^ & $F0)%(badr^ RSH 4) FI x = bcount WHILE x > 0 DO badr ==+ 1 wadr ==+ 1 wadr^ =(wadr^ LSH 4)%(badr^ RSH 4) x ==- 1 OD wadr^ ==& $F0 OD RETURN ; null proc for now PROC ins_ch(BYTE POINTER adr, BYTE col) BYTE POINTER badr,wadr BYTE x, y, bcount bcount = (79-col) RSH 1 FOR y = 1 TO 7 DO adr ==+ 40 badr = adr + 39 wadr = badr - 1 x = bcount WHILE x > 0 DO badr^ =(wadr^ LSH 4)%(badr^ RSH 4) x ==- 1 badr ==- 1 wadr ==- 1 OD IF col & 1 THEN badr^ ==& $F0 ELSE badr^ ==RSH 4 FI OD RETURN ; null proc for now PROC Achr(BYTE cx, cy, cc) BYTE POINTER base, offset BYTE i, chr, c BYTE ARRAY chset = [ $00 $00 $00 $00 $00 $00 $00 ; SP $44 $44 $44 $00 $44 $00 $00 $AA $AA $00 $00 $00 $00 $00 $AA $EE $AA $EE $AA $00 $00 $EE $CC $EE $66 $EE $00 $00 $AA $22 $44 $88 $AA $00 $00 $CC $44 $CC $EE $EE $00 $00 $66 $22 $44 $00 $00 $00 $00 $22 $44 $44 $44 $22 $00 $00 $88 $44 $44 $44 $88 $00 $00 $00 $AA $EE $AA $00 $00 $00 $00 $44 $EE $44 $00 $00 $00 $00 $00 $00 $66 $22 $44 $00 $00 $00 $EE $00 $00 $00 $00 $00 $00 $00 $66 $66 $00 $00 $22 $22 $44 $44 $88 $88 $00 $44 $AA $AA $AA $44 $00 $00 ;'0' $44 $CC $44 $44 $EE $00 $00 $CC $22 $44 $88 $EE $00 $00 $CC $22 $44 $22 $CC $00 $00 $AA $AA $EE $22 $22 $00 $00 $EE $88 $CC $22 $CC $00 $00 $44 $88 $EE $AA $44 $00 $00 $EE $22 $44 $88 $88 $00 $00 $44 $AA $44 $AA $44 $00 $00 $44 $AA $66 $22 $44 $00 $00 $66 $66 $00 $66 $66 $00 $00 $66 $66 $00 $66 $22 $44 $00 $22 $44 $88 $44 $22 $00 $00 $00 $EE $00 $EE $00 $00 $00 $88 $44 $22 $44 $88 $00 $00 $CC $22 $44 $00 $44 $00 $00 $44 $AA $AA $88 $66 $00 $00 ;'@' $44 $AA $EE $AA $AA $00 $00 $CC $AA $CC $AA $CC $00 $00 $66 $88 $88 $88 $66 $00 $00 $CC $AA $AA $AA $CC $00 $00 $EE $88 $CC $88 $EE $00 $00 $EE $88 $CC $88 $88 $00 $00 $66 $88 $AA $AA $66 $00 $00 $AA $AA $EE $AA $AA $00 $00 $EE $44 $44 $44 $EE $00 $00 $66 $22 $22 $AA $EE $00 $00 $AA $CC $88 $CC $AA $00 $00 $88 $88 $88 $88 $EE $00 $00 $AA $EE $EE $AA $AA $00 $00 $CC $AA $AA $AA $AA $00 $00 $66 $AA $AA $AA $CC $00 $00 $CC $AA $CC $88 $88 $00 $00 ;'P' $66 $AA $AA $AA $EE $22 $00 $CC $AA $CC $CC $AA $00 $00 $66 $88 $CC $22 $EE $00 $00 $EE $44 $44 $44 $44 $00 $00 $AA $AA $AA $AA $66 $00 $00 $AA $AA $AA $44 $44 $00 $00 $AA $AA $EE $EE $AA $00 $00 $AA $AA $44 $AA $AA $00 $00 $AA $AA $44 $44 $44 $00 $00 $EE $22 $44 $88 $EE $00 $00 $66 $44 $44 $44 $66 $00 $00 $88 $88 $44 $44 $22 $22 $00 $CC $44 $44 $44 $CC $00 $00 $44 $AA $00 $00 $00 $00 $00 $00 $00 $00 $00 $EE $00 $00 $66 $44 $22 $00 $00 $00 $00 $00 $CC $66 $AA $66 $00 $00 ;'a' $88 $CC $AA $AA $CC $00 $00 $00 $66 $88 $88 $66 $00 $00 $22 $66 $AA $AA $66 $00 $00 $00 $EE $EE $88 $66 $00 $00 $22 $44 $EE $44 $44 $00 $00 $00 $66 $AA $AA $66 $22 $CC $88 $EE $AA $AA $AA $00 $00 $44 $00 $CC $44 $EE $00 $00 $44 $00 $CC $44 $44 $88 $00 $88 $88 $AA $CC $AA $00 $00 $CC $44 $44 $44 $EE $00 $00 $00 $CC $EE $EE $AA $00 $00 $00 $CC $AA $AA $AA $00 $00 $00 $66 $AA $AA $CC $00 $00 $00 $CC $AA $AA $CC $88 $88 ;'p' $00 $66 $AA $AA $66 $22 $22 $00 $EE $88 $88 $88 $00 $00 $00 $CC $EE $22 $CC $00 $00 $44 $EE $44 $44 $44 $00 $00 $00 $AA $AA $AA $66 $00 $00 $00 $AA $AA $44 $44 $00 $00 $00 $AA $EE $EE $66 $00 $00 $00 $AA $44 $AA $AA $00 $00 $00 $AA $AA $AA $66 $22 $CC $00 $EE $44 $88 $EE $00 $00 $66 $44 $88 $44 $66 $00 $00 $44 $44 $44 $44 $44 $00 $00 $CC $44 $22 $44 $CC $00 $00 $CC $66 $00 $00 $00 $00 $00 $AA $44 $AA $44 $AA $44 $AA ] ;strip high bit (inverse video) offset = cc - $20 ;display character dlist=sdlist + cy * 10 + 3 base = dlist.adrs + (cx RSH 1) + 40 IF ins_mode THEN ins_ch(dlist.adrs, cx) FI offset = chset+(offset LSH 3)-offset FOR i = 1 TO 7 DO c = offset^ c = c XOR enhance(i) chr = base^ IF (cx & 1) THEN c ==& $0F chr ==& $F0 ELSE c ==& $F0 chr ==& $0F FI base^ = chr % c base ==+ 40 offset ==+1 OD RETURN PROC Acurse(); move cursor BYTE old_y ;Where we left cursor Zero(cursad+(old_y LSH 2), 4) hposm0 = (colcrs LSH 1) + 48 MoveBlock(cursad+(rowcrs LSH 2),cursor,4) old_y = rowcrs ;memory for later clr pcolr0=5 IF curcnt < 255 THEN curcnt=254 FI RETURN PROC scroll(BYTE first, last) line POINTER tdlist CARD tempadrs INT delta BYTE i dlist=sdlist+3 + first*10 tempadrs=dlist.adrs Zero(tempadrs,320) IF first>last THEN i=first first=last last=i delta=-1 ELSE delta=1 FI FOR i=first+1 TO last DO tdlist = dlist+10 *delta dlist.adrs = tdlist.adrs dlist = tdlist OD dlist.adrs = tempadrs RETURN PROC Amargin() ; keep between margins IF colcrs > rmargin THEN colcrs = lmargin rowcrs ==+ 1 FI ;fallthrough to Ascroll() PROC Ascroll() ; roll screen if req'd IF rowcrs > 23 THEN scroll(0,23) rowcrs = 23 FI RETURN PROC curpos(BYTE chr) IF need = 2 THEN ; 1st ESC Y needx = chr - $20 need ==- 1 ELSEIF need = 1 THEN ; 2nd ESC Y chr ==- $20 IF (needx <= 23) AND (chr <= rmargin) THEN colcrs = chr rowcrs = needx ; Acurse() FI state = 0 FI RETURN PROC cursat(BYTE chr) ;cursor type IF chr = '2 THEN ;blinking block? curcnt = 254 SetBlock(cursor,4,3) ELSEIF chr = '4 THEN ;steady line? curcnt = 255 SetBlock(cursor,3,0) cursor(3) = 3 FI pcolr0=5 ;third-intensity cursor state=0 RETURN PROC attrib(BYTE chr) ; enhance IF chr = '0 THEN Zero(enhance, 8) ELSEIF chr = '4 THEN ; reverse SetBlock(enhance, 8, $FF) ELSEIF chr = '8 THEN ; underline Zero(enhance, 8) enhance(6) = $FF ELSEIF chr = '> THEN ; both modes SetBlock(enhance, 8, $FF) enhance(6) = $00 FI state = 0 RETURN PROC Aesc(BYTE chr) ; escape sequence BYTE ch CARD i IF chr = 'E THEN ; insert line dlist=sdlist+3+rowcrs*10 scroll(23,rowcrs) ELSEIF chr = '. THEN ; cursor attrib state = CMO ; cursor rendition RETURN ELSEIF chr = 'G THEN ; inverse off state = SGR ; select rendition RETURN ELSEIF chr = 'I THEN ; back tab colcrs = (colcrs - 1) & $F8 ELSEIF chr = 'j THEN ; reverse lf IF rowcrs > 0 THEN rowcrs ==- 1 ELSE scroll(23,0) FI ; Acurse() ELSEIF chr = '* THEN ; home & clear rowcrs = 0 colcrs = 0 Aesc('Y) ; erase to EOS ( y?? ) ELSEIF chr = 'Y OR chr = 'y THEN FOR ch = colcrs TO 79 DO Achr(ch,rowcrs,' ) OD IF rowcrs < 23 THEN dlist=sdlist+3+10*rowcrs FOR i = rowcrs+1 TO 23 DO dlist==+ 10 Zero(dlist.adrs,320) OD FI ; Acurse() ; erase to EOL ELSEIF chr = 'T OR chr = 't THEN FOR ch = colcrs TO 79 DO Achr(ch,rowcrs,' ) OD ; Acurse() ELSEIF chr = 'R THEN ; delete line dlist=sdlist+3+10*rowcrs scroll(rowcrs,23) ELSEIF chr = '= THEN ; cursor addr state = CUP need = 2 RETURN ELSEIF chr = 'Q THEN ; insert char dlist=sdlist+3+10*rowcrs ins_ch(dlist.adrs,colcrs) ELSEIF chr = 'W THEN ; delete char dlist=sdlist+3+10*rowcrs del_ch(dlist.adrs,colcrs) ELSEIF chr = 'Z THEN ; multi-insert ins_mode = 1; ELSEIF chr = 'r THEN ; end multi-ins ins_mode = 0; ELSEIF chr = 'b THEN ; BlackOnWhite SetColor(2,0,15) SetColor(1,0,0) ELSEIF chr = 'd THEN ; WhiteOnBlack SetColor(2,0,0) SetColor(1,0,15) FI state = 0 RETURN PROC Aopen() BYTE i sdmctl=0 ;No Antic DMA till DL ready vvblkd=vbi ;Put our vbi routine in brkky=brk ;Put our break routine in ; Examine data array for alignment sdlist=(display & $F000) + $1C80 pmbase=sdlist RSH 8 ;page of plr/mis cursad=sdlist+$100 dlist=sdlist FOR i = 0 TO 2 DO dlist.mode = SKIP8 dlist==+1 OD curln=display FOR i=0 TO 23 DO IF (curln = sdlist) THEN curln==+ $180 FI IF (curln & $FFF) > $EC0 THEN curln = (curln & $F000) + $1000 FI dlist.mode = GR8 + LMS dlist.adrs = curln SetBlock(dlist+3,7,GR8) curln==+ 320 dlist ==+ 10 OD dlist.mode = JVP dlist.adrs = sdlist SetColor(2,0,0) ; was 0,0,0 SetColor(1,0,15) ; was 1,12,15 SetColor(4,0,2) ; new - border gprior=8 ;cursor behind letters gractl=1 ;turn missiles on sdmctl=$26 ;enable missile DMA Zero(cursad,128) ;clear missile data cursad ==+ 16 ;true top of screen state = 0 lmargin = 0 rmargin = 79 rowcrs = 0 colcrs = 0 Acurse() attrib('0) ;normal video cursat('4) ;normal cursor [LDY 1 RTS] PROC Aclose() [LDY 1 RTS] PROC Aput(BYTE areg) IF state = ESC THEN; escape sequence Aesc(areg) ELSEIF state = CUP THEN ; cursor pos curpos(areg) ELSEIF state = CMO THEN ; curs enhnc cursat(areg) ELSEIF state = SGR THEN ; enhance attrib(areg) ELSEIF areg = $1B THEN ; ESC state = ESC ELSEIF areg = $1A THEN ; ClearScreen colcrs = 0 rowcrs = 0 Aesc('Y) ELSEIF areg = $1E THEN ; home colcrs = 0 rowcrs = 0 ; Acurse() ELSEIF areg = $0B THEN ; cursor up IF rowcrs > 0 THEN rowcrs ==- 1 ; Acurse() FI ELSEIF areg = $16 THEN ; cursor down IF rowcrs < 23 THEN rowcrs ==+ 1 ; Acurse() FI ELSEIF areg = $0C THEN ; cursor right IF colcrs < rmargin THEN colcrs ==+ 1 ; Acurse() FI ELSEIF areg = $0D THEN ; CR colcrs = lmargin ; was = 0 ELSEIF areg = $0A THEN ; lf rowcrs ==+ 1 IF colcrs > rmargin THEN colcrs = 0 ;altos vi kludge FI Ascroll() ELSEIF areg = $08 THEN ; BS IF colcrs > lmargin THEN ;was >0 colcrs ==- 1 ELSEIF rowcrs > 0 THEN ;bs wraps colcrs = rmargin rowcrs==- 1 FI ELSEIF areg = $07 THEN ; bell saudc1 = $F0 ; bel = 16 ; vbi() will pickup ELSEIF areg = $09 THEN ; TAB colcrs = (colcrs + 8) & $F8 Amargin() ELSEIF areg > $1F THEN ;printable Amargin() ;new here Achr(colcrs,rowcrs,areg) colcrs ==+ 1 ;ELSE unrecognized control-nothing FI Acurse() ;update cursor [LDY 1 RTS] PROC Anofunc() [RTS] PROC Adummy() [LDY 1 RTS] PROC Ahandler() BYTE ARRAY hatabs = $031A BYTE pos, found ;do not change the following 3 lines CARD ARRAY atab(6) BYTE Jump = [JMP] CARD init ; define device entry points atab(0) = Aopen - 1 ;OPEN atab(1) = Aclose - 1 ;CLOSE atab(2) = Anofunc - 1 ;READ atab(3) = Aput - 1 ;WRITE atab(4) = Adummy - 1 ;STATUS atab(5) = Anofunc - 1 ;SPECIAL init = Adummy ;INIT ; find entry in hatabs found = 0; pos = 0 WHILE (pos < 34) AND (found = 0) DO IF hatabs(pos) = 0 THEN found = 1 ELSE pos ==+ 3 FI OD IF found = 0 THEN PrintE("*** A: too many devices") ELSE hatabs(pos) = 'A hatabs(pos + 1) = atab & 255 hatabs(pos + 2) = atab RSH 8 FI RETURN ;******************************* ;* MAIN PROGRAM ;******************************* MODULE BYTE ch = $02FC, bcount = $02EB, speed = [3], ;CWG 1=300BPS 3=1200 wsize = [0], sbits = [0], lf = [0], iparity = [0], oparity = [0] PROC init_R(); set options for R: Close(3) Open(3,"R:",13,0) XIO(3,0,38,lf*64+32+iparity*4+oparity,0,"R1:") ;32=no xlate XIO(3,0,36,speed+7+wsize*16+128*sbits,0,"R1:") XIO(3,0,34,192,0,"R1:") XIO(3,0,40,0,0,"R1:") ;concurrent IO bcount = 0 RETURN PROC init_A(); set up A: device Ahandler() ; install A: handler Close(2) ; Graphics(8+16) Open(2,"A:",8,0) RETURN PROC intro() soundr=0 Close(7) Open(7,"K:",4,0) keydef = xlate ; load key translate init_R() init_A() soundr=0 RETURN PROC do_remote(); process remote BYTE chr BYTE stop = [0] BYTE HIWAT = [128] XIO(3,0,13,0,0,"R:") IF bcount > HIWAT THEN PutD(3,$13) ;XOFF stop=1 FI WHILE bcount > 0 DO chr = GetD(3) PutD(2,chr & $7F) bcount ==- 1 OD IF stop THEN PutD(3,$11) ;XON stop=0 FI RETURN PROC do_local(); process local BYTE chr IF $FF - ch THEN ;INPUT chr = GetD(7) PutD(3,chr) FI ; END IF CHAR RETURN PROC main() intro() DO do_remote() do_local() OD RETURN