Verilog HDL 程序设计教程.docx
《Verilog HDL 程序设计教程.docx》由会员分享,可在线阅读,更多相关《Verilog HDL 程序设计教程.docx(40页珍藏版)》请在冰豆网上搜索。
VerilogHDL程序设计教程
《VerilogHDL程序设计教程》代码例子
-1-
【例3.1】4位全加器
moduleadder4(cout,sum,ina,inb,cin);
output[3:
0]sum;
outputcout;
input[3:
0]ina,inb;
inputcin;
assign{cout,sum}=ina+inb+cin;
endmodule
【例3.2】4位计数器
modulecount4(out,reset,clk);
output[3:
0]out;
inputreset,clk;
reg[3:
0]out;
always@(posedgeclk)
begin
if(reset)out<=0;//同步复位
elseout<=out+1;//计数
end
endmodule
【例3.3】4位全加器的仿真程序
`timescale1ns/1ns
`include"adder4.v"
moduleadder_tp;//测试模块的名字
reg[3:
0]a,b;//测试输入信号定义为reg型
regcin;
wire[3:
0]sum;//测试输出信号定义为wire型
wirecout;
integeri,j;
adder4adder(sum,cout,a,b,cin);//调用测试对象
always#5cin=~cin;//设定cin的取值
initial
begin
a=0;b=0;cin=0;
for(i=1;i<16;i=i+1)
#10a=i;//设定a的取值
end
程序文本
-2-
initial
begin
for(j=1;j<16;j=j+1)
#10b=j;//设定b的取值
end
initial//定义结果显示格式
begin
$monitor($time,,,"%d+%d+%b={%b,%d}",a,b,cin,cout,sum);
#160$finish;
end
endmodule
【例3.4】4位计数器的仿真程序
`timescale1ns/1ns
`include"count4.v"
modulecoun4_tp;
regclk,reset;//测试输入信号定义为reg型
wire[3:
0]out;//测试输出信号定义为wire型
parameterDELY=100;
count4mycount(out,reset,clk);//调用测试对象
always#(DELY/2)clk=~clk;//产生时钟波形
initial
begin//激励信号定义
clk=0;reset=0;
#DELYreset=1;
#DELYreset=0;
#(DELY*20)$finish;
end
//定义结果显示格式
initial$monitor($time,,,"clk=%dreset=%dout=%d",clk,reset,out);
endmodule
【例3.5】“与-或-非”门电路
moduleAOI(A,B,C,D,F);//模块名为AOI(端口列表A,B,C,D,F)
inputA,B,C,D;//模块的输入端口为A,B,C,D
outputF;//模块的输出端口为F
王金明:
《VerilogHDL程序设计教程》
-3-
wireA,B,C,D,F;//定义信号的数据类型
assignF=~((A&B)|(C&D));//逻辑功能描述
endmodule
【例5.1】用case语句描述的4选1数据选择器
modulemux4_1(out,in0,in1,in2,in3,sel);
outputout;
inputin0,in1,in2,in3;
input[1:
0]sel;
regout;
always@(in0orin1orin2orin3orsel)//敏感信号列表
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】同步置数、同步清零的计数器
modulecount(out,data,load,reset,clk);
output[7:
0]out;
input[7:
0]data;
inputload,clk,reset;
reg[7:
0]out;
always@(posedgeclk)//clk上升沿触发
begin
if(!
reset)out=8'h00;//同步清0,低电平有效
elseif(load)out=data;//同步预置
elseout=out+1;//计数
end
endmodule
【例5.3】用always过程语句描述的简单算术逻辑单元
`defineadd3'd0
`defineminus3'd1
`defineband3'd2
`definebor3'd3
`definebnot3'd4
程序文本
-4-
modulealu(out,opcode,a,b);
output[7:
0]out;
reg[7:
0]out;
input[2:
0]opcode;//操作码
input[7:
0]a,b;//操作数
always@(opcodeoraorb)//电平敏感的always块
begin
case(opcode)
`add:
out=a+b;//加操作
`minus:
out=a-b;//减操作
`band:
out=a&b;//求与
`bor:
out=a|b;//求或
`bnot:
out=~a;//求反
default:
out=8'hx;//未收到指令时,输出任意态
endcase
end
endmodule
【例5.4】用initial过程语句对测试变量A、B、C赋值
`timescale1ns/1ns
moduletest;
regA,B,C;
initial
begin
A=0;B=1;C=0;
#50A=1;B=0;
#50A=0;C=1;
#50B=1;
#50B=0;C=0;
#50$finish;
end
endmodule
【例5.5】用begin-end串行块产生信号波形
`timescale10ns/1ns
modulewave1;
regwave;
parametercycle=10;
initial
begin
王金明:
《VerilogHDL程序设计教程》
-5-
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并行块产生信号波形
`timescale10ns/1ns
modulewave2;
regwave;
parametercycle=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】持续赋值方式定义的2选1多路选择器
moduleMUX21_1(out,a,b,sel);
inputa,b,sel;
outputout;
assignout=(sel==0)?
a:
b;
//持续赋值,如果sel为0,则out=a;否则out=b
endmodule
【例5.8】阻塞赋值方式定义的2选1多路选择器
moduleMUX21_2(out,a,b,sel);
inputa,b,sel;
程序文本
-6-
outputout;
regout;
always@(aorborsel)
begin
if(sel==0)out=a;//阻塞赋值
elseout=b;
end
endmodule
【例5.9】非阻塞赋值
modulenon_block(c,b,a,clk);
outputc,b;
inputclk,a;
regc,b;
always@(posedgeclk)
begin
b<=a;
c<=b;
end
endmodule
【例5.10】阻塞赋值
moduleblock(c,b,a,clk);
outputc,b;
inputclk,a;
regc,b;
always@(posedgeclk)
begin
b=a;
c=b;
end
endmodule
【例5.11】模为60的BCD码加法计数器
modulecount60(qout,cout,data,load,cin,reset,clk);
output[7:
0]qout;
outputcout;
input[7:
0]data;
inputload,cin,clk,reset;
reg[7:
0]qout;
always@(posedgeclk)//clk上升沿时刻计数
王金明:
《VerilogHDL程序设计教程》
-7-
begin
if(reset)qout<=0;//同步复位
elseif(load)qout<=data;//同步置数
elseif(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
assigncout=((qout==8'h59)&cin)?
1:
0;//产生进位输出信号
endmodule
【例5.12】BCD码—七段数码管显示译码器
moduledecode4_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
程序文本
-8-
endmodule
【例5.13】用casez描述的数据选择器
modulemux_casez(out,a,b,c,d,select);
outputout;
inputa,b,c,d;
input[3:
0]select;
regout;
always@(selectoraorborcord)
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】隐含锁存器举例
moduleburied_ff(c,b,a);
outputc;
inputb,a;
regc;
always@(aorb)
begin
if((b==1)&&(a==1))c=a&b;
end
endmodule
【例5.15】用for语句描述的七人投票表决器
modulevoter7(pass,vote);
outputpass;
input[6:
0]vote;
reg[2:
0]sum;
integeri;
regpass;
always@(vote)
begin
sum=0;
王金明:
《VerilogHDL程序设计教程》
-9-
for(i=0;i<=6;i=i+1)//for语句
if(vote[i])sum=sum+1;
if(sum[2])pass=1;//若超过4人赞成,则pass=1
elsepass=0;
end
endmodule
【例5.16】用for语句实现2个8位数相乘
modulemult_for(outcome,a,b);
parametersize=8;
input[size:
1]a,b;//两个操作数
output[2*size:
1]outcome;//结果
reg[2*size:
1]outcome;
integeri;
always@(aorb)
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实现8位二进制数的乘法
modulemult_repeat(outcome,a,b);
parametersize=8;
input[size:
1]a,b;
output[2*size:
1]outcome;
reg[2*size:
1]temp_a,outcome;
reg[size:
1]temp_b;
always@(aorb)
begin
outcome=0;
temp_a=a;
temp_b=b;
repeat(size)//repeat语句,size为循环次数
begin
if(temp_b[1])//如果temp_b的最低位为1,就执行下面的加法
outcome=outcome+temp_a;
temp_a=temp_a<<1;//操作数a左移一位
程序文本
-10-
temp_b=temp_b>>1;//操作数b右移一位
end
end
endmodule
【例5.18】同一循环的不同实现方式
moduleloop1;//方式1
integeri;
initial
for(i=0;i<4;i=i+1)//for语句
begin
$display(“i=%h”,i);
end
endmodule
moduleloop2;//方式2
integeri;
initialbegin
i=0;
while(i<4)//while语句
begin
$display("i=%h",i);
i=i+1;
end
end
endmodule
moduleloop3;//方式3
integeri;
initialbegin
i=0;
repeat(4)//repeat语句
begin
$display("i=%h",i);
i=i+1;
end
end
endmodule
【例5.19】使用了`include语句的16位加法器
王金明:
《VerilogHDL程序设计教程》
-11-
`include"adder.v"
moduleadder16(cout,sum,a,b,cin);
outputcout;
parametermy_size=16;
output[my_size-1:
0]sum;
input[my_size-1:
0]a,b;
inputcin;
addermy_adder(cout,sum,a,b,cin);//调用adder模块
endmodule
//下面是adder模块代码
moduleadder(cout,sum,a,b,cin);
parametersize=16;
outputcout;
output[size-1:
0]sum;
inputcin;
input[size-1:
0]a,b;
assign{cout,sum}=a+b+cin;
endmodule
【例5.20】条件编译举例
modulecompile(out,A,B);
outputout;
inputA,B;
`ifdefadd//宏名为add
assignout=A+B;
`else
assignout=A-B;
`endif
endmodule
【例6.1】加法计数器中的进程
modulecount(data,clk,reset,load,cout,qout);
outputcout;
output[3:
0]qout;
reg[3:
0]qout;
input[3:
0]data;
inputclk,reset,load;
程序文本
-12-
always@(posedgeclk)//进程1,always过程块
begin
if(!
reset)qout=4'h00;//同步清0,低电平有效
elseif(load)qout=data;//同步预置
elseqout=qout+1;//加法计数
end
assigncout=(qout==4'hf)?
1:
0;//进程2,用持续赋值产生进位信号
endmodule
【例6.2】任务举例
modulealutask(code,a,b,c);
input[1:
0]code;
input[3:
0]a,b;
output[4:
0]c;
reg[4:
0]c;
taskmy_and;//任务定义,注意无端口列表
input[3:
0]a,b;//a,b,out名称的作用域范围为task任务内部
output[4:
0]out;
integeri;
begin
for(i=3;i>=0;i=i-1)
out[i]=a[i]&b[i];//按位与
end
endtask
always@(codeoraorb)
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
王金明:
《VerilogHDL程序设计教程》
-13-
【例6.3】测试程序
`include"alutask.v"
modulealu_tp;
reg[3:
0]a,b;
reg[1:
0]code;
wire[4:
0]c;
parameterDELY=100;
alutaskADD(code,a,b,c);//调用被测试模块
initialbegin
code=4'd0;a=4'b0000;b=4'b1111;
#DELYcode=4'd0;a=4'b0111;b=4'b1101;
#DELYcode=4'd1;a=4'b0001;b=4'b0011;
#DELYcode=4'd2;a=4'b1001;b=4'b0011;
#DELYcode=4'd3;a=4'b0011;b=4'b0001;
#DELYcode=4'd3;a=4'b0111;b=4'b1001;
#DELY$finish;
end
initial$monitor($time,,,"code=%ba=%bb=%bc=%b",code,a,b,c);
endmodule
【例6.4】函数
function[7:
0]get0;
input[7:
0]x;
reg[7:
0]count;
integeri;
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语句描述的编码器(不含优先顺序)
modulecode_83(din,dout);
input[7:
0]din;
output[2:
0]dout;
程序文本
-14-
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
assigndout=code(din);//函数调用
endmodule
【例6.6】阶乘运算函数
modulefunct(clk,n,result,reset);
output[31:
0]result;
input[