今天在看verilog数字系统设计(王建民版)中,书上有一点代码是这样写的:
module sreg8bit(
input wire clk, si, ld, rst_n, en,
input wire [7:0]d,
output wire [7:0]q
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
q <= 8'b0000_0000;
else begin
if(en)
q <= {q[6:0], si};
if(ld)
q <= d;
end
end
endmodule
首先可以看出这是一个带使能端的移位寄存器,并且带有并行load功能。
这里边出现了两个if并列而且对同一个信号赋值,我们在写Verilog 代码是很少会通过两个if并列来对同一个信号赋值,总是通过条件语句让其只走到一个分支里面,赋值一次。出去好奇,使用vivado跑了一下仿真(综合后),发现他的波形是这样的:
可以看到
在en = 0, ld = 1的时候,正常加载数据,if(ld)条件执行,
当en = 1, ld = 0时,正常执行移位功能,if(en)条件分支执行
在en = 0, ld = 0时,数据保持,if(en) 和if(ld)条件分支都不执行
在en = 1,ld = 1时,执行加载数据功能,虽然两个条件分支都达到了,但是只执行最后一个if(ld)
也就是说上述always块里面的代码相当于下面这样子描述
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
q <= 8'b0000_0000;
else if(ld)
q <= d;
else if(en)
q <= {q[6:0], si};
end
也就是说,在这种情况下,最后一个优先级是最高的,所以写成上面这种形式,才更符合代码的可读性。事实上,这两段代码的使用vivado查看RTL结构也是一样的。
这里q_reg是书上的描述,q0_reg是刚才笔者第二段的RTL描述,看一看到这两个的结构是一样的。
乍一看,这个RTL结构怎么还有点复杂,跟笔者想的不大一样
这里vivado调用了它自己的器件库,使用了一个带使能端(CE)的寄存器,它相当于下面这段描述
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
q <= 0;
else if(en)
q <= d;
end
其中en会接入器件的CE端。 如下图
这样再看vivado的RTL结构,就可以看到当ld=1时,他是默认CE端接1的,只有当ld=0时,CE端才会接入en信号,这同样是通过ld来选择控制CE端到底来接什么。另一个选择器是控制到底是加载(load)数据还是移位,至于保持,当CE端接0时,这个器件会自动保持。所以也就是看到只有移位会用到当前状态的,而没有保持的相关的连线了(因为它已经做到这个带使能端的器件里了)