
verilog课程实验报告
院 系: 电子工程学院
专业班级:
学 号:
姓 名:
2013年 6月 12 日
实验一 异或门设计
1.实验内容
my_or,my_and和my_not门构造一个双输入端的xor门,其功能是计算z=x’y+xy’,其中x和y为输入,z为输出;编写激励模块对x和y的四种输入组合进行测试仿真。
2.实验目的
(1)熟悉Modelsim 软件
(2)掌握Modelsim 软件的编译、仿真方法
(3)熟练运用Modelsim 软件进行HDL 程序设计开发
3.实验步骤
(1)建立工程
(2)添加文件到工程
(3)编译文件
(4)查看编译后的设计单元
(5)加入波形窗口
(6)进行仿真
实验描述如下:
module my_and(a_out,a1,a2);
output a_out;
input a1,a2;
wire s1;
nand(s1,a1,a2);
nand(a_out,s1,1'b1);
endmodule
module my_not(n_out,b);
output n_out;
input b;
nand(n_out,b,1'b1);
endmodule
module my_or(o_out,c1,c2);
output o_out;
input c1,c2;
wire s1,s2;
nand(s1,c1,1'b1);
nand(s2,c2,1'b1);
nand(o_out,s1,s2);
endmodule
module MY_XOR(z,x,y);
output z;
input x,y;
wire a1,a2,n1,n2;
my_not STEP01(n1,x);
my_not STEP02(n2,y);
my_and STEP03(a1,n1,y);
my_and STEP04(a2,n2,x);
my_or STEP05(z,a1,a2);
Endmodule
module stimulus;
reg X,Y;
wire OUTPUT;
MY_XOR xor01(OUTPUT,X,Y);
initial
begin
$monitor($time,"X=%b,Y=%b --- OUTPUT=%b\\n",X,Y,OUTPUT);
end
initial
begin
X = 1'b0; Y = 1'b0;
#5 X = 1'b1; Y = 1'b0;
#5 X = 1'b1; Y = 1'b1;
#5 X = 1'b0; Y = 1'b1;
end
endmodule
实验结果
波形图:
4.实验中遇到的问题及解决方法
(1)缺少begin-end 语句或begin-end 语句不匹配;
(2)过程赋值的左边不声明为寄存器类型;
(3)自定义函数实例化时一定要有函数名。
5.心得体会
过程赋值语句可以建模不同的硬件结构:如果这个条件是时钟的上升沿或下降沿,那么这个硬件模型就是一个触发器;如果这个条件是某一信号的高电平或低电平,那么这个硬通过这次实验,对reg及wire型连线有了更深一步的理解。reg相当于存储单元,wire相当于物理连线。reg表示一定要有触发,没有输入的时候可以保持原来的值,但不直接实际的硬件电路对应。wire表示直通,即输入有变化,输出马上无条件地反映(如与、非门的简单连接)。
两者的区别是:寄存器型数据保持最后一次的赋值,而线型数据需要持续的驱动。wire使用在连续赋值语句中,而reg使用在过程赋值语句中。在连续赋值语句中,表达式右侧的计算结果可以立即更新表达式的左侧。在理解上,相当于一个逻辑之后直接连了一条线,这个逻辑对应于表达式的右侧,而这条线就对应于wire。在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。根据触发条件的不同,件模型就是一个锁存器;如果这个条件是赋值语句右侧任意操作数的变化,那么这个硬件模型就是一个组合逻辑。
实验二 二进制全加器设计
1.实验内容
一位全加器使用乘积项之和的形式可以表示为:
sum=a·b·c_in+a’ ·b·c_in’+a’ ·b’ ·c_in+a·b’ ·c_in’
c_out=a·b+b·c_in+a·c_in
其中a,b和c_in为输入,sum和c_out为输出,只使用与门,或门,非门实现一个一位全加器,写出Verilog描述,是每个门最多只能有四个输入端。编写激励模块对其功能进行检查,并对全部的输入组合输入组合进行测试。
2.实验目的
(1)熟悉Verilog HDL 元件实例化语句的作用
(2)熟悉全加器的工作原理
(3)用Verilog HDL 语言设计一位二进制全加器,并仿真,验证其功能
3. 实验步骤
(1)建立工程
(2)添加文件到工程
(3)编译文件
(4)查看编译后的设计单元
(5)加入波形窗口
(6)进行仿真
实验描述如下:
module fulladd(sum,c_out,a,b,c_in);
output sum,c_out;
input a,b,c_in;
wire s1,s2,s3,s4,a1,b1,c_in1,c1,c2,c3;
and(s1,a,b,c_in);
not(a1,a);
not(b1,b);
not(c_in1,c_in);
and(s2,a1,b,c_in1);
and(s3,a1,b1,c_in);
and(s4,a,b1,c_in1);
and(c1,a,b);
and(c2,b,c_in);
and(c3,a,c_in);
or(sum,s1,s2,s3,s4);
or(c_out,c1,c2,c3);
endmodule
module stimulus;
reg A,B,C_IN;
wire SUM,C_OUT;
fulladd FA1(SUM,C_OUT,A,B,C_IN);
initial
begin
$monitor($time,"A=%b, B=%b,C_IN=%b,---C_OUT=%b,SUM=%b\\n",A,B,C_IN,C_OUT,SUM);
end
initial
begin
A=1'd0;B=1'd0;C_IN=1'b0;
#5 A=1'd0;B=1'd0;C_IN=1'b1;
#5 A=1'd0;B=1'd1;C_IN=1'b0;
#5 A=1'd0;B=1'd1;C_IN=1'b1;
#5 A=1'd1;B=1'd0;C_IN=1'b0;
#5 A=1'd1;B=1'd0;C_IN=1'b1;
#5 A=1'd1;B=1'd1;C_IN=1'b0;
#5 A=1'd1;B=1'd1;C_IN=1'b1;
end
实验结果波形:
4.实验中遇到的问题及解决方法
(1)尝试用保留字作为标识符例如xor;
(2)编译通过,但不能仿真,主要是因为仿真激励没能添加到 work2000或者是某个子函数未能添加进去。这是需要细心检查代码,因为模块编译通过,这里就得特别注意模块的衔接处。
5.心得体会
通过这次实验让我明白,定义端口时要特别注意,输入端口可以由wire/reg驱动,但输入端口只能是wire;输出端口可以使wire/reg类型,输出端口只能驱动wire;若输出端口在过程块中赋值则为reg型,若在过程块外赋值则为net型。用关键词inout声明一个双向端口, inout端口不能声明为reg类型,只能是wire类型。默认信号是wire类型,reg类型要申明。这里所说的默认是指输出信号申明成output时为wire。如果是模块内部信号,必须申明成wire或者reg.对于always语句而言,赋值要申明成reg。连续赋值assign的时候要用wire。
实验三 使用JK触发器设计一个计数器
1.实验内容
一个同步计数器可以使用主从JK触发器来设计。设计一个同步计数器,其逻辑图和JK触发器的逻辑图如书中图所示。清零信号clear低电平有效,输入数据在时钟信号clock的上升沿被锁存,触发器在clock的下降沿输出;当count_enable信号为低电平时停止计数。写出同步计数器的Verilog描述和激励模块,在激励模块中使用clear和count_enable对计数器进行测试,并显示输出计数Q[3:0]。
本次试验有三个模块,分别是JK主从触发器设计模块,计数器设计模块及激励模块。对于JK触发器,共有四个输入端(j,k,clear,clock),两个输出端(q,qbar),根据其实际电路结构做出相应的设计;对于计数器模块,有三个输入端(clear,clock,counter_clock),四个输出(Q[3:0]),使用的是四个JK触发器和门电路组合,采用同步清零和同步脉冲构成四位同步计数器;激励模块中根据技术模块输入端口进行相关赋值以便进行仿真观察;
2.实验目的
(1)熟悉Modelsim 软件
(2)掌握Modelsim 软件的编译、仿真方法
(3)熟练运用Modelsim 软件进行HDL 程序设计开发
3. 实验步骤
(1)建立工程
(2)添加文件到工程
(3)编译文件
(4)查看编译后的设计单元
(5)加入波形窗口
(6)进行仿真
实验描述如下:
JK触发器模块:
module m_c_jkff(q,qbar,J,K,clear,clock);
output q,qbar;
input J,K,clear,clock;
wire a,b,c,d,y,ybar,cbar;
assign cbar=~clock;
assign #1 a=~(J & qbar & clock & clear),
b=~(K & q & clock),
y=~(a & ybar),
ybar=~(y & b & clear),
c=~(y & cbar),
d=~(ybar & cbar);
assign #1 q=~(c & qbar);
assign #1 qbar=~(d & clear & q);
endmodule
计数器模块:
module four_count_ff(Q,clear,clock,count_enable);
output [3:0] Q;
input clear,clock,count_enable;
wire a1,a2,a3;
assign a1=count_enable & Q[0],
a2=a1&Q[1], a3=a2&Q[2];
m_c_jkff m1(Q[0],,count_enable,count_enable,clear,clock);
m_c_jkff m2(Q[1],,a1,a1,clear,clock);
m_c_jkff m3(Q[2],,a2,a2,clear,clock);
m_c_jkff m4(Q[3],,a3,a3,clear,clock);
endmodule
激励模块:
module stimulus;
reg clock,clear,count_enable;
wire [3:0] Q;
initial
$monitor($time,"Count Q = %b Clear = %b",Q[3:0],clear);
four_count_ff f1(Q,clear,clock,count_enable);
initial
begin
clear=1'b0;
count_enable=1'b1;
#10 clear=1'b1;
//#1 count_enable=1'b1;
//#50 clear=1'b0;
//#100 count_enable=1'b0;
//#100 clear=1'b0;
//#50 clear=1'b1;
//#50 count_enable=1'b1;
end
initial
begin
clock=1'b0;
forever #20 clock=~clock;
end
initial
#1000 $finish;
Endmodule
波形图:
4.实验中遇到的问题及解决方法
(1)Always 内没有定时控制导致无限循环
(2)在Verilog HDL的结构描述中,对wire型的连线可以缺省其连线类型说明,但线宽说明不能被省略。如果连线的位宽不是一位,必须显式的说明连线的宽度。通常对端口类型的说明不容易被遗漏,对寄存器类型的说明也比较容易把握,出现最多的是遗漏对带线宽的连线类型的说明。尤其在对电路结构中的内部连线进行描述时,经常发生这样的错误。
5.心得体会
通过这次实验让我明白,整个verilog中是以module为编写基本单元的,module不宜过大,目标是实现一些基本功能即可,module的层次不宜太深,一般3-5层即可,给module划分层次的原则是:实现最基本功能的为底层module ,然后中层是调用这些基本module,实现大的功能,最高层是系统级模块,统筹各大块之间端口连接,时序关系等。
在module内部编写中,最基本块是initial,always,以及assign块(此外还有一些UDP原语,在行为级暂且不谈),其他语句都要包含在这些块里面。这其中,initial块是不可综合语句,可以用来编写testbench,这里面的内容在程序运行时只执行一次;assign语句是在不用寄存器的情况下直接编写组合逻辑。
实验四 八功能算术运算单元
1.实验内容
使用case语句设计八门功能的算术运算单元(ALU),输入信号a,b为4位,功能选择信号select为3位,输出信号out为5位。忽略输出结果中的上溢和下溢。
2.实验目的
(1)熟悉Modelsim 软件
(2)掌握Modelsim 软件的编译、仿真方法
(3)熟练运用Modelsim 软件进行HDL 程序设计开发
3. 实验步骤
(1)建立工程
(2)添加文件到工程
(3)编译文件
(4)查看编译后的设计单元
(5)加入波形窗口
(6)进行仿真
实验描述如下:
module alu(out,a,b,select);
output [4:0] out;
input [3:0] a, b;
input [2:0] select;
reg [4:0] out;
always @(a or b or select)
begin
case (select)
3'b000 : out = a;
3'b001 : out = a+b;
3'b010 : out = a-b;
3'b011 : out = a/b;
3'b100 : out = a%b;
3'b101 : out = a<<1;
3'b110 : out = a>>1;
3'b111 : out = a>b;
default : $display("Invalid ALU control signal");
endcase
end
endmodule
module stimulus;
reg [3:0] A,B;
reg [2:0] SELECT;
wire [4:0] OUT;
initial
$monitor($time," A= %b B= %b SELECT= %b OUT= %b ",A[3:0],B[3:0],SELECT[2:0],OUT[4:0]);
alu alu1(OUT,A,B,SELECT);
initial
begin
A = 4'b0011;B = 4'b1011;SELECT = 3'b000;
repeat(7)
begin
SELECT = #10 3'b001+SELECT;
end
#10 A = 4'b1111;B = 4'b1001;SELECT = 3'b000;
repeat(7)
begin
SELECT = #10 3'b001+SELECT;
end
#10 A = 4'b0000;B = 4'b0000;SELECT = 3'b000;
repeat(7)
begin
SELECT = #10 3'b001+SELECT;
end
#10 A = 4'b1111;B = 4'b1111;SELECT = 3'b000;
repeat(7)
begin
SELECT = #10 3'b001+SELECT;
end
end
endmodule
波形图:
(1)二进制数缺少基’b 也就是说编译器将它们看作是十进制数
(2)“清零信号clear低电平有效,输入数据在时钟信号clock上升沿被锁存,触发器在clock下降沿输出;当count-enable为低电平时停止计数。
5.心得体会
通过这次实验我学会了运用case语句,当一个变量可能取多个值时,用case语句来构成多分支结构。就好像地址译码一样,不同的地址对应执行不同的任务。使用case语句可以替代嵌套的if-else语句,这与C语言中的switch语句相类似。完整的case语句以保留字“case”开始,以保留字“endcase”结束(Verilog不使用大括号来分隔代码段)。为case语句增加default语句是一个很好的习惯,例如在设计有限状态机时,如果当前的状态不满足任何一种情况,则执行default段代码,可以在default段代码中将状态机复位,使其恢复工作,从而保证状态机一直处于可控制的状态。特别要注意:不论是if-else语句还是case语句,如果条件没有覆盖所有可能的取值,且在if-else语句中没有”else”语句,在case语句中没有“default”语句,则可能会将寄存器引入到设计中来,尽管我们希望只是用组合逻辑来实现它。
实验五 八位ALU功能的函数
1.实验内容
设计一个实现八位ALU功能的函数,输入信号a,b为4位,功能选择信号select为3位,输出信号out为5位。忽略输出结果中的上溢和下溢。
2.实验目的
(1)熟悉Modelsim 软件
(2)掌握Modelsim 软件的编译、仿真方法
(3)熟练运用Modelsim 软件进行HDL 程序设计开发
3. 实验步骤
(1)建立工程
(2)添加文件到工程
(3)编译文件
(4)查看编译后的设计单元
(5)加入波形窗口
(6)进行仿真
实验描述如下:
module bit8_ALU(out,a,b,select);
output [4:0] out;
input [3:0] a,b;
input [2:0] select;
reg [4:0] out;
// reg [3:0] a,b;
// reg [2:0] select;
always @(a or b or select)
begin
out = bit8_function(a,b,select);
end
function [4:0] bit8_function;
input [3:0] a,b;
input [2:0] sel;
parameter S0 = 3'b000,
S1 = 3'b001,
S2 = 3'b010,
S3 = 3'b011,
S4 = 3'b100,
S5 = 3'b101,
S6 = 3'b110,
S7 = 3'b111;
begin
case(sel)
S0:bit8_function = a;
S1:bit8_function = a+b;
S2:bit8_function = a-b;
S3:bit8_function = a/b;
S4:bit8_function = a%b;
S5:bit8_function = a<<1;
S6:bit8_function = a>>1;
S7:bit8_function = (a>b);
default : $display("Invalid ALU control signal");
endcase
end
endfunction
endmodule
module stimulus;
reg [3:0] A,B;
reg [2:0] SELECT;
wire [4:0] OUT;
bit8_ALU alu(OUT,A,B,SELECT);
initial
begin
$monitor($time,"A=%b, B=%b, SELECT=%b, --- OUT=%b\\n",A,B,SELECT,OUT);
end
initial
begin
A=4'b0000;B=4'b0000; SELECT=3'b000;
repeat(7)
begin
SELECT = #10 SELECT + 3'b001;
end
#100 A=4'b1111;B=4'b0000; SELECT=3'b000;
repeat(7)
begin
SELECT = #10 SELECT + 3'b001;
end
#100 A=4'b0000;B=4'b1111; SELECT=3'b000;
repeat(7)
begin
SELECT = #10 SELECT + 3'b001;
end
#100 A=4'b0011;B=4'b0011; SELECT=3'b000;
repeat(7)
begin
SELECT = #10 SELECT + 3'b001;
end
#100 A=4'b1111;B=4'b1111; SELECT=3'b000;
repeat(7)
begin
SELECT = #10 SELECT + 3'b001;
end
end
Endmodule
波形图:
(1)二进制数缺少基’b 也就是说编译器将它们看作是十进制数
(2)在事件控制例如@(a or b) 中用逻辑或运算符|| 代替保留字or
5.心得体会
通过这次实验我学会了运用always块,always块是最常用的块,其语法格式是always @(*);其中括号里称为敏感列表,即对于组合逻辑而言,必须是所实现逻辑的所有输入变量,意思是当组合逻辑的每一个变量发生变化,结果立刻发生变化(这与实际情况一致,对于任何组合逻辑,输入变化,输出立刻变化),对于时序逻辑,常为always @(posedge/negedge clk),指在时钟上升沿/下降沿到来时,输出才根据那一时刻的输入来决定输出结果。
实验六 状态自动机
1.实验内容
使用同步有限状态自动机方法设计一个电路,它的引脚in接受一位的输入流。每当检测到模式10101时,输出引脚reset被赋值为高电平引脚。reset引脚以同步方式初始化电路。输入引脚clk 用于给电路提供时针信号。使用身边现有的任何工艺库综合该电路,优化电路,使其达到最快速度。把同样的激励应用到RTL和们级网表上,比较它们的输出。
2.实验目的
(1)熟悉Modelsim 软件
(2)掌握Modelsim 软件的编译、仿真方法
(3)熟练运用Modelsim 软件进行HDL 程序设计开发
3. 实验步骤
(1)建立工程
(2)添加文件到工程
(3)编译文件
(4)查看编译后的设计单元
(5)加入波形窗口
(6)进行仿真
实验描述如下:
module select(in,clk,reset,match);
input in;
input clk;
input reset;
output match;
wire match;
wire [4:0] NEXT_STATE;
reg [4:0] PRES_STATE;
parameter s1=5'b00000;
parameter s2=5'b00001;
parameter s3=5'b00010;
parameter s4=5'b00101;
parameter s5=5'b01010;
parameter s6=5'b10101;
function [5:0] fsm;
input fsm_in;
input [4:0] fsm_PRES_STATE;
reg fsm_match;
reg [4:0] fsm_NEXT_STATE;
begin
case(fsm_PRES_STATE)
s1:
begin
if(fsm_in==1'b1)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s2;
end
else if(fsm_in==1'b0)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s1;
end
end
s2:
begin
if(fsm_in==1'b1)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s2;
end
else if(fsm_in==1'b0)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s3;
end
end
s3:
begin
if(fsm_in==1'b1)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s4;
end
else if(fsm_in==1'b0)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s1;
end
end
s4:
begin
if(fsm_in==1'b1)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s2;
end
else if(fsm_in==1'b0)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s5;
end
end
s5:
begin
if(fsm_in==1'b1)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s6;
end
else if(fsm_in==1'b0)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s1;
end
end
s6:
begin
if(fsm_in==1'b1)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s2;
end
else if(fsm_in==1'b0)
begin
fsm_match=1'b0;
fsm_NEXT_STATE=s5;
end
end
endcase
fsm={fsm_match,fsm_NEXT_STATE};
end
endfunction
assign {match,NEXT_STATE}=fsm(in,PRES_STATE);
always @(posedge clk)
begin
if (reset==1'b1)
PRES_STATE<=s1;
else
PRES_STATE<=NEXT_STATE;
end
endmodule
module stimulus;
reg clk;
reg in;
reg reset;
wire match;
select se(in,clk,reset,match);
initial
begin
clk=0;
in=0;
reset=1;
#100 reset=0;
#30 in=1;
#40 in=1;
#40 in=0;
#40 in=1;
#40 in=0;
#40 in=1;
#40 in=1;
#40 in=1;
#40 in=0;
#40 in=0;
#40 in=1;
#40 in=1;
#40 in=0;
#40 in=0;
#40 in=1;
#40 in=0;
#40 in=1;
#40 in=0;
#40 in=1;
#40 in=1;
#40 in=1;
#50 $finish;
end
always
begin
#20 clk=~clk;
end
endmodule
波形图:
(1)用过程连续赋值代替连续赋值即assign 在错误的地方使用
(2)尝试在任务或函数名字后面的方括号中定义任务和函数参数
5.心得体会
通过这次实验我学习了有限状态机,有限状态机(Finite State Machine,FSM)在数字系统设计中应用十分广泛。根据状态机的输出是否与输入有关,可将状态机分为两大类:摩尔(Moore)型状态机和米莉 (Mealy)型状态机。Moore型状态机的输出仅与现态有关;Mealy型状态机的输出不仅与现态有关,而且和输入也有关。图1是有限状态机的一般结构图,它主要包括三个部分,其中组合逻辑部分包括状态译码器和输出译码器,状态译码器确定状态机的下一个状态,输出译码器确定状态机的输出,状态寄存器属于时序逻辑部分,用来存储状态机的内部状态。
