北航电子电路设计训练数字部分实验报告.docx
《北航电子电路设计训练数字部分实验报告.docx》由会员分享,可在线阅读,更多相关《北航电子电路设计训练数字部分实验报告.docx(44页珍藏版)》请在冰点文库上搜索。
北航电子电路设计训练数字部分实验报告
2014-2015-2-G02A3050-1
电子电路设计训练(数字EDA部分)
实验报告
(2015年6月24日)
仪器科学与光电工程学院
实验一、简单组合逻辑和简单时序逻辑
1.1实验任务1——简单组合逻辑
1.1.1实验要求
实验代码提供的是一个可综合的数据比较器。
从语句中可以看出是比较数据a,b的结果,结果相同输出1,否则输出0.测试模块用于检测模块设计是否正确,给出输入信号,观察模块的内部信号和输出信号以确定设计是否正确。
练习题:
设计一个字节(8位)的比较器,比较两个字节的大小,如a[7:
0]大于b[7:
0]则输出高电平,否则输出低电平。
1.1.2模块的核心逻辑设计
//compare.v第一种实现方式:
assign
modulecompare(equal,a,b);
inputa,b;//a、b为输入
outputequal;//equal为输出
assignequal=(a==b)?
1:
0;
//a=b时输出为1,否则输出为0
endmodule
//compare.v第二种实现方式:
always
modulecompare(equal,a,b);
inputa,b;
outputequal;
regequal;
always@(aorb)
//a或b的值发生变化时执行判断
if(a==b)
equal=1;
else
equal=0;
endmodule
//练习题compare_8.v:
modulecompare_8(a,b,out);
//与练习一的不同只在于a、b要定义为8位
input[7:
0]a;
input[7:
0]b;
outputout;
regout;
always@(aorb)
begin
if(a>b)
out=1;
else
out=0;
end
endmodule
1.1.3测试程序的核心逻辑设计
//compare_test.v
`timescale1ns/1ns
//仿真时间及步长设置
…
initial
begin
a=0;
b=0;
//a、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));
//compare模块实例化
//compare_8_test.v
initial//变量初始化
begin
a=0;
b=0;
clock=0;
end
always#50clock=~clock;
//产生周期为100ns时钟信号
always@(posedgeclock)
//每次时钟上升沿到来,用随机数给a、b赋值,观察输出的变化
begin
/a={$random}%8;b={$random}%8;
//产生8位随机二进制数字
end
1.1.4仿真实验关键结果及其解释
练习一的仿真结果如图1所示。
可以看到,随着a和b的值变化,输出值按照要求变化,并且在功能仿真中没有延迟,同步变化。
图1练习一仿真波形
练习题的仿真结果如下图所示。
可以看到,每次时钟上升沿到来时a、b的值发生变化,输出随之变化。
图2练习题仿真结果
1.2实验任务2——简单时序逻辑
1.2.1实验要求
设计二分之一分频器的可综合模型。
1.2.2模块的核心逻辑设计
always@(posedgeclk_in)
begin
if(!
reset)//reset为同步复位输入端
clk_out=0;
else
clk_out=~clk_out;//每次输入时钟的上升沿让输出时钟反转,实现二分频
end
1.2.3测试程序的核心逻辑设计
`defineclk_cycle50//宏定义
…
always#`clk_cycleclk=~clk;//产生输入时钟
initial
begin
clk=0;
reset=1;
#10reset=0;
#110reset=1;//将初始时的不定态进行复位,开始分频输出。
#100000$stop;//停止仿真
end
1.2.4仿真实验关键结果及其解释
仿真结果如下图所示。
可以看到,输出时钟clk_out的周期是输入时钟clk的二倍,即实现了二分频。
图3练习二仿真结果
1.3实验小结
本次实验中,我们第一次学习使用Modelsim软件,对课上所学的Verilog语法进行了巩固和提高,参考书中给出的例子自己进行了基本组合电路和时序电路的设计,也学会了编写简单的测试模块对系统进行较为全面的测试。
实验二、条件语句和always过程块
2.1实验任务1——条件语句实现计数分频时序电路
2.1.1实验要求
通过定义计数器,利用条件语句,获得一个1/20分频器,将10MHz的时钟分频为500KHz。
练习题:
利用10MHz的时钟设计一个单周期形状的周期波形。
2.1.2模块的核心逻辑设计
//练习三fdivision.v:
always@(posedgeF10M)
if(!
reset)//同步复位端
begin
F500K<=0;
j<=0;
end
else
begin
if(j==9)
/*用j实现计数,从0开始每个时钟上升沿自增1,增加到9后输出反转,实现20分频。
这里书中是增加到19后反转,这样得到的信号周期是原信号的1/40,并不是1/20,故在实验中进行了修改*/
begin
j<=0;
F500K=~F500K;
end
else
j<=j+1;
end
//练习题:
wave.v
always@(posedgeF10M)
if(!
reset)begin
outwave<=0;j<=0;
end
elsebegin
if(j==200)begin
//从0开始累加到200后输出置1
j<=j+1;
outwave<=1;
end
elseif(j==300)begin
//累加到300时输出置0
j<=j+1;
outwave<=0;
end
elseif(j==500)begin
//累加到500时,完成一个周期,计数器清零
j<=0;
outwave<=0;
end
else
j<=j+1;
end
2.1.3测试程序的核心逻辑设计
//fdivision_test.v
always#`clkF10M=~F10M;//产生输入时钟信号
initial
begin
reset=1;
F10M=0;
#100reset=0;
#100reset=1;
#10000$stop;
end
fdivisionfdivision(.reset(reset),.F10M(F10M),.F500K(F500K));//模块实例化
//wave_test.v
always#`clkF10M=~F10M;//产生输入时钟
initial
begin
reset=1;
F10M=0;
#100reset=0;
#100reset=1;
#1000000$stop;
end
2.1.4仿真实验关键结果及其解释
练习三的仿真结果如下图所示。
可以看到,输出时钟F500K的周期是输入F10M的1/20,符合题目要求,说明对书中代码的修改是正确的。
图4练习三仿真结果
练习题的功能仿真结果如下图所示。
可以看到,最终输出的波形周期为50us,符合题目要求。
图5练习题仿真结果
2.2实验任务2——always块实现较复杂的组合逻辑电路
2.2.1实验要求
设计一个简单的指令译码电路。
通过判断指令,对输入数据执行相应的操作,包括加减与或求反,需要做出及时的反应。
练习题:
运用always块设计一个8路数据选择器。
2.2.2模块的核心逻辑设计
//练习五:
alu.v
`defineplus3'd0
`defineminus3'd1
`defineband3'd2
`definebor3'd3
`defineunegate3'd4//宏定义不同的操作方式
…
always@(opcodeoraorb)
begin
case(opcode)
//判断操作方式,对操作数a、b进行相应的操作
`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
//练习题:
mux_8.v
always@(addrorin1orin2orin3orin4orin5orin6orin7orin0orncs)
//in0至in7为8个数据输入端,三维寄存器addr为选择输入,用case分支完成选择
begin
if(!
ncs)
case(addr)
3'b000:
mout=in0;
3'b001:
mout=in1;
3'b010:
mout=in2;
3'b011:
mout=in3;
3'b100:
mout=in4;
3'b101:
mout=in5;
3'b110:
mout=in6;
3'b111:
mout=in7;
endcase
else
mout=0;
end
2.2.3测试程序的核心逻辑设计
//alu_test.v
parametert=5;
initial
begin
a={$random}%256;
b={$random}%256;
opcode=3'h0;
repeat(t)
begin
#100a={$random}%256;
b={$random}%256;
//给a、b随机赋值
opcode=opcode+1;
end
#100$stop;
end
//mux_8_test.v
initial
begin
ncs=0;
in0={$random}%16;
…
in7={$random}%16;
addr=3'b000;
repeat(9)
//用随机数每次给数据输入端赋不同的值,观察输出结果
begin
#10in0={$random}%16;…in7={$random}%16;
addr=addr+1;
end
#10$stop;
end
2.2.4仿真实验关键结果及其解释
练习五仿真结果如下图所示,可以看到操作数取0、1、2、3、4时,分别完成了加、减、与、或、求反操作。
图6练习五仿真结果
练习题仿真结果如下图所示。
从图中看出,addr取不同值时,输出mout分别等于不同输入端的值,说明仿真结果是正确的。
图7练习题仿真结果
2.3实验小结
本次实验中比第一次更为复杂,有更多需要自己编程实现的部分,并且书中也有一些错误的地方需要修改,因此我们使用Verilog进行开发的能力进一步增强,也学会了if、case条件分支的使用以及always块在较复杂的组合逻辑电路中的应用。
实验三、赋值、函数和任务
3.1实验任务1——阻塞赋值与非阻塞赋值的区别
3.1.1实验要求
通过实验,掌握阻塞赋值和非阻塞赋值的区别,了解两者的不同使用场合。
3.1.2模块的核心逻辑设计
//练习四blocking.v
moduleblocking(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
//练习四练习题blocking1.v
moduleblocking1(clk,a,b,c);
output[3:
0]b,c;
input[3:
0]a;
inputclk;
reg[3:
0]b,c;
always@(posedgeclk)
begin
c=b;
b=a;
$display("Blocking1:
a=%d,b=%d,c=%d.",a,b,c);
end
endmodule
//练习四练习题blocking2.v
moduleblocking2(clk,a,b,c);
output[3:
0]b,c;
input[3:
0]a;
inputclk;
reg[3:
0]b,c;
always@(posedgeclk)b=a;
always@(posedgeclk)c=b;
endmodule
3.1.3测试程序的核心逻辑设计
//compare_Top.v
`timescale1ns/100ps
modulecompare_Top;
wire[3:
0]b1,c1,b2,c2,b3,c3,b4,c4;
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);
blocking1blocking1(clk,a,b3,c3);
blocking2blocking2(clk,a,b4,c4);
endmodule
3.1.4仿真实验关键结果及其解释
图8练习四仿真结果
仿真图中a对应输入,b1、c1对应blocking.v的模块逻辑输出,b1=c1,可以看出在时序逻辑中使用阻塞赋值有可能会导致输出逻辑结果不正确。
而在blocking1中,改变了两者的赋值顺序,就可以实现和non_blocking.v一样的效果。
Blocking2.v中使用多个时钟,在无优化的仿真中,逻辑输出也有错误。
3.2实验任务2——在VerilogHDL中使用函数
3.2.1实验要求
利用一个函数调用的实例,采用同步时钟触发运算的执行,每个clk时钟周期前都会执行一次运算,并在测试模块中,通过调用系统任务$display及在时钟下降沿显示每次计算的结果。
3.2.2模块的核心逻辑设计
//练习六tryfunct.v
moduletryfunct(clk,n,result,reset);
output[31:
0]result;
input[3:
0]n;
inputreset,clk;
reg[31:
0]result;
always@(posedgeclk)
begin
if(!
resetmoduletryfunct(clk,n,result,reset);
output[31:
0]result;
input[3:
0]n;
inputreset,clk;
reg[31:
0]result;
always@(posedgeclk)
begin
if(!
reset)
result<=0;
else
begin
result<=n*factorial(n)/((n*2)+1);
end
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
endfunction
endmodule
)
result<=0;
else
begin
result<=n*factorial(n)/((n*2)+1);
end
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
endfunction
endmodule
//练习六练习题controlfunc.v
modulecontrolfunc(clk,n,result,reset,a);
output[7:
0]result;
input[3:
0]n;
input[1:
0]a;
inputreset,clk;
reg[7:
0]result;
always@(posedgeclkora)
begin
if(!
reset)result<=0;
else
begin
case(a)
2'b00:
result=1;
2'b01:
result=factorial(n);
2'b10:
result=pf(n);
2'b11:
result=lf(n);
endcase
end
end
function[7:
0]factorial;
input[3:
0]operand;
reg[3:
0]index;
begin
factorial=(operand<6&&operand>=0)?
1:
0;
for(index=2;index<=operand;index=index+1)
factorial=index*factorial;
end
endfunction
function[7:
0]pf;
input[3:
0]operand;
reg[3:
0]index;
begin
pf=operand*operand;
end
endfunction
function[7:
0]lf;
input[3:
0]operand;
reg[3:
0]index;
begin
lf=operand*operand*operand;
end
endfunction
endmodule
3.2.3测试程序的核心逻辑设计
//练习六tryfuctTop.v
`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;
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
//练习六练习题test.v
`include"./controlfunc.v"
`timescale1us/1ns
`defineclk_cycle50
moduletest;
reg[3:
0]n;
reg[1:
0]a;
regreset,clk;
wire[7:
0]result;
parametert=16;
initial
begin
clk=0;
n=0;
reset=1;
a=2'b0;
#10reset=0;
#50reset=1;
repeat(t)
begin
#200a={$random}%3;
#200n={$random}%15;
end
#100$stop;
end
always#`clk_cycleclk=~clk;
controlfuncm(.clk(clk),.n(n),.result(result),.reset(reset),.a(a));
endmodule
3.2.4仿真实验关键结果及其解释
//练习六仿真结果
图9练习六仿真结果
仿真结果利用十进制表示,模块调用函数来完成输入值n的阶乘,之后输出n*n!
/(n*2+1)的整数部分,机result值。
//实验六练习题
图10练习六