当前位置: 首页 > news >正文

Qemu-NUC980(八):GPIO Controller

概述

本文描述了添加980 GPIO控制器功能代码的步骤,在描述过程中,为了清晰的描述添加框架,部分代码的细节被删除,详细的代码,请参考文末的工程链接。

添加步骤

1、修改hw/arm/Kconfig,如下所示:

+号部分为新增加内容

--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -121,6 +121,7 @@ config NUC980select NUC980_UARTselect NUC980_AICselect NUC980_TIMER
+    select NUC980_GPIOconfig NUC980_EVBbool

2、修改hw/arm/nuc980_soc.c,如下所示:

+号部分为新增加内容

index c56402a8..f4d68719 100644
--- a/hw/arm/nuc980_soc.c
+++ b/hw/arm/nuc980_soc.c
@@ -39,6 +39,16 @@ static struct devinfo timer_table[TIMER_COUNT] = {{ TIMER5_BASE, 34},};+static struct devinfo gpio_table[GPIO_COUNT] = {
+    { GPIOA_BASE, 8},
+    { GPIOB_BASE, 9},
+    { GPIOC_BASE, 10},
+    { GPIOD_BASE, 11},
+    { GPIOE_BASE, 49},
+    { GPIOF_BASE, 57},
+    { GPIOG_BASE, 63},
+};
+static void nuc980_init(Object *obj){int i;
@@ -69,6 +79,12 @@ static void nuc980_init(Object *obj)sysbus_init_child_obj(obj, name, &s->timer[i], sizeof(s->timer[i]),TYPE_NUC980_TIMER);}
+    /* gpio */
+    for (i = 0; i < GPIO_COUNT; i++) {
+        snprintf(name, NAME_SIZE, "gpio%d", i + 1);
+        sysbus_init_child_obj(obj, name, &s->gpio[i], sizeof(s->gpio[i]),
+                              TYPE_NUC980_GPIO);
+    }}static void nuc980_realize(DeviceState *dev, Error **errp)
@@ -135,6 +151,18 @@ static void nuc980_realize(DeviceState *dev, Error **errp)qdev_get_gpio_in(DEVICE(&s->aic),timer_table[i].irq));}
+    /* gpio */
+    for (i = 0; i < GPIO_COUNT; i++) {
+        object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+                           qdev_get_gpio_in(DEVICE(&s->aic),
+                            gpio_table[i].irq));
+    }}static void nuc980_class_init(ObjectClass *oc, void *data)

3、修改hw/gpio/Kconfig,如下所示:

+号部分为新增加内容

index 9227cb55..231a42b5 100644
--- a/hw/gpio/Kconfig
+++ b/hw/gpio/Kconfig
@@ -7,3 +7,6 @@ config PL061config GPIO_KEYbool
+
+config NUC980_GPIO
+    bool

4、修改hw/gpio/Makefile.objs,如下所示:

+号部分为新增加内容

index d305b3b2..ff5e31a3 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -10,3 +10,4 @@ obj-$(CONFIG_IMX) += imx_gpio.oobj-$(CONFIG_RASPI) += bcm2835_gpio.oobj-$(CONFIG_NRF51_SOC) += nrf51_gpio.oobj-$(CONFIG_ASPEED_SOC) += aspeed_gpio.o
+obj-$(CONFIG_NUC980_GPIO) += nuc980_gpio.o

5、创建hw/gpio/nuc980_gpio.c,如下所示:

+号部分为新增加内容

new file mode 100644
index 00000000..75a51995
--- /dev/null
+++ b/hw/gpio/nuc980_gpio.c
@@ -0,0 +1,195 @@
+/*
+ * NUC980 SOC System emulation.
+ *
+ * Copyright (c) 2023- yanl1229@163.com.
+ * Written by yanl1229
+ *
+ * This code is licensed under the GPL.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "hw/gpio/nuc980_gpio.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qemu/module.h"
+
+#ifndef STM_GPIO_ERR_DEBUG
+#define STM_GPIO_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+    if (STM_GPIO_ERR_DEBUG >= lvl) { \
+        qemu_log("%s: " fmt, __func__, ## args); \
+    } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void nuc980_gpio_reset(DeviceState *dev)
+{
+    NUC980GPIOState *s = NUC980_GPIO(dev);
+    s->gpio_mode    = 0x00000000;
+    s->gpio_dinoff  = 0x00000000;
+    s->gpio_dout    = 0x0000ffff;
+    s->gpio_datmsk  = 0x00000000;
+    s->gpio_pin     = 0x00000000;
+    s->gpio_dben    = 0x00000000;
+    s->gpio_inttype = 0x00000000;
+    s->gpio_inten   = 0x00000000;
+    s->gpio_intsrc  = 0x00000000;
+    s->gpio_smten   = 0x00000000;
+    s->gpio_slewctl = 0x00000000;
+    s->gpio_pusel   = 0x00000000;
+}
+
+static uint64_t nuc980_gpio_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    NUC980GPIOState *s = opaque;
+    uint64_t retvalue = 0;
+
+    DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
+    switch(addr) {
+    case GPIO_MODE:
+        retvalue = s->gpio_mode;
+        break;
+    case GPIO_DINOFF:
+        retvalue = s->gpio_dinoff;
+        break;
+    case GPIO_DOUT:
+        retvalue = s->gpio_dout;
+        break;
+    case GPIO_DATMSK:
+        retvalue = s->gpio_datmsk;
+        break;
+    case GPIO_PIN:
+        retvalue = s->gpio_pin;
+        break;
+    case GPIO_DBEN:
+        retvalue = s->gpio_dben;
+        break;
+    case GPIO_INTTYPE:
+        retvalue = s->gpio_inttype;
+        break;
+    case GPIO_INTEN:
+        retvalue = s->gpio_inten;
+        break;
+    case GPIO_INTSRC:
+        retvalue = s->gpio_intsrc;
+        break;
+    case GPIO_SMTEN:
+        retvalue = s->gpio_smten;
+        break;
+    case GPIO_SLEWCTL:
+        retvalue = s->gpio_slewctl;
+        break;
+    case GPIO_PUSEL:
+        retvalue = s->gpio_pusel;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+            __func__, addr);
+        retvalue = 0;
+        break;
+    }
+    return retvalue;
+}
+
+static void nuc980_gpio_write(void *opaque, hwaddr addr,
+                                uint64_t val64, unsigned int size)
+{
+    NUC980GPIOState *s = opaque;
+    uint32_t value = val64;
+
+    DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", addr, value);
+    switch(addr) {
+    case GPIO_MODE:
+        s->gpio_mode = value;
+        break;
+    case GPIO_DINOFF:
+        s->gpio_dinoff = value;
+        break;
+    case GPIO_DOUT:
+        s->gpio_dout = value;
+        break;
+    case GPIO_DATMSK:
+        s->gpio_datmsk = value;
+        break;
+    case GPIO_DBEN:
+        s->gpio_dben = value;
+        break;
+    case GPIO_INTTYPE:
+        s->gpio_inttype = value;
+        break;
+    case GPIO_INTEN:
+        s->gpio_inten = value;
+        break;
+    case GPIO_INTSRC:
+        s->gpio_intsrc = value;
+        break;
+    case GPIO_SMTEN:
+        s->gpio_smten = value;
+        break;
+    case GPIO_SLEWCTL:
+        s->gpio_slewctl = value;
+        break;
+    case GPIO_PUSEL:
+        s->gpio_pusel = value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+            __func__, addr);
+    }
+}
+
+static const MemoryRegionOps nuc980_gpio_ops = {
+    .read = nuc980_gpio_read,
+    .write = nuc980_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_nuc980_gpio = {
+    .name = TYPE_NUC980_GPIO,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(gpio_mode, NUC980GPIOState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void nuc980_gpio_init(Object *obj)
+{
+    NUC980GPIOState *s = NUC980_GPIO(obj);
+
+    memory_region_init_io(&s->mmio, obj, &nuc980_gpio_ops, s,
+                          TYPE_NUC980_GPIO, 0x34);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+}
+
+static void nuc980_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = nuc980_gpio_reset;
+    dc->vmsd = &vmstate_nuc980_gpio;
+}
+
+static const TypeInfo nuc980_gpio_info = {
+    .name          = TYPE_NUC980_GPIO,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(NUC980GPIOState),
+    .instance_init = nuc980_gpio_init,
+    .class_init    = nuc980_gpio_class_init,
+};
+
+static void nuc980_gpio_register_types(void)
+{
+    type_register_static(&nuc980_gpio_info);
+}
+
+type_init(nuc980_gpio_register_types)

6、修改include/hw/arm/nuc980.h,如下所示:

+号部分为新增加内容

diff --git a/include/hw/arm/nuc980.h b/include/hw/arm/nuc980.h
index 82e8aad2..4e34be38 100644
--- a/include/hw/arm/nuc980.h
+++ b/include/hw/arm/nuc980.h
@@ -19,6 +19,7 @@#include "hw/intc/nuc980_aic.h"#include "hw/char/nuc980_uart.h"#include "hw/timer/nuc980_timer.h"
+#include "hw/gpio/nuc980_gpio.h"#define SDRAM_BASE      0x0000000#define SDRAM_SIZE      (64 *1024 * 1024)
@@ -44,6 +45,15 @@#define TIMER5_BASE     0xb0052100#define TIMER_COUNT     6+#define GPIOA_BASE  0xb0004000
+#define GPIOB_BASE  0xb0004040
+#define GPIOC_BASE  0xb0004080
+#define GPIOD_BASE  0xb00040c0
+#define GPIOE_BASE  0xb0004100
+#define GPIOF_BASE  0xb0004140
+#define GPIOG_BASE  0xb0004180
+#define GPIO_COUNT  7
+#define AIC_BASE                0xb0042000#define TYPE_NUC980 "nuc980"
@@ -64,6 +74,7 @@ typedef struct NUC980State {NUC980UartState uart[UART_COUNT];NUC980AICState aic;NUC980TimerState timer[TIMER_COUNT];
+    NUC980GPIOState gpio[GPIO_COUNT];} NUC980State;

7、创建include/hw/gpio/nuc980_gpio.h,如下所示:

+号部分为新增加内容

new file mode 100644
index 00000000..66ead156
--- /dev/null
+++ b/include/hw/gpio/nuc980_gpio.h
@@ -0,0 +1,55 @@
+/*
+ * NUC980 SOC System emulation.
+ *
+ * Copyright (c) 2023- yanl1229@163.com.
+ * Written by yanl1229
+ *
+ * This code is licensed under the GPL.
+ */
+#ifndef NUC980_GPIO_H
+#define NUC980_GPIO_H
+
+#include "hw/sysbus.h"
+
+#define GPIO_MODE       0x00
+#define GPIO_DINOFF     0x04
+#define GPIO_DOUT       0x08
+#define GPIO_DATMSK     0x0c
+#define GPIO_PIN        0x10
+#define GPIO_DBEN       0x14
+#define GPIO_INTTYPE    0x18
+#define GPIO_INTEN      0x1c
+#define GPIO_INTSRC     0x20
+#define GPIO_SMTEN      0x24
+#define GPIO_SLEWCTL    0x28
+#define GPIO_PUSEL      0x30
+
+#define TYPE_NUC980_GPIO "nuc980-gpio"
+#define NUC980_GPIO(obj) \
+    OBJECT_CHECK(NUC980GPIOState, (obj), TYPE_NUC980_GPIO)
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+
+    uint32_t gpio_mode;
+    uint32_t gpio_dinoff;
+    uint32_t gpio_dout;
+    uint32_t gpio_datmsk;
+    uint32_t gpio_pin;
+    uint32_t gpio_dben;
+    uint32_t gpio_inttype;
+    uint32_t gpio_inten;
+    uint32_t gpio_intsrc;
+    uint32_t gpio_smten;
+    uint32_t gpio_slewctl;
+    uint32_t gpio_pusel;
+
+
+    qemu_irq irq;
+} NUC980GPIOState;
+
+#endif

总结

本文描述了980平台上GPIO控制器的实现,这里主要描述的是框架代码,因为qemu模拟不了硬件的电气特性,只能模拟寄存器功能,因此GPIO的模拟中,仅仅添加了寄存器读写功能。

工程链接

https://gitee.com/yanl1229/qemu.git

http://www.dtcms.com/a/499499.html

相关文章:

  • 外贸型企业网站建设开源商城源码
  • JS逆向-安全辅助项目Yakit热加载魔术方法模版插件语法JSRpc进阶调用接口联动
  • 使用IOT-Tree接入各种数据转BACnet模拟设备输出
  • 网站搭建说明北京海淀区是几环
  • 基于多模态AI技术的传统行业智能化升级路径研究——以开源AI大模型、AI智能名片与S2B2C商城小程序为例
  • 【C语言进阶】指针进阶_数组指针的使用,数组参数和指针参数
  • PySide6 控件插入日期时间(QDateTime)
  • 网站建设 jsp php垂直网站建设
  • 招商网站大全企业官方网站建设的流程
  • 征程 6 | 工具链如何支持 Matmul/Conv 双 int16 输入量化?
  • 【案例实战】鸿蒙分布式调度:跨设备协同实战
  • 中英文网站设计网站开发投标文件
  • Langgraph译文1:让AI自主决策的代理架构
  • 如何让百度能查到自己衡阳专业的关键词优化终报价
  • 为什么.NET的System.IO.Compression无法解压zlib流
  • 微信小程序:日常零售供应系统
  • 安卓如何查看settings是被哪个进程更新的?相关dumpsys命令剖析
  • 网络营销方式案例分析郑州网站优化推广
  • 下载软件太慢的加速操作
  • 网站改版技术要求git wordpress中文免费主题
  • 从应力到位移:混合模式分层损伤起始点推导
  • Gartner 2025年新兴技术成熟度曲线
  • HCIA DAY2
  • 【Go】--文件上传
  • 基于SpringBoot及PostgreSQL的国家减肥食谱管理项目(中):食谱与菜单配置搭建
  • 网站建设 需要准备材料安徽六安特产有哪些
  • Qt的QT_QPA_EGLFS_INTEGRATION环境变量浅解
  • ppt设计网站有哪些银行管理系统网站建设
  • 矽塔 SA8209 输入耐压36V 8A过流保护阈值 过压过流保护芯片 SOT23
  • 【Trae】如何使用Trae编译C++(附带MinGW)