RISC-V ACT测试

下面我按 "目标 → 输入物 → 流程阶段 → 关键文件/工具 → 结果闭环" 来梳理一遍:
RISC-V ACT 测试中,基于 RTL + VCS + 人工定义 cover point 的完整流程

场景本质上是:

用 ACT 测试程序去跑 RTL 仿真,借助人工定义的 cover point 来评估"架构点是否被覆盖到"。

这和普通功能仿真不完全一样,重点在于:

  • 测试程序来自 ACT/arch-test/自研 case
  • DUT 是 RTL
  • 仿真工具是 VCS
  • coverage 目标不是简单代码覆盖,而是架构覆盖点
  • cover point 往往需要人工建模


一、先说整体流程图

可以先记成这 8 步:

  1. 确定验证范围
  2. 拆解架构需求,人工定义 cover point
  3. 建立 cover point 到 test plan / spec 的映射
  4. 准备测试程序(ACT case)
  5. 搭建 RTL 仿真环境(VCS)
  6. 在 testbench / monitor 中采集事件并打点 cover point
  7. 运行回归,生成 coverage 结果
  8. 分析 coverage hole,补 test / 补 cover point / 补 checker

一句话:

spec → cover point → test case → RTL 仿真 → coverage 采集 → gap 分析 → 迭代补齐


二、流程的输入是什么

通常有 4 类输入:


1. 架构规范 / 设计规格

例如:

  • RISC-V Unprivileged Spec
  • Privileged Spec
  • 扩展 spec(A/M/F/D/C/V/Zicsr/Zifencei/AIA/CLIC 等)
  • 内部微架构约束文档
  • 平台中断/CSR/PMP/MMU 设计文档

这是 cover point 的来源根基。


2. DUT RTL

即:

  • CPU core RTL
  • SoC RTL(如果 ACT 跑在 SoC 级)
  • 中断控制器 / memory subsystem / CSR block

3. ACT 测试程序

测试来源可能是:

  • riscv-arch-test
  • riscv-ctg 生成
  • riscv-isac coverage 驱动生成
  • 自研 directed case
  • 随机 test + signature check

4. 仿真环境

包括:

  • testbench
  • memory model
  • bus model
  • interrupt model
  • reference monitor / scoreboard
  • VCS compile/run 脚本

三、第一步:确定验证范围

这一步最重要,因为你不可能一开始就"全 ISA 全覆盖"。

要先划定本轮 ACT 想覆盖的范围,例如:

  • RV64I 基础指令
  • M/S/U privilege
  • CSR 访问
  • trap/interrupt
  • PMP
  • MMU(Sv39)
  • AIA / CLIC(如果实现)
  • 原子指令 A 扩展

然后对每个模块定义:

  • 测哪些 feature
  • 不测哪些 feature
  • 哪些配置适用
  • 哪些是 N/A

这一步产出通常是:

  • feature list
  • verification scope
  • test plan 初稿

四、第二步:人工定义 cover point

这一步是核心。

因为你说的是:

cover point 需要人工定义

那本质就是要把 spec requirement 拆成可观测的验证点


4.1 cover point 的来源

常见来源有:

指令语义

例如:

  • ADD 正常结果
  • SUB 边界值
  • JALR 强制清 bit0
  • DIV 除零行为

CSR 行为

例如:

  • M 模式可写 mstatus
  • U 模式访问 trap
  • 只读位写入忽略
  • WARL/WPRI 规则

异常/中断

例如:

  • illegal instruction trap
  • ecall from U/S/M
  • mtip pending and taken
  • mepc 保存正确
  • mret 恢复正确

地址/边界

例如:

  • misaligned load/store
  • page boundary crossing
  • PMP TOR 边界
  • satp mode 切换

配置条件

例如:

  • RV32 / RV64
  • extension present / absent
  • delegated trap / non-delegated trap

4.2 cover point 怎么写

建议统一命名:

功能对象 + 条件 + 预期行为

例如:

  • instr_add_basic
  • instr_jalr_lsb_clear
  • csr_mstatus_rw_m_mode
  • csr_mstatus_access_u_mode_trap
  • trap_illegal_instruction_taken
  • interrupt_mtimer_taken
  • mret_restore_mstatus_mie
  • pmp_tor_read_fault

4.3 cover point 的粒度

不要太粗,也不要太碎。

太粗的坏处

比如:

  • csr_test_done
    这没有意义,不知道到底覆盖了什么。

太碎的坏处

比如把一条指令每个位级效果都拆成几十个点,维护会爆炸。

一般建议粒度是:

  • 一条架构要求 = 一个或少量 cover point
  • 一个 cover point 必须能通过仿真观测到

五、第三步:建立 cover point 与 spec/testplan 的映射

这一步建议强制做。

做一张表:

Spec条目 Feature Cover Point Test Case 观测方式 适用配置
Priv Spec x.x mtimer interrupt interrupt_mtimer_taken mtimer_basic.S trap monitor M-mode
Priv Spec x.x mret restore MIE mret_restore_mie mret_restore.S CSR sample M-mode
Unpriv Spec x.x JALR clears bit0 instr_jalr_lsb_clear jalr_align.S PC monitor RV32/RV64

这样后面 coverage hole 才能追到 spec。


六、第四步:准备测试程序

这一步就是把 ACT case 准备好,并能在 RTL 上跑起来。

来源可能有:


6.1 官方/标准 arch-test

如 riscv-arch-test 提供的:

  • rv64i
  • m
  • privileged
    等 case

优点:

  • 标准化
  • 易比对

缺点:

  • 对你自定义 cover point 未必够细

6.2 自研 directed test

当官方 ACT 覆盖不到某些点时,需要自己加:

例如:

  • 特定 trap delegation 场景
  • 中断嵌套
  • PMP 边界
  • WARL 特殊值
  • AIA/CLIC 实现特性

6.3 生成类测试

如果你有 riscv-ctg / 随机约束生成器,也可以根据 cover point 反向生成测试。


6.4 测试编译

测试程序通常流程是:

  • .S/.c → gcc/clang → elf
  • objcopy → bin/hex
  • load 到 memory model 中

七、第五步:搭建 RTL + VCS 仿真环境

这一步是让 case 真正跑在 RTL 上。


7.1 编译 RTL

VCS compile 典型包括:

  • DUT RTL
  • testbench
  • monitors
  • checkers
  • coverage model
  • DPI/PLI(如果有)

例如:

bash 复制代码
vcs -full64 -sverilog \
    -f filelist.f \
    -cm line+cond+fsm+tgl+branch \
    -debug_access+all \
    -l compile.log

注意:

  • 这里 -cm ... 是代码覆盖率,不等于架构 cover point
  • 架构 cover point 还需要你在 SV/UVM/testbench 里定义 covergroup / coverpoint

7.2 装载测试程序

一般会:

  • $readmemh
  • 或 bootrom model
  • 或 DPI loader
  • 把 elf/bin 装到 instruction/data memory

7.3 驱动环境

testbench 还要负责:

  • clock/reset
  • 中断注入
  • MMIO 响应
  • timer 驱动
  • 外设 stub

特别是中断/异常类 ACT,没有这些环境根本跑不起来。


八、第六步:在 testbench / monitor 中采集 cover point

这是你关心的重点:
人工定义的 cover point 怎么真正落在仿真里。

通常有 3 种方式。


8.1 用 SystemVerilog covergroup / coverpoint

这是最常见的方式。

例如你想统计 trap cause:

systemverilog 复制代码
covergroup cg_trap @(posedge clk);
  cp_trap_taken: coverpoint trap_valid;
  cp_mcause: coverpoint mcause iff (trap_valid) {
    bins illegal_instr = {2};
    bins breakpoint    = {3};
    bins ecall_u       = {8};
    bins ecall_m       = {11};
  }
endgroup

如果是中断:

systemverilog 复制代码
covergroup cg_interrupt @(posedge clk);
  cp_irq_taken: coverpoint irq_taken;
  cp_irq_cause: coverpoint irq_cause iff (irq_taken) {
    bins msoft  = {3};
    bins mtimer = {7};
    bins mext   = {11};
  }
endgroup

这样 VCS/URG 可以直接统计。


8.2 用 monitor + 事件打点

有些架构点不容易直接用 covergroup 表达,就先在 monitor 中提取事件。

例如:

  • 指令 retire monitor
  • CSR access monitor
  • trap monitor
  • interrupt monitor
  • PMP fault monitor

监测到事件后:

  • 触发 covergroup sample()
  • 或手动写日志
  • 或写数据库

示例:

systemverilog 复制代码
if (retire_valid && instr_is_jalr) begin
    jalr_target_lsb = retire_pc_next[0];
    cg_jalr.sample();
end

8.3 用 reference model / trace 对比后再打点

更高阶一点的方法是:

  • 先抓 instruction trace / CSR trace
  • 和 ISS/reference model 对比
  • 当某个场景确认成立时,再记 cover point hit

这种方式适合复杂语义点,但实现成本更高。


九、第七步:如何定义 cover point 的"观测信号"

人工定义 cover point 后,必须明确:

它到底靠什么信号判定命中?

通常来源有:


9.1 提交级(retire)信号

适合看:

  • 指令是否执行
  • 执行结果
  • rd 写回
  • PC 跳转
  • trap 前 faulting instruction

9.2 CSR 读写事件

适合看:

  • CSR access
  • privilege violation
  • 返回状态恢复
  • mtvec/mstatus/mie/mip

9.3 trap/interrupt 事件

适合看:

  • trap taken
  • cause
  • delegation
  • mepc/sepc
  • mtval/stval

9.4 memory/bus 事件

适合看:

  • load/store misalign
  • page fault
  • access fault
  • PMA/PMP fault

9.5 外部环境事件

适合看:

  • timer interrupt asserted
  • external interrupt pending
  • software interrupt injected

十、第八步:跑回归

回归本质上是:

  • 批量编译测试
  • 批量加载到 RTL
  • 批量运行 VCS
  • 收集 pass/fail
  • 收集 coverage database

典型流程:

bash 复制代码
for test in test_list:
    build_test(test)
    run_vcs_sim(test)
    collect_log(test)
    merge_cov()

如果使用 VCS coverage:

  • 每个 test 会生成 simv.vdb
  • 最后用 urg 合并

例如:

bash 复制代码
urg -dir test1.vdb test2.vdb test3.vdb -report urgReport

十一、第九步:查看 coverage 结果

这里有两种 coverage 要区分:


11.1 RTL 代码覆盖率

VCS 自带:

  • line
  • branch
  • cond
  • toggle
  • fsm

这回答的是:

RTL 代码有没有被跑到

但它不能直接回答:

架构 spec 有没有被覆盖到


11.2 架构 cover point 覆盖率

这是你人工定义的那些:

  • instruction semantic coverpoint
  • trap coverpoint
  • CSR privilege coverpoint
  • interrupt coverpoint

这才是 ACT 更关心的。

所以最后报告一般要同时看:

  • test pass/fail
  • functional coverage(架构 cover point)
  • code coverage(辅助)

十二、第十步:coverage hole 分析

这是闭环最重要的一步。

一个 cover point 没 hit,常见有几种原因:


12.1 测试没覆盖到

需要补新的 ACT case

例如:

  • 没有 case 触发 ecall from S
  • 没有 case 触发 mtimer interrupt when mie=1

12.2 cover point 定义不对

例如:

  • 观测条件写错
  • sample 时机不对
  • 取错信号
  • trap 与 retire 同周期关系处理错了

12.3 DUT 功能有 bug

例如:

  • 测试明明应该 hit,但一直没 hit
  • log 显示中断没进
  • mcause 错了

12.4 配置不适用

例如:

  • DUT 没实现 S mode
  • 却定义了 sepc_write 的 cover point

这种点要标记为 N/A。


十三、建议的实际工程文件结构

建议类似这样组织:

text 复制代码
act_verif/
├── spec/
│   └── feature_list.xlsx
├── testplan/
│   └── act_coverpoint_map.xlsx
├── tests/
│   ├── rv64i/
│   ├── csr/
│   ├── trap/
│   └── interrupt/
├── rtl/
├── tb/
│   ├── monitors/
│   ├── checkers/
│   ├── covergroups/
│   └── env/
├── sim/
│   ├── vcs_compile.sh
│   ├── run_regress.py
│   └── urg_merge.sh
└── reports/
    ├── pass_fail/
    ├── code_cov/
    └── func_cov/

十四、推荐的 cover point 分层方法

建议把 cover point 分层,不然会很乱。


层 1:指令执行覆盖

  • 每类指令是否执行
  • 特殊语义是否触发
  • 边界值是否覆盖

层 2:CSR/权限覆盖

  • 哪些 CSR 访问成功
  • 哪些非法访问 trap
  • side effect 是否出现

层 3:trap/exception 覆盖

  • 所有 trap cause
  • delegation
  • return path

层 4:interrupt 覆盖

  • software/timer/external
  • mask/unmask
  • pending/taken
  • nested(若支持)

层 5:地址/保护机制覆盖

  • PMP/MMU/page fault/access fault/misaligned

十五、一个中断类 cover point 示例

假设你要测 machine timer interrupt,可以定义:

cover point 列表

  • mtip_pending_asserted
  • mie_mtie_enabled
  • mstatus_mie_enabled
  • mtimer_interrupt_taken
  • mcause_mtimer
  • mepc_saved_before_trap
  • mtvec_entry_correct
  • mret_restore_pc
  • interrupt_masked_when_mie_zero

观测方式

  • monitor mtime/mtimecmp
  • monitor mip.mtip
  • monitor mie.mtie
  • monitor trap valid + mcause
  • monitor CSR before/after trap
  • monitor return PC after mret

然后用 covergroup 表达。


十六、一个最小可执行流程总结

如果你现在要马上落地,我建议最小闭环按这个来:


Step 1

选一个小范围,比如:

  • RV64I + CSR + machine trap + machine interrupt

Step 2

列出 30~50 个 cover point

Step 3

为每个 cover point 指定:

  • 观测信号
  • 对应 test case
  • 配置条件

Step 4

在 VCS testbench 里写:

  • retire monitor
  • trap monitor
  • csr monitor
  • interrupt monitor
  • covergroup

Step 5

跑 ACT case 到 RTL

Step 6

用 URG 出 coverage report

Step 7

分析未覆盖点:

  • 补测试
  • 修 covergroup
  • 抓 bug

十七、一句话总结

RISC-V ACT 下基于 RTL+VCS 的 cover point 流程,本质上是:先从 spec 人工拆出架构覆盖点,再把这些覆盖点映射到测试和可观测 RTL 事件上,通过 testbench monitor + SystemVerilog covergroup 在 VCS 仿真中采集覆盖,最后结合 ACT 测试结果和 coverage report 做闭环分析。


下一步可以直接落地的东西:

  1. 一个 ACT 中断/CSR/trap 的 cover point Excel 模板
  2. 一个 VCS/SystemVerilog covergroup 示例框架
  3. 一个"spec → cover point → test case → monitor signal"映射表示例

如果你现在就是要开工,我最建议我下一步直接给你:
"一套可直接使用的的 RISC-V ACT cover point 模板(含 interrupt/trap/CSR)"

相关推荐
yusur2 小时前
开芯院院长唐丹一行来访中科驭数 共探RISC-V与DPU算力协同创新之路
risc-v
加强洁西卡2 小时前
【RISC-V】RVV选摘
risc-v
加强洁西卡1 天前
【RISC-V】fclass数值类型对照表
risc-v
国科安芯2 天前
空间辐射环境下电机伺服系统的抗扰动控制:AS32S601 抗辐射 MCU 在航天机电执行机构中的多场景应用与可靠性评估
单片机·嵌入式硬件·mcu·cocos2d·risc-v
国科安芯2 天前
AS32S601 抗辐射 MCU 在星载高速光通信链路的集成设计与性能验证
网络·单片机·嵌入式硬件·risc-v·安全性测试
国科安芯2 天前
抗辐射 MCU 赋能商业航天电源系统:基于 AS32S601 的高可靠能量管理控制器设计与辐照验证
stm32·单片机·嵌入式硬件·mcu·risc-v·空间计算
硬汉嵌入式5 天前
实现H7-TOOL脱机烧录沁恒RISC-V内核单线模式的CH32V003,至此单线和双线模式都支持了
risc-v·ch32v003·h7-tool·脱机烧录·1拖4脱机烧录·1拖16脱机烧录·ch32v20x
嵌入式小企鹅6 天前
国产算力突破、RISC-V车规生态成型、AI编程工具免费化浪潮
学习·开源·ai编程·risc-v·昇腾·deepseek v4
sinovoip14 天前
香蕉派开源社区联合进迭进空重磅打造: BPI‑SM10(K3-Com260) 和 K3 Pico‑ITX 计算机将于5月11日全球发货
人工智能·开源·risc-v