riscv

您所在的位置:网站首页 minu翻译 riscv

riscv

2023-08-14 04:31| 来源: 网络整理| 查看: 265

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录 前言一、RV32I基本整数指令集二、使用步骤 1.引入库2.定义单例对象control3 对外接口ControlSignals4 定义Control模块总结

前言

        RISC-V(读音“risk-five”)是一个新的指令集体系结构(ISA),它最初用于支持计算机体系结构研究和教学,该项目2010年始于加州大学伯克利分校。我大学不是学的计算机专业,学的是电气专业,但是怀着一颗探索世界的初心,自学了王爽老师的《汇编语言》之后,对cpu运行原理越来越感兴趣。尤其回想其最后用bochs启动自己写的调用bios中断程序,运行出现菜单的那一幕,仍然感到油然而生的成就感。工作之后没有太多业余时间,后来学习了雷思磊老师的《自己动手写cpu》,从搭建流水线架构的第一行代码起,到最后把一条一条指令的把指令添加到框架里,到运行程序,我学到了很多cpu 流水线,冒险,流水线控制的知识。后来结合着MIT的alpha21264 源码,学习了姚永斌老师的《超标量处理器设计》,学习了多线程乱序的实现。alpha21264 源码简洁明了,有助于初学者学习,每一个部件都是姚老师书中的完美实现。risc-v我接触的很早,刚开始公布的时候,就在自己家电脑里跑了一下rocket。后来好多年没有接触了,最近越来越火,又重新点燃了学习的兴趣。

      看代码首先是了解思想,思想最终要,思想就是算法,最后希望我的专栏能够带你入门cpu设计

一、RV32I基本整数指令集

基本指令集中程序源模型如下:

有31个通用寄存器,一个0值寄存器和一个PC 指令地址寄存器。

 

基本指令格式如图所示。可以看到非常整齐,没有arm的那么多花花绕绕。mips也是非常整齐。

 含有立即数的指令需要扩展成32位格式

 

 

二、解码模块control解析 1.引入库 package mini import chisel3._ import chisel3.util.ListLookup import freechips.rocketchip.config.Parameters

第1行 定义mini包,3-5行 用import 引用其他包,因为chisel本质是scala语言,需要统一引入chisel3,Parameters是可裁剪参数引用。参考chisel参数机制

2.定义单例对象control object Control { val Y = true.B val N = false.B // pc_sel val PC_4 = 0.U(2.W) val PC_ALU = 1.U(2.W) val PC_0 = 2.U(2.W) val PC_EPC = 3.U(2.W) // A_sel val A_XXX = 0.U(1.W) val A_PC = 0.U(1.W) val A_RS1 = 1.U(1.W) // B_sel val B_XXX = 0.U(1.W) val B_IMM = 0.U(1.W) val B_RS2 = 1.U(1.W) // imm_sel val IMM_X = 0.U(3.W) val IMM_I = 1.U(3.W) val IMM_S = 2.U(3.W) val IMM_U = 3.U(3.W) val IMM_J = 4.U(3.W) val IMM_B = 5.U(3.W) val IMM_Z = 6.U(3.W) // br_type val BR_XXX = 0.U(3.W) val BR_LTU = 1.U(3.W) val BR_LT = 2.U(3.W) val BR_EQ = 3.U(3.W) val BR_GEU = 4.U(3.W) val BR_GE = 5.U(3.W) val BR_NE = 6.U(3.W) // st_type val ST_XXX = 0.U(2.W) val ST_SW = 1.U(2.W) val ST_SH = 2.U(2.W) val ST_SB = 3.U(2.W) // ld_type val LD_XXX = 0.U(3.W) val LD_LW = 1.U(3.W) val LD_LH = 2.U(3.W) val LD_LB = 3.U(3.W) val LD_LHU = 4.U(3.W) val LD_LBU = 5.U(3.W) // wb_sel val WB_ALU = 0.U(2.W) val WB_MEM = 1.U(2.W) val WB_PC4 = 2.U(2.W) val WB_CSR = 3.U(2.W) import Instructions._ import ALU._ val default = // kill wb_en illegal? // pc_sel A_sel B_sel imm_sel alu_op br_type | st_type ld_type wb_sel | csr_cmd | // | | | | | | | | | | | | | List(PC_4, A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, Y) val map = Array( LUI -> List(PC_4 , A_PC, B_IMM, IMM_U, ALU_COPY_B, BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), AUIPC -> List(PC_4 , A_PC, B_IMM, IMM_U, ALU_ADD , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), JAL -> List(PC_ALU, A_PC, B_IMM, IMM_J, ALU_ADD , BR_XXX, Y, ST_XXX, LD_XXX, WB_PC4, Y, CSR.N, N), JALR -> List(PC_ALU, A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, Y, ST_XXX, LD_XXX, WB_PC4, Y, CSR.N, N), BEQ -> List(PC_4 , A_PC, B_IMM, IMM_B, ALU_ADD , BR_EQ , N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), BNE -> List(PC_4 , A_PC, B_IMM, IMM_B, ALU_ADD , BR_NE , N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), BLT -> List(PC_4 , A_PC, B_IMM, IMM_B, ALU_ADD , BR_LT , N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), BGE -> List(PC_4 , A_PC, B_IMM, IMM_B, ALU_ADD , BR_GE , N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), BLTU -> List(PC_4 , A_PC, B_IMM, IMM_B, ALU_ADD , BR_LTU, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), BGEU -> List(PC_4 , A_PC, B_IMM, IMM_B, ALU_ADD , BR_GEU, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), LB -> List(PC_0 , A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, Y, ST_XXX, LD_LB , WB_MEM, Y, CSR.N, N), LH -> List(PC_0 , A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, Y, ST_XXX, LD_LH , WB_MEM, Y, CSR.N, N), LW -> List(PC_0 , A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, Y, ST_XXX, LD_LW , WB_MEM, Y, CSR.N, N), LBU -> List(PC_0 , A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, Y, ST_XXX, LD_LBU, WB_MEM, Y, CSR.N, N), LHU -> List(PC_0 , A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, Y, ST_XXX, LD_LHU, WB_MEM, Y, CSR.N, N), SB -> List(PC_4 , A_RS1, B_IMM, IMM_S, ALU_ADD , BR_XXX, N, ST_SB , LD_XXX, WB_ALU, N, CSR.N, N), SH -> List(PC_4 , A_RS1, B_IMM, IMM_S, ALU_ADD , BR_XXX, N, ST_SH , LD_XXX, WB_ALU, N, CSR.N, N), SW -> List(PC_4 , A_RS1, B_IMM, IMM_S, ALU_ADD , BR_XXX, N, ST_SW , LD_XXX, WB_ALU, N, CSR.N, N), ADDI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_ADD , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SLTI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_SLT , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SLTIU -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_SLTU , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), XORI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_XOR , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), ORI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_OR , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), ANDI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_AND , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SLLI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_SLL , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SRLI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_SRL , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SRAI -> List(PC_4 , A_RS1, B_IMM, IMM_I, ALU_SRA , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), ADD -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_ADD , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SUB -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_SUB , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SLL -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_SLL , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SLT -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_SLT , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SLTU -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_SLTU , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), XOR -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_XOR , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SRL -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_SRL , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), SRA -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_SRA , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), OR -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_OR , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), AND -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_AND , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N), FENCE -> List(PC_4 , A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), FENCEI-> List(PC_0 , A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, Y, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N), CSRRW -> List(PC_0 , A_RS1, B_XXX, IMM_X, ALU_COPY_A, BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, Y, CSR.W, N), CSRRS -> List(PC_0 , A_RS1, B_XXX, IMM_X, ALU_COPY_A, BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, Y, CSR.S, N), CSRRC -> List(PC_0 , A_RS1, B_XXX, IMM_X, ALU_COPY_A, BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, Y, CSR.C, N), CSRRWI-> List(PC_0 , A_XXX, B_XXX, IMM_Z, ALU_XXX , BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, Y, CSR.W, N), CSRRSI-> List(PC_0 , A_XXX, B_XXX, IMM_Z, ALU_XXX , BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, Y, CSR.S, N), CSRRCI-> List(PC_0 , A_XXX, B_XXX, IMM_Z, ALU_XXX , BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, Y, CSR.C, N), ECALL -> List(PC_4 , A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, N, ST_XXX, LD_XXX, WB_CSR, N, CSR.P, N), EBREAK-> List(PC_4 , A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, N, ST_XXX, LD_XXX, WB_CSR, N, CSR.P, N), ERET -> List(PC_EPC, A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, Y, ST_XXX, LD_XXX, WB_CSR, N, CSR.P, N), WFI -> List(PC_4 , A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N)) }

obj单例对象通常用于定义同名类的常量

Y、N是用于流水线控制,可以看到Load 跳转 状态寄存器指令需要清空流水线。因为这些指令导致PC 地址发生变化。

pc_sel用于控制 PC 指令地址在下个时钟的地址变化,PC_0代表流水线暂停,指令执行需要多个周期,这时候PC地址不变,PC_4代表指令需要一个周期,PC_ALU代表跳转指令,下一条指令地址发生跳转,对于简单的流水线cpu,没有bpu单元,跳转指令需要通过ALU 计算。PC_EPC代表中断返回指令地址。

A_sel和B_sel,以及imm_sel用于选择ALU的两个输入,ALU部件有两个输入接口,详细后续介绍。

后面br_type st_type ld_type 分别用于区分3种指令类型,

wb_sel用于写回寄存器时候,根据指令类型 写的数据来源。

defult 代表nop cpu什么不做的时候,各个部件的操作。

map 用于每一条指令,流水线中各个部件需要进行的动作,这些动作相互配合,最终完成一条指令的执行。

3.对外接口ControlSignals class ControlSignals(implicit p: Parameters) extends CoreBundle()(p) { val inst = Input(UInt(xlen.W)) val pc_sel = Output(UInt(2.W)) val inst_kill = Output(Bool()) val A_sel = Output(UInt(1.W)) val B_sel = Output(UInt(1.W)) val imm_sel = Output(UInt(3.W)) val alu_op = Output(UInt(4.W)) val br_type = Output(UInt(3.W)) val st_type = Output(UInt(2.W)) val ld_type = Output(UInt(3.W)) val wb_sel = Output(UInt(2.W)) val wb_en = Output(Bool()) val csr_cmd = Output(UInt(3.W)) val illegal = Output(Bool()) }

上面比较简单,就是定义对外的接口,p引用config的参数

4、定义Control模块 class Control(implicit p: Parameters) extends Module { val io = IO(new ControlSignals) val ctrlSignals = ListLookup(io.inst, Control.default, Control.map) // Control signals for Fetch io.pc_sel := ctrlSignals(0) io.inst_kill := ctrlSignals(6).toBool // Control signals for Execute io.A_sel := ctrlSignals(1) io.B_sel := ctrlSignals(2) io.imm_sel := ctrlSignals(3) io.alu_op := ctrlSignals(4) io.br_type := ctrlSignals(5) io.st_type := ctrlSignals(7) // Control signals for Write Back io.ld_type := ctrlSignals(8) io.wb_sel := ctrlSignals(9) io.wb_en := ctrlSignals(10).toBool io.csr_cmd := ctrlSignals(11) io.illegal := ctrlSignals(12) }

上面的比较简单,首先定义接口部分,输入是inst指令,通过ListLoop 硬件模型针对不同的指令选择出对应的控制信号。最后把对应的信号赋值给输出接口。模块中没有寄存器,就有一个选择逻辑实现。

总结

上面对于具体指令的控制信号分析比较简单,后续可以根据指令手册具体分析控制信号的设置。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3