26.【Verilog】Verilog 其他系统任务
第一步分析与整理Verilog 其他系统任务1. 仿真控制$finish,$stop系统任务调用格式描述结束仿真$finish(type);终止仿真。type0不打印任何信息type1打印仿真时间和所在行type2额外打印存储器、CPU时间使用情况。暂停仿真$stop(type);暂停仿真类似断点可继续运行。用法同$finish。区别$finish永久结束$stop可恢复。示例initial begin forever begin #100; if ($time 10000) $finish(0); // 或 1, 2 end end2. 时间格式控制$printtimescale,$timeformat$printtimescale(hierarchy);打印指定模块的时间单位和精度。hierarchy省略则打印当前模块。$timeformat(unit_num, precision_num, suffix_string, min_field_width);设置%t格式输出的时间样式。unit_num时间单位0~-15对应秒到飞秒见表格。precision_num小数位数。suffix_string后缀如ns。min_field_width最小字符宽度。示例initial begin #10; $timeformat(-12, 5, my-ps, 15); // 单位 ps5位小数 end initial begin #5; $printtimescale(); $display(Time before resetup: %t, $time); #10; $printtimescale(); $display(Time after resetup: %t, $time); end3. 仿真时间获取$time,$stime,$realtime任务返回值类型说明$time64位整数按当前时间精度四舍五入$stime32位整数同上但仅低32位$realtime实数精确的时间值不四舍五入示例initial begin #10; $display($time: %t, $time); // 四舍五入 #3.2; $display($realtime: %t, $realtime); // 精确 end4. 命令行传参$test$plusargs,$value$plusargs$test$plusargs(str)检查命令行是否包含str返回1/0。$value$plusargs(format_str, var)从命令行读取数值到变量var格式format_str如INFO_SEL%b。返回值1/0。示例initial begin if ($test$plusargs(DISPLAY_CTRL)) $display(Display simulation information!!!); end reg [1:0] display_sel; initial begin if ($value$plusargs(INFO_SEL%b, display_sel)) $display(Parameter transfer succeeds!!!); else display_sel 2b0; end // 命令行添加DISPLAY_CTRL INFO_SEL01第二步费曼教学法 – 通俗讲解其他系统任务今天讲的是 Verilog 中“杂七杂八但超级有用的系统任务”控制仿真停止、设置时间显示格式、读取命令行参数等。这些任务让你的 testbench 更灵活、更专业。一、仿真停止与暂停$finish和$stop$finish就像关掉电源。仿真彻底结束不能再继续。0/1/2决定了“关电源时是否响警报”。$stop就像按了下“暂停键”仿真暂停但你可以再按“运行”继续。非常适合在出错时停下来交互调试。工作中一般用$finish结束正常仿真用$stop结合断点调试。二、时间格式控制$printtimescale和$timeformat$printtimescale就像问“现在用的时间刻度是多少”它会打印出当前模块的timescale单位和精度。$timeformat可以重新设置%t输出的格式。例如你想以皮秒为单位显示加后缀ps设置小数位数。为什么需要不同模块可能有不同的timescale统一输出格式有利于日志分析。三、获取仿真时间$time,$stime,$realtime$time和$stime是整数会按当前精度四舍五入。例如精度 1ns时间 3.2ns →$time 3。$realtime返回实数保留小数精确。使用场景需要精确计算时间间隔时用$realtime仅需整数周期数用$time。四、命令行传参$test$plusargs和$value$plusargs这是最强大的调试技巧之一。你可以在不修改代码的情况下通过命令行改变仿真行为。$test$plusargs(DEBUG)检查是否加了DEBUG参数。常用于开关详细打印。$value$plusargs(BURST_LEN%d, len)从命令行读取数值BURST_LEN16赋给len。好处同一个 testbench 可以运行不同配置无需重新编译非常适合回归测试。第三步详解示例 – 使用命令行参数控制仿真模式下面构造一个完整示例一个 testbench 用于测试一个 FIFO。通过命令行参数选择不同的测试模式随机读写、满压力、空压力和数据包数量。代码timescale1ns/1ps module tb_fifo_plusargs;reg clk;reg rstn;reg wr_en,rd_en;reg[7:0]wr_data;wire[7:0]rd_data;wire full,empty;// 实例化 FIFO (假设深度16)fifo_simpleu_fifo(.clk(clk),.rstn(rstn),.wr_en(wr_en),.wr_data(wr_data),.rd_en(rd_en),.rd_data(rd_data),.full(full),.empty(empty));// 时钟initial clk0;always #5clk~clk;// 通过命令行参数选择测试模式和数据量integer test_mode;// 0: random, 1: stress_full, 2: stress_emptyinteger num_packets;// 数据包数量integer seed;initial begin// 读取测试模式默认0if(!$value$plusargs(MODE%d,test_mode))test_mode0;// 读取数据包数量默认100if(!$value$plusargs(NUM%d,num_packets))num_packets100;// 读取随机种子默认12345if(!$value$plusargs(SEED%d,seed))seed12345;$display(Simulation config: MODE%0d, NUM%0d, SEED%0d,test_mode,num_packets,seed);// 设置随机种子$srandom(seed);// 复位rstn0;repeat(10)(posedge clk);rstn1;(posedge clk);// 根据不同模式执行测试case(test_mode)0:random_test(num_packets);1:stress_full_test(num_packets);2:stress_empty_test(num_packets);default:$display(Unknown mode, exit);endcase $finish(0);end taskrandom_test(intnum);integer i;$display(Starting random test with %0d transactions,num);for(i0;inum;i)begin wr_en$random%2;rd_en$random%2;if(wr_en!full)wr_data$random;(posedge clk);end endtask taskstress_full_test(intnum);integer i;$display(Stress full test: writing until full, then reading);// 连续写直到满while(!fullinum)begin wr_en1;rd_en0;wr_datai[7:0];(posedge clk);i;end// 连续读直到空while(!empty)begin wr_en0;rd_en1;(posedge clk);end endtask taskstress_empty_test(intnum);// 类似 stress_full_test先写后读但侧重读空$display(Stress empty test);// 写 num 个数据repeat(num)begin wr_en1;rd_en0;wr_data$random;(posedge clk);end// 读完while(!empty)begin wr_en0;rd_en1;(posedge clk);end endtask// 可选通过 $test$plusargs 控制是否打印详细波形initial beginif($test$plusargs(DEBUG))begin $display(Debug mode enabled, dumping waveform);$dumpfile(tb_fifo_plusargs.vcd);$dumpvars(0,tb_fifo_plusargs);end end endmodule编译与运行命令示例# 默认模式运行随机测试100次vsim-c-dorun -alltb_fifo_plusargs# 带参数运行模式1满压力测试数据包200随机种子999vsim-c-dorun -alltb_fifo_plusargs MODE1NUM200SEED999# 同时开启调试打印和波形vsim-c-dorun -alltb_fifo_plusargs DEBUG MODE2NUM50详解$value$plusargs读取整数%d可以读取十进制整数。注意如果没提供参数返回0我们设置默认值。$srandom(seed)设置随机种子使每次仿真可重复或不同。$test$plusargs控制调试加上DEBUG就会生成波形文件否则不生成节省仿真时间和磁盘。任务封装不同测试模式写成独立任务使代码清晰。工作中如何应用回归测试自动化编写脚本循环运行同一 testbench每次传入不同参数如种子、模式、数据量收集覆盖率。调试开关用DEBUG控制是否打印详细日志避免海量输出。性能与随机性用SEED固定问题复现场景或随机探索新场景。时间显示在结果文件中用$timeformat统一时间单位便于比较不同仿真器的日志。常见错误与提示$value$plusargs的格式字符串中不要加空格如MODE%d命令行参数必须写MODE5。多个参数用空格分隔顺序无关。字符串比较是区分大小写的debug和DEBUG不同。$test$plusargs只检测参数名不关心参数值。若要传值必须用$value$plusargs。总结这些系统任务就像遥控器上的特殊按钮$finish关机键$stop暂停键$timeformat设置时间显示格式像调手表$time/$realtime读当前时间秒表$test$plusargs/$value$plusargs接收遥控器额外指令调频道验证工程师最常用的是最后两个——它们让你无需重新编译即可改变仿真行为极大提高了调试和回归测试的效率。记住参数化你的 testbench不要硬编码这样你就能用一个 TB 应对上百种场景。