From 1191d479c5b987edd4dff9f40d166070725d4d44 Mon Sep 17 00:00:00 2001 From: kostic2000 Date: Wed, 4 Oct 2017 09:59:33 +0100 Subject: [PATCH] Add support for framing error in uart (#258) * uart: Add support for a framing error. Useful for detecting breaks * Fix spacing for "if" --- simavr/sim/avr_uart.c | 70 ++++++++++++++++++++++++++++--------------- simavr/sim/avr_uart.h | 6 +++- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/simavr/sim/avr_uart.c b/simavr/sim/avr_uart.c index 49ac1b2..bde5cc0 100644 --- a/simavr/sim/avr_uart.c +++ b/simavr/sim/avr_uart.c @@ -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); diff --git a/simavr/sim/avr_uart.h b/simavr/sim/avr_uart.h index dd3a536..f480385 100644 --- a/simavr/sim/avr_uart.h +++ b/simavr/sim/avr_uart.h @@ -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)) -- 2.39.5