head     56.3;
access   paws bayes jws quist brad dew jwh;
symbols  ;
locks    ; strict;
comment  @# @;


56.3
date     93.01.27.13.26.45;  author jwh;  state Exp;
branches ;
next     56.2;

56.2
date     93.01.27.12.05.09;  author jwh;  state Exp;
branches ;
next     56.1;

56.1
date     91.11.05.09.47.02;  author jwh;  state Exp;
branches ;
next     55.1;

55.1
date     91.08.25.10.24.04;  author jwh;  state Exp;
branches ;
next     54.1;

54.1
date     91.03.18.15.27.30;  author jwh;  state Exp;
branches ;
next     53.1;

53.1
date     91.03.11.19.28.20;  author jwh;  state Exp;
branches ;
next     52.1;

52.1
date     91.02.19.09.12.19;  author jwh;  state Exp;
branches ;
next     51.1;

51.1
date     91.01.30.16.12.04;  author jwh;  state Exp;
branches ;
next     50.1;

50.1
date     90.10.29.16.26.43;  author jwh;  state Exp;
branches ;
next     49.1;

49.1
date     90.08.14.14.11.00;  author jwh;  state Exp;
branches ;
next     48.1;

48.1
date     90.07.26.11.17.11;  author jwh;  state Exp;
branches ;
next     47.1;

47.1
date     90.05.14.11.00.10;  author dew;  state Exp;
branches ;
next     46.1;

46.1
date     90.05.07.08.47.22;  author jwh;  state Exp;
branches ;
next     45.1;

45.1
date     90.04.19.15.55.15;  author jwh;  state Exp;
branches ;
next     44.1;

44.1
date     90.04.01.22.12.18;  author jwh;  state Exp;
branches ;
next     43.1;

43.1
date     90.03.20.14.04.16;  author jwh;  state Exp;
branches ;
next     42.1;

42.1
date     90.01.23.17.49.03;  author jwh;  state Exp;
branches ;
next     41.1;

41.1
date     89.12.22.11.31.02;  author jwh;  state Exp;
branches ;
next     40.2;

40.2
date     89.12.15.11.03.01;  author dew;  state Exp;
branches ;
next     40.1;

40.1
date     89.09.29.11.52.52;  author jwh;  state Exp;
branches ;
next     39.1;

39.1
date     89.09.26.16.37.05;  author dew;  state Exp;
branches ;
next     38.1;

38.1
date     89.08.29.11.29.13;  author jwh;  state Exp;
branches ;
next     37.1;

37.1
date     89.05.12.11.41.37;  author dew;  state Exp;
branches ;
next     36.1;

36.1
date     89.02.06.10.19.54;  author dew;  state Exp;
branches ;
next     35.1;

35.1
date     89.02.02.13.35.00;  author dew;  state Exp;
branches ;
next     34.1;

34.1
date     89.01.23.16.10.06;  author jwh;  state Exp;
branches ;
next     33.1;

33.1
date     89.01.16.11.41.56;  author dew;  state Exp;
branches ;
next     32.1;

32.1
date     89.01.10.11.50.42;  author bayes;  state Exp;
branches ;
next     31.1;

31.1
date     88.12.14.18.11.50;  author bayes;  state Exp;
branches ;
next     30.1;

30.1
date     88.12.09.13.48.39;  author dew;  state Exp;
branches ;
next     29.1;

29.1
date     88.10.31.15.33.42;  author bayes;  state Exp;
branches ;
next     28.1;

28.1
date     88.10.06.11.00.19;  author dew;  state Exp;
branches ;
next     27.1;

27.1
date     88.09.29.11.36.25;  author bayes;  state Exp;
branches ;
next     26.1;

26.1
date     88.09.28.13.15.34;  author bayes;  state Exp;
branches ;
next     25.1;

25.1
date     88.03.02.09.32.08;  author bayes;  state Exp;
branches ;
next     24.1;

24.1
date     87.08.31.09.52.32;  author jws;  state Exp;
branches ;
next     23.1;

23.1
date     87.08.26.10.30.23;  author bayes;  state Exp;
branches ;
next     22.1;

22.1
date     87.08.17.11.16.55;  author bayes;  state Exp;
branches ;
next     21.1;

21.1
date     87.08.12.13.59.06;  author bayes;  state Exp;
branches ;
next     20.1;

20.1
date     87.07.30.11.12.08;  author bayes;  state Exp;
branches ;
next     19.1;

19.1
date     87.06.01.08.27.34;  author jws;  state Exp;
branches ;
next     18.1;

18.1
date     87.05.20.15.27.50;  author bayes;  state Exp;
branches ;
next     17.1;

17.1
date     87.04.30.10.38.16;  author jws;  state Exp;
branches ;
next     16.1;

16.1
date     87.04.26.15.50.13;  author jws;  state Exp;
branches ;
next     15.1;

15.1
date     87.04.13.09.25.50;  author jws;  state Exp;
branches ;
next     14.1;

14.1
date     87.04.01.15.31.11;  author jws;  state Exp;
branches ;
next     13.1;

13.1
date     87.02.28.18.35.18;  author jws;  state Exp;
branches ;
next     12.1;

12.1
date     87.02.02.13.26.09;  author jws;  state Exp;
branches ;
next     11.1;

11.1
date     87.01.19.09.52.36;  author jws;  state Exp;
branches ;
next     10.1;

10.1
date     86.12.24.11.01.40;  author jws;  state Exp;
branches ;
next     9.1;

9.1
date     86.12.12.14.43.38;  author bayes;  state Exp;
branches ;
next     8.1;

8.1
date     86.11.27.11.59.32;  author jws;  state Exp;
branches ;
next     7.1;

7.1
date     86.11.20.13.50.09;  author hal;  state Exp;
branches ;
next     6.1;

6.1
date     86.11.04.18.02.00;  author paws;  state Exp;
branches ;
next     5.1;

5.1
date     86.10.28.16.50.49;  author hal;  state Exp;
branches ;
next     4.1;

4.1
date     86.09.30.19.50.24;  author hal;  state Exp;
branches ;
next     3.1;

3.1
date     86.09.01.12.00.27;  author hal;  state Exp;
branches ;
next     2.1;

2.1
date     86.07.30.14.47.46;  author hal;  state Exp;
branches ;
next     1.1;

1.1
date     86.06.30.15.17.46;  author danm;  state tmp;
branches ;
next     ;


desc
@Base file for PWS 3.2 release.

@


56.3
log
@
pws2rcs automatic delta on Wed Jan 27 13:14:25 MST 1993
@
text
@	TTL IOLIB RS - RS232 DRIVERS
******************************************************************************
*
*       COPYRIGHT (C) 1985 BY HEWLETT-PACKARD COMPANY
*
******************************************************************************
*
*
*       IOLIB     RS
*
*
******************************************************************************
*
*
*
*       Library - IOLIB
*
*       Purpose - This set of assembly language code is intended to be used as
*                 a PASCAL module for I/O drivers for use by the external I/O
*                 procedures library.
*
*
*       Date    - 8-6-82
*       Update  - 6-5-84 BY J Schmidt
*       Release - 7-12-85
*
*
*       Source  - RS: RS.TEXT
*       Object  - RS: RS.CODE
*
*
*
*
******************************************************************************
*
*
*           RELEASED        VERSION 3.1
*
*
******************************************************************************
*
*       CHANGES (since 2.0):
*           {aaa} -- changes for ignore parity error register 20.
*
*       CHANGES for 3.0
*           {ttt} -- timing changes for 680xx -- JS 8/3/83, 5/3/84
*
*       CHANGES for 3.1
*           (jws}  -- new default setups, add control/status 21, 22. 6/5/85
*
*       CHANGES for 3.23
*           {dew1}  -- fixed timing problem with reset.  DW 12/89
*
******************************************************************************
	 PAGE
******************************************************************************
*
*
*       The following lines are used to tell the LINKER/LOADER what this
*       module looks like in PASCAL terms.
*
*       Note that it is possible to create assembly modules that are functions.
*       These routines are called through an indirect pointer using the CALL
*       facility which does NOT permit functions.
*
*       This module is called 'RS' ( upper or lower case - doesn't matter )
*       independent of the file name ( by use of the MNAME pseudo-op ).
*
*       All the externally used procedures are called 'RS_@@@@@@@@@@@@@@@@' in
*       this module.  If you are using assembly to access them use the
*       'RS_@@@@@@@@@@@@@@' name.  If you are using Pascal use the '@@@@@@@@@@@@@@'
*       name.
*
*******************************************************************************

	MNAME RS

	SRC MODULE RS;
	SRC IMPORT iodeclarations;
	SRC EXPORT
	SRC
	SRC        PROCEDURE rs_init    ( temp : ANYPTR );
	SRC        PROCEDURE rs_isr     ( temp : PISRIB );
	SRC        PROCEDURE rs_rdb     ( temp : ANYPTR ; VAR x : CHAR );
	SRC        PROCEDURE rs_wtb     ( temp : ANYPTR ;  val  : CHAR );
	SRC        PROCEDURE rs_rdw     ( temp : ANYPTR ; VAR x : io_word);
	SRC        PROCEDURE rs_wtw     ( temp : ANYPTR ;  val  : io_word);
	SRC        PROCEDURE rs_rds     ( temp : ANYPTR ;  reg  : io_word;
	SRC                                               VAR x : io_word);
	SRC        PROCEDURE rs_wtc     ( temp : ANYPTR ;  reg  : io_word;
	SRC                                                val  : io_word );
	SRC        PROCEDURE rs_tfr     ( temp : ANYPTR ;  bcb  : ANYPTR);
	SRC END; { of RS }
	PAGE
******************************************************************************
*
*       SYMBOLS FOR EXPORT AS PROCEDURE NAMES
*
******************************************************************************

	DEF RS_RS

	DEF RS_RS_INIT
	DEF RS_RS_ISR
	DEF RS_RS_RDB
	DEF RS_RS_WTB
	DEF RS_RS_RDW
	DEF RS_RS_WTW
	DEF RS_RS_RDS
	DEF RS_RS_WTC
	DEF RS_RS_TFR

******************************************************************************
*
*       SYMBOLS FOR IMPORT
*
******************************************************************************

	LMODE   ABORT_IO,LOGEOT
	REFA    ABORT_IO,LOGEOT
	REFA    DELAY_TIMER,CHECK_TIMER              ttt JS 8/3/83
	LMODE   DELAY_TIMER,CHECK_TIMER              ttt JS 8/3/83


	INCLUDE IOLIB:COMDCL
	page
*
*       REGISTER USAGE SUMMARY (of utility routines)
*
*       Global Usage
*          a5 -- Pascal Global Base
*          a6 -- Pascal Stack Frame
*          a7 -- Stack Pointer
*          a1 -- Card Address
*          a2 -- Driver Attributes ('temp' space)
*
*       ROUTINE         a0  a3  a4  d0  d1  d2  d3  d4  d5  d6  d7
*       ----------------------------------------------------------
*       queue_space      -   -   -   -   -   -   O   -   -   -   -
*       queue_empty      -   -   -   -   -   -   -   -   -   -   T
*       queue_full       -   -   -   -   -   -   -   -   -   -   T
*       inqueue          -   -   G   -   -   I   -   -   -   -   G
*       outqueue         -   -   G   -   -   O   -   -   -   -   G
*       init_queue       -   -   -   -   -   -   -   -   -   -   -
*       check_queue      -   -   -   -   -   -   -   -   -   -   T
*       check_dsr_cts    -   -   -   -   -   -   -   -   -   -   T
*       wait             -   -   I   -   -   -   -   G   -   L   T
*       send             -   -   P   -   -   -   I   L   -   L   T
*       get_char         -   -   L   T   -   O   P   L   -   L   L
*       wait_send        -   -   L   -   -   -   I   L   -   L   L
*       wait_get         -   -   P   L   -   O   L   L   -   L   L
*       check_error      -   -   -   -   -   -   -   -   -   -   -
*       soft_reset*      -   -   -   -   -   -   -   -   -   T   T
*       connect*         -   -   -   -   -   -   -   -   -   L   L
*       disconnect       -   -   -   -   -   -   -   -   -   -   -
*       rdivu            -   -   -   I   O   -   -   -   -   -   -
*       check_xfer_in    -   -   -   -   -   -   -   -   -   -   -
*       check_xfer_out   -   -   -   -   -   -   -   -   -   -   -
*       clear_xfer+      -   I   -   -   -   -   -   -   -   -   -
*       set_xfer         -   I   -   -   -   -   -   -   -   -   -
*       dump_buffer      G   I   L   L   -   O   L   L   -   L   L
*
*       NOTATION (in order of importance)
*          O :  output parameter
*          I :  input parameter
*          G :  used by routine (register has consistent meaning throughout routine
*          P :  used to pass parameter to called routines
*          T :  used by routine (temporary)
*          L :  possible usage by called routines
*          - :  not used by routine
*
*       NOTE:  the registers used by routines to do an ioescape have been
*              left out since they do not effect other routines.
*
*       *This routine calls ABORT_IO which uses other registers not listed
*       +This routine calls LOGEOT which uses other registers not listed

	page
*
*       ROUTINE USAGE SUMMARY
*
*       ROUTINE         CALLS
*       -------         -----
*       queue_space     <none>
*       queue_empty     <none>
*       queue_full      <none>
*       inqueue         <none>
*       outqueue        <none>
*       init_queue      <none>
*       check_queue     <none>
*       check_dsr_cts   <none>
*       wait            check_queue, check_dsr_cts (both indirectly)
*       send            wait, check_dsr_cts
*       get_char        outqueue, queue_space, send
*       wait_send       send, check_error
*       wait_get        wait, check_error, get_char, check_queue
*       check_error     ioescape
*       soft_reset      init_queue, ABORT_IO
*       connect         soft_reset
*       disconnect      <none>
*       rdivu           <none>
*       check_xfer_in   ioescape
*       check_xfer_out  ioescape
*       clear_xfer      <none>
*       set_xfer        <none>
*       dump_buffer     queue_empty, get_char, clear_xfer, LOGEOT
*       ioescape        <none>
*       init            init_queue, ABORT_IO
*       rdb             connect, check_error, check_xfer_in, wait_get
*       wtb             connect, check_error, check_xfer_out, wait_send
*       rdw             connect, check_error, check_xfer_in, wait_get
*       wtw             connect, check_error, check_xfer_out, wait_send
*       rds             queue_empty, get_char, check_error, rdivu, ioescape,
*                       connect
*       wtc             check_error, soft_reset, connect, disconnect, rdivu,
*                       ioescape
*       isr             queue_space, queue_full, inqueue, check_dsr_cts,
*                       send, dump_buffer, LOGEOT
*       tfr             connect, check_error, dump_buffer, set_xfer

	page
*
*
*       ROUTINE         CALLED BY
*       -------         ---------
*       queue_space     get_char, isr
*       queue_empty     dump_buffer, rds (6, 10)
*       queue_full      isr
*       inqueue         isr
*       outqueue        get_char
*       init_queue      init, soft_reset
*       check_queue     wait_get (with wait)
*       check_dsr_cts   isr, send (with and without wait)
*       wait            wait_get, wait_send, send
*       send            isr, wait_send, get_char
*       get_char        rds(6), dump_buffer, wait_get
*       wait_send       wtb, wtw
*       wait_get        rdb, rdw,
*       check_error     rdb, wtb, rdw, wtw, rds(6), wtc(6), tfr,
*                       wait_send, wait_get
*       soft_reset      wtc(14), connect
*       connect         rdb, wtb, rdw, wtw, wtc(12), tfr
*       disconnect      wtc(12)
*       rdivu           rds(3), wtc(3)
*       check_xfer_in   rdb, rdw,
*       check_xfer_out  wtb, wtw
*       clear_xfer      isr, dump_buffer
*       set_xfer        tfr
*       dump_buffer     tfr, isr
*       ioescape        rds, wtc, tfr, check_error, check_xfer_in,
*                       check_xfer_out
*       ABORT_IO        init, soft_reset
*       LOGEOT          isr, dump_buffer


	TTL     RS232 DRIVERS
	page
*****************************************************************************
*
*       module initialization -- none required.
*
*****************************************************************************

RS_RS   EQU *
	RTS


*****************************************************************************
*
*       98626 card register mnemonics
*
*****************************************************************************

RESET_REG       EQU     1               write only
ID_REG          EQU     1               read only
INTR_SW         EQU     3               interrupt switches
BAUD_SW         EQU     5               baud rate switch bank
LINE_SW         EQU     7               line characteristic switches

*
*       UART registers
*

DATA            EQU     17              receive/transmit buffer (dlab=0)
INTR_EN         EQU     19              interrupt enable register(dlab=0)
DIV0            EQU     17              divisor latch (LSB)   (DLAB=1)
DIV1            EQU     19              divisor latch (MSB)   (DLAB=1)
INTR_ID         EQU     21              interrupt identification
LINE_CONT       EQU     23              line control register
MODEM_CONT      EQU     25              modem control register
LINE_STAT       EQU     27              line status register
MODEM_STAT      EQU     29              modem status register
		page
******************************************************************************
*
*       ATTRIBUTE space offset mnemonics
*         (do not mix -- word boundary problems)
*         the word address is assumed to be EVEN
*         starting at AVAIL_OFF
*
******************************************************************************
*                                     size
*                                     ----
S_ERROR         EQU     AVAIL_OFF       4  pending error number
IN_ISR          EQU     S_ERROR+4       1
XIN_ACT         EQU     IN_ISR+1        1
CONNECTED       EQU     XIN_ACT+1       1
MODEM_ON        EQU     CONNECTED+1     1
RECEIVING       EQU     MODEM_ON+1      1
XMITTING        EQU     RECEIVING+1     1
S_MODEM         EQU     XMITTING+1      1  modem status copy
S_LINE          EQU     S_MODEM+1       1  line status copy
S_HANDSH        EQU     S_LINE+1        1  contains current handshake
XON_CHAR        EQU     S_HANDSH+1      1
XOFF_CHAR       EQU     XON_CHAR+1      1
ENQ_CHAR        EQU     XOFF_CHAR+1     1
ACK_CHAR        EQU     ENQ_CHAR+1      1
CONV_CHAR       EQU     ACK_CHAR+1      1
IGNORE_PE       EQU     CONV_CHAR+1     1  {aaa}
*empty                                  1  {aaa}
Q_DESCRIPT      EQU     IGNORE_PE+2        {aaa}
Q_SIZE          EQU     Q_DESCRIPT      2
Q_IN            EQU     Q_DESCRIPT+2    2
Q_OUT           EQU     Q_DESCRIPT+4    2
Q_BUFFER        EQU     Q_DESCRIPT+6    134 the rest is internal buffer {aaa}
DEF_BAUD        EQU     Q_BUFFER+134    2  jws  Note: stuck here for
DEF_LINE        EQU     DEF_BAUD+2      1  jws        code compatibility.
*empty                                  1  jws
*                                       ---
*                                       164  total space used    {jws}


******************************************************************************
*
*       constants (mnemonics)
*
******************************************************************************

TEMP_SIZE       EQU     160
BUFFER_SIZE     EQU     TEMP_SIZE-Q_BUFFER+AVAIL_OFF
DC1             EQU     17              ASCII CHARACTER 17
DC3             EQU     19              ASCII CHARACTER 19
ENQ             EQU     5               ASCII CHARACTER 5
ACK             EQU     6               ASCII CHARACTER 6
UNDERSCORE      EQU     95              ASCII CHARACTER 95
OVERRUN_ERROR   EQU     314             receive buffer overflow error
ACK_SIZE        EQU     80              hysteresis for ENQ/ACK handshake
XOFF_SIZE       EQU     40              when to send XOFF
XON_SIZE        EQU     BUFFER_SIZE-XOFF_SIZE
REG_MAX         EQU     22              maximum control/status register number {aaa}
	TTL     RS232 DRIVERS -- initialize
	page
*****************************************************************************
*
*       driver initialization
*
*****************************************************************************

RS_RS_INIT      EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0        * get return address
	MOVEA.L (SP)+,A2        * get temp address
	MOVEA.L C_ADR(A2),A1    * get card address
	PEA     (A0)            * restore return address
*
*   Assembler initialize entry point
*       ON ENTRY:  A1  and  A2  are set to card address and
*                  temp space address (respectively)
*

ASM_INIT        EQU *

*
*   Stop transfers and Reset the card
*

	JSR     ABORT_IO        * stop transfers
*                                 -- RESET CARD --
	ST      RESET_REG(A1)   *  write to reg 1
*
*   wait at least 25us
*
	MOVE.L  #40,-(SP)       USE DELAY ROUTINE   dew1 12/89
	JSR     DELAY_TIMER     DELAY FOR 40us

*
*       global attribute initialization
*
*                                  -- init queue descriptors --
	BSR     INIT_QUEUE
*                                  -- init pseudo registers --
	CLR.B   XIN_ACT(A2)
	CLR.B   IN_ISR(A2)
	CLR.L   S_ERROR(A2)
	CLR.B   S_MODEM(A2)
	CLR.B   S_LINE(A2)
	CLR.B   CONNECTED(A2)
	CLR.B   MODEM_ON(A2)
	CLR.B   IGNORE_PE(A2)           {aaa}
*                                  -- set flags --
	MOVE.B  #1,RECEIVING(A2)
	MOVE.B  #1,XMITTING(A2)
*                                  -- default characters --
	MOVE.B  #DC1,XON_CHAR(A2)
	MOVE.B  #DC3,XOFF_CHAR(A2)
	MOVE.B  #ENQ,ENQ_CHAR(A2)
	MOVE.B  #ACK,ACK_CHAR(A2)
	MOVE.B  #UNDERSCORE,CONV_CHAR(A2)

*
*   Set defaults from the switches (done after attribute initialization
*                just in case the card is not completely reset already)
*
*                                  -- set baud rate from DEF_BAUD --
*
	BSET    #7,LINE_CONT(A1) *   set DLAB to get to divisor latches
	MOVE.B  DEF_BAUD(A2),DIV1(A1)      jws
	MOVE.B  DEF_BAUD+1(A2),DIV0(A1)    jws


*                                  -- SET LINE CHARACTERISTICS --  jws
	MOVE.B  DEF_LINE(A2),D0  *  get handshake and line status defaults
	MOVE.B  D0,D1            *
	ANDI.B  #$3F,D0          *  mask and set default line status
	MOVE.B  D0,LINE_CONT(A1) *     (also restores dlab)
*                                  -- SAVE HANDSHAKE --
	ANDI.B  #$C0,D1          *  handshake is top two bits
	LSR.B   #5,D1            *  adjust it (for jump tables)
	MOVE.B  D1,S_HANDSH(A2)  *  save it

	RTS
*
*       baud rate/divisor table (for switches)  jws-- not presently used
*
*BAUD    DC.W    3072            *    50 Baud
*       DC.W    2048            *    75
*       DC.W    1396            *   110
*       DC.W    1142            *   134.5
*       DC.W    1024            *   150
*       DC.W     768            *   200
*       DC.W     512            *   300
*       DC.W     256            *   600
*       DC.W     128            *  1200
*       DC.W      85            *  1800
*       DC.W      64            *  2400
*       DC.W      43            *  3600
*       DC.W      32            *  4800
*       DC.W      21            *  7200
*       DC.W      16            *  9600
*       DC.W       8            * 19200
	TTL     RS232 DRIVERS -- read byte
	page
*****************************************************************************
*
*       read byte
*
*****************************************************************************

RS_RS_RDB       EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get VAR address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead (any of the three can do an ioescape)
*
	BSR     CONNECT                 make sure the card is active
	BSR     CHECK_ERROR             check for errors saved by ISRs
	BSR     CHECK_XFER_IN           make sure no input transfers active

	BSR     WAIT_GET                get character with wait
	MOVE.B  D2,(A3)                 return the character
	RTS

	TTL     RS232 DRIVERS -- write byte
	page
*****************************************************************************
*
*       write byte
*
*****************************************************************************

RS_RS_WTB       EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0                get return address
	MOVE.B  (SP)+,D3                get char to be written
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead
*
	BSR     CONNECT                 autoconnect
	BSR     CHECK_ERROR             check for errors found by ISRs
	BSR     CHECK_XFER_OUT          make sure no output transfers are active

	BSR     WAIT_SEND               send the character
	RTS

	TTL     RS232 DRIVERS -- read word
	page
*****************************************************************************
*
*       read word
*
*****************************************************************************

RS_RS_RDW       EQU *

	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get VAR address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead (any of the three can do an ioescape)
*
	BSR     CONNECT                 make sure the card is active
	BSR     CHECK_ERROR             check for errors saved by ISRs
	BSR     CHECK_XFER_IN           make sure no input transfers are active

	BSR     WAIT_GET                get character with wait
	LSL.W   #8,D2                   shift first character
	BSR     WAIT_GET                get second character
	MOVE.W  D2,(A3)                 return the word
	RTS
	TTL     RS232 DRIVERS -- write word
	page
*****************************************************************************
*
*       write word
*
*****************************************************************************

RS_RS_WTW       EQU *

	MOVEA.L (SP)+,A0                get return address
	MOVE.W  (SP)+,D3                get word to be written
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead (any of the three can do an ioescape)
*
	BSR     CONNECT                 make sure the card is active
	BSR     CHECK_ERROR             check for errors saved by ISRs
	BSR     CHECK_XFER_OUT          make sure no output transfers are active

	ROR.W   #8,D3                   position the first character
	BSR     WAIT_SEND               send it
	ROR.W   #8,D3                   position the second character
	BSR     WAIT_SEND               send it

	RTS
	TTL     RS232 DRIVERS -- status
	page
*****************************************************************************
*
*       read status
*----------------------------------------------------------------------------
*       CONVENTION:  A3 -- place to put the result (word sized)
*
*****************************************************************************

RS_RS_RDS       EQU *
*
*   Pascal Interface Overhead
*

	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get VAR address
	MOVE.W  (SP)+,D1                get register number
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address

*
*   Check for legal registers and jump to correct register handler
*

	TST.W   D1                      check for negative register number
	BLT.S   STS_ERROR               if so goto common ioescape routine
	CMP.W   #REG_MAX,D1             check for too large register number
	BGT.S   STS_ERROR

	CLR.W   (A3)                    clear the top half of the return word
	ADDQ.L  #1,A3                   point a3 to lower half byte of return word

	LSL.W   #1,D1                   get ready for (word) table jump
	MOVE.W  STS_TABLE(D1),D1        get offset from status table
	JMP     STS_TABLE(D1)           do the indexed jump

STS_TABLE       EQU *
	DC.W    STS_0-STS_TABLE         ID register
	DC.W    STS_1-STS_TABLE         Interrupt status register
	DC.W    STS_2-STS_TABLE         Busy bits register
	DC.W    STS_3-STS_TABLE         Baud rate
	DC.W    STS_4-STS_TABLE         Character control register
	DC.W    STS_5-STS_TABLE         Modem control register
	DC.W    STS_6-STS_TABLE         Data in register
	DC.W    STS_7-STS_TABLE         Optional circuits register
	DC.W    STS_8-STS_TABLE         Interrupt Enable Mask register
	DC.W    STS_9-STS_TABLE         Interrupt Cause register
	DC.W    STS_10-STS_TABLE        UART Status register
	DC.W    STS_11-STS_TABLE        Modem Status register
	DC.W    STS_12-STS_TABLE        Connect/Disconnect register
	DC.W    STS_13-STS_TABLE        Hardware handshake register
	DC.W    STS_14-STS_TABLE        Error status register
	DC.W    STS_15-STS_TABLE        Current Xon Character
	DC.W    STS_16-STS_TABLE        Current Xoff Character
	DC.W    STS_17-STS_TABLE        Current ENQ Character
	DC.W    STS_18-STS_TABLE        Current ACK Character
	DC.W    STS_19-STS_TABLE        Current FE/PE convert Character
	DC.W    STS_20-STS_TABLE        Ignore FE/PE
	DC.W    STS_21-STS_TABLE        Default baud rate       jws
	DC.W    STS_22-STS_TABLE        Default line settings   jws

STS_ERROR       EQU *
	MOVEQ   #BAD_RDS,D0
	BRA     IOESCAPE                error number is passed in d0
*-----------------------------------------------------------------------------
STS_0           EQU *                   -- ID register --
	MOVE.B  ID_REG(A1),(A3)         get id from card
	RTS
*-----------------------------------------------------------------------------
STS_1           EQU *                   -- Interrupt Status --
	MOVE.B  INTR_SW(A1),(A3)        get result from card
	RTS
*-----------------------------------------------------------------------------
STS_2           EQU *                   -- "Busy Bits" --
	MOVE.B  INTR_SW(A1),D7          --> interrupt enabled bit (1)
	AND.B   #$80,D7
	LSR.B   #6,D7                   move it to correct position

	TST.L   BUFI_OFF(A2)            --> transfer active bit (0)
	BNE.S   SET_BIT_0
	TST.L   BUFO_OFF(A2)
	BEQ.S   DO_BIT_4                neither transfer is active

SET_BIT_0       EQU *                   set transfer active bit
	BSET    #0,D7

DO_BIT_4        EQU *                   --> not transmitting bit (4)
	TST.B   XMITTING(A2)
	BNE.S   DO_BIT_5
	BSET    #4,D7

DO_BIT_5        EQU *                   --> not receiving bit (5)
	TST.B   RECEIVING(A2)
	BNE.S   END_STS_2
	BSET    #5,D7

END_STS_2       EQU *                   store away result
	MOVE.B  D7,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_3           EQU *                   -- Baud rate --
	SUBQ.L  #1,A3                   this routine returns a word
*
*   Get divisor (a critical section since it uses DLAB)
*
	MOVE.B  INTR_SW(A1),D7          save card interrupt status
	CLR.B   INTR_SW(A1)             disable interrupts

	BSET    #7,LINE_CONT(A1)        get access to divisor latches
	MOVE.B  DIV1(A1),D0             get upper half of divisor
	LSL.W   #8,D0
	MOVE.B  DIV0(A1),D0             get lower half of divisor
	BCLR    #7,LINE_CONT(A1)        reset DLAB so normal operation can resume

	MOVE.B  D7,INTR_SW(A1)          restore interrupts
*
*   Check for special divisors which division is inexact
*
STS_3B  TST.W   D0                      - infinite baud rate ? -
	  BNE.S   IS85
	  RTS                           return zero baud rate
IS85    CMP.W   #85,D0                  - 1800 baud ? -
	  BNE.S   IS77
	  MOVE.W  #1800,(A3)
	  RTS
IS77    CMP.W   #77,D0                  - 2000 baud ? -
	  BNE.S   IS43
	  MOVE.W  #2000,(A3)
	  RTS
IS43    CMP.W   #43,D0                  - 3600 baud ? -
	  BNE.S   IS21
	  MOVE.W  #3600,(A3)
	  RTS
IS21    CMP.W   #21,D0                  - 7200 baud ? -
	  BNE.S   REGULAR
	  MOVE.W  #7200,(A3)
	  RTS
REGULAR         EQU *
*
*   Compute baud rate by:  baud_rate = (freq/16) / divisor
*
	MOVE.L  #153600,D1
	BSR     RDIVU                   do the division
	MOVE.W  D1,(A3)                 store away the answer (d1)
	RTS
*-----------------------------------------------------------------------------
STS_4           EQU *                   -- Character control --
	MOVE.B  LINE_CONT(A1),D7        get line control
	AND.B   #$3F,D7                 remove top two bits

	MOVE.B  S_HANDSH(A2),D6         get handshake
	LSL.B   #5,D6                   move it to top two bits

	OR.B    D6,D7                   combine to form register result
	MOVE.B  D7,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_5           EQU *                   -- Modem control --
	MOVE.B  MODEM_CONT(A1),(A3)     read directly from the UART
	RTS
*-----------------------------------------------------------------------------
STS_6           EQU *                   -- Data in --
	BSR     CHECK_ERROR             check for errors trapped by ISRs

	BSR     QUEUE_EMPTY             read from buffer if not empty
	BEQ.S   READ_UART               else read directly from UART

	MOVE.B  INTR_SW(A1),D5          save interrupt state
	CLR.B   INTR_SW(A1)             disable card interrupts for critical section

	BSR     GET_CHAR                (get character with handshake)
	MOVE.B  D2,(A3)

	MOVE.B  D5,INTR_SW(A1)          restore interrupt state
	RTS
READ_UART       EQU *
	MOVE.B  DATA(A1),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_7           EQU *                   -- Optional circuits --
	MOVEQ   #0,D7                   RETURN 0 IF 98644
	MOVE.B  ID_REG(A1),D6           GET ID REG
	BCLR    #7,D6                   CLEAR REMOTE BIT
	CMP.B   #66,D6                  BRANCH IF 98644
	BEQ.S   STS_7B
	MOVE.B  BAUD_SW(A1),D7          read from the card hardware
	LSR.B   #4,D7                   right justify (and get rid of baud info)
STS_7B  MOVE.B  D7,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_8           EQU *                   -- interrupt enable mask --
	MOVE.B  INTR_EN(A1),(A3)        read directly from the UART
	RTS
*-----------------------------------------------------------------------------
STS_9           EQU *                   -- interrupt cause --
	MOVE.B  INTR_ID(A1),(A3)        read directly from the UART
	RTS
*-----------------------------------------------------------------------------
STS_10          EQU *                   -- UART status --
	MOVE.B  INTR_SW(A1),D7          save card interrupt condition
	CLR.B   INTR_SW(A1)             disable interrupts for critical section

	MOVE.B  S_LINE(A2),D6           get accumulated line status
	CLR.B   S_LINE(A2)              reset it since it is read destructive

	MOVE.B  D7,INTR_SW(A1)          restore interrupts (end critical section)

	AND.B   #$1E,D6                 only use the read destructive bits
	OR.B    LINE_STAT(A1),D6        combine it with the current status

	BSR     QUEUE_EMPTY             use internal buffer to determine bit 0
	BEQ.S   DONT_SET
	BSET    #0,D6                   set receive buffer full bit
DONT_SET        EQU *
	MOVE.B  D6,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_11          EQU *                   -- modem status --
	MOVE.B  INTR_SW(A1),D7          save card interrupt condition
	CLR.B   INTR_SW(A1)             disable interrupts for critical section

	MOVE.B  S_MODEM(A2),D6          get accumulated copy of modem status
	CLR.B   S_MODEM(A2)             clear it since it is read destructive

	MOVE.B  D7,INTR_SW(A1)          restore interrupts (end critical section)

	AND.B   #$0F,D6                 only use the read destructive bits
	OR.B    MODEM_STAT(A1),D6       combine it with the current status
	MOVE.B  D6,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_12          EQU *                   -- connect/disconnect --
	MOVE.B  CONNECTED(A2),(A3)      get the pseudo-register
	RTS
*-----------------------------------------------------------------------------
STS_13          EQU *                   -- hardware handshake register --
	MOVE.B  MODEM_ON(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_14          EQU *                   -- current error status --
	MOVE.B  INTR_SW(A1),D7          save interrupt state
	CLR.B   INTR_SW(A1)             disable interrupts

	MOVE.W  S_ERROR+2(A2),-1(A3)    get (lower word of) the error
*                                       this is a word register!
	CLR.L   S_ERROR(A2)             the read is destructive

	MOVE.B  D7,INTR_SW(A1)          restore interrupt state
	RTS
*-----------------------------------------------------------------------------
STS_15          EQU *                   -- Current Xon character --
	MOVE.B  XON_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_16          EQU *                   -- Current Xoff character --
	MOVE.B  XOFF_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_17          EQU *                   -- Current ENQ character --
	MOVE.B  ENQ_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_18          EQU *                   -- Current ACK character --
	MOVE.B  ACK_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_19          EQU *                   -- Current FE/PE convert character --
	MOVE.B  CONV_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_20          EQU *                   -- Ignore FE/PE {aaa}
	MOVE.B  IGNORE_PE(A2),(A3)                      {aaa}
	RTS                                             {aaa}
	TTL     RS232 DRIVERS -- control
	page
*-----------------------------------------------------------------------------
STS_21          EQU *                   -- Default baud rate      jws
	SUBQ.L  #1,A3                  return a word              jws
	MOVE.W  DEF_BAUD(A2),D0        get default divisor        jws
	BRA     STS_3B                 same as status 3 from hr   jws
*-----------------------------------------------------------------------------
STS_22          EQU *                   -- Default line switch    jws
	MOVE.B  DEF_LINE(A2),(A3)                                 jws
	RTS
*
*****************************************************************************
*
*       write control
*----------------------------------------------------------------------------
*       CONVENTION:  D0.W -- value of the control
*
*****************************************************************************

RS_RS_WTC       EQU *

*
*   Pascal Interface Overhead
*

	MOVEA.L (SP)+,A0                get return address
	MOVE.W  (SP)+,D0                get value
	MOVE.W  (SP)+,D1                get register number
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address

*
*   Check for legal registers and jump to correct register handler
*

	TST.W   D1                      check for negative register number
	BMI.S   CONT_ERROR              if so goto common ioescape routine
	CMP.W   #REG_MAX,D1             check for too large register number
	BGT.S   CONT_ERROR

	LSL.W   #1,D1                   get ready for (word) table jump
	MOVE.W  CONT_TABLE(D1),D1       get offset from status table
	JMP     CONT_TABLE(D1)          do the indexed jump

CONT_TABLE       EQU *
	DC.W    CONT_0-CONT_TABLE       Reset
	DC.W    CONT_1-CONT_TABLE       Break
	DC.W    CONT_ERROR-CONT_TABLE   Register 2 Undefined
	DC.W    CONT_3-CONT_TABLE       Baud rate
	DC.W    CONT_4-CONT_TABLE       Character control register
	DC.W    CONT_5-CONT_TABLE       Modem control register
	DC.W    CONT_6-CONT_TABLE       Data out register
	DC.W    CONT_7-CONT_TABLE       Optional circuits register
	DC.W    CONT_ERROR-CONT_TABLE   Register 8 Undefined
	DC.W    CONT_ERROR-CONT_TABLE   Register 9 Undefined
	DC.W    CONT_ERROR-CONT_TABLE   Register 10 Undefined
	DC.W    CONT_ERROR-CONT_TABLE   Register 11 Undefined
	DC.W    CONT_12-CONT_TABLE      Connect/Disconnect register
	DC.W    CONT_13-CONT_TABLE      Hardware handshake register
	DC.W    CONT_14-CONT_TABLE      Soft reset register
	DC.W    CONT_15-CONT_TABLE      Redefine Xon Character
	DC.W    CONT_16-CONT_TABLE      Redefine Xoff Character
	DC.W    CONT_17-CONT_TABLE      Redefine ENQ Character
	DC.W    CONT_18-CONT_TABLE      Redefine ACK Character
	DC.W    CONT_19-CONT_TABLE      Redefine FE/PE convert Character
	DC.W    CONT_20-CONT_TABLE      Ignore FE/PE {aaa}
	DC.W    CONT_21-CONT_TABLE      Set default baud rate
	DC.W    CONT_22-CONT_TABLE      Set default line control


CONT_ERROR      EQU *
	MOVEQ   #BAD_RDS,D0
	BRA     IOESCAPE                error number is passed in d0
*-----------------------------------------------------------------------------
CONT_0          EQU *                   -- reset --
	TST.W   D0
	BNE     ASM_INIT                initialize if any bit is set
	RTS
*-----------------------------------------------------------------------------
CONT_1          EQU *                   -- send break --
	TST.W   D0
	BEQ.S   EXIT_C1                 no-op if control value is zero
*
*   set and hold break for 400ms
*
	BSET    #6,LINE_CONT(A1)        set the break bit in UART
	MOVE.L  #400000,-(SP)           USE DELAY ROUTINE   ttt  JS 8/3/83
WAIT_BREAK      EQU *
	JSR     DELAY_TIMER             CALL DELAY ROUTINE   ttt JS 8/3/83
*
*   release break and wait 60ms for break to clear
*
	BCLR    #6,LINE_CONT(A1)        clear the break bit in UART
	MOVE.L  #60000,-(SP)            SETUP FOR DELAY ROUTINE  ttt JS 8/3/83
WAIT_BREAK2     EQU *
	JSR     DELAY_TIMER             CALL DELAY ROUTINE       ttt JS 8/3/83
EXIT_C1 RTS
*-----------------------------------------------------------------------------
CONT_3          EQU *                   -- Baud rate --
*
*   check for overflow -- a baud rate with a resulting divisor more than
*                         sixteen bits long.
*   (underflow is not checked because it cannot be generated with a word
*    length baud rate)
*
	CMP.W   #5,D0                   5 is the lowest baud rate possible
	BGE.S   CALC_DIV

	MOVEQ   #IO_MISC,D0             value out of range -- io misc error
	BRA     IOESCAPE
*
*   calculate divisor :  div = (freq/16) / baud_rate
*
CALC_DIV        EQU *
	MOVE.L  #153600,D1              d1 := freq/16
	BSR     RDIVU                   d1.w := d1.l / d0.w ( freq/16 / baud )
*
*   move the divisor to hardware (critical section: uses DLAB)
*
	MOVE.B  INTR_SW(A1),D7          save card interrupt state
	CLR.B   INTR_SW(A1)             disable card interrupts

	BSET    #7,LINE_CONT(A1)        set DLAB to get access to divisor latches
	MOVE.B  D1,DIV0(A1)             set lower half of divisor latch
	LSR.W   #8,D1
	MOVE.B  D1,DIV1(A1)             set upper half of divisor latch
	BCLR    #7,LINE_CONT(A1)        clear DLAB for normal use

	MOVE.B  D7,INTR_SW(A1)          restore card interrupt state

	RTS
*-----------------------------------------------------------------------------
CONT_4          EQU *                   -- Character Control --
	MOVE.B  D0,D7                   save a copy of control value

	AND.B   #$3F,D0                 use only bottom 6 bits
	MOVE.B  D0,LINE_CONT(A1)        for line control

	AND.B   #$C0,D7                 handshake is top two bits
	LSR.B   #5,D7                   shift it for later use
	CMP.B   S_HANDSH(A2),D7         if handshake changed
	BEQ.S   EXIT_C4

	MOVE.B  INTR_SW(A1),D6          save interrupt state
	CLR.B   INTR_SW(A1)             disable interrupts

	MOVE.B  D7,S_HANDSH(A2)         save new handshake
	MOVE.B  #1,RECEIVING(A2)        \
	MOVE.B  #1,XMITTING(A2)         /   reset the handshake flags

	MOVE.B  D6,INTR_SW(A1)          restore interrupt state
EXIT_C4 RTS
*-----------------------------------------------------------------------------
CONT_5          EQU *                   -- modem control --
	MOVE.B  D0,MODEM_CONT(A1)       write directly to UART
	RTS
*-----------------------------------------------------------------------------
CONT_6          EQU *                   -- Data out --
	BSR     CHECK_ERROR             check for errors trapped by ISRs

	MOVE.B  D0,DATA(A1)             write directly to UART
	RTS
*-----------------------------------------------------------------------------
CONT_7          EQU *                   -- Optional Circuits --
	MOVE.B  ID_REG(A1),D6           GET ID REG
	BCLR    #7,D6                   CLEAR REMOTE BIT
	CMP.B   #66,D6                  IS THIS A 98644 ?
	BEQ.S   CONT_7R                 YES, NO OP
	LSL.B   #4,D0                   left justify
	MOVE.B  D0,BAUD_SW(A1)          write directly to card hardware
CONT_7R RTS
*-----------------------------------------------------------------------------
CONT_12         EQU *                   -- connect/disconnect --
	TST.B   D0                      check for d0=0
	BEQ     DISCONNECT              disconnect will do return
	CMP.B   #1,D0
	BEQ     CONNECT                 connect will return
VAL_ERR         EQU *
	MOVEQ   #IO_MISC,D0             illegal value for register
	BRA     IOESCAPE
*-----------------------------------------------------------------------------
CONT_13         EQU *                   -- hardware handshake --
	TST.B   D0                      check for too small value
	BLT.S   VAL_ERR                 (located in cont_12)
	CMP.B   #1,D0                   check for too large value
	BGT.S   VAL_ERR
	MOVE.B  D0,MODEM_ON(A2)         assign modem flag
	RTS
*-----------------------------------------------------------------------------
CONT_14         EQU *                   -- soft reset --
	TST.W   D0                      any bit will do reset
	BEQ.S   EXIT_14                 zero value does nothing

	BSR     SOFT_RESET
EXIT_14 RTS
*-----------------------------------------------------------------------------
CONT_15         EQU *                   -- redefine Xon character --
	MOVE.B  D0,XON_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_16         EQU *                   -- redefine Xoff character --
	MOVE.B  D0,XOFF_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_17         EQU *                   -- redefine ENQ character --
	MOVE.B  D0,ENQ_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_18         EQU *                   -- redefine ACK character --
	MOVE.B  D0,ACK_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_19         EQU *                   -- redefine FE/PE convert character --
	MOVE.B  D0,CONV_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_20         EQU *                   -- Ignore PE/FE --        {aaa}
	TST.B   D0                      check for too small value {aaa}
	BLT.S   VAL_ERR2                                          {aaa}
	CMP.B   #1,D0                   check for too large value {aaa}
	BGT.S   VAL_ERR2                                          {aaa}
	MOVE.B  D0,IGNORE_PE(A2)        assign modem flag         {aaa}
	RTS                                                       {aaa}
VAL_ERR2        EQU *                                             {aaa}
	MOVEQ   #IO_MISC,D0             illegal value for register{aaa}
	BRA     IOESCAPE                                          {aaa}
*-----------------------------------------------------------------------------
CONT_21         EQU *                   -- Set default baud rate  {jws}
	CMP.W   #5,D0                   check for overflow        {jws}
	BGE.S   CALC_DIV21              if ok then skip           {jws}
	MOVEQ   #IO_MISC,D0             else give error           {jws}
	BRA     IOESCAPE                                          {jws}

CALC_DIV21      EQU *                                             {jws}
	MOVE.L  #153600,D1              calculate divisor         {jws}
	BSR     RDIVU                   same as CONT_3            {jws}
	MOVE    D1,DEF_BAUD(A2)         save divisor as DEF_BAUD  {jws}
	RTS
*----------------------------------------------------------------------------
CONT_22         EQU *                   -- Set default line sw.   {jws}
	MOVE.B  D0,DEF_LINE(A2)                                   {jws}
	RTS                                                       {jws}

	TTL     RS232 DRIVERS -- interrupt service routines
	page
*****************************************************************************
*
*       interrupt service routine
*
*****************************************************************************

RS_RS_ISR       EQU *

*
*       pascal interface overhead
*

	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address

*
*       verify there is an interrupt
*

	MOVE.B  INTR_ID(A1),D0          get interrupt cause
	BTST    #0,D0                   make sure an interrupt is pending
	BEQ.S   INTR_EXIST
	RTS                             no interrupt-- return
*
*       jump to appropriate interrupt handler
*

INTR_EXIST      EQU *
	MOVE.B  #1,IN_ISR(A2)           mark isr processing

	EXT.W   D0
	MOVE.W  INTR_TABLE(D0),D0       (get appropriate address)
	JMP     INTR_TABLE(D0)          (jump to the proper case)

INTR_TABLE      EQU *
	DC.W    MODEM_INTR-INTR_TABLE        modem change interrupt
	DC.W    OUTPUT_INTR-INTR_TABLE       output empty interrupt
	DC.W    INPUT_INTR-INTR_TABLE        input available interrupt
	DC.W    ERROR_INTR-INTR_TABLE        error interrupt
	page
*
*   Check for possible unexpected interrupts, if found clear the interrupt
*      (different for each type of interrupt) and disable that type of
*      interrupt.

ERROR_INTR      EQU *
	MOVE.B  LINE_STAT(A1),D0        clear the interrupt (by reading line status)
	OR.B    D0,S_LINE(A2)           save line status for user
	BCLR    #2,INTR_EN(A1)          disable interrupts since it should not happen
	BRA     END_ISR

MODEM_INTR      EQU *
	TST.B   MODEM_ON(A2)            modem handshake on?
	BEQ.S   ABORT_MODEM                -- no abort
	MOVE.L  BUFO_OFF(A2),D7         output transfer active?
	BNE.S   XFER_OUT                   -- yes do transfer

ABORT_MODEM     EQU *
	MOVE.B  MODEM_STAT(A1),D0       clear the interrupt (by reading modem status)
	OR.B    D0,S_MODEM(A2)          save modem status for user
	BCLR    #3,INTR_EN(A1)          disable interrupt so it won't happen again
	BRA     END_ISR

OUTPUT_INTR     EQU *
	MOVE.L  BUFO_OFF(A2),D7         output interrupt transfer active ?
	BNE.S   XFER_OUT                  -- yes do transfer

	BCLR    #1,INTR_EN(A1)            -- no disable interrupt
	BRA     END_ISR
	page
*
*   Do the output interrupt transfer
*       (but only if the THRE and the modem lines are high)
*

XFER_OUT        EQU *
	MOVEA.L D7,A3                   a3 := buffer control block
	MOVE.B  LINE_STAT(A1),D7        check for THRE
	OR.B    D7,S_LINE(A2)           save line status for user
	BTST    #5,D7
	BEQ     END_ISR

	TST.B   MODEM_ON(A2)
	BEQ.S   MOVE_OUT
	BSR     CHECK_DSR_CTS
	BNE     END_ISR

MOVE_OUT        EQU *
	CLR.W   D7                      clear d7.w
	MOVEA.L TEMP_OFF(A3),A0         a0 := buffer empty pointer
	MOVE.B  (A0)+,D7                d7 := character
	MOVE.B  D7,DATA(A1)             write the character
	MOVE.L  A0,TEMP_OFF(A3)         update empty pointer

	SUBQ.L  #1,TCNT_OFF(A3)         decrement the count
	BLE.S   END_XOUT                count=0, transfer ends
	CMP.W   TCHR_OFF(A3),D7         character = term. char ?
	BNE     END_ISR

END_XOUT        EQU *
	TST.B   TEND_OFF(A3)            end condition enabled ?
	BEQ.S   CLR_XOUT
	TST.B   MODEM_ON(A2)            modem handshake on ?
	BEQ.S   CLR_XOUT
	ANDI.B  #$F5,INTR_EN(A1)        disable output and modem interrupts
LOOP_LAST       EQU *
	MOVE.B  LINE_STAT(A1),D7        wait for everything transferred
	OR.B    D7,S_LINE(A2)           before dropping RTS
	NOT.B   D7
	AND.B   #$60,D7
	BNE.S   LOOP_LAST
	BCLR    #1,MODEM_CONT(A1)       drop RTS is the EOI condition

	BSR     CLEAR_XFER              clear the transfer
	JSR     LOGEOT                  call the eot procedure
	BRA     END_ISR

CLR_XOUT        EQU *
	ANDI.B  #$F5,INTR_EN(A1)        disable output and modem interrupts
	BSR     CLEAR_XFER              clear the transfer
	JSR     LOGEOT                  call the eot procedure
	BRA     END_ISR
	page
*
*   Input interrupts are normally active in order to fill the internal
*       buffer
*
INPUT_INTR      EQU *
	MOVE.B  LINE_STAT(A1),D1
	MOVE.B  DATA(A1),D2             get the input byte (clears interrupt)
	OR.B    D1,S_LINE(A2)           preserve line status for user

	TST.B   MODEM_ON(A2)
	BEQ.S   CHECK_BREAK             skip modem stuff if handshake off
*
*   check for both CD and DSR
*
	MOVE.B  MODEM_STAT(A1),D0
	OR.B    D0,S_MODEM(A2)          preserve modem status for user
	NOT     D0
	ANDI    #$A0,D0                 mask appropriate bits
	BNE     INPUT_END               if zero then they were set previously
*
*   ignore character if break received
*
CHECK_BREAK     EQU *
	BTST    #4,D1                   if break received,
	BNE     INPUT_END               then ignore character
*
*   convert Framing and Parity errors to specified character
*
	MOVE.B  D1,D0                   save line status for later use
	ANDI    #$0C,D0                 check for PARITY and FRAMING errors
	BEQ.S   NO_CONVERT
	TST.B   IGNORE_PE(A2)           {aaa}
	BNE.S   NO_CONVERT              {aaa}
	MOVE.B  CONV_CHAR(A2),D2        convert the character

NO_CONVERT      EQU *
*
*       jump to appropriate handshake handler
*
	MOVE.B  S_HANDSH(A2),D0
	EXT.W   D0
	MOVE.W  HAND_TABLE(D0),D0       get address to jump
	JMP     HAND_TABLE(D0)

HAND_TABLE      EQU *
	DC.W    ENQ_HAND-HAND_TABLE
	DC.W    XON_HAND-HAND_TABLE
	DC.W    NO_HAND-HAND_TABLE
	DC.W    NO_HAND-HAND_TABLE
	page
XON_HAND        EQU *
*
*   Do host part of the handshake -- check for Xon and Xoff
*
	CMP.B   XON_CHAR(A2),D2
	BNE.S   CHECK_XOFF
	MOVE.B  #1,XMITTING(A2)         turn transmitting back on

	TST.L   BUFO_OFF(A2)            \
	BEQ     INPUT_END                \
	BSET    #1,INTR_EN(A1)            \  enable interrupts if output
	TST.B   MODEM_ON(A2)              /  transfer is active
	BEQ     INPUT_END                /
	BSET    #3,INTR_EN(A1)          /
	BRA     INPUT_END

CHECK_XOFF      EQU *
	CMP.B   XOFF_CHAR(A2),D2
	BNE.S   TERM_HAND
	CLR.B   XMITTING(A2)            turn transmitting off

	MOVE.B  #$1,INTR_EN(A1)         turn any possible output interrupts off
	BRA     INPUT_END

*
*   Do terminal part of the handshake
*
TERM_HAND       EQU *
	TST.B   RECEIVING(A2)           if receiving is on, might have
	BEQ.S   PUTINQ                     to turn it off
	BSR     QUEUE_SPACE             d3 := space left in queue
	CMP.W   #XOFF_SIZE,D3
	BGE.S   PUTINQ
*
*   Have to turn receiving off
*
	MOVE.B  XOFF_CHAR(A2),D3        prepare to send Xoff
	BSR     SEND                    send character
	BNE.S   PUTINQ                  send did not succeed
	CLR.B   RECEIVING(A2)           no longer expecting input
	BRA.S   PUTINQ                  but put present char in queue

	page

ENQ_HAND        EQU *
	CMP.B   ENQ_CHAR(A2),D2         IF char <> ENQ
	BNE     PUTINQ                     THEN put char in queue
	BSR     QUEUE_SPACE                ELSE
	CMP.W   #ACK_SIZE,D3                 IF queue_space <= 80
	BGE.S   SEND_ACK
	CLR.B   RECEIVING(A2)                   receiving := false
	BRA     INPUT_END

SEND_ACK        EQU *
	MOVE.B  ACK_CHAR(A2),D3         set up parameter in D3
	BSR     SEND                    send ACK
	BEQ     INPUT_END

	CLR.B   RECEIVING(A2)           not receiving since ACK not sent
	BRA     INPUT_END

*
*   Put character (d2) in queue, and check for overrun.
*
NO_HAND         EQU *
PUTINQ          EQU *
	BSR     QUEUE_FULL      IF queue_full
	BEQ.S   OVERRUN            THEN overrun_error
	BSR     INQUEUE            ELSE inqueue(char)

INPUT_END       EQU *
	ANDI    #$02,D1         check for overrun error
	BEQ.S   CHECK_XIN

OVERRUN         EQU *
	MOVE.L  #OVERRUN_ERROR,S_ERROR(A2)

*
*   If transfer in is active then do the transfer
*
CHECK_XIN       EQU *
	TST.B   XIN_ACT(A2)             check for transfer active
	BEQ.S   END_ISR

	MOVEA.L BUFI_OFF(A2),A3         a3 := buffer control block pointer
	BSR     DUMP_BUFFER

END_ISR         EQU *
	CLR.B   IN_ISR(A2)              not in isr any longer
	RTS
	TTL     RS232 DRIVERS -- transfer
	page
*****************************************************************************
*
*       transfer
*
*****************************************************************************

RS_RS_TFR       EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get buffer control block address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead
*
	BSR     CONNECT
	BSR     CHECK_ERROR
*
*   Check for unsupported transfer modes
*       ( done by table jump also )
*
	TST.B   T_BW_OFF(A3)            word mode?
	BNE.S   WORD_ERR                  -- is unsupported

	MOVE.B  TUSR_OFF(A3),D1         d1.w := offset into transfer table
	EXT.W   D1
	ADD.W   D1,D1                   d1.w := word offset into table
	MOVE.W  XFER_TABLE(D1),D1
	JMP     XFER_TABLE(D1)

XFER_TABLE      EQU *
	DC.W    XFER_ERR-XFER_TABLE     not used
	DC.W    DMA_ERR-XFER_TABLE      serial DMA -- not supported
	DC.W    SER_FHS-XFER_TABLE      serial FHS
	DC.W    SER_FHS-XFER_TABLE      serial fastest -- same as serial FHS
	DC.W    XFER_ERR-XFER_TABLE     not used

	DC.W    INTR_XFER-XFER_TABLE    overlap INTR
	DC.W    DMA_ERR-XFER_TABLE      overlap DMA -- not supported
	DC.W    XFER_ERR-XFER_TABLE     overlap FHS -- not supported
	DC.W    INTR_XFER-XFER_TABLE    overlap FASTEST -- same as overlap INTR
	DC.W    INTR_XFER-XFER_TABLE    overlap overlap -- same as overlap INTR
	page
*
*   Error escapes
*
END_ERR         EQU *
DMA_ERR         EQU *
XFER_ERR        EQU *
	BSR     CLEAR_XFER
	MOVEQ   #TFR_ERR,D0
	BRA     IOESCAPE

WORD_ERR        EQU *

	BSR     CLEAR_XFER
	MOVEQ   #NO_WORD,D0
	BRA     IOESCAPE
*
*   Set the actual mode for transfers
*
SER_FHS         EQU *
	MOVE.B  #TT_FHS,TACT_OFF(A3)    set the actual mode
	TST.B   TDIR_OFF(A3)            jump to correct direction handler
	BNE.S   OUTPUT_XFER
	BRA.S   INPUT_XFER

INTR_XFER       EQU *
	MOVE.B  #TT_INT,TACT_OFF(A3)    set actual mode to INTR
	TST.B   TDIR_OFF(A3)            jump to correct direction handler
	BNE.S   OUTPUT_XFER
*       BRA.S   INPUT_XFER

*
*   Input transfer setup.
*

INPUT_XFER      EQU *
	TST.B   TEND_OFF(A3)            end condition not allowed on input xfers
	BNE.S   END_ERR

	BSR     DUMP_BUFFER             do most of transfers with intr enabled
	BEQ.S   EXIT_TFR                if transfer done, then exit

	CLR.B   INTR_SW(A1)             disable interrupts for critical section
	MOVE.B  #1,XIN_ACT(A2)
	BSR     SET_XFER                set interface busy
	BSR     DUMP_BUFFER             make sure that buffer is empty (prevent deadlock)
*                                       if eot the following code will exit
*                                       so no explicit exit is done
	BSET    #7,INTR_SW(A1)          end of critical section

	BRA.S   CHECK_FHS               end of input transfer setup
	page
*
*   Output transfer setup
*

OUTPUT_XFER     EQU *

	CLR.B   INTR_SW(A1)             disable interrupts for critical section

	BSR     SET_XFER                set interface busy
	BSET    #1,MODEM_CONT(A1)       set RTS
	TST.B   XMITTING(A2)            if not transmitting, don't enable interrupts
	BEQ.S   CHECK_FHS
	BSET    #1,INTR_EN(A1)          enable output interrupts
	TST.B   MODEM_ON(A2)            if modem handshake
	BEQ.S   CHECK_FHS
	BSET    #3,INTR_EN(A1)          enable modem interrupts

*
*   IF serial transfer THEN wait until transfer is done
*
CHECK_FHS       EQU *
	BSET    #7,INTR_SW(A1)          end of critical section

	CMPI.B  #TT_FHS,TACT_OFF(A3)
	BNE.S   EXIT_TFR
WAIT_FHS        EQU *
	CMPI.B  #255,T_SC_OFF(A3)       wait until buffer is not busy
	BNE.S   WAIT_FHS
EXIT_TFR        EQU *
	RTS
	TTL     RS232 DRIVERS -- transfer support routines
	page
******************************************************************************
*
*       TRANSFER SUPPORT ROUTINES
*
******************************************************************************
*
*       DUMP BUFFER
*          transfer from the internal queue to user queue
*
*       ON ENTRY: a3 - points to buffer control block
*       ON EXIT : IF transfer was completed
*                    THEN d2.L=0 and Z=1
*                    ELSE d2.L=1 and Z=0
*       USES:     a0 - current fill pointer to user input buffer
*                 d2 - character being transfered
*-----------------------------------------------------------------------------

DUMP_BUFFER     EQU *
	MOVEA.L TFIL_OFF(A3),A0         get fill pointer
	CLR.W   D2                      clear top half of D2 (for later compares)

DUMP_LOOP       EQU *
	BSR     QUEUE_EMPTY
	BEQ.S   EXIT_DUMP
	BSR     GET_CHAR                d2 := character
	MOVE.B  D2,(A0)+                put it in the linear buffer
	SUBQ.L  #1,TCNT_OFF(A3)         decrement count
	BLE.S   END_XIN
	CMP.W   TCHR_OFF(A3),D2
	BNE.S   DUMP_LOOP

END_XIN         EQU *
	MOVE.L  A0,TFIL_OFF(A3)         update fill pointer
	CLR.B   XIN_ACT(A2)
	BSR     CLEAR_XFER
	JSR     LOGEOT

	CLR.L   D2                      set Z flag to mark transfer ended
	RTS

EXIT_DUMP       EQU *
	MOVE.L  A0,TFIL_OFF(A3)         update fill pointer

	MOVEQ   #1,D2                   clear Z flage to mark transfer still active
	RTS
	page
*-----------------------------------------------------------------------------
*       CLEAR_XFER
*          make a transfer inactive (unlink temp space and buffer control block)
*       ON ENTRY:  a3 - points to the buffer control block
*-----------------------------------------------------------------------------

CLEAR_XFER      EQU *
	CLR.B   TACT_OFF(A3)            clear actual transfer mode
	MOVE.B  #255,T_SC_OFF(A3)       set the buffer not busy
	TST.B   TDIR_OFF(A3)
	BNE.S   CLEAR_OUT
	CLR.L   BUFI_OFF(A2)            clear input transfer
	RTS
CLEAR_OUT       EQU *
	CLR.L   BUFO_OFF(A2)            clear output transfer
	RTS

*-----------------------------------------------------------------------------
*       SET_XFER
*          make a transfer active (link temp space with buffer control block)
*       ON ENTRY:  a3 - the buffer control block
*-----------------------------------------------------------------------------

SET_XFER        EQU *
	MOVE.B  IO_SC(A2),T_SC_OFF(A3)  set the buffer busy
	TST.B   TDIR_OFF(A3)
	BNE.S   SET_OUT
	MOVE.L  A3,BUFI_OFF(A2)         set sc's input active
	RTS
SET_OUT         EQU *
	MOVE.L  A3,BUFO_OFF(A2)         set sc's output active
	RTS

*-----------------------------------------------------------------------------
*       CHECK_XFER_IN, CHECK_XFER_OUT
*          gives an error if a transfer is active
*       USES:  d0 -- only if an ioescape is to be given
*-----------------------------------------------------------------------------

CHECK_XFER_IN   EQU *
	TST.L   BUFI_OFF(A2)
	BNE.S   BUSY_ERR
	RTS

CHECK_XFER_OUT  EQU *
	TST.L   BUFO_OFF(A2)
	BNE.S   BUSY_ERR
	RTS

BUSY_ERR        EQU *
	MOVEQ   #SC_BUSY,D0
	BRA     IOESCAPE
	TTL     RS232 DRIVERS -- common utilities
	page
*****************************************************************************
*
*       Useful Subroutines
*
*****************************************************************************
*
*       IOESCAPE
*          ON ENTRY:  d0.L -- contains the escape code
*----------------------------------------------------------------------------

IOESCAPE        EQU *
	MOVE.L  D0,IOE_RSLT(A5)         *  put ioe_result
	CLR.L   D0                      *<<< BUG FIX >>>
	MOVE.B  IO_SC(A2),D0            *  get select code of card
	MOVE.L  D0,IOE_SC(A5)           *  put ioe_sc
	MOVE.W  #IOE_ERROR,ESC_CODE(A5) *  escapecode := ioe_error
	TRAP    #10                     *  do Pascal escape

*----------------------------------------------------------------------------
*       RDIVU
*          unsigned integer divide rounded.
*          ON ENTRY:  d0.w -- divisor (unchanged by this routine)
*                     d1.l -- dividend
*          ON EXIT:   d1.w -- rounded quotient
*----------------------------------------------------------------------------
RDIVU           EQU *
	DIVU    D0,D1                   do truncated division
	SWAP    D1                      get access to remainder
	LSL.W   #1,D1                   multiply remainder by 2
	BCS.S   ROUND                   if carry then remainder*2>divisor
	CMP.W   D1,D0                   remainder*2 > divisor ?
	BLE.S   ROUND                   round up if so.
*                                       --do not round --
	SWAP    D1                      get quotient
	RTS
ROUND           EQU *                   --round up--
	SWAP    D1                      get old quotient
	ADDQ.W  #1,D1                   increment (do the rounding)
	RTS
	page
*----------------------------------------------------------------------------
*       CONNECT
*          connects the card if not connected already.
*
*       uses : d6,d7 by called routines
*----------------------------------------------------------------------------

CONNECT         EQU *
	TST.B   CONNECTED(A2)           IF connected THEN do nothing
	BNE.S   EXIT_CONNECT

	BSET    #0,MODEM_CONT(A1)       set DTR
	BSR     SOFT_RESET              initialize the dynamic data
	MOVE.B  #1,INTR_EN(A1)          enable receive interrupts
	MOVE.B  #1,CONNECTED(A2)        set connected
	BSET    #7,INTR_SW(A1)          enable card interrupts
EXIT_CONNECT    EQU *
	RTS


*-----------------------------------------------------------------------------
*       DISCONNECT
*          disconnect and disable interrupts
*-----------------------------------------------------------------------------

DISCONNECT      EQU *
	BCLR    #7,INTR_SW(A1)          disable card interrupts
	CLR.B   CONNECTED(A2)           set disconnected
	ANDI.B  #$FC,MODEM_CONT(A1)     drop DTR and RTS
	NOP
	CLR.B   INTR_EN(A1)             disable all UART interrupts
	RTS
	page
*-----------------------------------------------------------------------------
*       SOFT_RESET
*          initialize the "dynamic" attributes of the drivers
*
*       uses :  d6,d7 as temporary
*-----------------------------------------------------------------------------

SOFT_RESET      EQU *

	JSR     ABORT_IO                abort transfers

	MOVE.B  INTR_SW(A1),D6          save interrupt state
	CLR.B   INTR_SW(A1)             disable interrupts

	ANDI.B  #1,INTR_EN(A1)          disable modem and transmit interrupts
	BSR     INIT_QUEUE
	MOVE.B  DATA(A1),D7             destroy any data
	CLR.B   S_LINE(A2)
	MOVE.B  LINE_STAT(A1),D7        reset the line status (destructive read)
	CLR.B   S_MODEM(A2)
	MOVE.B  MODEM_STAT(A1),D7       reset the modem status (destructive read)


	CLR.L   S_ERROR(A2)
	MOVE.B  #1,RECEIVING(A2)
	MOVE.B  #1,XMITTING(A2)

	MOVE.B  D6,INTR_SW(A1)          restore the interrupt state
	RTS


*----------------------------------------------------------------------------
*       CHECK_ERROR
*          check for errors recorded in interrupt service routines (ISRs)
*          USES:  D0,D7 only if doing ioescape
*----------------------------------------------------------------------------

CHECK_ERROR     EQU *
	TST.L   S_ERROR(A2)             is error present
	BNE.S   ERROR_EXIST
	RTS                             return if not error
ERROR_EXIST     EQU *
	MOVE.B  INTR_SW(A1),D7          save interrupt condition
	CLR.B   INTR_SW(A1)             disable interrupt for critical section

	MOVE.L  S_ERROR(A2),D0          get error
	CLR.L   S_ERROR(A2)             clear errors

	MOVE.B  D7,INTR_SW(A1)          restore interrupts
	BRA     IOESCAPE                do pascal escape
	page
*-----------------------------------------------------------------------------
*       WAIT_SEND
*          This routine waits for the transmitting flag then sends
*          a character.  It escapes if SEND returns with an error.
*       NOTE:  this routine cannot be called by ISRs!!!
*       ON ENTRY:  d3.B -- character to be sent
*       USES    :  a4 -- used by called routines
*                  d4,d6,d7 -- by called routines
*-----------------------------------------------------------------------------

WAIT_SEND       EQU *

*
*   Wait for xmitting flag (no timeouts !!)
*       (the wait is important for Xon/Xoff as host)
*
	TST.B   XMITTING(A2)
	BEQ.S   WAIT_SEND
*
*   Send the character
*
OK_XMIT         EQU *
	BSR     SEND                    send character with timeout
	BSR     CHECK_ERROR             check for errors found by send
	RTS


*-----------------------------------------------------------------------------
*       WAIT_GET
*          wait until the queue is empty before getting a character
*       ON EXIT:  D2.B contains the character
*                 (the rest of D2 is not altered!)
*       USES:     A4.L -- parameter to WAIT
*                 D0,D3,D4,D6,D7 -- used by called routines
*-----------------------------------------------------------------------------

WAIT_GET        EQU *

*
*   Wait (with timeout) for queue not empty
*
	LEA     CHECK_QUEUE,A4          \  call wait with the not queue empty
	BSR     WAIT                    /  function
	BSR     CHECK_ERROR             check for wait error

	BSR     GET_CHAR
	BSR     CHECK_ERROR
	RTS
	page
*-----------------------------------------------------------------------------
*       GET_CHAR
*          get a character with software handshake.
*       ON ENTRY :  the queue is not empty!
*       ON EXIT:  D2.B contains the character
*                 (the rest of D2 is not altered!)
*       USES:     D3 -- space left in queue/temporary for character
*                 D0.W -- handshake type & temporary
*                 A4,D4,D6,D7 -- temporary
*-----------------------------------------------------------------------------


GET_CHAR        EQU *

*
*   Read the character ( and pass it back )
*
	BSR     OUTQUEUE                get the character (into D2)
*
*   Check for and do handshake overhead
*
	TST.B   RECEIVING(A2)           if receiving
	BNE.S   READ_END                then no overhead needed
*
*   Jump to appropriate handshake handler
*
	MOVE.B  S_HANDSH(A2),D0         get handshake
	EXT.W   D0
	MOVE.W  H_TABLE(D0),D0
	JMP     H_TABLE(D0)

H_TABLE         EQU *
	DC.W    ENQ_H-H_TABLE
	DC.W    XON_H-H_TABLE
	DC.W    READ_END-H_TABLE        no handshake (no overhead)
	DC.W    READ_END-H_TABLE        no handshake
	page
*
*   ENQ/ACK handshake--send ACK if queue can handle more than 80 chars
*
ENQ_H           EQU *
	BSR     QUEUE_SPACE             returns space left in D3
	CMP.W   #ACK_SIZE,D3
	BLT.S   READ_END                space not big enough to send ACK
*
*   Send character to indicate card is receiving and set receiving flag
*
	MOVE.B  ACK_CHAR(A2),D3         send ack
	BRA.S   SEND_HAND

*
*   Xon/Xoff handshake--send Xon if queue can handle more characters
*
XON_H           EQU *
	BSR     QUEUE_SPACE             d3 := space left in queue
	CMP.W   #XON_SIZE,D3
	BLT.S   READ_END                space not big enough to send XON
*
*   Send character to indicate card is receiving and set receiving flag
*
	MOVE.B  XON_CHAR(A2),D3

SEND_HAND       EQU *                   send handshake character (in D3)
	MOVE.B  #1,INTR_EN(A1)          only have receive interrupt enabled
	BSR     SEND                    send char which is in d2
	BNE.S   RESTORE
	MOVE.B  #1,RECEIVING(A2)        turn receiving back on
RESTORE         EQU *                   recalculate interrupt enable mask
	MOVE.B  INTR_SW(A1),D7          save interrupt status
	CLR.B   INTR_SW(A1)             critical section
	TST.L   BUFO_OFF(A2)
	BEQ.S   END_RESTORE
	TST.B   XMITTING(A2)
	BEQ.S   END_RESTORE
	BSET    #1,INTR_EN(A1)
	TST.B   MODEM_ON(A2)
	BEQ.S   END_RESTORE
	BSET    #3,INTR_EN(A1)
END_RESTORE     EQU *
	MOVE.B  D7,INTR_SW(A1)          end critical section

READ_END        EQU *
	RTS
	page
*-----------------------------------------------------------------------------
*       SEND
*       ON ENTRY:  d3.B -- character to be sent
*       ON EXIT :  IF character sent
*                     THEN Z=1
*                     ELSE Z=0, S_ERROR updated to newest error
*       USES    : a4 -- parameter to WAIT
*                 d7 -- temporary
*                 d6 -- by called routines
*-----------------------------------------------------------------------------

SEND            EQU *
	BSET    #1,MODEM_CONT(A1)       set RTS
*
*   Wait (with timeout) for transmit registers empty
*
LOOP_THRE       EQU *
	MOVE.B  LINE_STAT(A1),D7
	OR.B    D7,S_LINE(A2)           save line status for user
	AND.B   #$20,D7                 look at THRE bit
	BEQ.S   LOOP_THRE

	TST.B   MODEM_ON(A2)            skip modem stuff if modem handshake off
	BEQ.S   XMIT_CHAR
*
*   Modem checking depends on if this routine was called from an ISR
*
	TST.B   IN_ISR(A2)
	BEQ.S   NOT_ISR

	BSR     CHECK_DSR_CTS
	BEQ.S   XMIT_CHAR              modem lines are up, goto transmit

	MOVE.L  #316,S_ERROR(A2)        CTS false error
	RTS                             side effect -- Z:=0
*
*   Wait (with timeout) for DSR and CTS
*
NOT_ISR         EQU *
	LEA     CHECK_DSR_CTS,A4        \  call WAIT with appropriate
	BSR     WAIT                    /  function parameter
	BEQ.S   XMIT_CHAR              no errors, goto transmit
	RTS                             (Z=0 still)
*
*   Send the character (in d3)
*
XMIT_CHAR      EQU *
	MOVE.B  D3,DATA(A1)             do actual transmit
	CLR.B   D7                      indicate no errors  (Z := 1)
	RTS
	page
*-----------------------------------------------------------------------------
*       WAIT
*          this function waits with timeout for a condition to happen,
*          if the condition does not happen within the timeout, then
*          S_ERROR(A2) is marked with the timeout error.
*       ON ENTRY:  A4.L  points to the routine which will determine if
*                        the condition is met.  This routine should have
*                        the following conditions:
*                          --uses at the most d7,d6
*                          --returns Z=1 if the condition is met
*                          --all routines should have similar timing
*       ON EXIT:   IF error is found
*                       THEN Z=0, S_ERROR indicates the error
*                       ELSE Z=1
*       USES    :  D4.L  --  timeout counter
*                  D7,D6 --  can be used by called routine (see above)
*-----------------------------------------------------------------------------

WAIT            EQU *
	JSR     (A4)                    check the condition
	BEQ.S   EXIT_WAIT               exit if condition met (Z=1)

	MOVE.L  TIMEOUT(A2),D4
	BEQ.S   WAIT_LOOP2              infinite timeout if value is 0.

	BTST    #TIMER_PRESENT,SYSFLAG2  SEE IF TIMER EXISTS     ttt JS 8/3/83
	BEQ.S   WAIT_TMR                 IF SO GO USE IT         ttt JS 8/3/83

	MOVE.L  D4,D7                   \
	LSL.L   #1,D7                    \   initialize counter
	LSL.L   #2,D4                     \     (multiply by 54)
	ADD.L   D7,D4                      |
	MOVE.L  D4,D7                     /
	LSL.L   #3,D4                    /
	ADD.L   D7,D4                   /

WAIT_LOOP       EQU *
	TST.L   S_ERROR(A2)          check for errors saved during wait
	BNE.S   EXIT_WAIT               exit (Z=0)
	JSR     (A4)                    check the condition
	BEQ.S   EXIT_WAIT               exit if conditon met (Z=1)

	SUBQ.L  #1,D4                   counter := counter - 1
	BPL.S   WAIT_LOOP

	MOVE.L  #TMO_ERR,S_ERROR(A2) save the timeout error (Z:=0)
	RTS

WAIT_LOOP2      EQU *                   wait loop for infinite timeout
	TST.L   S_ERROR(A2)          check for errors saved by ISRs
	BNE.S   EXIT_WAIT               exit (Z=0)
	JSR     (A4)
	BNE.S   WAIT_LOOP2

EXIT_WAIT       EQU *
	RTS

WAIT_TMR    EQU *
	MOVE.B  #1,-(SP)               SET UP TIMER RECORD  ttt JS 8/3/83
	MOVE.L  D4,-(SP)               D4 HAS MS TO WAIT    ttt JS 8/3/83
WAIT_TMR1   EQU *                                           ttt JS 8/3/83
	TST.L   S_ERROR(A2)            CHECK FOR ERRORS     ttt JS 8/3/83
	BNE.S   WAIT_TEXIT             BR IF ERROR          ttt JS 8/3/83
	JSR     (A4)                   CHECK CONDITION      ttt JS 8/3/83
	BEQ.S   WAIT_TEXIT              BR IF CONDITION MET  ttt JS 8/3/83
	PEA     (SP)                   POINT TO TIMER REC   ttt JS 8/3/83
	JSR     CHECK_TIMER            AND CHECK TIMER      ttt JS 8/3/83
	BPL     WAIT_TMR1              IF NO TIMEOUT BRANCH ttt JS 8/3/83
	ADDQ    #6,SP                  TIMEOUT, BUT GET ONE ttt JS 5/3/84
	MOVEQ   #20,D4                 MORE CHANCE WITH     ttt JS 5/3/84
	BRA     WAIT_LOOP              SHORT COUNT          ttt JS 5/3/84
WAIT_TEXIT  EQU *                                           ttt JS 8/3/83
	ADDQ    #6,SP                  CLEANUP STACK        ttt JS 8/3/83
	RTS                            AND DONE!            ttt JS 8/3/83
	page
******************************************************************************
*
*       CHECK_DSR_CTS, CHECK_QUEUE
*
*       FUNCTIONs to be used with WAIT, they all return Z=1 when the
*          condition is met.
*
*       USES:  the function is allowed to use only d6 and d7
*
******************************************************************************

*
*   condition:  queue is empty
*
CHECK_QUEUE     EQU *
	MOVE.W  Q_OUT(A2),D7            (12)
	CMP.W   Q_IN(A2),D7             (12)  Z=1 if empty
	EORI    #$04,CCR                (20)  invert the Z bit (Z=1 if full)
	RTS                             (----> 44 )

*
*   condition:  DSR=1 and CTS=1  (ok to send with modem handshake)
*
CHECK_DSR_CTS   EQU *
	MOVE.B  MODEM_STAT(A1),D7       (12)
	OR.B    D7,S_MODEM(A2)          (16)  save modem status for user
	NOT.B   D7                      ( 4)
	AND     #$30,D7                 ( 8)  if both DSR and CTS were true, Z=0
	NOP                             ( 4)
	RTS                             (----> 44 )

	TTL     RS232 DRIVERS -- queue utilities
	page
*****************************************************************************
*
*       Buffer routines
*
*****************************************************************************

*----------------------------------------------------------------------------
*       INIT_QUEUE
*          initializes the queue descriptor.
*----------------------------------------------------------------------------

INIT_QUEUE      EQU *
	MOVE.W  #BUFFER_SIZE,Q_SIZE(A2)         * initialize  queue_size
	CLR.W   Q_IN(A2)                        *  queue_in := 0
	CLR.W   Q_OUT(A2)                       *  queue_out := 0
	RTS

*-----------------------------------------------------------------------------
*       QUEUE_EMPTY
*          tells if queue is empty.
*          ON EXIT:  Z=empty (IF EMPTY THEN Z:=1 ELSE Z:=0)
*          USES   :  D7
*-----------------------------------------------------------------------------

QUEUE_EMPTY     EQU *
	MOVE.W  Q_OUT(A2),D7
	CMP.W   Q_IN(A2),D7             *  RETURN( queue_in = queue_out )
	RTS

*-----------------------------------------------------------------------------
*       QUEUE_FULL
*          tells if queue is full.
*          ON EXIT:  Z=full (IF FULL THEN Z:=1 ELSE Z:=0)
*          USES   :  D7
*-----------------------------------------------------------------------------

QUEUE_FULL      EQU *
	MOVE.W  Q_IN(A2),D7             *
	ADDQ.W  #1,D7                   *
	CMP.W   Q_OUT(A2),D7            *  queue_out = queue_in+1 ?
	BNE.S   CHECK_OR                *
	RTS                             *        ( YES so return with Z=1)
CHECK_OR        EQU *
	CMP.W   Q_SIZE(A2),D7           *  queue_in+1 = queue_size ?
	BEQ.S   CHECK_AND               *
	RTS                             *        ( NO  so return with Z=0)
CHECK_AND       EQU *
	MOVE.W  Q_OUT(A2),D7            *  queue_out = 0  ?
	RTS                             *        ( ANSWER is result of function )
	page
*-----------------------------------------------------------------------------
*       INQUEUE
*          puts a character in the queue
*          ON ENTRY:  d2.B - character to be put in the queue
*                     buffer NOT full !!
*          USES    :  a4.L - queue_addr
*                     d7.W - queue_in
*-----------------------------------------------------------------------------

INQUEUE         EQU *
	MOVE.W  Q_IN(A2),D7             *
	MOVE.B  D2,Q_BUFFER(A2,D7.W)    *  (queue_addr+queue_in)^ := char

	ADDQ.W  #1,D7                   *  queue_in := queue_in+1

	CMP.W   Q_SIZE(A2),D7           *
	BGE.S   RESET_IN                *  IF queue_in >= queue_size
	MOVE.W  D7,Q_IN(A2)             *
	RTS                             *
RESET_IN        EQU *                   *
	CLR.W   Q_IN(A2)                *    THEN queue_in := 0
	RTS                             *

*-----------------------------------------------------------------------------
*       OUTQUEUE
*          take the next character out of the queue
*          ON ENTRY:  buffer NOT full
*          ON EXIT :  d2.B - character from the queue
*          USES    :  a4.L - queue_addr
*                     d7.W - queue_in
*-----------------------------------------------------------------------------

OUTQUEUE         EQU *
	MOVE.W  Q_OUT(A2),D7            *
	MOVE.B  Q_BUFFER(A2,D7.W),D2    *  char := (queue_addr+queue_out)^

	ADDQ.W  #1,D7                   *  queue_out := queue_out+1

	CMP.W   Q_SIZE(A2),D7           **
	BGE.S   RESET_OUT               *  IF queue_out >= queue_size
	MOVE.W  D7,Q_OUT(A2)            *
	RTS                             *
RESET_OUT        EQU *                  *
	CLR.W   Q_OUT(A2)               *    THEN queue_out := 0
	RTS                             **
	page
*-----------------------------------------------------------------------------
*       QUEUE_SPACE
*          returns amount of space remaining in the queue
*          ON EXIT:  d3.W - contains the space remaining in the queue.
*-----------------------------------------------------------------------------

QUEUE_SPACE     EQU *
	MOVE.W  Q_OUT(A2),D3            *
	SUB.W   Q_IN(A2),D3             *  IF  queue_in >= queue_out
	BGT.S   OUT_GREATER             *

	SUBQ.W  #1,D3                   *  THEN queue_space :=
	ADD.W   Q_SIZE(A2),D3           *     queue_size + queue_out-queue_in - 1
	RTS
OUT_GREATER     EQU *
	SUBQ.W  #1,D3                   *  ELSE queue_space :=
	RTS                             *     queue_out-queue_in - 1
	END


@


56.2
log
@
pws2rcs automatic delta on Wed Jan 27 11:57:27 MST 1993
@
text
@d1 2116
@


56.1
log
@Automatic bump of revision number for PWS version 3.25
@
text
@a0 2116
	TTL IOLIB RS - RS232 DRIVERS
******************************************************************************
*
*       COPYRIGHT (C) 1985 BY HEWLETT-PACKARD COMPANY
*
******************************************************************************
*
*
*       IOLIB     RS
*
*
******************************************************************************
*
*
*
*       Library - IOLIB
*
*       Purpose - This set of assembly language code is intended to be used as
*                 a PASCAL module for I/O drivers for use by the external I/O
*                 procedures library.
*
*
*       Date    - 8-6-82
*       Update  - 6-5-84 BY J Schmidt
*       Release - 7-12-85
*
*
*       Source  - RS: RS.TEXT
*       Object  - RS: RS.CODE
*
*
*
*
******************************************************************************
*
*
*           RELEASED        VERSION 3.1
*
*
******************************************************************************
*
*       CHANGES (since 2.0):
*           {aaa} -- changes for ignore parity error register 20.
*
*       CHANGES for 3.0
*           {ttt} -- timing changes for 680xx -- JS 8/3/83, 5/3/84
*
*       CHANGES for 3.1
*           (jws}  -- new default setups, add control/status 21, 22. 6/5/85
*
*       CHANGES for 3.23
*           {dew1}  -- fixed timing problem with reset.  DW 12/89
*
******************************************************************************
	 PAGE
******************************************************************************
*
*
*       The following lines are used to tell the LINKER/LOADER what this
*       module looks like in PASCAL terms.
*
*       Note that it is possible to create assembly modules that are functions.
*       These routines are called through an indirect pointer using the CALL
*       facility which does NOT permit functions.
*
*       This module is called 'RS' ( upper or lower case - doesn't matter )
*       independent of the file name ( by use of the MNAME pseudo-op ).
*
*       All the externally used procedures are called 'RS_@@@@@@@@@@@@@@@@' in
*       this module.  If you are using assembly to access them use the
*       'RS_@@@@@@@@@@@@@@' name.  If you are using Pascal use the '@@@@@@@@@@@@@@'
*       name.
*
*******************************************************************************

	MNAME RS

	SRC MODULE RS;
	SRC IMPORT iodeclarations;
	SRC EXPORT
	SRC
	SRC        PROCEDURE rs_init    ( temp : ANYPTR );
	SRC        PROCEDURE rs_isr     ( temp : PISRIB );
	SRC        PROCEDURE rs_rdb     ( temp : ANYPTR ; VAR x : CHAR );
	SRC        PROCEDURE rs_wtb     ( temp : ANYPTR ;  val  : CHAR );
	SRC        PROCEDURE rs_rdw     ( temp : ANYPTR ; VAR x : io_word);
	SRC        PROCEDURE rs_wtw     ( temp : ANYPTR ;  val  : io_word);
	SRC        PROCEDURE rs_rds     ( temp : ANYPTR ;  reg  : io_word;
	SRC                                               VAR x : io_word);
	SRC        PROCEDURE rs_wtc     ( temp : ANYPTR ;  reg  : io_word;
	SRC                                                val  : io_word );
	SRC        PROCEDURE rs_tfr     ( temp : ANYPTR ;  bcb  : ANYPTR);
	SRC END; { of RS }
	PAGE
******************************************************************************
*
*       SYMBOLS FOR EXPORT AS PROCEDURE NAMES
*
******************************************************************************

	DEF RS_RS

	DEF RS_RS_INIT
	DEF RS_RS_ISR
	DEF RS_RS_RDB
	DEF RS_RS_WTB
	DEF RS_RS_RDW
	DEF RS_RS_WTW
	DEF RS_RS_RDS
	DEF RS_RS_WTC
	DEF RS_RS_TFR

******************************************************************************
*
*       SYMBOLS FOR IMPORT
*
******************************************************************************

	LMODE   ABORT_IO,LOGEOT
	REFA    ABORT_IO,LOGEOT
	REFA    DELAY_TIMER,CHECK_TIMER              ttt JS 8/3/83
	LMODE   DELAY_TIMER,CHECK_TIMER              ttt JS 8/3/83


	INCLUDE IOLIB:COMDCL
	page
*
*       REGISTER USAGE SUMMARY (of utility routines)
*
*       Global Usage
*          a5 -- Pascal Global Base
*          a6 -- Pascal Stack Frame
*          a7 -- Stack Pointer
*          a1 -- Card Address
*          a2 -- Driver Attributes ('temp' space)
*
*       ROUTINE         a0  a3  a4  d0  d1  d2  d3  d4  d5  d6  d7
*       ----------------------------------------------------------
*       queue_space      -   -   -   -   -   -   O   -   -   -   -
*       queue_empty      -   -   -   -   -   -   -   -   -   -   T
*       queue_full       -   -   -   -   -   -   -   -   -   -   T
*       inqueue          -   -   G   -   -   I   -   -   -   -   G
*       outqueue         -   -   G   -   -   O   -   -   -   -   G
*       init_queue       -   -   -   -   -   -   -   -   -   -   -
*       check_queue      -   -   -   -   -   -   -   -   -   -   T
*       check_dsr_cts    -   -   -   -   -   -   -   -   -   -   T
*       wait             -   -   I   -   -   -   -   G   -   L   T
*       send             -   -   P   -   -   -   I   L   -   L   T
*       get_char         -   -   L   T   -   O   P   L   -   L   L
*       wait_send        -   -   L   -   -   -   I   L   -   L   L
*       wait_get         -   -   P   L   -   O   L   L   -   L   L
*       check_error      -   -   -   -   -   -   -   -   -   -   -
*       soft_reset*      -   -   -   -   -   -   -   -   -   T   T
*       connect*         -   -   -   -   -   -   -   -   -   L   L
*       disconnect       -   -   -   -   -   -   -   -   -   -   -
*       rdivu            -   -   -   I   O   -   -   -   -   -   -
*       check_xfer_in    -   -   -   -   -   -   -   -   -   -   -
*       check_xfer_out   -   -   -   -   -   -   -   -   -   -   -
*       clear_xfer+      -   I   -   -   -   -   -   -   -   -   -
*       set_xfer         -   I   -   -   -   -   -   -   -   -   -
*       dump_buffer      G   I   L   L   -   O   L   L   -   L   L
*
*       NOTATION (in order of importance)
*          O :  output parameter
*          I :  input parameter
*          G :  used by routine (register has consistent meaning throughout routine
*          P :  used to pass parameter to called routines
*          T :  used by routine (temporary)
*          L :  possible usage by called routines
*          - :  not used by routine
*
*       NOTE:  the registers used by routines to do an ioescape have been
*              left out since they do not effect other routines.
*
*       *This routine calls ABORT_IO which uses other registers not listed
*       +This routine calls LOGEOT which uses other registers not listed

	page
*
*       ROUTINE USAGE SUMMARY
*
*       ROUTINE         CALLS
*       -------         -----
*       queue_space     <none>
*       queue_empty     <none>
*       queue_full      <none>
*       inqueue         <none>
*       outqueue        <none>
*       init_queue      <none>
*       check_queue     <none>
*       check_dsr_cts   <none>
*       wait            check_queue, check_dsr_cts (both indirectly)
*       send            wait, check_dsr_cts
*       get_char        outqueue, queue_space, send
*       wait_send       send, check_error
*       wait_get        wait, check_error, get_char, check_queue
*       check_error     ioescape
*       soft_reset      init_queue, ABORT_IO
*       connect         soft_reset
*       disconnect      <none>
*       rdivu           <none>
*       check_xfer_in   ioescape
*       check_xfer_out  ioescape
*       clear_xfer      <none>
*       set_xfer        <none>
*       dump_buffer     queue_empty, get_char, clear_xfer, LOGEOT
*       ioescape        <none>
*       init            init_queue, ABORT_IO
*       rdb             connect, check_error, check_xfer_in, wait_get
*       wtb             connect, check_error, check_xfer_out, wait_send
*       rdw             connect, check_error, check_xfer_in, wait_get
*       wtw             connect, check_error, check_xfer_out, wait_send
*       rds             queue_empty, get_char, check_error, rdivu, ioescape,
*                       connect
*       wtc             check_error, soft_reset, connect, disconnect, rdivu,
*                       ioescape
*       isr             queue_space, queue_full, inqueue, check_dsr_cts,
*                       send, dump_buffer, LOGEOT
*       tfr             connect, check_error, dump_buffer, set_xfer

	page
*
*
*       ROUTINE         CALLED BY
*       -------         ---------
*       queue_space     get_char, isr
*       queue_empty     dump_buffer, rds (6, 10)
*       queue_full      isr
*       inqueue         isr
*       outqueue        get_char
*       init_queue      init, soft_reset
*       check_queue     wait_get (with wait)
*       check_dsr_cts   isr, send (with and without wait)
*       wait            wait_get, wait_send, send
*       send            isr, wait_send, get_char
*       get_char        rds(6), dump_buffer, wait_get
*       wait_send       wtb, wtw
*       wait_get        rdb, rdw,
*       check_error     rdb, wtb, rdw, wtw, rds(6), wtc(6), tfr,
*                       wait_send, wait_get
*       soft_reset      wtc(14), connect
*       connect         rdb, wtb, rdw, wtw, wtc(12), tfr
*       disconnect      wtc(12)
*       rdivu           rds(3), wtc(3)
*       check_xfer_in   rdb, rdw,
*       check_xfer_out  wtb, wtw
*       clear_xfer      isr, dump_buffer
*       set_xfer        tfr
*       dump_buffer     tfr, isr
*       ioescape        rds, wtc, tfr, check_error, check_xfer_in,
*                       check_xfer_out
*       ABORT_IO        init, soft_reset
*       LOGEOT          isr, dump_buffer


	TTL     RS232 DRIVERS
	page
*****************************************************************************
*
*       module initialization -- none required.
*
*****************************************************************************

RS_RS   EQU *
	RTS


*****************************************************************************
*
*       98626 card register mnemonics
*
*****************************************************************************

RESET_REG       EQU     1               write only
ID_REG          EQU     1               read only
INTR_SW         EQU     3               interrupt switches
BAUD_SW         EQU     5               baud rate switch bank
LINE_SW         EQU     7               line characteristic switches

*
*       UART registers
*

DATA            EQU     17              receive/transmit buffer (dlab=0)
INTR_EN         EQU     19              interrupt enable register(dlab=0)
DIV0            EQU     17              divisor latch (LSB)   (DLAB=1)
DIV1            EQU     19              divisor latch (MSB)   (DLAB=1)
INTR_ID         EQU     21              interrupt identification
LINE_CONT       EQU     23              line control register
MODEM_CONT      EQU     25              modem control register
LINE_STAT       EQU     27              line status register
MODEM_STAT      EQU     29              modem status register
		page
******************************************************************************
*
*       ATTRIBUTE space offset mnemonics
*         (do not mix -- word boundary problems)
*         the word address is assumed to be EVEN
*         starting at AVAIL_OFF
*
******************************************************************************
*                                     size
*                                     ----
S_ERROR         EQU     AVAIL_OFF       4  pending error number
IN_ISR          EQU     S_ERROR+4       1
XIN_ACT         EQU     IN_ISR+1        1
CONNECTED       EQU     XIN_ACT+1       1
MODEM_ON        EQU     CONNECTED+1     1
RECEIVING       EQU     MODEM_ON+1      1
XMITTING        EQU     RECEIVING+1     1
S_MODEM         EQU     XMITTING+1      1  modem status copy
S_LINE          EQU     S_MODEM+1       1  line status copy
S_HANDSH        EQU     S_LINE+1        1  contains current handshake
XON_CHAR        EQU     S_HANDSH+1      1
XOFF_CHAR       EQU     XON_CHAR+1      1
ENQ_CHAR        EQU     XOFF_CHAR+1     1
ACK_CHAR        EQU     ENQ_CHAR+1      1
CONV_CHAR       EQU     ACK_CHAR+1      1
IGNORE_PE       EQU     CONV_CHAR+1     1  {aaa}
*empty                                  1  {aaa}
Q_DESCRIPT      EQU     IGNORE_PE+2        {aaa}
Q_SIZE          EQU     Q_DESCRIPT      2
Q_IN            EQU     Q_DESCRIPT+2    2
Q_OUT           EQU     Q_DESCRIPT+4    2
Q_BUFFER        EQU     Q_DESCRIPT+6    134 the rest is internal buffer {aaa}
DEF_BAUD        EQU     Q_BUFFER+134    2  jws  Note: stuck here for
DEF_LINE        EQU     DEF_BAUD+2      1  jws        code compatibility.
*empty                                  1  jws
*                                       ---
*                                       164  total space used    {jws}


******************************************************************************
*
*       constants (mnemonics)
*
******************************************************************************

TEMP_SIZE       EQU     160
BUFFER_SIZE     EQU     TEMP_SIZE-Q_BUFFER+AVAIL_OFF
DC1             EQU     17              ASCII CHARACTER 17
DC3             EQU     19              ASCII CHARACTER 19
ENQ             EQU     5               ASCII CHARACTER 5
ACK             EQU     6               ASCII CHARACTER 6
UNDERSCORE      EQU     95              ASCII CHARACTER 95
OVERRUN_ERROR   EQU     314             receive buffer overflow error
ACK_SIZE        EQU     80              hysteresis for ENQ/ACK handshake
XOFF_SIZE       EQU     40              when to send XOFF
XON_SIZE        EQU     BUFFER_SIZE-XOFF_SIZE
REG_MAX         EQU     22              maximum control/status register number {aaa}
	TTL     RS232 DRIVERS -- initialize
	page
*****************************************************************************
*
*       driver initialization
*
*****************************************************************************

RS_RS_INIT      EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0        * get return address
	MOVEA.L (SP)+,A2        * get temp address
	MOVEA.L C_ADR(A2),A1    * get card address
	PEA     (A0)            * restore return address
*
*   Assembler initialize entry point
*       ON ENTRY:  A1  and  A2  are set to card address and
*                  temp space address (respectively)
*

ASM_INIT        EQU *

*
*   Stop transfers and Reset the card
*

	JSR     ABORT_IO        * stop transfers
*                                 -- RESET CARD --
	ST      RESET_REG(A1)   *  write to reg 1
*
*   wait at least 25us
*
	MOVE.L  #40,-(SP)       USE DELAY ROUTINE   dew1 12/89
	JSR     DELAY_TIMER     DELAY FOR 40us

*
*       global attribute initialization
*
*                                  -- init queue descriptors --
	BSR     INIT_QUEUE
*                                  -- init pseudo registers --
	CLR.B   XIN_ACT(A2)
	CLR.B   IN_ISR(A2)
	CLR.L   S_ERROR(A2)
	CLR.B   S_MODEM(A2)
	CLR.B   S_LINE(A2)
	CLR.B   CONNECTED(A2)
	CLR.B   MODEM_ON(A2)
	CLR.B   IGNORE_PE(A2)           {aaa}
*                                  -- set flags --
	MOVE.B  #1,RECEIVING(A2)
	MOVE.B  #1,XMITTING(A2)
*                                  -- default characters --
	MOVE.B  #DC1,XON_CHAR(A2)
	MOVE.B  #DC3,XOFF_CHAR(A2)
	MOVE.B  #ENQ,ENQ_CHAR(A2)
	MOVE.B  #ACK,ACK_CHAR(A2)
	MOVE.B  #UNDERSCORE,CONV_CHAR(A2)

*
*   Set defaults from the switches (done after attribute initialization
*                just in case the card is not completely reset already)
*
*                                  -- set baud rate from DEF_BAUD --
*
	BSET    #7,LINE_CONT(A1) *   set DLAB to get to divisor latches
	MOVE.B  DEF_BAUD(A2),DIV1(A1)      jws
	MOVE.B  DEF_BAUD+1(A2),DIV0(A1)    jws


*                                  -- SET LINE CHARACTERISTICS --  jws
	MOVE.B  DEF_LINE(A2),D0  *  get handshake and line status defaults
	MOVE.B  D0,D1            *
	ANDI.B  #$3F,D0          *  mask and set default line status
	MOVE.B  D0,LINE_CONT(A1) *     (also restores dlab)
*                                  -- SAVE HANDSHAKE --
	ANDI.B  #$C0,D1          *  handshake is top two bits
	LSR.B   #5,D1            *  adjust it (for jump tables)
	MOVE.B  D1,S_HANDSH(A2)  *  save it

	RTS
*
*       baud rate/divisor table (for switches)  jws-- not presently used
*
*BAUD    DC.W    3072            *    50 Baud
*       DC.W    2048            *    75
*       DC.W    1396            *   110
*       DC.W    1142            *   134.5
*       DC.W    1024            *   150
*       DC.W     768            *   200
*       DC.W     512            *   300
*       DC.W     256            *   600
*       DC.W     128            *  1200
*       DC.W      85            *  1800
*       DC.W      64            *  2400
*       DC.W      43            *  3600
*       DC.W      32            *  4800
*       DC.W      21            *  7200
*       DC.W      16            *  9600
*       DC.W       8            * 19200
	TTL     RS232 DRIVERS -- read byte
	page
*****************************************************************************
*
*       read byte
*
*****************************************************************************

RS_RS_RDB       EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get VAR address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead (any of the three can do an ioescape)
*
	BSR     CONNECT                 make sure the card is active
	BSR     CHECK_ERROR             check for errors saved by ISRs
	BSR     CHECK_XFER_IN           make sure no input transfers active

	BSR     WAIT_GET                get character with wait
	MOVE.B  D2,(A3)                 return the character
	RTS

	TTL     RS232 DRIVERS -- write byte
	page
*****************************************************************************
*
*       write byte
*
*****************************************************************************

RS_RS_WTB       EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0                get return address
	MOVE.B  (SP)+,D3                get char to be written
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead
*
	BSR     CONNECT                 autoconnect
	BSR     CHECK_ERROR             check for errors found by ISRs
	BSR     CHECK_XFER_OUT          make sure no output transfers are active

	BSR     WAIT_SEND               send the character
	RTS

	TTL     RS232 DRIVERS -- read word
	page
*****************************************************************************
*
*       read word
*
*****************************************************************************

RS_RS_RDW       EQU *

	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get VAR address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead (any of the three can do an ioescape)
*
	BSR     CONNECT                 make sure the card is active
	BSR     CHECK_ERROR             check for errors saved by ISRs
	BSR     CHECK_XFER_IN           make sure no input transfers are active

	BSR     WAIT_GET                get character with wait
	LSL.W   #8,D2                   shift first character
	BSR     WAIT_GET                get second character
	MOVE.W  D2,(A3)                 return the word
	RTS
	TTL     RS232 DRIVERS -- write word
	page
*****************************************************************************
*
*       write word
*
*****************************************************************************

RS_RS_WTW       EQU *

	MOVEA.L (SP)+,A0                get return address
	MOVE.W  (SP)+,D3                get word to be written
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead (any of the three can do an ioescape)
*
	BSR     CONNECT                 make sure the card is active
	BSR     CHECK_ERROR             check for errors saved by ISRs
	BSR     CHECK_XFER_OUT          make sure no output transfers are active

	ROR.W   #8,D3                   position the first character
	BSR     WAIT_SEND               send it
	ROR.W   #8,D3                   position the second character
	BSR     WAIT_SEND               send it

	RTS
	TTL     RS232 DRIVERS -- status
	page
*****************************************************************************
*
*       read status
*----------------------------------------------------------------------------
*       CONVENTION:  A3 -- place to put the result (word sized)
*
*****************************************************************************

RS_RS_RDS       EQU *
*
*   Pascal Interface Overhead
*

	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get VAR address
	MOVE.W  (SP)+,D1                get register number
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address

*
*   Check for legal registers and jump to correct register handler
*

	TST.W   D1                      check for negative register number
	BLT.S   STS_ERROR               if so goto common ioescape routine
	CMP.W   #REG_MAX,D1             check for too large register number
	BGT.S   STS_ERROR

	CLR.W   (A3)                    clear the top half of the return word
	ADDQ.L  #1,A3                   point a3 to lower half byte of return word

	LSL.W   #1,D1                   get ready for (word) table jump
	MOVE.W  STS_TABLE(D1),D1        get offset from status table
	JMP     STS_TABLE(D1)           do the indexed jump

STS_TABLE       EQU *
	DC.W    STS_0-STS_TABLE         ID register
	DC.W    STS_1-STS_TABLE         Interrupt status register
	DC.W    STS_2-STS_TABLE         Busy bits register
	DC.W    STS_3-STS_TABLE         Baud rate
	DC.W    STS_4-STS_TABLE         Character control register
	DC.W    STS_5-STS_TABLE         Modem control register
	DC.W    STS_6-STS_TABLE         Data in register
	DC.W    STS_7-STS_TABLE         Optional circuits register
	DC.W    STS_8-STS_TABLE         Interrupt Enable Mask register
	DC.W    STS_9-STS_TABLE         Interrupt Cause register
	DC.W    STS_10-STS_TABLE        UART Status register
	DC.W    STS_11-STS_TABLE        Modem Status register
	DC.W    STS_12-STS_TABLE        Connect/Disconnect register
	DC.W    STS_13-STS_TABLE        Hardware handshake register
	DC.W    STS_14-STS_TABLE        Error status register
	DC.W    STS_15-STS_TABLE        Current Xon Character
	DC.W    STS_16-STS_TABLE        Current Xoff Character
	DC.W    STS_17-STS_TABLE        Current ENQ Character
	DC.W    STS_18-STS_TABLE        Current ACK Character
	DC.W    STS_19-STS_TABLE        Current FE/PE convert Character
	DC.W    STS_20-STS_TABLE        Ignore FE/PE
	DC.W    STS_21-STS_TABLE        Default baud rate       jws
	DC.W    STS_22-STS_TABLE        Default line settings   jws

STS_ERROR       EQU *
	MOVEQ   #BAD_RDS,D0
	BRA     IOESCAPE                error number is passed in d0
*-----------------------------------------------------------------------------
STS_0           EQU *                   -- ID register --
	MOVE.B  ID_REG(A1),(A3)         get id from card
	RTS
*-----------------------------------------------------------------------------
STS_1           EQU *                   -- Interrupt Status --
	MOVE.B  INTR_SW(A1),(A3)        get result from card
	RTS
*-----------------------------------------------------------------------------
STS_2           EQU *                   -- "Busy Bits" --
	MOVE.B  INTR_SW(A1),D7          --> interrupt enabled bit (1)
	AND.B   #$80,D7
	LSR.B   #6,D7                   move it to correct position

	TST.L   BUFI_OFF(A2)            --> transfer active bit (0)
	BNE.S   SET_BIT_0
	TST.L   BUFO_OFF(A2)
	BEQ.S   DO_BIT_4                neither transfer is active

SET_BIT_0       EQU *                   set transfer active bit
	BSET    #0,D7

DO_BIT_4        EQU *                   --> not transmitting bit (4)
	TST.B   XMITTING(A2)
	BNE.S   DO_BIT_5
	BSET    #4,D7

DO_BIT_5        EQU *                   --> not receiving bit (5)
	TST.B   RECEIVING(A2)
	BNE.S   END_STS_2
	BSET    #5,D7

END_STS_2       EQU *                   store away result
	MOVE.B  D7,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_3           EQU *                   -- Baud rate --
	SUBQ.L  #1,A3                   this routine returns a word
*
*   Get divisor (a critical section since it uses DLAB)
*
	MOVE.B  INTR_SW(A1),D7          save card interrupt status
	CLR.B   INTR_SW(A1)             disable interrupts

	BSET    #7,LINE_CONT(A1)        get access to divisor latches
	MOVE.B  DIV1(A1),D0             get upper half of divisor
	LSL.W   #8,D0
	MOVE.B  DIV0(A1),D0             get lower half of divisor
	BCLR    #7,LINE_CONT(A1)        reset DLAB so normal operation can resume

	MOVE.B  D7,INTR_SW(A1)          restore interrupts
*
*   Check for special divisors which division is inexact
*
STS_3B  TST.W   D0                      - infinite baud rate ? -
	  BNE.S   IS85
	  RTS                           return zero baud rate
IS85    CMP.W   #85,D0                  - 1800 baud ? -
	  BNE.S   IS77
	  MOVE.W  #1800,(A3)
	  RTS
IS77    CMP.W   #77,D0                  - 2000 baud ? -
	  BNE.S   IS43
	  MOVE.W  #2000,(A3)
	  RTS
IS43    CMP.W   #43,D0                  - 3600 baud ? -
	  BNE.S   IS21
	  MOVE.W  #3600,(A3)
	  RTS
IS21    CMP.W   #21,D0                  - 7200 baud ? -
	  BNE.S   REGULAR
	  MOVE.W  #7200,(A3)
	  RTS
REGULAR         EQU *
*
*   Compute baud rate by:  baud_rate = (freq/16) / divisor
*
	MOVE.L  #153600,D1
	BSR     RDIVU                   do the division
	MOVE.W  D1,(A3)                 store away the answer (d1)
	RTS
*-----------------------------------------------------------------------------
STS_4           EQU *                   -- Character control --
	MOVE.B  LINE_CONT(A1),D7        get line control
	AND.B   #$3F,D7                 remove top two bits

	MOVE.B  S_HANDSH(A2),D6         get handshake
	LSL.B   #5,D6                   move it to top two bits

	OR.B    D6,D7                   combine to form register result
	MOVE.B  D7,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_5           EQU *                   -- Modem control --
	MOVE.B  MODEM_CONT(A1),(A3)     read directly from the UART
	RTS
*-----------------------------------------------------------------------------
STS_6           EQU *                   -- Data in --
	BSR     CHECK_ERROR             check for errors trapped by ISRs

	BSR     QUEUE_EMPTY             read from buffer if not empty
	BEQ.S   READ_UART               else read directly from UART

	MOVE.B  INTR_SW(A1),D5          save interrupt state
	CLR.B   INTR_SW(A1)             disable card interrupts for critical section

	BSR     GET_CHAR                (get character with handshake)
	MOVE.B  D2,(A3)

	MOVE.B  D5,INTR_SW(A1)          restore interrupt state
	RTS
READ_UART       EQU *
	MOVE.B  DATA(A1),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_7           EQU *                   -- Optional circuits --
	MOVEQ   #0,D7                   RETURN 0 IF 98644
	MOVE.B  ID_REG(A1),D6           GET ID REG
	BCLR    #7,D6                   CLEAR REMOTE BIT
	CMP.B   #66,D6                  BRANCH IF 98644
	BEQ.S   STS_7B
	MOVE.B  BAUD_SW(A1),D7          read from the card hardware
	LSR.B   #4,D7                   right justify (and get rid of baud info)
STS_7B  MOVE.B  D7,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_8           EQU *                   -- interrupt enable mask --
	MOVE.B  INTR_EN(A1),(A3)        read directly from the UART
	RTS
*-----------------------------------------------------------------------------
STS_9           EQU *                   -- interrupt cause --
	MOVE.B  INTR_ID(A1),(A3)        read directly from the UART
	RTS
*-----------------------------------------------------------------------------
STS_10          EQU *                   -- UART status --
	MOVE.B  INTR_SW(A1),D7          save card interrupt condition
	CLR.B   INTR_SW(A1)             disable interrupts for critical section

	MOVE.B  S_LINE(A2),D6           get accumulated line status
	CLR.B   S_LINE(A2)              reset it since it is read destructive

	MOVE.B  D7,INTR_SW(A1)          restore interrupts (end critical section)

	AND.B   #$1E,D6                 only use the read destructive bits
	OR.B    LINE_STAT(A1),D6        combine it with the current status

	BSR     QUEUE_EMPTY             use internal buffer to determine bit 0
	BEQ.S   DONT_SET
	BSET    #0,D6                   set receive buffer full bit
DONT_SET        EQU *
	MOVE.B  D6,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_11          EQU *                   -- modem status --
	MOVE.B  INTR_SW(A1),D7          save card interrupt condition
	CLR.B   INTR_SW(A1)             disable interrupts for critical section

	MOVE.B  S_MODEM(A2),D6          get accumulated copy of modem status
	CLR.B   S_MODEM(A2)             clear it since it is read destructive

	MOVE.B  D7,INTR_SW(A1)          restore interrupts (end critical section)

	AND.B   #$0F,D6                 only use the read destructive bits
	OR.B    MODEM_STAT(A1),D6       combine it with the current status
	MOVE.B  D6,(A3)
	RTS
*-----------------------------------------------------------------------------
STS_12          EQU *                   -- connect/disconnect --
	MOVE.B  CONNECTED(A2),(A3)      get the pseudo-register
	RTS
*-----------------------------------------------------------------------------
STS_13          EQU *                   -- hardware handshake register --
	MOVE.B  MODEM_ON(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_14          EQU *                   -- current error status --
	MOVE.B  INTR_SW(A1),D7          save interrupt state
	CLR.B   INTR_SW(A1)             disable interrupts

	MOVE.W  S_ERROR+2(A2),-1(A3)    get (lower word of) the error
*                                       this is a word register!
	CLR.L   S_ERROR(A2)             the read is destructive

	MOVE.B  D7,INTR_SW(A1)          restore interrupt state
	RTS
*-----------------------------------------------------------------------------
STS_15          EQU *                   -- Current Xon character --
	MOVE.B  XON_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_16          EQU *                   -- Current Xoff character --
	MOVE.B  XOFF_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_17          EQU *                   -- Current ENQ character --
	MOVE.B  ENQ_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_18          EQU *                   -- Current ACK character --
	MOVE.B  ACK_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_19          EQU *                   -- Current FE/PE convert character --
	MOVE.B  CONV_CHAR(A2),(A3)
	RTS
*-----------------------------------------------------------------------------
STS_20          EQU *                   -- Ignore FE/PE {aaa}
	MOVE.B  IGNORE_PE(A2),(A3)                      {aaa}
	RTS                                             {aaa}
	TTL     RS232 DRIVERS -- control
	page
*-----------------------------------------------------------------------------
STS_21          EQU *                   -- Default baud rate      jws
	SUBQ.L  #1,A3                  return a word              jws
	MOVE.W  DEF_BAUD(A2),D0        get default divisor        jws
	BRA     STS_3B                 same as status 3 from hr   jws
*-----------------------------------------------------------------------------
STS_22          EQU *                   -- Default line switch    jws
	MOVE.B  DEF_LINE(A2),(A3)                                 jws
	RTS
*
*****************************************************************************
*
*       write control
*----------------------------------------------------------------------------
*       CONVENTION:  D0.W -- value of the control
*
*****************************************************************************

RS_RS_WTC       EQU *

*
*   Pascal Interface Overhead
*

	MOVEA.L (SP)+,A0                get return address
	MOVE.W  (SP)+,D0                get value
	MOVE.W  (SP)+,D1                get register number
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address

*
*   Check for legal registers and jump to correct register handler
*

	TST.W   D1                      check for negative register number
	BMI.S   CONT_ERROR              if so goto common ioescape routine
	CMP.W   #REG_MAX,D1             check for too large register number
	BGT.S   CONT_ERROR

	LSL.W   #1,D1                   get ready for (word) table jump
	MOVE.W  CONT_TABLE(D1),D1       get offset from status table
	JMP     CONT_TABLE(D1)          do the indexed jump

CONT_TABLE       EQU *
	DC.W    CONT_0-CONT_TABLE       Reset
	DC.W    CONT_1-CONT_TABLE       Break
	DC.W    CONT_ERROR-CONT_TABLE   Register 2 Undefined
	DC.W    CONT_3-CONT_TABLE       Baud rate
	DC.W    CONT_4-CONT_TABLE       Character control register
	DC.W    CONT_5-CONT_TABLE       Modem control register
	DC.W    CONT_6-CONT_TABLE       Data out register
	DC.W    CONT_7-CONT_TABLE       Optional circuits register
	DC.W    CONT_ERROR-CONT_TABLE   Register 8 Undefined
	DC.W    CONT_ERROR-CONT_TABLE   Register 9 Undefined
	DC.W    CONT_ERROR-CONT_TABLE   Register 10 Undefined
	DC.W    CONT_ERROR-CONT_TABLE   Register 11 Undefined
	DC.W    CONT_12-CONT_TABLE      Connect/Disconnect register
	DC.W    CONT_13-CONT_TABLE      Hardware handshake register
	DC.W    CONT_14-CONT_TABLE      Soft reset register
	DC.W    CONT_15-CONT_TABLE      Redefine Xon Character
	DC.W    CONT_16-CONT_TABLE      Redefine Xoff Character
	DC.W    CONT_17-CONT_TABLE      Redefine ENQ Character
	DC.W    CONT_18-CONT_TABLE      Redefine ACK Character
	DC.W    CONT_19-CONT_TABLE      Redefine FE/PE convert Character
	DC.W    CONT_20-CONT_TABLE      Ignore FE/PE {aaa}
	DC.W    CONT_21-CONT_TABLE      Set default baud rate
	DC.W    CONT_22-CONT_TABLE      Set default line control


CONT_ERROR      EQU *
	MOVEQ   #BAD_RDS,D0
	BRA     IOESCAPE                error number is passed in d0
*-----------------------------------------------------------------------------
CONT_0          EQU *                   -- reset --
	TST.W   D0
	BNE     ASM_INIT                initialize if any bit is set
	RTS
*-----------------------------------------------------------------------------
CONT_1          EQU *                   -- send break --
	TST.W   D0
	BEQ.S   EXIT_C1                 no-op if control value is zero
*
*   set and hold break for 400ms
*
	BSET    #6,LINE_CONT(A1)        set the break bit in UART
	MOVE.L  #400000,-(SP)           USE DELAY ROUTINE   ttt  JS 8/3/83
WAIT_BREAK      EQU *
	JSR     DELAY_TIMER             CALL DELAY ROUTINE   ttt JS 8/3/83
*
*   release break and wait 60ms for break to clear
*
	BCLR    #6,LINE_CONT(A1)        clear the break bit in UART
	MOVE.L  #60000,-(SP)            SETUP FOR DELAY ROUTINE  ttt JS 8/3/83
WAIT_BREAK2     EQU *
	JSR     DELAY_TIMER             CALL DELAY ROUTINE       ttt JS 8/3/83
EXIT_C1 RTS
*-----------------------------------------------------------------------------
CONT_3          EQU *                   -- Baud rate --
*
*   check for overflow -- a baud rate with a resulting divisor more than
*                         sixteen bits long.
*   (underflow is not checked because it cannot be generated with a word
*    length baud rate)
*
	CMP.W   #5,D0                   5 is the lowest baud rate possible
	BGE.S   CALC_DIV

	MOVEQ   #IO_MISC,D0             value out of range -- io misc error
	BRA     IOESCAPE
*
*   calculate divisor :  div = (freq/16) / baud_rate
*
CALC_DIV        EQU *
	MOVE.L  #153600,D1              d1 := freq/16
	BSR     RDIVU                   d1.w := d1.l / d0.w ( freq/16 / baud )
*
*   move the divisor to hardware (critical section: uses DLAB)
*
	MOVE.B  INTR_SW(A1),D7          save card interrupt state
	CLR.B   INTR_SW(A1)             disable card interrupts

	BSET    #7,LINE_CONT(A1)        set DLAB to get access to divisor latches
	MOVE.B  D1,DIV0(A1)             set lower half of divisor latch
	LSR.W   #8,D1
	MOVE.B  D1,DIV1(A1)             set upper half of divisor latch
	BCLR    #7,LINE_CONT(A1)        clear DLAB for normal use

	MOVE.B  D7,INTR_SW(A1)          restore card interrupt state

	RTS
*-----------------------------------------------------------------------------
CONT_4          EQU *                   -- Character Control --
	MOVE.B  D0,D7                   save a copy of control value

	AND.B   #$3F,D0                 use only bottom 6 bits
	MOVE.B  D0,LINE_CONT(A1)        for line control

	AND.B   #$C0,D7                 handshake is top two bits
	LSR.B   #5,D7                   shift it for later use
	CMP.B   S_HANDSH(A2),D7         if handshake changed
	BEQ.S   EXIT_C4

	MOVE.B  INTR_SW(A1),D6          save interrupt state
	CLR.B   INTR_SW(A1)             disable interrupts

	MOVE.B  D7,S_HANDSH(A2)         save new handshake
	MOVE.B  #1,RECEIVING(A2)        \
	MOVE.B  #1,XMITTING(A2)         /   reset the handshake flags

	MOVE.B  D6,INTR_SW(A1)          restore interrupt state
EXIT_C4 RTS
*-----------------------------------------------------------------------------
CONT_5          EQU *                   -- modem control --
	MOVE.B  D0,MODEM_CONT(A1)       write directly to UART
	RTS
*-----------------------------------------------------------------------------
CONT_6          EQU *                   -- Data out --
	BSR     CHECK_ERROR             check for errors trapped by ISRs

	MOVE.B  D0,DATA(A1)             write directly to UART
	RTS
*-----------------------------------------------------------------------------
CONT_7          EQU *                   -- Optional Circuits --
	MOVE.B  ID_REG(A1),D6           GET ID REG
	BCLR    #7,D6                   CLEAR REMOTE BIT
	CMP.B   #66,D6                  IS THIS A 98644 ?
	BEQ.S   CONT_7R                 YES, NO OP
	LSL.B   #4,D0                   left justify
	MOVE.B  D0,BAUD_SW(A1)          write directly to card hardware
CONT_7R RTS
*-----------------------------------------------------------------------------
CONT_12         EQU *                   -- connect/disconnect --
	TST.B   D0                      check for d0=0
	BEQ     DISCONNECT              disconnect will do return
	CMP.B   #1,D0
	BEQ     CONNECT                 connect will return
VAL_ERR         EQU *
	MOVEQ   #IO_MISC,D0             illegal value for register
	BRA     IOESCAPE
*-----------------------------------------------------------------------------
CONT_13         EQU *                   -- hardware handshake --
	TST.B   D0                      check for too small value
	BLT.S   VAL_ERR                 (located in cont_12)
	CMP.B   #1,D0                   check for too large value
	BGT.S   VAL_ERR
	MOVE.B  D0,MODEM_ON(A2)         assign modem flag
	RTS
*-----------------------------------------------------------------------------
CONT_14         EQU *                   -- soft reset --
	TST.W   D0                      any bit will do reset
	BEQ.S   EXIT_14                 zero value does nothing

	BSR     SOFT_RESET
EXIT_14 RTS
*-----------------------------------------------------------------------------
CONT_15         EQU *                   -- redefine Xon character --
	MOVE.B  D0,XON_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_16         EQU *                   -- redefine Xoff character --
	MOVE.B  D0,XOFF_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_17         EQU *                   -- redefine ENQ character --
	MOVE.B  D0,ENQ_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_18         EQU *                   -- redefine ACK character --
	MOVE.B  D0,ACK_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_19         EQU *                   -- redefine FE/PE convert character --
	MOVE.B  D0,CONV_CHAR(A2)
	RTS
*-----------------------------------------------------------------------------
CONT_20         EQU *                   -- Ignore PE/FE --        {aaa}
	TST.B   D0                      check for too small value {aaa}
	BLT.S   VAL_ERR2                                          {aaa}
	CMP.B   #1,D0                   check for too large value {aaa}
	BGT.S   VAL_ERR2                                          {aaa}
	MOVE.B  D0,IGNORE_PE(A2)        assign modem flag         {aaa}
	RTS                                                       {aaa}
VAL_ERR2        EQU *                                             {aaa}
	MOVEQ   #IO_MISC,D0             illegal value for register{aaa}
	BRA     IOESCAPE                                          {aaa}
*-----------------------------------------------------------------------------
CONT_21         EQU *                   -- Set default baud rate  {jws}
	CMP.W   #5,D0                   check for overflow        {jws}
	BGE.S   CALC_DIV21              if ok then skip           {jws}
	MOVEQ   #IO_MISC,D0             else give error           {jws}
	BRA     IOESCAPE                                          {jws}

CALC_DIV21      EQU *                                             {jws}
	MOVE.L  #153600,D1              calculate divisor         {jws}
	BSR     RDIVU                   same as CONT_3            {jws}
	MOVE    D1,DEF_BAUD(A2)         save divisor as DEF_BAUD  {jws}
	RTS
*----------------------------------------------------------------------------
CONT_22         EQU *                   -- Set default line sw.   {jws}
	MOVE.B  D0,DEF_LINE(A2)                                   {jws}
	RTS                                                       {jws}

	TTL     RS232 DRIVERS -- interrupt service routines
	page
*****************************************************************************
*
*       interrupt service routine
*
*****************************************************************************

RS_RS_ISR       EQU *

*
*       pascal interface overhead
*

	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address

*
*       verify there is an interrupt
*

	MOVE.B  INTR_ID(A1),D0          get interrupt cause
	BTST    #0,D0                   make sure an interrupt is pending
	BEQ.S   INTR_EXIST
	RTS                             no interrupt-- return
*
*       jump to appropriate interrupt handler
*

INTR_EXIST      EQU *
	MOVE.B  #1,IN_ISR(A2)           mark isr processing

	EXT.W   D0
	MOVE.W  INTR_TABLE(D0),D0       (get appropriate address)
	JMP     INTR_TABLE(D0)          (jump to the proper case)

INTR_TABLE      EQU *
	DC.W    MODEM_INTR-INTR_TABLE        modem change interrupt
	DC.W    OUTPUT_INTR-INTR_TABLE       output empty interrupt
	DC.W    INPUT_INTR-INTR_TABLE        input available interrupt
	DC.W    ERROR_INTR-INTR_TABLE        error interrupt
	page
*
*   Check for possible unexpected interrupts, if found clear the interrupt
*      (different for each type of interrupt) and disable that type of
*      interrupt.

ERROR_INTR      EQU *
	MOVE.B  LINE_STAT(A1),D0        clear the interrupt (by reading line status)
	OR.B    D0,S_LINE(A2)           save line status for user
	BCLR    #2,INTR_EN(A1)          disable interrupts since it should not happen
	BRA     END_ISR

MODEM_INTR      EQU *
	TST.B   MODEM_ON(A2)            modem handshake on?
	BEQ.S   ABORT_MODEM                -- no abort
	MOVE.L  BUFO_OFF(A2),D7         output transfer active?
	BNE.S   XFER_OUT                   -- yes do transfer

ABORT_MODEM     EQU *
	MOVE.B  MODEM_STAT(A1),D0       clear the interrupt (by reading modem status)
	OR.B    D0,S_MODEM(A2)          save modem status for user
	BCLR    #3,INTR_EN(A1)          disable interrupt so it won't happen again
	BRA     END_ISR

OUTPUT_INTR     EQU *
	MOVE.L  BUFO_OFF(A2),D7         output interrupt transfer active ?
	BNE.S   XFER_OUT                  -- yes do transfer

	BCLR    #1,INTR_EN(A1)            -- no disable interrupt
	BRA     END_ISR
	page
*
*   Do the output interrupt transfer
*       (but only if the THRE and the modem lines are high)
*

XFER_OUT        EQU *
	MOVEA.L D7,A3                   a3 := buffer control block
	MOVE.B  LINE_STAT(A1),D7        check for THRE
	OR.B    D7,S_LINE(A2)           save line status for user
	BTST    #5,D7
	BEQ     END_ISR

	TST.B   MODEM_ON(A2)
	BEQ.S   MOVE_OUT
	BSR     CHECK_DSR_CTS
	BNE     END_ISR

MOVE_OUT        EQU *
	CLR.W   D7                      clear d7.w
	MOVEA.L TEMP_OFF(A3),A0         a0 := buffer empty pointer
	MOVE.B  (A0)+,D7                d7 := character
	MOVE.B  D7,DATA(A1)             write the character
	MOVE.L  A0,TEMP_OFF(A3)         update empty pointer

	SUBQ.L  #1,TCNT_OFF(A3)         decrement the count
	BLE.S   END_XOUT                count=0, transfer ends
	CMP.W   TCHR_OFF(A3),D7         character = term. char ?
	BNE     END_ISR

END_XOUT        EQU *
	TST.B   TEND_OFF(A3)            end condition enabled ?
	BEQ.S   CLR_XOUT
	TST.B   MODEM_ON(A2)            modem handshake on ?
	BEQ.S   CLR_XOUT
	ANDI.B  #$F5,INTR_EN(A1)        disable output and modem interrupts
LOOP_LAST       EQU *
	MOVE.B  LINE_STAT(A1),D7        wait for everything transferred
	OR.B    D7,S_LINE(A2)           before dropping RTS
	NOT.B   D7
	AND.B   #$60,D7
	BNE.S   LOOP_LAST
	BCLR    #1,MODEM_CONT(A1)       drop RTS is the EOI condition

	BSR     CLEAR_XFER              clear the transfer
	JSR     LOGEOT                  call the eot procedure
	BRA     END_ISR

CLR_XOUT        EQU *
	ANDI.B  #$F5,INTR_EN(A1)        disable output and modem interrupts
	BSR     CLEAR_XFER              clear the transfer
	JSR     LOGEOT                  call the eot procedure
	BRA     END_ISR
	page
*
*   Input interrupts are normally active in order to fill the internal
*       buffer
*
INPUT_INTR      EQU *
	MOVE.B  LINE_STAT(A1),D1
	MOVE.B  DATA(A1),D2             get the input byte (clears interrupt)
	OR.B    D1,S_LINE(A2)           preserve line status for user

	TST.B   MODEM_ON(A2)
	BEQ.S   CHECK_BREAK             skip modem stuff if handshake off
*
*   check for both CD and DSR
*
	MOVE.B  MODEM_STAT(A1),D0
	OR.B    D0,S_MODEM(A2)          preserve modem status for user
	NOT     D0
	ANDI    #$A0,D0                 mask appropriate bits
	BNE     INPUT_END               if zero then they were set previously
*
*   ignore character if break received
*
CHECK_BREAK     EQU *
	BTST    #4,D1                   if break received,
	BNE     INPUT_END               then ignore character
*
*   convert Framing and Parity errors to specified character
*
	MOVE.B  D1,D0                   save line status for later use
	ANDI    #$0C,D0                 check for PARITY and FRAMING errors
	BEQ.S   NO_CONVERT
	TST.B   IGNORE_PE(A2)           {aaa}
	BNE.S   NO_CONVERT              {aaa}
	MOVE.B  CONV_CHAR(A2),D2        convert the character

NO_CONVERT      EQU *
*
*       jump to appropriate handshake handler
*
	MOVE.B  S_HANDSH(A2),D0
	EXT.W   D0
	MOVE.W  HAND_TABLE(D0),D0       get address to jump
	JMP     HAND_TABLE(D0)

HAND_TABLE      EQU *
	DC.W    ENQ_HAND-HAND_TABLE
	DC.W    XON_HAND-HAND_TABLE
	DC.W    NO_HAND-HAND_TABLE
	DC.W    NO_HAND-HAND_TABLE
	page
XON_HAND        EQU *
*
*   Do host part of the handshake -- check for Xon and Xoff
*
	CMP.B   XON_CHAR(A2),D2
	BNE.S   CHECK_XOFF
	MOVE.B  #1,XMITTING(A2)         turn transmitting back on

	TST.L   BUFO_OFF(A2)            \
	BEQ     INPUT_END                \
	BSET    #1,INTR_EN(A1)            \  enable interrupts if output
	TST.B   MODEM_ON(A2)              /  transfer is active
	BEQ     INPUT_END                /
	BSET    #3,INTR_EN(A1)          /
	BRA     INPUT_END

CHECK_XOFF      EQU *
	CMP.B   XOFF_CHAR(A2),D2
	BNE.S   TERM_HAND
	CLR.B   XMITTING(A2)            turn transmitting off

	MOVE.B  #$1,INTR_EN(A1)         turn any possible output interrupts off
	BRA     INPUT_END

*
*   Do terminal part of the handshake
*
TERM_HAND       EQU *
	TST.B   RECEIVING(A2)           if receiving is on, might have
	BEQ.S   PUTINQ                     to turn it off
	BSR     QUEUE_SPACE             d3 := space left in queue
	CMP.W   #XOFF_SIZE,D3
	BGE.S   PUTINQ
*
*   Have to turn receiving off
*
	MOVE.B  XOFF_CHAR(A2),D3        prepare to send Xoff
	BSR     SEND                    send character
	BNE.S   PUTINQ                  send did not succeed
	CLR.B   RECEIVING(A2)           no longer expecting input
	BRA.S   PUTINQ                  but put present char in queue

	page

ENQ_HAND        EQU *
	CMP.B   ENQ_CHAR(A2),D2         IF char <> ENQ
	BNE     PUTINQ                     THEN put char in queue
	BSR     QUEUE_SPACE                ELSE
	CMP.W   #ACK_SIZE,D3                 IF queue_space <= 80
	BGE.S   SEND_ACK
	CLR.B   RECEIVING(A2)                   receiving := false
	BRA     INPUT_END

SEND_ACK        EQU *
	MOVE.B  ACK_CHAR(A2),D3         set up parameter in D3
	BSR     SEND                    send ACK
	BEQ     INPUT_END

	CLR.B   RECEIVING(A2)           not receiving since ACK not sent
	BRA     INPUT_END

*
*   Put character (d2) in queue, and check for overrun.
*
NO_HAND         EQU *
PUTINQ          EQU *
	BSR     QUEUE_FULL      IF queue_full
	BEQ.S   OVERRUN            THEN overrun_error
	BSR     INQUEUE            ELSE inqueue(char)

INPUT_END       EQU *
	ANDI    #$02,D1         check for overrun error
	BEQ.S   CHECK_XIN

OVERRUN         EQU *
	MOVE.L  #OVERRUN_ERROR,S_ERROR(A2)

*
*   If transfer in is active then do the transfer
*
CHECK_XIN       EQU *
	TST.B   XIN_ACT(A2)             check for transfer active
	BEQ.S   END_ISR

	MOVEA.L BUFI_OFF(A2),A3         a3 := buffer control block pointer
	BSR     DUMP_BUFFER

END_ISR         EQU *
	CLR.B   IN_ISR(A2)              not in isr any longer
	RTS
	TTL     RS232 DRIVERS -- transfer
	page
*****************************************************************************
*
*       transfer
*
*****************************************************************************

RS_RS_TFR       EQU *

*
*   Pascal interface overhead
*
	MOVEA.L (SP)+,A0                get return address
	MOVEA.L (SP)+,A3                get buffer control block address
	MOVEA.L (SP)+,A2                get temp address
	MOVEA.L C_ADR(A2),A1            get card address
	PEA     (A0)                    restore return address
*
*   Card overhead
*
	BSR     CONNECT
	BSR     CHECK_ERROR
*
*   Check for unsupported transfer modes
*       ( done by table jump also )
*
	TST.B   T_BW_OFF(A3)            word mode?
	BNE.S   WORD_ERR                  -- is unsupported

	MOVE.B  TUSR_OFF(A3),D1         d1.w := offset into transfer table
	EXT.W   D1
	ADD.W   D1,D1                   d1.w := word offset into table
	MOVE.W  XFER_TABLE(D1),D1
	JMP     XFER_TABLE(D1)

XFER_TABLE      EQU *
	DC.W    XFER_ERR-XFER_TABLE     not used
	DC.W    DMA_ERR-XFER_TABLE      serial DMA -- not supported
	DC.W    SER_FHS-XFER_TABLE      serial FHS
	DC.W    SER_FHS-XFER_TABLE      serial fastest -- same as serial FHS
	DC.W    XFER_ERR-XFER_TABLE     not used

	DC.W    INTR_XFER-XFER_TABLE    overlap INTR
	DC.W    DMA_ERR-XFER_TABLE      overlap DMA -- not supported
	DC.W    XFER_ERR-XFER_TABLE     overlap FHS -- not supported
	DC.W    INTR_XFER-XFER_TABLE    overlap FASTEST -- same as overlap INTR
	DC.W    INTR_XFER-XFER_TABLE    overlap overlap -- same as overlap INTR
	page
*
*   Error escapes
*
END_ERR         EQU *
DMA_ERR         EQU *
XFER_ERR        EQU *
	BSR     CLEAR_XFER
	MOVEQ   #TFR_ERR,D0
	BRA     IOESCAPE

WORD_ERR        EQU *

	BSR     CLEAR_XFER
	MOVEQ   #NO_WORD,D0
	BRA     IOESCAPE
*
*   Set the actual mode for transfers
*
SER_FHS         EQU *
	MOVE.B  #TT_FHS,TACT_OFF(A3)    set the actual mode
	TST.B   TDIR_OFF(A3)            jump to correct direction handler
	BNE.S   OUTPUT_XFER
	BRA.S   INPUT_XFER

INTR_XFER       EQU *
	MOVE.B  #TT_INT,TACT_OFF(A3)    set actual mode to INTR
	TST.B   TDIR_OFF(A3)            jump to correct direction handler
	BNE.S   OUTPUT_XFER
*       BRA.S   INPUT_XFER

*
*   Input transfer setup.
*

INPUT_XFER      EQU *
	TST.B   TEND_OFF(A3)            end condition not allowed on input xfers
	BNE.S   END_ERR

	BSR     DUMP_BUFFER             do most of transfers with intr enabled
	BEQ.S   EXIT_TFR                if transfer done, then exit

	CLR.B   INTR_SW(A1)             disable interrupts for critical section
	MOVE.B  #1,XIN_ACT(A2)
	BSR     SET_XFER                set interface busy
	BSR     DUMP_BUFFER             make sure that buffer is empty (prevent deadlock)
*                                       if eot the following code will exit
*                                       so no explicit exit is done
	BSET    #7,INTR_SW(A1)          end of critical section

	BRA.S   CHECK_FHS               end of input transfer setup
	page
*
*   Output transfer setup
*

OUTPUT_XFER     EQU *

	CLR.B   INTR_SW(A1)             disable interrupts for critical section

	BSR     SET_XFER                set interface busy
	BSET    #1,MODEM_CONT(A1)       set RTS
	TST.B   XMITTING(A2)            if not transmitting, don't enable interrupts
	BEQ.S   CHECK_FHS
	BSET    #1,INTR_EN(A1)          enable output interrupts
	TST.B   MODEM_ON(A2)            if modem handshake
	BEQ.S   CHECK_FHS
	BSET    #3,INTR_EN(A1)          enable modem interrupts

*
*   IF serial transfer THEN wait until transfer is done
*
CHECK_FHS       EQU *
	BSET    #7,INTR_SW(A1)          end of critical section

	CMPI.B  #TT_FHS,TACT_OFF(A3)
	BNE.S   EXIT_TFR
WAIT_FHS        EQU *
	CMPI.B  #255,T_SC_OFF(A3)       wait until buffer is not busy
	BNE.S   WAIT_FHS
EXIT_TFR        EQU *
	RTS
	TTL     RS232 DRIVERS -- transfer support routines
	page
******************************************************************************
*
*       TRANSFER SUPPORT ROUTINES
*
******************************************************************************
*
*       DUMP BUFFER
*          transfer from the internal queue to user queue
*
*       ON ENTRY: a3 - points to buffer control block
*       ON EXIT : IF transfer was completed
*                    THEN d2.L=0 and Z=1
*                    ELSE d2.L=1 and Z=0
*       USES:     a0 - current fill pointer to user input buffer
*                 d2 - character being transfered
*-----------------------------------------------------------------------------

DUMP_BUFFER     EQU *
	MOVEA.L TFIL_OFF(A3),A0         get fill pointer
	CLR.W   D2                      clear top half of D2 (for later compares)

DUMP_LOOP       EQU *
	BSR     QUEUE_EMPTY
	BEQ.S   EXIT_DUMP
	BSR     GET_CHAR                d2 := character
	MOVE.B  D2,(A0)+                put it in the linear buffer
	SUBQ.L  #1,TCNT_OFF(A3)         decrement count
	BLE.S   END_XIN
	CMP.W   TCHR_OFF(A3),D2
	BNE.S   DUMP_LOOP

END_XIN         EQU *
	MOVE.L  A0,TFIL_OFF(A3)         update fill pointer
	CLR.B   XIN_ACT(A2)
	BSR     CLEAR_XFER
	JSR     LOGEOT

	CLR.L   D2                      set Z flag to mark transfer ended
	RTS

EXIT_DUMP       EQU *
	MOVE.L  A0,TFIL_OFF(A3)         update fill pointer

	MOVEQ   #1,D2                   clear Z flage to mark transfer still active
	RTS
	page
*-----------------------------------------------------------------------------
*       CLEAR_XFER
*          make a transfer inactive (unlink temp space and buffer control block)
*       ON ENTRY:  a3 - points to the buffer control block
*-----------------------------------------------------------------------------

CLEAR_XFER      EQU *
	CLR.B   TACT_OFF(A3)            clear actual transfer mode
	MOVE.B  #255,T_SC_OFF(A3)       set the buffer not busy
	TST.B   TDIR_OFF(A3)
	BNE.S   CLEAR_OUT
	CLR.L   BUFI_OFF(A2)            clear input transfer
	RTS
CLEAR_OUT       EQU *
	CLR.L   BUFO_OFF(A2)            clear output transfer
	RTS

*-----------------------------------------------------------------------------
*       SET_XFER
*          make a transfer active (link temp space with buffer control block)
*       ON ENTRY:  a3 - the buffer control block
*-----------------------------------------------------------------------------

SET_XFER        EQU *
	MOVE.B  IO_SC(A2),T_SC_OFF(A3)  set the buffer busy
	TST.B   TDIR_OFF(A3)
	BNE.S   SET_OUT
	MOVE.L  A3,BUFI_OFF(A2)         set sc's input active
	RTS
SET_OUT         EQU *
	MOVE.L  A3,BUFO_OFF(A2)         set sc's output active
	RTS

*-----------------------------------------------------------------------------
*       CHECK_XFER_IN, CHECK_XFER_OUT
*          gives an error if a transfer is active
*       USES:  d0 -- only if an ioescape is to be given
*-----------------------------------------------------------------------------

CHECK_XFER_IN   EQU *
	TST.L   BUFI_OFF(A2)
	BNE.S   BUSY_ERR
	RTS

CHECK_XFER_OUT  EQU *
	TST.L   BUFO_OFF(A2)
	BNE.S   BUSY_ERR
	RTS

BUSY_ERR        EQU *
	MOVEQ   #SC_BUSY,D0
	BRA     IOESCAPE
	TTL     RS232 DRIVERS -- common utilities
	page
*****************************************************************************
*
*       Useful Subroutines
*
*****************************************************************************
*
*       IOESCAPE
*          ON ENTRY:  d0.L -- contains the escape code
*----------------------------------------------------------------------------

IOESCAPE        EQU *
	MOVE.L  D0,IOE_RSLT(A5)         *  put ioe_result
	CLR.L   D0                      *<<< BUG FIX >>>
	MOVE.B  IO_SC(A2),D0            *  get select code of card
	MOVE.L  D0,IOE_SC(A5)           *  put ioe_sc
	MOVE.W  #IOE_ERROR,ESC_CODE(A5) *  escapecode := ioe_error
	TRAP    #10                     *  do Pascal escape

*----------------------------------------------------------------------------
*       RDIVU
*          unsigned integer divide rounded.
*          ON ENTRY:  d0.w -- divisor (unchanged by this routine)
*                     d1.l -- dividend
*          ON EXIT:   d1.w -- rounded quotient
*----------------------------------------------------------------------------
RDIVU           EQU *
	DIVU    D0,D1                   do truncated division
	SWAP    D1                      get access to remainder
	LSL.W   #1,D1                   multiply remainder by 2
	BCS.S   ROUND                   if carry then remainder*2>divisor
	CMP.W   D1,D0                   remainder*2 > divisor ?
	BLE.S   ROUND                   round up if so.
*                                       --do not round --
	SWAP    D1                      get quotient
	RTS
ROUND           EQU *                   --round up--
	SWAP    D1                      get old quotient
	ADDQ.W  #1,D1                   increment (do the rounding)
	RTS
	page
*----------------------------------------------------------------------------
*       CONNECT
*          connects the card if not connected already.
*
*       uses : d6,d7 by called routines
*----------------------------------------------------------------------------

CONNECT         EQU *
	TST.B   CONNECTED(A2)           IF connected THEN do nothing
	BNE.S   EXIT_CONNECT

	BSET    #0,MODEM_CONT(A1)       set DTR
	BSR     SOFT_RESET              initialize the dynamic data
	MOVE.B  #1,INTR_EN(A1)          enable receive interrupts
	MOVE.B  #1,CONNECTED(A2)        set connected
	BSET    #7,INTR_SW(A1)          enable card interrupts
EXIT_CONNECT    EQU *
	RTS


*-----------------------------------------------------------------------------
*       DISCONNECT
*          disconnect and disable interrupts
*-----------------------------------------------------------------------------

DISCONNECT      EQU *
	BCLR    #7,INTR_SW(A1)          disable card interrupts
	CLR.B   CONNECTED(A2)           set disconnected
	ANDI.B  #$FC,MODEM_CONT(A1)     drop DTR and RTS
	NOP
	CLR.B   INTR_EN(A1)             disable all UART interrupts
	RTS
	page
*-----------------------------------------------------------------------------
*       SOFT_RESET
*          initialize the "dynamic" attributes of the drivers
*
*       uses :  d6,d7 as temporary
*-----------------------------------------------------------------------------

SOFT_RESET      EQU *

	JSR     ABORT_IO                abort transfers

	MOVE.B  INTR_SW(A1),D6          save interrupt state
	CLR.B   INTR_SW(A1)             disable interrupts

	ANDI.B  #1,INTR_EN(A1)          disable modem and transmit interrupts
	BSR     INIT_QUEUE
	MOVE.B  DATA(A1),D7             destroy any data
	CLR.B   S_LINE(A2)
	MOVE.B  LINE_STAT(A1),D7        reset the line status (destructive read)
	CLR.B   S_MODEM(A2)
	MOVE.B  MODEM_STAT(A1),D7       reset the modem status (destructive read)


	CLR.L   S_ERROR(A2)
	MOVE.B  #1,RECEIVING(A2)
	MOVE.B  #1,XMITTING(A2)

	MOVE.B  D6,INTR_SW(A1)          restore the interrupt state
	RTS


*----------------------------------------------------------------------------
*       CHECK_ERROR
*          check for errors recorded in interrupt service routines (ISRs)
*          USES:  D0,D7 only if doing ioescape
*----------------------------------------------------------------------------

CHECK_ERROR     EQU *
	TST.L   S_ERROR(A2)             is error present
	BNE.S   ERROR_EXIST
	RTS                             return if not error
ERROR_EXIST     EQU *
	MOVE.B  INTR_SW(A1),D7          save interrupt condition
	CLR.B   INTR_SW(A1)             disable interrupt for critical section

	MOVE.L  S_ERROR(A2),D0          get error
	CLR.L   S_ERROR(A2)             clear errors

	MOVE.B  D7,INTR_SW(A1)          restore interrupts
	BRA     IOESCAPE                do pascal escape
	page
*-----------------------------------------------------------------------------
*       WAIT_SEND
*          This routine waits for the transmitting flag then sends
*          a character.  It escapes if SEND returns with an error.
*       NOTE:  this routine cannot be called by ISRs!!!
*       ON ENTRY:  d3.B -- character to be sent
*       USES    :  a4 -- used by called routines
*                  d4,d6,d7 -- by called routines
*-----------------------------------------------------------------------------

WAIT_SEND       EQU *

*
*   Wait for xmitting flag (no timeouts !!)
*       (the wait is important for Xon/Xoff as host)
*
	TST.B   XMITTING(A2)
	BEQ.S   WAIT_SEND
*
*   Send the character
*
OK_XMIT         EQU *
	BSR     SEND                    send character with timeout
	BSR     CHECK_ERROR             check for errors found by send
	RTS


*-----------------------------------------------------------------------------
*       WAIT_GET
*          wait until the queue is empty before getting a character
*       ON EXIT:  D2.B contains the character
*                 (the rest of D2 is not altered!)
*       USES:     A4.L -- parameter to WAIT
*                 D0,D3,D4,D6,D7 -- used by called routines
*-----------------------------------------------------------------------------

WAIT_GET        EQU *

*
*   Wait (with timeout) for queue not empty
*
	LEA     CHECK_QUEUE,A4          \  call wait with the not queue empty
	BSR     WAIT                    /  function
	BSR     CHECK_ERROR             check for wait error

	BSR     GET_CHAR
	BSR     CHECK_ERROR
	RTS
	page
*-----------------------------------------------------------------------------
*       GET_CHAR
*          get a character with software handshake.
*       ON ENTRY :  the queue is not empty!
*       ON EXIT:  D2.B contains the character
*                 (the rest of D2 is not altered!)
*       USES:     D3 -- space left in queue/temporary for character
*                 D0.W -- handshake type & temporary
*                 A4,D4,D6,D7 -- temporary
*-----------------------------------------------------------------------------


GET_CHAR        EQU *

*
*   Read the character ( and pass it back )
*
	BSR     OUTQUEUE                get the character (into D2)
*
*   Check for and do handshake overhead
*
	TST.B   RECEIVING(A2)           if receiving
	BNE.S   READ_END                then no overhead needed
*
*   Jump to appropriate handshake handler
*
	MOVE.B  S_HANDSH(A2),D0         get handshake
	EXT.W   D0
	MOVE.W  H_TABLE(D0),D0
	JMP     H_TABLE(D0)

H_TABLE         EQU *
	DC.W    ENQ_H-H_TABLE
	DC.W    XON_H-H_TABLE
	DC.W    READ_END-H_TABLE        no handshake (no overhead)
	DC.W    READ_END-H_TABLE        no handshake
	page
*
*   ENQ/ACK handshake--send ACK if queue can handle more than 80 chars
*
ENQ_H           EQU *
	BSR     QUEUE_SPACE             returns space left in D3
	CMP.W   #ACK_SIZE,D3
	BLT.S   READ_END                space not big enough to send ACK
*
*   Send character to indicate card is receiving and set receiving flag
*
	MOVE.B  ACK_CHAR(A2),D3         send ack
	BRA.S   SEND_HAND

*
*   Xon/Xoff handshake--send Xon if queue can handle more characters
*
XON_H           EQU *
	BSR     QUEUE_SPACE             d3 := space left in queue
	CMP.W   #XON_SIZE,D3
	BLT.S   READ_END                space not big enough to send XON
*
*   Send character to indicate card is receiving and set receiving flag
*
	MOVE.B  XON_CHAR(A2),D3

SEND_HAND       EQU *                   send handshake character (in D3)
	MOVE.B  #1,INTR_EN(A1)          only have receive interrupt enabled
	BSR     SEND                    send char which is in d2
	BNE.S   RESTORE
	MOVE.B  #1,RECEIVING(A2)        turn receiving back on
RESTORE         EQU *                   recalculate interrupt enable mask
	MOVE.B  INTR_SW(A1),D7          save interrupt status
	CLR.B   INTR_SW(A1)             critical section
	TST.L   BUFO_OFF(A2)
	BEQ.S   END_RESTORE
	TST.B   XMITTING(A2)
	BEQ.S   END_RESTORE
	BSET    #1,INTR_EN(A1)
	TST.B   MODEM_ON(A2)
	BEQ.S   END_RESTORE
	BSET    #3,INTR_EN(A1)
END_RESTORE     EQU *
	MOVE.B  D7,INTR_SW(A1)          end critical section

READ_END        EQU *
	RTS
	page
*-----------------------------------------------------------------------------
*       SEND
*       ON ENTRY:  d3.B -- character to be sent
*       ON EXIT :  IF character sent
*                     THEN Z=1
*                     ELSE Z=0, S_ERROR updated to newest error
*       USES    : a4 -- parameter to WAIT
*                 d7 -- temporary
*                 d6 -- by called routines
*-----------------------------------------------------------------------------

SEND            EQU *
	BSET    #1,MODEM_CONT(A1)       set RTS
*
*   Wait (with timeout) for transmit registers empty
*
LOOP_THRE       EQU *
	MOVE.B  LINE_STAT(A1),D7
	OR.B    D7,S_LINE(A2)           save line status for user
	AND.B   #$20,D7                 look at THRE bit
	BEQ.S   LOOP_THRE

	TST.B   MODEM_ON(A2)            skip modem stuff if modem handshake off
	BEQ.S   XMIT_CHAR
*
*   Modem checking depends on if this routine was called from an ISR
*
	TST.B   IN_ISR(A2)
	BEQ.S   NOT_ISR

	BSR     CHECK_DSR_CTS
	BEQ.S   XMIT_CHAR              modem lines are up, goto transmit

	MOVE.L  #316,S_ERROR(A2)        CTS false error
	RTS                             side effect -- Z:=0
*
*   Wait (with timeout) for DSR and CTS
*
NOT_ISR         EQU *
	LEA     CHECK_DSR_CTS,A4        \  call WAIT with appropriate
	BSR     WAIT                    /  function parameter
	BEQ.S   XMIT_CHAR              no errors, goto transmit
	RTS                             (Z=0 still)
*
*   Send the character (in d3)
*
XMIT_CHAR      EQU *
	MOVE.B  D3,DATA(A1)             do actual transmit
	CLR.B   D7                      indicate no errors  (Z := 1)
	RTS
	page
*-----------------------------------------------------------------------------
*       WAIT
*          this function waits with timeout for a condition to happen,
*          if the condition does not happen within the timeout, then
*          S_ERROR(A2) is marked with the timeout error.
*       ON ENTRY:  A4.L  points to the routine which will determine if
*                        the condition is met.  This routine should have
*                        the following conditions:
*                          --uses at the most d7,d6
*                          --returns Z=1 if the condition is met
*                          --all routines should have similar timing
*       ON EXIT:   IF error is found
*                       THEN Z=0, S_ERROR indicates the error
*                       ELSE Z=1
*       USES    :  D4.L  --  timeout counter
*                  D7,D6 --  can be used by called routine (see above)
*-----------------------------------------------------------------------------

WAIT            EQU *
	JSR     (A4)                    check the condition
	BEQ.S   EXIT_WAIT               exit if condition met (Z=1)

	MOVE.L  TIMEOUT(A2),D4
	BEQ.S   WAIT_LOOP2              infinite timeout if value is 0.

	BTST    #TIMER_PRESENT,SYSFLAG2  SEE IF TIMER EXISTS     ttt JS 8/3/83
	BEQ.S   WAIT_TMR                 IF SO GO USE IT         ttt JS 8/3/83

	MOVE.L  D4,D7                   \
	LSL.L   #1,D7                    \   initialize counter
	LSL.L   #2,D4                     \     (multiply by 54)
	ADD.L   D7,D4                      |
	MOVE.L  D4,D7                     /
	LSL.L   #3,D4                    /
	ADD.L   D7,D4                   /

WAIT_LOOP       EQU *
	TST.L   S_ERROR(A2)          check for errors saved during wait
	BNE.S   EXIT_WAIT               exit (Z=0)
	JSR     (A4)                    check the condition
	BEQ.S   EXIT_WAIT               exit if conditon met (Z=1)

	SUBQ.L  #1,D4                   counter := counter - 1
	BPL.S   WAIT_LOOP

	MOVE.L  #TMO_ERR,S_ERROR(A2) save the timeout error (Z:=0)
	RTS

WAIT_LOOP2      EQU *                   wait loop for infinite timeout
	TST.L   S_ERROR(A2)          check for errors saved by ISRs
	BNE.S   EXIT_WAIT               exit (Z=0)
	JSR     (A4)
	BNE.S   WAIT_LOOP2

EXIT_WAIT       EQU *
	RTS

WAIT_TMR    EQU *
	MOVE.B  #1,-(SP)               SET UP TIMER RECORD  ttt JS 8/3/83
	MOVE.L  D4,-(SP)               D4 HAS MS TO WAIT    ttt JS 8/3/83
WAIT_TMR1   EQU *                                           ttt JS 8/3/83
	TST.L   S_ERROR(A2)            CHECK FOR ERRORS     ttt JS 8/3/83
	BNE.S   WAIT_TEXIT             BR IF ERROR          ttt JS 8/3/83
	JSR     (A4)                   CHECK CONDITION      ttt JS 8/3/83
	BEQ.S   WAIT_TEXIT              BR IF CONDITION MET  ttt JS 8/3/83
	PEA     (SP)                   POINT TO TIMER REC   ttt JS 8/3/83
	JSR     CHECK_TIMER            AND CHECK TIMER      ttt JS 8/3/83
	BPL     WAIT_TMR1              IF NO TIMEOUT BRANCH ttt JS 8/3/83
	ADDQ    #6,SP                  TIMEOUT, BUT GET ONE ttt JS 5/3/84
	MOVEQ   #20,D4                 MORE CHANCE WITH     ttt JS 5/3/84
	BRA     WAIT_LOOP              SHORT COUNT          ttt JS 5/3/84
WAIT_TEXIT  EQU *                                           ttt JS 8/3/83
	ADDQ    #6,SP                  CLEANUP STACK        ttt JS 8/3/83
	RTS                            AND DONE!            ttt JS 8/3/83
	page
******************************************************************************
*
*       CHECK_DSR_CTS, CHECK_QUEUE
*
*       FUNCTIONs to be used with WAIT, they all return Z=1 when the
*          condition is met.
*
*       USES:  the function is allowed to use only d6 and d7
*
******************************************************************************

*
*   condition:  queue is empty
*
CHECK_QUEUE     EQU *
	MOVE.W  Q_OUT(A2),D7            (12)
	CMP.W   Q_IN(A2),D7             (12)  Z=1 if empty
	EORI    #$04,CCR                (20)  invert the Z bit (Z=1 if full)
	RTS                             (----> 44 )

*
*   condition:  DSR=1 and CTS=1  (ok to send with modem handshake)
*
CHECK_DSR_CTS   EQU *
	MOVE.B  MODEM_STAT(A1),D7       (12)
	OR.B    D7,S_MODEM(A2)          (16)  save modem status for user
	NOT.B   D7                      ( 4)
	AND     #$30,D7                 ( 8)  if both DSR and CTS were true, Z=0
	NOP                             ( 4)
	RTS                             (----> 44 )

	TTL     RS232 DRIVERS -- queue utilities
	page
*****************************************************************************
*
*       Buffer routines
*
*****************************************************************************

*----------------------------------------------------------------------------
*       INIT_QUEUE
*          initializes the queue descriptor.
*----------------------------------------------------------------------------

INIT_QUEUE      EQU *
	MOVE.W  #BUFFER_SIZE,Q_SIZE(A2)         * initialize  queue_size
	CLR.W   Q_IN(A2)                        *  queue_in := 0
	CLR.W   Q_OUT(A2)                       *  queue_out := 0
	RTS

*-----------------------------------------------------------------------------
*       QUEUE_EMPTY
*          tells if queue is empty.
*          ON EXIT:  Z=empty (IF EMPTY THEN Z:=1 ELSE Z:=0)
*          USES   :  D7
*-----------------------------------------------------------------------------

QUEUE_EMPTY     EQU *
	MOVE.W  Q_OUT(A2),D7
	CMP.W   Q_IN(A2),D7             *  RETURN( queue_in = queue_out )
	RTS

*-----------------------------------------------------------------------------
*       QUEUE_FULL
*          tells if queue is full.
*          ON EXIT:  Z=full (IF FULL THEN Z:=1 ELSE Z:=0)
*          USES   :  D7
*-----------------------------------------------------------------------------

QUEUE_FULL      EQU *
	MOVE.W  Q_IN(A2),D7             *
	ADDQ.W  #1,D7                   *
	CMP.W   Q_OUT(A2),D7            *  queue_out = queue_in+1 ?
	BNE.S   CHECK_OR                *
	RTS                             *        ( YES so return with Z=1)
CHECK_OR        EQU *
	CMP.W   Q_SIZE(A2),D7           *  queue_in+1 = queue_size ?
	BEQ.S   CHECK_AND               *
	RTS                             *        ( NO  so return with Z=0)
CHECK_AND       EQU *
	MOVE.W  Q_OUT(A2),D7            *  queue_out = 0  ?
	RTS                             *        ( ANSWER is result of function )
	page
*-----------------------------------------------------------------------------
*       INQUEUE
*          puts a character in the queue
*          ON ENTRY:  d2.B - character to be put in the queue
*                     buffer NOT full !!
*          USES    :  a4.L - queue_addr
*                     d7.W - queue_in
*-----------------------------------------------------------------------------

INQUEUE         EQU *
	MOVE.W  Q_IN(A2),D7             *
	MOVE.B  D2,Q_BUFFER(A2,D7.W)    *  (queue_addr+queue_in)^ := char

	ADDQ.W  #1,D7                   *  queue_in := queue_in+1

	CMP.W   Q_SIZE(A2),D7           *
	BGE.S   RESET_IN                *  IF queue_in >= queue_size
	MOVE.W  D7,Q_IN(A2)             *
	RTS                             *
RESET_IN        EQU *                   *
	CLR.W   Q_IN(A2)                *    THEN queue_in := 0
	RTS                             *

*-----------------------------------------------------------------------------
*       OUTQUEUE
*          take the next character out of the queue
*          ON ENTRY:  buffer NOT full
*          ON EXIT :  d2.B - character from the queue
*          USES    :  a4.L - queue_addr
*                     d7.W - queue_in
*-----------------------------------------------------------------------------

OUTQUEUE         EQU *
	MOVE.W  Q_OUT(A2),D7            *
	MOVE.B  Q_BUFFER(A2,D7.W),D2    *  char := (queue_addr+queue_out)^

	ADDQ.W  #1,D7                   *  queue_out := queue_out+1

	CMP.W   Q_SIZE(A2),D7           **
	BGE.S   RESET_OUT               *  IF queue_out >= queue_size
	MOVE.W  D7,Q_OUT(A2)            *
	RTS                             *
RESET_OUT        EQU *                  *
	CLR.W   Q_OUT(A2)               *    THEN queue_out := 0
	RTS                             **
	page
*-----------------------------------------------------------------------------
*       QUEUE_SPACE
*          returns amount of space remaining in the queue
*          ON EXIT:  d3.W - contains the space remaining in the queue.
*-----------------------------------------------------------------------------

QUEUE_SPACE     EQU *
	MOVE.W  Q_OUT(A2),D3            *
	SUB.W   Q_IN(A2),D3             *  IF  queue_in >= queue_out
	BGT.S   OUT_GREATER             *

	SUBQ.W  #1,D3                   *  THEN queue_space :=
	ADD.W   Q_SIZE(A2),D3           *     queue_size + queue_out-queue_in - 1
	RTS
OUT_GREATER     EQU *
	SUBQ.W  #1,D3                   *  ELSE queue_space :=
	RTS                             *     queue_out-queue_in - 1
	END


@


55.1
log
@Automatic bump of revision number for PWS version 3.25A
@
text
@@


54.1
log
@Automatic bump of revision number for PWS version 3.24
@
text
@@


53.1
log
@Automatic bump of revision number for PWS version 3.24B
@
text
@@


52.1
log
@Automatic bump of revision number for PWS version 3.24A
@
text
@@


51.1
log
@Automatic bump of revision number for PWS version 3.24d
@
text
@@


50.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@@


49.1
log
@Automatic bump of revision number for PWS version 3.24b
@
text
@@


48.1
log
@Automatic bump of revision number for PWS version 3.24a
@
text
@@


47.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


46.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


45.1
log
@Automatic bump of revision number for PWS version 3.23C
@
text
@@


44.1
log
@Automatic bump of revision number for PWS version 3.23B
@
text
@@


43.1
log
@Automatic bump of revision number for PWS version 3.23aA
@
text
@@


42.1
log
@Automatic bump of revision number for PWS version 3.23e
@
text
@@


41.1
log
@Automatic bump of revision number for PWS version 3.23d
@
text
@@


40.2
log
@RS 232 timing fix.
@
text
@@


40.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@d51 3
a382 1
	MOVEQ   #70,D0          *  wait AT LEAST 25 us
d384 1
a384 1
* Count changed from 32 to 70 to allow for 16MHz processors JS 8/3/83
d386 2
a387 1
	DBRA    D0,*            *  ( not yet timed -- #32 was initial est.)
@


39.1
log
@Automatic bump of revision number for PWS version 3.23b
@
text
@@


38.1
log
@Automatic bump of revision number for PWS version 3.23a
@
text
@@


37.1
log
@Automatic bump of revision number for PWS version 3.3a
@
text
@@


36.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


35.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


34.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


33.1
log
@Automatic bump of revision number for PWS version 3.22D
@
text
@@


32.1
log
@Automatic bump of revision number for PWS version 3.22C
@
text
@@


31.1
log
@Automatic bump of revision number for PWS version 3.22B
@
text
@@


30.1
log
@Automatic bump of revision number for PWS version 3.22A
@
text
@@


29.1
log
@Automatic bump of revision number for PWS version 3.22b
@
text
@@


28.1
log
@Automatic bump of revision number for PWS version 3.3b
@
text
@@


27.1
log
@Automatic bump of revision number for PWS version 3.3a
@
text
@@


26.1
log
@Automatic bump of revision number for PWS version 3.3 Synch
@
text
@@


25.1
log
@Automatic bump of revision number for PWS version 3.2Y
@
text
@@


24.1
log
@Automatic bump of revision number for PWS version 3.2
@
text
@@


23.1
log
@Automatic bump of revision number for PWS version 3.2P
@
text
@@


22.1
log
@Automatic bump of revision number for PWS version 3.2N
@
text
@@


21.1
log
@Automatic bump of revision number for PWS version 3.2M
@
text
@@


20.1
log
@Automatic bump of revision number for PWS version 3.2L
@
text
@@


19.1
log
@Automatic bump of revision number for PWS version 3.2K
@
text
@@


18.1
log
@Automatic bump of revision number for PWS version 3.2J
@
text
@@


17.1
log
@Automatic bump of revision number for PWS version 3.2I+
@
text
@@


16.1
log
@Automatic bump of revision number for PWS version 3.2I
@
text
@@


15.1
log
@Automatic bump of revision number for PWS version 3.2H
@
text
@@


14.1
log
@Automatic bump of revision number for PWS version 3.2G
@
text
@@


13.1
log
@Automatic bump of revision number for PWS version 3.2F
@
text
@@


12.1
log
@Automatic bump of revision number for PWS version 3.2E
@
text
@@


11.1
log
@Automatic bump of revision number for PWS version 3.2D
@
text
@@


10.1
log
@Automatic bump of revision number for PWS version 3.2C
@
text
@@


9.1
log
@Automatic bump of revision number for PWS version 3.2B
@
text
@@


8.1
log
@Automatic bump of revision number for PWS version 3.2A
@
text
@@


7.1
log
@Automatic bump of revision number for PWS version 3.2l
@
text
@@


6.1
log
@Automatic bump of revision number for PWS version 3.2k
@
text
@@


5.1
log
@Automatic bump of revision number for PWS version 3.2j
@
text
@@


4.1
log
@Automatic bump of revision number for PWS version 3.2i
@
text
@@


3.1
log
@Automatic bump of revision number for PWS version 3.2h
@
text
@@


2.1
log
@Auto bump rev number to 2.1 for sys 3.2e.
@
text
@@


1.1
log
@Initial revision
@
text
@@
