王金明:《Verilog HDL程序設(shè)計(jì)教程》【例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位計(jì)數(shù)器
module count4(out,reset,clk);
output[3:0] out;
input reset,clk;
reg[3:0] out;
always @(posedge clk)
begin
if (reset) out<=0; //同步復(fù)位
else out<=out+1; //計(jì)數(shù)
end
endmodule
【例3.3】4位全加器的仿真程序
`timescale 1ns/1ns
`include "adder4.v"
module adder_tp; //測(cè)試模塊的名字
reg[3:0] a,b; //測(cè)試輸入信號(hào)定義為reg型
reg cin;
wire[3:0] sum; //測(cè)試輸出信號(hào)定義為wire型
wire cout;
integer i,j;
adder4 adder(sum,cout,a,b,cin); //調(diào)用測(cè)試對(duì)象
always #5 cin=~cin; //設(shè)定cin的取值
initial
begin
a=0;b=0;cin=0;
for(i=1;i<16;i=i+1)
#10 a=i; //設(shè)定a的取值
end
- 1 - 程序文本
initial
begin
for(j=1;j<16;j=j+1)
#10 b=j; //設(shè)定b的取值
end
initial //定義結(jié)果顯示格式
begin
$monitor($time,,,"%d + %d + %b={%b,%d}",a,b,cin,cout,sum);
#160 $finish;
end
endmodule
【例3.4】4位計(jì)數(shù)器的仿真程序
`timescale 1ns/1ns
`include "count4.v"
module coun4_tp;
reg clk,reset; //測(cè)試輸入信號(hào)定義為reg型
wire[3:0] out; //測(cè)試輸出信號(hào)定義為wire型
parameter DELY=100;
count4 mycount(out,reset,clk); //調(diào)用測(cè)試對(duì)象
always #(DELY/2) clk = ~clk; //產(chǎn)生時(shí)鐘波形
initial
begin //激勵(lì)信號(hào)定義
clk =0; reset=0;
#DELY reset=1;
#DELY reset=0;
#(DELY*20) $finish;
end
//定義結(jié)果顯示格式
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(xiàn))
input A,B,C,D; //模塊的輸入端口為A,,B,C,,D
output F; //模塊的輸出端口為F
- 2 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》wire A,B,C,D,F; //定義信號(hào)的數(shù)據(jù)類型
assign F= ~((A&B)|(C&D)); //邏輯功能描述
endmodule
【例5.1】用case語句描述的4選1數(shù)據(jù)選擇器
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) //敏感信號(hào)列表
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】同步置數(shù),、同步清零的計(jì)數(shù)器
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上升沿觸發(fā)
begin
if (!reset) out = 8'h00; //同步清0,低電平有效
else if (load) out = data; //同步預(yù)置
else out = out + 1; //計(jì)數(shù)
end
endmodule
【例5.3】用always過程語句描述的簡單算術(shù)邏輯單元
`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; //操作數(shù)
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; //未收到指令時(shí),,輸出任意態(tài)
endcase
end
endmodule
【例5.4】用initial過程語句對(duì)測(cè)試變量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串行塊產(chǎn)生信號(hào)波形
`timescale 10ns/1ns
module wave1;
reg wave;
parameter cycle=10;
initial
begin
- 4 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》
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",wave);
endmodule
【例5.6】用fork-join并行塊產(chǎn)生信號(hào)波形
`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",wave);
endmodule
【例5.7】持續(xù)賦值方式定義的2選1多路選擇器
module MUX21_1(out,a,b,sel);
input a,b,sel;
output out;
assign out=(sel==0)?a:b;
//持續(xù)賦值,,如果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碼加法計(jì)數(shù)器
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上升沿時(shí)刻計(jì)數(shù)- 6 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》begin
if (reset) qout<=0; //同步復(fù)位
else if(load) qout<=data; //同步置數(shù)
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; //產(chǎn)生進(jìn)位輸出信號(hào)
endmodule
【例5.12】BCD碼—七段數(shù)碼管顯示譯碼器
module decode4_7(decodeout,indec);
output[6:0] decodeout;
input[3:0] indec;
reg[6:0] decodeout;
always @(indec)
begin
case(indec) //用case語句進(jìn)行譯碼
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描述的數(shù)據(jù)選擇器
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程序設(shè)計(jì)教程》
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;
end
endmodule
【例5.16】用for語句實(shí)現(xiàn)2個(gè)8位數(shù)相乘
module mult_for(outcome,a,b);
parameter size=8;
input[size:1] a,b; //兩個(gè)操作數(shù)
output[2*size:1] outcome; //結(jié)果
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));
end
endmodule
【例5.17】用repeat實(shí)現(xiàn)8位二進(jìn)制數(shù)的乘法
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為循環(huán)次數(shù)
begin
if(temp_b[1]) //如果temp_b的最低位為1,,就執(zhí)行下面的加法
outcome=outcome+temp_a;
temp_a=temp_a<<1; //操作數(shù)a左移一位
- 9 - 程序文本
temp_b=temp_b>>1; //操作數(shù)b右移一位
end
end
endmodule
【例5.18】同一循環(huán)的不同實(shí)現(xiàn)方式
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程序設(shè)計(jì)教程》`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); //調(diào)用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】加法計(jì)數(shù)器中的進(jìn)程
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) //進(jìn)程1,,always過程塊
begin
if (!reset) qout= 4'h00; //同步清0,低電平有效
else if (load) qout= data; //同步預(yù)置
else qout=qout + 1; //加法計(jì)數(shù)
end
assign cout=(qout==4'hf)?1:0; //進(jìn)程2,,用持續(xù)賦值產(chǎn)生進(jìn)位信號(hào)
endmodule
【例6.2】任務(wù)舉例
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; //任務(wù)定義,,注意無端口列表
input[3:0] a,b; //a,b,out名稱的作用域范圍為task任務(wù)內(nèi)部
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);
/* 用任務(wù)my_and,需注意端口列表的順序應(yīng)與任務(wù)定義中的一致,,這里的a,b,c分別對(duì)應(yīng)任務(wù)定義中的a,b,out */
2'b01: c=a|b; //或
2'b10: c=a-b; //相減
2'b11: c=a+b; //相加
endcase
end
endmodule
- 12 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》【例6.3】測(cè)試程序
`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); //調(diào)用被測(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", code,a,b,c);
endmodule
【例6.4】函數(shù)
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】用函數(shù)和case語句描述的編碼器(不含優(yōu)先順序)
module code_83(din,dout);
input[7:0] din;
output[2:0] dout;
- 13 - 程序文本
function[2:0] code; //函數(shù)定義
input[7:0] din; //函數(shù)只有輸入,,輸出為函數(shù)名本身
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) ; //函數(shù)調(diào)用
endmodule
【例6.6】階乘運(yùn)算函數(shù)
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的上升沿時(shí)執(zhí)行運(yùn)算
begin
if(!reset) result<=0; //復(fù)位
else begin
result <= 2 * factorial(n); //調(diào)用factorial函數(shù)
end
end
function[31:0] factorial; //階乘運(yùn)算函數(shù)定義(注意無端口列表)
input[3:0] opa; //函數(shù)只能定義輸入端,輸出端口為函數(shù)名本身
reg[3:0] i;
begin
factorial = opa ? 1 : 0;
for(i= 2; i <= opa; i = i+1) //該句若要綜合通過,,opa應(yīng)賦具體的數(shù)值
factorial = i* factorial; //階乘運(yùn)算
end
- 14 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》endfunction
endmodule
【例6.7】測(cè)試程序
`define clk_cycle 50
`include "funct.v"
module funct_tp;
reg[3:0] n;
reg reset,clk;
wire[31:0] result;
initial //定義激勵(lì)向量
begin
n=0; reset=1; clk=0;
for(n=0;n<=15;n=n+1)
#100 n=n;
end
initial $monitor($time,,,"n=%d result=%d",n,result);
//定義輸出顯示格式
always # `clk_cycle clk=~clk; //產(chǎn)生時(shí)鐘信號(hào)
funct funct_try(.clk(clk),.n(n),.result(result),.reset(reset));
//調(diào)用被測(cè)試模塊
endmodule
【例6.8】順序執(zhí)行模塊1
module serial1(q,a,clk);
output q,a;
input clk;
reg q,a;
always @(posedge clk)
begin
q=~q;
a=~q;
end
endmodule
【例6.9】順序執(zhí)行模塊2
module 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】并行執(zhí)行模塊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】并行執(zhí)行模塊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】調(diào)用門元件實(shí)現(xiàn)的4選1 MUX- 16 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》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 MUX
module 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;
endcase
endmodule
【例7.3】行為描述方式實(shí)現(xiàn)的4位計(jì)數(shù)器
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;
end
endmodule
- 17 - 程序文本
【例7.4】數(shù)據(jù)流方式描述的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】用條件運(yùn)算符描述的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】門級(jí)結(jié)構(gòu)描述的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】數(shù)據(jù)流描述的2選1MUX
module MUX2_1c(out,a,b,sel);
output out;
- 18 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》input a,b,sel;
assign out = sel ? b : a;
endmodule
【例7.9】調(diào)用門元件實(shí)現(xiàn)的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】數(shù)據(jù)流方式描述的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
end
endmodule
【例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】調(diào)用門元件實(shí)現(xiàn)的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】數(shù)據(jù)流描述的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程序設(shè)計(jì)教程》reg sum,cout; //在always塊中被賦值的變量應(yīng)定義為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;
end
endmodule
【例7.17】混合描述的1位全加器
module full_add5(a,b,cin,sum,cout);
input a,b,cin;
output sum,cout;
reg cout,m1,m2,m3; //在always塊中被賦值的變量應(yīng)定義為reg型wire s1;
xor x1(s1,a,b); //調(diào)用門元件
always @(a or b or cin) //always塊語句
begin
m1 = a & b;
m2 = b & cin;
m3 = a & cin;
cout = (m1| m2) | m3;
end
assign sum = s1 ^ cin; //assign持續(xù)賦值語句
endmodule
【例7.18】結(jié)構(gòu)描述的4位級(jí)連全加器
`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); //級(jí)連描述
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】數(shù)據(jù)流描述的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的區(qū)別
`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); //使用函數(shù)$time- 22 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》endmodule
【例8.2】$random函數(shù)的使用
`timescale 10ns/1ns
module 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; //每次產(chǎn)生一個(gè)隨機(jī)數(shù)
end
endmodule
【例8.3】1位全加器進(jìn)位輸出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;
endtable
endprimitive
【例8.4】包含x態(tài)輸入的1位全加器進(jìn)位輸出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; //只要有兩個(gè)輸入為0,,則進(jìn)位輸出肯定為0
0 x 0 : 0;
x 0 0 : 0;
1 1 x : 1; //只要有兩個(gè)輸入為1,則進(jìn)位輸出肯定為1
1 x 1 : 1;
x 1 1 : 1;
endtable
endprimitive
【例8.5】用簡縮符“,?”表述的1位全加器進(jìn)位輸出UDP元件
primitive carry_udpx2(cout,cin,a,b);
input cin,a,b;
output cout;
table
// cin a b : cout //真值表
0 0 : 0; //只要有兩個(gè)輸入為0,,則進(jìn)位輸出肯定為0
0 ? 0 : 0;
0 0 ? : 0;
1 1 : 1; //只要有兩個(gè)輸入為1,則進(jìn)位輸出肯定為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; //當(dāng)s2s1=00時(shí),,Y=in0
1 ? ? 0 0 : 1;
0 ? 0 1 : 0; //當(dāng)s2s1=01時(shí),,Y=in1
- 24 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》
1 ? 0 1 : 1;
0 1 ? : 0; //當(dāng)s2s1=1?時(shí),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;
endtable
endprimitive
【例8.7】電平敏感的1位數(shù)據(jù)鎖存器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,,鎖存器的輸出保持原值,,用符號(hào)“-”表示
endtable
endprimitive
【例8.8】上升沿觸發(fā)的D觸發(fā)器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保持原值
(??) : ? : - ; //時(shí)鐘不變,,輸出也不變
- 25 - 程序文本
endtable
endprimitive
【例8.9】帶異步置1和異步清零的上升沿觸發(fā)的D觸發(fā)器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; //異步復(fù)位
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程序設(shè)計(jì)教程》
endspecify
endmodule
【例8.13】激勵(lì)波形的描述
'timescale 1ns/1ns
module test1;
reg A,B,C;
initial
begin //激勵(lì)波形描述
A = 0; B = 1; C = 0;
#100 C = 1;
#100 A = 1; B = 0;
#100 A = 0;
#100 C = 0;
#100 $finish;
end
initial $monitor($time,,,"A=%d B=%d C=%d",A,B,C); //顯示
endmodule
【例8.15】用always過程塊產(chǎn)生兩個(gè)時(shí)鐘信號(hào)
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;
end
initial $monitor($time,,,"clk1=%b clk2=%b",clk1,clk2);
endmodule
【例8.17】存儲(chǔ)器在仿真程序中的應(yīng)用
module ROM(addr,data,oe);
output[7:0] data; //數(shù)據(jù)信號(hào)
input[14:0] addr; //地址信號(hào)
input oe; //讀使能信號(hào),低電平有效
- 27 - 程序文本
reg[7:0] mem[0:255]; //存儲(chǔ)器定義
parameter DELAY = 100;
assign #DELAY data=(oe==0) ? mem[addr] : 8'hzz;
initial $readmemh("rom.hex",mem); //從文件中讀入數(shù)據(jù)
endmodule
【例8.18】8位乘法器的仿真程序
`timescale 10ns/1ns
module mult_tp; //測(cè)試模塊的名字
reg[7:0] a,b; //測(cè)試輸入信號(hào)定義為reg型
wire [15:0] out; //測(cè)試輸出信號(hào)定義為wire型
integer i,j;
mult8 m1(out,a,b); //調(diào)用測(cè)試對(duì)象
//激勵(lì)波形設(shè)定
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 //定義結(jié)果顯示格式
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; //兩個(gè)操作數(shù)
output[2*size:1] out; //結(jié)果
assign out=a*b; //乘法運(yùn)算符- 28 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》endmodule
【例8.19】8位加法器的仿真程序
`timescale 1ns/1ns
module add8_tp; //仿真模塊無端口列表
reg[7:0] A,B; //輸入激勵(lì)信號(hào)定義為reg型
reg cin;
wire[7:0] SUM; //輸出信號(hào)定義為wire型
wire cout;
parameter DELY = 100;
add8 AD1(SUM,cout,A,B,cin); //調(diào)用測(cè)試對(duì)象
initial begin //激勵(lì)波形設(shè)定
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);endmodule
module add8(SUM,cout,A,B,cin); //待測(cè)試的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/1ns
module mux_tp;
reg a,b,sel;
wire out;
- 29 - 程序文本
MUX2_1 m1(out,a,b,sel); //調(diào)用待測(cè)試模塊
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); //待測(cè)試的2選1MUX模塊
input a,b,sel;
output out;
not #(0.4,0.3) (sel_,sel); //#(0.4,0.3)為門延時(shí)
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位計(jì)數(shù)器的仿真
`timescale 10ns/1ns
module count8_tp;
reg clk,reset; //輸入激勵(lì)信號(hào)定義為reg型
wire[7:0] qout; //輸出信號(hào)定義為wire型
parameter DELY=100;
counter C1(qout,reset,clk); //調(diào)用測(cè)試對(duì)象
always #(DELY/2) clk = ~clk; //產(chǎn)生時(shí)鐘波形
initial
begin //激勵(lì)波形定義
clk =0; reset=0;
- 30 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》#DELY reset=1;
#DELY reset=0;
#(DELY*300) $finish;
end
//結(jié)果顯示
initial $monitor($time,,,"clk=%d reset=%d qout=%d",clk,reset,qout);endmodule
module counter(qout,reset,clk); //待測(cè)試的8位計(jì)數(shù)器模塊
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)門級(jí)結(jié)構(gòu)描述
module gate1(F,A,B,C,D);
input A,B,C,D;
output F;
nand(F1,A,B); //調(diào)用門元件
and(F2,B,C,D);
or(F,F1,F2);
endmodule
(2)數(shù)據(jù)流描述
module gate2(F,A,B,C,D);
input A,B,C,D;
output F;
assign F=(A&B)|(B&C&D); //assign持續(xù)賦值
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關(guān)鍵字描述的三態(tài)門
module tri_1(in,en,out);
input in,en;
output out;
tri out;
bufif1 b1(out,in,en); //注意三態(tài)門端口的排列順序
endmodule
【例9.3】用assign語句描述的三態(tài)門
module tri_2(out,in,en);
output out;
input in,en;
assign out = en ? in : 'bz;
//若en=1,,則out=in,;若en=0,則out為高阻態(tài)
endmodule
【例9.4】三態(tài)雙向驅(qū)動(dòng)器
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】三態(tài)雙向驅(qū)動(dòng)器
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程序設(shè)計(jì)教程》
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優(yōu)先編碼器
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】用函數(shù)定義的8-3優(yōu)先編碼器
module code_83(din, dout);
input[7:0] din;
output[2:0] dout;
function[2:0] code; //函數(shù)定義
input[7:0] din; //函數(shù)只有輸入端口,,輸出為函數(shù)名本身
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); //函數(shù)調(diào)用
endmodule
【例9.9】七段數(shù)碼管譯碼器
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語句進(jìn)行譯碼
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程序設(shè)計(jì)教程》
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】奇偶校驗(yàn)位產(chǎn)生器
module parity(even_bit,odd_bit,input_bus);
output even_bit,odd_bit;
input[7:0] input_bus;
assign odd_bit = ^ input_bus; //產(chǎn)生奇校驗(yàn)位
assign even_bit = ~odd_bit; //產(chǎn)生偶校驗(yàn)位
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 - 程序文本
case(sel)
2'b00: out=in0;
2'b01: out=in1;
2'b10: out=in2;
default: out=in3;
endcase
end
endmodule
【例9.13】用組合電路實(shí)現(xiàn)的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觸發(fā)器- 36 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》module DFF(Q,D,CLK);
output Q;
input D,CLK;
reg Q;
always @(posedge CLK)
begin
Q <= D;
end
endmodule
【例9.15】帶異步清0、異步置1的D觸發(fā)器
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
end
endmodule
【例9.16】帶同步清0、同步置1的D觸發(fā)器
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觸發(fā)器
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位數(shù)據(jù)鎖存器
module latch_1(q,d,clk);
output q;
input d,clk;
assign q = clk ? d : q; //時(shí)鐘信號(hào)為高電平時(shí),,將輸入端數(shù)據(jù)鎖存
endmodule
【例9.19】帶置位和復(fù)位端的1位數(shù)據(jù)鎖存器
module latch_2(q,d,clk,set,reset);
output q;
- 38 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》input d,clk,set,reset;
assign q = reset ? 0 : (set ? 1 : (clk ? d : q));
endmodule
【例9.20】8位數(shù)據(jù)鎖存器
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位數(shù)據(jù)寄存器
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; //同步清0,,高電平有效
else
begin
dout <= dout << 1; //輸出信號(hào)左移一位
- 39 - 程序文本
dout[0] <= din; //輸入信號(hào)補(bǔ)充到輸出信號(hào)的最低位
end
end
endmodule
【例9.23】可變模加法/減法計(jì)數(shù)器
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; //同步預(yù)置
else if (up_down) cnt = cnt + 1; //加法計(jì)數(shù)
else cnt = cnt - 1; //減法計(jì)數(shù)
end
endmodule
【例9.24】4位Johnson計(jì)數(shù)器(異步復(fù)位)
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程序設(shè)計(jì)教程》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; //定義數(shù)據(jù)寬度
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; //參數(shù)賦值
defparam ram.lpm_widthad=8;
defparam ram.lpm_indata="REGISTERED";
defparam ram.lpm_outdata="REGISTERED";
defparam ram.lpm_file="map_lpm_ram.mif"; //RAM塊中的內(nèi)容取自該文件endmodule
【例9.27】4位串并轉(zhuǎn)換器
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}; //使用連接運(yùn)算符
end
endmodule
【例9.28】用函數(shù)實(shí)現(xiàn)簡單的處理器
module mpc(instr,out);
input[17:0] instr; //instr為輸入的指令
- 41 - 程序文本
output[8:0] out; //輸出結(jié)果
reg[8:0] out;
reg func;
reg[7:0] op1,op2; //從指令中提取的兩個(gè)操作數(shù)
function[16:0] code_add; //函數(shù)的定義
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位是操作數(shù)opr1
case(code)
2'b00:
begin
add_func=1;
opr2=instr[15:8]; //從instr中取第二個(gè)操作數(shù)
end
2'b01:
begin
add_func=0;
opr2=instr[15:8]; //從instr中取第二個(gè)操作數(shù)
end
2'b10:
begin
add_func=1;
opr2=8'd1; //第二個(gè)操作數(shù)取為1,,實(shí)現(xiàn)+1操作
end
default:
begin
add_func=0;
opr2=8'd1; //實(shí)現(xiàn)-1操作
end
endcase
code_add={add_func,opr2,opr1};
end
endfunction
always @(instr)
begin
- 42 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》
{func,op2,op1}=code_add(instr); //調(diào)用函數(shù)
if(func==1) out=op1+op2; //實(shí)現(xiàn)兩數(shù)相加,、操作數(shù)1加1操作
else out=op1-op2; //實(shí)現(xiàn)兩數(shù)相減、操作數(shù)1減1操作
end
endmodule
【例9.29】微處理器的測(cè)試代碼
`timescale 10ns/1ns
`include "mpc.v"
module mpc_tp;
reg[17:0] instr;
wire[8:0] out;
parameter DELY=10;
mpc m1(instr,out); //調(diào)用待測(cè)試模塊
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;
end
initial $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; //函數(shù)定義,,mult函數(shù)完成乘法操作
input[7:0] opa,opb; //函數(shù)只能定義輸入端,,輸出端口為函數(shù)名本身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】乘累加器的測(cè)試代碼
'timescale 1ns/1ns
'include "mac.v"
module mac_tp;
reg[7:0] opa,opb; //測(cè)試輸入信號(hào)用reg型變量
reg clr,clk;
wire[15:0] out; //測(cè)試輸出信號(hào)用wire型變量
parameter DELY = 100;
//測(cè)試對(duì)象調(diào)用
MAC m1(out,opa,opb,clk,clr);
always #(DELY) clk = ~clk; //產(chǎn)生時(shí)鐘波形
initial begin //激勵(lì)波形定義
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程序設(shè)計(jì)教程》#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
//結(jié)果顯示
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; //輸入數(shù)據(jù)鎖存
end
always @(posedge clk)
begin
{cout,sum}=tempa+tempb+tempc;
end
endmodule
【例10.2】4級(jí)流水方式的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; //輸入數(shù)據(jù)緩存
end
always @(posedge clk)
begin
{firstco,firsts}=tempa[1:0]+tempb[1:0]+tempci;
//第一級(jí)加(低2位)
firsta=tempa[7:2]; //未參加計(jì)算的數(shù)據(jù)緩存
firstb=tempb[7:2];
end
always @(posedge clk)
begin
{secondco,seconds}={firsta[1:0]+firstb[1:0]+firstco,firsts};
//第二級(jí)加(第2、3位相加)
seconda=firsta[5:2]; //數(shù)據(jù)緩存
secondb=firstb[5:2];
end
always @(posedge clk)
begin
{thirdco,thirds}={seconda[1:0]+secondb[1:0]+secondco,seconds};
//第三級(jí)加(第4,、5位相加)
thirda=seconda[3:2]; //數(shù)據(jù)緩存
thirdb=secondb[3:2];
end
always @(posedge clk)
begin
{cout,sum}={thirda[1:0]+thirdb[1:0]+thirdco,thirds};
//第四級(jí)加(高兩位相加)
end
endmodule
【例10.3】兩個(gè)加法器和一個(gè)選擇器的實(shí)現(xiàn)方式
module resource1(sum,a,b,c,d,sel);
parameter size=4;
output[size:0] sum;
- 46 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》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;
end
endmodule
【例10.4】兩個(gè)選擇器和一個(gè)加法器的實(shí)現(xiàn)方式
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;
end
endmodule
【例10.5】狀態(tài)機(jī)設(shè)計(jì)的例子
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;
/*狀態(tài)編碼,,采用格雷(Gray)編碼方式*/
always @(posedge clk or posedge clr) /*該進(jìn)程定義起始狀態(tài)*/
begin
if (clr) state <= state0;
else state <= next_state;
- 47 - 程序文本
end
always @(state or start or step2 or step3) /*該進(jìn)程實(shí)現(xiàn)狀態(tài)的轉(zhuǎn)換*/
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) /*該進(jìn)程定義組合邏輯(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語句,避免鎖存器的產(chǎn)生*/
endcase
end
endmodule
【例10.6】自動(dòng)轉(zhuǎn)換量程頻率計(jì)控制器
/*信號(hào)定義:
clk: 輸入時(shí)鐘,;
- 48 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》clear: 為整個(gè)頻率計(jì)的異步復(fù)位信號(hào),;
reset: 用來在量程轉(zhuǎn)換開始時(shí)復(fù)位計(jì)數(shù)器;
std_f_sel: 用來選擇標(biāo)準(zhǔn)時(shí)基,;
cntover: 代表超量程,;
cntlow: 代表欠量程。
狀態(tài)A,,B,,C,,D,E,,F(xiàn)采用一位熱碼編碼 */
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; //用于保存當(dāng)前狀態(tài)和次態(tài)的中間變量parameter start_fl00k=6'b000001, //狀態(tài)A編碼,,采用1位熱碼
fl00k_cnt=6'b000010, //狀態(tài)B
start_fl0k=6'b000100, //狀態(tài)C
fl0k_cnt=6'b001000, //狀態(tài)D
start_flk=6'b010000, //狀態(tài)E
flk_cnt=6'b100000; //狀態(tài)F
always @(posedge clk or posedge clear)
begin
if(clear) present<=start_fl0k; //start_fl0k為起始狀態(tài)
else present<=next;
end
always @(present or cntover or cntlow)
begin
case(present) //用case語句描述狀態(tài)轉(zhuǎn)換
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; //缺省狀態(tài)為起始狀態(tài)
endcase
end
always @(present) //該進(jìn)程產(chǎn)生各狀態(tài)下的輸出
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程序設(shè)計(jì)教程》reg[7:0] qout;
always @(posedge clk or posedge clear)
begin
if(clear) qout=0; //異步清0
else qout=in;
end
endmodule
【例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); //調(diào)用add8子模塊
reg8 accreg8(accout,sum,clk,clear); //調(diào)用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); //調(diào)用add8子模塊
reg8 accreg8(accout,sum,clk,clear); //調(diào)用reg8子模塊
endmodule
【例10.11】阻塞賦值方式描述的移位寄存器1
module 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程序設(shè)計(jì)教程》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;
end
endmodule
【例10.15】長幀同步時(shí)鐘的產(chǎn)生
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;
end
begin
if(counter<=(delay-1)) strb=1;
else strb=0;
end
endmodule
【例10.16】引入了D觸發(fā)器的長幀同步時(shí)鐘的產(chǎn)生
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; //引入一個(gè)觸發(fā)器
end
begin
if(counter<=(delay-1)) temp=1;
else temp=0;
end
endmodule
【例11.1】數(shù)字跑表
/*信號(hào)定義:
CLK: CLK為時(shí)鐘信號(hào);
CLR: 為異步復(fù)位信號(hào),;
PAUSE: 為暫停信號(hào),;
MSH,MSL: 百分秒的高位和低位,;
SH,,SL: 秒信號(hào)的高位和低位;
MH,,ML: 分鐘信號(hào)的高位和低位,。 */
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為百分秒向秒的進(jìn)位,cn2為秒向分的進(jìn)位
//百分秒計(jì)數(shù)進(jìn)程,,每計(jì)滿100,,cn1產(chǎn)生一個(gè)進(jìn)位
always @(posedge CLK or posedge CLR)
begin
if(CLR) begin //異步復(fù)位
{MSH,MSL}<=8'h00;
cn1<=0;
end
else if(!PAUSE) //PAUSE為0時(shí)正常計(jì)數(shù),為1時(shí)暫停計(jì)數(shù)
begin
if(MSL==9) begin
- 54 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》
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
//秒計(jì)數(shù)進(jìn)程,,每計(jì)滿60,,cn2產(chǎn)生一個(gè)進(jìn)位
always @(posedge cn1 or posedge CLR)
begin
if(CLR) egin //異步復(fù)位
{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; end
end
//分鐘計(jì)數(shù)進(jìn)程,每計(jì)滿60,,系統(tǒng)自動(dòng)清零
always @(posedge cn2 or posedge CLR)
begin
if(CLR)
begin {MH,ML}<=8'h00; end //異步復(fù)位
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位數(shù)字頻率計(jì)控制模塊
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信號(hào)的產(chǎn)生
end
end
assign count_clr=~clk&load; //count_clr信號(hào)的產(chǎn)生
endmodule
【例11.3】4位數(shù)字頻率計(jì)計(jì)數(shù)子模塊
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; //產(chǎn)生進(jìn)位信號(hào)
endmodule
【例11.4】頻率計(jì)鎖存器模塊
module latch_16(qo,din,load);
output[15:0] qo;
- 56 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》input[15:0] din;
input load;
reg[15:0] qo;
always @(posedge load)
begin qo=din; end
endmodule
【例11.5】交通燈控制器
/* 信號(hào)定義與說明:
CLK: 為同步時(shí)鐘,;
EN: 使能信號(hào),為1的話,,則控制器開始工作,;
LAMPA: 控制A方向四盞燈的亮滅;其中,,LAMPA0~LAMPA3,,分別控制A方向的
左拐燈、綠燈,、黃燈和紅燈,;
LAMPB: 控制B方向四盞燈的亮滅;其中,,LAMPB0 ~ LAMPB3,,分別控制B方向的
左拐燈、綠燈,、黃燈和紅燈,;
ACOUNT: 用于A方向燈的時(shí)間顯示,8位,可驅(qū)動(dòng)兩個(gè)數(shù)碼管,;
BCOUNT: 用于B方向燈的時(shí)間顯示,,8位,可驅(qū)動(dòng)兩個(gè)數(shù)碼管,。 */
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 //設(shè)置各種燈的計(jì)數(shù)器的預(yù)置數(shù)
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) //該進(jìn)程控制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 //倒計(jì)時(shí)
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) //該進(jìn)程控制B方向的四種燈
begin
if (EN)
begin
if(!tempb)
- 58 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》
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 //倒計(jì)時(shí)
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】“梁?!睒非葑嚯娐?/DIV>
//信號(hào)定義與說明:
//clk_4Hz: 用于控制音長(節(jié)拍)的時(shí)鐘頻率;
//clk_6MHz: 用于產(chǎn)生各種音階頻率的基準(zhǔn)頻率,;
//speaker: 用于激勵(lì)揚(yáng)聲器的輸出信號(hào),,本例中為方波信號(hào);
//high, med, low:分別用于顯示高音,、中音和低音音符,,各驅(qū)動(dòng)一個(gè)數(shù)碼管來顯示。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分頻產(chǎn)生方波信號(hào)
end
always @(posedge clk_4Hz)
begin
case({high,med,low}) //分頻比預(yù)置
'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; //計(jì)時(shí),,以實(shí)現(xiàn)循環(huán)演奏
else counter=counter+1;
case(counter) //記譜
- 60 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》0: {high,med,low}='b000000000011; //低音“3”
1: {high,med,low}='b000000000011; //持續(xù)4個(gè)時(shí)鐘節(jié)拍2: {high,med,low}='b000000000011;
3: {high,med,low}='b000000000011;
4: {high,med,low}='b000000000101; //低音“5”
5: {high,med,low}='b000000000101; //發(fā)3個(gè)時(shí)鐘節(jié)拍
6: {high,med,low}='b000000000101;
7: {high,med,low}='b000000000110; //低音“6”
8: {high,med,low}='b000000010000; //中音“1”
9: {high,med,low}='b000000010000; //發(fā)3個(gè)時(shí)鐘節(jié)拍
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; //發(fā)3個(gè)時(shí)鐘節(jié)拍
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; //持續(xù)11個(gè)時(shí)鐘節(jié)拍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; //持續(xù)8個(gè)時(shí)鐘節(jié)拍
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】自動(dòng)售飲料機(jī)
/*信號(hào)定義:
clk: 時(shí)鐘輸入,;
reset: 為系統(tǒng)復(fù)位信號(hào);
half_dollar: 代表投入5角硬幣,;
one_dollar: 代表投入1元硬幣,;
half_out: 表示找零信號(hào);
dispense: 表示機(jī)器售出一瓶飲料,;
collect: 該信號(hào)用于提示投幣者取走飲料。 */
- 62 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》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為中間狀態(tài)變量,,代表投入幣值的幾種情況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】多功能數(shù)字鐘
/* 信號(hào)定義:
clk: 標(biāo)準(zhǔn)時(shí)鐘信號(hào),,本例中,其頻率為4Hz,;
clk_1k: 產(chǎn)生鬧鈴音,、報(bào)時(shí)音的時(shí)鐘信號(hào),本例中其頻率為1024Hz,;
mode: 功能控制信號(hào),; 0:計(jì)時(shí)功能;
為1:鬧鐘功能,;
為2:手動(dòng)校時(shí)功能,;
turn: 接按鍵,在手動(dòng)校時(shí)功能時(shí),,選擇是調(diào)整小時(shí),,還是分鐘;
若長時(shí)間按住該鍵,,還可使秒信號(hào)清零,,用于精確調(diào)時(shí);
change: 接按鍵,手動(dòng)調(diào)整時(shí),,每按一次,,計(jì)數(shù)器加1;
如果長按,,則連續(xù)快速加1,,用于快速調(diào)時(shí)和定時(shí);
hour,min,sec:此三信號(hào)分別輸出并顯示時(shí),、分,、秒信號(hào),
皆采用BCD碼計(jì)數(shù),,分別驅(qū)動(dòng)6個(gè)數(shù)碼管顯示時(shí)間,;
alert: 輸出到揚(yáng)聲器的信號(hào),用于產(chǎn)生鬧鈴音和報(bào)時(shí)音,;
鬧鈴音為持續(xù)20秒的急促的“嘀嘀嘀”音,,若按住“change”鍵,
則可屏蔽該音,;整點(diǎn)報(bào)時(shí)音為“嘀嘀嘀嘀—嘟”四短一長音,;
LD_alert: 接發(fā)光二極管,指示是否設(shè)置了鬧鐘功能,;
LD_hour: 接發(fā)光二極管,,指示當(dāng)前調(diào)整的是小時(shí)信號(hào);
LD_min: 接發(fā)光二極管,,指示當(dāng)前調(diào)整的是分鐘信號(hào),。
*/
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程序設(shè)計(jì)教程》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信號(hào)用于產(chǎn)生或屏蔽聲音
else begin sound<=sound+1; ear<=0; end
end
always @(posedge clk_2Hz) //由4Hz的輸入時(shí)鐘產(chǎn)生1Hz的時(shí)基信號(hào)
clk_1Hz<=~clk_1Hz;
always @(posedge mode) //mode信號(hào)控制系統(tǒng)在三種功能間轉(zhuǎn)換
begin if(m==2) m<=0; else m<=m+1; end
always @(posedge turn)
fm<=~fm;
always //該進(jìn)程產(chǎn)生count1,count2,counta,countb四個(gè)信號(hào)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;
endcase
end
- 65 - 程序文本
always @(negedge clk)
//如果長時(shí)間按下“change”鍵,則生成“num1”信號(hào)用于連續(xù)快速加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) //產(chǎn)生num2信號(hào)
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用于計(jì)時(shí),、校時(shí)中的分鐘計(jì)數(shù)
assign ct2=(num1&clk)|(!num1&count2); //ct2用于定時(shí)狀態(tài)下調(diào)整分鐘信號(hào)
assign cta=(num4&clk)|(!num4&h_clk); //cta用于計(jì)時(shí),、校時(shí)中的小時(shí)計(jì)數(shù)
assign ctb=(num2&clk)|(!num2&countb); //ctb用于定時(shí)狀態(tài)下調(diào)整小時(shí)信號(hào)
always @(posedge clk_1Hz) //秒計(jì)時(shí)和秒調(diào)整進(jìn)程
if(!(sec1^8'h59)|turn&(!m))
begin
sec1<=0; if(!(turn&(!m))) minclk<=1;
- 66 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》
end
//按住“turn”按鍵一段時(shí)間,秒信號(hào)可清零,,該功能用于手動(dòng)精確調(diào)時(shí)
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) //分計(jì)時(shí)和分調(diào)整進(jìn)程
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) //小時(shí)計(jì)時(shí)和小時(shí)調(diào)整進(jìn)程
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) //鬧鐘定時(shí)功能中的分鐘調(diào)節(jié)進(jìn)程
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) //鬧鐘定時(shí)功能中的小時(shí)調(diào)節(jié)進(jìn)程
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; //控制鬧鈴的時(shí)間長短
else alert1<=0;
else alert1<=0;
always //時(shí)、分,、秒的顯示控制
case(m)
3'b00: begin hour<=hour1; min<=min1; sec<=sec1; end
//計(jì)時(shí)狀態(tài)下的時(shí),、分、秒顯示
3'b01: begin hour<=ahour; min<=amin; sec<=8'hzz; end
//定時(shí)狀態(tài)下的時(shí),、分,、秒顯示
3'b10: begin hour<=hour1; min<=min1; sec<=8'hzz; end
//校時(shí)狀態(tài)下的時(shí)、分,、秒顯示
endcase
assign LD_alert=(ahour|amin)?1:0; //指示是否進(jìn)行了鬧鈴定時(shí)
assign alert=((alert1)?clk_1k&clk:0)|alert2; //產(chǎn)生鬧鈴音或整點(diǎn)報(bào)時(shí)音
always //產(chǎn)生整點(diǎn)報(bào)時(shí)信號(hào)alert2
begin
if((min1==8'h59)&&(sec1>8'h54)||(!(min1|sec1)))
if(sec1>8'h54) alert2<=ear&clk_1k; //產(chǎn)生短音
else alert2<=!ear&clk_1k; //產(chǎn)生長音
else alert2<=0;
end
endmodule
【例11.9】電話計(jì)費(fèi)器程序
/*信號(hào)定義:
clk: 時(shí)鐘信號(hào),,本例中其頻率值為1Hz,;
decide: 電話局反饋回來的信號(hào),代表話務(wù)種類,,“01”表示市話,,“10”表示
長話,“11”表示特話,;
dispmoney: 用來顯示卡內(nèi)余額,,其單位為角,這里假定能顯示的最大數(shù)額為50元
(500角),;
disptime: 顯示本次通話的時(shí)長,;
write,read: 當(dāng)write信號(hào)下降沿到來時(shí)寫卡,當(dāng)話卡插入,,read信號(hào)變高時(shí)讀卡,;
warn: 余額過少時(shí)的告警信號(hào)。本例中,,當(dāng)打市話時(shí),,余額少于3角,打長
話時(shí),,余額少于6角,,即會(huì)產(chǎn)生告警信號(hào);
cut: 當(dāng)告警時(shí)間過長時(shí)自動(dòng)切斷通話信號(hào),。 */
- 68 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》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為分時(shí)鐘
reg set,reset_ena;
integer num1,temp;
assign dispmoney=card?money:0;
assign disptime=dtime;
assign read=card?1:0;
//產(chǎn)生分時(shí)鐘
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) //該進(jìn)程完成電話計(jì)費(fèi)功能
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 //市話計(jì)費(fèi)
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;
//市話通話計(jì)時(shí)
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
//通話計(jì)時(shí)
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;
//長話計(jì)費(fèi)
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程序設(shè)計(jì)教程》
end
endcase
else write<=0;
else begin dtime<=0; warn<=0; write<=0; reset_ena<=0; end
//取卡后對(duì)一些信號(hào)進(jìn)行復(fù)位
end
always @(posedge clk) //該進(jìn)程在告警時(shí)間過長的情況下切斷本次通話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; //復(fù)位cut信號(hào)
temp<=0;
end
end
endmodule
【例12.1】8位級(jí)連加法器
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); //級(jí)連描述
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位超前進(jìn)位加法器
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]; //產(chǎn)生第0位本位值和進(jìn)位值
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]; //產(chǎn)生第1位本位值和進(jìn)位值
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]; //產(chǎn)生第2位本位值和進(jìn)位值
assign P[2]=a[2]|b[2];
- 72 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》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]; //產(chǎn)生第3位本位值和進(jìn)位值
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]; //產(chǎn)生第4位本位值和進(jìn)位值
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]; //產(chǎn)生第5位本位值和進(jìn)位值
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]; //產(chǎn)生第6位本位值和進(jìn)位值
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]; //產(chǎn)生第7位本位值和進(jìn)位值
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]); //產(chǎn)生最高位進(jìn)位輸出
endmodule
【例12.4】8位并行乘法器
module mult(outcome,a,b);
parameter size=8;
input[size:1] a,b; //兩個(gè)操作數(shù)
output[2*size:1] outcome; //結(jié)果
assign outcome=a*b; //乘法運(yùn)算符
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); //模塊調(diào)用
always @(posedge clk)
begin
out = (outa << 4) + (outb << 2) + (outc << 2) + outd;
end
endmodule
module lookup(out,a,b,clk); //用查找表方式實(shí)現(xiàn)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程序設(shè)計(jì)教程》
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; //該函數(shù)實(shí)現(xiàn)8×1乘法
input[7:0] operand;
input sel;
begin
mult8x1= (sel) ? (operand) : 8'b00000000;
- 75 - 程序文本
end
endfunction
always @(posedge clk) //調(diào)用函數(shù)實(shí)現(xiàn)操作數(shù)b 各位與操作數(shù)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; //加法器樹運(yùn)算
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數(shù)字濾波器
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程序設(shè)計(jì)教程》
t3<=tap2+tap8;
t4<=tap1+tap9;
t5<=tap0+tap10; //利用對(duì)稱性
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位高速數(shù)字相關(guān)器
- 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), //模塊調(diào)用
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); //該模塊實(shí)現(xiàn)4位相關(guān)器
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程序設(shè)計(jì)教程》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]; //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]為錯(cuò)誤圖樣
c = e ^ y; //c為輸出碼字
end
endmodule
【例12.11】(7,,4)循環(huán)碼編碼器
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循環(huán)計(jì)算碼組的前4個(gè)碼元
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循環(huán)計(jì)算碼組的后3個(gè)碼元
begin
temp = d2;
d2 = d1; d1 = d0 ^ temp;
d0 = temp; c[i] = temp;
end
end
- 80 -
王金明:《Verilog HDL程序設(shè)計(jì)教程》endmodule
【例12.12】(7,,4)循環(huán)碼糾錯(cuò)譯碼器
module decoder2(c,y,clk);
output[6:0] c; //c為輸出碼字,c[6]為高次項(xiàng)
input[6:0] y; //y為接收碼字,,y[6]為高次項(xiàng)
input clk;
reg[6:0] c,c_buf,buffer;
reg temp;
reg s0,s1,s2; //伴隨式電路寄存器
reg e; //錯(cuò)誤檢測(cè)輸出信號(hào)
integer i;
always @(posedge clk)
begin
s0=0; s1=0; s2=0; //初始化
temp=0;
buffer=y; //接收碼字移入緩存
for (i=6;i>=0;i=i-1) //接收碼字進(jìn)入除法電路
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) //輸出糾錯(cuò)譯碼后的碼字
begin
e=s0&(~s1)&temp;
temp=s2;
s2=s1;
s1=s0^temp;
s0=temp^e;
c_buf[i]=buffer[i]^e;
if (e==1) //若出錯(cuò),,對(duì)緩存進(jìn)行清零
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程序設(shè)計(jì)教程》
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 - |
|