VT52 Emulator #
The following is a very primitive vt52 emulator for the 800. This actually is a vt52 with insert/delete line added, with auto-wrap, and tabs. It is written in Action! with lower case enabled.
To use this, you will need an rs232 device (I have only tested this at 300 buad using an 850 interface and 830 modem, but it seems to work well). The rs232 parameters are hard coded, so you will probably have to change the values of baud, parity, etc. Consult your 850 or R-verter manual. The values that may require change are the following..
speed = ~[1], wsize = ~[0], sbits = ~[0], lf = ~[0], iparity = ~[0], oparity = ~[0]
This works by defining an output device A: which works in graphics mode 8, which writes characters in 4 bits. I have used this emulator with vi, rogue, jove, etc., under UNIX using the vt52 termcap entry, and also (with some slight modification to allow generation of ENTER, pf, and cursor keys) under CMS. If anyone wants this version, I can mail the diff's.
The following characters are defined in addition to those found on the keyboard.
ctrl clear - {
ctrl insert - }
ctrl delete - ~
;*********************************
;* *
;* VT52A.ACT - a VT52+ emulator *
;* written in ACTION(tm) by *
;* *
;* Michael R. M. Jenkin *
;* University of Toronto *
;* ...!utcsri!utai!jenkin *
;* copyright(c) 1985 *
;* *
;* released into the public *
;* domain May, 1986. No part of *
;* this program may be *
;* redistributed for profit *
;* without permission of the *
;* author. *
;* *
;*********************************
MODULE
;A: handler, by Michael Jenkin
DEFINE LDY = "$A0",
RTS = "$60",
JMP = "$4C"
BYTE lmargin = $52, rmargin = $53,
rowcrs = $54, oldrow = $5A,
colcrs = $55,
oldchr = $5D, inesc, need,
needx, inv
CARD savmsc = $58,
oldcol = $5B
PROC Achr(BYTE cx, cy, cc)
BYTE POINTER base, offset
BYTE i, char, c
BYTE ARRAY chset = ~[
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 6 6 6 6 0 6 0
0 10 10 10 0 0 0 0
10 14 10 14 10 0 0 0
4 14 8 14 2 14 4 0
0 10 2 6 12 8 10 0
0 14 2 6 6 2 14 0
0 6 6 6 0 0 0 0
0 6 12 8 8 12 6 0
0 12 6 2 2 6 12 0
0 10 4 14 4 10 0 0
0 4 4 14 4 4 0 0
0 0 0 0 0 6 6 12
0 0 0 14 0 0 0 0
0 0 0 0 0 6 6 0
0 2 2 4 4 8 8 0
0 14 10 10 10 10 14 0
0 4 12 4 4 4 14 0
0 14 2 2 14 8 14 0
0 14 2 14 2 2 14 0
0 10 10 10 14 2 2 0
0 14 8 14 2 2 14 0
0 14 8 14 10 10 14 0
0 14 2 6 4 4 4 0
0 14 10 14 10 10 14 0
0 14 10 14 2 2 2 0
0 0 6 6 0 6 6 0
0 0 6 6 0 6 6 12
0 2 6 12 12 6 2 0
0 0 14 0 0 14 0 0
0 8 12 6 6 12 8 0
0 4 10 2 4 0 4 0
14 10 10 14 8 8 14 0
0 4 14 10 10 14 10 0
0 12 10 12 10 10 12 0
0 14 10 8 8 10 14 0
0 12 10 10 10 10 12 0
0 14 8 12 8 8 14 0
0 14 8 12 8 8 8 0
0 14 8 8 10 10 14 0
0 10 10 14 10 10 10 0
0 14 4 4 4 4 14 0
0 2 2 2 2 10 14 0
0 10 10 12 12 10 10 0
0 8 8 8 8 8 14 0
0 10 14 14 10 10 10 0
0 12 10 10 10 10 10 0
0 14 10 10 10 10 14 0
0 14 10 14 8 8 8 0
0 14 10 10 10 10 14 2
0 14 10 14 12 10 10 0
0 14 8 14 2 2 14 0
128 14 4 4 4 4 4 0
0 10 10 10 10 10 14 0
0 10 10 10 10 10 4 0
0 10 10 10 14 14 10 0
0 10 10 4 4 10 10 0
0 10 10 4 4 4 4 0
0 14 2 4 4 8 14 0
0 14 8 8 8 8 14 0
0 8 8 4 4 2 2 0
0 14 2 2 2 2 14 0
0 4 4 10 0 0 0 0
0 0 0 0 0 0 15 0
0 4 6 2 0 0 0 0
0 0 14 2 14 10 14 0
0 8 8 14 10 10 14 0
0 0 0 14 8 8 14 0
0 2 2 14 10 10 14 0
0 0 14 10 14 8 14 0
0 0 14 8 12 8 8 0
0 0 14 10 10 14 2 14
0 8 8 14 10 10 10 0
0 6 0 6 6 6 6 0
0 6 0 6 6 6 6 12
0 8 8 10 14 10 10 0
0 12 4 4 4 4 14 0
0 0 10 14 14 10 10 0
0 0 12 10 10 10 10 0
0 0 14 10 10 10 14 0
0 0 14 10 10 14 8 8
0 0 14 10 10 14 2 2
0 0 14 10 8 8 8 0
0 0 14 8 14 2 14 0
0 4 14 4 4 4 4 0
0 0 10 10 10 10 14 0
0 0 10 10 10 10 4 0
0 0 10 10 14 14 10 0
0 0 10 14 4 14 10 0
0 0 10 10 10 14 2 14
0 0 14 2 4 8 14 0
2 4 4 8 4 4 2 0
6 6 6 0 0 6 6 6
8 4 4 2 4 4 8 0
0 10 5 0 0 0 0 0
0 0 0 0 0 0 0 0
]
;strip high bit (inverse video)
cc ==& $7F
;display character
base = (cx RSH 1) + cy * 320 + savmsc
offset = cc
offset = offset LSH 3
offset ==+ chset
FOR i = 0 TO 7
DO
c = offset^
IF inv = 1 THEN
c = c XOR $FF ; c = NOT c
FI
char = base^
IF (cx & 1) THEN
c ==& $0F
char ==& $F0
ELSE
c = c LSH 4
char ==& $0F
FI
base^ = char % c
base ==+ 40
offset ==+1
OD
RETURN
PROC Acurse(BYTE cx, cy); invert char
BYTE POINTER base
BYTE i, char
base = (cx RSH 1) + 320 * cy + savmsc
FOR i = 0 TO 7
DO
char = base^
IF (cx & 1) THEN
char = char XOR $0F
ELSE
char = char XOR $F0
FI
base^ = char
base ==+ 40
OD
RETURN
PROC Ascroll() ; update cursor
IF colcrs > rmargin THEN
colcrs = lmargin
rowcrs ==+ 1
FI
IF rowcrs > 23 THEN
MoveBlock(savmsc,savmsc+320,320*23)
Zero(savmsc+23*320,320)
rowcrs = 23
FI
Acurse(colcrs,rowcrs)
RETURN
PROC Aesc(BYTE char) ; escape sequence
BYTE ch
BYTE POINTER addr
CARD i
IF need = 2 THEN ; 1st ESC Y
needx = char - $20
need ==- 1
ELSEIF need = 1 THEN ; 2nd ESC Y
char ==- $20
IF (needx <= 23) AND (char <= rmargin) THEN
Acurse(colcrs,rowcrs)
colcrs = char
rowcrs = needx
Acurse(colcrs,rowcrs)
FI
need = 0
ELSEIF char = 'A THEN ; cursor up
IF rowcrs > 0 THEN
Acurse(colcrs,rowcrs)
rowcrs ==- 1
Acurse(colcrs,rowcrs)
FI
ELSEIF char = 'B THEN ; cursor down
IF rowcrs < 23 THEN
Acurse(colcrs,rowcrs)
rowcrs ==+ 1
Acurse(colcrs,rowcrs)
FI
ELSEIF char = 'C THEN ; cursor right
IF colcrs < rmargin THEN
Acurse(colcrs,rowcrs)
colcrs ==+ 1
Acurse(colcrs,rowcrs)
FI
ELSEIF char = 'D THEN ; cursor left
IF colcrs > 0 THEN
Acurse(colcrs,rowcrs)
colcrs ==- 1
Acurse(colcrs,rowcrs)
FI
ELSEIF char = 'F THEN ; inverse on
inv = 1
ELSEIF char = 'G THEN ; inverse off
inv = 0
ELSEIF char = 'H THEN ; home
Acurse(colcrs,rowcrs)
colcrs = 0
rowcrs = 0
Acurse(colcrs,rowcrs)
ELSEIF char = 'I THEN ; reverse lf
Acurse(colcrs,rowcrs)
IF rowcrs > 0 THEN
rowcrs ==- 1
Acurse(colcrs,rowcrs)
ELSE
FOR i = 0 TO 22 DO
addr = savmsc+320*(23-i)
MoveBlock(addr,addr-320,320)
OD
Zero(savmsc,320)
Acurse(colcrs,rowcrs)
FI
ELSEIF char = 'J THEN ; erase to EOS
FOR ch = colcrs TO 79
DO
Achr(ch,rowcrs,' )
OD
IF rowcrs < 23 THEN
Zero(savmsc+320*(rowcrs+1),320*(23-rowcrs))
FI
Acurse(colcrs,rowcrs)
ELSEIF char = 'K THEN ; erase to EOL
FOR ch = colcrs TO 79
DO
Achr(ch,rowcrs,' )
OD
Acurse(colcrs,rowcrs)
ELSEIF char = 'L THEN ; insert line
Acurse(colcrs,rowcrs)
FOR i = rowcrs TO 22 DO
addr = savmsc+320*(23-i+rowcrs)
MoveBlock(addr,addr-320,320)
OD
Zero(savmsc+320*rowcrs,320)
colcrs = 0
Acurse(colcrs,rowcrs)
ELSEIF char = 'M THEN ; delete line
IF rowcrs < 23 THEN
MoveBlock(savmsc+320*rowcrs,savmsc+320*(rowcrs+1),320*(23-rowcrs))
FI
Zero(savmsc+320*22,320)
colcrs = 0
Acurse(colcrs,rowcrs)
ELSEIF char = 'Y THEN ; cursor addr
need = 2
FI
IF need = 0 THEN
inesc = 0
FI
RETURN
PROC Aopen()
SetColor(0,0,0)
SetColor(1,12,15)
inesc = 0
inv = 0
need = 0
lmargin = 0
rmargin = 79
rowcrs = 0
colcrs = 0
Acurse(colcrs,rowcrs)
~[LDY 1 RTS]
PROC Aclose()
~[LDY 1 RTS]
PROC Aput(BYTE areg)
BYTE i, n
IF inesc = 1 THEN; escape sequence
Aesc(areg)
ELSEIF areg = $1B THEN ; ESC
inesc = 1
ELSEIF areg = $9B THEN ; EOL
Acurse(colcrs,rowcrs)
colcrs = 0
Ascroll()
ELSEIF areg = $0A THEN ; lf
Acurse(colcrs,rowcrs)
rowcrs ==+ 1
Ascroll()
ELSEIF areg = $08 THEN ; BS
IF colcrs > 0 THEN
Acurse(colcrs,rowcrs)
colcrs ==- 1
Ascroll()
FI
ELSEIF areg = $07 THEN ; bell
; do nothing
ELSEIF areg = $09 THEN ; TAB
Acurse(colcrs,rowcrs)
colcrs = (colcrs + 8) & $F8
Ascroll()
ELSE
Achr(colcrs,rowcrs,areg)
colcrs ==+ 1
Ascroll()
FI
~[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 Jmp = ~[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 = ~[1],
wsize = ~[0],
sbits = ~[0],
lf = ~[0],
iparity = ~[0],
oparity = ~[0]
; iocb 3 definitions
BYTE iocb3cmd=$372 ; cmd byte
CARD iocb3buf=$374,; buffer address
iocb3len=$378 ; buffer length
DEFINE BUFLEN = "1024"
BYTE ARRAY BUFFER(BUFLEN)
PROC CIO=$E456(BYTE areg, xreg)
PROC init_R(); set options for R:
Close(3)
Open(3,"R:",13,0)
XIO(3,0,38,lf*64+oparity+4*iparity,0,"R1:")
XIO(3,0,36,speed+7+wsize*16+128*sbits,0,"R1:")
XIO(3,0,34,192,0,"R1:")
iocb3cmd=40 ; start concurrent I/O
iocb3buf=BUFFER
iocb3len=BUFLEN
CIO(0,$30) ; *** call CIO ***
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()
Close(7)
Open(7,"K:",4,0)
init_R()
init_A()
RETURN
BYTE FUNC remote(); remote char?
XIO(3,0,13,0,0,"R:")
IF bcount = 0 THEN
RETURN(0)
FI
RETURN(1)
PROC do_remote(); process remote
BYTE char
char = GetD(3)
PutD(2,char)
RETURN
BYTE FUNC local() ; local char?
RETURN($FF - ch)
PROC do_local(); process local
BYTE char
char = GetD(7)
IF char = 127 THEN ;tab
char = 9
ELSEIF char = 125 THEN ;left curl
char = 123
ELSEIF char = 255 THEN ;right curl
char = 125
ELSEIF char = 96 THEN ;tilde
char = 126
ELSEIF char = 126 THEN ; delete
char = 127
FI
PutD(3,char)
RETURN
PROC main()
intro()
DO
IF remote() THEN
do_remote()
ELSEIF local() THEN
do_local()
FI
OD
RETURN