Search
lxdream.org :: lxdream/src/sh4/scif.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/scif.c
changeset 20:3ffb66aa25c7
next21:fda269b432a7
author nkeynes
date Thu Dec 22 13:28:16 2005 +0000 (18 years ago)
permissions -rw-r--r--
last change Add scif.c (oops)
Convert interrupts to be level-triggered rather than edge-triggered
(although shouldn't be any visible difference)
view annotate diff log raw
     1 /**
     2  * $Id: scif.c,v 1.1 2005-12-22 13:28:16 nkeynes Exp $
     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 "sh4core.h"
    24 #include "sh4mmio.h"
    25 #include "intc.h"
    26 #include "clock.h"
    27 #include "serial.h"
    28 #include "modules.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 void SCIF_save_state( FILE *f ) 
   163 {
   166 }
   168 int SCIF_load_state( FILE *f ) 
   169 {
   170     return 0;
   171 }
   173 int SCIF_recvq_triggers[4] = {1, 4, 8, 14};
   174 struct SCIF_fifo SCIF_recvq = {0,0,1};
   176 int SCIF_sendq_triggers[4] = {8, 4, 2, 1};
   177 struct SCIF_fifo SCIF_sendq = {0,0,8};
   179 static inline uint8_t SCIF_recvq_size( ) 
   180 {
   181     int val = SCIF_recvq.tail - SCIF_recvq.head;
   182     if( val < 0 ) {
   183 	val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;
   184     }
   185     return val;
   186 }
   188 int SCIF_recvq_dequeue( gboolean clearFlags )
   189 {
   190     uint8_t result;
   191     uint32_t tmp, length;
   192     if( SCIF_recvq.head == SCIF_recvq.tail )
   193 	return -1; /* No data */
   194     result = SCIF_recvq.data[SCIF_recvq.head++];
   195     if( SCIF_recvq.head > FIFO_LENGTH )
   196 	SCIF_recvq.head = 0;
   198     /* Update data count register */
   199     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
   200     length = SCIF_recvq_size();
   201     MMIO_WRITE( SCIF, SCFDR2, tmp | length );
   203     /* Clear flags (if requested ) */
   204     if( clearFlags && length < SCIF_recvq.trigger ) {
   205 	tmp = SCFSR2_RDF;
   206 	if( length == 0 )
   207 	    tmp |= SCFSR2_DR;
   208 	tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
   209 	MMIO_WRITE( SCIF, SCFSR2, tmp );
   210 	/* If both flags are cleared, clear the interrupt as well */
   211 	if( tmp & (SCFSR2_DR|SCFSR2_RDF) == 0 )
   212 	    intc_clear_interrupt( INT_SCIF_RXI );
   213     }
   215     return (int)(unsigned int)result;
   216 }
   218 gboolean SCIF_recvq_enqueue( uint8_t value )
   219 {
   220     uint32_t tmp, length;
   221     int newpos = SCIF_recvq.tail + 1;
   222     if( newpos > FIFO_LENGTH )
   223 	newpos = 0;
   224     if( newpos == SCIF_recvq.head ) {
   225 	/* FIFO full - set ORER and discard the value */
   226 	MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );
   227 	if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
   228 	    intc_raise_interrupt( INT_SCIF_ERI );
   229 	return FALSE;
   230     }
   231     SCIF_recvq.data[SCIF_recvq.tail] = value;
   233     /* Update data count register */
   234     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
   235     length = SCIF_recvq_size();
   236     MMIO_WRITE( SCIF, SCFDR2, tmp | length );
   238     /* Update status register */
   239     tmp = MMIO_READ( SCIF, SCFSR2 );
   240     if( length >= SCIF_recvq.trigger ) {
   241 	tmp |= SCFSR2_RDF;
   242 	if( IS_RECEIVE_IRQ_ENABLED() ) 
   243 	    intc_raise_interrupt( INT_SCIF_RXI );
   244     }
   245     MMIO_WRITE( SCIF, SCFSR2, tmp );
   246     return TRUE;
   247 }
   250 /**
   251  * Reset the receive FIFO to its initial state. Manual is unclear as to
   252  * whether this also clears flags/interrupts, but we're assuming here that
   253  * it does until proven otherwise.
   254  */
   255 void SCIF_recvq_clear( void ) 
   256 {
   257     SCIF_recvq.head = SCIF_recvq.tail = 0;
   258     MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );
   259     MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );
   260     intc_clear_interrupt( INT_SCIF_RXI );
   261 }
   263 static inline uint8_t SCIF_sendq_size( ) 
   264 {
   265     int val = SCIF_sendq.tail - SCIF_sendq.head;
   266     if( val < 0 ) {
   267 	val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;
   268     }
   269     return val;
   270 }
   272 /**
   273  * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),
   274  * updating all status flags as required.
   275  * @return The byte dequeued, or -1 if the queue is empty.
   276  */
   277 int SCIF_sendq_dequeue( )
   278 {
   279     uint8_t result;
   280     uint32_t tmp, length;
   281     if( SCIF_sendq.head == SCIF_sendq.tail )
   282 	return -1; /* No data */
   284     /* Update queue head pointer */
   285     result = SCIF_sendq.data[SCIF_sendq.head++];
   286     if( SCIF_sendq.head > FIFO_LENGTH )
   287 	SCIF_sendq.head = 0;
   289     /* Update data count register */
   290     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
   291     length = SCIF_sendq_size();
   292     MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
   294     /* Update status register */
   295     if( length <= SCIF_sendq.trigger ) {
   296 	tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;
   297 	if( length == 0 )
   298 	    tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */
   299 	if( IS_TRANSMIT_IRQ_ENABLED() ) 
   300 	    intc_raise_interrupt( INT_SCIF_TXI );
   301 	MMIO_WRITE( SCIF, SCFSR2, tmp );
   302     }
   303     return (int)(unsigned int)result;
   304 }
   306 /**
   307  * Enqueue a single byte in the SCIF transmit queue. If the queue is full,
   308  * the value will be discarded.
   309  * @param value to be queued.
   310  * @param clearFlags TRUE if the TEND/TDFE flags should be cleared
   311  *   if the queue exceeds the trigger level. (According to the manual,
   312  *   DMAC writes will clear the flag, whereas regular SH4 writes do NOT
   313  *   automatically clear it. Go figure).
   314  * @return gboolean TRUE if the value was queued, FALSE if the queue was
   315  *   full.
   316  */
   317 gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )
   318 {
   319     uint32_t tmp, length;
   320     int newpos = SCIF_sendq.tail + 1;
   321     if( newpos > FIFO_LENGTH )
   322 	newpos = 0;
   323     if( newpos == SCIF_sendq.head ) {
   324 	/* FIFO full - discard */
   325 	return FALSE;
   326     }
   327     SCIF_sendq.data[SCIF_sendq.tail] = value;
   328     SCIF_sendq.tail = newpos;
   330     /* Update data count register */
   331     tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
   332     length = SCIF_sendq_size();
   333     MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
   335     /* Update flags if requested */
   336     if( clearFlags ) {
   337 	tmp = SCFSR2_TEND;
   338 	if( length > SCIF_sendq.trigger ) {
   339 	    tmp |= SCFSR2_TDFE;
   340 	    intc_clear_interrupt( INT_SCIF_TXI );
   341 	}
   342 	tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
   343 	MMIO_WRITE( SCIF, SCFSR2, tmp );
   344     }
   345     return TRUE;
   346 }
   348 void SCIF_sendq_clear( void ) 
   349 {
   350     SCIF_sendq.head = SCIF_sendq.tail = 0;
   351     MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );
   352     MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );
   353     if( IS_TRANSMIT_IRQ_ENABLED() ) {
   354 	intc_raise_interrupt( INT_SCIF_TXI );
   355     }
   356 }
   359 /**
   360  * Set the break detected flag
   361  */
   362 void SCIF_set_break( void ) 
   363 {
   364     MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );
   365     if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
   366 	intc_raise_interrupt( INT_SCIF_BRI );
   367 }
   369 const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};
   371 /**
   372  * Calculate the current line speed.
   373  */
   374 void SCIF_update_line_speed( void )
   375 {
   376     /* If CKE1 is set, use the external clock as a base */
   377     if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {
   380     } else {
   382 	/* Otherwise, SH4 peripheral clock divided by n */
   383 	int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];
   385 	/* Then process the bitrate register */
   386 	int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;
   388 	int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );
   390 	if( serial_device != NULL && serial_device->set_line_speed != NULL )
   391 	    serial_device->set_line_speed( baudrate );
   392 	INFO( "SCIF baud rate set to %d", baudrate );
   393 	/*
   394 	  clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );
   395 	*/
   396     }
   397 }
   399 int32_t mmio_region_SCIF_read( uint32_t reg )
   400 {
   401     switch( reg ) {
   402     case SCFRDR2: /* Receive data */
   403 	return SCIF_recvq_dequeue(FALSE);
   404     default:
   405 	return MMIO_READ( SCIF, reg );
   406     }
   407 }
   409 void mmio_region_SCIF_write( uint32_t reg, uint32_t val ) 
   410 {
   411     uint32_t tmp;
   412     switch( reg ) {
   413     case SCSMR2: /* Serial mode register */
   414 	/* Bit 6 => 0 = 8-bit, 1 = 7-bit
   415 	 * Bit 5 => 0 = Parity disabled, 1 = parity enabled
   416 	 * Bit 4 => 0 = Even parity, 1 = Odd parity
   417 	 * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits
   418 	 * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/64
   419 	 */
   420 	val &= 0x007B;
   421 	if( serial_device != NULL ) {
   422 	    serial_device->set_line_params( val );
   423 	}
   424 	tmp = MMIO_READ( SCIF, SCSMR2 );
   425 	if( tmp & 0x03 != val & 0x03 ) {
   426 	    /* Clock change */
   427 	    SCIF_update_line_speed( );
   428 	}
   429 	/* Save for later read-back */
   430 	MMIO_WRITE( SCIF, SCSMR2, val );
   431 	break;
   432     case SCBRR2: /* Bit rate register */
   433 	MMIO_WRITE( SCIF, SCBRR2, val );
   434 	SCIF_update_line_speed( );
   435 	break;
   436     case SCSCR2: /* Serial control register */
   437 	/* Bit 7 => Transmit-FIFO-data-empty interrupt enabled 
   438 	 * Bit 6 => Receive-data-full interrupt enabled 
   439 	 * Bit 5 => Transmit enable 
   440 	 * Bit 4 => Receive enable 
   441 	 * Bit 3 => Receive-error/break interrupt enabled
   442 	 * Bit 1 => Clock enable
   443 	 */
   444 	val &= 0x00FA;
   445 	/* Clear any interrupts that just became disabled */
   446 	if( val & SCSCR2_TIE == 0 )
   447 	    intc_clear_interrupt( INT_SCIF_TXI );
   448 	if( val & SCSCR2_RIE == 0 )
   449 	    intc_clear_interrupt( INT_SCIF_RXI );
   450 	if( val & (SCSCR2_RIE|SCSCR2_REIE) == 0 ) {
   451 	    intc_clear_interrupt( INT_SCIF_ERI );
   452 	    intc_clear_interrupt( INT_SCIF_BRI );
   453 	}
   455 	MMIO_WRITE( SCIF, reg, val );
   456 	break;
   457     case SCFTDR2: /* Transmit FIFO data register */
   458 	SCIF_sendq_enqueue( val, FALSE );
   459 	break;
   460     case SCFSR2: /* Serial status register */
   461 	/* Bits 12-15 Parity error count
   462 	 * Bits 8-11 Framing erro count 
   463 	 * Bit 7 - Receive error
   464 	 * Bit 6 - Transmit end
   465 	 * Bit 5 - Transmit FIFO data empty
   466 	 * Bit 4 - Break detect
   467 	 * Bit 3 - Framing error
   468 	 * Bit 2 - Parity error
   469 	 * Bit 1 - Receive FIFO data full
   470 	 * Bit 0 - Receive data ready
   471 	 */
   472 	tmp = MMIO_READ( SCIF, SCFSR2 );
   473 	tmp &= val;
   474 	/* Clear off any flags/interrupts that are being set to 0 */
   475 	MMIO_WRITE( SCIF, reg, tmp );
   476 	break;
   477     case SCFCR2: /* FIFO control register */
   478 	val &= 0x0F;
   479 	SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];
   480 	SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];
   481 	if( val & SCFCR2_TFRST ) {
   482 	    SCIF_sendq_clear();
   483 	}
   484 	if( val & SCFCR2_RFRST ) {
   485 	    SCIF_recvq_clear();
   486 	}
   488 	MMIO_WRITE( SCIF, reg, val );
   489 	break;
   490     case SCSPTR2: /* Serial Port Register */
   491 	MMIO_WRITE( SCIF, reg, val );
   492 	/* NOT IMPLEMENTED */
   493 	break;
   494     case SCLSR2:
   495 	val = val & SCLSR2_ORER;
   496 	if( val == 0 ) {
   497 	    MMIO_WRITE( SCIF, SCLSR2, val );
   498 	    if( MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER == 0) 
   499 		intc_clear_interrupt( INT_SCIF_ERI );
   500 	}
   502 	break;
   503     }
   504 }
   506 /**
   507  * Flag to indicate if data was received (ie added to the receive queue)
   508  * during the last SCIF clock tick. Used to determine when to set the DR
   509  * flag.
   510  */
   511 gboolean SCIF_rcvd_last_tick = FALSE;
   513 /**
   514  * Actions for a single tick of the serial clock, defined as the transmission
   515  * time of a single frame.
   516  *
   517  * If transmit queue is non-empty:
   518  *    Transmit one byte and remove from queue
   519  * If input receive source is non-empty:
   520  *    Transfer one byte to the receive queue (if queue is full, byte is lost)
   521  * If recvq is non-empty, less than the trigger level, and no data has been
   522  *    received in the last 2 ticks (including this one), set the DR flag and
   523  *    IRQ if appropriate.
   524  */
   525 void SCIF_clock_tick( void ) 
   526 {
   527     gboolean rcvd = FALSE;
   529     if( IS_LOOPBACK_ENABLED() ) {
   530 	if( IS_TRANSMIT_ENABLED() ) {
   531 	    int val = SCIF_sendq_dequeue();
   532 	    if( val != -1 && IS_RECEIVE_ENABLED() ) {
   533 		SCIF_recvq_enqueue( val );
   534 		rcvd = TRUE;
   535 	    }
   536 	}
   537     } else {
   538 	if( IS_TRANSMIT_ENABLED() ) {
   539 	    int val = SCIF_sendq_dequeue();
   540 	    if( val != -1 && serial_device != NULL && 
   541 		serial_device->receive_data != NULL ) {
   542 		serial_device->receive_data( val );
   543 	    }
   544 	}
   546 	if( IS_RECEIVE_ENABLED() ) {
   547 	    int val = serial_transmit_dequeue();
   548 	    if( val != -1 ) {
   549 		SCIF_recvq_enqueue( val );
   550 		rcvd = TRUE;
   551 	    }
   552 	}
   553     }
   555     /* Check if we need to set the DR flag */
   556     if( !rcvd && !SCIF_rcvd_last_tick &&
   557 	SCIF_recvq.head != SCIF_recvq.tail &&
   558 	SCIF_recvq_size() < SCIF_recvq.trigger ) {
   559 	uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );
   560 	if( tmp & SCFSR2_DR == 0 ) {
   561 	    MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );
   562 	    if( IS_RECEIVE_IRQ_ENABLED() )
   563 		intc_raise_interrupt( INT_SCIF_RXI );
   564 	}
   565     }
   566     SCIF_rcvd_last_tick = rcvd;
   567 }
.