1、选择器介绍
多路选择器(MUX)是一种重要的数字电路元件,用于选择多个输入信号中的一个,并将其传递到单个输出。多路选择器也是 FPGA 内部的一个基本资源,主要用于内部信号的选通。
2、实战任务
这里我们选择一个简单的 2 选 1 的选择器,主要功能是通过选通控制信号 sel 确定输入信号 A 和 B 哪一个信号作为输出。当选通控制信号 sel 为 0 时,输出为 A 端信号;当选通控制信号 sel 为 1 时,信号输出为 B 端信号。
3、系统框图
根据实战任务描述是一个二选一的多路选择器,因此给模块命名为 2_sel_1。模块中的输入为三个一位的信号,其中 A 和 B 为两个输入信号,sel 为一位(因为两个输入端,sel 位宽取一位(即0/1即可表示选择的是 A 还是 B ))输入的控制信号,X 为输出信号。模块图如下图所示:
4、真值表
根据实战任务所述,二选一的多路选择器的真值表,如下表所示:
输入 A | 输入 B | 选择 sel | 输出 X |
0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
1 | 0 | 0 | 1 |
1 | 1 | 0 | 1 |
0 | 0 | 1 | 0 |
0 | 1 | 1 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | 1 | 1 |
5、波形图
通过对真值表进行分析,我们可以绘制多路选择器的输入与输出波形。其波形如下图所示:
6、程序编写
首先我们来编写二选一多路选择器的逻辑代码,其中实现二选一多路选择器功能的 Verilog 代码形式有很多种,这里选择 assign 中条件运算符(三目运算符)实现方法(注:由于语法规则我们将 2_sel_1 改为 sel_2_1 ,避免编译器报错):
module sel_2_1(
input A, // 输入信号 A
input B, // 输入信号 B
input sel, // 选择控制信号 sel
output X // 输出信号 X
);
// 三目运算符实现多路选择器
assign X = (sel == 1'b0) ? A : B;
//(sel == 1'b0)这是一个布尔表达式。如果这个表达式的结果为真,则返回 A;如果为假,则返回 B
//当条件为真时,返回 A 的值。
//当条件为假时,返回 B 的值。
//X 为存储最终结果的变量。
//即 assign out = (sel == 1'b0) ? A : B; 表示如果 sel == 1'b0 为真,则 out 输出 A;如果 sel != 1'b0 为假,则 out 输出 B。
endmodule
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注:
第 2 - 6 行:定义两个输入信号 A 和 B ,选择控制信号为 sel ,输出信号为 X 。
第 10 行:是一个三目运算符。
这里的 (sel ) 这是一个布尔表达式也可以写成成这样(sel == 1'b1)。如果这个表达式的结果为真,则返回 A;如果为假,则返回 B 。
当条件为真时,返回 A 的值。
当条件为假时,返回 B 的值。
X 为存储最终结果的变量。
即 assign out = (sel == 1'b0) ? A : B; 表示如果 sel == 1'b0 为真,则 out 输出 A;如果 sel != 1'b0 为假,则 out 输出 B。
7、仿真编写
`timescale 1ns / 1ns // 定义时间单位和精度为 1 纳秒
module sel_2_1_mod(); // 模块 sel_2_1_mod 的开始
// define
reg A; // 输入 A
reg B; // 输入 B
reg sel; // 选择信号 sel
wire X; // 输出 X
initial begin // 初始块开始
A = 1'b0; // 设置 A 为 0
B = 1'b0; // 设置 B 为 0
sel = 1'b0; // 设置 sel 为 0
#200; // 延迟 200 纳秒
A = 1'b0; // 设置 A 为 0
B = 1'b1; // 设置 B 为 1
sel = 1'b0; // 设置 sel 为 0
#200; // 延迟 200 纳秒
A = 1'b1; // 设置 A 为 1
B = 1'b0; // 设置 B 为 0
sel = 1'b0; // 设置 sel 为 0
#200; // 延迟 200 纳秒
A = 1'b1; // 设置 A 为 1
B = 1'b1; // 设置 B 为 1
sel = 1'b0; // 设置 sel 为 0
#200; // 延迟 200 纳秒
A = 1'b0; // 设置 A 为 0
B = 1'b0; // 设置 B 为 0
sel = 1'b1; // 设置 sel 为 1
#200; // 延迟 200 纳秒
A = 1'b0; // 设置 A 为 0
B = 1'b1; // 设置 B 为 1
sel = 1'b1; // 设置 sel 为 1
#200; // 延迟 200 纳秒
A = 1'b1; // 设置 A 为 1
B = 1'b0; // 设置 B 为 0
sel = 1'b1; // 设置 sel 为 1
#200; // 延迟 200 纳秒
A = 1'b1; // 设置 A 为 1
B = 1'b1; // 设置 B 为 1
sel = 1'b1; // 设置 sel 为 1
#1000; // 延迟 1000 纳秒,允许观察结果
$stop; // 停止仿真
end
// 例化 2选1 多路选择器
sel_2_1 u_sel_2_1(
.A(A), // 将输入 A 连接到选择器
.B(B), // 将输入 B 连接到选择器
.sel(sel), // 将选择信号 sel 连接到选择器
.X(X) // 将输出 X 连接到选择器输出
);
endmodule // 模块结束
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
程序注释:
第 1 行 :时间尺度预编译指令 时间单位/时间精度,第一个 1ns 是时间单位,第二个 1ns 是时间精度。
第 3 行:定义了仿真模块名称。
第 12 ~ 26 行:使用 initial 语句块进行输入信号的初始化,根据真值表依次将输入的状态都列举出来。从而能够观察程序是否与我们所列真值表相同。
第 58 ~ 63 行:对我们的 sel_2_1.v 文件的输出输入信号进行一个绑定。
8、项目工程
开始使用 Gowin 创建项目工程了,芯片选型如下所示:
接着在 Gowin 的 Design 窗口空白地方右键点击选择 New Files... 添加文件。如下图所示:
分别创建所需的文件 sel_2_1.v 跳转到程序编写 和 sel_2_1_mod.v跳转到仿真程序编写 ,如下图所示:
添加完对应程序后(记得要失能 sel_2_1_mod.v文件),然后开始仿真,新建工程将 Project_Name 和 Default Library Name 都改成 logical_and 名称,如下图所示:
分别添加我们仿真所需的文件 sel_2_1.v 和 sel_2_1_mod.v,如下图所示:
接下来选择 Compile->Compile All ,编译没有问题后,在 Add Simulation Configuration 配置好对应的文件,如下图所示:
仿真结果如下:
由上面的仿真图,可以看出与我们的真值表所列出的来结果是一致的,证明我们的程序没有问题。
9、RTL 原理图
开始 Synthesize 编译判断 sel_2_1.v 文件是否有语法错误,执行 Synthesize 编译,接下来的就该绑定引脚,由于我们 逻辑派 板载按键只有两个所以本章只讲仿真和查看 RTL 电路图,如有需要做此实验,则可以拿一个1.5K电阻当按键,一边连接你自己定义的 I/O 上面,另一般连接 3V3 或者 GND 来模拟按键按下的情况。
注:若出现然后违规操作,或者操作不当(I/O口被烧等情况),我们概不负责,实验有风险,请谨慎操作~~~~~~
若出现然后违规操作,或者操作不当(I/O口被烧等情况),我们概不负责,实验有风险,请谨慎操作~~~~~~
若出现然后违规操作,或者操作不当(I/O口被烧等情况),我们概不负责,实验有风险,请谨慎操作~~~~~~
接下来在过程管理窗口 Process > Place & Route > Run,来对代码布局布线进行综合(如果前面没有执行 Synthesize 编译,直接执行这个,编译器会自动执行前面的内容),如下图所示:
再点击 tools -> Shematic Viewer -> RTL Design Viewer 然后查看 RTL 电路图,如下图所示:
然后查看 RTL 电路图,在软件里二选一选择器是怎样的,如下图所示:
至此我们的二选一选择器就讲完了。