2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Verilog2——赋值语句 条件分支与循环语句 块语句与生成语句

Verilog2——赋值语句 条件分支与循环语句 块语句与生成语句

时间:2023-09-16 00:33:42

相关推荐

Verilog2——赋值语句 条件分支与循环语句 块语句与生成语句

Verilog2——赋值语句、条件分支与循环语句、块语句与生成语句

前言:本文结合练习题目理解总结——赋值语句中阻塞赋值与非阻塞赋值的区别,条件分支与循环语句的使用,块语句和生成语句的语法

一、阻塞赋值与非阻塞赋值

语法理解:

过程赋值与连续赋值

**1-过程赋值(procedure assign)**是在 initial 或 always 语句块里面的赋值,赋值对象是寄存器、整数、实数等类型。

这些变量在被赋值后,其值将保持不变,直到重新被赋予新值。

1)语法上,没有关键词“assign”;2)过程赋值语句只能出现在过程块(procedure block)中;3)左侧被赋值的数据类型必须是寄存器类型的变量(reg);

2-连续赋值(continuous assign)是在initial 或 always 语句块外面的赋值,总是处于激活状态,任何操作数的改变都会影响表达式的结果;

1)语法上,有关键词“assign”来标识;2)左侧被赋值的数据类型必须是线网型数据(wire);

3)连续赋值语句不能出现在过程快中(initial/always);4)连续赋值语句产生作用后,赋值表达式中信号的任何变化都将立即被反映到赋值线网型数据的取值上;

过程赋值只有在语句执行的时候,才会起作用。这是连续性赋值与过程性赋值的区别。

Verilog 过程赋值包括 2 种语句:阻塞赋值与非阻塞赋值。(另外一种是过程连续赋值,不可综合)

非阻塞赋值(Non-blocking)

[ b <= a LHS <= RHS ]

1-在语句块中,此语句所赋变量的值不能直接为后续语句使用;

2-当整个块结束,此条语句方可完成赋值操作,RHS方可得到值;

3-执行到非阻塞赋值语句时,完成/计算RHS、更新LHS/两个时间上分裂的操作;always块得到触发则开始计算RHS,always块结束,方可更新LHS;

4-所谓非阻塞,即该语句未完成赋值(LHS未得到值)时其他语句也可以开始计算RHS的操作,即计算RHS时,其中所涉及的变量也可以在别的Verilog语句中计算和更新。

5-非阻塞赋值操作只能对寄存器型变量赋值,只能用在initial块和always块中,不允许连续赋值;

6-常用于时序逻辑块中;

阻塞赋值(blocking)

[ b = a LHS = RHS ]

1-执行阻塞赋值语句,先计算RHS,计算时不允许其他语句的打断干扰,该语句完成后,其他赋值语句方可执行。

2-阻塞赋值只有一个完整的步骤----计算后即更新,所谓阻塞,即同一个always块中,后面的赋值语句要在前面的语句完成赋值后才可以开始赋值;

总结

1、时序逻辑建模、锁存器建模采用非阻塞赋值;

2、always块建立组合逻辑电路时,采用阻塞赋值;

3、同一个always块中,两者不能同时出现使用;

4、同一个always块建立时序和组合逻辑电路时,用非阻塞赋值;

5、不能在多个always块中为同一个变量赋值

举例:

题目描述:

异步复位的串联T触发器

实现方法:

`timescale 1ns/1nsmodule Tff_2 (input wire data, clk, rst,output reg q );//*************code***********//reg data_1;always @ (posedge clk or negedge rst) beginif (!rst)data_1 <= 1'b0;elsedata_1 <= data ^ data_1 ;//TFF关系为 Q*=Q^T;endalways @ (posedge clk or negedge rst) beginif (!rst)q <= 1'b0;elseq <= data_1 ^ q;end//*************code***********//endmodule

二、条件、分支语句与循环语句

Verilog的过程块提供了丰富的语句集,在过程块中,可以将多条语句合成一组,进行行为级描述。

条件语句(if_else)与分支语句(case)

题目描述1:

实现方法:

`timescale 1ns/1nsmodule multi_sel(input [7:0]d ,input clk,input rst,output reg input_grant,output reg [10:0]out);//*************code***********//reg [1:0]cnt;reg [7:0]data_reg;always@(posedge clk or negedge rst)beginif(!rst) begincnt <= 0;endelse if(cnt == 2'd3) begincnt <= 0;endelse begincnt <= cnt + 1'd1;endendalways@(posedge clk or negedge rst)beginif(!rst)begininput_grant <= 0;data_reg <= 0;endelse if(cnt == 2'd0) begin//没有复位且cnt置0,说明计满或者开始计数input_grant <= 1;data_reg <= d;//读取输入数据endelse begininput_grant <= 0;data_reg <= data_reg;//读取输入数据endendalways@(posedge clk or negedge rst)beginif(!rst)out <= 0;else case(cnt)2'd0: out <= d;2'd1: out <= (data_reg<<2) - data_reg;//移位的优先级比加减法更低,前面加括号2'd2:out <= (data_reg<<3)- data_reg;2'd3: out <= (data_reg<<3) ;default: out <= 0;endcaseend //*************code***********//endmodule

题目描述2:

实现方法:

`timescale 1ns/1nsmodule data_cal(input clk,input rst,input [15:0]d,input [1:0]sel,output [4:0]out,output validout);//*************code***********//reg [3:0]data3_0;reg [3:0]data7_4;reg [3:0]data11_8;reg [3:0]data15_12;reg [4:0]out_reg;always@(posedge clk or negedge rst)beginif(!rst) begindata3_0 <= 4'b0;data7_4 <= 4'b0;data11_8 <= 4'b0;data15_12 <= 4'b0;endelse if(sel == 0)begin //这里必须要加上sel的判断信号作为赋值条件,题目要求只有在sel=0时输入有效,所以不能在所有上升沿都赋值data3_0 <= d[3:0];data7_4 <= d[7:4];data11_8 <= d[11:8];data15_12 <=d[15:12];endendalways@(posedge clk or negedge rst)beginif(!rst) beginout_reg <= 0;endelse if(sel == 0)beginout_reg <= 0;endelse case(sel)2'd1: beginout_reg <= data3_0 + data7_4;end2'd2: beginout_reg <= data11_8 + data3_0;end2'd3: beginout_reg <= data3_0 + data15_12;enddefault : out_reg <= 0;endcaseendassign validout = (sel ==0) ? 1'b0 : 1'b1;assign out = out_reg;//*************code***********//endmodule

循环语句(forever repeat while for )
forever语句

常用于产生周期性的波形,用来作为仿真测试信号。不能独立写在程序中,只能放在initial块里;

一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。

//实现一个时钟regclk ;initial beginclk = 0 ;forever beginclk = ~clk ;#5 ;endend

for语句

//初始化memoryinitial begin//读入两路的复乘系数coe和滤波系数for ( x =0 ;x<2500 ;x=x+1 ) beginIdata_m[x] <= 0;Qdata_m[x] <= 0;endfor ( y =0 ;y<33 ;y=y+1 ) beginQcoe_m[y] <= 0;Icoe_m[y] <= 0;endfor ( Z =0 ;Z<66 ;Z=Z+1 ) beginfilter_m[Z] <= 0;endend

while循环

while(满足条件继续执行否则退出)beginend//实现0-10计数reg [3:0] counter ;initial begincounter = 'b0 ;while (counter<=10) begin#10 ;counter = counter + 1'b1 ;endend//stop the simulationalways begin#10 ; if ($time >= 1000) $finish ;endendmodule

repeat循环

repeat 的功能是执行固定次数的循环,它不能像 while 循环那样用一个逻辑表达式来确定循环是否继续执行。

repeat 循环的次数必须是一个常量、变量或信号。如果循环次数是变量信号,则循环次数是开始执行 repeat 循环时变量信号的值。即便执行期间,循环次数代表的变量信号值发生了变化,repeat 执行次数也不会改变。

//语法格式repeat (loop_times)beginend//连续存储always @(posedge clk or negedge rstn) beginj = 0 ;if (!rstn) beginrepeat (8) beginbuffer[j] <= 'b0 ;//没有延迟的赋值,即同时赋值为0j = j + 1 ;endendelse if (enable) beginrepeat (8) begin@(posedge clk) buffer[j] <= counter3 ; //在下一个clk的上升沿赋值j = j + 1 ;endendend

三、块语句

顺序块

顺序块用关键字 begin 和 end 来表示。

顺序块中的语句是一条条执行的。非阻塞赋值除外。

并行块

并行块有关键字 fork 和 join 来表示。

并行块中的语句是并行执行的,阻塞形式的赋值也是并行执行。

举例

`timescale1ns/1nsmodule test ;reg [3:0] ai_sequen2, bi_sequen2 ;reg [3:0] ai_paral2, bi_paral2 ;//顺序块和并行块的嵌套使用initial begin: block_out // 块语句命名,可以通过disable block_out禁用ai_sequen2 = 4'd5 ; //at 0ns//顺序块中每条语句的时延总是与其相邻的前面语句执行的时间相关。fork: block_in//并行块中每条语句的时延都是与块语句开始执行的时间相关。#10 ai_paral2= 4'd5 ; //at 10ns#15 bi_paral2= 4'd8 ; //at 15nsjoin//前一语句结束时为15ns#20 bi_sequen2= 4'd8 ; //at 35nsendendmodule

四、生成块

用途:

Verilog中的generate语句常用于编写可配置的、可综合的RTL的设计结构。它可用于创建模块的多个实例化,或者有条件的实例化代码块。

语法:

generate相关的有generate for——用来构造循环结构,用来多次实例化某个模块;

generate if, generate case——用来在多个块之间最多选择一个代码块;

generate block,genvar;

用法:

generate的用法还是很宽泛的,它和module可以说是一个等级的。

1.在generate中的要求和在module中很类似,因为generate就是生成一个电路,电路结构就是你在generate中表述的内容。

2.可以独立存在于generate块或者module的应当是变量声明,常量定义,assign赋值,门级语句,块声明,实例调用方法(I/O匹配表);像if-else,while,for,case这类的语句都是高级语句,是不能独立出现的,必须放在initial或always块中。

3.在generate block里面可以有:instance 实例化,assign 语句,always 模块。

举例:

generate for

//首先使用genvar声明循环中使用的临时索引变量,被用来判断generate循环是否继续;//genvar声明在生成块内部外部均可,不同块使用相同的变量名亦可只要不嵌套,仿真时该变量不存在;//在“展开”生成循环的每个实例中,将创建一个隐式localparam,其名称和类型与循环索引变量相同。它的值是“展开”循环的特定实例的“索引”。可以从RTL引用此localparam以控制生成的代码,甚至可以由分层引用来引用。(这里不太理解)

module alu ( inputa, b,output sum,cout);assign sum = a ^ b;assign cout = a & b;endmodulemodule my_design#(parameter N=4)input [N-1:0] a, b,output [N-1:0]sum, cout);genvar i;// Generate for loop to instantiate N timesgenerate (optional)for (i =; i< N; i++) begin: genalu alu_inst (a[i],b[i],sum[i], cout[i]);endendgenerateendmodule

case generate & if generate

参考链接

五、参考资料

1-菜鸟教程

2-Verilog数字系统设计教程讲解

3-generate理解

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。