Verilog基础语法
1, 二进制表示如下:4'b0101表示4位二进制数0101;
2, 标识符用于定义模块名、端口名、信号名,例如:clk_50;
3, 寄存器数据类型,线网数据类型和参数数据类型;
reg[31:0] delay_cnt; //延时计数
reg key_reg; //默认位宽为1
Reg类型的数据只能在always语句和initial语句中被赋值;
如果该过程语句描述的是时序逻辑,即always语句带有时钟信号,则改寄存器变量对应为触发器;
如果该过程语句描述的是组合逻辑,即always语句不带有时钟信号,则改寄存器变量对应为硬件连线;
3.1线网类型:表示结构实体(例如门)之间的物理连线;
不能存储值,它的值由驱动它的元件所决定;
如果没有驱动元件连接到线网类型的变量上,则改变 量就是高阻,即值为Z;
wire key_flag; //默认位宽为1
3.2参数类型:参数其实就是一个常量,用parameter定义 常量;
parameter H_SYNC = 11'd41; //行同步
parameter H_DISP = 11'd480; //行有效数据
常用于状态机的状态,数据为宽和延迟大小;
4,运算符
算术运算符
符号 使用方法 说明
+ a+b a加上b
- a-b a减去b
* a*b a乘以b
/ a/b a除以b //a除以b的整数
% a%b a模除b //a除以b的余数
关系运算符
符号 使用方法 说明
> a>b a大于b
< a<b a小于b
>= a>=b a大于等于b
<= a<=b a小于等于b
== a== b a等于b
!= a!=b a不等于b
逻辑运算符
符号 使用方法 说明
! !a a的非
&& a&&b a与上b
|| a||b a或上b
条件运算符
符号 使用方法 说明
?: a?b:c 如果a为真,就选择b,否则选择c
位运算符
符号 使用方法 说明
~ ~a 将a的每个位进行取反
& a&b 将a的每个位与b相同的位进行相与
| a|b 将a的每个位与b相同的位进行相或
^ a^b 将a的每个位与b相同的位进行相或
(备注:为宽不同时,高位补零)
移位运算符
符号 使用方法 说明
<< a<< b 将a左移b位
>> a>> b 将a右移b位
左移时,位宽增加;右移时,位宽不变;
4'b1001<<2=6'b100100;
4'b1001>> 2=4'b0100;
拼接运算符符号 使用方法 说明
{} {a,b} 将a和b拼接起来,作为一个新信号;
C={a,b[3:0]}; //假如a和b都是4位,那么c就是8位
运算符优先级:
5,Verilog关键字:
关键字 含义
module 模块开始定义
input 输入端口定义
output 输出端口定义
inout 双向端口定义
parameter 信号参数定义
wire wire信号定义
reg reg信号定义
always 产生reg信号语句的关键字
assign 产生wire信号语句的关键字
begin 语句起始标志
end 语句结束标志
edge /posedge/negedge 时序电路的标志
case case语句起始标记
default case语句的默认分支标志
endcase case语句结束标记
if if/else语句标记
else if/else语句标记
for for语句标记
endmodule 模块结束定义
Verilog快速入门知识学习之二
1,模块结构
Module block (a,b,c,d);
input a,b;
output c,d;
assign c=a|b;
assign d=a&b;
endmodule
每个Verilog程序包括4个主要部分:
端口定义、IO说明、内部信号声明、功能定义。
功能定义部分有三种方法:
1, assign语句
描述组合逻辑
2, always语句
描述组合/时序逻辑
3, 例化实例元件
如:and#2 u1(q,a,b);
上述三种逻辑功能是并行的
在always块种,逻辑是顺序执行的,而多个always块之间是并行的。
2,结构语句
initial和always
initial语句它在模块中制执行一次。
它常用于测试文件的编码写,用来产生仿真测试信号(激励信号),或者用于对存储器变量赋初值;
always语句一直在不断地重复活动;但是只有和一定时间控制结合在一起才有作用;
always的时间控制可以是沿触发,也可以是电平触发;
可以是单个信号,也可以是多个信号,多个信号中间要用关键字or连接。
always语句后紧跟的过程块是否运行,要看它的触发条件是否满足。
always @(posedge sys clk or negedge sys_rst_n) begin
if (!sys_rst_n)
counter <=24'd0;
elst if (counter < 24'd1000_0000)
counter <= counter +1'b0;
else
counter <=24'd0;
end
沿触发的always块常常描述时序逻辑行为。由关键词or连接的多个事件名或信号名组成的列表称为"敏感列表"
电平触发的always块常常描述组合逻辑行为。
always @(a or b or c or d or e or f or g or h or p or m) begin
out1=a?(b+c)d+e);
out2=f?(g+h)p+m);
end
@(*)表示对后面语句块中所有输入变量的变化都是敏感的。
always @(*) begin
out1=a?(b+c)d+e);
out2=f?(g+h)p+m);
end
3,赋值语句
3.1,阻塞赋值(blocking),如b=a;
3.2,非阻塞赋值(Non blocking) 如b<=a;
阻塞赋值 在本语句中"右式计算"和"左式更新"完全完成之后,才开始执行下一条语句;
非阻塞:当前语句的执行不会阻塞下一语句的执行。
先看阻塞赋值的情况,我们来看这段代码:
always @(posedge Clk)
begin
Q1 = D;
Q2 = Q1;
Q3 = Q2;
end
always语句块对Clk的上升沿敏感,当发生Clk 0~1的跳变时,执行该always语句。在本例中,D的值赋给Q1以后,再执行Q2 = Q1;同样在Q2的值更新以后,才执行Q3 = Q2。这样,最终的计算结果就是Q3 = D。
接下来,再看看非阻塞赋值的情况。
所谓非阻塞赋值,顾名思义,就是指当前语句的执行不会阻塞下一语句的执行。
always @(posedge Clk)
begin
Q1 <= D;
Q2 <= Q1;
Q3 <= Q2;
end
首先执行Q1 <= D,产生一个更新事件,将D的当前值赋给Q1,但是这个赋值过程并没有立刻执行,而是在事件队列中处于等待状态。然后执行Q2 <= Q1,同样产生一个更新事件,将Q1的当前值(注意上一语句中将D值赋给Q1的过程并没有完成,Q1还是旧值)赋给Q2,这个赋值事件也将在事件队列中处于等待状态。
再执行Q3 <= Q2,产生一个更新事件,将Q2的当前值赋给Q3,这个赋值事件也将在事件队列中等待执行。
这时always语句块执行完成,开始对下一个Clk上升沿敏感。
当发生第一次Clk 0~1的跳变时,结果为Q1=D;Q2 = Q1; Q3 = Q2;
当发生第二次Clk 0~1的跳变时,结果为Q1=D;Q2 = D; Q3 = Q2;
当发生第三次Clk 0~1的跳变时,结果为Q1=D;Q2 = D; Q3 = D;
注意:非阻塞赋值只能用于对寄存器类型的变量进行赋值,因此只能用在initial和always块等过程块中;
在描述组合逻辑的always块中用阻塞赋值=;
这种电路结构只与输入电平的变化有关系。
在描述时序逻辑的always块中用阻塞赋值<=;
这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值的变化。
注意:在同一个always块中不要即用非阻塞赋值又用阻塞赋值;
不允许在多个always块中对同一个变量进行赋值;
4,条件语句
If_else语句
If(a>b)
out =data_1
else
out =data_2
条件语句必须在intinal和always语句引导的块语句中使用。 原创:卧龙会 玉京龙