资源
HDLBits 基础题目学习
Github 上有哪些优秀的 Verilog/FPGA 项目?
Complex Digital Systems MIT课程
基础
语法
相比于VHDL的entity,Verilog的设计由module组成,其基本表示如下(Verilog-2001和Verilog-1995支持的写法略有不同)
1 | module top_module ( output out ); |
每一个模块由module…endmodule组成,module后面跟的是模块名称以及参数,括号内包含了输入或输出参数,分别以input或output关键字修饰。Verilog的行末如同C语言,都需要带上分号。
关键字
module / endmodule: 模块定义,模块的连接可以按名称或者按参数顺序,如
1
2
3
4
5module top_module(input in, output out);
//module定义:module top_module(input a, output o);
module_m m1(.a(in),.o(out)); //使用名称连接
module_m m2(in,out);// 使用参数顺序
endmoduleassign: 用于连续赋值,相当于硬件连线操作,非单个时刻的事件
例如将模块输入输出接在一起
1
2
3module top_module(input in, output out);
assign out = in;
endmoduleinput / output / inout: 端口输入/输出/双向定义类型
wire: wire类型变量相当于物理连线,只能被assign赋值
reg: reg类型变量相当于寄存器,只能在always和initial语句块中被赋值
generate: 生成代码块,总是以
generate...endgenerate
组成,例如1
2
3
4
5
6genvar i;
generate
for(i=0;i<100;i++)begin:gen
//...generate by i
end
endgenerate其中
begin:gen
的gen为必须的代码块名称,for循环内部可引用i自动生成
运算符
位运算符:输出与输入数据位数等长,包括&, |, ~, ^,分别代表与,或,非以及异或
逻辑运算符:即把两侧都看作一个单独的值进行操作,输出只有一位,其中包括&&, || , !,分别代表逻辑与,逻辑或,以及逻辑非
关系运算符:
> < <= >= == !=
拼接运算符:用于拼接多个符号,如
{a,b}
,花括号前可带数字代表重复,例如{{2{a}},{2{b}}}
等同于aabb拼接在一起移位运算符: << >>
归约操作符:只有一个操作数的逻辑运算符,表示对某个向量操作数逐位进行操作,最终输出一位的结果,其中包括包括:归约与(&),归约与非(~&),归约或(|),归约或非(~|),归约异或(^),归约同或(~^)。
1
2A = 4'b1010 ;
&A ; //相当于 1 & 0 & 1 & 0 = 1'b0,可用来判断变量A是否全1双目运算符:同C语言里的双目运算符,形如
condition_expression ? true_expression : false_expression
特性
Vector
类似C语言的数组,Verilog变量可以被声明为多个元素的vector,其格式为
1 type [upper:lower] vector_name;
例如wire [7:0] w;
为8bit的名为w的wire(最高位在第七位),访问变量可以只截取部分,但是不能逆定义顺序访问,如用w[0:7]
访问刚才定义的w是非法的。
数值表示
Verilog的四种电平:0,1,x(未知),z(高阻)
通常数值表示以位宽'类型 数值
来表示,例如
1 | 3'b000 //二进制 |
位宽即开头数字不一定需要指定,但是'
是必须的,类型有b,h,d,o
分别代表二进制,十六进制,十进制,八进制。数值中间可以增加下划线(对数值本身无影响)
带参数例化
可以在声明模块时定义参数,用#号开头即可声明参数列表,但是例化时参数列表在模块名之前
1 | module m //#号开头表示参数列表 |
第二种办法是在模块内部定义parameter
,再用defparam a.para=xxx
指定某个类型的模块的参数。但这种办法一般不建议使用。
赋值类型
连续赋值:使用
assign
关键字的赋值,赋值左值必须是wire类型,赋值过程相当于硬件连线,时间上连续,语句形如assign x = y;
,多用于组合逻辑的门级描述。过程阻塞赋值:在
always @(*)
语句块内的赋值,赋值左值必须是reg类型,其他与连续赋值基本相似,语句形如x=y;
,多用于组合逻辑的行为描述过程无阻塞赋值:在
always @(posedge clk)
内的赋值,即带时钟信号的赋值,赋值左值必须为reg类型,相当于触发器锁存行为,语句形如x <= y;
,多用于时序逻辑的行为描述。Blocking vs. Non-Blocking Assignment
There are three types of assignments in Verilog:
- Continuous assignments (
assign x = y;
). Can only be used when not inside a procedure (“always block”). - Procedural blocking assignment: (
x = y;
). Can only be used inside a procedure. - Procedural non-blocking assignment: (
x <= y;
). Can only be used inside a procedure.
In a combinational always block, use blocking assignments. In a clocked always block, use non-blocking assignments. A full understanding of why is not particularly useful for hardware design and requires a good understanding of how Verilog simulators keep track of events. Not following this rule results in extremely hard to find errors that are both non-deterministic and differ between simulation and synthesized hardware.
- Continuous assignments (