FPGA学习笔记:单次调用@(posedge clk)(没有always)

本文通过一个测试平台示例,探讨了Verilog中@(posedge)触发器的行为特性及其如何影响后续语句的执行。实验表明,@(posedge)语句会阻塞后续操作,类似于wait指令的效果。

之前看小梅哥视频,对下面语句有所疑惑:

不知道这个@(posedge)触发后只执行一句还是后面的都执行,能不能加begin end只触发某几句;如果能用begin end的话,没有触发上升沿那么这个语句会不会阻塞后面的语句,自己就写了个testbench,代码如下:

`timescale 1ns/1ns
`define tm 20
module tb();
	
	reg clk;
	reg test1;
	reg test2;
	reg test3;
	reg clk1;
	
	
	initial clk = 1'b0;
	
	always#(`tm/2) clk = ~clk;
	
	initial begin
		test1 = 1'b0;
		test2 = 1'b0;
		test3 = 1'b0;
		clk1 = 1'b0;
		#(`tm*3);
		@(posedge clk)begin
		test1 = 1'b1;
		test2 = 1'b1;
		end	
		#(`tm*3);	
		@(posedge clk1)begin
		test3 = 1'b1;
		end
		#(`tm*3);
		test1 = 1'b0;
		test2 = 1'b0;
		test3 = 1'b0;
		@(posedge clk)begin
			test1 = 1'b1;
		end
		#(`tm*10);
		$stop;
	end
endmodule 

波形结果:

结论是会阻塞,@(posedge clk)语句其实等同于wait。

### 时钟上升沿触发中 `forever` 与 `always` 的区别 在 Verilog 中,`forever @(posedge clk)` 和 `always @(posedge clk)` 都用于在时钟上升沿触发代码执行,但它们的使用场景、行为特性以及适用范围存在显著差异。 #### 1. `always @(posedge clk)` 的用途与特性 `always @(posedge clk)` 是 Verilog 中用于描述时序逻辑的标准结构,常用于可综合的 RTL 设计中。它会在每次 `clk` 上升沿到来时执行一次代码块,并在执行完毕后继续等待下一个上升沿。该结构在硬件综合时会被映射为寄存器和组合逻辑,适用于描述同步状态机、寄存器传输等行为。 例如,以下代码实现了一个简单的同步 D 触发器: ```verilog always @(posedge clk) begin q <= d; end ``` 这种结构在多个 `always` 块之间是并行执行的,且在综合过程中能够被综合工具正确识别和转换为门级逻辑[^2]。 #### 2. `forever @(posedge clk)` 的用途与特性 `forever @(posedge clk)` 是一种行为建模结构,通常用于测试平台(testbench)中模拟时钟驱动的行为。它会在仿真过程中无限循环,每次在 `clk` 上升沿触发时执行指定的代码块。 例如,以下代码用于在测试平台中生成一个周期为 10 时间单位的时钟信号: ```systemverilog initial begin clk = 0; forever #5 clk = ~clk; end ``` 此外,`forever @(posedge clk)` 也可以用于监控信号变化、记录波形等行为建模任务: ```systemverilog initial begin forever @(posedge clk) begin $display("At time %0t, a = %b", $time, a); end end ``` 需要注意的是,`forever` 是一种不可综合的结构,仅适用于仿真环境。它不能直接映射为硬件逻辑,因此不能用于 RTL 设计中[^1]。 #### 3. 行为差异与适用范围 - **执行方式**:`always @(posedge clk)` 是一种事件驱动结构,在每个上升沿执行一次;而 `forever @(posedge clk)` 是一个无限循环结构,持续等待并响应上升沿。 - **可综合性**:`always @(posedge clk)` 是可综合的,适用于 RTL 设计;而 `forever @(posedge clk)` 仅适用于仿真,不可综合为硬件逻辑。 - **代码结构**:`always` 块可以独立存在,且多个 `always` 块之间是并行执行的;而 `forever` 必须嵌套在 `initial` 或 `always` 块中,且只能在行为仿真中使用[^3]。 #### 4. 示例对比 以下代码展示了 `always @(posedge clk)` 和 `forever @(posedge clk)` 的典型用法对比: ```systemverilog module testbench; reg clk; reg [7:0] data_in; wire [7:0] data_out; // DUT always @(posedge clk) begin data_out <= data_in; end // Clock generation initial begin clk = 0; forever #5 clk = ~clk; end // Monitor initial begin forever @(posedge clk) begin $display("At time %0t, data_in = %b, data_out = %b", $time, data_in, data_out); end end // Test sequence initial begin data_in = 8'h00; #10 data_in = 8'hAA; #10 data_in = 8'h55; #10 $finish; end endmodule ``` 在上述示例中,`always @(posedge clk)` 用于描述 DUT 的同步行为,而 `forever @(posedge clk)` 用于生成时钟和监控信号变化。 #### 5. 使用建议 - 在 RTL 设计中应优先使用 `always @(posedge clk)`,以确保代码的可综合性和可维护性。 - 在测试平台中可以使用 `forever @(posedge clk)` 来模拟时钟驱动、监控信号变化或执行周期性操作。 - 避免在 RTL 代码中使用 `forever @(posedge clk)`,因其不可综合,可能导致仿真与综合结果不一致[^4]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值