summaryrefslogtreecommitdiff
path: root/uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'uart.c')
-rw-r--r--uart.c120
1 files changed, 117 insertions, 3 deletions
diff --git a/uart.c b/uart.c
index f49c1cb..e53978b 100644
--- a/uart.c
+++ b/uart.c
@@ -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(&regs[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(&regs[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,
};