我们计组老师让我们写出jalr的实现, 于是正好总结一下单周期cpu是如何执行指令的.
周期开始, PC在时钟周期上升沿读取送来的地址, 随后组合电路 Instruction Memory 在一个短小的延迟后输出了指令.
随后, 指令被分为了多个部分, 送往寄存器文件, 立即数生成器和控制单元.
我们现在主要关注作为I-type
指令的 jalr
, 其指令格式是:
其作用是将当前 PC 中的地址送入 rd
(通常是 ra
), 然后把 rs1 + immediate
的值送入PC.
而return
一般用代码 jalr x0, ra, x0
实现.
我们可以看到, 其 0~6
位的 opcode
被送往了 control
单元.
然后, 在阅读了 opcode
后, control
单元会生成以下信号:
ALUop
, 这是一个两位的指令, 被送往ALU. 其用于决定ALU执行什么类型的运算. (add sub and or… etc.)
不同情况下的ALUop
如下:
在这里, 我们的ALU要实现一个加法, 并且不需要查看funct3的值. 我们可以合理推测其ALUOP也是 00.
ALU control 在收到ALUOP后, 发现自己不需要看funt3 和 funt7, 于是生成了一个 值为 0010
的ALU control.
而 ALU control 将会告诉ALU, 其需要做的就是对其的两个输入求和.
-
ALUsrc 用于控制ALU的第二个输入是立即数还是寄存器, 这里我们是I型指令, 于是ALUSrc 为1.
-
Memread, MemtoReg, RegWrite: 这个例子中不需要读写内存, 但是需要向寄存器写入数据. 因此前两者为0, RegWrite为1.
-
Jump (这是我们新增的一个控制) 用于控制ALU的结果是否会用于PC跳转, 这里我们需要将PC设为
imm + rs1
, 因此毋庸置疑要设为1. -
Branch 关于PC的跳转, 我们已经交由Jump控制, 所以Branch 的值无关紧要.
现在, 所有信号均已就位. 数据继续运行.
指令的19~15位被送入寄存器文件, ALU的端口Read data 1 被送入了一个数据.
与此同时, 指令的11~7位被送入了寄存器文件. 这是我们的rd寄存器.
整个指令被送入了立即数生成器, 它生成了一个imm.
由于ALUSrc 的存在, Mux被标记为1, 立即数和rs
里的值被执行加法.
把ALU输出的值和Jump
做一个与(这里增加一个与门), 接入上方的mux. (注意这里不要经过移位器, jalr
和j-type
, b-type
不同, 立即数是不左移的.)
然后把jump
和branch
和zero
的与做一个或, 接入mux的控制位, 这么一来这个问题就解决了.
即使如此, 还是有很多小知识点没有总结, 我会在期中考试前夕完成一个完整的知识点总结. 今晚要完成离散数学的第四章内容.