搜索
您的当前位置:首页正文

Verilog实例讲解

来源:小奈知识网
王金明:《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;

end endmodule

【例3.3】4位全加器的仿真程序

`timescale 1ns/1ns `include \"adder4.v\" module adder_tp; reg[3:0] a,b;

reg cin;

wire[3:0] sum;

wire cout; integer i,j;

adder4 adder(sum,cout,a,b,cin); always #5 cin=~cin;

initial begin

a=0;b=0;cin=0; for(i=1;i<16;i=i+1) #10 a=i;

end

同步复位 //计数

//测试模块的名字

//测试输入信号定义为reg型

//测试输出信号定义为wire型

//调用测试对象 //设定cin的取值 //设定a的取值

- 1 -

程序文本

initial begin

for(j=1;j<16;j=j+1) #10 b=j; end

initial begin

$monitor($time,,,\"%d + %d + %b={%b,%d}\#160 $finish; end endmodule

//定义结果显示格式

//设定b的取值

【例3.4】4位计数器的仿真程序

`timescale 1ns/1ns `include \"count4.v\" module coun4_tp; reg clk,reset; 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\endmodule

//产生时钟波形 //调用测试对象

//测试输入信号定义为reg型 //测试输出信号定义为wire型

wire[3:0] out;

【例3.5】“与-或-非”门电路

module AOI(A,B,C,D,F); input A,B,C,D; output F;

//模块名为AOI(端口列表A,B,C,D,F) //模块的输入端口为A,B,C,D //模块的输出端口为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; endcase endmodule

【例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;

begin

case(opcode)

`add: out = a+b; `band: out = a&b; `bnot: out=~a; endcase end endmodule

//加操作 //减操作 //求与 //求或 //求反

//未收到指令时,输出任意态

`minus: out = a-b; `bor: out = a|b; default: out=8'hx;

//操作码 //操作数

//电平敏感的always块

always@(opcode or a or b)

【例5.4】用initial过程语句对测试变量A、B、C赋值

`timescale 1ns/1ns module test; reg A,B,C; initial begin #50 #50 #50 #50 #50 end endmodule

A = 0; B = 1; C = 0; A = 1; B = 0; A = 0; C = 1; B = 1;

B = 0; C = 0; $finish ;

【例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 ; end initial $monitor($time,,,\"wave=%b\endmodule 【例5.6】用fork-join并行块产生信号波形 `timescale 10ns/1ns module 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; join

initial $monitor($time,,,\"wave=%b\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=b

endmodule

【例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

end

assign 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语句

//若超过4人赞成,则pass=1

if(vote[i]) sum=sum+1; if(sum[2]) pass=1; else

end endmodule

pass=0;

【例5.16】用for语句实现2个8位数相乘

module mult_for(outcome,a,b); parameter size=8; input[size:1] a,b; reg[2*size:1] outcome; integer i;

always @(a or b) begin

outcome=0;

for(i=1; i<=size; i=i+1) end endmodule

//for语句

if(b[i]) outcome=outcome +(a << (i-1));

//两个操作数 //结果

output[2*size:1] outcome;

【例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)

begin

if(temp_b[1])

//如果temp_b的最低位为1,就执行下面的加法

//操作数a左移一位

//repeat语句,size为循环次数

outcome=outcome+temp_a; temp_a=temp_a<<1;

- 9 -

程序文本

temp_b=temp_b>>1; end

end endmodule

//操作数b右移一位

【例5.18】同一循环的不同实现方式

module loop1; integer i; initial

for(i=0;i<4;i=i+1) begin

$display(“i=%h”,i); end

endmodule

module loop2; integer i; initial begin

i=0;

while(i<4) begin

$display (\"i=%h\i=i+1; end end endmodule

module loop3; integer i; initial begin

i=0; repeat(4) begin

$display (\"i=%h\i=i+1; end end endmodule

//repeat语句

//方式3

//while语句

//方式2

//for语句

//方式1

【例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; `endif endmodule

【例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)

begin

if (!reset) else

assign cout=(qout==4'hf)?1:0; endmodule

//进程2,用持续赋值产生进位信号

end

qout= 4'h00;

//同步清0,低电平有效 //同步预置 //加法计数

else if (load) qout= data;

//进程1,always过程块

qout=qout + 1;

【例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; 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

//或 //相减 //相加 //按位与

//任务定义,注意无端口列表

//a,b,out名称的作用域范围为task任务内部

- 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; end

initial $monitor($time,,,\"code=%b a=%b b=%b c=%b\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; end endfunction

【例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)

begin

if(!reset) result<=0;

else begin

result <= 2 * factorial(n); 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) factorial = i* factorial; end

- 14 -

函数调用 在clk的上升沿时执行运算

复位

调用factorial函数 阶乘运算函数定义(注意无端口列表) 函数只能定义输入端,输出端口为函数名本身该句若要综合通过,opa应赋具体的数值 阶乘运算

//////////// ////王金明:《Verilog HDL程序设计教程》

#DELY reset=1; #DELY reset=0; #(DELY*300) $finish; end

//结果显示

initial $monitor($time,,,\"clk=%d reset=%d qout=%d\endmodule

module 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;

end endmodule

【例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;

end endmodule

【例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 end endmodule

【例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) else if(a) else end endmodule

outtemp=4'b0001; outtemp=4'b0000; outtemp=4'b1000;

【例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])

else if (din[6]) else if (din[5]) else if (din[4]) else if (din[3]) else if (din[2]) else if (din[1]) else

assign dout = code(din); //函数调用 endmodule

endfunction

//函数只有输入端口,输出为函数名本身 code = 3'd7; code = 3'd6; code = 3'd5; code = 3'd4; code = 3'd3; code = 3'd2; code = 3'd1; code = 3'd0;

【例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; reg a,b,c,d,e,f,g;

always @(D3 or D2 or D1 or D0) begin

case({D3,D2,D1,D0})

//用case语句进行译码

//输入的4位BCD码

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 end endmodule

【例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 MUX

module 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;

end endmodule

【例9.12】用case语句描述的4选1 MUX

module 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 -

王金明:《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;

end endmodule

【例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;

end endmodule

【例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; else begin

dout <= dout << 1;

//输出信号左移一位

//同步清0,高电平有效

- 39 -

程序文本

begin

if(counter==255) else end

always@(posedge clk) begin

strb=temp; //引入一个触发器 end

always@(counter) begin

if(counter<=(delay-1)) temp=1; else

end endmodule

temp=0;

counter=0;

counter=counter+1;

【例11.1】数字跑表

/*信号定义: CLK: CLR:

CLK为时钟信号; 为异步复位信号; 为暂停信号; 百分秒的高位和低位; 秒信号的高位和低位; 分钟信号的高位和低位。 */

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;

//百分秒计数进程,每计满100,cn1产生一个进位 always @(posedge CLK or posedge CLR) begin

if(CLR) begin

//异步复位

//cn1为百分秒向秒的进位,cn2为秒向分的进位

{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

end

end

//秒计数进程,每计满60,cn2产生一个进位 always @(posedge cn1 or posedge CLR) begin

if(CLR) begin

//异步复位

{SH,SL}<=8'h00;

cn2<=0; end

else

if(SL==9)

//低位是否为9

begin SL<=0; if(SH==5) begin SH<=0; cn2<=1; else SH<=SH+1; end else

begin SL<=SL+1; cn2<=0; end

end

//分钟计数进程,每计满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

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) begin count_en=0; load=1; else begin

count_en=~count_en; load=~count_en;

end

end

assign count_clr=~clk&load;

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;

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 -

end //load信号的产生

//count_clr信号的产生

//异步清0

//产生进位信号

王金明:《Verilog HDL程序设计教程》

input[15:0] din;

input load; reg[15:0] qo;

always @(posedge load)

begin qo=din; end endmodule

【例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; 1: begin numa<=ayellow; 2: begin numa<=aleft; 3: begin numa<=ayellow; 4: begin numa<=ared; default: 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 end end else

begin

LAMPA<=4'b1000; counta<=0; tempa<=0; end

end

always @(posedge CLK) begin if (EN) begin if(!tempb)

//该进程控制B方向的四种灯

numa[3:0]<=numa[3:0]-1;

if (numa==2) tempa<=0;

LAMPA<=2; counta<=1; end LAMPA<=4; counta<=2; end LAMPA<=1; counta<=3; end LAMPA<=4; counta<=4; end LAMPA<=8; counta<=0; end LAMPA<=8;

- 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

end endmodule

【例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; 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

case(counter)

//计时,以实现循环演奏 //记谱

counter=counter+1;

//2分频产生方波信号

- 60 -

王金明:《Verilog HDL程序设计教程》

0: {high,med,low}='b000000000011; 1: {high,med,low}='b000000000011; 2: {high,med,low}='b000000000011; 3: {high,med,low}='b000000000011; 4: {high,med,low}='b000000000101; 5: {high,med,low}='b000000000101; 6: {high,med,low}='b000000000101; 7: {high,med,low}='b000000000110; //低音“6”

//低音“5” //发3个时钟节拍

//低音“3” //持续4个时钟节拍

8: {high,med,low}='b000000010000; 9: {high,med,low}='b000000010000; 10: {high,med,low}='b000000010000; 11: {high,med,low}='b000000100000; 12: {high,med,low}='b000000000110; 13: {high,med,low}='b000000010000; 14: {high,med,low}='b000000000101; 15: {high,med,low}='b000000000101;

16: {high,med,low}='b000001010000; 17: {high,med,low}='b000001010000; 18: {high,med,low}='b000001010000; 19: {high,med,low}='b000100000000; 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; 25: {high,med,low}='b000000100000; 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; 36: {high,med,low}='b000000000111; 37: {high,med,low}='b000000000111;

//中音“1”

//发3个时钟节拍 //中音“2”

//低音“6” //中音“5”

//发3个时钟节拍

//高音“1” //中音“2”

//持续11个时钟节拍 //中音“3”

//低音“7” - 61 -

程序文本 38: {high,med,low}='b000000000110; 39: {high,med,low}='b000000000110; 40: {high,med,low}='b000000000101; 41: {high,med,low}='b000000000101; 42: {high,med,low}='b000000000101; 43: {high,med,low}='b000000000110; 44: {high,med,low}='b000000010000;

//低音“6” //中音“1”

//低音“5”

//低音“6”

45: {high,med,low}='b000000010000; 46: {high,med,low}='b000000100000; 47: {high,med,low}='b000000100000;

48: {high,med,low}='b000000000011; 49: {high,med,low}='b000000000011; 50: {high,med,low}='b000000010000; 51: {high,med,low}='b000000010000; 52: {high,med,low}='b000000000110;

53: {high,med,low}='b000000000101; 54: {high,med,low}='b000000000110; 55: {high,med,low}='b000000010000; 56: {high,med,low}='b000000000101; 57: {high,med,low}='b000000000101; 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 -

//中音“2”

//低音“3”

//中音“1”

//低音“5”

//中音“1” //低音“5”

//持续8个时钟节拍

*/

王金明:《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;

产生闹铃音、报时音的时钟信号,本例中其频率为1024Hz; 功能控制信号; 为0:计时功能;

为1:闹钟功能; 为2:手动校时功能;

clk_1k: mode:

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; end end

always @(posedge clk_2Hz) //由4Hz的输入时钟产生1Hz的时基信号

clk_1Hz<=~clk_1Hz;

always @(posedge mode) //mode信号控制系统在三种功能间转换 begin if(m==2) m<=0; else m<=m+1; end always @(posedge turn)

fm<=~fm;

always begin case(m)

2: begin if(fm)

begin else

begin counta<=change; {LD_min,LD_hour}<=1; end {count2,countb}<=0;

end

1: begin if(fm)

begin 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; endcase end

count2<=change; {LD_min,LD_hour}<=2; end count1<=change; {LD_min,LD_hour}<=2; end

//该进程产生count1,count2,counta,countb四个信号

- 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)

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)

begin

sec1<=0; if(!(turn&(!m))) minclk<=1;

//秒计时和秒调整进程

if(!(sec1^8'h59)|turn&(!m))

//产生num2信号

- 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; end

assign 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

end

assign 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;

always 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

//产生长音

//产生整点报时信号alert2 //指示是否进行了闹铃定时

//产生闹铃音或整点报时音

assign alert=((alert1)?clk_1k&clk:0)|alert2;

【例11.9】电话计费器程序

/*信号定义: clk:

时钟信号,本例中其频率值为1Hz;

电话局反馈回来的信号,代表话务种类,“01”表示市话,“10”表示 长话,“11”表示特话;

dispmoney: 用来显示卡内余额,其单位为角,这里假定能显示的最大数额为50元

(500角);

disptime: 显示本次通话的时长;

write,read: 当write信号下降沿到来时写卡,当话卡插入,read信号变高时读卡; warn: cut:

余额过少时的告警信号。本例中,当打市话时,余额少于3角,打长 话时,余额少于6角,即会产生告警信号; 当告警时间过长时自动切断通话信号。 */

decide:

- 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

end

always @(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; 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 -

end 王金明:《Verilog HDL程序设计教程》

end

endcase

else write<=0;

else begin dtime<=0; warn<=0; write<=0; reset_ena<=0; end

//取卡后对一些信号进行复位

end

always @(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

end endmodule

【例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); endmodule

module 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];

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];

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];

assign P[2]=a[2]|b[2];

- 72 -

产生第0位本位值和进位值

产生第1位本位值和进位值 产生第2位本位值和进位值

//////王金明:《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];

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];

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];

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];

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];

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查找表乘法器

//产生第3位本位值和进位值

//产生第4位本位值和进位值

//产生第5位本位值和进位值

//产生第6位本位值和进位值

//产生第7位本位值和进位值

//产生最高位进位输出

//两个操作数 //结果 //乘法运算符

- 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),

always @(posedge clk) begin

out = (outa << 4) + (outb << 2) + (outc << 2) + outd; end endmodule

module lookup(out,a,b,clk); 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;

//用查找表方式实现2×2乘法

m4(outd,seconda,secondb,clk); //模块调用

- 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

end endmodule

【例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) 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 assign assign

out2 = temp2 + temp3; out3 = temp4 + temp5; out4 = temp6 + temp7;

//加法器树运算

//调用函数实现操作数b 各位与操作数a的相乘

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 add4

module detect(sum,a,b,clk); 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); output[3:0] add; input[2:0] a,b; input clk;

//3位加法器

//该模块实现4位相关器

u5(temp1,sum1,sum2,clk), u6(temp2,sum3,sum4,clk); u7(out,temp1,temp2,clk);

endmodule

//模块调用

- 78 -

王金明:《Verilog HDL程序设计教程》

reg[3:0] add;

always @(posedge clk)

begin add = a + b; end endmodule

module 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; end endmodule

【例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] ; end endmodule

【例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]; 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]; c = e ^ y; end endmodule

//e[0]~ e[6]为错误图样 //c为输出码字

//s[0]~ s[2]为伴随子

【例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; d1=0; begin

temp = d2 ^ c[i]; d2 = d1; end

for (i=4;i<7;i=i+1) begin temp = d2; d2 = d1; end end

d1 = d0 ^ temp;

d0 = temp; c[i] = temp;

//该for循环计算码组的后3个码元

d1 = d0 ^ temp;

d0 = temp; c[i] = u[i];

d2=0;

//初始化

//该for循环计算码组的前4个码元

for (i=0;i<4;i=i+1)

- 80 -

王金明:《Verilog HDL程序设计教程》

endmodule

【例12.12】(7,4)循环码纠错译码器

module decoder2(c,y,clk); output[6:0] c; input[6:0] y;

//c为输出码字,c[6]为高次项 //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 -

因篇幅问题不能全部显示,请点此查看更多更全内容

Top