使用步骤
为了在时序图中显示信号,我们定义了三个Verilog宏:
- 'probe(signal )):向定时图添加信号。
- 'probe_start :在初始块内使用此法开始新的计时图
- 'probe_stop:在初始方块内使用这个来停止当前的计时图
你需要probe_start来开始做计时图。
限制:每个信号只能添加一次。信号数量最多只能有512个。每个信号最多只能是512位的总线
- 顶级模块必须叫做top_module
运行仿真时,你通常会有一个(可合成的)模块(被测设备 (DUT))来测试,还有一个测试平台,负责实例化你的模块并在适当时间驱动其输入。
一个基础测试平台使用一些 regs 和初始块来赋值。初始块类似于始终块,但它只在模拟开始时执行一次。Verilog 过程块允许在语句中添加延迟。例如,x = 0;#10;x = 1;将x设为0,然后等待10个时间单位,再将x = 1。
基础调试可以通过打印信号的数值,使用display、strobe或monitor来完成。display的原理类似于 C语言中的 printf。
使用系统任务$finish结束模拟。
Simulation下的"Run a Simulation(Icarus Verilog)"


module top_module ();
reg clk=0;
always #5 clk = ~clk; // Create clock with period=10
initial `probe_start; // Start the timing diagram
`probe(clk); // Probe signal "clk"
// A testbench
reg in=0;
initial begin
#10 in <= 1;
#10 in <= 0;
#20 in <= 1;
#20 in <= 0;
$display ("Hello world! The current time is (%0d ps)", $time);
#50 $finish; // Quit the simulation
end
invert inst1 ( .in(in) ); // Sub-modules work too.
endmodule
module invert(input in, output out);
assign out = ~in;
`probe(in); // Sub-modules can also have `probe()
`probe(out);
endmodule
probe是什么?这不是 Verilog 标准语法,而是 仿真工具(比如 HDL Designer、Vivado 内部集成工具)的自定义宏。作用:
- ```probe_start``:开始记录波形
- ```probe(信号)``:把信号加入波形图
你可以把它理解为:让信号能在波形窗口里看到。
点击"Submit(New window)"在新界面中进行仿真


将编写好的Testbench代码和RTL代码放到一个文件中(Testbench在上面,RTL代码在下面,这个平台可以将两种文件放在一起)
示例
5分频,50%占空比
module top_module ();
reg clk=0;
always #5 clk = ~clk; // 时钟周期=10,和你示例完全一样
initial `probe_start; // 启动波形探测
`probe(clk); // 探测输入时钟
// 5分频需要复位信号
reg rst_n;
initial begin
rst_n = 0; // 初始复位
#20 rst_n = 1; // 20个时间单位后释放复位
end
// 例化 5分频模块
wire clk_out;
div5 u_div5 (
.clk_in(clk),
.rst_n(rst_n),
.clk_out(clk_out)
);
// 仿真结束控制
initial begin
#200 $finish;
end
endmodule
// ===================== 5分频模块 ====================
module div5(
input clk_in,
input rst_n,
output clk_out
);
reg [2:0] cnt;
reg clk_p;
reg clk_n;
// 计数器 0~4 循环
always @(posedge clk_in or negedge rst_n) begin
if(!rst_n)
cnt <= 0;
else if(cnt == 4)
cnt <= 0;
else
cnt <= cnt + 1;
end
// 上升沿生成中间时钟
always @(posedge clk_in or negedge rst_n) begin
if(!rst_n)
clk_p <= 0;
else if(cnt == 2 || cnt == 4)
clk_p <= ~clk_p;
end
// 下降沿生成中间时钟
always @(negedge clk_in or negedge rst_n) begin
if(!rst_n)
clk_n <= 0;
else if(cnt == 2 || cnt == 4)
clk_n <= ~clk_n;
end
// 输出 50% 占空比 5分频
assign clk_out = clk_p | clk_n;
// 波形探测
`probe(clk_in);
`probe(rst_n);
`probe(cnt);
`probe(clk_p);
`probe(clk_n);
`probe(clk_out);
endmodule

复位阶段(0~20ns)
- 时间节点:0ns ~ 20ns
- 关键信号状态 :
rst_n:低电平(0),异步复位生效cnt:保持 0,计数器复位clk_p/clk_n/clk_out:全部保持低电平(0)
- 设计逻辑:异步复位确保电路上电后从初始状态开始工作,避免亚稳态。
复位释放与计数启动(20ns)
- 时间节点:20ns
- 关键信号状态 :
rst_n:跳变为高电平(1),复位释放cnt:在 clk 上升沿(20ns)开始递增,从 0→1
- 设计逻辑:复位释放后,计数器在每个输入时钟上升沿正常计数,进入 0-4 循环。
第一个分频周期(20ns ~ 70ns)
| 时间节点 | 关键事件 | 信号状态 | |
|---|---|---|---|
| 30ns | cnt=2(上升沿) |
clk_p 翻转(0→1) |
|
| 35ns | cnt=2(下降沿) |
clk_n 翻转(0→1) |
|
| 40ns | clk_out 由 `clk_p |
clk_n` 生成,跳变为高电平(0→1) | clk_out=1 |
| 50ns | cnt=4(上升沿) |
clk_p 翻转(1→0) |
|
| 55ns | cnt=4(下降沿) |
clk_n 翻转(1→0) |
|
| 60ns | clk_out 跳变为低电平(1→0) |
clk_out=0 |
|
| 70ns | 第一个 5 分频周期结束 | clk_out 周期 = 50ns(5×10ns 输入周期) |
占空比验证(核心指标)
clk_out高电平时间:40ns ~ 65ns,持续 25nsclk_out低电平时间:65ns ~ 90ns,持续 25ns- 结论:完美 50% 占空比,符合奇数分频双边沿合成的设计目标
后续周期(70ns 之后)
- 计数器持续
0→1→2→3→4→0循环,clk_p/clk_n按相同逻辑翻转 clk_out以 50ns 为周期稳定输出,无毛刺、无相位偏移,分频比稳定为 5:1
- 双边沿合成技术 :通过上升沿触发的
clk_p和下降沿触发的clk_n,相位相差半个输入时钟周期,经或运算后生成 50% 占空比的奇数分频时钟。- 异步复位:低电平复位确保电路上电后状态可控,复位释放后立即进入正常工作状态。
- 计数器逻辑 :3 位计数器 0-4 循环,在
cnt=2和cnt=4时翻转中间时钟,是实现 5 分频的核心计数逻辑。