qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Tiva C Implementation
@ 2023-05-17  8:11 Mohamed ElSayed
  2023-05-17  8:11 ` [PATCH 1/8] The tivac board initial machine definition Mohamed ElSayed
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

This contribution aims to add the Tiva C support into QEMU.
The code could be found at https://github.com/moesay/qemu_TivaC

Mohamed ElSayed (8):
  The tivac board initial machine definition
  tiva c usart module implementation
  tiva c gpio implementation
  tiva c sysctl implementation
  tiva c watchdog timers implementation
  tiva c general purpose timers implementation
  tiva c board documentation
  adding tiva c to the qemu build system and adding my info to the
    maintainers list

 MAINTAINERS                             |   9 +
 configs/devices/arm-softmmu/default.mak |   1 +
 docs/system/arm/tivac.rst               |  47 ++
 hw/arm/Kconfig                          |  13 +
 hw/arm/meson.build                      |   3 +
 hw/arm/tivac.c                          |  56 ++
 hw/arm/tm4c123gh6pm_soc.c               | 275 +++++++
 hw/char/Kconfig                         |   3 +
 hw/char/meson.build                     |   1 +
 hw/char/tm4c123_usart.c                 | 381 +++++++++
 hw/char/trace-events                    |   4 +
 hw/gpio/Kconfig                         |   3 +
 hw/gpio/meson.build                     |   1 +
 hw/gpio/tm4c123_gpio.c                  | 372 +++++++++
 hw/gpio/trace-events                    |   4 +
 hw/misc/Kconfig                         |   3 +
 hw/misc/meson.build                     |   1 +
 hw/misc/tm4c123_sysctl.c                | 989 ++++++++++++++++++++++++
 hw/misc/trace-events                    |   5 +
 hw/timer/Kconfig                        |   3 +
 hw/timer/meson.build                    |   1 +
 hw/timer/tm4c123_gptm.c                 | 495 ++++++++++++
 hw/timer/trace-events                   |   5 +
 hw/watchdog/Kconfig                     |   3 +
 hw/watchdog/meson.build                 |   1 +
 hw/watchdog/tm4c123_watchdog.c          | 297 +++++++
 hw/watchdog/trace-events                |   3 +
 include/hw/arm/tm4c123gh6pm_soc.h       |  71 ++
 include/hw/char/tm4c123_usart.h         | 124 +++
 include/hw/gpio/tm4c123_gpio.h          | 127 +++
 include/hw/misc/tm4c123_sysctl.h        | 307 ++++++++
 include/hw/timer/tm4c123_gptm.h         | 131 ++++
 include/hw/watchdog/tm4c123_watchdog.h  |  97 +++
 33 files changed, 3836 insertions(+)
 create mode 100644 docs/system/arm/tivac.rst
 create mode 100644 hw/arm/tivac.c
 create mode 100644 hw/arm/tm4c123gh6pm_soc.c
 create mode 100644 hw/char/tm4c123_usart.c
 create mode 100644 hw/gpio/tm4c123_gpio.c
 create mode 100644 hw/misc/tm4c123_sysctl.c
 create mode 100644 hw/timer/tm4c123_gptm.c
 create mode 100644 hw/watchdog/tm4c123_watchdog.c
 create mode 100644 include/hw/arm/tm4c123gh6pm_soc.h
 create mode 100644 include/hw/char/tm4c123_usart.h
 create mode 100644 include/hw/gpio/tm4c123_gpio.h
 create mode 100644 include/hw/misc/tm4c123_sysctl.h
 create mode 100644 include/hw/timer/tm4c123_gptm.h
 create mode 100644 include/hw/watchdog/tm4c123_watchdog.h

-- 
2.34.1



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/8] The tivac board initial machine definition
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
@ 2023-05-17  8:11 ` Mohamed ElSayed
  2023-06-08 13:15   ` Peter Maydell
  2023-05-17  8:11 ` [PATCH 2/8] tiva c usart module implementation Mohamed ElSayed
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 hw/arm/tivac.c                    |  56 ++++++
 hw/arm/tm4c123gh6pm_soc.c         | 275 ++++++++++++++++++++++++++++++
 include/hw/arm/tm4c123gh6pm_soc.h |  71 ++++++++
 3 files changed, 402 insertions(+)
 create mode 100644 hw/arm/tivac.c
 create mode 100644 hw/arm/tm4c123gh6pm_soc.c
 create mode 100644 include/hw/arm/tm4c123gh6pm_soc.h

diff --git a/hw/arm/tivac.c b/hw/arm/tivac.c
new file mode 100644
index 0000000000..5d917a8f9e
--- /dev/null
+++ b/hw/arm/tivac.c
@@ -0,0 +1,56 @@
+/*
+ * TivaC Board Implementation
+ *
+ * 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 "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
+#include "qemu/error-report.h"
+#include "hw/arm/tm4c123gh6pm_soc.h"
+#include "hw/arm/boot.h"
+
+
+/* Main SYSCLK frequency in Hz (24MHz) */
+#define SYSCLK_FRQ 24000000ULL
+
+static void tivac_init(MachineState *machine)
+{
+    DeviceState *dev;
+    dev = qdev_new(TYPE_TM4C123GH6PM_SOC);
+
+    qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+    armv7m_load_kernel(ARM_CPU(first_cpu),
+            machine->kernel_filename,
+            0, FLASH_SIZE);
+}
+
+static void tivac_machine_init(MachineClass *mc)
+{
+    mc->desc = "Tiva C (Cortex-M4)";
+    mc->init = tivac_init;
+}
+DEFINE_MACHINE("tivac", tivac_machine_init)
diff --git a/hw/arm/tm4c123gh6pm_soc.c b/hw/arm/tm4c123gh6pm_soc.c
new file mode 100644
index 0000000000..3e61911bba
--- /dev/null
+++ b/hw/arm/tm4c123gh6pm_soc.c
@@ -0,0 +1,275 @@
+/*
+ * TM4C123GH6PM SoC
+ *
+ * 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 "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/arm/boot.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/tm4c123gh6pm_soc.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
+#include "sysemu/sysemu.h"
+
+static const uint32_t gpio_addrs[GPIO_COUNT] = {
+    0x40004000,
+    0x40005000,
+    0x40006000,
+    0x40007000,
+    0x40024000,
+    0x40025000
+};
+
+static const uint32_t usart_addrs[USART_COUNT] = {
+    0x4000C000,
+    0x4000D000,
+    0x4000E000,
+    0x4000F000,
+    0x40010000,
+    0x40011000,
+    0x40012000,
+    0x40013000
+};
+
+static const uint32_t wdt_addrs[WDT_COUNT] = {
+    0x40000000,
+    0x40001000
+};
+
+static const uint32_t gptm_addrs[GPTM_COUNT] = {
+    0x40030000,
+    0x40031000,
+    0x40032000,
+    0x40033000,
+    0x40034000,
+    0x40035000,
+    0x40036000,
+    0x40037000,
+    0x4003C800,
+    0x4003D000,
+    0x4003E000,
+    0x4003F000,
+};
+
+static const uint16_t usart_irqs[USART_COUNT] = {5, 6, 33, 59, 60, 61, 62, 63};
+static const uint16_t gpio_irqs[GPIO_COUNT] = {0, 1, 2, 3, 4, 30};
+static const uint16_t wdt_irqs[WDT_COUNT] = {18, 18};
+static const uint16_t gptm_irqs[GPTM_COUNT * 2] = {
+    19, 20, 21, 22, 23, 24, 35, 36, 70, 71, 92, 93,
+    94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105};
+
+static void tm4c123gh6pm_soc_initfn(Object *obj)
+{
+    int i;
+    TM4C123GH6PMState *s = TM4C123GH6PM_SOC(obj);
+
+    object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+    object_initialize_child(obj, "sysctl", &s->sysctl, TYPE_TM4C123_SYSCTL);
+
+    for (i = 0; i < USART_COUNT; i++) {
+        object_initialize_child(obj, "usart[*]",
+                                &s->usart[i], TYPE_TM4C123_USART);
+    }
+
+    for (i = 0; i < GPIO_COUNT; i++) {
+        object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_TM4C123_GPIO);
+    }
+
+    for (i = 0; i < WDT_COUNT; i++) {
+        object_initialize_child(obj, "watchdog-timer[*]",
+                                &s->wdt[i], TYPE_TM4C123_WATCHDOG);
+    }
+
+    for (i = 0; i < GPTM_COUNT; i++) {
+        object_initialize_child(obj, "gptm[*]", &s->gptm[i], TYPE_TM4C123_GPTM);
+    }
+}
+
+static void tm4c123gh6pm_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+    TM4C123GH6PMState *s = TM4C123GH6PM_SOC(dev_soc);
+    DeviceState *armv7m;
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    int i;
+
+    MemoryRegion *system_memory = get_system_memory();
+
+    /* init flash memory */
+    memory_region_init_rom(
+            &s->flash, OBJECT(dev_soc),
+            "TM4C123GH6PM.flash", FLASH_SIZE, &error_fatal
+            );
+    memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
+
+    /* init sram and the sram alias region */
+    memory_region_init_ram(
+            &s->sram, OBJECT(dev_soc),
+            "TM4C123GH6PM.sram", SRAM_SIZE, &error_fatal);
+    memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
+
+    /* Init ARMv7m */
+    armv7m = DEVICE(&s->armv7m);
+    qdev_prop_set_uint32(armv7m, "num-irq", 138);
+    qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
+    qdev_prop_set_bit(armv7m, "enable-bitband", true);
+    qdev_connect_clock_in(armv7m, "cpuclk", s->sysctl.mainclk);
+    qdev_connect_clock_in(armv7m, "refclk", s->sysctl.mainclk);
+    object_property_set_link(OBJECT(&s->armv7m), "memory",
+            OBJECT(get_system_memory()), &error_abort);
+
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
+        return;
+    }
+
+    /* USART */
+    for (i = 0; i < USART_COUNT; i++) {
+        dev = DEVICE(&(s->usart[i]));
+        s->usart[i].sysctl = &s->sysctl;
+        qdev_prop_set_chr(dev, "chardev", serial_hd(i));
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) {
+            return;
+        }
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, usart_addrs[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irqs[i]));
+    }
+
+    /* GPIO */
+    for (i = 0; i < GPIO_COUNT; i++) {
+        dev = DEVICE(&(s->gpio[i]));
+        s->gpio[i].sysctl = &s->sysctl;
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
+            return;
+        }
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, gpio_addrs[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, gpio_irqs[i]));
+    }
+
+    /* Watchdog Timers */
+    for (i = 0; i < WDT_COUNT; i++) {
+        dev = DEVICE(&(s->wdt[i]));
+        s->wdt[i].sysctl = &s->sysctl;
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+            return;
+        }
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, wdt_addrs[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, wdt_irqs[i]));
+    }
+
+    /* General purpose timers */
+    int j = 0;
+    for (i = 0, j = 0; i < GPTM_COUNT; i++, j += 2) {
+        dev = DEVICE(&(s->gptm[i]));
+        s->gptm[i].sysctl = &s->sysctl;
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->gptm[i]), errp)) {
+            return;
+        }
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, gptm_addrs[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, gptm_irqs[j]));
+        sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(armv7m, gptm_irqs[j + 1]));
+    }
+
+    /* SYSCTL */
+    dev = DEVICE(&(s->sysctl));
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), errp)) {
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, SYSCTL_ADDR);
+
+
+    create_unimplemented_device("SSI_0", 0x40008000, 0xFFF);
+    create_unimplemented_device("SSI_1", 0x40009000, 0xFFF);
+    create_unimplemented_device("SSI_2", 0x4000A000, 0xFFF);
+    create_unimplemented_device("SSI_3", 0x4000B000, 0xFFF);
+
+    create_unimplemented_device("I2C_0", 0x40020000, 0xFFF);
+    create_unimplemented_device("I2C_1", 0x40021000, 0xFFF);
+    create_unimplemented_device("I2C_2", 0x40022000, 0xFFF);
+    create_unimplemented_device("I2C_3", 0x40023000, 0xFFF);
+
+    create_unimplemented_device("PWM_0", 0x40028000, 0xFFF);
+    create_unimplemented_device("PWM_1", 0x40029000, 0xFFF);
+
+    create_unimplemented_device("QEI_0", 0x4002C000, 0xFFF);
+    create_unimplemented_device("QEI_1", 0x4002D000, 0xFFF);
+
+    create_unimplemented_device("ADC_0", 0x40038000, 0xFFF);
+    create_unimplemented_device("ADC_1", 0x40039000, 0xFFF);
+
+    create_unimplemented_device("ANALOG_CMP", 0x4003C000, 0xFFF);
+
+    create_unimplemented_device("CAN_0", 0x40040000, 0xFFF);
+    create_unimplemented_device("CAN_1", 0x40041000, 0xFFF);
+
+    create_unimplemented_device("USB", 0x40050000, 0xFFF);
+
+    create_unimplemented_device("GPIO_A_AHB", 0x40058000, 0xFFF);
+    create_unimplemented_device("GPIO_B_AHB", 0x40059000, 0xFFF);
+    create_unimplemented_device("GPIO_C_AHB", 0x4005A000, 0xFFF);
+    create_unimplemented_device("GPIO_D_AHB", 0x4005B000, 0xFFF);
+    create_unimplemented_device("GPIO_E_AHB", 0x4005C000, 0xFFF);
+    create_unimplemented_device("GPIO_F_AHB", 0x4005D000, 0xFFF);
+
+    create_unimplemented_device("EEPROM", 0x400AF000, 0xFFF);
+    create_unimplemented_device("SYS_EXC", 0x400F9000, 0xFFF);
+    create_unimplemented_device("HIBERNATION_MOD", 0x400FC000, 0xFFF);
+    create_unimplemented_device("FLASH_CONT", 0x400FD000, 0xFFF);
+    create_unimplemented_device("SYS_CONT", 0x400FE000, 0xFFF);
+
+    create_unimplemented_device("uDMA", 0x400FF000, 0xFFF);
+}
+
+static Property tm4c123gh6pm_soc_properties[] = {
+    DEFINE_PROP_STRING("cpu-type", TM4C123GH6PMState, cpu_type),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tm4c123gh6pm_soc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = tm4c123gh6pm_soc_realize;
+    device_class_set_props(dc, tm4c123gh6pm_soc_properties);
+}
+
+static const TypeInfo tm4c123gh6pm_soc_info = {
+    .name          = TYPE_TM4C123GH6PM_SOC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TM4C123GH6PMState),
+    .instance_init = tm4c123gh6pm_soc_initfn,
+    .class_init    = tm4c123gh6pm_soc_class_init,
+};
+
+static void tm4c123gh6pm_soc_types(void)
+{
+    type_register_static(&tm4c123gh6pm_soc_info);
+}
+
+type_init(tm4c123gh6pm_soc_types)
diff --git a/include/hw/arm/tm4c123gh6pm_soc.h b/include/hw/arm/tm4c123gh6pm_soc.h
new file mode 100644
index 0000000000..1841483a78
--- /dev/null
+++ b/include/hw/arm/tm4c123gh6pm_soc.h
@@ -0,0 +1,71 @@
+/*
+ * TM4C123GH6PM SoC
+ *
+ * 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_TM4C123GH6PM_SOC_H
+#define HW_ARM_TM4C123GH6PM_SOC_H
+
+#include "hw/arm/armv7m.h"
+#include "qom/object.h"
+#include "hw/clock.h"
+#include "hw/char/tm4c123_usart.h"
+#include "hw/misc/tm4c123_sysctl.h"
+#include "hw/gpio/tm4c123_gpio.h"
+#include "hw/watchdog/tm4c123_watchdog.h"
+#include "hw/timer/tm4c123_gptm.h"
+
+#define TYPE_TM4C123GH6PM_SOC "tm4c123gh6pm-soc"
+
+OBJECT_DECLARE_SIMPLE_TYPE(TM4C123GH6PMState, TM4C123GH6PM_SOC)
+
+#define FLASH_BASE_ADDRESS 0x00000000
+#define FLASH_SIZE (256 * 1024)
+#define SRAM_BASE_ADDRESS 0x20000000
+#define SRAM_SIZE (32 * 1024)
+
+#define SYSCTL_ADDR 0x400FE000
+
+#define USART_COUNT 8
+#define GPIO_COUNT 6
+#define WDT_COUNT 2
+#define GPTM_COUNT 12
+
+struct TM4C123GH6PMState {
+    SysBusDevice parent_obj;
+
+    char *cpu_type;
+
+    ARMv7MState armv7m;
+
+    TM4C123USARTState usart[USART_COUNT];
+    TM4C123SysCtlState sysctl;
+    TM4C123GPIOState gpio[GPIO_COUNT];
+    TM4C123WatchdogState wdt[WDT_COUNT];
+    TM4C123GPTMState gptm[GPTM_COUNT];
+
+    MemoryRegion sram;
+    MemoryRegion alias_region;
+    MemoryRegion flash;
+};
+
+#endif
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/8] tiva c usart module implementation
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
  2023-05-17  8:11 ` [PATCH 1/8] The tivac board initial machine definition Mohamed ElSayed
@ 2023-05-17  8:11 ` Mohamed ElSayed
  2023-06-08 13:36   ` Peter Maydell
  2023-05-17  8:11 ` [PATCH 3/8] tiva c gpio implementation Mohamed ElSayed
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

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

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
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/8] tiva c gpio implementation
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
  2023-05-17  8:11 ` [PATCH 1/8] The tivac board initial machine definition Mohamed ElSayed
  2023-05-17  8:11 ` [PATCH 2/8] tiva c usart module implementation Mohamed ElSayed
@ 2023-05-17  8:11 ` Mohamed ElSayed
  2023-06-08 13:37   ` Peter Maydell
  2023-05-17  8:12 ` [PATCH 4/8] tiva c sysctl implementation Mohamed ElSayed
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 hw/gpio/tm4c123_gpio.c         | 372 +++++++++++++++++++++++++++++++++
 hw/gpio/trace-events           |   4 +
 include/hw/gpio/tm4c123_gpio.h | 127 +++++++++++
 3 files changed, 503 insertions(+)
 create mode 100644 hw/gpio/tm4c123_gpio.c
 create mode 100644 include/hw/gpio/tm4c123_gpio.h

diff --git a/hw/gpio/tm4c123_gpio.c b/hw/gpio/tm4c123_gpio.c
new file mode 100644
index 0000000000..9a27e0664e
--- /dev/null
+++ b/hw/gpio/tm4c123_gpio.c
@@ -0,0 +1,372 @@
+/*
+ * TM4C123 GPIO
+ *
+ * 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/gpio/tm4c123_gpio.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/misc/tm4c123_sysctl.h"
+#include "qemu/bitops.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 gpio_clock_enabled(TM4C123SysCtlState *s, hwaddr addr)
+{
+    switch(addr) {
+        case GPIO_A:
+            return test_bit(0, (const unsigned long*)&s->sysctl_rcgcgpio);
+            break;
+        case GPIO_B:
+            return test_bit(1, (const unsigned long*)&s->sysctl_rcgcgpio);
+            break;
+        case GPIO_C:
+            return test_bit(2, (const unsigned long*)&s->sysctl_rcgcgpio);
+            break;
+        case GPIO_D:
+            return test_bit(3, (const unsigned long*)&s->sysctl_rcgcgpio);
+            break;
+        case GPIO_E:
+            return test_bit(4, (const unsigned long*)&s->sysctl_rcgcgpio);
+            break;
+        case GPIO_F:
+            return test_bit(5, (const unsigned long*)&s->sysctl_rcgcgpio);
+            break;
+    }
+    return false;
+}
+
+static void tm4c123_gpio_reset(DeviceState *dev)
+{
+    TM4C123GPIOState *s = TM4C123_GPIO(dev);
+
+    s->gpio_data = 0x00000000;
+    s->gpio_dir = 0x00000000;
+    s->gpio_is = 0x00000000;
+    s->gpio_ibe = 0x00000000;
+    s->gpio_iev = 0x00000000;
+    s->gpio_im = 0x00000000;
+    s->gpio_ris = 0x00000000;
+    s->gpio_mis = 0x00000000;
+    s->gpio_icr = 0x00000000;
+    s->gpio_afsel = 0x00000000;
+    s->gpio_dr2r = 0x000000FF;
+    s->gpio_dr4r = 0x00000000;
+    s->gpio_dr8r = 0x00000000;
+    s->gpio_odr = 0x00000000;
+    s->gpio_pur = 0x00000000;
+    s->gpio_pdr = 0x00000000;
+    s->gpio_slr = 0x00000000;
+    s->gpio_den = 0x00000000;
+    s->gpio_lock = 0x00000001;
+    s->gpio_ocr = 0x00000000;
+    s->gpio_amsel = 0x00000000;
+    s->gpio_pctl = 0x00000000;
+    s->gpio_adcctl = 0x00000000;
+    s->gpio_dmactl = 0x00000000;
+    s->gpio_per_id4 = 0x00000000;
+    s->gpio_per_id5 = 0x00000000;
+    s->gpio_per_id6 = 0x00000000;
+    s->gpio_per_id7 = 0x00000000;
+    s->gpio_per_id0 = 0x00000061;
+    s->gpio_per_id1 = 0x00000000;
+    s->gpio_per_id2 = 0x00000018;
+    s->gpio_per_id3 = 0x00000001;
+    s->gpio_pcell_id0 = 0x0000000D;
+    s->gpio_pcell_id1 = 0x000000F0;
+    s->gpio_pcell_id2 = 0x00000005;
+    s->gpio_pcell_id3 = 0x000000B1;
+}
+
+static void tm4c123_gpio_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size)
+{
+    TM4C123GPIOState *s = opaque;
+    uint32_t val32 = val64;
+
+    if (!gpio_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("GPIO module clock is not enabled");
+    }
+    trace_tm4c123_gpio_write(addr, val32);
+
+    switch(addr) {
+        case GPIO_DATA:
+            {
+                uint32_t rising_edge = (val32 ^ s->gpio_data) & val32;
+                //level detection
+                s->gpio_mis = s->gpio_is & s->gpio_iev & val32;
+                s->gpio_mis |= s->gpio_is & ~(s->gpio_iev | val32);
+                s->gpio_mis &= s->gpio_im;
+
+                //edge detection
+                //both edges
+                s->gpio_mis |= (s->gpio_is | s->gpio_ibe) & (~s->gpio_is);
+                //rising edge
+                s->gpio_mis |= (~(s->gpio_is | s->gpio_ibe | s->gpio_iev)) & rising_edge;
+                //falling edge
+                s->gpio_mis |= ~(s->gpio_is | s->gpio_ibe | s->gpio_iev | rising_edge);
+                s->gpio_mis &= s->gpio_im;
+                s->gpio_ris |= s->gpio_mis & val32;
+
+                s->gpio_data = val32;
+                if (s->gpio_im != 0)
+                    qemu_irq_pulse(s->irq);
+            }
+            break;
+        case GPIO_DIR:
+            s->gpio_dir = val32;
+            break;
+        case GPIO_IS:
+            s->gpio_is = val32;
+            break;
+        case GPIO_IBE:
+            s->gpio_ibe = val32;
+            break;
+        case GPIO_IEV:
+            s->gpio_iev = val32;
+            break;
+        case GPIO_IM:
+            s->gpio_im = val32;
+            break;
+        case GPIO_RIS:
+            s->gpio_ris = val32;
+            break;
+        case GPIO_MIS:
+            READONLY;
+            break;
+        case GPIO_ICR:
+            s->gpio_mis ^= val32;
+            s->gpio_ris ^= val32;
+            s->gpio_icr = val32;
+            break;
+        case GPIO_AFSEL:
+            s->gpio_afsel = val32;
+            break;
+        case GPIO_DR2R:
+            s->gpio_dr2r = val32;
+            break;
+        case GPIO_DR4R:
+            s->gpio_dr4r = val32;
+            break;
+        case GPIO_DR8R:
+            s->gpio_dr8r = val32;
+            break;
+        case GPIO_ODR:
+            s->gpio_odr = val32;
+            break;
+        case GPIO_PUR:
+            s->gpio_pur = val32;
+            break;
+        case GPIO_PDR:
+            s->gpio_pdr = val32;
+            break;
+        case GPIO_SLR:
+            s->gpio_slr = val32;
+            break;
+        case GPIO_DEN:
+            s->gpio_den = val32;
+            break;
+        case GPIO_LOCK:
+            s->gpio_lock = val32;
+            break;
+        case GPIO_OCR:
+            s->gpio_ocr = val32;
+            break;
+        case GPIO_AMSEL:
+            s->gpio_amsel = val32;
+            break;
+        case GPIO_PCTL:
+            s->gpio_pctl = val32;
+            break;
+        case GPIO_ADCCTL:
+            s->gpio_adcctl = val32;
+            break;
+        case GPIO_DMACTL:
+            s->gpio_dmactl = val32;
+            break;
+        case GPIO_PER_ID4:
+            READONLY;
+            break;
+        case GPIO_PER_ID5:
+            READONLY;
+            break;
+        case GPIO_PER_ID6:
+            READONLY;
+            break;
+        case GPIO_PER_ID7:
+            READONLY;
+            break;
+        case GPIO_PER_ID0:
+            READONLY;
+            break;
+        case GPIO_PER_ID1:
+            READONLY;
+            break;
+        case GPIO_PER_ID2:
+            READONLY;
+            break;
+        case GPIO_PER_ID3:
+            READONLY;
+            break;
+        case GPIO_PCELL_ID0:
+            READONLY;
+            break;
+        case GPIO_PCELL_ID1:
+            READONLY;
+            break;
+        case GPIO_PCELL_ID2:
+            READONLY;
+            break;
+        case GPIO_PCELL_ID3:
+            READONLY;
+            break;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+    }
+}
+
+static uint64_t tm4c123_gpio_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    TM4C123GPIOState *s = opaque;
+
+    trace_tm4c123_gpio_read(addr);
+
+    if (!gpio_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("GPIO module clock is not enabled");
+    }
+
+    switch(addr) {
+        case GPIO_DATA:
+            return s->gpio_data;
+        case GPIO_DIR:
+            return s->gpio_dir;
+        case GPIO_IS:
+            return s->gpio_is;
+        case GPIO_IBE:
+            return s->gpio_ibe;
+        case GPIO_IEV:
+            return s->gpio_iev;
+        case GPIO_IM:
+            return s->gpio_im;
+        case GPIO_RIS:
+            return s->gpio_ris;
+        case GPIO_MIS:
+            return s->gpio_mis;
+        case GPIO_ICR:
+            return s->gpio_icr;
+        case GPIO_AFSEL:
+            return s->gpio_afsel;
+        case GPIO_DR2R:
+            return s->gpio_dr2r;
+        case GPIO_DR4R:
+            return s->gpio_dr4r;
+        case GPIO_DR8R:
+            return s->gpio_dr8r;
+        case GPIO_ODR:
+            return s->gpio_odr;
+        case GPIO_PUR:
+            return s->gpio_pur;
+        case GPIO_PDR:
+            return s->gpio_pdr;
+        case GPIO_SLR:
+            return s->gpio_slr;
+        case GPIO_DEN:
+            return s->gpio_den;
+        case GPIO_LOCK:
+            return s->gpio_lock;
+        case GPIO_OCR:
+            return s->gpio_ocr;
+        case GPIO_AMSEL:
+            return s->gpio_amsel;
+        case GPIO_PCTL:
+            return s->gpio_pctl;
+        case GPIO_ADCCTL:
+            return s->gpio_adcctl;
+        case GPIO_DMACTL:
+            return s->gpio_dmactl;
+        case GPIO_PER_ID4:
+            return s->gpio_per_id4;
+        case GPIO_PER_ID5:
+            return s->gpio_per_id5;
+        case GPIO_PER_ID6:
+            return s->gpio_per_id6;
+        case GPIO_PER_ID7:
+            return s->gpio_per_id7;
+        case GPIO_PER_ID0:
+            return s->gpio_per_id0;
+        case GPIO_PER_ID1:
+            return s->gpio_per_id1;
+        case GPIO_PER_ID2:
+            return s->gpio_per_id2;
+        case GPIO_PER_ID3:
+            return s->gpio_per_id3;
+        case GPIO_PCELL_ID0:
+            return s->gpio_pcell_id0;
+        case GPIO_PCELL_ID1:
+            return s->gpio_pcell_id1;
+        case GPIO_PCELL_ID2:
+            return s->gpio_pcell_id2;
+        case GPIO_PCELL_ID3:
+            return s->gpio_pcell_id3;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+    }
+    return 0;
+}
+
+static const MemoryRegionOps tm4c123_gpio_ops = {
+    .read = tm4c123_gpio_read,
+    .write = tm4c123_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void tm4c123_gpio_init(Object *obj)
+{
+    TM4C123GPIOState *s = TM4C123_GPIO(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+    memory_region_init_io(&s->mmio, obj, &tm4c123_gpio_ops, s, TYPE_TM4C123_GPIO, 0xFFF);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void tm4c123_gpio_class_init(ObjectClass *kclass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(kclass);
+    dc->reset = tm4c123_gpio_reset;
+}
+
+static const TypeInfo tm4c123_gpio_info = {
+    .name = TYPE_TM4C123_GPIO,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TM4C123GPIOState),
+    .instance_init = tm4c123_gpio_init,
+    .class_init = tm4c123_gpio_class_init,
+};
+
+static void tm4c123_gpio_register_types(void)
+{
+    type_register_static(&tm4c123_gpio_info);
+}
+
+type_init(tm4c123_gpio_register_types)
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
index 9736b362ac..22d282495d 100644
--- a/hw/gpio/trace-events
+++ b/hw/gpio/trace-events
@@ -1,5 +1,9 @@
 # See docs/devel/tracing.rst for syntax documentation.
 
+# tm4c123_gpio.c
+tm4c123_gpio_read(uint64_t offset) " offset: 0x%" PRIx64
+tm4c123_gpio_write(uint64_t offset, uint64_t value) " offset: 0x%" PRIx64 " - value: 0x%" PRIx64
+
 # npcm7xx_gpio.c
 npcm7xx_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
 npcm7xx_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
diff --git a/include/hw/gpio/tm4c123_gpio.h b/include/hw/gpio/tm4c123_gpio.h
new file mode 100644
index 0000000000..5162e7bd53
--- /dev/null
+++ b/include/hw/gpio/tm4c123_gpio.h
@@ -0,0 +1,127 @@
+/*
+ * TM4C123 GPIO
+ *
+ * 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_GPIO_H
+#define HW_ARM_TM4C123_GPIO_H
+
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "qom/object.h"
+#include "hw/misc/tm4c123_sysctl.h"
+
+/* #define GPIO_DATA 0x00 */
+#define GPIO_DATA 0x3FC
+#define GPIO_DIR 0x400
+#define GPIO_IS 0x404
+#define GPIO_IBE 0x408
+#define GPIO_IEV 0x40C
+#define GPIO_IM 0x410
+#define GPIO_RIS 0x414
+#define GPIO_MIS 0x418
+#define GPIO_ICR 0x41C
+#define GPIO_AFSEL 0x420
+#define GPIO_DR2R 0x500
+#define GPIO_DR4R 0x504
+#define GPIO_DR8R 0x508
+#define GPIO_ODR 0x50C
+#define GPIO_PUR 0x510
+#define GPIO_PDR 0x514
+#define GPIO_SLR 0x518
+#define GPIO_DEN 0x51C
+#define GPIO_LOCK 0x520
+#define GPIO_OCR 0x524
+#define GPIO_AMSEL 0x528
+#define GPIO_PCTL 0x52C
+#define GPIO_ADCCTL 0x530
+#define GPIO_DMACTL 0x534
+#define GPIO_PER_ID4 0xFD0
+#define GPIO_PER_ID5 0xFD4
+#define GPIO_PER_ID6 0xFD8
+#define GPIO_PER_ID7 0xFDC
+#define GPIO_PER_ID0 0XFE0
+#define GPIO_PER_ID1 0xFE4
+#define GPIO_PER_ID2 0xFE8
+#define GPIO_PER_ID3 0xFEC
+#define GPIO_PCELL_ID0 0xFF0
+#define GPIO_PCELL_ID1 0xFF4
+#define GPIO_PCELL_ID2 0xFF8
+#define GPIO_PCELL_ID3 0xFFC
+
+#define GPIO_A 0x40004000
+#define GPIO_B 0x40005000
+#define GPIO_C 0x40006000
+#define GPIO_D 0x40007000
+#define GPIO_E 0x40024000
+#define GPIO_F 0x40025000
+
+#define TYPE_TM4C123_GPIO "tm4c123-gpio"
+
+OBJECT_DECLARE_SIMPLE_TYPE(TM4C123GPIOState, TM4C123_GPIO)
+
+struct TM4C123GPIOState {
+    SysBusDevice parent_obj;
+    MemoryRegion mmio;
+
+    uint32_t gpio_data;
+    uint32_t gpio_dir;
+    uint32_t gpio_is;
+    uint32_t gpio_ibe;
+    uint32_t gpio_iev;
+    uint32_t gpio_im;
+    uint32_t gpio_ris;
+    uint32_t gpio_mis;
+    uint32_t gpio_icr;
+    uint32_t gpio_afsel;
+    uint32_t gpio_dr2r;
+    uint32_t gpio_dr4r;
+    uint32_t gpio_dr8r;
+    uint32_t gpio_odr;
+    uint32_t gpio_pur;
+    uint32_t gpio_pdr;
+    uint32_t gpio_slr;
+    uint32_t gpio_den;
+    uint32_t gpio_lock;
+    uint32_t gpio_ocr;
+    uint32_t gpio_amsel;
+    uint32_t gpio_pctl;
+    uint32_t gpio_adcctl;
+    uint32_t gpio_dmactl;
+    uint32_t gpio_per_id4;
+    uint32_t gpio_per_id5;
+    uint32_t gpio_per_id6;
+    uint32_t gpio_per_id7;
+    uint32_t gpio_per_id0;
+    uint32_t gpio_per_id1;
+    uint32_t gpio_per_id2;
+    uint32_t gpio_per_id3;
+    uint32_t gpio_pcell_id0;
+    uint32_t gpio_pcell_id1;
+    uint32_t gpio_pcell_id2;
+    uint32_t gpio_pcell_id3;
+
+    qemu_irq irq;
+    TM4C123SysCtlState *sysctl;
+};
+
+#endif
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/8] tiva c sysctl implementation
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
                   ` (2 preceding siblings ...)
  2023-05-17  8:11 ` [PATCH 3/8] tiva c gpio implementation Mohamed ElSayed
@ 2023-05-17  8:12 ` Mohamed ElSayed
  2023-06-08 13:58   ` Peter Maydell
  2023-05-17  8:12 ` [PATCH 5/8] tiva c watchdog timers implementation Mohamed ElSayed
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 hw/misc/tm4c123_sysctl.c         | 989 +++++++++++++++++++++++++++++++
 hw/misc/trace-events             |   5 +
 include/hw/misc/tm4c123_sysctl.h | 307 ++++++++++
 3 files changed, 1301 insertions(+)
 create mode 100644 hw/misc/tm4c123_sysctl.c
 create mode 100644 include/hw/misc/tm4c123_sysctl.h

diff --git a/hw/misc/tm4c123_sysctl.c b/hw/misc/tm4c123_sysctl.c
new file mode 100644
index 0000000000..c996609fc7
--- /dev/null
+++ b/hw/misc/tm4c123_sysctl.c
@@ -0,0 +1,989 @@
+/*
+ * TM4C123 SYSCTL
+ *
+ * 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/misc/tm4c123_sysctl.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 void tm4c123_sysctl_update_system_clock(void *opaque)
+{
+    TM4C123SysCtlState *s = opaque;
+
+    uint32_t RCC_Val = s->sysctl_rcc;
+    uint32_t RCC2_Val = s->sysctl_rcc2;
+
+    uint32_t __CORE_CLK_PRE;
+    uint32_t __CORE_CLK;
+
+    if (RCC2_Val & (1UL << 31)) {  /* is rcc2 used? */
+        if (RCC2_Val & (1UL << 11)) {  /* check BYPASS */
+            if (((RCC2_Val >> 4) & 0x07) == 0x0) {
+                if (((RCC_Val >> 6) & 0x1F) == 0x0) {
+                    __CORE_CLK_PRE = 1000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x1) {
+                    __CORE_CLK_PRE = 1843200UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x2) {
+                    __CORE_CLK_PRE = 2000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x3) {
+                    __CORE_CLK_PRE = 2457600UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x4) {
+                    __CORE_CLK_PRE = 3579545UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x5) {
+                    __CORE_CLK_PRE = 3686400UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x6) {
+                    __CORE_CLK_PRE = 4000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x7) {
+                    __CORE_CLK_PRE = 4096000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x8) {
+                    __CORE_CLK_PRE = 4915200UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x9) {
+                    __CORE_CLK_PRE = 5000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0xA) {
+                    __CORE_CLK_PRE = 5120000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0xB) {
+                    __CORE_CLK_PRE = 6000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0xC) {
+                    __CORE_CLK_PRE = 6144000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0xD) {
+                    __CORE_CLK_PRE = 7372800UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0xE) {
+                    __CORE_CLK_PRE = 8000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0xF) {
+                    __CORE_CLK_PRE = 8192000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x10) {
+                    __CORE_CLK_PRE = 10000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x11) {
+                    __CORE_CLK_PRE = 12000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x12) {
+                    __CORE_CLK_PRE = 12288000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x13) {
+                    __CORE_CLK_PRE = 13560000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x14) {
+                    __CORE_CLK_PRE = 14318180UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x15) {
+                    __CORE_CLK_PRE = 16000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x16) {
+                    __CORE_CLK_PRE = 16384000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x17) {
+                    __CORE_CLK_PRE = 18000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x18) {
+                    __CORE_CLK_PRE = 20000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x19) {
+                    __CORE_CLK_PRE = 24000000UL;
+                } else if (((RCC_Val >> 6) & 0x1F) == 0x1A) {
+                    __CORE_CLK_PRE = 25000000UL;
+                } else {
+                    __CORE_CLK_PRE = 0UL;
+                }
+                __CORE_CLK = __CORE_CLK_PRE / 2UL;  /* divide by 2 since BYPASS is set */
+            } else {  /* PLL is used */
+                uint32_t __PLL_MULT = ((RCC2_Val >> 4) & 0x1F) + 2;
+                uint32_t __PLL_DIV = ((RCC2_Val >> 0) & 0x3F) + 1;
+                uint32_t __PLL_SOURCE = ((RCC2_Val >> 13) & 0x01);
+                if (__PLL_SOURCE == 0) {  /* source is XTAL */
+                    __CORE_CLK_PRE = (XTALI * __PLL_MULT) / __PLL_DIV;
+                } else {  /* source is internal oscillator */
+                    __CORE_CLK_PRE = (16000000UL * __PLL_MULT) / __PLL_DIV;  /* internal oscillator frequency is 16MHz */
+                }
+                __CORE_CLK = __CORE_CLK_PRE / 2UL;  /* divide by 2 since BYPASS is set */
+            }
+        } else {  /* BYPASS is not set */
+            uint32_t __SYS_DIV = ((RCC2_Val >> 22) & 0x7F) + 1;
+            uint32_t __PLL_MULT = ((RCC2_Val >> 4) & 0x1F) + 2;
+            uint32_t __PLL_DIV = ((RCC2_Val >> 0) & 0x3F) + 1;
+            uint32_t __PLL_SOURCE = ((RCC2_Val >> 13) & 0x01);
+            if (__PLL_SOURCE == 0) {  /* source is XTAL */
+                __CORE_CLK_PRE = (XTALI * __PLL_MULT) / __PLL_DIV;
+            } else {  /* source is internal oscillator */
+                __CORE_CLK_PRE = (16000000UL * __PLL_MULT) / __PLL_DIV;  /* internal oscillator frequency is 16MHz */
+            }
+            __CORE_CLK = __CORE_CLK_PRE / __SYS_DIV;
+        }
+    } else {  /* rcc2 is not used */
+        if (((RCC_Val >> 16) & 0x01) == 0x01) {  /* check USESYSCLK */
+            if (((RCC_Val >> 23) & 0x01) == 0x01) {  /* check BYPASS */
+                __CORE_CLK_PRE = XTALI;
+            } else {  /* PLL is used */
+                uint32_t __PLL_MULT = ((RCC_Val >> 18) & 0x1F) + 2;
+                uint32_t __PLL_DIV = ((RCC_Val >> 12) & 0x3F) + 1;
+                uint32_t __PLL_SOURCE = ((RCC_Val >> 16) & 0x01);
+                if (__PLL_SOURCE == 0) {  /* source is XTAL */
+                    __CORE_CLK_PRE = (XTALI * __PLL_MULT) / __PLL_DIV;
+                } else {  /* source is internal oscillator */
+                    __CORE_CLK_PRE = (16000000UL * __PLL_MULT) / __PLL_DIV;  /* internal oscillator frequency is 16MHz */
+                }
+            }
+        } else {  /* USESYSCLK bit is not set */
+            __CORE_CLK_PRE = 16000000UL;  /* default to internal oscillator frequency */
+        }
+        __CORE_CLK = __CORE_CLK_PRE / 1UL;  /* no division needed since BYPASS is not set */
+    }
+    trace_tm4c123_sysctl_update_system_clock(__CORE_CLK);
+    clock_update_hz(s->mainclk, __CORE_CLK);
+}
+
+static void tm4c123_sysctl_reset(DeviceState *dev)
+{
+    TM4C123SysCtlState *s = TM4C123_SYSCTL(dev);
+
+    s->sysctl_did0 = 0x00000000;
+    s->sysctl_did1 = 0x10A1606E;
+    s->sysctl_pborctl = 0x00000000;
+    s->sysctl_ris = 0x00000000;
+    s->sysctl_imc = 0x00000000;
+    s->sysctl_misc = 0x00000000;
+    s->sysctl_resc = 0x00000000;
+    s->sysctl_rcc = 0x078E3AD1;
+    s->sysctl_gpiohbctl = 0x00007E00;
+    s->sysctl_rcc2 = 0x07C06810;
+    s->sysctl_moscctl = 0x00000000;
+    s->sysctl_dslpclkcfg = 0x07800000;
+    s->sysctl_sysprop = 0x00001D31;
+    s->sysctl_piosccal = 0x00000000;
+    s->sysctl_pioscstat = 0x00000040;
+    s->sysctl_pllfreq0 = 0x00000032;
+    s->sysctl_pllfreq1 = 0x00000001;
+    s->sysctl_pllstat = 0x00000000;
+    s->sysctl_slppwrcfg = 0x00000000;
+    s->sysctl_dslppwrcfg = 0x00000000;
+    s->sysctl_ldospctl = 0x00000018;
+    s->sysctl_ldospcal = 0x00001818;
+    s->sysctl_ldodpctl = 0x00000012;
+    s->sysctl_ldodpcal = 0x00001212;
+    s->sysctl_sdpmst = 0x00000000;
+    s->sysctl_ppwd = 0x00000003;
+    s->sysctl_pptimer = 0x0000003F;
+    s->sysctl_ppgpio = 0x0000003F;
+    s->sysctl_ppdma = 0x00000001;
+    s->sysctl_pphib = 0x00000001;
+    s->sysctl_ppuart = 0x000000FF;
+    s->sysctl_ppsi = 0x0000000F;
+    s->sysctl_ppi2c = 0x0000000F;
+    s->sysctl_ppusb = 0x00000001;
+    s->sysctl_ppcan = 0x00000003;
+    s->sysctl_ppadc = 0x00000003;
+    s->sysctl_ppacmp = 0x00000001;
+    s->sysctl_pppwm = 0x00000003;
+    s->sysctl_ppqei = 0x00000003;
+    s->sysctl_ppeeprom = 0x00000001;
+    s->sysctl_ppwtimer = 0x0000003F;
+    s->sysctl_srwd = 0x00000000;
+    s->sysctl_srtimer = 0x00000000;
+    s->sysctl_srgpio = 0x00000000;
+    s->sysctl_srdma = 0x00000000;
+    s->sysctl_srhib = 0x00000000;
+    s->sysctl_sruart = 0x00000000;
+    s->sysctl_srssi = 0x00000000;
+    s->sysctl_sri2c = 0x00000000;
+    s->sysctl_srusb = 0x00000000;
+    s->sysctl_srcan = 0x00000000;
+    s->sysctl_sradc = 0x00000000;
+    s->sysctl_sracmp = 0x00000000;
+    s->sysctl_srpwm = 0x00000000;
+    s->sysctl_srqei = 0x00000000;
+    s->sysctl_sreeprom = 0x00000000;
+    s->sysctl_srwtimer = 0x00000000;
+    s->sysctl_rcgcwd = 0x00000000;
+    s->sysctl_rcgctimer = 0x00000000;
+    s->sysctl_rcgcgpio = 0x00000000;
+    s->sysctl_rcgcdma = 0x00000000;
+    s->sysctl_rcgchib = 0x00000001;
+    s->sysctl_rcgcuart = 0x00000000;
+    s->sysctl_rcgcssi = 0x00000000;
+    s->sysctl_rcgci2c = 0x00000000;
+    s->sysctl_rcgcusb = 0x00000000;
+    s->sysctl_rcgccan = 0x00000000;
+    s->sysctl_rcgcadc = 0x00000000;
+    s->sysctl_rcgcacmp = 0x00000000;
+    s->sysctl_rcgcpwm = 0x00000000;
+    s->sysctl_rcgcqei = 0x00000000;
+    s->sysctl_rcgceeprom = 0x00000000;
+    s->sysctl_rcgcwtimer = 0x00000000;
+    s->sysctl_scgcwd = 0x00000000;
+    s->sysctl_scgctimer = 0x00000000;
+    s->sysctl_scgcgpio = 0x00000000;
+    s->sysctl_scgcdma = 0x00000000;
+    s->sysctl_scgchib = 0x00000001;
+    s->sysctl_scgcuart = 0x00000000;
+    s->sysctl_scgcssi = 0x00000000;
+    s->sysctl_scgci2c = 0x00000000;
+    s->sysctl_scgcusb = 0x00000000;
+    s->sysctl_scgccan = 0x00000000;
+    s->sysctl_scgcadc = 0x00000000;
+    s->sysctl_scgcacmp = 0x00000000;
+    s->sysctl_scgcpwm = 0x00000000;
+    s->sysctl_scgcqei = 0x00000000;
+    s->sysctl_scgceeprom = 0x00000000;
+    s->sysctl_scgcwtimer = 0x00000000;
+    s->sysctl_dcgcwd = 0x00000000;
+    s->sysctl_dcgctimer = 0x00000000;
+    s->sysctl_dcgcgpio = 0x00000000;
+    s->sysctl_dcgcdma = 0x00000000;
+    s->sysctl_dcgchib = 0x00000001;
+    s->sysctl_dcgcuart = 0x00000000;
+    s->sysctl_dcgcssi = 0x00000000;
+    s->sysctl_dcgci2c = 0x00000000;
+    s->sysctl_dcgcusb = 0x00000000;
+    s->sysctl_dcgccan = 0x00000000;
+    s->sysctl_dcgcadc = 0x00000000;
+    s->sysctl_dcgcacmp = 0x00000000;
+    s->sysctl_dcgcpwm = 0x00000000;
+    s->sysctl_dcgcqei = 0x00000000;
+    s->sysctl_dcgceeprom = 0x00000000;
+    s->sysctl_dcgcwtime = 0x00000000;
+    s->sysctl_prwd = 0x00000000;
+    s->sysctl_prtimer = 0x00000000;
+    s->sysctl_prgpio = 0x00000000;
+    s->sysctl_prdma = 0x00000000;
+    s->sysctl_prhib = 0x00000001;
+    s->sysctl_pruart = 0x00000000;
+    s->sysctl_prssi = 0x00000000;
+    s->sysctl_pri2c = 0x00000000;
+    s->sysctl_prusb = 0x00000000;
+    s->sysctl_prcan = 0x00000000;
+    s->sysctl_pradc = 0x00000000;
+    s->sysctl_pracmp = 0x00000000;
+    s->sysctl_prpwm = 0x00000000;
+    s->sysctl_prqei = 0x00000000;
+    s->sysctl_preeprom = 0x00000000;
+    s->sysctl_prwtimer = 0x00000000;
+}
+
+static void tm4c123_sysctl_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size)
+{
+    TM4C123SysCtlState *s = opaque;
+    uint32_t val32 = val64;
+
+    trace_tm4c123_sysctl_write(addr, val32);
+
+    switch (addr) {
+        case SYSCTL_DID0:
+            READONLY;
+            break;
+        case SYSCTL_DID1:
+            READONLY;
+            break;
+        case SYSCTL_PBORCTL:
+            s->sysctl_pborctl = val32;
+            break;
+        case SYSCTL_RIS:
+            READONLY;
+            break;
+        case SYSCTL_IMC:
+            s->sysctl_imc = val32;
+            /*
+             * setting the MISC
+             */
+            s->sysctl_misc = val32;
+            break;
+        case SYSCTL_MISC:
+            s->sysctl_misc = val32;
+            break;
+        case SYSCTL_RESC:
+            s->sysctl_resc = val32;
+            break;
+        case SYSCTL_RCC:
+            s->sysctl_rcc = val32;
+            /*
+             * Setting the SYSCTL_RIS manually for now.
+             */
+            if (s->sysctl_rcc & SYSCTL_RCC_PWRDN && !(s->sysctl_rcc2 & SYSCTL_RCC2_USERCC2)) {
+                s->sysctl_ris |= SYSCTL_RIS_PLLRIS;
+            }
+            tm4c123_sysctl_update_system_clock(s);
+            break;
+        case SYSCTL_GPIOHBCTL:
+            s->sysctl_gpiohbctl = val32;
+            break;
+        case SYSCTL_RCC2:
+            s->sysctl_rcc2 = val32;
+            /*
+             * Setting the SYSCTL_RIS manually for now.
+             */
+            if (s->sysctl_rcc2 & SYSCTL_RCC2_USERCC2 && !(s->sysctl_rcc2 & SYSCTL_RCC2_PWRDN2)) {
+                s->sysctl_ris |= SYSCTL_RIS_PLLRIS;
+            }
+            tm4c123_sysctl_update_system_clock(s);
+            break;
+        case SYSCTL_MOSCCTL:
+            s->sysctl_moscctl = val32;
+            break;
+        case SYSCTL_DSLPCLKCFG:
+            s->sysctl_dslpclkcfg = val32;
+            break;
+        case SYSCTL_SYSPROP:
+            READONLY;
+            break;
+        case SYSCTL_PIOSCCAL:
+            s->sysctl_piosccal = val32;
+            break;
+        case SYSCTL_PIOSCSTAT:
+            READONLY;
+            break;
+        case SYSCTL_PLLFREQ0:
+            READONLY;
+            break;
+        case SYSCTL_PLLFREQ1:
+            READONLY;
+            break;
+        case SYSCTL_PLLSTAT:
+            READONLY;
+            break;
+        case SYSCTL_SLPPWRCFG:
+            s->sysctl_slppwrcfg = val32;
+            break;
+        case SYSCTL_DSLPPWRCFG:
+            s->sysctl_dslppwrcfg = val32;
+            break;
+        case SYSCTL_LDOSPCTL:
+            s->sysctl_ldospctl = val32;
+            break;
+        case SYSCTL_LDOSPCAL:
+            READONLY;
+            break;
+        case SYSCTL_LDODPCTL:
+            s->sysctl_ldodpctl = val32;
+            break;
+        case SYSCTL_LDODPCAL:
+            READONLY;
+            break;
+        case SYSCTL_SDPMST:
+            s->sysctl_sdpmst = val32;
+            break;
+        case SYSCTL_PPWD:
+            READONLY;
+            break;
+        case SYSCTL_PPTIMER:
+            READONLY;
+            break;
+        case SYSCTL_PPGPIO:
+            READONLY;
+            break;
+        case SYSCTL_PPDMA:
+            READONLY;
+            break;
+        case SYSCTL_PPHIB:
+            READONLY;
+            break;
+        case SYSCTL_PPUART:
+            READONLY;
+            break;
+        case SYSCTL_PPSI:
+            READONLY;
+            break;
+        case SYSCTL_PPI2C:
+            READONLY;
+            break;
+        case SYSCTL_PPUSB:
+            READONLY;
+            break;
+        case SYSCTL_PPCAN:
+            READONLY;
+            break;
+        case SYSCTL_PPADC:
+            READONLY;
+            break;
+        case SYSCTL_PPACMP:
+            READONLY;
+            break;
+        case SYSCTL_PPPWM:
+            READONLY;
+            break;
+        case SYSCTL_PPQEI:
+            READONLY;
+            break;
+        case SYSCTL_PPEEPROM:
+            READONLY;
+            break;
+        case SYSCTL_PPWTIMER:
+            READONLY;
+            break;
+        case SYSCTL_SRWD:
+            s->sysctl_srwd = val32;
+            break;
+        case SYSCTL_SRTIMER:
+            s->sysctl_srtimer = val32;
+            break;
+        case SYSCTL_SRGPIO:
+            s->sysctl_srgpio = val32;
+            break;
+        case SYSCTL_SRDMA:
+            s->sysctl_srdma = val32;
+            break;
+        case SYSCTL_SRHIB:
+            s->sysctl_srhib = val32;
+            break;
+        case SYSCTL_SRUART:
+            s->sysctl_sruart = val32;
+            break;
+        case SYSCTL_SRSSI:
+            s->sysctl_srssi = val32;
+            break;
+        case SYSCTL_SRI2C:
+            s->sysctl_sri2c = val32;
+            break;
+        case SYSCTL_SRUSB:
+            s->sysctl_srusb = val32;
+            break;
+        case SYSCTL_SRCAN:
+            s->sysctl_srcan = val32;
+            break;
+        case SYSCTL_SRADC:
+            s->sysctl_sradc = val32;
+            break;
+        case SYSCTL_SRACMP:
+            s->sysctl_sracmp = val32;
+            break;
+        case SYSCTL_SRPWM:
+            s->sysctl_srpwm = val32;
+            break;
+        case SYSCTL_SRQEI:
+            s->sysctl_srqei = val32;
+            break;
+        case SYSCTL_SREEPROM:
+            s->sysctl_sreeprom = val32;
+            break;
+        case SYSCTL_SRWTIMER:
+            s->sysctl_srwtimer = val32;
+            break;
+        case SYSCTL_RCGCWD:
+            s->sysctl_rcgcwd = val32;
+            break;
+        case SYSCTL_RCGCTIMER:
+            s->sysctl_rcgctimer = val32;
+            break;
+        case SYSCTL_RCGCGPIO:
+            s->sysctl_rcgcgpio = val32;
+            s->sysctl_prgpio = val32;
+            break;
+        case SYSCTL_RCGCDMA:
+            s->sysctl_rcgcdma = val32;
+            s->sysctl_prdma = val32;
+            break;
+        case SYSCTL_RCGCHIB:
+            s->sysctl_rcgchib = val32;
+            s->sysctl_prhib = val32;
+            break;
+        case SYSCTL_RCGCUART:
+            s->sysctl_rcgcuart = val32;
+            s->sysctl_pruart = val32;
+            break;
+        case SYSCTL_RCGCSSI:
+            s->sysctl_rcgcssi = val32;
+            s->sysctl_prssi = val32;
+            break;
+        case SYSCTL_RCGCI2C:
+            s->sysctl_rcgci2c = val32;
+            s->sysctl_pri2c = val32;
+            break;
+        case SYSCTL_RCGCUSB:
+            s->sysctl_rcgcusb = val32;
+            s->sysctl_prusb = val32;
+            break;
+        case SYSCTL_RCGCCAN:
+            s->sysctl_rcgccan = val32;
+            s->sysctl_prcan = val32;
+            break;
+        case SYSCTL_RCGCADC:
+            s->sysctl_rcgcadc = val32;
+            s->sysctl_pradc = val32;
+            break;
+        case SYSCTL_RCGCACMP:
+            s->sysctl_rcgcacmp = val32;
+            s->sysctl_pracmp = val32;
+            break;
+        case SYSCTL_RCGCPWM:
+            s->sysctl_rcgcpwm = val32;
+            s->sysctl_prpwm = val32;
+            break;
+        case SYSCTL_RCGCQEI:
+            s->sysctl_rcgcqei = val32;
+            s->sysctl_prqei = val32;
+            break;
+        case SYSCTL_RCGCEEPROM:
+            s->sysctl_rcgceeprom = val32;
+            s->sysctl_preeprom = val32;
+            break;
+        case SYSCTL_RCGCWTIMER:
+            s->sysctl_rcgcwtimer = val32;
+            s->sysctl_prwtimer = val32;
+            break;
+        case SYSCTL_SCGCWD:
+            s->sysctl_scgcwd = val32;
+            break;
+        case SYSCTL_SCGCTIMER:
+            s->sysctl_scgctimer = val32;
+            break;
+        case SYSCTL_SCGCGPIO:
+            s->sysctl_scgcgpio = val32;
+            break;
+        case SYSCTL_SCGCDMA:
+            s->sysctl_scgcdma = val32;
+            break;
+        case SYSCTL_SCGCHIB:
+            s->sysctl_scgchib = val32;
+            break;
+        case SYSCTL_SCGCUART:
+            s->sysctl_scgcuart = val32;
+            break;
+        case SYSCTL_SCGCSSI:
+            s->sysctl_scgcssi = val32;
+            break;
+        case SYSCTL_SCGCI2C:
+            s->sysctl_scgci2c = val32;
+            break;
+        case SYSCTL_SCGCUSB:
+            s->sysctl_scgcusb = val32;
+            break;
+        case SYSCTL_SCGCCAN:
+            s->sysctl_scgccan = val32;
+            break;
+        case SYSCTL_SCGCADC:
+            s->sysctl_scgcadc = val32;
+            break;
+        case SYSCTL_SCGCACMP:
+            s->sysctl_scgcacmp = val32;
+            break;
+        case SYSCTL_SCGCPWM:
+            s->sysctl_scgcpwm = val32;
+            break;
+        case SYSCTL_SCGCQEI:
+            s->sysctl_scgcqei = val32;
+            break;
+        case SYSCTL_SCGCEEPROM:
+            s->sysctl_scgceeprom = val32;
+            break;
+        case SYSCTL_SCGCWTIMER:
+            s->sysctl_scgcwtimer = val32;
+            break;
+        case SYSCTL_DCGCWD:
+            s->sysctl_dcgcwd = val32;
+            break;
+        case SYSCTL_DCGCTIMER:
+            s->sysctl_dcgctimer = val32;
+            break;
+        case SYSCTL_DCGCGPIO:
+            s->sysctl_dcgcgpio = val32;
+            break;
+        case SYSCTL_DCGCDMA:
+            s->sysctl_dcgcdma = val32;
+            break;
+        case SYSCTL_DCGCHIB:
+            s->sysctl_dcgchib = val32;
+            break;
+        case SYSCTL_DCGCUART:
+            s->sysctl_dcgcuart = val32;
+            break;
+        case SYSCTL_DCGCSSI:
+            s->sysctl_dcgcssi = val32;
+            break;
+        case SYSCTL_DCGCI2C:
+            s->sysctl_dcgci2c = val32;
+            break;
+        case SYSCTL_DCGCUSB:
+            s->sysctl_dcgcusb = val32;
+            break;
+        case SYSCTL_DCGCCAN:
+            s->sysctl_dcgccan = val32;
+            break;
+        case SYSCTL_DCGCADC:
+            s->sysctl_dcgcadc = val32;
+            break;
+        case SYSCTL_DCGCACMP:
+            s->sysctl_dcgcacmp = val32;
+            break;
+        case SYSCTL_DCGCPWM:
+            s->sysctl_dcgcpwm = val32;
+            break;
+        case SYSCTL_DCGCQEI:
+            s->sysctl_dcgcqei = val32;
+            break;
+        case SYSCTL_DCGCEEPROM:
+            s->sysctl_dcgceeprom = val32;
+            break;
+        case SYSCTL_DCGCWTIME:
+            s->sysctl_dcgcwtime = val32;
+            break;
+        case SYSCTL_PRWD:
+            READONLY;
+            break;
+        case SYSCTL_PRTIMER:
+            READONLY;
+            break;
+        case SYSCTL_PRGPIO:
+            READONLY;
+            break;
+        case SYSCTL_PRDMA:
+            READONLY;
+            break;
+        case SYSCTL_PRHIB:
+            READONLY;
+            break;
+        case SYSCTL_PRUART:
+            READONLY;
+            break;
+        case SYSCTL_PRSSI:
+            READONLY;
+            break;
+        case SYSCTL_PRI2C:
+            READONLY;
+            break;
+        case SYSCTL_PRUSB:
+            READONLY;
+            break;
+        case SYSCTL_PRCAN:
+            READONLY;
+            break;
+        case SYSCTL_PRADC:
+            READONLY;
+            break;
+        case SYSCTL_PRACMP:
+            READONLY;
+            break;
+        case SYSCTL_PRPWM:
+            READONLY;
+            break;
+        case SYSCTL_PRQEI:
+            READONLY;
+            break;
+        case SYSCTL_PREEPROM:
+            READONLY;
+            break;
+        case SYSCTL_PRWTIMER:
+            READONLY;
+            break;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+            break;
+    }
+}
+
+static uint64_t tm4c123_sysctl_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    TM4C123SysCtlState *s = opaque;
+
+    trace_tm4c123_sysctl_read(addr);
+
+    switch (addr) {
+        case SYSCTL_DID0:
+            return s->sysctl_did0;
+        case SYSCTL_DID1:
+            return s->sysctl_did1;
+        case SYSCTL_PBORCTL:
+            return s->sysctl_pborctl;
+        case SYSCTL_RIS:
+            return s->sysctl_ris;
+        case SYSCTL_IMC:
+            return s->sysctl_imc;
+        case SYSCTL_MISC:
+            return s->sysctl_misc;
+        case SYSCTL_RESC:
+            return s->sysctl_resc;
+        case SYSCTL_RCC:
+            return s->sysctl_rcc;
+        case SYSCTL_GPIOHBCTL:
+            return s->sysctl_gpiohbctl;
+        case SYSCTL_RCC2:
+            return s->sysctl_rcc2;
+        case SYSCTL_MOSCCTL:
+            return s->sysctl_moscctl;
+        case SYSCTL_DSLPCLKCFG:
+            return s->sysctl_dslpclkcfg;
+        case SYSCTL_SYSPROP:
+            return s->sysctl_sysprop;
+        case SYSCTL_PIOSCCAL:
+            return s->sysctl_piosccal;
+        case SYSCTL_PIOSCSTAT:
+            return s->sysctl_pioscstat;
+        case SYSCTL_PLLFREQ0:
+            return s->sysctl_pllfreq0;
+        case SYSCTL_PLLFREQ1:
+            return s->sysctl_pllfreq1;
+        case SYSCTL_PLLSTAT:
+            return s->sysctl_pllstat;
+        case SYSCTL_SLPPWRCFG:
+            return s->sysctl_slppwrcfg;
+        case SYSCTL_DSLPPWRCFG:
+            return s->sysctl_dslppwrcfg;
+        case SYSCTL_LDOSPCTL:
+            return s->sysctl_ldospctl;
+        case SYSCTL_LDOSPCAL:
+            return s->sysctl_ldospcal;
+        case SYSCTL_LDODPCTL:
+            return s->sysctl_ldodpctl;
+        case SYSCTL_LDODPCAL:
+            return s->sysctl_ldodpcal;
+        case SYSCTL_SDPMST:
+            return s->sysctl_sdpmst;
+        case SYSCTL_PPWD:
+            return s->sysctl_ppwd;
+        case SYSCTL_PPTIMER:
+            return s->sysctl_pptimer;
+        case SYSCTL_PPGPIO:
+            return s->sysctl_ppgpio;
+        case SYSCTL_PPDMA:
+            return s->sysctl_ppdma;
+        case SYSCTL_PPHIB:
+            return s->sysctl_pphib;
+        case SYSCTL_PPUART:
+            return s->sysctl_ppuart;
+        case SYSCTL_PPSI:
+            return s->sysctl_ppsi;
+        case SYSCTL_PPI2C:
+            return s->sysctl_ppi2c;
+        case SYSCTL_PPUSB:
+            return s->sysctl_ppusb;
+        case SYSCTL_PPCAN:
+            return s->sysctl_ppcan;
+        case SYSCTL_PPADC:
+            return s->sysctl_ppadc;
+        case SYSCTL_PPACMP:
+            return s->sysctl_ppacmp;
+        case SYSCTL_PPPWM:
+            return s->sysctl_pppwm;
+        case SYSCTL_PPQEI:
+            return s->sysctl_ppqei;
+        case SYSCTL_PPEEPROM:
+            return s->sysctl_ppeeprom;
+        case SYSCTL_PPWTIMER:
+            return s->sysctl_ppwtimer;
+        case SYSCTL_SRWD:
+            return s->sysctl_srwd;
+        case SYSCTL_SRTIMER:
+            return s->sysctl_srtimer;
+        case SYSCTL_SRGPIO:
+            return s->sysctl_srgpio;
+        case SYSCTL_SRDMA:
+            return s->sysctl_srdma;
+        case SYSCTL_SRHIB:
+            return s->sysctl_srhib;
+        case SYSCTL_SRUART:
+            return s->sysctl_sruart;
+        case SYSCTL_SRSSI:
+            return s->sysctl_srssi;
+        case SYSCTL_SRI2C:
+            return s->sysctl_sri2c;
+        case SYSCTL_SRUSB:
+            return s->sysctl_srusb;
+        case SYSCTL_SRCAN:
+            return s->sysctl_srcan;
+        case SYSCTL_SRADC:
+            return s->sysctl_sradc;
+        case SYSCTL_SRACMP:
+            return s->sysctl_sracmp;
+        case SYSCTL_SRPWM:
+            return s->sysctl_srpwm;
+        case SYSCTL_SRQEI:
+            return s->sysctl_srqei;
+        case SYSCTL_SREEPROM:
+            return s->sysctl_sreeprom;
+        case SYSCTL_SRWTIMER:
+            return s->sysctl_srwtimer;
+        case SYSCTL_RCGCWD:
+            return s->sysctl_rcgcwd;
+        case SYSCTL_RCGCTIMER:
+            return s->sysctl_rcgctimer;
+        case SYSCTL_RCGCGPIO:
+            return s->sysctl_rcgcgpio;
+        case SYSCTL_RCGCDMA:
+            return s->sysctl_rcgcdma;
+        case SYSCTL_RCGCHIB:
+            return s->sysctl_rcgchib;
+        case SYSCTL_RCGCUART:
+            return s->sysctl_rcgcuart;
+        case SYSCTL_RCGCSSI:
+            return s->sysctl_rcgcssi;
+        case SYSCTL_RCGCI2C:
+            return s->sysctl_rcgci2c;
+        case SYSCTL_RCGCUSB:
+            return s->sysctl_rcgcusb;
+        case SYSCTL_RCGCCAN:
+            return s->sysctl_rcgccan;
+        case SYSCTL_RCGCADC:
+            return s->sysctl_rcgcadc;
+        case SYSCTL_RCGCACMP:
+            return s->sysctl_rcgcacmp;
+        case SYSCTL_RCGCPWM:
+            return s->sysctl_rcgcpwm;
+        case SYSCTL_RCGCQEI:
+            return s->sysctl_rcgcqei;
+        case SYSCTL_RCGCEEPROM:
+            return s->sysctl_rcgceeprom;
+        case SYSCTL_RCGCWTIMER:
+            return s->sysctl_rcgcwtimer;
+        case SYSCTL_SCGCWD:
+            return s->sysctl_scgcwd;
+        case SYSCTL_SCGCTIMER:
+            return s->sysctl_scgctimer;
+        case SYSCTL_SCGCGPIO:
+            return s->sysctl_scgcgpio;
+        case SYSCTL_SCGCDMA:
+            return s->sysctl_scgcdma;
+        case SYSCTL_SCGCHIB:
+            return s->sysctl_scgchib;
+        case SYSCTL_SCGCUART:
+            return s->sysctl_scgcuart;
+        case SYSCTL_SCGCSSI:
+            return s->sysctl_scgcssi;
+        case SYSCTL_SCGCI2C:
+            return s->sysctl_scgci2c;
+        case SYSCTL_SCGCUSB:
+            return s->sysctl_scgcusb;
+        case SYSCTL_SCGCCAN:
+            return s->sysctl_scgccan;
+        case SYSCTL_SCGCADC:
+            return s->sysctl_scgcadc;
+        case SYSCTL_SCGCACMP:
+            return s->sysctl_scgcacmp;
+        case SYSCTL_SCGCPWM:
+            return s->sysctl_scgcpwm;
+        case SYSCTL_SCGCQEI:
+            return s->sysctl_scgcqei;
+        case SYSCTL_SCGCEEPROM:
+            return s->sysctl_scgceeprom;
+        case SYSCTL_SCGCWTIMER:
+            return s->sysctl_scgcwtimer;
+        case SYSCTL_DCGCWD:
+            return s->sysctl_dcgcwd;
+        case SYSCTL_DCGCTIMER:
+            return s->sysctl_dcgctimer;
+        case SYSCTL_DCGCGPIO:
+            return s->sysctl_dcgcgpio;
+        case SYSCTL_DCGCDMA:
+            return s->sysctl_dcgcdma;
+        case SYSCTL_DCGCHIB:
+            return s->sysctl_dcgchib;
+        case SYSCTL_DCGCUART:
+            return s->sysctl_dcgcuart;
+        case SYSCTL_DCGCSSI:
+            return s->sysctl_dcgcssi;
+        case SYSCTL_DCGCI2C:
+            return s->sysctl_dcgci2c;
+        case SYSCTL_DCGCUSB:
+            return s->sysctl_dcgcusb;
+        case SYSCTL_DCGCCAN:
+            return s->sysctl_dcgccan;
+        case SYSCTL_DCGCADC:
+            return s->sysctl_dcgcadc;
+        case SYSCTL_DCGCACMP:
+            return s->sysctl_dcgcacmp;
+        case SYSCTL_DCGCPWM:
+            return s->sysctl_dcgcpwm;
+        case SYSCTL_DCGCQEI:
+            return s->sysctl_dcgcqei;
+        case SYSCTL_DCGCEEPROM:
+            return s->sysctl_dcgceeprom;
+        case SYSCTL_DCGCWTIME:
+            return s->sysctl_dcgcwtime;
+        case SYSCTL_PRWD:
+            return s->sysctl_prwd;
+        case SYSCTL_PRTIMER:
+            return s->sysctl_prtimer;
+        case SYSCTL_PRGPIO:
+            return s->sysctl_prgpio;
+        case SYSCTL_PRDMA:
+            return s->sysctl_prdma;
+        case SYSCTL_PRHIB:
+            return s->sysctl_prhib;
+        case SYSCTL_PRUART:
+            return s->sysctl_pruart;
+        case SYSCTL_PRSSI:
+            return s->sysctl_prssi;
+        case SYSCTL_PRI2C:
+            return s->sysctl_pri2c;
+        case SYSCTL_PRUSB:
+            return s->sysctl_prusb;
+        case SYSCTL_PRCAN:
+            return s->sysctl_prcan;
+        case SYSCTL_PRADC:
+            return s->sysctl_pradc;
+        case SYSCTL_PRACMP:
+            return s->sysctl_pracmp;
+        case SYSCTL_PRPWM:
+            return s->sysctl_prpwm;
+        case SYSCTL_PRQEI:
+            return s->sysctl_prqei;
+        case SYSCTL_PREEPROM:
+            return s->sysctl_preeprom;
+        case SYSCTL_PRWTIMER:
+            return s->sysctl_prwtimer;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+            break;
+    }
+    return 0;
+}
+
+static const MemoryRegionOps tm4c123_sysctl_ops = {
+    .read = tm4c123_sysctl_read,
+    .write = tm4c123_sysctl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void tm4c123_sysctl_init(Object *obj)
+{
+    TM4C123SysCtlState *s = TM4C123_SYSCTL(obj);
+
+    s->mainclk = clock_new(OBJECT(s), "main-clk");
+    clock_set_hz(s->mainclk, 1000 * 1000);
+    s->outclk = qdev_init_clock_out(DEVICE(s), "outclk");
+    clock_set_source(s->outclk, s->mainclk);
+
+    memory_region_init_io(&s->mmio, obj, &tm4c123_sysctl_ops, s, TYPE_TM4C123_SYSCTL, 0xFFF);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void tm4c123_sysctl_realize(DeviceState *dev, Error **errp)
+{
+    TM4C123SysCtlState *s = TM4C123_SYSCTL(dev);
+    tm4c123_sysctl_update_system_clock(s);
+
+}
+
+static void tm4c123_sysctl_class_init(ObjectClass *kclass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(kclass);
+    dc->reset = tm4c123_sysctl_reset;
+    dc->realize = tm4c123_sysctl_realize;
+}
+
+static const TypeInfo tm4c123_sysctl_info = {
+    .name = TYPE_TM4C123_SYSCTL,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TM4C123SysCtlState),
+    .instance_init = tm4c123_sysctl_init,
+    .class_init = tm4c123_sysctl_class_init,
+};
+
+static void tm4c123_sysctl_register_types(void)
+{
+    type_register_static(&tm4c123_sysctl_info);
+}
+
+type_init(tm4c123_sysctl_register_types)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index c47876a902..0c40b49457 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -1,5 +1,10 @@
 # See docs/devel/tracing.rst for syntax documentation.
 
+# tm4c123_sysctl.c
+tm4c123_sysctl_read(uint64_t offset) " offset: 0x%" PRIu64
+tm4c123_sysctl_write(uint64_t offset, uint64_t value) " offset: 0x%" PRIu64 " - value: 0x%"PRIu64
+tm4c123_sysctl_update_system_clock(uint32_t value) "New clock value = %"PRIu32" Hz"
+
 # allwinner-cpucfg.c
 allwinner_cpucfg_cpu_reset(uint8_t cpu_id, uint32_t reset_addr) "id %u, reset_addr 0x%" PRIx32
 allwinner_cpucfg_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
diff --git a/include/hw/misc/tm4c123_sysctl.h b/include/hw/misc/tm4c123_sysctl.h
new file mode 100644
index 0000000000..a8219a8693
--- /dev/null
+++ b/include/hw/misc/tm4c123_sysctl.h
@@ -0,0 +1,307 @@
+/*
+ * TM4C123 SYSCTL
+ *
+ * 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_SYSCTL_H
+#define HW_ARM_TM4C123_SYSCTL_H
+
+#include "qom/object.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/clock.h"
+#include "hw/qdev-clock.h"
+#include "qapi/error.h"
+
+#define XTALM       (16000000UL)            /* Main         oscillator freq */
+#define XTALI       (16000000UL)            /* Internal     oscillator freq */
+#define XTAL30K     (   30000UL)            /* Internal 30K oscillator freq */
+#define XTAL32K     (   32768UL)            /* external 32K oscillator freq */
+
+#define PLL_CLK    (400000000UL)
+#define ADC_CLK     (PLL_CLK/25)
+#define CAN_CLK     (PLL_CLK/50)
+
+#define SYSCTL_DID0 0x000
+#define SYSCTL_DID1 0x004
+#define SYSCTL_PBORCTL 0x030
+#define SYSCTL_RIS 0x050
+#define SYSCTL_IMC 0x054
+#define SYSCTL_MISC 0x058
+#define SYSCTL_RESC 0x05C
+#define SYSCTL_RCC 0x060
+#define SYSCTL_GPIOHBCTL 0x06C
+#define SYSCTL_RCC2 0x070
+#define SYSCTL_MOSCCTL 0x07C
+#define SYSCTL_DSLPCLKCFG 0x144
+#define SYSCTL_SYSPROP 0x14C
+#define SYSCTL_PIOSCCAL 0x150
+#define SYSCTL_PIOSCSTAT 0x154
+#define SYSCTL_PLLFREQ0 0x160
+#define SYSCTL_PLLFREQ1 0x164
+#define SYSCTL_PLLSTAT 0x168
+#define SYSCTL_SLPPWRCFG 0x188
+#define SYSCTL_DSLPPWRCFG 0x18C
+#define SYSCTL_LDOSPCTL 0x1B4
+#define SYSCTL_LDOSPCAL 0x1B8
+#define SYSCTL_LDODPCTL 0x1Bc
+#define SYSCTL_LDODPCAL 0x1C0
+#define SYSCTL_SDPMST 0x1CC
+#define SYSCTL_PPWD 0x300
+#define SYSCTL_PPTIMER 0x304
+#define SYSCTL_PPGPIO 0x308
+#define SYSCTL_PPDMA 0x30C
+#define SYSCTL_PPHIB 0x314
+#define SYSCTL_PPUART 0x318
+#define SYSCTL_PPSI 0x31C
+#define SYSCTL_PPI2C 0x320
+#define SYSCTL_PPUSB 0x328
+#define SYSCTL_PPCAN 0x334
+#define SYSCTL_PPADC 0x338
+#define SYSCTL_PPACMP 0x33C
+#define SYSCTL_PPPWM 0x340
+#define SYSCTL_PPQEI 0x344
+#define SYSCTL_PPEEPROM 0x358
+#define SYSCTL_PPWTIMER 0x35C
+#define SYSCTL_SRWD 0x500
+#define SYSCTL_SRTIMER 0x504
+#define SYSCTL_SRGPIO 0x508
+#define SYSCTL_SRDMA 0x50C
+#define SYSCTL_SRHIB 0x514
+#define SYSCTL_SRUART 0x518
+#define SYSCTL_SRSSI 0x51C
+#define SYSCTL_SRI2C 0x520
+#define SYSCTL_SRUSB 0x528
+#define SYSCTL_SRCAN 0x534
+#define SYSCTL_SRADC 0x538
+#define SYSCTL_SRACMP 0x53C
+#define SYSCTL_SRPWM 0x540
+#define SYSCTL_SRQEI 0x544
+#define SYSCTL_SREEPROM 0x558
+#define SYSCTL_SRWTIMER 0x55C
+#define SYSCTL_RCGCWD 0x600
+#define SYSCTL_RCGCTIMER 0x604
+#define SYSCTL_RCGCGPIO 0x608
+#define SYSCTL_RCGCDMA 0x60C
+#define SYSCTL_RCGCHIB 0x614
+#define SYSCTL_RCGCUART 0x618
+#define SYSCTL_RCGCSSI 0x61C
+#define SYSCTL_RCGCI2C 0x620
+#define SYSCTL_RCGCUSB 0x628
+#define SYSCTL_RCGCCAN 0x634
+#define SYSCTL_RCGCADC 0x638
+#define SYSCTL_RCGCACMP 0x63C
+#define SYSCTL_RCGCPWM 0x640
+#define SYSCTL_RCGCQEI 0x644
+#define SYSCTL_RCGCEEPROM 0x658
+#define SYSCTL_RCGCWTIMER 0x65C
+#define SYSCTL_SCGCWD 0x700
+#define SYSCTL_SCGCTIMER 0x704
+#define SYSCTL_SCGCGPIO 0x708
+#define SYSCTL_SCGCDMA 0x70C
+#define SYSCTL_SCGCHIB 0x714
+#define SYSCTL_SCGCUART 0x718
+#define SYSCTL_SCGCSSI 0x71C
+#define SYSCTL_SCGCI2C 0x720
+#define SYSCTL_SCGCUSB 0x728
+#define SYSCTL_SCGCCAN 0x734
+#define SYSCTL_SCGCADC 0x738
+#define SYSCTL_SCGCACMP 0x73C
+#define SYSCTL_SCGCPWM 0x740
+#define SYSCTL_SCGCQEI 0x744
+#define SYSCTL_SCGCEEPROM 0x758
+#define SYSCTL_SCGCWTIMER 0x75C
+#define SYSCTL_DCGCWD 0x800
+#define SYSCTL_DCGCTIMER 0x804
+#define SYSCTL_DCGCGPIO 0x808
+#define SYSCTL_DCGCDMA 0x80C
+#define SYSCTL_DCGCHIB 0x814
+#define SYSCTL_DCGCUART 0x818
+#define SYSCTL_DCGCSSI 0x81C
+#define SYSCTL_DCGCI2C 0x820
+#define SYSCTL_DCGCUSB 0x828
+#define SYSCTL_DCGCCAN 0x834
+#define SYSCTL_DCGCADC 0x838
+#define SYSCTL_DCGCACMP 0x83C
+#define SYSCTL_DCGCPWM 0x840
+#define SYSCTL_DCGCQEI 0x844
+#define SYSCTL_DCGCEEPROM 0x858
+#define SYSCTL_DCGCWTIME 0x85C
+#define SYSCTL_PRWD 0xA00
+#define SYSCTL_PRTIMER 0xA04
+#define SYSCTL_PRGPIO 0xA08
+#define SYSCTL_PRDMA 0xA0C
+#define SYSCTL_PRHIB 0xA14
+#define SYSCTL_PRUART 0xA18
+#define SYSCTL_PRSSI 0xA1C
+#define SYSCTL_PRI2C 0xA20
+#define SYSCTL_PRUSB 0xA28
+#define SYSCTL_PRCAN 0xA34
+#define SYSCTL_PRADC 0xA38
+#define SYSCTL_PRACMP 0xA3C
+#define SYSCTL_PRPWM 0xA40
+#define SYSCTL_PRQEI 0xA44
+#define SYSCTL_PREEPROM 0xA58
+#define SYSCTL_PRWTIMER 0xA5C
+
+
+#define SYSCTL_RCC_PWRDN (1 << 13)
+#define SYSCTL_RCC2_PWRDN2 (1 << 13)
+#define SYSCTL_RCC2_USERCC2 (1 << 31)
+#define SYSCTL_RIS_PLLRIS (1 << 6)
+
+#define TYPE_TM4C123_SYSCTL "tm4c123-sysctl"
+OBJECT_DECLARE_SIMPLE_TYPE(TM4C123SysCtlState, TM4C123_SYSCTL)
+
+struct TM4C123SysCtlState {
+
+    SysBusDevice parent_obj;
+    MemoryRegion mmio;
+
+    uint32_t sysctl_did0;
+    uint32_t sysctl_did1;
+    uint32_t sysctl_pborctl;
+    uint32_t sysctl_ris;
+    uint32_t sysctl_imc;
+    uint32_t sysctl_misc;
+    uint32_t sysctl_resc;
+    uint32_t sysctl_rcc;
+    uint32_t sysctl_gpiohbctl;
+    uint32_t sysctl_rcc2;
+    uint32_t sysctl_moscctl;
+    uint32_t sysctl_dslpclkcfg;
+    uint32_t sysctl_sysprop;
+    uint32_t sysctl_piosccal;
+    uint32_t sysctl_pioscstat;
+    uint32_t sysctl_pllfreq0;
+    uint32_t sysctl_pllfreq1;
+    uint32_t sysctl_pllstat;
+    uint32_t sysctl_slppwrcfg;
+    uint32_t sysctl_dslppwrcfg;
+    uint32_t sysctl_ldospctl;
+    uint32_t sysctl_ldospcal;
+    uint32_t sysctl_ldodpctl;
+    uint32_t sysctl_ldodpcal;
+    uint32_t sysctl_sdpmst;
+    uint32_t sysctl_ppwd;
+    uint32_t sysctl_pptimer;
+    uint32_t sysctl_ppgpio;
+    uint32_t sysctl_ppdma;
+    uint32_t sysctl_pphib;
+    uint32_t sysctl_ppuart;
+    uint32_t sysctl_ppsi;
+    uint32_t sysctl_ppi2c;
+    uint32_t sysctl_ppusb;
+    uint32_t sysctl_ppcan;
+    uint32_t sysctl_ppadc;
+    uint32_t sysctl_ppacmp;
+    uint32_t sysctl_pppwm;
+    uint32_t sysctl_ppqei;
+    uint32_t sysctl_ppeeprom;
+    uint32_t sysctl_ppwtimer;
+    uint32_t sysctl_srwd;
+    uint32_t sysctl_srtimer;
+    uint32_t sysctl_srgpio;
+    uint32_t sysctl_srdma;
+    uint32_t sysctl_srhib;
+    uint32_t sysctl_sruart;
+    uint32_t sysctl_srssi;
+    uint32_t sysctl_sri2c;
+    uint32_t sysctl_srusb;
+    uint32_t sysctl_srcan;
+    uint32_t sysctl_sradc;
+    uint32_t sysctl_sracmp;
+    uint32_t sysctl_srpwm;
+    uint32_t sysctl_srqei;
+    uint32_t sysctl_sreeprom;
+    uint32_t sysctl_srwtimer;
+    uint32_t sysctl_rcgcwd;
+    uint32_t sysctl_rcgctimer;
+    uint32_t sysctl_rcgcgpio;
+    uint32_t sysctl_rcgcdma;
+    uint32_t sysctl_rcgchib;
+    uint32_t sysctl_rcgcuart;
+    uint32_t sysctl_rcgcssi;
+    uint32_t sysctl_rcgci2c;
+    uint32_t sysctl_rcgcusb;
+    uint32_t sysctl_rcgccan;
+    uint32_t sysctl_rcgcadc;
+    uint32_t sysctl_rcgcacmp;
+    uint32_t sysctl_rcgcpwm;
+    uint32_t sysctl_rcgcqei;
+    uint32_t sysctl_rcgceeprom;
+    uint32_t sysctl_rcgcwtimer;
+    uint32_t sysctl_scgcwd;
+    uint32_t sysctl_scgctimer;
+    uint32_t sysctl_scgcgpio;
+    uint32_t sysctl_scgcdma;
+    uint32_t sysctl_scgchib;
+    uint32_t sysctl_scgcuart;
+    uint32_t sysctl_scgcssi;
+    uint32_t sysctl_scgci2c;
+    uint32_t sysctl_scgcusb;
+    uint32_t sysctl_scgccan;
+    uint32_t sysctl_scgcadc;
+    uint32_t sysctl_scgcacmp;
+    uint32_t sysctl_scgcpwm;
+    uint32_t sysctl_scgcqei;
+    uint32_t sysctl_scgceeprom;
+    uint32_t sysctl_scgcwtimer;
+    uint32_t sysctl_dcgcwd;
+    uint32_t sysctl_dcgctimer;
+    uint32_t sysctl_dcgcgpio;
+    uint32_t sysctl_dcgcdma;
+    uint32_t sysctl_dcgchib;
+    uint32_t sysctl_dcgcuart;
+    uint32_t sysctl_dcgcssi;
+    uint32_t sysctl_dcgci2c;
+    uint32_t sysctl_dcgcusb;
+    uint32_t sysctl_dcgccan;
+    uint32_t sysctl_dcgcadc;
+    uint32_t sysctl_dcgcacmp;
+    uint32_t sysctl_dcgcpwm;
+    uint32_t sysctl_dcgcqei;
+    uint32_t sysctl_dcgceeprom;
+    uint32_t sysctl_dcgcwtime;
+    uint32_t sysctl_prwd;
+    uint32_t sysctl_prtimer;
+    uint32_t sysctl_prgpio;
+    uint32_t sysctl_prdma;
+    uint32_t sysctl_prhib;
+    uint32_t sysctl_pruart;
+    uint32_t sysctl_prssi;
+    uint32_t sysctl_pri2c;
+    uint32_t sysctl_prusb;
+    uint32_t sysctl_prcan;
+    uint32_t sysctl_pradc;
+    uint32_t sysctl_pracmp;
+    uint32_t sysctl_prpwm;
+    uint32_t sysctl_prqei;
+    uint32_t sysctl_preeprom;
+    uint32_t sysctl_prwtimer;
+
+    Clock* mainclk;
+    Clock* outclk;
+
+};
+
+#endif
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 5/8] tiva c watchdog timers implementation
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
                   ` (3 preceding siblings ...)
  2023-05-17  8:12 ` [PATCH 4/8] tiva c sysctl implementation Mohamed ElSayed
@ 2023-05-17  8:12 ` Mohamed ElSayed
  2023-06-08 14:05   ` Peter Maydell
  2023-05-17  8:12 ` [PATCH 6/8] tiva c general purpose " Mohamed ElSayed
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 hw/watchdog/tm4c123_watchdog.c         | 297 +++++++++++++++++++++++++
 hw/watchdog/trace-events               |   3 +
 include/hw/watchdog/tm4c123_watchdog.h |  97 ++++++++
 3 files changed, 397 insertions(+)
 create mode 100644 hw/watchdog/tm4c123_watchdog.c
 create mode 100644 include/hw/watchdog/tm4c123_watchdog.h

diff --git a/hw/watchdog/tm4c123_watchdog.c b/hw/watchdog/tm4c123_watchdog.c
new file mode 100644
index 0000000000..ea0a41f3c0
--- /dev/null
+++ b/hw/watchdog/tm4c123_watchdog.c
@@ -0,0 +1,297 @@
+/*
+ * TM4C123 Watchdog Timers
+ *
+ * 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/watchdog/tm4c123_watchdog.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
+#include "sysemu/runstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/nmi.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 locked;
+
+static void tm4c123_wdt_expired(void *opaque)
+{
+    TM4C123WatchdogState *s = opaque;
+    /*if this is the first timeout/the ris is not cleared */
+    if (!test_bit(0, (const unsigned long *)&s->wdt_mis)) {
+        set_bit(0, (unsigned long *)&s->wdt_mis);
+        nmi_monitor_handle(0, NULL);
+        qemu_irq_pulse(s->irq);
+    } else {
+        if (test_bit(1, (const unsigned long *)&s->wdt_ctl))
+            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        else {
+            nmi_monitor_handle(0, NULL);
+            qemu_irq_pulse(s->irq);
+        }
+    }
+}
+
+static bool wdt_clock_enabled(TM4C123SysCtlState *s, hwaddr addr)
+{
+    switch (addr) {
+        case WDT_0:
+            return s->sysctl_rcgcwd & (1 << 0);
+            break;
+        case WDT_1:
+            return s->sysctl_rcgcwd & (1 << 1);
+            break;
+    }
+    return false;
+}
+
+static void tm4c123_wdt_reset(DeviceState *dev)
+{
+    TM4C123WatchdogState *s = TM4C123_WATCHDOG(dev);
+
+    s->wdt_load = 0xFFFFFFFF;
+    s->wdt_value = 0xFFFFFFFF;
+    s->wdt_ctl = (s->mmio.addr == WDT_0 ? 0x00000000 : 0x80000000);
+    s->wdt_icr = 0x00000000;
+    s->wdt_ris = 0x00000000;
+    s->wdt_mis = 0x00000000;
+    s->wdt_test = 0x00000000;
+    s->wdt_lock = 0x00000000;
+    s->wdt_per_id4 = 0x00000000;
+    s->wdt_per_id5 = 0x00000000;
+    s->wdt_per_id6 = 0x00000000;
+    s->wdt_per_id7 = 0x00000000;
+    s->wdt_per_id0 = 0x00000005;
+    s->wdt_per_id1 = 0x00000018;
+    s->wdt_per_id2 = 0x00000018;
+    s->wdt_per_id3 = 0x00000001;
+    s->wdt_pcell_id0 = 0x0000000D;
+    s->wdt_pcell_id1 = 0x000000F0;
+    s->wdt_pcell_id2 = 0x00000006;
+    s->wdt_pcell_id3 = 0x000000B1;
+}
+
+static uint64_t tm4c123_wdt_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    TM4C123WatchdogState *s = opaque;
+
+    if (!wdt_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("Watchdog timer module clock is not enabled");
+    }
+
+    switch (addr) {
+        case WDT_LOAD:
+            return s->wdt_load;
+        case WDT_VALUE:
+            return ptimer_get_count(s->timer);
+        case WDT_CTL:
+            return s->wdt_ctl;
+        case WDT_ICR:
+            return s->wdt_icr;
+        case WDT_RIS:
+            return s->wdt_ris;
+        case WDT_MIS:
+            return s->wdt_mis;
+        case WDT_TEST:
+            return s->wdt_test;
+        case WDT_LOCK:
+            return s->wdt_lock;
+        case WDT_PER_ID4:
+            return s->wdt_per_id4;
+        case WDT_PER_ID5:
+            return s->wdt_per_id5;
+        case WDT_PER_ID6:
+            return s->wdt_per_id6;
+        case WDT_PER_ID7:
+            return s->wdt_per_id7;
+        case WDT_PER_ID0:
+            return s->wdt_per_id0;
+        case WDT_PER_ID1:
+            return s->wdt_per_id1;
+        case WDT_PER_ID2:
+            return s->wdt_per_id2;
+        case WDT_PER_ID3:
+            return s->wdt_per_id3;
+        case WDT_PCELL_ID0:
+            return s->wdt_pcell_id0;
+        case WDT_PCELL_ID1:
+            return s->wdt_pcell_id1;
+        case WDT_PCELL_ID2:
+            return s->wdt_pcell_id2;
+        case WDT_PCELL_ID3:
+            return s->wdt_pcell_id3;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+    }
+    return 0;
+}
+
+static void tm4c123_wdt_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size)
+{
+    TM4C123WatchdogState *s = opaque;
+    uint32_t val32 = val64;
+
+    trace_tm4c123_wdt_write(addr, val64);
+    if (!wdt_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("Watchdog module clock is not enabled");
+    }
+
+    switch (addr) {
+        case WDT_LOAD:
+            s->wdt_load = val32;
+            locked = true;
+            s->wdt_ctl |= WDT_CTL_INTEN;
+            ptimer_transaction_begin(s->timer);
+            ptimer_set_count(s->timer, s->wdt_load);
+            ptimer_set_limit(s->timer, s->wdt_load, 1);
+            ptimer_run(s->timer, 0);
+            ptimer_transaction_commit(s->timer);
+            break;
+        case WDT_VALUE:
+            READONLY;
+            break;
+        case WDT_CTL:
+            s->wdt_ctl = val32;
+            break;
+        case WDT_ICR:
+            ptimer_transaction_begin(s->timer);
+            ptimer_set_limit(s->timer, s->wdt_load, 1);
+            ptimer_transaction_commit(s->timer);
+            clear_bit(0, (unsigned long *)&s->wdt_ris);
+            clear_bit(0, (unsigned long *)&s->wdt_mis);
+            s->wdt_icr = val32;
+            break;
+        case WDT_RIS:
+            READONLY;
+            break;
+        case WDT_MIS:
+            READONLY;
+            break;
+        case WDT_TEST:
+            s->wdt_test = val32;
+            break;
+        case WDT_LOCK:
+            /* The actual hardware never locks the module */
+            if (val32 == UNLOCK_VALUE) {
+                locked = false;
+                s->wdt_lock = 0;
+            }
+            break;
+        case WDT_PER_ID4:
+            READONLY;
+            break;
+        case WDT_PER_ID5:
+            READONLY;
+            break;
+        case WDT_PER_ID6:
+            READONLY;
+            break;
+        case WDT_PER_ID7:
+            READONLY;
+            break;
+        case WDT_PER_ID0:
+            READONLY;
+            break;
+        case WDT_PER_ID1:
+            READONLY;
+            break;
+        case WDT_PER_ID2:
+            READONLY;
+            break;
+        case WDT_PER_ID3:
+            READONLY;
+            break;
+        case WDT_PCELL_ID0:
+            READONLY;
+            break;
+        case WDT_PCELL_ID1:
+            READONLY;
+            break;
+        case WDT_PCELL_ID2:
+            READONLY;
+            break;
+        case WDT_PCELL_ID3:
+            READONLY;
+            break;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+    }
+}
+
+const struct MemoryRegionOps tm4c123_wdt_ops = {
+    .read = tm4c123_wdt_read,
+    .write = tm4c123_wdt_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void tm4c123_wdt_init(Object *obj)
+{
+    TM4C123WatchdogState *s = TM4C123_WATCHDOG(obj);
+
+    s->wdt_clock = qdev_init_clock_in(DEVICE(s), "wdt_clock", NULL, NULL, 0);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+    memory_region_init_io(&s->mmio, obj, &tm4c123_wdt_ops, s, TYPE_TM4C123_WATCHDOG, 0xFFF);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void tm4c123_wdt_realize(DeviceState *dev, Error **errp)
+{
+    TM4C123WatchdogState *s = TM4C123_WATCHDOG(dev);
+    qdev_connect_clock_in(dev, "wdt_clock", qdev_get_clock_out(DEVICE(s->sysctl), "outclk"));
+
+    s->timer = ptimer_init(tm4c123_wdt_expired, s,
+                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_set_period_from_clock(s->timer, s->wdt_clock, 1);
+    ptimer_set_limit(s->timer, 0xFFFFFFFF, 0);
+    ptimer_transaction_commit(s->timer);
+}
+
+static void tm4c123_wdt_class_init(ObjectClass *kclass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(kclass);
+    dc->realize = tm4c123_wdt_realize;
+    dc->reset = tm4c123_wdt_reset;
+}
+
+static const TypeInfo tm4c123_wdt_info = {
+    .name = TYPE_TM4C123_WATCHDOG,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TM4C123WatchdogState),
+    .instance_init = tm4c123_wdt_init,
+    .class_init = tm4c123_wdt_class_init,
+};
+
+static void tm4c123_wdt_register_types(void)
+{
+    type_register_static(&tm4c123_wdt_info);
+}
+
+type_init(tm4c123_wdt_register_types)
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
index 2739570652..802aed4a6f 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -1,5 +1,8 @@
 # See docs/devel/tracing.rst for syntax documentation.
 
+# tm4c123_wdt.c
+tm4c123_wdt_write(uint64_t offset, uint64_t data) "TM4C123-WDT Write: [ Offset 0x%" PRIx64 " - Data 0x%" PRIx64 "]"
+
 # allwinner-wdt.c
 allwinner_wdt_read(uint64_t offset, uint64_t data, unsigned size) "Allwinner watchdog read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
 allwinner_wdt_write(uint64_t offset, uint64_t data, unsigned size) "Allwinner watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
diff --git a/include/hw/watchdog/tm4c123_watchdog.h b/include/hw/watchdog/tm4c123_watchdog.h
new file mode 100644
index 0000000000..2621b5d805
--- /dev/null
+++ b/include/hw/watchdog/tm4c123_watchdog.h
@@ -0,0 +1,97 @@
+/*
+ * TM4C123 Watchdog Timers
+ *
+ * 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_WATCHDOG_H
+#define HW_ARM_TM4C123_WATCHDOG_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+#include "hw/misc/tm4c123_sysctl.h"
+#include "hw/ptimer.h"
+
+#define WDT_0 0x40000000
+#define WDT_1 0x40001000
+
+#define WDT_LOAD 0x000
+#define WDT_VALUE 0x004
+#define WDT_CTL 0x008
+#define WDT_ICR 0x00C
+#define WDT_RIS 0x010
+#define WDT_MIS 0x014
+#define WDT_TEST 0x418
+#define WDT_LOCK 0xC00
+#define WDT_PER_ID4 0xFD0
+#define WDT_PER_ID5 0xFD4
+#define WDT_PER_ID6 0xFD8
+#define WDT_PER_ID7 0xFDC
+#define WDT_PER_ID0 0xFE0
+#define WDT_PER_ID1 0xFE4
+#define WDT_PER_ID2 0xFE8
+#define WDT_PER_ID3 0xFEC
+#define WDT_PCELL_ID0 0xFF0
+#define WDT_PCELL_ID1 0xFF4
+#define WDT_PCELL_ID2 0xFF8
+#define WDT_PCELL_ID3 0xFFC
+
+#define UNLOCK_VALUE 0x1ACCE551
+
+#define WDT_CTL_INTEN (1 << 0)
+#define WDT_CTL_INTTYPE (1 << 2)
+
+#define TYPE_TM4C123_WATCHDOG "tm4c123-watchdog"
+
+OBJECT_DECLARE_SIMPLE_TYPE(TM4C123WatchdogState, TM4C123_WATCHDOG)
+
+struct TM4C123WatchdogState {
+    SysBusDevice parent_obj;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    struct ptimer_state *timer;
+    TM4C123SysCtlState* sysctl;
+
+    uint32_t wdt_load;
+    uint32_t wdt_value;
+    uint32_t wdt_ctl;
+    uint32_t wdt_icr;
+    uint32_t wdt_ris;
+    uint32_t wdt_mis;
+    uint32_t wdt_test;
+    uint32_t wdt_lock;
+    uint32_t wdt_per_id4;
+    uint32_t wdt_per_id5;
+    uint32_t wdt_per_id6;
+    uint32_t wdt_per_id7;
+    uint32_t wdt_per_id0;
+    uint32_t wdt_per_id1;
+    uint32_t wdt_per_id2;
+    uint32_t wdt_per_id3;
+    uint32_t wdt_pcell_id0;
+    uint32_t wdt_pcell_id1;
+    uint32_t wdt_pcell_id2;
+    uint32_t wdt_pcell_id3;
+
+    Clock* wdt_clock;
+};
+
+#endif
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 6/8] tiva c general purpose timers implementation
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
                   ` (4 preceding siblings ...)
  2023-05-17  8:12 ` [PATCH 5/8] tiva c watchdog timers implementation Mohamed ElSayed
@ 2023-05-17  8:12 ` Mohamed ElSayed
  2023-06-08 14:28   ` Peter Maydell
  2023-05-17  8:12 ` [PATCH 7/8] tiva c board documentation Mohamed ElSayed
  2023-05-17  8:12 ` [PATCH 8/8] adding tiva c to the qemu build system and adding my info to the maintainers list Mohamed ElSayed
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 hw/timer/tm4c123_gptm.c         | 495 ++++++++++++++++++++++++++++++++
 hw/timer/trace-events           |   5 +
 include/hw/timer/tm4c123_gptm.h | 131 +++++++++
 3 files changed, 631 insertions(+)
 create mode 100644 hw/timer/tm4c123_gptm.c
 create mode 100644 include/hw/timer/tm4c123_gptm.h

diff --git a/hw/timer/tm4c123_gptm.c b/hw/timer/tm4c123_gptm.c
new file mode 100644
index 0000000000..bdbaff776c
--- /dev/null
+++ b/hw/timer/tm4c123_gptm.c
@@ -0,0 +1,495 @@
+/*
+ * TM4C123 General purpose timers
+ *
+ * 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 "hw/timer/tm4c123_gptm.h"
+#include "hw/irq.h"
+#include "trace.h"
+#include "qemu/timer.h"
+#include <time.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 uint64_t ns_to_ticks(void *opaque, uint64_t ns, uint32_t prescaler)
+{
+    TM4C123GPTMState *s = opaque;
+
+    uint32_t freq = clock_get_hz(s->clk) / prescaler;
+    float sec = (float)ns / (float)NANOSECONDS_PER_SECOND;
+    return sec * freq;
+}
+
+static unsigned long ticks_to_time_ns(void *opaque, uint64_t ticks, uint32_t prescaler)
+{
+    TM4C123GPTMState *s = opaque;
+    uint32_t freq = clock_get_hz(s->clk) / prescaler;
+    return ((float)ticks / (float)freq) * NANOSECONDS_PER_SECOND;
+}
+
+static uint16_t get_timer_width(void *opaque)
+{
+    TM4C123GPTMState *s = opaque;
+    switch (s->mmio.addr) {
+        case TIMER0_32...TIMER5_32:
+            return TIMER_WIDTH_32;
+        case TIMER0_64...TIMER5_64:
+            return TIMER_WIDTH_64;
+    }
+    return 0;
+}
+
+static uint64_t build_interval_value(void *opaque)
+{
+    TM4C123GPTMState *s = opaque;
+    uint16_t timer_width = get_timer_width(s);
+    uint64_t interval_value = 0;
+    if (timer_width == TIMER_WIDTH_32) {
+        /* timer is in 32 bit mode or 32bit rtc*/
+        uint16_t upper16 = extract32(s->gptm_talir, 16, 16);
+        uint16_t lower16 = extract32(s->gptm_tblir, 0, 16);
+        interval_value = ((uint32_t)lower16 << 16) + upper16;
+    } else if (timer_width == TIMER_WIDTH_64) {
+        interval_value = ((uint64_t)s->gptm_talir << 32) + s->gptm_tblir;
+    }
+
+    trace_tm4c123_gptm_build_interval_value(s->gptm_talir, s->gptm_tblir, interval_value);
+    return interval_value;
+}
+
+static void set_timers(void *opaque)
+{
+    TM4C123GPTMState *s = opaque;
+    uint64_t interval_value;
+    uint16_t timer_width;
+    if (s->gptm_ctl & GPTM_TACTL_EN) {
+        timer_width = get_timer_width(s);
+        if (timer_width == TIMER_WIDTH_32) {
+            /* What is the mode of the timer? 16/32 */
+            if (s->gptm_cfg == 0x4) {
+                /* 16 bit mode */
+                interval_value = extract32(s->gptm_talir, 0, 16);
+                /* Start the timer? */
+                timer_mod(s->a, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_time_ns(s, interval_value, s->gptm_tapr));
+            } else if (s->gptm_cfg == 0x1) {
+                /* 32 bit mode rtc */
+                interval_value = build_interval_value(s);
+                timer_mod(s->a, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ticks_to_time_ns(s, interval_value, s->gptm_tapr));
+            } else if (s->gptm_cfg == 0x0) {
+                /* 32 bit mode rtc */
+                interval_value = build_interval_value(s);
+                timer_mod(s->a, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_time_ns(s, interval_value, s->gptm_tapr));
+            }
+        } else if (timer_width == TIMER_WIDTH_64) {
+            /* What is the mode of the timer? 32/64 */
+            if (s->gptm_cfg == 0) {
+                /* 64 bit mode */
+                interval_value = build_interval_value(s);
+                timer_mod(s->a, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_time_ns(s, interval_value, s->gptm_tapr));
+            } else if (s->gptm_cfg == 0x1) {
+                /* 64 bit mode */
+                interval_value = build_interval_value(s);
+                timer_mod(s->a, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ticks_to_time_ns(s, interval_value, s->gptm_tapr));
+            } else if (s->gptm_cfg == 0x4) {
+                interval_value = s->gptm_talir;
+                timer_mod(s->a, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ticks_to_time_ns(s, interval_value, s->gptm_tapr));
+            }
+        }
+    } else if (s->gptm_ctl & GPTM_TBCTL_EN) {
+        timer_width = get_timer_width(s);
+        if (timer_width == TIMER_WIDTH_32) {
+            /* What is the mode of the timer? 16/32 */
+            if (s->gptm_cfg == 0x4) {
+                /* 16 bit mode */
+                interval_value = extract32(s->gptm_tblir, 0, 16);
+                /* Start the timer? */
+                timer_mod(s->b, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_time_ns(s, interval_value, s->gptm_tbpr));
+            } else if (s->gptm_cfg == 0x01) {
+                /* 32 bit mode rtc */
+                interval_value = build_interval_value(s);
+                timer_mod(s->b,
+                        qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ticks_to_time_ns(s, interval_value, s->gptm_tbpr));
+            } else if (s->gptm_cfg == 0x00) {
+                /* 32 bit mode rtc */
+                interval_value = build_interval_value(s);
+                timer_mod(s->b,
+                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_time_ns(s, interval_value, s->gptm_tbpr));
+            }
+        } else if (timer_width == TIMER_WIDTH_64) {
+            /* What is the mode of the timer? 32/64 */
+            if (s->gptm_cfg == 0) {
+                /* 64 bit mode */
+                interval_value = build_interval_value(s);
+                timer_mod(s->b,
+                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_time_ns(s, interval_value, s->gptm_tbpr));
+            } else if (s->gptm_cfg == 0x1) {
+                /* 64 bit mode */
+                interval_value = build_interval_value(s);
+                timer_mod(s->b,
+                        qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ticks_to_time_ns(s, interval_value, s->gptm_tbpr));
+            } else if (s->gptm_cfg == 0x4) {
+                interval_value = s->gptm_tblir;
+                timer_mod(s->b,
+                        qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ticks_to_time_ns(s, interval_value, s->gptm_tbpr));
+            }
+        }
+    }
+}
+
+static bool gptm_clock_enabled(TM4C123SysCtlState *s, hwaddr addr)
+{
+    switch (addr) {
+        case TIMER0_32:
+            return test_bit(0, (const unsigned long *)&s->sysctl_rcgctimer);
+            break;
+        case TIMER1_32:
+            return test_bit(1, (const unsigned long *)&s->sysctl_rcgctimer);
+            break;
+        case TIMER2_32:
+            return test_bit(2, (const unsigned long *)&s->sysctl_rcgctimer);
+            break;
+        case TIMER3_32:
+            return test_bit(3, (const unsigned long *)&s->sysctl_rcgctimer);
+            break;
+        case TIMER4_32:
+            return test_bit(4, (const unsigned long *)&s->sysctl_rcgctimer);
+            break;
+        case TIMER5_32:
+            return test_bit(5, (const unsigned long *)&s->sysctl_rcgctimer);
+            break;
+        case TIMER0_64:
+            return test_bit(0, (const unsigned long *)&s->sysctl_rcgcwtimer);
+            break;
+        case TIMER1_64:
+            return test_bit(1, (const unsigned long *)&s->sysctl_rcgcwtimer);
+            break;
+        case TIMER2_64:
+            return test_bit(2, (const unsigned long *)&s->sysctl_rcgcwtimer);
+            break;
+        case TIMER3_64:
+            return test_bit(3, (const unsigned long *)&s->sysctl_rcgcwtimer);
+            break;
+        case TIMER4_64:
+            return test_bit(4, (const unsigned long *)&s->sysctl_rcgcwtimer);
+            break;
+        case TIMER5_64:
+            return test_bit(5, (const unsigned long *)&s->sysctl_rcgcwtimer);
+            break;
+    }
+    return false;
+}
+
+static void tm4c123_gptm_reset(DeviceState *dev)
+{
+    TM4C123GPTMState *s = TM4C123_GPTM(dev);
+
+    s->gptm_cfg = 0x00000000;
+    s->gptm_amr = 0x00000000;
+    s->gptm_bmr = 0x00000000;
+    s->gptm_ctl = 0x00000000;
+    s->gptm_sync = 0x00000000;
+    s->gptm_imr = 0x00000000;
+    s->gptm_ris = 0x00000000;
+    s->gptm_mis = 0x00000000;
+    s->gptm_icr = 0x00000000;
+    s->gptm_talir = 0xFFFFFFFF;
+    s->gptm_tblir = 0x00000000;
+    s->gptm_tamatchr = 0xFFFFFFFF;
+    s->gptm_tbmatchr = 0x00000000;
+    s->gptm_tapr = 0x00000000;
+    s->gptm_tbpr = 0x00000000;
+    s->gptm_tapmr = 0x00000000;
+    s->gptm_tbpmr = 0x00000000;
+    s->gptm_tar = 0xFFFFFFFF;
+    s->gptm_tbr = 0x00000000;
+    s->gptm_tav = 0xFFFFFFFF;
+    s->gptm_tbv = 0x00000000;
+    s->gptm_rtcpd = 0x00007FFF;
+    s->gptm_taps = 0x00000000;
+    s->gptm_tbps = 0x00000000;
+    s->gptm_tapv = 0x00000000;
+    s->gptm_tbpv = 0x00000000;
+    s->gptm_pp = 0x00000000;
+}
+
+static uint64_t tm4c123_gptm_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    TM4C123GPTMState *s = opaque;
+
+    if (!gptm_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("GPTM module clock is not enabled");
+    }
+
+    trace_tm4c123_gptm_read(addr);
+
+    switch (addr) {
+        case GPTM_CFG:
+            return s->gptm_cfg;
+        case GPTM_AMR:
+            return s->gptm_amr;
+        case GPTM_BMR:
+            return s->gptm_bmr;
+        case GPTM_CTL:
+            return s->gptm_ctl;
+        case GPTM_SYNC:
+            return s->gptm_sync;
+        case GPTM_IMR:
+            return s->gptm_imr;
+        case GPTM_RIS:
+            return s->gptm_ris;
+        case GPTM_MIS:
+            return s->gptm_mis;
+        case GPTM_ICR:
+            return s->gptm_icr;
+        case GPTM_TALIR:
+            return s->gptm_talir;
+        case GPTM_TBLIR:
+            return s->gptm_tblir;
+        case GPTM_TAMATCHR:
+            return s->gptm_tamatchr;
+        case GPTM_TBMATCHR:
+            return s->gptm_tbmatchr;
+        case GPTM_TAPR:
+            return s->gptm_tapr;
+        case GPTM_TBPR:
+            return s->gptm_tbpr;
+        case GPTM_TAPMR:
+            return s->gptm_tapmr;
+        case GPTM_TBPMR:
+            return s->gptm_tbpmr;
+        case GPTM_TAR:
+            return s->gptm_tar;
+        case GPTM_TBR:
+            return s->gptm_tbr;
+        case GPTM_TAV:
+            if (get_timer_width(s) == TIMER_WIDTH_64 && s->gptm_cfg == 0) {
+                return extract64(
+                        ns_to_ticks(s, s->a->expire_time - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), s->gptm_tapr),
+                        0, 31);
+            } else {
+                return ns_to_ticks(s, s->a->expire_time - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), s->gptm_tapr);
+            }
+        case GPTM_TBV:
+            if (get_timer_width(s) == TIMER_WIDTH_64 && s->gptm_cfg == 0) {
+                return extract64(
+                        ns_to_ticks(s, s->a->expire_time - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), s->gptm_tapr),
+                        32, 64);
+            } else {
+                return ns_to_ticks(s, s->b->expire_time - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), s->gptm_tapr);
+            }
+        case GPTM_RTCPD:
+            return s->gptm_rtcpd;
+        case GPTM_TAPS:
+            return s->gptm_taps;
+        case GPTM_TBPS:
+            return s->gptm_tbps;
+        case GPTM_TAPV:
+            return s->gptm_tapv;
+        case GPTM_TBPV:
+            return s->gptm_tbpv;
+        case GPTM_PP:
+            return s->gptm_pp;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+    }
+
+    return 0;
+}
+
+static void tm4c123_gptm_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size)
+{
+    TM4C123GPTMState *s = opaque;
+    uint32_t val32 = val64;
+
+    if (!gptm_clock_enabled(s->sysctl, s->mmio.addr)) {
+        hw_error("GPTM module clock is not enabled");
+    }
+
+    trace_tm4c123_gptm_write(addr, val32);
+
+    switch (addr) {
+        case GPTM_CFG:
+            s->gptm_cfg = val32;
+            break;
+        case GPTM_AMR:
+            s->gptm_amr = val32;
+            break;
+        case GPTM_BMR:
+            s->gptm_bmr = val32;
+            break;
+        case GPTM_CTL:
+            s->gptm_ctl = val32;
+            set_timers(s);
+            break;
+        case GPTM_SYNC:
+            s->gptm_sync = val32;
+            break;
+        case GPTM_IMR:
+            s->gptm_imr = val32;
+            break;
+        case GPTM_RIS:
+            READONLY;
+            break;
+        case GPTM_MIS:
+            s->gptm_mis = val32;
+            break;
+        case GPTM_ICR:
+            s->gptm_ris &= ~val32;
+            s->gptm_mis &= ~val32;
+            break;
+        case GPTM_TALIR:
+            s->gptm_talir = val32;
+            break;
+        case GPTM_TBLIR:
+            s->gptm_tblir = val32;
+            break;
+        case GPTM_TAMATCHR:
+            s->gptm_tamatchr = val32;
+            break;
+        case GPTM_TBMATCHR:
+            s->gptm_tbmatchr = val32;
+            break;
+        case GPTM_TAPR:
+            s->gptm_tapr = val32;
+            break;
+        case GPTM_TBPR:
+            s->gptm_tbpr = val32;
+            break;
+        case GPTM_TAPMR:
+            s->gptm_tapmr = val32;
+            break;
+        case GPTM_TBPMR:
+            s->gptm_tbpmr = val32;
+            break;
+        case GPTM_TAR:
+            READONLY;
+            break;
+        case GPTM_TBR:
+            READONLY;
+            break;
+        case GPTM_TAV:
+            s->gptm_tav = val32;
+            break;
+        case GPTM_TBV:
+            s->gptm_tbv = val32;
+            break;
+        case GPTM_RTCPD:
+            READONLY;
+            break;
+        case GPTM_TAPS:
+            READONLY;
+            break;
+        case GPTM_TBPS:
+            READONLY;
+            break;
+        case GPTM_TAPV:
+            READONLY;
+            break;
+        case GPTM_TBPV:
+            READONLY;
+            break;
+        case GPTM_PP:
+            READONLY;
+            break;
+        default:
+            LOG(LOG_GUEST_ERROR, "Bad address 0x%"HWADDR_PRIx"\n", addr);
+    }
+}
+
+static const MemoryRegionOps tm4c123_gptm_ops = {
+    .read = tm4c123_gptm_read,
+    .write = tm4c123_gptm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timer_a_callback(void *opaque)
+{
+    TM4C123GPTMState *s = opaque;
+
+    if (test_bit(0, (unsigned long *)&s->gptm_imr)) {
+        qemu_irq_pulse(s->irq_a);
+        set_bit(0, (unsigned long *)&s->gptm_mis);
+    }
+    set_bit(0, (unsigned long *)&s->gptm_ris);
+    if ((s->gptm_amr & 0x0000000F) == 0x2) {
+        set_timers(s);
+    }
+}
+
+static void timer_b_callback(void *opaque)
+{
+    TM4C123GPTMState *s = opaque;
+
+    if (test_bit(8, (unsigned long *)&s->gptm_imr)) {
+        qemu_irq_pulse(s->irq_b);
+        set_bit(8, (unsigned long *)&s->gptm_mis);
+    }
+    set_bit(8, (unsigned long *)&s->gptm_ris);
+    if ((s->gptm_bmr & 0x0000000F) == 0x2) {
+        set_timers(s);
+    }
+}
+
+static void tm4c123_gptm_init(Object *obj)
+{
+    TM4C123GPTMState *s = TM4C123_GPTM(obj);
+    s->clk = qdev_init_clock_in(DEVICE(s), "gptm_clock", NULL, NULL, 0);
+    s->a = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_a_callback, s);
+    s->b = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_b_callback, s);
+    timer_init_ns(s->a, QEMU_CLOCK_VIRTUAL, timer_a_callback, s);
+    timer_init_ns(s->b, QEMU_CLOCK_VIRTUAL, timer_b_callback, s);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq_a);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq_b);
+    memory_region_init_io(&s->mmio, obj, &tm4c123_gptm_ops, s, TYPE_TM4C123_GPTM, 0xFFF);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void tm4c123_gptm_realize(DeviceState *dev, Error **errp)
+{
+    TM4C123GPTMState *s = TM4C123_GPTM(dev);
+    qdev_connect_clock_in(dev, "gptm_clock", qdev_get_clock_out(DEVICE(s->sysctl), "outclk"));
+
+}
+
+static void tm4c123_gptm_class_init(ObjectClass *kclass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(kclass);
+    dc->reset = tm4c123_gptm_reset;
+    dc->realize = tm4c123_gptm_realize;
+}
+
+static const TypeInfo tm4c123_gptm_info = {
+    .name = TYPE_TM4C123_GPTM,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TM4C123GPTMState),
+    .instance_init = tm4c123_gptm_init,
+    .class_init = tm4c123_gptm_class_init,
+};
+
+static void tm4c123_gptm_register_types(void)
+{
+    type_register_static(&tm4c123_gptm_info);
+}
+
+type_init(tm4c123_gptm_register_types)
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index 3eccef8385..e40b445630 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -1,5 +1,10 @@
 # See docs/devel/tracing.rst for syntax documentation.
 
+# tm4c123_gptm.c
+tm4c123_gptm_read(uint32_t offset) "offset: 0x%"PRIx32
+tm4c123_gptm_write(uint32_t offset, uint32_t value) "offset: 0x%"PRIx32" - value: 0x%"PRIx32
+tm4c123_gptm_build_interval_value(uint32_t talir, uint32_t tblir, uint64_t result) "TALIR: 0x%"PRIx32" - TBLIR: 0x%"PRIx32" - value: 0x%"PRIx64
+
 # slavio_timer.c
 slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit 0x%"PRIx64" count 0x%x0x%08x"
 slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count 0x%x0x%08x"
diff --git a/include/hw/timer/tm4c123_gptm.h b/include/hw/timer/tm4c123_gptm.h
new file mode 100644
index 0000000000..e86049f5c1
--- /dev/null
+++ b/include/hw/timer/tm4c123_gptm.h
@@ -0,0 +1,131 @@
+/*
+ * TM4C123 General purpose timers
+ *
+ * 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_GPTM_H
+#define HW_ARM_TM4C123_GPTM_H
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/misc/tm4c123_sysctl.h"
+#include "qemu/bitops.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "qom/object.h"
+
+#define TIMER_WIDTH_32 0x32B
+#define TIMER_WIDTH_64 0x64B
+
+#define TIMER0_32 0x40030000
+#define TIMER1_32 0x40031000
+#define TIMER2_32 0x40032000
+#define TIMER3_32 0x40033000
+#define TIMER4_32 0x40034000
+#define TIMER5_32 0x40035000
+
+#define TIMER0_64 0x40036000
+#define TIMER1_64 0x40037000
+#define TIMER2_64 0x4003C000
+#define TIMER3_64 0x4003D000
+#define TIMER4_64 0x4003E000
+#define TIMER5_64 0x4003F000
+
+#define GPTM_CFG 0x000
+#define GPTM_AMR 0x004
+#define GPTM_BMR 0x008
+#define GPTM_CTL 0x00C
+#define GPTM_SYNC 0x010
+#define GPTM_IMR 0x018
+#define GPTM_RIS 0x01C
+#define GPTM_MIS 0x020
+#define GPTM_ICR 0x024
+#define GPTM_TALIR 0x028
+#define GPTM_TBLIR 0x02C
+#define GPTM_TAMATCHR 0x030
+#define GPTM_TBMATCHR 0x034
+#define GPTM_TAPR 0x038
+#define GPTM_TBPR 0x03C
+#define GPTM_TAPMR 0x040
+#define GPTM_TBPMR 0x044
+#define GPTM_TAR 0x048
+#define GPTM_TBR 0x04C
+#define GPTM_TAV 0x050
+#define GPTM_TBV 0x054
+#define GPTM_RTCPD 0x058
+#define GPTM_TAPS 0x05C
+#define GPTM_TBPS 0x060
+#define GPTM_TAPV 0x064
+#define GPTM_TBPV 0x068
+#define GPTM_PP 0xFC0
+
+#define GPTM_TACTL_EN (1 << 0)
+#define GPTM_TBCTL_EN (1 << 8)
+#define GPTM_TAM_CD   (1 << 4)
+#define GPTM_TAM_MODE_ONESHOT (1 << 1)
+#define GPTM_TAM_PERIODIC (1 << 2)
+
+#define TYPE_TM4C123_GPTM "tm4c123-gptm"
+
+OBJECT_DECLARE_SIMPLE_TYPE(TM4C123GPTMState, TM4C123_GPTM)
+
+struct TM4C123GPTMState {
+    SysBusDevice parent_obj;
+    MemoryRegion mmio;
+    qemu_irq irq_a;
+    qemu_irq irq_b;
+    TM4C123SysCtlState *sysctl;
+
+    uint32_t gptm_cfg;
+    uint32_t gptm_amr;
+    uint32_t gptm_bmr;
+    uint32_t gptm_ctl;
+    uint32_t gptm_sync;
+    uint32_t gptm_imr;
+    uint32_t gptm_ris;
+    uint32_t gptm_mis;
+    uint32_t gptm_icr;
+    uint32_t gptm_talir;
+    uint32_t gptm_tblir;
+    uint32_t gptm_tamatchr;
+    uint32_t gptm_tbmatchr;
+    uint32_t gptm_tapr;
+    uint32_t gptm_tbpr;
+    uint32_t gptm_tapmr;
+    uint32_t gptm_tbpmr;
+    uint32_t gptm_tar;
+    uint32_t gptm_tbr;
+    uint32_t gptm_tav;
+    uint32_t gptm_tbv;
+    uint32_t gptm_rtcpd;
+    uint32_t gptm_taps;
+    uint32_t gptm_tbps;
+    uint32_t gptm_tapv;
+    uint32_t gptm_tbpv;
+    uint32_t gptm_pp;
+    QEMUTimer *a;
+    QEMUTimer *b;
+    Clock* clk;
+};
+
+#endif
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 7/8] tiva c board documentation
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
                   ` (5 preceding siblings ...)
  2023-05-17  8:12 ` [PATCH 6/8] tiva c general purpose " Mohamed ElSayed
@ 2023-05-17  8:12 ` Mohamed ElSayed
  2023-06-08 14:11   ` Peter Maydell
  2023-05-17  8:12 ` [PATCH 8/8] adding tiva c to the qemu build system and adding my info to the maintainers list Mohamed ElSayed
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 docs/system/arm/tivac.rst | 47 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 docs/system/arm/tivac.rst

diff --git a/docs/system/arm/tivac.rst b/docs/system/arm/tivac.rst
new file mode 100644
index 0000000000..8e78726c01
--- /dev/null
+++ b/docs/system/arm/tivac.rst
@@ -0,0 +1,47 @@
+Texas Instruments EK-TM4C123GXL Evaluation Board, ``Tiva C``
+========================================================================================
+
+The `Tiva C`_ board is an evaluation platform for ARM Cortex-M4-based microcontrollers.
+Its based on the `TM4C123GH6PM`_ microcontroller by Texas Instruments.
+
+.. _Tiva C: https://www.ti.com/tool/EK-TM4C123GXL
+.. _TM4C123GH6PM: https://www.ti.com/product/TM4C123GH6PM
+
+Supported modules
+-----------------
+
+ * ARM Cortex-M4
+ * General Purpose Input/Output (GPIO)
+ * General Purpose Timers (GPTM)
+ * Serial Ports (USART)
+ * System Control (SYSCTL)
+ * Watchdog Timers (WDT)
+
+Missing modules
+---------------
+
+ * Dynamic Memory Access (uDMA)
+ * Analog to Digital Converter (ADC)
+ * Synchronous Serial Interface (SSI)
+ * Inter-Integrated Circuit Interface (I2C)
+ * Controller Area Network (CAN)
+ * USB Controller
+ * Analog Comparators
+ * Pulse Width Modulator (PWM)
+ * Quadrature Encoder Interface (QEI)
+
+Boot options
+------------
+
+The Tiva C machines could be started using the ``-kernel`` option to load a binary file.
+
+.. code-block:: bash
+
+  $ qemu-system-arm -M tivac -kernel binary.elf -s -S
+
+The ``-s -S`` switches are for debugging, in another terminal window you can do:
+
+.. code-block:: bash
+
+   $ arm-none-eabi-gdb binary.elf
+   (gdb) target remote :1234
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 8/8] adding tiva c to the qemu build system and adding my info to the maintainers list
  2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
                   ` (6 preceding siblings ...)
  2023-05-17  8:12 ` [PATCH 7/8] tiva c board documentation Mohamed ElSayed
@ 2023-05-17  8:12 ` Mohamed ElSayed
  2023-06-08 14:16   ` Peter Maydell
  7 siblings, 1 reply; 17+ messages in thread
From: Mohamed ElSayed @ 2023-05-17  8:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, Mohamed ElSayed

Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
---
 MAINTAINERS                             |  9 +++++++++
 configs/devices/arm-softmmu/default.mak |  1 +
 hw/arm/Kconfig                          | 13 +++++++++++++
 hw/arm/meson.build                      |  3 +++
 hw/char/Kconfig                         |  3 +++
 hw/char/meson.build                     |  1 +
 hw/gpio/Kconfig                         |  3 +++
 hw/gpio/meson.build                     |  1 +
 hw/misc/Kconfig                         |  3 +++
 hw/misc/meson.build                     |  1 +
 hw/timer/Kconfig                        |  3 +++
 hw/timer/meson.build                    |  1 +
 hw/watchdog/Kconfig                     |  3 +++
 hw/watchdog/meson.build                 |  1 +
 14 files changed, 46 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b22b85bc3a..dcd902fadf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1008,6 +1008,15 @@ F: include/hw/misc/zynq_slcr.h
 F: include/hw/adc/zynq-xadc.h
 X: hw/ssi/xilinx_*
 
+Tiva C
+M: Mohamed ElSayed <m.elsayed4420@gmail.com>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/*/tm4c123*
+F: include/hw/*/tm4c123*
+F: hw/arm/tivac.c
+F: docs/system/arm/tivac.rst
+
 Xilinx ZynqMP and Versal
 M: Alistair Francis <alistair@alistair23.me>
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak
index 1b49a7830c..d3490f6d11 100644
--- a/configs/devices/arm-softmmu/default.mak
+++ b/configs/devices/arm-softmmu/default.mak
@@ -43,3 +43,4 @@ CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 CONFIG_ALLWINNER_H3=y
+CONFIG_TIVAC=y
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index b53bd7f0b2..ef8046ab1b 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -581,3 +581,16 @@ config ARMSSE
     select UNIMP
     select SSE_COUNTER
     select SSE_TIMER
+
+config TM4C123GH6PM_SOC
+    bool
+    select ARM_V7M
+    select TM4C123_USART
+    select TM4C123_SYSCTL
+    select TM4C123_GPIO
+    select TM4C123_WDT
+    select TM4C123_GPTM
+
+config TIVAC
+    bool
+    select TM4C123GH6PM_SOC
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index b545ba0e4f..29503388a5 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -62,10 +62,13 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.
 arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
 arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
 arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
+arm_ss.add(when: 'CONFIG_TM4C123GH6PM_SOC', if_true: files('tm4c123gh6pm_soc.c'))
+arm_ss.add(when: 'CONFIG_TIVAC', if_true: files('tivac.c'))
 
 softmmu_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
 softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
 softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
 softmmu_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c'))
 
+
 hw_arch += {'arm': arm_ss}
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 6b6cf2fc1d..88da979b75 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -71,3 +71,6 @@ config GOLDFISH_TTY
 
 config SHAKTI_UART
     bool
+
+config TM4C123_USART
+    bool
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 0807e00ae4..8461748c8d 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -33,6 +33,7 @@ softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
 softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
 softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
 softmmu_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
+softmmu_ss.add(when: 'CONFIG_TM4C123_USART', if_true: files('tm4c123_usart.c'))
 softmmu_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))
 
 specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
index d2cf3accc8..1b843d669a 100644
--- a/hw/gpio/Kconfig
+++ b/hw/gpio/Kconfig
@@ -16,3 +16,6 @@ config GPIO_PWR
 
 config SIFIVE_GPIO
     bool
+
+config TM4C123_GPIO
+    bool
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
index b726e6d27a..b253e8ce67 100644
--- a/hw/gpio/meson.build
+++ b/hw/gpio/meson.build
@@ -12,3 +12,4 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c'))
 softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c'))
 softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c'))
 softmmu_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c'))
+softmmu_ss.add(when: 'CONFIG_TM4C123_GPIO', if_true: files('tm4c123_gpio.c'))
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 2ef5781ef8..c8be9ae285 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -180,4 +180,7 @@ config AXP209_PMU
     bool
     depends on I2C
 
+config TM4C123_SYSCTL
+    bool
+
 source macio/Kconfig
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index a40245ad44..95ddb4b1b4 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -141,3 +141,4 @@ softmmu_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c'))
 
 # HPPA devices
 softmmu_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c'))
+softmmu_ss.add(when: 'CONFIG_TM4C123_SYSCTL', if_true: files('tm4c123_sysctl.c'))
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
index 010be7ed1f..aaf42e3f3f 100644
--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -60,3 +60,6 @@ config STELLARIS_GPTM
 
 config AVR_TIMER16
     bool
+
+config TM4C123_GPTM
+    bool
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index 03092e2ceb..118593e959 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -36,5 +36,6 @@ softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_timer.c
 softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c'))
 specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c'))
 softmmu_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c'))
+softmmu_ss.add(when: 'CONFIG_TM4C123_GPTM', if_true: files('tm4c123_gptm.c'))
 
 specific_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c'))
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 861fd00334..ada7163055 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -24,3 +24,6 @@ config WDT_SBSA
 config ALLWINNER_WDT
     bool
     select PTIMER
+
+config TM4C123_WDT
+    bool
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
index 5dcd4fbe2f..cc48d2dec9 100644
--- a/hw/watchdog/meson.build
+++ b/hw/watchdog/meson.build
@@ -7,4 +7,5 @@ softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
 softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
 softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
 softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
+softmmu_ss.add(when: 'CONFIG_TM4C123_WDT', if_true: files('tm4c123_watchdog.c'))
 specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 1/8] The tivac board initial machine definition
  2023-05-17  8:11 ` [PATCH 1/8] The tivac board initial machine definition Mohamed ElSayed
@ 2023-06-08 13:15   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 13:15 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

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/arm/tivac.c                    |  56 ++++++
>  hw/arm/tm4c123gh6pm_soc.c         | 275 ++++++++++++++++++++++++++++++
>  include/hw/arm/tm4c123gh6pm_soc.h |  71 ++++++++
>  3 files changed, 402 insertions(+)
>  create mode 100644 hw/arm/tivac.c
>  create mode 100644 hw/arm/tm4c123gh6pm_soc.c
>  create mode 100644 include/hw/arm/tm4c123gh6pm_soc.h

Hi; thanks for this patchseries; sorry it's taken me a while
to get to reviewing it.

A note on patch series order -- generally the patch adding
the board model goes last, because otherwise it's just dead
code not being compiled. If you put it at the end of the series
then the patch adding it can also add it to the meson.build file.

>
> diff --git a/hw/arm/tivac.c b/hw/arm/tivac.c
> new file mode 100644
> index 0000000000..5d917a8f9e
> --- /dev/null
> +++ b/hw/arm/tivac.c
> @@ -0,0 +1,56 @@
> +/*
> + * TivaC Board Implementation
> + *
> + * 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.
> + */

It's usually a good idea to have a comment here with the URL of
the documentation of the hardware, in this case
https://www.ti.com/tool/EK-TM4C123GXL . I know you've put that
in the docs, but often developers look at the sources first,
so having it in both places is handy.



> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/boards.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/qdev-clock.h"
> +#include "qemu/error-report.h"
> +#include "hw/arm/tm4c123gh6pm_soc.h"
> +#include "hw/arm/boot.h"
> +
> +
> +/* Main SYSCLK frequency in Hz (24MHz) */
> +#define SYSCLK_FRQ 24000000ULL

Where has this number come from? The docs suggest the SoC runs
at 80MHz. It seems like the SoC doesn't support the board
giving it a non-standard external clock, though, so better
to just do all the clock logic inside the SoC model.

> +
> +static void tivac_init(MachineState *machine)
> +{
> +    DeviceState *dev;
> +    dev = qdev_new(TYPE_TM4C123GH6PM_SOC);
> +
> +    qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));

Assuming the SoC is always a Cortex-M4, you don't really
need the machinery to set the CPU type from the board model:
you can just hard-wire it as an M4 in the SoC model.

> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> +    armv7m_load_kernel(ARM_CPU(first_cpu),
> +            machine->kernel_filename,
> +            0, FLASH_SIZE);

The indentation here is a bit off -- our style generally lines up
subsequent lines with the part inside the brackets in the first line,
so here the 'm' and '0' should line up with the 'A'.

More generally, scripts/checkpatch.pl will do some style checks
on your patches. It doesn't catch everything (it didn't catch
this, for instance), and sometimes it warns about things that
aren't really style issues because it misparses the C code,
so you need to be a bit cautious in interpreting its output,
but it's a good thing to get in the habit of running.

> +}
> +
> +static void tivac_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "Tiva C (Cortex-M4)";
> +    mc->init = tivac_init;
> +}
> +DEFINE_MACHINE("tivac", tivac_machine_init)

Looking at the TI website, "Tiva C Series" seems to be TI's name
for the whole series of microcontrollers, not for the specific
evaluation board. This board seems to be called the
EK-TM4C123GXL or the "TM4C123G LaunchPad Evaluation Board".
I think the board name (and correspondingly the source file
name, etc) should be something matching the hardware board name.
(TI might put out some other Tiva C series evaluation board
or boards that we might want to model in future, so we shouldn't
use an over-generic name here.) The board PDF calls it a
"Tiva C Series LaunchPad" so perhaps something like that would
do if you don't want the rather unmemorable product number in it.
(Other boards in the series seem to include the "Connected
LaunchPad" and the "Crypto Connected LaunchPad", so we're
probably OK assuming the product number alone won't be used
as a differentiator.)

> diff --git a/hw/arm/tm4c123gh6pm_soc.c b/hw/arm/tm4c123gh6pm_soc.c
> new file mode 100644
> index 0000000000..3e61911bba
> --- /dev/null
> +++ b/hw/arm/tm4c123gh6pm_soc.c
> @@ -0,0 +1,275 @@
> +/*
> + * TM4C123GH6PM SoC
> + *
> + * 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 "qapi/error.h"
> +#include "qemu/module.h"
> +#include "hw/arm/boot.h"

Do you really need boot.h here?

> +#include "exec/address-spaces.h"
> +#include "hw/arm/tm4c123gh6pm_soc.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/qdev-clock.h"
> +#include "hw/misc/unimp.h"
> +#include "sysemu/sysemu.h"
> +
> +static const uint32_t gpio_addrs[GPIO_COUNT] = {
> +    0x40004000,
> +    0x40005000,
> +    0x40006000,
> +    0x40007000,
> +    0x40024000,
> +    0x40025000
> +};
> +
> +static const uint32_t usart_addrs[USART_COUNT] = {
> +    0x4000C000,
> +    0x4000D000,
> +    0x4000E000,
> +    0x4000F000,
> +    0x40010000,
> +    0x40011000,
> +    0x40012000,
> +    0x40013000
> +};
> +
> +static const uint32_t wdt_addrs[WDT_COUNT] = {
> +    0x40000000,
> +    0x40001000
> +};
> +
> +static const uint32_t gptm_addrs[GPTM_COUNT] = {
> +    0x40030000,
> +    0x40031000,
> +    0x40032000,
> +    0x40033000,
> +    0x40034000,
> +    0x40035000,
> +    0x40036000,
> +    0x40037000,
> +    0x4003C800,
> +    0x4003D000,
> +    0x4003E000,
> +    0x4003F000,
> +};
> +
> +static const uint16_t usart_irqs[USART_COUNT] = {5, 6, 33, 59, 60, 61, 62, 63};
> +static const uint16_t gpio_irqs[GPIO_COUNT] = {0, 1, 2, 3, 4, 30};
> +static const uint16_t wdt_irqs[WDT_COUNT] = {18, 18};
> +static const uint16_t gptm_irqs[GPTM_COUNT * 2] = {
> +    19, 20, 21, 22, 23, 24, 35, 36, 70, 71, 92, 93,
> +    94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105};
> +
> +static void tm4c123gh6pm_soc_initfn(Object *obj)
> +{
> +    int i;
> +    TM4C123GH6PMState *s = TM4C123GH6PM_SOC(obj);
> +
> +    object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
> +    object_initialize_child(obj, "sysctl", &s->sysctl, TYPE_TM4C123_SYSCTL);
> +
> +    for (i = 0; i < USART_COUNT; i++) {
> +        object_initialize_child(obj, "usart[*]",
> +                                &s->usart[i], TYPE_TM4C123_USART);
> +    }
> +
> +    for (i = 0; i < GPIO_COUNT; i++) {
> +        object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_TM4C123_GPIO);
> +    }
> +
> +    for (i = 0; i < WDT_COUNT; i++) {
> +        object_initialize_child(obj, "watchdog-timer[*]",
> +                                &s->wdt[i], TYPE_TM4C123_WATCHDOG);
> +    }
> +
> +    for (i = 0; i < GPTM_COUNT; i++) {
> +        object_initialize_child(obj, "gptm[*]", &s->gptm[i], TYPE_TM4C123_GPTM);
> +    }
> +}
> +
> +static void tm4c123gh6pm_soc_realize(DeviceState *dev_soc, Error **errp)
> +{
> +    TM4C123GH6PMState *s = TM4C123GH6PM_SOC(dev_soc);
> +    DeviceState *armv7m;
> +    DeviceState *dev;
> +    SysBusDevice *busdev;
> +    int i;
> +
> +    MemoryRegion *system_memory = get_system_memory();
> +
> +    /* init flash memory */
> +    memory_region_init_rom(
> +            &s->flash, OBJECT(dev_soc),
> +            "TM4C123GH6PM.flash", FLASH_SIZE, &error_fatal
> +            );

This is weirdly indented -- generally don't put a newline immediately
after the opening bracket, and don't put the closing bracket on a line
of its own.

> +    memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
> +
> +    /* init sram and the sram alias region */
> +    memory_region_init_ram(
> +            &s->sram, OBJECT(dev_soc),
> +            "TM4C123GH6PM.sram", SRAM_SIZE, &error_fatal);
> +    memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);

The comment says there's an SRAM alias region, but the code doesn't
create one...

> +
> +    /* Init ARMv7m */
> +    armv7m = DEVICE(&s->armv7m);
> +    qdev_prop_set_uint32(armv7m, "num-irq", 138);
> +    qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
> +    qdev_prop_set_bit(armv7m, "enable-bitband", true);
> +    qdev_connect_clock_in(armv7m, "cpuclk", s->sysctl.mainclk);
> +    qdev_connect_clock_in(armv7m, "refclk", s->sysctl.mainclk);

The SoC docs say the systick is connected to
 * the system clock
 * the PIOSC / 4  (which will be 4MHz)
(which one is used depending on STCTRL.CLK_SRC).
So you don't want to connect both cpuclk and refclk to the same thing.
refclk here should be connected to a fixed 4MHz clksource.

Also, you generally don't want to reach directly into the internals
of other device objects. Instead of directly using s->sysctl.mainclk,
you have the sysctl device create the clock with
qdev_init_clock_out(..., "my-clock-name"), and then the code here
can use qdev_get_clock_out(DEVICE(s->sysctl), "my-clock-name")
to get the clock.

> +    object_property_set_link(OBJECT(&s->armv7m), "memory",
> +            OBJECT(get_system_memory()), &error_abort);
> +
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
> +        return;
> +    }
> +
> +    /* USART */
> +    for (i = 0; i < USART_COUNT; i++) {
> +        dev = DEVICE(&(s->usart[i]));
> +        s->usart[i].sysctl = &s->sysctl;
> +        qdev_prop_set_chr(dev, "chardev", serial_hd(i));
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) {
> +            return;
> +        }
> +        busdev = SYS_BUS_DEVICE(dev);
> +        sysbus_mmio_map(busdev, 0, usart_addrs[i]);
> +        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irqs[i]));
> +    }
> +
> +    /* GPIO */
> +    for (i = 0; i < GPIO_COUNT; i++) {
> +        dev = DEVICE(&(s->gpio[i]));
> +        s->gpio[i].sysctl = &s->sysctl;
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
> +            return;
> +        }
> +        busdev = SYS_BUS_DEVICE(dev);
> +        sysbus_mmio_map(busdev, 0, gpio_addrs[i]);
> +        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, gpio_irqs[i]));
> +    }
> +
> +    /* Watchdog Timers */
> +    for (i = 0; i < WDT_COUNT; i++) {
> +        dev = DEVICE(&(s->wdt[i]));
> +        s->wdt[i].sysctl = &s->sysctl;
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
> +            return;
> +        }
> +        busdev = SYS_BUS_DEVICE(dev);
> +        sysbus_mmio_map(busdev, 0, wdt_addrs[i]);
> +        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, wdt_irqs[i]));
> +    }
> +
> +    /* General purpose timers */
> +    int j = 0;
> +    for (i = 0, j = 0; i < GPTM_COUNT; i++, j += 2) {
> +        dev = DEVICE(&(s->gptm[i]));
> +        s->gptm[i].sysctl = &s->sysctl;
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->gptm[i]), errp)) {
> +            return;
> +        }
> +        busdev = SYS_BUS_DEVICE(dev);
> +        sysbus_mmio_map(busdev, 0, gptm_addrs[i]);
> +        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, gptm_irqs[j]));
> +        sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(armv7m, gptm_irqs[j + 1]));
> +    }
> +
> +    /* SYSCTL */
> +    dev = DEVICE(&(s->sysctl));
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), errp)) {
> +        return;
> +    }
> +    busdev = SYS_BUS_DEVICE(dev);
> +    sysbus_mmio_map(busdev, 0, SYSCTL_ADDR);

> +

> +
> +    create_unimplemented_device("SSI_0", 0x40008000, 0xFFF);

These lengths look very fishy. Is there really a 1 byte gap
between the end of SSI_0 and the start of SSI_1 ?  0x1000 seems
more plausible.

> +    create_unimplemented_device("SSI_1", 0x40009000, 0xFFF);
> +    create_unimplemented_device("SSI_2", 0x4000A000, 0xFFF);
> +    create_unimplemented_device("SSI_3", 0x4000B000, 0xFFF);

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/8] tiva c usart module implementation
  2023-05-17  8:11 ` [PATCH 2/8] tiva c usart module implementation Mohamed ElSayed
@ 2023-06-08 13:36   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 13:36 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

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


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/8] tiva c gpio implementation
  2023-05-17  8:11 ` [PATCH 3/8] tiva c gpio implementation Mohamed ElSayed
@ 2023-06-08 13:37   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 13:37 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

On Wed, 17 May 2023 at 09:14, Mohamed ElSayed <m.elsayed4420@gmail.com> wrote:
>
> Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
> ---
>  hw/gpio/tm4c123_gpio.c         | 372 +++++++++++++++++++++++++++++++++
>  hw/gpio/trace-events           |   4 +
>  include/hw/gpio/tm4c123_gpio.h | 127 +++++++++++
>  3 files changed, 503 insertions(+)
>  create mode 100644 hw/gpio/tm4c123_gpio.c
>  create mode 100644 include/hw/gpio/tm4c123_gpio.h

Again, TI are quietly reusing the PL061 GPIO controller here, so
we should add support for this variant to hw/gpio/pl061.c rather
than defining a completely separate implementation for it.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/8] tiva c sysctl implementation
  2023-05-17  8:12 ` [PATCH 4/8] tiva c sysctl implementation Mohamed ElSayed
@ 2023-06-08 13:58   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 13:58 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

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/misc/tm4c123_sysctl.c         | 989 +++++++++++++++++++++++++++++++
>  hw/misc/trace-events             |   5 +
>  include/hw/misc/tm4c123_sysctl.h | 307 ++++++++++
>  3 files changed, 1301 insertions(+)
>  create mode 100644 hw/misc/tm4c123_sysctl.c
>  create mode 100644 include/hw/misc/tm4c123_sysctl.h
>
> diff --git a/hw/misc/tm4c123_sysctl.c b/hw/misc/tm4c123_sysctl.c
> new file mode 100644
> index 0000000000..c996609fc7
> --- /dev/null
> +++ b/hw/misc/tm4c123_sysctl.c
> @@ -0,0 +1,989 @@
> +/*
> + * TM4C123 SYSCTL
> + *
> + * 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/misc/tm4c123_sysctl.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)

See the remarks in an earlier patch about these macros.

> +
> +static void tm4c123_sysctl_update_system_clock(void *opaque)
> +{
> +    TM4C123SysCtlState *s = opaque;
> +
> +    uint32_t RCC_Val = s->sysctl_rcc;
> +    uint32_t RCC2_Val = s->sysctl_rcc2;
> +
> +    uint32_t __CORE_CLK_PRE;
> +    uint32_t __CORE_CLK;

Please don't use double-underscore prefixes or all-caps for
variables.

> +
> +    if (RCC2_Val & (1UL << 31)) {  /* is rcc2 used? */
> +        if (RCC2_Val & (1UL << 11)) {  /* check BYPASS */
> +            if (((RCC2_Val >> 4) & 0x07) == 0x0) {
> +                if (((RCC_Val >> 6) & 0x1F) == 0x0) {
> +                    __CORE_CLK_PRE = 1000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x1) {
> +                    __CORE_CLK_PRE = 1843200UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x2) {
> +                    __CORE_CLK_PRE = 2000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x3) {
> +                    __CORE_CLK_PRE = 2457600UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x4) {
> +                    __CORE_CLK_PRE = 3579545UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x5) {
> +                    __CORE_CLK_PRE = 3686400UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x6) {
> +                    __CORE_CLK_PRE = 4000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x7) {
> +                    __CORE_CLK_PRE = 4096000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x8) {
> +                    __CORE_CLK_PRE = 4915200UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x9) {
> +                    __CORE_CLK_PRE = 5000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0xA) {
> +                    __CORE_CLK_PRE = 5120000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0xB) {
> +                    __CORE_CLK_PRE = 6000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0xC) {
> +                    __CORE_CLK_PRE = 6144000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0xD) {
> +                    __CORE_CLK_PRE = 7372800UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0xE) {
> +                    __CORE_CLK_PRE = 8000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0xF) {
> +                    __CORE_CLK_PRE = 8192000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x10) {
> +                    __CORE_CLK_PRE = 10000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x11) {
> +                    __CORE_CLK_PRE = 12000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x12) {
> +                    __CORE_CLK_PRE = 12288000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x13) {
> +                    __CORE_CLK_PRE = 13560000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x14) {
> +                    __CORE_CLK_PRE = 14318180UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x15) {
> +                    __CORE_CLK_PRE = 16000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x16) {
> +                    __CORE_CLK_PRE = 16384000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x17) {
> +                    __CORE_CLK_PRE = 18000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x18) {
> +                    __CORE_CLK_PRE = 20000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x19) {
> +                    __CORE_CLK_PRE = 24000000UL;
> +                } else if (((RCC_Val >> 6) & 0x1F) == 0x1A) {
> +                    __CORE_CLK_PRE = 25000000UL;
> +                } else {
> +                    __CORE_CLK_PRE = 0UL;
> +                }
> +                __CORE_CLK = __CORE_CLK_PRE / 2UL;  /* divide by 2 since BYPASS is set */
> +            } else {  /* PLL is used */
> +                uint32_t __PLL_MULT = ((RCC2_Val >> 4) & 0x1F) + 2;
> +                uint32_t __PLL_DIV = ((RCC2_Val >> 0) & 0x3F) + 1;
> +                uint32_t __PLL_SOURCE = ((RCC2_Val >> 13) & 0x01);
> +                if (__PLL_SOURCE == 0) {  /* source is XTAL */
> +                    __CORE_CLK_PRE = (XTALI * __PLL_MULT) / __PLL_DIV;
> +                } else {  /* source is internal oscillator */
> +                    __CORE_CLK_PRE = (16000000UL * __PLL_MULT) / __PLL_DIV;  /* internal oscillator frequency is 16MHz */
> +                }
> +                __CORE_CLK = __CORE_CLK_PRE / 2UL;  /* divide by 2 since BYPASS is set */
> +            }
> +        } else {  /* BYPASS is not set */
> +            uint32_t __SYS_DIV = ((RCC2_Val >> 22) & 0x7F) + 1;
> +            uint32_t __PLL_MULT = ((RCC2_Val >> 4) & 0x1F) + 2;
> +            uint32_t __PLL_DIV = ((RCC2_Val >> 0) & 0x3F) + 1;
> +            uint32_t __PLL_SOURCE = ((RCC2_Val >> 13) & 0x01);
> +            if (__PLL_SOURCE == 0) {  /* source is XTAL */
> +                __CORE_CLK_PRE = (XTALI * __PLL_MULT) / __PLL_DIV;
> +            } else {  /* source is internal oscillator */
> +                __CORE_CLK_PRE = (16000000UL * __PLL_MULT) / __PLL_DIV;  /* internal oscillator frequency is 16MHz */
> +            }
> +            __CORE_CLK = __CORE_CLK_PRE / __SYS_DIV;
> +        }
> +    } else {  /* rcc2 is not used */
> +        if (((RCC_Val >> 16) & 0x01) == 0x01) {  /* check USESYSCLK */
> +            if (((RCC_Val >> 23) & 0x01) == 0x01) {  /* check BYPASS */
> +                __CORE_CLK_PRE = XTALI;
> +            } else {  /* PLL is used */
> +                uint32_t __PLL_MULT = ((RCC_Val >> 18) & 0x1F) + 2;
> +                uint32_t __PLL_DIV = ((RCC_Val >> 12) & 0x3F) + 1;
> +                uint32_t __PLL_SOURCE = ((RCC_Val >> 16) & 0x01);
> +                if (__PLL_SOURCE == 0) {  /* source is XTAL */
> +                    __CORE_CLK_PRE = (XTALI * __PLL_MULT) / __PLL_DIV;
> +                } else {  /* source is internal oscillator */
> +                    __CORE_CLK_PRE = (16000000UL * __PLL_MULT) / __PLL_DIV;  /* internal oscillator frequency is 16MHz */
> +                }
> +            }
> +        } else {  /* USESYSCLK bit is not set */
> +            __CORE_CLK_PRE = 16000000UL;  /* default to internal oscillator frequency */
> +        }
> +        __CORE_CLK = __CORE_CLK_PRE / 1UL;  /* no division needed since BYPASS is not set */
> +    }
> +    trace_tm4c123_sysctl_update_system_clock(__CORE_CLK);
> +    clock_update_hz(s->mainclk, __CORE_CLK);
> +}

> +static void tm4c123_sysctl_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size)
> +{
> +    TM4C123SysCtlState *s = opaque;
> +    uint32_t val32 = val64;
> +
> +    trace_tm4c123_sysctl_write(addr, val32);
> +
> +    switch (addr) {
> +        case SYSCTL_DID0:
> +            READONLY;
> +            break;
> +        case SYSCTL_DID1:
> +            READONLY;
> +            break;
> +        case SYSCTL_PBORCTL:
> +            s->sysctl_pborctl = val32;
> +            break;
> +        case SYSCTL_RIS:
> +            READONLY;
> +            break;
> +        case SYSCTL_IMC:
> +            s->sysctl_imc = val32;
> +            /*
> +             * setting the MISC
> +             */
> +            s->sysctl_misc = val32;
> +            break;

What's this for? The spec does not say anything about the MISC
register being written by the IMC. In fact the MISC is just
the masked status of the current interrupts, so it shouldn't
have a status field at all. Reading the MISC register ought
to return s->sysctl_ris & s->sysctl_imc.

> +        case SYSCTL_MISC:
> +            s->sysctl_misc = val32;

Writing to MISC should change bits in RIS on a write-on-to-clear
basis, so this isn't right. It should be
   s->sysctl_ris &= ~val32; /* W1C */

> +            break;

> +        case SYSCTL_RESC:
> +            s->sysctl_resc = val32;
> +            break;
> +        case SYSCTL_RCC:
> +            s->sysctl_rcc = val32;
> +            /*
> +             * Setting the SYSCTL_RIS manually for now.
> +             */
> +            if (s->sysctl_rcc & SYSCTL_RCC_PWRDN && !(s->sysctl_rcc2 & SYSCTL_RCC2_USERCC2)) {
> +                s->sysctl_ris |= SYSCTL_RIS_PLLRIS;
> +            }

I don't entirely understand the comment here. My guess is that we're
opting for "report the PLL as locked immediately rather than
emulating the real hardware's timed delay before reporting it"
(which is fine, though I think the comment could be clearer
about what it's doing).

However should we really be testing PWRDN == 1 here ? That means
"PLL powered down", not "powered up"; it doesn't match the logic
you have below for the similar RCC2 bits either.

> +            tm4c123_sysctl_update_system_clock(s);
> +            break;
> +        case SYSCTL_GPIOHBCTL:
> +            s->sysctl_gpiohbctl = val32;
> +            break;
> +        case SYSCTL_RCC2:
> +            s->sysctl_rcc2 = val32;
> +            /*
> +             * Setting the SYSCTL_RIS manually for now.
> +             */
> +            if (s->sysctl_rcc2 & SYSCTL_RCC2_USERCC2 && !(s->sysctl_rcc2 & SYSCTL_RCC2_PWRDN2)) {
> +                s->sysctl_ris |= SYSCTL_RIS_PLLRIS;
> +            }
> +            tm4c123_sysctl_update_system_clock(s);

Because the logic for "do we set the PLLRIS bit?" depends
on both the rcc and rcc2 values, you need to check everything
in both places. Otherwise if the guest writes RCC.PWRDN to
0 first and RCC2.USERCC2 to 0 second then you won't notice.
So I think you should move this logic to the
tm4c123_sysctl_update_system_clock() function.

> +            break;

> +
> +static void tm4c123_sysctl_class_init(ObjectClass *kclass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(kclass);
> +    dc->reset = tm4c123_sysctl_reset;
> +    dc->realize = tm4c123_sysctl_realize;

You also need to set dc->vmsd. (Every device with internal
state needs to set up a VMStateDescription, which describes
that internal state for the purposes of migration and
for VM state save/restore.)

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 5/8] tiva c watchdog timers implementation
  2023-05-17  8:12 ` [PATCH 5/8] tiva c watchdog timers implementation Mohamed ElSayed
@ 2023-06-08 14:05   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 14:05 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

On Wed, 17 May 2023 at 09:14, Mohamed ElSayed <m.elsayed4420@gmail.com> wrote:
>
> Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
> ---
>  hw/watchdog/tm4c123_watchdog.c         | 297 +++++++++++++++++++++++++
>  hw/watchdog/trace-events               |   3 +
>  include/hw/watchdog/tm4c123_watchdog.h |  97 ++++++++
>  3 files changed, 397 insertions(+)
>  create mode 100644 hw/watchdog/tm4c123_watchdog.c
>  create mode 100644 include/hw/watchdog/tm4c123_watchdog.h

This one's just a variant of TYPE_LUMINARY_WATCHDOG,
which you can find in hw/watchdog/cmsdk-apb-watchdog.c.
Probably you only need to add a new variant with
the ID register values different. You want the
"is_luminary == true" behaviour in this variant.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 7/8] tiva c board documentation
  2023-05-17  8:12 ` [PATCH 7/8] tiva c board documentation Mohamed ElSayed
@ 2023-06-08 14:11   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 14:11 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

On Wed, 17 May 2023 at 09:13, Mohamed ElSayed <m.elsayed4420@gmail.com> wrote:
>
> Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
> ---
>  docs/system/arm/tivac.rst | 47 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 47 insertions(+)
>  create mode 100644 docs/system/arm/tivac.rst

This is missing the line to add this new file to the
docs:

--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -105,6 +105,7 @@ undocumented; you can get a complete list by running
    arm/sx1
    arm/stellaris
    arm/stm32
+   arm/tivac
    arm/virt
    arm/xlnx-versal-virt

Without this Sphinx will complain, which should cause a build
failure. Check that you're really building the docs
(passing --enable-docs to configure will make it fail if
you don't have the necessary tools installed to build docs).

> diff --git a/docs/system/arm/tivac.rst b/docs/system/arm/tivac.rst
> new file mode 100644
> index 0000000000..8e78726c01
> --- /dev/null
> +++ b/docs/system/arm/tivac.rst
> @@ -0,0 +1,47 @@
> +Texas Instruments EK-TM4C123GXL Evaluation Board, ``Tiva C``
> +========================================================================================

Underlines below titles should be the same length as the title-text,
not over-length.

> +
> +The `Tiva C`_ board is an evaluation platform for ARM Cortex-M4-based microcontrollers.

See remarks on board naming from patch 1.

> +Its based on the `TM4C123GH6PM`_ microcontroller by Texas Instruments.

"It is"

> +
> +.. _Tiva C: https://www.ti.com/tool/EK-TM4C123GXL
> +.. _TM4C123GH6PM: https://www.ti.com/product/TM4C123GH6PM
> +
> +Supported modules
> +-----------------
> +
> + * ARM Cortex-M4
> + * General Purpose Input/Output (GPIO)
> + * General Purpose Timers (GPTM)
> + * Serial Ports (USART)
> + * System Control (SYSCTL)
> + * Watchdog Timers (WDT)
> +
> +Missing modules
> +---------------
> +
> + * Dynamic Memory Access (uDMA)
> + * Analog to Digital Converter (ADC)
> + * Synchronous Serial Interface (SSI)
> + * Inter-Integrated Circuit Interface (I2C)
> + * Controller Area Network (CAN)
> + * USB Controller
> + * Analog Comparators
> + * Pulse Width Modulator (PWM)
> + * Quadrature Encoder Interface (QEI)
> +
> +Boot options
> +------------
> +
> +The Tiva C machines could be started using the ``-kernel`` option to load a binary file.

"can be started"

> +
> +.. code-block:: bash
> +
> +  $ qemu-system-arm -M tivac -kernel binary.elf -s -S

Are there any standard/well-known guest binaries that run on the board
that we could point to? (If not, that's fine.)

> +
> +The ``-s -S`` switches are for debugging, in another terminal window you can do:
> +
> +.. code-block:: bash
> +
> +   $ arm-none-eabi-gdb binary.elf
> +   (gdb) target remote :1234

The -s and -S stuff is standard, so you don't need to mention
it here.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 8/8] adding tiva c to the qemu build system and adding my info to the maintainers list
  2023-05-17  8:12 ` [PATCH 8/8] adding tiva c to the qemu build system and adding my info to the maintainers list Mohamed ElSayed
@ 2023-06-08 14:16   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 14:16 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

On Wed, 17 May 2023 at 09:14, Mohamed ElSayed <m.elsayed4420@gmail.com> wrote:
>
> Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
> ---
>  MAINTAINERS                             |  9 +++++++++
>  configs/devices/arm-softmmu/default.mak |  1 +
>  hw/arm/Kconfig                          | 13 +++++++++++++
>  hw/arm/meson.build                      |  3 +++
>  hw/char/Kconfig                         |  3 +++
>  hw/char/meson.build                     |  1 +
>  hw/gpio/Kconfig                         |  3 +++
>  hw/gpio/meson.build                     |  1 +
>  hw/misc/Kconfig                         |  3 +++
>  hw/misc/meson.build                     |  1 +
>  hw/timer/Kconfig                        |  3 +++
>  hw/timer/meson.build                    |  1 +
>  hw/watchdog/Kconfig                     |  3 +++
>  hw/watchdog/meson.build                 |  1 +
>  14 files changed, 46 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b22b85bc3a..dcd902fadf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1008,6 +1008,15 @@ F: include/hw/misc/zynq_slcr.h
>  F: include/hw/adc/zynq-xadc.h
>  X: hw/ssi/xilinx_*
>
> +Tiva C
> +M: Mohamed ElSayed <m.elsayed4420@gmail.com>
> +L: qemu-arm@nongnu.org
> +S: Maintained
> +F: hw/*/tm4c123*
> +F: include/hw/*/tm4c123*
> +F: hw/arm/tivac.c
> +F: docs/system/arm/tivac.rst
> +

Subsections inside this file are in alphabetical order,
so this should go a little further up, between
"STM32VLDISCOVERY" and "Versatile Express".

>  Xilinx ZynqMP and Versal
>  M: Alistair Francis <alistair@alistair23.me>
>  M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak
> index 1b49a7830c..d3490f6d11 100644
> --- a/configs/devices/arm-softmmu/default.mak
> +++ b/configs/devices/arm-softmmu/default.mak
> @@ -43,3 +43,4 @@ CONFIG_FSL_IMX6UL=y
>  CONFIG_SEMIHOSTING=y
>  CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
>  CONFIG_ALLWINNER_H3=y
> +CONFIG_TIVAC=y

This file has changed recently, so now you only need
a commented out line
# CONFIG_TIVAC=n

> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index b53bd7f0b2..ef8046ab1b 100644
> --- a/hw/arm/Kconfig
> +++ b/hw/arm/Kconfig
> @@ -581,3 +581,16 @@ config ARMSSE
>      select UNIMP
>      select SSE_COUNTER
>      select SSE_TIMER
> +
> +config TM4C123GH6PM_SOC
> +    bool
> +    select ARM_V7M
> +    select TM4C123_USART
> +    select TM4C123_SYSCTL
> +    select TM4C123_GPIO
> +    select TM4C123_WDT
> +    select TM4C123_GPTM
> +
> +config TIVAC
> +    bool
> +    select TM4C123GH6PM_SOC

The same recent change that means the handling in default.mak
is different also means that the config stanza for a board
(but not for a SoC) also needs two new lines:

       default y
       depends on TCG && ARM

(These go just below the 'bool' line -- check eg STM32VLDISCOVERY
for an example).

> diff --git a/hw/arm/meson.build b/hw/arm/meson.build
> index b545ba0e4f..29503388a5 100644
> --- a/hw/arm/meson.build
> +++ b/hw/arm/meson.build
> @@ -62,10 +62,13 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.
>  arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
>  arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
>  arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
> +arm_ss.add(when: 'CONFIG_TM4C123GH6PM_SOC', if_true: files('tm4c123gh6pm_soc.c'))
> +arm_ss.add(when: 'CONFIG_TIVAC', if_true: files('tivac.c'))
>
>  softmmu_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
>  softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
>  softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
>  softmmu_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c'))
>
> +
>  hw_arch += {'arm': arm_ss}
> diff --git a/hw/char/Kconfig b/hw/char/Kconfig
> index 6b6cf2fc1d..88da979b75 100644
> --- a/hw/char/Kconfig
> +++ b/hw/char/Kconfig
> @@ -71,3 +71,6 @@ config GOLDFISH_TTY
>
>  config SHAKTI_UART
>      bool
> +
> +config TM4C123_USART
> +    bool
> diff --git a/hw/char/meson.build b/hw/char/meson.build
> index 0807e00ae4..8461748c8d 100644
> --- a/hw/char/meson.build
> +++ b/hw/char/meson.build
> @@ -33,6 +33,7 @@ softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
>  softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
>  softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
>  softmmu_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
> +softmmu_ss.add(when: 'CONFIG_TM4C123_USART', if_true: files('tm4c123_usart.c'))
>  softmmu_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))
>
>  specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))

As I noted earlier, changes to meson.build and Kconfig for each
device should go in that device's patch. The changes for
the top level board go in the patch that adds the board
(which should come last in the patch series).

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 6/8] tiva c general purpose timers implementation
  2023-05-17  8:12 ` [PATCH 6/8] tiva c general purpose " Mohamed ElSayed
@ 2023-06-08 14:28   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2023-06-08 14:28 UTC (permalink / raw)
  To: Mohamed ElSayed; +Cc: qemu-devel, qemu-arm

On Wed, 17 May 2023 at 09:14, Mohamed ElSayed <m.elsayed4420@gmail.com> wrote:
>
> Signed-off-by: Mohamed ElSayed <m.elsayed4420@gmail.com>
> ---
>  hw/timer/tm4c123_gptm.c         | 495 ++++++++++++++++++++++++++++++++
>  hw/timer/trace-events           |   5 +
>  include/hw/timer/tm4c123_gptm.h | 131 +++++++++
>  3 files changed, 631 insertions(+)
>  create mode 100644 hw/timer/tm4c123_gptm.c
>  create mode 100644 include/hw/timer/tm4c123_gptm.h
>

These look like they're either TYPE_STELLARIS_GPTM
(hw/timer/stellaris-gptm.c) or a minor variation on them.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2023-06-08 14:29 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-17  8:11 [PATCH 0/8] Tiva C Implementation Mohamed ElSayed
2023-05-17  8:11 ` [PATCH 1/8] The tivac board initial machine definition Mohamed ElSayed
2023-06-08 13:15   ` Peter Maydell
2023-05-17  8:11 ` [PATCH 2/8] tiva c usart module implementation Mohamed ElSayed
2023-06-08 13:36   ` Peter Maydell
2023-05-17  8:11 ` [PATCH 3/8] tiva c gpio implementation Mohamed ElSayed
2023-06-08 13:37   ` Peter Maydell
2023-05-17  8:12 ` [PATCH 4/8] tiva c sysctl implementation Mohamed ElSayed
2023-06-08 13:58   ` Peter Maydell
2023-05-17  8:12 ` [PATCH 5/8] tiva c watchdog timers implementation Mohamed ElSayed
2023-06-08 14:05   ` Peter Maydell
2023-05-17  8:12 ` [PATCH 6/8] tiva c general purpose " Mohamed ElSayed
2023-06-08 14:28   ` Peter Maydell
2023-05-17  8:12 ` [PATCH 7/8] tiva c board documentation Mohamed ElSayed
2023-06-08 14:11   ` Peter Maydell
2023-05-17  8:12 ` [PATCH 8/8] adding tiva c to the qemu build system and adding my info to the maintainers list Mohamed ElSayed
2023-06-08 14:16   ` Peter Maydell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).