实验练习
说明
- 每一次实验我们会为大家准备若干练习题目。不同的题目有着不同的难度,请大家量力而行;
- 你可以查阅任何开源资料完成实验练习,但不能直接抄袭。一经发现,我们将取消所有抄袭参与者本次的实验成绩。情节特别严重的,我们将按照学校的有关规定进行处理;
- 部分题目我们提供了代码框架,你需要在框架指定的位置完成代码内容。你也可以自由修改框架代码,但需要根据题目要求完成练习;
- 如果你使用了我们预料之外的方法完成练习也没有关系,我们将根据思考量与任务量单独确定给分情况;
- 本次实验的部分题目需要上板验证,具体的端口变量与对应关系请按照题目要求设定。
提醒
为了保证效率,请大家在找助教 Debug 前务必编写对应的仿真文件。我们不接受没有仿真波形的 Debug 请求。
必做内容
每一名同学都需要完成必做部分的内容。
题目 1:加法器(2 分)
请参照实验文档中对 4bits 超前进位加法器和层次扩展的描述,设计并编写一个基于 8bits 超前进位加法器实现的 32bits 加法器。本题的分数组成如下:
- 8 位超前进位加法器:1 分
- 8 位超前进位加法器 + 层次扩展成 32 位:1 分
本题要求自行编写仿真文件进行测试,代码框架与部分仿真信号输入如下:
Adder_LookAhead4.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Adder.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
下面是一些你可能会用到的代码:
1 2 3 4 5 6 |
|
Adder_tb.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 |
|
提示
tb 文件仅作参考,我们鼓励大家自行设计合适的信号输入,这对你的能力提升也会有很大的帮助。本题需要完成的内容有:
- 补全 Adder_LookAhead4 模块的相关代码用于理解超前进位加法器的原理;(不检查)
- 自己编写 Adder_LookAhead8 模块;
- 基于 Adder_LookAhead8 模块在 Adder 模块中使用层次扩展的方法得到 32 位加法器。
题目 2:ALU(5 分)
请参照实验文档中对 ALU 及其部件的描述,设计并编写一个完整的 32 位 ALU,支持表格中列出的全部十二种运算。其中加法、减法、有符号比较、无符号比较四种运算需要基于超前进位加法器或自己设计的模块实现,而不能直接使用相应的运算符;其他的运算可以使用 Verilog 自带的运算符实现。
本题的分数组成如下:
- 加法运算:上一题已经实现,故不额外算分
- 减法运算:1 分
- 有符号比较:1 分
- 无符号比较:1 分
- 其他运算:1 分
- 信号选择:1 分
非 32 位的 ALU 会被酌情扣分。
本题要求自行编写仿真文件进行测试,代码框架与部分仿真信号输入如下:
ALU.v | |
---|---|
1 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 |
|
ALU_tb.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
你需要参考教程,编写实现 Adder、AddSub、Comp 模块。
提示
针对有、无符号比较,建议多尝试一些样例以测试实现是否正确。经典的易错样例有:32'hffff_ffff与32'h1, 32'h1与32'h0, 32'hffff_ffff与32'hffff_fffe, 32'h0与32'hffff_ffff。
选择性必做内容
选择性必做内容是针对不同层次学生设计的分层内容。不同难度的题目对应不同的分值,请大家根据自身实际情况进行选择。
例外:
本次不限制选择性必做题目的完成数量。但是约束获得最大分值总分值不超过 3 分。
题目 1:可视化 ALU(2 分)
本小题中的 ALU 限制到 3 位,与 Lab3 中的七段数码管显示模块结合,实现一个可视化的 ALU。
其中,用 sw[5:3]
与 sw[2:0]
分别表示输入 src0、src1,使用 sw[7:6]
代表 sel
选择 ALU 运算,输出结果显示在七段数码管上。其中, sw[7:6]=2'b00
时表示加法;sw[7:6]=2'b01
时表示减法;sw[7:6]=2'b10
时表示有符号比较;sw[7:6]=2'b11
时表示无符号比较。
此外,考虑到 ALU 是一个组合逻辑单元,因此其运算结果需可以根据输入的变化实时更新。比如:sw[7:0]=8'b00_100_011
时,七段数码管显示 7;拨动开关使得 sw[7:0]=8'b11_100_011
时,七段数码管显示 0。
本题要求上板测试,代码框架与对应部分的限制文件如下:
Top.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
提示
Verilog 编程很多时候就是一个「搭积木」的过程,本题中所需要的「积木」已在之前的实验中搭好,即本次实验完成的 ALU 模块与 Lab3 完成的 Segment 模块,大家需要做的仅仅是考虑如何将已有的「积木」连接起来。
题目 2:可视化 ALU-plus(3 分)
本题是上一题的升级版,上一题中,限于开关的数目,我们的 ALU 只能可视化三位运算;本题通过用两位开关选择不同的输入模式,实现分时复用,从而可视化了五位运算。此外,前一题是组合逻辑电路,所有开关的输入都会即时地影响运算的结果;而这里则是一个时序逻辑,我们会在不同次输入中分别改变并存储 src0、src1 以及 sel,通过多个周期完成输入与运算结果的输出。
具体的说,我们有以下的功能要求:
enable
信号与按钮相连,rst
信号与 sw[7]
相连,ctrl
信号与 sw[6:5]
相连,in
信号与 sw[4:0]
相连。在 enable
为高电平时才进行信号输入,ctrl[1:0]
用于选择本次信号输入的模式:
-
ctrl=2'b00
时,按下enable
,表示选择ID = in[4:0]
的 ALU 运算,in[4:0]
不在 1~12 范围内的视为零运算,即无论操作数 src0 和 src1 的值,输出结果都为 0。 -
ctrl=2'b01
时,按下enable
,表示将 src0 的值改为in[4:0]
。 -
ctrl=2'b10
时,按下enable
,表示将 src1 的值改为in[4:0]
。 -
ctrl=2'b11
时,按下enable
,表示输出结果,通过seg_an
与seg_data
以七段数码管的形式显示出来。(注意:数码管的输出数据output_data
只在此时更新)
比如:ctrl
设为 2'b00
,in[4:0]
设为 5'b01001
,按下 enable
,选择了逻辑左移运算;ctrl
设为 2'b01
,in[4:0]
设为 5'b01011
,按下 enable
,此时 src0
的值变为 5'b01011
;ctrl
设为 2'b10
,in[4:0]
设为 5'b00011
,按下 enable
,此时 src1
的值变为 5'b00011
;ctrl
设为 2'b11
,按下 enable
,此时输出结果 5'b11000
,并通过 seg_an
与 seg_data
在七段数码管上以十六进制的形式显示出来。
疑问
七段数码管的输出 output_data
不是 32 位吗?是的!你只需要在运算结果前面的位补 0 即可使用 Segment 完成输出。
该设计的参考电路图如下:
本题按照 ctrl[1:0]
的不同情况的功能完整性给分:2'b00
的功能 1 分,2'b01
和 2'b10
的功能 1 分,2'b11
的功能 1 分。
本题要求仿真和上板测试,代码框架与部分仿真信号输入及对应部分的限制文件如下:
Top.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Top_tb.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
提示
本题由于需要支持 enable
,而 FPGAOL 上只有一个按钮,故将 rst
连接到最左侧的开关上。
题目 3:移位器(3 分)
ALU 中包含三种移位运算,分别是逻辑左移、逻辑右移和算术右移。此前,我们是使用 Verilog 中自带的符号实现的,而在本小题中,我们需要自己去实现移位操作。在这里,我们只实现逻辑右移 SRL 和算术右移 SRA。
可以注意到,常数位移事实上可以通过位拼接来实现,举例来说,对于 src0[31:0]
,逻辑左移 3 位,那么 src0<<3 = {src0[28:0],3'b0}
;逻辑右移 2 位,那么 src0>>2 = {2'b0,src0[31:2]}
;算术右移 2 位,那么 src0>>>2 = {{2{src0[31]}},src0[31:2]}
。
对应于前面的超前进位加法器和层次扩展的设计,移位器也有高效但消耗资源、耗时但节省资源的两种实现方式:
-
我们可以枚举所有的右操作数,并通过对应的位拼接来实现;注意到右操作数的范围是 0~31,所以我们需要枚举 32 种情况。这种实现方式只需要经过一次查找表和一个位拼接的延迟,就可以查出对应的结果,但是需要消耗大量的资源,共需要 32 个位拼接单元。
-
我们也可以按照右操作数
src1[4:0]
二进制的各位数字,对src0
连续地进行 16、8、4、2、1 移位。举例来说,src1[4:0]=5'b10110
时,可以用位拼接对src0
移 16 位,再移 4 位,最后移 2 位。这种实现方式最多需要经过五次位拼接操作和多选器的延迟,耗时相对较长,但只需要 5 个位拼接单元,资源压力较小。(类似快速幂的思路)
请你尝试实现这两种移位器,并尝试类似加法器的设计过程,对两种方法做一结合,得到在时间和空间上都占优的方法。
本题要求同时结合两种实现方式,占 3 分,其中逻辑右移与算术右移的分数各占一半。结合两种方式的实现要求最多经过 3 次"位拼接和多选器"
的延迟,总共使用不多于 12 个位拼接单元(由题意,显然逻辑右移和算数右移是两个独立的模块,所以这里规定的是一个模块使用不多于12个)。
本题要求自行编写仿真文件进行测试,代码框架与部分仿真信号输入如下:
Shifter.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
Shifter_tb.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
题目 4:无符号扩展 (1 分)
我们在实现加法器的过程中,默认是使用有符号数进行运算的。但是在实际的应用中,我们可能会遇到无符号数的运算。在本题中,我们要求你实现一个无符号数的加法器和减法器。
同时,需要做一个选择信号,当选择信号为 0 时,使用有符号数进行运算;当选择信号为 1 时,使用无符号数进行运算。
要求只能够使用一个
加法器部件,输入的数据为 x 位,则输出的数据为 x + 1 位。(进一步体会多路复用的技术)
参考实现效果如下:
0100 + 1111 = 00011 ——有符号加法
0100 + 1111 = 10011 ——无符号加法
1111 - 0100 = 11011 ——有符号减法
1111 - 0100 = 01011 ——无符号减法
提示
无符号数的ALU与有符号数的ALU的区别在于,运算结果的符号位的处理。
选做内容
选做内容为扩展内容,不计入实验成绩。大家可以根据兴趣自行完成。
题目 1:性能比较
本次实验中,我们从理论上分析了多种加法器、移位器的实现方式的性能比较,那么,在实际中他们的差距有多大呢?可以参考 lab7 的电路性能分析小节(点击电路性能分析跳转),利用vivado测试比较各种电路的最大工作频率与资源使用情况。
题目 2:倍数检测器——再再临?
提醒:本题有一定难度,想要挑战自己的同学,可以以此稍作消遣。
在前面的两次实验练习中,我们分别尝试了使用数论和状态机的方法,用 Verilog 实现了倍数检测器。这两种方法各有劣势:数论方法的电路复杂度和延迟相对较高,而状态方法使用的周期数较多。结合我们本次实验中的权衡时间与空间的设计思想,你能不能将此二者做一结合呢?
本题要求能够在 16 周期内处理 128 位二进制数的 5 的倍数检测,或者甚至计算出余数。
代码框架如下:
MOD5.v | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
题王归来,众题跪拜,「三周之期已到,恭迎题王归位」「我不会再临了,这就是我最后的波纹」
真的不会再临了吗?