home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
cpm86
/
c86xv9.a86
< prev
next >
Wrap
Text File
|
2011-08-09
|
24KB
|
685 lines
; * * * * * * * * * * * * * * * version 2.9 * * * * * * * * * * * * * * *
; [35] Modify the Rainbow 100 version to handle the Victor 9000/Sirius
; Eric Zurcher, Utah State University, Logan, Utah (REHABIV@USU.BITNET)
; 07/07/86
; * * * * * * * * * * * * * * * version 2.8 * * * * * * * * * * * * * * *
; [34] Insert milli-second wait-loop for Break-timing - label MSWAIT:
; [33] Fix printer on hanging system problem by letting CP/M handle the
; interrupts from the 7201 that we don't care about. Thanks to
; Paul Ford, U. of Chicago Graduate School of Business
; * * * * * * * * * * * * * * * version 2.7 * * * * * * * * * * * * * * *
; [30d] Add SET PORT command, currently unimplemented.
; [30c] Isolate all machine dependencies in KERIO.
; 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.
; The following is the I/O code for the Victor 9000.
CSEG $
; Clock rate *10 for timing loops ;[19g]
clckrt equ 48 ;[19g] 4.8 Mhz
;[35a] begin
; Offsets of memory-mapped Victor "ports" within segment 0E000H
mdmseg EQU 0E000H ;Segement for memory-mapped 7201 of Victor
mnstat EQU 042H ;Status port A.
mndata EQU 040H ;Data port A.
mnctl1 EQU 000H ;Interrupt controller.
mnctl2 EQU 001H ;Interrupt controller.
mnclk1 EQU 023H ;For setting baud rate
mnclk2 EQU 020H ; "
;[35a] end
; Interrupt vector locations. These are all in data segment 0.
mnoff EQU 84H ;Main data port interrupt routine offset. [35]
mnseg EQU 86H ;Main data port interrupt routine segment. [35]
output EQU 04H ;Bit for output ready.
input EQU 01H ;Bit for input ready.
outlmt EQU 1000H ;Number of times to check output status
; before giving up on send. ;[20d]
; Input data from port. Preserves all ACs 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
mov bx, offset 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
; Output data to port. Trashes DX and prints char in AL.
;[35b] begin
outchr: push es
push si
mov dx, mdmseg
mov es, dx
mov si, mndata
mov es:[si], al
pop si
pop es
ret
;[35b] end
; Test if data is available from port.
instat: cmp mnchrn, 0 ;Any chars in the buffer?
jnz inst2
ret
inst2: jmp rskp
; Test if port is ready to send next char. Returns RETSKP 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
;[35c] begin
push es
push si
mov dx, mdmseg
mov es, dx
mov si, mnstat
mov al, es:[si]
test al, output
pop si
pop es
;[35c] end
pop ax
jnz outwt2
ret
outwt2: jmp rskp
; Output the character, checking first to make sure the port is clear.
prtout: call dopar ;[par]
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
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
mov sp, offset mnstk
push ds ;Save all registers.
push es
push bp
push di
push si
push dx
push cx
push bx
mov ds, ax
mov dx, mdmseg ;[35]
mov es, dx ;[35]
call mnproc ;Process the character.
;[35d] begin
mov si, mnctl1 ;Point to the interrupt controller
mov al, 061H
mov es:[si], al ;Re-enable interrupts
mov si, mnstat ;Get the status port.
mov al, 38H
mov es:[si], al ;Tell the port we finished with the interrupt.
;[35d] end
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 main port
; and puts it in the infamous circular buffer.
mnproc: mov si, mnstat ;[35] Check port status
mov al, es:[si] ;[35]
test al, input ;Any there?
jnz mnpro2 ;Yup, go take care of it.
;[33] Begin addition
; If not a received character, simulate an interrupt transferring
; control to the CPM routine. Let it handle worrisome things like
; someone turning on the printer.
;[35e] begin
;Unlike the Rainbow, Victor CP/M does not normally handle these interrupts.
;Let's just return, lest we wreak havoc...
; pushf ; Save flags, like an int.
; callf dword ptr mnoldo ; Call CPM's routine.
;[35e] end
ret ; Now back to MNINT.
;[33] End addition
;[35f] begin
mnpro2: mov al, 1 ;Point to RR1.
mov es:[si], al
mov al, es:[si] ;Read RR1.
mov ah, al ;Save it.
mov al, 30H ;Reset any errors.
mov es:[si], al
mov si, mndata
mov al, es:[si] ;Read the char.
;[35f] 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
mov bx, offset 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 ; [19e] start
prtbrk: ;
;[35g] begin
push es ;save registers
push si
mov dx, mdmseg ;Point to "port" segment
mov es, dx
mov si, mnstat ;status reg. address for port
mov al, 15H ;select reg. 5
mov es:[si], al
mov al, 0FAH ;8 bits, TX, Break, RTS, & DTR
mov es:[si], al ;Turn Break on
mov ax, 275 ;.. for 275 millisec's [34]
call mswait ; [34]
mov al, 15H ;select reg. 5
mov es:[si], al
mov al, 0EAH ;same as above without Break
mov es:[si], al ;turn it off
pop si
pop es
ret ; [19e] end
;[35g] end
mswait: ; [34] start
mov cx,5*clckrt ; inner loop count for 1 millisec.
mswai1:
sub cx,1 ;** inner loop takes 20 clock cycles
jnz mswai1 ;**
dec ax ; outer loop counter
jnz mswait ; wait another millisecond
ret ; [34] end
;
; Init the 7201 for 8 bits, no parity, and 1 stop bit.
serini: ;call ansmod ;Switch from VT52 to ANSI mode ;[30c][35] removed
cmp mninit, 0FFH
je serin2
mov mninit, 0FFH
mov ax, ds
mov cs:mndseg, ax ;Save the data segment somewhere in CSEG.
push ds ;Save the data segment.
mov ax, 0
mov ds, ax ;We want DSEG = 0.
cli ;Turn off interrupts.
mov bx, .mnoff ;[33] Get original interrupt offset.
mov es, .mnseg ;[33] Get original interrupt segment.
mov ax, offset mnint;Point to the interrupt routine offset.
mov .mnoff, ax ;Put in the main port interrupt offset addr.
mov ax, cs ;Get our code segment.
mov .mnseg, ax ;Put in the main port interrupt segment addr.
pop ds ;Restore data segment.
mov mnoldo, bx ;[33] Stash original serial interrupt offset.
mov mnolds, es ;[33] Stash original segment.
;[35h] begin
push es ;Save registers
push si
mov dx, mdmseg ;Get "port" segment
mov es, dx
mov si, mnstat ;Point to status port.
mov al, 18H ;Reset the port.
mov es:[si], al
mov al, 14H ;Select register 4.
mov es:[si], al
mov al, 48H ;16X clock, 1.5 stop bits, no parity.
mov es:[si], al
mov al, 13H ;Select register 3.
mov es:[si], al
mov al, 0C1H ;8 bits/char, RX enable.
mov es:[si], al
mov al, 15H ;Select register 5.
mov es:[si], al
mov al, 0EAH ;8 bits/char, TX enable, RTS and DTR.
mov es:[si], al
mov al, 11H ;Select register 1.
mov es:[si], al
mov al, 18H ;Enable interrupt processing on this port.
mov es:[si], al
mov si, mnctl2 ;point to 8259 interrput controller
mov al,es:[si]
and al, 0FDH ;Enable interrupt processing
mov es:[si], al
mov si, mnctl1
mov al, 061H
mov es:[si], al ;Clears outstanding requests
sti ;Restore interrupts.
pop si
pop es
call stbaud
serin2: ret
serfin:
call clrscr ;[19b] clear screen ;[30c]
cmp mninit, 0FFH
jne serfn2
mov mninit, 0
cli
push es
push si
mov dx, mdmseg ;Victor
mov es, dx ;Victor
mov si, mnctl2 ;point to 8259 interrput controller
mov al,es:[si] ;Enable interrupt processing
or al, 02H
mov es:[si], al
mov si, mnstat
mov al, 01
mov es:[si], al
mov al, 00
mov es:[si], al
mov ax, mnoldo ;[33] Get original interrupt offset.
mov es, mnolds ;[33] Get original interrupt segment.
push ds ;Save the data segment.
mov dx, 0
mov ds, dx ;We want DSEG = 0.
mov .mnoff, ax ;Put in the main port interrupt offset addr.
mov .mnseg, es ;Put in the main port interrupt segment addr.
pop ds ;Restore data segment.
pop si
pop es
sti
serfn2: ret
;[35h] end
; 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
DSEG $
mnchnd equ 256 ;[19a] Size of circular buffer.
mntrg1 equ 64 ;[19a] Low trigger point for Auto XON/XOFF
mntrg2 equ 192 ;[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
mnchrn DW 0 ;[19a] Number of chars in the 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.
mnoldo RW 1 ;[33] CPM's 7201 interrupt vector offset
mnolds RW 1 ;[33] and segment.
mninit DB 0 ;set to 0FFH if initialization has been done
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.
;[35i] begin
; This is the SET BAUD rate subcommand
; set the baud rate
stbaud: mov al,mnbaud ;get the baud rate information
cmp al,15 ;check for valid range (0-15)
ja stb02
mov bx,offset baudtb;get address of baud rate table
add al,al ;compute word offset
mov ah,0
add bx,ax
push es
push si
mov ax, mdmseg
mov es, ax
mov si, mnclk1
mov al, 036H
mov es:[si], al
mov si, mnclk2
mov ax, [bx]
mov es:[si], al
mov es:[si], ah
pop si
pop es
stb02: ret
dseg $
; Serial port default parameters
mnbaud db 13 ;9600 baud
; Interval Timer values (assumes 16x baud rate mode)
baudtb dw 061Bh ;50 baud 0
dw 0412h ;75 baud 1
dw 02C6h ;110 baud 2
dw 0245h ;135 baud 3
dw 0209h ;150 baud 4
dw 0104h ;300 baud 5
dw 0082h ;600 baud 6
dw 0041h ;1200 baud 7
dw 002Bh ;1800 baud 8
dw 0027h ;2000 baud 9
dw 0021h ;2400 baud 10
dw 0016h ;3600 baud 11
dw 0010h ;4800 baud 12
dw 0008h ;9600 baud 13
dw 0004h ;19200 baud 14
dw 0002h ;38400 baud 15
CSEG $
bdset: mov dx, offset bdtab
mov bx, offset 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
;[35i] end
;This is the SET PORT subcommand (not implemented in Victor at this time)
prtset: mov ah, cmcfm
call comnd ;Get a confirm.
jmp $+3 ; Didn't get a confirm.
mov dx, offset 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.
;[35j] begin
shobd: mov dx, offset bdst ;Baud rate string.
call tcrmsg
mov al, mnbaud ;Print the keyword corresponding to the
mov bx, offset bdtab ; current value of mnbaud.
call tabprt
ret
DSEG $
bdtab db 16 ;Thirteen entries ;[6] begin
db 3,'110$'
dw 0002H
db 4,'1200$'
dw 0007H
db 3,'135$'
dw 0003H
db 3,'150$'
dw 0004H
db 4,'1800$'
dw 0008H
db 5,'19200$'
dw 000EH
db 4,'2000$'
dw 0009H
db 4,'2400$'
dw 000AH
db 3,'300$'
dw 0005H
db 4,'3600$'
dw 000BH
db 5,'38400$'
dw 000FH
db 4,'4800$'
dw 000CH
db 2,'50$'
dw 0000H
db 3,'600$'
dw 0006H
db 2,'75$'
dw 0001H
db 4,'9600$'
dw 000DH ;[6] end
bdhlp:
db cr,lf,' 50 110 150 600 1800 2400 4800 19200'
db cr,lf,' 75 135 300 1200 2000 3600 9600 38400$'
CSEG $
;[35j] end
shoprt: ret ;Port selection not implemented.
; 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.
;[35k] begin
poscur:
mov si, dx
mov dx, offset anspos ; move prefix string
mov cl, prstr
int bdos
xor dx,dx
mov dl, [si]
add dl,01FH ; this is the row
mov cl,dconio ; no checking please
int bdos
mov dl, 1[si]
add dl,01FH ; this is the column
mov cl,dconio
int bdos
ret
;[35k] end
; CLRSCR - homes cursor and clears screen.
clrscr: mov dx, offset anscls
call tmsg
ret
; CLRLIN - clears from cursor to end of line.
clrlin: mov dl, cr ;Go to beginning of line
call bout
clreol: mov dx, offset ansclr ;Clear from cursor to end of line
call tmsg
ret
; REVON - turns on reverse video display
revon: mov dx, offset ansron
call tmsg
ret
; REVOFF - turns off reverse video display
revoff: mov dx, offset ansrof
call tmsg
ret
; BLDON - turns on bold (highlighted) display
bldon: mov dx, offset ansbon
call tmsg
ret
; BLDOFF - turns off bold (highlighted) display
bldoff: mov dx, offset ansbof
call tmsg
ret
; ANSMOD - enters ANSI mode from VT52 mode
;[35l] begin ; Just keep Victor in VT52 (actually Heath-19) mode
ansmod: ;mov dx, offset ansion
;call tmsg
ret
DSEG $
anspos db esc,'Y$' ;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,'p$' ;Turn on reverse video
ansrof db esc,'q$' ;Turn off reverse video
ansbon db esc,'($' ;Turn on bold (highlight) display
ansbof db esc,')$' ;Turn off bold display
ansion db '$' ;Enter ANSI mode
;[35l] end
; 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 ' Victor 9000$' ;[35]