/* * Copyright (C) 2010 Tobias Klauser * Copyright (C) 2010 chysun2000@gmail.com * * This file is part of nios2sim-ng. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #include #include #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 size_t uart_read(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; 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; } 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 = NULL, /* use generic */ .read = uart_read, .write = uart_write, .has_irq = uart_has_irq, .simulate = uart_simulate, };