0 引言
与 YADAN Board 最配套的软核处理器是 基于 YADAN Core 的 YADAN SoC,它简洁优雅,是为学习设计 RISC-V 处理器的方法而设计的一款 SoC(虽然配套教程仍在编写中)。不过,除了跟随 YADAN 的配套教程学习之外,有的同学可能也想尝试在这块 FPGA 开发板中部署其他的软核处理器,比如 wujian100、蜂鸟 E203、Cortex-M0 等。
恰巧,我们曾有个案例是给 SparkRoad-V 开发板部署 Cortex-M0,YADAN Board 与 SparkRoad-V 搭载的 FPGA 同属于安路科技的 EG4S20 系列,两款 FPGA 有许多相似之处。假如我们想在 YADAN Board 上部署 Cortex-M0,可以直接参考当时的 EG4S20withM0 案例项目。本文将基于该案例,介绍如何在 YADAN Board 上部署 Cortex-M0。
后文将分为两部分:第一部分将介绍如何参考 EG4S20withM0 案例项目快速在 YADAN Board 上部署 Cortex-M0,并在 Keil MDK 中使用 C 语言开始编程;第二部分将介绍从 Arm 官网下载 Cortex-M0 的 HDL 源码之后,需要修改与增加哪些内容才能实现第一部分的操作,读者可通过此来概览源码的大致结构,以便挂载其他外设。
1 在 YADAN Board 上快速部署 Cortex-M0
1.1 部署 Cortex-M0
下载 EG4S20withM0 案例项目,可以看到里边的 M0
目录中有三个文件夹,它们的名字和概述分别是:
EG4S20withM0/M0
|
├─IPCore # Arm 官网下载到的 Cortex-M0 DesignStart Eval Package
|
├─MDK # 点亮 LED 的 Keil MDK 项目
|
└─prj # 在 SparkRoad-V 上部署 Cortex-M0 的 TD 项目
我们打开 prj
,可以发现里边的 RTL
文件夹内有许多 .v
的 Verilog HDL 文件,而 M0demo
文件夹内是 al_ip
、项目文件、引脚约束文件等其他一些文件。
YADAN Board 上的 FPGA 是 EG4S20NG88,而 SparkRoad-V 上的是 EG4S20BG256,它们支持的 PLL IP 是相同的,而项目文件是不一样的,引脚排布也是不一样的。所以,我们可以 保留 al_ip
文件夹,然后删除 prj
文件夹内的其他所有文件。(如果你想在其他 FPGA 上部署 Cortex-M0,可能也需要根据情况删除 al_ip
,然后修改成适配的 PLL IP)
打开安路科技的 TD 工具(4.6 版本 经测试可实现此文章中的操作,可在 安路官网 下载,其他版本暂未测试),创建一个适配 EG4S20NG88 器件的新项目,然后将 RTL
文件夹内的所有 .v
文件添加进项目,再将 prj/al_ip/M0clkpll.v
这个调用 PLL IP 的文件添加进项目,最后将 M0demo.v
设置为顶层模块。此时可在 Hierarchy Navigation 中看到如下图所示的层次结构。
创建引脚约束文件(例如取名为 M0demo.adc
),向其写入下列内容:
set_pin_assignment { NRST } { LOCATION = P51; }
set_pin_assignment { nTRST } { LOCATION = P50; }
set_pin_assignment { SWCLKTCK } { LOCATION = P13; }
set_pin_assignment { SWDIOTMS } { LOCATION = P12; }
set_pin_assignment { XTAL1 } { LOCATION = P34; }
set_pin_assignment { XTAL2 } { LOCATION = P86; }
set_pin_assignment { b_pad_gpio_porta[0] } { LOCATION = P23; }
将该文件添加进项目,该文件将 HDL 代码中定义的部分端口映射至了 FPGA 芯片上的实体引脚,例如最后一行是将 HDL 中定义的 b_pad_gpio_porta 中的 0 号端口映射至了 P23 号引脚,P23 号引脚在开发板上连接了 LED_23,便于观察效果。
最后,综合整个项目,生成比特流文件,烧写进开发板,即部署完成。
1.2 在 Keil MDK 中使用 C 语言开始编程
P12 和 P13 引脚被配置为 SWD 调试引脚,我们可以 使用支持 SWD 协议的调试器连接上这两个引脚,以便烧写与调试程序。
EG4S20withM0/M0
目录内还有一个文件夹叫做 MDK
,点开它,可发现有一 CM0_Hello.uvprojx
文件,直接双击它即可使用 Keil MDK 打开这个项目(如果没有安装 Keil MDK,可在 Arm 官网 下载)。
点击 Keil MDK 上方工具栏中的 Options for Target...
,打开目标设置页面。
在该页面中的 “debug” 选项卡中,选择你使用的调试器,然后点击 Settings
打开调试器设置页面。
在调试器设置页面中可以检查调试器通过 SWD 检测到的设备,如果之前的步骤均顺利完成,此处可以发现列有一个名为 ARM CoreSight SW-DP
的设备。
如果调试器能检测到这个设备,即可尝试 编译项目,然后将生成的文件烧写至 Cortex-M0,或者进入 debug 模式运行,观察 LED_23 的亮灭。
此时,你已经成功实现在 YADAN Board 上部署 Cortex-M0,并可以用 C 语言给其编写程序了。
2 如何实现的?
我们曾将给 SparkRoad-V 部署 Cortex-M0 的操作过程录制成了两个视频发在了 b 站上:BV1oE411d7XP、BV1YE411C7As,本节将以图文的形式介绍它大致包含了哪些步骤。
在 Arm 官网可以看到 Cortex-M0 的介绍,我们注册或登录 Arm 账号,然后可以在 Arm CPU Evaluation 中点击 Apply Now
申请下载 Cortex-M0 的 DesignStart Eval Package。
这个 Package 包含了可部署 Cortex-M0 的 Verilog 代码及若干介绍文档。
EG4S20withM0 案例项目 包含了这个 Package 中的下列文件,这些文件实现了 Cortex-M0 的一些基础组件:
RevC/SMM_M0DS/fpga_top/verilog/cmsdk_ahb_cs_rom_table.v
RevC/SMM_M0DS/fpga_top/verilog/cmsdk_mcu_addr_decode.v
RevC/SMM_M0DS/fpga_top/verilog/cmsdk_mcu_defs.v
RevC/SMM_M0DS/fpga_top/verilog/cmsdk_mcu_stclkctrl.v
RevC/SMM_M0DS/fpga_top/verilog/cmsdk_mcu_sysctrl.v
RevC/SMM_M0DS/fpga_top/verilog/cmsdk_mcu_system.v
RevC/SMM_M0DS/fpga_top/verilog/fpga_options_defs.v
systems/cortex_m0_mcu/verilog/cmsdk_clkreset.v
systems/cortex_m0_mcu/verilog/cmsdk_mcu_clkctrl.v
systems/cortex_m0_mcu/verilog/cmsdk_mcu_pin_mux.v
systems/cortex_m0_mcu/verilog/cmsdk_mcu.v
cores/cortexm0_designstart_r2p0/logical/cortexm0_integration/verilog/CORTEXM0INTEGRATION.v
cores/cortexm0_designstart_r2p0/logical/cortexm0_integration/verilog/cortexm0ds_logic.v
models/protocol_checkers/AhbLitePC/verilog/AhbLitePC.v
models/memories/cmsdk_ahb_memory_models_defs.v
models/memories/cmsdk_ahb_ram_beh.v
models/memories/cmsdk_ahb_rom.v
logical/cmsdk_ahb_bitband/verilog/cmsdk_ahb_bitband.v
logical/cmsdk_ahb_default_slave/verilog/cmsdk_ahb_default_slave.v
logical/cmsdk_ahb_master_mux/verilog/cmsdk_ahb_master_mux.v
logical/cmsdk_ahb_slave_mux/verilog/cmsdk_ahb_slave_mux.v
logical/cmsdk_ahb_to_apb/verilog/cmsdk_ahb_to_apb.v
logical/cmsdk_ahb_gpio/verilog/cmsdk_ahb_gpio.v
logical/cmsdk_ahb_gpio/verilog/cmsdk_ahb_to_iop.v
logical/cmsdk_apb_slave_mux/verilog/cmsdk_apb_slave_mux.v
logical/cmsdk_apb_subsystem/verilog/cmsdk_apb_subsystem_m0ds.v
logical/cmsdk_apb_uart/verilog/cmsdk_apb_uart.v
logical/cmsdk_iop_gpio/verilog/cmsdk_iop_gpio.v
项目中 gpio.v
、gpio_ctrl.v
、gpio_apbif.v
三个文件实现了与 GPIO 控制器相关的模块,AHB2MEM.v
实现了通过 AHB 总线访问片上存储器的模块。这些模块可以自行编写,也可以在各种开源托管网站寻找。此项目中的 GPIO 控制器是来源于平头哥以前开源的模块,AHB2MEM.v
是自行编写的。
接下来,为了让 Cortex-M0 能够访问片上存储器、开启 SWD 调试功能、访问 GPIO 控制器,当时的项目修改了以下文件:
- 在
cmsdk_mcu.v
中,添加 SWD 调试功能需连接的信号。将访存相关的模块修改为 AHB2MEM.v
中的模块。
- 在
cmsdk_mcu_system.v
中,添加 SWD 调试功能所需的信号,并在例化 cortex_m0_integration
模块时连接上这些信号。修改例化 cmsdk_apb_subsystem_m0ds
模块时传入的参数以配置启用的模块,并添加 GPIO 相关的信号。
- 在
cmsdk_apb_subsystem_m0ds.v
中,添加与 GPIO 及其中断相关的信号,例化 GPIO 模块,并将其接入 APB 总线。然后,在分配中断号的 apbsubsys_interrupt
中添加 GPIO 中断。
- 在
cmsdk_mcu_pin_mux.v
中,设置 GPIO 为单独输出功能,并注释所有对 P0 的拉高语句。
最后,用 TD 工具生成调用 PLL IP 的模块 M0clkpll.v
,再写个顶层文件 M0demo.v
就完成了。在 EG4S20withM0 的 GitHub 页面 中可以了解更多代码细节。