美文网首页
Rocket Core : 译码逻辑

Rocket Core : 译码逻辑

作者: gs要加油呀 | 来源:发表于2020-01-10 23:24 被阅读0次

    Rocket Chip 代码注释已上传至github,持续更新中。

    Decode

    本文分析Rocket Core中的译码逻辑。

    以RV32I为例,指令集手册中RISC-V指令编码主要有下图六种类型


    常见编码格式

    译码模块需要根据opcode与func3/func7字段对指令译码,基于指令类型生成相应的控制信号送往对应模块。

    相关代码

    • Instructions.cala
    • IDecode.scala
    • Decode.scala

    Instructions.scala

    该文件基于RISC-V指令集架构手册中定义的RISC-V指令集编码,使用脚本自动生成。

    Instuctions.scala 文件主要包含三个部分:

    1. 指令集编码

    rocket-core中指令编码如下图所示

    object Instructions {
      def BEQ   = BitPat("b?????????????????000?????1100011")
      def BNE   = BitPat("b?????????????????001?????1100011")
      def BLT   = BitPat("b?????????????????100?????1100011")
      def BGE   = BitPat("b?????????????????101?????1100011")
      def BLTU  = BitPat("b?????????????????110?????1100011")
      def BGEU  = BitPat("b?????????????????111?????1100011")
      
      ...
    }
    

    为了提取opcode以及func字段,Chisel中定义了BitPat类来描述不同指令编码的pattern:

    指令编码Pattern

    width即为二进制长度,RV32I中指令的BitPat宽度均为32

    BitPat中利用parse函数来从指令Pattern中解析 value 和 mask。

    // BitPat中parse函数的关键代码
      for (d <- x.tail) {
        if (d != '_') {
          require("01?".contains(d), "Literal: " + x + " contains illegal character: " + d)
          mask = (mask << 1) + (if (d == '?') 0 else 1)
          bits = (bits << 1) + (if (d == '1') 1 else 0)
        }
      }
    
    • mask将"?"的位置标记无效,“0”和“1”有效
    • value只记录“1”的位置

    以指令BEQ为例

    def BEQ  = BitPat("b?????????????????000?????1100011")
    
    1. value : "b00000000000000000000000001100011"
    2. mask : "b00000000000000000111000001111111"

    2. Causes

    定义了异常/中断原因的编码,具体参考RISC-V指令集手册: 特权级架构

    object Causes {
      val misaligned_fetch    = 0x0 
      val fetch_access        = 0x1
      val illegal_instruction = 0x2
      val breakpoint          = 0x3
      val misaligned_load     = 0x4
      val load_access         = 0x5
      val misaligned_store    = 0x6
      val store_access        = 0x7
      val user_ecall          = 0x8
      val supervisor_ecall    = 0x9
      val hypervisor_ecall    = 0xa
      val machine_ecall       = 0xb
      val fetch_page_fault    = 0xc
      val load_page_fault     = 0xd
      val store_page_fault    = 0xf
    

    3. CSRs

    定义了CSR寄存器地址编码,具体参考RISC-V指令集手册: 特权级架构

    object CSRs {
      val ustatus = 0x0
      val uie = 0x4
      val utvec = 0x5
      val vstart = 0x8
      val vxsat = 0x9
      val vxrm = 0xa
      val uscratch = 0x40
      val uepc = 0x41
    ...
    }
    

    IDecode.scala

    IDecode : Instruction Decode, 主要包含两部分:

    1. 译码生成的控制信号
    2. 指令集译码表

    1. IntCtrlSigs: 译码得到的控制信号

    class IntCtrlSigs extends Bundle {
        // 1. 译码生成的控制信号
        val legal = Bool()  // 是否非法指令
        val fp = Bool()     // 是否浮点指令
        val rocc = Bool()   // 是否协处理器相关指令
        val branch = Bool()
        val jal = Bool()
        val jalr = Bool()
    
        // 读使能信号(xs猜测是excute stage)
        val rxs2 = Bool()
        val rxs1 = Bool()
        val scie = Bool()
    
        // ALU 控制信号
        val sel_alu2 = Bits(width = A2_X.getWidth)
        val sel_alu1 = Bits(width = A1_X.getWidth)
        val sel_imm = Bits(width = IMM_X.getWidth)
        val alu_dw = Bool()                       // double word 是否是64位
        val alu_fn = Bits(width = FN_X.getWidth)  // ALU function
    
        val mem = Bool()
        val mem_cmd = Bits(width = M_SZ)
    
        // 下面三个信号目前没找到连线,还不清楚
        val rfs1 = Bool()
        val rfs2 = Bool()
        val rfs3 = Bool()
    
        val wfd = Bool()
        val mul = Bool()
        val div = Bool()
        val wxd = Bool()
        val csr = Bits(width = CSR.SZ)
        val fence_i = Bool()
        val fence = Bool()
        val amo = Bool() // 原子指令
        val dp = Bool()  // 双精度浮点指令
        
        // 2. default:译码表缺失,说明是非法指令
        //    译码结果第一项legal信号为N,表明非法
        def default: List[BitPat] = List(N, ... X, X, X)
        
        // 3. 译码逻辑主体部分,基于指令和译码表,译码得到结果,返回该Bundle
        def decode(inst: UInt, table: Iterable[(BitPat, List[BitPat])]) = {
          
              // 调用DecodeLogic方法,译码结果存在decoder中
              val decoder = DecodeLogic(inst, default, table)
              
    
              // 利用scala高阶特性: zip + map将decoder译码结果赋值给本Bundle中
              // 展开来相当于
              //      legal   := decoder.legal
              //      fp      := decoder.fp
              //      rocc    := decoder.rocc
              //      ... 省略十几行orz
              val sigs = Seq(legal, fp, rocc, branch, jal, jalr, rxs2, rxs1, scie, sel_alu2,
                             sel_alu1, sel_imm, alu_dw, alu_fn, mem, mem_cmd,
                             rfs1, rfs2, rfs3, wfd, mul, div, wxd, csr, fence_i, fence, amo, dp)
              sigs zip decoder map {case(s,d) => s := d}
              
              // 最后返回this, 即返回赋值完成后的IntCtrlSigs
              this
          }
        
    }
    

    可以看到,译码逻辑相关的方法定义在控制信号中。

    备注:
    IntCtrlSigs命名中的Int即整数Int,与之相对应的就是浮点数的FPCtrlSigs
    FPCtrlSigs的译码逻辑与IntCtrlSigs相类似,参考FPU即可

    指令集译码表

    译码表类视图
    1. DecodeConstants定义为abstract trait,类似于C++中的虚基类,其中只定义了一个译码表(table),
    2. 剩下的所有xxxDecode均继承自DecodeConstants,内部定义了各个指令扩展的译码表(table)。

    RISC-V模块化的设计使得Rocket Core可以通过config配置需要的指令扩展,并将选择的指令译码表整合。

    举个例子,例如我们需要实现RV32IM,配置config后,Rocket Generator会将IDecode.table与MDecode.table合并成一张译码表(decode_table),合并相关的逻辑如下所示(只截取部分代码说明,完整代码见RocketCore.scala)

      val decode_table = {
      
        // usingMulDiv来自rocket-core的配置
        (if (usingMulDiv) new MDecode(pipelinedMul) ++:
        
        // RV32I是文档中要求必须实现的部分
        Seq(new IDecode)
        
      } flatMap(_.table) // 合并成一张译码表
    

    合并逻辑在Chisel代码编译过程中自动生成所需要的译码逻辑,无关的指令集扩展会被直接无视,并不会产生冗余的译码逻辑电路。

    Decode.scala

    上面IntCtrlSigs的decode函数中调用了DecodeLogic函数来译码,该函数就定义在Decode.scala中,这里实现了Quine-McCluskey算法,以简化指令Pattern的译码逻辑。

    网络上资料讲解得比较清楚(但我没弄清楚,有点复杂orz),这里只罗列一些重要的参考资料。

    重要名词解释

    文章(来源于公众号:故事v历史)

    相关文章

      网友评论

          本文标题:Rocket Core : 译码逻辑

          本文链接:https://www.haomeiwen.com/subject/wxxvactx.html