revision 20:3ffb66aa25c7
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 20:3ffb66aa25c7 |
parent | 19:9da7a8e38f9d |
child | 21:fda269b432a7 |
author | nkeynes |
date | Thu Dec 22 13:28:16 2005 +0000 (17 years ago) |
Add scif.c (oops)
Convert interrupts to be level-triggered rather than edge-triggered
(although shouldn't be any visible difference)
Convert interrupts to be level-triggered rather than edge-triggered
(although shouldn't be any visible difference)
![]() | src/asic.c | view | annotate | diff | log | |
![]() | src/sh4/intc.c | view | annotate | diff | log | |
![]() | src/sh4/scif.c | view | annotate | diff | log |
1.1 --- a/src/asic.c Thu Dec 22 07:38:12 2005 +00001.2 +++ b/src/asic.c Thu Dec 22 13:28:16 2005 +00001.3 @@ -13,8 +13,6 @@1.4 * Open questions:1.5 * 1) Does changing the mask after event occurance result in the1.6 * interrupt being delivered immediately?1.7 - * 2) If the pending register is not cleared after an interrupt, does1.8 - * the interrupt line remain high? (ie does the IRQ reoccur?)1.9 * TODO: Logic diagram of ASIC event/interrupt logic.1.10 *1.11 * ... don't even get me started on the "EXTDMA" page, about which, apparently,1.12 @@ -24,6 +22,8 @@1.13 struct dreamcast_module asic_module = { "ASIC", asic_init, NULL, NULL, NULL,1.14 NULL, NULL };1.16 +void asic_check_cleared_events( void );1.17 +1.18 void asic_init( void )1.19 {1.20 register_io_region( &mmio_region_ASIC );1.21 @@ -40,6 +40,8 @@1.22 case PIRQ2:1.23 /* Clear any interrupts */1.24 MMIO_WRITE( ASIC, reg, MMIO_READ(ASIC, reg)&~val );1.25 + DEBUG( "ASIC Write %08X => %08X", val, reg );1.26 + asic_check_cleared_events();1.27 break;1.28 case MAPLE_STATE:1.29 MMIO_WRITE( ASIC, reg, val );1.30 @@ -98,6 +100,23 @@1.31 intc_raise_interrupt( INT_IRQ9 );1.32 }1.34 +void asic_check_cleared_events( )1.35 +{1.36 + int i, setA = 0, setB = 0, setC = 0;1.37 + uint32_t bits;1.38 + for( i=0; i<3; i++ ) {1.39 + bits = MMIO_READ( ASIC, PIRQ0 + i );1.40 + setA |= (bits & MMIO_READ(ASIC, IRQA0 + i ));1.41 + setB |= (bits & MMIO_READ(ASIC, IRQB0 + i ));1.42 + setC |= (bits & MMIO_READ(ASIC, IRQC0 + i ));1.43 + }1.44 + if( setA == 0 )1.45 + intc_clear_interrupt( INT_IRQ13 );1.46 + if( setB == 0 )1.47 + intc_clear_interrupt( INT_IRQ11 );1.48 + if( setC == 0 )1.49 + intc_clear_interrupt( INT_IRQ9 );1.50 +}1.53 MMIO_REGION_WRITE_FN( EXTDMA, reg, val )
2.1 --- a/src/sh4/intc.c Thu Dec 22 07:38:12 2005 +00002.2 +++ b/src/sh4/intc.c Thu Dec 22 13:28:16 2005 +00002.3 @@ -115,18 +115,36 @@2.5 void intc_clear_interrupt( int which )2.6 {2.7 -2.8 + int i;2.9 + for( i=intc_num_pending-1; i>=0; i-- ) {2.10 + if( intc_pending[i] == which ) {2.11 + /* Shift array contents down */2.12 + while( i < intc_num_pending-1 ) {2.13 + intc_pending[i] = intc_pending[++i];2.14 + }2.15 + intc_num_pending--;2.16 + if( intc_num_pending == 0 )2.17 + sh4r.int_pending = 0;2.18 + else2.19 + sh4r.int_pending = PRIORITY(intc_pending[intc_num_pending-1]);2.20 + break;2.21 + }2.22 + }2.23 +2.24 }2.26 uint32_t intc_accept_interrupt( void )2.27 {2.28 assert(intc_num_pending > 0);2.29 + return INTCODE(intc_pending[intc_num_pending-1]);2.30 + /*2.31 intc_num_pending--;2.32 if( intc_num_pending > 0 )2.33 sh4r.int_pending = PRIORITY(intc_pending[intc_num_pending-1]);2.34 else2.35 sh4r.int_pending = 0;2.36 return INTCODE(intc_pending[intc_num_pending]);2.37 + */2.38 }2.40 void intc_mask_changed( void )
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00003.2 +++ b/src/sh4/scif.c Thu Dec 22 13:28:16 2005 +00003.3 @@ -0,0 +1,567 @@3.4 +/**3.5 + * $Id: scif.c,v 1.1 2005-12-22 13:28:16 nkeynes Exp $3.6 + * SCIF (Serial Communication Interface with FIFO) implementation - part of the3.7 + * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs3.8 + * external serial port3.9 + *3.10 + * Copyright (c) 2005 Nathan Keynes.3.11 + *3.12 + * This program is free software; you can redistribute it and/or modify3.13 + * it under the terms of the GNU General Public License as published by3.14 + * the Free Software Foundation; either version 2 of the License, or3.15 + * (at your option) any later version.3.16 + *3.17 + * This program is distributed in the hope that it will be useful,3.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of3.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the3.20 + * GNU General Public License for more details.3.21 + */3.22 +3.23 +#include <glib.h>3.24 +#include "dream.h"3.25 +#include "mem.h"3.26 +#include "sh4core.h"3.27 +#include "sh4mmio.h"3.28 +#include "intc.h"3.29 +#include "clock.h"3.30 +#include "serial.h"3.31 +#include "modules.h"3.32 +3.33 +void SCIF_set_break(void);3.34 +3.35 +/************************* External serial interface ************************/3.36 +3.37 +/**3.38 + * Note: serial_* operations are called from outside the SH4, and as such are3.39 + * named relative to the external serial device. SCIF_* operations are only3.40 + * called internally to the SH4 and so are named relative to the CPU.3.41 + */3.42 +3.43 +/**3.44 + * Storage space for inbound/outbound data blocks. It's a little more3.45 + * convenient for serial consumers to be able to deal with block-sized pieces3.46 + * rather than a byte at a time, even if it makes all this look rather3.47 + * complicated.3.48 + *3.49 + * Currently there's no limit on the number of blocks that can be queued up.3.50 + */3.51 +typedef struct serial_data_block {3.52 + uint32_t length;3.53 + uint32_t offset;3.54 + struct serial_data_block *next;3.55 + char data[];3.56 +} *serial_data_block_t;3.57 +3.58 +serial_data_block_t serial_recvq_head = NULL, serial_recvq_tail = NULL;3.59 +serial_device_t serial_device = NULL;3.60 +3.61 +void serial_attach_device( serial_device_t dev )3.62 +{3.63 + if( serial_device != NULL )3.64 + serial_detach_device();3.65 + serial_device = dev;3.66 +}3.67 +3.68 +3.69 +void serial_detach_device( void )3.70 +{3.71 + serial_device = NULL;3.72 +}3.73 +3.74 +/**3.75 + * Add a block of data to the serial receive queue. The data will be received3.76 + * by the CPU at the appropriate baud rate.3.77 + */3.78 +void serial_transmit_data( char *data, int length ) {3.79 + if( length == 0 )3.80 + return;3.81 + serial_data_block_t block =3.82 + g_malloc( sizeof( struct serial_data_block ) + length );3.83 + block->length = length;3.84 + block->offset = 0;3.85 + block->next = NULL;3.86 + memcpy( block->data, data, length );3.87 +3.88 + if( serial_recvq_head == NULL ) {3.89 + serial_recvq_head = serial_recvq_tail = block;3.90 + } else {3.91 + serial_recvq_tail->next = block;3.92 + serial_recvq_tail = block;3.93 + }3.94 +}3.95 +3.96 +/**3.97 + * Dequeue a byte from the serial input queue3.98 + */3.99 +static int serial_transmit_dequeue( ) {3.100 + if( serial_recvq_head != NULL ) {3.101 + uint8_t val = serial_recvq_head->data[serial_recvq_head->offset++];3.102 + if( serial_recvq_head->offset >= serial_recvq_head->length ) {3.103 + serial_data_block_t next = serial_recvq_head->next;3.104 + g_free( serial_recvq_head );3.105 + serial_recvq_head = next;3.106 + if( next == NULL )3.107 + serial_recvq_tail = NULL;3.108 + }3.109 + return (int)(unsigned int)val;3.110 + }3.111 + return -1;3.112 +3.113 +}3.114 +3.115 +void serial_transmit_break() {3.116 + SCIF_set_break();3.117 +}3.118 +3.119 +/********************************* SCIF *************************************/3.120 +3.121 +#define FIFO_LENGTH 163.122 +#define FIFO_ARR_LENGTH (FIFO_LENGTH+1)3.123 +3.124 +/* Serial control register flags */3.125 +#define SCSCR2_TIE 0x803.126 +#define SCSCR2_RIE 0x403.127 +#define SCSCR2_TE 0x203.128 +#define SCSCR2_RE 0x103.129 +#define SCSCR2_REIE 0x083.130 +#define SCSCR2_CKE 0x023.131 +3.132 +#define IS_TRANSMIT_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TIE)3.133 +#define IS_RECEIVE_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RIE)3.134 +#define IS_RECEIVE_ERROR_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & (SCSCR2_RIE|SCSCR2_REIE))3.135 +/* Receive is enabled if the RE bit is set in SCSCR2, and the ORER bit is cleared in SCLSR2 */3.136 +#define IS_RECEIVE_ENABLED() ( (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RE) && (MMIO_READ(SCIF,SCLSR2) & SCLSR2_ORER == 0) )3.137 +/* Transmit is enabled if the TE bit is set in SCSCR2 */3.138 +#define IS_TRANSMIT_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TE)3.139 +#define IS_LOOPBACK_ENABLED() (MMIO_READ(SCIF,SCFCR2) & SCFCR2_LOOP)3.140 +3.141 +/* Serial status register flags */3.142 +#define SCFSR2_ER 0x803.143 +#define SCFSR2_TEND 0x403.144 +#define SCFSR2_TDFE 0x203.145 +#define SCFSR2_BRK 0x103.146 +#define SCFSR2_RDF 0x023.147 +#define SCFSR2_DR 0x013.148 +3.149 +/* FIFO control register flags */3.150 +#define SCFCR2_MCE 0x083.151 +#define SCFCR2_TFRST 0x043.152 +#define SCFCR2_RFRST 0x023.153 +#define SCFCR2_LOOP 0x013.154 +3.155 +/* Line Status Register */3.156 +#define SCLSR2_ORER 0x013.157 +3.158 +struct SCIF_fifo {3.159 + int head;3.160 + int tail;3.161 + int trigger;3.162 + uint8_t data[FIFO_ARR_LENGTH];3.163 +};3.164 +3.165 +void SCIF_save_state( FILE *f )3.166 +{3.167 +3.168 +3.169 +}3.170 +3.171 +int SCIF_load_state( FILE *f )3.172 +{3.173 + return 0;3.174 +}3.175 +3.176 +int SCIF_recvq_triggers[4] = {1, 4, 8, 14};3.177 +struct SCIF_fifo SCIF_recvq = {0,0,1};3.178 +3.179 +int SCIF_sendq_triggers[4] = {8, 4, 2, 1};3.180 +struct SCIF_fifo SCIF_sendq = {0,0,8};3.181 +3.182 +static inline uint8_t SCIF_recvq_size( )3.183 +{3.184 + int val = SCIF_recvq.tail - SCIF_recvq.head;3.185 + if( val < 0 ) {3.186 + val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;3.187 + }3.188 + return val;3.189 +}3.190 +3.191 +int SCIF_recvq_dequeue( gboolean clearFlags )3.192 +{3.193 + uint8_t result;3.194 + uint32_t tmp, length;3.195 + if( SCIF_recvq.head == SCIF_recvq.tail )3.196 + return -1; /* No data */3.197 + result = SCIF_recvq.data[SCIF_recvq.head++];3.198 + if( SCIF_recvq.head > FIFO_LENGTH )3.199 + SCIF_recvq.head = 0;3.200 +3.201 + /* Update data count register */3.202 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;3.203 + length = SCIF_recvq_size();3.204 + MMIO_WRITE( SCIF, SCFDR2, tmp | length );3.205 +3.206 + /* Clear flags (if requested ) */3.207 + if( clearFlags && length < SCIF_recvq.trigger ) {3.208 + tmp = SCFSR2_RDF;3.209 + if( length == 0 )3.210 + tmp |= SCFSR2_DR;3.211 + tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);3.212 + MMIO_WRITE( SCIF, SCFSR2, tmp );3.213 + /* If both flags are cleared, clear the interrupt as well */3.214 + if( tmp & (SCFSR2_DR|SCFSR2_RDF) == 0 )3.215 + intc_clear_interrupt( INT_SCIF_RXI );3.216 + }3.217 +3.218 + return (int)(unsigned int)result;3.219 +}3.220 +3.221 +gboolean SCIF_recvq_enqueue( uint8_t value )3.222 +{3.223 + uint32_t tmp, length;3.224 + int newpos = SCIF_recvq.tail + 1;3.225 + if( newpos > FIFO_LENGTH )3.226 + newpos = 0;3.227 + if( newpos == SCIF_recvq.head ) {3.228 + /* FIFO full - set ORER and discard the value */3.229 + MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );3.230 + if( IS_RECEIVE_ERROR_IRQ_ENABLED() )3.231 + intc_raise_interrupt( INT_SCIF_ERI );3.232 + return FALSE;3.233 + }3.234 + SCIF_recvq.data[SCIF_recvq.tail] = value;3.235 +3.236 + /* Update data count register */3.237 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;3.238 + length = SCIF_recvq_size();3.239 + MMIO_WRITE( SCIF, SCFDR2, tmp | length );3.240 +3.241 + /* Update status register */3.242 + tmp = MMIO_READ( SCIF, SCFSR2 );3.243 + if( length >= SCIF_recvq.trigger ) {3.244 + tmp |= SCFSR2_RDF;3.245 + if( IS_RECEIVE_IRQ_ENABLED() )3.246 + intc_raise_interrupt( INT_SCIF_RXI );3.247 + }3.248 + MMIO_WRITE( SCIF, SCFSR2, tmp );3.249 + return TRUE;3.250 +}3.251 +3.252 +3.253 +/**3.254 + * Reset the receive FIFO to its initial state. Manual is unclear as to3.255 + * whether this also clears flags/interrupts, but we're assuming here that3.256 + * it does until proven otherwise.3.257 + */3.258 +void SCIF_recvq_clear( void )3.259 +{3.260 + SCIF_recvq.head = SCIF_recvq.tail = 0;3.261 + MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );3.262 + MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );3.263 + intc_clear_interrupt( INT_SCIF_RXI );3.264 +}3.265 +3.266 +static inline uint8_t SCIF_sendq_size( )3.267 +{3.268 + int val = SCIF_sendq.tail - SCIF_sendq.head;3.269 + if( val < 0 ) {3.270 + val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;3.271 + }3.272 + return val;3.273 +}3.274 +3.275 +/**3.276 + * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),3.277 + * updating all status flags as required.3.278 + * @return The byte dequeued, or -1 if the queue is empty.3.279 + */3.280 +int SCIF_sendq_dequeue( )3.281 +{3.282 + uint8_t result;3.283 + uint32_t tmp, length;3.284 + if( SCIF_sendq.head == SCIF_sendq.tail )3.285 + return -1; /* No data */3.286 +3.287 + /* Update queue head pointer */3.288 + result = SCIF_sendq.data[SCIF_sendq.head++];3.289 + if( SCIF_sendq.head > FIFO_LENGTH )3.290 + SCIF_sendq.head = 0;3.291 +3.292 + /* Update data count register */3.293 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;3.294 + length = SCIF_sendq_size();3.295 + MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );3.296 +3.297 + /* Update status register */3.298 + if( length <= SCIF_sendq.trigger ) {3.299 + tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;3.300 + if( length == 0 )3.301 + tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */3.302 + if( IS_TRANSMIT_IRQ_ENABLED() )3.303 + intc_raise_interrupt( INT_SCIF_TXI );3.304 + MMIO_WRITE( SCIF, SCFSR2, tmp );3.305 + }3.306 + return (int)(unsigned int)result;3.307 +}3.308 +3.309 +/**3.310 + * Enqueue a single byte in the SCIF transmit queue. If the queue is full,3.311 + * the value will be discarded.3.312 + * @param value to be queued.3.313 + * @param clearFlags TRUE if the TEND/TDFE flags should be cleared3.314 + * if the queue exceeds the trigger level. (According to the manual,3.315 + * DMAC writes will clear the flag, whereas regular SH4 writes do NOT3.316 + * automatically clear it. Go figure).3.317 + * @return gboolean TRUE if the value was queued, FALSE if the queue was3.318 + * full.3.319 + */3.320 +gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )3.321 +{3.322 + uint32_t tmp, length;3.323 + int newpos = SCIF_sendq.tail + 1;3.324 + if( newpos > FIFO_LENGTH )3.325 + newpos = 0;3.326 + if( newpos == SCIF_sendq.head ) {3.327 + /* FIFO full - discard */3.328 + return FALSE;3.329 + }3.330 + SCIF_sendq.data[SCIF_sendq.tail] = value;3.331 + SCIF_sendq.tail = newpos;3.332 +3.333 + /* Update data count register */3.334 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;3.335 + length = SCIF_sendq_size();3.336 + MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );3.337 +3.338 + /* Update flags if requested */3.339 + if( clearFlags ) {3.340 + tmp = SCFSR2_TEND;3.341 + if( length > SCIF_sendq.trigger ) {3.342 + tmp |= SCFSR2_TDFE;3.343 + intc_clear_interrupt( INT_SCIF_TXI );3.344 + }3.345 + tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);3.346 + MMIO_WRITE( SCIF, SCFSR2, tmp );3.347 + }3.348 + return TRUE;3.349 +}3.350 +3.351 +void SCIF_sendq_clear( void )3.352 +{3.353 + SCIF_sendq.head = SCIF_sendq.tail = 0;3.354 + MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );3.355 + MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );3.356 + if( IS_TRANSMIT_IRQ_ENABLED() ) {3.357 + intc_raise_interrupt( INT_SCIF_TXI );3.358 + }3.359 +}3.360 +3.361 +3.362 +/**3.363 + * Set the break detected flag3.364 + */3.365 +void SCIF_set_break( void )3.366 +{3.367 + MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );3.368 + if( IS_RECEIVE_ERROR_IRQ_ENABLED() )3.369 + intc_raise_interrupt( INT_SCIF_BRI );3.370 +}3.371 +3.372 +const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};3.373 +3.374 +/**3.375 + * Calculate the current line speed.3.376 + */3.377 +void SCIF_update_line_speed( void )3.378 +{3.379 + /* If CKE1 is set, use the external clock as a base */3.380 + if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {3.381 +3.382 +3.383 + } else {3.384 +3.385 + /* Otherwise, SH4 peripheral clock divided by n */3.386 + int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];3.387 +3.388 + /* Then process the bitrate register */3.389 + int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;3.390 +3.391 + int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );3.392 +3.393 + if( serial_device != NULL && serial_device->set_line_speed != NULL )3.394 + serial_device->set_line_speed( baudrate );3.395 + INFO( "SCIF baud rate set to %d", baudrate );3.396 + /*3.397 + clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );3.398 + */3.399 + }3.400 +}3.401 +3.402 +int32_t mmio_region_SCIF_read( uint32_t reg )3.403 +{3.404 + switch( reg ) {3.405 + case SCFRDR2: /* Receive data */3.406 + return SCIF_recvq_dequeue(FALSE);3.407 + default:3.408 + return MMIO_READ( SCIF, reg );3.409 + }3.410 +}3.411 +3.412 +void mmio_region_SCIF_write( uint32_t reg, uint32_t val )3.413 +{3.414 + uint32_t tmp;3.415 + switch( reg ) {3.416 + case SCSMR2: /* Serial mode register */3.417 + /* Bit 6 => 0 = 8-bit, 1 = 7-bit3.418 + * Bit 5 => 0 = Parity disabled, 1 = parity enabled3.419 + * Bit 4 => 0 = Even parity, 1 = Odd parity3.420 + * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits3.421 + * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/643.422 + */3.423 + val &= 0x007B;3.424 + if( serial_device != NULL ) {3.425 + serial_device->set_line_params( val );3.426 + }3.427 + tmp = MMIO_READ( SCIF, SCSMR2 );3.428 + if( tmp & 0x03 != val & 0x03 ) {3.429 + /* Clock change */3.430 + SCIF_update_line_speed( );3.431 + }3.432 + /* Save for later read-back */3.433 + MMIO_WRITE( SCIF, SCSMR2, val );3.434 + break;3.435 + case SCBRR2: /* Bit rate register */3.436 + MMIO_WRITE( SCIF, SCBRR2, val );3.437 + SCIF_update_line_speed( );3.438 + break;3.439 + case SCSCR2: /* Serial control register */3.440 + /* Bit 7 => Transmit-FIFO-data-empty interrupt enabled3.441 + * Bit 6 => Receive-data-full interrupt enabled3.442 + * Bit 5 => Transmit enable3.443 + * Bit 4 => Receive enable3.444 + * Bit 3 => Receive-error/break interrupt enabled3.445 + * Bit 1 => Clock enable3.446 + */3.447 + val &= 0x00FA;3.448 + /* Clear any interrupts that just became disabled */3.449 + if( val & SCSCR2_TIE == 0 )3.450 + intc_clear_interrupt( INT_SCIF_TXI );3.451 + if( val & SCSCR2_RIE == 0 )3.452 + intc_clear_interrupt( INT_SCIF_RXI );3.453 + if( val & (SCSCR2_RIE|SCSCR2_REIE) == 0 ) {3.454 + intc_clear_interrupt( INT_SCIF_ERI );3.455 + intc_clear_interrupt( INT_SCIF_BRI );3.456 + }3.457 +3.458 + MMIO_WRITE( SCIF, reg, val );3.459 + break;3.460 + case SCFTDR2: /* Transmit FIFO data register */3.461 + SCIF_sendq_enqueue( val, FALSE );3.462 + break;3.463 + case SCFSR2: /* Serial status register */3.464 + /* Bits 12-15 Parity error count3.465 + * Bits 8-11 Framing erro count3.466 + * Bit 7 - Receive error3.467 + * Bit 6 - Transmit end3.468 + * Bit 5 - Transmit FIFO data empty3.469 + * Bit 4 - Break detect3.470 + * Bit 3 - Framing error3.471 + * Bit 2 - Parity error3.472 + * Bit 1 - Receive FIFO data full3.473 + * Bit 0 - Receive data ready3.474 + */3.475 + tmp = MMIO_READ( SCIF, SCFSR2 );3.476 + tmp &= val;3.477 + /* Clear off any flags/interrupts that are being set to 0 */3.478 + MMIO_WRITE( SCIF, reg, tmp );3.479 + break;3.480 + case SCFCR2: /* FIFO control register */3.481 + val &= 0x0F;3.482 + SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];3.483 + SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];3.484 + if( val & SCFCR2_TFRST ) {3.485 + SCIF_sendq_clear();3.486 + }3.487 + if( val & SCFCR2_RFRST ) {3.488 + SCIF_recvq_clear();3.489 + }3.490 +3.491 + MMIO_WRITE( SCIF, reg, val );3.492 + break;3.493 + case SCSPTR2: /* Serial Port Register */3.494 + MMIO_WRITE( SCIF, reg, val );3.495 + /* NOT IMPLEMENTED */3.496 + break;3.497 + case SCLSR2:3.498 + val = val & SCLSR2_ORER;3.499 + if( val == 0 ) {3.500 + MMIO_WRITE( SCIF, SCLSR2, val );3.501 + if( MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER == 0)3.502 + intc_clear_interrupt( INT_SCIF_ERI );3.503 + }3.504 +3.505 + break;3.506 + }3.507 +}3.508 +3.509 +/**3.510 + * Flag to indicate if data was received (ie added to the receive queue)3.511 + * during the last SCIF clock tick. Used to determine when to set the DR3.512 + * flag.3.513 + */3.514 +gboolean SCIF_rcvd_last_tick = FALSE;3.515 +3.516 +/**3.517 + * Actions for a single tick of the serial clock, defined as the transmission3.518 + * time of a single frame.3.519 + *3.520 + * If transmit queue is non-empty:3.521 + * Transmit one byte and remove from queue3.522 + * If input receive source is non-empty:3.523 + * Transfer one byte to the receive queue (if queue is full, byte is lost)3.524 + * If recvq is non-empty, less than the trigger level, and no data has been3.525 + * received in the last 2 ticks (including this one), set the DR flag and3.526 + * IRQ if appropriate.3.527 + */3.528 +void SCIF_clock_tick( void )3.529 +{3.530 + gboolean rcvd = FALSE;3.531 +3.532 + if( IS_LOOPBACK_ENABLED() ) {3.533 + if( IS_TRANSMIT_ENABLED() ) {3.534 + int val = SCIF_sendq_dequeue();3.535 + if( val != -1 && IS_RECEIVE_ENABLED() ) {3.536 + SCIF_recvq_enqueue( val );3.537 + rcvd = TRUE;3.538 + }3.539 + }3.540 + } else {3.541 + if( IS_TRANSMIT_ENABLED() ) {3.542 + int val = SCIF_sendq_dequeue();3.543 + if( val != -1 && serial_device != NULL &&3.544 + serial_device->receive_data != NULL ) {3.545 + serial_device->receive_data( val );3.546 + }3.547 + }3.548 +3.549 + if( IS_RECEIVE_ENABLED() ) {3.550 + int val = serial_transmit_dequeue();3.551 + if( val != -1 ) {3.552 + SCIF_recvq_enqueue( val );3.553 + rcvd = TRUE;3.554 + }3.555 + }3.556 + }3.557 +3.558 + /* Check if we need to set the DR flag */3.559 + if( !rcvd && !SCIF_rcvd_last_tick &&3.560 + SCIF_recvq.head != SCIF_recvq.tail &&3.561 + SCIF_recvq_size() < SCIF_recvq.trigger ) {3.562 + uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );3.563 + if( tmp & SCFSR2_DR == 0 ) {3.564 + MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );3.565 + if( IS_RECEIVE_IRQ_ENABLED() )3.566 + intc_raise_interrupt( INT_SCIF_RXI );3.567 + }3.568 + }3.569 + SCIF_rcvd_last_tick = rcvd;3.570 +}
.