|
Message
From: György 'nog' Jeney<nog@s...>
Date: Sun May 29 17:52:56 CEST 2005
Subject: [openrisc] [or1ksim #100] UART: Move RX logic out of uart_clock16
[2/6]
Hi,Changelog says it all. ChangeLog: * Move RX logic out of uart_clock16.
nog. -------------- next part -------------- --- ../or1ksim-patch/peripheral/16450.c 2005-05-29 15:50:19.000000000 +0200 +++ peripheral/16450.c 2005-05-29 15:49:27.000000000 +0200 @@ -52,6 +52,12 @@ DEFAULT_DEBUG_CHANNEL(uart); #define MIN(a,b) ((a) < (b) ? (a) : (b)) +void uart_recv_break(void *dat); +void uart_recv_char(void *dat); +void uart_check_vapi(void *dat); +void uart_check_char(void *dat); +static void uart_sched_recv_check(struct dev_16450 *uart); +static void uart_vapi_cmd(void *dat); void uart_tx_send(void *dat); /* Number of clock cycles (one clock cycle is one call to the uart_clock()) @@ -220,6 +226,119 @@ void uart_tx_send(void *dat) } } +/*-------------------------------------------------------[ Receiver logic ]---*/ +/* Adds a character to the RX FIFO */ +static void uart_add_char (struct dev_16450 *uart, int ch) +{ + uart->regs.lsr |= UART_LSR_RDRDY; + uart->istat.timeout_count = 0; + + if (uart->istat.rxbuf_full + 1 > uart->fifo_len) { + uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR; + } else { + TRACE("add %02x\n", ch); + uart->regs.rxbuf[uart->istat.rxbuf_head] = ch; + uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len; + if(!uart->istat.rxbuf_full++) { + uart->regs.lsr |= ch >> 8; + } + } +} + +/* Called when a break sequence is about to start. It stops receiveing + * characters and schedules the uart_recv_break to send the break */ +void uart_recv_break_start(void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.receiveing = 0; + uart->istat.recv_break = 1; + + SCHED_FIND_REMOVE(uart_recv_char, uart); + + if(uart->vapi_id && (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr)) + uart_vapi_cmd(uart); + + SCHED_ADD(uart_recv_break, uart, + UART_BREAK_COUNT * uart->vapi.char_clks * UART_CLOCK_DIVIDER); +} + +/* Stops sending breaks and starts receiveing characters */ +void uart_recv_break_stop(void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.recv_break = 0; + SCHED_FIND_REMOVE(uart_recv_break, dat); +} + +/* Receives a break */ +void uart_recv_break(void *dat) +{ + struct dev_16450 *uart = dat; + unsigned lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY; + + uart_add_char(uart, lsr << 8); +} + +/* Moves a character from the serial register to the RX FIFO */ +void uart_recv_char(void *dat) +{ + struct dev_16450 *uart = dat; + uint16_t char_to_add; + + /* Set unused character bits to zero and allow lsr register in fifo */ + char_to_add = uart->iregs.rxser & (((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00); + + TRACE("Receiving 0x%02"PRIx16"'%c' via UART at %"PRIxADDR"\n", + char_to_add, (char)char_to_add, uart->baseaddr); + PRINTF ("%c", (char)char_to_add); + + if (uart->regs.mcr & UART_MCR_LOOP) { + uart->iregs.rxser = uart->iregs.loopback; + uart->istat.receiveing = 1; + SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER); + } else { + uart->istat.receiveing = 0; + uart_sched_recv_check(uart); + if(uart->vapi_id && (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr)) + SCHED_ADD(uart_vapi_cmd, uart, 0);
+ }
+
+ uart_add_char(uart, char_to_add);
+}
+
+/* Checks if there is a character waiting to be received */
+void uart_check_char(void *dat)
+{
+ struct dev_16450 *uart = dat;
+ char buffer[1];
+ int retval;
+
+ /* Check if there is something waiting, and put it into rxser */
+ retval = channel_read(uart->channel, buffer, 1);
+ if(retval > 0) {
+ uart->iregs.rxser = (unsigned char)buffer[0];
+ uart->istat.receiveing = 1;
+ SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
+ return;
+ }
+
+ if(!retval) {
+ SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
+ return;
+ }
+
+ if(retval < 0)
+ perror(uart->channel_str);
+}
+
+static void uart_sched_recv_check(struct dev_16450 *uart)
+{
+ if(!uart->vapi_id)
+ SCHED_ADD(uart_check_char, uart, UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER);
+}
+
/* Set a specific UART register with value. */
void uart_write_byte(oraddr_t addr, uint8_t value, void *dat)
{
@@ -343,10 +462,12 @@ uint8_t uart_read_byte(oraddr_t addr, vo
value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
uart->istat.rxbuf_full--;
- }
+ TRACE("Reading %"PRIx8" out of RX FIFO\n", value);
+ } else
+ TRACE("Trying to read out of RX FIFO but it's empty!\n");
- if (uart->istat.rxbuf_full)
- uart->regs.lsr |= UART_LSR_RDRDY;
+ if(uart->istat.rxbuf_full)
+ uart->regs.lsr |= UART_LSR_RDRDY | uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
else
uart->regs.lsr &= ~UART_LSR_RDRDY;
@@ -388,8 +509,9 @@ uint8_t uart_read_byte(oraddr_t addr, vo
/*--------------------------------------------------------[ VAPI handling ]---*/
/* Decodes the read vapi command */
-static void uart_vapi_cmd(struct dev_16450 *uart)
+static void uart_vapi_cmd(void *dat)
{
+ struct dev_16450 *uart = dat;
int received = 0;
while (!received) {
@@ -425,7 +547,10 @@ static void uart_vapi_cmd(struct dev_164
if(uart->regs.lcr & UART_LCR_PARITY)
uart->iregs.rxser |= UART_LSR_PARITY << 8;
}
- uart->istat.rxser_full = 1;
+ if(!uart->istat.recv_break) {
+ uart->istat.receiveing = 1;
+ SCHED_ADD(uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER);
+ }
received = 1;
break;
case 0x01:
@@ -439,8 +564,25 @@ static void uart_vapi_cmd(struct dev_164
uart->vapi.skew = (signed short)(data & 0xffff);
break;
case 0x04:
- uart->vapi.next_break_cnt = data & 0xffff;
- uart->vapi.next_break = (data >> 16) & 1;
+ if((data >> 16) & 1) {
+ /* If data & 0xffff is 0 then set the break imediatly and handle the
+ * following commands as appropriate */
+ if(!(data & 0xffff))
+ uart_recv_break_start(uart);
+ else
+ /* Schedule a job to start sending breaks */
+ SCHED_ADD(uart_recv_break_start, uart,
+ (data & 0xffff) * UART_CLOCK_DIVIDER);
+ } else {
+ /* If data & 0xffff is 0 then release the break imediatly and handle
+ * the following commands as appropriate */
+ if(!(data & 0xffff))
+ uart_recv_break_stop(uart);
+ else
+ /* Schedule a job to stop sending breaks */
+ SCHED_ADD(uart_recv_break_stop, uart,
+ (data & 0xffff) * UART_CLOCK_DIVIDER);
+ }
break;
default:
WARN("WARNING: Invalid vapi command %02lx\n", data >> 24);
@@ -461,22 +603,8 @@ void uart_vapi_read (unsigned long id, u
fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
exit (1);
}
-}
-
-/* Adds a character to the FIFO */
-
-void uart_add_char (struct dev_16450 *uart, int ch)
-{
- if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
- uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
- else {
- TRACE("add %02x\n", ch);
- uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
- uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
- uart->istat.rxbuf_full++;
- }
- uart->regs.lsr |= UART_LSR_RDRDY;
- uart->istat.timeout_count = 0;
+ if(!uart->istat.receiveing)
+ uart_vapi_cmd(uart);
}
/* Simulation hook. Must be called every clock cycle to simulate all UART
@@ -484,7 +612,6 @@ void uart_add_char (struct dev_16450 *ua
void uart_clock16 (void *dat)
{
struct dev_16450 *uart = dat;
- int retval;
/* Schedule for later */
SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
@@ -498,76 +625,6 @@ void uart_clock16 (void *dat)
TRACE("\tChannel stream or VAPI checks out ok\n");
- if (uart->vapi.next_break_cnt >= 0)
- if (--uart->vapi.next_break_cnt < 0) {
- if (!(uart->vapi.cur_break = uart->vapi.next_break))
- uart->istat.break_set = 0;
- }
-
- /***************** Receive *****************/
-
- /* Is there a break? */
- if (uart->vapi.cur_break) {
- uart->vapi.cur_break_cnt++;
- if (uart->vapi.cur_break_cnt > UART_BREAK_COUNT * uart->vapi.char_clks) {
- if (!uart->istat.break_set) {
- unsigned lsr;
- uart->istat.break_set = 1;
- lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY;
- PRINTF ("[%x]\n", uart->regs.lsr);
- uart->istat.rxser_full = 0;
- uart->istat.rxser_clks = 0;
- uart_add_char (uart, lsr << 8);
- } else
- uart->vapi.cur_break_cnt = 0;
- }
- if (uart->istat.rxser_full) {
- uart->istat.rxser_full = 0;
- uart->istat.rxser_clks = 0;
- }
- } else {
- if (uart->istat.rxser_full) {
- if (uart->char_clks <= uart->istat.rxser_clks++) {
- /* Set unused character bits to zero and allow lsr register in fifo */
- uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
- TRACE("\tReceiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
- uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
- PRINTF ("%c", (char)uart->iregs.rxser);
- uart->istat.rxser_full = 0;
- uart->istat.rxser_clks = 0;
- uart_add_char (uart, uart->iregs.rxser);
- }
- }
- }
-
- /* Check if there is something waiting, and put it into rxser */
- if (uart->regs.mcr & UART_MCR_LOOP) {
- uart->iregs.rxser = uart->iregs.loopback;
- uart->istat.rxser_full = 1;
- } else {
- if (!uart->vapi_id) {
- if(uart->istat.rxser_full == 0) {
- if (uart->slowdown)
- uart->slowdown--;
- else {
- char buffer[1];
- retval = channel_read(uart->channel, buffer, 1);
- if(retval < 0)
- perror(uart->channel_str);
- else if(retval > 0) {
- uart->iregs.rxser = (unsigned char)buffer[0];
- uart->istat.rxser_full = 1;
- } else
- uart->slowdown = UART_FGETC_SLOWDOWN;
- }
- }
- } else { /* VAPI */
- /* do not handle commands while receiving */
- if (uart->istat.rxser_full) return;
- uart_vapi_cmd(uart);
- }
- }
-
/***************** Loopback *****************/
if (uart->regs.mcr & UART_MCR_LOOP) {
TRACE("uart_clock: Loopback\n");
@@ -594,13 +651,6 @@ void uart_clock16 (void *dat)
if (uart->regs.lsr & UART_LSR_RDRDY)
uart->istat.timeout_count++;
- /* Update LSR error bits from the ones from rx FIFO */
- if (uart->istat.rxbuf_full) {
- uart->regs.lsr |= uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8;
- /* we must delete the lsr status, so that we can clear it from lsr */
- uart->regs.rxbuf[uart->istat.rxbuf_tail] &= 0xff;
- }
-
/* Interrupt detection in proper priority order. */
uart->regs.iir = UART_IIR_NO_INT;
if (uart->regs.ier & UART_IER_RLSI && /* Receiver LS */
@@ -660,24 +710,21 @@ void uart_reset(void *dat)
uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0;
uart->istat.txbuf_head = uart->istat.txbuf_tail = 0;
- uart->istat.rxser_full = 0;
uart->istat.txbuf_full = uart->istat.rxbuf_full = 0;
- uart->istat.rxser_clks = 0;
-
uart->istat.thre_int = 0;
- uart->istat.break_set = 0;
uart->istat.timeout_count = 0;
// For FIFO-mode only, THRE interrupt is set when both THR and FIFO are empty
uart->istat.thre_int = (uart->fifo_len == 16);
uart->char_clks = 0;
- uart->slowdown = UART_FGETC_SLOWDOWN;
uart->iregs.txser = 0;
uart->iregs.rxser = 0;
uart->iregs.loopback = 0;
+ uart->istat.receiveing = 0;
+ uart->istat.recv_break = 0;
memset(uart->regs.txbuf, 0, sizeof(uart->regs.txbuf));
memset(uart->regs.rxbuf, 0, sizeof(uart->regs.rxbuf));
@@ -693,8 +740,6 @@ void uart_reset(void *dat)
uart->regs.msr = 0;
uart->regs.scr = 0;
- uart->vapi.cur_break = uart->vapi.cur_break_cnt = uart->vapi.next_break = 0;
- uart->vapi.next_break_cnt = -1;
uart->vapi.skew = 0;
uart->vapi.lcr = 0;
uart->vapi.dll = 0;
@@ -705,6 +750,7 @@ void uart_reset(void *dat)
memset(uart->vapi_buf, 0, sizeof(uart->vapi_buf));
SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
+ uart_sched_recv_check(uart);
}
/* Print register values on stdout. */
@@ -732,8 +778,6 @@ void uart_status(void *dat)
PRINTF("\nInternal status (sim debug):\n");
PRINTF("char_clks: %ld\n", uart->char_clks);
- PRINTF("rxser_clks: %ld\n", uart->istat.rxser_clks);
- PRINTF("rxser: %d\n", uart->istat.rxser_full);
PRINTF("rxbuf_full: %d txbuf_full: %d\n", uart->istat.rxbuf_full, uart->istat.txbuf_full);
PRINTF("Using IRQ%i\n", uart->irq);
if (uart->vapi_id)
--- ../or1ksim-patch/peripheral/16450.h 2005-05-29 15:50:16.000000000 +0200
+++ peripheral/16450.h 2005-05-29 15:49:00.000000000 +0200
@@ -57,13 +57,12 @@ struct dev_16450 {
int txbuf_tail;
int rxbuf_head;
int rxbuf_tail;
- unsigned int rxser_full;
unsigned int txbuf_full;
unsigned int rxbuf_full;
unsigned thre_int;
- unsigned break_set;
- unsigned long rxser_clks;
unsigned timeout_count;
+ int receiveing; /* Receiveing a char */
+ int recv_break; /* Receiveing a break */
} istat; /* Internal status */
/* Clocks per char */
@@ -75,10 +74,6 @@ struct dev_16450 {
int dll, dlh;
int lcr;
int skew;
- int next_break;
- int next_break_cnt;
- int cur_break;
- int cur_break_cnt;
} vapi;
/* Required by VAPI - circular buffer */
@@ -91,9 +86,6 @@ struct dev_16450 {
/* Length of FIFO, 16 for 16550, 1 for 16450 */
int fifo_len;
- /* fgetc slowdown */
- int slowdown;
-
struct channel *channel;
/* Configuration */
|
 |