资源描述
2024/4/18周四第第3章章 Verilog硬件描述语言(三)硬件描述语言(三)3.4 Verilog HDL行为语句v赋值语句赋值语句v顺序块和并行块语句顺序块和并行块语句v过程模块的结构说明语句过程模块的结构说明语句v条件语句条件语句v循环语句循环语句v命令语句命令语句2024/4/18周四3.4.1 赋值语句vVerilog HDLVerilog HDL常用赋值方式有过程赋值和连续赋值两常用赋值方式有过程赋值和连续赋值两种种 v过程赋值语句的更新对象是寄存器,整数,实数等,过程赋值语句的更新对象是寄存器,整数,实数等,这些类型变量在被赋值后,可以保持不变,直到赋这些类型变量在被赋值后,可以保持不变,直到赋值进程又被触发,变量才被赋予新值。值进程又被触发,变量才被赋予新值。v连续赋值语句中,任何一个操作数的变化都会重新连续赋值语句中,任何一个操作数的变化都会重新计算赋值表达式,重新进行赋值。计算赋值表达式,重新进行赋值。过程赋值 v阻塞赋值:操作符是用阻塞赋值:操作符是用“=”例例3-293-29:always always (posedge clkposedge clk)beginbegina=b+1;a=b+1;c=a;c=a;endend 过程赋值v非阻塞赋值:操作符是用非阻塞赋值:操作符是用“=”表示表示例例3-30:always(posedge clk)begina=b+1;c=a;end 连续赋值语句v连续赋值常用于数据流行为建模。连续赋值常用于数据流行为建模。v语句格式:语句格式:assign 赋值目标线网赋值目标线网 表达式表达式;v例例3-31:assigna=b|c;assignc,sum3:0=a3:0+b3:0+c_in;assignc=max(a,b);v说明:说明:(1 1)式子左边的式子左边的“赋值目标线网赋值目标线网”只能是线网变量。只能是线网变量。(2 2)式子右边表达式的操作数可以是线网,可以是寄存式子右边表达式的操作数可以是线网,可以是寄存器,也可以是函数。器,也可以是函数。(3 3)一旦等式右边任何一个操作数发生变化,右边的表一旦等式右边任何一个操作数发生变化,右边的表达式就会立刻被重新计算,再进行一次新的赋值。达式就会立刻被重新计算,再进行一次新的赋值。(4 4)assignassign可以使用条件运算符进行条件判断后赋值可以使用条件运算符进行条件判断后赋值assign data_out=sel?a:bassign data_out=sel?a:b;过程赋值和连续赋值的区别begin执行语句1;执行语句2;.end顺序块语句 begin 块名块内变量、参数定义;执行语句1;执行语句2;.end格式:格式:并行块v格式:fork 执行语句1;执行语句2;joinfork 块名 块内变量、参数定义语句;执行语句1;执行语句2;join顺序块和并行块程序执行过程的区别例3-32:并行块:forks=0;#2s=1;#4s=0;#7s=1;#8s=0;join顺序块:begins=0;#2s=1;#2s=0;#3s=1;#1s=0;end3.4.3 结构说明语句v1initial 语句语句语句格式:initialbegin语句1;语句2;endv一个模块中可以包含多个一个模块中可以包含多个initialinitial语句,所有的语句,所有的initialinitial语句都同时从语句都同时从0 0时刻开始并行执行,但是只时刻开始并行执行,但是只能执行一次。能执行一次。vinitialinitial语句常用于测试文本中信号的初始化,生语句常用于测试文本中信号的初始化,生成输入仿真波形,监测信号变化等。成输入仿真波形,监测信号变化等。v也可以使用也可以使用forkforkjoin join 对语句进行组合对语句进行组合。例3-33:timescale1ns/100psreg1:0a,b;regc;initialbegina=1;b=0;#10begina=2;b=3;end#10begina=0;b=2;endendinitialc=1;always 语句 v语句格式:语句格式:always 语句或语句组语句或语句组说明:说明:1)1)alwaysalways的触发事件可以是控制信号的变化、时钟边沿的触发事件可以是控制信号的变化、时钟边沿的跳变等。的跳变等。alwaysalways块的触发控制信号可以是一个,也块的触发控制信号可以是一个,也可以是多个,其间用可以是多个,其间用oror连接连接例:always (posedge clock or posedge reset)always (a or b or c or d)2 2)只要)只要 alwaysalways的触发事件产生一次,的触发事件产生一次,alwaysalways就会执行就会执行一次。在整个仿真过程中,如果触发事件不断产生,则一次。在整个仿真过程中,如果触发事件不断产生,则alwaysalways中的语句将被反复执行中的语句将被反复执行 例例3-343-34:reg q;reg q;always (posedge clock)always (posedge clock)q=d;q=d;v一个模块中可以有多个一个模块中可以有多个alwaysalways语句,每个语句,每个alwaysalways语句的执行时间各个语句的执行时间各个alwaysalways语句书写的前后顺序语句书写的前后顺序无关无关 例例:always(posedgeclk)if(rst)counter=4b0000;elsecounter=counter+1always(counter)$display(thecounteris=%d,counter);v练习:分别用assign,always语句实现模块模块名:my_module输入信号:位宽:1bit信号名:data_in1,data_in2,data_in3输出信号:位宽3bits信号名:data_out功能描述:data_out2=data_in1&data_in2data_out1:0=data_in1+data_in2+data_in32024/4/18周四任务(task)v语句格式:语句格式:task task 任务名;任务名;语句语句1 1;语句语句2 2;endtaskendtask1)1)任务定义在关键字任务定义在关键字“tasktask”和和“endtaskendtask”之间之间 2 2)任务调用与变量的传递,输入和输出是局部寄存)任务调用与变量的传递,输入和输出是局部寄存器,执行完返回结果。器,执行完返回结果。格式:任务名(端口格式:任务名(端口1 1,端口,端口2 2,端口,端口n n)3 3)当任务被调用时,任务被激活。同时一个任务可)当任务被调用时,任务被激活。同时一个任务可以调用别的任务或函数以调用别的任务或函数 moduletop;./例化一个fifofifoctlr_ccu1(.clock_in(clockin),.write_enable(write_enable),write_data(write_data),read_enable(read_enable).);taskwriteburst;input7:0wdata;beginalways(posedgeclockin)beginwrite_enable=#21;write_data=#2wdata;endendendtaskinitialbeginwriteburst(128);.endendmodule4 4)任务也可以没有参数的输入,只执行操作)任务也可以没有参数的输入,只执行操作例例3-37:将输入信号的与和或的结果分别输出:将输入信号的与和或的结果分别输出module result(data_in1,data_in2,data_out1,data_out2);.reg data_out1,data_out2;task example;/定义任务定义任务examplebegin data_out1=data_in1&data_in2;data_out2=data_in1|data_in2;endendtaskalways (data_in1 or data_in2)example;endmodulemodule operation;parameter delay=10;reg15:0 A,B;reg15:0 AB_AND,AB_OR,AB_XOR;always(A or B)beginbitwise_oper(AB_AND,AB_OR,AB_XOR,A,B);endtask bitwise_oper;output 15:0 ab_and,ab_or,ab_xor;input 15:0 a,b;begin#delay ab_and=a&b;ab_or=a|b;ab_xor=a b;endendtaskendmodule函数(function)v语句格式:语句格式:function function 函数名;函数名;beginbegin语句;语句;endendendfunctionendfunction1)函数定义在关键字)函数定义在关键字“function.”和和“endfunction”之间,函数的目的是返回一个之间,函数的目的是返回一个用于表达式的值用于表达式的值 例例3-38:function3:0 max;input3:0 a,b;begin if(ab)max=a;else max=b;endendfunction 函数的定义使得在模块中定义了一个和函数同函数的定义使得在模块中定义了一个和函数同名,位宽相同的寄存器类型变量名,位宽相同的寄存器类型变量 2 2)函数的调用是用和函数同名的寄存器变量作为表函数的调用是用和函数同名的寄存器变量作为表达式的操作数来进行,并根据函数输入数据的要达式的操作数来进行,并根据函数输入数据的要求,携带、传送数据。求,携带、传送数据。例:调用前述定义的例:调用前述定义的maxmax函数函数 c=max(10,5);c=max(10,5);3.4.4 条件语句 vif语句1格式:(1)if(表达式);(2)if(表达式);else;(3)if(表达式1);elseif(表达式2);elseif(表达式n);else;vifif后面的表达式,可以是逻辑表达式、关系表达后面的表达式,可以是逻辑表达式、关系表达式还可以是操作数式还可以是操作数 。v如如 if(a)if(a)等价于等价于 if(a=1)if(a=1)v如果如果ifif和和elseelse后有多个执行语句,可以用后有多个执行语句,可以用beginbegin endend块将其整合在一起块将其整合在一起 例例3-39:if(ab)begindata_out1=a;data_out2=b;endelsebegindata_out1=b;data_out2b)if(c)data_out=c+1;elsedata_out=a+1;elsedata_out=b;v如果不正确使用如果不正确使用elseelse,可能会生成不需要的锁,可能会生成不需要的锁存器存器。例3-41:always(aorb)beginif(a)data_out=a;endvif-elseif-else表达了一个条件选择的设计意图,它与条表达了一个条件选择的设计意图,它与条件运算符有重要的区别件运算符有重要的区别条件运算符可以出现在一个表达式中。条件运算符可以出现在一个表达式中。if-elseif-else只能出现在只能出现在always,initialalways,initial块语句,或块语句,或函数、任务中,一般只能在行为建模中使用。函数、任务中,一般只能在行为建模中使用。课堂练习v设计四位计数器(使用设计四位计数器(使用always,if-elsealways,if-else语句)语句)输入:输入:CLK,RST,ENACLK,RST,ENA输出:输出:Q Q(位宽(位宽4bits)4bits)功能描述:功能描述:当当RSTRST有效(等于有效(等于1 1)时,输出置零)时,输出置零;ENA;ENA有效有效RSRS无无效时,将对效时,将对CLKCLK的输入个数进行计数的输入个数进行计数2024/4/18周四课堂练习vmodule CNT4B(CLK,RST,ENA,OUTY,COUT);vinput CLK,RST,ENA;voutput3:0 Q;vreg3:0 Q;vreg COUT;v valways(posedge CLK or negedge RST)vbeginvif(RST)vbeginv Q=4b0000;vendvelsevif(ENA)vbeginv Q=Q+1;vendvendv endmodule2024/4/18 周四case语句 v如果选项数目很多,用如果选项数目很多,用if-else-ifif-else-if会不方便,可会不方便,可使用使用casecase语句。语句。v语句格式:语句格式:case(case(控制表达式控制表达式)分支表达式分支表达式1 1:语句语句1;1;分支表达式分支表达式n:n:语句语句n;n;default:default:默认语句默认语句;endcaseendcase例3-42:用case语句实现四选一电路modulemux4(clk,rst,data_in1,data_in2,data_in3,data_in4,select,data_out);input3:0data_in1,data_in2,data_in3,data_in4;input1:0select;inputclk,rst;output3:0data_out;reg3:0data_out;always(posedgeclk)if(rst)data_out=4b0000;elsecase(select)2b00:data_out=data_in1;2b01:data_out=data_in2;2b10:data_out=data_in3;2b11:data_out=data_in4;default:$display(thecontrolsignalisinvalid);endcaseendmodulev如果多个不同的状态值有相同的执行语句,可如果多个不同的状态值有相同的执行语句,可以用逗号将各个状态隔开。以用逗号将各个状态隔开。例例3-43:case(select)2b00:data_out=data_in1;2b01:data_out=data_in2;2b10:data_out=data_in3;2b11:data_out=data_in4;2b0 x,2bx0,2b1x,2bx1,2bxx:data_out=4bxxxx;2b0z,2bz0,2b1z,2bz1,2bzz:data_out=4bzzzz;default:$display(thecontrolsignalisinvalid);endcasev建议在建议在casecase语句中最好加入语句中最好加入defaultdefault分支分支 3.4.5 循环语句 v循环语句只能在initial,always块中使用。v下面介绍常用的循环句:for、forever、repeat和while2024/4/18周四for语句v语句格式:for(表达式1;表达式2;表达式3)语句;2024/4/18周四初始条件表达式循环终止条件改变循环控制变量的赋值语句语句执行过程语句执行过程例3-44:用for语句对存储器组进行初始化。reg7:0my_memory511:0;integeri;initialbeginfor(i=0;i512;i=i+1)my_memoryi=8b0;end2024/4/18周四例:initialbeginfor(i=0;i32;i=i+2)stagei=0;for(i=1;i32;i=i+2)statei=1;end2024/4/18周四实现了:实现了:所有偶元素初始化为所有偶元素初始化为0所有奇元素初始化为所有奇元素初始化为1vfor循环一般用于具有固定开始和结束条件的循环,如果只有一个执行循环的条件,最好还是用while循环2024/4/18周四while语句v语句格式:while(条件表达式)语句语句执行过程先求解条件表达式的值,如果值为真(等于1),执行内嵌的执行语句(组),否则结束循环。如果一开始就不满足条件表达式,则循环不执行。2024/4/18周四例3-45:用while语句求从1加到100的值,加法完成后打印结果modulecount(clk,data_out);inputclk;output12:0data_out;reg12:0data_out;integerj;initial/data_out和j赋初值为0begindata_out=0;j=0;endalways(posedgeclk)beginwhile(j=100)begindata_out=data_out+j;j=j+1;end$display(thesumis%d,j=%d,data_out,j);endendmodule语句格式:forever语句;v表示永久循环,无条件地无限次执行其后的语句,相当于while(1),直到遇到系统任务$finish或$stopv不能独立写在程序中,必须写在initial结构中。2024/4/18周四foreverforever语句语句 例3-46:使用forever语句生成一个周期为20个时间单位的时钟信号。regclock;initialbeginclock=0;forever#10clock=clock;end2024/4/18周四repeat语句v语句格式:repeat(表达式)语句repeat语句执行其表达式所确定的固定次数的循环操作。其表达式通常是常数,也可以是一个变量,或者一个信号,如果是变量或者信号,循环次数是循环开始时刻变量或信号的值,而不是循环执行期间的值2024/4/18周四modulemux(data_in1,data_in2,data_out);input3:0data_in1,data_in2;output7:0data_out;reg7:0data_out;reg7:0data_in1_shift,data_in2_shift;initialbegindata_in1_shift=data_in1;data_in2_shift=data_in2;data_out=0;repeat(4)beginif(data_in2_shift0)data_out=data_out+data_in1_shift;data_in1_shift=data_in1_shift1;endendendmodule系统任务和系统函数$符号表示符号表示 Verilog Verilog 的系统任务和函数的系统任务和函数常用的系统任务和函数有下面几种:常用的系统任务和函数有下面几种:1)$time/找到当前的仿真时间2)$display,$monitor/显示和监视信号值的变化3)$stop/暂停仿真4)$finish/结束仿真5)$readmemb和$readmemh/*将文件中的数据读到存储器阵列中*/6)$fopen和$fclose2024/4/18周四$display v用于变量,字符串,表达式的屏幕显示,格式:$display(p1,p2,pn);v表3.8,表3.92024/4/18周四例3-48:$display(TESTEDCOMPLETEPNSEQUENCErollingovertotestagain.);显示结果:TESTEDCOMPLETEPNSEQUENCErollingovertotestagain.$display(a=%d,b=%2.2f”,a,b);/数值的显示,设a=5,b=2.345显示结果:a=5,b=2.35$display(“hellonworld);/特殊字符的显示显示结果:helloworld2024/4/18周四$monitor v函数提供了对信号变化进行监控的功能,格式:$monitor(p1,p2.pn);p1,p2.pn可以是字符串,变量,表达式,时间函数$time等。2024/4/18周四v在整个仿真过程中,在任意一个时刻,只要监测的一个或多个变量发生变化时,就会启动$monitor函数,输出这一时刻的数值情况。例:initial$monitor($time,”a=%b,b=%h”,a,b);/*每当a 或b值变化时该系统任务都显示当前的仿真时刻并分别用二进制和十六进制显示信号a和 b的值*/2024/4/18周四说明:说明:说明:v$monitor函数一般书写在initial块中,即,只需调用一次$monitor函数,在整个仿真过程中都有效,这与$display不同。v在仿真过程中,若在源程序中调用了多个$monitor函数,只有最后一个调用有效。vVerilog语言提供了两个用于控制监控函数的系统任务$monitoron,$monitoroff,$monitoron用于启动监控任务,$monitoroff用于关闭监控任务。2024/4/18周四$stop和$finishv$stop暂停仿真,进入交互模式,将控制权交给用户;v$finish结束仿真过程,返回主操作系统2024/4/18周四例3-49initialbegin#100begina=1;b=1;end#100$stop;/在200ns暂停仿真,交由用户控制#200$finish;/在400ns时,退出仿真end2024/4/18周四$readmemb和$readmemh格式:$readmemb(“文件名”,存储器名,起始地址,终止地址);$readmemh(“文件名”,存储器名,起始地址,终止地址);2024/4/18周四moduletest();reg1:0my_mem7:0;integeri;initialbegin$readmemb(D:/test/my_data.dat,my_mem);for(i=0;i8;i=i+1)$display(my_mem%d=%b,i,my_memi);endendmodule/定义了8个宽度为2位存储器组/将位于D:/test目录下的my_data.dat中的数据读入my_mem中其中my_data.dat如下内容:00011011000110112024/4/18周四执行结果如下:memory 0=00memory 1=01memory 2=10memory 3=11memory 4=00memory 5=01memory 6=10memory 7=11v数据文件中可以用将数据存入存储器的指定位置,地址用十六进制数表示,和间不能有空格。例:1000061xz1执行结果如下:my_mem0=xxmy_mem1=00my_mem2=00my_mem3=xxmy_mem4=xxmy_mem5=xxmy_mem6=1xmy_mem7=z1v语句中的起始地址和终止地址的不同定义对数据装载有影响例:initial$readmemh(“mem.data”,mem);initial$readmemh(“mem.data”,mem,16);2024/4/18周四$fopen和$fclosevVerilog语言支持将仿真结果输出到指定的文件中,使用系统函数$fopen打开一个可以写入数据的文件;再使用系统任务$fclose将前面打开的文件关闭。v格式:=$fopen(“文件名”);2024/4/18周四3.4.7 编译预处理命令v在进行Verilog语言综合时,综合工具首先对这些编译预处理命令进行“预处理”,然后将得到的结果和源程序一起再进行通常的编译处理。v编译预处理指令前有一个标志符“”(反引号)加以确认。v其作用范围是:命令定义后直到本文件结束或其他命令替代或取消该命令为止。2024/4/18周四宏定义命令 definev宏定义define指定一个宏名来代表一个字符串。v语句格式:define宏名字符串2024/4/18周四说明v为与变量名区别,建议使用大写字符定义宏名。v在源文件中引用已定义的宏名时,必须在宏名前加“”。例:defineADDa+b/用a+b表示ADD字符串assignc=ADD;2024/4/18周四v宏定义可嵌套使用。例:defineADD1a+bdefineADD2ADD1+dassigndata_out=ADD2;2024/4/18周四/等同于data_out=a+b+d;条件编译命令 ifdef、elsif、else和endifv应用场合:在一些特定的情况下,对源程序中满足指定编译条件的语句才进行编译,或者满足某条件时,对一组语句进行编译,否则编译另一组语句。v一般有以下几种情况:1)选择模块的不同代表部分2)选择不同的时序或结构信息3)对不同的EDA工具,选择不同的激励。2024/4/18周四格式v格式1:ifdef宏名(标识符)程序段1else程序段2endif2024/4/18周四格式2:ifdef宏名(标识符)程序段1endif文件包含命令 includev文件包含是指一个源文件可以将另外一个源文件的内容全部“拷贝”过来,作为一个源程序进行编译。v语句格式:include“文件名”2024/4/18周四说明:v该语句可以出现在VerilogHDL程序的任何地方。v编译时,“include文件名这一行文字由被包含的文件内容全部代替。v设计中可将常用的宏定义、任务、函数组成一个文件,用include命令包含到源文件中。v该语句后无分号。2024/4/18周四2024/4/18周四v文件包含命令可以:1)节省程序设计人员的重复劳动。将一些常用的宏定义命令或任务(task)组成一个文件,然后用include命令将这些宏定义包含到自己所写的源文件中,相当于工业上的标准元件拿来使用。2)一个源文件可能经常要用到另外几个源文件中的模块,遇到这种情况即可用include命令将所需模块的源文件包含进来。2024/4/18周四v一个include只能包含一个文件,如果要包含多个文件,需要写多个include命令。2024/4/18周四如果源文件top.v包含sourse1,而soruse1.v又需要用到sourse2.v的内容,则可以将soruse1.v和sourse2.v用include包含到源文件中,但是,sourse2.v应出现在sourse1.v之前。include“sourse2.v”include“sourse1.v”等价于2024/4/18周四时间尺度命令 timescalev使用timescale命令将单位时间与实际时间相关联。用于定义仿真时间、延迟时间的单位和时延精度。v格式:timescale时间单位/时间精度2024/4/18周四v时间单位是指时间和延迟的测量单位,时间精度是指仿真过程中延迟值进位取整的精度,时间精度应该小于等于时间单位。2024/4/18周四timescale1ns/100ps/表示时间单位为ns,时间精度为100psmoduletestbench();initialbegin/在0时刻,a=0,b=0a=0;b=0;/在0+10*1=10ns时,a=4;b=2#10begina=4;b=2;end/在0+10+20*1=30ns时,a=2;b=3;#20begina=2;b=3;endendendmodule2024/4/18周四例:timescale10ns/1nsmoduletest;regset;parameterd=1.55;initialbegin#dset=0;#dset=1;endendmodule2024/4/18周四根据时间精度,参数d值被从1.55取整为1.6。16ns时,set=032ns时,set=1
展开阅读全文