Commit 1191d479c5b987edd4dff9f40d166070725d4d44
authorkostic2000 <kostic2000@users.noreply.github.com>
Wed, 4 Oct 2017 08:59:33 +0000 (09:59 +0100)
committerMichel Pollet <github.com@pollet.net>
Wed, 4 Oct 2017 08:59:33 +0000 (09:59 +0100)
* uart: Add support for a framing error. Useful for detecting breaks

* Fix spacing for "if"

2 files changed:
simavr/sim/avr_uart.c
simavr/sim/avr_uart.h

index 49ac1b285e7c48961009c986fb41ba84db0ab137..bde5cc03f8739d0fc3ccd8fb395c6e3f26018a34 100644 (file)
@@ -45,7 +45,7 @@
 #define TRACE(_w)
 #endif
 
-DEFINE_FIFO(uint8_t, uart_fifo);
+DEFINE_FIFO(uint16_t, uart_fifo);
 
 static inline void
 avr_uart_clear_interrupt(
@@ -129,34 +129,52 @@ avr_uart_rxc_raise(
 }
 
 static uint8_t
-avr_uart_rxc_read(
+avr_uart_status_read(
                struct avr_t * avr,
                avr_io_addr_t addr,
                void * param)
 {
        avr_uart_t * p = (avr_uart_t *)param;
-       uint8_t v = avr_core_watch_read(avr, addr);
 
-       //static uint8_t old = 0xff; if (v != old) printf("UCSRA read %02x\n", v); old = v;
-       //
-       // if RX is enabled, and there is nothing to read, and
-       // the AVR core is reading this register, it's probably
-       // to poll the RXC TXC flag and spinloop
-       // so here we introduce a usleep to make it a bit lighter
-       // on CPU and let data arrive
-       //
-       uint8_t ri = !avr_regbit_get(avr, p->rxen) || !avr_regbit_get(avr, p->rxc.raised);
-       uint8_t ti = !avr_regbit_get(avr, p->txen) || !avr_regbit_get(avr, p->txc.raised);
-
-       if (p->flags & AVR_UART_FLAG_POLL_SLEEP) {
-
-               if (ri && ti)
-                       usleep(1);
+       if (addr == p->fe.reg) {
+               if (!uart_fifo_isempty(&p->input)) {
+                       uint16_t d = uart_fifo_read_at(&p->input, 0);
+
+                       uint8_t st = avr->data[addr];
+
+                       st &= ~(p->fe.mask << p->fe.bit);
+                       if (d & UART_INPUT_FE) {
+                               st |= p->fe.mask << p->fe.bit;
+                       }
+
+                       avr->data[addr] = st;
+               }
        }
-       // if reception is idle and the fifo is empty, tell whomever there is room
-       if (avr_regbit_get(avr, p->rxen) && uart_fifo_isempty(&p->input)) {
-               avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 0);
-               avr_raise_irq(p->io.irq + UART_IRQ_OUT_XON, 1);
+
+       uint8_t v = avr_core_watch_read(avr, addr);
+
+       if (addr == p->rxc.raised.reg) {
+               //static uint8_t old = 0xff; if (v != old) printf("UCSRA read %02x\n", v); old = v;
+               //
+               // if RX is enabled, and there is nothing to read, and
+               // the AVR core is reading this register, it's probably
+               // to poll the RXC TXC flag and spinloop
+               // so here we introduce a usleep to make it a bit lighter
+               // on CPU and let data arrive
+               //
+               uint8_t ri = !avr_regbit_get(avr, p->rxen) || !avr_regbit_get(avr, p->rxc.raised);
+               uint8_t ti = !avr_regbit_get(avr, p->txen) || !avr_regbit_get(avr, p->txc.raised);
+
+               if (p->flags & AVR_UART_FLAG_POLL_SLEEP) {
+
+                       if (ri && ti)
+                               usleep(1);
+               }
+               // if reception is idle and the fifo is empty, tell whomever there is room
+               if (avr_regbit_get(avr, p->rxen) && uart_fifo_isempty(&p->input)) {
+                       avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 0);
+                       avr_raise_irq(p->io.irq + UART_IRQ_OUT_XON, 1);
+               }
        }
 
        return v;
@@ -182,7 +200,7 @@ avr_uart_read(
                goto avr_uart_read_check;
        }
        if (!uart_fifo_isempty(&p->input)) { // probably redundant check
-               v = uart_fifo_read(&p->input);
+               v = (uint8_t)uart_fifo_read(&p->input) & 0xFF;
                p->rx_cnt++;
                if ((p->rx_cnt > 1) && // UART actually has 2-character rx buffer
                                ((avr->cycle-p->rxc_raise_time)/p->rx_cnt < p->cycles_per_byte)) {
@@ -519,8 +537,12 @@ avr_uart_init(
 
        avr_register_io_write(avr, p->r_udr, avr_uart_udr_write, p);
        avr_register_io_read(avr, p->r_udr, avr_uart_read, p);
+
+       // status bits
        // monitor code that reads the rxc flag, and delay it a bit
-       avr_register_io_read(avr, p->rxc.raised.reg, avr_uart_rxc_read, p);
+       avr_register_io_read(avr, p->rxc.raised.reg, avr_uart_status_read, p);
+       if (p->fe.reg != p->rxc.raised.reg)
+               avr_register_io_read(avr, p->fe.reg, avr_uart_status_read, p);
 
        if (p->udrc.vector)
                avr_register_io_write(avr, p->udrc.enable.reg, avr_uart_write, p);
index dd3a53626780d6962eb6fa4db8c057e81b7c1523..f4803853916e78237e1d16310dc38c13e16c2c53 100644 (file)
@@ -30,7 +30,7 @@ extern "C" {
 
 #include "fifo_declare.h"
 
-DECLARE_FIFO(uint8_t, uart_fifo, 64);
+DECLARE_FIFO(uint16_t, uart_fifo, 64);
 
 /*
  * The method of "connecting" the the UART from external code is to use 4 IRQS.
@@ -72,6 +72,10 @@ enum {
        UART_IRQ_COUNT
 };
 
+enum {
+       UART_INPUT_FE = 0x8000          // framing error
+};
+
 // add port number to get the real IRQ
 #define AVR_IOCTL_UART_GETIRQ(_name) AVR_IOCTL_DEF('u','a','r',(_name))