:Verilog的135个经典设计实例

来源:百度文库 编辑:九乡新闻网 时间:2024/05/04 09:19:56
    王金明:《Verilog HDL程序设计教程》【例3.1】4位全加器module adder4(cout,sum,ina,inb,cin);output[3:0] sum;output cout;input[3:0] ina,inb;input cin;assign {cout,sum}=ina+inb+cin;endmodule【例3.2】4位计数器module count4(out,reset,clk);output[3:0] out;input reset,clk;reg[3:0] out;always @(posedge clk)    begin    if (reset)  out<=0;           //同步复位    else         out<=out+1;     //计数    endendmodule【例3.3】4位全加器的仿真程序`timescale 1ns/1ns`include "adder4.v"module adder_tp;                   //测试模块的名字reg[3:0] a,b;      //测试输入信号定义为reg型reg cin;wire[3:0] sum;       //测试输出信号定义为wire型wire cout;integer i,j;adder4 adder(sum,cout,a,b,cin);  //调用测试对象always #5 cin=~cin;       //设定cin的取值initialbegina=0;b=0;cin=0;for(i=1;i<16;i=i+1)#10   a=i;      //设定a的取值end    - 1 - 程序文本   initial   begin   for(j=1;j<16;j=j+1)   #10   b=j;      //设定b的取值   end   initial       //定义结果显示格式   begin   $monitor($time,,,"%d + %d + %b={%b,%d}",a,b,cin,cout,sum);   #160  $finish;   end   endmodule    【例3.4】4位计数器的仿真程序   `timescale 1ns/1ns   `include "count4.v"   module coun4_tp;   reg clk,reset;       //测试输入信号定义为reg型   wire[3:0] out;             //测试输出信号定义为wire型   parameter DELY=100;   count4 mycount(out,reset,clk);       //调用测试对象   always #(DELY/2) clk = ~clk;      //产生时钟波形   initial    begin       //激励信号定义    clk =0; reset=0;    #DELY    reset=1;    #DELY    reset=0;    #(DELY*20) $finish;    end   //定义结果显示格式   initial $monitor($time,,,"clk=%d reset=%d out=%d", clk, reset,out);   endmodule    【例3.5】“与-或-非”门电路    module AOI(A,B,C,D,F);     //模块名为AOI(端口列表A,B,C,D,F)    input A,B,C,D;     //模块的输入端口为A,B,C,D    output F;     //模块的输出端口为F- 2 -    王金明:《Verilog HDL程序设计教程》wire A,B,C,D,F;                    //定义信号的数据类型    assign  F= ~((A&B)|(C&D));  //逻辑功能描述endmodule【例5.1】用case语句描述的4选1数据选择器module mux4_1(out,in0,in1,in2,in3,sel);output out;input in0,in1,in2,in3;input[1:0] sel;reg out;always @(in0 or in1 or in2 or in3 or sel)    //敏感信号列表   case(sel)    2'b00:  out=in0;    2'b01:  out=in1;    2'b10:  out=in2;    2'b11:  out=in3;    default: out=2'bx;   endcaseendmodule【例5.2】同步置数、同步清零的计数器module count(out,data,load,reset,clk);output[7:0] out;input[7:0] data;input load,clk,reset;reg[7:0] out;always @(posedge clk)                   //clk上升沿触发    begin    if (!reset)     out = 8'h00;     //同步清0,低电平有效    else if (load)   out = data;      //同步预置         else     out = out + 1;     //计数    end endmodule【例5.3】用always过程语句描述的简单算术逻辑单元`define add 3'd0`define minus 3'd1`define band 3'd2`define bor 3'd3`define bnot 3'd4    - 3 - 程序文本   module alu(out,opcode,a,b);   output[7:0] out;   reg[7:0] out;   input[2:0] opcode;       //操作码   input[7:0] a,b;      //操作数   always@(opcode or a or b)      //电平敏感的always块    begin    case(opcode)    `add: out = a+b;          //加操作    `minus: out = a-b;         //减操作    `band: out = a&b;         //求与    `bor: out = a|b;            //求或    `bnot: out=~a;         //求反    default: out=8'hx;         //未收到指令时,输出任意态    endcase    end   endmodule    【例5.4】用initial过程语句对测试变量A、B、C赋值   `timescale 1ns/1ns   module test;   reg A,B,C;   initial    begin    A = 0;  B = 1;  C = 0;    #50    A = 1;  B = 0;    #50    A = 0;  C = 1;    #50    B = 1;    #50    B = 0;  C = 0;    #50    $finish ;    end   endmodule    【例5.5】用begin-end串行块产生信号波形   `timescale 10ns/1ns   module wave1;   reg wave;   parameter cycle=10;   initial    begin- 4 -    王金明:《Verilog HDL程序设计教程》    wave=0;   #(cycle/2)  wave=1;   #(cycle/2)  wave=0;   #(cycle/2)  wave=1;   #(cycle/2)  wave=0;   #(cycle/2)  wave=1;   #(cycle/2)  $finish ;  endinitial $monitor($time,,,"wave=%b",wave);endmodule【例5.6】用fork-join并行块产生信号波形`timescale 10ns/1nsmodule wave2;reg wave;parameter cycle=5;initial fork    wave=0;    #(cycle)    wave=1;    #(2*cycle)  wave=0;    #(3*cycle)  wave=1;    #(4*cycle)  wave=0;    #(5*cycle)  wave=1;    #(6*cycle)  $finish; joininitial $monitor($time,,,"wave=%b",wave);endmodule【例5.7】持续赋值方式定义的2选1多路选择器module MUX21_1(out,a,b,sel);input a,b,sel;output out;assign out=(sel==0)?a:b;    //持续赋值,如果sel为0,则out=a ;否则out=bendmodule【例5.8】阻塞赋值方式定义的2选1多路选择器module MUX21_2(out,a,b,sel);input a,b,sel;    - 5 - 程序文本    output out;    reg out;    always@(a or b or sel)    begin    if(sel==0) out=a;         //阻塞赋值    else        out=b;    end    endmodule    【例5.9】非阻塞赋值    module non_block(c,b,a,clk);    output c,b;    input clk,a;    reg c,b;    always @(posedge clk)    begin    b<=a;    c<=b;    end    endmodule    【例5.10】阻塞赋值    module block(c,b,a,clk);    output c,b;    input clk,a;    reg c,b;    always @(posedge clk)    begin    b=a;    c=b;    end    endmodule    【例5.11】模为60的BCD码加法计数器    module count60(qout,cout,data,load,cin,reset,clk);    output[7:0] qout;    output cout;    input[7:0] data;    input load,cin,clk,reset;    reg[7:0] qout;    always @(posedge clk)     //clk上升沿时刻计数- 6 -    王金明:《Verilog HDL程序设计教程》begin    if (reset)     qout<=0;     //同步复位    else  if(load)     qout<=data;      //同步置数          else  if(cin)    begin    if(qout[3:0]==9)     //低位是否为9,是则    begin    qout[3:0]<=0;     //回0,并判断高位是否为5    if (qout[7:4]==5)  qout[7:4]<=0;    else    qout[7:4]<=qout[7:4]+1;      //高位不为5,则加1    end    else     //低位不为9,则加1    qout[3:0]<=qout[3:0]+1;    end endassign cout=((qout==8'h59)&cin)?1:0;     //产生进位输出信号endmodule【例5.12】BCD码—七段数码管显示译码器module decode4_7(decodeout,indec);output[6:0] decodeout;input[3:0] indec;reg[6:0] decodeout;always @(indec) begin    case(indec)             //用case语句进行译码    4'd0:decodeout=7'b1111110;    4'd1:decodeout=7'b0110000;    4'd2:decodeout=7'b1101101;    4'd3:decodeout=7'b1111001;    4'd4:decodeout=7'b0110011;    4'd5:decodeout=7'b1011011;    4'd6:decodeout=7'b1011111;    4'd7:decodeout=7'b1110000;    4'd8:decodeout=7'b1111111;    4'd9:decodeout=7'b1111011;    default: decodeout=7'bx;    endcase end    - 7 - 程序文本    endmodule    【例5.13】用casez描述的数据选择器    module mux_casez(out,a,b,c,d,select);    output out;    input a,b,c,d;    input[3:0] select;    reg out;   always @(select or a or b or c or d)    begin    casez(select)    4'b???1: out = a;    4'b??1?: out = b;    4'b?1??: out = c;    4'b1???: out = d;    endcase    end   endmodule    【例5.14】隐含锁存器举例    module buried_ff(c,b,a);    output c;    input b,a;    reg c;    always @(a or b)    begin    if((b==1)&&(a==1))  c=a&b;    end    endmodule    【例5.15】用for语句描述的七人投票表决器    module voter7(pass,vote);    output pass;    input[6:0] vote;    reg[2:0] sum;    integer i;    reg pass;    always @(vote)    begin    sum=0;- 8 -    王金明:《Verilog HDL程序设计教程》    for(i=0;i<=6;i=i+1)      //for语句    if(vote[i]) sum=sum+1;    if(sum[2])  pass=1;       //若超过4人赞成,则pass=1    else       pass=0;  endendmodule【例5.16】用for语句实现2个8位数相乘module mult_for(outcome,a,b);parameter size=8;input[size:1] a,b;     //两个操作数output[2*size:1] outcome;     //结果reg[2*size:1] outcome;integer i;always @(a or b)    begin    outcome=0;    for(i=1; i<=size; i=i+1)      //for语句    if(b[i])  outcome=outcome +(a << (i-1));    endendmodule【例5.17】用repeat实现8位二进制数的乘法module mult_repeat(outcome,a,b);parameter size=8;input[size:1] a,b;output[2*size:1] outcome;reg[2*size:1] temp_a,outcome;reg[size:1] temp_b;always @(a or b) begin    outcome=0;    temp_a=a;    temp_b=b;    repeat(size)          //repeat语句,size为循环次数    begin    if(temp_b[1])        //如果temp_b的最低位为1,就执行下面的加法    outcome=outcome+temp_a;    temp_a=temp_a<<1;        //操作数a左移一位    - 9 - 程序文本    temp_b=temp_b>>1;        //操作数b右移一位    end    end    endmodule    【例5.18】同一循环的不同实现方式   module loop1;              //方式1   integer i;   initial    for(i=0;i<4;i=i+1)     //for语句    begin    $display(“i=%h”,i);    end   endmodule   module loop2;     //方式2   integer i;   initial begin    i=0;    while(i<4)       //while语句    begin    $display ("i=%h",i);    i=i+1;    end    end   endmodule   module loop3;     //方式3   integer i;   initial begin    i=0;    repeat(4)     //repeat语句    begin    $display ("i=%h",i);    i=i+1;    end    end   endmodule    【例5.19】使用了`include语句的16位加法器- 10 -    王金明:《Verilog HDL程序设计教程》`include "adder.v"module adder16(cout,sum,a,b,cin);output cout;parameter my_size=16;output[my_size-1:0] sum;input[my_size-1:0] a,b;input cin;adder my_adder(cout,sum,a,b,cin);        //调用adder模块endmodule//下面是adder模块代码module adder(cout,sum,a,b,cin);parameter size=16;output cout;output[size-1:0] sum;input cin;input[size-1:0] a,b;    assign {cout,sum}=a+b+cin;endmodule【例5.20】条件编译举例module compile(out,A,B);output out;input A,B;`ifdef  add                         //宏名为add    assign out=A+B;`else    assign out=A-B;`endifendmodule【例6.1】加法计数器中的进程module count(data,clk,reset,load,cout,qout);output cout;output[3:0] qout;reg[3:0] qout;input[3:0] data;input clk,reset,load;    - 11 - 程序文本    always @(posedge clk)        //进程1,always过程块    begin    if (!reset)     qout= 4'h00;     //同步清0,低电平有效    else if (load)   qout= data;      //同步预置    else         qout=qout + 1;     //加法计数    end    assign cout=(qout==4'hf)?1:0;     //进程2,用持续赋值产生进位信号    endmodule    【例6.2】任务举例   module alutask(code,a,b,c);   input[1:0] code;   input[3:0] a,b;   output[4:0] c;   reg[4:0] c;   task my_and;                     //任务定义,注意无端口列表   input[3:0] a,b;                 //a,b,out名称的作用域范围为task任务内部   output[4:0] out;   integer i;    begin    for(i=3;i>=0;i=i-1)    out[i]=a[i]&b[i];            //按位与    end   endtask   always@(code or a or b)    begin    case(code)    2'b00: my_and(a,b,c);    /* 用任务my_and,需注意端口列表的顺序应与任务定义中的一致,这里的a,b,c分别对应任务定义中的a,b,out */    2'b01: c=a|b;               //或    2'b10: c=a-b;              //相减    2'b11: c=a+b;         //相加    endcase    end   endmodule- 12 -    王金明:《Verilog HDL程序设计教程》【例6.3】测试程序`include "alutask.v"module alu_tp;reg[3:0] a,b;reg[1:0] code;wire[4:0] c;parameter DELY = 100;alutask ADD(code,a,b,c);                 //调用被测试模块initial begin    code=4'd0; a= 4'b0000; b= 4'b1111;#DELY   code=4'd0; a= 4'b0111; b= 4'b1101;#DELY   code=4'd1; a= 4'b0001; b= 4'b0011;#DELY   code=4'd2; a= 4'b1001; b= 4'b0011;#DELY   code=4'd3; a= 4'b0011; b= 4'b0001;#DELY   code=4'd3; a= 4'b0111; b= 4'b1001;#DELY   $finish;endinitial $monitor($time,,,"code=%b a=%b b=%b c=%b", code,a,b,c);endmodule【例6.4】函数function[7:0] get0;input[7:0] x;reg[7:0] count;integer i;    begin    count=0;    for (i=0;i<=7;i=i+1)    if (x[i]=1'b0)  count=count+1;    get0=count;    endendfunction【例6.5】用函数和case语句描述的编码器(不含优先顺序)module code_83(din,dout);input[7:0] din;output[2:0] dout;    - 13 - 程序文本    function[2:0] code;                   //函数定义    input[7:0] din;                     //函数只有输入,输出为函数名本身    casex (din)    8'b1xxx_xxxx : code = 3'h7;    8'b01xx_xxxx : code = 3'h6;    8'b001x_xxxx : code = 3'h5;    8'b0001_xxxx : code = 3'h4;    8'b0000_1xxx : code = 3'h3;    8'b0000_01xx : code = 3'h2;    8'b0000_001x : code = 3'h1;    8'b0000_000x : code = 3'h0;    default: code = 3'hx;    endcase    endfunction    assign dout = code(din) ;           //函数调用    endmodule    【例6.6】阶乘运算函数   module funct(clk,n,result,reset);   output[31:0] result;   input[3:0] n;   input reset,clk;   reg[31:0] result;   always @(posedge clk)         //在clk的上升沿时执行运算    begin    if(!reset)  result<=0;         //复位    else  begin    result <= 2 * factorial(n); //调用factorial函数    end    end   function[31:0] factorial;         //阶乘运算函数定义(注意无端口列表)   input[3:0] opa;              //函数只能定义输入端,输出端口为函数名本身   reg[3:0] i;    begin    factorial = opa ? 1 : 0;    for(i= 2; i <= opa; i = i+1)      //该句若要综合通过,opa应赋具体的数值    factorial = i* factorial;         //阶乘运算    end- 14 -    王金明:《Verilog HDL程序设计教程》endfunctionendmodule【例6.7】测试程序`define clk_cycle  50`include "funct.v"module funct_tp;reg[3:0] n;reg reset,clk;wire[31:0] result;   initial                       //定义激励向量   begin   n=0;  reset=1;  clk=0;   for(n=0;n<=15;n=n+1)   #100  n=n;   endinitial $monitor($time,,,"n=%d result=%d",n,result);    //定义输出显示格式always  # `clk_cycle  clk=~clk;           //产生时钟信号funct funct_try(.clk(clk),.n(n),.result(result),.reset(reset));    //调用被测试模块endmodule【例6.8】顺序执行模块1module serial1(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)    begin    q=~q;    a=~q;    endendmodule【例6.9】顺序执行模块2module serial2(q,a,clk);output q,a;    - 15 - 程序文本    input clk;    reg q,a;    always @(posedge clk)    begin    a=~q;    q=~q;    end    endmodule    【例6.10】并行执行模块1    module paral1(q,a,clk);    output q,a;    input clk;    reg q,a;    always @(posedge clk)    begin    q=~q;    end    always @(posedge clk)    begin    a=~q;    end    endmodule    【例6.11】并行执行模块2    module paral2(q,a,clk);    output q,a;    input clk;    reg q,a;    always @(posedge clk)    begin    a=~q;    end    always @(posedge clk)    begin    q=~q;    end    endmodule    【例7.1】调用门元件实现的4选1 MUX- 16 -    王金明:《Verilog HDL程序设计教程》module mux4_1a(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;wire notcntrl1,notcntrl2,w,x,y,z;not  notcntrl1,cntrl2),    (notcntrl2,cntrl2);and  (w,in1,notcntrl1,notcntrl2),    (x,in2,notcntrl1,cntrl2),    (y,in3,cntrl1,notcntrl2),    (z,in4,cntrl1,cntrl2);or  (out,w,x,y,z);endmodule【例7.2】用case语句描述的4选1 MUXmodule mux4_1b(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;reg out;always@(in1 or in2 or in3 or in4 or cntrl1 or cntrl2)    case({cntrl1,cntrl2})    2'b00:out=in1;    2'b01:out=in2;    2'b10:out=in3;    2'b11:out=in4;    default:out=2'bx;    endcaseendmodule【例7.3】行为描述方式实现的4位计数器module count4(clk,clr,out);input clk,clr;output[3:0] out;reg[3:0] out;always @(posedge clk or posedge clr)    begin    if (clr)    out<=0;    else      out<=out+1;    endendmodule    - 17 - 程序文本    【例7.4】数据流方式描述的4选1 MUX    module mux4_1c(out,in1,in2,in3,in4,cntrl1,cntrl2);    output out;    input in1,in2,in3,in4,cntrl1,cntrl2;    assign out=(in1 & ~cntrl1 & ~cntrl2)|(in2 & ~cntrl1 & cntrl2)|    (in3 & cntrl1 & ~cntrl2)|(in4 & cntrl1 & cntrl2);    endmodule    【例7.5】用条件运算符描述的4选1 MUX    module mux4_1d(out,in1,in2,in3,in4,cntrl1,cntrl2);    output out;    input in1,in2,in3,in4,cntrl1,cntrl2;    assign out=cntrl1 ? (cntrl2 ? in4:in3):(cntrl2 ? in2:in1);    endmodule    【例7.6】门级结构描述的2选1MUX    module mux2_1a(out,a,b,sel);    output out;    input a,b,sel;    not (sel_,sel);    and  a1,a,sel_),    (a2,b,sel);    or (out,a1,a2);    endmodule    【例7.7】行为描述的2选1MUX    module mux2_1b(out,a,b,sel);    output out;    input a,b,sel;    reg out;    always @(a or b or sel)    begin    if(sel)     out = b;    else    out = a;    end    endmodule    【例7.8】数据流描述的2选1MUX    module MUX2_1c(out,a,b,sel);    output out;- 18 -    王金明:《Verilog HDL程序设计教程》input a,b,sel;    assign out = sel ? b : a;endmodule【例7.9】调用门元件实现的1位半加器module half_add1(a,b,sum,cout);input a,b;output sum,cout;and  cout,a,b);xor  sum,a,b);endmodule【例7.10】数据流方式描述的1位半加器module half_add2(a,b,sum,cout);input a,b;output sum,cout;assign sum=a^b;assign cout=a&b;endmodule【例7.11】采用行为描述的1位半加器module half_add3(a,b,sum,cout);input a,b;output sum,cout;reg sum,cout;always @(a or b) begin    case ({a,b})                    //真值表描述    2'b00: begin  sum=0; cout=0;  end    2'b01: begin  sum=1; cout=0;  end    2'b10: begin  sum=1; cout=0;  end    2'b11: begin  sum=0; cout=1;  end    endcase endendmodule【例7.12】采用行为描述的1位半加器module half_add4(a,b,sum,cout);input a,b;output sum,cout;    - 19 - 程序文本    reg sum,cout;    always @(a or b)    begin    sum= a^b;    cout=a&b;    end    endmodule    【例7.13】调用门元件实现的1位全加器    module full_add1(a,b,cin,sum,cout);    input a,b,cin;    output sum,cout;    wire s1,m1,m2,m3;    and  m1,a,b),    (m2,b,cin),    (m3,a,cin);    xor  s1,a,b),    (sum,s1,cin);    or  (cout,m1,m2,m3);    endmodule    【例7.14】数据流描述的1位全加器    module full_add2(a,b,cin,sum,cout);    input a,b,cin;    output sum,cout;    assign sum = a ^ b ^ cin;    assign cout = (a & b)|(b & cin)|(cin & a);    endmodule    【例7.15】1位全加器    module full_add3(a,b,cin,sum,cout);    input a,b,cin;    output sum,cout;    assign {cout,sum}=a+b+cin;    endmodule    【例7.16】行为描述的1位全加器    module full_add4(a,b,cin,sum,cout);    input a,b,cin;    output sum,cout;- 20 -    王金明:《Verilog HDL程序设计教程》reg sum,cout;     //在always块中被赋值的变量应定义为reg型reg m1,m2,m3;always @(a or b or cin)    begin    sum = (a ^ b) ^ cin;    m1 = a & b;    m2 = b & cin;    m3 = a & cin;    cout = (m1|m2)|m3;    endendmodule【例7.17】混合描述的1位全加器module full_add5(a,b,cin,sum,cout);input a,b,cin;output sum,cout;reg cout,m1,m2,m3;             //在always块中被赋值的变量应定义为reg型wire s1;xor x1(s1,a,b);            //调用门元件always @(a or b or cin)        //always块语句    begin    m1 = a & b;    m2 = b & cin;    m3 = a & cin;    cout = (m1| m2) | m3;    endassign sum = s1 ^ cin;       //assign持续赋值语句endmodule【例7.18】结构描述的4位级连全加器`include "full_add1.v"module add4_1(sum,cout,a,b,cin);output[3:0] sum;output cout;input[3:0] a,b;input cin;full_add1 f0(a[0],b[0],cin,sum[0],cin1);     //级连描述full_add1 f1(a[1],b[1],cin1,sum[1],cin2);full_add1 f2(a[2],b[2],cin2,sum[2],cin3);    - 21 - 程序文本   full_add1 f3(a[3],b[3],cin3,sum[3],cout);   endmodule    【例7.19】数据流描述的4位全加器   module add4_2(cout,sum,a,b,cin);   output[3:0] sum;   output cout;   input[3:0] a,b;   input cin;   assign {cout,sum}=a+b+cin;   endmodule    【例7.20】行为描述的4位全加器   module add4_3(cout,sum,a,b,cin);   output[3:0] sum;   output cout;   input[3:0] a,b;   input cin;   reg[3:0] sum;   reg cout;   always @(a or b or cin)   begin    {cout,sum}=a+b+cin;   end   endmodule    【例8.1】$time与$realtime的区别    `timescale 10ns/1ns    module time_dif;    reg ts;    parameter delay=2.6;    initial    begin    #delay  ts=1;    #delay  ts=0;    #delay  ts=1;    #delay  ts=0;    end    initial  $monitor($time,,,"ts=%b",ts);   //使用函数$time- 22 -    王金明:《Verilog HDL程序设计教程》endmodule【例8.2】$random函数的使用`timescale 10ns/1nsmodule random_tp;integer data;integer i;parameter delay=10;initial $monitor($time,,,"data=%b",data);initial begin    for(i=0; i<=100; i=i+1)    #delay  data=$random;         //每次产生一个随机数    endendmodule【例8.3】1位全加器进位输出UDP元件primitive carry_udp(cout,cin,a,b);input cin,a,b;output cout; table   //cin  a  b  :  cout            //真值表    0   0   0  :    0;    0   1   0  :    0;    0   0   1  :    0;    0   1   1  :    1;    1   0   0  :    0;    1   0   1  :    1;    1   1   0  :    1;    1   1   1  :    1;endtableendprimitive【例8.4】包含x态输入的1位全加器进位输出UDP元件primitive carry_udpx1(cout,cin,a,b);input cin,a,b;output cout;    table    // cin  a  b  :  cout     //真值表    0   0   0  :    0;    - 23 - 程序文本    0   1   0  :    0;    0   0   1  :    0;    0   1   1  :    1;    1   0   0  :    0;    1   0   1  :    1;    1   1   0  :    1;    1   1   1  :    1;    0   0   x  :    0;     //只要有两个输入为0,则进位输出肯定为0    0   x   0  :    0;    x   0   0  :    0;    1   1   x  :    1;     //只要有两个输入为1,则进位输出肯定为1    1   x   1  :    1;    x   1   1  :    1;    endtable    endprimitive    【例8.5】用简缩符“?”表述的1位全加器进位输出UDP元件   primitive carry_udpx2(cout,cin,a,b);   input cin,a,b;   output cout;    table    // cin  a  b :  cout           //真值表       0   0  :    0;      //只要有两个输入为0,则进位输出肯定为0    0   ?   0  :    0;    0   0   ?  :    0;       1   1  :    1;     //只要有两个输入为1,则进位输出肯定为1    1   ?   1  :    1;    1   1   ?  :    1;    endtable    endprimitive    【例8.6】3选1多路选择器UDP元件    primitive mux31(Y,in0,in1,in2,s2,s1);    input in0,in1,in2,s2,s1;    output Y;    table    //in0 in1 in2 s2 s1 : Y    0   ?   ?    0   0  :  0;     //当s2s1=00时,Y=in0    1   ?   ?    0   0  :  1;       0   ?    0   1  :  0;     //当s2s1=01时,Y=in1- 24 -    王金明:《Verilog HDL程序设计教程》       1   ?    0   1  :  1;          0    1   ?  :  0;     //当s2s1=1?时,Y=in2          1    1   ?  :  1;    0   0   ?    0   ?  :  0;    1   1   ?    0   ?  :  1;    0   ?   0    ?   0  :  0;    1   ?   1    ?   0  :  1;       0   0    ?   1  :  0;       1   1    ?   1  :  1;    endtableendprimitive【例8.7】电平敏感的1位数据锁存器UDP元件primitive latch(Q,clk,reset,D);input clk,reset,D;output Q;reg Q;initial Q = 1'b1;    //初始化    table    // clk reset D : state : Q       1   ?  : ? : 0 ;  //reset=1,则不管其他端口为什么值,输出都为0    0   0   0  : ? : 0 ;  //clk=0,锁存器把D端的输入值输出    0   0   1  : ? : 1 ;    1   0   ?  : ? : - ;   //clk=1,锁存器的输出保持原值,用符号“-”表示    endtableendprimitive【例8.8】上升沿触发的D触发器UDP元件primitive DFF(Q,D,clk);output Q;input D,clk;reg Q;   table   //clk  D : state : Q    (01)  0   : ? :   0;     //上升沿到来,输出Q=D    (01)  1   : ? :   1;    (0x)  1   : 1 :   1;    (0x)  0   : 0 :   0;    (?0)  ?   : ? :   -;     //没有上升沿到来,输出Q保持原值       (??)  : ? :   - ;     //时钟不变,输出也不变    - 25 - 程序文本    endtable   endprimitive    【例8.9】带异步置1和异步清零的上升沿触发的D触发器UDP元件   primitive DFF_UDP(Q,D,clk,clr,set);   output Q;   input D,clk,clr,set;   reg Q;    table    // clk  D   clr  et   state : Q    (01)  1   0   0   : ? :   0;    (01)  1   0   x   : ? :   0;            0   x   : 0 :   0;    (01)  0   0   0   : ? :   1;    (01)  0   x   0   : ? :   1;            x   0   : 1 :   1;    (x1)  1   0   0   : 0 :   0;    (x1)  0   0   0   : 1 :   1;    (0x)  1   0   0   : 0 :   0;    (0x)  0   0   0   : 1 :   1;            1   ?   : ? :   1;       //异步复位            0   1   : ? :   0;       //异步置1    n     ?   0   0   : ? :   -;         *   ?   ?   : ? :   -;            (?0) ?  : ? :   -;               (?0): ? :   -;                  : ? :   x;    endtable   endprimitive    【例8.12】延迟定义块举例    module delay(out,a,b,c);    output out;    input a,b,c;    and a1(n1,a,b);    or o1(out,c,n1);    specify    (a=>out)=2;    (b=>out)=3;    (c=>out)=1;- 26 -    王金明:《Verilog HDL程序设计教程》    endspecifyendmodule【例8.13】激励波形的描述'timescale 1ns/1nsmodule test1;reg A,B,C;initial    begin                    //激励波形描述    A = 0; B = 1; C = 0;    #100 C = 1;    #100 A = 1; B = 0;    #100 A = 0;    #100 C = 0;    #100 $finish;    endinitial $monitor($time,,,"A=%d B=%d C=%d",A,B,C);    //显示endmodule【例8.15】用always过程块产生两个时钟信号module test2;reg clk1,clk2;parameter CYCLE = 100;always  begin    {clk1,clk2} = 2'b10;    #(CYCLE/4)  {clk1,clk2} = 2'b01;    #(CYCLE/4)  {clk1,clk2} = 2'b11;    #(CYCLE/4)  {clk1,clk2} = 2'b00;    #(CYCLE/4)  {clk1,clk2} = 2'b10;   endinitial $monitor($time,,,"clk1=%b clk2=%b",clk1,clk2);endmodule【例8.17】存储器在仿真程序中的应用module ROM(addr,data,oe);output[7:0] data;      //数据信号input[14:0] addr;      //地址信号input oe;      //读使能信号,低电平有效    - 27 - 程序文本   reg[7:0] mem[0:255];      //存储器定义   parameter DELAY = 100;   assign #DELAY data=(oe==0) ? mem[addr] : 8'hzz;   initial $readmemh("rom.hex",mem);    //从文件中读入数据   endmodule    【例8.18】8位乘法器的仿真程序   `timescale 10ns/1ns   module mult_tp;                     //测试模块的名字   reg[7:0] a,b;      //测试输入信号定义为reg型   wire [15:0] out;      //测试输出信号定义为wire型   integer i,j;   mult8 m1(out,a,b);     //调用测试对象    //激励波形设定   initial    begin    a=0;b=0;    for(i=1;i<255;i=i+1)    #10 a=i;    end   initial    begin    for(j=1;j<255;j=j+1)    #10 b=j;    end   initial       //定义结果显示格式    begin    $monitor($time,,,"%d * %d= %d",a,b,out);    #2560  $finish;    end   endmodule   module mult8(out, a, b);      //8位乘法器源代码   parameter size=8;   input[size:1] a,b;     //两个操作数   output[2*size:1] out;     //结果   assign out=a*b;                 //乘法运算符- 28 -    王金明:《Verilog HDL程序设计教程》endmodule【例8.19】8位加法器的仿真程序`timescale 1ns/1nsmodule add8_tp;         //仿真模块无端口列表reg[7:0] A,B;      //输入激励信号定义为reg型reg cin;wire[7:0] SUM;        //输出信号定义为wire型wire cout;parameter DELY = 100;add8  AD1(SUM,cout,A,B,cin);      //调用测试对象initial begin     //激励波形设定    A= 8'd0;    B= 8'd0;    cin=1'b0;#DELY    A= 8'd100;  B= 8'd200;  cin=1'b1;#DELY    A= 8'd200;  B= 8'd88;#DELY    A= 8'd210;  B= 8'd18;   cin=1'b0;#DELY    A= 8'd12;   B= 8'd12;#DELY    A= 8'd100;  B= 8'd154;#DELY    A= 8'd255;  B= 8'd255;  cin=1'b1;#DELY    $finish;end//输出格式定义initial $monitor($time,,,"%d + %d + %b = {%b, %d}",A,B,cin,cout,SUM);endmodulemodule add8(SUM,cout,A,B,cin);     //待测试的8位加法器模块output[7:0] SUM;output cout;input[7:0] A,B;input cin;assign {cout,SUM}=A+B+cin;endmodule【例8.20】2选1多路选择器的仿真`timescale 1ns/1nsmodule mux_tp;reg a,b,sel;wire out;    - 29 - 程序文本   MUX2_1 m1(out,a,b,sel);         //调用待测试模块   initial   begin    a=1'b0; b=1'b0; sel=1'b0;   #5   sel=1'b1;   #5   a=1'b1;  el=1'b0;   #5   sel=1'b1;   #5   a=1'b0; b=1'b1;  el=1'b0;   #5   sel=1'b1;   #5   a=1'b1; b=1'b1; sel=1'b0;   #5   sel=1'b1;   end   initial $monitor($time,,,"a=%b b=%b sel=%b out=%b",a,b,sel,out);   endmodule   module MUX2_1(out,a,b,sel);         //待测试的2选1MUX模块   input a,b,sel;   output out;   not #(0.4,0.3) (sel_,sel);     //#(0.4,0.3)为门延时   and #(0.7,0.6) (a1,a,sel_);   and #(0.7,0.6) (a2,b,sel);   or #(0.7,0.6) (out,a1,a2);   endmodule    【例8.21】8位计数器的仿真   `timescale 10ns/1ns   module count8_tp;   reg clk,reset;       //输入激励信号定义为reg型   wire[7:0] qout;            //输出信号定义为wire型   parameter DELY=100;   counter  C1(qout,reset,clk);       //调用测试对象   always #(DELY/2) clk = ~clk;      //产生时钟波形   initial   begin      //激励波形定义    clk =0; reset=0;- 30 -    王金明:《Verilog HDL程序设计教程》#DELY   reset=1;#DELY   reset=0;#(DELY*300)  $finish;end    //结果显示initial $monitor($time,,,"clk=%d reset=%d qout=%d",clk,reset,qout);endmodulemodule counter(qout,reset,clk);      //待测试的8位计数器模块output[7:0] qout;input clk,reset;reg[7:0] qout;always @(posedge clk)   begin    if (reset)  qout<=0;    else     qout<=qout+1;   endendmodule【例9.1】基本门电路的几种描述方法(1)门级结构描述module gate1(F,A,B,C,D);input A,B,C,D;output F;nand(F1,A,B);     //调用门元件and(F2,B,C,D);or(F,F1,F2);endmodule(2)数据流描述module gate2(F,A,B,C,D);input A,B,C,D;output F;assign F=(A&B)|(B&C&D);      //assign持续赋值endmodule(3)行为描述module gate3(F,A,B,C,D);input A,B,C,D;output F;    - 31 - 程序文本    reg F;    always @(A or B or C or D)     //过程赋值    begin    F=(A&B)|(B&C&D);    end    endmodule    【例9.2】用bufif1关键字描述的三态门   module tri_1(in,en,out);   input in,en;   output out;   tri out;   bufif1 b1(out,in,en);     //注意三态门端口的排列顺序   endmodule    【例9.3】用assign语句描述的三态门   module tri_2(out,in,en);   output out;   input in,en;   assign out = en ? in : 'bz;    //若en=1,则out=in;若en=0,则out为高阻态    endmodule    【例9.4】三态双向驱动器   module bidir(tri_inout,out,in,en,b);   inout tri_inout;   output out;   input in,en,b;   assign tri_inout = en ? in : 'bz;   assign out = tri_inout ^ b;   endmodule    【例9.5】三态双向驱动器   module bidir2(bidir,en,clk);   inout[7:0] bidir;   input en,clk;   reg[7:0] temp;   assign bidir= en ? temp : 8'bz;   always @(posedge clk)    begin- 32 -    王金明:《Verilog HDL程序设计教程》    if(en)  temp=bidir;    else    temp=temp+1;   endendmodule【例9.6】3-8译码器module decoder_38(out,in);output[7:0] out;input[2:0] in;reg[7:0] out;always @(in)  begin   case(in)    3'd0: out=8'b11111110;    3'd1: out=8'b11111101;    3'd2: out=8'b11111011;    3'd3: out=8'b11110111;    3'd4: out=8'b11101111;    3'd5: out=8'b11011111;    3'd6: out=8'b10111111;    3'd7: out=8'b01111111;   endcase  endendmodule【例9.7】8-3优先编码器module encoder8_3(none_on,outcode,a,b,c,d,e,f,g,h);output none_on;output[2:0] outcode;input a,b,c,d,e,f,g,h;reg[3:0] outtemp;assign {none_on,outcode}=outtemp;always @(a or b or c or d or e or f or g or h)  begin    if(h)        outtemp=4'b0111;    else if(g)      outtemp=4'b0110;    else if(f)      outtemp=4'b0101;    else if(e)      outtemp=4'b0100;    else if(d)      outtemp=4'b0011;    else if(c)       outtemp=4'b0010;    - 33 - 程序文本    else if(b)      outtemp=4'b0001;    else if(a)      outtemp=4'b0000;    else         outtemp=4'b1000;    end    endmodule    【例9.8】用函数定义的8-3优先编码器   module code_83(din, dout);   input[7:0] din;   output[2:0] dout;   function[2:0] code;      //函数定义   input[7:0] din;           //函数只有输入端口,输出为函数名本身   if (din[7])       code = 3'd7;   else if (din[6])     code = 3'd6;   else if (din[5])     code = 3'd5;   else if (din[4])     code = 3'd4;   else if (din[3])     code = 3'd3;   else if (din[2])     code = 3'd2;   else if (din[1])     code = 3'd1;   else      code = 3'd0;   endfunction   assign  dout = code(din);   //函数调用   endmodule    【例9.9】七段数码管译码器    module decode47(a,b,c,d,e,f,g,D3,D2,D1,D0);    output a,b,c,d,e,f,g;    input D3,D2,D1,D0;     //输入的4位BCD码    reg a,b,c,d,e,f,g;    always @(D3 or D2 or D1 or D0)    begin    case({D3,D2,D1,D0})          //用case语句进行译码    4'd0: {a,b,c,d,e,f,g}=7'b1111110;    4'd1: {a,b,c,d,e,f,g}=7'b0110000;    4'd2: {a,b,c,d,e,f,g}=7'b1101101;    4'd3: {a,b,c,d,e,f,g}=7'b1111001;    4'd4: {a,b,c,d,e,f,g}=7'b0110011;    4'd5: {a,b,c,d,e,f,g}=7'b1011011;- 34 -    王金明:《Verilog HDL程序设计教程》    4'd6: {a,b,c,d,e,f,g}=7'b1011111;    4'd7: {a,b,c,d,e,f,g}=7'b1110000;    4'd8: {a,b,c,d,e,f,g}=7'b1111111;    4'd9: {a,b,c,d,e,f,g}=7'b1111011;    default: {a,b,c,d,e,f,g}=7'bx;    endcase  endendmodule【例9.10】奇偶校验位产生器module parity(even_bit,odd_bit,input_bus);output even_bit,odd_bit;input[7:0] input_bus;assign odd_bit = ^ input_bus;     //产生奇校验位assign even_bit = ~odd_bit;      //产生偶校验位endmodule【例9.11】用if-else语句描述的4选1 MUXmodule mux_if(out,in0,in1,in2,in3,sel);output out;input in0,in1,in2,in3;input[1:0] sel;reg out;always @(in0 or in1 or in2 or in3 or sel)    begin    if(sel==2'b00)         out=in0;    else if(sel==2'b01)    out=in1;    else if(sel==2'b10)    out=in2;    else       out=in3;    endendmodule【例9.12】用case语句描述的4选1 MUXmodule mux_case(out,in0,in1,in2,in3,sel);output out;input in0,in1,in2,in3;input[1:0] sel;reg out;always @(in0 or in1 or in2 or in3 or sel) begin    - 35 - 程序文本    case(sel)    2'b00: out=in0;    2'b01: out=in1;    2'b10: out=in2;    default: out=in3;    endcase    end   endmodule    【例9.13】用组合电路实现的ROM    module rom(addr,data);    input[3:0] addr;    output[7:0] data;    function[7:0] romout;    input[3:0] addr;    case(addr)    0 : romout = 0;    1 : romout = 1;    2 : romout = 4;    3 : romout = 9;    4 : romout = 16;    5 : romout = 25;    6 : romout = 36;    7 : romout = 49;    8 : romout = 64;    9 : romout = 81;    10 : romout = 100;    11 : romout = 121;    12 : romout = 144;    13 : romout = 169;    14 : romout = 196;    15 : romout = 225;    default : romout = 8'hxx;    endcase    endfunction    assign data = romout(addr);    endmodule    【例9.14】基本D触发器- 36 -    王金明:《Verilog HDL程序设计教程》module DFF(Q,D,CLK);output Q;input D,CLK;reg Q;always @(posedge CLK)    begin    Q <= D;    endendmodule【例9.15】带异步清0、异步置1的D触发器module DFF1(q,qn,d,clk,set,reset);input d,clk,set,reset;output q,qn;reg q,qn;always @(posedge clk or negedge set or negedge reset) begin    if (!reset) begin    q <= 0;      //异步清0,低电平有效    qn <= 1;    end    else if (!set)  begin    q <= 1;      //异步置1,低电平有效    qn <= 0;    end    else       begin    q <= d;    qn <= ~d;    end endendmodule【例9.16】带同步清0、同步置1的D触发器module DFF2(q,qn,d,clk,set,reset);input d,clk,set,reset;output q,qn;reg q,qn;always @(posedge clk) begin    if (reset)  begin    - 37 - 程序文本    q <= 0; qn <= 1;     //同步清0,高电平有效    end    else if (set) begin    q <=1; qn <=0;      //同步置1,高电平有效    end    else       begin    q <= d;  n <= ~d;    end    end    endmodule    【例9.17】带异步清0、异步置1的JK触发器    module JK_FF(CLK,J,K,Q,RS,SET);    input CLK,J,K,SET,RS;    output Q;    reg Q;    always @(posedge CLK or negedge RS or negedge SET)    begin    if(!RS)  Q <= 1'b0;    else if(!SET) Q <= 1'b1;    else case({J,K})    2'b00 :   <= Q;    2'b01 :   <= 1'b0;    2'b10 : Q <= 1'b1;    2'b11 : Q <= ~Q;    default: Q<= 1'bx;    endcase    end    endmodule    【例9.18】电平敏感的1位数据锁存器   module latch_1(q,d,clk);   output q;   input d,clk;   assign q = clk ? d : q;     //时钟信号为高电平时,将输入端数据锁存   endmodule    【例9.19】带置位和复位端的1位数据锁存器   module latch_2(q,d,clk,set,reset);   output q;- 38 -    王金明:《Verilog HDL程序设计教程》input d,clk,set,reset;assign q = reset ? 0 : (set ? 1 : (clk ? d : q));endmodule【例9.20】8位数据锁存器module latch_8(qout,data,clk);output[7:0] qout;input[7:0] data;input clk;reg[7:0] qout;always @(clk or data)    begin    if (clk) qout<=data;    endendmodule【例9.21】8位数据寄存器module reg8(out_data,in_data,clk,clr);output[7:0] out_data;input[7:0] in_data;input clk,clr;reg[7:0] out_data;always @(posedge clk or posedge clr)    begin    if(clr)  out_data <=0;    else     out_data <=in_data;    endendmodule【例9.22】8位移位寄存器module shifter(din,clk,clr,dout);input din,clk,clr;output[7:0] dout;reg[7:0] dout;always @(posedge clk)    begin    if (clr)  dout<= 8'b0;     //同步清0,高电平有效    else    begin    dout <= dout << 1;     //输出信号左移一位    - 39 - 程序文本    dout[0] <= din;      //输入信号补充到输出信号的最低位    end    end   endmodule    【例9.23】可变模加法/减法计数器   module updown_count(d,clk,clear,load,up_down,qd);   input[7:0] d;   input clk,clear,load;   input up_down;   output[7:0] qd;   reg[7:0] cnt;   assign qd = cnt;   always @(posedge clk)    begin    if (!clear)       cnt = 8'h00;     //同步清0,低电平有效    else  if (load)     cnt = d;     //同步预置    else  if (up_down)  cnt = cnt + 1;     //加法计数    else       cnt = cnt - 1;     //减法计数    end    endmodule    【例9.24】4位Johnson计数器(异步复位)   module johnson(clk,clr,out);   input clk,clr;   output[3:0] out;   reg[3:0] out;   always @(posedge clk or posedge clr)    begin    if (clr)    out<= 4'h0;    else    begin   out<= out<< 1;    out[0]<= ~out[3];    end    end   endmodule    【例9.25】256×8 RAM模块   module ram256x8(data,address,we,inclock,outclock,q);   input[7:0] data;- 40 -    王金明:《Verilog HDL程序设计教程》input[7:0] address;input we,inclock,outclock;output[7:0] q;lpm_ram_dq myram(.q(q),.data(data),.address(address),    .we(we),.inclock(inclock),.outclock(outclock));defparam myram.lpm_width=8;     //定义数据宽度defparam myram.lpm_widthad=8;     //定义地址宽度endmodule【例9.26】256×16 RAM块module map_lpm_ram(dataout,datain,addr,we,inclk,outclk);input[15:0] datain;      //端口定义input[7:0] addr;input we,inclk,outclk;output[15:0] dataout;    //lpm_ram_dq元件例化lpm_ram_dq ram(.data(datain),.address(addr),.we(we),.inclock(inclk),    .outclock(outclk),.q(dataout));defparam ram.lpm_width=16;     //参数赋值defparam ram.lpm_widthad=8;defparam ram.lpm_indata="REGISTERED";defparam ram.lpm_outdata="REGISTERED";defparam ram.lpm_file="map_lpm_ram.mif";     //RAM块中的内容取自该文件endmodule【例9.27】4位串并转换器module serial_pal(clk,reset,en,in,out);input clk,reset,en,in;output[3:0] out;reg[3:0] out;always @(posedge clk)    begin    if(reset)      out<=4'h0;    else if(en)     out<={out,in};         //使用连接运算符    endendmodule【例9.28】用函数实现简单的处理器module mpc(instr,out);input[17:0] instr;                 //instr为输入的指令    - 41 - 程序文本   output[8:0] out;      //输出结果   reg[8:0] out;   reg func;   reg[7:0] op1,op2;     //从指令中提取的两个操作数   function[16:0] code_add;      //函数的定义   input[17:0] instr;   reg add_func;   reg[7:0] code,opr1,opr2;    begin    code=instr[17:16];     //输入指令instr的高2位是操作码    opr1=instr[7:0];      //输入指令instr的低8位是操作数opr1    case(code)    2'b00:    begin    add_func=1;    opr2=instr[15:8];     //从instr中取第二个操作数    end    2'b01:    begin    add_func=0;    opr2=instr[15:8];     //从instr中取第二个操作数    end    2'b10:    begin    add_func=1;    opr2=8'd1;     //第二个操作数取为1,实现+1操作    end    default:    begin    add_func=0;    opr2=8'd1;       //实现-1操作    end    endcase    code_add={add_func,opr2,opr1};    end    endfunction   always @(instr)    begin- 42 -    王金明:《Verilog HDL程序设计教程》    {func,op2,op1}=code_add(instr);     //调用函数    if(func==1)  out=op1+op2;     //实现两数相加、操作数1加1操作    else         out=op1-op2;     //实现两数相减、操作数1减1操作    endendmodule【例9.29】微处理器的测试代码`timescale 10ns/1ns`include "mpc.v"module mpc_tp;reg[17:0] instr;wire[8:0] out;parameter DELY=10;mpc m1(instr,out);                   //调用待测试模块initial begin    instr=18'd0;#DELY instr=18'b00_01001101_00101111;#DELY instr=18'b00_11001101_11101111;#DELY instr=18'b01_01001101_11101111;#DELY instr=18'b01_01001101_00101111;#DELY instr=18'b10_01001101_00101111;#DELY instr=18'b11_01001101_00101111;#DELY instr=18'b00_01001101_00101111;#DELY $finish;endinitial $monitor($time,,,"instr=%b out=%b",instr,out);endmodule【例9.30】乘累加器(MAC)代码module MAC(out,opa,opb,clk,clr);output[15:0] out;input[7:0] opa,opb;input clk,clr;wire[15:0] sum;reg[15:0] out;function[15:0] mult;        //函数定义,mult函数完成乘法操作input[7:0] opa,opb;         //函数只能定义输入端,输出端口为函数名本身reg[15:0] result;    - 43 - 程序文本   integer i;   begin    result = opa[0]? opb : 0;    for(i= 1; i <= 7; i = i+1)    begin    if(opa[i]==1)  result=result+(opb<<(i-1));    end    mult=result;   end   endfunction   assign sum=mult(opa,opb)+out;   always @(posedge clk or posedge clr)    begin    if(clr)  out<=0;    else     out<=sum;    end   endmodule    【例9.31】乘累加器的测试代码   'timescale 1ns/1ns   'include "mac.v"   module mac_tp;   reg[7:0] opa,opb;      //测试输入信号用reg型变量   reg clr,clk;   wire[15:0] out;       //测试输出信号用wire型变量   parameter DELY = 100;   //测试对象调用   MAC m1(out,opa,opb,clk,clr);   always #(DELY) clk = ~clk;     //产生时钟波形   initial begin      //激励波形定义    clr=1;clk=0;opa=8'd0; opb=8'd0;   #DELY clr=0;opa=8'd1; opb=8'd10;   #DELY opa=8'd2; opb=8'd10;   #DELY opa=8'd3; opb=8'd10;- 44 -    王金明:《Verilog HDL程序设计教程》#DELY opa=8'd4; opb=8'd10;#DELY opa=8'd5; opb=8'd10;#DELY opa=8'd6; opb=8'd10;#DELY opa=8'd7; opb=8'd10;#DELY opa=8'd8; opb=8'd10;#DELY opa=8'd9; opb=8'd10;#DELY opa=8'd10; opb=8'd10;#DELY $finish;end    //结果显示initial $monitor($time,,,"clr=%b opa=%d opb=%d out=%d",clr,opa,opb,out);endmodule【例10.1】非流水线方式8位全加器module adder8(cout,sum,ina,inb,cin,clk);output[7:0] sum;output cout;input[7:0] ina,inb;input cin,clk;reg[7:0] tempa,tempb,sum;reg cout;reg tempc;always @(posedge clk)    begin    tempa=ina;  tempb=inb;  tempc=cin;       //输入数据锁存    endalways @(posedge clk)    begin    {cout,sum}=tempa+tempb+tempc;    endendmodule【例10.2】4级流水方式的8位全加器module pipeline(cout,sum,ina,inb,cin,clk);output[7:0] sum;output cout;input[7:0] ina,inb;input cin,clk;reg[7:0] tempa,tempb,sum;reg tempci,firstco,secondco,thirdco,cout;    - 45 - 程序文本   reg[1:0] firsts,thirda,thirdb;   reg[3:0] seconda,secondb,seconds;   reg[5:0] firsta,firstb,thirds;   always @(posedge clk)    begin    tempa=ina;  tempb=inb;  tempci=cin;      //输入数据缓存    end    always @(posedge clk)    begin    {firstco,firsts}=tempa[1:0]+tempb[1:0]+tempci;    //第一级加(低2位)    firsta=tempa[7:2];     //未参加计算的数据缓存    firstb=tempb[7:2];    end    always @(posedge clk)    begin    {secondco,seconds}={firsta[1:0]+firstb[1:0]+firstco,firsts};    //第二级加(第2、3位相加)    seconda=firsta[5:2];     //数据缓存    secondb=firstb[5:2];    end    always @(posedge clk)    begin    {thirdco,thirds}={seconda[1:0]+secondb[1:0]+secondco,seconds};    //第三级加(第4、5位相加)    thirda=seconda[3:2];     //数据缓存    thirdb=secondb[3:2];    end    always @(posedge clk)    begin    {cout,sum}={thirda[1:0]+thirdb[1:0]+thirdco,thirds};    //第四级加(高两位相加)    end    endmodule    【例10.3】两个加法器和一个选择器的实现方式   module resource1(sum,a,b,c,d,sel);   parameter size=4;   output[size:0] sum;- 46 -    王金明:《Verilog HDL程序设计教程》input sel;input[size-1:0] a,b,c,d;reg[size:0] sum;always @(a or b or c or d or sel)    begin    if(sel)  um=a+b;    else    sum=c+d;    endendmodule【例10.4】两个选择器和一个加法器的实现方式module resource2(sum,a,b,c,d,sel);parameter size=4;output[size-1:0] sum;input sel;input[size-1:0] a,b,c,d;reg[size-1:0] atemp,btemp;reg[size:0] sum;always @(a or b or c or d or sel)    begin    if(sel)  egin  atemp=a;  btemp=b;  end    else    begin  atemp=c;  btemp=d;  end    sum=atemp+btemp;    endendmodule【例10.5】状态机设计的例子module FSM(clk,clr,out,start,step2,step3);input clk,clr,start,step2,step3;output[2:0] out;reg[2:0] out;reg[1:0] state,next_state;parameter    state0=2'b00,state1=2'b01,    state2=2'b11,state3=2'b10;    /*状态编码,采用格雷(Gray)编码方式*/always @(posedge clk or posedge clr)      /*该进程定义起始状态*/begin    if (clr) state <= state0;    else state <= next_state;    - 47 - 程序文本   end   always @(state or start or step2 or step3)      /*该进程实现状态的转换*/   begin   case (state)    state0: begin    if (start)  next_state <=state1;    else      next_state <=state0;    end    state1: begin    next_state <= state2;    end    state2: begin    if (step2)  next_state <=state3;    else      next_state <=state0;    end    state3: begin    if (step3)  next_state <=state0;    else      next_state <=state3;    end    default:     next_state <=state0;    /*default语句*/    endcase   end   always @(state)       /*该进程定义组合逻辑(FSM的输出)*/   begin   case(state)    state0: out=3'b001;    state1: out=3'b010;    state2: out=3'b100;    state3: out=3'b111;    default:out=3'b001;      /*default语句,避免锁存器的产生*/   endcase   end   endmodule    【例10.6】自动转换量程频率计控制器   /*信号定义:   clk:     输入时钟;- 48 -    王金明:《Verilog HDL程序设计教程》clear:     为整个频率计的异步复位信号;reset:     用来在量程转换开始时复位计数器;std_f_sel: 用来选择标准时基;cntover:    代表超量程;cntlow:     代表欠量程。状态A,B,C,D,E,F采用一位热码编码  */module control(std_f_sel,reset,clk,clear,cntover,cntlow);output[1:0] std_f_sel;output reset;input clk,clear,cntover,cntlow;reg[1:0] std_f_sel;reg reset;reg[5:0] present,next;     //用于保存当前状态和次态的中间变量parameter start_fl00k=6'b000001,     //状态A编码,采用1位热码    fl00k_cnt=6'b000010,     //状态B    start_fl0k=6'b000100,     //状态C    fl0k_cnt=6'b001000,      //状态D    start_flk=6'b010000,     //状态E    flk_cnt=6'b100000;     //状态Falways @(posedge clk or posedge clear)    begin    if(clear)   present<=start_fl0k;     //start_fl0k为起始状态    else      present<=next;    endalways @(present or cntover or cntlow)    begin    case(present)      //用case语句描述状态转换    start_fl00k:    next<=fl00k_cnt;    fl00k_cnt:    begin    if(cntlow)  next<=start_fl0k;    else      next<=fl00k_cnt;    end    start_fl0k:     next<=fl0k_cnt;    fl0k_cnt:    begin    if(cntlow)       next<=start_flk;    else  if(cntover)   next<=start_fl00k;    - 49 - 程序文本    else       next<=fl0k_cnt;    end    start_flk:     next<=flk_cnt;    flk_cnt:    begin    if(cntover)     next<=start_fl0k;    else       next<=flk_cnt;    end    default:next<=start_fl0k;        //缺省状态为起始状态    endcase    end   always @(present)     //该进程产生各状态下的输出    begin    case(present)    start_fl00k:    begin   reset=1;  std_f_sel=2'b00;  end    fl00k_cnt:     begin   reset=0;  std_f_sel=2'b00;  end    start_fl0k:     begin   reset=1;  std_f_sel=2'b01;  end    fl0k_cnt:     begin   reset=0;  std_f_sel=2'b01;  end    start_flk:     begin   reset=1;  std_f_sel=2'b11;  end    flk_cnt:     begin   reset=0;  std_f_sel=2'b11;  end    default:     begin   reset=1;  std_f_sel=2'b01;  end    endcase    end   endmodule    【例10.7】8位全加器   module add8(sum,cout,b,a,cin);   output[7:0] sum;   output cout;   input[7:0] a,b;   input cin;    assign {cout,sum}=a+b+cin;   endmodule    【例10.8】8位寄存器    module reg8(qout,in,clk,clear);    output[7:0] qout;    input[7:0] in;    input clk,clear;- 50 -    王金明:《Verilog HDL程序设计教程》reg[7:0] qout;always @(posedge clk or posedge clear)    begin    if(clear)   qout=0;     //异步清0    else       qout=in;    endendmodule【例10.9】累加器顶层连接文本描述module acc(accout,cout,accin,cin,clk,clear);output[7:0] accout;output cout;input[7:0] accin;input cin,clk,clear;wire[7:0] sum;add8 accadd8(sum,cout,accout,accin,cin);     //调用add8子模块reg8 accreg8(accout,sum,clk,clear);     //调用reg8子模块endmodule【例10.10】用`include描述的累加器`include “add8.v”;`include “reg8.v”;module accn(accout,cout,accin,cin,clk,clear);output[7:0] accout;output cout;input[7:0] accin;input cin,clk,clear;wire[7:0] sum;add8 accadd8(sum,cout,accout,accin,cin);     //调用add8子模块reg8 accreg8(accout,sum,clk,clear);     //调用reg8子模块endmodule【例10.11】阻塞赋值方式描述的移位寄存器1module block1(Q0,Q1,Q2,Q3,din,clk);output Q0,Q1,Q2,Q3;input clk,din;    - 51 - 程序文本    reg Q0,Q1,Q2,Q3;    always @(posedge clk)    begin    Q3=Q2;         //注意赋值语句的顺序    Q2=Q1;    Q1=Q0;    Q0=din;    end    endmodule    【例10.12】阻塞赋值方式描述的移位寄存器2    module block2(Q0,Q1,Q2,Q3,din,clk);    output Q0,Q1,Q2,Q3;    input clk,din;    reg Q0,Q1,Q2,Q3;    always @(posedge clk)    begin    Q3=Q2;    Q1=Q0;           //该句与下句的顺序与例10.11颠倒    Q2=Q1;    Q0=din;    end    endmodule    【例10.13】阻塞赋值方式描述的移位寄存器3    module block3(Q0,Q1,Q2,Q3,din,clk);    output Q0,Q1,Q2,Q3;    input clk,din;    reg Q0,Q1,Q2,Q3;    always @(posedge clk)    begin    Q0=din;       //4条赋值语句的顺序与例10.11完全颠倒    Q1=Q0;    Q2=Q1;    Q3=Q2;    end    endmodule    【例10.14】非阻塞赋值方式描述的移位寄存器    module block4(Q0,Q1,Q2,Q3,din,clk);- 52 -    王金明:《Verilog HDL程序设计教程》output Q0,Q1,Q2,Q3;input clk,din;reg Q0,Q1,Q2,Q3;always @(posedge clk)    begin    Q3<=Q2;    Q1<=Q0;    Q2<=Q1;    Q0<=din;    endendmodule【例10.15】长帧同步时钟的产生module longframe1(clk,strb);parameter delay=8;input clk;output strb;reg strb;reg[7:0] counter;always@(posedge clk)    begin    if(counter==255)    counter=0;    else      counter=counter+1;    endalways@(counter)    begin    if(counter<=(delay-1))  strb=1;    else       strb=0;    endendmodule【例10.16】引入了D触发器的长帧同步时钟的产生module longframe2(clk,strb);parameter delay=8;input clk;output strb;reg[7:0] counter;reg temp;reg strb;always@(posedge clk)    - 53 - 程序文本    begin    if(counter==255)    counter=0;    else       counter=counter+1;    end    always@(posedge clk)    begin    strb=temp;          //引入一个触发器    end    always@(counter)    begin    if(counter<=(delay-1))  temp=1;    else       temp=0;    end    endmodule    【例11.1】数字跑表    /*信号定义:    CLK:     CLK为时钟信号;    CLR:     为异步复位信号;    PAUSE:     为暂停信号;    MSH,MSL:  百分秒的高位和低位;    SH,SL:     秒信号的高位和低位;    MH,ML:     分钟信号的高位和低位。 */    module paobiao(CLK,CLR,PAUSE,MSH,MSL,SH,SL,MH,ML);    input CLK,CLR;    input PAUSE;    output[3:0] MSH,MSL,SH,SL,MH,ML;    reg[3:0] MSH,MSL,SH,SL,MH,ML;    reg cn1,cn2;     //cn1为百分秒向秒的进位,cn2为秒向分的进位    //百分秒计数进程,每计满100,cn1产生一个进位    always @(posedge CLK or posedge CLR)    begin    if(CLR)  begin     //异步复位    {MSH,MSL}<=8'h00;    cn1<=0;    end    else      if(!PAUSE)      //PAUSE为0时正常计数,为1时暂停计数    begin    if(MSL==9)  begin- 54 -    王金明:《Verilog HDL程序设计教程》    MSL<=0;    if(MSH==9)    begin  MSH<=0;  cn1<=1;  end    else  MSH<=MSH+1;    end    else     begin    MSL<=MSL+1;  cn1<=0;    end    endend//秒计数进程,每计满60,cn2产生一个进位always @(posedge cn1 or posedge CLR)begin    if(CLR)  egin     //异步复位    {SH,SL}<=8'h00;    cn2<=0;    end    else    if(SL==9)     //低位是否为9    begin    SL<=0;    if(SH==5)   begin  SH<=0;  cn2<=1;  end    else       SH<=SH+1;    end    else    begin  SL<=SL+1;  cn2<=0;  endend//分钟计数进程,每计满60,系统自动清零always @(posedge cn2 or posedge CLR)begin    if(CLR)    begin  {MH,ML}<=8'h00;  end     //异步复位    else  if(ML==9) begin    ML<=0;    if(MH==5)   MH<=0;    else       MH<=MH+1;    end    else    ML<=ML+1;end    - 55 - 程序文本    endmodule    【例11.2】4位数字频率计控制模块    module fre_ctrl(clk,rst,count_en,count_clr,load);    output count_en,count_clr,load;    input clk,rst;    reg count_en,load;    always @(posedge clk)    begin    if(rst)  egin  count_en=0;  load=1;  end    else    begin    count_en=~count_en;    load=~count_en;      //load信号的产生    end    end    assign  count_clr=~clk&load;      //count_clr信号的产生    endmodule    【例11.3】4位数字频率计计数子模块    module count10(out,cout,en,clr,clk);    output[3:0] out;    output cout;    input en,clr,clk;    reg[3:0] out;    always @(posedge clk or posedge clr)    begin    if (clr)  out = 0;     //异步清0    else   if(en)    begin    if(out==9)  out=0;    else       out = out+1;    end    end    assign  cout =((out==9)&en)?1:0;     //产生进位信号    endmodule    【例11.4】频率计锁存器模块    module latch_16(qo,din,load);    output[15:0] qo;- 56 -    王金明:《Verilog HDL程序设计教程》input[15:0] din;input load;reg[15:0] qo;always @(posedge load)    begin  qo=din;  endendmodule【例11.5】交通灯控制器/* 信号定义与说明:CLK:   为同步时钟;EN:     使能信号,为1的话,则控制器开始工作;LAMPA: 控制A方向四盏灯的亮灭;其中,LAMPA0~LAMPA3,分别控制A方向的    左拐灯、绿灯、黄灯和红灯;LAMPB: 控制B方向四盏灯的亮灭;其中,LAMPB0 ~ LAMPB3,分别控制B方向的    左拐灯、绿灯、黄灯和红灯;ACOUNT: 用于A方向灯的时间显示,8位,可驱动两个数码管;BCOUNT: 用于B方向灯的时间显示,8位,可驱动两个数码管。 */module traffic(CLK,EN,LAMPA,LAMPB,ACOUNT,BCOUNT);output[7:0] ACOUNT,BCOUNT;output[3:0] LAMPA,LAMPB;input CLK,EN;reg[7:0] numa,numb;reg tempa,tempb;reg[2:0] counta,countb;reg[7:0] ared,ayellow,agreen,aleft,bred,byellow,bgreen,bleft;reg[3:0] LAMPA,LAMPB;always @(EN)if(!EN) begin                       //设置各种灯的计数器的预置数    ared    <=8'd55;     //55秒    ayellow <=8'd5;      //5秒    agreen <=8'd40;     //40秒    aleft   <=8'd15;     //15秒    bred    <=8'd65;     //65秒    byellow <=8'd5;      //5秒    bleft   <=8'd15;     //15秒    bgreen <=8'd30;     //30秒 end    - 57 - 程序文本    assign  ACOUNT=numa;    assign  BCOUNT=numb;    always @(posedge CLK)        //该进程控制A方向的四种灯    begin    if(EN)    begin    if(!tempa)    begin    tempa<=1;    case(counta)         //控制亮灯的顺序    0:  begin numa<=agreen;     LAMPA<=2; counta<=1; end    1:  begin numa<=ayellow;    LAMPA<=4; counta<=2; end    2:  begin numa<=aleft;     LAMPA<=1; counta<=3; end    3:  begin numa<=ayellow;    LAMPA<=4; counta<=4; end    4:  begin numa<=ared;     LAMPA<=8; counta<=0; end    default:     LAMPA<=8;    endcase    end    else  begin               //倒计时    if(numa>1)    if(numa[3:0]==0) begin    numa[3:0]<=4'b1001;    numa[7:4]<=numa[7:4]-1;    end    else      numa[3:0]<=numa[3:0]-1;    if (numa==2)  tempa<=0;    end    end    else    begin    LAMPA<=4'b1000;    counta<=0;   tempa<=0;    end    end    always @(posedge CLK)            //该进程控制B方向的四种灯    begin    if (EN)    begin    if(!tempb)- 58 -    王金明:《Verilog HDL程序设计教程》    begin    tempb<=1;    case (countb)            //控制亮灯的顺序    0:  begin numb<=bred;     LAMPB<=8; countb<=1; end    1:  begin numb<=bgreen;     LAMPB<=2; countb<=2; end    2:  begin numb<=byellow;    LAMPB<=4; countb<=3; end    3:  begin numb<=bleft;     LAMPB<=1; countb<=4; end    4:  begin numb<=byellow;    LAMPB<=4; countb<=0; end    default:     LAMPB<=8;    endcase    end   else    begin                     //倒计时    if(numb>1)    if(!numb[3:0])    begin    numb[3:0]<=9;    numb[7:4]<=numb[7:4]-1;    end    else       numb[3:0]<=numb[3:0]-1;    if(numb==2)  tempb<=0;   end  end    else    begin    LAMPB<=4'b1000;    tempb<=0;   countb<=0;    end endendmodule【例11.6】“梁祝”乐曲演奏电路//信号定义与说明://clk_4Hz: 用于控制音长(节拍)的时钟频率;//clk_6MHz: 用于产生各种音阶频率的基准频率;//speaker: 用于激励扬声器的输出信号,本例中为方波信号;//high, med, low:分别用于显示高音、中音和低音音符,各驱动一个数码管来显示。module song(clk_6MHz,clk_4Hz,speaker,high,med,low);input clk_6MHz, clk_4Hz;output speaker;output[3:0] high,med,low;    - 59 - 程序文本    reg[3:0] high,med,low;    reg[13:0] divider,origin;    reg[7:0] counter;    reg speaker;    wire carry;    assign carry=(divider==16383);    always @(posedge clk_6MHz)    begin   if(carry)  divider=origin;    else    divider=divider+1;    end    always @(posedge carry)    begin    speaker=~speaker;      //2分频产生方波信号    end    always @(posedge clk_4Hz)    begin    case({high,med,low})         //分频比预置    'b000000000011: origin=7281;    'b000000000101: origin=8730;    'b000000000110: origin=9565;    'b000000000111: origin=10310;    'b000000010000: origin=10647;    'b000000100000: origin=11272;    'b000000110000: origin=11831;    'b000001010000: origin=12556;    'b000001100000: origin=12974;    'b000100000000: origin=13516;    'b000000000000: origin=16383;    endcase    end    always @(posedge clk_4Hz)    begin    if(counter==63)  counter=0;      //计时,以实现循环演奏    else      counter=counter+1;    case(counter)     //记谱- 60 -    王金明:《Verilog HDL程序设计教程》0: {high,med,low}='b000000000011;     //低音“3”1: {high,med,low}='b000000000011;     //持续4个时钟节拍2: {high,med,low}='b000000000011;3: {high,med,low}='b000000000011;4: {high,med,low}='b000000000101;     //低音“5”5: {high,med,low}='b000000000101;     //发3个时钟节拍6: {high,med,low}='b000000000101;7: {high,med,low}='b000000000110;     //低音“6”8: {high,med,low}='b000000010000;     //中音“1”9: {high,med,low}='b000000010000;     //发3个时钟节拍10: {high,med,low}='b000000010000;11: {high,med,low}='b000000100000;     //中音“2”12: {high,med,low}='b000000000110;     //低音“6”13: {high,med,low}='b000000010000;14: {high,med,low}='b000000000101;15: {high,med,low}='b000000000101;16: {high,med,low}='b000001010000;     //中音“5”17: {high,med,low}='b000001010000;     //发3个时钟节拍18: {high,med,low}='b000001010000;19: {high,med,low}='b000100000000;     //高音“1”20: {high,med,low}='b000001100000;21: {high,med,low}='b000001010000;22: {high,med,low}='b000000110000;23: {high,med,low}='b000001010000;24: {high,med,low}='b000000100000;     //中音“2”25: {high,med,low}='b000000100000;     //持续11个时钟节拍26: {high,med,low}='b000000100000;27: {high,med,low}='b000000100000;28: {high,med,low}='b000000100000;29: {high,med,low}='b000000100000;30: {high,med,low}='b000000100000;31: {high,med,low}='b000000100000;32: {high,med,low}='b000000100000;33: {high,med,low}='b000000100000;34: {high,med,low}='b000000100000;35: {high,med,low}='b000000110000;     //中音“3”36: {high,med,low}='b000000000111;     //低音“7”37: {high,med,low}='b000000000111;    - 61 - 程序文本    38: {high,med,low}='b000000000110;     //低音“6”    39: {high,med,low}='b000000000110;    40: {high,med,low}='b000000000101;     //低音“5”    41: {high,med,low}='b000000000101;    42: {high,med,low}='b000000000101;    43: {high,med,low}='b000000000110;     //低音“6”    44: {high,med,low}='b000000010000;     //中音“1”    45: {high,med,low}='b000000010000;    46: {high,med,low}='b000000100000;     //中音“2”    47: {high,med,low}='b000000100000;    48: {high,med,low}='b000000000011;     //低音“3”    49: {high,med,low}='b000000000011;    50: {high,med,low}='b000000010000;     //中音“1”    51: {high,med,low}='b000000010000;    52: {high,med,low}='b000000000110;    53: {high,med,low}='b000000000101;     //低音“5”    54: {high,med,low}='b000000000110;    55: {high,med,low}='b000000010000;     //中音“1”    56: {high,med,low}='b000000000101;     //低音“5”    57: {high,med,low}='b000000000101;     //持续8个时钟节拍    58: {high,med,low}='b000000000101;    59: {high,med,low}='b000000000101;    60: {high,med,low}='b000000000101;    61: {high,med,low}='b000000000101;    62: {high,med,low}='b000000000101;    63: {high,med,low}='b000000000101;    endcase    end    endmodule    【例11.7】自动售饮料机    /*信号定义:    clk:     时钟输入;    reset:      为系统复位信号;    half_dollar:   代表投入5角硬币;    one_dollar:     代表投入1元硬币;    half_out:     表示找零信号;    dispense:     表示机器售出一瓶饮料;    collect:     该信号用于提示投币者取走饮料。 */- 62 -    王金明:《Verilog HDL程序设计教程》module sell(one_dollar,half_dollar,    collect,half_out,dispense,reset,clk);parameter idle=0,one=2,half=1,two=3,three=4;    //idle,one,half,two,three为中间状态变量,代表投入币值的几种情况input one_dollar,half_dollar,reset,clk;output collect,half_out,dispense;reg collect,half_out,dispense;reg[2:0] D;always @(posedge clk) begin    if(reset)    begin    dispense=0;     collect=0;    half_out=0;     D=idle;    end    case(D)    idle:    if(half_dollar)  D=half;    else  if(one_dollar)    D=one;    half:    if(half_dollar)  D=one;    else if(one_dollar)    D=two;    one:    if(half_dollar) D=two;    else if(one_dollar)    D=three;    two:    if(half_dollar) D=three;    else if(one_dollar)    begin    dispense=1;        //售出饮料    collect=1;  D=idle;    end    three:    if(half_dollar)    begin    dispense=1;         //售出饮料    - 63 - 程序文本    collect=1;  D=idle;    end    else if(one_dollar)    begin    dispense=1;         //售出饮料    collect=1;    half_out=1; D=idle;    end    endcase    end    endmodule    【例11.8】多功能数字钟    /* 信号定义:    clk:     标准时钟信号,本例中,其频率为4Hz;    clk_1k:     产生闹铃音、报时音的时钟信号,本例中其频率为1024Hz;    mode:     功能控制信号;  0:计时功能;    为1:闹钟功能;    为2:手动校时功能;    turn:     接按键,在手动校时功能时,选择是调整小时,还是分钟;    若长时间按住该键,还可使秒信号清零,用于精确调时;    change:     接按键,手动调整时,每按一次,计数器加1;    如果长按,则连续快速加1,用于快速调时和定时;    hour,min,sec:此三信号分别输出并显示时、分、秒信号,    皆采用BCD码计数,分别驱动6个数码管显示时间;    alert:     输出到扬声器的信号,用于产生闹铃音和报时音;    闹铃音为持续20秒的急促的“嘀嘀嘀”音,若按住“change”键,    则可屏蔽该音;整点报时音为“嘀嘀嘀嘀—嘟”四短一长音;    LD_alert:  接发光二极管,指示是否设置了闹钟功能;    LD_hour:   接发光二极管,指示当前调整的是小时信号;    LD_min:     接发光二极管,指示当前调整的是分钟信号。    */    module clock(clk,clk_1k,mode,change,turn,alert,hour,min,sec,    LD_alert,LD_hour,LD_min);    input clk,clk_1k,mode,change,turn;    output alert,LD_alert,LD_hour,LD_min;    output[7:0] hour,min,sec;    reg[7:0] hour,min,sec,hour1,min1,sec1,ahour,amin;    reg[1:0] m,fm,num1,num2,num3,num4;    reg[1:0] loop1,loop2,loop3,loop4,sound;- 64 -    王金明:《Verilog HDL程序设计教程》reg LD_hour,LD_min;reg clk_1Hz,clk_2Hz,minclk,hclk;reg alert1,alert2,ear;reg count1,count2,counta,countb;wire ct1,ct2,cta,ctb,m_clk,h_clk;always @(posedge clk) begin    clk_2Hz<=~clk_2Hz;    if(sound==3)  begin sound<=0; ear<=1;  end    //ear信号用于产生或屏蔽声音    else  begin sound<=sound+1; ear<=0;  endendalways @(posedge clk_2Hz)    //由4Hz的输入时钟产生1Hz的时基信号    clk_1Hz<=~clk_1Hz;always @(posedge mode)       //mode信号控制系统在三种功能间转换 begin  if(m==2)  m<=0;  else  m<=m+1;  endalways @(posedge turn)    fm<=~fm;always        //该进程产生count1,count2,counta,countb四个信号begin case(m) 2: begin   if(fm)    begin   count1<=change; {LD_min,LD_hour}<=2;  end    else    begin  counta<=change;  {LD_min,LD_hour}<=1;  end    {count2,countb}<=0;    end 1: begin   if(fm)    begin   count2<=change;  {LD_min,LD_hour}<=2;  end    else    begin  countb<=change; {LD_min,LD_hour}<=1;  end    {count1,counta}<=2'b00;    end    default: {count1,count2,counta,countb,LD_min,LD_hour}<=0;    endcaseend    - 65 - 程序文本    always @(negedge clk)    //如果长时间按下“change”键,则生成“num1”信号用于连续快速加1    if(count2)  begin    if(loop1==3) num1<=1;    else    begin loop1<=loop1+1; num1<=0; end    end    else  begin  loop1<=0;  num1<=0;  end    always @(negedge clk)              //产生num2信号    if(countb)  begin    if(loop2==3)  num2<=1;    else    begin  loop2<=loop2+1;  num2<=0;  end    end    else  begin  loop2<=0;  num2<=0;  end    always @(negedge clk)    if(count1)  begin    if(loop3==3)  num3<=1;    else    begin  loop3<=loop3+1;  num3<=0;  end    end    else  begin  loop3<=0;  num3<=0;  end    always @(negedge clk)    if(counta)  begin    if(loop4==3) num4<=1;    else    begin  loop4<=loop4+1;  num4<=0;  end    end    else  begin  loop4<=0;  num4<=0;  end    assign ct1=(num3&clk)|(!num3&m_clk);     //ct1用于计时、校时中的分钟计数    assign ct2=(num1&clk)|(!num1&count2);   //ct2用于定时状态下调整分钟信号    assign cta=(num4&clk)|(!num4&h_clk);     //cta用于计时、校时中的小时计数    assign ctb=(num2&clk)|(!num2&countb);   //ctb用于定时状态下调整小时信号    always @(posedge clk_1Hz)         //秒计时和秒调整进程    if(!(sec1^8'h59)|turn&(!m))    begin    sec1<=0; if(!(turn&(!m)))  minclk<=1;- 66 -    王金明:《Verilog HDL程序设计教程》    end    //按住“turn”按键一段时间,秒信号可清零,该功能用于手动精确调时    else  begin    if(sec1[3:0]==4'b1001)    begin  sec1[3:0]<=4'b0000;  sec1[7:4]<=sec1[7:4]+1;  end    else  sec1[3:0]<=sec1[3:0]+1;   minclk<=0;    endassign  m_clk=minclk||count1;always @(posedge ct1)                //分计时和分调整进程 begin    if(min1==8'h59)  begin  min1<=0;  hclk<=1;  end    else    begin    if(min1[3:0]==9)    begin  min1[3:0]<=0;  min1[7:4]<=min1[7:4]+1;  end    else  min1[3:0]<=min1[3:0]+1;  hclk<=0;    end endassign  h_clk=hclk||counta;always @(posedge cta)             //小时计时和小时调整进程    if(hour1==8'h23) hour1<=0;    else    if(hour1[3:0]==9)    begin  hour1[7:4]<=hour1[7:4]+1;  hour1[3:0]<=0;  end    else  hour1[3:0]<=hour1[3:0]+1;always @(posedge ct2)              //闹钟定时功能中的分钟调节进程    if(amin==8'h59)  amin<=0;    else     if(amin[3:0]==9)    begin  amin[3:0]<=0;  amin[7:4]<=amin[7:4]+1;  end    else  amin[3:0]<=amin[3:0]+1;always @(posedge ctb)              //闹钟定时功能中的小时调节进程    if(ahour==8'h23)  ahour<=0;    else    if(ahour[3:0]==9)    begin  ahour[3:0]<=0;  ahour[7:4]<=ahour[7:4]+1;  end    else  ahour[3:0]<=ahour[3:0]+1;always            //闹铃功能    if((min1==amin)&&(hour1==ahour)&&(amin|ahour)&&(!change))    - 67 - 程序文本    //若按住“change”键不放,可屏蔽闹铃音    if(sec1<8'h20)  alert1<=1;     //控制闹铃的时间长短    else  alert1<=0;    else  alert1<=0;    always                      //时、分、秒的显示控制    case(m)    3'b00: begin  hour<=hour1;  min<=min1;  sec<=sec1;  end    //计时状态下的时、分、秒显示    3'b01: begin  hour<=ahour;  min<=amin;  sec<=8'hzz;  end    //定时状态下的时、分、秒显示    3'b10: begin  hour<=hour1;  min<=min1;  sec<=8'hzz;  end    //校时状态下的时、分、秒显示    endcase    assign  LD_alert=(ahour|amin)?1:0;       //指示是否进行了闹铃定时    assign  alert=((alert1)?clk_1k&clk:0)|alert2;    //产生闹铃音或整点报时音    always                     //产生整点报时信号alert2    begin    if((min1==8'h59)&&(sec1>8'h54)||(!(min1|sec1)))    if(sec1>8'h54)  alert2<=ear&clk_1k; //产生短音    else  alert2<=!ear&clk_1k;     //产生长音    else  alert2<=0;    end    endmodule    【例11.9】电话计费器程序    /*信号定义:    clk:     时钟信号,本例中其频率值为1Hz;    decide:     电话局反馈回来的信号,代表话务种类,“01”表示市话,“10”表示    长话,“11”表示特话;    dispmoney: 用来显示卡内余额,其单位为角,这里假定能显示的最大数额为50元    (500角);    disptime:  显示本次通话的时长;    write,read: 当write信号下降沿到来时写卡,当话卡插入,read信号变高时读卡;    warn:     余额过少时的告警信号。本例中,当打市话时,余额少于3角,打长    话时,余额少于6角,即会产生告警信号;    cut:     当告警时间过长时自动切断通话信号。  */- 68 -    王金明:《Verilog HDL程序设计教程》module account(state,clk,card,decide,disptime,dispmoney,    write,read,warn,cut);output write,read,warn,cut;input state,clk,card;input[2:1] decide;output[10:0] dispmoney;output[8:0] disptime;reg[10:0] money;reg[8:0] dtime;reg warn,cut,write,t1m;       //t1m为分时钟reg set,reset_ena;integer num1,temp;assign  dispmoney=card?money:0;assign  disptime=dtime;assign  read=card?1:0;    //产生分时钟always @(posedge clk) begin  if (num1==59)  begin  num1<=0;  t1m<=1;  end  else  begin    if(state)   num1<=num1+1;    else    num1<=0;  t1m<=0;    end endalways @(negedge clk)         //该进程完成电话计费功能begin if(!set)  begin  money<=11'h500;  set<=1;  end if(card&state)    if(t1m)    case({state,decide})  3'b101:  if(money<3)    begin  warn<=1;  write<=0;  reset_ena<=1;  end    else    begin     //市话计费    if(money[3:0]<4'b0011)    begin    money[3:0]<=money[3:0]+7;    - 69 - 程序文本    if(money[7:4]!=0)    money[7:4]<=money[7:4]-1;    else    begin  money[7:4]<=9;  money[10:8]<=money[10:8]-1;  end    end    else  money[3:0]<=money[3:0]-3;  write<=1;    //市话通话计时    if(dtime[3:0]==9)    begin    dtime[3:0]<=0;    if(dtime[7:4]==9)    begin  dtime[7:4]<=0;  dtime[8]<=dtime[8]+1;  end    else  dtime[7:4]<=dtime[7:4]+1;    end    else    begin    dtime[3:0]<=dtime[3:0]+1;  warn<=0;  reset_ena<=0;    end    end    3'b110:  if(money<6)    begin  warn<=1;  write<=0;  reset_ena<=1;  end    else begin    //通话计时    if(dtime[3:0]==9)    begin    dtime[3:0]<=0;  if(dtime[7:4]==9)    begin  dtime[7:4]<=0;  dtime[8]<=dtime[8]+1;  end    else dtime[7:4]<=dtime[7:4]+1;    end    else dtime[3:0]<=dtime[3:0]+1;    //长话计费    if(money[3:0]<4'b0110)    begin    money[3:0]<=money[3:0]+4;    if(!money[7:4])    begin  money[7:4]<=9;  money[10:8]<=money[10:8]-1;  end    else  money[7:4]<=money[7:4]-1;    end    else  money[3:0]<=money[3:0]-6;    write<=1;  reset_ena<=0;   warn<=0;- 70 -    王金明:《Verilog HDL程序设计教程》    end    endcase    else write<=0;    else  begin  dtime<=0;  warn<=0;  write<=0;  reset_ena<=0;  end    //取卡后对一些信号进行复位    endalways @(posedge clk)           //该进程在告警时间过长的情况下切断本次通话begin    if(warn)  temp<=temp+1;    else temp<=0;    if(temp==15)    begin  cut<=1;  temp<=0;  end    if(!card||!reset_ena)    begin    cut<=0;            //复位cut信号    temp<=0;    end  endendmodule【例12.1】8位级连加法器module add_jl(sum,cout,a,b,cin);output[7:0] sum;output cout;input[7:0] a,b;input cin;full_add1 f0(a[0],b[0],cin,sum[0],cin1);         //级连描述full_add1 f1(a[1],b[1],cin1,sum[1],cin2);full_add1 f2(a[2],b[2],cin2,sum[2],cin3);full_add1 f3(a[3],b[3],cin3,sum[3],cin4);full_add1 f4(a[4],b[4],cin4,sum[4],cin5);full_add1 f5(a[5],b[5],cin5,sum[5],cin6);full_add1 f6(a[6],b[6],cin6,sum[6],cin7);full_add1 f7(a[7],b[7],cin7,sum[7],cout);endmodulemodule full_add1(a,b,cin,sum,cout);     //1位全加器input a,b,cin;    - 71 - 程序文本   output sum,cout;   wire s1,m1,m2,m3;   and  (m1,a,b),    (m2,b,cin),    (m3,a,cin);   xor  (s1,a,b),    (sum,s1,cin);   or  (cout,m1,m2,m3);   endmodule    【例12.2】8位并行加法器   module add_bx(cout,sum,a,b,cin);   output[7:0] sum;   output cout;   input[7:0] a,b;   input cin;    assign {cout,sum}=a+b+cin;   endmodule    【例12.3】8位超前进位加法器   module add_ahead(sum,cout,a,b,cin);   output[7:0] sum;   output cout;   input[7:0] a,b;   input cin;   wire[7:0] G,P;   wire[7:0] C,sum;   assign G[0]=a[0]&b[0];             //产生第0位本位值和进位值   assign P[0]=a[0]|b[0];   assign C[0]=cin;   assign sum[0]=G[0]^P[0]^C[0];   assign G[1]=a[1]&b[1];     //产生第1位本位值和进位值   assign P[1]=a[1]|b[1];   assign C[1]=G[0]|(P[0]&cin);   assign sum[1]=G[1]^P[1]^C[1];   assign G[2]=a[2]&b[2];     //产生第2位本位值和进位值   assign P[2]=a[2]|b[2];- 72 -    王金明:《Verilog HDL程序设计教程》assign C[2]=G[1]|(P[1]&C[1]);assign sum[2]=G[2]^P[2]^C[2];assign G[3]=a[3]&b[3];     //产生第3位本位值和进位值assign P[3]=a[3]|b[3];assign C[3]=G[2]|(P[2]&C[2]);assign sum[3]=G[3]^P[3]^C[3];assign G[4]=a[4]&b[4];     //产生第4位本位值和进位值assign P[4]=a[4]|b[4];assign C[4]=G[3]|(P[3]&C[3]);assign sum[4]=G[2]^P[2]^C[2];assign G[5]=a[5]&b[5];       //产生第5位本位值和进位值assign P[5]=a[5]|b[5];assign C[5]=G[4]|(P[4]&C[4]);assign sum[5]=G[5]^P[5]^C[5];assign G[6]=a[6]&b[6];     //产生第6位本位值和进位值assign P[6]=a[6]|b[6];assign C[6]=G[5]|(P[5]&C[5]);assign sum[6]=G[6]^P[6]^C[6];assign G[7]=a[7]&b[7];       //产生第7位本位值和进位值assign P[7]=a[7]|b[7];assign C[7]=G[6]|(P[6]&C[6]);assign sum[7]=G[7]^P[7]^C[7];assign cout=G[7]|(P[7]&C[7]);      //产生最高位进位输出endmodule【例12.4】8位并行乘法器module mult(outcome,a,b);parameter size=8;input[size:1] a,b;     //两个操作数output[2*size:1] outcome;     //结果assign outcome=a*b;                //乘法运算符endmodule【例12.5】4×4查找表乘法器    - 73 - 程序文本   module mult4x4(out,a,b,clk);   output[7:0] out;   input[3:0] a,b;   input clk;   reg[7:0] out;   reg[1:0] firsta,firstb;   reg[1:0] seconda,secondb;   wire[3:0] outa,outb,outc,outd;   always @(posedge clk)   begin    firsta = a[3:2];  seconda = a[1:0];    firstb = b[3:2];  secondb = b[1:0];   end   lookup  m1(outa,firsta,firstb,clk),    m2(outb,firsta,secondb,clk),    m3(outc,seconda,firstb,clk),    m4(outd,seconda,secondb,clk);    //模块调用   always @(posedge clk)    begin    out = (outa << 4) + (outb << 2) + (outc << 2) + outd;    end   endmodule   module lookup(out,a,b,clk);              //用查找表方式实现2×2乘法   output[3:0] out;   input[1:0] a,b;   input clk;   reg[3:0] out;   reg[3:0] address;   always @(posedge clk)    begin    address = {a,b};    case(address)    4'h0 : out = 4 'b0000;    4'h1 : out = 4'b0000;    4'h2 : out = 4'b0000;    4'h3 : out = 4'b0000;    4'h4 : out = 4'b0000;- 74 -    王金明:《Verilog HDL程序设计教程》    4'h5 : out = 4'b0001;    4'h6 : out = 4'b0010;    4'h7 : out = 4'b0011;    4'h8 : out = 4'b0000;    4'h9 : out = 4'b0010;    4'ha : out = 4'b0100;    4'hb : out = 4'b0110;    4'hc : out = 4'b0000;    4'hd : out = 4'b0011;    4'he : out = 4'b0110;    4'hf : out = 4'b1001;    default : out='bx;  endcase endendmodule【例12.6】8位加法树乘法器module add_tree(out,a,b,clk);output[15:0] out;input[7:0] a,b;input clk;wire[15:0] out;wire[14:0] out1,c1;wire[12:0] out2;wire[10:0] out3,c2;wire[8:0] out4;reg[14:0] temp0;reg[13:0] temp1;reg[12:0] temp2;reg[11:0] temp3;reg[10:0] temp4;reg[9:0] temp5;reg[8:0] temp6;reg[7:0] temp7;function[7:0] mult8x1;     //该函数实现8×1乘法input[7:0] operand;input sel;   begin   mult8x1= (sel) ? (operand) : 8'b00000000;    - 75 - 程序文本    end   endfunction   always @(posedge clk)     //调用函数实现操作数b 各位与操作数a的相乘    begin    temp7<=mult8x1(a,b[0]);    temp6<=((mult8x1(a,b[1]))<<1);    temp5<=((mult8x1(a,b[2]))<<2);    temp4<=((mult8x1(a,b[3]))<<3);    temp3<=((mult8x1(a,b[4]))<<4);    temp2<=((mult8x1(a,b[5]))<<5);    temp1<=((mult8x1(a,b[6]))<<6);    temp0<=((mult8x1(a,b[7]))<<7);    end   assign  out1 = temp0 + temp1;     //加法器树运算   assign  out2 = temp2 + temp3;   assign  out3 = temp4 + temp5;   assign  out4 = temp6 + temp7;   assign  c1 = out1 + out2;   assign  c2 = out3 + out4;   assign  out = c1 + c2;   endmodule    【例12.7】11阶FIR数字滤波器   module fir(clk,x,y);   input[7:0] x;   input clk;   output[15:0] y;   reg[15:0] y;   reg[7:0] tap0,tap1,tap2,tap3,tap4,tap5,tap6,tap7,tap8,tap9,tap10;   reg[7:0] t0,t1,t2,t3,t4,t5;   reg[15:0] sum;   always@(posedge clk)    begin    t0<=tap5;    t1<=tap4+tap6;    t2<=tap3+tap7;- 76 -    王金明:《Verilog HDL程序设计教程》    t3<=tap2+tap8;    t4<=tap1+tap9;    t5<=tap0+tap10;           //利用对称性    sum<=(t1<<4)+{t1[7],t1[7:1]}+{t1[7],t1[7],t1[7:2]}+    {t1[7],t1[7],t1[7],    t1[7:3]}-(t2<<3)-(t2<<2)+t2-{t2[7],t2[7],t2[7:2]}    +(t3<<2)+t3+{t3[7],t3[7],t3[7:2]}+{t3[7],t3[7],t3[7],t3[7],t3[7:4]}    +{t3[7],t3[7],t3[7],t3[7],t3[7],t3[7:5]}    -t4-{t4[7],t4[7:1]}-{t4[7],t4[7],t4[7],t4[7:3]}    +{t5[7],t5[7:1]}-{t5[7],t5[7],t5[7],t5[7],t5[7],t5[7:5]}    +(t0<<7)-((t0<<2)<<2)-(t0<<2)+{t0[7],t0[7:1]}    +{t0[7],t0[7],t0[7:2]}+{t0[7],t0[7],t0[7],t0[7],t0[7:4]};    //16+0.5+0.25+0.125=16.875    //8+4-1+0.25=11.25    //4+1+0.25+0.0625+0.03125=5.34375    //1+0.5+0.125=1.625    //0.5-0.03125=0.46875    //128-4*4-4+0.5+0.25+0.0625=108.8125    /* 0.0036,-0.0127,0.0417,-0.0878,0.1318,0.8500,0.1318,-0.0878,    0.0417,-0.0127,0.0036,0.4608,-1.6256,5.3376,-11.2384,16.8704,    108.800,16.8704,-11.238,5.3376,-1.6256,0.4608 */    tap10<=tap9;    tap9<=tap8;    tap8<=tap7;    tap7<=tap6;    tap6<=tap5;    tap5<=tap4;    tap4<=tap3;    tap3<=tap2;    tap2<=tap1;    tap1<=tap0;    tap0<=x;   y<={sum[15],sum[15],sum[15],sum[15],sum[15],sum[15],sum[15],sum[15:7]};   end   endmodule    【例12.8】16位高速数字相关器    - 77 - 程序文本   module correlator(out,a,b,clk);   output[4:0] out;   input[15:0] a,b;   input clk;   wire[2:0] sum1,sum2,sum3,sum4;   wire[3:0] temp1,temp2;   detect  u1(sum1,a[3:0],b[3:0],clk),     //模块调用    u2(sum2,a[7:4],b[7:4],clk),    u3(sum3,a[11:8],b[11:8],clk),    u4(sum4,a[15:12],b[15:12],clk);   add3     u5(temp1,sum1,sum2,clk),    u6(temp2,sum3,sum4,clk);   add4     u7(out,temp1,temp2,clk);   endmodule   module detect(sum,a,b,clk);     //该模块实现4位相关器   output[2:0] sum;   input clk;   input[3:0] a,b;   wire[3:0] ab;   reg[2:0] sum;   assign ab = a ^ b;   always @(posedge clk)    begin    case(ab)    'd0: sum = 4;    'd1,'d2,'d4,'d8:   sum = 3;    'd3,'d5,'d6,'d9,'d10,'d12: sum = 2;    'd7,'d11,'d13,'d14: sum = 1;    'd15: sum = 0;    endcase    end   endmodule   module add3(add,a,b,clk);     //3位加法器   output[3:0] add;   input[2:0] a,b;   input clk;- 78 -    王金明:《Verilog HDL程序设计教程》reg[3:0] add;always @(posedge clk)   begin  add = a + b;  endendmodulemodule add4(add,a,b,clk);     //4位加法器output[4:0] add;input[3:0] a,b;input clk;reg[4:0] add;always @(posedge clk)   begin  add = a + b;  endendmodule【例12.9】(7,4)线性分组码编码器module linear(c,u,clk);output[6:0] c;     //c为编码输出码字input[3:0] u;input clk;reg[6:0] c;always @(posedge clk) begin    c[6] = u[3];    c[5] = u[2];    c[4] = u[1];    c[3] = u[0];    c[2] = u[1] ^ u[2] ^ u[3];    c[1] = u[0] ^ u[1] ^ u[2];    c[0] = u[0] ^ u[2] ^ u[3] ; endendmodule【例12.10】(7,4)线性分组码译码器module decoder1(c,y,clk);output[6:0] c;input[6:0] y;input clk;reg[2:0] s;reg[6:0] e,c;always @(posedge clk)    - 79 - 程序文本    begin    s[0] = y[0] ^ y[3] ^ y[5] ^ y[6];    s[1] = y[1] ^ y[3] ^ y[4] ^ y[5];    s[2] = y[2] ^ y[4] ^ y[5] ^ y[6];     //s[0]~ s[2]为伴随子    e[0] = s[0] & (~s[1]) & (~s[2]);    e[1] = (~s[0]) & s[1] & (~s[2]);    e[2] = (~s[0]) & (~s[1]) & s[2];    e[3] = s[0] & s[1] & (~s[2]);    e[4] = (~s[0]) & s[1] & s[2];    e[5] = s[0] & s[1] & s[2];    e[6] = s[0] & (~s[1]) & s[2];     //e[0]~ e[6]为错误图样    c = e ^ y;     //c为输出码字    end   endmodule    【例12.11】(7,4)循环码编码器   module cycle(c,u,clk);   output[6:0] c;   input[3:0] u;   input clk;   reg[2:0] i;   reg d0,d1,d2,temp;   reg[6:0] c;   always @(posedge clk)    begin    d0=0; 1=0;   d2=0;     //初始化    for (i=0;i<4;i=i+1)     //该for循环计算码组的前4个码元    begin    temp = d2 ^ c[i];    d2 = d1;    d1 = d0 ^ temp;    d0 = temp;  c[i] = u[i];    end    for (i=4;i<7;i=i+1)     //该for循环计算码组的后3个码元    begin    temp = d2;    d2 = d1;     d1 = d0 ^ temp;    d0 = temp; c[i] = temp;    end    end- 80 -    王金明:《Verilog HDL程序设计教程》endmodule【例12.12】(7,4)循环码纠错译码器module decoder2(c,y,clk);output[6:0] c;     //c为输出码字,c[6]为高次项input[6:0] y;     //y为接收码字,y[6]为高次项input clk;reg[6:0] c,c_buf,buffer;reg temp;reg s0,s1,s2;     //伴随式电路寄存器reg e;     //错误检测输出信号integer i;always @(posedge clk) begin    s0=0;   s1=0;   s2=0;     //初始化    temp=0;    buffer=y;     //接收码字移入缓存   for (i=6;i>=0;i=i-1)      //接收码字进入除法电路    begin    e=s0&(~s1)&temp;    temp=s2;    s2=s1;    s1=s0^temp;    s0=y[i]^temp^e;    end    for (i=6;i>=0;i=i-1)     //输出纠错译码后的码字    begin    e=s0&(~s1)&temp;    temp=s2;    s2=s1;    s1=s0^temp;    s0=temp^e;    c_buf[i]=buffer[i]^e;    if (e==1)     //若出错,对缓存进行清零    begin    s0=0;   s1=0;   s2=0;    - 81 - 程序文本    end    end    end   always @(posedge clk)    begin    c=c_buf;    end   endmodule    【例12.13】CRC编码   module crc(crc_reg,crc,d,calc,init,d_valid,clk,reset);   output[15:0] crc_reg;   output[7:0] crc;   input[7:0] d;   input calc;   input init;   input d_valid;   input clk;   input reset;   reg[15:0] crc_reg;   reg[7:0] crc;   wire[15:0] next_crc;   always @(posedge clk or posedge reset)    begin    if (reset)    begin    crc_reg <= 16'h0000;    crc <= 8'h00;    end    else if (init)    begin    crc_reg <= 16'h0000;    crc <= 8'h00;    end    else if (calc & d_valid)    begin- 82 -    王金明:《Verilog HDL程序设计教程》    crc_reg <= next_crc;    crc <= ~{next_crc[8], next_crc[9], next_crc[10], next_crc[11],    next_crc[12], next_crc[13], next_crc[14], next_crc[15]};    end    else if (~calc & d_valid)    begin    crc_reg <= {crc_reg[7:0], 8'h00};    crc <= ~{crc_reg[0], crc_reg[1], crc_reg[2], crc_reg[3],    crc_reg[4], crc_reg[5], crc_reg[6], crc_reg[7]};    end   end   assign next_crc[0] = crc_reg[12] ^ d[7] ^ crc_reg[8] ^ d[3];   assign next_crc[1] = crc_reg[13] ^ d[6] ^ d[2] ^ crc_reg[9];   assign next_crc[2] = d[5] ^ crc_reg[14] ^ d[1] ^ crc_reg[10];   assign next_crc[3] = d[4] ^ crc_reg[15] ^ d[0] ^ crc_reg[11];   assign next_crc[4] = crc_reg[12] ^ d[3];   assign next_crc[5]=crc_reg[12]^crc_reg[13]^d[7]^crc_reg[8]^d[2]^d[3];   assign next_crc[6] = crc_reg[13] ^ d[6] ^ crc_reg[14] ^ d[1] ^ d[2] ^crc_reg[9];   assign next_crc[7] = d[5] ^ crc_reg[14] ^ crc_reg[15] ^ d[0] ^ d[1] ^crc_reg[10];   assign next_crc[8] = d[4] ^ crc_reg[15] ^ d[0] ^ crc_reg[0] ^ crc_reg[11];   assign next_crc[9] = crc_reg[12] ^ crc_reg[1] ^ d[3];   assign next_crc[10] = crc_reg[13] ^ d[2] ^ crc_reg[2];   assign next_crc[11] = crc_reg[3] ^ crc_reg[14] ^ d[1];   assign next_crc[12] = crc_reg[12] ^ crc_reg[4] ^ d[7] ^ crc_reg[15]    ^ d[0] ^ crc_reg[8] ^ d[3];   assign next_crc[13] = crc_reg[13] ^ d[6] ^ crc_reg[5] ^ d[2] ^ crc_reg[9];   assign next_crc[14] = d[5] ^ crc_reg[14] ^ crc_reg[6] ^ d[1] ^ crc_reg[10];   assign next_crc[15] = d[4] ^ crc_reg[15] ^ d[0] ^ crc_reg[7] ^ crc_reg[11];   endmodule
    - 83 -