Search
lxdream.org :: lxdream :: r20:3ffb66aa25c7
lxdream 0.9.1
released Jun 29
Download Now
changeset20:3ffb66aa25c7
parent19:9da7a8e38f9d
child21:fda269b432a7
authornkeynes
dateThu Dec 22 13:28:16 2005 +0000 (18 years ago)
Add scif.c (oops)
Convert interrupts to be level-triggered rather than edge-triggered
(although shouldn't be any visible difference)
src/asic.c
src/sh4/intc.c
src/sh4/scif.c
1.1 --- a/src/asic.c Thu Dec 22 07:38:12 2005 +0000
1.2 +++ b/src/asic.c Thu Dec 22 13:28:16 2005 +0000
1.3 @@ -13,8 +13,6 @@
1.4 * Open questions:
1.5 * 1) Does changing the mask after event occurance result in the
1.6 * interrupt being delivered immediately?
1.7 - * 2) If the pending register is not cleared after an interrupt, does
1.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.15
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.33
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.51
1.52
1.53 MMIO_REGION_WRITE_FN( EXTDMA, reg, val )
2.1 --- a/src/sh4/intc.c Thu Dec 22 07:38:12 2005 +0000
2.2 +++ b/src/sh4/intc.c Thu Dec 22 13:28:16 2005 +0000
2.3 @@ -115,18 +115,36 @@
2.4
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 + else
2.19 + sh4r.int_pending = PRIORITY(intc_pending[intc_num_pending-1]);
2.20 + break;
2.21 + }
2.22 + }
2.23 +
2.24 }
2.25
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 else
2.35 sh4r.int_pending = 0;
2.36 return INTCODE(intc_pending[intc_num_pending]);
2.37 + */
2.38 }
2.39
2.40 void intc_mask_changed( void )
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/src/sh4/scif.c Thu Dec 22 13:28:16 2005 +0000
3.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 the
3.7 + * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs
3.8 + * external serial port
3.9 + *
3.10 + * Copyright (c) 2005 Nathan Keynes.
3.11 + *
3.12 + * This program is free software; you can redistribute it and/or modify
3.13 + * it under the terms of the GNU General Public License as published by
3.14 + * the Free Software Foundation; either version 2 of the License, or
3.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 of
3.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.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 are
3.39 + * named relative to the external serial device. SCIF_* operations are only
3.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 more
3.45 + * convenient for serial consumers to be able to deal with block-sized pieces
3.46 + * rather than a byte at a time, even if it makes all this look rather
3.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 received
3.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 queue
3.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 16
3.122 +#define FIFO_ARR_LENGTH (FIFO_LENGTH+1)
3.123 +
3.124 +/* Serial control register flags */
3.125 +#define SCSCR2_TIE 0x80
3.126 +#define SCSCR2_RIE 0x40
3.127 +#define SCSCR2_TE 0x20
3.128 +#define SCSCR2_RE 0x10
3.129 +#define SCSCR2_REIE 0x08
3.130 +#define SCSCR2_CKE 0x02
3.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 0x80
3.143 +#define SCFSR2_TEND 0x40
3.144 +#define SCFSR2_TDFE 0x20
3.145 +#define SCFSR2_BRK 0x10
3.146 +#define SCFSR2_RDF 0x02
3.147 +#define SCFSR2_DR 0x01
3.148 +
3.149 +/* FIFO control register flags */
3.150 +#define SCFCR2_MCE 0x08
3.151 +#define SCFCR2_TFRST 0x04
3.152 +#define SCFCR2_RFRST 0x02
3.153 +#define SCFCR2_LOOP 0x01
3.154 +
3.155 +/* Line Status Register */
3.156 +#define SCLSR2_ORER 0x01
3.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 to
3.255 + * whether this also clears flags/interrupts, but we're assuming here that
3.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 cleared
3.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 NOT
3.316 + * automatically clear it. Go figure).
3.317 + * @return gboolean TRUE if the value was queued, FALSE if the queue was
3.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 flag
3.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-bit
3.418 + * Bit 5 => 0 = Parity disabled, 1 = parity enabled
3.419 + * Bit 4 => 0 = Even parity, 1 = Odd parity
3.420 + * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits
3.421 + * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/64
3.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 enabled
3.441 + * Bit 6 => Receive-data-full interrupt enabled
3.442 + * Bit 5 => Transmit enable
3.443 + * Bit 4 => Receive enable
3.444 + * Bit 3 => Receive-error/break interrupt enabled
3.445 + * Bit 1 => Clock enable
3.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 count
3.465 + * Bits 8-11 Framing erro count
3.466 + * Bit 7 - Receive error
3.467 + * Bit 6 - Transmit end
3.468 + * Bit 5 - Transmit FIFO data empty
3.469 + * Bit 4 - Break detect
3.470 + * Bit 3 - Framing error
3.471 + * Bit 2 - Parity error
3.472 + * Bit 1 - Receive FIFO data full
3.473 + * Bit 0 - Receive data ready
3.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 DR
3.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 transmission
3.518 + * time of a single frame.
3.519 + *
3.520 + * If transmit queue is non-empty:
3.521 + * Transmit one byte and remove from queue
3.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 been
3.525 + * received in the last 2 ticks (including this one), set the DR flag and
3.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 +}
.