; 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 ;