页数:79页文件大小:287.8 KB来源: 硬件描述语言和数字系统设计ppt课件
本课件系统讲解Verilog的各类语句:持续赋值与过程块的适用范围,always块敏感量列表的写法,阻塞与非阻塞赋值的区别及典型时序风险,过程块内的if、case条件语句与循环语句,以及function与task的用法。
硬件描述语言和数字系统设计
连续/持续赋值4.2过程块与always块@(敏感量)解释4.3阻塞赋值和非阻塞赋值4.4过程块内部使用的条件语句4.5过程块内部使用的循环语句4.6function和task的了解主要内容:
连续/持续赋值知识点:
基本语法
理解module mux2to1 (out, a, b, sel);input a, b, sel;output out;wire out;assignout=(sel)?b:a;endmodule为什么不可以去掉assign,直接使用out=(sel)?b:a;赋值?//去掉assign好像也可以描述相同的电路功能。
module mux2to1 (out, a, b, sel); input a, b, sel; output out; wire out; assignout=(sel)?b:a; endmodule答案:去掉assign是可以描述电路功能。但是无法模拟出电路的不断刷新的动作。所以采用保留字assign,来模拟表达式左边信号out,随右边表达式信号sel、a或者b的变化,而不断刷新的动作!;assignout=(sel)?b:a;在上面的例子中,只要右边信号sel或a或b的值发生了改变,EDA工具提取assign保留字,映射成左边信号out能及时反应最新的逻辑结果。用assign赋值反应出这种不断刷新的过程,让建模语句的描述与实际电路工作情况吻合!
wire buserr, z; 例1:assign buserr = Parity| (One & OP); 例2:assign z= (A|B) & (C|D) & (E|F); 例2中,只要右边的信号A、B、C、D、E或F的值变化,右边整个表达式的逻辑将被刷新,结果Z将刷新为最新值。4.1.3连续赋值语句使用举例;目标是一个向量线网和一个标量线网的拼接结果。例3:wire Cout, Cin; wire [3:0] Sum, A, B; . . .assign {Cout, Sum} = A + B + Cin; 因为A和B是4位宽,加操作的结果最大能够产生5位结果。左端表达式的长度指定为5位(Cout 1位,Sum 4位)。赋值语句因此促使右端表达式最右边的4位的结果赋给Sum,第5位(进位)赋给Cout。;连续赋值的目标类型
例:用连续赋值方式描述1位全加器module FA_Df (A, B, Cin, Sum, Cout ); input A, B, Cin; output Sum, Cout; assign Cout=(A&Cin)|(B&Cin)|(A&B); assign Sum =A^B^Cin; endmodule4.1.5连续赋值语句的并行执行情况;用连续赋值方式描述1位全加器(cont.)在本例中,有两个连续赋值语句:assign Sum =A^B^Cin; assign Cout=(A&Cin)|(B&Cin)|(A&B); 这两个赋值语句是并行执行的,与其书写的顺序无关。只要信号A或者B或者Cin任何一个信号发生改变,和信号Sum与高位进位信号Cout的值就会立即相应的进行刷新,跟代码的前后顺序无关。;modulemux4to1_right(MUX1,a,b,c,d,sel);outputMUX1;inputa,b,c,d;input[1:0]sel;assignMUX1=(sel==2'b00)?a:((sel==2'b01)?b:((sel==2'b10)?c:d));endmodule错误表达:modulemux4to1_wrong(MUX2,a,b,c,d,sel1,sel2);input a, b, c, d;input sel1,sel2;output MUX2;wire MUX2;assignMUX2=(sel1)?b:a;//画出电路逻辑图assignMUX2=(sel2)?c:d;//为什么不能生成电路???endmodule134.1.6连续赋值语句的线与问题为什么这种做法不对????
线与逻辑是两个输出信号直接相连,实现与的功能。在CMOS工艺下,线与会使灌电流过大,而烧坏逻辑门。要用oc门或者od门来实现。(还可以继续深入下去:为什么oc门和od门可以实现线与逻辑?如何实现?)
么是"线与"逻辑,要实现它,在硬件特性上有什么具体要求?(汉王)
(敏感量)解释知识点:
(procedural)块
过程赋值(procedural assignment)的信号类型练习信号类型改错:module adder (out, a, b, cin); input a, b, cin; output [1:0] out; wire a, b, cin; reghalf_carry;wire half_sum; assignout = {half_carry, half_ sum}; always @( a or b or cin)beginhalf_sum = a ^ b ^ cin; half_carry= (a & b) | (a & cin) |(b & cin ); endendmodule;例如:module adder (out, a, b); input [2: 0] a, b; output [3: 0] out; reg [3: 0] out; always@( a or b)//过程块内语句描述电路功能://包括过程块赋值语句(=、<=)和条件判断语句等endendmodule1.过程块内语句描述具体电路结构、功能;2.过程块内语句多行用begin、end引导;3.用@(敏感量)来控制块里语句描述的电路刷新条件,如例题中,将敏感量改为always @( a)与always @( a or b)时电路刷新有什么不同?;module reg_ adder (out, a, b, clk); input clk; input [2: 0] a, b; output [3: 0] out; reg [3: 0] out; reg [3: 0] sum;//与wire [3:0] sum;assign sum = a + b; 相似endmodule;用关键字posedge(上升沿)和negedge(下降沿)限定信号敏感边沿。敏感表中可以有多个信号,用关键字or连接。module reg_ adder (out, a, b, clk); input clk; input [2: 0] a, b; output [3: 0] out; reg [3: 0] out; reg [3: 0] sum;endmodule;LOCKING、NONBLOCKING赋值的区别。(南山之桥)
知识点:
赋值操作符是“=”的过程赋值是阻塞性过程赋值。例如,RegA = 52;是阻塞性过程赋值。阻塞性过程赋值是顺序执行的,即写在前面的语句先执行,写在后面的语句后执行。
例1:…input A,B,Cin;output Cout;reg T1 , T2 , T3;always@(A or B or Cin)beginT1 = A&B; T2 = B & Cin; T3 = A & Cin; Cout = T1 | T2 | T3; end…T1赋值首先发生,计算T1;接着执行第二条语句,T2被赋值;然后执行第三条语句,T3被赋值;最后才执行Cout赋值语句。(如果某时刻,A信号变为1,B变为1,Cin变为0,然后过了t时刻,A从1变为0,此时假如B、Cin保持不变);上例中,如果将语句顺序换换,会有什么样的结果?如改为,例2:…input A,B,Cin;output Cout;reg T1 , T2 , T3;always@(A or B or Cin)beginCout = T1 | T2 | T3; T1 = A&B; T2 = B & Cin; T3 = A & Cin; End…(如果某时刻,A信号变为1,B变为1,Cin变为0,然后过了t时刻,A从1变为0,此时假如B、Cin保持不变,会有什么情况发生,Cout值为什么与例1不同?如何解决这个问题?);改正为例3:reg T1 , T2 , T3; reg Cout; always@(A or B or Cin orT1 or T2 or T3 )beginCout = T1 | T2 | T3; T1 = A&B; T2 = B & Cin; T3 = A & Cin; end问题得以解决!(如果某时刻,A信号变为1,B变为1,Cin变为0,然后过了t时刻,A从1变为0,此时假如B、Cin保持不变);或者改正为,例4:reg T1 , T2 , T3; reg Cout; always@(A or B or Cin orT1 or T2 or T3 )beginT1 = A&B; T2 = B & Cin; T3 = A & Cin; Cout = T1 | T2 | T3; end问题得以解决!实际工程中,例1、例2表达方式均不使用,而使用例3、例4方式!(如果某时刻,A信号变为1,B变为1,Cin变为0,然后过了t时刻,A从1变为0,此时假如B、Cin保持不变);1.在非阻塞性过程赋值中,使用赋值符号“< =”。2.非阻塞性过程赋值是并行执行的,即写在前面的语句与写在后面的语句同时执行,跟书写顺序没有关系。
例如:reg T1 , T2 , T3; reg Cout; always@(posedge clk)beginT1 <= A&B;T2 <= B & Cin;T3 <= A & Cin;Cout <= T1 | T2 | T3;end左边蓝色部分描述的逻辑跟右边绿色部分描述的逻辑完全一样,跟书写顺序没有关系!;句本身生成的逻辑电路有任何不同,但是会影响以后对赋值结果的使用。强烈建议!!!描述组合逻辑使用阻塞式赋值;而描述时序逻辑使用非阻塞式赋值。
下面这些表达的区别??:表达一(建议不使用该方式):module ……..reg B , out; always@ (A)beginout = B; B = A; endendmodule表达二(建议不使用该方式):reg B , out; always@ (A)beginB = A; out = B; end;表达三(可使用方式):module …..; reg B , out; always@ (A or B)beginB = A; out = B; endendmodule表达四(可使用方式):reg B , out; always@ (A or B)beginout = B; B = A; end;表达五(可使用方式):module …….reg B , out; always@ (A)B = A; always@ (B)out = B; endmodule;表达六(可使用方式):module …….wire B , out; assign B = A; assign out = B; endmodule;例1:module adder (out, a, b, cin); input a, b, cin; output [1:0] out; wire a, b, cin; reghalf_carry;wirehalf_sum; assign out = {half_carry, half_ sum}; assign half_sum = a ^ b ^ cin; always @( a or b or cin)beginhalf_carry = (a & b) | (a & cin) |(b & cin ); endendmodule;例2:modulereg_ adder (out, a, b, clk); input clk; input [2: 0] a, b; output [3: 0] out,sum; reg [3: 0] out; reg [3: 0] sum; always @( posedge clk)out <= a-b; always @( a or b)sum = a + b; endmodule;两种不同过程赋值语句的区别
综合时,网线数据类型的变量会被映射成硬件中的连线;寄存器数据类型的变量根据被赋值的具体情况,被映射成连线、触发器或者锁存器。下面详细讨论寄存器数据类型的变量。
寄存器型变量被综合成网线:wire acr,bar,fra;reg trg,sqp;…always @ (acr or bar or fra or trq)begintrq=bar&acr; sqp=trq|fra; end;寄存器的变量被综合成触发器:module target(clk,clr,rega,regb,mask); input clk,clr; input [3:0] mask, rega,; output [3:0] regb; reg [3:0] regb; always @ (posedge clk)if(!clr)regb <=4'b0000; elseregb <= rega& mask; endmodule;寄存器的变量被综合成触发器2
限制!!!!对同一个赋值对象不能既使用阻塞赋值,又使用非阻塞赋值。!!!!在同一个过程块里面,不能既使用阻塞赋值,又使用非阻塞赋值。如://error1reg T1 , T2 , T3; reg Cout; always@(A or B or Cin)begin//CARRY_OUTT1<=A&B; T2<=B & Cin; T3<=A & Cin; Cout=T1 | T2 | T3; 第52页:module dff 代码示例
改错:module dff(rst,clk,d,q);output q; reg q;elseq<=d; endmodule赋值的限制-举例;
第53页:常见过程块的线与
问题module dff(rst,clk,d,q);output q; regq; always @(negedge rst)if (!rst)q <=1'b0; always @(posedge clk)q<=d; endmodule上面示例为什么出错,如何修改?;
第54页:module dff 代码示例(续1)
答案:出现了线与问题,改正如下:module dff(rst,clk,d,q);output q; reg q; always @(posedge clk or negedge rst)if (!rst)q <=1'b0; elseq<=d; endmodule;
第55页:过程块内部使用的条件语句
过程块内部使用的条件语句知识点:
- 4.4.1条件语句-if语句
- 4.4.2条件语句-case分支语句
第56页:条件语句-if语句
- if语句的语法如下
- if(condition_1)beginprocedural _ statement _ 1endelse if(condition_2)beginprocedural _ statement _ 2endelseprocedural _ statement _ 3
第57页:if语句示例if
(Sum < 60)Total _A<=Total_A+1;else if(60< Sum<75)Total _B<=Total _ B +2;elseTotal _C<= Total _C+3;
第58页:条件语句-case分支语句
module compute (result, rega, regb, opcode); input [7: 0] rega, regb; input [2: 0] opcode; output [7: 0] result; reg [7: 0] result; always @( rega or regb or opcode)case (opcode)3'b000 :result = rega + regb; 3'b001 :result = rega-regb; 3'b010:3'b100 :result = rega & regb; default :result =8'b0; endcaseendmodulecase语句:在Verilog中重复说明case项是合法的,因为Verilog的case语句只执行第一个符合项。;
第59页:case语句是测试表达式与另外一系列表达
式分支是否匹配的一个多路条件语句。
- Case语句进行逐位比较以求完全匹配(包括x和z)。
- 多个default语句是非法的。重要内容:使用default语句是一个很好的编程习惯,特别是用于检测x和z。Casez和casex为case语句的变体,允许比较无关值。
- case表达式或case项中的任何位为无关值时,在比较过程中该位不予考虑。
- 在casez语句中,?和z被当作无关值。
- 在casex语句中,?,z和x被当作无关值。4.4.2条件语句-case分支语句
第60页:过程块内部使用的循环语句
过程块内部使用的循环语句知识点:
- 4.5.1循环语句
- 4.5.2 for语句示例
第61页:循环语句
Verilog HDL中有四类循环语句,它们是:1) forever循环2) repeat循环3) while循环4) for循环For循环语句是典型的能用于综合的循环语句。一个for循环语句按照指定的次数重复执行过程赋值语句若干次。
第62页:repeat:将一块语句循环执行确定次数
。repeat(次数表达式)<语句>while:在条件表达式为真时一直循环执行while(条件表达式)<语句>forever:重复执行直到仿真结束forever<语句>for:在执行过程中对变量进行计算和判断,在条件满足时执行for(赋初值;条件表达式;计算)<语句>综合工具还不支持,了解
第63页:for语句示例
…input [31:0] addr; output [3:0] line; reg [3:0] line; integer n;always @ (posedge clk)for(n=3; n>=0; n=n-1)if(addr==n)line[n]<=1; elseline[n]<=0;
第64页:function和task的了解
function和task的了解知识点:
- 4.6.1 Verilog的任务与函数
- 4.6.2任务task
- 4.6.3函数(function)
- 4.6.4实际工程中Function语句实例
- 4.6.5特别说明
第65页:Verilog的任务与函数
Verilog的任务与函数
- 任务(task)
- 通常用于调试
- 可以包含时序控制
- 可以有input,output,和inout参数
- 可以调用其他任务或函数
- 函数(function)
- 通常用于数学计算,描述组合逻辑
- 不能包含任何延迟;函数仿真时间为0
- 只含有input参数
- 由函数名返回一个结果
- 可以调用其他函数,但不能调用任务
- 任务和函数必须在module内定义和例化
第66页:任务task
任务既可表示组合逻辑又可表达时序逻辑,定义的形式如下:tasktask _ id;[declarations]procedural _ statementendtask任务可以没有或有一个或多个输入输出参数。值通过参数传入和传出。除input参数外,任务还能带有output参数(从任务中返回值)和inout参数。
第67页:task示例1moduleHas
_ Task……;….parameterMAXBITS =4'h8;taskReverse _ Bits;input[MAXBITS-1:0] Din;output[MAXBITS-1:0] Dout;integer k;beginfor (k = 0; k < MAXBITS; k = k + 1)Dout [MAXBITS-k] = Din[k] ;endendtask. . .endmodule
第68页:module mult 代码示例
modulemult(clk,a,b,out,en_mult); inputclk,en_adder; input[3:0]a,b; output[4:0]out; reg[4:0]out; always@(posedgeclk)adder_tme(a,b,en_adder,out);//任务定义input[3:0]add1,add2; inputen; output[4:0]result; if(en)result=add1+add2; endtaskendmoduletask示例2:任务调用时的参数按任务定义的顺序列出。;
第69页:函数
(function)函数表达的是组合逻辑。函数与任务的不同之处是函数只能返回一个值,它不能包含任何时延或时序控制(必须立即执行),函数必须带有至少一个输入,在函数中允许没有输出或输入输出说明。
第70页:module orand 代码示例
函数中不能有时序控制,但调用它的过程可以有时序控制。moduleorand(a,b,c,d,e,out); input[7:0]a,b,c,d,e; output[7:0]out; reg[7:0]out; always@(aorborcordore)out=f_or_and(a,b,c,d,e); function[7:0]f_or_and; input[7:0]a,b,c,d,e; if(e==1)f_or_and=(a|b)&(c|d); elsef_or_and=0; endfunctionendmodule;
第71页:主要特性:函数定义中不能包含任何时序控制
主要特性:
- 函数定义中不能包含任何时序控制语句。
- 函数至少有一个输入,不能包含任何输出或双向端口。
- 函数只返回一个数据,其缺省为reg类型。
- 传送到函数的参数顺序和函数输入参数的说明顺序相同。
- 函数在模块(module)内部定义。
- 虽然函数只返回单个值,但返回的值可以直接给信号连接赋值。这在需要有多个输出时非常有效。{o1,o2,o3,o4}=f_or_and(a,b,c,d,e);
第72页:module foo 代码示例
要返回一个向量值(多于一位),在函数定义时在函数名前说明范围。函数中需要多条语句时用begin和end。module foo; input [7: 0] loo; output [7: 0] goo;function[3: 0]zero_count; input [7: 0] in_ bus; reg [3:0] i;beginzero_count = 0; for (i = 4'h0; i < 4'h8; i = i + 1)if (! in_bus[ i ])zero_count = zero_count + 1; endendfunctionendmodule;
第73页:函数返回值可以声明为其它register
- 类型
- integer。在任何表达式中都可调用函数module checksub (neg, a, b);input a, b;output neg;reg neg;functioninteger subtr;input [7: 0] in_a, in_b;subtr = in_a-in_b;endfunctionalways @ (a or b)if (subtr( a, b) < 0)neg = 1;elseneg = 0;endmodule
第74页:函数中可以对返回值的个别位进行赋值
。函数值的位数、函数端口甚至函数功能都可以参数化。. . .parameter MAX_BITS = 8;reg [MAX_BITS: 1] D;function[MAX_BITS: 1]reverse_bits;input [MAX_BITS-1: 0] data;integer K;for (K = 0; K < MAX_BITS; K = K + 1)reverse_ bits[MAX_BITS-K] = data [K];endfunctionalways @ (posedge clk)D< =reverse_bits (D) ;. . .
第75页:实际工程中Function语句实例
- 例一
- function [22:0] uv_clamp;input [23:0]iuv;begin// Clamp to the most negative numberuv_clamp =(iuv[23:22]==2'd2)?23'h400001 :((iuv[23:22] == 2'd1)?23'h3fffff:iuv[22:0]);endendfunction
第76页:Verilog时序逻辑示例
always @(uvtmp_morei2tsw_u_morei2tsw_v_moruv_selorttt_uvtmp)case(uv_sel)2'd1:n_uvtmp = {ei2tsw_u_m, 5'b0}; 2'd2:// 2n_uvtmp = {ei2tsw_v_m, 5‘b0}; default:endcase// case (uv_sel);
第77页:例二:function [15
0]lod_clamp;input [16:0]ilod;beginlod_clamp=(ilod[16:15]==2 ' d2) ?16'h8000:((ilod[16:15] == 2'd1) ? 16'h7fff : ilod[15:0] );endendfunction
第78页:Verilog时序逻辑示例(续1)
always @(ei2tsw_lod_morlodtmp_morlod_selorttt_lodtmp)case (lod_sel)//synopsys parallel_case full_case2'd0:n_lodtmp = lodtmp_m; 2'd1:n_lodtmp = {ei2tsw_lod_m, 5‘b0}; default:endcase;
第79页:特别说明
特别说明
- begin-end和fork-join1. begin-end并不是顺序语句块,内部语句用阻塞赋值语句,当然是顺序执行
- 如果用非阻塞赋值语句,就是并行执行。2.实际工程中,描述可综合电路很少用fork-join。语句块-顺序语句块和并行语句块
下载地址:{{downurl}}
{{{a}}}
{{#b}}{{{b}}}
{{/b}} {{/title}} {{#nolog}}登陆注册
{{/nolog}} {{#djsx}}点我刷新
{{/djsx}} {{#gocz}} {{/gocz}} {{#ffqr}} {{/ffqr}}