home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
mskermit.tar.gz
/
mskermit.tar
/
msxrb1.asm
< prev
next >
Wrap
Assembly Source File
|
1991-03-18
|
80KB
|
2,805 lines
name msxrb1
; File msxrb1.asm
include mssdef.h
; Copyright (C) 1982,1991, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or
; institution to use, copy, or redistribute this software as long as
; it is not sold for profit and this copyright notice is retained.
; Kermit system dependent module for Rainbow
; Jeff Damens, July 1984
; with additional major changes by Joe Doupnik, 1986, 1987, 1988, 1989, 1991
; Edit history:
; 2 March 1991 version 3.10
; Last edit 1 March 1991
; 27-AUG-1990 [rhw]
; 27-AUG-1990 I had added shr cx,1 to divide the CX=swidth by 2
; but swidth is a const so I removed the shifts & simply
; divided the const by 2. This saves an shift in many places.
; [rhw-5] Robert H. Weiner
; 25-AUG-1990 Replaced MOVSB with MOVSW for all screen ops
; Divide counts by 2 1st for byte to word conversion
; Since swidth is always even, this can save alot of cycles:
; REP MOVSB -> MOVSW should save 17*132/2=1122 cycles for
; swidth char moves since iteration count is cut in half.
; [rhw-4] Robert H. Weiner
; 24-AUG-1990 Added print screen character XLAT table to make all the
; VT100 char graphics come out on a normal printer, xlat_tab[]
; Added same XLAT code to dumpscr code since that too is
; a real mess without it. Now linedraw boxes look like boxes.
; Added SETCHTAB definition that's now required in machine
; specific modules
; [rhw-3] Robert H. Weiner
; Present-
; 01-JUL-1990 MSYIBM.ASM screen rollback routines merged into MSXRB1.ASM
; This should speed up rollback screen handling
; Sorry, this code left out of this source release since its
; presently incomplete.
; [rhw-2] Robert H. Weiner
; MAY-1990 connect mode hangup (^]-H) fixed (needed delay) RHW/JRD
; [rhw-1] Robert H. Weiner (robert%progplus.uucp@uunet.uu.net)
; 30-Apr-1990 fix baud rate return [gbs]
; convert unprintable characters to "." in print screen
; 14-Feb-1990 fix VT102 initialization. gbs
; 11 Nov Revise for MS Kermit version 3. jrd
; 11-Nov-1989 reversed print controller/autoprint.
; Had it wrong the first time.
; Gary B. Stebbins
; 18-Oct-1989 added minimal print controller support & autoprint
; (module needs cleanup in incoming character handling)
; (print stuff doesn't handle DECEXT or DECPFF)
; (really kludged in...should be rewritten similar to
; input character handling for IBM PC)
; Gary B. Stebbins
; 4-Mar-1989 several problems related to modem signal handling fixed.
; Gary B. Stebbins, Don Metz
; 1 July 1988 Version 2.31
; 10 Jan 1988 Cleanup 8 bit display in outtty. [jrd]
; 1 Jan 1988 version 2.30
public serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl
public getbaud, beep, pcwait, dumpscr, termtb, shomodem
public count, xofsnt, puthlp, putmod, clrmod, poscur, getmodem
public sendbr, sendbl, term, machnam, setktab, setkhlp, showkey
public ihosts, ihostr, serhng, dtrlow, comptab, baudst
; action verb procedures for keyboard translator
public prvscr, nxtscr, prtscn
public uparrw, dnarrw, rtarr, lfarr, pf1, pf2, pf3, pf4
public kp0, kp1, kp2, kp3, kp4, kp5, kp6, kp7, kp8, kp9
public kpminus, kpcoma, kpenter, kpdot, chrout, cstatus, cquit
public cquery, prvscr, nxtscr, prvlin, nxtlin, trnprs, snull
public nxttop, nxtbot, klogon, klogof, cdos, chang
public portval, bdtab, setchtab
; rainbow-dependent screen constants
scrseg equ 0ee00H ; screen segment
latofs equ 0ef4h ; ptrs to line beginnings, used by firmware
l1ptr equ latofs ; ptr to first line
llptr equ latofs+23*2 ; ptr to last line
csrcol equ 0f41h ; current cursor column
csrlin equ 0f42h ; current cursor line
curlin equ 0f43h ; current line flags
wrpend equ 2 ; wrap pending
attoffs equ 1000H
rmargin equ 0f57h ; right margin limit
; rainbow-dependent firmware locations
nvmseg equ 0ed00h ; segment containing NVM
xmitbd equ 0a1h ; address of xmit baud
rcvbd equ 0a2h ; " " receive baud
autwrp equ 08dH ; b0 = 1 if auto wrap on (?)
newlmod equ 08eh ; b0 = 0 lf, = 1 newline (cr/lf)
bdprt equ 06h ; baud rate port
vt52mod equ 088h ; b0 = 1 if in ansi mode
off equ 0
bufon equ 1 ; buffer level xon/xoff on-state control flag
usron equ 2 ; user level xon/xoff on-state control flag
mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full
mntrgl equ bufsiz/4 ; Low point = 1/4 buffer full
mnstata equ 042H ; Status/command port A
mnstatb equ 043H ; Status/command port B
mndata equ 040H ; Data port
mndatb equ 041H
mnctrl equ 002H ; Control port
serchn equ 0A4H ; interrupt to use
serch1 equ 044H ; use this too for older rainbows
txrdy EQU 04H ;Bit for output ready
rxrdy EQU 01H ;Bit for input ready
fastcon equ 29H ; fast console handler
firmwr equ 18H ; Bios interrupt
kcurfn equ 8h ; disable cursor
rcurfn equ 0ah ; enable cursor
swidth equ 132 ; screen width
slen equ 24 ; screen length
npages equ 10 ; for use with dynamic memory allocation
stbrk equ 15 ; start sending a break
enbrk equ 16 ; stop sending break
; external variables used:
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; circular buffer ptr
cbuf struc
pp dw ? ; place ptr in buffer
bend dw ? ; end of buffer
orig dw ? ; buffer origin
lcnt dw 0 ; # of lines in buffer
lmax dw ? ; max lines of buffer
cbuf ends
; answerback structure
ans struc
anspt dw ? ; current pointer in answerback
ansct db ? ; count of chars in answerback
ansseq dw ? ; pointer to whole answerback
anslen db ? ; original length
ansrtn dw ? ; routine to call
ans ends
; structure for status information table sttab.
stent struc
sttyp dw ? ; type (actually routine to call)
msg dw ? ; message to print
val2 dw ? ; needed value: another message, or tbl addr
tstcel dw ? ; address of cell to test, in data segment
basval dw 0 ; base value, if non-zero
stent ends
data segment public 'data'
extrn flags:byte, trans:byte, filtst:byte, dmpname:byte
extrn rxtable:byte, kbdflg:byte, repflg:byte, diskio:byte
extrn ttyact:byte, denyflg:word, prnhand:word
; [rhw-3] Start Definitions for Print Screen Translation Table
xlat_tab_size equ 32 ; chars 00 through 31 decimal
; 0=null, 1=diamond, 2=blob, 3=HT, 4=FF, 5=CR, 6=LF, 7=degree, 8=+/-
; 9=NL, 10=VT, 11=low_rt_corner, 12=up_rt_corner, 13=up_left_corner,
; 14=low_left_corner, 15=cross, 16...20=horiz_line_scan1,3,5,7,9
; 21=left_t, 22=right_t, 23=bott_t, 24=top_t, 25=vertical, 26=<=
; 27=>=, 28=pi, 29=<>, 30=pound, 31=centered_dot
; 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7
xlat_tab db ' ', '*', '#', '.', '.', '.', '.', 'o'
; 8 , 9 , 10, 11, 12, 13, 14, 15
db '+', '.', '.', '+', '+', '+', '+', '+'
; 16, 17, 18, 19, 20, 21, 22, 23
db '_', '_', '-', '-', '-', '+', '+', '+'
; 24, 25, 26, 27, 28, 29, 30, 31
db '+', '|', '<', '>', 'p', '!', '#', '.'
; [rhw-3] End Print Screen Translation Table
setchtab db 1 ; [rhw-3] Set File Character-Set table
mkeyw 'VT102',0 ; [rhw-3] hardware default Code Page
;; mkeyw 'User-defined',1 ; User loadable table
setktab db 0
akeyflg db 0 ; non-zero if in alt keypad mode
ckeyflg db 0 ; non-zero if cursor is in applications mode
ourflgs db 0 ; our flags
fpscr equ 80H ; flag definitions
vtautop equ 1 ; autoprint enabled
vtcntp equ 2 ; controller print enabled
fairness dw 0 ; keyboard/port sharing counter
dupflg db 0 ; full (0) or half (1) duplex on port
argadr dw 0 ; pointer to arguments from msster
crlf db cr,lf,'$'
setkhlp db 0
machnam db 'Rainbow$'
nyimsg db cr,lf,'Not yet implemented$'
dmperr db cr,lf,'?Cannot access screen-dump file$',cr,lf
hngmsg db cr,lf,' The phone should have hungup.',cr,lf,'$'
hnghlp db cr,lf,' The modem control lines DTR and RTS for the current'
db ' port are forced low (off)'
db cr,lf,' to hangup the phone. Normally, Kermit leaves them'
db ' high (on) when it exits.'
db cr,lf,'$'
msmsg1 db cr,lf,' Modem is not ready: DSR is off$'
msmsg2 db cr,lf,' Modem is ready: DSR is on$'
msmsg3 db cr,lf,' no Carrier Detect: CD is off$'
msmsg4 db cr,lf,' Carrier Detect: CD is on$'
msmsg5 db cr,lf,' no Clear To Send: CTS is off$'
msmsg6 db cr,lf,' Clear To Send: CTS is on$'
rdbuf db swidth dup (?) ; temp buf
delstr db BS,BS,' ',BS,BS,'$' ; Delete string
clrlin db cr,'$' ; Clear line (just the cr part)
oldser dw ? ; old serial handler
oldseg dw ? ; segment of above
old1ser dw ? ; old serial handler, alternate address
old1seg dw ? ; segment of same
portin db 0 ; Has comm port been initialized
mdstreg db 0 ; Modem line status report for Show Modem
xofsnt db 0 ; Say if we sent an XOFF
xofrcv db 0 ; Say if we received an XOFF
parmsk db 0ffh ; 7-8 bit parity mask
flowon db 0 ; flow on char (xon or null)
flowoff db 0 ; flow off char (xoff or null)
mdmhand db 0 ; Modem status register, current
iobuf db 5 dup (?) ; buffer for ioctl
gopos db escape,'['
rowp db 20 dup (?)
clrseq db escape,'[H',escape,'[J$'
ceolseq db escape,'[K$'
invseq db escape,'[7m$'
nrmseq db escape,'[0m$'
ivlatt db swidth dup (0fH) ; a line's worth of inverse attribute
dumpbuf db swidth+2 dup (?) ; screen dump work buffer
dumpsep db FF,cr,lf ; screen dump image separator
dovt52 db escape,'[?2l$' ; set VT52 mode
dovt102 db escape,'<$' ; set VT102 mode
ourarg termarg <>
comptab db 2 ; communications port options
mkeyw '1',1
mkeyw 'COM1',1 ; only one option here
ontab db 2
mkeyw 'off',0
mkeyw 'on',1
vttbl db 3 ; SET TERM table
mkeyw 'Roll',10
mkeyw 'VT102',ttvt100
mkeyw 'VT52',ttvt52
termtb db 2 ; entries for Status, not Set
mkeyw 'VT102',ttvt100
mkeyw 'VT52',ttvt52
rolhlp db cr,lf,' Roll (undo screen roll back before writing new'
db ' chars, default=off)$'
vtrolst db 'Term rollback: $'
vtstbl stent <srchkw,vtrolst,ontab,vtroll> ; rollback
dw 0 ; end of table
; variables for serial interrupt handler
source db bufsiz DUP(?) ; Buffer for data from port
srcpnt dw source ; Pointer in buffer (DI)
count dw 0 ; Number of chars in int buffer
telflg db 0 ; non-zero if we're a terminal. NRU
ivec dw tranb ; transmit empty B
dw tranb ; status change B
dw tranb ; receive b
dw tranb ; special receive b
dw stxa ; transmit empty a
dw sstata ; status change a
dw srcva ; receive a
dw srcva ; special receive a
; baud rate definitions
; value is programmed into baud rate port
bdtab db 16 ; Baud rate table
mkeyw '50',0
mkeyw '75',1
mkeyw '110',2
mkeyw '134.5',3
mkeyw '150',4
mkeyw '200',5
mkeyw '300',6
mkeyw '600',7
mkeyw '1200',8
mkeyw '1800',9
mkeyw '2000',10
mkeyw '2400',11
mkeyw '3600',12
mkeyw '4800',13
mkeyw '9600',14
mkeyw '19200',15
; multi-screen stuff
twnd cbuf <> ; top screen spill-buffer struct
bwnd cbuf <> ; bottom screen spill buffer struct
topline dw swidth dup (?) ; top line screen spill buffer
botline dw swidth dup (?) ; bottom line screen spill buffer
rlbuf dw swidth dup (?) ; temp buffer for line scrolling
scrnbuf db swidth*slen dup (?) ; save-screen, text
attrbuf db swidth*slen dup (?) ; save-screen, attributes
srcseg dw 0
topdwn db escape,'[H',escape,'M$' ; go to top, scroll down
botup db escape,'[24;0H',escape,'D$' ; go to bottom, scroll up
curinq db escape,'[6n$' ; cursor inquiry
posbuf db 20 dup (?) ; place to store cursor position
gtobot db escape,'[24;0H$' ; go to bottom of screen
ourscr dw ?
ourattr dw ? ; storage for screen and attributes
inited db 0 ; terminal handler not inited yet
dosmsg db '?Must be run in version 2.05 or higher$'
dmphand dw ? ; file handle for screen dump
anssq1 db escape,'[c'
an1len equ $-anssq1
anssq2 db escape,'Z'
an2len equ $-anssq2
eakseq db escape,'='
eaklen equ $-eakseq
dakseq db escape,'>'
daklen equ $-dakseq
cuapseq db escape,'[?1h'
cuaplen equ $-cuapseq
cunapseq db escape,'[?1l'
cunaplen equ $-cunapseq
crsseq db escape,'c'
crslen equ $-crsseq
enqseq db escape,'[6n'
enqlen equ $-enqseq
apenable db escape,'[?5i' ;autoprint enable
apenlen equ $-apenable
apdisabl db escape,'[?4i' ;autoprint disable
apdislen equ $-apdisabl
pcenable db escape,'[5i' ;print controller enable
pcenlen equ $-pcenable
pcdisabl db escape,'[4i' ;print controller disable
pcdislen equ $-pcdisabl
pscrn0 db escape,'[i' ;print screen
psc0len equ $-pscrn0
pscrn1 db escape,'[0i' ;print screen
psc1len equ $-pscrn1
ansbk1 ans <anssq1,an1len,anssq1,an1len,sndans> ; two answerbacks
ansbk2 ans <anssq2,an2len,anssq2,an2len,sndans>
ansbk3 ans <eakseq,eaklen,eakseq,eaklen,enaaky> ; enable alt keypad
ansbk4 ans <dakseq,daklen,dakseq,daklen,deaaky> ; disable alt keypad
ansbk5 ans <crsseq,crslen,crsseq,crslen,sndspc> ; crash sequence (!)
ansbk6 ans <enqseq,enqlen,enqseq,enqlen,ansenq>
ansbk7 ans <cuapseq,cuaplen,cuapseq,cuaplen,cuapp> ; cursor application
ansbk8 ans <cunapseq,cunaplen,cunapseq,cunaplen,cunapp>; cursor cursor
ansbk9 ans <apenable,apenlen,apenable,apenlen,apon>; autoprint enable
ansbk10 ans <apdisabl,apdislen,apdisabl,apdislen,apoff>;autoprint disable
ansbk11 ans <pcenable,pcenlen,pcenable,pcenlen,prconon>;print control on
ansbk12 ans <pcdisabl,pcdislen,pcdisabl,pcdislen,pconoff>;print control off
ansbk13 ans <pscrn0,psc0len,pscrn0,psc0len,prtscn> ; print screen
ansbk14 ans <pscrn1,psc1len,pscrn1,psc1len,prtscn> ; print screen
ansret db escape,'[?6c'
db 10 dup (?)
ansrln equ $-ansret
vt52ret db escape,'/Z' ; VT52 identification
vt52ln equ $-vt52ret
temp dw 0
vtroll db 0
port1 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0>
portval dw port1 ; Default is to use port 1
;port initialization data for 7201 [ejz]
;enables Rx,Tx, CTS, DTR, 8 bits, no parity, 1.5 stop bits
prtpar db 18H,14H,48H,13H,0C1H,15H,0EAH,11H,18H,00H
data ends
code segment public 'code'
extrn comnd:near, dopar:near, sleep:near, sbrk:near, isfile:near
extrn strlen:near, strcpy:near, msuinit:near, keybd:near
extrn statc:near, srchkw:near, pntchr:near, pntflsh:near
assume cs:code, ds:data, es:nothing
; local initialization routine, called by Kermit initialization.
lclini proc near
mov ah,dosver ; make sure this is DOS version 2.05 or higher
int dos
xchg al,ah ; put major version in ah, minor in al
cmp ax,205H ; is it 2.05?
jae lclin1 ; yes, go on
mov dx,offset dosmsg
call tmsg
cmp flags.extflg,1 ; exit now
ret
lclin1: mov flags.vtflg,ttvt100 ; default to VT102
call setterm ; set terminal type to VT102
call msuinit ; initialize keyboard translator
mov ourscr,offset scrnbuf ; save-screen text buf address
mov ourattr,offset attrbuf ; save-screen attr buf address
mov ax,swidth*2*2 ; ask for two lines (1 per buffer)
call sbrk ; allocate mem. Exit Kermit on failure
;if we get here them we have the lines
mov bwnd.orig,ax ; memory segment, bottom window area
mov twnd.orig,ax ; top. same place for both buffers!
push es ; save this register
mov es,ax ; seg pointer to new memory block
mov bx,(swidth*slen*npages+7)/8 ; paragraphs wanted for roll back
add bx,24000D/16 ; plus paragraphs to run Command.com
mov ah,setblk ; DOS Setblock. Ask for that space
int dos ; bx has # paragraphs available
sub bx,24000D/16 ; deduct space for DOS 3.x Command.Com
cmp bx,(swidth*4+15)/16 ; any room left for buffers?
jae lclyin2 ; some space is available for buffers
mov bx,(swidth*4+15)/16 ; else use our sbrk allocation
lclyin2:mov ah,setblk ; ask for that many (bx) paragraphs
int dos ; Errors here == DOS deceived us
pop es ; restore reg
mov ax,bx ; bx = # paragraphs allocated by DOS
mov cl,3 ; 2**3 = 8
shl ax,cl ; paragraphs to words (char + attrib)
xor dx,dx ; clear extended size
mov cx,swidth ; number of chars per line in buffer
div cx ; ax = number of lines in buffer
mov bwnd.lmax,ax ; max lines per buffer (quotient)
mov twnd.lmax,ax ; max lines per buffer
add cx,cx ; count char and attribute per item
xor dx,dx ; clear extended numerator
mul cx ; ax = effective # bytes per buffer
dec ax ; adjust for counting from zero
mov bwnd.bend,ax ; offset of last byte in buffer
mov twnd.bend,ax ; offset of last byte in buffer
mov bwnd.pp,0 ; offset of first byte in buffer
mov twnd.pp,0 ; offset of first byte in buffer
mov bwnd.lcnt,0 ; number of lines occupied in buffer
mov twnd.lcnt,0 ; number of lines occupied in buffer
or denyflg,tekxflg ; deny automatic Tektronix invokation
ret
lclini endp
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
showkey proc near
ret
showkey endp
; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdmhand, the modem line status register. [jrd]
shomodem proc near
mov ah,cmeol ; get a confirm
call comnd
jc shomd5 ; c = failure
call getmodem ; get modem status
mov mdmhand,al
mov ah,prstr
mov dx,offset msmsg1 ; modem ready msg
test mdmhand,20h ; is DSR asserted?
jz shomd1 ; z = no
mov dx,offset msmsg2 ; say not asserted
shomd1: int dos
mov dx,offset msmsg3 ; CD asserted msg
test mdmhand,80h ; CD asserted?
jz shomd2 ; z = no
mov dx,offset msmsg4 ; say not asserted
shomd2: int dos
mov dx,offset msmsg5 ; CTS asserted msg
test mdmhand,10h ; CTS asserted?
jz shomd3 ; z = no
mov dx,offset msmsg6 ; say not asserted
shomd3: mov ah,prstr
int dos
clc
shomd5: ret
shomodem endp
; Get modem status and set global byte mdmhand. Preserve all registers.
; Uses byte mdstreg, the modem line status register, bits as follows:
; Int Z80, Int 8088, Hwd fail det enable, CD, CTS, DSR, SI/SecCD, RI [jrd]
getmodem proc near ; gets modem status upon request
push dx
mov al,0 ; assume nothing is on
mov dx,mnctrl ; modem control port (read 02h)
in al,dx ; read modem control port
not al ; invert RB modem bits (0=true) [gbs]
mov mdmhand,0 ; clear status byte
test al,4 ; DSR asserted?
jz getmod1 ; z = no
or mdmhand,20h ; set IBM spec DSR bit
getmod1:test al,8 ; CTS asserted?
jz getmod2 ; z = no
or mdmhand,10h ; set IBM spec CTS bit
getmod2:test al,10h ; CD asserted? [gbs]
jz getmod3 ; z = no
or mdmhand,80h ; set IBM spec CD bit [gbs]
getmod3:mov al,mdmhand ; setup return
mov ah,0 ; return status in al
pop dx
clc
ret
getmodem endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cli
mov srcpnt,offset source
mov count,0
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov dx,offset ceolseq ; clear sequence
jmp tmsg
CLEARL ENDP
; Put the char in AH to the serial port, assumimg the port is active.
; Returns carry clear if success, else carry set.
; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to
; prevent confusion of flow control logic at top of outchr; used by receiver
; buffer high/low water mark flow control code. [jrd]
OUTCHR PROC NEAR
cmp flowoff,0 ; Are we doing flow control
je outch2 ; No, just continue
cmp ah,flowoff ; sending xoff?
jne outch1 ; ne = no
mov xofsnt,usron ; indicate user level xoff being sent
jmp outch1b
outch1:
and xofsnt,not usron ; cancel user level xoff
cmp ah,flowon ; user sending xon?
jne outch1b ; ne = no
mov xofsnt,off ; say an xon has been sent (cancels xoff)
outch1b:cmp xofrcv,off ; Are we being held (xoff received)?
je outch2 ; e = no - it's OK to go on
cmp ttyact,0 ; in Connect mode?
je outch1d ; e = no
call beep ; let user know we are xoff-ed
mov xofrcv,off ; force off XOFF (unblock output)
jmp outch2 ; and send the char anyway
outch1d:cmp flags.timflg,0 ; is timer off?
je outch2 ; e = yes, no timeout period
push cx ; save reg
mov ch,trans.rtime ; receive timeout interval (sec)
xor cl,cl ; convert to 4 millsec increments
jcxz outch1c ; z = no timeout wanted
outch1a:cmp xofrcv,off ; Are we being held (xoff received)?
je outch1c ; e = no - it's OK to go on
push ax
mov ax,4 ; 4 millisec wait loop
call pcwait
pop ax
loop outch1a ; and try it again
mov xofrcv,off ; timed out, force it off and fall thru
outch1c:pop cx ; end of flow control section
; OUTCH2 is entry point for sending without flow control
OUTCH2: mov al,ah ; Parity routine works on AL
call dopar ; Set parity appropriately
mov ah,al ; Don't overwrite character with status
cmp repflg,0 ; doing REPLAY from a file?
je outch3 ; e = no
and al,7fh ; strip parity
cmp al,'C'-40h ; Control-C? (to exit playback mode)
je outch2a ; e = yes, return failure
clc ; return success, send nothing
ret
outch2a:stc ; return failure to exit playback mode
ret
outch3: push cx ; save registers
push dx
outch3b:cmp dupflg,0 ; full duplex?
je outch3d ; e = yes
mov al,0f1h ; enable RTS and DTR Note: bits reversed [gbs]
out mnctrl,al ;[DTR] compared to documentation
in al,mnctrl
test al,4 ; ignore CTS if DSR is not asserted
jz outch3d ; z = DSR not asserted
mov cx,8000 ; ~10 seconds worth of waiting on CTS
outch3c:in al,mnctrl
test al,8 ; is CTS asserted?
jnz outch3d ; nz = yes
push cx
push dx
mov ax,1 ; wait one millisec
call pcwait
pop dx
pop cx
loop outch3c ; test again
call beep ; half duplex timeout, make non-fatal
pop dx
pop cx
clc
ret
outch3d:xor cx,cx
mov dx,mnstata ; get port status
in al,dx
test al,txrdy ; transmitter ready?
jnz outch4 ; nz = yes
jmp $+2 ; use time, prevent overdriving UART
loop outch3b
jmp outch5 ; timeout
outch4: mov al,ah ; send it out
mov dx,mndata ; use a little time
jmp $+2
out dx,al
cmp dupflg,0 ; full duplex?
je outch4a ; e = yes
cmp al,trans.seol ; End of Line char?
jne outch4a ; ne = no
mov al,0f5h ; disable RTS (4)
out mnctrl,al
outch4a:pop dx ; exit success
pop cx
clc
ret
outch5: call beep
pop dx ; exit failure
pop cx
stc
ret
OUTCHR ENDP
; This routine blanks the screen.
CMBLNK PROC NEAR
mov dx,offset clrseq ; clear screen sequence
jmp tmsg
CMBLNK ENDP
; Locate; homes the cursor. Returns normally.
LOCATE PROC NEAR
xor dx,dx ; Go to top left corner of screen
jmp poscur
LOCATE ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov dx,24 * 100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
call tmsg
pop dx
call tmsg ; print the message
mov dx,offset nrmseq ; normal videw
call tmsg
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,24 * 100H
call poscur
jmp clearl
clrmod endp
; Put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push ax
mov dx,slen * 100H ; go to bottom line
call poscur
pop ax
push es
mov bx,ds
mov es,bx ; address data segment
mov si,ax ; convenient place for this
mov bx,101H ; current line/position
puthl1: mov di,offset rdbuf ; this is destination
xor cx,cx ; # of chars in the line
cld
puthl2: lodsb ; get a byte
cmp al,cr ; carriage return?
je puthl2 ; yes, ignore it
cmp al,lf ; linefeed?
je puthl3 ; yes, break the loop
cmp al,0
je puthl3 ; ditto for null
dec cx ; else count the character
stosb ; deposit into the buffer
jmp puthl2 ; and keep going
puthl3: add cx,80 ; this is desired length of the whole
mov al,' '
rep stosb ; fill the line
push bx
push si
push es ; firmware likes to eat this one
mov ax,0 ; send chars and attributes
mov cx,80 ; this is # of chars to send
mov dx,offset ivlatt ; this are attributes to send
mov si,offset rdbuf ; the actual message
mov di,14H ; send direct to screen
mov bp,ds ; need data segment as well
push ax
push cx
push dx
push di
mov di,14H ; send direct to screen
int firmwr
pop di
pop dx
pop cx
pop ax
pop es
pop si
pop bx ; restore everything
inc bx ; next line
cmp byte ptr [si-1],0 ; were we ended by a 0 last time?
jne puthl1 ; no, keep looping
pop es ; else restore this
clc
ret ; and return
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
BAUDST PROC NEAR
mov dx,offset bdtab ; baud rate table, ascii
xor bx,bx ; help is the table itself
mov ah,cmkey ; get keyword
call comnd
jc baudst1 ; c = failure
push bx ; save result
mov ah,cmeol ; get confirmation
call comnd
pop bx
jc baudst1 ; c = failure
mov si,portval
mov ax,[si].baud ; remember original value
mov [si].baud,bx ; set the baud rate
call dobaud ; use common code
clc
baudst1:ret
BAUDST ENDP
DOBAUD PROC NEAR
push bx
push ds
pop es ; set es to data segment
cld
mov al,bl
mov cl,4
shl bl,cl ; shift constant into high nibble
or al,bl
out bdprt,al ; write into port
or al,0f0h ; turn on high nibble
push es
mov bx,nvmseg
mov es,bx
mov es:[xmitbd],al
mov es:[rcvbd],al ; set baud in nvm
pop es
pop bx
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
push ax ; save some regs
push bx
push es
mov ax,nvmseg
mov es,ax
mov al,es:[xmitbd] ; get xmit baud rate [gbs]
pop es
and ax,0fh ; only low nibble is used [gbs]
mov bx,portval
mov [bx].baud,ax ; set value
pop bx ; restore regs
pop ax
ret ; and return
GETBAUD ENDP
; Get Char from serial port buffer.
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
; Revised 22 May 1986, and again slightly 2 August 1986 by [jrd]
; Copied from msxibm.asm [jrd]
PRTCHR PROC NEAR
call chkxon ; see if we need to xon
cmp repflg,0 ; REPLAY?
je prtch0 ; e = no
jmp prtch30 ; yes, do replay file reading
prtch0: cmp count,0 ; any characters available?
jnz prtch1 ; nz = yes, get one
prtch0a:xor dx,dx ; return count of zero
stc ; say no data
ret
prtch1: push si ; save si
cli ; interrupts off, to keep srcpnt & count consistent
mov si,srcpnt ; address of next available slot in buffer
sub si,count ; minus number of unread chars in buffer
cmp si,offset source ; located before start of buf?
jae prtch2 ; ae = no
add si,bufsiz ; else do arithmetic modulo bufsiz
prtch2: mov al,byte ptr [si] ; get a character into al
dec count ; one less unread char now
sti ; interrupts back on now
pop si
mov dx,count ; return # of chars in buffer
test flags.debug,logses ; debug mode?
jnz prtch14 ; nz = yes, pass all chars
cmp rxtable+256,0 ; translation turned off?
jne prtch14 ; ne = table is on, pass all chars
cmp al,0 ; NUL?
je prtch13 ; e = yes, ignore it
cmp al,DEL ; DEL char
jne prtch14 ; ne = no, pass char
prtch13:xor dx,dx
stc ; no data
ret
prtch14:clc ; return char in al
ret
prtch30:push bx ; REPLAY, read char from a file
push cx
test xofsnt,usron ; user level xoff sent?
jnz prtch31 ; nz = yes, suppress reading here
xor dx,dx
mov ax,100
mov bx,1
jmp $+2 ; flush lookahead buffer
div bx ; burn some cpu cycles
jmp $+2 ; because a 1 ms wait is too long
div bx
jmp $+2
div bx
mov ah,readf2
mov bx,diskio.handle ; file handle
mov cx,1 ; read one char
mov dx,offset rdbuf ; to this buffer
int dos
jc prtch31 ; c = read failure
cmp ax,cx ; read the byte?
jne prtch31 ; ne = no
pop cx
pop bx
mov al,rdbuf ; get the char into al
mov dx,1 ; external char count
clc
ret ; return it
prtch31:pop cx
mov bx,portval
mov [bx].portrdy,0 ; say port is not ready
pop bx
xor dx,dx
stc ; say no char
ret
PRTCHR ENDP
; IHOSTS - Initialize the host by sending XON. Requires that the port be
; initialized.
IHOSTS PROC NEAR
push ax ; save the registers
push cx
push dx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; doing flow control?
jz ihosts1 ; z = no, don't send a null
call outchr ; send it (release Host's output queue)
ihosts1:pop dx ; empty buffer. we are done here
pop cx
pop ax
ret
IHOSTS ENDP
; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port. 22 March 1986 [jrd]
; Modified 26 June 1986 to supress sending a null if no flow control. [jrd]
IHOSTR PROC NEAR
push ax ; save regs
push cx
mov xofrcv,off ; clear old xoff received flag
mov xofsnt,off ; and old xoff sent flag
mov ah,flowon ; put Go-ahead flow control char in ah
or ah,ah ; doing flow control?
jz ihostr1 ; z = no, don't send a null
call outchr ; send it (release Host's output queue)
ihostr1:pop cx
pop ax
ret
IHOSTR ENDP
; local routine to see if we have to transmit an xon
chkxon proc near
cmp flowon,0 ; doing flow control?
je chkxo1 ; no, skip all this
test xofsnt,usron ; did user send an xoff?
jnz chkxo1 ; nz = yes, don't contradict it here
test xofsnt,bufon ; have we sent a buffer level xoff?
jz chkxo1 ; z = no, forget it
cmp count,mntrgl ; below (low water mark) trigger?
jae chkxo1 ; no, forget it
mov ah,flowon ; ah gets xon
and xofsnt,off ; remember we've sent the xon
call outch2 ; send via non-flow controlled entry point
chkxo1: ret
chkxon endp
; Send a BREAK out the current serial port. Returns normally.
SENDBR PROC NEAR
push cx
mov cx,275 ; 275 millisec
call sendbw ; let worker routine do it
pop cx
clc ; don't exit Connect mode
ret
; Send a Log BREAK out the current serial port.
SENDBL: push cx
mov cx,1800 ; 1800 millisec
call sendbw ; let worker routine do it
pop cx
clc ; don't exit Connect mode
ret
sendbw: push ax ; worker routine to send a break [jrd]
push bx ; number of millisec is in cx
push dx
mov ah,ioctl
mov al,3 ; write to control channel
mov bx,3 ; aux port handle
mov dx,offset iobuf
mov iobuf,stbrk ; start sending a break
int dos
mov ax,cx ; # of ms to wait
call pcwait ; hold break for desired interval
mov ah,ioctl
mov al,3
mov bx,3
mov dx,offset iobuf
mov iobuf,enbrk ; stop sending the break
int dos
pop dx
pop bx
pop ax
clc
ret
SENDBR ENDP
; wait for the # of milliseconds in ax
; thanks to Bernie Eiben for this one.
pcwait proc near
push cx
pcwai0: mov cx,240 ; inner loop counter for 1 millisecond
pcwai1: sub cx,1 ; inner loop takes 20 clock cycles
jnz pcwai1
dec ax ; outer loop counter
jnz pcwai0 ; wait another millisecond
pop cx
ret
pcwait endp
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
add dx,101H ; start at 1,1
push es
push ax ; save some regs
push bx
push di
push dx
cld
mov ax,ds
mov es,ax ; address data segment
mov di,offset rowp
mov al,dh ; row comes first
mov ah,0
call nout
mov al,';'
stosb ; separated by a semicolon
pop dx
mov al,dl
mov ah,0
call nout
mov al,'H'
stosb ; end w/H
mov byte ptr [di],'$' ; and dollar sign
mov dx,offset gopos
call tmsg
pop di ; restore regs
pop bx
pop ax
pop es
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov dx,offset delstr ; Erase weird character
jmp tmsg
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov dx,offset clrlin ; this just goes to left margin
call tmsg
jmp clearl ; now clear line
CTLU ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
COMS ENDP
; Set Terminal command
VTS PROC NEAR ; SET TERM whatever [jrd]
mov ah,cmkey ; parse key word
xor bx,bx ; use built-in help
mov dx,offset vttbl ; use this table
call comnd
jc vts0
cmp bx,tttypes ; ROLL or more?
ja vts4 ; a = yes
; SET TERM {VT52 | VT102}
push bx
mov ah,cmeol
call comnd ; get a confirm
pop bx
jnc vts1 ; nc = success
vts0: ret
vts1: cmp bl,ttvt100 ; set to VT102?
je vts2 ; e = yes
mov flags.vtflg,ttvt52 ; say VT52
jmp vts3
vts2: mov flags.vtflg,ttvt100 ; say VT102
vts3: call setterm ; send the message to the console
ret
vts4: mov ah,cmkey ; SET TERM ROLL
mov bx,offset rolhlp ; help message
mov dx,offset ontab ; table of answers
call comnd
jc vts6
push bx
mov ah,cmeol
call comnd ; get a confirm
pop bx
jc vts6
mov vtroll,bl ; set the flag
vts6: ret
VTS ENDP
VTSTAT PROC NEAR ; Status routine for emulation. [jrd]
mov bx,offset vtstbl ; table of things to show
jmp statc ; status common code, in mssset
VTSTAT ENDP
; initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.
SERINI PROC NEAR
cmp portin,0 ; Did we initialize port already?
jne serin0 ; ne = yes, so just leave
cli ; Disable interrupts
cld ; Do increments in string operations
push es
push si ; [ejz] - Save this just in case
mov si,offset prtpar ; [ejz]
mov dx,mnstata ; [ejz]
push ds
pop es ; set es to data segment
call prtset ; [ejz]
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*serchn] ; get old serial handler
mov oldser,ax ; save
mov ax,es:[4*serchn+2] ; get segment
mov oldseg,ax ; save segment as well
mov ax,es:[4*serch1] ; this is alternate for older rainbows
mov old1ser,ax
mov ax,es:[4*serch1+2]
mov old1seg,ax ; pretty silly, huh?
mov ax,offset serint ; point to our routine
mov es:[4*serchn],ax ; point at our serial routine
mov es:[4*serch1],ax ; have to set both of these
mov es:[4*serchn+2],cs ; our segment
mov es:[4*serch1+2],cs
pop si ; [ejz]
pop es
mov al,0f1h ; enable RTS and DTR Note: bits reversed [gbs]
out mnctrl,al ;[DTR] compared to documentation
mov portin,1 ; Remember port has been initialized
sti ; Allow interrupts
push bx
mov bx,portval ; get port
mov parmsk,0ffh ; parity mask, assume parity is None
cmp [bx].parflg,parnon ; is it None?
je serin1 ; e = yes
mov parmsk,07fh ; no, pass lower 7 bits as data
serin1: mov bx,[bx].flowc ; get flow control chars
mov flowoff,bl ; xoff or null
mov flowon,bh ; xon or null
pop bx
serin0: clc ; carry clear for success
ret
SERINI ENDP
; this is used to by serini
prtset proc near
cld
lodsb ; get a byte
or al,al
jz prtse1 ; end of table, stop here
out dx,al ; else send it out
jmp short prtset ; and keep looping
prtse1: ret ; end of routine
prtset endp
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
cmp portin,0 ; reset already?
je srst1 ; e = yes, just leave
cli ; disable interrupts
push es ; preserve this
xor ax,ax
mov es,ax ; address segment 0
mov ax,oldser
mov es:[4*serchn],ax
mov ax,oldseg
mov es:[4*serchn+2],ax
mov ax,old1ser
mov es:[4*serch1],ax
mov ax,old1seg
mov es:[4*serch1+2],ax ; restore old handlers
mov portin,0 ; reset flag
pop es
sti ; re-enable interrupts
srst1: ret
SERRST ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
; New code, lifted from msxibm. [jrd]
serint PROC NEAR
push ax
push ds
push bx
push dx
mov ax,seg data
mov ds,ax ; address data segment
mov dx,mnstatb ; Asynch status port
xor al,al ; innocuous value
out dx,al ; send out to get into a known state
mov al,2 ; now address register 2
out dx,al
in al,dx ; read interrupt cause
cmp al,7 ; in range?
ja serin7 ; no, just dismiss (what about reset error?)
mov bl,al
shl bl,1 ; double for word index
xor bh,bh
call ivec[bx] ; call appropriate handler
jmp short serin8
serin7: mov dx,mnstata ; reload port address
mov al,38H
out dx,al ; tell the port we finished with the interrupt
sti ; turn on interrupts
serin8: pop dx
pop bx
pop ds
pop ax
intret: iret
; handler for serial receive, port A
srcva: mov dx,mnstata
xor al,al ; Asynch status port
out dx,al ; put into known state
jmp $+2
in al,dx
test al,rxrdy ; Data available?
jnz srcva0a ; nz = yes
srcva0: mov dx,mnstata
mov al,38h ; tell port we are finished with the interrupt
out dx,al
sti ; turn on interrupts
jmp retint ; and exit now (common jump point)
srcva0a:;;and al,mdmover ; select overrun bit
;; mov overrun,al ; save it for later
mov al,30h ; clear any errors
out dx,al
mov dx,mndata ; get modem rx data
in al,dx ; read the received character into al
cmp flowoff,0 ; flow control active?
je srcva2 ; e = no
mov ah,al ; ah = working copy. Check null, flow cntl
and ah,parmsk ; strip parity temporarily, if any
cmp ah,flowoff ; acting on Xoff?
jne srcva1 ; ne = Nope, go on
mov xofrcv,bufon ; Set the flag saying XOFF received
jmp srcva0 ; and exit
srcva1: cmp ah,flowon ; acting on Xon?
jne srcva2 ; ne = no, go on
mov xofrcv,off ; Clear the XOFF received flag
jmp srcva0 ; and exit
srcva2: push ax ; save rcvd char around this output cmd
mov dx,mnstata
mov al,38h ; tell port we are finished with the interrupt
out dx,al
pop ax
cli ; ensure interrupts are off, critical section
;; mov ah,overrun ; get overrun flag
;; or ah,ah ; overrun?
;; jz srcva2a ; z = no
;; mov ah,al ; yes, save present char
;; mov al,bell ; insert control-G for missing character
srcva2a:mov bx,srcpnt ; address of buffer storage slot
mov byte ptr [bx],al ; store the new char in buffer "source"
inc srcpnt ; point to next slot
inc bx
cmp bx,offset source + bufsiz ; beyond end of buffer?
jb srcva3 ; b = not past end
mov srcpnt,offset source ; wrap buffer around
srcva3: cmp count,bufsiz ; filled already?
jae srcva4 ; ae = yes
inc count ; no, add a char
srcva4:;;or ah,ah ; anything in overrun storage?
;; jz srcva4a ; z = no
;; mov al,ah ; recover any recent char from overrun
;; xor ah,ah ; clear overrun storage
;; jmp srcva2a ; yes, go store real second char
srcva4a:sti ; ok to allow interrupts now, not before
cmp count,mntrgh ; past the high trigger point?
jbe retint ; be = no, we're within our limit
test xofsnt,bufon ; Has an XOFF been sent by buffer control?
jnz retint ; nz = yes
mov al,flowoff ; get the flow off char (Xoff or null)
or al,al ; don't send null chars
jz retint ; z = null, nothing to send
call dopar ; Set parity appropriately
mov ah,al ; Don't overwrite character with status
push cx ; save reg
xor cx,cx ; loop counter
srcva5: mov dx,mnstata ; port status register
in al,dx
test al,txrdy ; Transmitter ready?
jnz srcva6 ; nz = yes
push ax ; use time, prevent overdriving UART
pop ax
loop srcva5 ; else wait loop, cx times
jmp short srcva7 ; Timeout
srcva6: mov al,ah ; Now send out the flow control char
mov dx,mndata
out dx,al
mov xofsnt,bufon ; Remember we sent an XOFF at buffer level
srcva7: pop cx ; restore reg
retint: ret
; The interrupt is for the 'B' port - transfer control to
; the original handler and hope for the best.
tranb: pushf ; put flags on stack to simulate interrupt
call dword ptr [old1ser] ; call old handler
jmp srccom ; take common exit
stxa: mov dx,mnstata
mov al,28H ; reset transmit interrupt
out dx,al
jmp srccom ; take common exit
sstata: mov dx,mnstata
mov al,10H ; reset status interrupt
out dx,al ; fall through to common exit srccom below
srccom: mov dx,mnstata ; common exit for above
mov al,38h ; tell port we are finished with the interrupt
out dx,al
sti ; turn on interrupts
ret
SERINT ENDP
DTRLOW PROC NEAR ; Global proc to Hangup the Phone by making
; DTR and RTS low.
mov ah,cmline ; allow text, to display help
mov bx,offset rdbuf ; dummy buffer
mov dx,offset hnghlp ; help message
call comnd ; get a confirm
jc dtrlow1
call serhng ; drop DTR and RTS
mov ah,prstr ; give a nice message
mov dx,offset hngmsg
int dos
clc
dtrlow1:ret
DTRLOW ENDP
; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; Returns normally.
serhng proc near
call serrst ; reset the port so can be restarted cleanly
cli ; Disable interrupts
mov al,0ffh ; disable RTS and DTR [gbs]
out mnctrl,al ; [DTR]
sti ; Allow interrupts
mov ax,500
call pcwait ; wait 500ms
clc
ret
serhng endp
; Produce a short beep.
; Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
clc
ret
BEEP ENDP
; put the number in ax into the buffer pointed to by di. Di is updated
nout proc near
mov dx,0 ; high order is always 0
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz nout1 ; zero, no more of number
call nout ; else call for rest of number
nout1: pop ax ; get digit back
add al,'0' ; make printable
cld
stosb ; drop it off
ret
nout endp
term proc near
mov si,ax ; this is source
mov argadr,ax ; save here too
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
cld
rep movsb ; copy into our arg blk
cmp inited,0 ; inited yet?
jne term0 ; ne = yes
call cmblnk ; clear the screen
call locate ; put cursor at top left corner
mov inited,1 ; say initialized
jmp short term0a
term0: call rstscr ; restore screen
term0a: mov inited,1 ; remember inited
mov parmsk,0ffh ; parity mask, assume parity = None
cmp ourarg.parity,parnon ; is parity None?
je term1 ; e = yes, keep all 8 bits
mov parmsk,07fh ; else keep lower 7 bits
term1: call portchr ; get char from port, apply parity mask
jnc short term3 ; nc = char
term2: mov fairness,0 ; say kbd was examined
call keybd ; call keyboard translator in msu
jnc term1 ; nc = no char or have processed it
call pntflsh ; flush printer buffer
call savscr ; save screen
mov dx,offset gtobot ; go to last line on screen
call tmsg
stc
ret ; carry set = quit connect mode
term3: call outtty ; print on terminal
inc fairness ; say read port but not kbd, again
cmp fairness,200 ; this many port reads before kbd?
jb term1 ; b = no, read port again
call pntflsh ; flush printer buffer
jmp short term2 ; yes, let user have a chance too
term endp
; Get a char from the serial port manager, return it in al
; returns with carry clear if a character is available, else carry set
portchr proc near
call prtchr ; character at port?
jnc portc1 ; nc = yes
portc0: stc ; carry = no character
ret
portc1: and al,parmsk ; apply 8/7 bit parity mask
or al,al ; catch nulls
jz portc0 ; z = null, ignore it
cmp al,del ; catch dels
je portc0 ; e = del, ignore it
portc2: clc ; have a character, in AL
ret
portchr endp
; put the character in al to the screen
outtty proc near
push es ; protect es around fastcon calls
test flags.remflg,d8bit ; keep 8 bits for displays?
jnz outnp5 ; nz = yes, 8 bits if possible
and al,7fh ; remove high bit
outnp5: cmp rxtable+256,0 ; translation turned off?
je outnp7 ; e = yes, no translation
push bx
mov bx,offset rxtable ; address of translate table
xlatb ; new char is in al
pop bx
outnp7: test ourflgs,fpscr+vtautop+vtcntp ; should we be printing?
jz outnop ; z = no, keep going
call pntchr ; queue char for printer
jnc outnop ; nc = successful print
push ax
call beep ; else make a noise and
call trnprs ; turn off printing
pop ax
and ourflgs,not (fpscr+vtautop+vtcntp) ; turn off printing
pop ax
outnop: test ourarg.flgs,capt ; capturing output?
jz outnoc ; z = no, forget this part
push ax ; save char
call ourarg.captr ; give it captured character
pop ax ; restore character and keep going
outnoc:
cmp vtroll,0 ; auto roll back allowed?
jz outnp6 ; z = no, leave screen as is
cmp bwnd.lcnt,0 ; is screen rolled back? [dlk]
je outnp6 ; e = no
call nxtbot ; restore screen before writing [dlk]
outnp6: push ax
call scrprep ; need to save top line
pop ax
test ourarg.flgs,trnctl ; debug? if so use Bios tty mode
jz outnp3 ; z = no
cmp al,7fh ; Ascii Del char or greater?
jb outnp1 ; b = no
je outnp0 ; e = Del char
push ax ; save the char
mov al,7eh ; output a tilde for 8th bit
int fastcon
pop ax ; restore char
and al,7fh ; strip high bit
outnp0: cmp al,7fh ; is char now a DEL?
jne outnp1 ; ne = no
and al,3fH ; strip next highest bit (Del --> '?')
jmp outnp2 ; send, preceded by caret
outnp1: cmp al,' ' ; control char?
jae outnp3 ; ae = no
add al,'A'-1 ; make visible
outnp2: push ax ; save char
mov al,5eh ; caret
int fastcon ; display it
pop ax ; recover the non-printable char
outnp3: call ansbak ; match answerback sequences
test ourflgs,vtcntp ; autoprint on? ;gbs
jnz outnp4 ; if so, don't output to screen
push ax
int fastcon ; write without intervention
pop ax
outnp4: pop es
ret
outtty endp
; enter with current terminal character in al.
; calls answerback routine if necessary.
; This can be used to make the emulator recognize any sequence.
ansbak proc near
push bx
mov bx,offset ansbk1 ; check 1st answerback
call ansbak0 ; check for answerback
mov bx,offset ansbk2 ; maybe second answerback
call ansbak0 ; should probably loop thru a table
mov bx,offset ansbk3
call ansbak0
mov bx,offset ansbk4
call ansbak0
mov bx,offset ansbk5
call ansbak0
mov bx,offset ansbk6
call ansbak0
mov bx,offset ansbk7
call ansbak0
mov bx,offset ansbk8
call ansbak0
mov bx,offset ansbk9
call ansbak0
mov bx,offset ansbk10
call ansbak0
mov bx,offset ansbk11
call ansbak0
mov bx,offset ansbk12
call ansbak0
mov bx,offset ansbk13
call ansbak0
mov bx,offset ansbk14
call ansbak0
pop bx
ret
ansbak0: ; worker routine for above
push ax ; preserve these
push si
mov si,[bx].anspt ; get current pointer
cmp al,[si] ; is it correct?
jne ansba1 ; no, reset pointers and go on
inc [bx].anspt ; increment pointer
dec [bx].ansct ; decrement counter
jnz ansba2 ; not done, go on
push bx
call [bx].ansrtn ; send answerback
pop bx
ansba1: mov ax,[bx].ansseq ; get original sequence
mov [bx].anspt,ax
mov al,[bx].anslen ; and length
mov [bx].ansct,al
ansba2: pop si
pop ax
ret
ansbak endp
; send the answerback message.
sndans proc near
push cx
mov si,offset ansret ; ansi ident message
mov cx,ansrln ; length of same
push es ; save seg register
mov ax,nvmseg ; fetch address of nvm
mov es,ax ; put in segment reg
test byte ptr es:[vt52mod],1 ; check bit zero
pop es ; restore the seg register
jnz sndan1 ; nz = ansi mode
mov si,offset VT52ret ; say VT52
mov cx,VT52ln
sndan1: cld
lodsb ; get a byte
mov ah,al
push si
push cx
call outchr ; send ah out the serial port
pop cx
pop si
loop sndan1
pop cx
ret
sndans endp
; enable alternate keypad mode
enaaky proc near
mov akeyflg,1 ; set keypad alternate mode
ret
enaaky endp
; disable alternate keypad mode
deaaky proc near
mov akeyflg,0
ret
deaaky endp
cuapp proc near
mov ckeyflg,1 ; set cursor keys to applications mode
ret
cuapp endp
cunapp proc near
mov ckeyflg,0 ; set cursor keys to cursor mode
ret
cunapp endp
; ESC c handler.
; Send a space so the firmware doesn't see bad escape sequences. [jrd]
sndspc proc near
mov akeyflg,0 ; reset keypad applications mode
mov ckeyflg,0 ; reset cursor applications mode
mov al,' ' ; space separates the ESC and 'c'
int fastcon ; send this to upset esc parser
push ax
call nxtbot ; go to end of screen buffer
call cmblnk ; clear the screen too
pop ax
clc
ret
sndspc endp
; answer a cursor position report
ansenq proc near
push es
push di
mov di,offset rdbuf ; convenient scratch buffer
mov al,escape
cld
push ds
pop es ; set es to data segment
stosb
mov al,'['
stosb
push es
mov ax,scrseg
mov es,ax
mov al,es:[csrlin]
mov ah,es:[csrcol]
pop es
push ax
xor ah,ah
call nout
mov al,';'
stosb
pop ax
xchg ah,al
xor ah,ah
call nout
mov al,'R'
stosb
mov si,offset rdbuf
sub di,si
mov cx,di
ansen1: lodsb ; get a byte
push si
push cx
mov ah,al
call outchr ; send it along
pop cx
pop si
loop ansen1 ; loop thru all
pop di
pop es
ret ; and return
ansenq endp
; set terminal to vt52 or vt102, based on current flags.vtflg [jrd]
setterm proc near
push es ; save seg register
mov ax,nvmseg ; fetch address of nvm
mov es,ax ; put in segment reg
test byte ptr es:[vt52mod],1 ; check bit zero
pop es ; restore the seg register
push ds
pop es ; set es to data segment
cld
jnz setter1 ; nz = ansi mode
cmp flags.vtflg,ttvt52 ; are we already a VT52?
je setterx ; e = nothing to do
mov si,offset dovt102 ; change from vt52 to VT102
jmp setter2
setter1:cmp flags.vtflg,ttvt100 ; already a VT102?
je setterx ; e = nothing to do
mov si,offset dovt52 ; change from vt102 to vt52
setter2:lodsb
cmp al,'$'
je setterx
push es
push si
int fastcon
pop si
pop es
jmp setter2
setterx:ret
setterm endp
; Handle the print screen key - copy whole screen to printer.
; Rewritten 26 June 1986 by [jrd] to avoid confusion over segment addressing
; and line length counting. Based on procedure dumpscr code.
; 30-Apr-1990 [gbs] convert line-drawing characters to ".". Otherwise, they
; output as control characters. (Could shift in/shift out if output
; printer is DEC printer.)
; 24-AUG-1990 [rhw-3] added translation table for VT100 graphics to chars
; a normal printer (even non-dec) can swollow. At least linedraw will
; come out looking like boxes, etc. See xlat_tab usage below...
; This replaces [gbs] change above.
;
prtscn proc near
push ax ; save some regs
push bx
push cx
push dx
push si
push di
push es
call pntflsh ; flush printer buffer now
xor bx,bx ; index for current line pointer
mov cx,slen ; number of screen lines
prtsc1: push cx ; save outer loop (lines to do) count
push bx ; save index value for bottom of loop
mov cx,swidth ; number of screen columns = 132
mov di,offset dumpbuf ; data segment memory (work buffer)
mov ax,scrseg ; make es hold screen segment
mov es,ax ; for inner read-a-row loop
mov si,es:[latofs+bx] ; get pointer to current line
and si,0fffh ; only 12 bits are significant
prtsc2: mov al,es:byte ptr [si] ; inner loop. read text char
mov byte ptr [di],al ; just store char, don't use es:
inc si ; update pointers (si needed below)
inc di
loop prtsc2 ; do for all 132 columns, fixed format
; find end of line, replace nulls with spaces
mov cx,swidth ; max chars in a line
mov di,offset dumpbuf ; look at start of line
prtsc3: mov al,byte ptr [di] ; get a byte into al
cmp al,0ffh ; end of line indicator?
je prtsc5 ; e = yes, exit with count left in cx
;; cmp al,0 ; is it a nasty null? x[rhw-3]
;; jne prtsc4 ; ne = no x[rhw-3]
;; mov al,' ' ; replace null with nice space x[rhw-3]
prtsc4: cmp al,' ' ; is it a ctrl (line-draw) char? [gbs]
jae prtsc4a ; ae = no
;; mov al,'.' ; if so, replace with "."[gbs], x[rhw-3]
mov dx,bx ; [rhw-3] save bx, need to use it
mov bx,offset xlat_tab ; [rhw-3] get ptr to xlation buffer
xlat ; [rhw-3] lookup & swap old for new char
mov bx,dx ; [rhw-3] restore bx
prtsc4a:mov byte ptr [di],al ; put back into buffer
inc di ; look ahead for next char
loop prtsc3 ; scan the rest of the line
prtsc5: dec di ; make di point at eol address
mov ax,swidth ; max line length
sub ax,cx ; minus chars scanned = length of line
mov cx,ax ; remember it here
; trim line of trailing spaces
mov ax,ds ; di needs to point to data space
mov es,ax ; string ops use es:di
mov al,' ' ; thing to scan over
std ; set scan backward
repe scasb ; scan until non-space, dec's di
cld ; set direction forward
jz prtsc6 ; z = all spaces (count was exhausted)
inc cx ; go forward over last non-space
inc di ; ditto for address
prtsc6: mov word ptr [di+1],0A0Dh ; append cr/lf
add cx,2 ; line count + cr/lf
mov dx,offset dumpbuf ; array to be written
mov bx,prnhand ; file handle of Connect mode printer
mov ah,write2 ; write the line
int dos
pop bx ; restore index for line pointer
inc bx ; add 2 for next pointer's location
inc bx
pop cx ; get line counter again
loop prtsc1 ; do next line (needs si preset)
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
clc
ret
prtscn endp
; toggle print flag. If turning on printing, check for printer ready; skip
; printing if not ready and beep the user. [jrd]
trnprs proc near
test ourflgs,fpscr ; printing currently?
jnz trnpr1 ; nz = yes, its on and going off
call ckprn ; see if printer is available
jc trnpr2 ; c = printer not ready
trnpr1: xor ourflgs,fpscr ; flip the flag
trnpr2: clc
ret
trnprs endp
; autoprint on
apon proc near
call ckprn ; printer ready?
jc apon1 ; c = printer not ready
or ourflgs,vtautop ; enable autoprint
apon1: clc
ret
apon endp
; autoprint off
apoff proc near
and ourflgs,not vtautop ; disable autoprint
ret
apoff endp
; print controller on
prconon proc near
call ckprn ; printer ready?
jc pcon1 ; c = printer not ready
or ourflgs,vtcntp ; enable print controller
pcon1: clc
ret
prconon endp
; print controller off
pconoff proc near
and ourflgs,not vtcntp ; disable print controller
ret
pconoff endp
; check for printer ready -
; if not ready, return carry and beep
ckprn proc near
push ax
mov ah,ioctl
mov al,7 ; get output status of printer
push bx
mov bx,prnhand ; file handle for system printer
int dos
pop bx
jc ckprn1 ; not ready...return carry
cmp al,0ffh ; Ready status?
jnz ckprn1 ; nz ==> not ready
clc ; show ready
jmp ckprn2
ckprn1: call beep ; let someone know
stc ; indicate not ready
ckprn2: pop ax
ret
ckprn endp
; Save the screen to a buffer and then append buffer to a disk file. [jrd]
; Default filename is Kermit.scn; actual file can be a device too. Filename
; is determined by mssset and is passed as pointer dmpname.
; Modified 1 Sept 1986 to do test for dump destination being ready. [jrd]
; Modified 24-AUG-90 [rhw-3] added translation table for VT100 graphics
; to normal ascii chars. This will make the dump file readable &
; printable on any printer (even non-dec). Now linedraw chars will
; come out looking like boxes, etc. See xlat_tab usage below...
dumpscr proc near ; global dump-screen procedure
push ax
push bx
push cx
push dx
call savscr ; first, save screen to memory
mov dmphand,-1 ; preset illegal handle
mov dx,offset dmpname ; name of disk file, from mssset
mov ax,dx ; where isfile wants name ptr
call isfile ; what kind of file is this?
jc dmp5 ; c = no such file, create it
test byte ptr filtst.dta+21,1fh ; file attributes, ok to write?
jnz dmp0 ; nz = no.
mov al,1 ; writing
mov ah,open2 ; open existing file
int dos
jc dmp0 ; c = failure
mov dmphand,ax ; save file handle
mov bx,ax ; need handle here
mov cx,0ffffh ; setup file pointer
mov dx,-1 ; and offset
mov al,2 ; move to eof minus one byte
mov ah,lseek ; seek the end
int dos
jmp dmp1
dmp5: test filtst.fstat,80h ; access problem?
jnz dmp0 ; nz = yes
mov ah,creat2 ; file did not exist
mov cx,20h ; attributes, archive bit
int dos
mov dmphand,ax ; save file handle
jnc dmp1 ; nc = ok
dmp0: mov dx,offset dmperr ; say no can do
mov ah,prstr
int dos
pop dx
pop cx
pop bx
pop ax
clc
ret
; read screen buffer (132 char/line), write lines to file
dmp1: mov ah,ioctl ; is destination ready for output?
mov al,7 ; test output status
mov bx,dmphand ; handle
int dos
jc dmp0 ; c = error
cmp al,0ffh ; ready?
jne dmp0 ; ne = not ready
push di ; save regs around this work
push si
mov si,ourscr ; buffer where screen was stored
mov cx,slen ; number of saved screen lines
dmp2: push cx ; save outer loop counter
mov di,offset dumpbuf ; data segement memory (work buffer)
mov cx,swidth ; number of screen columns = 132
dmp3: mov al,byte ptr [si] ; read text char
mov byte ptr [di],al ; store just char, don't use es:
inc si ; update pointers (si needed below)
inc di
loop dmp3 ; do for all 132 columns, fixed format
; find end of line, replace nulls with spaces
mov cx,swidth ; max chars in a line
mov di,offset dumpbuf ; look at start of line
dmp7: mov al,byte ptr [di] ; get a byte into al
cmp al,0ffh ; end of line indicator?
je dmp9 ; e = yes, exit with count left in cx
;; cmp al,0 ; is it a nasty null? x[rhw-3]
;; jne dmp8 ; ne = no x[rhw-3]
;; mov al,' ' ; replace null with nice space x[rhw-3]
cmp al,' ' ; [rhw-3] see if unprintable
jae dmp8 ; [rhw-3] if its >= space then ok
mov dx,bx ; [rhw-3] save bx, need to use it
mov bx,offset xlat_tab ; [rhw-3] get ptr to xlation buffer
xlat ; [rhw-3] lookup & swap old for new char
mov bx,dx ; [rhw-3] restore bx
dmp8: mov byte ptr [di],al ; put back into buffer
inc di ; look ahead for next char
loop dmp7 ; scan the rest of the line
dmp9: dec di ; make di point at eol address
mov ax,swidth ; max line length
sub ax,cx ; minus chars scanned = length of line
mov cx,ax ; remember it here
; trim line of trailing spaces
push es ; save register
mov ax,ds ; di needs to point to data space
mov es,ax ; string ops use es:di
mov al,' ' ; thing to scan over
std ; set scan backward
repe scasb ; scan until non-space, dec's di
cld ; set direction forward
pop es ; restore reg
jz dmp3a ; z = all spaces (count was exhausted)
inc cx ; go forward over last non-space
inc di ; ditto for address
dmp3a: mov word ptr [di+1],0A0Dh ; append cr/lf
add cx,2 ; line count + cr/lf
mov dx,offset dumpbuf ; array to be written
mov bx,dmphand ; need file handle
mov ah,write2 ; write the line
int dos
pop cx ; get line counter again
loop dmp2 ; do next line (needs si preset)
mov dx,offset dumpsep ; put in formfeed/cr/lf
mov cx,3 ; three bytes overall
mov ah,write2
mov bx,dmphand
int dos
mov ah,close2 ; close the file now
int dos
pop si
pop di
pop dx
pop cx
pop bx
pop ax
clc
ret
dumpscr endp
; Send a character to the host, handle local echo
sndhst proc near
push ax ; save the character
mov ah,al
call outchr ; send char in ah out the serial port
pop ax
test ourarg.flgs,lclecho ; echoing?
jz sndhs2 ; z = no, exit
call outtty ; echo to screen
sndhs2: ret
sndhst endp
; print a message to the screen. Returns normally.
; also puts the terminal into vt100 mode so our escape sequences work...
tmsg proc near
push es
push bx
mov bx,nvmseg
mov es,bx ; address firmware
mov bl,0f1h ; turn on vt100 mode
xchg bl,es:[vt52mod] ; remember old mode
mov ah,prstr
int dos
mov es:[vt52mod],bl ; restore mode
pop bx
pop es
ret
tmsg endp
; save the screen for later
savscr proc near
push es
push ds
call kilcur ; turn off cursor
mov di,ourscr ; place to save screen
mov dx,ourattr ; and to save attributes
mov ax,ds
mov es,ax ; save buffer is in data space (ds seg)
mov cx,slen ; # of lines to do
mov ax,scrseg
mov ds,ax
mov bx,0 ; current line #
savsc1: push cx ; save current count
mov si,ds:[latofs+bx] ; get line ptr
and si,0fffh ; ptr is in 12 bits
push si ; save pointer
mov cx,swidth/2 ; # of words/line, [RHW-5] swidth always even
cld
rep movsw ; [RHW-4] copy it out by words
pop si ; restore pointer
add si,attoffs ; this is where attributes start
xchg dx,di ; this holds attribute ptr
mov cx,swidth/2 ; # of words of attrs to move, [RHW-5]
rep movsw ; [RHW-4] copy words at a time (quicker)
xchg dx,di
pop cx ; restore counter
add bx,2 ; increment line ptr
loop savsc1 ; save all lines and attributes
pop ds
call rstcur ; put cursor back
call savpos ; might as well save cursor pos
pop es
ret
savscr endp
; restore the screen saved by savscr
rstscr proc near
call cmblnk ; start by clearing screen
mov si,ourscr ; point to saved screen
mov dx,ourattr ; and attributes
mov cx,slen ; # of lines/screen
mov bx,101H ; start at top left corner
rstsc1: push bx
push cx
push si ; save ptrs
push dx
mov ax,si ; this is source
call prlina ; print the line
pop dx
pop si
pop cx
pop bx
add si,swidth ; point to next line
add dx,swidth ; and next attributes
inc bx ; address next line
loop rstsc1 ; keep restore lines
call rstpos ; don't forget position
ret
rstscr endp
; Put a line into the circular buffer. Pass the buffer structure in bx.
; Source is srcseg:si
; Rewritten by [jrd]
putcirc proc near
push es
push di
push cx
mov cl,swidth ; number of columns
xor ch,ch
mov es,[bx].orig ; get segment of memory area
cmp bx,offset bwnd ; bottom buffer?
je putci6 ; e = yes
mov di,twnd.pp ; pick up buffer ptr (offset from es)
add di,cx ; increment to next available slot
add di,cx ; char and attribute
cmp di,twnd.bend ; would line extend beyond buffer?
jb putci1 ; b = not beyond end
mov di,0 ; else start at the beginning
putci1: mov twnd.pp,di ; update ptr
cld ; set direction to forward
mov cx,swidth
push ds ; save regular data seg reg
mov ds,srcseg ; use source segment for ds:si
rep movsw ; copy into buffer
pop ds ; restore regular data segment
mov cx,twnd.lmax ; line capacity of buffer
dec cx ; minus one work space line
cmp twnd.lcnt,cx ; can we increment line count?
jae putci1b ; ae = no, keep going
inc twnd.lcnt ; else count this line
putci1b:cmp bwnd.lcnt,0 ; any lines in bottom buffer?
je putci2 ; e = no
mov cx,bwnd.pp ; see if we overlap bot buf
cmp cx,twnd.pp ; is this line in bot buf area?
jne putci2 ; ne = no
add cl,swidth ; move bottom pointer one slot earlier
adc ch,0
add cl,swidth ; words
adc ch,0
cmp cx,bwnd.bend ; beyond end of buffer?
jb putci1a ; b = no
mov cx,0 ; yes, start at beginning of buffer
putci1a:mov bwnd.pp,cx ; new bottom pointer
dec bwnd.lcnt ; one less line in bottom buffer
putci2: pop cx
pop di
pop es
ret
putci6: ; bottom buffer
add cx,cx ; words worth
cmp bwnd.lcnt,0 ; any lines in the buffer yet?
jne putci7 ; ne = yes
mov di,twnd.pp ; get latest used slot of top buff
add di,cx ; where first free (?) slot starts
cmp di,bwnd.bend ; are we now beyond the buffer?
jb putci6a ; b = no
mov di,0 ; yes, start at beginning of buffer
putci6a:add di,cx ; start of second free (?) slot
cmp di,bwnd.bend ; are we now beyond the buffer?
jb putci6b ; b = no
mov di,0 ; yes, start at beginning of buffer
putci6b:mov cx,twnd.lmax ; buffer line capacity
sub cx,twnd.lcnt ; minus number used by top buffer
sub cx,2 ; minus one work slot and one we need
cmp cx,0 ; overused some slots?
jge putci8 ; ge = enough to share
add twnd.lcnt,cx ; steal these from top window beginning
jmp short putci8
putci7: mov es,bwnd.orig ; get segment of memory area
mov di,bwnd.pp ; pick up buffer ptr (offset from es)
cmp di,0 ; would line start before buffer?
jne putci7a ; ne = after start of buffer
mov di,bwnd.bend ; else start at the end minus one slot
inc di
putci7a:sub di,cx
putci8: mov bwnd.pp,di ; update ptr (this is latest used slot)
mov cl,swidth
xor ch,ch
cld ; set direction to forward
push ds ; save regular data seg reg
mov ds,srcseg ; use source segment for ds:si
rep movsw ; copy into buffer
pop ds ; restore regular data segment
mov cx,bwnd.lmax ; line capacity of buffer
cmp bwnd.lcnt,cx ; can we increment line count?
jae putci8b ; ae = no, keep going
inc bwnd.lcnt ; else count this line
putci8b:cmp twnd.lcnt,0 ; any lines in top line buf?
je putci9 ; e = no
mov cx,twnd.pp ; yes, see if we used last top line
cmp cx,bwnd.pp ; where we just wrote
jne putci9 ; not same place, so all is well
dec twnd.lcnt ; one less line in top window
cmp cx,0 ; currently at start of buffer?
jne putci8a ; ne = no
mov cx,twnd.bend ; yes
inc cx
putci8a:sub cl,swidth ; back up top window
sbb ch,0
sub cl,swidth ; by one line
sbb ch,0
mov twnd.pp,cx ; next place to read
putci9: pop cx
pop di
pop es
ret
putcirc endp
; Get a line from the circular buffer, removing it from the buffer.
; returns with carry on if the buffer is empty.
; Pass the buffer structure in bx.
; Destination preset in es:di.
; Rewritten by [jrd]
getcirc proc near
cmp [bx].lcnt,0 ; any lines in buffer?
jne getci1 ; ne = yes, ok to take one out
stc ; else set carry
ret ; and return
getci1: push cx ; top and bottom window common code
push si
mov cl,swidth ; # of chars to copy
xor ch,ch
push di ; save destintion offset
push cx ; save around calls
mov si,[bx].pp ; this is source
cld ; set direction to forward
push ds ; save original ds
mov ds,[bx].orig ; use seg address of buffer for si
rep movsw
pop ds ; recover original data segment
pop cx ;
pop di ; recover destination offset
push cx ; save again
mov si,[bx].pp ; get ptr again
pop cx
add cx,cx ; words
cmp bx,offset bwnd ; bottom window?
je getci6 ; e = yes
sub si,cx ; top window, move back
jnc getcir2 ; nc = still in buffer, continue
mov si,twnd.bend ; else use end of buffer
sub si,cx ; minus length of a piece
inc si
getcir2:mov twnd.pp,si ; update ptr
dec twnd.lcnt ; decrement # of lines in buffer
pop si
pop cx
clc ; make sure no carry
ret
getci6: ; bottom window
add si,cx ; words, move back (bot buf = reverse)
cmp si,bwnd.bend ; still in buffer?
jb getci7 ; b = yes
mov si,0 ; else use beginning of buffer
getci7: mov bwnd.pp,si ; update ptr
dec bwnd.lcnt ; decrement # of lines in buffer
pop si
pop cx
clc ; make sure no carry
ret
getcirc endp
; prepares for scrolling by saving the top line in topbuf.
scrprep proc near
push ax ; save regs
push es
cmp al,cr ; carriage return?
je scrpr3 ; yes, will never change line
cmp al,lf ; outputting a linefeed?
je scrpr2 ; yes, will change line
mov ax,scrseg
mov es,ax ; address screen segment
test es:byte ptr [curlin],wrpend ; wrap pending?
jz scrpr3 ; no, forget it
mov ax,nvmseg
mov es,ax
test es:byte ptr [autwrp],1 ; auto-wrap mode?
jz scrpr3 ; no, forget this
; about to change lines, see if bottom line
scrpr2: mov ax,scrseg
mov es,ax
cmp es:byte ptr [csrlin],slen ; are we at the bottom?
je scrpr4 ; yes, have to save line
scrpr3: pop es ; get here if not saving line
pop ax
ret
scrpr4: pop es ; restore registers
pop ax
; alternate entry that doesn't check if we're on the bottom row.
savtop: push ax ; save ax
push bx
push cx
push si
push di
call kilcur ; kill cursor
push es
push ds
mov ax,ds
mov es,ax
mov ax,scrseg
mov ds,ax ; address screen segment
mov si,ds:word ptr [l1ptr] ; get ptr to top line
and si,0fffh ; only 12 bits are significant
push si
mov di,offset topline ; this is where it goes
mov cx,swidth/2 ; # of words to copy, [RHW-5]
cld
rep movsw ; [RHW-4] get the top line
pop si ; restore pointer
add si,attoffs ; add offset of attributes
mov cx,swidth/2 ; [RHW-5] # words to copy (swidth even)
rep movsw ; [RHW-4] get the top line's attributes
pop ds
pop es ; restore segments
mov srcseg,seg topline ; set segment of source
mov si,offset topline ; set offset of source
mov bx,offset twnd ; buffer structure pointer
call putcirc ; put into circular buffer
call rstcur
pop di
pop si
pop cx
pop bx
pop ax ; restore character in ax
ret ; and return
scrprep endp
; get the screen's bottom line into the buffer in ax.
getbot proc near
push cx
push si
push di
push es
push ds
push ax ; save destination on the stack
call kilcur ; kill cursor
push ds
pop es
mov si,scrseg
mov ds,si
mov si,ds:word ptr [llptr] ; get ptr to bottom line
and si,0fffh ; only 12 bits are pointer
pop di ; destination is on stack
push si ; preserve pointer
mov cx,swidth/2 ; # of words to copy [RHW-5]
cld
rep movsw ; [RHW-4] get the top line
pop si ; get pointer back
add si,attoffs ; this is where attributes are
mov cx,swidth/2 ; [RHW-5] # words to copy
rep movsw ; [RHW-4] get the top line
pop ds ; restore segments
pop es
call rstcur ; restore cursor
pop di
pop si
pop cx
ret
getbot endp
; handle the previous screen button...
prvscr proc near
mov cx,slen
cmp twnd.lcnt,cx
jge prvs1
mov cx,twnd.lcnt
prvs1: jcxz prvs2
call prvlin
loop prvs1
prvs2: clc
ret
prvscr endp
; handle the next screen button...
nxtscr proc near
mov cx,slen
cmp bwnd.lcnt,cx
jge nxts1
mov cx,bwnd.lcnt
nxts1: jcxz nxts2
call nxtlin
loop nxts1
nxts2: clc
ret
nxtscr endp
; save a screen by rolling them into a circular buffer.
; enter with ax/ circular buffer ptr, bx/ first line to get
; dx/ increment
rolscr proc near
mov cx,slen ; # of lines to save
cmp cx,[bx].lcnt ; enough space left in this buffer?
jbe rolsc0 ; be = enough
mov cx,[bx].lcnt ; use only as many as we have
jcxz rolscx ; z = none, so quit here
rolsc0: shl dx,1 ; double increment for word ptr
dec bx ; ptr starts at 0
shl bx,1 ; convert to word ptr
push es
push ds
pop es ; set es to data segment
mov temp,0 ; save number of lines done
rolsc1: push cx
push dx
push bx
push ax
push ds
call kilcur ; kill cursor
mov di,offset rlbuf
mov ax,scrseg
mov ds,ax ; address screen
mov si,ds:[latofs+bx] ; get current line
and si,0fffh ; ptr is in 12 bits
push si ; save pointer
mov cx,swidth/2 ; # of words to move, [RHW-5]
rep movsw ; [RHW-4] get the line
pop si ; restore pointer
add si,attoffs ; where attributes start
mov cx,swidth/2 ; # of bytes to move, [RHW-5]
rep movsw ; [RHW-4] move attributes as well
pop ds ; restore segment
call rstcur ; restore cursor
pop bx ; this is desired circ buffer ptr
mov srcseg,seg rlbuf ; segment of source
mov si,offset rlbuf ; offset of source
call putcirc ; save in circular buffer
mov ax,bx ; put buffer ptr back where it belongs
pop bx ; get line pos back
pop dx ; and increment
pop cx ; don't forget counter
add bx,dx ; move to next line
inc temp
loop rolsc1 ; loop thru all lines
pop es
rolscx: ret ; and return
rolscr endp
; move screen down a line, get one previous line back
prvlin proc near ; get the previous line back
push ax
push bx
push dx
cmp twnd.lcnt,0 ; any lines in top window?
je prvli1 ; e = no, ignore request
mov ax,offset botline ; place for bottom line
call getbot ; fetch bottom line
mov srcseg,seg botline ; segement of source
mov si,offset botline ; offset of source
mov bx,offset bwnd ; buffer structure pointer
call putcirc ; save in circular buffer
mov bx,offset twnd ; source structure
push es
mov di,seg topline
mov es,di
mov di,offset topline ; es:di is address of destination
call getcirc ; try to get a line
pop es
jc prvli1 ; no more, just return
call savpos ; save cursor position
call kilcur ; turn off cursor
mov dx,offset topdwn ; home, then reverse index
call tmsg
mov ax,offset topline ; point to data
mov bx,0101H ; print line at top of screen
mov dx,ax
add dx,swidth
call prlina ; print the line
call rstcur
call rstpos ; restore cursor position
prvli1: pop dx
pop bx
pop ax
clc
ret ; and return
prvlin endp
; move screen up a line, get one bottom line back
nxtlin proc near
push ax
push bx
push dx
cmp bwnd.lcnt,0 ; any lines in bottom window?
je nxtli1 ; e = no
mov bx,offset bwnd ; source structure
push es
mov di,seg botline
mov es,di
mov di,offset botline ; es:di is address of destination
call getcirc ; try to get a line
pop es
jc nxtli1 ; no more, just return
call savtop ; save one line off of top
call savpos ; save cursor position
call kilcur ; turn off cursor
mov dx,offset botup ; go to bottom, then scroll up a line
call tmsg
mov ax,offset botline ; point to data
mov bx,0100H + slen ; print at bottom line
mov dx,ax
add dx,swidth
call prlina ; print the line
call rstcur ; turn cursor back on
call rstpos ; restore cursor position
nxtli1: pop dx
pop bx
pop ax
clc
ret
nxtlin endp
; move screen up until no more saved in bottom buffer [jrd]
nxtbot proc near
push cx
mov cx,bwnd.lcnt ; number of pages of scroll back memory
nxtbot1:push cx
call nxtlin
pop cx
loop nxtbot1 ; do all pages
pop cx
clc
ret
nxtbot endp
nxttop proc near ; move to top of screen buffer memory [jrd]
push cx
mov cx,twnd.lcnt ; number of pages of scroll back memory
nxttop1:push cx
call prvlin
pop cx
loop nxttop1 ; do all pages
pop cx
clc
ret
nxttop endp
; save cursor position
savpos proc near
push di
mov dx,offset curinq ; where is the cursor?
call tmsg
mov posbuf,escape ; put an escape in the buffer first
mov di,offset posbuf+1
savpo1: mov ah,8 ; read, no echo
int dos
cld
cmp al,'R' ; end of report?
je savpo2 ; yes
stosb ; no, save it
jmp short savpo1 ; and go on
savpo2: mov al,'H' ; this ends the sequence when we send it
stosb
mov byte ptr [di],'$' ; need this to print it later
pop di
ret
savpos endp
; restore the position saved by savpos
rstpos proc near
mov dx,offset posbuf
call tmsg ; just print this
ret
rstpos endp
; kill cursor so it doesn't get saved along with real data
kilcur proc near
push ax
push bx
push cx
push dx
push si
push es
push di
mov di,kcurfn
int firmwr
pop di
pop es
pop si
pop dx
pop cx
pop bx
pop ax
ret
kilcur endp
; restore the cursor
rstcur proc near
push ax
push bx
push cx
push dx
push si
push es
push di
mov di,rcurfn
int firmwr
pop di
pop es
pop si
pop dx
pop cx
pop bx
pop ax
ret
rstcur endp
; print a ff-terminated line at most swidth long... Pass the line in ax.
; cursor position should be in bx.
; prlina writes attributes as well, which should be passed in dx.
prlin proc near
mov bp,2 ; print characters only
jmp short prli1
prlina: xor bp,bp ; 0 means print attributes as well
prli1: push es ; this trashes es!!!
push ax ; save regs
push cx
push es
mov cx,scrseg
mov es,cx ; address screen seg for a moment
mov cl,es:byte ptr [rmargin] ; get max line length
mov ch,0
pop es ; address user's segment again
push cx ; remember original length
mov si,ax ; better place for ptr
mov di,ax ; need it here for scan
mov al,0ffh ; this marks the end of the line
cld
repne scasb ; look for the end
jne prli2 ; not found
inc cx ; account for pre-decrement
prli2: neg cx
pop ax ; get original length back
add cx,ax
; add cx,swidth ; figure out length of line
jcxz prli3 ; 0-length line, skip it
mov ax,bp ; writing characters
mov bp,ds ; wants segment here
push bx
push dx
push si
push di
mov di,14H ; fast write to screen
int firmwr
pop di
pop si
pop dx
pop bx
prli3: pop cx ; restore registers
pop ax
pop es
ret
prlin endp
; action routines for keyboard translator.
; These are invoked by a jump instruction. Return carry clear for normal
; processing, return carry set for invoking Quit (kbdflg has transfer char).
uparrw: mov al,'A' ; cursor keys
jmp short comarr
dnarrw: mov al,'B'
jmp short comarr
rtarr: mov al,'C'
jmp short comarr
lfarr: mov al,'D'
comarr: push ax ; save final char
mov al,escape ; Output an escape
call sndhst ; Output, echo permitted
push es ; save seg register
mov ax,nvmseg ; fetch address of nvm
mov es,ax ; put in segment reg
test byte ptr es:[vt52mod],1 ; check bit zero
pop es ; restore the seg register
jnz comar1 ; nz = ansi mode
jmp comar3 ; VT52 mode
comar1: mov al,'[' ; Maybe this next?
cmp ckeyflg,0 ; applications cursor mode?
je comar2 ; e = no
mov al,'O' ; applications mode
comar2: call sndhst ; Output it (echo permitted)
comar3: pop ax ; recover final char
call sndhst ; Output to port (echo permitted)
clc
ret
pf1: mov al,'P' ; keypad function keys
jmp short compf
pf2: mov al,'Q'
jmp short compf
pf3: mov al,'R'
jmp short compf
pf4: mov al,'S'
compf: push ax ; save final char
mov al,escape ; Output an escape
call prtbout
push es ; save seg register
mov ax,nvmseg ; fetch address of nvm
mov es,ax ; put in segment reg
test byte ptr es:[vt52mod],1 ; check bit zero
pop es ; restore the seg register
jz compf1 ; z = VT52 mode
mov al,'O' ; send an "O" in ansi mode
call prtbout ; Output it
compf1: pop ax ; Get the saved char back
call prtbout ; Output to port
clc
ret
kp0: mov al,'p' ; keypad numeric keys
jmp short comkp
kp1: mov al,'q'
jmp short comkp
kp2: mov al,'r'
jmp short comkp
kp3: mov al,'s'
jmp short comkp
kp4: mov al,'t'
jmp short comkp
kp5: mov al,'u'
jmp short comkp
kp6: mov al,'v'
jmp short comkp
kp7: mov al,'w'
jmp short comkp
kp8: mov al,'x'
jmp short comkp
kp9: mov al,'y'
jmp short comkp
kpminus:mov al,'m'
jmp short comkp
kpcoma: mov al,'l'
jmp short comkp
kpenter:mov al,'M'
jmp short comkp
kpdot: mov al,'n'
comkp: cmp akeyflg,0 ; alternate keypad mode?
jne comkp1 ; ne = yes
sub al,'p'-'0' ; change to numeric codes
jmp comkp3 ; and send just the ascii char
comkp1: push ax ; save final char
mov al,escape ; Output an escape
call prtbout
mov al,3fh ; Output the "?" in VT52 mode
push es ; save seg register
mov cx,nvmseg ; fetch address of nvm
mov es,cx ; put in segment reg
test byte ptr es:[vt52mod],1 ; check bit zero
pop es ; restore the seg register
jz comkp2 ; z = VT52 mode
mov al,'O' ; Output the "O" in ansi mode
comkp2: call prtbout
pop ax ; recover final char
comkp3: call prtbout ; send it
clc
ret
snull proc near ; send a null byte
mov al,0 ; the null
call prtbout ; send without logging and local echo
clc
ret
snull endp
chrout: push es ; save segment
push bx
mov bx,nvmseg ; point to nvm
mov es,bx ; set the segment
test byte ptr es:[newlmod],1 ; check if we are set to new line
pop bx
pop es ; restore the segment register
jz chrout1 ; just send the cr if bit is off
call sndhst ; else send the carriage return first
mov al,lf ; then the line-feed
chrout1:call sndhst ; send char in al to serial port
clc ; for keyboard translator
ret ; can echo and log
prtbout:mov ah,al ; output char with no echo
call outchr ; outchr works with ah
ret
cdos: mov al,'P' ; Connect mode help screen items
jmp short cmdcom
cstatus:mov al,'S' ; these commands invoke Quit
jmp short cmdcom
cquit: mov al,'C' ; C = exit connection
jmp short cmdcom
cquery: mov al,'?' ; help
jmp short cmdcom
chang: mov al,'H' ; Hangup, drop DTR & RTS
jmp short cmdcom
cmdcom: mov kbdflg,al ; pass char to msster.asm via kbdflg
stc ; signal that Quit is needed
ret
klogon proc near ; resume logging (if any)
test flags.capflg,logses ; session logging enabled?
jz klogn ; z = no, forget it
or ourarg.flgs,capt ; turn on capture flag
or argadr.flgs,capt ; permanent argument array too
klogn: clc
ret
klogon endp
klogof proc near ; suspend logging (if any)
and argadr.flgs,not capt ; stop capturing
and ourarg.flgs,not capt ; stop capturing
klogo: clc
ret
klogof endp
code ends
end