;AM100L         Serial Port Interface Driver for the AM-100/L
;
;                                                               ASL-02017-00
;                                 NOTICE
;
;All  rights  reserved.  This software is the property of Alpha Microsystems
;and the material contained herein is the  proprietary  property  and  trade
;secrets  of  Alpha Microsystems, embodying substantial creative efforts and
;confidential information, ideas and expressions, no part of  which  may  be
;reproduced  or  transmitted  in  any  form  or  by  any  means, electronic,
;mechanical,  or  otherwise,  including  photocopying  or  input  into   any
;information  storage  or  retrieval  system  without  the  express  written
;permission of Alpha Microsystems.
;
;CAUTION: Unauthorized distribution or reproduction  of  this  material  may
;subject you to legal action.
;
;
;This interface driver supports the two serial ports contained on the
;AM-100/L CPU board.  Unlike the AM-100/T, both ports have full modem
;(and therefore printer) control.
;
;Ports are addressed in the TRMDEF statement as 0 and 1.
;
;Edit History:
;
;[102] 27 October 1982
;       Changed to turn off interrupts faster.
;[101] 22 April 1982
;       Make sure our size is even.
;[100] 9 April 1982
;       Fix baud rate terminal to reflect BR1941-05 baud rate generator
;       since that is what is used on the new rev. L and A boards.
;

       SEARCH  SYS
       SEARCH  SYSSYM
       SEARCH  TRM

       OBJNAM  AM100L.IDV

       PORT0 = ^H0FFFE20               ; I/O base for port 0
       PORT1 = ^H0FFFE24               ; I/O base for port 1
       PORTB = ^H0FFFE28               ; Baud rate generator port
       INTV0 = ^H068                   ; Interrupt vector for port 0
       INTV1 = ^H06C                   ; Interrupt vector for port 1

       FTDEBUG=0                       ; set to 1 for debug features

DEFINE  DEBUG ARG
       IF NE, FTDEBUG
           MOVB    #^H0'ARG,^H0FFFE00
       ENDC
ENDM

PAGE
;Define Miscellaneous Parameters and Constants
;
;Define 6850 Status Register Bits
;

ST$RDRF =   0                           ; 1 = Receive Data Register Full
ST$TDRE =   1                           ; 1 = Transmit Data Register Empty
ST$DCD  =   2                           ; 1 = DCD bar has gone high (no carrier)
ST$CTS  =   3                           ; 0 = CTS bar is low (OK to transmit)
ST$FE   =   4                           ; 1 = Framing Error
ST$OVRN =   5                           ; 1 = Overrun Error
ST$PE   =   6                           ; 1 = Parity Error
ST$IRQ  =   7                           ; 1 = Interrupt has been requested

;Define 6850 Command Register Bits
;

CM$RESET =   3                          ; Master Reset for ACIA
CM$16    =   1                          ; Clock is divide by 16
CM$1STP  =  24                          ; 8 data bits, 1 stop bit, no parity
CM$2STP  =  20                          ; 8 data bits, 2 stop bits, no parity
CM$TXD   =   0                          ; RTS bar low, transmitter disabled
CM$TXE   =  40                          ; RTS bar low, transmitter enabled
CM$BREAK = 140                          ; Force break
CM$RCE   = 200                          ; Receiver Enabled

;Define I/O Port Offsets
;
;These are defined as offset to the base of the serial port block (i.e., base
;of the board + 4).
;

P.SR =  0                               ; Status Register (Input)
P.CMD = 0                               ; Command Register (Output)
P.RCV = 2                               ; Receiver Holding Register (Input)
P.TXM = 2                               ; Tranmitter Holding Register (Output)

PAGE

;Driver Commumnications Area
;
;This is the standard branch table used by TRMDEF and TRMSER.  Only TRMDEF
;is allowed to call the initialization routine.
;

AM1:    BR      CHROUT                  ; character output routine
       BR      INIT                    ; initialization routine
       NOP

PAGE
;INIT           Initialize the AM-100/L Port
;
;This routine is called by TRMDEF each time a port on the AM-100/L is defined.
;The routine must intialize the proper port to the specified configuration,
;or, if the default is specified, it must set the 100/L up for async 19200 baud
;operation.
;
;Inputs:        D0      Specified baud rate code.
;               A5      Points to terminal definition block.
;
;Outputs:       Outputs to 100/L board only.
;
;Modifies:      D1, A3, A4; 100/L command register;
;

INIT:   LEA     A6,BAUDTB               ; index the baud rate table
       MOVB    0(A6)[D0],D0            ; is it valid?
       JMI     BDBAUD                  ;   no - invalid baud rate
       TST     T.IHM(A5)               ; are we selecting port 0?
       BEQ     10$                     ;   yes -
;Set up port 1 baud rate load, I/O port, and interrupt vector
       MOVB    #40,D2                  ;   no - select port 1 baud rate load
       MOV     #PORT1,A4               ;        and I/O port
       LEA     A3,INTR1                ; index port 1 interrupt routine
       MOV     A3,INTV1                ; store it
       BR      20$

;Set up port 0 baud rate load, I/O port, and interrupt vector
10$:    MOVB    #20,D2                  ; get port 0 select bit
       MOV     #PORT0,A4               ; index port 0
       LEA     A3,INTR0                ; index port 0 interrupt routine
       MOV     A3,INTV0                ; store it
;Send baud rate code to baud rate generator and reset ACIA
20$:    ORB     D0,D2                   ; combine selector code with baud rate
       MOVB    D2,PORTB                ; send to baud rate generator
       MOV     A4,T.IHW(A5)            ; store I/O addr terminal definition blk
       MOV     A5,OFF(A3)              ; store term def ptr in interrupt routine
       MOVB    #CM$RESET,@A4           ; reset the 6850 ACIA chip
;Set up the ACIA for 16X clock, correct # of stop bits, transmitter disabled,
;   and receiver enabled
       MOVB    #CM$16!CM$1STP!CM$TXD!CM$RCE,D2
       CMPB    D0,#2                   ; did we want 110 baud?
       BNE     30$                     ;   no -
       MOVB    #CM$16!CM$2STP!CM$TXD!CM$RCE,D2
30$:    MOVB    D2,@A4                  ; set up ACIA
       DEBUG   F0
       RTN

PAGE
;CHROUT         Output Character Initiation Routine
;
;Enable the 6850 transmitter which generates an initial interrupt which
;will be dispatched to the transmitter routine, starting the output
;process.  This routine is called by clock routine set up by TRMSER.
;
;Inputs:        A5      Pointer to terminal definition block
;
;Outputs:       None
;
;Modifies:      None
;

CHROUT: MOVB    #CM$16!CM$1STP!CM$TXD!CM$RCE!CM$TXE,D7
       CMPW    T.BAU(A5),#2            ; are we set to 110 baud?
       BNE     10$                     ;   no -
       MOVB    #CM$16!CM$2STP!CM$TXD!CM$RCE!CM$TXE,D7
10$:    MOV     T.IHW(A5),A6            ; set terminal definition index
       MOVB    D7,@A6                  ; enable transmitter
       DEBUG   F1
       RTN

PAGE
;INTRn          Define Serial Port Routines
;
;These routines contain code that is modified by the initialization routine.
;Called at interrupt level.
;
;Inputs:        None
;
;Outputs:       A5      Terminal definition block index
;
;Modifies:      A5

INTR0:  SVLOK                           ; turn off interrupts                   [102]
       SAVE    A0-A6,D0-D7             ; save registers
           OFF=.-INTR0+2               ; define offset for modifying code
       MOV     #7777,A5                ; set channel 0 terminal definition index
       BR      GINTRP

INTR1:  SVLOK                           ; turn off interrupts                   [102]
       SAVE    A0-A6,D0-D7             ; save registers
       MOV     #7777,A5                ; set channel 1 terminal definition index
;fall thru to GINTRP...

PAGE
;GINTRP         Handle Serial Port Interrupt
;
;Come here whenever we get a serial port interrupt.  Determine what type it
;is and dispatch to appropriate routine.  Called at interrupt level.
;
;Inputs:        A5      Terminal definition index
;               All registers SAVEd on stack
;
;Outputs:       D1      6850 Status Register
;               A4      Pointer to base of I/O ports
;
;Modifies:      D1, A4
;

GINTRP: MOV     T.IHW(A5),A4            ; get I/O register base into A4
       MOVB    @A4,D1                  ; read the 6850 status register
       BTST    #ST$RDRF,D1             ; check receiver data register full flag
       BNE     INPR                    ;   and go process if set
       BTST    #ST$TDRE,D1             ; check transmitter empty flag
       BNE     OUTPR                   ;   and go process if set
       BR      INFI                    ; handle false interrupt

;INPR           Input Character Interrupt Routine
;
;Come here whenever we get a receiver interrupt.  Read the character from
;the AM-100/L and pass on to TRMSER.
;
;Inputs:        A4      I/O register base
;               All registers SAVEd on stack
;
;Outputs:       None
;
;Modifies:      Restores registers
;

INPR:   DEBUG   F2
       MOVB    P.RCV(A4),D1            ; read the data character
       TRMICP                          ; go process the character
INTX:   REST    A0-A6,D0-D7             ; restore registers
       RTE

PAGE
;INFI           False Interrupt Routine
;
;Come here when interrupt was caused by neither transmitter or receiver.
;The interrupt is either DCD change or spurious.  In either case, we just
;ignore the interrupt.
;
;Inputs:        D1      6850 Status Register
;               A4      I/O register base address
;               All registers SAVEd on stack
;
;Outputs:       None
;
;Modifies:      Restores registers
;

INFI:   DEBUG   F3
       REST    A0-A6,D0-D7             ; restore register
       RTE                             ; return

PAGE
;OUTPR          Transmitter Interrupt Routine
;
;Come here on a transmitter interrupt.  If another character is available
;for output, grab it and send it to the 6850.
;Otherwise, clear the OIP flag and dismiss interrupt.
;
;Inputs:        D1      6850 Status Register
;               A4      I/O register base address
;               A5      Terminal definition index
;               All registers SAVEd on the stack
;
;Outputs:       Only to AM-100/L
;
;Modifies:      Registers restored
;

OUTPR:  DEBUG   F4
       TRMOCP                          ; get next output character from TRMSER
       TST     D1                      ; data available?
       BPL     OPRG                    ;   yes -
       ANDW    #^C<OIP>,@A5            ;   no - clear the OIP flag
       MOVB    #CM$16!CM$1STP!CM$TXD!CM$RCE,D7
       CMPW    T.BAU(A5),#2            ; is terminal set for 110 baud?
       BNE     10$                     ;   no -
       MOVB    #CM$16!CM$2STP!CM$TXD!CM$RCE,D7
10$:    MOVB    D7,@A4                  ; set mode bits
OPRD:   BR      INTX                    ; return

;Send character to transmitter
OPRG:   MOVB    D1,P.TXM(A4)            ; send character to 6850
       BR      INTX                    ; return

PAGE
;Come here if an invalid baud rate was specified
BDBAUD: TYPECR  <?Invalid baud rate for specified interface>
       RTN                             ; just ignore initialization

;Define baud rate table

BAUDTB: BYTE    0                       ; 50 baud
       BYTE    1                       ; 75 baud
       BYTE    2                       ; 110 baud
       BYTE    3                       ; 134.5 baud
       BYTE    4                       ; 150 baud
       BYTE    -1                      ; 200 baud (not valid on 1941-05)       [100]
       BYTE    5                       ; 300 baud
       BYTE    6                       ; 600 baud
       BYTE    7                       ; 1200 baud
       BYTE    10                      ; 1800 baud
       BYTE    11                      ; 2000 baud                             [100]
       BYTE    12                      ; 2400 baud
       BYTE    13                      ; 3600 baud
       BYTE    14                      ; 4800 baud
       BYTE    15                      ; 7200 baud
       BYTE    16                      ; 9600 baud
       BYTE    17                      ; 19200 baud

       EVEN

       END