Verilog编程规范——reset

有样学样,本篇内容从Verilog编程规范中的复位信号,讲到FPGA中复位的场景。

内容实质来自《通信IC设计》一书,仅作整合用于学习。

Verilog 编程规范中的复位

规则1:禁止采用以下代码实现同步复位。

正常情况下,任何一个模块都可以同步复位和异步复位。但一般情况下,在同 一时钟域内必须使用单一的全局同步复位电路,或者使用单一的全局异步复位电路。

而大多数ASIC设计通常还需要在FPGA上进行验证,而FPGA对同步与异步复位的处理方式是不一致的。

为保证代码的通用性,针对ASIC项目,均强制使用异步复位方式,因此下述同步复位方式禁止使用;

always @ ( posedge clk ) begin
    if (syn_rst) begin
        ;
    end else begin
        ;
    end
end

规则2:建议使用同步化异步复位信号,实现电路如下图:

用verilog把resnet部署到fpga上 verilog resetall_reset

上图中,ext_asy_rst是来自外部的复位信号,虽然asy_rst_12p88的下降沿与时钟同步,但它还是用作异步复位。

原则上每一个时钟源都输出一个异步复位信号。

上述电路的标准Verilog程序如下:

always @ ( posedge clk_122p88 or posedge ext_asy_rst ) begin
    if ( ext_asy_rst ) begin
        rst_shft[1:0] <= 2'b11; 
    end else begin
        rst_shft[1:0] <= {rst_shft[0], 1'b0};
    end
end

assign asy_rst_122p88 = rst_shft[1];

标准的异步复位语句规则如下:

always @ ( posedge clk_122p88 or posedge asy_rst_122p88 ) begin
    if ( asy_rst_122p88 ) begin
        ;
    end else begin
        ;
    end
end

规则3:除非第三方IP制定,否则所有的异步复位必须采用统一的有效电平;

FPGA中复位的应用场景

对于ASIC而言,任何一个同步寄存器单元都需要复位;对于FPGA而言,没有确切的规定。

实际上,很多FPGA单元无需复位,因为复位信号通常需要占用FPGA内部的通道资源,而复位信号的负载通常很多,容易造成复位信号布线困难,整体性能下降,编译时间增加的问题。

因此在FPGA设计中能省略的复位尽量省略

此外FPGA通常在高级选项中会统一制定寄存器的复位信号电平,这样能够进一步节省复位资源开销。

下面给出几个能够省略的复位例子,但不是绝对适用。

移位寄存器

通常情况下,只需要复位第一级移位寄存器,然后保持若干个周期,移位寄存器就被彻底复位了,而不用为每个移位单元都添加复位。

如果每个单元都需要复位,必然会导致纯粹的D触发器实现,而FPGA厂商提供的是IP映射。

分频用的计数器

分频电路就是一个多位计数器,如果初始相位无需控制,就没有必要对计数器进行初始复位,只需要每个时钟加1即可。例如下面是一个2**N的计数分频器。

reg [N-1:0] cnt;
always @ ( posedge clk ) begin
   cnt <= cnt + 1'b1; 
end

Moore型状态机输出

对于Moore型状态机的输出,只要复位了状态机,下一周期就会被复位。对存储状态不复位可能会引起反震出现不定态(X)的问题。这个问题可以通过寄存器赋初值解决,例如:

reg[N-1:0] current_state = 0;

同步复位与异步复位

在复位设计中,一个常见的问题是电路采用同步复位还是异步复位。

Xilinx推荐电路采用同步复位,但笔者采用同步化的异步复位方式,下表阐述优缺点:

用verilog把resnet部署到fpga上 verilog resetall_reset_02

下面是笔者推荐的异步复位同步化方法,如图所示:

用verilog把resnet部署到fpga上 verilog resetall_异步复位同步化_03

实现代码如下:

module reset_sync(
	input clk,
 	input  rst_x_in, //
 	output reg rst_x_out //
 	);
reg rst_x1,rst_x2,rst_x3;
wire rst_x_pulse;
 
always @(posedge clk)begin
	rst_x1<=rst_x_in;
	rst_x2<=rst_x1;
	rst_x3<=rst_x2;
end
 
assign rst_x_pulse=rst_x2|rst_x3;
always @(posedge clk)
	rst_x_out<=rst_x_pulse;
endmodule

After

上述中的一些设计,无论时同步复位,还是异步复位,亦或者是异步复位同步化,之前都有遇到过;但是一直没有成规则,搞不清楚,什么时候该用什么类型的复位。

以前做设计的时候,随着自己的想法来,想怎么弄,怎么弄;

现在急需一套实用的Design rules,不止是节约时间,避免重复设计,更需要跟进行业内的标准;统一的标准会有很大的效率提升。

言而总之,复位的设计:

按照本人的理解,全部用最后推荐的异步时钟同步化,就是最合适的方案。