riscv-sodor-rv32_1stage(2)

接riscv-sodor-rv32_1stage(1)的内容,先放rv32_1stage的结构图:

下面进行说明的是dpath.scala:

package Sodor
{import chisel3._
import chisel3.util._import Constants._
import Common._
import Common.Constants._//定义cpath到dpath的一些控制信号
//inst:从memory中读取的instruction
//br_eq:分支判断条件,当判断为相等时
//br_lt:分支判断条件,当有符号数,判断为小于时
//br_ltu:分支判断条件,当无符号数,判断为小于时
//csr_eret:当当前的执行指令为csr的call/break/ret时,该位置1
class DatToCtlIo(implicit conf: SodorConfiguration) extends Bundle()
{val inst   = Output(UInt(32.W))val br_eq  = Output(Bool())val br_lt  = Output(Bool())val br_ltu = Output(Bool())val csr_eret = Output(Bool())override def cloneType = { new DatToCtlIo().asInstanceOf[this.type] }
}//定义dpath的端口部分
//Flipped是反转的作用,将DebugCPath()中定义的端口反过来,并在cpath模块中命名为dcpath,即input在这边边ouput
//imem是cpath取指令的memory,MemPortIo()在/commo/memory.scala中定义,后面再说明吧,在这里知道它是声明了一片sram就可以了
//dmem是cpath出来数据的memory,MemPortIo()在/commo/memory.scala中定义,后面再说明吧,在这里知道它是声明了一片sram就可以了
//dat是在DatToCtlIo()的调用,DatToCtlIo()在上面已经做了说明
//ctl是CtlToDatIo()的调用,利用Flipped将端口的方向翻转
class DpathIo(implicit conf: SodorConfiguration) extends Bundle()
{val ddpath = Flipped(new DebugDPath())val imem = new MemPortIo(conf.xprlen)val dmem = new MemPortIo(conf.xprlen)val ctl  = Flipped(new CtlToDatIo())val dat  = new DatToCtlIo()
}//主体部分,DatPath的主要逻辑
class DatPath(implicit conf: SodorConfiguration) extends Module
{//先声明一个io的端口,调用上面的DpathIo(),并赋随机值val io = IO(new DpathIo())io := DontCare//定义几个32位、wire类型的信号//pc_next:下一个pc的值//pc_plus4:当前pc+4//br_target:分支判断的目标//jmp_target:直接跳转的目标//jump_reg_target:以寄存器的值为地址的跳转// exception_target:异常的跳转// Instruction Fetchval pc_next          = Wire(UInt(32.W))val pc_plus4         = Wire(UInt(32.W))val br_target        = Wire(UInt(32.W))val jmp_target       = Wire(UInt(32.W))val jump_reg_target  = Wire(UInt(32.W))val exception_target = Wire(UInt(32.W))//pc_next的变化情况,根据io.ctl.pc_sel的值来选择// PC Registerpc_next := MuxCase(pc_plus4, Array((io.ctl.pc_sel === PC_4)   -> pc_plus4,(io.ctl.pc_sel === PC_BR)  -> br_target,(io.ctl.pc_sel === PC_J )  -> jmp_target,(io.ctl.pc_sel === PC_JR)  -> jump_reg_target,(io.ctl.pc_sel === PC_EXC) -> exception_target))//定义一个pc register,初始值为START_ADDRval pc_reg = Reg(init = START_ADDR) //当流水线不暂停时,每个clk上升沿来时,将pc_next的值赋给pc_regwhen (!io.ctl.stall) {pc_reg := pc_next}//pc_plus4的值为pc_reg+4,即当前pc+4,在不支持压缩指令的情况下,pc的运行以word对齐pc_plus4 := (pc_reg + 4.asUInt(conf.xprlen.W))               //请求memory中instruction的数据,请求地址为pc的值,请求信号为true,当io.imem.resp.valid为假//时,inst输出BUBBLE,当然这里永远都是真的io.imem.req.bits.addr := pc_regio.imem.req.valid := true.B val inst = Mux(io.imem.resp.valid, io.imem.resp.bits.data, BUBBLE) //提前指令中rs1,rs2,wb的地址,提前rs1,rs2,wb通用寄存器的编号,这里需要对RISCV指令比较熟悉// Decodeval rs1_addr = inst(RS1_MSB, RS1_LSB)val rs2_addr = inst(RS2_MSB, RS2_LSB)val wb_addr  = inst(RD_MSB,  RD_LSB)//声明wb_data信号,位宽为conf.xprlen的长度val wb_data = Wire(UInt(conf.xprlen.W))//声明通用寄存器,32个通用寄存器,通用寄存器的位宽为conf.xprlen// Register Fileval regfile = Mem(UInt(conf.xprlen.W), 32)//当写寄存器使能了,且写的寄存器编号不为0,同时没有异常生成时,将wb_data赋给相应的寄存器//这步操作是在时钟上升沿来时完成,类似于always @(posedge clk)
when (io.ctl.rf_wen && (wb_addr != 0.U) && !io.ctl.exception){regfile(wb_addr) := wb_data}//debug用的接口,当在debug模式时,给出了ddpath.addr,即将相应寄存器的值赋给ddpath.rdata//类似的,当ddpath.validreq有效时,将debug写的ddpath.wdata赋给相应的寄存器中(ddpath.addr)DebugModuleio.ddpath.rdata := regfile(io.ddpath.addr)when(io.ddpath.validreq){regfile(io.ddpath.addr) := io.ddpath.wdata}/////根据inst中提取rs1,rs2的寄存器编号,利用这个编号提取寄存器中的值,若rs1和rs2为0时,则//rs1_data,rs2_data输出0值val rs1_data = Mux((rs1_addr != 0.U), regfile(rs1_addr), 0.asUInt(conf.xprlen.W))val rs2_data = Mux((rs2_addr != 0.U), regfile(rs2_addr), 0.asUInt(conf.xprlen.W))//如果inst中包含的不是寄存器的编号,即不是rs1,rs2和wb的编号,而是立即数的话,则通过下面//的步骤将立即数重组,不同指令有不同立即数类型,这点需要看RISCV指令的用户使用册2.2// immediatesval imm_i = inst(31, 20) val imm_s = Cat(inst(31, 25), inst(11,7))val imm_b = Cat(inst(31), inst(7), inst(30,25), inst(11,8))val imm_u = inst(31, 12)val imm_j = Cat(inst(31), inst(19,12), inst(20), inst(30,21))val imm_z = Cat(Fill(27,0.U), inst(19,15))//下面是对符号位进行扩展,将符号位进行高位填充// sign-extend immediatesval imm_i_sext = Cat(Fill(20,imm_i(11)), imm_i)val imm_s_sext = Cat(Fill(20,imm_s(11)), imm_s)val imm_b_sext = Cat(Fill(19,imm_b(11)), imm_b, 0.U)val imm_u_sext = Cat(imm_u, Fill(12,0.U))val imm_j_sext = Cat(Fill(11,imm_j(19)), imm_j, 0.U)//根据ctl.op1_sel信号来选择alu_op1是rs1_data(寄存器的值),还是U类立即数imm_u_sext,//还是Z类的立即数imm_z,或者是0val alu_op1 = MuxCase(0.U, Array((io.ctl.op1_sel === OP1_RS1) -> rs1_data,(io.ctl.op1_sel === OP1_IMU) -> imm_u_sext,(io.ctl.op1_sel === OP1_IMZ) -> imm_z)).toUInt//根据ctl.op2_sel信号来选择alu_op2是rs2_data(寄存器的值),还是pc寄存器的值,还是I类立即数//imm_u_sext,还是S类的立即数imm_z,或者是0val alu_op2 = MuxCase(0.U, Array((io.ctl.op2_sel === OP2_RS2) -> rs2_data,(io.ctl.op2_sel === OP2_PC)  -> pc_reg,(io.ctl.op2_sel === OP2_IMI) -> imm_i_sext,(io.ctl.op2_sel === OP2_IMS) -> imm_s_sext)).toUInt//定义一个alu_out信号,位宽为conf.xprlen// ALUval alu_out   = Wire(UInt(conf.xprlen.W))//定义一个alu_shamt信号,取alu_op2数据的低5位val alu_shamt = alu_op2(4,0).toUInt//进行ALU运算,根据ctl.alu_fun信号来确定运算的类型,->为运算的逻辑,最后将运算值赋给alu_outalu_out := MuxCase(0.U, Array((io.ctl.alu_fun === ALU_ADD)  -> (alu_op1 + alu_op2).toUInt,(io.ctl.alu_fun === ALU_SUB)  -> (alu_op1 - alu_op2).toUInt,(io.ctl.alu_fun === ALU_AND)  -> (alu_op1 & alu_op2).toUInt,(io.ctl.alu_fun === ALU_OR)   -> (alu_op1 | alu_op2).toUInt,(io.ctl.alu_fun === ALU_XOR)  -> (alu_op1 ^ alu_op2).toUInt,(io.ctl.alu_fun === ALU_SLT)  -> (alu_op1.toSInt < alu_op2.toSInt).toUInt,(io.ctl.alu_fun === ALU_SLTU) -> (alu_op1 < alu_op2).toUInt,(io.ctl.alu_fun === ALU_SLL)  -> ((alu_op1 << alu_shamt)(conf.xprlen-1, 0)).toUInt,(io.ctl.alu_fun === ALU_SRA)  -> (alu_op1.toSInt >> alu_shamt).toUInt,(io.ctl.alu_fun === ALU_SRL)  -> (alu_op1 >> alu_shamt).toUInt,(io.ctl.alu_fun === ALU_COPY1)-> alu_op1))//跳转目标的处理//br_target:当前pc加br的立即数//jmp_target:当前pc+跳转的立即数// jump_reg_target:rs1寄存器值+立即数的跳转// Branch/Jump Target Calculationbr_target       := pc_reg + imm_b_sextjmp_target      := pc_reg + imm_j_sextjump_reg_target := (rs1_data.toUInt + imm_i_sext.toUInt)// Control Status Registers//什么一个csr的模块,调用CSRFile()val csr = Module(new CSRFile())csr.io := DontCare//根据inst数据中的(CSR_ADDR_MSB,CSR_ADDR_LSB)来确定是哪个csr寄存器需要被操作csr.io.decode.csr := inst(CSR_ADDR_MSB,CSR_ADDR_LSB)//根据ctl.csr_cmd的信号来说明csr的具体操作是什么,如写/读/清除/置位csr.io.rw.cmd   := io.ctl.csr_cmd //操作csr寄存器的数据csr.io.rw.wdata := alu_out//csr寄存器中有一个特别的csr寄存器为instret,用于记录某时刻开始后系统执行了多少条指令//这里csr模块中的retire就是用于记录执行了多少条指令,当流水线不暂停时,每个//时钟来临,retiret都会为1,然后instret就自动+1csr.io.retire    := !io.ctl.stall//csr寄存器记录系统是否有异常csr.io.exception := io.ctl.exception//csr模块中的pc信号记录当前pc寄存器的值 csr.io.pc        := pc_reg//若发生异常时,异常跳转的目标由csr模块中的csr.io.evec(这是一个csr寄存器)给出exception_target := csr.io.evec//将csr的eret信号传输给cpath模块,用于下一个pc的选择io.dat.csr_eret := csr.io.eret// Add your own uarch counters here!//增加自定义的计数器,非指令集规定的计数器csr.io.counters.foreach(_.inc := false.B)//writeback数据的选择,通过cpath模块传过来WB_ALU信号进行选择,是ALU的运算结果alu_out//还是mem数据的读取,还是当前pc+4后的值,还是csr寄存器读取的值// WB Muxwb_data := MuxCase(alu_out, Array((io.ctl.wb_sel === WB_ALU) -> alu_out,(io.ctl.wb_sel === WB_MEM) -> io.dmem.resp.bits.data, (io.ctl.wb_sel === WB_PC4) -> pc_plus4,(io.ctl.wb_sel === WB_CSR) -> csr.io.rw.rdata))//dpath模块给cpath模块的数据//inst为指令的数据,若(rs1_data === rs2_data),则br_eq为1,若有符号数(rs1_data.toSInt < rs2_data.toSInt)//则br_lt为1,若无符号数(rs1_data.toUInt < rs2_data.toUInt),则br_ltu为1// datapath to controlpath outputsio.dat.inst   := instio.dat.br_eq  := (rs1_data === rs2_data)io.dat.br_lt  := (rs1_data.toSInt < rs2_data.toSInt) io.dat.br_ltu := (rs1_data.toUInt < rs2_data.toUInt)//dpath模块请求写data到memory中,请求地址为alu_out,写的数据为无符号的rs2_data// datapath to data memory outputsio.dmem.req.bits.addr  := alu_outio.dmem.req.bits.data := rs2_data.toUInt //这部分是打印的内容,与dpath的主体逻辑无关,用于在spike跑仿真时,能打印流水线的相关内容,//所以这部分我不做详细说明了// Printout// pass output through the spike-dasm binary (found in riscv-tools) to turn// the DASM(%x) into a disassembly string.printf("Cyc= %d Op1=[0x%x] Op2=[0x%x] W[%c,%d= 0x%x] %c Mem[%d: R:0x%x W:0x%x] PC= 0x%x %c%c DASM(%x)\n", csr.io.time(31,0), alu_op1, alu_op2, Mux(io.ctl.rf_wen, Str("W"), Str("_")), wb_addr, wb_data, Mux(csr.io.exception, Str("E"), Str(" ")) // EXC -> E, io.ctl.wb_sel, io.dmem.resp.bits.data, io.dmem.req.bits.data, pc_reg, Mux(io.ctl.stall, Str("s"), Str(" ")), Mux(io.ctl.pc_sel  === 1.U, Str("B"),Mux(io.ctl.pc_sel === 2.U, Str("J"),Mux(io.ctl.pc_sel === 3.U, Str("K"),// JR -> KMux(io.ctl.pc_sel === 4.U, Str("X"),// EX -> XMux(io.ctl.pc_sel === 0.U, Str(" "), Str("?")))))), inst)if (PRINT_COMMIT_LOG){when (!io.ctl.stall){// use "sed" to parse out "@@@" from the other printf code above.val rd = inst(RD_MSB,RD_LSB)when (io.ctl.rf_wen && rd != 0.U){printf("@@@ 0x%x (0x%x) x%d 0x%x\n", pc_reg, inst, rd, Cat(Fill(32,wb_data(31)),wb_data))}.otherwise{printf("@@@ 0x%x (0x%x)\n", pc_reg, inst)}}}
}}

riscv-sodor-rv32_1stage(2)相关推荐

  1. 五、分享优秀的 RISC-V 项目资源

    处理器实现 BOOM: Christopher Celio的RV64乱序处理器实现.Chisel, BSD Licensed. [GitHub] [Doc] BottleRocket: RV32IMC ...

  2. 常见RISC-V介绍

    当前一颗新出的CPU:RISC-V简直火透了半边天,无论是财大气粗的阿里系的平头哥,还是新创企业,似乎只要和RISC-V挂上钩就足可以实现赶英超美.那事实上RISC-V是什么?除了国内那些简直红透了半 ...

  3. 基于RISC-V架构的开源处理器及SoC研究综述

    RISC-V是加州大学伯克利分校(University of California at Berkeley,以下简称UCB)设计并发布的一种开源指令集架构,其目标是成为指令集架构领域的Linux,应用 ...

  4. RISC-V架构总结1

    国产芯片能够自主一直是大家共同的期待!但无奈起步较晚,目前的通用计算平台已经是外国企业的天下.国产自主的芯片不仅仅是在工艺上还达不到目前商用芯片的水平,最底层的CPU指令集架构上也是处处受制于ARM, ...

  5. 优秀的 Verilog/FPGA开源项目介绍(三十六)-RISC-V(新增一)

    关于RISC-V的二三事 risc-v官网 ❝ https://riscv.org/ RISC-V(跟我读:"risk----------------five")是一个基于精简指令 ...

  6. Imagination发布四款RISC-V CPU

    Imagination发布四款RISC-V CPU RISC-V(发音为"risk-five")是一个基于精简指令集(RISC)原则的开源指令集架构(ISA). 与大多数指令集相比 ...

  7. Arm Cortex-M23 MCU,Arm Cortex-M33 MCU与RISC-V MCU技术

    Arm Cortex-M23 MCU,Arm Cortex-M33 MCU与RISC-V MCU技术 本文介绍以下技术 Arm Cortex-M23 MCU Arm Cortex-M33 MCU RI ...

  8. RISC-V与DSA计算机架构

    RISC-V与DSA计算机架构 相信所有和计算机体系结构打过交道的朋友们都看过David Patterson与John Hennessy的煌煌巨作,<计算机体系架构:量化研究方法>.两位在 ...

  9. RISC-V架构上的Debian和Fedora现状

    RISC-V仍然是开源/Linux用户非常感兴趣的,因为它是免版税且完全开放的CPU架构.部分原因是由于缺乏经济实惠的RISC-V硬件,限制了开发人员在这种架构上的更多工作,Linux发行版支持的RI ...

  10. RISC-V 正在成为芯片世界中的 Linux

    [编者按]芯片推动了人类社会数字化.信息化.智能化的发展.从某种程度上来说,芯片技术的发展也影响着行业未来的走向.你觉得未来的芯片世界将会如何? 编译 | 虎说八道  责编 | 张文 头图 | CSD ...

最新文章

  1. 车载360度全景监视系统
  2. 《税务登记管理办法》
  3. python练习题:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度
  4. c#利用宏定义调试代码
  5. GA,RC,Alpha,Beta,Final等软件版本名词释义
  6. Linux C 编程技巧--利用有限状态机模型编程
  7. 心电图 python_ST段凹面型向上抬高,一定是早期复极?心电图读图第201期
  8. LoadRunner动态连接库函数的调用
  9. win7免费升级win10官方工具
  10. 【转载】世界上最牛的编辑器: Vim 3 (原创动图演示所有例子!)
  11. 苹果软解ID软件(X.PASSWORD-XIMEI 苹果id锁)--上帝左手汉化组(内附即时更新)
  12. Spring核心之一:Spring的配置文件是干什么的
  13. 软件测试团队口号及队名,团队口号及队名精选
  14. 第一章 复数 1-2 复数的几何表示
  15. 【云原生 | Kubernetes 系列】K8s 实战 管理 Secret 详解
  16. Hbase完全分布式部署
  17. 微信小程序怎么实现防止截屏
  18. 嵌入式裸机课程之C语言程序调用和重定位学习笔记
  19. include,include_once,require,require_once的区别
  20. ”核高基“培育”外国种“(COM)究竟是谁的责任?

热门文章

  1. dataframe列时间字段提取年、月、日、时、分
  2. 文献翻译-北京大学黄岩谊课题组在nature biotechnology的ECC测序方法文章
  3. ffmpeg js转换音频_linux下使用ffmpeg将amr转成mp3
  4. NOIP 陶陶摘苹果
  5. 【Python】如何判断丑数
  6. EMI-EMC设计注意事项
  7. [原创]java实现word转pdf
  8. opencv android安装教程,opencv for android安装教程.doc
  9. 【渝粤题库】广东开放大学 形成性考核 - 副本 (11)
  10. ReactNative 接talkingdata统计