一生一芯F6

通过RTFM初步了解RISC-V指令集

题目

查阅RISC-V手册的目录, 你发现RV32I在哪一章进行介绍? 尝试在该章节中查阅RV32I的相关内容, 回答下列问题:

  1. PC寄存器的位宽是多少?
  2. GPR共有多少个? 每个GPR的位宽是多少?
  3. R[0]和sISA的R[0]有什么不同之处?
  4. 指令编码的位宽是多少? 指令有多少种基本格式?
  5. 在指令的基本格式中, 需要多少位来表示一个GPR? 为什么?
  6. add指令的格式具体是什么?
  7. 还有一种基础指令集称为RV32E, 它和RV32I有什么不同?

RV32I在第2章RV32I Base Integer Instruction Set, Version 2.1进行介绍:

  1. PC寄存器的位宽是32.
  2. GPR共有31个(x1-x31),每个GPR的位宽为32.
  3. RV32I中的R[0]被硬连线为全0,而sISA中R[0]则为通用寄存器.
  4. 指令编码的位宽为32.指令有6种基本格式(R/I/S/B/U/J).
  5. RV32I基本格式中至少需要4位来表示一个GPR,因为RV32I选择了32个整数寄存器的配置.
  6. add指令的具体格式为:
1
2
31      25 24     20 19     15 14   12 11     7 6        0
| 0000000 | rs2 | rs1 | 000 | rd | 0110011 |
  1. RV32E为为资源受限的嵌入式设备设计的RV32I简化版本,唯一的变化是将整数寄存器数量减少到16个。

实现两条指令的minirv处理器

题目

理解addijalr指令的功能后, 根据你之前设计sISA处理器的经验, 尝试设计一个支持这两条RISC-V指令的处理器.

由于GPR需要进行较多的连线工作, 为了减轻大家的负担, 我们准备了一个预先完成大量连线工作的GPR子模块. 下载后, 通过Logisim打开文件GPR.circ, 即可看到GPR的电路设计, 你可以整体选择这个电路后, 通过复制和粘贴将其加入到你工程中. 不过, 这个电路并没有实现GPR的完整功能, 你需要根据你对GPR的理解完善它.

1
2
3
4
5
6
7
8
9
00000000 <_start>:
0: 01400513 addi a0,zero,20
4: 010000e7 jalr ra,16(zero) # 10 <fun>
8: 00c000e7 jalr ra,12(zero) # c <halt>
0000000c <halt>:
c: 00c00067 jalr zero,12(zero) # c <halt>
00000010 <fun>:
10: 00a50513 addi a0,a0,10
14: 00008067 jalr zero,0(ra)

尝试通过指令集的状态机理解这个程序的功能. 理解后, 将程序其放置在ROM中, 并尝试运行你的处理器, 然后检查处理器的运行结果是否符合预期.

GPR模块的连线如下:
F6_GPR.png

译码模块如下:
F6_IDv1.png

miniCPU的整体结构如下:
F6_miniCPUv1.png

测试addi指令

题目

在上述测试程序中, addi指令的立即数比较小. 为了测试符号扩展的实现是否正确, 你需要让处理器执行一些立即数为负数的addi指令. 尝试编写若干条这种类型的addi指令, 并放置到ROM中, 检查你的实现是否正确.

测试以下指令:

1
2
3
0: 0x300093    addi a0, zero, 3
4: 0xfff08093 addi a0, a0, -1
8: 0x800067 jalr zero, 8(zero)

运行后,cpu的x1寄存器的值应该为2,如图所示:
miniCPUv1_test.png

实现完整的minirv处理器

题目

实现addlui指令. 实现后, 尝试编写一些简单的指令序列放置到ROM中, 来初步检查你的实现是否正确.

改动后的译码器如下:
F6_IDv2.png

整体结构如下:
F6_miniCPUv2.png

使用如下程序进行测试:

1
2
3
4
0: 0x000010b7 lui x1, 1
4: 0x00002137 lui x2, 2
8: 0x00c00067 add x1, x1, x2
c: 0x00a00067 jalr zero, c(zero)

运行后,cpu的x1寄存器的值应该为3,x2寄存器的值应为2,如图所示:
F6_miniCPUv2_test.png