Search
lxdream.org :: lxdream/src/sh4/scif.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/scif.c
changeset 828:b42865f00fb5
prev736:a02d1475ccfd
next929:fd8cb0c82f5f
author nkeynes
date Thu Dec 11 23:26:03 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Disable the generational translation cache - I've got no evidence that it
actually helps performance, and it simplifies things to get rid of it (in
particular, translated code doesn't have to worry about being moved now).
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * SCIF (Serial Communication Interface with FIFO) implementation - part of the 
     4  * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs
     5  * external serial port
     6  *
     7  * Copyright (c) 2005 Nathan Keynes.
     8  *
     9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  */
    20 #include <glib.h>
    21 #include "dream.h"
    22 #include "mem.h"
    23 #include "sh4/sh4core.h"
    24 #include "sh4/sh4mmio.h"
    25 #include "sh4/intc.h"
    26 #include "sh4/dmac.h"
    27 #include "clock.h"
    28 #include "serial.h"
    30 void SCIF_set_break(void);
    32 /************************* External serial interface ************************/
    34 /**
    35  * Note: serial_* operations are called from outside the SH4, and as such are
    36  * named relative to the external serial device. SCIF_* operations are only
    37  * called internally to the SH4 and so are named relative to the CPU.
    38  */
    40 /**
    41  * Storage space for inbound/outbound data blocks. It's a little more
    42  * convenient for serial consumers to be able to deal with block-sized pieces
    43  * rather than a byte at a time, even if it makes all this look rather
    44  * complicated.
    45  *
    46  * Currently there's no limit on the number of blocks that can be queued up.
    47  */
    48 typedef struct serial_data_block {
    49     uint32_t length;
    50     uint32_t offset;
    51     struct serial_data_block *next;
    52     char data[];
    53 } *serial_data_block_t;
    55 serial_data_block_t serial_recvq_head = NULL, serial_recvq_tail = NULL;
    56 serial_device_t serial_device = NULL;
    58 void serial_attach_device( serial_device_t dev ) 
    59 {
    60     if( serial_device != NULL )
    61         serial_detach_device();
    62     serial_device = dev;
    63 }
    66 void serial_detach_device( void )
    67 {
    68     serial_device = NULL;
    69 }
    71 /**
    72  * Add a block of data to the serial receive queue. The data will be received
    73  * by the CPU at the appropriate baud rate.
    74  */
    75 void serial_transmit_data( char *data, int length ) {
    76     if( length == 0 )
    77         return;
    78     serial_data_block_t block = 
    79         g_malloc( sizeof( struct serial_data_block ) + length );
    80     block->length = length;
    81     block->offset = 0;
    82     block->next = NULL;
    83     memcpy( block->data, data, length );
    85     if( serial_recvq_head == NULL ) {
    86         serial_recvq_head = serial_recvq_tail = block;
    87     } else {
    88         serial_recvq_tail->next = block;
    89         serial_recvq_tail = block;
    90     }
    91 }
    93 /**
    94  * Dequeue a byte from the serial input queue
    95  */
    96 static int serial_transmit_dequeue( ) {
    97     if( serial_recvq_head != NULL ) {
    98         uint8_t val = serial_recvq_head->data[serial_recvq_head->offset++];
    99         if( serial_recvq_head->offset >= serial_recvq_head->length ) {
   100             serial_data_block_t next = serial_recvq_head->next;
   101             g_free( serial_recvq_head );
   102             serial_recvq_head = next;
   103             if( next == NULL )
   104                 serial_recvq_tail = NULL;
   105         }
   106         return (int)(unsigned int)val;
   107     }
   108     return -1;
   110 }
   112 void serial_transmit_break() {
   113     SCIF_set_break();
   114 }
   116 /********************************* SCIF *************************************/
   118 #define FIFO_LENGTH 16
   119 #define FIFO_ARR_LENGTH (FIFO_LENGTH+1)
   121 /* Serial control register flags */
   122 #define SCSCR2_TIE  0x80
   123 #define SCSCR2_RIE  0x40
   124 #define SCSCR2_TE   0x20
   125 #define SCSCR2_RE   0x10
   126 #define SCSCR2_REIE 0x08
   127 #define SCSCR2_CKE 0x02
   129 #define IS_TRANSMIT_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TIE)
   130 #define IS_RECEIVE_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RIE)
   131 #define IS_RECEIVE_ERROR_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & (SCSCR2_RIE|SCSCR2_REIE))
   132 /* Receive is enabled if the RE bit is set in SCSCR2, and the ORER bit is cleared in SCLSR2 */
   133 #define IS_RECEIVE_ENABLED() ( (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RE) && ((MMIO_READ(SCIF,SCLSR2) & SCLSR2_ORER) == 0) )
   134 /* Transmit is enabled if the TE bit is set in SCSCR2 */
   135 #define IS_TRANSMIT_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TE)
   136 #define IS_LOOPBACK_ENABLED() (MMIO_READ(SCIF,SCFCR2) & SCFCR2_LOOP)
   138 /* Serial status register flags */
   139 #define SCFSR2_ER   0x80
   140 #define SCFSR2_TEND 0x40
   141 #define SCFSR2_TDFE 0x20
   142 #define SCFSR2_BRK  0x10
   143 #define SCFSR2_RDF  0x02
   144 #define SCFSR2_DR   0x01
   146 /* FIFO control register flags */
   147 #define SCFCR2_MCE   0x08
   148 #define SCFCR2_TFRST 0x04
   149 #define SCFCR2_RFRST 0x02
   150 #define SCFCR2_LOOP  0x01
   152 /* Line Status Register */
   153 #define SCLSR2_ORER 0x01
   155 struct SCIF_fifo {
   156     int head;
   157     int tail;
   158     int trigger;
   159     uint8_t data[FIFO_ARR_LENGTH];
   160 };
   162 int SCIF_recvq_triggers[4] = {1, 4, 8, 14};
   163 struct SCIF_fifo SCIF_recvq = {0,0,1};
   165 int SCIF_sendq_triggers[4] = {8, 4, 2, 1};
   166 struct SCIF_fifo SCIF_sendq = {0,0,8};
   168 /**
   169  * Flag to indicate if data was received (ie added to the receive queue)
   170  * during the last SCIF clock tick. Used to determine when to set the DR
   171  * flag.
   172  */
   173 gboolean SCIF_rcvd_last_tick = FALSE;
   175 uint32_t SCIF_tick_period = 0;
   176 uint32_t SCIF_tick_remainder = 0;
   178 void SCIF_save_state( FILE *f ) 
   179 {
   180     fwrite( &SCIF_recvq, sizeof(SCIF_recvq), 1, f );
   181     fwrite( &SCIF_sendq, sizeof(SCIF_sendq), 1, f );
   182     fwrite( &SCIF_rcvd_last_tick, sizeof(gboolean), 1, f );
   184 }
   186 int SCIF_load_state( FILE *f ) 
   187 {
   188     fread( &SCIF_recvq, sizeof(SCIF_recvq), 1, f );
   189     fread( &SCIF_sendq, sizeof(SCIF_sendq), 1, f );
   190     fread( &SCIF_rcvd_last_tick, sizeof(gboolean), 1, f );
   191     return 0;
   192 }
   194 static inline uint8_t SCIF_recvq_size( ) 
   195 {
   196     int val = SCIF_recvq.tail - SCIF_recvq.head;
   197     if( val < 0 ) {
   198         val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;
   199     }
   200     return val;
   201 }
   203 int SCIF_recvq_dequeue( gboolean clearFlags )
   204 {
   205     uint8_t result;
   206     uint32_t tmp, length;
   207     if( SCIF_recvq.head == SCIF_recvq.tail )
   208         return -1; /* No data */
   209     result = SCIF_recvq.data[SCIF_recvq.head++];
   210     if( SCIF_recvq.head > FIFO_LENGTH )
   211         SCIF_recvq.head = 0;
   213     /* Update data count register */
   214     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
   215     length = SCIF_recvq_size();
   216     MMIO_WRITE( SCIF, SCFDR2, tmp | length );
   218     /* Clear flags (if requested ) */
   219     if( clearFlags && length < SCIF_recvq.trigger ) {
   220         tmp = SCFSR2_RDF;
   221         if( length == 0 )
   222             tmp |= SCFSR2_DR;
   223         tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
   224         MMIO_WRITE( SCIF, SCFSR2, tmp );
   225         /* If both flags are cleared, clear the interrupt as well */
   226         if( (tmp & (SCFSR2_DR|SCFSR2_RDF)) == 0 && IS_RECEIVE_IRQ_ENABLED() )
   227             intc_clear_interrupt( INT_SCIF_RXI );
   228     }
   230     return (int)(unsigned int)result;
   231 }
   233 gboolean SCIF_recvq_enqueue( uint8_t value )
   234 {
   235     uint32_t tmp, length;
   236     int newpos = SCIF_recvq.tail + 1;
   237     if( newpos > FIFO_LENGTH )
   238         newpos = 0;
   239     if( newpos == SCIF_recvq.head ) {
   240         /* FIFO full - set ORER and discard the value */
   241         MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );
   242         if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
   243             intc_raise_interrupt( INT_SCIF_ERI );
   244         return FALSE;
   245     }
   246     SCIF_recvq.data[SCIF_recvq.tail] = value;
   248     /* Update data count register */
   249     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
   250     length = SCIF_recvq_size();
   251     MMIO_WRITE( SCIF, SCFDR2, tmp | length );
   253     /* Update status register */
   254     tmp = MMIO_READ( SCIF, SCFSR2 );
   255     if( length >= SCIF_recvq.trigger ) {
   256         tmp |= SCFSR2_RDF;
   257         if( IS_RECEIVE_IRQ_ENABLED() ) 
   258             intc_raise_interrupt( INT_SCIF_RXI );
   259         DMAC_trigger( DMAC_SCIF_RDF );
   260     }
   261     MMIO_WRITE( SCIF, SCFSR2, tmp );
   262     return TRUE;
   263 }
   266 /**
   267  * Reset the receive FIFO to its initial state. Manual is unclear as to
   268  * whether this also clears flags/interrupts, but we're assuming here that
   269  * it does until proven otherwise.
   270  */
   271 void SCIF_recvq_clear( void ) 
   272 {
   273     SCIF_recvq.head = SCIF_recvq.tail = 0;
   274     MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );
   275     MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );
   276     if( IS_RECEIVE_IRQ_ENABLED() )
   277         intc_clear_interrupt( INT_SCIF_RXI );
   278 }
   280 static inline uint8_t SCIF_sendq_size( ) 
   281 {
   282     int val = SCIF_sendq.tail - SCIF_sendq.head;
   283     if( val < 0 ) {
   284         val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;
   285     }
   286     return val;
   287 }
   289 /**
   290  * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),
   291  * updating all status flags as required.
   292  * @return The byte dequeued, or -1 if the queue is empty.
   293  */
   294 int SCIF_sendq_dequeue( )
   295 {
   296     uint8_t result;
   297     uint32_t tmp, length;
   298     if( SCIF_sendq.head == SCIF_sendq.tail )
   299         return -1; /* No data */
   301     /* Update queue head pointer */
   302     result = SCIF_sendq.data[SCIF_sendq.head++];
   303     if( SCIF_sendq.head > FIFO_LENGTH )
   304         SCIF_sendq.head = 0;
   306     /* Update data count register */
   307     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
   308     length = SCIF_sendq_size();
   309     MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
   311     /* Update status register */
   312     if( length <= SCIF_sendq.trigger ) {
   313         tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;
   314         if( length == 0 )
   315             tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */
   316         if( IS_TRANSMIT_IRQ_ENABLED() ) 
   317             intc_raise_interrupt( INT_SCIF_TXI );
   318         DMAC_trigger( DMAC_SCIF_TDE );
   319         MMIO_WRITE( SCIF, SCFSR2, tmp );
   320     }
   321     return (int)(unsigned int)result;
   322 }
   324 /**
   325  * Enqueue a single byte in the SCIF transmit queue. If the queue is full,
   326  * the value will be discarded.
   327  * @param value to be queued.
   328  * @param clearFlags TRUE if the TEND/TDFE flags should be cleared
   329  *   if the queue exceeds the trigger level. (According to the manual,
   330  *   DMAC writes will clear the flag, whereas regular SH4 writes do NOT
   331  *   automatically clear it. Go figure).
   332  * @return gboolean TRUE if the value was queued, FALSE if the queue was
   333  *   full.
   334  */
   335 gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )
   336 {
   337     uint32_t tmp, length;
   338     int newpos = SCIF_sendq.tail + 1;
   339     if( newpos > FIFO_LENGTH )
   340         newpos = 0;
   341     if( newpos == SCIF_sendq.head ) {
   342         /* FIFO full - discard */
   343         return FALSE;
   344     }
   345     SCIF_sendq.data[SCIF_sendq.tail] = value;
   346     SCIF_sendq.tail = newpos;
   348     /* Update data count register */
   349     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
   350     length = SCIF_sendq_size();
   351     MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
   353     /* Update flags if requested */
   354     if( clearFlags ) {
   355         tmp = SCFSR2_TEND;
   356         if( length > SCIF_sendq.trigger ) {
   357             tmp |= SCFSR2_TDFE;
   358             if( IS_TRANSMIT_IRQ_ENABLED() )
   359                 intc_clear_interrupt( INT_SCIF_TXI );
   360         }
   361         tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
   362         MMIO_WRITE( SCIF, SCFSR2, tmp );
   363     }
   364     return TRUE;
   365 }
   367 void SCIF_sendq_clear( void ) 
   368 {
   369     SCIF_sendq.head = SCIF_sendq.tail = 0;
   370     MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );
   371     MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );
   372     if( IS_TRANSMIT_IRQ_ENABLED() ) {
   373         intc_raise_interrupt( INT_SCIF_TXI );
   374         DMAC_trigger( DMAC_SCIF_TDE );
   375     }
   376 }
   378 /**
   379  * Update the SCFSR2 status register with the given mask (ie clear any values
   380  * that are set to 0 in the mask. According to a strict reading of the doco
   381  * though, the bits will only actually clear if the flag state is no longer
   382  * true, so we need to recheck everything...
   383  */
   384 void SCIF_update_status( uint32_t mask )
   385 {
   386     uint32_t value = MMIO_READ( SCIF, SCFSR2 );
   387     uint32_t result = value & mask;
   388     uint32_t sendq_size = SCIF_sendq_size();
   389     uint32_t recvq_size = SCIF_recvq_size();
   391     if( sendq_size != 0 )
   392         result |= SCFSR2_TEND;
   394     if( sendq_size <= SCIF_sendq.trigger )
   395         result |= SCFSR2_TDFE;
   396     else if( (result & SCFSR2_TDFE) == 0 && IS_TRANSMIT_IRQ_ENABLED() )
   397         intc_clear_interrupt( INT_SCIF_TXI );
   399     if( recvq_size >= SCIF_recvq.trigger )
   400         result |= SCFSR2_RDF;
   401     if( (value & SCFSR2_DR) != 0 && (result & SCFSR2_DR) == 0 &&
   402             recvq_size != 0 )
   403         result |= SCFSR2_DR;
   404     if( (result & (SCFSR2_DR|SCFSR2_RDF)) == 0 && IS_RECEIVE_IRQ_ENABLED() )
   405         intc_clear_interrupt( INT_SCIF_RXI );
   407     if( IS_RECEIVE_ERROR_IRQ_ENABLED() ) {
   408         if( (result & SCFSR2_BRK) == 0 )
   409             intc_clear_interrupt( INT_SCIF_BRI );
   410         if( (result & SCFSR2_ER) == 0 && 
   411                 (MMIO_READ( SCIF, SCLSR2 ) & SCLSR2_ORER) == 0 )
   412             intc_clear_interrupt( INT_SCIF_ERI );
   413     }
   414 }
   416 /**
   417  * Set the break detected flag
   418  */
   419 void SCIF_set_break( void ) 
   420 {
   421     MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );
   422     if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
   423         intc_raise_interrupt( INT_SCIF_BRI );
   424 }
   426 const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};
   428 /**
   429  * Calculate the current line speed.
   430  */
   431 void SCIF_update_line_speed( void )
   432 {
   433     /* If CKE1 is set, use the external clock as a base */
   434     if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {
   437     } else {
   439         /* Otherwise, SH4 peripheral clock divided by n */
   440         int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];
   442         /* Then process the bitrate register */
   443         int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;
   445         int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );
   447         if( serial_device != NULL && serial_device->set_line_speed != NULL )
   448             serial_device->set_line_speed( baudrate );
   450         SCIF_tick_period = sh4_peripheral_period * (32 * mult * (bbr+1));
   452         /*
   453 	  clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );
   454          */
   455     }
   456 }
   458 int32_t mmio_region_SCIF_read( uint32_t reg )
   459 {
   460     switch( reg ) {
   461     case SCFRDR2: /* Receive data */
   462         return SCIF_recvq_dequeue(FALSE);
   463     default:
   464         return MMIO_READ( SCIF, reg );
   465     }
   466 }
   468 void mmio_region_SCIF_write( uint32_t reg, uint32_t val ) 
   469 {
   470     uint32_t tmp;
   471     switch( reg ) {
   472     case SCSMR2: /* Serial mode register */
   473         /* Bit 6 => 0 = 8-bit, 1 = 7-bit
   474          * Bit 5 => 0 = Parity disabled, 1 = parity enabled
   475          * Bit 4 => 0 = Even parity, 1 = Odd parity
   476          * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits
   477          * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/64
   478          */
   479         val &= 0x007B;
   480         if( serial_device != NULL ) {
   481             serial_device->set_line_params( val );
   482         }
   483         tmp = MMIO_READ( SCIF, SCSMR2 );
   484         if( (tmp & 0x03) != (val & 0x03) ) {
   485             /* Clock change */
   486             SCIF_update_line_speed( );
   487         }
   488         /* Save for later read-back */
   489         MMIO_WRITE( SCIF, SCSMR2, val );
   490         break;
   491     case SCBRR2: /* Bit rate register */
   492         MMIO_WRITE( SCIF, SCBRR2, val );
   493         SCIF_update_line_speed( );
   494         break;
   495     case SCSCR2: /* Serial control register */
   496         /* Bit 7 => Transmit-FIFO-data-empty interrupt enabled 
   497          * Bit 6 => Receive-data-full interrupt enabled 
   498          * Bit 5 => Transmit enable 
   499          * Bit 4 => Receive enable 
   500          * Bit 3 => Receive-error/break interrupt enabled
   501          * Bit 1 => Clock enable
   502          */
   503         val &= 0x00FA;
   504         /* Clear any interrupts that just became disabled */
   505         if( (val & SCSCR2_TIE) == 0 )
   506             intc_clear_interrupt( INT_SCIF_TXI );
   507         if( (val & SCSCR2_RIE) == 0 )
   508             intc_clear_interrupt( INT_SCIF_RXI );
   509         if( (val & (SCSCR2_RIE|SCSCR2_REIE)) == 0 ) {
   510             intc_clear_interrupt( INT_SCIF_ERI );
   511             intc_clear_interrupt( INT_SCIF_BRI );
   512         }
   514         MMIO_WRITE( SCIF, reg, val );
   515         break;
   516     case SCFTDR2: /* Transmit FIFO data register */
   517         SCIF_sendq_enqueue( val, FALSE );
   518         break;
   519     case SCFSR2: /* Serial status register */
   520         /* Bits 12-15 Parity error count
   521          * Bits 8-11 Framing erro count 
   522          * Bit 7 - Receive error
   523          * Bit 6 - Transmit end
   524          * Bit 5 - Transmit FIFO data empty
   525          * Bit 4 - Break detect
   526          * Bit 3 - Framing error
   527          * Bit 2 - Parity error
   528          * Bit 1 - Receive FIFO data full
   529          * Bit 0 - Receive data ready
   530          */
   531         /* Clear off any flags/interrupts that are being set to 0 */
   532         SCIF_update_status( val );
   533         break;
   534     case SCFCR2: /* FIFO control register */
   535         val &= 0x0F;
   536         SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];
   537         SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];
   538         if( val & SCFCR2_TFRST ) {
   539             SCIF_sendq_clear();
   540         }
   541         if( val & SCFCR2_RFRST ) {
   542             SCIF_recvq_clear();
   543         }
   545         MMIO_WRITE( SCIF, reg, val );
   546         break;
   547     case SCSPTR2: /* Serial Port Register */
   548         MMIO_WRITE( SCIF, reg, val );
   549         /* NOT IMPLEMENTED - 'direct' serial I/O */
   550         if( val != 0 ) {
   551             WARN( "SCSPTR2 not implemented: Write %08X", val );
   552         }
   553         break;
   554     case SCLSR2:
   555         val = val & SCLSR2_ORER;
   556         if( val == 0 ) {
   557             MMIO_WRITE( SCIF, SCLSR2, val );
   558             if( (MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER) == 0 &&
   559                     IS_RECEIVE_ERROR_IRQ_ENABLED() ) 
   560                 intc_clear_interrupt( INT_SCIF_ERI );
   561         }
   563         break;
   564     }
   565 }
   567 /**
   568  * Actions for a single tick of the serial clock, defined as the transmission
   569  * time of a single frame.
   570  *
   571  * If transmit queue is non-empty:
   572  *    Transmit one byte and remove from queue
   573  * If input receive source is non-empty:
   574  *    Transfer one byte to the receive queue (if queue is full, byte is lost)
   575  * If recvq is non-empty, less than the trigger level, and no data has been
   576  *    received in the last 2 ticks (including this one), set the DR flag and
   577  *    IRQ if appropriate.
   578  */
   579 void SCIF_clock_tick( void ) 
   580 {
   581     gboolean rcvd = FALSE;
   583     if( IS_LOOPBACK_ENABLED() ) {
   584         if( IS_TRANSMIT_ENABLED() ) {
   585             int val = SCIF_sendq_dequeue();
   586             if( val != -1 && IS_RECEIVE_ENABLED() ) {
   587                 SCIF_recvq_enqueue( val );
   588                 rcvd = TRUE;
   589             }
   590         }
   591     } else {
   592         if( IS_TRANSMIT_ENABLED() ) {
   593             int val = SCIF_sendq_dequeue();
   594             if( val != -1 && serial_device != NULL && 
   595                     serial_device->receive_data != NULL ) {
   596                 serial_device->receive_data( val );
   597             }
   598         }
   600         if( IS_RECEIVE_ENABLED() ) {
   601             int val = serial_transmit_dequeue();
   602             if( val != -1 ) {
   603                 SCIF_recvq_enqueue( val );
   604                 rcvd = TRUE;
   605             }
   606         }
   607     }
   609     /* Check if we need to set the DR flag */
   610     if( !rcvd && !SCIF_rcvd_last_tick &&
   611             SCIF_recvq.head != SCIF_recvq.tail &&
   612             SCIF_recvq_size() < SCIF_recvq.trigger ) {
   613         uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );
   614         if( (tmp & SCFSR2_DR) == 0 ) {
   615             MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );
   616             if( IS_RECEIVE_IRQ_ENABLED() )
   617                 intc_raise_interrupt( INT_SCIF_RXI );
   618             DMAC_trigger( DMAC_SCIF_RDF );
   619         }
   620     }
   621     SCIF_rcvd_last_tick = rcvd;
   622 }
   624 void SCIF_reset( void )
   625 {
   626     SCIF_recvq_clear();
   627     SCIF_sendq_clear();
   628     SCIF_update_line_speed();
   629 }
   631 void SCIF_run_slice( uint32_t nanosecs ) 
   632 {
   633     SCIF_tick_remainder += nanosecs;
   634     while( SCIF_tick_remainder >= SCIF_tick_period ) {
   635         SCIF_tick_remainder -= SCIF_tick_period;
   636         SCIF_clock_tick();
   637     }
   638 }
.