module lab2_1(
input [3:0]x,
output reg [7:0]seg,
output [7:0]an
assign an=8'b1111_1110;
always@(*)
case(x)
0: seg= 8'b 1100_0000;
1: seg= 8'b 1111_1001;
2:seg= 8'b 1010_0100;
3: seg= 8'b 1011_0000;
4: seg= 8'b 1001_1001;
5: seg= 8'b 1001_0010;
6: seg= 8'b 1000_0010;
7: seg= 8'b 1111_1000;
8: seg= 8'b 1000_0000;
9:seg= 8'b 1001_0000;
default seg=8'bxxxx_xxxx;
endcase
endmodule
修改对应的xdc文件段落,大致如下图:
set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { seg[0] }]; #IO_L24N_T3_A00_D16_14 Sch=ca
set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { seg[1] }]; #IO_25_14 Sch=cb
set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { seg[2] }]; #IO_25_15 Sch=cc
set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { seg[3] }]; #IO_L17P_T2_A26_15 Sch=cd
set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { seg[4] }]; #IO_L13P_T2_MRCC_14 Sch=ce
set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { seg[5] }]; #IO_L19P_T3_A10_D26_14 Sch=cf
set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { seg[6] }]; #IO_L4P_T0_D04_14 Sch=cg
set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { seg[7] }]; #IO_L19N_T3_A21_VREF_15 Sch=dp
set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0]
set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1]
set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2]
set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3]
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4]
set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5]
set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6]
set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7]
将 4 比特的输入转化为相应的 2 位十进制数(BCD码)后输出到 LED 灯(最高位)和最右边的七段数码管(更低位)上。
设计一个能将 4 比特的二进制数 v 转换到它相应的 2 位十进制数,z 和m。由于正确的输入范围是 0 到 15,最高位可以只使用一个 LED 等来显示。下表显示了要求的输出值。下图中给出了设计框图。它包含一个检查 v 值是否大于 9 的比较器(comparator),并使用比较器的输出来控制七段数码管的显示。提示:只要 v 大于二进制的 1001,m3 就会是 0。
Verilog HDL程序是由模块构成的。每个模块的内容都是嵌在module和endmodule两个语句之间。每个模块实现特定的功能。模块可以进行层次嵌套。
每个模块要进行端口定义,并说明输入输出口,然后对模块的功能进行行为逻辑描述。
Verilog HDL程序的书写格式自由,一行可以写几个语句,一个语句也可以分写多行。
除了endmodule语句外,每个语句和数据定义的最后必须有分号。
可以用/…../和//…….对Verilog HDL程序的任何部分作注释。一个好的,有使
用价值的源程序都应当加上必要的注释,以增强程序的可读性和可维护性。
Verilog 模块调用端口的连接规则
在verilog中,所有的端口隐含地声明wire类型;如果输出类型的端口需要保存数值,则必须将其显式地声明为reg数据类型。
不能将input和inout类型的端口声明为reg数据类型,因为reg类型的变量是用于保存数值的,而输入端口只反映与其相连的外部信号的变化。
在verilog中,有两种端口声明风格:
具体端口连接规则
端口连接规则 将一个端口看成由相互链接的两个部分组成,一部分位于模块内部,另一部分位于模块外部。当在一个模块中调用(实例引用)另一个模块时,端口之间的连接必须遵守一些规则。
输入端口:从模块内部来讲,输入端口必须为线网数据类型,从模块外部来看,输入端口可以连接到线网或者reg数据类型的变量。
输出端口:从模块内部来讲,输出端口可以是线网或者reg数据类型,从模块外部来看,输出必须连接到线网类型的变量(显式,隐式),而不能连接到reg类型的变量。
输入/输出端口(必须为wire) 从模块内部来讲,输入/输出端口必须为线网数据类型;从模块外部来看,输入/输出端口也必须连接到线网类型的变量。
打开Vivado,创建一个名为 lab2_2_1 的空白工程。
创建并添加一个 Verilog 模块(命名为 lab2.2)以 v[3:0]为输入,z 和 m[3:0] 作为输出。创建并添加模块,使用数据流结构(dataflow constructs)来完成比较器数据流(comparator_dataflow),lab2 的电路 A 的数据流(lab2_circuitA_dataflow),实例化 2-to-1 多路选择器(Lab1 的),并将它们按上图连接起来。
创建一个包含bcdto7segment_dataflow decoder(你在Lab1 中开发的) 的顶层模块(lab2.1)并提供一个 7 比特的输出 seg0 而不是m。
将与开发板对应的XDF 文件添加到工程中,编辑文件添加相关的端口。将输入 v 赋给 SW3 到 SW0,z 赋给 LED0,seg0 赋给七段数码管显示阴极 CA 到CG,将 an 赋给端口 J17,J18,T9,J14,P14,T14,K2,U13(对于 Nexys4 DDR)或是 U2, U4,V4,W4(对于 Basys3)。
综合(Synthesize)并实现(implement)设计。
生成比特流(bitstream),将它下载到 Basys3 或是 Nexys4 DDR 开发板上,并验证它的功能。
参考代码及讲解
由对应关系:
4'b0000: begin z=0; m=4'b0000; end
4'b0001: begin z=0; m=4'b0001; end
4'b0010: begin z=0; m=4'b0010; end
4'b0011: begin z=0; m=4'b0011; end
4'b0100: begin z=0; m=4'b0100; end
4'b0101: begin z=0; m=4'b0101; end
4'b0110: begin z=1; m=4'b0000; end
4'b0111: begin z=1; m=4'b0001; end
4'b1000: begin z=1; m=4'b0010; end
4'b1001: begin z=1; m=4'b0011; end
4'b1010: begin z=1; m=4'b0100; end
4'b1011: begin z=1; m=4'b0101; end
4'b1100: begin z=1; m=4'b0110; end
4'b1101: begin z=1; m=4'b0111; end
4'b1110: begin z=1; m=4'b1000; end
4'b1111: begin z=1; m=4'b1001; end
endcase
添加我们在lab1中的代码:
在这里选择添加,也可以使用快捷键ALT+A
选择add desgin source 并且选择你的lab1文件source中的代码
在lab2.2函数中写入这个函数,并且实例化它
综上所述,具体的代码如下:
module lab2_2(
input [3:0]v,
output reg z,
output [7:0]seg,
output [7:0]an
reg [3:0]m;
always@(*)
begin
case(v)
4'b0000: begin z=0; m=4'b0000; end
4'b0001: begin z=0; m=4'b0001; end
4'b0010: begin z=0; m=4'b0010; end
4'b0011: begin z=0; m=4'b0011; end
4'b0100: begin z=0; m=4'b0100; end
4'b0101: begin z=0; m=4'b0101; end
4'b0110: begin z=0; m=4'b0110; end
4'b0111: begin z=0; m=4'b0111; end
4'b1000: begin z=0; m=4'b1000; end
4'b1001: begin z=0; m=4'b1001; end
4'b1010: begin z=1; m=4'b0000; end
4'b1011: begin z=1; m=4'b0001; end
4'b1100: begin z=1; m=4'b0010; end
4'b1101: begin z=1; m=4'b0011; end
4'b1110: begin z=1; m=4'b0100; end
4'b1111: begin z=1; m=4'b0101; end
endcase
lab2_1 A(m,seg,an); //A是实例化的名称
endmodule
在你具体在函数中写入调用函数时,会自动生成两个函数之间的调用关系,这是你可以看到lab2_2函数成为了顶层模块。
仅使用数据流级建模创建一个 4 比特波纹进位加法器。
当两个 1 比特的数相加时,它们可能会产生一个 2 比特的输出。比如,1 + 1 = 10(都是二
进制)。当你将三个 1 比特的数相加是,结果也会是 2 比特,比如,1 + 1 = 11。这种简单的操作可以被视为将两个比特与一个更低位的操作的进位输入相加,结果产生一个和与一个进位输出——左边的比特是进位输出,右边的比特是和。下图显示了一个 4 比特的加法器。由于进位是像波纹一样从最低比特位(cin)向最高比特位传递的,这样的加法器也叫波纹进位加法器(待确定)。
打开Vivado 并创建一个名为 lab2.3 的空白工程。
创建并使用数据流级建模添加一个有三个输入(a, b, cin)和两个输出(s 和 cout) 的名为 fulladder_dataflow 的 Verilog module。所有的输入和输出都应该是 1 比特位宽的。
在工程中创建并添加一个有三个输入(a, b, cin)和两个输出(s 和 cout)的 Verilog module(名为 rca_dataflow),实例化全加器(FA)四次,并将它们按所需连接起来。这里的 a,b,和 s 应该是一个 4 比特的向量,cin 和 cout 应该是 1 比特位宽。
对设计进行仿真(行为仿真)80ns 并验证功能。
将与开发板对应的 XDF 文件添加到工程中,编辑文件添加相关的端口。将 SW4 到SW7 赋给 a,将 SW0 到SW3 赋给 b,LED3 到LED0 赋给 s,SW15 赋给 cin,LED15 赋给 cout。
综合(Synthesize)并实现(implement)设计。
参考代码及讲解
首先,我们需要编写一个一位的加法,具体原理请看前面的讲解:
module one_bit_add(
input a,
input b,
input cin,
output s,
output reg cout
assign s=a^b^cin;
always@(*)
begin
if(a&b|a&cin|b&cin)
cout=1;
cout=0;
endmodule
在lab2.3的工程中重复调用这个模块,来实现我们的四位加法器,具体代码如下:
module lab2_3(
input [3:0]a,
input [3:0]b,
output [3:0]s,
input cin,
output cout
wire temp0,temp1,temp2;
one_bit_add A(a[0],b[0],cin,s[0],temp0);
one_bit_add B(a[1],b[1],temp0,s[1],temp1);
one_bit_add C(a[2],b[2],temp1,s[2],temp2);
one_bit_add D(a[3],b[3],temp2,s[3],cout);
endmodule #### 仿真代码 因为对参数中的变量手动一次次修改对于比较大的数字较为麻烦,所以在这里使用了循环语句。
module lab2_3_tb(
reg [3:0]a;
reg [3:0]b;
wire [3:0]s;
reg cin;
wire cout;
integer k;
lab2_3 dut(a,b,s,cin,cout);
initial
begin
a=0; b=0; cin=0;
for(k=0;k<20;k=k+1)
begin
#10 if(k<10)
a=a+1;
b=b+1;
if(k==10)
cin=1;
endmodule
查看仿真代码,确定自己的代码是否正确:
扩展实验内容
扩展实验1
修改 3 中的工程,将 4 比特的输入看作BCD 码完成加法,生成 BCD 码的结果并在 LED0 和最右边的七段数码管上显示出来。使用开关来输入两个 4 比特 BCD 数并用SW15 输入进位。根据需求复用 2 和 3 中开发的模型。使用数据流级建模。
打开Vivado 并创建一个名为 lab2.kuozhan1 的空白工程。
按需求修改 3 中的工程,使之能完成需求的功能并将结果输出到 LED0 和最右边的七段数码管上显示
将与开发板对应的 XDF 文件添加到工程中,编辑文件添加相关的端口。使用开关
SW72-SW0 来给两个 4 比特的 BCD 提供输入,SW15 给进位。
综合(Synthesize)并实现(implement)设计。
生成比特流(bitstream),将它下载到 Basys3 或是 Nexys4 DDR 开发板上,并验证它的功能。
扩展实验2
通过修改 3中的工程并使用数据流级建模创建一个超前进位加法器电路
波纹进位加法器在处理两个很大的数(比如 8 比特,16 比特,32 比特)的加法时会花很长时间运算。为了降低运算时间,可以使用另一个结构,超前进位加法器。它的工作方式是, 基于以下轻轻为每个比特位分别创建两个信号(P 和 G):进位信号是否会从较低比特位传播过来(即至少有一个输入是 1),进位信号是否由此比特位生成(即两个输入均为 1),或者进位信号是否会被此比特位消灭(两个输入均为 0)。P 和 G 生成后,每个比特位的进位信号也生成了。
此处𝑃𝑖 = 𝐴𝑖 + 𝐵𝑖,𝐺𝑖 = 𝐴𝑖𝐵𝑖。在超前进位单元内,𝐶𝑖+1 = 𝐺𝑖 + 𝑃𝑖𝐶𝑖。这个加速是通过使
𝐶𝑖和相应的第i 为一起生成而达到的。
打开Vivado 并打开你在 3 中创建的工程。
按需修改 3 中的工程,来使用超前进位结构完成两个 4 比特的数的加法并将结果输出到 LED 灯上。有由 SW15 提供进位。提示:你只需要将全加器修改为输出𝑃𝑖和
𝐺𝑖,然后创建并添加另一个超前进位(CLA)模块来完成超前进位功能(即输入𝑐0和
𝑝𝑖𝑔𝑖(i = 0 到 3)并输出𝑐4、𝑝𝑔和𝑔𝑔。
修改 XDF 文件来通过 SW3-SW0 提供输入 b,通过 SW7-SW4 提供输入 a,SW15
输入 cin。通过 LED15 输出 cout,LED3-LED0 输出 sum。
综合(Synthesize)并实现(implement)设计。
生成比特流(bitstream),将它下载到 Basys3 或是 Nexys4 DDR 开发板上,并验证它的功能。
在这个实验中,你会学到如何定义不同进制的数。你还会使用数据流设计不同的转换数字的电路。你还会学习到一个提高加法速度的技能。