Commit ee118d95af0fcc0f9175d7b0f094d4178ea54a0c

Authored by Edgar E. Iglesias
1 parent 388f60b1

xilinx: Add uartlite emulation.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Showing 1 changed file with 218 additions and 0 deletions
hw/xilinx_uartlite.c 0 → 100644
  1 +/*
  2 + * QEMU model of Xilinx uartlite.
  3 + *
  4 + * Copyright (c) 2009 Edgar E. Iglesias.
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +#include "sysbus.h"
  26 +#include "qemu-char.h"
  27 +
  28 +#define DUART(x)
  29 +
  30 +#define R_RX 0
  31 +#define R_TX 1
  32 +#define R_STATUS 2
  33 +#define R_CTRL 3
  34 +#define R_MAX 4
  35 +
  36 +#define STATUS_RXVALID 0x01
  37 +#define STATUS_RXFULL 0x02
  38 +#define STATUS_TXEMPTY 0x04
  39 +#define STATUS_TXFULL 0x08
  40 +#define STATUS_IE 0x10
  41 +#define STATUS_OVERRUN 0x20
  42 +#define STATUS_FRAME 0x40
  43 +#define STATUS_PARITY 0x80
  44 +
  45 +#define CONTROL_RST_TX 0x01
  46 +#define CONTROL_RST_RX 0x02
  47 +#define CONTROL_IE 0x10
  48 +
  49 +struct xlx_uartlite
  50 +{
  51 + SysBusDevice busdev;
  52 + CharDriverState *chr;
  53 + qemu_irq irq;
  54 +
  55 + uint8_t rx_fifo[8];
  56 + unsigned int rx_fifo_pos;
  57 + unsigned int rx_fifo_len;
  58 +
  59 + uint32_t regs[R_MAX];
  60 +};
  61 +
  62 +static void uart_update_irq(struct xlx_uartlite *s)
  63 +{
  64 + unsigned int irq;
  65 +
  66 + if (s->rx_fifo_len)
  67 + s->regs[R_STATUS] |= STATUS_IE;
  68 +
  69 + irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE);
  70 + qemu_set_irq(s->irq, irq);
  71 +}
  72 +
  73 +static void uart_update_status(struct xlx_uartlite *s)
  74 +{
  75 + uint32_t r;
  76 +
  77 + r = s->regs[R_STATUS];
  78 + r &= ~7;
  79 + r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */
  80 + r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1;
  81 + r |= (!!s->rx_fifo_len);
  82 + s->regs[R_STATUS] = r;
  83 +}
  84 +
  85 +static uint32_t uart_readl (void *opaque, target_phys_addr_t addr)
  86 +{
  87 + struct xlx_uartlite *s = opaque;
  88 + uint32_t r = 0;
  89 + addr >>= 2;
  90 + switch (addr)
  91 + {
  92 + case R_RX:
  93 + r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
  94 + if (s->rx_fifo_len)
  95 + s->rx_fifo_len--;
  96 + uart_update_status(s);
  97 + uart_update_irq(s);
  98 + break;
  99 +
  100 + default:
  101 + if (addr < ARRAY_SIZE(s->regs))
  102 + r = s->regs[addr];
  103 + DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
  104 + break;
  105 + }
  106 + return r;
  107 +}
  108 +
  109 +static void
  110 +uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
  111 +{
  112 + struct xlx_uartlite *s = opaque;
  113 + unsigned char ch = value;
  114 +
  115 + addr >>= 2;
  116 + switch (addr)
  117 + {
  118 + case R_STATUS:
  119 + hw_error("write to UART STATUS?\n");
  120 + break;
  121 +
  122 + case R_CTRL:
  123 + if (value & CONTROL_RST_RX) {
  124 + s->rx_fifo_pos = 0;
  125 + s->rx_fifo_len = 0;
  126 + }
  127 + s->regs[addr] = value;
  128 + break;
  129 +
  130 + case R_TX:
  131 + if (s->chr)
  132 + qemu_chr_write(s->chr, &ch, 1);
  133 +
  134 + s->regs[addr] = value;
  135 +
  136 + /* hax. */
  137 + s->regs[R_STATUS] |= STATUS_IE;
  138 + break;
  139 +
  140 + default:
  141 + DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
  142 + if (addr < ARRAY_SIZE(s->regs))
  143 + s->regs[addr] = value;
  144 + break;
  145 + }
  146 + uart_update_status(s);
  147 + uart_update_irq(s);
  148 +}
  149 +
  150 +static CPUReadMemoryFunc *uart_read[] = {
  151 + &uart_readl,
  152 + &uart_readl,
  153 + &uart_readl,
  154 +};
  155 +
  156 +static CPUWriteMemoryFunc *uart_write[] = {
  157 + &uart_writel,
  158 + &uart_writel,
  159 + &uart_writel,
  160 +};
  161 +
  162 +static void uart_rx(void *opaque, const uint8_t *buf, int size)
  163 +{
  164 + struct xlx_uartlite *s = opaque;
  165 +
  166 + /* Got a byte. */
  167 + if (s->rx_fifo_len >= 8) {
  168 + printf("WARNING: UART dropped char.\n");
  169 + return;
  170 + }
  171 + s->rx_fifo[s->rx_fifo_pos] = *buf;
  172 + s->rx_fifo_pos++;
  173 + s->rx_fifo_pos &= 0x7;
  174 + s->rx_fifo_len++;
  175 +
  176 + uart_update_status(s);
  177 + uart_update_irq(s);
  178 +}
  179 +
  180 +static int uart_can_rx(void *opaque)
  181 +{
  182 + struct xlx_uartlite *s = opaque;
  183 + int r;
  184 +
  185 + r = s->rx_fifo_len < sizeof(s->rx_fifo);
  186 + if (!r)
  187 + printf("cannot receive!\n");
  188 + return r;
  189 +}
  190 +
  191 +static void uart_event(void *opaque, int event)
  192 +{
  193 +
  194 +}
  195 +
  196 +static void xilinx_uartlite_init(SysBusDevice *dev)
  197 +{
  198 + struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
  199 + int uart_regs;
  200 +
  201 + sysbus_init_irq(dev, &s->irq);
  202 +
  203 + uart_update_status(s);
  204 + uart_regs = cpu_register_io_memory(0, uart_read, uart_write, s);
  205 + sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
  206 +
  207 + s->chr = qdev_init_chardev(&dev->qdev);
  208 + if (s->chr)
  209 + qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
  210 +}
  211 +
  212 +static void xilinx_uart_register(void)
  213 +{
  214 + sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite),
  215 + xilinx_uartlite_init);
  216 +}
  217 +
  218 +device_init(xilinx_uart_register)
... ...