diff mbox series

[2/8] tiva c usart module implementation

Message ID 20230517081204.30333-3-m.elsayed4420@gmail.com
State New
Headers show
Series Tiva C Implementation | expand

Commit Message

Mohamed ElSayed May 17, 2023, 8:11 a.m. UTC
Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 hw/char/tm4c123_usart.c         | 381 ++++++++++++++++++++++++++++++++
 hw/char/trace-events            |   4 +
 include/hw/char/tm4c123_usart.h | 124 +++++++++++
 3 files changed, 509 insertions(+)
 create mode 100644 hw/char/tm4c123_usart.c
 create mode 100644 include/hw/char/tm4c123_usart.h

Comments

Peter Maydell June 8, 2023, 1:36 p.m. UTC | #1
On Wed, 17 May 2023 at 09:13, Mohamed ElSayed <m.elsayed4420@gmail.com> wrote:
>
> Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
> ---
>  hw/char/tm4c123_usart.c         | 381 ++++++++++++++++++++++++++++++++
>  hw/char/trace-events            |   4 +
>  include/hw/char/tm4c123_usart.h | 124 +++++++++++

Patches that add new device source files should also have
the changes to the Kconfig and meson.build files that tie
them in to the build system (which you currently have put
all together in patch 8).

>  3 files changed, 509 insertions(+)
>  create mode 100644 hw/char/tm4c123_usart.c
>  create mode 100644 include/hw/char/tm4c123_usart.h
>
> diff --git a/hw/char/tm4c123_usart.c b/hw/char/tm4c123_usart.c
> new file mode 100644
> index 0000000000..21bfe781b0
> --- /dev/null
> +++ b/hw/char/tm4c123_usart.c
> @@ -0,0 +1,381 @@
> +/*
> + * TM4C123 USART
> + *
> + * Copyright (c) 2023 Mohamed ElSayed <m.elsayed4420@gmail.com>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */

TI don't explicitly say so, but this UART is a variant of the PL011.
So I think instead of a completely separate model for it, we should
extend the hw/char/pl011.c code to handle any specific new behaviour
we need for this variant. There's already handling in pl011.c
for the TYPE_PL011_LUMINARY, which is an older TI-specific PL011
flavour, so you have a pattern to work with. For that variant the
only thing we needed to override was the ID register values; you
might need a little bit more for this one, but likely not much.

So below I've only noted a few things rather than doing a review
of the whole device.

> +#include "qemu/osdep.h"
> +#include "hw/char/tm4c123_usart.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/qdev-properties-system.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "trace.h"
> +
> +#define LOG(mask, fmt, args...) qemu_log_mask(mask, "%s: " fmt, __func__, ## args)

Please don't hide simple calls to qemu_log_mask() behind
macros like this.

> +#define READONLY LOG(LOG_GUEST_ERROR, "0x%"HWADDR_PRIx" is a readonly field\n.", addr)

If you put all the readonly registers together and let them
fall through, ie.
   case USART_FR:
   case USART_RIS:
       /* etc */
       qemu_log_mask(...);

then you only need one line which reports the write to a read-only
register, and the macro isn't really necessary.

(Also, stray trailing '.' after the newline.)


> +
> +static bool usart_clock_enabled(TM4C123SysCtlState *s, hwaddr addr)
> +{
> +    switch (addr) {
> +        case USART_0:
> +            return s->sysctl_rcgcuart & (1 << 0);
> +            break;
> +        case USART_1:
> +            return s->sysctl_rcgcuart & (1 << 1);
> +            break;
> +        case USART_2:
> +            return s->sysctl_rcgcuart & (1 << 2);
> +            break;
> +        case USART_3:
> +            return s->sysctl_rcgcuart & (1 << 3);
> +            break;
> +        case USART_4:
> +            return s->sysctl_rcgcuart & (1 << 4);
> +            break;
> +        case USART_5:
> +            return s->sysctl_rcgcuart & (1 << 5);
> +            break;
> +        case USART_6:
> +            return s->sysctl_rcgcuart & (1 << 6);
> +            break;
> +        case USART_7:
> +            return s->sysctl_rcgcuart & (1 << 7);
> +            break;
> +    }
> +    return false;
> +}

The UART device shouldn't have a direct pointer to the sysctl
device like this, and it shouldn't be poking around inside
its MMIORegion to find out its physical address either.

The "right" approach here is that the sysctl device has a
bunch of clock outputs for the various UART clocks, the SoC
code wires up each clock output to the appropriate UART
device, and the UART device calls clock_is_enabled() on
its input clock.

The simple approach is to say "we'll just assume the
UART clock has been enabled", because correct guest code
will do that anyway and the device implementation doesn't
much care what the clock is. That's what we usually do
with UART models.

thanks
-- PMM
diff mbox series

Patch

diff --git a/hw/char/tm4c123_usart.c b/hw/char/tm4c123_usart.c
new file mode 100644
index 0000000000..21bfe781b0
--- /dev/null
+++ b/hw/char/tm4c123_usart.c
@@ -0,0 +1,381 @@ 
+/*
+ * TM4C123 USART
+ *
+ * Copyright (c) 2023 Mohamed ElSayed <m.elsayed4420@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/tm4c123_usart.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "trace.h"
+
+#define LOG(mask, fmt, args...) qemu_log_mask(mask, "%s: " fmt, __func__, ## args)
+#define READONLY LOG(LOG_GUEST_ERROR, "0x%"HWADDR_PRIx" is a readonly field\n.", addr)
+
+static bool usart_clock_enabled(TM4C123SysCtlState *s, hwaddr addr)
+{
+    switch (addr) {
+        case USART_0:
+            return s->sysctl_rcgcuart & (1 << 0);
+            break;
+        case USART_1:
+            return s->sysctl_rcgcuart & (1 << 1);
+            break;
+        case USART_2:
+            return s->sysctl_rcgcuart & (1 << 2);
+            break;
+        case USART_3:
+            return s->sysctl_rcgcuart & (1 << 3);
+            break;
+        case USART_4:
+            return s->sysctl_rcgcuart & (1 << 4);
+            break;
+        case USART_5:
+            return s->sysctl_rcgcuart & (1 << 5);
+            break;
+        case USART_6:
+            return s->sysctl_rcgcuart & (1 << 6);
+            break;
+        case USART_7:
+            return s->sysctl_rcgcuart & (1 << 7);
+            break;
+    }
+    return false;
+}
+
+
+static int tm4c123_usart_can_receive(void *opaque)
+{
+    TM4C123USARTState *s = opaque;
+
+    if (!(s->usart_fr & USART_FR_RXFF)) {
+        return 1;
+    }
+    return 0;
+}
+
+static void tm4c123_usart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    TM4C123USARTState *s = opaque;
+
+    if (!(s->usart_ctl & USART_CR_EN && s->usart_ctl & USART_CR_RXE)) {
+        LOG(LOG_GUEST_ERROR, "The module is not enbled\n");
+        return;
+    }
+
+    s->usart_dr = *buf;
+    s->usart_ctl &= ~USART_FR_RXFE;
+
+    if (s->usart_im & USART_IM_RXIM) {
+        qemu_set_irq(s->irq, 1);
+    }
+}
+
+static void tm4c123_usart_reset(DeviceState *dev)
+{
+    TM4C123USARTState *s = TM4C123_USART(dev);
+
+    s->usart_dr = 0x00000000;
+    s->usart_rsr = 0x00000000;
+    s->usart_fr = 0x00000090;
+    s->usart_ilpr = 0x00000000;
+    s->usart_ibrd = 0x00000000;
+    s->usart_fbrd = 0x00000000;
+    s->usart_lcrh = 0x00000000;
+    s->usart_ctl = 0x00000300;
+    s->usart_ifls = 0x00000012;
+    s->usart_im = 0x00000000;
+    s->usart_ris = 0x00000000;
+    s->usart_mis = 0x00000000;
+    s->usart_icr = 0x00000000;
+    s->usart_dma_ctl = 0x00000000;
+    s->usart_9bit_addr = 0x00000000;
+    s->usart_9bit_mask = 0x000000FF;
+    s->usart_pp = 0x00000003;
+    s->usart_cc = 0x00000000;
+    s->usart_per_id4 = 0x00000000;
+    s->usart_per_id5 = 0x00000000;
+    s->usart_per_id6 = 0x00000000;
+    s->usart_per_id7 = 0x00000000;
+    s->usart_per_id0 = 0x00000060;
+    s->usart_per_id1 = 0x00000000;
+    s->usart_per_id2 = 0x00000018;
+    s->usart_per_id3 = 0x00000001;
+    s->usart_pcell_id0 = 0x0000000D;
+    s->usart_pcell_id1 = 0x000000F0;
+    s->usart_pcell_id2 = 0x00000005;
+    s->usart_pcell_id3 = 0x000000B1;
+
+    qemu_set_irq(s->irq, 0);
+}
+
+static uint64_t tm4c123_usart_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    TM4C123USARTState *s = opaque;
+
+    if (!usart_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("USART module clock is not enabled");
+    }
+
+    trace_tm4c123_usart_read(addr);
+
+    switch (addr) {
+        case USART_DR:
+            return s->usart_dr;
+        case USART_RSR:
+            return s->usart_rsr;
+        case USART_FR:
+            return s->usart_fr;
+        case USART_ILPR:
+            return s->usart_ilpr;
+        case USART_IBRD:
+            return s->usart_ibrd;
+        case USART_FBRD:
+            return s->usart_fbrd;
+        case USART_LCRH:
+            return s->usart_lcrh;
+        case USART_CTL:
+            return s->usart_ctl;
+        case USART_IFLS:
+            return s->usart_ifls;
+        case USART_IM:
+            return s->usart_im;
+        case USART_RIS:
+            return s->usart_ris;
+        case USART_MIS:
+            return s->usart_mis;
+        case USART_ICR:
+            return s->usart_icr;
+        case USART_DMA_CTL:
+            return s->usart_dma_ctl;
+        case USART_9BIT_ADDR:
+            return s->usart_9bit_addr;
+        case USART_9BIT_MASK:
+            return s->usart_9bit_mask;
+        case USART_PP:
+            return s->usart_pp;
+        case USART_CC:
+            return s->usart_cc;
+        case USART_PER_ID4:
+            return s->usart_per_id4;
+        case USART_PER_ID5:
+            return s->usart_per_id5;
+        case USART_PER_ID6:
+            return s->usart_per_id6;
+        case USART_PER_ID7:
+            return s->usart_per_id7;
+        case USART_PER_ID0:
+            return s->usart_per_id0;
+        case USART_PER_ID1:
+            return s->usart_per_id1;
+        case USART_PER_ID2:
+            return s->usart_per_id2;
+        case USART_PER_ID3:
+            return s->usart_per_id3;
+        case USART_PCELL_ID0:
+            return s->usart_pcell_id0;
+        case USART_PCELL_ID1:
+            return s->usart_pcell_id1;
+        case USART_PCELL_ID2:
+            return s->usart_pcell_id2;
+        case USART_PCELL_ID3:
+            return s->usart_pcell_id3;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+            return 0;
+    }
+
+    return 0;
+}
+
+static void tm4c123_usart_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size)
+{
+    TM4C123USARTState *s = opaque;
+    uint32_t val32 = val64;
+    unsigned char ch;
+
+    if (!usart_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("USART module clock is not enabled");
+    }
+
+    trace_tm4c123_usart_write(addr, val32);
+
+    switch (addr) {
+        case USART_DR:
+            s->usart_dr = val32;
+            if (val32 < 0xF000) {
+                ch = val32;
+                qemu_chr_fe_write_all(&s->chr, &ch, 1);
+            }
+            break;
+        case USART_RSR:
+            s->usart_rsr = val32;
+            break;
+        case USART_FR:
+            READONLY;
+            break;
+        case USART_ILPR:
+            s->usart_ilpr = val32;
+            break;
+        case USART_IBRD:
+            s->usart_ibrd = val32;
+            break;
+        case USART_FBRD:
+            s->usart_fbrd = val32;
+            break;
+        case USART_LCRH:
+            s->usart_lcrh = val32;
+            break;
+        case USART_CTL:
+            s->usart_ctl = val32;
+            break;
+        case USART_IFLS:
+            s->usart_ifls = val32;
+            break;
+        case USART_IM:
+            s->usart_im = val32;
+            break;
+        case USART_RIS:
+            READONLY;
+            break;
+        case USART_MIS:
+            READONLY;
+            break;
+        case USART_ICR:
+            s->usart_icr = val32;
+            break;
+        case USART_DMA_CTL:
+            s->usart_dma_ctl = val32;
+            break;
+        case USART_9BIT_ADDR:
+            s->usart_9bit_addr = val32;
+            break;
+        case USART_9BIT_MASK:
+            s->usart_9bit_mask = val32;
+            break;
+        case USART_PP:
+            READONLY;
+            break;
+        case USART_CC:
+            s->usart_cc = val32;
+            break;
+        case USART_PER_ID4:
+            READONLY;
+            break;
+        case USART_PER_ID5:
+            READONLY;
+            break;
+        case USART_PER_ID6:
+            READONLY;
+            break;
+        case USART_PER_ID7:
+            READONLY;
+            break;
+        case USART_PER_ID0:
+            READONLY;
+            break;
+        case USART_PER_ID1:
+            READONLY;
+            break;
+        case USART_PER_ID2:
+            READONLY;
+            break;
+        case USART_PER_ID3:
+            READONLY;
+            break;
+        case USART_PCELL_ID0:
+            READONLY;
+            break;
+        case USART_PCELL_ID1:
+            READONLY;
+            break;
+        case USART_PCELL_ID2:
+            READONLY;
+            break;
+        case USART_PCELL_ID3:
+            READONLY;
+            break;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+            return;
+    }
+
+    return;
+}
+
+static const MemoryRegionOps tm4c123_usart_ops = {
+    .read = tm4c123_usart_read,
+    .write = tm4c123_usart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static Property tm4c123_usart_properties[] = {
+    DEFINE_PROP_CHR("chardev", TM4C123USARTState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tm4c123_usart_init(Object *obj)
+{
+    TM4C123USARTState *s = TM4C123_USART(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+    memory_region_init_io(&s->mmio, obj, &tm4c123_usart_ops, s,
+            TYPE_TM4C123_USART, 0xFFF);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void tm4c123_usart_realize(DeviceState *dev, Error **errp)
+{
+    TM4C123USARTState *s = TM4C123_USART(dev);
+
+    qemu_chr_fe_set_handlers(&s->chr, tm4c123_usart_can_receive,
+            tm4c123_usart_receive, NULL, NULL,
+            s, NULL, true);
+}
+
+static void tm4c123_usart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = tm4c123_usart_reset;
+    device_class_set_props(dc, tm4c123_usart_properties);
+    dc->realize = tm4c123_usart_realize;
+}
+
+static const TypeInfo tm4c123_usart_info = {
+    .name          = TYPE_TM4C123_USART,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TM4C123USARTState),
+    .instance_init = tm4c123_usart_init,
+    .class_init    = tm4c123_usart_class_init,
+};
+
+static void tm4c123_usart_register_types(void)
+{
+    type_register_static(&tm4c123_usart_info);
+}
+
+type_init(tm4c123_usart_register_types)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 2ecb36232e..47b7e3b772 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -1,5 +1,9 @@ 
 # See docs/devel/tracing.rst for syntax documentation.
 
+# tm4c123_usart.c
+tm4c123_usart_read(uint64_t offset) " offset: 0x%" PRIu64
+tm4c123_usart_write(uint64_t offset, uint64_t value) " offset: 0x%" PRIu64 " - value: 0x%" PRIu64
+
 # parallel.c
 parallel_ioport_read(const char *desc, uint16_t addr, uint8_t value) "read [%s] addr 0x%02x val 0x%02x"
 parallel_ioport_write(const char *desc, uint16_t addr, uint8_t value) "write [%s] addr 0x%02x val 0x%02x"
diff --git a/include/hw/char/tm4c123_usart.h b/include/hw/char/tm4c123_usart.h
new file mode 100644
index 0000000000..be98eb3948
--- /dev/null
+++ b/include/hw/char/tm4c123_usart.h
@@ -0,0 +1,124 @@ 
+/*
+ * TM4C123 USART
+ *
+ * Copyright (c) 2023 Mohamed ElSayed <m.elsayed4420@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_ARM_TM4C123_USART_H
+#define HW_ARM_TM4C123_USART_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+#include "chardev/char-fe.h"
+#include "hw/misc/tm4c123_sysctl.h"
+
+#define USART_DR            0x000
+#define USART_RSR           0x004
+#define USART_FR            0x018
+#define USART_ILPR          0x020
+#define USART_IBRD          0x024
+#define USART_FBRD          0x028
+#define USART_LCRH          0x02C
+#define USART_CTL           0x030
+#define USART_IFLS          0x034
+#define USART_IM            0x038
+#define USART_RIS           0x03C
+#define USART_MIS           0x040
+#define USART_ICR           0x044
+#define USART_DMA_CTL       0x048
+#define USART_9BIT_ADDR     0x0A4
+#define USART_9BIT_MASK     0x0A8
+#define USART_PP            0xFC0
+#define USART_CC            0xFC8
+#define USART_PER_ID4       0x0FD0
+#define USART_PER_ID5       0xFD4
+#define USART_PER_ID6       0xFD8
+#define USART_PER_ID7       0xFDC
+#define USART_PER_ID0       0xFE0
+#define USART_PER_ID1       0xFE4
+#define USART_PER_ID2       0xFE8
+#define USART_PER_ID3       0xFEC
+#define USART_PCELL_ID0     0xFF0
+#define USART_PCELL_ID1     0xFF4
+#define USART_PCELL_ID2     0xFF8
+#define USART_PCELL_ID3     0xFFC
+
+#define USART_FR_RXFF (1 << 6)
+#define USART_FR_TXFF (1 << 5)
+#define USART_FR_RXFE (1 << 4)
+#define USART_FR_BUSY (1 << 3)
+#define USART_CR_RXE  (1 << 9)
+#define USART_CR_EN   (1 << 0)
+#define USART_IM_RXIM (1 << 4)
+
+#define USART_0 0x4000C000
+#define USART_1 0x4000D000
+#define USART_2 0x4000E000
+#define USART_3 0x4000F000
+#define USART_4 0x40010000
+#define USART_5 0x40011000
+#define USART_6 0x40012000
+#define USART_7 0x40013000
+#define TYPE_TM4C123_USART "tm4c123-usart"
+
+OBJECT_DECLARE_SIMPLE_TYPE(TM4C123USARTState, TM4C123_USART)
+
+struct TM4C123USARTState {
+    SysBusDevice parent_obj;
+    MemoryRegion mmio;
+
+    uint32_t usart_dr;
+    uint32_t usart_rsr;
+    uint32_t usart_fr;
+    uint32_t usart_ilpr;
+    uint32_t usart_ibrd;
+    uint32_t usart_fbrd;
+    uint32_t usart_lcrh;
+    uint32_t usart_ctl;
+    uint32_t usart_ifls;
+    uint32_t usart_im;
+    uint32_t usart_ris;
+    uint32_t usart_mis;
+    uint32_t usart_icr;
+    uint32_t usart_dma_ctl;
+    uint32_t usart_9bit_addr;
+    uint32_t usart_9bit_mask;
+    uint32_t usart_pp;
+    uint32_t usart_cc;
+    uint32_t usart_per_id4;
+    uint32_t usart_per_id5;
+    uint32_t usart_per_id6;
+    uint32_t usart_per_id7;
+    uint32_t usart_per_id0;
+    uint32_t usart_per_id1;
+    uint32_t usart_per_id2;
+    uint32_t usart_per_id3;
+    uint32_t usart_pcell_id0;
+    uint32_t usart_pcell_id1;
+    uint32_t usart_pcell_id2;
+    uint32_t usart_pcell_id3;
+
+    CharBackend chr;
+    qemu_irq irq;
+    TM4C123SysCtlState *sysctl;
+};
+
+#endif