home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
cpm86
/
c86xrb.a86
< prev
next >
Wrap
Text File
|
2011-08-09
|
13KB
|
485 lines
; * * * * * * * * * * * * * * * 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 DEC Rainbow.
CSEG $
; Clock rate *10 for timing loops ;[19g]
clckrt equ 48 ;[19g] 4.8 Mhz
; Interrupt vector locations, in data segment
mnstat EQU 042H ;Status port.
mndata EQU 040H ;Data port.
mnctrl EQU 002H ;Control port.
; Interrupt vector locations. These are all in data segment 0.
mnoff EQU 90H ;Main data port interrupt routine offset.
mnseg EQU 92H ;Main data port interrupt routine segment.
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.
outchr: mov dx, mndata
out dx, al
ret
; 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
mov dx, mnstat
in al, dx
test al, output
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
call mnproc ;Process the character.
mov dx, mnstat ;Get the status port.
mov al, 38H
out dx, al ;Tell the port we finished with the interrupt.
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 dx, mnstat
in al, dx ;Get the port status.
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.
pushf ; Save flags, like an int.
callf dword ptr mnoldo ; Call CPM's routine.
ret ; Now back to MNINT.
;[33] End addition
mnpro2: mov al, 1 ;Point to RR1.
out dx, al
in al, dx ;Read RR1.
mov ah, al ;Save it.
mov al, 30H ;Reset any errors.
out dx, al
mov dx, mndata
in al, dx ;Read the char.
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: ;
mov dx, mnstat ;status reg. address for port
mov al, 15H ;select reg. 5
out dx, al ;
mov al, 0FAH ;8 bits, TX, Break, RTS, & DTR
out dx, al ;Turn Break on
mov ax, 275 ;.. for 275 millisec's [34]
call mswait ; [34]
mov al, 15H ;select reg. 5
out dx, al ;
mov al, 0EAH ;same as above without Break
out dx, al ;turn it off
ret ; [19e] 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]
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.
sti ;Restore interrupts.
pop ds ;Restore data segment.
mov mnoldo, bx ;[33] Stash original serial interrupt offset.
mov mnolds, es ;[33] Stash original segment.
mov dx, mnstat ;Point to status port.
mov al, 18H
out dx, al ;Reset the port.
mov al, 14H
out dx, al ;Select register 4.
mov al, 44H ;16X clock, 1 stop bit, no parity.
out dx, al
mov al, 13H
out dx, al ;Select register 3.
mov al, 0C1H ;8 bits/char, RX enable.
out dx, al
mov al, 15H
out dx, al ;Select register 5.
mov al, 0EAH ;8 bits/char, TX enable, RTS and DTR.
out dx, al
mov al, 11H
out dx, al ;Select register 1.
mov al, 18H
out dx, al ;Enable interrupt processing on this port.
mov dx, mnctrl ;point to comm control port
mov al, 0F0H ;set RTS & DTR high
out dx, al
ret
serfin:
call clrscr ;[19b] clear screen ;[30c]
ret ;Nothing to deinitialize on Rainbow.
; 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.
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 (not implemented in Rainbow)
bdset: 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
; This is the SET PORT subcommand (not implemented in Rainbow)
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.
shobd: ret ;Baud rate selection not implemented.
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.
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
mov dx, offset anspos ;Print cursor positioning string.
call tmsg
ret
; 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
ansmod: mov dx, offset 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,'<$' ;Enter 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 ' DEC Rainbow-100$'