#异步复位
always @(posedge clk or nogedge rst_n)
if(!rst_n) b <=1'b0;
else b<=a;
#同步复位
always @(posedge clk)
if(!rst_n)b <=1'b0;
else b<=a;
阻塞赋值和非阻塞赋值的区别
阻塞(Blocking)赋值方式”=“,如b = a;
赋值语句执行后,块才结束
b的值在赋值语句执行完成后立刻就改变的
阻塞赋值(LHS=RHS)
阻塞赋值时先计算等号右手方向RHS部分的值,这时赋值语句不允许任何别的语句的干扰,直到现行的赋值完成时刻,即把RHS赋值给LHS的时刻,它才允许别的赋值语句的执行
一般可综合的阻塞赋值操作在RHS 不能设定有延迟(因为在设计语句中,延时是不可综合的,而验证是不需要可综合的,故在验证的代码中是可以设计延时语句的)
所谓的阻塞概念是指在同一个always块中,其后面的赋值语句是在前一句赋值语句结束后再开始赋值的
![](https://img-blog.csdnimg.cn/img_convert/ef7b8bc7483580f786ec6f6b6928c514.png)
非阻塞(Non Blocking)赋值方式”<=“,如b<=a;
块结束后才完成赋值操作,b的值并不是立刻就变
这是一种比较常用的赋值方式(特别在编写可综合时序模块时)
非阻塞赋值(LHS<=RHS)可以理解成并行
非阻塞赋值的操作可以看作为两个步骤的过程
在赋值时刻开始时,计算非阻塞赋值RHS表达式
在赋值时刻结束时,更新非阻塞赋值LHS表达式
非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用于initial块和always块等过程中,非阻塞赋值不允许用于连续赋值
![](https://img-blog.csdnimg.cn/img_convert/e9789843a3a2bc7823a362c5aaa64b6f.png)
![](https://img-blog.csdnimg.cn/img_convert/e311d3b0307068ce25436ca56771f22a.png)
verilog模块编程要点
时序电路建模时,用非阻塞赋值
锁存器电路建模时,用非阻塞赋值
用always块建立组合逻辑模型时,用阻塞赋值
在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值
在同一个always块中既用非阻塞赋值又用阻塞赋值
不要在一个以上的always块中为同一个变量赋值
在赋值时不要使用#0延迟
assign左手边一般是wire型
always左手边一般是reg型
非阻塞左手边一定是reg型
块语句
用来将两条或多条语句组合在一起,使其在格式上更像一条语句,以增加程序的可读性
块语句有两种
begin end 表示顺序执行的语句 一般为阻塞赋值
fork join表示并行执行的语句 一般为非阻塞赋值
块内的语句是顺序执行的;
每条语句的延迟时间是相对与前一条语句的仿真时间而言的;
直到最后一条语句执行完,程序流程控制才跳出该顺序块;
顺序块
特点
![](https://img-blog.csdnimg.cn/img_convert/ff8f036c66fa8dfc90a75a2d008d3606.png)
![](https://img-blog.csdnimg.cn/img_convert/fd12875be7330da6bf6a8791030e29b7.png)
PS:例2这种begin end块中有时延的,一定是在testbench中,而不是设计文件中的
#用顺序块和延迟控制组合产生一个时序波形
parameter d = 50;
reg[7:0]r;//定义了一个8位的寄存器常量r
initial//initial-end块只执行一次
begin
#d r = ’h35;//表示十六进制的35转化为二进制是00110101
#d r = ‘hE2//表示十六进制的E2转化为二进制是11100010
#d r = ’h00
#d r = ‘hf7//表示十六进制的F7转化为二进制是11111111
end
该代码每一个d表示50个时间单位,由于begin end块是顺序执行的,故这串代码的总时延一定是200个时间单位
在设计代码中不能有延迟代码,因为是不可综合的
每条语句的延迟时间d是相对于前一条语句的仿真时间而言的
并行块(用fork-join标识的块,fork-join语句是不可综合的)
特点:
块内的语句是同时执行的;
块内每条语句的延时时间是相对于程序流程控制进入到块内时的仿真时间而言的
延迟时间用于给赋值语句提供时序
当按时间排序在最后的语句执行完或一个disable语句执行时,程序流程控制跳出该并行块
#用并行块和延迟控制组合产生一个时序波形
reg[7:0]r;//定义了一个8位的寄存器常量r
initial//initial-end块只执行一次
fork
#50 r = ’h35;//表示十六进制的35转化为二进制是00110101
#100 r = ‘hE2//表示十六进制的E2转化为二进制是11100010
#150 r = ’h00
#200 r = ‘hf7//表示十六进制的F7转化为二进制是11111111
join
由于fork join块是并行执行的,故这串代码的总时延一定选取的是该串代码中时延产生最大的,故总时延一定200
h35信号和h00信号之间的时延是100个时间单位
fork-in块内,各语句的时延为递增的,最好按被执行的顺序书写
条件语句if-else
条件语句分为两种:if-else语句和case语句;
它们都是顺序语句,应该放在always块内
判定所给条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一
if-else语句的3种形式:
其中表达式为逻辑表达式或关系表达式,或一位的变量
若表达式的值为0或z,则判定的结果为假
其余值就为真
语句可为单句,也为多句,多句时一定要用begin-end语句括起来,形成一个复合块语句
if(表达式)语句1;//方式1
方式二
if(表达式1)语句1;
else 语句2;
方式3
if(表达式1)语句1;
else if(表达式2)语句2;
![](https://img-blog.csdnimg.cn/img_convert/823cf018fde20020f52803e5f491ea47.png)
if(!rst_n)表达式1 复位低电平有效
if语句可以嵌套
若if和else的数目不一样,一定要用begin-end语句来确定if于else的配对关系
![](https://img-blog.csdnimg.cn/img_convert/f1097762aa2bd1fea31328639fd27632.png)
![](https://img-blog.csdnimg.cn/img_convert/a85ba791653a8fc820eb6677a088a15d.png)
时钟激励的产生(测试模块一定要给设计模块一个时钟激励):
方式一:
initial
begin
clk1=0;
clk2=0;
end
always #10 clk1=~clk1; clk1的时钟周期为20
always #20 clk2=~clk2; clk2的时钟周期为40
方式二:
always
begin
#20clk=0;
#20clk=1;
end//时钟周期为40
写always @ 一定要用begin-end包起来