实验1:组合逻辑电路
提示
在查阅本文档进行实验时,verilog的基础知识可查阅普通班lab1,vivado的基本使用方法可查阅提高班预备知识-vivado的使用。
在本次实验中,我们有以下任务:
- 设计32位ALU,可以实现加法、减法、与、或、异或、取反等运算。
- 设计4线-10线BCD译码器,实现4位BCD编码向10位独热码的转换。
- 设计七段数码管译码器,并完成上板测试。
1 ALU
ALU(Arithmetic Logic Unit,算术逻辑单元)是计算机中的一种重要组件,它可以实现算术运算和逻辑运算。在龙芯架构32位精简版指令集中,ALU需要支持以下运算:
- 简单算术运算:加法(ADD)、减法(SUB)、小于比较(SLT)、无符号小于比较(SLTU)
- 逻辑运算:按位或非(NOR),按位与(AND),按位或(OR),按位异或(XOR),左移(SLL)、右移(SRL)、算术右移(SRA)
ALU是同时将两个源操作数送到所有运算单元,每个运算单元都进行计算并输出,再通过op(操作码)来借助多选器选择哪个运算单元的输出作为最终的结果。

图中及示例里的op是operation(操作)的缩写,在本实验要求的接口中命名为f(flag),用来选择ALU的输出模式。a和b是两个操作数,y是输出结果。
f采用独热码,每一位对应一种运算。例如,f[0]=1且其余位为0时选择加法,输出y=a+b;f[1]=1且其余位为0时选择减法,输出y=a-b。
在处理独热码的编码时,我们可以有两种选择:
-
RTL级描述方式:使用assign或例化模块等方式分别实现每个运算单元,再使用与或运算来对所有运算单元的输出结果进行多选。设一共有\(n\)个运算单元,设第\(i\)个运算单元对应了操作码的第\(i\)位(例如在本次实验中,加法作为第0个运算单元,对应了独热码的第0位),那么我们可以使用如下的逻辑来实现多选:
注意上述的省略号是简写,真正编写代码需要把所有的运算单元都列出来。 这里涉及到了位拓展和位拼接运算,32{k}表示将k这个数据重复32次,最外层的大括号表示将这重复了32次的数据拼接起来。 -
**行为级描述方式:**使用always+case的行为级描述来实现ALU,在case的不同情况下给ALU输出结果赋相应的值,相信编译器可以将代码优化为上述逻辑。
这两种方法都是可以的,但是我们推荐使用第一种方法,因为这样可以让你更加清楚地知道自己的代码是如何工作的。
"资源优化与通路复用
在ALU的设计中,你必然可以使用case和各类运算符来完成这个设计。但是,你是否可以尝试使用资源优化和通路复用的思想来完成这个设计呢?例如,我们可以将加法器的计算结果复用起来计算减法,再使用加减法的计算结果实现小于比较,更可以将左移和右移的计算结果复用起来。如果你能够做到这些,那么你的ALU将会非常紧凑,而且性能也会非常好。openLA500中的alu就实现了这些。
2 译码器
译码器是一种将其他编码格式(例如\(log_2n\)位二进制编码)转换为 \(n\)位独热码或其他类型信号的组合电路元件。在本次实验中,我们将实现4线-10线BCD译码器和七段数码管译码器。
2.1 4线-10线BCD译码器
4线-10线BCD译码器可以将4位BCD编码转换为10位独热码。输入为0-9时,这种输出有且仅有一位为1。
若输入的BCD码不合法(即输入为10-15,如输入为4'b1010),则输出为10'b0。

d[3:0]:data,待译码的4位BCD数据,BCD全称为Binary-Coded Decimal(二进制编码的十进制数)。y[9:0]:译码结果。输入数字为几,就将对应编号的输出位置1,例如d=3时只有y[3]为1。
这里我们推荐使用行为级描述来进行实现,但你也可以尝试使用assign + 左移运算来完成这个设计。
2.2 七段数码管译码器
七段数码管译码器可以将4位BCD编码转换为七段数码管的控制信号。这里我们使用共阳极七段数码管,因此输出信号为低电平有效信号。
若输入的BCD码不合法(即输入为10-15),则输出为7'b1111111,所有段均熄灭。
七段数码管由两个控制信号构成,分别为段选信号(ca-cg)和位选信号(an),均为低电平有效。段选信号用于控制七段数码管的哪一段被点亮,位选信号用于控制哪一位的七段数码管被点亮。译码器只负责将输入的BCD码转换为段选信号。在本次实验中,我们希望最低位的七段数码管被点亮,因此位选信号an恒为8'b11111110。

d[3:0]:data,待显示数字的4位BCD数据。yn[6:0]:低电平有效的译码输出,y表示输出,后缀n表示negative(低电平有效)。每一位控制一段,0表示点亮,1表示熄灭。ca至cg:c表示cathode(阴极),后面的a至g是段的编号,分别控制对应段的亮灭。an[7:0]:anode(阳极)的位选控制信号,决定哪一位数码管显示;板上的位选控制为低电平有效。
七段数码管的段选信号和物理上的七段数码管的对应关系如下图所示:

其中,ca-cg也就对应了图中a-g的位置,译码器输出yn[6:0]从高位到低位依次对应a-g,即yn[6:0]={a,b,c,d,e,f,g}。你只需要将ca-cg对应的位置置为0,就可以点亮对应的段。
3 译码器联合电路设计

我们需要实现的电路如上所示。顶层信号的名称与用途如下:
| 信号 | 名称含义 | 用途 |
|---|---|---|
sw[4:0] |
switch,拨码开关 | sw[3:0]提供BCD数据,sw[4]选择LED或数码管显示 |
led[9:0] |
light-emitting diode,发光二极管 | 控制0至9号LED,1表示点亮对应LED |
cn[6:0] |
c表示cathode,n表示低电平有效 |
输出经显示链路选择后的段码,从高位到低位控制a至g段 |
an[7:0] |
anode,阳极位选控制 | 固定为8'b11111110,选中最右侧一位数码管 |
dp |
decimal point,小数点 | 0表示点亮,1表示熄灭,本实验固定为1 |
图中的MUX是multiplexer(多路选择器),根据选择信号决定将哪一路输入送到输出。
-
输入的BCD码由0-3号开关提供,对应
sw[3:0],其中0号开关是最低位。两个译码器同时对这组BCD码进行译码。 -
显示链路由4号开关选择,对应
sw[4]。当4号开关为0时,4线-10线BCD译码器的输出接入到0-9号led指示灯中,数码管熄灭;当4号开关为1时,七段数码管显示对应的数字,所有led指示灯熄灭。 -
对于显示链路的选择,我们使用4号开关作为控制信号,通过两个MUX分别选择译码结果或关闭值。LED的关闭值为
10'b0,数码管段选的关闭值为7'b1111111。 -
若输入的BCD码不合法(即输入为10-15),则led指示灯和数码管均熄灭。位选信号an固定为
8'b11111110,只选中最右侧一位数码管;小数点信号dp固定为1'b1,使小数点始终熄灭。
vivado项目内的设计资源结构示例:

仿真测试文件
本次实验助教为大家提供了一个仿真测试文件的示例,请点击这里下载。示例中已完成lab1_top的例化,并演示了输入赋值、显示链路切换和循环遍历。请参考其中的写法完成自己的testbench,并结合波形检查电路输出。
示例中的initial块在仿真开始时执行一次,块内的语句按顺序执行。#10表示等待10ns,repeat(16)表示将后面的begin...end块重复执行16次。示例先通过逐次赋值观察输入变化,再分别遍历两种显示链路下的0-15输入。你可以修改输入值、延时和变化顺序,增加自己的测试用例。
请注意,这个仿真测试文件的后缀为.sv,也就是SystemVerilog文件。示例中使用logic声明输入和输出信号。如果使用Verilog文件编写testbench,则在initial中赋值的输入信号应声明为reg,连接被测模块输出的信号应声明为wire。
你可以参考「预备知识-vivado的使用-step4:对设计进行仿真」来学习仿真测试文件的编写。