; * * * * * * * * * * * * * * * version 2.7 * * * * * * * * * * * * * * * ; [30e] Add support for Fujitsu Micro 16s ; Chris Barker, 01/04/85 ; [30d] Add SET PORT command, currently unimplemented. ; [30c] Isolate all machine dependencies in KERIO. ; [30a] Add keyboard DEL key alteration for APC ; 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 ; * * * * * * * * * * * * * * * 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. ; Here are the I/O routines for the Fujitsu Micro 16s CSEG $ ; Clock rate *10 for timing loops ;[19g] clckrt equ 80 ;[19g] 8.0 Mhz ;[30e] ; Interrupt vector locations, in data segment 0 mnioff equ 30h ;sio interrupt offset mniseg equ 32h ;sio interrupt segment ; 8259 Interrupt controller (master) iccmd equ 00h ;interrupt command register icmask equ 02h ;interrupt mask register ; 8259 commands and masks icEOI equ 20h ;end of interrupt (command) ;ictmof equ 08h ;disable timer (mask) icmnof equ 04h ;disable RS232 (mask) ; Baud Rate controller (MB 14417) bdport equ 0FD59h ;baud rate select (read/write) ; 8251A USART controller mndata equ 0FD06h ; data port mnsts1 equ 0FD07h ;in status port mncmd equ 0FD07h ;out command port ; 8251 status port 1 bits mninp equ 02h ;receive ready value mnout equ 01h ;send ready value mndsr equ 80h ;data set ready ; 8251 initialization instructions ; command instructions ctxe equ 01h ;transmit enable cdtr equ 02h ;dtr signal high crxe equ 04h ;receive enable cbrk equ 08h ;send break cerr equ 10h ;error reset crts equ 20h ;rts signal high cmode equ 40h ;reset - go to mode instruction format chunt equ 80h ;hunt for sync characters ; mode instructions m1x equ 01h ;baud rate factor: 1x m16x equ 02h ; 16x m64x equ 03h ; 64x m5d equ 00h ;data bits: 5 m6d equ 04h ; 6 m7d equ 08h ; 7 m8d equ 0Ch ; 8 mpn equ 00h ;parity: none mpo equ 10h ; odd mpe equ 30h ; even m1s equ 40h ;stop bits: 1 m15s equ 80h ; 1.5 m2s equ 0C0h ; 2 outlmt equ 1000h ;Number of times to check output status ; before giving up on send. ;[20d] ; Test if port is ready to send next char. Returns RSKP 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,mnsts1 in al,dx and al,mndsr+mnout sub al,mndsr+mnout jz outwt2 outwt1: pop ax ret outwt2: pop ax jmp rskp ; Output data to port. Trashes DX and prints char in AL. outchr: mov dx,mndata out dx,al ret ; Output the character in AL, checking first to make sure the port is clear. prtout: call dopar ;[par] set parity 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 ; Test if data is available from port. instat: cmp mnchrn,0 ;Any chars in the buffer? jnz inst2 ret inst2: jmp rskp ; Input data from port. Preserves all registers 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 lea bx,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 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 lea sp, mnstk push ds ;Save all registers. push es push bp push di push si push dx push cx push bx mov ds, ax ;Get our data segment address. call mnproc ;Process the character. mov dx, iccmd mov al, icEOI ;signal end of interrupt to 8259A out dx, al 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 serial port ; and puts it in the ring buffer. mnproc: mov dx,mnsts1 in al,dx ;Get the port status. and al,mninp ;Is a character waiting? jnz mnpro2 ; Yes, go take care of it. ret ; No, just a false alarm. mnpro2: 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 lea bx,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 ; [20b] start prtbrk: mov dx,mncmd ;break goes to command port mov al,cbrk+crts+cerr+crxe+cdtr+ctxe ;add break to normal command out dx,al mov cx, 25000 ;sit for a while prtbk1: loop prtbk1 mov al,crts+cerr+crxe+cdtr+ctxe ;RTS & DTR high, Rx & Tx enabled out dx,al ;return to normal setting ret ; [20b] end ; serini - This routine initializes all devices that need it. ; Called at the start of the program. serini: cmp mninit,0FFh ; must only do this initialization once je serin2 mov mninit,0FFh push es mov dx,icmask in al,dx ;get current interrupt mask mov mnxmsk,al ;save it for restore ; or al,ictmof+icmnof;mask off timer and sio interrupts or al,icmnof ;mask off sio interrupt out dx,al mov ax,ds ;save data segment in cseg mov cs:mndseg,ax ; for use by the interrupt handler mov ax,0 ;point to zero page to replace mov es,ax ;the sio interrupt vector mov ax,es:.mniseg ;after first saving the current vector mov mnxseg,ax mov ax,es:.mnioff mov mnxoff,ax cli mov ax,cs mov es:.mniseg,ax mov ax,offset mnint mov es:.mnioff,ax sti ; call stmode ;set mode & baud to defaults call stbaud mov dx,mndata ;dummy read to clear buffer in al,dx mov dx,icmask in al,dx ;enable sio interrupts and al,not icmnof out dx,al pop es serin2: ret ; serfin - this routine is used to "undo" what serini has done, called ; just before exiting back to cp/m. serfin: call clrscr ;[19b] clear screen ;[30c] cmp mninit,0FFh ;check if initialization has been done jne serfn2 ;if not, don't de-initialize mov mninit,0 push es cli mov dx,icmask mov al,mnxmsk ;restore the old interrupt mask out dx,al mov ax,0 mov es,ax mov ax,mnxseg ;restore sio interrupt vector mov es:.mniseg,ax mov ax,mnxoff mov es:.mnioff,ax sti pop es serfn2: ret ; 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 ; set the parity, number of data bits, and number of stop bits stmode: ;do this all in stbaud for micro16s ; set the baud rate stbaud: mov al,mnbaud ;get the baud rate information cmp al,6 ;check for valid range (0-6) ja stb03 ;j/ out of valid range mov bx,offset baudtb;get address of baud rate table mov ah,0 add bx,ax mov dx,bdport mov al,[bx] ;get value out dx,al ;output byte mov al,m64x jne stb02 ; mov al,m16x ;for 19200 bd stb02: push ax mov dx,mncmd mov al,0 ;recommended reset procedure: out dx,al ;three 0's followed by a cmode mov al,0 out dx,al mov al,0 out dx,al mov al,cmode ;enable mode setting out dx,al pop ax add al,m1s ;1 stop, no parity, 8 data, 16x baud add al,mpn ;Note: these adds are distinct to add al,m8d ; allow the 8251 time to reset out dx,al mov al,crts+cerr+crxe+cdtr+ctxe ;RTS & DTR high, Rx & Tx enabled out dx,al stb03: ret dseg $ ; Serial port default parameters mnbaud db 5 ;9600 baud ; Interval Timer values (assumes 64x baud rate mode) baudtb db 00h ;300 baud 0 db 11h ;600 baud 1 db 22h ;1200 baud 2 db 33h ;2400 baud 3 db 44h ;4800 baud 4 db 55h ;9600 baud 5 db 44h ;19200 baud 6 - requires 16x rate mode mninit db 0 ;set to 0FFh if initialization has been done mnxmsk db 0 ;8259 interrupt mask storage mnxseg dw 0 ;system sio interrupt vector mnxoff dw 0 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 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 bdset: lea dx, bdtab lea bx, 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 ; This is the SET PORT subcommand (not implemented in APC) prtset: mov ah, cmcfm call comnd ;Get a confirm. jmp $+3 ; Didn't get a confirm. lea dx, 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: lea dx, bdst ;Baud rate string. call tcrmsg mov al, mnbaud ;Print the keyword corresponding to the lea bx, bdtab ; current value of mnbaud. call tabprt ret shoprt: ret ;Port selection not implemented. DSEG $ bdtab db 7 ;Thirteen entries ;[6] begin db 4,'1200$' dw 0002h db 5,'19200$' dw 0006h db 4,'2400$' dw 0003h db 3,'300$' dw 0000h db 4,'4800$' dw 0004h db 3,'600$' dw 0001h db 4,'9600$' dw 0006h ;[6] end bdhlp db cr,lf,' 300 600 1200 2400' db cr,lf,' 4800 9600 19200$' ; 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 ax, [bx] ; add ax, ' ' ;Add 20h to both row and column mov word ptr anspos+2, ax lea dx, anspos ;Print cursor positioning string. call tmsg ret ; CLRSCR - homes cursor and clears screen. clrscr: lea dx, fujcls call tmsg ret ; CLRLIN - clears from cursor to end of line. clrlin: mov dl, cr ;Go to beginning of line call bout clreol: lea dx, ansclr ;Clear from cursor to end of line call tmsg ret ; REVON - turns on reverse video display revon: lea dx, ansron call tmsg ret ; REVOFF - turns off reverse video display revoff: lea dx, ansrof call tmsg ret ; BLDON - turns on bold (highlighted) display bldon: lea dx, ansbon ; call tmsg ; ret ; BLDOFF - turns off bold (highlighted) display bldoff: lea dx, ansbof ; call tmsg ; ret DSEG $ anspos db esc,'=00$' ;Position cursor to row and column fujcls db 1Eh,1Ah,'$' ;Home cursor and clear screen ansclr db esc,'T$' ;Clear from cursor to end of line ansron db esc,'G',0Ch,'$' ;Turn on reverse video (green) ansrof db esc,'G',04h,'$' ;Turn off reverse video (green) ansbon db esc,'G',05h,'$' ;Turn on bold (uses blue) ansbof db esc,'G',04h,'$' ;Turn off bold (back to green) ; Here tab expansion is done if necessary. If not, just return retskp. cseg $ dotab: jmp rskp ;No, just proceed. dseg $ curbuf db 2,0,0 ;command, row, column of cursor position delstr db 10O, 10O, '$' ;Delete string. system db ' FUJITSU Micro 16s $' ;[1][20a]