Tock 在 OpenTitan 平台上的完整实战指南:CW310 FPGA、Verilator 仿真与 QEMU 运行
Tock 在 OpenTitan 平台上的完整实战指南:CW310 FPGA、Verilator 仿真与 QEMU 运行
OpenTitan 是 lowRISC 主导的开源项目,目标是打造透明、高质量、可复制的硅片信任根(Root of Trust,RoT)参考设计与集成规范。Tock 以安全嵌入式操作系统(Secure Embedded OS)的身份,将 OpenTitan 作为官方支持的目标平台之一:当前支持在 ChipWhisperer CW310 FPGA 开发板上运行,同时提供 Verilator 仿真与 QEMU 模拟两条无需硬件的开发路径。读完本文,你将掌握 Tock 在 OpenTitan 平台上的完整开发闭环:环境搭建与版本对齐、CW310 真机烧录、Verilator 仿真跑通、QEMU 快速验证、GDB 远程调试,以及内核单元测试的运行与判读。
本文以仓库 boards/opentitan/README.md 为主体,结合 earlgrey-cw310 板级目录 中的 Makefile、Cargo.toml、main.rs 与 tests 源码展开,所有命令均以当前仓库实际内容为准。
OpenTitan 与 Tock 的结合方式
OpenTitan 为信任根芯片提供开源参考实现,其第一颗芯片代号 EarlGrey(e300 系列 RISC-V SoC,核心为 Ibex RISC-V CPU)。Tock 将 OpenTitan 作为一个完整的板级平台进行支持,硬件目标为 ChipWhisperer CW310 FPGA 开发板。
Tock 对该平台的支撑涉及仓库内多个层次:
- 板级入口:boards/opentitan/earlgrey-cw310 下的
main.rs定义了EarlGrey平台结构,注册了 LED、GPIO、Console、Alarm、HMAC、I2C、SPI、RNG、AES、KV Store、低层调试(LLDB)等 syscall 驱动; - 芯片层:chips/earlgrey 提供 EarlGrey 外设寄存器实现,chips/lowrisc 提供 FlashCtrl、HMAC、CSRNG、SPI Host、AON Timer 等外设驱动;
- 架构层:使用 arch/rv32i 的 RISC-V 基础支持,包括 ePMP 内存保护与 trap 处理。
从 main.rs 可以看到,同一个板级 crate 通过 Cargo feature 区分目标平台,并直接影响时钟频率等关键参数:
fpga_cw310(默认):CPU 频率 24 MHz、外设频率 6 MHz、AON Timer 250 kHz、UART 波特率 115200;sim_verilator:CPU 频率 500 kHz、外设频率 125 kHz、AON Timer 125 kHz、UART 波特率 7200(仿真环境对速率做了降频处理)。
这一设计意味着:为 FPGA 编译的内核默认不适用于 Verilator,反之亦然,编译时必须显式指定 BOARD_CONFIGURATION。
支持的 OpenTitan 版本
OpenTitan 项目正在推进其首颗芯片 EarlGrey 的量产(tape-out)。由于 OpenTitan 代码库演进很快,Tock 只保证对特定版本的 OpenTitan 代码库做过验证,使用时应当使用与该版本对应的 FPGA bitstream 或仿真器构建产物。
Tock 当前支持的 OpenTitan 版本(commit SHA)定义在 earlgrey-cw310/Makefile 的 OPENTITAN_SUPPORTED_SHA 变量中:
OPENTITAN_SUPPORTED_SHA := edf5e35f5d50a5377641c90a315109a351de7635
Makefile 中的注释说明:该 commit 位于 earlgrey_es 分支,即 EarlGrey 首颗流片芯片对应的分支。
版本校验机制:ot-check 这个 make 目标会对比 OPENTITAN_TREE 指向的 OpenTitan 仓库当前 HEAD 与实际支持的 SHA。若不一致,构建会直接报错并提示你当前处于哪个版本(见 Makefile)。在跨版本开发或测试场景下,可以通过传参跳过这一检查:
make SKIP_OT_VERSION_CHECK=yes ...
一般建议用户从
OPENTITAN_SUPPORTED_SHA指定的 commit 开始使用,更新的版本未经测试,可能引入不兼容变化。
环境搭建:准备 OpenTitan 仓库
克隆与对齐版本
OpenTitan 官方文档提供了完整的入门指南(见 https://opentitan.org/book/doc/getting_started/index.html),以及非官方(unofficial)的依赖安装细节。快速步骤如下:
git clone https://github.com/lowRISC/opentitan.git
cd opentitan
# 使用 Tock 当前支持的 OpenTitan_SHA
git checkout <OpenTitan_SHA>
pip3 install --user -r python-requirements.txt
其中 <OpenTitan_SHA> 即上文提到的 OPENTITAN_SUPPORTED_SHA。后续所有 OpenTitan 构建命令(./bazelisk.sh ...)都在该仓库根目录执行。
构建 OpenTitan 工具链(opentitantool)
无论是烧录 FPGA 还是运行 Verilator 仿真,都需要 OpenTitan 的宿主工具 opentitantool。在 OpenTitan 仓库内构建:
./bazelisk.sh build //sw/host/opentitantool
如果构建过程报错,可能需要先建立系统符号链接(具体取决于发行版环境):
ln -s /usr/bin/ld.lld /usr/sbin/ld.lld
ln -s /usr/bin/gcc /usr/sbin/gcc
方案一:在 ChipWhisperer CW310 FPGA 上运行
CW310 是当前 Tock 支持 OpenTitan 的主要硬件平台。完整流程为:烧录 bitstream → 连接串口 → 编译 Tock → bootstrap 烧写。
1. 连接串口终端
先用第二个终端连接板载串口(注意:cs8,-ixon,-ixoff 为 Tock 控制台所需的 8 位数据位、禁用软件流控配置):
screen /dev/ttyACM1 115200,cs8,-ixon,-ixoff
2. 烧录 FPGA bitstream
./bazel-bin/sw/host/opentitantool/opentitantool.runfiles/lowrisc_opentitan/sw/host/opentitantool/opentitantool --interface=cw310 fpga load-bitstream lowrisc_systems_chip_earlgrey_cw310_0.1.bit.orig
烧录成功后,串口窗口应能看到 OpenTitan 的启动输出。对应的 bitstream 也可从 OpenTitan 发布的预编译包下载(earlgrey_es 分支的 bitstream-edf5e35f5d50a5377641c90a315109a351de7635.tar.gz)。
3. 导出 OpenTitan 树路径并编译烧写 Tock
在 Tock 的板级目录(tock/boards/opentitan/earlgrey-cw310)中,先将 OPENTITAN_TREE 指向 OpenTitan 仓库:
export OPENTITAN_TREE=/home/opentitan/
然后即可烧写内核或运行硬件测试:
make flash # 烧写内核到板子
make test-hardware # 在硬件上运行内核单元测试
make flash 实际执行的命令(见 Makefile)是调用 opentitantool 以 bootstrap 方式烧写 target/riscv32imc-unknown-none-elf/release/earlgrey-cw310.bin:
flash: $(TARGET_PATH)/release/$(PLATFORM).bin
$(OPENTITAN_TREE)/bazel-bin/sw/host/opentitantool/opentitantool.runfiles/lowrisc_opentitan/sw/host/opentitantool/opentitantool --interface=cw310 bootstrap $(TARGET_PATH)/release/$(PLATFORM).bin
注意 FLASHID=--dev-id="0403:6010"(Makefile)用于在存在多个 FTDI 设备时锁定目标板。
4. 编译目标架构说明
Tock 内核针对 RISC-V 32 位 IMC(rv32imc)目标编译,产物位于:
target/riscv32imc-unknown-none-elf/release/earlgrey-cw310.bin
板级 crate 名称为 earlgrey-cw310(见 Cargo.toml),默认 feature 为 fpga_cw310。链接脚本 layout.ld 定义了关键内存布局:
rom:0x20000000 起始,0x30000 长度(内核代码区,头部为 OpenTitan manifest);prog:0x20030000 起始,0x60000 长度(应用(app)映像区,支持至 0x2009_0000);fs:0x20090000 起始,0x70000 长度(flash 存储区,用于 TicKV 键值存储等);ram:0x10000650 起始(前 0x650 字节保留给 boot ROM),长度 0x20000 - 0x650。
同时,layout.ld 在 rom 起始处为 OpenTitan 的硅片引导程序(silicon creator)保留了 manifest 结构(RSA 签名、modulus、usage constraints、代码范围、入口点等),确保 Tock 内核满足 OpenTitan 的启动协议。
方案二:在 Verilator 仿真环境中运行
OpenTitan 同时支持 FPGA 与 Verilator 仿真两种运行方式,但不同平台需要略有差异的 EarlGrey 芯片实现,默认内核按 FPGA 编译。Verilator 仿真适合没有硬件、或需要在 CI 中自动化验证的场景。
1. 构建仿真所需目标
在 OpenTitan 仓库内,只构建本次需要的目标以节省时间;可用 --jobs x 指定并行线程数加速:
# 构建 test-ROM(测试引导 ROM)
./bazelisk.sh build //sw/device/lib/testing/test_rom:test_rom
# 构建 OTP(一次性可编程存储)镜像
./bazelisk.sh build //hw/ip/otp_ctrl/...
# 构建 FuseSOC / Verilator 仿真器
./bazelisk.sh build //hw:verilator
2. 验证 Verilator 环境
可自动构建相关目标并快速自测:
./bazelisk.sh test --test_output=streamed //sw/device/tests:uart_smoketest_sim_verilator
也可以手动运行仿真器。先用 test ROM 和 OTP 镜像初始化内存,再观察串口输出:
bazel-out/k8-fastbuild/bin/hw/build.verilator_real/sim-verilator/Vchip_sim_tb \
--meminit=rom,./bazel-out/k8-fastbuild-ST-97f470ee3b14/bin/sw/device/lib/testing/test_rom/test_rom_sim_verilator.scr.39.vmem \
--meminit=otp,./bazel-out/k8-fastbuild/bin/hw/ip/otp_ctrl/data/rma_image_verilator.vmem
# 从输出中找到 UART 伪终端地址,例如
# "UART: Created /dev/pts/4 for uart0. Connect to it with any terminal program, "
screen /dev/pts/4
# 等待数分钟
# 当看到 "Test ROM complete, jumping to flash!" 即表示 test ROM 运行正常
# (此时尚未提供 flash 镜像,因此流程到此为止)
看到 Test ROM complete, jumping to flash! 说明 OpenTitan 在 Verilator 上已就绪,可以继续加载 Tock 内核。
3. 编译并运行 Tock 内核(自动方式)
Tock 提供了 verilator make 目标,可自动完成「编译相关目标并启动 Verilator 仿真」:
make BOARD_CONFIGURATION=sim_verilator verilator
该目标(Makefile)内部做了这些事:
- 用
objcopy复制内核 ELF 为_verilator.elf(避免污染原始产物); - 若有
APP参数,将 app 的.appssection 链接进内核 ELF; - 将 ELF 转成二进制,再用
srec_cat生成 64 位 VMEM 文件(--byte-swap 8做字节序交换,--fill 0xff填充空白); - 调用 Verilator 仿真器,以
--meminit分别加载 test ROM、Tock 内核(flash0)与 OTP 镜像。
4. 编译并运行 Tock 内核(手动方式)
先手动编译 Verilator 版本内核:
make BOARD_CONFIGURATION=sim_verilator
然后在 Tock 仓库根目录生成 VMEM 文件(注意必须位于 TOP_DIR 执行):
srec_cat \
target/riscv32imc-unknown-none-elf/release/earlgrey-cw310.bin \
--binary --offset 0 --byte-swap 8 --fill 0xff \
-within target/riscv32imc-unknown-none-elf/release/earlgrey-cw310.bin\
-binary -range-pad 8 --output binary.64.vmem --vmem 64
最后启动 Verilator(内核通过 flash 内存初始化加载):
${OPENTITAN_TREE}/bazel-out/k8-fastbuild/bin/hw/build.verilator_real/sim-verilator/Vchip_sim_tb \
--meminit=rom,${OPENTITAN_TREE}/bazel-out/k8-fastbuild-ST-97f470ee3b14/bin/sw/device/lib/testing/test_rom/test_rom_sim_verilator.scr.39.vmem \
--meminit=flash,./binary.64.vmem \
--meminit=otp,${OPENTITAN_TREE}/bazel-out/k8-fastbuild/bin/hw/ip/otp_ctrl/data/rma_image_verilator.vmem
无论自动还是手动方式,Verilator 仿真都需要运行数十分钟量级才会有可见输出,属于正常现象。
在 Tock 中编程 App:flash-app 与 Verilator 加载
OpenTitan 的 Tock app 必须与内核打包进同一个二进制文件中烧写(app 采用 tree 外构建,即 app 单独编译,再链接进内核映像)。
1. 在硬件上烧写带 App 的内核
使用 flash-app make 目标,它会自动完成 app 的链接与烧写:
make flash-app APP=<...> OPENTITAN_TREE=/home/opentitan/
从 Makefile 看,该目标实际执行:
flash-app: $(TARGET_PATH)/release/$(PLATFORM).elf
$(RISC_PREFIX)-objcopy --set-section-flags .apps=LOAD,ALLOC $^ $(TARGET_PATH)/release/$(PLATFORM)-app.elf
$(RISC_PREFIX)-objcopy --update-section .apps=$(APP) $(TARGET_PATH)/release/$(PLATFORM)-app.elf
$(RISC_PREFIX)-objcopy --output-target=binary $(TARGET_PATH)/release/$(PLATFORM)-app.elf $(TARGET_PATH)/release/$(PLATFORM)-app.bin
$(OPENTITAN_TREE)/bazel-bin/sw/host/opentitantool/... --interface=cw310 bootstrap $(TARGET_PATH)/release/$(PLATFORM)-app.bin
即:将 app 的 .tbf(Tock Binary Format)文件写入内核 ELF 的 .apps section,再转换为二进制并通过 opentitantool bootstrap 烧写。
重要依赖:flash-app 需要 GCC 版本的 RISC-V 32 位 objcopy(如 riscv64-linux-gnu-objcopy,由 RISC_PREFIX 变量指定,默认 riscv64-linux-gnu),因为 LLVM 版本的 objcopy 不支持更新 section。
2. 在 Verilator 中加载单个 App
单个 .tbf app 可以通过 APP 参数与内核一起打包加载进 Verilator:
make APP=<...> BOARD_CONFIGURATION=sim_verilator verilator
3. Libtock-C App 的 Verilator 示例
以 libtock-c 的 c_hello 示例为例。先构建 app:
git clone https://github.com/tock/libtock-c.git
cd libtock-c/examples/c_hello/
make RISCV=1
然后进入 Tock 的板级目录加载并运行:
make APP=<PATH_TO_LIBTOCK-C>/examples/c_hello/build/rv32imc/rv32imc.0x20030080.0x10005000.tbf BOARD_CONFIGURATION=sim_verilator verilator
务必使用正确的 tbf 文件:rv32imc.0x20030080.0x10005000.tbf。文件名中的地址对应当前板子支持的 app flash 区域(0x20030080)与 RAM 区域(0x10005000),与 layout.ld 中 prog 区起始 0x20030000(加上 0x80 的 TBF header 偏移)及 ram 区 0x10000650 附近的布局一致。
启动 Verilator 后,从输出中找到伪终端端点(如 UART: Created /dev/pts/7 for uart0),连接即可看到内核与 app 的输出:
$ screen /dev/pts/7
.
...
OpenTitan initialisation complete. Entering main loop
Hello World!
OpenTitan initialisation complete. Entering main loop 这一行来自 main.rs 的 debug! 输出,标志着内核初始化完成并进入主循环。
在 QEMU 中运行(无需硬件)
QEMU 的 OpenTitan RISC-V 模拟是快速测试的捷径,也适合暂时没有 FPGA 开发板的开发者。但需要 QEMU 7.2——该版本在多数发行版仓库中尚未提供。Tock 可以自动为你构建 QEMU,在 Tock 源码根目录执行:
make ci-setup-qemu
按照提示完成构建后,即可使用 qemu make 目标启动内核:
make qemu
对应命令(Makefile)为:
$(QEMU) -M opentitan -kernel <elf> -nographic -serial mon:stdio \
-global driver=riscv.lowrisc.ibex.soc,property=resetvec,value=0x20000400
QEMU_ENTRY_POINT=0x20000400 是内核入口点,由链接脚本计算得出:ORIGIN(rom) + size_manifest = 0x20000000 + 0x400(见 Makefile 与 layout.ld 中 0x400 字节的 manifest 区)。通过 -global 将 Ibex SoC 的复位向量指向该地址,QEMU 才能从内核真实入口启动。
加载用户态 App
使用 qemu-app 目标,内核与 app 一并启动:
make APP=/path/to/app.tbf qemu-app
QEMU 通过 -device loader,file=$(APP),addr=0x20030000 将 app 加载到 flash 中的应用区(见 Makefile)。
app 必须针对 OpenTitan 板编译。例如从 libtock-rs 构建 console 示例:
cd "$libtock_rs_dir"
make opentitan EXAMPLE=console
cd "${tock_dir}/boards/opentitan/earlgrey-cw310"
make APP=$"{libtock_rs_dir}/target/tbf/opentitan/console.tbf" qemu-app
使用 GDB 调试 QEMU 中的内核与 App
QEMU 支持 GDB 远程调试,对定位特定内核或应用问题很有帮助。
1. 安装对应架构的 GDB
Arch Linux:
sudo pacman -S riscv32-elf-gdb
Ubuntu:
sudo apt-get install gdb-multiarch
2. 以挂起状态启动 QEMU
在板级目录下,QEMU 会以挂起(-S)状态启动并等待 GDB 连接:
make qemu-gdb
或带 app 启动(qemu-app-gdb):
make APP=/path/to/app.tbf qemu-app-gdb
对应目标在 Makefile 中加入了 -s -S 参数(-s 监听默认端口 1234,-S 启动即暂停)。
3. 连接 GDB
另开一个终端启动 GDB:
Arch:
$ riscv32-elf-gdb [/path/to/tock.elf]
> target remote:1234 #1234 是默认端口
Ubuntu:
$ gdb-multiarch [/path/to/tock.elf]
> set arch riscv
> target remote:1234 #1234 是默认端口
连接成功后即具备标准 GDB 能力。如需补充调试符号:
add-symbol-file <tock.elf>
add-symbol-file <app.elf>
内核单元测试
Tock 的 OpenTitan 板级目录内置了自动化单元测试,用于在 QEMU、Verilator 与真机上验证内核功能。
在 QEMU 上运行测试
make test
该目标(Makefile)使用 LINKER_SCRIPT_OVERRIDE=test_layout.ld 覆盖链接脚本,并通过 cargo test 将测试编入内核。测试框架在 main.rs 中实现:test_runner 先完成完整的 setup() 初始化,再顺序执行所有 #<a href="https://link.gitcode.com/i/c8c1e23fcc74c329ee8192795a36c60c" target="_blank">test_case] 测试,最后通过 RISC-V semihosting 命令以退出码 0 结束 QEMU(见 [tests/mod.rs)。
测试用例包括(tests/mod.rs):aes_test(AES-128 ECB/CBC/CTR/CCM/GCM)、csrng(熵源)、flash(Flash 控制)、hmac、multi_alarm(多 Alarm 并发)、otbn(OpenTitan 安全模块)、rsa 与 rsa_4096(RSA 硬件加速)、sha256soft_test(软件 SHA-256 capsule)、sip_hash、spi_host。
在硬件(CW310)上运行测试
硬件测试需要先构建 OTBN 二进制。注意:构建 rsa.elf 需要安装 Vivado 2020.2 Lab Edition(OpenTitan 文档有安装指南)。安装后先 source 环境脚本:
source <path_to_installation>/Xilinx/Vivado_Lab/2020.2/settings64.sh
然后在 OpenTitan 仓库内构建 OTBN RSA 二进制并打包为 Tock app:
cd "${OPENTITAN_TREE}"
# 构建 OTBN 二进制
./bazelisk.sh build //sw/device/tests:otbn_rsa_test
# 打包二进制为 Tock app
elf2tab --verbose -n "otbn-rsa" --kernel-minor 0 --kernel-major 2 --disable --app-heap 0 --kernel-heap 0 --stack 0 ./bazel-out/k8-fastbuild-ST-2cc462681f62/bin/sw/otbn/crypto/rsa.elf
# 在硬件上运行
cd "${tock_dir}/boards/opentitan/earlgrey-cw310"
make APP="${OPENTITAN_TREE}/bazel-out/sw/otbn/rsa.tbf" test-hardware
test-hardware 目标(Makefile)会先执行 ot-check 版本校验,再以 --features=hardware_tests 重新编译测试。只有启用 hardware_tests feature 时,部分依赖真实硬件的测试(如 AES ECB/CBC/CTR、RSA、OTBN)才会真正执行——例如 aes_test.rs 中 #[cfg(feature = "hardware_tests")] 块内的 t.run() 调用。
注意
test目标在设置了OPENTITAN_TREE时会直接报错并提示"Running on QEMU, use test-hardware to run on hardware"(见 Makefile),避免误在 QEMU 上执行硬件测试。
在 Verilator 上运行测试
将 OTBN 二进制打包为 app 后加载到 Verilator:
elf2tab --verbose -n "otbn-rsa" --kernel-minor 0 --kernel-major 2 --disable --app-heap 0 --kernel-heap 0 --stack 0 ./bazel-out/k8-fastbuild-ST-2cc462681f62/bin/sw/otbn/crypto/rsa.elf
make APP="${OPENTITAN_TREE}/bazel-out/k8-fastbuild-ST-2cc462681f62/bin/sw/otbn/crypto/rsa.tbf" BOARD_CONFIGURATION=sim_verilator test-verilator
对应目标(Makefile)以 --features=hardware_tests,sim_verilator 编译测试,并交由 run.sh 脚本完成 ELF→二进制→VMEM 转换与仿真器启动。run.sh 中通过 VERILATOR=yes 环境变量区分 Verilator 与真机流程。
测试输出解读
CW310 上运行硬件测试的典型输出如下(QEMU 上运行时会跳过 hardware_tests 相关的加密/OTBN 子测试,只保留可模拟的部分):
OpenTitan initialisation complete. Entering main loop
check run AES128 ECB...
aes_test passed (ECB Enc Src/Dst)
aes_test passed (ECB Dec Src/Dst)
aes_test passed (ECB Enc In-place)
aes_test passed (ECB Dec In-place)
[ok]
check run AES128 CBC...
aes_test passed (CBC Enc Src/Dst)
aes_test passed (CBC Dec Src/Dst)
aes_test passed (CBC Enc In-place)
aes_test passed (CBC Dec In-place)
[ok]
check run AES128 CTR...
aes_test CTR passed: (CTR Enc Ctr Src/Dst)
aes_test CTR passed: (CTR Dec Ctr Src/Dst)
[ok]
check run CSRNG Entropy 32...
Entropy32 test: first get Ok(())
Entropy test: obtained all 8 values. They are:
[00]: 11358ec6
[01]: cad739e8
[02]: 236b897e
[03]: 707c0162
[04]: 2627c579
[05]: 86b6562c
[06]: a8e0e4f8
[07]: 4b298bcd
[ok]
check hmac load binary...
[ok]
check hmac check verify...
[ok]
start multi alarm test...
[ok]
check otbn run binary...
[ok]
start TicKV append key test...
---Starting TicKV Tests---
Key: [18, 52, 86, 120, 154, 188, 222, 240] with value [16, 32, 48] was added
Now retrieving the key
Key: [18, 52, 86, 120, 154, 188, 222, 240] with value [16, 32, 48, 0] was retrieved
Removed Key: [18, 52, 86, 120, 154, 188, 222, 240]
Try to read removed key: [18, 52, 86, 120, 154, 188, 222, 240]
Unable to find key: [18, 52, 86, 120, 154, 188, 222, 240]
Let's start a garbage collection
Finished garbage collection
---Finished TicKV Tests---
[ok]
trivial assertion...
[ok]
从输出可以看出测试覆盖了:AES-128 三种模式(ECB/CBC/CTR,含就地与源/目的两种缓冲方式)、CSRNG 熵源、HMAC 加载与校验、多 Alarm 调度、OTBN 安全处理器、基于 TicKV 的 flash 键值存储(含追加、读取、删除、垃圾回收),以及最基本的 trivial assertion。TicKV 测试对应 main.rs 中基于 FlashCtrl + SipHash 构建的 TicKV 系统。
Verilator 上的测试同样可用:
make BOARD_CONFIGURATION=sim_verilator test-verilator
注意:Verilator 上的测试可能需要数小时才能完成,适合夜间或 CI 批量运行。
常见问题与调试要点
- 版本不匹配:
ot-check报错提示 OpenTitan 版本与OPENTITAN_SUPPORTED_SHA不一致时,要么 checkout 到目标 SHA,要么临时用SKIP_OT_VERSION_CHECK=yes跳过(跨版本开发时使用,不代表得到验证)。 - FPGA 与 Verilator 内核混用:默认编译目标为
fpga_cw310;Verilator 必须显式传BOARD_CONFIGURATION=sim_verilator,两者的时钟与 UART 波特率配置不同(见 main.rs)。 - VMEM 生成必须在 Tock 根目录:手动 Verilator 流程中
srec_cat的输出路径./binary.64.vmem相对于仓库根目录,请确认执行位置。 - Verilator 等待时间长:仿真输出需要数十分钟甚至数小时(测试场景),属正常现象,可通过
screen连接伪终端持续观察。 - objcopy 选择:
flash-app/Verilator 链接 app 需要 GCC 版 RISC-V objcopy,LLVM 版不支持 section 更新。 - QEMU 版本:需要 QEMU 7.2,优先用
make ci-setup-qemu由 Tock 自行构建,避免发行版版本过旧。
小结
Tock 对 OpenTitan 的支持形成了「真机(CW310 FPGA)— 仿真(Verilator)— 模拟(QEMU)」三级开发与验证体系:真机用于最终验证与硬件测试(含 OTBN/RSA 等硬件加速单元),Verilator 用于无硬件条件下的内核与 app 联调,QEMU 用于秒级启动的快速迭代与 CI 测试。三者的编译差异集中在 BOARD_CONFIGURATION feature 与链接脚本选择上,理解 Makefile 中的目标(flash、flash-app、verilator、qemu、qemu-gdb、test、test-hardware、test-verilator)即可自由切换。结合 layout.ld 的内存分区与 main.rs 的平台初始化代码,开发者可以在此基础上进一步移植驱动、扩充 capsule 或编写面向信任根场景的应用。