home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
cpm86.tar.gz
/
cpm86.tar
/
c86xfu.a86
< prev
next >
Wrap
Text File
|
2011-08-09
|
28KB
|
1,038 lines
; STARTSYSDEP ; This is so:
; ; PIP LISTING=86KERMIT.LST[WSSTARTSYSDEP^ZQENDxSYSDEP^Z]
; ; will work.
;
;
; **************************************************************************
;
; This is the i/o support module for the Future Computers FX20/FX30
; Running CP/M-86 or Concurrent CP/M.
;
; Tony Chabot, University of Birmingham, UK October 1985
; (Based on the version for the Honeywell MSE by Mark Hewitt).
;
; This module checks which type of CP/M system it is running under,
; and alters its performance accordingly. No separate assembly is
; required for CP/M-86 and Concurrent.
; It is preferable to use the KERUTL from Concurrent implementations
; as that will work with both types of CP/M, whereas the standard
; version of KERUTL (for CP/M-86) will not work fully with Concurrent.
;
; This implementation allows only the modem port to be used.
; This is because the printer port does not have its rx interrupt request
; line connected to the 8259 interrupt controller.
;
; The modem port uses a 7201 Multi Protocol Serial Controller, situated
; at address C120-C123, with the relevant addresses for the modem part
; of it being C121 & C123.(Note - the FX20/FX30 manual incorrectly gives
; the addresses as C122 and C123).
; The baud rate generator is an 8253-5, timer 1.
; The range of addresses for this device is C060-C063. The generator
; has a 4MHz clock input (gleaned from a scope, so this is not too accurate,
; but a frequency meter seemed to think the frequency was 1MHz +- 10% !).
; The 7201 is programmed to divide by 16, so the baud rate divider is given
; by
; divider = 4000000/(16*baudrate)
;
; The 8259 interrupt controller is programmed (by CP/M) to base its vectors
; at 100. The relationship between the 8259 IR lines and the requesting device
; is:
;
; IR0 ?
; IR1 PIT (out0)
; IR2 7201
; IR3 ?
; IR4 ?
; IR5 Keyboard 8251 RxRdy
; IR6 Printer 8251 TxRdy
; IR7 Pulled up.
;
; Only IR0, IR1 and IR5 have useful interrupt service routines, as well
; as the predefined vectors and CP/M system call vectors. All other
; vectors point, via some register saving code, to an illegal interrupt
; routine. It is thus simple to patch the vector for the 7201 (at 108-10B)
; to point to our ISR.
;
; ** W A R N I N G **
;
; The 7201 also handles the LAN, so if you have lan software running, it
; is likely that this code will cause problems.
;
;
; **************************************************************************
CSEG $
; Port base definitions
bgen equ 0C060h ; Baud Rate Generator (8253-5)
ictrl equ 0C000h ; Interrupt Controller (8259A)
; And the I/O ports themselves
bgcmd equ bgen+3 ; Baud rate generator command port
iccmd equ ictrl+0 ; Interrupt controller command port
icmask equ ictrl+1 ; Interrupt controller mask register port
mdmcmd equ 0C123h ; modem command port
mdmbg equ bgen+1 ; Baud rate countdown value for modem port
mdmio equ 0C121h ;modem data io port (Note-FX30 manual is wrong)
ptrcmd equ 0C122h
;
;
; Port selection
;
pmdm equ 0
;
; Interrupt vectors in page 0
;
mdmvec equ 0108h ; Interrupt vector for modem.
;
; Interrupt masks
;
immdm equ 04h ; Mask for modem port.
;
; Baud rate generator command words
;
mdmbsel equ 76h ; Select modem baud rate register
;
; Interrupt controller commands
;
iceoi equ 20h ; end of interrupt
;
; I/O register bits:
;
; For 7201 'Multiprotocol Serial Communications Controller' ( a name
; worthy of IBM !).
;
ccreg0 equ 00h ; Control instruction - select register 0
ccreg1 equ 01h ; Control instruction - select register 1
ccreg2 equ 02h ; Control instruction - select register 2
ccreg3 equ 03h ; Control instruction - select register 3
ccreg4 equ 04h ; Control instruction - select register 4
ccreg5 equ 05h ; Control instruction - select register 5
ccreg6 equ 06h ; Control instruction - select register 6
ccreg7 equ 07h ; Control instruction - select register 7
c0null equ 00h ; Register 0 - null command
c0abort equ 08h ; Register 0 - send abort
c0resi equ 10h ; Register 0 - reset ext. status ints.
c0chrst equ 18h ; Register 0 - channel reset
c0eninc equ 20h ; Register 0 - enable int. on next character
c0rpti equ 28h ; Register 0 - reset pending tx int./DMA req.
c0errst equ 30h ; Register 0 - error reset
c0eoi equ 38h ; Register 0 - end of interrupt
c0rxcrc equ 40h ; Register 0 - reset rx CRC checker
c0txcrc equ 80h ; Register 0 - reset tx CRC generator
c0ricrc equ 0C0h ; Register 0 - reset idle/CRC latch
c1stien equ 01h ; Register 1 - external/status int enable
c1txien equ 02h ; Register 1 - transmitter interrupt enable
c1cav equ 03h ; Register 1 - condition affects vector
c1noi equ 00h ; Register 1 - no rx or DMA interrupts
c1i1st equ 08h ; Register 1 - int. on 1st received character
c1iall equ 10h ; Register 1 - int. on all received characters
c1ialp equ 18h ; Register 1 - int on all rx'd chars, no parity
c1wrxtx equ 20h ; Register 1 - WAIT on rx/tx
c1txbcm equ 40h ; Register 1 - TX byte count mode enbable
c1wten equ 80h ; Register 1 - WAIT function enable
;
; and some useful abbreviations
;
c1norm equ c1ialp
;
c2dma0 equ 00h ; Register 2 - No DMA
c2dma1 equ 01h ; Register 2 - DMA mode 1
c2dma2 equ 02h ; Register 2 - DMA mode 2
c2dma3 equ 03h ; Register 2 - DMA mode 3
c2pri equ 04h ; Register 2 - Set DMA priority
c2ack0 equ 00h ; Register 2 - Int Ack mode 0 (NV,D432)
c2ack1 equ 08h ; Register 2 - Int Ack mode 1 (NV, D432)
c2ack2 equ 10h ; Register 2 - Int Ack mode 2 (NV, D210)
c2ack4 equ 20h ; Register 2 - Int Ack mode 4 (8085 master)
c2ack5 equ 28h ; Register 2 - Int Ack mode 5 (8085 slave)
c2ack6 equ 30h ; Register 2 - Int Ack mode 6 (8086)
c2ack7 equ 38h ; Register 2 - Int Ack mode 7(8085/8259A slave)
c2rxim equ 40h ; Register 2 - rx interrupt mask
c2syncb equ 80h ; Register 2 - pin 10 ~RTSB or ~SYNCB
c3rxen equ 01h ; Register 3 - receive enable
c3scli equ 02h ; Register 3 - sync character load inhibit
c3asm equ 04h ; Register 3 - address search mode
c3rxcrc equ 08h ; Register 3 - receiver CRC enable
c3hunt equ 10h ; Register 3 - enter hunt phase
c3aen equ 20h ; Register 3 - auto enables on DCD/CTS
c3r5bit equ 00h ; Register 3 - 5 bit data
c3r6bit equ 40h ; Register 3 - 6 bit data
c3r7bit equ 80h ; Register 3 - 7 bit data
c3r8bit equ 0C0h ; Register 3 - 8 bit data
;
; and some useful abbreviations
;
c3norm equ c3rxen+c3r8bit
;
c4pen equ 01h ; Register 4 - parity enable
c4ep equ 02h ; Register 4 - even parity
c41stp equ 04h ; Register 4 - 1 stop bit
c415stp equ 08h ; Register 4 - 1.5 stop bits
c42stp equ 0C0h ; Register 4 - 2 stop bits
c48syn equ 00h ; Register 4 - 8 bit internal sync (monosync)
c416syn equ 10h ; Register 4 - 16 bit internal sync (bisync)
c4sdlc equ 20h ; Register 4 - SDLC
c4exts equ 30h ; Register 4 - External sync
c41clk equ 00h ; Register 4 - 1x clock rate
c416clk equ 40h ; Register 4 - 16x clock rate
c432clk equ 80h ; Register 4 - 32x clock rate
c464clk equ 0C0h ; Register 4 - 64x clock rate
;
; and some useful abbreviations
;
c4norm equ c41stp+c416clk
;
c5txcrc equ 01h ; Register 5 - transmitter CRC enable
c5rts equ 02h ; Register 5 - request to send
c5poly equ 04h ; Register 5 - CRC polynomial select
c5txen equ 08h ; Register 5 - transmitter enable
c5sbrk equ 10h ; Register 5 - send break
c5t5bit equ 00h ; Register 5 - transmit 5 bit data
c5t6bit equ 20h ; Register 5 - transmit 6 bit data
c5t7bit equ 40h ; Register 5 - transmit 7 bit data
c5t8bit equ 60h ; Register 5 - transmit 8 bit data
c5dtr equ 80h ; Register 5 - data terminal ready
;
; and some useful abbreviations
;
c5norm equ c5rts+c5txen+c5t8bit+c5dtr
;
cs0rxr equ 01h ; Status register 0 - received char ready
cs0ip equ 02h ; Status register 0 - interrupt pending
cs0tbe equ 04h ; Status register 0 - tx buffer empty
cs0dcd equ 08h ; Status register 0 - data carrier detect
cs0sync equ 10h ; Status register 0 - sync status
cs0cts equ 20h ; Status register 0 - clear to send
cs0idle equ 40h ; Status register 0 - idle CRC latch status
cs0brk equ 80h ; Status register 0 - break detect
cs1sent equ 01h ; Status register 1 - all sent
cs1sdlc equ 0Eh ; Status register 1 - SDLC residue code
cs1pe equ 10h ; Status register 1 - parity error
cs1oe equ 20h ; Status register 1 - overrun error
cs1fe equ 40h ; Status register 1 - framing error
cs1eosf equ 80h ; Status register 1 - end of SDLC frame
; System call defs for concurrent version.
p_dispatch equ 8Eh ; Reschedule.
f_errmode equ 2Dh ; Set BDOS error mode.
;
; Clock rate *10 for timing loops ;[19g]
;
clckrt equ 80 ;[19g] 8.0 Mhz
;
; Maximum number of examinations of output port to be ready before
; rescheduling.
;
outlmt equ 1000h
;
; The executable code starts here
;
;
; ===========================================================================
;
; INITIALISATION ROUTINES
;
; ===========================================================================
;
; INTERFACE ROUTINE SERINI - Initialisation code
;
serini: cmp mninit, true ; Ensure that we only initialise once
je serin2
mov mninit, true
; Get type of CP/M system.
;
mov cl,0ch
int bdos
mov cpmtyp, bh
;
; Initialise the screen
;
call clrscr ; Clear the screen.
;
; Disable I/O interrupts, and save the old interrupt mask.
;
mov dx, icmask ; read the current interrupt mask
in al, dx
mov oldmsk, al ; and save it
or al, immdm ; mask off i/o interrupts
out dx, al ; and reprogram interrupt controller
;
; Save the system i/o interrupt vectors
;
mov ax, ds ; save the data segment in code segment
mov cs:mndseg, ax ; for use by interrupt handler
mov ax, 0 ; point to zero page and save both the
mov es, ax ; system's i/o interrupt vectors
mov ax,es:.mdmvec+0 ; for the modem channel
mov vscoff, ax
mov ax, es:.mdmvec+2
mov vscseg, ax
; Configure the default port
;
mov ax, 0 ; point to zero page and set the interrupt
mov es, ax ; vector for the modem/printer channel to my
; interrupt service routine
mov ax, offset isr ; set offset address
mov es:.mdmvec+0, ax
mov ax, cs ; set segment address
mov es:.mdmvec+2, ax
call setmode ; set UART mode for current port
call setbaud ; set the baud rate for the current port
call mnflush ; flush and enable the current port
call inton ; turn interrupts on for current port
; If concurrent, set BDOS error mode.
;
cmp cpmtyp, 14h
jne serin2
mov cl, f_errmode
mov dl, 0FEh ; Set err mode to display and return.
int bdos
serin2: ret ; initialisation over
;
; INTERFACE ROUTINE SERFIN - restore environment (as far as possible)
; to that which existed before we played with it
;
serfin: cmp mninit, true ; only deinitialise if necessary
jne serfn2
mov mninit, false
;
; Disable i/o interrupt while we reset the vectors
;
mov dx, icmask ; get present interrupt mask
in al, dx ; and turn off all i/o interrupts
or al, immdm ; from the modem channel
out dx, al ; reprogram the interrupt controller
;
; Reset the i/o interrupt vectors
;
mov ax, 0 ; point at page 0 and reset the int. vectors
mov es, ax
mov ax, vscoff ; for the modem/printer port
mov es:.mdmvec+0, ax
mov ax, vscseg
mov es:.mdmvec+2, ax
;
; turn interrupts back on (or off...)
;
mov al, oldmsk ; restore original interrupt mask
out dx, al
;
; Reset screen modes
;
call clrscr ; Be tidy - clear the screen.
serfn2: ret ; deinitialisation over
;
;
; INTERNAL ROUTINE SETMODE - set the operating mode for current port's UART.
;
setmode:
push ax
push dx ; we'll need this
mov dx, mdmcmd ; Command port adrs.
mov al, c0chrst ; reset the port
out dx, al
mov al, c0resi+ccreg4 ; select register 4
out dx, al
mov al, c4norm ; 16x Clock, 1 stop bit, no parity
out dx, al
mov al, c0resi+ccreg3 ; Select register 3
out dx, al
mov al, c3norm ; 8 bits/character, RX enable
out dx, al
mov al, c0resi+ccreg5 ; select register 5
out dx, al
mov al, c5norm ; 8 bits/character, TX enable RTS and DTR
out dx, al
mov al, c0resi+ccreg1 ; select register 1
out dx, al
mov al, c1norm ; Interrupt enable
out dx, al
pop dx ; modes now set, restore regs. and return
pop ax
ret
;
; INTERNAL ROUTINE SETBAUD - set the baud rate of a current port.
; port number in cport.
; timer countdown table offset in cbaud.
;
setbaud:
push bx ; we'll be using this
push dx ; and this
push ax ; and this too
mov al, bdtab ; check that rate is legal
dec al ; pick up number of valid rates from BDTAB
cmp cbaud, al ; 0 <= cbaud <= [bdtab]-1
ja setbd2 ; just return if not legal
mov bx, offset bdtct; get timer value
mov al, cbaud ; from timer countdown table
mov ah, 0
add al, al ; word offset
add bx, ax ; bx now points to correct value
mov dx, bgcmd ; dx is now baud rate generator command port
cmp cport, pmdm ; is it the modem port?
jne setbd2 ; just return if not
mov al, mdmbsel ; set baud rate for modem port
out dx, al
mov dx, mdmbg
jmp setbd3
setbd3: mov ax, [bx] ; set the countdown value
out dx, al
mov al, ah
out dx, al
setbd2: pop ax ; baud rate set, retore regs. and return
pop dx
pop bx
ret
;
; INTERNAL ROUTINE MNFLUSH - enable and flush current port.
; Port in cport.
;
mnflush:
push ax ; preserve registers
push dx
mov dx, mdmio ; Modem data port adrs.
in al, dx ; flush the port
in al, dx
in al, dx
mov dx, mdmcmd ; reset any pending interrupts
mov al, c0errst
out dx, al
mov al, c0resi
out dx, al
pop dx ; port flushed, retore regs. and return
pop ax
ret
;
; INTERNAL ROUTINE INTON - enable interrupts for the selected port
; (This version simply enables the modem port!)
; Ensure that the port selected is enabled, and
; that all other ports are as the system would
; wish them!
inton:
push ax
push dx
mov dx, icmask
in al,dx ; Read current interrupt mask.
and al, not immdm ; Enable modem interrupts.
out dx, al
inton2: pop dx
pop ax ; interrupts now enabled - restore regs.
ret ; and return
DSEG $ ; Data used by initialisation/deinitialisation
mninit db false ; flag set when initialised
oldmsk rb 1 ; Old interrupt mask
cpmtyp db 0 ; CP/M type (0 = CP/M-86, 14h = concurrent).
;
; Current port status
;
cport db pmdm ; current port number - default to modem
cbaud db 8 ; current baud rate - default to 4800
ciop dw mdmio ; current i/o port - default to modem
ccmdp dw mdmcmd ; current command/status port - default modem
;
; Storage for system interrupt vectors
;
vscoff rw 1 ; offset for system v.24/printer int. vector
vscseg rw 1 ; seg. address for system v.24/printer int. vec
;
; Baud rate timer countdown table
; (The accuracy of these is uncertain as the baud rate generator clock
; frequency was measured with a scope).
;
bdtct dw 5000 ; 50 baud, code 0
dw 3333 ; 75
dw 2273 ; 110
dw 1667 ; 150
dw 833 ; 300
dw 417 ; 600
dw 208 ; 1200
dw 104 ; 2400
dw 52 ; 4800
dw 26 ; 9600
dw 13 ; 19200
CSEG $
; ===========================================================================
;
; SET COMMANDS
;
; ===========================================================================
;
; INTERFACE ROUTINE BDSET - set baud rate for current port (cport).
; save current baud rate in cbaud.
;
bdset: mov dx, offset bdtab ; table of valid baud rates
mov bx, offset bdhlp ; help information for SET BAUD
mov ah, cmkey ; Command parser - KEYWORD lookup
call comnd
jmp r ; error return
mov settmp, bx ; Normal return - save value
mov ah, cmcfm ; Command parser - CONFIRM
call comnd
jmp r
mov bx, settmp
mov cbaud, bl ; save the baud rate
call setbaud ; and set it for the current port
jmp rskp ; end of parsing SET BAUD command
DSEG $
settmp rw 1 ; temporary storage for baud rate
CSEG $
;
; INTERFACE ROUTINE PRTSET - set the current port.
;
prtset: mov dx, offset potab ; table of valid port names
mov bx, offset pohlp ; help information for SET PORT
mov ah, cmkey ; Command parser - KEYWORD lookup
call comnd
jmp r ; error return
mov settmp, bx ; Normal return - save value
mov ah, cmcfm ; Command parser - CONFIRM
call comnd
jmp r
jmp rskp ; end of parsing SET PORT command
;
; Data required by the SET commands
;
DSEG $ ; SET command data
;
; Baud rate table
;
bdtab db 11 ; number of entries
db 3, '110$' ; size of entry, and the keyword$
dw 02 ; value returned
db 3, '150$'
dw 03
db 4, '1200$'
dw 06
db 5, '19200$'
dw 10
db 4, '2400$'
dw 07
db 3, '300$'
dw 04
db 4, '4800$'
dw 8
db 2, '50$'
dw 00
db 3, '600$'
dw 05
db 2, '75$'
dw 01
db 4, '9600$'
dw 09
;
; Help table for baud rate setting
;
bdhlp db cr, lf, ' 50 75 110 150 300 600'
db cr, lf, ' 1200 2400 4800 9600 19200'
db '$'
;
; Port table
;
potab db 1
db 5, 'MODEM$'
dw pmdm
;
; Help table for port selection
;
pohlp db cr, lf, 'MODEM$'
CSEG $
; ===========================================================================
;
; SHOW COMMANDS
;
; ===========================================================================
;
; INTERFACE ROUTINE SHOBD - display the currently set baud rate within
; the SHOW command.
;
shobd: mov dx, offset bdst ;Baud rate string.
call tcrmsg
mov al, cbaud ;Print the keyword corresponding to the
mov bx, offset bdtab; current value of mnbaud.
call tabprt
ret
;
; INTERFACE ROUTINE SHOPRT - display the currently selected communication
; port within the SHOW command.
;
shoprt: mov dx, offset prtst ; Port name string
call tcrmsg
mov al, cport ; current port code
mov bx, offset potab ; and print the corresponding
call tabprt ; textual description
mov dx, offset prtst2
call tmsg
ret
DSEG $
prtst db 'Communicating via $'
prtst2 db ' port$'
CSEG $
; ===========================================================================
;
; I/O ROUTINES
;
; ===========================================================================
;
; INTERNAL ROUTINE ISR - Interrupt service routine for modem port.
;
isr:
cli ; disable intrerupts
mov cs:mnax, ax ; save ax - we will need a register
mov ax, sp
mov cs:mnsp, ax ; save current stack pointer
mov ax, ss
mov cs:mnsseg, ax ; Save current stack segment
mov ax, cs:mndseg ; Switch to my stack
mov ss, ax
mov sp, offset mnstk
push ds ; Save registers
push es
push bp
push di
push si
push dx
push cx
push bx
mov ds, ax ; set our data segment address
;
; That's the housekeeping out of the way - now we can start
;
mov dx, mdmcmd ; see if char. ready at default port
in al, dx
test al, cs0rxr ; is there a character for us?
jz iprt3 ; no - clear interrupt, and return
iprt2: mov dx, mdmio ; Fetch the character
in al, dx
call iproc ; Process the character in AL
iprt3: mov dx, iccmd ; Signal end of interrupt to
mov al, iceoi ; interrupt controller
out dx, al
mov dx, ptrcmd ; Clear interrupt status at
mov al, c0eoi ; 7201
out dx, al ; (note we use the A channel).
pop bx ; Restore registers
pop cx
pop dx
pop si
pop di
pop bp
pop es
pop ds
mov ax, cs:mnsp ; restore interrupt stack
mov sp, ax
mov ax, cs:mnsseg ; restore original stack segment
mov ss, ax
mov ax, cs:mnax ; restore original AX
iret ; all over - return
;
; CSEG data required by interrupt service routine
;
mnax dw 0 ; temp. copy of AX
mnsp dw 0 ; interrupt stack pointer
mnsseg dw 0 ; interrupt stack segment
mndseg dw 0 ; location of our data segment
;
; INTERNAL ROUTINE IPROC - process incoming character from Rx interrupt
; Character in AL
;
iproc: cmp floctl, floxon ;are we doing flow-control ? [19a] start
jne ipr2b ;no - go on
cmp al, xoff ;is it an XOFF?
jne ipr2a ;no - go on
mov xofrcv, true ;set the flag
ret
ipr2a: cmp al, xon ;an XON?
jne ipr2b ;no
mov xofrcv, false ;clear the flag
ret ; [19a] end
ipr2b: cmp mnchrn,mnchnd ;Is the buffer full?
je iperr ;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 ipro3
mov bx, offset mnchrs ;Yes, point to the start again.
ipro3: mov mnchip,bx ;Save the pointer.
mov [bx],al ;Put the character in the buffer.
cmp floctl, floxon ;do flow-control? [19a] start
je ipro4 ;If yes jump
ret
ipro4: cmp xofsnt, true ;Have we sent an XOFF
jnz ipro5
ret ;return if we have
ipro5: cmp mnchrn, mntrg2 ;Past the High trigger point?
ja ipro6 ;yes - jump
ret
ipro6: mov al, xoff
call prtout ;send an XOFF
mov xofsnt, true ;set the flag
ret ; [19a] End
iperr: ret ; just return on error for now
;
; INTERFACE ROUTINE CFIBF - Clear serial port input buffer
;
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
;
; INTERFACE ROUTINE PRTOUT - send character in AL to current port.
;
prtout: call dopar ; set parity if necessary
push dx
push cx
mov cx, outlmt
prtou2: call outwait ; wait for port to be free, or timeout
loop prtou2
nop
call outchr ; output the character
pop cx
pop dx
ret
;
; INTERNAL ROUTINE OUTWAIT - test if port ready for next char to be sent.
; returns RSKP if ready.
;
outwait:
cmp floctl, floxon
jne outwt1
cmp xofrcv, true
je outwt3
outwt1:
push ax
mov dx, mdmcmd
in al, dx
test al, cs0tbe
jnz outwt4
pop ax
outwt3:
cmp cpmtyp, 14h ; Concurrent?
jne outwt35 ; No.
call dispatch ; Yes - redispatch the processor.
outwt35:
ret
outwt4: pop ax
jmp rskp
;
; INTERNAL ROUTINE OUTCHR - send data to a port
;
outchr: mov dx, mdmio
out dx, al
ret
;
; INTERFACE ROUTINE INSTAT - determine if there is any data to receive.
;
instat: cmp mnchrn, 0 ; any characters in buffer?
jne inst2
ret
inst2: jmp rskp
;
; INTERFACE ROUTINE INCHR - read a character from a port
;
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
;
; INTERFACE ROUTINE PRTBRK - Send a BREAK sequence to the default port
;
prtbrk: mov dx, mdmcmd ; Modem port cmd byte.
cmp cport, pmdm ; is it modem port?
jne brka ; must be an error - just return
brkc:
mov al, c0resi+ccreg5 ; Break to modem port.
out dx, al ; Select register 5
mov al, c5norm+c5sbrk ; 8 bits, TX enable, Break, RTS & DTR
out dx, al
mov ax, 275 ; for 275 mS
call mswait
mov al, c0resi+ccreg5 ; select register 5
out dx, al
mov al, c5norm ; 8 bits, TX enable, RTS & DTR
out dx, al
ret
brka: ret
DSEG $
;
; Input character queue
;
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
;
; a small stack for interrupt handling
;
rw 64 ;Interrupt stack ;[28e]
mnstk dw 0 ;bottom of stack ;[28e]
CSEG $
; ===========================================================================
;
; UTILITY ROUTINES
;
; ===========================================================================
;
; INTERNAL ROUTINE MSWAIT - Delay for AL milliseconds
;
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
;
; INTERNAL ROUTINE DISPATCH
;
; Function Redispatch processor.
;
; Inputs None.
;
; Outputs None.
;
; Side effects Processor is redispatched.
; All registers preserved.
;
dispatch:
push ax
push bx
push cx
mov cl, p_dispatch
int bdos
pop cx
pop bx
pop ax
ret
; ===========================================================================
;
; SCREEN CONTROL ROUTINES
;
; ===========================================================================
;
; INTERFACE ROUTINE POSCUR - positions cursor to row and col (each 1 byte)
; pointed to by dx.
;
poscur:
mov bx, dx ;Do cursor positioning.
mov dx, offset scrpos ;Print cursor positioning string.
call tmsg
mov al, [bx] ;Get row value
add ax, 1Fh ;Convert to ASCII
mov dl,al
push bx ;(Gets clobbered by bout)
call bout
pop bx
mov al, 1[bx] ;Do same for column value
add ax, 1Fh
mov dl,al
call bout
ret
;
; INTERFACE ROUTINE CLRSCR - homes cursor and clears screen.
;
clrscr: mov dx, offset scrcls
call tmsg
ret
;
; INTERFACE ROUTINE CLRLIN - clears line.
;
clrlin: mov dl, cr ;Go to beginning of line
call bout
;
; ...FALL THROUGH
;
; INTERFACE ROUTINE CLREOL - clear to end of line
;
clreol: mov dx, offset scrclr ;Clear from cursor to end of line
call tmsg
ret
;
; INTERFACE ROUTINE REVON - turns on reverse video display
;
revon: mov dx, offset scrron
call tmsg
ret
;
; INTERFACE ROUTINE REVOFF - turns off reverse video display
;
revoff: mov dx, offset scrrof
call tmsg
ret
;
; INTERFACE ROUTINE BLDON - turns on bold (highlighted) display
;
bldon: mov dx, offset scrbon
call tmsg
ret
;
; INTERFACE ROUTINE BLDOFF - turns off bold (highlighted) display
;
bldoff: mov dx, offset scrbof
call tmsg
ret
DSEG $
scrpos db esc, 'Y$' ;Position cursor to row and column
scrcls db esc, 'E$' ;Home cursor and clear screen
scrclr db esc, 'K$' ;Clear from cursor to end of line
scrron db esc, 'p$' ;Turn on reverse video
scrrof db esc, 'q$' ;Turn off reverse video
scrbon db esc, 'm$' ; Bold on (Actually underline).
scrbof db esc, 'n$' ; Bold off
CSEG $
;
; INTERFACE ROUTINE DOTAB - do tab expansion if necessary
;
dotab: jmp rskp ; assume h/w does it for now
;
; Assorted textual constants required as part of the machine interface
;
DSEG $
delstr db esc,'D ',esc,'D$' ;Delete string.
system db ' Future Computers FX20/FX30 (TC - Oct 85)$'
CSEG $
;
; ENDSYSDEP
;