Arm Ethos-U65 IP 集成、验证环境与仿真运行

Arm Ethos-U65 IP 集成、验证环境与仿真运行

本文是 Arm Ethos‑U65 学习与实践系列笔记的第三篇,从芯片设计与验证的角度,梳理该 NPU IP 的集成与功能验证流程。

集成

IP配置

U65包含两种MAC单元数 256 和 512 两种规格,需要在生成时通过配置文件指定。

打开 logical/config/ethosu65.yaml 配置文件进行配置,可以看到只有2个配置项,第1个是修改顶层 moudle 名称,保持注释就会使用默认名称;第2个是配置 MAC 单元数量,可以选256或512。

IP生成

然后在 logical 目录执行生成脚本,通过 -output 指定生成 rtl 的路径,整体生成流程比较简单。

./generate -config <yaml configuration file> -output <directory for configured RTL output>

然后在 output 路径会出现生成文件,其中 ethoseu65 前缀为设计文件,设计文件语言为system verilog,models路径为待替换的 ram 等模型,testbench 路径为验证环境。

验证

验证环境包含 execution_tb、ram_integration_tb和 integration_kit 三个目录,分别为APB读写、RAM读写和运算程序三个环境。下面会用 execution_tb 的验证环境 + integration_kit 的程序进行功能仿真。

验证环境

首先查看 execution_tb 路径,参照 README 可以直接执行 vcs 仿真,默认 dump 波形,需要自己再写一个 verdi 指令打开波形。

make compile SIM=vcs make run SIM=vcs TESTNAME=config_check

验证环境中将 IP 和 axi slave ram 模型 包成了一个小系统ethosu_exetb_wrapper,testbench 顶层只需要提供时钟、复位,就可以 通过 apb 配置 IP 工作。

环境中还包含 apb 读写方法和 memory 后门读写方法,memory 模型是按页划分的三维数组,最好简化修改一下,后续自己 readmemh 命令流和数据会方便一些。

task write_reg; input [APB_ADDR_WIDTH-1:0] address; input [APB_DATA_WIDTH-1:0] data; output error;
task read_reg; input [APB_ADDR_WIDTH-1:0] address; output [APB_DATA_WIDTH-1:0] data; output error;
task write_memory; input [48:0] address; input [3:0] wmask; input [31:0] wdata; input mark_as_written;
task read_memory; input [48:0] address; output [31:0] rdata; input mark_as_read;

环境包含 5 个 case,分别为 apb 读写和功耗评估 case,下图为 apb 写读写读波形,case 内容参考性一般,主要是借用 testbench 环境进行后续验证

验证用例

ram_integration_tb 路径下为存储访问,这里不再做参考,integration_kit 路径为 pooling、conv2d 等算子实现程序,下面进行说明。

integration_kit 路径实际是一个软件编译环境,环境下均为 c 程序,makefile.inc 中可以指定处理器为 M33 或 M55,然后通过 Makefile 编译出 axf 二进制文件。

环境运行首先需要 CMSIS,从 github 上下载再在 makefile.inc 里指定 CMSIS 路径即可(https://github.com/ARM-software/CMSIS_6)。

然后需要 Arm Compiler,linux 环境下没有 keil,剩余的方法就是安装 Arm Development Studio 或直接安装 Arm Compiler,Arm Compiler 可以用 DS 的 license。

最后执行 make all,可以看到编译出来的 test0~3,但由于本人没有 M33 系统仿真环境或实物测试环境,所以上述过程其实没什么用,哈哈。因为不编译也可以直接在 test 路径下查看几个 test 的 c 程序,然后转到 systemverilog 环境。其中 test0 是空程序,test1 是 pooling,test2 是带权重的点运算,test3 是不带 pad 的卷积,test4 是带 pad 的卷积。

仿真结果

integration_kit 路径下 tests/common/test_commands.h 中包含了 NPU 的配置流程,test0~4 的区别仅在命令流、输入数据、权重(有的 test 没有)不同,APB 配置基本是完全一样的。这里使用上述路径下的 test3 卷积case 的命令流,结合 execution_tb 路径的验证环境进行功能运算的仿真。

首先将配置程序从 c 转成 sv,在 ethosu65_exetb.sv 中加入配置,可以直接用环境附带的 apb 方法,配置中区域 0、1、2、3 的定义是由命令流决定的。

write_reg(NPU_REG_AXI_LIMIT0, 32'h0f0f0001, error); //AXI 0 接口配置 write_reg(NPU_REG_AXI_LIMIT1, 32'h0f0f0001, error); write_reg(NPU_REG_AXI_LIMIT2, 32'h0f0f0001, error); //AXI 1 接口配置 write_reg(NPU_REG_AXI_LIMIT3, 32'h0f0f0001, error); write_reg(NPU_REG_BASEP0, addr_weights, error); //区域0地址 权重 write_reg(NPU_REG_BASEP2, addr_scratch, error); //区域1地址 缓存数据 write_reg(NPU_REG_BASEP4, addr_data_in, error); //区域2地址 输入图像 write_reg(NPU_REG_BASEP6, addr_data_out, error); //区域3地址 输出图像 write_reg(NPU_REG_QBASE0, addr_cmd, error); //命令流地址 write_reg(NPU_REG_QSIZE, cmd_st.size(), error); //命令流大小 write_reg(NPU_REG_REGIONCFG, 32'h00000022, error); //指定区域AXI接口 read_reg(NPU_REG_CMD, read_val, error); write_reg(NPU_REG_CMD, read_val | 32'h00000001, error); //触发NPU工作

然后将命令流、权重、输入、输出数组从 c 转成 sv ,命令流数组 readmemh 到 QBASE0 地址;命令流中可以看到权重需要 readmemh 到区域0地址;输入数据(IFM)需要 $readmemh 到区域2地址;IP会将输出写到区域3地址,输出数组是用来结果比对的不用存。

从命令流中可以看到,会执行 conv2d 运算,不带 pad,输入尺寸 [1, 8, 16, 16],输出尺寸相同,然后拆成 2 个 block。波形和命令相符,哪个区域通过哪个 AXI 实现是由寄存器 REG_REGIONCFG 配置。