逻辑0:低电平。
逻辑1:高电平。
逻辑X:未知,可能是高电平,也可能是低电平。
逻辑Z:高阻态,外部没有激励信号,是一个悬空状态。
十进制数10的表示:
二进制:4'b1010
十进制:4‘d10
十六进制:4’ha
若不指定位宽,默认32位位宽
若不指定位宽和进制,默认32位十进制
16‘b1001_1010_1010_1001 = 16'h9AA9
用于定义模块名、端口名、信号名等。
是任意一组字母、数字、$符号和_(下划线)符号的组合,第一个字符必须是字母或者下划线,区分大小写。
推荐写法:普通内部信号建议全部小写,用下划线区分词。
sum、cpu_addr、clk_50、clk_cpu
Verilog中,三大数据类型:(1)寄存器;(2)线网;(3)参数。
寄存器表示一个抽象的数据存储单元,通过赋值语句可以改变寄存器存储的值。
寄存器数据类型的关键字是reg,reg类型数据的默认初始值为不定值x。
reg [31:0] delay_cnt;
reg key_reg;
reg类型的数据只能在always语句和initial语句中被赋值。
时序逻辑中,寄存器对应为触发器;组合逻辑中,寄存器对应位硬件连线。
线网数据类型表示结构实体之间的物理连线,不能存储值。
驱动线网类型变量的元件有门、连续赋值语句、assign等。
如果没有驱动元件连接到线网类型的变量上,则该变量就是高阻的,其值为z。
线网数据类型包括wire和tri,常用的为wire
wire key_flag;
常量,用parameter定义。
parameter H_SYNC = 11'd41;
parameter H_BACK = 11'd2;
parameter H_DISP = 11'd480;
参数型数据常用于定义状态机的状态、数据位宽和延迟大小等。
采用标识符来代表一个常量可以提高程序的可读性和可维护性。
在模块调用时,可通过参数传递来改变被调用模块中已定义的参数。
除法只能整除
两种注释方式:和C语言相同//和/* */
Verilog 的基本设计单元是“模块”
一个模块由两部分组成,一部分描述接口,另一部分描述逻辑功能。
module block(a, b, c, d);
input a, b;
output c, d;
assign c = a | b;
assign d = a & b;
endmodule
每个Verilog程序包括4个主要的部分:(1)端口定义、(2)IO说明、(3)内部信号声明、(4)功能定义。
流水灯模块
`timescale 1ns / 1ps
module led(
output reg[3:0] led,
input clk,
input rst_n
);
reg [31:0] cnt;
reg [1:0] led_on_number;
parameter CLOCK_FREQ = 50000000;
parameter COUNTER_MAX_CNT = CLOCK_FREQ/2-1;
always @(posedge clk, negedge rst_n)begin
if(!rst_n) begin
cnt <= 31'd0;
led_on_number <= 2'd0;
end
else begin
cnt <= cnt + 1'b1;
if(cnt == COUNTER_MAX_CNT) begin
cnt <= 31'd0;
led_on_number <= led_on_number + 1'b1;
end
end
end
always@(led_on_number) begin
case(led_on_number)
0:led<=4'b0001;
1:led<=4'b0010;
2:led<=4'b0100;
3:led<=4'b1000;
endcase
end
endmodule
功能定义部分有三种方法:
1. assign语句:描述组合逻辑
2. always语句:描述组合/时序逻辑
3. 例化实例元件
上述三种逻辑功能是并行的。
在always块中,逻辑是顺序执行的;而多个always块之间是并行的。
模块的输入端可以是wire类型,也可以是reg类型;输出端必须是wire类型。
initial语句:在模块中只执行一次,常用于测试文件的编写,用来仿真测试信号。
always语句:一直在不断地重复活动,但是只有和一定的时间控制结合在一起才有作用。
always的时间控制可以是沿触发,也可以是电平触发。触发信号可以是单个信号,也可以是多个信号,多个信号中间要用关键字or连接。
always语句后紧跟的过程块是否运行,要看其触发条件是否满足。
沿触发的always语句块常常描述时序逻辑行为,如上图。 时序逻辑中,任意时刻的输出不仅仅取决于当时的输入信号,而且还取决于电路原来的状态。或者说还与以前的输入有关,因此时序逻辑必须具备记忆功能。
电平触发的always块常常描述组合逻辑行为,如下图。组合逻辑中,任意时刻的输出仅仅取决于该时刻的输入,与电路原来的状态无关。
Verilog HDL语句中,信号有两种赋值方式:(1)阻塞赋值;(2)非阻塞赋值。
(1)阻塞赋值
在同一个always块中,后面的赋值语句是前一句赋值语句结束后才开始。
阻塞赋值:计算RHS并更新LHS。
(2)非阻塞赋值
在计算非阻塞赋值的RHS以及更新LHS期间,允许其他的非阻塞赋值语句同时计算RHS和更新LHS。
非阻塞赋值只能用于对寄存器类型的变量进行赋值,因此只能用在initial块和always块等过程块中。
非阻塞赋值:(1)赋值开始时,计算RHS;(2)赋值结束时,更新LHS。
在描述组合逻辑的always块中用阻塞赋值,综合成组合逻辑的电路结构;在描述时序逻辑的always块中使用非阻塞赋值,综合成时序逻辑的电路结构。
在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
不允许在多个always块中对同一个变量进行赋值。
(1)if(a)等同于if(a==1) if(!a) 等同于 if(a!=1)
(2)if语句对表达式的值进行判断,若为0、x、z,则按假处理;若为1,则按真处理。
(3)if和else后面的操作语句可以用begin和end包含多个语句。
(4)语序if语句的嵌套
case语句 (多分支选择语句)