基于RISC-V指令集的CPU设计和FPGA实现(一)
概述
实现该32位CPU为哈尔滨工业大学(深圳)大二小学期的实验,基于RISC-V的指令集架构和Xilinx开发板( XC7A100T-1FGG484C)开发的FPGA处理器。
该CPU将会实现37条基础指令,包括 算术运算指令、逻辑运算指令、移位运算指令、载入指令、存储指令、条件跳转指令、无条件跳转指令、比较指令。同时采用统一编址的方式实现与外设的连接和交互。
实现的指令:
| 指令类型 | 指令 |
|---|---|
| 算术运算指令 | add, addi, sub, lui, auipc |
| 逻辑运算指令 | and, andi, or, ori, xor, xori |
| 移位运算指令 | sll, slli, srl, srli, sra, srai |
| 载入&存储指令 | lw, sw, lb, lbu, lh, lhu, sb, sh |
| 跳转指令 | beq, bne, blt, bge, bltu, bgeu |
| 无条件跳转指令 | jal, jalr |
| 比较指令 | slt, slti, sltu, sltiu |
该专栏将分为 单周期CPU 和 流水线CPU 的实现,同时探索超标量CPU 的简单实现。在实现后通过学校的测试程序并运行自己写的简单的计算器程序。
需要具备的知识:
-
数字逻辑电路基础
-
计算机组成原理
-
RISC-V 汇编
-
Verilog 开发
工具
-
RARS模拟器1.4
-
WSL2 + Ubuntu22.04
-
VSCode和一系列插件
-
VIVADO 2018.3
-
Logisim
参考书目:
-
《计算机组成与设计(硬件/软件接口)第五版》
-
《计算机组成原理 第三版》(唐朔飞著)
-
《超标量处理器设计》(姚永斌著)
-
学校的实验指导书
计算器程序
要求
从拨码开关输入操作类型和操作数(8位),判断操作类型并实现加法、减法、按位与、按位或、左移、右移、乘法的计算,输出结果(32位)到数码管LED
拨码开关(24位)输入数据的结构如下:
| 操作数 | NOP | NUM1 | NUM2 |
|---|---|---|---|
| 23---21 | 20---16 | 15---8 | 7---0 |
RARS 操作
对于测试的电路,学校是给了个Logisim模拟电路的,这里涉及版权就不放出了。但是通过RARS模拟器通过改变输入操作数也能够达到测试的效果。

注意:
-
由于需要将该代码写入CPU进行执行,需要确保该代码只用到要实现的指令,不然可能判断出错或者没有效果。
-
由于写的是 32 位 CPU,新版的 RARS 会有 64 位的选项,可以在 Settings 选项卡中关闭
-
对于
.data段定义的数据地址可以在Settings -> Memory Configuration中找到和更改,这里.data的数据从0x00002000开始
程序源码
.data# 测试用数据,在这里写入测试用的拨码开关操作数switch: .word 0x00E003FE.text# 寄存器含义# s3 : switch# s1 : num1# s2 : num2# s0 : ope# a0 : resINIT:addi t2, zero, -0x080 # t2 = 0xFFFFF80 符号扩展用# Release,上板的时候将下面代码取消注释lui t1, 0xFFFFFlw s3, 0x70(t1) # read switch# Debug, 测试的时候将下面代码取消注释# lui s3, 0x00002# lw s3, 0x0(s3)# 译码操作addi t1, zero, 0x80NUM2:andi s2, s3, 0x0FF blt s2, t1, NUM1or s2, s2, t2 # 符号扩展NUM1:srli s1, s3, 8andi s1, s1, 0x0FFblt s1, t1, OPEor s1, s1, t2 # 符号扩展OPE:srli s0, s3, 21andi s0, s0, 0x007# Initialize res registeraddi a0, zero, 0 # 选择操作SWITCH: # Choose operationaddi t0, zero, 0beq s0, t0, INITaddi t0, t0, 1beq s0, t0, ADDaddi t0, t0, 1beq s0, t0, SUBaddi t0, t0, 1beq s0, t0, ANDaddi t0, t0, 1beq s0, t0, ORaddi t0, t0, 1beq s0, t0, MV_LEFTaddi t0, t0, 1beq s0, t0, MV_RIGHTaddi t0, t0, 1beq s0, t0, MULjal x0, INIT # Default# 加法运算ADD:add a0, s1, s2jal x0, EXIT# 减法运算SUB:sub a0, s1, s2jal x0, EXIT# 按位与运算AND:and a0, s1, s2jal x0, EXIT# 按位或运算OR:or a0, s1, s2jal x0, EXIT# 逻辑左移MV_LEFT:sll a0, s1, s2jal x0, EXIT# 逻辑右移MV_RIGHT:sra a0, s1, s2jal x0, EXIT# 补码一位乘(反向)实现MUL: addi t0, zero, 30# 负数单独处理bge s2, zero, MUL_LOOPsub a0, a0, s1MUL_LOOP:slli a0, a0, 1# 判断是否加上 num1sra t1, s2, t0andi t1, t1, 1beq t1, zero, MUL_NOPadd a0, a0, s1MUL_NOP:addi t0, t0, -1bge t0, zero, MUL_LOOP# 最后处理MUL_END:jal x0, EXIT# 退出处理(循环)EXIT:lui t1, 0xFFFFFsw a0, 0x60(t1) # 写 LED 灯,只需一次END_KEEP:sw a0, 0x00(t1) # 写数码管,需要稳定刷新lw t0, 0x70(t1) # 监视指令变更beq s3, t0, END_KEEPjal x0, INIT
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
