diff options
Diffstat (limited to 'uart.c')
-rw-r--r-- | uart.c | 120 |
1 files changed, 117 insertions, 3 deletions
@@ -9,18 +9,119 @@ * for more details. */ +#include <stdio.h> +#include <stdlib.h> + #include "nios2sim-ng.h" #include "device.h" #include "uart.h" +#define uart_printf(fmt, args...) fprintf(stdout, fmt, ##args) + +struct uart { + struct io_register regs[UART_REG_COUNT]; + bool has_rx_data; + bool has_tx_data; +}; + +static const uint32_t uart_valid_mask[UART_REG_COUNT] = { + 0x000001FF, /* rxdata */ + 0x000001FF, /* txdata */ + 0x00001FFF, /* status */ + 0x00001FFF, /* control */ + 0x0000FFFF, /* divisor */ + 0x000001FF, /* endofpacket */ +}; + +static const uint32_t uart_readonly_mask[UART_REG_COUNT] = { + 0x000001FF, /* rxdata */ + 0x00000000, /* txdata */ + 0x00000000, /* status */ + 0x00000000, /* control */ + 0x00000000, /* divisor */ + 0x00000000, /* endofpacket */ +}; + static int uart_init(struct device *dev) { + struct uart *u; + struct io_register *regs; + unsigned int i; + + u = malloc(sizeof(struct uart)); + if (unlikely(u == NULL)) + return -1; + + regs = u->regs; + for (i = 0; i < UART_REG_COUNT; i++) { + io_register_init(®s[i], + UART_BASE + REG_TO_OFF(i), + uart_valid_mask[i], + uart_readonly_mask[i], + 0); + } + + u->has_rx_data = false; + u->has_tx_data = false; + + dev->priv = u; + return 0; } -static bool uart_is_dev_addr(struct device *dev, uint32_t addr) +static size_t uart_read(struct device *dev, uint32_t addr, uint8_t *data, size_t count) { - if (addr >= dev->base && addr < dev->base + dev->size) + struct uart *u = dev->priv; + struct io_register *regs = u->regs; + unsigned int reg; + uint32_t val; + size_t ret; + + trace("count=%zu\n", count); + + if (addr < dev->base || addr >= dev->base + dev->size) + return 0; + + reg = OFF_TO_REG(addr - dev->base); + val = io_register_read(®s[reg]); + + if (reg == UART_RXDATA_REG) { + u->has_rx_data = false; + regs[UART_STATUS_REG].value &= ~UART_CONTROL_RRDY_MASK; + } + + return count; +} + +static size_t uart_write(struct device *dev, uint32_t addr, uint8_t *data, size_t count) +{ + struct uart *u = dev->priv; + struct io_register *regs = u->regs; + unsigned int reg; + uint32_t val; + size_t ret; + + trace("count=%zu\n", count); + + if (addr < dev->base || addr >= dev->base + dev->size) + return 0; + + + return count; +} + +static bool uart_has_irq(struct device *dev) +{ + struct uart *u = dev->priv; + uint32_t ctrl = u->regs[UART_CONTROL_REG].value; + uint32_t status = u->regs[UART_STATUS_REG].value; + + /* Check TX ready IRQ */ + if ((ctrl & UART_CONTROL_TRDY_MASK) && (status & UART_STATUS_TRDY_MASK)) + return true; + + /* Check RX ready IRQ */ + if ((ctrl & UART_CONTROL_RRDY_MASK) && (status & UART_STATUS_RRDY_MASK)) return true; return false; @@ -28,14 +129,27 @@ static bool uart_is_dev_addr(struct device *dev, uint32_t addr) static void uart_simulate(struct device *dev) { + struct uart *u = dev->priv; + struct io_register *regs = u->regs; + + if (u->has_tx_data) { + regs[UART_STATUS_REG].value &= ~UART_STATUS_TRDY_MASK; + } + + if (u->has_rx_data) { + } } struct device uart_core = { .name = "UART Core", .base = UART_BASE, .size = UART_SIZE, + .irq_mask = IRQ_TO_MASK(IRQ_UART), .init = uart_init, - .is_dev_addr = uart_is_dev_addr, + .is_dev_addr = NULL, /* use generic */ + .read = uart_read, + .write = uart_write, + .has_irq = uart_has_irq, .simulate = uart_simulate, }; |