*****************************************************
*   UART Programming Example Using Interrupts       *
*         and the Control Character Table.          *
*                                                   *
* This code is derived from the UART sample code    *
* on page 7-170 of the 68360 UM but uses 4 transmit *
* and 4 receive BDs along with an interrupt driven  *
* receive routine and an entry in the control char. *
* table.                                            *
*****************************************************
* 1) The code sets up SCC4 in UART mode                 *
* 2) It sets up 4 transmit buffer descriptors that      *
* that will send data when the transmitter is enabled.  *
* 3) It sets up 4 receive buffer descriptors to receive *
* the incoming data                                     *
* 4) It sets up the vectors to the interrupt handling   *
* routines                                              *
* 5) Finally, it turns on the transmitter and receiver  *
* in local loopback mode                                *
*                                    JS 7/13/94         *
*********************************************************
* If you wish to move this code so that it works on     *
* another SCC, there are quite a few things that need to*
* be done.                                              *
*       1) Change the names of all of the SCC equates   *
*       2) Change the SCC4PB equate to SCCx and set it  *
*          to the correct offset (see page 3-4)         *
*       3) Change the equate for the SCC Vector         *
*       4) Change the port pin setup instructions so    *
*          that they activate the correct pins          *
*       5) Change the SICR register so that the correct *
*          SCC gets clocking                            *
*       6) Change the INIT RX&TX PARAMETERS command so  *
*          that it refers to the correct SCC (p. 7-7)   *
*       7) Change the CIMR setup so that the new SCC    *
*          can generate interrupts                      *
*       8) Change the CISR clearing in the interrupt    *
*          service routine so that it clears the bit    *
*          corresponding to the new SCC                 *
***********************************************************************
*
* Board Specific Equates
INIT    EQU     $0403000        ; QUADS Board DRAM User Space

************************** DUAL PORT RAM ******************************
MBAR    EQU     $03FF00 ; Module Base Address, (MBAR)=REGB
*
***********************************************************************
* The following equates assume that they will be used in register
* indirect addressing.  The address register  should hold the base
* address of the QUICC internal memory.  All system equates are
* offsets into this memory
REGB    EQU     $1000   ; Base address of Internal Registers
SCC4PB  EQU     $0F00   ; SCC4 Protocol Base address

************************ SIM Module registers **************************
MCR     EQU     REGB+$0000      ; Module Configuration
*
************************ CPM Module registers *******************
*
*** SDMA
SDSR    EQU     REGB+$051C      ; SDMA Status
SDCR    EQU     REGB+$051E      ; SDMA Configuration Register
SDAR    EQU     REGB+$0520      ; SDMA Address Register
*** CP Interrupt
CICR    EQU     REGB+$0540      ; CP Interrupt Configuration
CIPR    EQU     REGB+$0544      ; CP Interrupt Pending
CIMR    EQU     REGB+$0548      ; CP Interrupt Mask
CISR    EQU     REGB+$054C      ; CP Interrupt In-service
*** Port A, B, C
PADIR   EQU     REGB+$0550      ; Port A Data Direction Assignment
PAPAR   EQU     REGB+$0552      ; Port A Pin Function Assignment
PAODR   EQU     REGB+$0554      ; Port A Open Drain Assignment
PADAT   EQU     REGB+$0556      ; Port A Data Content
*
PBDIR   EQU     REGB+$06B8      ; Port B Data Direction Assignment
PBPAR   EQU     REGB+$06BC      ; Port B Pin Function Assignment
PBODR   EQU     REGB+$06C0      ; Port B Open Drain Assignment
PBDAT   EQU     REGB+$06C4      ; Port B Data Content
*
PCDIR   EQU     REGB+$0560      ; Port C Data Direction Assignment
PCPAR   EQU     REGB+$0562      ; Port C Pin Assignment
PCSO    EQU     REGB+$0564      ; Port C Special Options
PCDAT   EQU     REGB+$0566      ; Port C Data Content
PCINT   EQU     REGB+$0568      ; Port C Interrupt Control
*** CP
CR      EQU     REGB+$05C0      ; CP Command
RCCR    EQU     REGB+$05C4      ; RISC Configuration
RTER    EQU     REGB+$05D6      ; RISC Timer Event Register
RTMR    EQU     REGB+$05DA      ; RISC Timer Mask Register
* BRG 1, 2, 3, 4
BRGC1   EQU     REGB+$05F0      ; BRG1 Configuration
BRGC2   EQU     REGB+$05F4      ; BRG2 Configuration
BRGC3   EQU     REGB+$05F8      ; BRG3 Configuration
BRGC4   EQU     REGB+$05FC      ; BRG4 Configuration
*** SCC 1, 2, 3, 4
* SCC4
GSMR_L4 EQU     REGB+$0660      ; SCC4 General Mode
GSMR_H4 EQU     REGB+$0664      ; SCC4 General Mode
PSMR4   EQU     REGB+$0668      ; SCC4 Protocol Specific Mode
TODR4   EQU     REGB+$066C      ; SCC4 Transmit On Demand
DSR4    EQU     REGB+$066E      ; SCC4 Data Sync
SCCE4   EQU     REGB+$0670      ; SCC4 Event
SCCM4   EQU     REGB+$0674      ; SCC4 Mask
SCCS4   EQU     REGB+$0677      ; SCC4 Status
*** Serial Interface
SIMODE  EQU     REGB+$06E0      ; SI Mode
SIGMR   EQU     REGB+$06E4      ; SI Global Mode
SISTR   EQU     REGB+$06E6      ; SI Status
SICMR   EQU     REGB+$06E7      ; SI Command
SICR    EQU     REGB+$06EC      ; SI Clock Routing
SIRP    EQU     REGB+$06F0      ; SI RAM Pointer
SIRAM   EQU     REGB+$0700      ; SI Routing RAM

************************ END of SIM/CPM Register MAP *******************

************************ SCC Parameters ********************************
****** SCC4
RBASE4  EQU     SCC4PB+$000     ; SCC4 RX BD Base Address
TBASE4  EQU     SCC4PB+$002     ; SCC4 TX BD Base Address
RFCR4   EQU     SCC4PB+$004     ; SCC4 RX Function Code
TFCR4   EQU     SCC4PB+$005     ; SCC4 TX Function Code
MRBLR4  EQU     SCC4PB+$006     ; SCC4 MAX Buffer Length - RX
RSTATE4 EQU     SCC4PB+$008     ; SCC4 RX Internal State
RBPRT4  EQU     SCC4PB+$010     ; SCC4 RX BD Pointer
TSTATE4 EQU     SCC4PB+$018     ; SCC4 TX Internal State
TBPRT4  EQU     SCC4PB+$020     ; SCC4 TX BD Pointer
RCRC4   EQU     SCC4PB+$028     ; SCC4 Temp Receive CRC
TCRC4   EQU     SCC4PB+$02C     ; SCC4 Temp Transmit CRC
CRC_C4  EQU     SCC4PB+$030     ; SCC4 CRC Constant Total-Transparent
CRC_P4  EQU     SCC4PB+$034     ; SCC4 CRC Preset Total-Transparent

************************** Specific Parameters ******************************

* SCC4, UART Specific Parameters
MAXIDL4 EQU     SCC4PB+$38      ; SCC4 MAX IDLe cchars
IDLC4   EQU     SCC4PB+$3A      ; SCC4 temp IDLe Counter
BRKCR4  EQU     SCC4PB+$3C      ; SCC4 BReaK Count Register (TX)
PAREC4  EQU     SCC4PB+$3E      ; SCC4 Parity Error Counter (RX)
FRMER4  EQU     SCC4PB+$40      ; SCC4 Framing Error Counter (RX)
NOSEC4  EQU     SCC4PB+$42      ; SCC4 Noise Counter (RX)
BRKEC4  EQU     SCC4PB+$44      ; SCC4 BReaK Condition Counter (RX)
BRKLN4  EQU     SCC4PB+$46      ; SCC4 Last BReaK Length (RX)
UADDR14 EQU     SCC4PB+$48      ; SCC4 UART Address Character 1
UADDR24 EQU     SCC4PB+$4A      ; SCC4 UART Address Character 2
RETMP4  EQU     SCC4PB+$4C      ; SCC4 Temp storage
TOSEQ4  EQU     SCC4PB+$4E      ; SCC4 TX out of sequence Character
CCHAR14 EQU     SCC4PB+$50      ; SCC4 Control Character 1
CCHAR24 EQU     SCC4PB+$52      ; SCC4 Control Character 2
CCHAR34 EQU     SCC4PB+$54      ; SCC4 Control Character 3
CCHAR44 EQU     SCC4PB+$56      ; SCC4 Control Character 4
CCHAR54 EQU     SCC4PB+$58      ; SCC4 Control Character 5
CCHAR64 EQU     SCC4PB+$5A      ; SCC4 Control Character 6
CCHAR74 EQU     SCC4PB+$5C      ; SCC4 Control Character 7
CCHAR84 EQU     SCC4PB+$5E      ; SCC4 Control Character 8
RCCM4   EQU     SCC4PB+$60      ; SCC4 RX Control Character Mask
RCCR4   EQU     SCC4PB+$62      ; SCC4 RX Control Character
RLBC4   EQU     SCC4PB+$64      ; SCC4 RX Last Break Character

* Program Specific Equates
MBUFS   EQU     $0010           ; Max Buffer Size = 16 bytes
SCC4VEC EQU     $1b             ; Vector for SCC4 (5 bits)
*********
* Start of Program
*********

        ORG     INIT

*** Get Pointer to Base of DPRAM
        move.l  #7,d0           ; "0111" is the function code for CPU Space
        movec   d0,SFC          ; Store "0111" into both the Src Fcn Code Reg
        movec   d0,DFC          ; and the Dest. Fcn Code Reg
        moves.l MBAR,a0         ; Move MBAR into a0
        move.l  a0,d0
        andi.l  #$ffffe000,d0   ; Extract the base address from MBAR
        move.l  d0,a5           ; Move it to a5 for register indexing

*** Set up SDMA Control Register for SCCs
        move.w  #$0740,SDCR(a5) ; SDMA interrupt service mask = 7,
*                               ;  bus arbit. priority = 4

*** Set up Port A Pins
* to get PA6&7 to be Rxd4 & Txd4, we set PAPAR, PADIR, and PAODR as in
* Table 7-16 on page 7-351.
        or.w    #$00c0,PAPAR(a5)        ; bits 6&7 must be 1
        and.w   #$FF7F,PAODR(a5)        ; bit 7 must be zero
        and.w   #$FF3F,PADIR(a5)        ; bits 6&7 must be 0


*** Set up Port C pins
* to get PC10&PC11 to be CTS4 and CD4 and PC3 to be RTS4,
* we set PCPAR, PCDIR, and PCODR as in Table 7-18 on page 7-358.
        and.w   #$F3FF,PCPAR(a5)        ; bits 10&11 must = 0
        or.w    #$0008,PCPAR(a5)        ; ad bit 3 must =1         
        and.w   #$F3F7,PCDIR(a5)        ; bits 3, 10, & 11 must be = 0
        or.w    #$0C00,PCSO(a5)         ; bits 10&11 must = 1
*                                       ; bit 3 is a don't care  



*** Set up BRG1 for SCC4
        move.l  #$010144,BRGC1(a5)      ; set brg1 to baud rate 9600bits/s
*                                       ; CD=$A2, EN=1, DIV16=0
*                                       ; 25Mhz/($A2+1)=153374=~9,585 * 16
*                                       ; and GSMR selects 16x clock
        move.l  #$00000000,SICR(a5)     ; route brg1 to scc4 and select nmsi

*** Set up General SCC Parameters
        move.w  #$0000,RBASE4(a5)       ; Receive BDs start at 0(a5)
        move.w  #$0020,TBASE4(a5)       ; Transmit BDs start at 32(a5) 
        move.b  #$18,RFCR4(a5)  ; mot=1(msbyte first), rx function code = 1000
        move.b  #$18,TFCR4(a5)  ; mot=1(msbyte first), tx function code = 1000
        move.w  #MBUFS,MRBLR4(a5)       ; max. bytes per Buffer (16)

*** Execute the INIT RX & TX Parameters for SCC4
        move.w  #$00c1,CR(a5)   ; initialize transmit and receive parameter
*                               ; in the parameter ram of scc4


*** Set up UART Specific Parameters
        move.w  #$0005,MAXIDL4(a5)      ; set idle timeout to a value
        move.w  #$0001,BRKCR4(a5)       ; stop trans issues 1 break chara.
        move.w  #$0,PAREC4(a5)          ; clear error counters
        move.w  #$0,FRMER4(a5)
        move.w  #$0,NOSEC4(a5)
        move.w  #$0,BRKEC4(a5)
        move.w  #$0,UADDR14(a5)         ; no multidrop address
        move.w  #$0,UADDR24(a5)
        move.w  #$0,TOSEQ4(a5)          ; No CTRL Char to be sent
        move.w  #$000D,CCHAR14(a5)      ; CR will close buffer
        move.w  #$8000,CCHAR24(a5)      ; No more control Characters
        move.w  #$c0ff,RCCM4(a5)        ; No masking of received Ctl Chars

*** Set up the Receive BDs 
* (set the ready bit after the Buffer pointer is set up)
        move.l  a5,a0
        add.w   RBASE4(a5),a0           ; make pointer to Receive BDs
* BD1
        clr.w   2(a0)                   ; initialize length
        move.l  #RXBUF+0*MBUFS,4(a0)    ; pointer to buffer number 0
        move.w  #$9000,(a0)             ; empty, nowrap, int
* BD2
        clr.w   10(a0)                  ; initialize length
        move.l  #RXBUF+1*MBUFS,12(a0)   ; pointer to buffer number 1
        move.w  #$9000,8(a0)            ; empty, nowrap, int
* BD3
        clr.w   18(a0)                  ; initialize length
        move.l  #RXBUF+2*MBUFS,20(a0)   ; pointer to buffer number 2
        move.w  #$9000,16(a0)           ; empty, nowrap, int
* BD4
        clr.w   26(a0)                  ; initialize length
        move.l  #RXBUF+3*MBUFS,28(a0)   ; pointer to buffer number 3
        move.w  #$b000,24(a0)           ; empty, wrap, int

*** Set up Process Receive Data Pointer (part of interrupt service routine)
        move.w  RBASE4(a5),PRDPTR       ; PRDPTR points to BD#1


*** Set up Transmit BDs
* (set the ready bit after the Buffer pointer & length is set up)
        movea.l a5,a0                   ; get pointer to base of DPRAM
        adda.w  TBASE4(a5),a0           ; make pointer to Transmit BDs
* BD1
        move.w  #13,2(a0)               ; length 13
        move.l  #TBUF0,4(a0)            ; pointer to buffer #0
        move.w  #$8800,(a0)             ; ready, nowrap, noint, Normal CTS
* BD2
        move.w  #13,10(a0)              ; length 13
        move.l  #TBUF1,12(a0)           ; pointer to buffer #1
        move.w  #$8800,8(a0)            ; ready, nowrap, noint, normal CTS
* BD3
        move.w  #13,18(a0)              ; length 13
        move.l  #TBUF2,20(a0)           ; pointer to buffer #2
        move.w  #$8800,16(a0)           ; ready, nowrap, noint, normal CTS
* BD4
        move.w  #13,26(a0)              ; length 13
        move.l  #TBUF3,28(a0)           ; pointer to buffer #3
        move.w  #$a800,24(a0)           ; ready, nowrap, noint, normal CTS



*** Set up Vector Table, Configure SCC4 to be SCCa.
* 
* Set up CICR. (In most situations, the VBA2-0 bits and the IRL2-0 bits
* would be set by the kernal and the SCC Priority bits would be set
* by the SCC control program ("user code")).  The QUADS boot rom
* does not set up this register so this code will do both in separate
* steps.

* kernel step
        move.l  #$00008040,CICR(a5)     ; Int Level=4, Vec Base=2
*                                       ; *note* VEC BASE Must Be >=2

* user steps
        move.l  CICR(a5),d0             ; get CICR
        andi.l  #$0000e0e0,d0           ; mask out all but IRL & VBA
        clr.l   d1
        move.b  d0,d1                   ; store copy of VBA
        ori.l   #$00931f00,d0           ; Priority=4,1,2,3; Std HP
*                                       ; Grouped SCCs
        move.l  d0,CICR(a5)                     

* now calculate the Vector Table Location for SCCa Exception Vector
        ori.b   #SCC4VEC,d1             ; concatenate VBA with Vec Num
        asl.l   #2,d1                   ; create offset into vector table
        movec.l VBR,a4                  ; get Vector Base Register
        move.l  #SCC4INT,0(a4,d1)       ; put address of service routine
*                                       ; into vector table     



*** Final Set up
        move.w  #$ffff,SCCE4(a5)        ; clear scc4 event register
        move.w  #$0001,SCCM4(a5)        ; enable rx interrupts
        or.l  #$08000000,CIMR(a5)       ; Allow SCC4 interrupts
        andi.w  #$f8ff,SR               ; Set CPU IMASK to 0
        
        move.l  #$00000060,GSMR_H4(a5)  ; rx fifo set to 4 bytes
*                                       ; tx FIFO is 1 byte
        move.l  #$00028044,GSMR_L4(a5)  ; tdcr ='10', txclk is 16* clock mode
*                               ; rdcr ='10', rxclk is 16* clock mode
*                               ; local loopback mode
*                               ; channel protocol mode = uart
        move.w  #$b000,PSMR4(a5)        ; set automatic flow control
*                               ; character length set to 8 bits

        ori.l   #$00000030,GSMR_L4(a5)  ; enable transmitter and receiver

self    bra     self                    ; loop forever

*** When this code is "done", all four TX Buffers will have been sent (and
*thus the Ready Bit in each BD will be clear).  The Rx Routine will "service"
*each Rx BD when the RXB event bit is set in the Event Register.
*The TXB bit does not generate an interrupt but will be set each time the
*TX Buffer is sent.
*The received data will appear in the RX Buffers, but they will not 
*correspond to the sending TX buffers because there is no framing 
*structure in UART.  However, the control character settings tell
*the receiver to close a buffer when the $D is received and thus
*the fourth TX buffer will fill a separate BD from the first 3. 

**** SCC4 Interrupt Routine
* The framework for this routine can be found on page D-12 of the 68302 UM
* It has been changed to accomodate CM mode.  The condition for stopping
* is no longer the E bit set (because in CM mode, the E bit is ALWAYS set)
* The BD processing now stops when PRDPTR=RBPRT4.  ***Note that RBPRT4 is
* now an offset into DPRAM rather than the BD number (1..8)

SCC4INT movem.l d0-d2/a0-a2,-(a7)       ; save context registers
        move.w  SCCE4(a5),-(a7) ; temporarily store SCC event 
*                               ; register on stack
        move.w  #$ffff,SCCE4(a5)        ; Clear all SCC events 
        move.w  (a7),d2         ; get a copy of the register
        andi.w  #1,d2           ; is RX set?
        beq     INT1
        bsr     REC_BD          ;   if so, process the BD
INT1    move.l  #$08000000,CISR(a5)     ; clear SCC4 bit in ISR 
        move.w  (a7)+,d2        ; remove SCCE4 from stack
        movem.l (a7)+,d0-d2/a0-a2       ; Restore Context
        rte

REC_BD  move.w  PRDPTR,d0       ; put PRDPTR into d0
        move.l  a5,a0
        add.w   d0,a0           ; a0 is absolute pointer to unprocessed BD
        move.w  (a0),d0         ; get copy of BD status word
        andi.w  #$001f,d0       ; save error indicators
        bne     ERR_HAND        ; branch to error handler if errors
*
** Process the received data here
*
        clr.w   2(a0)           ; Clear the length word
        andi.w  #$f200,(a0)     ; clear status bits
        bset.b  #7,(a0)         ; Set the Empty Bit
        btst.b  #5,(a0)         ; Is the wrap bit set?
        bne     WRAP_R          ;  if so, point PRD to RBASE
        addq.w  #$8,PRDPTR      ; else increment PRDPTR to next BD
        bra     CHKMOR          ; and check the next BD
WRAP_R  move.w  RBASE4(a5),PRDPTR       
CHKMOR  move.w  PRDPTR,d0       
        cmp.w   RBPRT4(a5),d0   ; if PRDPTR=RBPRT4
        bne     REC_BD
        rts                     ; done servicing RXB/RXF
        
        
*** Error Handler Ignores Receive Errors
ERR_HAND        rts


**** demo data
                ORG INIT+$2000
                
RXBUF:  ds.b    MBUFS*4                 ; reserve space for 4 buffers


*put data in send buffers
TBUF0:  dc.b    'Buffer 1 data'
TBUF1:  dc.b    'Buffer 2 data'
TBUF2:  dc.b    'Buf3 plus CR',$0d      ; CR in data will close Receive BD 
TBUF3:  dc.b    'Buffer 4 data'          
                                          
PRDPTR: ds.w    1                       ; pointer to next Receive BD to
*                                       ; process

        END



