home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Between Heaven & Hell 2
/
BetweenHeavenHell.cdr
/
300
/
257
/
msxapc.asm
< prev
next >
Wrap
Assembly Source File
|
1984-12-18
|
46KB
|
1,602 lines
; ************ START MSXAPC.ASM ***********************************
; Kermit system dependent module for NEC Advanced Personal Computer (APC)
; Ron Blanford, University of Washington, August 1984
; Modified to get key scan codes directly from fifo buffer in IO.SYS
; This version works with MS-DOS Versions 2.00 (000) and 2.11 (001); it
; should work with future MS-DOS revisions so long as NECIS maintains
; the configuration table in IO.SYS - the thing most apt to fail is the
; key autorepeat because kbrepflg is furthest from a hook in config table.
; If this happens the equate for offset of kbrepflg will need adjusting.
; Ian Gibbons, University of Hawaii, 10/26/84
; Fixed incorrect timer command port assignment so that program will run
; under MS-DOS 2.00 as well as 2.11.
; Added autodetermination of color/mono using crttype byte in IO.SYS; this
; works only under DOS 2.11 (and future above ?)
; IG 10/28/84
; Added direct CRT I/O handling through BIOS in order to increase speed and
; flexibility of help menus. It gives only an imitation window but it works
; fairly well.
; IG 10/31/84
; Added simplified mode line data to the [Connecting to host...]" line which
; has been moved here from MSTERM in order to have more system dependent
; control.
; IG 11/4/84
; Make unredefined break/stop key act as a scroll/noscroll key in telnet by
; sending alternately a ^S and a ^Q.
; IG 11/5/84
; By now code for this MSXAPC module could well be divided into separate
; transmission and terminal modules, but I don't want to spend more time
; on it. It's not as readable as it might be, but so far as I know
; everything works.IG 11/6/84
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, lclrst, prtchr, dobaud,
public discon, clearl, dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
false equ 0
true equ 1
BIOS EQU 0DCH ; NEC-APC BIOS interrupt call
fifoclr equ 6 ; clears keyboard fifo buffer
crtcmd equ 7 ; Direct CRT I/O command call
; port assignments for 8251 serial controllers
; Standard interface
mndata equ 30H ; Data port (read/write)
mnst1a equ 32H ; Status port (when read)
mncmda equ 32H ; Command port (when written)
mnst2a equ 34H ; Alternate status port (when read)
mnmska equ 34H ; Mask port (when written)
mntdca equ 36H ; Transmit disable port (write only)
; Optional (H14) interface
mndatb equ 31H ; Data port (read/write)
mnst1b equ 33H ; Status port (when read)
mncmdb equ 33H ; Command port (when written)
mnst2b equ 35H ; Alternate status port (when read)
mnmskb equ 35H ; Mask port (when written)
mntdcb equ 37H ; Transmit disable port (write only)
; Status bits from mnst1
txrdy equ 01H ; Bit for output ready.
rxrdy equ 02H ; Bit for input ready.
; Command values for mncmd
ccmd equ 37H ; RTS & DTR high, RX & TX enabled, reset ERR
cbrk equ 08H ; break enabled
cmode equ 40H ; enable mode reset
mmode equ 4EH ; 16x rate, 8 data, no parity, 1 stop
; Mask values for mnmsk
txmsk equ 01H ; disables transmit ready interrupt
rxmsk equ 02H ; disables receive ready interrupt
tbemsk equ 04H ; disables transmit buffer empty interrupt
; port assignments for 8253 timers
; Standard interface
tmdata equ 2BH ; data port
tmcmda equ 2FH ; command port (Was 27H Ian 10/27/84)
; Optional (H14) interface
tmdatb equ 61H ; data port
tmcmdb equ 67H ; command port
; values for tmcmd which select timer channel and mode
tmsela equ 76H ; Channel 1, mode 3 (standard port)
tmselb equ 36H ; Channel 0, mode 3 (optional port)
; Timer information for current port selection
tmrinfo struc
tmdat dw 0 ; data port
tmcmd dw 0 ; command port
tmsel db 0 ; byte which selects channel and mode
tmrinfo ends
; port assignments for 8259 interrupt controllers
; Standard interface
intcmda equ 20H ; Command port (master controller)
intmska equ 22H ; Mask port
ictmsk equ 08H ; Timer interrupt mask (to master)
icsmska equ 02H ; Standard serial interrupt mask (to master)
icsvcta equ 11H ; Interrupt vector for standard interface
; Optional (H14) interface
; The interrupt request vector for the optional (H14) serial interface is
; jumper-selectable to any of vectors IR2, IR5, IR8, or IR12. NEC recommends
; that IR8 be used, so that has been selected as the default here. To use
; any of the other vectors, set the following conditionals appropriately.
; Only one of the following should be true:
IR2 equ false ; interrupt vector 2
IR5 equ false ; interrupt vector 5
IR8 equ true ; interrupt vector 8
IR12 equ false ; interrupt vector 12
IF IR2
intcmdb equ 20H ; Command port (master controller)
intmskb equ 22H ; Mask port
icsmskb equ 04H ; Interrupt mask
icsvctb equ 12H ; Interrupt table index
ENDIF
IF IR5
intcmdb equ 20H ; Command port (master controller)
intmskb equ 22H ; Mask port
icsmskb equ 20H ; Interrupt mask
icsvctb equ 15H ; Interrupt table index
ENDIF
IF IR8
intcmdb equ 28H ; Command port (slave controller)
intmskb equ 2AH ; Mask port
icsmskb equ 02H ; Interrupt mask
icsvctb equ 19H ; Interrupt table index
ENDIF
IF IR12
intcmdb equ 28H ; Command port (slave controller)
intmskb equ 2AH ; Mask port
icsmskb equ 20H ; Interrupt mask
icsvctb equ 1DH ; Interrupt table index
ENDIF
crtinfo struc ; Structure for color/mono formatting info
nrmseq db esc,'[0m$' ; Default
invseq db esc,'[7m$000' ; Inverse (extra space for color)
bldseq db esc,'[17m$' ; Bold video
nrmcrt dw 8080H ; Normal data for direct crt i/o
bldcrt dw 9090H ; Inverse data for direct crt i/o
crtinfo ends
icEOI equ 20H ; generic end of interrupt for intcmd
kbfifosiz equ 64 ; size of fifo buffer in IO.SYS
; miscellaneous constants
ctrlP equ 10H ; ^P.
ctrl_q equ 11H ; ^Q
ctrl_s equ 13H ; ^S
printkey equ 00FFH ; Scan code of unshifted PRINT key.
brkstp equ 0096H ; Scan code of unshifted break/stop key.
mntrgh equ bufsiz*3/4 ; High XON/XOFF trigger = 3/4 of buffer full.
; external variables used:
; drives - # of disk drives on system
; 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.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'NEC APC$'
nyimsg db cr,lf,'Not implemented$'
badbd db cr,lf,'Unimplemented baud rate$'
bdkscn db cr,lf,'Unable to install key translate table'
db cr,lf,'Possibly incompatible MS-DOS version',cr,lf
db cr,lf,'(MS-KERMIT can be used without keyboard translation'
db ' feature)',cr,lf,'$'
nokbtr db cr,lf,'No key translation table is installed$'
prtmsg db cr,lf,'You cannot redefine the PRINT key$'
escmsg db cr,lf,'You cannot redefine the current CTRL-ESCAPE key$'
hngcfm db cr,lf,'Please confirm DISCONNECT command. (Y/N) $'
dismsg db cr,lf,'Disconnecting for 3 seconds',cr,lf,'$'
rcnmsg db cr,lf,'Reconnected',cr,lf,'$'
cnmsg db cr,lf,'Connecting to host at '
cnmsgb db ' '
db ' baud on port '
cnmsgp db ' ',cr,lf,'(Type $'
cnmsg1 db ' C to return to PC)',cr,lf,lf,lf,'$'
crlf db cr,lf,'$'
delstr db BS,' ',BS,'$' ; Delete string.
clrlin db cr,'$' ; Clear line (just the cr part).
ceolseq db esc,'[K$' ; Clear to end of line
cpseq db esc,'=rc' ; rc replaced by row and column before display
clrseq db 01EH,01AH,'$' ; Home cursor and clear screen
lstpos dw 0 ; column position for printer echoing
; Storage for color and mono formatting strings
nrmcol db esc,'[0m$'
invcol db esc,'[3;21m$' ; Yellow with green overline
bldcol db esc,'[21m$' ; Yellow
ncrtcol dw 8080H ; Green
bcrtcol dw 0A0A0H ; Yellow
;nrmmon db esc,'[0m$'
;invmon db esc,'[7m$000' ; Inverse video
;bldmon db esc,'[17m$' ; Bold video
;ncrtmon dw 8080H ; Normal green
;bcrtmon dw 9090H ; Inverse video
formdat crtinfo <>
formdtl db $-formdat
nocur db esc,'[>5h$' ; Disable cursor
recur db esc,'[>5l$' ; Reenable cursor
storcur db esc,'[s$' ; Store cursor position
rstcur db esc,'[u$' ; Restore cursor position
upcur db esc,'[A$' ; Move cursor up one line
savcur dw 0 ; storage for cursor position
msglns db 0 ; No of lines in help message
rnoc dw 0 ; Raw NOC for screen write
; Data area for direct CRT I/O
EVEN ; Force alignment to word boundary
dispadr db 2000 dup (0) ; Storage for string data
attradr db 2000 dup (0) ; Storage for attribute data
; Command block for direct CRT I/O
cmd db 0 ; CRT command number
la db 0 ; Line address (0-24 binary)
ca db 0 ; Column address (0-79 binary)
noc dw 0 ; Number of chars (0-2000 binary)
dispptr dw dispadr ; Pointer to string data block
dispseg dw datas ;
attrptr dw attradr ; Pointer to attribute data block
attrseg dw datas
ourarg termarg <>
modem mdminfo <mndata,mnst1a,mncmda,0,0,0,0>
timer tmrinfo <tmdata,tmcmda,tmsela>
ourflgs db 0 ; Flags for telnet options
fprint equ 80H ; echo screen output to printer
movcur equ 40H ; cursor moved - needs resetting
kbtrflg equ 20H ; local flag showing if kb trans.is enabled
autorepflg equ 10H ; is this an autorepeat cycle
inited equ 8H ; are we initiating first call to term
tlnxof equ 4H ; have we sent a ^S in telnet with brk/stp
savscn dw 0 ; save last key-in for auto repeat if needed
escscan dw 0 ; scan code for current ctrl-escape key
oldsera dw ? ; old serial handler for standard port
oldsega dw ? ; segment of above
oldmska db ? ; old interrupt controller mask
portina db 0 ; Has comm port been initialized.
oldserb dw ? ; old serial handler for optional port
oldsegb dw ? ; segment of same.
oldmskb db ? ; old interrupt controller mask
portinb db 0 ; Has comm port been initialized.
dosseg dw 40H ; Segment to read IO.SYS
zero dw 0 ; Use to load segment regs for low core
; Space for addresses in IO.SYS to be calculated at run time in 'lclini'
configptr equ 3H ; Offset of pointer to base of config table
configbas dw 0 ; base address of config table in IO.SYS
fifobas dw 0 ; equ 0A62H for DOS 2.11
; offsets from configbas
statlnptr equ 0CH
kbinptr equ 2CH ; kbin addr = base of fifodata area (fifobas)
crtptr equ 48H
; offsets from fifobas
kbin equ 0 ; fifobas
kbout equ 1 ; fifobas + 1
kbfifo equ 2 ; fifobas + 2
kbrepflg equ 0D9H ; fifobas + 0D9H
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
; variables for serial interrupt handler
source db bufsiz DUP (?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
savesi dw 0 ; Save SI register here.
dw 80 DUP (?) ; local stack for interrupt processing
mnstk dw ?
mnsp dw ? ; remote stack info
mnsseg dw ?
shkbuf db 300 dup (?) ; room to display key definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
setktab db 24
mkeyw 'BACKSPACE',9CH
mkeyw 'F1',80H
mkeyw 'F2',81H
mkeyw 'F3',82H
mkeyw 'F4',83H
mkeyw 'F5',84H
mkeyw 'F6',85H
mkeyw 'F7',86H
mkeyw 'F8',87H
mkeyw 'F9',88H
mkeyw 'F10',89H
mkeyw 'F11',8AH
mkeyw 'F12',8BH
mkeyw 'F13',8CH
mkeyw 'F14',8DH
mkeyw 'F15',8EH
mkeyw 'F16',8FH
mkeyw 'F17',90H
mkeyw 'F18',91H
mkeyw 'F19',92H
mkeyw 'F20',93H
mkeyw 'F21',94H
mkeyw 'F22',95H
mkeyw 'SCAN',-1
setkhlp db cr,lf,'Either keyname: Backspace, F1, ...,F22',cr,lf
db ' or "SCAN" followed by scan code'
db ' (given by SHOW KEY)',cr,lf,'$'
comptab db 7
mkeyw '1',1
mkeyw '2',0
mkeyw 'COM1',1
mkeyw 'COM2',0
mkeyw 'H14',0
mkeyw 'OPTIONAL',0
mkeyw 'STANDARD',1
bddat label word
dw 0D30H ; 45.5 baud
dw 0C00H ; 50 baud
dw 0800H ; 75 baud
dw 0574H ; 110 baud
dw 0476H ; 134.5 baud
dw 0400H ; 150 baud
dw 0200H ; 300 baud
dw 0100H ; 600 baud
dw 0080H ; 1200 baud
dw 0055H ; 1800 baud
dw 004DH ; 2000 baud
dw 0040H ; 2400 baud
dw 0020H ; 4800 baud
dw 0010H ; 9600 baud
dw 0008H ; 19200 baud
dw 0004H ; 38400 baud (not tested - may not work)
; some static data for mode line
unkbaud db ' Unk ' ; must be 5 chars...
baudn db ' 45.5' ; [g4 start]
db ' 50 '
db ' 75 '
db ' 110 '
db ' 135 '
db ' 150 '
db ' 300 '
db ' 600 '
db ' 1200'
db ' 1800'
db ' 2000'
db ' 2400'
db ' 4800'
db ' 9600'
db '19200' ; [g4 end]
baudnsiz equ 15 ; # of baud rates known (tbl size / 5)
datas ends
code segment public
extrn comnd:near, dopar:near, escprt:near
assume cs:code,ds:datas
; local initialization routine, called by Kermit initialization.
LCLINI PROC NEAR
cld
mov flags.vtflg,0 ; turn off heath emulation
push es
mov es,dosseg
mov bx,configptr
mov bx,es:[bx] ; Get offset of configuration table in IO.SYS
mov configbas,bx ; store it
mov cl,fifoclr ; Clear fifobuffer in case user has been
int bios ; typing while program was loading
mov bx,es:[bx].kbinptr ; Should be address of kbin
mov cl,es:[bx] ; Confirm we're in right location
cmp cl,byte ptr es:1[bx] ; by showing kbin = kbout
jne lclin1 ; Fails for DOS 2.00 (no kbinptr)
mov fifobas,bx ; Kbin is base of fifo area
or ourflgs,kbtrflg ; Show we have a key tranlate table
jmp short lclin2 ; Localization finished
lclin1: mov bx,configbas ; DOS 2.00 does have pointer to status line
mov bx,es:[bx].statlnptr ; Address of 'MS-DOS' in status line
sub bx,6BH ; Work back to where kbin should be
mov cl,es:[bx] ; Confirm we're in right location
cmp cl,byte ptr es:1[bx] ; by showing kbin = kbout
jnz lclin3 ; Nothing else to try - report failure
mov fifobas,bx ; We've made it!
or ourflgs,kbtrflg ; Show we have a key tranlate table
xor ax,ax ; Set zero flag for mono format default
jmp short lcli20
lclin2: mov bx,configbas
mov bx,es:[bx].crtptr ; Get address of crttype byte
mov al,es:[bx] ; get the crttype byte
test al,1 ; Is it a color crt?
lcli20: mov dx,ds ; DOS 2.00 has no crt data and
mov es,dx ; and defaults to mono
mov cl,formdtl ; Length of crt format block
mov di,offset formdat ; Where we want data
jnz lcli21 ; No, it's color
jmp short lclin4
lcli21: mov si,offset nrmcol ; Source of color data
rep movsb ; Move data to working location
jmp short lclin4
lclin3: mov dx,offset bdkscn
call tmsg
and ourflgs,not kbtrflg ; Show no translate table enabled
lclin4: mov dx,offset formdat.nrmseq ; set to our normal background color
call tmsg
pop es
ret
LCLINI ENDP
; Local reset routine, called upon exit from Kermit
LCLRST PROC NEAR
ret
LCLRST ENDP
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. The only problem is that a value of two
; is returned for single drive systems to be consistent
; with the idea of the system having logical drives A and
; B. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; current disk value to AL.
int dos
mov dl,al ; put current disk in DL.
mov ah,seldsk ; select current disk.
int dos ; get number of drives in AL.
mov drives,al
ret
DODISK 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.
; In this version, the complete untranslated key scan codes are obtained
; from the fifo buffer in IO.SYS. The fifo buffer pointers are then updated
; to show that the key has been read. Certain key scan codes which are
; intercepted in the kb interrupt routine give a blank or functional response
; to SHOW KEY (eg FNC + CTRL + BREAK-STOP, PRINT, and CTRL + 0...9 )
; and these cannot be translated.
SHOWKEY PROC NEAR
push es
test ourflgs,kbtrflg
jnz showk0
push ax ; Keep stack balanced
mov bx,ax
and [bx].flgs,not havtt ; reset flag
mov dx,offset nokbtr ; Inform no table installed and return
jmp short shoerr
showk0: push ax ; save the terminal argument block
mov al,trans.escchr ; calculate scan code for ctrl-escape key
add al,40H ; uncontrolify escape char
mov ah,2 ; control byte
mov escscan,ax ; save it
showk1: call inscan ; get key-in scan code from IO.SYS
jmp short showk1 ; Nothing there yet - keep trying
nop
call inckbo ; increment kbout pointer
cmp al,printkey ; Is it the print key (any version) ?
jnz show11
mov dx,offset prtmsg ; If so complain
jmp short shoerr
show11: cmp al,byte ptr escscan ; Is it current ctrl-escape key ?
jnz show12
test ah,02 ; With ctrl + anything
jz show12
mov dx,offset escmsg ; Then complain
jmp short shoerr
show12: cld
mov cx,ds
mov es,cx
push ax ; save scan code
mov di,offset shkbuf ; move 'Scan code' message to buffer
mov si,offset shkmsg
mov cx,shkmln
rep movsb
call nout ; add scan code to buffer
mov si,offset shkms1 ; move 'Definition' message to buffer
mov cx,shkm1ln
rep movsb
pop ax ; retrieve scan code
pop bx ; and terminal argument block
mov cx,[bx].klen ; length of translation table
jcxz showk3 ; no table, key not defined
push di
mov di,[bx].ktab ; get table address
repne scasw ; look for scan code
mov si,di
pop di
jne showk3 ; not defined
sub si,[bx].ktab ; compute entry offset in table
sub si,2
add si,[bx].krpl ; index to replacement
mov si,[si] ; get its address
mov cl,[si] ; get its length
mov ch,0
inc si
rep movsb ; transfer replacement to display buffer
showk3: mov ax,offset shkbuf ; return address of buffer in ax
mov cx,di ; and length in cx
sub cx,ax
pop es
ret
shoerr: call tmsg
mov cx,0 ;
pop ax ; get rid of junk
pop es
ret
SHOWKEY ENDP
; copy numeric value from AX to ASCII buffer indicated by DI. DI is updated.
NOUT PROC NEAR
mov dx,0 ; zero high word
mov bx,10 ; divide
div bx
push dx ; save remainder digit
or ax,ax ; anything left?
jz nout1 ; no, start output phase
call nout
nout1: pop ax ; retrieve a digit
add al,'0' ; make it ASCII
stosb ; put it in buffer
ret
NOUT ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we have to xon the host.
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: pushf ; save current interrupt value
cli ; disable interrupts while manipulating pointers
mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
popf ; restore original interrupt flag
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
CHKXON PROC NEAR
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop ; ignore failure
nop
nop
mov xofsnt,false ; remember we've sent an xon.
chkxo1: pop bx ; restore register
ret ; and return
CHKXON ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
OUTCHR PROC NEAR
mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
sub cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,modem.mdstat ; port status register
outch3: in al,dx
test al,txrdy ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
OUTCHR ENDP
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
mov dx,modem.mdcom ; send to command port
mov al,cbrk+ccmd ; add break to normal command
out dx,al
sub cx,cx ; wait a while
sndbr1: loop sndbr1
mov al,ccmd ; restore normal command
out dx,al
ret ; and return.
SENDBR ENDP
DISCON PROC NEAR
mov dx,offset hngcfm
call besure ; Get confimation of command
jmp short discn1
nop
mov dx,offset dismsg ; Say what we're doing
call tmsg
mov al,CCMD
xor al,2 ; Reset bit to drop DTR.
mov dx,modem.mdcom
out dx,al
mov bx,05H ; Set outer counter 5 X --> 3sec.
pause2: xor cx,cx
pause3: push bx ; Waste time for 600ms.
pop bx
loop pause3 ; Loop on inner loop.
dec bx
jnz pause2 ; Loop on outer loop.
or al,2 ; Set bit to enable DTR again.
out dx,al
mov dx,offset rcnmsg
call tmsg
discn1: ret
DISCON ENDP
BESURE PROC NEAR ; Receives addr of prompt in DX.
call tmsg
mov ah,conin
int dos
and al,137Q ; Convert to upper case if necessary.
cmp al,'Y'
jz besur1 ; We must return rskp for a 'Y'/'y'
mov dx,offset crlf ; For any other character input send a cr/lf.
call tmsg
ret ; And return.
besur1: jmp rskp
BESURE 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
pushf ; save current interrupt value
cli ; disable interrupts
mov ax,offset source ; reset pointers to beginning of buffer
mov srcpnt,ax
mov savesi,ax
mov count,0
popf ; restore original interrupt value
ret
CLRBUF ENDP
; Set the baud rate for the current port, based on the value in the
; portinfo structure. On entry, previous value of baud rate is saved in AX.
; Returns normally.
DOBAUD PROC NEAR
mov bp,portval
mov bx,ds:[bp].baud ;make sure new value is valid
shl bx,1
add bx,offset bddat
cmp word ptr [bx],0FFH
jne dobd0
mov ds:[bp].baud,ax ;replace bad rate with previous value
mov dx,offset badbd
jmp tmsg
dobd0: mov dx,timer.tmcmd ;timer command port
mov al,timer.tmsel ;select proper channel and mode
out dx,al
mov ax,[bx] ;get timer initializer for this rate
mov dx,timer.tmdat ;timer data port
out dx,al ;output low byte
mov al,ah
out dx,al ;output high byte
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
mov bx,portval ; no way to determine baud rate on APC
mov [bx].baud,B1200 ; so set default baud rate to 1200
ret
GETBAUD ENDP
; Set the mode for the current port. This is part of the serial
; initialization routine.
DOMODE PROC NEAR
mov dx,modem.mdcom ;send 3 zeros to command port to reset chip
mov al,0
out dx,al
mov al,0
out dx,al
mov al,0
out dx,al
mov al,cmode ;enable mode setting
out dx,al
mov cx,100 ;allow chip time to reset
mode1: loop mode1
mov al,mmode ;mode: 16x rate, 8 data, no parity, 1 stop
out dx,al
mov cx,100
mode2: loop mode2
mov al,ccmd ;RTS & DTR high, RX & TX enabled, reset errors
out dx,al
ret
DOMODE ENDP
; Reassure user about connection to the host. Tell him what escape
; sequence to use to return and the communications port and baud
; rate being used. [19b]
DOMSG PROC NEAR
mov bx,offset ourarg ; get argument block
mov al,[bx].baudb ; get baud bits
mov si,offset unkbaud ; Assume unknown baud.
cmp al,baudnsiz ; too big?
jnb dmsg12 ; yes, use default
mov cl,2 ; each is 5 bytes long
shl al,cl ; 4 X
add al,[bx].baudb ; make 4+1 = 5
mov ah,0
add ax,offset baudn
mov si,ax
dmsg12: mov cx,5 ; length of baud space
mov di,offset cnmsgb
rep movsb ; copy in baud rate
mov al,'1'
cmp ourarg.prt,1 ; One means port 1
je dmsg15 ; yes, keep going
mov al,'2' ; Zero means port 2
dmsg15: mov cnmsgp,al ; fill in port number
mov dx,offset cnmsg
call tmsg
call escprt ; in MSSET
mov dx,offset cnmsg1
call tmsg
ret
DOMSG ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset comptab ;get port selection
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm ;get a confirmation
call comnd
jmp comx
nop
pop bx
mov flags.comflg,bl ;save port selection
cmp flags.comflg,1
jne coms2
mov ax,offset port1 ;set to run on port 1
mov portval,ax
call resetb ;reset port 2, if in use
call inita ;set up port 1
ret
coms2: mov ax,offset port2 ;set to run on port 2
mov portval,ax
call reseta ;reset port 1, if in use
call initb ;set up port 2
ret
comx: pop bx
ret
COMS 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 flags.comflg,1
jne seri2
call resetb
call inita
ret
seri2: call reseta
call initb
ret
SERINI 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
call reseta ;reset port 1
call resetb ;reset port 2
mov dx,offset recur ; Reenable cursor display
call tmsg
and ourflgs,not inited ; Reset init flag for term usage
ret
SERRST ENDP
; Local routine to initialize the standard serial port
INITA PROC NEAR
cmp portina,1 ; Did we initialize port already? [21c]
je inita0 ; Yes, so just leave. [21c]
push es
cli ; Disable interrupts
mov ax,offset port1
mov portval,ax
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*icsvcta] ; save standard port interrupt vector
mov oldsera,ax
mov ax,es:[4*icsvcta+2]
mov oldsega,ax
mov ax,offset serint ; point to our routine
mov es:[4*icsvcta],ax ; point at our serial routine
mov es:[4*icsvcta+2],cs ; our segment
mov dx,intmska ; set up standard port...
in al,dx
mov oldmska,al ; save old master controller mask
; NEC recommends that the timer interrupt be disabled during interrupt-
; driven serial I/O, but this disables the clock display and keyboard
; repeat. I have not had any problems leaving it enabled, so I will
; leave it alone here. If problems develop, uncomment the following
; line to disable timer interrupts. -- RonB
; or al,ictmsk ; disable timer interrupt
and al,not icsmska ; enable serial interrupt at master controller
out dx,al
mov dx,mnmska ; enable serial interrupt at port
mov al,txmsk+tbemsk ; disable tx and tbe interrupts (enable rx)
out dx,al
mov dx,mntdca ; enable operation of serial port
mov al,0
out dx,al
mov modem.mddat,mndata
mov modem.mdstat,mnst1a
mov modem.mdcom,mncmda
mov timer.tmdat,tmdata
mov timer.tmcmd,tmcmda
mov timer.tmsel,tmsela
call domode
call dobaud
mov portina,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
pop es
inita0: ret
INITA ENDP
; Local routine to initialize the optional (H14) serial port
INITB PROC NEAR
cmp portinb,1 ; Did we initialize port already? [21c]
je initb0 ; Yes, so just leave. [21c]
push es
cli ; Disable interrupts
mov ax,offset port2
mov portval,ax
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*icsvctb] ; save optional port interrupt vector
mov oldserb,ax
mov ax,es:[4*icsvctb+2]
mov oldsegb,ax
mov ax,offset serint ; point to our routine
mov es:[4*icsvctb],ax ; point at our serial routine
mov es:[4*icsvctb+2],cs ; our segment
mov dx,intmskb ; set up optional port...
in al,dx
mov oldmskb,al ; save old master or slave controller mask
and al,not icsmskb ; enable serial interrupt at controller
out dx,al
mov dx,mnmskb ; enable serial interrupt at port
mov al,txmsk+tbemsk ; disable tx and tbe interrupts (enable rx)
out dx,al
mov dx,mntdcb ; enable operation of serial port
mov al,0
out dx,al
mov modem.mdstat,mnst1b
mov modem.mddat,mndatb
mov modem.mdcom,mncmdb
mov timer.tmdat,tmdatb
mov timer.tmcmd,tmcmdb
mov timer.tmsel,tmselb
call domode
call dobaud
mov portinb,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
pop es
initb0: ret
INITB ENDP
; Reset standard serial port
RESETA PROC NEAR
cmp portina,0 ; Did we reset port already?
je rsta0 ; Yes, so just leave.
push es
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov ax,oldsera ; Restore interrupt vector
mov es:[4*icsvcta],ax
mov ax,oldsega
mov es:[4*icsvcta+2],ax
mov dx,intmska ; restore old master controller mask
mov al,oldmska
out dx,al
mov dx,mnmska ; disable serial interrupts at port
mov al,txmsk+rxmsk+tbemsk
out dx,al
mov portina,0 ; Remember port has been reset
sti ; Allow interrupts
pop es
rsta0: ret
RESETA ENDP
; Reset optional (H14) serial port
RESETB PROC NEAR
cmp portinb,0 ; Did we reset port already?
je rstb0 ; Yes, so just leave.
push es
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov ax,oldserb ; Restore interrupt vector
mov es:[4*icsvctb],ax
mov ax,oldsegb
mov es:[4*icsvctb+2],ax
mov dx,intmskb ; restore old slave controller mask
mov al,oldmskb
out dx,al
mov dx,mnmskb ; disable serial interrupts at port
mov al,txmsk+rxmsk+tbemsk
out dx,al
mov portinb,0 ; Remember port has been reset
sti ; Allow interrupts
pop es
rstb0: ret
RESETB ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
SERINT PROC NEAR
push ds ; save these on remote stack
push ax
mov ax,seg datas ; get our own data segment
mov ds,ax
mov mnsp,sp ; save remote stack information
mov mnsseg,ss
mov sp,offset mnstk ; switch to local stack
mov ss,ax
push es ; and save remaining registers
push bp
push di
push si
push dx
push cx
push bx
mov es,ax
call mnproc ; process the interrupt
mov al,icEOI
cmp flags.comflg,1 ; If using standard port
je intr1
mov dx,intcmdb ; or H14 vectored to master
cmp dx,intcmda
je intr1 ; only signal End of Interrupt to master,
out dx,al ; otherwise signal to both slave and master.
intr1: mov dx,intcmda
out dx,al
pop bx ; restore registers from stack
pop cx
pop dx
pop si
pop di
pop bp
pop es
mov ax,mnsseg ; switch back to remote stack
mov ss,ax
mov ax,mnsp
mov sp,ax
pop ax
pop ds
iret
; handler for serial input
mnproc: cld
mov di,srcpnt ; get buffer pointer
mov dx,modem.mdstat ; is data available?
in al,dx
test al,rxrdy
jz mnpro7
mov dx,modem.mddat ; read data
in al,dx
or al,al
jz mnpro7 ; Ignore nulls.
cmp al,7FH ; Ignore rubouts, too.
jz mnpro7
mov ah,al
and ah,7fH ; only consider low-order 7 bits for flow ctl.
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je mnpro4 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp ah,bl ; Is it an XOFF?
jne mnpro3 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp short mnpro7
mnpro3: cmp ah,bh ; Get an XON?
jne mnpro4 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp mnpro7
mnpro4: stosb
cmp di,offset source + bufsiz
jb mnpro5 ; not past end...
mov di,offset source ; wrap buffer around
mnpro5: mov srcpnt,di ; update ptr
inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je mnpro7 ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je mnpro7 ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe mnpro7 ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop ; ignore failure.
nop
nop
mov xofsnt,true ; Remember we sent it.
mnpro7: ret
SERINT ENDP
; Dumb terminal emulator. Anyone wishing to enhance it is encouraged
; to do so.
TERM PROC NEAR
push es
test ourflgs,inited ; Have we been here before
jnz term01 ; if so, skip this stuff
or ourflgs,inited ; show we've been here
test ourflgs,kbtrflg
jnz term0
mov bx,ax
and [bx].flgs,not havtt ; If no table then reset flag
term0: mov si,ax ; save argument block locally
mov di,offset ourarg
mov ax,ds
mov es,ax
mov cx,size termarg
rep movsb
mov al,trans.escchr ; Calculate scan code for cntrl-escape char
add al,40H ; Uncontollify escape char
mov ah,02H ; Control byte for escape scan code
mov escscan,ax ; save it
call domsg ; tell user how we're connecting.
term01: test ourflgs,movcur ; Do we need to reset cursor position
jz term1
mov dx,offset cmd
mov cx,savcur
mov word ptr la,cx
mov noc,0
mov cmd,1 ; Bios move cursor call
mov cl,crtcmd
int bios
and ourflgs, not movcur
term1: call prtchr ; Serial port input processor
jmp short term2 ; ...have a char
nop
jmp term4 ; no char, continue
term2: and al,7FH ; only use ASCII in terminal mode
push ax
mov dl,al
mov ah,conout
int dos ; display char
pop ax
test ourarg.flgs,capt ; are we capturing output?
jz term3
push ax
call ourarg.captr
pop ax
term3: test ourflgs,fprint ; are we echoing to printer?
jz term4
call lstchr
term4: test ourflgs,kbtrflg
jz term50
call inscan
jmp short term1
nop
cmp al,printkey ; All shifts of print key do special duty.
jne term41
cmp ah,0
jne term40 ; but toggle printer only if unshifted print
xor ourflgs,fprint ; go toggle printer
term40: call inckbo ; increment kbout pointer
jmp term1
term41: cmp al,byte ptr escscan ; Is it current escape key
jne term42
test ah,02 ; with ctrl + anything ?
jz term42
call inckbo
mov cx,100 ; Delay for memory stability
trm420: loop trm420
jmp short termx ; it's ctrl-escape key so just return
term42: call trnout ; Returns rskp if char not sent.
jmp short term1 ; Translation found and already sent.
nop ; no translation so move char via DCONIO
cmp ax,brkstp ; is it unredefined/unshifted break/stop key
jnz term50 ; if not, just continue
mov ax,ctrl_s ; get a ^S ready
test ourflgs,tlnxof ; have we already sent a ^S ?
jz term43 ; no, we can just set flag and send the ^S
mov ax,ctrl_q ; yes, so now we need a ^Q
term43: xor ourflgs,tlnxof ; change the flag in either case
call sndhst ; send our ^S/ ^Q - IO.SYS 2.11 won't do it
mov ah,dconio ; do a dummy read to clear IO.SYS flush flag
mov dl,0FFH
int dos
jmp term1 ; and go back for more
term50: mov ah,dconio ; Keyboard input processor
mov dl,0FFH
int dos ; check console
jnz term51
jmp term1 ; no char, continue .Too far for rel jmp.
term51: cmp al,ourarg.escc ; is it the escape char?
je termx ; allows use of unredef left arrow key to esc
call sndhst ; no translation, just send it out
jmp term1 ; and go back for more
termx: pop es
ret
; do appropriate translations on input key, and transmit
; if translation entry found it sends char(s) to sndhst and returns normally
; if no translation entry is found, returns rskp with unsent scan code in ax
; so that CONIN in IO.SYS can do its translation if neessary.
trnout: test ourflgs,kbtrflg ; is there a translation table?
jz trnou3
mov cx,ourarg.klen ; get table length and origin
mov di,ourarg.ktab
push es
mov bx,ds
mov es,bx
jcxz trnou3 ; Needed for case of table zero length
repne scasw ; look for key
jne trnou3 ; if not found, return rskp
sub di,ourarg.ktab ; reset to offset of replacement
sub di,2
add di,ourarg.krpl
mov si,[di]
mov cl,[si] ; get length of replacement
mov ch,0
jcxz trnou3 ; if length is zero, send nothing
inc si
trnou1: lodsb ; get replacement character
push si
push cx
call sndhst ; send it to port
pop cx
pop si
loop trnou1 ; continue until translation complete
trnou2: call inckbo ; increment kbout pointer
pop es
ret ; return after translating and sending
trnou3: pop es
jmp rskp ; plain characters return rskp
; get key-in scan code from fifo buffer in IO.SYS
; if gets a key-in, skip returns with scan code in ax
; returns normally if no key-in
inscan: push es
mov es,dosseg ; Address IO.SYS segment with es
and ourflgs,not autorepflg ; Reset auto repeat flag
mov bx,fifobas ; Offset of fifobas in IO.SYS (from LCLINI)
insca1: mov al,es:[bx].kbout ; Get value of kbin pointer
cmp al,es:[bx].kbin ; Compare value of kbout pointer
jz insca2 ; If equal, no key-in yet so exit
sub ah,ah
add bx,ax ; Calculate address pointed to (-2)
mov ax,es:2[bx] ; Get scan code pointed to by kbout.
xchg ah,al ; Get control byte -> ah, data byte -> al.
mov savscn,ax ; Save scan data in case key repeat needed.
pop es
jmp rskp
insca2: mov bx,fifobas
cmp byte ptr es:[bx].kbrepflg,0 ; Is it time to repeat last key-in
jz inscax ; Nope so exit
mov ax,savscn ; Get last key-in
or ourflgs,autorepflg ; Show we are on auto repeat cycle
pop es ; And make it look like new
jmp rskp
inscax: pop es
ret
; increments kbout pointer (with reset to zero) and returns normally
; (on auto repeat cycles resets kbrepflg and returns )
inckbo: push es
mov es,dosseg
mov bx,fifobas
test ourflgs,autorepflg ; new key-in or autorepeat
jnz inckb2
mov cl,0 ; Update kbout pointer to fifo
cli
cmp byte ptr es:[bx].kbout,kbfifosiz-2 ; End of fifo buff ?
je inckb1 ; Yes, so start back at beginning
mov cl,es:[bx].kbout ; No, just update our place
add cl,2
inckb1: mov es:[bx].kbout,cl ; Write back new pointer value
sti
jmp short inckbx
inckb2: mov byte ptr es:[bx].kbrepflg,0 ; Reset autorepeat flag in IO.SYS
inckbx: pop es
ret
; send character in AL to port, with possible local echo
sndhst: push ax
mov ah,al
call outchr ; send char to port
nop ; ...don't care if it fails
nop
nop
pop ax
test ourarg.flgs,lclecho ; doing local echo?
jz sndhs2
mov dl,al
mov ah,conout
int dos ; if so, display char
sndhs2: ret
; send character to printer. The only special case is the tab, which must
; be expanded to spaces because MS-DOS doesn't.
lstchr: cmp al,tab
jne lstch2
mov ax,lstpos ; current column position
mov cx,8 ; # of spaces = 8 - (column % 8)
div cl
sub cl,ah
add lstpos,cx ; update the column position
mov al,' '
lstch1: call lstch4 ; print all the spaces
loop lstch1
ret
lstch2: cmp al,cr ; CR returns column count to zero
jne lstch3
mov lstpos,0
lstch3: cmp al,' ' ; only printable characters are counted
jb lstch4
cmp al,del
je lstch4
inc lstpos
lstch4: mov dl,al ; print the character in any case
mov ah,lstout
int dos
ret
TERM ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
VTS ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
push si
cmp dh,25 ; out of range just assumes high value
jb poscu1
mov dh,24
poscu1: cmp dl,80
jb poscu2
mov dl,79
poscu2: add dx,2020H ; add offset for ADM cursor addressing
mov cpseq+2,dh
mov cpseq+3,dl
mov si,offset cpseq ; print sequence (ESC=rc)
mov cx,4
posc1: lodsb
mov dl,al
mov ah,conout
int dos
loop posc1
pop si
ret
POSCUR ENDP
; Locate; homes cursor position and disables its display. Returns normally.
LOCATE PROC NEAR
mov dx,offset nocur ; Disable cursor
call tmsg
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
cmp al,del ; Del character needs extra backspace
jne dodel1
mov dl,bs
mov ah,conout
int dos
dodel1: 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
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov dx,offset ceolseq ; clear sequence
jmp tmsg
CLEARL ENDP
; This routine blanks the screen and homes the cursor. Returns normally.
CMBLNK PROC NEAR
mov dx,offset clrseq ; clear screen and home cursor sequence
jmp tmsg
CMBLNK 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 formdat.invseq ; put into inverse video
call tmsg
pop dx ; print the message
call tmsg
mov dx,offset formdat.nrmseq ; normal video
jmp tmsg ; Jump to return
PUTMOD ENDP
; clear the mode line written by putmod. Returns normally.
CLRMOD PROC NEAR
mov dx,24*100H
call poscur
mov dx,offset ceolseq
jmp tmsg
CLRMOD ENDP
; Put a help message in a box at the top of the screen.
; This one uses inverse video (or yellow if color)
; Pass the message in ax, terminated by a null. Returns normally.
PUTHLP PROC NEAR
cld
mov dx,ax ; Prepare to pass message to 'getnoc'
call getnoc ;
mov rnoc,cx ; This is unformatted NOC in message
mov cx,5 ; Calculate formatted area needed (in words)
rol bx,cl ; BX is no of lf's.
mov NOC,bx
mov cx,2
ror bx,cl
add NOC,bx ; This is Lines X 40
add NOC,80 ; Current line + one more
mov cx,NOC
mov si,dx ; Source of message given us
mov di,attrptr ; Pointer to screen attrib area
mov ax,formdat.bldcrt ; Need bold attribute
rep stosw ; Cover attribute area needed
mov ax,formdat.nrmcrt ; Rest of screen needs normal color
mov cx,1000 ; Whole screen
sub cx,NOC ; Attribute area left to cover
rep stosw ; Do it
mov cx,1000 ; Fill screen data area with null bytes
mov di,dispptr ; Pointer to screen data area
xor ax,ax ; This is source of null bytes
rep stosw ; Prepare clean screen data area
mov cx,rnoc ; No of unformatted data bytes
mov di,dispptr ; Destination is screen data area
pthlp0: push di ; Save start of current line
pthlp1: lodsb ; Load data bytes 1-by-1
cmp al,cr ; Is this one an eol?
jz pthlp2 ; Yep - handle cr/lf's ourselves
stosb ; No - move character
loop pthlp1 ; And go back for next
jmp short pthlp3 ; Finished moving chars, so exit.
pthlp2: dec cx ; Account for cr and lf
dec cx
inc si ; Skip the lf
pop di ; Get start of current line.
add di,80 ; Adjust pointer to next line
jmp short pthlp0 ; And go back for more
pthlp3: pop di
mov noc,2000 ; We are going to write over whole screen
test ourflgs,movcur ; Save cursor only if not previously saved
jnz pthlp4
mov cmd,2 ; Get cursor position before writing
mov dx,offset cmd
mov cl,crtcmd
int bios ; Get cursor call
mov cx,word ptr la
mov savcur,cx ; Store cursor position
pthlp4: mov la,24 ; Prepare to roll down 24 lines
mov ca,0
mov cmd,3 ; Screen roll down command
mov dx,offset cmd
mov cl,crtcmd
int bios ; Do it!
mov la,0 ; Begin our msg on top line of screen
mov cmd,1 ; String write command
int bios ; Write it.
mov cx,1000 ; Delay for video memory stability
pthlp5: loop pthlp5
mov dx,offset upcur
call tmsg
mov dx,offset upcur ; Put cursor up onto clean screen
call tmsg
or ourflgs,movcur ; Tell that we've moved the cursor
ret
PUTHLP ENDP
; Receives message pointer in DX, terminating character in CL
; Returns with message ptr in DX, NOC in CX, and number of lf's in BX.
GETNOC PROC NEAR
cld
mov di,dx
mov al,cl ; Move terminator to AL
mov cx,2000 ; Longest acceptible message.
repnz scasb ; Look for terminator
jz gtnoc1
xor cx,cx
ret ; Error return
gtnoc1: sub di,dx ; Calculate NOC
mov cx,di ; Move it to counter
dec cx ; Discount terminator
push cx ; Save NOC
mov di,dx
mov al,lf
xor bx,bx
gtnoc2: repnz scasb ; Now count lf's
jcxz gtnoc3 ; If the counter ran out
inc bx
jmp short gtnoc2
gtnoc3: pop cx ; Recover NOC
ret
GETNOC ENDP
; Produce a short beep. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; Prints $-terminated message in dx, for local use only
TMSG PROC NEAR
mov ah,prstr
int dos
ret
TMSG ENDP
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end
; END OF MSXAPC.ASM