HDLBits_Verilog学习笔记(to be continued)
文章目录
There are some HDLBits practices.
Verilog Language
Procedures
Alwaysblock1
由于数字电路由导线连接的逻辑门组成,任何电路都可以表示为一些模块的组合和赋值语句。然而,有时这并不是描述电路最方便的方式。过程(always块就是一个例子)提供了描述电路的另一种语法。
对于硬件综合,两种类型的always块是相关的:
- 组合电路:always @(*)
- 时序电路:always @(posedge clk)
组合always块等价于赋值语句,因此总有一种方法可以用这两种方式来表示组合电路。选择使用哪一种主要是哪一种语法更方便的问题。== 注意:过程块内部的代码语法与外部的代码不同。== 过程块有更丰富的语句集(例如,if-then, case),不能包含连续赋值,但也引入了许多新的非直观的出错方式。(程序性连续作业确实存在,但与连续作业有所不同)。
例如,赋值和组合always块描述同一电路。两者都创造了相同的组合逻辑。当任何一个输入(右边)改变值时,两者都会重新计算输出。
assgin out1 = a & b | c^ d;
always @(*)
out2 = a & b | c ^ d;
对于组合的always块,始终使用(*)的敏感信号列表。显式地列出信号很容易出错(如果漏掉一个),并且在硬件综合时被忽略。如果你显式地指定了灵敏度列表,但漏了一个信号,综合硬件仍然会像(*)被指定一样工作,但是仿真模拟将不会也不匹配硬件的行为。(在SystemVerilog中,使用always_comb)。
关于wire和reg的注释: assign语句的左侧必须是net类型(例如wire),而过程赋值语句(在always块中)的左侧必须是变量类型(例如reg)。这些类型(wire vs. reg)与所综合的硬件没有任何关系,只是Verilog作为硬件模拟语言使用时留下的语法。
练习
使用赋值语句和组合的always块构建AND门。(由于赋值语句和组合块总是相同的功能,没有办法强制你使用这两个方法。但你是来练习的,对吧?(让你都是实现一遍))。
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always @(*)
begin
out_alwaysblock = a & b;
end
endmodule
assign,连续赋值,就是无条件全等,对象为wire类型;alyways 就是敏感赋值,有条件相等,对象为reg,敏感信号列表,电平触发时,综合为组合电路,边沿触发时,才综合为时序电路。
Alwaysblock2
对于综合电路,两种类型always模块总是相关联的:
- 组合电路:always @(*)
- 时序电路:always @(posedge clk)
时序always块创建一团组合逻辑,就像组合always块一样,但也在一团组合逻辑的输出上创建一组触发器(或“寄存器”)。一团逻辑块的输出不能立即可见,而是只在下一个(posedge clk)之后的输出可见。(a blob of :一系列,团,块;不能详细定义形容的整体)。
阻塞 VS 非阻塞 赋值语句
Verilog中存在的三种赋值语句:
- 连续赋值(assign x = y;):只能用在always块外
- 阻塞性赋值(x = y;):用于(initial or always)程序语句内部,在赋值时,先计算等号右手部分的值,再赋值给左边变量,直到该语句赋值完成,后面的语句才能执行,会阻塞后面的语句。(顺序执行)
- 非阻塞性赋值(x <= y;): 用于(initial or always)程序语句内部,执行赋值语句右边,然后将begin-end之间的所有赋值语句同时赋值到赋值语句的左边,但是左边的变量的值不会立即更新,直到always块所有语句执行完,才将左边变量的值更新。
注意
- 在描述组合逻辑的always 块中用阻塞赋值,则综合成组合逻辑的电路结构。
- 在描述时序逻辑的always 块中用非阻塞赋值,则综合成时序逻辑的电路结构。
在一个组合always块中,使用阻塞赋值。在时序always块中,使用非阻塞赋值。充分理解Verilog模拟器如何跟踪事件对硬件设计是特别有用的。如果不遵循这一规则,将很难找到仿真和合成硬件之间的不确定性和不同的错误。
练习
用三种方法构建异或门,使用赋值语句、组合always块和时序always块。请注意,时钟always块产生一个不同于其他两个的电路:有一个触发器,所以输出延迟。
// synthesis verilog_input_version verilog_2001
module top_module(
input clk,
input a,
input b,
output wire out_assign,
output reg out_always_comb,
output reg out_always_ff );
assign out_assign = a ^ b;
always @(*)
begin
out_always_comb = a ^ b;
end
always @(posedge clk )
begin
out_always_ff <= a ^ b;
end
endmodule
Always if
if条件语句相当于一个二选一选择器,eg:
always @(*) begin
if (condition) begin
out = x;
end
else begin
out = y;
end
end
如果条件为真输出if下的,为假输出其他的;这相当于条件预算符下的连续赋值:
assign out = (condition) ? x : y;
然而,过程赋值if条件语句中有新的一种错误,只有输出有赋值的时候才能综合成组合电路。
练习
构建一个2-to-1多路选择器,在a和b之间进行选择。如果sel_b1和sel_b2都为true,则选择b。否则,选择a。重复同样的操作两次,一次使用assign语句,一次使用过程性if语句。
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
assign out_assign = (sel_b1 & sel_b2)? b : a;
always @(*)
begin
if (sel_b1 == 1'b1 & sel_b2 == 1'b1)
begin
out_always = b;
end
else
begin
out_always = a;
end
end
endmodule
always = b;
end
else
begin
out_always = a;
end
end
endmodule