1、编译的警告 Warning:Design contains 2 input pin(s)that do not drive logicWarning:No output dependent on input pin clk1Warning:No output dependent on input pin clk2 module shift_regester(data_in,data_out,clk1);input data_in,clk1;output data_out;reg1:7 reg_data;reg data_out;integer i;always(negedge clk1)beg
2、in data_out=reg_data1;for(i=1;i=7;i=i+1)reg_datai=reg_datai+1;reg_data7=data_in;end endmodule6.5 条件语句 与常用的高级程序语言一样,为了描述较为复杂 的时序关系,Verilog HDL提供了条件语句供分支判 断时使用。在可综合风格的Verilog HDL模型中常用 的条件语句有ifelse和caseendcase两种结构,用法和C程序语言中类似。两者相较,ifelse用于 不很复杂的分支关系,实际编写可综合风格的模 块、特别是用状态机构成的模块时,更常用的是 caseendcase风格的代码 If
3、_else语句 Case语句6.5.1 if-else条件语句 if-else条件分支语句的作用是根据指定的判断条件是否满足来确定下一步要执行的操作。它在使用时可以采用如下三种形式:(1)使用形式1:if ()语句或语句块;在if-else条件分支语句的这种使用形式中没有出现else项这种情况下条件分支语句的执行过程将是:如果指定的“”成立(也就是这个条件表达式的逻辑值为“1”),则执行条件分支语句内给出的“语句或语句块”,然后退出条件分支语句的执行。如果“”不成立(也就是条件表达式的逻辑值为“0”、“x”或“z”时),则不执行条件分支语句内给出的“语句或语句块”,而是直接退出条件分支语句的执
4、行。一条没有elseelse选项的ifif语句映射到硬件上,形成的是一个锁存器 例如下面这条条件分支语句:if(enable=1)out=data_in;在执行时就会根据条件表达式“enable=1”是否成立来决定 是否执行赋值语句“out=data_in;”:如果enable取值为“1”,则赋值语句得到执行,输出信号out得到data的值;如 果enable的值为“0”、“x”或“z”(取值不为“1”),则不 执行指定的赋值语句,输出信号out保持原有值不变。(2)使用形式2:if()语句或语句块1 else 语句或语句块2 这种形式的条件分支语句将以如下方式得到执行:如果指定的“”成立(也
5、就是这个条件 表达式的逻辑值为“1”),则执行条件分支语句第一行所指 定的“语句或语句块1”,然后结束条件分支语句的执行。如果“”不成立,则执行由条件分支语 句内第二行的else项所指定的“语句或语句块2”,然后结 束条件分支语句的执行。一条一有elseelse选项的ifif语句映射到硬件上,通常形成的是一个多路选择器(MUXMUX)例如,下面这条条件分支语句:if(select=1)out=input1;else out=input0;在执行时会根据条件表达式“select=1”是否成立来 决定执行两条过程赋值语句中的哪一条。如果select 取值为“1”,则第一行if这一项所指定的赋值语句
6、“out=input1;”得到执行,输出信号out得到input1的 取值;如果select取值不为“1”(取值为“0”、“x”或“z”),则执行第二行else项所指定的赋值语句“out=input0;”,输出信号out将得到input0的取值。(3)使用形式3:if ()语句或语句块1else if()语句或语句块2else if()语句或语句块nelse 语句或语句块n+1在这种使用形式中一共出现了n+1个条件分支项,其中每个分支项都指定了当该分支项的条件满足时所要执行的操作。在执行这种形式的if-else条件分支语句时,将按照各分支项的排列顺序对各个条件表达式是否成立作出判断,当遇到某一
7、项的条件表达式成立时,就执行这一项所指定的“语句或语句块”。比如假设“”成立,那么就执行“语句或语句块m”。如果所有的条件表达式都不成立,则执行最后的else项(这一项没有给出条件表达式)所指定的操作(语句或语句块n+1)。这种形式的if-else条件分支语句实现了一种多路分支选择控制。比如在例6-21给出的模块中就使用了这种形式的if-else条件分支语句。【例例6-21】第三种形式的if-else条件分支语句。module sel_from_three(q,sela,selb,a,b,c);input sela,selb,a,b,c;output q;reg q;always (sela
8、or selb or a or b or c)beginif(sela)q=a;else if(selb)q=b;else q=c;endendmodule在例6-21模块内的if-else条件分支语句中出现了三个分支项,这个条件分支语句在执行时将依次对控制信号sela和selb的取值是否为“1”进行判断:(1)如果sela的取值为1,则第一个分支项的条件表达式“(sela)”成立,因而第一个分支项所指定的赋值操作“q=a;”将得到执行。(2)如果sela的取值不为1,而selb的取值为1,则第二个分支项的条件表达式“(selb)”成立,因而第二个分支项所指定的赋值操作“q=b;”将得到执行。
9、(3)如果sela和selb的取值都不为1,则“(sela)”和“(selb)”这两个条件表达式都不成立,这时else分支项所指定的赋值操作“q=c;”将得到执行。(4)如果sela和selb的取值都是1,那么第一个条件表达式“(sela)”以及第二个条件表达式“(selb)”都是成立的。在这种情形下,由于首先被检测为成立的条件表达式是第一个分支项的条件表达式“(sela)”,所以此时将执行第一分支项指定的赋值操作q=a;”。图6.11 例6-21所示模块描述的电路功能二选一MUXbcse1b二选一MUXqase1a因此,例621所示模块描述的是图6.11所示的硬件电路功能。由上例条件表达式取
10、值的第四种情况我们可以看出:这种形式的if-else条件分支语句(第三种使用形式)内各个条件表达式的排列顺序决定了对各个条件进行判断的先后次序,这种排列顺序隐含着一种优先级关系,也就是说排在前面的分支项所指定的操作具有较高的优先级。比如,在前面讨论过的例中条件分支语句的第四种执行情况下,虽然两个条件表达式都是成立的,但是由于条件表达式“(sela)”排在“(selb)”的前面,所以“(sela)”这一项所对应的赋值语句“q=a;”具有较高优先级,因此这时得到执行的将是语句“q=a;”而不是“q=b;”。说明(1)三种形式的if语句中在if后面都有“表达式”,一般为逻辑表达式或关系表达式。系统对
11、表达式的值进行判断,若为0,x,z,按“假”处理,若为1,按“真”处理,执行指定的语句。(2)第二、第三种形式的if语句中,在每个else前面有一分号,整个语句结束处有一分号。例如:If(ab)out1=int1;else out1 b)begin out1=int1;out2=int2;end else begin out1=int2;out2=int1;end 注意在end后不需要再加分号。因为begin_end内是一个完整的复合语句,不需再附加分号 (4).允许一定形式的表达式简写方式。如下面的例子:if(expression)等同与 if(expression=1)if(!expres
12、sion)等同与 if(expression!=1)描述一个具有同步清零功能(低电平有效)的上升沿D D触发器 module dff_sync(q,d,clear,clk);module dff_sync(q,d,clear,clk);output q;output q;input d,clear,clk;input d,clear,clk;reg q;reg q;always(posedge clk)always(posedge clk)if(!clear)if(!clear)q=0;/q=0;/清零清零 elseelse q=d;/q0)for(scani=0;scani0)begin$d
13、isplay(.);memoryscani=0;end else/*WRONG*/$display(error-indexiszero)错误(6).if_else例子。下面的例子是取自某程序中的一部分。这部分程序用if_else语句来检测变量index以决定三个寄存器modify_segn中哪一个的值应当与index相加作为memory的寻址地址。并且将相加值存入寄存器index以备下次检测使用。程序的前十行定义寄存器和参数 /定义寄存器和参数。reg 31:0 instruction,segment_area255:0;reg 7:0 index;reg 5:0 modify_seg1,mo
14、dify_seg2,modify_seg3;parameter segment1=0,inc_seg1=1,segment2=20,inc_seg2=2,segment3=64,inc_seg3=4,data=128;/检测寄存器index的值 if(indexsegment2)begin instruction=segment_areaindex+modify_seg1;index=index+inc_seg1;end else if(indexsegment3)begin instruction=segment_areaindex+modify_seg2;index=index+inc_s
15、eg2;end else if(indexdata)begin instruction=segment_areaindex+modify_seg3;index=index+inc_seg3;end else instruction=segment_areaindex 模为60的BCD码加法计数器 module count60(qout,cout,data,load,reset,clk);output7:0 qout;output cout;input7:0 data;input load,cin,clk,reset;reg7:0 qout;always (posedge clk)begin i
16、f(reset)qout=0;else if(load)qout=data;else if(in)begin if(qout3:0=9)begin qout3:0=0;if(qout7:4=5)qout7:4=0;else qout7:4=qout7:4+1;end else qout3:0=qout3:0+1;end end assign cout=(qout=8h59)&cin)?1:0;endmodule1/2分频器的设计 module half_clk(reset,clk_in,clk_out);input clk_in,reset;output clk_out;reg clk_out
17、;always(posedge clk_in)begin if(!reset)clk_out=0;else clk_out=clk_out;end endmodule时钟分频器的设计 将10M的时钟分频为500K的时钟。基本原理与1/2分频器是一样的,但是需要定义一个计数器,以便准确获得1/20分频 module fdivision(RESET,F10M,F500K);input F10M,RESET;output F500K;reg F500K;reg 7:0j;always(posedge F10M)if(!RESET)/低电平复位。begin F500K=0;j=0;end else b
18、egin if(j=19)/对计数器进行判断,以确定F500K信号是否反转。begin j=0;F500K=F500K;end else j=j+1;end endmodule6.5.2 Case语句 当多路选择的控制条件集中在某个变量的变 化上时,用case语句加以表达显得更为方便 与直观case语句最适宜于对CPU的译码等部件的 描述以及对有限状态机的描述 case语句分为case、casez、casex共三种表示方式case语句的表示形式 case语句的格式如下:case():语句块1;:语句块2;:语句块n;default:语句块n+1;endcase 在上述格式中:“”代表着对程序流
19、向进行控制的控制信号;各个“”则是控制表达式的某些具体状态取值,在实际使用中这些分支项表达式通常是一些常量表达式;各个“语句块”则指定了在各个分支下所要执行的操作,它们也可以是由单条语句构成的;处于最后的、以关键词“default”开头的那个分支项被称为“default分支项”,它是可以缺省的。说明 1 case括弧内的表达式称为控制表达式,case分支项中的表达式称为分支表达式。控制表达式通常表示为控制信号的某些位,分支表达式则用这些控制信号的具体状态值来表示,因此分支表达式又可以称为常量表达式。2 当控制表达式的值与分支表达式的值相等时,就执行分支表达式后面的语句。如果所有的分支表达式的值
20、都没有与控制表达式的值相匹配的,就执行default后面的语句。3 default项可有可无,一个case语句里只准有一个default项。4 每一个case分项的分支表达式的值必须互不相同,否则就会出现矛盾现象(对表达式的同一个值,有多种执行方案)。5 执行完case分项后的语句,则跳出该case语句结构,终止case语句的执行。6 在用case语句表达式进行比较的过程中,只有当信号的对应位的值能明确进行比较时,比较才能成功。因此要注意详细说明case分项的分支表达式的值。7 case语句的所有表达式的值的位宽必须相等,只有这样控制表达式和分支表达式才能进行对应位的比较。一个经常犯的错误是用
21、bx,bz 来替代 nbx,nbz,这样写是不对的,因为信号x,z的缺省宽度是机器的字节宽度,通常是32位(此处 n 是case控制表达式的位宽)。case语句的执行过程(1)当“控制表达式”的取值等于“分支项表达式1”时,执行第一个分支项所包含的“语句块1”。(2)当“控制表达式”的取值等于“分支项表达式2”时,执行第二个分支项所包含的“语句块2”。(3)如果“控制表达式”的取值与所有n个分支项表达式的值都不相同,则执行“default分支项”所包含的“语句块n+1”。(4)在执行了某一分支项内的语句块后,跳出case语句结构,终止case语句的执行。case语句中各个“分支项表达式”的取值
22、必须是互不相同的,否则就会出现矛盾现象。如果“控制表达式”有几种不同取值情况对应着同一操作,则上述格式可以这样进行简写:用逗号将代表着这几种不同取值情况的多个“分支项表达式”隔开,再将在这些情况下需要执行的语句块放在这几个分支项表达式的后面。比如下面的语句:case(op_code)2b00:out=a|b;/op_code取值为“2b00”时的分支项 2b01,2b10,2b11:out=a&b;/op_code取值为“2b01”、“2b10”或 “2b11”时要执行的操作都是“out=a&b;”default:out=0;/default分支项 endcase在上面的语句中,三个分支项表达
23、式“2b01”、“2b10”和“2b11”之间用“,”隔开,同时在这几个分支项表达式后面指定了要执行的语句“out=a&b;”。这表明当控制信号op_code取值为2b01、2b10或2b11时,对应的操作都是由语句“out=a&b;”指定的赋值操作。上例是如下多条语句的简写形式:case(op_code)2b00:out=a|b;/op_code取值为“2b00”时的分支项2b01:out=a&b;/op_code取值为“2b01”时的分支项 2b10:out=a&b;/op_code取值为“2b10”时的分支项2b11:out=a&b;/op_code取值为“2b11”时的分支项defau
24、lt:out=0;/default分支项endcasecase语句在执行时,控制表达式和分支项表达式之间进行的比较是一种按位进行的“全等比较”,也就是说,只有在分支项表达式和控制表达式对应的每一位都彼此相等的情况下才认为分支项表达式和控制表达式两者是“相等”的。在进行对应位的比较时,“x”和“z”这两种逻辑状态也与“0”、“1”逻辑状态一样作为合法的状态参与比较。这些逻辑状态在进行位取值比较时的真值表如表1所示,其中第一行和第一列是参加比较的两个位的可能逻辑状态,在表中用符号“yes”表示比较结果为“两者相等”,用符号“no”表示比较结果为“两者不相等”。case,casez,casex 的真
25、值表 我们举一个例子来说明这种“全等比较”的特点,如例下所示。例6-22 casecase语句执行时对“x”状态和“z”状态的处理。module demo_xz(sig);input sig;always(sig)case(sig)1b1:$display(“signalvalue is 1”);1b0:$display(“signalvalue is 0”);1bx:$display(“signalis in unknown state”);1bz:$display(“signalis in high impedance state”);endcase endmodule在例6-22所示模块
26、中,控制表达式为“a”,同时还列出了四个分支项。在进行控制表达式和各个分支项表达式的比较时,“0”、“1”、“x”和“z”这四个逻辑状态将作为四个不同的合法状态参与比较。所以当输入信号a的取值为“x”时,只有第三个分支项表达式与控制表达式的比较结果是“两者相等”,此时第三个分支项后面指定的语句将得到执行;同样,当输入a取值为“z”时,只有第四个分支项表达式与控制表达式的比较结果是“两者相等”,此时将执行第四个分支项后面所指定的语句。由于case语句有上面这种按位进行全等比较的特点,case语句中的控制表达式和所有分支项表达式必须具有相同的位宽,因为只有这样控制表达式和分支表达式才能进行对应位的
27、比较;当各个分支项表达式以常数形式给出时,必须显式地标明每个常数的位宽,否则Verilog编译器会认为它们具有与机器字长相同的位宽。例6-23是一个用case语句来实现操作码译码的例子。module decode_of_opcode_use_case(a,b,opcode,out);input7:0 a,b;input2:1 opcode;output7:0 out;reg 7:0 out;always (a or b or opcode)begincase(opcode)2b10:out=a+b;2b11:out=a-b;2b01:out=(a)+1;2b00:out=(b)+1;endca
28、se endendmodule在例6-23所示模块中,输入信号opcode是宽度为两位的操作码,它的取值指定了对输入a,b执行的运算类型:如果操作码为“2b10”,则求a,b的和(第一个分支项)。如果操作码为“2b11”,则求a,b的差(第二个分支项)。如果操作码为“2b01”,则求a的补码(第三个分支项)。如果操作码为“2b00”,则求b的补码(第四个分支项)。【例】BCD 码七段数码管显示译码器 module decode4_7(decodeout,indec);output6:0 decodeout;input3:0 indec;reg6:0 decodeout;always(indec
29、)begin case(indec)4d0:decodeout=7b1111110;4d1:decodeout=7b0110000;4d2:decodeout=7b1101101;4d3:decodeout=7b1111001;4d4:decodeout=7b0110011;4d5:decodeout=7b1011011;4d6:decodeout=7b1011111;4d7:decodeout=7b1110000;4d8:decodeout=7b1111111;4d9:decodeout=7b1111011;default:decodeout=7bx;endcase end2 Casez、C
30、asex语句 Verilog HDL还提供了另外两种形式的case分支语 句,它们是casez语句和casex语句。可以利用它们来 实现这样的分支控制:由控制表达式和分支项表达式 的一部分数位的比较结果来决定程序的流向。casez语句执行时的比较过程将不考虑控制表达式 及分支项表达式中处于高阻态“z”的那些位的比较,而casex语句则将高阻状态“z”和不定状态“x”都视为不 必关心的情况。通过这两种形式的分支控制语句,就 可以通过对控制表达式和分支项表达式的灵活设定来 实现由一部分数位取值决定的分支控制。1)casez语句casez语句的格式如下:casez():语句块1;:语句块2;:语句块
31、n;default:语句块n+1;endcase从上面的格式我们可以看出:casez语句与case语句的使用格式完全相同,两者唯一的差别是关键词“casez”和“case”的不同。在casez语句中,如果控制表达式或分支项表达式的某一位取值为“z”,则在分支语句执行时将忽略该位的比较,也就是说这种情况下控制表达式和分支项表达式在这一位的取值将不会对程序流程分支的选择产生任何影响。casez语句进行位取值比较时的真值表如表1所示,其中第一行和第一列是参加比较的两个位的可能取值状态,我们在表中用符号“yes”来表示比较结果为“两者相等”,用符号“no”来表示比较结果为“两者不相等”。例【6.24】
32、用casez 描述的数据选择器module mux_casez(out,a,b,c,d,select);output out;input a,b,c,d;input3:0 select;reg out;always(select or a or b or c or d)begin Casez(select)4bzzz1:out=a;4b?1?:out=b;4b?1?:out=c;4b1?:out=d;endcaseendendmodule在例6-24所示的模块中,输入信号select为四位宽的选择信号,它用来指定对于输入a,b,c,d执行的输出,casez语句内的控制表达式为操作码“selec
33、t”,各个分支项表达式以常量形式给出:第一个分支项表达式是4bzzz1,它的第4、3、2位为“z”,所以控制表达式在与该分支项表达式进行比较时将忽略这三位而只对最低位进行比较。所以只要选择信号select的最高位取值为“1”,两个表达式的比较结果就是“相等”,该分支项对应的语句“out=a;”就得到执行。第二个分支项表达式是4b?1?:,它的高二位和低位数值为“?”,这里符号“?”的含义就代表“z”。所以在进行两个表达式的比较时将忽略?位而只对3二位数值进行比较。所以只要选择信号select第3位取值为“1”,就执行第二个分支项对应的语句“out=b;”。2)casex语句casex语句的格式
34、如下:casex():语句块1;:语句块2;:语句块n;default:语句块n+l;endcasecasex语句与case语句以及casez语句所使用的格式完全相同,唯一的差别是这里的关键词为“casex”。与casez语句一样,casex语句中的控制表达式和分支项表达式在进行比较时将忽略某些位的比较,casex语句和casez语句的不同之处在于:在casex语句中,处于“x”或“z”这两种逻辑状态的位都被忽略;而在casez语句中只忽略处于“z”状态的位。casex语句在进行数位比较时的真值表如表1所示。【例例6-25】用casex语句实现操作码译码。module decode_of_op
35、code_use_casex(a,b,opcode,out);input7:0 a,b;input4:1 opcode;output7:0 out;reg 7:0 out;always (a or b or opcode)begin casex(opcode)4b1zzx:out=a+b;/分支项14b01xx:out=a-b;/分支项24b001?:out=(a)+1;/分支项34b0001:out=(b)+1;/分支项4 endcase end endmodule例6-25所示模块中的控制表达式“opcode”在与各个分支项表达式进行比较时,将分别忽略其中取值为“z”、“x”、“?”的位。
36、所以与例6-24的执行一样:只要操作码opcode最高位取值为“1”,就执行第一个分支项对应的语句“out=a+b;”。只要操作码opcode最高二位取值为“01”,就执行第二个分支项对应的语句“out=a-b;”。只要操作码opcode最高三位取值为“001”,就执行第三个分支项对应的语句“out=(a)+1;”。当操作码opcode等于“4b0001”时,执行第四个分支项对应的语句“out=(b)+1;”。条件语句使用要点 1 在使用条件语句时,要列出所有条件分支,否则,编译器认为条件不满足时,会引进一个触发器保持原值,这一点可以用在时序逻辑中,但在组合逻辑设计中,应避免这种隐含触发器的存
37、在。可在可在ifif语句,写上语句,写上elseelse项。在项。在casecase语句,写上语句,写上defaultdefault项项 2 在硬件语句中使用if语句和case语句的区别。如果有分支情况,尽量使用case语句,这是因为case语句是并行执行的,没有优先级的区别。而if语句的选择分支是串行执行的,是按照书写的顺序逐次判断的。如果设计中没有优先级的考虑,if语句和case语句相比,会占用更多的硬件资源。错误使用if语句 always(al or d)begin if(al)q=d;end 有锁存器always(al or d)begin if(al)q=d;else q=0 end
38、 无锁存器在always块内,如果在给定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁存器!错误使用case语句 always(sel1:0 or a or b)case(sel1:0)2b00:q=a;2b11:q=b;endcase 有锁存器 always(sel1:0oraorb)case(sel1:0)2b00:q=a;2b11:q=b;default:q200)disable FOREVER_PART;#25 clk=clk;end /内层块结束标志end /FOREVER_PART语句块的结束标志end endmodule6.6.2 repeat 循环语句 repe
39、at循环语句实现的是一种循环次数预先指定的循环,这种循环语句内的循环体部分将被重复执行指定的次数。repeat循环语句的格式如下:repeat ()语句或语句块;在上述格式中:“”用于指定循环次数,它可以是一个整数、变量或一个数值表达式。如果是变量或数值表达式,其取值只在第一次进入循环时得到计算(从而得以事先确定循环次数)。“语句或语句块”是要被重复执行的循环体部分。【例例6-28】用repeat循环语句来实现一个8位乘法器。module 8_bits_multiplier(result,opa,opb);parameter SIZE=8,LONGSIZE=16;input SIZE:1 op
40、a,opb;output LONGSIZE:1 result;regSIZE:1 opa,opb;regLONGSIZE:1 result;always(opa or opb)begin:multreg LONGSIZE:1 shift_opa,shift_opb;/局部变量定义shift_opa=opa;shift_opb=opb;result0;repeat(SIZE)/repeat循环语句begin /循环体语句块if(shift_opb1)resultresult+shift_opa;shift_opashift_opa1;end /循环体语句块结束标志endendmodule在上例中
41、,repeat循环语句内指定的“循环次数表达式”是一个参数“SIZE”,它代表了数值“8”,于是后面的循环体将被重复执行8次;循环体部分由一个begin-end语句块构成,这个语句块每执行一次就进行一次移位相加操作,在重复执行8次后就完成了两个8位输入操作数的相乘运算。repeat循环语句还有一种特别的用法在此必须加以说明,我们看如下语句块:initialbegin out=0;repeat(NUM)(posedge clk);out=1;end 在上述initial过程块中,repeat循环语句后面的循环体部分是一条时间控制语句“(posedge clk);”。在这种情况下,这条repeat
42、循环语句的作用是:等待时钟信号clk的NUM次正跳变。因此下一条语句“out=1;”将在时钟第NUM次正跳变后得到执行,out的低电平状态共保持了NUM个时钟周期的时间。6.6.3 while 循环语句 while循环语句实现的循环是一种“条件循环”,就是说只 有在指定的条件表达式取值为“真”时才会重复执行循环 体,否则就不执行循环体。while循环语句的格式如下:while()语句或语句块;在上述格式中:“”代表了循环体得到继续重复执行时必 须满足的条件,它常常是一个逻辑表达式。在每一次执行循 环体之前都要对这个条件表达式是否成立进行判断。“语句或语句块”代表了被重复执行的循环体部分。whi
43、le循环语句的执行过程是这样的:首先判断条件表达式是否成立,如果成立,则执行后面指定的“语句或语句块(循环体部分)”,然后再次对条件表达式是否成立作出判断,只要其取值为“真”就再次重复执行循环体,直到在某一次循环后判断出条件表达式不成立,循环过程才结束,程序流程退出while循环语句。假如条件表达式在一开始就不成立,则循环体一次也不被执行。例6-29所示过程块是用while循环语句来实现从0计数到100,并在第101次计数时退出循环。【例例6-29】while循环语句。initialbegincount=0;while(count 100)begin /循环体语句块$display(“coun
44、t=%d”,count);#5 count=count+1;endend在上例的描述中,while循环控制语句执行时首先判断条件表达式“count 100”是否成立,如果条件成立,则执行后面指定的begin-end语句块(也就是循环体部分),这个语句块实现了对计数变量“count”进行修改和显示的操作。在while循环语句开始执行时,count变量初值为0,条件表达式成立,循环体语句块得到执行,count取值增1后再次对条件表达式是否成立进行判断,其判断结果决定着是否再次执行循环体语句块。这样,随着循环体语句块的不断重复执行,count的取值不断增加,直到进行了第100次循环后,count取值
45、变为100,这时条件表达式“count 1;end end endmodule6.6.4 for 循环语句与while循环语句一样,for循环语句实现的循环也是一种“条件循环”,只有在指定的条件表达式成立时才进行循环。for循环语句的格式如下:for(;)循环体语句或语句块;在上述格式中:“”和“”是两条过程赋值语句,它们分别用来对循环计数变量执行赋初值操作和增值操作。“”代表着循环继续进行时必须满足的条 件,它常常是一个逻辑表达式。在每一次执行循环体之前都 要对这个条件表达式是否成立进行判断。“循环体语句或语句块”是要被重复执行的循环体部分。for循环语句的执行过程可以分成如下几步:(1)执
46、行“”。(2)对“”是否成立做出判断:若“条件表达式”取值为真,则执行for循环语句中指定的“循环体语句或语句块”,然后继续执行下面的第(3)步;若“条件表达式”取值不为真,则不再执行循环体部分,循环过程结束,退出for循环语句的执行。(3)执行“”,然后转到(2)继续执行。由上面说明的执行步骤可以看出:“”只在第一次循环开始之前被执行了一次,它通常是一条给循环计数变量赋初值的过程赋值语句;“”是在每次循环结束后、下一次循环开始前被执行的,它通常用于对循环计数变量的取值进行修改;而“条件表达式”取值的判断是在每次循环开始前发生的,它的结果决定着“是否继续执行循环”。条件表达式的取值往往是随着循
47、环的进行而发生变化的。这是因为:如果条件表达式的取值在整个循环过程中一直保持不变,那么循环体要么是一次都得不到执行,要么是进入被执行无限次循环的死循环状态。因此,for循环语句实际上等价于由while循环语句构建的如下循环结构:begin;while()begin循环体语句或语句块;endend这样,对于使用while循环语句时需要3条语句才能完成的一个循环控制,for循环语句只需一条语句就可以实现。下面使用for循环语句来描述与例7-11相同的功能。【例例6-30】for循环语句。initialfor(count=0;count100;count=count+1)begin /循环体语句块$
48、display(count=%d,count);#5;end上例中for循环语句的执行过程是:首先执行“count=0;”,给循环变量count赋初值0;然后判断条件表达式“count 100”是否成立,根据判断结果确定是否要继续执行循环体语句块:如果条件表达式成立,则执行循环体语句块,然后语句“count=count+1”得到执行,实现循环变量count的增值操作,然后再重新转回到判断条件表达式那一步。如果条件表达式“count 100”不成立,则循环体语句块不被执行,结束循环过程,退出for循环语句的执行。所以循环变量count将由初值0开始,在每次循环后其值增1。这样条件表达式在前100
49、次循环时始终是成立的,而在开始第101次循环前,count取值为100,此时条件表达式“count 100”不再成立,因此这时将结束循环并退出for循环语句的执行。下面再举两个使用for循环语句的例子。例6-31所示模块利用for循环语句实现了在例6-28中用repeat语句来实现的乘法器功能,而例6-32则用for循环语句实现了一个4位左移器。例 用for 语句实现2 个8 位数相乘 module mult_for(outcome,a,b);parameter size=8;inputsize:1 a,b;/两个操作数 output2*size:1 outcome;/结果 reg2*size
50、:1 outcome;Integer i;always(a or b)begin outcome=0;for(i=1;i=size;i=i+1)/for 语句 if(bi)outcome=outcome+(a (i-1);end endmodule【例例6-31】用for循环语句来实现一个8位乘法器。module 8_bits_multiplier(result,opa,opb);parameter SIZE=8,LONGSIZE=16;input SIZE:1 opa,opb;output LONGSIZE:1 result;regSIZE:1 opa,opb;regLONGSIZE:1 r