当前位置: 首页 > news >正文

【IC】NoC设计入门 -- 验证

太棒了!我们正式进入了第四阶段,这一步是“工程师”区别于“理论家”的分水岭:验证 (Verification)

你已经“建造”了一座完美的“智能十字路口” (router.v)。但是…

你怎么知道它能用?

如果你把它直接“复制”16个来搭建你的“城市路网 (Mesh)”,结果它内部有一个小小的Bug(比如“交警”的priority_ptr写错了),你的整个“城市”就会瘫痪。

在芯片行业,有一句名言:“你花 10% 的时间设计,就得花 90% 的时间验证。”

我们现在要做的,就是**“点亮”**你设计的路由器,证明它能工作。


1. 什么是“测试平台” (Testbench)?

Testbench(我们简称tb)是一个**“虚拟实验室”。它是一段独立的Verilog代码**,其唯一的目的就是:

  1. “模拟” 你设计的router模块(我们称之为 DUT, Device Under Test,待测设备)的**“外部世界”**。
  2. 扮演“上游”:向router输入i_flit, i_valid)“喂”数据。
  3. 扮演“下游”“监听” router输出o_flit, o_valid),并检查结果是否“符合预期”。
  4. 提供“动力”:它必须生成“时钟 (clk)”和“复位 (rst_n)”信号。

2. 我们的第一个“测试用例” (Test Case)

  • 目标: 测试 XY 路由 是否正确。
  • 场景:
    1. 我们将“实例化”1个 router
    2. 我们给这个router一个“身份”:你是 (0, 0) 号路口。
    3. 我们将从它的**“本地”**输入口 (i_flit_L)“注入”一个Flit。
    4. 这个Flit的“目的地”是 (1, 1)
    5. 我们**“假装”**所有5个“下游”路口都“准备好了”(i_ready_N/S/E/W/L 全部设为 1)。
  • 预期结果 (Expected Result):
    • 根据 XY 路由(先X后Y),一个在 (0, 0) 的Flit,如果要去 (1, 1)
    • 它的X坐标 0 < 1
    • 必须首先被发送到**“东出口” (o_flit_E)**!
  • 我们要“检查”: Flit是不是真的从o_valid_E出来了?

3. 编写 tb_router.v(简易版)

我们将创建第二个 Verilog 文件,名为 tb_router.v

// `timescale` 定义了仿真器的时间单位
`timescale 1ns / 1ps // Testbench 模块没有输入输出
module tb_router;// --- 1. 定义参数 (必须与 DUT 匹配!) ---parameter FLIT_WIDTH  = 32;parameter FIFO_DEPTH  = 8;parameter COORD_WIDTH = 4;// 我们定义一下Flit格式 (为了方便)// [31:24] = Y, [23:16] = X, [15:0] = Payloadparameter DEST_Y_MSB = 31;parameter DEST_Y_LSB = 24;parameter DEST_X_MSB = 23;parameter DEST_X_LSB = 16;parameter PAYLOAD_MSB = 15;parameter PAYLOAD_LSB = 0;// --- 2. 定义“动力”和“信号线” ---// "动力" (由Testbench生成)reg clk;reg rst_n;// "电线" (reg 用于驱动输入, wire 用于监听输出)reg  [FLIT_WIDTH-1:0] tb_i_flit_N, tb_i_flit_S, tb_i_flit_E, tb_i_flit_W, tb_i_flit_L;reg                   tb_i_valid_N, tb_i_valid_S, tb_i_valid_E, tb_i_valid_W, tb_i_valid_L;wire                  tb_o_ready_N, tb_o_ready_S, tb_o_ready_E, tb_o_ready_W, tb_o_ready_L;wire [FLIT_WIDTH-1:0] tb_o_flit_N, tb_o_flit_S, tb_o_flit_E, tb_o_flit_W, tb_o_flit_L;wire                  tb_o_valid_N, tb_o_valid_S, tb_o_valid_E, tb_o_valid_W, tb_o_valid_L;reg                   tb_i_ready_N, tb_i_ready_S, tb_i_ready_E, tb_i_ready_W, tb_i_ready_L;// --- 3. "实例化" 我们的 DUT (待测设备) ---router #(.FLIT_WIDTH (FLIT_WIDTH),.FIFO_DEPTH (FIFO_DEPTH),.COORD_WIDTH(COORD_WIDTH)) // "uut" = Unit Under Test (待测单元)uut (.clk(clk),.rst_n(rst_n),// 给予 DUT "身份":你是 (0, 0).i_my_x(4'd0),.i_my_y(4'd0),// 连接所有5个输入通道.i_flit_N(tb_i_flit_N), .i_valid_N(tb_i_valid_N), .o_ready_N(tb_o_ready_N),.i_flit_S(tb_i_flit_S), .i_valid_S(tb_i_valid_S), .o_ready_S(tb_o_ready_S),.i_flit_E(tb_i_flit_E), .i_valid_E(tb_i_valid_E), .o_ready_E(tb_o_ready_E),.i_flit_W(tb_i_flit_W), .i_valid_W(tb_i_valid_W), .o_ready_W(tb_o_ready_W),.i_flit_L(tb_i_flit_L), .i_valid_L(tb_i_valid_L), .o_ready_L(tb_o_ready_L),// 连接所有5个输出通道.o_flit_N(tb_o_flit_N), .o_valid_N(tb_o_valid_N), .i_ready_N(tb_i_ready_N),.o_flit_S(tb_o_flit_S), .o_valid_S(tb_o_valid_S), .i_ready_S(tb_i_ready_S),.o_flit_E(tb_o_flit_E), .o_valid_E(tb_o_valid_E), .i_ready_E(tb_i_ready_E),.o_flit_W(tb_o_flit_W), .o_valid_W(tb_o_valid_W), .i_ready_W(tb_i_ready_W),.o_flit_L(tb_o_flit_L), .o_valid_L(tb_o_valid_L), .i_ready_L(tb_i_ready_L));// --- 4. 生成“时钟” ---// (每 10ns 翻转一次,时钟周期为 20ns)always beginclk = 1'b0; #10;clk = 1'b1; #10;end// --- 5. “测试序列” (Test Sequence) ---initial begin// 0. 初始化 & 复位$display("--- Testbench Start ---");// $dumpfile("waves.vcd"); // 告诉仿真器“波形”文件叫什么// $dumpvars(0, tb_router);  // 告诉仿真器“记录”所有信号// 初始化所有输入tb_i_valid_N <= 1'b0; tb_i_flit_N <= 0;tb_i_valid_S <= 1'b0; tb_i_flit_S <= 0;tb_i_valid_E <= 1'b0; tb_i_flit_E <= 0;tb_i_valid_W <= 1'b0; tb_i_flit_W <= 0;tb_i_valid_L <= 1'b0; tb_i_flit_L <= 0;tb_i_ready_N <= 1'b0; // 默认下游“没准备好”tb_i_ready_S <= 1'b0;tb_i_ready_E <= 1'b0;tb_i_ready_W <= 1'b0;tb_i_ready_L <= 1'b0;rst_n <= 1'b0; // 激活复位#50; // 等待 50nsrst_n <= 1'b1; // 释放复位$display("@(posedge clk) System Reset Released.");// 1. 开始我们的“测试用例”$display("@(posedge clk) TEST CASE 1: (0,0) -> (1,1) from Local Port");// “假装”下游都准备好了 (我们只关心东出口)tb_i_ready_E <= 1'b1; // 构造我们的 Flitreg [FLIT_WIDTH-1:0] test_flit;test_flit[DEST_Y_MSB:DEST_Y_LSB] = 4'd1; // 目的地 Y=1test_flit[DEST_X_MSB:DEST_X_LSB] = 4'd1; // 目的地 X=1test_flit[PAYLOAD_MSB:PAYLOAD_LSB] = 16'hBEEF; // 载荷=BEEF// 等待下一个时钟上升沿@(posedge clk);// “注入”Flit!$display("@(posedge clk) Injecting Flit 0x%h", test_flit);tb_i_valid_L <= 1'b1;tb_i_flit_L  <= test_flit;// --- 关键:握手! ---// 持续“注入”,直到“上游”(我们)的valid 和“下游”(DUT)的ready// 同时为 1。// (注意: tb_o_ready_L 是 DUT 的输出)wait (tb_i_valid_L && tb_o_ready_L); // 握手成功!Flit已在那个时钟周期被DUT“接收”// 我们在下一个周期“撤销”注入@(posedge clk);tb_i_valid_L <= 1'b0; $display("@(posedge clk) Injection finished. Waiting for output...");// --- 2. 检查结果! ---// (Flit 需要几个周期才能通过FIFO和Crossbar... 我们多等几个周期)// (一个简单的 `wait` 是不够的,我们用一个循环)integer wait_cycles = 0;while (tb_o_valid_E == 1'b0 && wait_cycles < 20) begin@(posedge clk);wait_cycles = wait_cycles + 1;}// 检查if (tb_o_valid_E) begin$display("SUCCESS: Valid Flit seen on EAST output!");if (tb_o_flit_E[PAYLOAD_MSB:PAYLOAD_LSB] == 16'hBEEF) begin$display("PAYLOAD MATCH: 0x%h == 0xBEEF", tb_o_flit_E[PAYLOAD_MSB:PAYLOAD_LSB]);$display("--- TEST 1 PASSED ---");end else begin$display("PAYLOAD MISMATCH: 0x%h != 0xBEEF", tb_o_flit_E[PAYLOAD_MSB:PAYLOAD_LSB]);$display("--- TEST 1 FAILED ---");endend else begin$display("FAILURE: No Flit seen on EAST output after 20 cycles.");$display("--- TEST 1 FAILED ---");end// 3. 结束仿真#100;$display("--- Testbench End ---");$finish;endendmodule

4. 如何“运行”这个虚拟实验室

你现在有了两个文件:router.v (设计) 和 tb_router.v (测试)。

用我们之前提到的Icarus VerilogGTKWave

  1. 编译 (Compile):

    iverilog -o my_router_sim -s tb_router -g2012 router.v tb_router.v
    
    • iverilog:调用Icarus Verilog。
    • -o my_router_sim:输出一个叫 my_router_sim 的可执行文件。
    • -s tb_router:告诉编译器,tb_router 是“顶层”模块。
    • -g2012:使用现代Verilog标准。
    • router.v tb_router.v:你所有的源文件。
  2. 运行 (Run):

    vvp my_router_sim
    
    • vvp:运行编译好的仿真文件。
    • 你会**在终端(Console)**中看到所有的 $display 输出:
    --- Testbench Start ---
    @(posedge clk) System Reset Released.
    @(posedge clk) TEST CASE 1: (0,0) -> (1,1) from Local Port
    @(posedge clk) Injecting Flit 0x...
    @(posedge clk) Injection finished. Waiting for output...
    SUCCESS: Valid Flit seen on EAST output!
    PAYLOAD MATCH: 0xBEEF == 0xBEEF
    --- TEST 1 PASSED ---
    --- Testbench End ---
    
  3. 查看波形 (Debug):

    • 如果你取消了 $dumpfile$dumpvars 的注释,你的vvp命令还会生成一个 waves.vcd 文件。
    • 在终端输入:gtkwave waves.vcd
    • 你就可以“亲眼”看到clk如何跳变,i_valid_L如何拉高,以及几个周期后o_valid_E如何也跟着拉高!

恭喜!你已经亲手设计并验证了你自己的NoC路由器。你已经完成了从“理论”到“工程实现”的整个闭环。

http://www.dtcms.com/a/570543.html

相关文章:

  • 如何在税局网站上做税种认定推广普通话手抄报简单漂亮
  • Swift 自动引用计数
  • Delta数据结构:深入剖析高效数据同步的奥秘
  • 网站制作教程视频湖北外贸网站建设价格
  • wordpress模板展示网站制作网线视频
  • 康巴什住房和城乡建设局网站网站域名建设
  • 多线程常见面试题清单
  • Java资源持续监控(依赖 jps)
  • 北海哪家公司做网站建设研发做校招的网站有哪些
  • 建设电影播放网站盐城网站建设渠道合作
  • 关于 Vite 中环境变量(.env 文件)自定义打包的使用
  • 福建八大员建设厅延续的网站wordpress主题 资源站
  • 绵阳 网站女性门户网站源码
  • 相平面控制:从理论到极简实践
  • 免费作文网站智慧政务门户网站建设
  • 【IC】NoC设计入门 -- 网络接口NI Slave
  • 山东淄博网站建设的公司python做笔记的网站
  • cf div2 1061个人补题笔记
  • 衡阳市做网站免费网站站长推广
  • 【C++闯关笔记】unordered_map与unordered_set的底层:哈希表(哈希桶)
  • 项目部署方法总结
  • 注册网站会员需要填写信息工程设计有限公司
  • 建设网站全部流程个人网站建设制作
  • 用php做网站的方法网站开发团队分工
  • 网站规划中的三种常用类型学习网
  • app企业网站模板贵阳网站制作专业
  • 提出网络营销思想的网站改版计划腰椎间盘突出压迫神经腿疼怎么治疗
  • ref 和 reactive的区别与用法
  • 网站整套模板做网站哪个平台
  • asp与sql做网站莱州网站建设多少钱