home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
cpm86
/
c86xtx.a86
< prev
next >
Wrap
Text File
|
2020-01-01
|
15KB
|
590 lines
; * * * * * * * * * * * * * * * version 2.7 * * * * * * * * * * * * * * *
; Tektronix 4170 version - TransEra Corporation
; Robert Raymond, 3707 North Canyon Road, Building 4, Provo, UT 84601
; [31c] set default baud to 9600
; [31b] Changes made for 4170 port hardware
; [31a] Use ansi routines from 86keri.rb
; * * * * * * * * * * * * * * * version 2.7 * * * * * * * * * * * * * * *
; [30d] Add SET PORT command, currently unimplemented.
; [30c] Isolate all machine dependencies in KERIO.
; [30a] Add keyboard DEL key alteration for APC
; RonB, 04/18/84
; * * * * * * * * * * * * * * * version 2.6 * * * * * * * * * * * * * * *
; [28e] Switch to local stack on interrupts.
; RonB, 03/28/84
; * * * * * * * * * * * * * * * version 2.4 * * * * * * * * * * * * * * *
; [20b] Add PRTBRK to send break & set correct clock rate for NEC.
; [20d] Add a pseudo time-out to PRTOUT so it doesn't loop forever.
; RonB,03/02/84
; [19a] Add XON/XOFF type flow control
; [19b] Clear screen and beginning and end of program.
; [19e] Add PRTBRK to send break to port (Rainbow only)
; [19g] Put in EQU for clock rate for timing loops.
; Rg, 2/84 <Oc.Garland%CU20B@Columbia-20>
; * * * * * * * * * * * * * * * version 2.3 * * * * * * * * * * * * * * *
; [par] Added calls to set parity, strip parity on input if
; other than none parity is called for.
; JD, 2/84
; * * * * * * * * * * * * * * * version 2.2 * * * * * * * * * * * * * * *
; [2] Add a de-initialization routine for the serial port, to restore
; changed interrupt vectors, etc.
; RonB,12/23/83
; [1] Add I/O support for the NEC Advanced Personal Computer
; RonB,12/23/83
; * * * * * * * * * * * * * * * version 2.0 * * * * * * * * * * * * * * *
; This module contains all the low level communications port I/O
; routines.
; Here are the I/O routines for the TEK 4170.
CSEG $
; Clock rate *10 for timing loops ;[19g]
clckrt equ 49 ;[19g] 4.9 Mhz ;[20b]
; Interrupt vector locations, in data segment 0
mnioff equ 200h ;HO_In_Int interrupt offset ;[31b]
mniseg equ 202h ;HO_In_Int interrupt segment ;[31b]
;
; equates for 2661B chip -- host initialization parameters
;
HO_Data equ 0e0h
HO_Stat equ 0e2h
HO_Mode equ 0e4h
HO_Cmd equ 0e6h
HOCLKRATE equ 02h ;sets async mode, 16x clock on host port
HOSB2 equ 0c0h ;two stop bits
HOSB1 equ 040h ;one stop bits
HOEVEN equ 020h ;select even parity, not odd parity
HOPENB equ 010h ;enable parity on the host
HOSTART equ 037h ;RTS, DTR set, Rx & Tx enabled, reset errors
HOBREAK equ 4 ; force break
HO_Thre equ 01h ;one on this indicates thre, 0 is thr busy
HO_DRdy equ 02h ;one indicates data ready, 0 no data
outlmt EQU 1000H ;Number of times to check output status
; before giving up on send. ;[20d]
; Test if port is ready to send next char. Returns RSKP if ready.
; Trashes dx.
outwt: cmp floctl, floxon ;are we doing flow-control? [19a] start
jne outwta ;no - go on
cmp xofrcv, true ;are we being held?
jne outwta ;no - ok go on
ret ;held - say we're busy. [19a] end
outwta: push ax
mov dx,HO_Stat ;[31b] begin
in al,dx
test al,HO_Thre ;transmit holding register empty
pop ax
jnz outwt2
ret
outwt2: jmp rskp ;[31b] end
; Output data to port. Trashes DX and prints char in AL.
outchr: mov dx,HO_Data ;[31b] begin
out dx,al
; don't ask me why we do this:
mov al,HO_START ;rts and start scanning
out HO_Cmd,al
ret ;[31b] end
; Output the character in AL, checking first to make sure the port is clear.
prtout: call dopar ;[par] set parity
push dx
push cx ;[20d] begin
mov cx,outlmt
prtou2: call outwt ;Wait until the port is ready
loop prtou2 ; or too much time has passed.
nop
call outchr ;Output it.
pop cx ;[20d] end
pop dx
ret
; Test if data is available from port.
instat: cmp mnchrn,0 ;Any chars in the buffer?
jnz inst2
ret
inst2: jmp rskp
; Input data from port. Preserves all registers and returns char in
; AL. Gets the char from the ring buffer. Assumes a char is
; already there.
inchr: push bx
cli ;Disable interrupts while were are playing.
dec mnchrn ;Decrement the number of chars in the buffer.
mov bx,mnchop ;Get the pointer into the buffer.
inc bx ;Increment to the next char.
cmp bx,offset mnchrs+mnchnd ;Past the end?
jb inchr2
lea bx,mnchrs ;If so wrap around to the start.
inchr2: mov mnchop,bx ;Save the updated pointer.
mov al,[bx] ;Get the character.
sti ;All done, we can restore interrupts.
pop bx
cmp parflg,parnon ;[par] no parity?
je inchr3 ;[par] yup, don't bother stripping
and al,7fh ;[par] checking parity, strip off
inchr3: cmp floctl, floxon ;do flow-control? [19a] start
je inchr4 ;If yes jump
ret
inchr4: cmp xofsnt, true ;Have we sent an XOFF
je inchr5 ;Jump if yes
ret
inchr5: cmp mnchrn, mntrg1 ;Under the low trigger point?
jb inchr6 ;yes - jump
ret
inchr6: push ax ;save current character
mov al, xon
call prtout ;send an XON
mov xofsnt, false ;turn off the flag
pop ax ;get back character
ret ; [19a] end
mnax dw 0 ;Storage in CSEG ;[28e] begin
mnsp dw 0 ; for use by interrupt handler
mnsseg dw 0
mndseg dw 0
; This routine handles the interrupts on input.
mnint: cli
mov cs:mnax, ax ;Save interrupt stack location.
mov ax, sp
mov cs:mnsp, ax
mov ax, ss
mov cs:mnsseg, ax
mov ax, cs:mndseg ;Switch to our internal stack.
mov ss, ax
lea sp, mnstk
push ds ;Save all registers.
push es
push bp
push di
push si
push dx
push cx
push bx
mov ds, ax ;Get our data segment address.
call mnproc ;Process the character.
pop bx ;Restore all registers.
pop cx
pop dx
pop si
pop di
pop bp
pop es
pop ds
mov ax, cs:mnsp ;Restore the original stack.
mov sp, ax
mov ax, cs:mnsseg
mov ss, ax
mov ax, cs:mnax
iret ;Return from the interrupt. ;[28e] end
; This routine (called by MNINT) gets a char from the serial port
; and puts it in the ring buffer.
mnproc: mov dx,HO_Stat
in al,dx ;Get the port status. [31b] start
test al,HO_DRdy ;Is a character waiting?
jnz mnpro2 ; Yes, go take care of it.
ret ; No, just a false alarm.
mnpro2: mov dx,HO_Data
in al,dx ;Read the char. [31b] end
cmp floctl, floxon ;are we doing flow-control ? [19a] start
jne mnpr2b ;no - go on
cmp al, xoff ;is it an XOFF?
jne mnpr2a ;no - go on
mov xofrcv, true ;set the flag
ret
mnpr2a: cmp al, xon ;an XON?
jne mnpr2b ;no
mov xofrcv, false ;clear the flag
ret ; [19a] end
mnpr2b: cmp mnchrn,mnchnd ;Is the buffer full?
je mnperr ;If so, take care of the error.
inc mnchrn ;Increment the character count.
mov bx,mnchip ;Get the buffer input pointer.
inc bx ;Increment it.
cmp bx,offset mnchrs+mnchnd ;Past the end?
jb mnpro3
lea bx,mnchrs ;Yes, point to the start again.
mnpro3: mov mnchip,bx ;Save the pointer.
mov [bx],al ;Put the character in the buffer.
cmp floctl, floxon ;do flow-control? [19a] start
je mnpro4 ;If yes jump
ret
mnpro4: cmp xofsnt, true ;Have we sent an XOFF
jnz mnpro5
ret ;return if we have
mnpro5: cmp mnchrn, mntrg2 ;Past the High trigger point?
ja mnpro6 ;yes - jump
ret
mnpro6: mov al, xoff
call prtout ;send an XOFF
mov xofsnt, true ;set the flag
ret ; [19a] End
mnperr: ret ;Just return on an error for now.
; prtbrk - send a break ; [31b] start
prtbrk:
mov dx,HO_Cmd ;break goes to command port
mov al,HO_START+HO_BREAK ;add break to normal command
out dx,al
mov cx, 25000 ;sit for a while
prtbk1: loop prtbk1
mov al,HO_START ;normal command,RTS & DTR high, Rx & Tx enabled
out dx,al ;return to normal setting
ret
; serini - This routine initializes all devices that need it.
; Called at the start of the program.
serini: cmp mninit,0FFh ; must only do this initialization once
je serin2
mov mninit,0FFh
call ansmod ; switch from tek mode to ansi mode
push es
;code could be added here
;to tell the interrupt controller to diable host interrupt
mov ax,ds ;save data segment in cseg
mov cs:mndseg,ax ; for use by the interrupt handler
mov ax,0 ;point to zero page to replace
mov es,ax ;the sio interrupt vector
mov ax,es:.mniseg ;after first saving the current vector
mov mnxseg,ax
mov ax,es:.mnioff
mov mnxoff,ax
cli
mov ax,cs
mov es:.mniseg,ax
mov ax,offset mnint
mov es:.mnioff,ax
sti
call stmode ;set mode & baud to defaults
call stbaud
;enable transmission of data
mov al,HOSTART ;DTR high, Rx & Tx enabled, reset error
out HO_Cmd,al
in al,HO_Data ;dummy read to clear buffer
;code could be added here
;to tell the interrupt controller to re-enable host interrupt
mov dx,0ebh
mov al,24h ;turn on host read interrupt
out dx,al ;[31b] end
pop es
serin2: ret
; serfin - this routine is used to "undo" what serini has done, called
; just before exiting back to cp/m.
serfin:
call clrscr ;[19b] clear screen ;[30c]
cmp mninit,0FFh ;check if initialization has been done
jne serfn2 ;if not, don't de-initialize
mov mninit,0
push es
cli
;code could be added here to assure the interrupt controller
;is restored to the state is was in when kermit started
mov ax,0
mov es,ax
mov ax,mnxseg ;restore sio interrupt vector
mov es:.mniseg,ax
mov ax,mnxoff
mov es:.mnioff,ax
sti
pop es
serfn2: ret
; This routine clears the serial port input buffer. It is called to
; clear out excess NAKs that can result from server mode operation.
cfibf: mov mnchrn, 0 ;Say no characters in the buffer.
mov mnchip, OFFSET mnchrs-1+mnchnd ;Reset input pointer.
mov mnchop, OFFSET mnchrs-1+mnchnd ;Reset output pointer.
ret
; set the parity, number of data bits, and number of stop bits
stmode: mov dx,HO_Cmd ;[31b] start
mov al,0 ;reset
out dx,al
in al,dx ;reset mode1/2 sequencer
mov dx,HO_Mode
mov al,HOCLKRATE ;init async mode, 16x baud, no parity
add al,HOSB1 ;1 stop bit
add al,0ch ;8 data bits
out dx,al ;[31b] end
ret
; set the baud rate
stbaud: mov dx,HO_Cmd ;[31b] start
in al,dx ;reset mode1/2 sequencer
mov dx,HO_Mode
in al,dx ;get mode1 register
; can the next 4 lines be skipped?
mov ah,al ;save it
in al,dx ;get mode2 register to reset sequence
mov al,ah ; write back old contents of mode 1
out dx,al
; next out will set mode 2 - baud rate
mov al,mnbaud ;get the baud rate information
cmp al,15 ;check for valid range (0-15)
ja stb02
or al, 70h ;internal baud clock, 16x
out dx,al ;[31b] end
stb02: ret
dseg $
; Serial port default parameters
mnbaud db 0dh ;9600 baud [31c]
mninit db 0 ;set to 0FFh if initialization has been done
mnxseg dw 0 ;system host interrupt vector
mnxoff dw 0
mnchnd equ 512 ;Size of circular buffer.
mnchrs rb mnchnd ;Circular character buffer for input.
mnchip dw mnchrs-1+mnchnd ;Input pointer into character buffer.
mnchop dw mnchrs-1+mnchnd ;Output pointer into character buffer.
mnchrn dw 0 ;Number of chars in the buffer.
mntrg1 equ 128 ;[19a] Low trigger point for Auto XON/XOFF
mntrg2 equ 384 ;[19a] High trigger point for Auto XON/XOFF
floctl db 1 ;[19a] If floctl=floxon do Auto XON/XOFF logic
xofsnt db 0 ;[19a] set if XOFF was sent
xofrcv db 0 ;[19a] set if XOFF was recieved
rw 32 ;Interrupt stack ;[28e]
mnstk dw 0 ;bottom of stack ;[28e]
CSEG $
; The following routines do the SET and SHOW for the machine dependent
; features of Kermit. At present there are only two: baud rate setting
; and port selection.
; This is the SET BAUD rate subcommand
bdset: lea dx, bdtab
lea bx, bdhlp
mov ah, cmkey
call comnd
jmp r
mov temp1, bx
mov ah, cmcfm
call comnd ;Get a confirm.
jmp r ; Didn't get a confirm.
mov bx, temp1
mov mnbaud, bl ;Set the baud rate table index.
call stbaud
jmp rskp
; This is the SET PORT subcommand (not implemented in TEK)
prtset: mov ah, cmcfm
call comnd ;Get a confirm.
jmp $+3 ; Didn't get a confirm.
lea dx, infms6 ;Tell user it's not implemented
call tcrmsg
jmp rskp
; The following procedures implement the SHOW command for the system
; dependent features of baud rate and port selection.
shobd: lea dx, bdst ;Baud rate string.
call tcrmsg
mov al, mnbaud ;Print the keyword corresponding to the
lea bx, bdtab ; current value of mnbaud.
call tabprt
ret
shoprt: ret ;Port selection not implemented.
DSEG $
bdtab db 16 ; 16 entries ;[31d] begin
db 3,'110$'
dw 0003H
db 4,'1200$'
dw 0008H
db 3,'135$'
dw 0004H
db 3,'150$'
dw 0005H
db 4,'1800$'
dw 0009H
db 5,'19200$'
dw 000EH
db 4,'2000$'
dw 000AH
db 4,'2400$'
dw 000BH
db 3,'300$'
dw 0006H
db 5,'38400$'
dw 000FH
db 2,'45$'
dw 0000H
db 4,'4800$'
dw 000CH
db 2,'50$'
dw 0001H
db 3,'600$'
dw 0007H
db 2,'75$'
dw 0002H
db 4,'9600$'
dw 000DH
bdhlp db cr,lf,' 45 75 135 300 1200 2000 4800 19200'
db cr,lf,' 50 110 150 600 1800 2400 9600 38400$'
;[31d] end
;[31a] begin -- to end of file
; The following routines do screen control. These are isolated here because
; the screen control sequences are likely to vary from system to system, even
; though the Rainbow and APC (the only systems implemented to date) both use
; ANSI sequences for this purpose.
CSEG $
; POSCUR - positions cursor to row and col (each 1 byte) pointed to by dx.
poscur: mov bx, dx ;Do ANSI cursor positioning.
mov cl, 10
mov al, [bx] ;Get row value
sub ah, ah
div cl ;units digit in ah, tens digit in al
add ax, '00' ;Convert both to ASCII
mov word ptr anspos+2, ax ;Save reversed (al,ah)
mov al, 1[bx] ;Do same for column value
sub ah, ah
div cl
add ax, '00'
mov word ptr anspos+5, ax
lea dx, anspos ;Print cursor positioning string.
call tmsg
ret
; CLRSCR - homes cursor and clears screen.
clrscr: lea dx, anscls
call tmsg
ret
; CLRLIN - clears from cursor to end of line.
clrlin: mov dl, cr ;Go to beginning of line
call bout
clreol: lea dx, ansclr ;Clear from cursor to end of line
call tmsg
ret
; REVON - turns on reverse video display
revon: lea dx, ansron
call tmsg
ret
; REVOFF - turns off reverse video display
revoff: lea dx, ansrof
call tmsg
ret
; BLDON - turns on bold (highlighted) display
bldon: lea dx, ansbon
call tmsg
ret
; BLDOFF - turns off bold (highlighted) display
bldoff: lea dx, ansbof
call tmsg
ret
; ANSMOD - enters ANSI mode from Tek mode
ansmod: lea dx, ansion
call tmsg
ret
DSEG $
anspos db esc,'[00;00H$' ;Position cursor to row and column
anscls db esc,'[H',esc,'[J$' ;Home cursor and clear screen
ansclr db esc,'[K$' ;Clear from cursor to end of line
ansron db esc,'[7m$' ;Turn on reverse video
ansrof db esc,'[m$' ;Turn off reverse video
ansbon db esc,'[1m$' ;Turn on bold (highlight) display
ansbof db esc,'[m$' ;Turn off bold display
ansion db esc,'%!1$' ;SelectCode Ansi mode
; Here tab expansion is done if necessary. If not, just return retskp.
CSEG $
dotab: jmp rskp
DSEG $
delstr db ' ',10O,10O,'$' ;Delete string.
system db ' Tektronix 4170$'