Rocket Core : 译码逻辑

2020-01-10  本文已影响0人  gs要加油呀

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)
    }
  }

以指令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历史)

上一篇下一篇

猜你喜欢

热点阅读