1.1 结构语句
结构语句主要是initial语句和always语句, initial 语句它在模块中只执行一次,而always语句则不断重复执行,以下是一个比较好解释的图:

(图片来源于知乎博主罗成,画的很好很直观!)
1.1.1 initial语句
initial 语句它在模块中只执行一次。
它常用于测试文件的编写,用来产生仿真测试信号(激励信号),或者用于对存储器变量赋初值。
语法格式:
initial begin ...
endPS:当initial与语句内只有一个执行语句时,可以省略begin..end。
1.1.2 always语句
always 语句一直在不断地重复活动,但是只有和一定的时间控制结合在一起才有作用。
语法格式:
always @ ( 敏感列表**) begin
...
end**
PS:敏感列表即触发always语句执行的条件,多个触发条件用or连接。同样,当always语句内只有一个执行语句时,可以省略begin..end。
always语句可用于组合逻辑也可用于时序逻辑,电平触发往往是组合逻辑,边沿触发往往是时序逻辑,因此可进一步细分:
(1)电平触发------组合逻辑:
这个程序表示每当信号abcdefghm的值(即电平变化)发生变化时,always块中的所有语句都会被执行 。

如果组合逻辑块语句的输入变量很多,可简写以下形式,@(*)表示对后面语句块中所有输入变量的变化都是敏感的(即所有变量有任何一个变化就执行always语句。)

(2)边沿触发------时序逻辑:
当检测到边沿时,执行always语句,如:

posedge 和 negedge为关键字,分别表示上升沿和下降沿,这个程序表示当 sys_clk为上升沿或者 sys_ret_n为下降沿时,执行always语句。
1.1.3 实例理解


理解:
initial语句中定义了三个信号,sys_clk,sys_rst_n, touch_key,以sys_rst_n, touch_key为例,波形图对应为第二行和第三行。以下操作只执行了一次。
- 首先sys_rst_n, touch_key均赋值为0(程序从注释开始算第3行和第5行);
- 代码第6行,延迟20ns后,sys_rst_n赋值为1,对应于波形图中红色线(20ns时刻)时sys_rst_n信号由低电平跳变至高电平。
- 代码第7行,又延迟10ns后,即30ns处(蓝色线),touch_key赋值为1
- 代码第8~10行,touch_key类似操作。
always语句则不断重复操作,每延迟10ns,sys_clk就取反一次,故波形图上(第一行)对应为产生一个周期信号。
1.2 赋值语句
1.2.1 阻塞赋值 " = "
阻塞赋值可以认为只有一个步骤的操作:即计算 RHS 并更新LHS(RHS为式子右边,LHS为式子左边)。
所谓阻塞的概念是指,在同一个always块中:后面的赋值语句是在前一句赋值语句结束后才开始赋值的。

以上例子理解:
当clk信号为上升沿或者rest_n信号处于下降沿时,执行操作。
- 在波形图部分,从-6时刻开始,直接clk信号上升沿,且满足rest_n为低电平,执行if语句,故abc分别赋值为1,2,3。
- 然后 -6 ~ 0时刻,rest_n恒为低电平,每到clk信号上升沿,执行操作中if语句,故-6 ~ 0时刻abc值恒为1,2,3。
- 0时刻时,rest_n跳变为高电平,是上升沿不是下降沿,故不执行操作。
- 0时刻后,rest_n恒为高电平,clk信号第一个上升沿为2时刻,执行操作,此时不满足if语句(rest_n为高电平),则执行else语句。由于赋值语句是在前一句赋值语句结束后才开始赋值的,故a=0执行完后,b = a = 0执行完, 在执行c = b = 0;
- 2时刻后rest_n恒为高电平,每到clk信号上升沿,执行操作中else语句,故此后abc值都为0。
1.2.2 非阻塞赋值 " <="
非阻塞赋值的操作过程可以看作两个步骤:(1)赋值开始的时候,计算RHS;(2)赋值结束的时候,更新LHS
非阻塞赋值可以理解为:第一条非阻塞赋值语句开始时,所有非阻塞语句同时赋值计算好对应的RHS并保存放置一边,全部计算好后,再将各自保存好的RHS传递到对应的LHS中。
非阻寒赋值只能用于对寄存器类型的变量进行赋值:因此只能用在initial块和always块等过程块中。

以上例子与1.1.1中例子只有阻塞赋值与非阻塞赋值的区别:
同理,当clk信号为上升沿或者rest_n信号处于下降沿时,执行操作。
- 在波形图部分,从-6时刻开始,直接clk信号上升沿,且满足rest_n为低电平,执行if语句,赋值语句右边为1,2,3然后对应赋值到abc上。
- 然后 -6 ~ 0时刻,rest_n恒为低电平,每到clk信号上升沿,执行操作中if语句,故-6 ~ 0时刻abc值恒为1,2,3。
- 0时刻时,rest_n跳变为高电平,是上升沿不是下降沿,故不执行操作。
- 0时刻后,rest_n恒为高电平,clk信号第一个上升沿为2时刻,执行操作,此时不满足if语句(rest_n为高电平),则执行else语句。赋值语句右边0,a(值为1),b(值为2)【由于此时ab值为临近2时刻的值】,则对应将其赋值到abc上得到a=0,b=1,c=2**。**
- 2时刻后rest_n恒为高电平,4时刻又到了clk信号上升沿,执行操作中else语句,。赋值语句右边0,a(值为0),b(值为1)【由于此时ab值为临近4时刻的值】,则对应将其赋值到abc上得到a=0,b=0,c=1;
- 2时刻后rest_n恒为高电平,6时刻又到了clk信号上升沿,执行操作中else语句。赋值语句右边0,a(值为0),b(值为0)【由于此时ab值为临近6时刻的值】,则对应将其赋值到abc上得到a=0,b=0,c=0;
- 此后,abc都为0,按照非阻塞也为0了。
1.3 条件语句
条件语句必须在过程块语句中使用,即是指由initial和always语向引导的块语句。
1.3.1 if语句
使用方法类似于C语言。

- 允许一定形式的简写, if(a) 等同于 if(a==1);if(!a) 等同于 if(a!=1)
- if语句对表达式的值进行判断,若为0,x,z则按假处理:若为1,按真处理:
- if和else后面的操作语句可以用begin和end包含多个语句。
- 允许if语句的嵌套。
1.3.2 case语句
case (<expression>)
case1 : ...
case2: ...
case3 : ...
case4 : begin
<multiple statements>
end
default: <statement>
endcase
语法解释:
- 其中,case1~case4这些写的是情况1~4,或者说是看<expression>符合case1~case4的哪一种情况,对应进入执行该情况;
- default表示如果没有expression没有匹配的 case 情况,执行 default 语句;
- 看case4知,如果情况中有多个执行语句,用begin..end来写。
注意点:
- 分支表达式的值互不相同(即每种情况应不同,不然编译会出现矛盾)
- 所有表达式的位宽必须相等不能用:bx 来代替:n'bx
除此之外还有另外两种表达:casez...endcase和casex...endcase。
casez不考虑表达式中的高阻值比较时;casex:不考虑高阻值之和不定值x。
例如:以下例子判定sel的值是否满足以下哪种情况,情况1是8'b1100_zzzz,其中后四位"zzzz"为高阻值不用考虑,即只需要看前4位是否与sel的值相匹配;情况2是8'b1100_xxzz,后两位才是高阻值不用考虑,看前6位是否与sel匹配。sel=1100_0011,可知前4位与情况1匹配,前6位与情况2不匹配,故进入情况1。
