Verilog实验报告.docx
《Verilog实验报告.docx》由会员分享,可在线阅读,更多相关《Verilog实验报告.docx(31页珍藏版)》请在冰豆网上搜索。
Verilog实验报告
2014-2015-2-G02A3050-1
电子电路设计训练(数字EDA部分)
实验报告
(2015年5月20日)
教学班
学号
组长
签名
成绩
自动化科学与电气工程学院
实验一、简单组合逻辑和简单时序逻辑
1.1实验任务1——简单组合逻辑
1.1.1实验要求
(1)设计一个两位数据比较器,比较两个数据a和b。
若两数据相同,则给出结果1,否则给出结果0。
(2)设计一个字节(8位)的比较器,比较两个字节a[7:
0]和b[7:
0]的大小。
若a大于b,则输出高电平,否则输出低电平。
1.1.2模块的核心逻辑设计
(1)两位数据比较器
assignequal=(a==b)?
1:
0;//用连续赋值语句assign对结果equal赋值,a=b时,equal输出为1,否则为0
(2)字节数据比较器
assignres=(a>b)?
1:
0;//用连续语句assign对结果equal赋值,a>b时equal输出为1,否则输出为0
1.1.3测试程序的核心逻辑设计
(1)两位数据比较器
always#50clock=~clock;//产生周期性跳变的时钟,50个时间单位跳变一次
always(negedgeclock)//always后的语句表示时序控制,每次时钟下降沿时刻产生不同的a和b
begin
a={$random}%2;
b={$random}%2;//每次随机产生a和b
end
initial
begin#100000000$stop;end//系统任务,暂停仿真以观察波形
(2)字节数据比较器
a={$random}%256;
b={$random}%256;//a和b从0~255共256个数中随机产生,即可生成8位字节数据
1.1.4仿真实验关键结果及其解释
(1)两位数据比较器
图1两位数据比较器波形图
如图1所示,a和b相同时equal输出为高电平,否则输出低电平。
(2)字节数据比较器
图2字节数据比较器波形图
如图2所示,a>b时,res输出高电平,否则res输出低电平。
1.2实验任务2——简单时序逻辑
1.2.1实验要求
设计一个分频器,将时钟波形二分频。
1.2.2模块的核心逻辑设计
always(posedgeclk_in)//always语句后表示时序控制,每次clk_in时钟上升沿时刻进行动作
begin
if(!
reset)clk_out=0;//reset信号为低电平时,输出清零
elseclk_out=~clk_out;//reset为高电平时,输出时钟clk_out在输入时钟clk_in的上升沿时刻翻转
end
1.2.3测试程序的核心逻辑设计
always#`clk_cycleclk=~clk;//产生输入时钟
initial
begin
clk=0;
reset=1;
#10reset=0;//reset给低电平,输出清零
#110reset=1;//reset复位
#100000$stop;//系统任务,暂停仿真以便观察波形
end
1.2.4仿真实验关键结果及其解释
图3二分频器的波形图
如图3所示,输入时钟clk被二分频输出。
1.3实验小结
通过实验一,我掌握了如下容:
1)assign连续赋值语句的使用。
2)always,initial块的使用。
3)reg,wire等数据类型的适用围
4)调用被测试模块的方法
实验二、条件语句和always过程块
2.1实验任务1——利用条件语句实现计数分频时序电路
2.1.1实验要求
(1)设计20分频计数器,将10MHz的时钟分频为500kHz的时钟。
(2)利用10MHz的时钟,设计一个给定单周期形状的周期波形。
2.1.2模块的核心逻辑设计
(1)20分频计数器
begin
if(j==9)//对计数器进行判断,计十个数翻转一次,则一个周期计20个数,即实现20分频
begin
j<=0;//输出时钟翻转的同时计数器置零
F500K<=~F500K;
end
else
j<=j+1;//若还没计到十个数,继续计数
end
(2)给定单周期形状的波形
begin
if(j<=20)
begin
FDIV<=0;
j<=j+1;//前20个输入时钟周期,计数器计数,但输出不跳变
end
elseif((j>20)&&(j<=30))
begin
FDIV<=1;
j<=j+1;//中间10个时钟周期输出跳变成高电平,保持计数
end
elseif((j>30)&&(j<=50))
begin
FDIV<=0;
j<=j+1;//后20个时钟周期输出跳变成低电平,保持计数
end
else
j<=0;//计数器清零
end
2.1.3测试程序的核心逻辑设计
(1)20分频计数器
always#`clk_cycleF10M_clk=~F10M_clk;//产生输入的10MHz时钟
initial
begin
RESET=1;
F10M_clk=0;
#100RESET=0;//reset给低电平,输出清零
#100RESET=1;//reset复位
#10000$stop;//系统任务,暂停仿真以便观察波形
end
(2)给定单周期形状的波形
begin
RESET=1;
F10M_clk=0;
#100RESET=0;
#100RESET=1;
#100000$stop;
end//与
(1)一致
2.1.4仿真实验关键结果及其解释
(1)20分频计数器
图420分频计数器波形图
如图4所示,10MHz的时钟F10M被20分频成500kHz的时钟F500k。
(2)给定单周期形状的波形
图5给定单周期形状的波形图
如图5所示,生成了题目要求形状的周期波形图。
2.2实验任务2——用always块实现较复杂的组合逻辑电路
2.2.1实验要求
(1)设计一个指令译码电路,对输入数据执行相应的操作,包括加、减、与、或和求反。
(2)运用always块设计一个8路数据选择器。
要求:
每路输入数据与输出数据均为4位2进制数,当选择开关(至少3位)或输入数据发生变化时,输出数据也相应变化。
2.2.2模块的核心逻辑设计
(1)指令译码电路
always(opcodeoraorb)//电平敏感的always块,当输入数据a,b或控制信号opcode变化时,输出发生变化
begin
case(opcode)
`plus:
out=a+b;//控制信号为'plus时,输出等于a+b
`minus:
out=a-b;//控制信号为'minus时,输出等于a-b
`band:
out=a&b;//控制信号为'band时,输出等于a&b
`bor:
out=a|b;//控制信号为'bor时,输出等于a|b
`unegate:
out=~a;//控制信号为'unegate时,输出等于~a
default:
out=8'hx;//未收到指令时,输出任意态
endcase
(2)8路数据选择器
always(ctlora0ora1ora2ora3ora4ora5ora6ora7)//电平敏感模块,控制信号ctl或输入a0~a7变化时,输出发生变化
begin
case(ctl)
`ctl0:
out=a0;
`ctl1:
out=a1;
`ctl2:
out=a2;
`ctl3:
out=a3;
`ctl4:
out=a4;
`ctl5:
out=a5;
`ctl6:
out=a6;
`ctl7:
out=a7;//控制端为ctl0~ctl7对应输出a0~a7
default:
out=4'dx;//未收到指令时,输出任意态
endcase
2.2.3测试程序的核心逻辑设计
(1)指令译码电路
begin
a={$random}%256;//从0~255共256个数中随机生成一个数作为输入a
b={$random}%256;//从0~255共256个数中随机生成一个数作为输入b
opcode=3'h0;//控制信号设为初值0,即'plus,求和
repeat(times)//repeat循环语句使控制及输入信号重复变化
begin
#100a={$random}%256;
b={$random}%256;
opcode=opcode+1;//每一时钟到来时,输入a,b改变一随机数,控制信号+1
end
#100$stop;//系统任务,暂停仿真以观察输出波形
end
(2)8路数据选择器
begin
a0={$random}%16;
a1={$random}%16;
a2={$random}%16;
a3={$random}%16;
a4={$random}%16;
a5={$random}%16;
a6={$random}%16;
a7={$random}%16;//从0~15中随机生成输入a0~a7
ctl=3'd0;//控制端置ctl0
repeat(times)//repeat语句重复改变输入
begin
#100a0={$random}%16;
a1={$random}%16;
a2={$random}%16;
a3={$random}%16;
a4={$random}%16;
a5={$random}%16;
a6={$random}%16;
a7={$random}%16;//随机生成a0~a7
ctl=ctl+1;//控制端每次加1
end
#100$stop;
end
2.2.4仿真实验关键结果及其解释
(1)指令译码电路
图6指令译码电路波形
指令译码电路输出波形如图所示。
控制信号opcode为0时,输出为a+b;控制信号opcode为1时,输出为a-b;......以此类推。
(2)8路数据选择器
图78选1数据选择器波形图
8路数据选择器输出波形如图7所示,控制端ctl为0~7时对应输出a0~a7。
2.3实验小结
通过实验二,我掌握了如下容:
1)if...else条件语句的使用。
2)case条件语句的使用
实验三、赋值、函数和任务
3.1实验任务1——阻塞赋值与非阻塞赋值的区别
3.1.1实验要求
本实验中两个模块"blocking"和"non_blocking"分别采用阻塞赋值和非阻塞赋值语句,从实验结果比较他们的区别。
3.1.2模块的核心逻辑设计
(1)阻塞赋值
always(posedgeclk)
begin
b=a;
c=b;//阻塞赋值,a赋给b,b赋给c
$display("Blocking:
a=%d,b=%d,c=%d.",a,b,c);//在Transcript窗口中显示赋值后a,b,c的值
end
(2)非阻塞赋值
always(posedgeclk)
begin
b<=a;
c<=b;//非阻塞赋值,a赋给b,b赋给c
$display("Non_Blocking:
a=%d,b=%d,c=%d.",a,b,c);//在Transcript窗口中显示赋值后a,b,c的值
end
(3)改变阻塞赋值程序的写法,再比较二者的区别(测试程序仅改变调用的阻塞赋值模块)
always(posedgeclk)
begin
c=b;
b=a;//改变阻塞赋值的顺序,b赋给c,a赋给b
$display("Blocking:
a=%d,b=%d,c=%d.",a,b,c);
end
(3)再改变阻塞赋值程序的写法,比较二者的区别(测试程序仅改变调用的阻塞赋值模块)
always(posedgeclk)b=a;
always(posedgeclk)c=b;
3.1.3测试程序的核心逻辑设计
将阻塞与非阻塞赋值模块用同一测试程序测试,比较其输出的不同。
begin
a=4'h3;
$display("____________");
#100a=4'h7;
$display("____________");
#100a=4'hf;
$display("____________");
#100a=4'ha;
$display("____________");
#100a=4'h2;
$display("____________");
#100$display("___________");//每隔100个时间单位改变一次输入a的值,并显示输出
$stop;
end
blockingblocking(clk,a,b1,c1);//阻塞赋值输出用b1,c1表示
non_blockingnon_blocking(clk,a,b2,c2);//非阻塞赋值输出用b2,c2表示
3.1.4仿真实验关键结果及其解释
(1)阻塞赋值写法1
图8阻塞与非阻塞赋值比较波形图
图9阻塞与非阻塞赋值输出结果
如图8所示,b1,c1为阻塞赋值输出,输入a的值改变时,输出b的值随之改变,同时b的值赋给c,即赋值语句执行完后输出b,c值立即改变,然后块才结束。
b2,c2为非阻塞赋值输出,赋值语句之后输出b,c的值并不立即改变,而是在块结束后才进行赋值操作,当下一时钟上升沿到来时,上一个a值才赋给b,同时上一b值赋给c。
以上即阻塞与非阻塞赋值的区别。
a和b的输出结果如图9所示。
(2)阻塞赋值写法2
图10阻塞赋值程序变形1波形图
图11阻塞赋值程序变形1输出结果
改变阻塞赋值程序后的波形图如图10所示,可见将b=a,c=b的顺序调换之后,阻塞赋值程序先将上一次时钟上升沿时b的值赋给c,再将这一次时钟上升沿时a的值赋给b,即b与a同时变化但c的值是上一个b值。
在波形图上看,由于输入a的变化时刻对应的是时钟下降沿,而输出要在下一时钟上升沿才能显示,故阻塞与非阻塞输出c在波形图上看是一致的,实际上在时钟下降沿a发生变化时,阻塞输出c的值已经发生变化。
输出结果如图11
(3)阻塞赋值写法3
图12阻塞赋值程序变形2波形图
图13阻塞赋值程序变形2输出结果
阻塞赋值程序变形2的输出波形与结果如图12、图13所示。
由于两个阻塞操作用同一个时钟沿触发,执行顺序是不确定的。
3.2实验任务2——在VerilogHDL中使用函数
3.2.1实验要求
(1)设计程序实现函数调用
(2)设计一个带控制端的逻辑运算电路,分别完成正整数的平方、立方和最大数为5的阶乘运算。
3.2.2模块的核心逻辑设计
(1)设计程序实现函数调用
always(posedgeclk)//clk上升沿触发同步运算
begin
if(!
reset)
result<=0;//reset为低时复位
else
begin
result<=n*factorial(n)/((n*2)+1);//调用factorial函数,verilog在整数除法运算结果中不考虑余数
end
end
function[31:
0]factorial;//函数定义,返回一个32位的数
input[3:
0]operand;//输入一个4位操作数
reg[3:
0]index;//函数部计数用中间变量
begin
factorial=operand?
1:
0;//操作数为0时函数输出为0,否则为1
for(index=2;index<=operand;index=index+1)
factorial=index*factorial;//表示阶乘的迭代运算
end
endfunction
(2)带控制端的逻辑运算电路
always(posedgeclk)
begin
if(!
reset)
result<=0;
else
begin
if(sel==0)result<=n*n;//控制端输入sel=0时,执行平方操作
elseif(sel==1)result<=n*n*n;//控制端输入sel=1时,执行立方操作
elseif(sel==2&&n<=5)result<=factorial(n);//控制端输入sel=2且输入n小于等于5时,计算n!
elseresult<=factorial(5);//否则计算5!
end
end
function[31:
0]factorial;//函数定义,返回一个32位的数
input[3:
0]operand;//输入一个4位操作数
reg[3:
0]index;//函数部计数用中间变量
begin
factorial=operand?
1:
0;//操作数为0时函数输出为0,否则为1
for(index=2;index<=operand;index=index+1)
factorial=index*factorial;//表示阶乘的迭代运算
end
3.2.3测试程序的核心逻辑设计
(1)设计程序实现函数调用
initial
begin
clk=0;
n=0;
reset=1;
#100reset=0;//产生复位信号的负跳变沿
#100reset=1;//复位信号恢复高电平后输入n
for(i=0;i<=15;i=i+1)
begin
#200n=i;//用循环结构,每隔200个时钟周期改变一次输入n的值
end
#100$stop;
end
(2)带控制端的逻辑运算电路
begin
clk=0;
n=0;
reset=1;
#100reset=0;//产生复位信号的负跳变沿
#100reset=1;//复位信号恢复高电平后输入n
for(i=0;i<=15;i=i+1)
begin
#200sel={$random}%3;
n={$random}%16;//用循环结构,每隔200个时钟周期改变一次控制端sel和输入n的值,n从0~15中随机生成
end
#100$stop;
end
3.2.4仿真实验关键结果及其解释
(1)设计程序实现函数调用
图14函数调用输出结果波形图
调用函数实现的运算输出结果波形如图14所示。
通过调用函数实现了
的结果输出。
(由于输入n,i为4位二进制数,计算机默认为补码形式,若以十进制显示,9~15将显示负值,为避免混乱,输入用二进制显示)。
(2)带控制端的逻辑运算电路
图15带控制端的逻辑运算电路输出结果波形图
逻辑运算电路输出结果波形如图15所示。
从图中可见,输入n=4,控制端sel=2,输出result=4!
=24;输入n=11,控制端sel=1,输出
;输入n=13,控制端sel=2,输出result=5!
=120;输入n=4,控制端sel=0,输出
。
3.3实验任务3——在VerilogHDL中使用任务
3.3.1实验要求
使用任务设计4个4位并行输入数的排序组合逻辑。
3.3.2模块的核心逻辑设计
always(aorborcord)
begin
{va,vb,vc,vd}={a,b,c,d};
rank2(va,vb);
rank2(va,vc);
rank2(va,vd);
rank2(vb,vc);
rank2(vb,vd);
rank2(vc,vd);
{ra,rb,rc,rd}={va,vb,vc,vd};//用选择排序法排序
end
taskrank2;//执行排序算法的任务
inout[3:
0]x,y;
reg[3:
0]tmp;
if(x>y)
begin
tmp=x;
x=y;
y=tmp;//x与y变量容互换,要求顺序执行,采用阻塞赋值方式
end
endtask
(实验指导书上采用快速排序算法,我对快速排序不熟悉,故采用选择排序算法)
3.2.3测试程序的核心逻辑设计
begin
a=0;b=0;c=0;d=0;
repeat(50)
begin
#100a={$random}%15;
b={$random}%15;
c={$random}%15;
d={$random}%15;//随机生成参与排序的数a,b,c,d
end
3.2.4仿真实验关键结果及其解释
图16使用任务进行排序输出波形
使用任务进行排序得到的输出波形如图16所示。
输出以16进制显示,可见排序功能实现正确。
3.3实验小结
通过实验三,我掌握了如下容:
(1)深入理解了阻塞与非阻塞赋值的区别。
(2)掌握了在VerilogHDL中使用函数的方法,进一步熟悉了if...else和case分支结构的使用。
(3)掌握了用repeat语句实现for循环结构的方法。
(4)掌握了在VerilogHDL中使用任务的方法,回顾了排序算法。
实验四、有限状态机
4.1实验任务1——基于状态机的串行数据检测器
4.1.1实验要求
设计一个串行数据监测器。
要:
连续4个或4个以上为1时输出1,其他情况下输出0。
4.1.2模块的核心逻辑设计
always(posedgeclk)
if(!
rst)
state<=Q0;
else
state<=nextstate;//复位端为0时输出状态置零,复位端为1时输出状态始终向下一状态变化
always(stateorx)
case(state)
Q0:
if(x==1)
nextstate=Q1;
else
nextstate=Q0;
Q1:
if(x==1)
nextstate=Q2;
else
nextstate=Q0;
Q2:
if(x==1)
nextstate=Q3;
else
nextstate=Q0;
Q3:
if(x==1)
nextstate=Q4;
else
nextstate=Q0;
Q4:
if(x==1)
nextstate=Q4;
else
nextstat