home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
cpm86.tar.gz
/
cpm86.tar
/
c86xr2.a86
< prev
next >
Wrap
Text File
|
2011-08-09
|
16KB
|
574 lines
; * * * * * * * * * * * * * * * version 2.9 * * * * * * * * * * * * * * *
; [35a] Kermit now sets a default baud rate.
; [35b] Implemented the SET BAUD command.
; [35c] Implemented the baud rate function to the SHOW command.
; The above was done to make operation compatable with CPM-80 version
; and simplify use by non computer orientated users.
; Mark Woollard, 4/12/85, Animal and Grassland Research Institute
; * * * * * * * * * * * * * * * 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]
defbd EQU 0BH ; [35a] Default baud rate, 0=50 baud, 1=75,
; 2=110, 3=134.5, 4=150, 5=200, 6=300, 7=600
; 8=1200, 9=1800, 10=2000, 11=2400, 12=3600
; 13=4800, 14=9600 and 15=19200
; 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
mov al,defbd ; [35a] Get default baud
mov dl,al ; Save it
mov cl,4 ; Move low nibble into high
shl al,cl ;
or al,dl ; Replace low nibble
out 6,al ; Write to baud control port
mov baudrt,al ; Save it for show baud ;[35a] end
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]
baudrt rb 1 ;Current baud rate
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 bdset1 ; Didn't get a confirm.
jmp bdset2 ; [35b] Go and ask for baud
bdset1: mov dx, offset ermes3 ; Tell user unknown command option
call tcrmsg
jmp rskp
bdset2: mov dx, offset bdlst ; Print list of baud speeds
call tmsg
bdstrt: mov cl,1 ; Get a response from keyboard
int 224
and al,5fH ; Force upper case
cmp al,'A'
jnb bdset3 ; AL >= 'A'...
jmp bdset4 ; Response too low
bdset3: cmp al,'P'
jle bdset5 ; AL <= 'P'...
bdset4: mov dx,offset rtrmss ; Incorrect response so delete char
call tmsg ; typed and make keyboard beep
jmp bdstrt ; Go and try again...
bdset5: sub al,'A' ; Convert to internal baud rate code
mov dl,al ; Save AL
mov cl,4 ; Move lower nibble into upper
shl al,cl
or al,dl ; replace lower nibble
out 6,al ; Write to baud port
mov baudrt,al ; Save for SHOW BAUD ;[35b] end
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.
; SHOW BAUD command
shobd: mov dx, offset bdst ;[35c] Print 'Baud rate:'
call tcrmsg
mov al,baudrt ; Get current baud rate
and al,0FH ; Mask off high nibble
mov cl,6 ; Multiply by 6
mul cl
add ax, offset bdmss2 ; Set up DX as an offset into
mov dx,ax ; the list of baud strings
call tmsg ; Print the string
ret ; ;[35c] 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.
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$'
bdlst db esc,'[H',esc,'[J','Baud rates available :' ;[35b] Baud rate list
db cr,lf,cr,lf,' A) 50' ;for SET BAUD
db cr,lf,' B) 75'
db cr,lf,' C) 110'
db cr,lf,' D) 134.5'
db cr,lf,' E) 150'
db cr,lf,' F) 200'
db cr,lf,' G) 300'
db cr,lf,' H) 600'
db cr,lf,' I) 1200'
db cr,lf,' J) 1800'
db cr,lf,' K) 2000'
db cr,lf,' L) 2400'
db cr,lf,' M) 3600'
db cr,lf,' N) 4800'
db cr,lf,' O) 9600'
db cr,lf,' P) 19200'
db cr,lf,cr,lf,'Enter choice > $'
rtrmss db 8,' ',8,7,'$' ;[35b] Delete char and beep string
bdmss2 db '50 $' ;[35c] Used by SHOW BAUD option
db '75 $'
db '110 $'
db '134.5$'
db '150 $'
db '200 $'
db '300 $'
db '600 $'
db '1200 $'
db '1800 $'
db '2000 $'
db '2400 $'
db '3600 $'
db '4800 $'
db '9600 $'
db '19200$'