/* * 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 "jtag_uart.h" #define JTAG_UART_CLK_COUNT_INIT 500 #define jtag_uart_printf(fmt, args...) fprintf(stdout, fmt, ##args) struct jtag_uart_fifo { uint8_t data; bool has_data; }; struct jtag_uart { struct io_register regs[JTAG_UART_REG_COUNT]; struct jtag_uart_fifo tx_fifo; unsigned int clk_count; }; static const uint32_t jtag_uart_valid_mask[JTAG_UART_REG_COUNT] = { 0xFFFF80FF, /* data */ 0xFFFF0703, /* control */ }; static const uint32_t jtag_uart_readonly_mask[JTAG_UART_REG_COUNT] = { 0xFFFF8000, /* data */ 0xFFFF0300, /* control */ }; static int jtag_uart_init(struct device *dev) { struct jtag_uart *ju; struct io_register *regs; unsigned int i; ju = malloc(sizeof(struct jtag_uart)); if (unlikely(ju == NULL)) return -1; /* Initialite registers */ regs = ju->regs; for (i = 0; i < JTAG_UART_REG_COUNT; i++) { io_register_init(®s[i], JTAG_UART_BASE + REG_TO_OFF(i), jtag_uart_valid_mask[i], jtag_uart_readonly_mask[i], 0); } /* Explicitely initialize control register */ regs[JTAG_UART_CTRL_REG].value = (JTAG_UART_FIFO_SIZE << JTAG_UART_CTRL_WSPACE_OFF) & JTAG_UART_CTRL_WSPACE_MASK; ju->clk_count = JTAG_UART_CLK_COUNT_INIT; dev->priv = ju; return 0; } static bool jtag_uart_is_dev_addr(struct device *dev, uint32_t addr) { struct jtag_uart *ju = dev->priv; unsigned int i; for (i = 0; i < JTAG_UART_REG_COUNT; i++) if (ju->regs[i].addr == addr) return true; return false; } static bool jtag_uart_has_irq(struct device *dev) { struct jtag_uart *ju = dev->priv; uint32_t ctrl_val; ju->clk_count--; if (ju->clk_count > 0) return false; ctrl_val = ju->regs[JTAG_UART_CTRL_REG].value; /* handle write interrupt */ if (ctrl_val & JTAG_UART_CTRL_WE_MASK) if ((ctrl_val & JTAG_UART_CTRL_WSPACE_MASK) != 0) return true; /* TODO: Read interrupt */ return false; } static void jtag_uart_simulate(struct device *dev) { struct jtag_uart *ju = dev->priv; struct io_register *regs = ju->regs; if (ju->tx_fifo.has_data) { jtag_uart_printf("%c", ju->tx_fifo.data); ju->tx_fifo.has_data = false; /* set available fifo size */ regs[JTAG_UART_CTRL_REG].value |= (JTAG_UART_FIFO_SIZE << JTAG_UART_CTRL_WSPACE_OFF) & JTAG_UART_CTRL_WSPACE_MASK; if (regs[JTAG_UART_CTRL_REG].value & JTAG_UART_CTRL_WE_MASK) regs[JTAG_UART_CTRL_REG].value |= JTAG_UART_CTRL_WI_MASK; } else { if ((regs[JTAG_UART_CTRL_REG].value & JTAG_UART_CTRL_WSPACE_MASK) != 0 && (regs[JTAG_UART_CTRL_REG].value & JTAG_UART_CTRL_WE_MASK)) regs[JTAG_UART_CTRL_REG].value |= JTAG_UART_CTRL_WI_MASK; } } struct device jtag_uart_core = { .name = "JTAG UART Core", .base = JTAG_UART_BASE, .size = JTAG_UART_SIZE, .irq_mask = IRQ_TO_MASK(IRQ_JTAG_UART), .init = jtag_uart_init, .is_dev_addr = jtag_uart_is_dev_addr, .has_irq = jtag_uart_has_irq, .simulate = jtag_uart_simulate, }; #if 0 static uint32_t uart_read(struct io_device * self, uint32_t addr, uint32_t data_len) { if (addr == priv.regs[JTAG_UART_CTRL_REG].addr){ return priv.regs[JTAG_UART_CTRL_REG].value; } else if (addr == priv.regs[JTAG_UART_DATA_REG].addr){ return priv.regs[JTAG_UART_DATA_REG].value; } return 0; } static void write_tx_fifo(uint32_t data) { priv.tx_fifo.data = data & 0xFF; priv.tx_fifo.is_write = 1; /* clean WI bit */ priv.regs[JTAG_UART_CTRL_REG].value &= (~ALTERA_JTAGUART_CONTROL_WI_MSK); /* clean write space bits */ priv.regs[JTAG_UART_CTRL_REG].value &= 0xFFFF; } static void uart_write(struct io_device * self, uint32_t addr, uint32_t data, uint32_t data_len) { int32_t i = 0; for (i=0;i