实验二 多路数据选择器
2.1 实验目的
-
理解多路数据选择器的概念;
-
使用门级结构描述实现多路选择器;
-
使用行为描述实现多路选择器;
-
完成实验设计、仿真,并在DE1-SOC上验证电路。
2.2 原理介绍
在多路数据传送过程中,能够根据需要将其中任意一路选出来的电路,叫做数据选择器(Data Selector)。也称多路选择器或多路开关(Multiplexer)等。
如图 2.1a 所示,在选择信号sel的控制下,从多路数据输入(in1,in2, ...)中选择某一路数据送至输出端(out)。对于一个具有 2^n 个输入和 1 个输出的多路选择器,需要有 n 个选择信号。
如图 2.1b所示,假设有4个1位输入 A,B,C和D,它们的值分别设为0,1,1和0。这种选择允许第三个输入C连接到输出端F,因此得到输出结果是1。 每次C输入的值改变,输出的值F也将跟着改变。如果想将另一个输入连接到输出端F,就需要改变选择器的选择信号。
图2.1 多路选择器的原理
多路选择器也是 FPGA 内部的一个基本资源,主要用于内部信号的选通。简单的多路选择器还可以通过级联生成更大的多路选择器。
2.2.1 1位二选一数据选择器
如图2.2二选一多路选择器模块框图所示,1位二选一多路选择器的数据输入有两个,分别为in1和in2,两个输入都是1位宽。为了确定选择哪一路输入数据连接到输出端,还需要一个选择信号(sel)。因为输入只有两路数据,选择端只要能够表现出两种状态即可,因而选择信号位宽为1即可。当sel为0时,选择in1通过;当sel为1时,选择in2通过;out表示数据选择器的数据输出。
图2.2 二选一多路选择器模块框图
根据上述功能可以列出二选一真值表如下:
表2.1 二选一多路选择器真值表
in1 | in2 | sel | out |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 |
0 | 1 | 1 | 1 |
1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 |
根据真值表2.1我们可以绘制出二选一数据选择器的信号波形关系图2.3, 从这个图我们可以直观的看到输入和输出之间具体的映射关系 。
图2.3 二选一多路选择器信号波形关系图
实现 二选一多路选择器的 Verilog HDL代码形式有很多种 ,下面我们分别用门级结构描述和行为描述来实现它。
门级结构描述二选一多路选择器
所谓门级结构描述是指在设计中直接调用基本逻辑门级元件来构建电路。根据真值表2.1化简得出布尔表达式:
out = (in1 & (~sel)) | (in2 & sel)
根据布尔表达式得出二选一多路选择器门级结构原理图如下:
图2.4 二选一多路选择器门级结构原理图
根据图2.4可以写出1位二选一多路选择器门级结构描述代码如下:
module mux2x1( //模块的开头以“module”开始,然后是模块名“mux2_1”input in1,in2, //两路数据输入信号in1,in2input sel, //选择信号output out //数据输出信号);
wire sel_,a,b; //定义中间变量
not U1(sel_,sel); //非门,实现sel信号的取反
and U2(a,in1,sel_); //与门,实现a和in1的逻辑与运算
and U3(b,in2,sel); //与门,实现b和in2的逻辑与运算
or U4(out,a,b); //或门,实现a和b的逻辑或运算
endmodule //每个模块的结尾以“endmodule”结束
代码2.1 门级结构描述二选一多路选择器
在Quartus的Tools -->Netlist Viewers -->RTL Viewer查看到二选一多路选择器门级描述综合出的电路图结果如下(虽然该图和图2.4不太一样,但是其功能是一样的):
图2.5 二选一多路选择器门级实现RTL Viewer图
其实我们直接用语句“assign out = (in1 & (~sel)) | (in2 & sel);”替换掉代码2.1里面的4个门语句的电路描述也可以得到图2.5所示的电路。这种主要使用assign持续赋值语句描述的方式称之为数据流描述。
行为描述二选一多路选择器
所谓行为描述就是对设计实体的数学模型的描述,其抽象程度远高于结构描述,行为描述类似于高级编程语言,当我们描述一个设计实体的行为时,我们无需知道电路的具体结构,只需要描述输入输出信号的行为,而不必花费心思关注设计功能的门级实现,这将大大提高了设计者的设计效率。
根据图2.2的功能描述我们可写出二选一多路选择器行为描述的代码。实现二选一多路选择器功能的行为描述方法有很多种,常见的有这三种:
(1) 条件语句 if-else 实现方法
module mux2x1( //模块的开头以“module”开始,然后是模块名“mux2_1”input in1,in2,//两路数据输入信号input sel, //选择信号output reg out //数据输出信号);
always@(*) //只要 if 括号中的条件或赋值号右边的变量发生变化则立即执行下面的代码if(sel == 1'b1) //当sel设置为1时执行下面的语句out = in1; //always 块中如果表达的是组合逻辑关系时使用“=”进行赋值else out=in2;
endmodule //每个模块的结尾以“endmodule”结束
代码2.2 用条件语句 if-else 描述二选一多路选择器
always 语句用来表示组合逻辑时,即可以采用门电路的描述方法,也可以采用功能性的描述语句。
always 块中被赋值的一定要是 reg 型变量,但它并没有生成寄存器而是实现的的组合逻辑的功能,这是因为这个变量在仿真时需要占据内存空间,而上面的 always 块只对 sel、 in1、 in2 三个变量的输入敏感,如果没有这三个变量的变化事件,则 out 变量将需要保存其值,因此它们必须被定义为 reg 型变量,但是在综合之后,并不对应硬件锁存器或者触发器(后面第四章会讲到什么时候会出现综合成这两种的情况)。
在Quartus的Tools -->Netlist Viewers -->RTL Viewer查看到代码2.2对应的二选一多路选择综合出的电路图结果如下:
图2.6 代码2.2综合出的二选一多路选择器RTL Viewer图
(2) 条件语句 case 实现方法
module mux2x1( //模块的开头以“module”开始,然后是模块名“mux2_1”input in1, //数据输入信号in1input in2, //数据输入信号in2input sel, //选通信号output reg out //输出信号
);
always@(*) begincase(sel) 1'b1 : out = in1;1'b0 : out = in2;
//如果 sel 不能列举出所有的情况一定要加 default
//此处 sel 只有两种情况,并且完全列举了,所以 default 可以省略default : out = in1;endcaseend
endmodule
代码2.3 用条件语句 case 描述二选一多路选择器
在case语句中,首先会判断变量和哪个分支相同,并且执行对应的表达式。当和所有的分支都不相同时,执行default后的那个表达式。
代码2.3条件语句 case 实现二选一多路选择器对应的RTL Viewer图如下:
图2.7 代码2.3综合出的二选一多路选择器RTL Viewer图
(3) 条件运算符(三目运算符)实现方法
module mux2x1( //模块的开头以“module”开始,然后是模块名“mux2_1”input in1, //数据输入信号in1input in2, //数据输入信号in2input sel, //选通信号output reg out //输出信号
);
//此处使用的是条件运算符(三目运算符),当括号里面的条件成立时
//执行"?”后面的结果;如果括号里面的条件不成立时,执行“: ”后面的结果assign out = (sel == 1'b1) ? in2 : in1;
endmodule
代码2.4 用 三目运算符描述二选一多路选择器
用条件运算符(三目运算符)实现方法对应的RTL Viewer图:
图2.8 代码2.4综合出的二选一多路选择器RTL Viewer图
通过以上三种不同的代码编写方式,我们可以了解到一个最基本模块的书写格式和实现方法,还知道 Verilog HDL 语言和 C 语言相似的地方就是实现相同功能,其代码方式是多种多样的,所以大家在代码的实现上就有很多的选择。通过对比发现以上三种不同代码方式实现的 2 选 1 多路选择器对应综合出的 RTL 视图虽有所差别,但综合工具在布局布线和最后映射 FPGA 资源时会自动优化,使最终的功能和占用的逻辑资源都是相同的。
2.2.2 1位四选一数据选择器
图2.9展示了如何使用三个二选一数据选择器来构建一个四选一数据选择器,该选择器有一个2位的选择输入端sel[1:0],四个1位的数据输入in1,in2,in3,in4,以及一个1位的数据输出out。
图2.9 用二选一数据选择器构建四选一数据据选择器图
根据组合逻辑设计规则,我们可以将所有的情况全部列出,得出真值表,进而得到布尔表达式和门级电路原理图。但是现在输入的组合排列变多了(2的4次幂),后面还会拓展到4位四选一,这时直接列出真值表显得麻烦,可以选择直接用行为级语句描述会显得更高效。
四选一多路选择器的实体设计分析如下:四选一多路选择器的数据输入有四个,分别为in1、in2、in3和in4。为了能够确定选择那一路数据能够通过,还需要一个选择端(sel)。因为输入四路数据,选择端要求能够表现出四种状态,因而选择端位宽为2(2的2次幂是4)。假设in1、in2、in3和in4都是位宽为1的数据输入,当sel为00时,选择in1输出;当sel为01时,选择in2输出;当sel为10时,选择in3输出;当sel为11时,选择in4输出;out表示数据输出。
图2.10 1位四选一数据选择器功能框图
根据1位四选一数据选择器功能框图2.10可写出行为描述的代码如下:
module mux4x1( input in1, //数据输入信号in1input in2, //数据输入信号in2input in3, //数据输入信号in3input in4, //数据输入信号in4input [1:0] sel, //选通信号output reg out //输出信号
);always @ ( * ) begincase (sel) 2'b00 : out = in1;2'b01 : out = in2;2'b10 : out = in3;2'b11 : out = in4;default : out = in1;endcaseend
endmodule
代码2.5 1位四选一数据选择器的代码实现
2.2.3 2位四选一数据选择器
2位四选一数据选择器是在1位四选一数据选择器的基础上将每个数据输入信号从1位拓展到2位。2位四选一数据选择器的具体介绍以及代码实现参考本章的2.2章节到2.5章节的实验内容。
2.3 实验任务
设计并实现2位四选一多路选择器,通过选通控制信号确定选通四路数据输入中的某一路作为输出信号。
2.4 设计实现
2.4.1 硬件介绍
我们使用DE1-SOC上的滑动SW开关和 LED 灯等硬件进行四选一多路选择器的验证,选取 SW[1:0],SW[3:2],SW[5:4],SW[7:6] 分别作为四路(in1,in2,in3,in4)信号的输入端,选取SW[9:8] 作为选择信号 sel 的信号输入;选取 LEDR[1:0] 作为信号输出 out的显示,具体的硬件映射关系如图 2.11所示 :
图2.11 4位四选一数据选择器与外设对应关系
2.4.2 设计思路
图2.12 是2位四选一数据选择器功能框图,跟1位四选一数据选择器一样,当选通控制信号 sel 为 00 时,信号输出为 in1路的信号;当选通控制信号 sel 为 01时,信号输出为 in2 路的信号;当选通控制信号 sel 为 10时,信号输出为 in3 路的信号;当选通控制信号 sel 为 11时,信号输出为 in4 路的信号。
图2.12 2位四选一数据选择器功能框图
如下表2.2 是2位四选一数据选择器的输入输出信号描述。
表2.2 4位四选一数据选择器信号描述列表
信号 | 位宽 | 类型 | 功能描述 |
---|---|---|---|
in1 | 2-bit | Input | 输入信号1 |
in2 | 2-bit | Input | 输入信号2 |
in3 | 2-bit | Input | 输入信号3 |
in4 | 2-bit | Input | 输入信号4 |
sel | 2-bit | Input | 选通信号 |
out | 2-bit | Output | 输出信号 |
2.4.3 代码
代码2.6是2位四选一数据选择器的代码实现:
module mux4x1(input [1:0] in1, //数据输入信号in1input [1:0] in2, //数据输入信号in2input [1:0] in3, //数据输入信号in3input [1:0] in4, //数据输入信号in4input [1:0] sel, //选通信号output reg [1:0] out //输出信号
);always @ ( * ) begincase (sel) 2'b00 : out = in1;2'b01 : out = in2;2'b10 : out = in3;2'b11 : out = in4;default : out = in1;endcaseendendmodule
代码2.6 4位四选一数据选择器的代码实现
如下图2.13 是4位四选一数据选择器RTL Viewer图:
图2.13 4位四选一数据选择器RTL Viewer图
2.5 实验步骤
2.5.1 创建工程
1. 点击电脑右下角的开始菜单找到Quartus软件,双击Quartus (Quartus Prime 17.1)打开Quartus Prime软件。
2. 点击菜单File-->New Project Wizard弹出工程创建的对话框。在弹出的对话框中点击Next。
3. 在您的DE1-SOC 工作文件夹下创建一个lab2的文件夹,并将工程路径指向该文件夹,且工程的名称也命名lab2。
图2.14 选择工程路径以及工程命名
4. 连续点击3次Next得到如下界面,通过器件过滤器筛选选中DE1-SoC的Cyclone V 5CSEMA5F31C6器件。
图2.15 筛选出DE1-SOC的FPGA 器件
5. 点击Next两次后得到工程的生成报告窗口,检查无误后点击Finish完成工程创建。
图2.16 lab2工程
6. 在Quartus工具栏依次点击File-->New,在New窗口中选择Verilog HDL File后点击OK按钮新建一个空白Verilog HDL文件,将代码2.6复制到新创建的.v文件中,并点击File-->Save As ...将该文件重命名为mux4x1.v,并新建名为v的文件夹,将mux4x1.v保存在v文件夹中。
图2.17 创建v文件夹
图2.18 Quartus软件中的mux4x1.v文件
7. 点击Quartus软件工具栏的Processing --> Start --> Start Analysis & Synthesis或点击
按钮对Verilog HDL代码执行语法检查和综合,该过程成功完成之后在Quartus软件窗口的Tasks页面中,Analysis & Synthesis旁边将显示一个绿色勾型标记,如图2.19所示。如果在该过程中提示有错误,请检查Verilog HDL代码语法,确保与上述代码块完全一致。
图2.19 对Verilog代码进行分析和综合
2.5.2 仿真
1. 点击Quartus软件工具栏的File --> New --> Verilog HDL File,点击OK,新建一个空白Verilog HDL文件,再点击File --> Save As ...保存,命名为mux4x1_tb.v,保存在v文件夹中,如图2.20所示。
图2.20 新建并保存test bench文件
2. 在lab2_tb.v文件中输入如下代码,并保存。
`timescale 1ns/1psmodule mux4x1_tb;reg [1:0] in1;reg [1:0] in2;reg [1:0] in3;reg [1:0] in4;reg [1:0] sel;wire [1:0] out;mux4x1 mux4x1_inst(.in1 (in1),.in2 (in2),.in3 (in3),.in4 (in4),.sel (sel),.out (out));initial beginrepeat(8) beginin1 = {$random} % 4;in2 = {$random} % 4;in3 = {$random} % 4;in4 = {$random} % 4;sel = {$random} % 4;# 20;end end
endmodule
代码2.8 lab_tb.v文件代码
图2.21 Quartus软件中的mux4x1_tb.v文件
由于本次输入的的组合太多,不能全覆盖测试。故采用随机数来进行测试。
$random是一个系统函数,调用时,可以返回一个随机值。注意:这个系统函数只能出现在testbench中,在设计中出现是不可综合的。
$random函数调用时返回一个32位的随机数,它是一个带符号的整形数。例如:
reg[23:0] rand;
rand=$random % 60; //产生一个在 -59—59范围的随机数
产生0~59之间的随机数,例如:
reg[23:0] rand;
rand={$random} % 60; //通过{}产生0—59范围的随机数
产生在min, max之间随机数,例如:
reg[23:0] rand;
rand = min+{$random}%(max-min+1);
因为2位信号输入的取值范围是0~3,所以我们代码里面这样写({$random} % 4)。在testbench中,需要按照一定顺序给输入信号赋值。在lab2_tb中,我们可以通过延迟赋值,然后再次延迟赋值,来完成赋值。因为赋值时采用随机数,所以每次编写的语句是相同的。Verilog HDL中提供了repeat语句,用来减少人工输入。
3. 点击Assignments --> Settings,然后选中Simulation栏,Tool name选择ModelSim-Altera,然后选择新建Test Bench文件,如图2.22所示的步骤。
图2.22选择新建Test Bench文件
4. 按照图2.23所示的步骤选择mux4x1_tb.v文件,点击Add进行添加,然后点击OK。
图2.23 添加Test Bench文件mux4x1_tb.v
-
这样就可以在Test Bench看到添加的mux4x1_tb.v文件,点击OK ,如图2.24所示。添加完成后,在Settings窗口点击Apply和OK,然后将其关闭。
图2.24 Test Bench文件添加完成
-
在Quartus Prime中选择菜单项Tools --> Run Simulation Tool --> RTL Simulation,即可调用ModelSim工具进行仿真,如图2.25所示。
图2.25 运行Simulation Tool
-
运仿真结果如图2.26所示(点击Zoo Full(F)图标显示全部波形)。
图2.26 ModelSim 仿真结果
-
从2.26中的波形图可以看出:
a. 当sel=00时,out为in1的输入值;
b. 当sel=01时,out为in2的输入值;
c. 当sel=10时,out为in3的输入值;
d. 当sel=11时,out为in4的输入值;
结果与预期一致,说明我们的4位四选一数据选择器功能已实现。
2.5.3 引脚分配、全编译与烧录
关于引脚分配信息可以查看DE1-SoC_v.5.1.3_HWrevF.revG_SystemCD\UserManual\DE1-SoC_User_manual.pdf第 25、26页或者E:\CD_Package\01-DE1-SoC\DE1-SoC_v.5.1.3_HWrevF.revG_SystemCD\Schematic\DE1-SoC.pdf的第3页。
这里,in1到 in4以及sel0和sel1可以通过拨码开关SW0到SW9来控制,s0到s3信号分别输出到LEDR0和LEDR1。
-
点击Quartus软件工具栏的Processing --> Start Compilation或点击
按钮编译工程,编译完成后,如图2.27所示。
图2.27 编译Verilog HDL代码
此外还可以看到在output_files文件夹中生成了lab2.sof文件,如图2.28所示。
图2.28 编译生成lab2.sof文件
-
使用上一步中编译生成的lab2.sof文件对FPGA进行编程。给DE1-SOC开发板供电开机,点击Quartus软件工具栏的Tools --> Programmer或点击
按钮打开Programmer窗口,如图2.29所示。
图2.29 Programmer窗口
-
点击Hardware Setup...打开Hardware Setup窗口,在Currently selected hardware的下拉框中选择"USB-Blaster",点击Close,如图2.30所示。
图2.30 Hardware Setup窗口
-
点击Auto Detect按钮,在弹出的Select Device窗口中,选择5CSEMA5(DE1-SOC开发板上的FPGA器件为Cyclone V 5CSEMA5F31C6),并点击OK,如图2.31所示。
图2.31 选择5CSEMA5器件
在弹出的Quartus Prime提示窗口中,点击Yes。
图2.32 提示弹窗
然后在Programmer窗口会出现SOCVHPS和FPGA两个器件,如图2.33所示。
图2.33 Programmer窗口出现SOCVHPS和FPGA两个器件
-
左键单击选中5CSEBA6器件,然后点击Change File按钮,添加mux4x1.sof文件,添加完成后如图2.34所示。
图2.34 添加lab2.sof文件
-
勾选Program/Configure,点击Start按钮,烧录lab2.sof文件,如图2.35所示。
图2.35 开始烧录
2.5.4 实验现象观察
-
在lab2中,使用的SW、LEDR如下图所示。
图2.36 lab2中SW、LEDR对应关系
-
通过切换滑动开关SW9-0到 up或 down 位置,观察LEDR1-0的状态来测试设计的功能。
a. 当sel=00时,out为in1的输入值;
b. 当sel=01时,out为in2的输入值;
c. 当sel=10时,out为in3的输入值;
d. 当sel=11时,out为in4的输入值;
结果与预期一致,说明我们的4位四选一数据选择器功能已实现。
2.6 实验小结
本章通过介绍1位二选一数据选择器,1位四选一数据选择器和4位四选一数据选择器的原理与设计,让读者学会如何通过门级结构描述和行为描述去实现特定功能的电路,然后还通过实验的实战演练,让读者学会编写仿真代码对电路进行仿真验证以及如何将设计下载到板卡进行实操验证。