FPGA基础 -- Verilog 验证平台之 **cocotb 验证 `阶乘计算模块(factorial)` 的例子**

发布于:2025-06-25 ⋅ 阅读:(20) ⋅ 点赞:(0)

一个完整的 cocotb 验证 阶乘计算模块(factorial) 的例子,涵盖:

  1. Verilog RTL 设计(组合/时序可选)
  2. cocotb Python 验证平台(含随机激励、断言、日志)
  3. 仿真运行说明(使用 iverilog + gtkwave

1. Verilog RTL:阶乘计算器(同步启动、串行计算)

// factorial.v
module factorial (
    input         clk,
    input         rst_n,
    input         start,
    input  [3:0]  n,         // 最大支持 15!(4位)
    output reg    done,
    output reg [31:0] result
);
    reg [3:0] i;
    reg [31:0] acc;
    reg busy;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            acc    <= 1;
            i      <= 0;
            busy   <= 0;
            done   <= 0;
            result <= 0;
        end else begin
            if (start && !busy) begin
                acc  <= 1;
                i    <= n;
                busy <= 1;
                done <= 0;
            end else if (busy) begin
                if (i > 1) begin
                    acc <= acc * i;
                    i   <= i - 1;
                end else begin
                    result <= acc;
                    busy   <= 0;
                    done   <= 1;
                end
            end else begin
                done <= 0;
            end
        end
    end
endmodule

2. cocotb 测试代码:测试随机 0~12 的阶乘

# test_factorial.py
import cocotb
from cocotb.triggers import RisingEdge, Timer
from cocotb.clock import Clock
import random
import math


@cocotb.test()
async def test_factorial(dut):
    """随机测试多组阶乘计算"""
    # 创建时钟 10ns 周期
    cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())

    # 初始化
    dut.rst_n.value = 0
    dut.start.value = 0
    dut.n.value = 0
    await RisingEdge(dut.clk)
    dut.rst_n.value = 1
    await RisingEdge(dut.clk)

    for trial in range(10):
        x = random.randint(0, 12)
        expected = math.factorial(x)

        # 启动计算
        dut.n.value = x
        dut.start.value = 1
        await RisingEdge(dut.clk)
        dut.start.value = 0

        # 等待 done
        for _ in range(50):
            await RisingEdge(dut.clk)
            if dut.done.value:
                break
        else:
            assert False, f"Timeout: DUT failed to complete for n={x}"

        got = dut.result.value.integer
        assert got == expected, f"Failed: {x}! = {got}, expected {expected}"
        dut._log.info(f"PASS: {x}! = {got}")

3. 仿真运行说明(以 Icarus Verilog + cocotb 为例)

文件结构

project/
├── factorial.v
├── test_factorial.py
├── Makefile

Makefile 示例(适配 Icarus)

TOPLEVEL_LANG = verilog
VERILOG_SOURCES = $(PWD)/factorial.v
TOPLEVEL = factorial
MODULE = test_factorial

SIM = icarus

include $(shell cocotb-config --makefiles)/Makefile.sim

4. 运行与结果

make

输出类似:

[INFO] cocotb.regression                         Test Passed: test_factorial
PASS: 5! = 120
PASS: 0! = 1
PASS: 7! = 5040
...

5. 优点总结(相比纯 Verilog TB)

项目 cocotb 测试优势
语言友好 使用 Python 写用例、随机测试、断言都非常简单
数学函数丰富 可直接调用 math.factorial 做黄金模型
日志与报错 assert + dut._log.info 提供直观日志
脚本化测试 易于与 GitLab CI / pytest 等整合

如需扩展:

  • 加入 边界值测试(如 n = 12、15)
  • 测试 非法输入行为(如 n > 15)
  • 加入 波形支持vcd 输出可通过 $dumpfile 查看

网站公告

今日签到

点亮在社区的每一天
去签到