EDA技术与verilog语言练习题.docx
《EDA技术与verilog语言练习题.docx》由会员分享,可在线阅读,更多相关《EDA技术与verilog语言练习题.docx(20页珍藏版)》请在冰豆网上搜索。
![EDA技术与verilog语言练习题.docx](https://file1.bdocx.com/fileroot1/2023-1/26/23f1d381-1c0e-4c40-915e-2d58accbbc08/23f1d381-1c0e-4c40-915e-2d58accbbc081.gif)
EDA技术与verilog语言练习题
设计示范和上机习题
练习一.简单的组合逻辑设计
〃(方法一):
//文件名compare.v
modulecompare(equal,a,b);
inputa,b;
outputequal;
assignequal=(a==b)?
1:
0;
//a等于b时,equal输出为1;a不等于b时,equal输出为0。
endmodule
//(方法二):
modulecompare(equal,a,b);
inputa,b;
outputequal;
regequal;
always@(aorb)
if(a==b)//a等于b时,equal输出为1;
equal=1;
else//a不等于b时,equal输出为0。
equal=0;〃思考:
如果不写else部分会产生什么逻辑?
endmodule
//
//测试模块源代码(方法之一):
//initial常用于仿真时信号的给出
//包含模块文件。
在有的仿真调试环境中并不需要此语句
//而需要从调试环境的菜单中键入有关模块文件的路径和名称
modulet;rega,b;wireequal;initialbegina=0;b=0;
#100a=0;b=1;
#100a=1;b=1;
#100a=1;b=0;
#100a=0;b=0;
#100$stop;〃系统任务,暂停仿真以便观察仿真波形。
end
comparem(.equal(equal),.a(a),.b(b));〃调用被测试模块t.m
endmodule
//测试模块源代码(方法之二):
'timescale1ns/1ns
'include"./compare.v"
//定义时间单位。
//包含模块文件。
在有的仿真调试环境中并不需要此语句。
//而需要从调试环境的菜单中键入有关模块文件的路径和名称
modulet;rega,b;regclock;wireequal;initialbegina=0;b=0;
//initial常用于仿真时信号的给出。
clock=0;
end
//定义一个时钟变量
always#50clock=~clock;//产生周期性的时钟
always@(posedgeclock)
〃在每次时钟正跳变沿时刻产生不同的a和b
begin
a={$random}%2;
〃每次a是0还是1是随机的。
b={$random}%2;
〃每次b是0还是1是随机的。
end
initial
begin#100000$stop;
end〃系统任务,暂停仿真以便观察仿真波形。
comparem(.equal(equal),.a(a),.b(b));〃调用被测试模块t.m
endmodule
练习二.简单分频时序逻辑电路的设计
modulehalf_clk(reset,clk_in,clk_out);inputclk_in,reset;
outputclk_out;
regclk_out;
always@(posedgeclk_in)begin
if(!
reset)clk_out=0;
elseclk_out=~clk_out;end
endmodule
//测试模块的源代码:
//文件名top.v'timescale1ns/100ps'defineclk_cycle50moduletop;
regclk,reset;wireclk_out;
always#'clk_cycleclk=~clk;//产生测试时钟
initial
begin
clk=0;reset=1;
#10reset=0;
#110reset=1;
#100000$stop;
end
half_clkm0(.reset(reset),.clk_in(clk),.clk_out(clk_out));endmodule
练习三.利用条件语句实现计数分频时序电路
//模块源代码:
//fdivision.v
modulefdivision(RESET,F10M,F500K);
inputF10M,RESET;
outputF500K;
regF500K;
reg[7:
0]j;
always@(posedgeF10M)if(!
RESET)〃低电平复位。
begin
F500K<=0;
j<=0;
end
else
begin
if(j==19)//对计数器进行判断,以确定F500K信号是否反转。
begin
j<=0;
F500K<=~F500K;
end
else
j<=j+1;
end
endmodule
//测试模块源代码:
//fdivision_Top.v
'timescale1ns/100ps
'defineclk_cycle50
moduledivision_Top;
regF10M,RESET;
wireF500K_clk;
always#'clk_cycleF10M_clk=~F10M_clk;
initial
begin
RESET=1;
F10M=0;
#100RESET=0;
#100RESET=1;
#10000$stop;
end
fdivisionfdivision(.RESET(RESET),.F10M(F10M),.F500K(F500K_clk));
endmodule
练习四.阻塞赋值与非阻塞赋值的区别
〃模块源代码:
-
//blocking.vmoduleblocking(clk,a,b,c);
output[3:
0]b,c;
input[3:
0]a;
inputclk;
reg[3:
0]b,c;
always@(posedgeclk)
begin
b=a;
c=b;
$display("Blocking:
a=%d,b=%d,c=%d",a,b,c);end
endmodule
//non_blocking.v-
modulenon_blocking(clk,a,b,c);
output[3:
0]b,c;
input[3:
0]a;
inputclk;
reg[3:
0]b,c;
always@(posedgeclk)begin
b<=a;
c<=b;
$display("Non_Blocking:
a=%d,b=%d,c=%d",a,b,c);end
endmodule
//测试模块源代码:
//compareTop.v
'timescale1ns/100ps
'include"./blocking.v"
'include"./non_blocking.v"
modulecompareTop;
wire[3:
0]b1,c1,b2,c2;
reg[3:
0]a;
regclk;
initial
begin
clk=0;
forever#50clk=~clk;//思考:
如果在本句后还有语句,能否执行?
为什么?
end
initial
begin
a=4'h3;
$display(”");
#100a=4'h7;
$display("");
#100a=4'hf;
$display("");
#100a=4'ha;
$display("");
#100a=4'h2;
$display("");
#100$display("");
$stop;
end
non_blockingnon_blocking(clk,a,b2,c2);
blockingblocking(clk,a,b1,c1);
endmodule
练习五.用always块实现较复杂的组合逻辑电路
//文件名alu.v
'defineplus3'd0
'defineminus3'd1
'defineband3'd2
'definebor3'd3
'defineunegate3'd4
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)
'plus:
out=
:
a+b;
〃加操作。
'minus:
out=
a-b;
〃减操作。
'band:
out
=a&b;
〃求与。
'bor:
out:
=a|b;
//求或。
'unegate:
out=~a;/求反。
default:
out=8'hx;〃未收到指令时,输出任意态。
endcase
end
endmodule
//指令译码器的测试模块源代码:
//alutest.v'timescale1ns/1ns
'include"./alu.v"
modulealutest;
wire[7:
0]out;
reg[7:
0]a,b;
reg[2:
0]opcode;
parametertimes=5;
initial
begin
a={$random}%256;//Givearadomnumberblongsto[0,255].b={$random}%256;//Givearadomnumberblongsto[0,255].opcode=3'h0;
repeat(times)
begin
#100a={$random}%256;//Givearadomnumber.
b={$random}%256;//Givearadomnumber.
opcode=opcode+1;
end
#100$stop;
end
alualu1(out,opcode,a,b);
endmodule
练习六・在VerilogHDL中使用函数
//模块源代码:
//文件名tryfunct.v
moduletryfunct(clk,n,result,reset);output[31:
0]result;
input[3:
0]n;
inputreset,clk;
reg[31:
0]result;
always@(posedgeclk)//clk的上沿触发同步运算。
begin
if(!
reset)//reset为低时复位。
result<=0;
else
begin
result<=n*factorial(n)/((n*2)+1);
end//verilog在整数除法运算结果中不考虑余数
//函数定义,返回的是一个32位的数
//输入只有一个四位的操作数
//函数内部计数用中间变量
//先定义操作数为零时函数的输岀为零,不为零时为
end
function[31:
0]factorial;input[3:
0]operand;reg[3:
0]index;
begin
factorial=operand?
1:
0;
for(index=2;index<=operand;index=index+1)factorial=index*factorial;//表示阶乘的算术迭代运算
end
endfunctionendmodule
//测试模块源代码:
'include"./tryfunct.v"'timescale1ns/100ps'defineclk_cycle50
moduletryfuctTop;
reg[3:
0]n,i;
regreset,clk;
wire[31:
0]result;
initial
begin
clk=0;
n=0;
reset=1;
#100reset=0;〃产生复位信号的负跳沿
#100reset=1;//复位信号恢复高电平后才开始输入n
for(i=0;i<=15;i=i+1)
begin
#200n=i;
end
#100$stop;
end
always#'clk_cycleclk=~clk;
tryfunctm(.clk(clk),.n(n),.result(result),.reset(reset));
endmodule
练习七・在VerilogHDL中使用任务(task)
//模块源代码:
//文件名sort4.v
modulesort4(ra,rb,rc,rd,a,b,c,d);output[3:
0]ra,rb,rc,rd;
input[3:
0]a,b,c,d;
reg[3:
0]ra,rb,rc,rd;
reg[3:
0]va,vb,vc,vd;
always@(aorborcord)begin
{va,vb,vc,vd}={a,b,c,d};
sort2(va,vc);
//va
与vc互换。
sort2(vb,vd);
//vb
与vd互换。
sort2(va,vb);
//va
与vb互换。
sort2(vc,vd);
//vc
与vd互换。
sort2(vb,vc);〃vb与vc互换。
{ra,rb,rc,rd}={va,vb,vc,vd};
end
tasksort2;
inout[3:
0]x,y;
reg[3:
0]tmp;
if(x>y)
begin
tmp=x;//x与y变量的内容互换,要求顺序执行,所以采用阻塞赋值方式。
x=y;
y=tmp;
end
endtask
endmodule
//测试模块源代码:
'timescale1ns/100ps
'include"sort4.v"
moduletask_Top;
reg[3:
0]a,b,c,d;
wire[3:
0]ra,rb,rc,rd;
initial
begin
a=O;b=O;c=O;d=O;
repeat(50)
begin
#100a={$random}%15;
b={$random}%15;
c={$random}%15;
d={$random}%15;
end
#100$stop;
sort4sort4(.a(a),.b(b),.c(c),.d(d),.ra(ra),.rb(rb),.rc(rc),.rd(rd));
endmodule
练习八.利用有限状态机进行时序逻辑的设计
〃模块源代码:
-
//文件名seqdet.v---
moduleseqdet(x,z,clk,rst,state);inputx,clk,rst;
outputz;output[2:
0]state;
reg[2:
0]state;wirez;
A='d1,B='d2,
C='d3,D='d4
E='d5,F='d6,
G='d7;
parameterIDLE='dO,assignz=(state==E&&x==0)?
1:
0;
//当x序列10010最后一个0刚到时刻,时钟沿立刻将状态变为E,此时z应该变为高
always@(posedgeclk)
if(!
rst)
begin
state<=IDLE;
end
else
casex(state)
IDLE:
if(x==1)//第一个码位对,记状态A
begin
state<=A;
end
A:
if(x==0)〃第二个码位对,记状态B
begin
state<=B;
end
B:
if(x==0)〃第三个码位对,记状态C
begin
state<=C;
end
else//第三个码位不对,前功尽弃,记状态为F
begin
state<=F;
end
C:
if(x==1)//第四个码位对
begin
state<=D;
end
else//第四个码位不对,前功尽弃,记状态为G
begin
state<=G;
end
D:
if(x==O)//第五个码位对,记状态E
begin
state<=E;〃此时开始应有z的输出
end
else
〃第五个码位不对,前功尽弃,只有刚进入的1有用,回到第一个码位对状态,记状态A
begin
state<=A;
end
E:
if(x==0)
〃连着前面已经输入的x序列10010考虑,又输入了0码位可以认为第三个码位已对,记状态C
begin
state<=C;
end
else//前功尽弃,只有刚输入的1码位对,记状态为A
begin
state<=A;
end
F:
if(x==1)〃只有刚输入的1码位对,记状态为A
begin
state<=A;
end
else//又有1码位对,记状态为B
begin
state<=B;
end
G:
if(x==1)〃只有刚输入的1码位对,记状态为A
begin
state<=F;
end
default:
state=IDLE;〃缺省状态为初始状态。
endcase
endmodule
//测试模块源代码:
//文件名seqdet.v
'timescale1ns/1ns
'inelude"./seqdet.v"
moduleseqdet_Top;
regclk,rst;
reg[23:
0]data;
wire[2:
0]state;
wire乙x;
assignx=data[23];
always#10clk=~clk;
always@(posedgeclk)
data={data[22:
0],data[23]};〃形成数据向左移环行流,最高位与x连接
initial
begin
clk=0;
rst=1;
#2rst=0;
#30rst=1;
data='b1100_1001_0000_1001_0100;
#500$stop;
end
seqdetm(x,z,clk,rst,state);
endmodule
练习九•利用状态机实现比较复杂的接口设计
//模块源代码:
modulewriting(reset,clk,address,data,sda,ack);inputreset,clk;
input[7:
0]data,address;
outputsda,ack;//sda负责串行数据输出;
//ack是一个对象操作完毕后,模块给出的应答信号reglink_write;//link_write决定何时输出。
reg[3:
0]state;//主状态机的状态字。
reg[4:
0]sh8out_state;//从状态机的状态字。
reg[7:
0]sh8out_buf;//输入数据缓冲。
regfinish_F;//用以判断是否处理完一个操作对象。
regack;
parameter
idle=0,addr_write=1,data_write=2,stop_ack=3;
parameter
bit0=1,bit1=2,bit2=3,bit3=4,bit4=5,bit5=6,bit6=7,bit7=8;
assignsda=link_write?
sh8out_buf[7]:
1'bz;
always@(posedgeclk)
begin
if(!
reset)〃复位。
begin
link_write<=0;//挂起串行单总线
state<=idle;
finish_F<=0;//结束标志清零
sh8out_state<=idle;
ack<=0;
sh8out_buf<=0;
end
else
case(state)
idle:
begin
link_write<=0;〃断开串行单总线
finish_F<=0;
sh8out_state<=idle;
ack<=0;
sh8out_buf<=address;〃并行地址存入寄存器state<=addr_write;//进入下一个状态
end
addr_write:
〃地址的输入。
begin
if(finish_F==O)
beginshift8_out;end//地址的串行输出
else
begin
sh8out_state<=idle;
sh8out_buf<=data;〃并行数据存入寄存器state<=data_write;
finish_F<=0;
end
end
begin
if(finish_F==O)
beginshift8_out;end//数据的串行输出
else
begin
link_write<=0;
state<=stop_ack;
finish_F<=0;
ack<=1;〃向信号源发出应答。
end
end
stop_ack:
//向信号源发出应答结束。
begin
ack<=0;
state<=idle;
end
endcase
end
taskshift8_out;//地址和数据的串行输出。
begin
case(sh8out_state)
idle:
MSB)
begin
link_write<=1;〃连接串行单总线,立即输出地址或数据的最高位(
sh8out_state<=bit7;
end
bit7:
begin
link_write<=1;〃连接串行单总线
sh8out_state<=bit6;
sh8out_buf<=sh8out_buf<<1;〃输出地址或数据的次高位(bit6)end
bit6:
begin
sh8out_state<=bit5;
sh8out_buf<=sh8out_buf<<1;
end
begin
sh8out_state<=bit4;
sh