riscv-mini 学习记录三 RegFile模块和ImmGen模块

一、RegFile模块

在记录一中,我们列出了RV32I的32个寄存器。下面分析寄存器模块的定义。

package mini

import chisel3._
import freechips.rocketchip.config.Parameters

class RegFileIO(implicit p: Parameters)  extends CoreBundle()(p) {
  val raddr1 = Input(UInt(5.W))
  val raddr2 = Input(UInt(5.W))
  val rdata1 = Output(UInt(xlen.W))
  val rdata2 = Output(UInt(xlen.W))
  val wen    = Input(Bool())
  val waddr  = Input(UInt(5.W))
  val wdata  = Input(UInt(xlen.W))
}

class RegFile(implicit val p: Parameters) extends Module with CoreParams {
  val io = IO(new RegFileIO)
  val regs = Mem(32, UInt(xlen.W))
  io.rdata1 := Mux(io.raddr1.orR, regs(io.raddr1), 0.U)
  io.rdata2 := Mux(io.raddr2.orR, regs(io.raddr2), 0.U)
  when(io.wen & io.waddr.orR) {
    regs(io.waddr) := io.wdata
  }
}

从上面的代码中可以看到,寄存器模块分为接口定义和寄存器定义两个部分。

接口分为读寄存器和写寄存器,由于指令通常需要一次读取2个源寄存器RS1和RS2,写回的时候,通常只需要对一个目的寄存器RD进行读写,因此接口定义为2个读接口和一个写接口,通常读接口在译码阶段就需要读出,写接口在写回阶段会写入。寄存器的地址来自与指令中rs1 rs2 和rd 部分。

regs用Mem 硬件模型定义,第一个参数是数量,第二个参数是位宽,位宽xlen来自与参数中预定义,这里是32.

io.rdata1 用:=进行赋值,因为之前用val定义的,在scala里不能用=赋值的,这里chisel 定义了新的:= 操作方法用于赋值。regs(io.raddr1) 调用Mem定义的apply方法,参数是寄存器地址。读出寄存器值。应为需要一直读取寄存器,因此没有使能定义。

写寄存器有一个io.wen使能信号,when chisel定义的触发条件,条件成立,写入寄存器rd。

二、immgen模块

/ See LICENSE for license details.

package mini

import chisel3._
import chisel3.util._
import freechips.rocketchip.config.Parameters
import Control._

class ImmGenIO(implicit p: Parameters) extends CoreBundle()(p) {
  val inst = Input(UInt(xlen.W))
  val sel  = Input(UInt(3.W))
  val out  = Output(UInt(xlen.W))
}

abstract class ImmGen(implicit p: Parameters) extends Module {
  val io = IO(new ImmGenIO)
}

class ImmGenWire(implicit p: Parameters) extends ImmGen()(p) {
  val Iimm = io.inst(31, 20).asSInt
  val Simm = Cat(io.inst(31, 25), io.inst(11,7)).asSInt
  val Bimm = Cat(io.inst(31), io.inst(7), io.inst(30, 25), io.inst(11, 8), 0.U(1.W)).asSInt
  val Uimm = Cat(io.inst(31, 12), 0.U(12.W)).asSInt
  val Jimm = Cat(io.inst(31), io.inst(19, 12), io.inst(20), io.inst(30, 25), io.inst(24, 21), 0.U(1.W)).asSInt
  val Zimm = io.inst(19, 15).zext

  io.out := MuxLookup(io.sel, Iimm & -2.S, 
    Seq(IMM_I -> Iimm, IMM_S -> Simm, IMM_B -> Bimm, IMM_U -> Uimm, IMM_J -> Jimm, IMM_Z -> Zimm)).asUInt
}

class ImmGenMux(implicit p: Parameters) extends ImmGen()(p) {
  val sign = Mux(io.sel === IMM_Z, 0.S, io.inst(31).asSInt)
  val b30_20 = Mux(io.sel === IMM_U, io.inst(30,20).asSInt, sign)
  val b19_12 = Mux(io.sel =/= IMM_U && io.sel =/= IMM_J, sign, io.inst(19,12).asSInt)
  val b11 = Mux(io.sel === IMM_U || io.sel === IMM_Z, 0.S,
            Mux(io.sel === IMM_J, io.inst(20).asSInt,
            Mux(io.sel === IMM_B, io.inst(7).asSInt, sign)))
  val b10_5 = Mux(io.sel === IMM_U || io.sel === IMM_Z, 0.U, io.inst(30,25))
  val b4_1 = Mux(io.sel === IMM_U, 0.U,
             Mux(io.sel === IMM_S || io.sel === IMM_B, io.inst(11,8),
             Mux(io.sel === IMM_Z, io.inst(19,16), io.inst(24,21))))
  val b0 = Mux(io.sel === IMM_S, io.inst(7),
           Mux(io.sel === IMM_I, io.inst(20),
           Mux(io.sel === IMM_Z, io.inst(15), 0.U)))

  io.out := Cat(sign, b30_20, b19_12, b11, b10_5, b4_1, b0).asSInt.asUInt
}

immgen模块单独拿出来用于对指令中的imm 立即数生成 作为ALU模块的B操作数输入到ALU模块进行运算,在这里asInt扩展成32位有符号数。

immgen模块输入 为取值阶段输入的指令 和control模块输入的imm_sel,输出为产生的立即数。

ImmGenWire简单粗暴,直接根据imm_sel,把 每种指令类型产生的imm直接输出。而ImmGenMux是按照32位中的每一部分,分别根据涉及到的指令类型 进行数据产生。最后用Cat组合成32位立即数赋值给io.out.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值