filename | src/sh4/scif.c |
changeset | 1077:136fc24d17ef |
prev | 975:007bf7eb944f |
next | 1078:d8f1cf224e7e |
author | nkeynes |
date | Wed Oct 07 17:53:56 2009 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Create a host attachment for the SCIF serial port. By default, uses /dev/console Add general fd listening to netutil, and rename to ioutil Add SCIF update on port read/write - fixes KOS timing problems but needs to be redone properly. |
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);
31 void SCIF_run_to(uint32_t nanosecs);
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 serial_device_t serial_get_device( )
59 {
60 return serial_device;
61 }
63 serial_device_t serial_attach_device( serial_device_t dev )
64 {
65 serial_device_t olddev = serial_device;
66 if( serial_device != NULL )
67 serial_detach_device();
68 serial_device = dev;
69 if( serial_device != NULL && serial_device->attach != NULL )
70 serial_device->attach(serial_device);
71 return olddev;
72 }
75 serial_device_t serial_detach_device( void )
76 {
77 serial_device_t dev = serial_device;
78 if( serial_device != NULL && serial_device->detach != NULL ) {
79 serial_device->detach(serial_device);
80 }
81 serial_device = NULL;
82 return dev;
83 }
85 void serial_destroy_device( serial_device_t dev )
86 {
87 if( dev != NULL ) {
88 if( serial_device == dev )
89 serial_detach_device();
90 if( dev->destroy )
91 dev->destroy(dev);
92 }
93 }
95 /**
96 * Add a block of data to the serial receive queue. The data will be received
97 * by the CPU at the appropriate baud rate.
98 */
99 void serial_transmit_data( char *data, int length ) {
100 if( length == 0 )
101 return;
102 serial_data_block_t block =
103 g_malloc( sizeof( struct serial_data_block ) + length );
104 block->length = length;
105 block->offset = 0;
106 block->next = NULL;
107 memcpy( block->data, data, length );
109 if( serial_recvq_head == NULL ) {
110 serial_recvq_head = serial_recvq_tail = block;
111 } else {
112 serial_recvq_tail->next = block;
113 serial_recvq_tail = block;
114 }
115 }
117 /**
118 * Dequeue a byte from the serial input queue
119 */
120 static int serial_transmit_dequeue( ) {
121 if( serial_recvq_head != NULL ) {
122 uint8_t val = serial_recvq_head->data[serial_recvq_head->offset++];
123 if( serial_recvq_head->offset >= serial_recvq_head->length ) {
124 serial_data_block_t next = serial_recvq_head->next;
125 g_free( serial_recvq_head );
126 serial_recvq_head = next;
127 if( next == NULL )
128 serial_recvq_tail = NULL;
129 }
130 return (int)(unsigned int)val;
131 }
132 return -1;
134 }
136 void serial_transmit_break() {
137 SCIF_set_break();
138 }
140 /********************************* SCIF *************************************/
142 #define FIFO_LENGTH 16
143 #define FIFO_ARR_LENGTH (FIFO_LENGTH+1)
145 /* Serial control register flags */
146 #define SCSCR2_TIE 0x80
147 #define SCSCR2_RIE 0x40
148 #define SCSCR2_TE 0x20
149 #define SCSCR2_RE 0x10
150 #define SCSCR2_REIE 0x08
151 #define SCSCR2_CKE 0x02
153 #define IS_TRANSMIT_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TIE)
154 #define IS_RECEIVE_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RIE)
155 #define IS_RECEIVE_ERROR_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & (SCSCR2_RIE|SCSCR2_REIE))
156 /* Receive is enabled if the RE bit is set in SCSCR2, and the ORER bit is cleared in SCLSR2 */
157 #define IS_RECEIVE_ENABLED() ( (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RE) && ((MMIO_READ(SCIF,SCLSR2) & SCLSR2_ORER) == 0) )
158 /* Transmit is enabled if the TE bit is set in SCSCR2 */
159 #define IS_TRANSMIT_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TE)
160 #define IS_LOOPBACK_ENABLED() (MMIO_READ(SCIF,SCFCR2) & SCFCR2_LOOP)
162 /* Serial status register flags */
163 #define SCFSR2_ER 0x80
164 #define SCFSR2_TEND 0x40
165 #define SCFSR2_TDFE 0x20
166 #define SCFSR2_BRK 0x10
167 #define SCFSR2_RDF 0x02
168 #define SCFSR2_DR 0x01
170 /* FIFO control register flags */
171 #define SCFCR2_MCE 0x08
172 #define SCFCR2_TFRST 0x04
173 #define SCFCR2_RFRST 0x02
174 #define SCFCR2_LOOP 0x01
176 /* Line Status Register */
177 #define SCLSR2_ORER 0x01
179 struct SCIF_fifo {
180 int head;
181 int tail;
182 int trigger;
183 uint8_t data[FIFO_ARR_LENGTH];
184 };
186 int SCIF_recvq_triggers[4] = {1, 4, 8, 14};
187 struct SCIF_fifo SCIF_recvq = {0,0,1};
189 int SCIF_sendq_triggers[4] = {8, 4, 2, 1};
190 struct SCIF_fifo SCIF_sendq = {0,0,8};
192 /**
193 * Flag to indicate if data was received (ie added to the receive queue)
194 * during the last SCIF clock tick. Used to determine when to set the DR
195 * flag.
196 */
197 gboolean SCIF_rcvd_last_tick = FALSE;
199 uint32_t SCIF_tick_period = 0;
200 uint32_t SCIF_tick_remainder = 0;
201 uint32_t SCIF_slice_cycle = 0;
203 void SCIF_save_state( FILE *f )
204 {
205 fwrite( &SCIF_recvq, sizeof(SCIF_recvq), 1, f );
206 fwrite( &SCIF_sendq, sizeof(SCIF_sendq), 1, f );
207 fwrite( &SCIF_rcvd_last_tick, sizeof(gboolean), 1, f );
209 }
211 int SCIF_load_state( FILE *f )
212 {
213 fread( &SCIF_recvq, sizeof(SCIF_recvq), 1, f );
214 fread( &SCIF_sendq, sizeof(SCIF_sendq), 1, f );
215 fread( &SCIF_rcvd_last_tick, sizeof(gboolean), 1, f );
216 return 0;
217 }
219 static inline uint8_t SCIF_recvq_size( )
220 {
221 int val = SCIF_recvq.tail - SCIF_recvq.head;
222 if( val < 0 ) {
223 val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;
224 }
225 return val;
226 }
228 int SCIF_recvq_dequeue( gboolean clearFlags )
229 {
230 uint8_t result;
231 uint32_t tmp, length;
232 if( SCIF_recvq.head == SCIF_recvq.tail )
233 return -1; /* No data */
234 result = SCIF_recvq.data[SCIF_recvq.head++];
235 if( SCIF_recvq.head > FIFO_LENGTH )
236 SCIF_recvq.head = 0;
238 /* Update data count register */
239 tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
240 length = SCIF_recvq_size();
241 MMIO_WRITE( SCIF, SCFDR2, tmp | length );
243 /* Clear flags (if requested ) */
244 if( clearFlags && length < SCIF_recvq.trigger ) {
245 tmp = SCFSR2_RDF;
246 if( length == 0 )
247 tmp |= SCFSR2_DR;
248 tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
249 MMIO_WRITE( SCIF, SCFSR2, tmp );
250 /* If both flags are cleared, clear the interrupt as well */
251 if( (tmp & (SCFSR2_DR|SCFSR2_RDF)) == 0 && IS_RECEIVE_IRQ_ENABLED() )
252 intc_clear_interrupt( INT_SCIF_RXI );
253 }
255 return (int)(unsigned int)result;
256 }
258 gboolean SCIF_recvq_enqueue( uint8_t value )
259 {
260 uint32_t tmp, length;
261 int newpos = SCIF_recvq.tail + 1;
262 if( newpos > FIFO_LENGTH )
263 newpos = 0;
264 if( newpos == SCIF_recvq.head ) {
265 /* FIFO full - set ORER and discard the value */
266 MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );
267 if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
268 intc_raise_interrupt( INT_SCIF_ERI );
269 return FALSE;
270 }
271 SCIF_recvq.data[SCIF_recvq.tail] = value;
273 /* Update data count register */
274 tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
275 length = SCIF_recvq_size();
276 MMIO_WRITE( SCIF, SCFDR2, tmp | length );
278 /* Update status register */
279 tmp = MMIO_READ( SCIF, SCFSR2 );
280 if( length >= SCIF_recvq.trigger ) {
281 tmp |= SCFSR2_RDF;
282 if( IS_RECEIVE_IRQ_ENABLED() )
283 intc_raise_interrupt( INT_SCIF_RXI );
284 DMAC_trigger( DMAC_SCIF_RDF );
285 }
286 MMIO_WRITE( SCIF, SCFSR2, tmp );
287 return TRUE;
288 }
291 /**
292 * Reset the receive FIFO to its initial state. Manual is unclear as to
293 * whether this also clears flags/interrupts, but we're assuming here that
294 * it does until proven otherwise.
295 */
296 void SCIF_recvq_clear( void )
297 {
298 SCIF_recvq.head = SCIF_recvq.tail = 0;
299 MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );
300 MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );
301 if( IS_RECEIVE_IRQ_ENABLED() )
302 intc_clear_interrupt( INT_SCIF_RXI );
303 }
305 static inline uint8_t SCIF_sendq_size( )
306 {
307 int val = SCIF_sendq.tail - SCIF_sendq.head;
308 if( val < 0 ) {
309 val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;
310 }
311 return val;
312 }
314 /**
315 * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),
316 * updating all status flags as required.
317 * @return The byte dequeued, or -1 if the queue is empty.
318 */
319 int SCIF_sendq_dequeue( )
320 {
321 uint8_t result;
322 uint32_t tmp, length;
323 if( SCIF_sendq.head == SCIF_sendq.tail )
324 return -1; /* No data */
326 /* Update queue head pointer */
327 result = SCIF_sendq.data[SCIF_sendq.head++];
328 if( SCIF_sendq.head > FIFO_LENGTH )
329 SCIF_sendq.head = 0;
331 /* Update data count register */
332 tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
333 length = SCIF_sendq_size();
334 MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
336 /* Update status register */
337 if( length <= SCIF_sendq.trigger ) {
338 tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;
339 if( length == 0 )
340 tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */
341 if( IS_TRANSMIT_IRQ_ENABLED() )
342 intc_raise_interrupt( INT_SCIF_TXI );
343 DMAC_trigger( DMAC_SCIF_TDE );
344 MMIO_WRITE( SCIF, SCFSR2, tmp );
345 }
346 return (int)(unsigned int)result;
347 }
349 /**
350 * Enqueue a single byte in the SCIF transmit queue. If the queue is full,
351 * the value will be discarded.
352 * @param value to be queued.
353 * @param clearFlags TRUE if the TEND/TDFE flags should be cleared
354 * if the queue exceeds the trigger level. (According to the manual,
355 * DMAC writes will clear the flag, whereas regular SH4 writes do NOT
356 * automatically clear it. Go figure).
357 * @return gboolean TRUE if the value was queued, FALSE if the queue was
358 * full.
359 */
360 gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )
361 {
362 uint32_t tmp, length;
363 int newpos = SCIF_sendq.tail + 1;
364 if( newpos > FIFO_LENGTH )
365 newpos = 0;
366 if( newpos == SCIF_sendq.head ) {
367 /* FIFO full - discard */
368 return FALSE;
369 }
370 SCIF_sendq.data[SCIF_sendq.tail] = value;
371 SCIF_sendq.tail = newpos;
373 /* Update data count register */
374 tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
375 length = SCIF_sendq_size();
376 MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
378 /* Update flags if requested */
379 if( clearFlags ) {
380 tmp = SCFSR2_TEND;
381 if( length > SCIF_sendq.trigger ) {
382 tmp |= SCFSR2_TDFE;
383 if( IS_TRANSMIT_IRQ_ENABLED() )
384 intc_clear_interrupt( INT_SCIF_TXI );
385 }
386 tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
387 MMIO_WRITE( SCIF, SCFSR2, tmp );
388 }
389 return TRUE;
390 }
392 void SCIF_sendq_clear( void )
393 {
394 SCIF_sendq.head = SCIF_sendq.tail = 0;
395 MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );
396 MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );
397 if( IS_TRANSMIT_IRQ_ENABLED() ) {
398 intc_raise_interrupt( INT_SCIF_TXI );
399 DMAC_trigger( DMAC_SCIF_TDE );
400 }
401 }
403 /**
404 * Update the SCFSR2 status register with the given mask (ie clear any values
405 * that are set to 0 in the mask. According to a strict reading of the doco
406 * though, the bits will only actually clear if the flag state is no longer
407 * true, so we need to recheck everything...
408 */
409 void SCIF_update_status( uint32_t mask )
410 {
411 uint32_t value = MMIO_READ( SCIF, SCFSR2 );
412 uint32_t result = value & mask;
413 uint32_t sendq_size = SCIF_sendq_size();
414 uint32_t recvq_size = SCIF_recvq_size();
416 if( sendq_size != 0 )
417 result |= SCFSR2_TEND;
419 if( sendq_size <= SCIF_sendq.trigger )
420 result |= SCFSR2_TDFE;
421 else if( (result & SCFSR2_TDFE) == 0 && IS_TRANSMIT_IRQ_ENABLED() )
422 intc_clear_interrupt( INT_SCIF_TXI );
424 if( recvq_size >= SCIF_recvq.trigger )
425 result |= SCFSR2_RDF;
426 if( (value & SCFSR2_DR) != 0 && (result & SCFSR2_DR) == 0 &&
427 recvq_size != 0 )
428 result |= SCFSR2_DR;
429 if( (result & (SCFSR2_DR|SCFSR2_RDF)) == 0 && IS_RECEIVE_IRQ_ENABLED() )
430 intc_clear_interrupt( INT_SCIF_RXI );
432 if( IS_RECEIVE_ERROR_IRQ_ENABLED() ) {
433 if( (result & SCFSR2_BRK) == 0 )
434 intc_clear_interrupt( INT_SCIF_BRI );
435 if( (result & SCFSR2_ER) == 0 &&
436 (MMIO_READ( SCIF, SCLSR2 ) & SCLSR2_ORER) == 0 )
437 intc_clear_interrupt( INT_SCIF_ERI );
438 }
439 }
441 /**
442 * Set the break detected flag
443 */
444 void SCIF_set_break( void )
445 {
446 MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );
447 if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
448 intc_raise_interrupt( INT_SCIF_BRI );
449 }
451 const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};
453 /**
454 * Calculate the current line speed.
455 */
456 void SCIF_update_line_speed( void )
457 {
458 /* If CKE1 is set, use the external clock as a base */
459 if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {
462 } else {
464 /* Otherwise, SH4 peripheral clock divided by n */
465 int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];
467 /* Then process the bitrate register */
468 int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;
470 int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );
472 if( serial_device != NULL && serial_device->set_line_speed != NULL )
473 serial_device->set_line_speed( serial_device, baudrate );
475 SCIF_tick_period = sh4_peripheral_period * (32 * mult * (bbr+1));
477 /*
478 clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );
479 */
480 }
481 }
483 MMIO_REGION_READ_FN( SCIF, reg )
484 {
485 SCIF_run_to(sh4r.slice_cycle);
486 reg &= 0xFFF;
487 switch( reg ) {
488 case SCFRDR2: /* Receive data */
489 return SCIF_recvq_dequeue(FALSE);
490 default:
491 return MMIO_READ( SCIF, reg );
492 }
493 }
494 MMIO_REGION_READ_DEFSUBFNS(SCIF)
497 MMIO_REGION_WRITE_FN( SCIF, reg, val )
498 {
499 SCIF_run_to(sh4r.slice_cycle);
500 uint32_t tmp;
501 reg &= 0xFFF;
502 switch( reg ) {
503 case SCSMR2: /* Serial mode register */
504 /* Bit 6 => 0 = 8-bit, 1 = 7-bit
505 * Bit 5 => 0 = Parity disabled, 1 = parity enabled
506 * Bit 4 => 0 = Even parity, 1 = Odd parity
507 * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits
508 * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/64
509 */
510 val &= 0x007B;
511 if( serial_device != NULL ) {
512 serial_device->set_line_params( serial_device, val );
513 }
514 tmp = MMIO_READ( SCIF, SCSMR2 );
515 if( (tmp & 0x03) != (val & 0x03) ) {
516 /* Clock change */
517 SCIF_update_line_speed( );
518 }
519 /* Save for later read-back */
520 MMIO_WRITE( SCIF, SCSMR2, val );
521 break;
522 case SCBRR2: /* Bit rate register */
523 MMIO_WRITE( SCIF, SCBRR2, val );
524 SCIF_update_line_speed( );
525 break;
526 case SCSCR2: /* Serial control register */
527 /* Bit 7 => Transmit-FIFO-data-empty interrupt enabled
528 * Bit 6 => Receive-data-full interrupt enabled
529 * Bit 5 => Transmit enable
530 * Bit 4 => Receive enable
531 * Bit 3 => Receive-error/break interrupt enabled
532 * Bit 1 => Clock enable
533 */
534 val &= 0x00FA;
535 /* Clear any interrupts that just became disabled */
536 if( (val & SCSCR2_TIE) == 0 )
537 intc_clear_interrupt( INT_SCIF_TXI );
538 if( (val & SCSCR2_RIE) == 0 )
539 intc_clear_interrupt( INT_SCIF_RXI );
540 if( (val & (SCSCR2_RIE|SCSCR2_REIE)) == 0 ) {
541 intc_clear_interrupt( INT_SCIF_ERI );
542 intc_clear_interrupt( INT_SCIF_BRI );
543 }
545 MMIO_WRITE( SCIF, reg, val );
546 break;
547 case SCFTDR2: /* Transmit FIFO data register */
548 SCIF_sendq_enqueue( val, FALSE );
549 break;
550 case SCFSR2: /* Serial status register */
551 /* Bits 12-15 Parity error count
552 * Bits 8-11 Framing erro count
553 * Bit 7 - Receive error
554 * Bit 6 - Transmit end
555 * Bit 5 - Transmit FIFO data empty
556 * Bit 4 - Break detect
557 * Bit 3 - Framing error
558 * Bit 2 - Parity error
559 * Bit 1 - Receive FIFO data full
560 * Bit 0 - Receive data ready
561 */
562 /* Clear off any flags/interrupts that are being set to 0 */
563 SCIF_update_status( val );
564 break;
565 case SCFCR2: /* FIFO control register */
566 val &= 0x0F;
567 SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];
568 SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];
569 if( val & SCFCR2_TFRST ) {
570 SCIF_sendq_clear();
571 }
572 if( val & SCFCR2_RFRST ) {
573 SCIF_recvq_clear();
574 }
576 MMIO_WRITE( SCIF, reg, val );
577 break;
578 case SCSPTR2: /* Serial Port Register */
579 MMIO_WRITE( SCIF, reg, val );
580 /* NOT IMPLEMENTED - 'direct' serial I/O */
581 if( val != 0 ) {
582 WARN( "SCSPTR2 not implemented: Write %08X", val );
583 }
584 break;
585 case SCLSR2:
586 val = val & SCLSR2_ORER;
587 if( val == 0 ) {
588 MMIO_WRITE( SCIF, SCLSR2, val );
589 if( (MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER) == 0 &&
590 IS_RECEIVE_ERROR_IRQ_ENABLED() )
591 intc_clear_interrupt( INT_SCIF_ERI );
592 }
594 break;
595 }
596 }
598 /**
599 * Actions for a single tick of the serial clock, defined as the transmission
600 * time of a single frame.
601 *
602 * If transmit queue is non-empty:
603 * Transmit one byte and remove from queue
604 * If input receive source is non-empty:
605 * Transfer one byte to the receive queue (if queue is full, byte is lost)
606 * If recvq is non-empty, less than the trigger level, and no data has been
607 * received in the last 2 ticks (including this one), set the DR flag and
608 * IRQ if appropriate.
609 */
610 void SCIF_clock_tick( void )
611 {
612 gboolean rcvd = FALSE;
614 if( IS_LOOPBACK_ENABLED() ) {
615 if( IS_TRANSMIT_ENABLED() ) {
616 int val = SCIF_sendq_dequeue();
617 if( val != -1 && IS_RECEIVE_ENABLED() ) {
618 SCIF_recvq_enqueue( val );
619 rcvd = TRUE;
620 }
621 }
622 } else {
623 if( IS_TRANSMIT_ENABLED() ) {
624 int val = SCIF_sendq_dequeue();
625 if( val != -1 && serial_device != NULL &&
626 serial_device->receive_data != NULL ) {
627 serial_device->receive_data( serial_device, val );
628 }
629 }
631 if( IS_RECEIVE_ENABLED() ) {
632 int val = serial_transmit_dequeue();
633 if( val != -1 ) {
634 SCIF_recvq_enqueue( val );
635 rcvd = TRUE;
636 }
637 }
638 }
640 /* Check if we need to set the DR flag */
641 if( !rcvd && !SCIF_rcvd_last_tick &&
642 SCIF_recvq.head != SCIF_recvq.tail &&
643 SCIF_recvq_size() < SCIF_recvq.trigger ) {
644 uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );
645 if( (tmp & SCFSR2_DR) == 0 ) {
646 MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );
647 if( IS_RECEIVE_IRQ_ENABLED() )
648 intc_raise_interrupt( INT_SCIF_RXI );
649 DMAC_trigger( DMAC_SCIF_RDF );
650 }
651 }
652 SCIF_rcvd_last_tick = rcvd;
653 }
655 void SCIF_reset( void )
656 {
657 SCIF_recvq_clear();
658 SCIF_sendq_clear();
659 SCIF_update_line_speed();
660 }
662 void SCIF_run_to( uint32_t nanosecs )
663 {
664 SCIF_tick_remainder += nanosecs - SCIF_slice_cycle;
665 while( SCIF_tick_remainder >= SCIF_tick_period ) {
666 SCIF_tick_remainder -= SCIF_tick_period;
667 SCIF_clock_tick();
668 }
669 }
671 void SCIF_run_slice( uint32_t nanosecs )
672 {
673 SCIF_run_to(nanosecs);
674 SCIF_slice_cycle = 0;
675 }
.