F5 支持数列求和的简单处理器
我们已经学会了基本的数字电路逻辑和状态机的思想,现在我们要着手实现一个简单的处理器。首先我们需要明确接下来要实现的指令集sLSA和处理器的细节:
- PC位宽为4位, 初值为
0 - GPR有4个, 位宽均为8位
- 支持如下3条指令:
1 | 7 6 5 4 3 2 1 0 |
接下来完成实验的任务:
F5.1.1 实现取指功能
通过多路选择器实现一个ROM, 并在其中存放数列求和的指令序列, 然后通过PC寄存器取出指令. 你需要根据你的理解来确定ROM的规格.
先把数列求和的指令翻译成机器码,以1+2+3+...+10为例:
1 | 0: li r0, 10 |
然后将数据硬编码到我们的ROM中,并通过PC进行取值:
图中左上是PC寄存器,负责提供地址。右边这一堆是编码的ROM存储电路,可以将我们的数列求和程序读取出来
F5.1.2 实现GPR及其写入功能
在寄存器的基础上搭建一个RAM, 从而实现GPR的写入功能. 你需要根据你的理解来确定RAM的规格.
我们的GPR有4个寄存器,每个寄存器存储八位的数据。可以简单设计如下:
F5.1.3 实现仅支持li指令的sCPU
根据上文, 用数字电路实现
li的指令周期涉及的各个部件, 并将它们连接起来. 实现后, 尝试让sCPU执行数列求和程序中的前几条li指令, 并观察电路中GPR的状态是否与ISA的状态一致.
成功的从ROM中向寄存器写入了值:
F5.2.1 添加add指令
根据上文, 在sCPU中添加
add指令. 实现后, 尝试让sCPU继续执行数列求和程序中的几条add指令, 并观察电路中GPR的状态是否与ISA的状态一致.
经过上一个实验,现在我们的寄存器已经能够成功的接受写入了。但是为了实现进一步的指令支持,我们需要将我们的GPR优化并封装起来,我们需要实现以下端口:
- 第1个读端口:
raddr1(读地址),rdata1(读数据) - 第2个读端口:
raddr2,rdata2 - 写端口:
waddr(写地址),wdata(写数据),wen(写使能),clk(时钟)
这样我们就能满足add指令,同时读取两个源操作数和写入一个寄存器的操作了。
但是再次之前我们还需要进一步实现译码功能,从而将我们的add和li逻辑分离,不同的指令需要不同的信号:
- li:
- 需要
waddr和imm作为输入,需要写使能信号开启
- 需要
- add:
- 需要
raddr1和raddr2作为输入 - 接受
rdata1和rdata2,做加法输入到wdata - 根据
wdata、waddr和写使能信号,更新寄存器
- 需要
综上,我们可以规划出我们的电路图,以完成前6条指令的执行:
以下是执行一轮前六条指令后的寄存器状态:
F5.2.2 添加bner0指令
根据上文, 在sCPU中添加
bner0指令. 实现后, 尝试让sCPU执行完整的数列求和程序, 如果你的实现正确, 你应该能看到PC最终为7, 且在某GPR中存放求和结果55.
添加bner0我们首先分析他需要哪些输入和信号:
- 首先需要
addr用于改变PC的值,也就是说我们现在需要一个机制能支持我们改变PC的内容 - 同时需要读取
r0和r2的值进行比对,如果不同则跳转
这两个问题都可以简单的通过多路复用器的思路来解决:
我们的求和程序运行的最终情况如下。可以看到r2 = 0x37 = 55符合我们的预期:
F5.2.3 和数列求和电路进行对比
在学习数字电路时, 有一道必做题要求你通过寄存器和加法器, 计算出
1+2+...+10的结果. 现在你用sCPU完成了同样的计算, 尝试对比两个方案各有什么优点和缺点.
先前的数字求和电路,是通过设计电路的模式来实现”程序”的运行,那种行为类似于程序中的硬编码,比较死板,而且不方便改动。我们每想运行一个程序都需要重新设计一个电路。
但是想这种通过操控寄存器的方法,明显为我们带来了更好的可拓展性,我们可以通过现有的三个指令,运行各种加法程序。我们只需要对指令的内容进行改动就好了,这给我们带来了更好的可拓展性。所以我认为这是一种进步。不过相应的,为了满足电路能够运行指令,我们的设计也会更加的复杂,无法像先前的电路一样轻便。
F5.3.1 计算10以内的奇数之和
编写一段指令序列, 计算10以内的奇数之和, 即
1+3+5+7+9. 然后尝试用你设计的sCPU指令这段指令序列, 检查运行结果是否符合预期
首先我们需要为其编写相应的指令:
1 | 0: li r0, 11 |
然后将程序编写进我们的ROM中,执行得到结果如下(R2 = 0x19 = 25):
F5.3.2. 添加新指令
尝试为sISA添加一条新指令
out rs, 执行该指令后, 会将R[rs]以十六进制的形式输出到七段数码管. 你可以自行决定这条指令的编码.然后, 在sCPU中实现
out指令, 并修改数列求和程序, 使得在计算出结果后, 能在七段数码管中显示计算结果.
首先向我们的ISA中添加out的格式:
1 | 7 6 5 4 3 2 1 0 |
这个指令只需要读取rs2作为输入就可以了,所以我们添加一个显示内容的电路,就可以完成啦: