Compare commits

..

20 Commits

Author SHA1 Message Date
Felix c8144787b0 docs(README): 更新标题链接指向 github 仓库
4 months ago
Felix 82fe15aa3e feat(makefile): 为lab9增加benchmarks
8 months ago
Felix 6b950d2ea0 fix(makefile): 修复lab9未删除历史trace的问题
8 months ago
Felix a60237e7fd fix(makefile): 修复测例执行顺序问题
8 months ago
Liphen 6293d1cd89 fix(mstatus.mpp): 写入非法值时,mpp保持原值
8 months ago
Felix 2f2f9e9b54 fix(difftest): 修复只实现M模式的CSR初始值
9 months ago
Liphen 6e3f2de95f perf(difftest/makefile): 增加 help 提示
9 months ago
Liphen ee417a132c docs(README): 增加实验环境说明
10 months ago
Wang Jiadong 98c42ca11b perf(test/lab4): 强化 lab4 的测例
10 months ago
Liphen abb03ef3c3 fix(test/bin): 增加 bin 文件序号
10 months ago
Liphen 80b1cd00f2 docs(difftest): 修正cpu_trace描述,删除无用参数
10 months ago
Felix b0832deab0 feat(difftest/Makefile): 增加指定测例生成波形命令
10 months ago
Liphen 43209019e7 docs: 增加各模块功能说明和一些关键代码注释
10 months ago
Liphen 67a04e71d4 docs(README): 增加环境完整性测试使用说明
10 months ago
Liphen 8e6db9f912 fix(ARegfile): 修正寄存器位宽注释为XLEN
10 months ago
Felix 5c2305b0ed feat(Decoder): 增加代码提示,降低实验难度
10 months ago
Liphen c8b3c4a4a4 docs: 更新README文件,修正文件名和使用说明
10 months ago
Liphen 6e65185521 fix(top_sram_wrapper): 补充difftest下SRAM的顶层文件
10 months ago
Liphen 1a9fcc12b6 chore(.gitignore): 移除不必要的文件规则
10 months ago
Liphen c38ce0b538 init: 初始化实验框架
11 months ago

1
.gitignore vendored

@ -1,3 +1,4 @@
.vscode/
.metals/
.VSCodeCounter/
.DS_Store

@ -0,0 +1,54 @@
module top(
input clock,
input reset,
// Interrupts
input mei, // to PLIC
input msi, // to CLINT
input mti, // to CLINT
input sei, // to PLIC
// inst sram interface
output inst_sram_en,
output [ 3:0] inst_sram_wen,
output [31:0] inst_sram_addr,
output [31:0] inst_sram_wdata,
input [31:0] inst_sram_rdata,
// data sram interface
output data_sram_en,
output [ 7:0] data_sram_wen,
output [31:0] data_sram_addr,
output [63:0] data_sram_wdata,
input [63:0] data_sram_rdata,
// trace debug interface
output debug_commit,
output [63:0] debug_pc,
output [4:0 ] debug_rf_wnum,
output [63:0] debug_rf_wdata
);
PuaCpu core(
.clock (clock),
.reset (reset),
// interrupts
.io_ext_int_mei (mei),
.io_ext_int_mti (mti),
.io_ext_int_msi (msi),
// inst sram interface
.io_inst_sram_en (inst_sram_en),
.io_inst_sram_wen (inst_sram_wen),
.io_inst_sram_addr (inst_sram_addr),
.io_inst_sram_wdata (inst_sram_wdata),
.io_inst_sram_rdata (inst_sram_rdata),
// data sram interface
.io_data_sram_en (data_sram_en),
.io_data_sram_wen (data_sram_wen),
.io_data_sram_addr (data_sram_addr),
.io_data_sram_wdata (data_sram_wdata),
.io_data_sram_rdata (data_sram_rdata),
// debug
.io_debug_pc (debug_pc),
.io_debug_commit (debug_commit),
.io_debug_rf_wnum (debug_rf_wnum),
.io_debug_rf_wdata (debug_rf_wdata)
);
endmodule

@ -0,0 +1,35 @@
package cpu
import chisel3._
import chisel3.util._
import defines._
import defines.Const._
import pipeline._
class Core extends Module {
val io = IO(new Bundle {
val interrupt = Input(new ExtInterrupt())
val instSram = new InstSram()
val dataSram = new DataSram()
val debug = new DEBUG()
})
val fetchUnit = Module(new FetchUnit()).io
val decodeStage = Module(new DecodeStage()).io
val decodeUnit = Module(new DecodeUnit()).io
val regfile = Module(new ARegFile()).io
val executeStage = Module(new ExecuteStage()).io
val executeUnit = Module(new ExecuteUnit()).io
val memoryStage = Module(new MemoryStage()).io
val memoryUnit = Module(new MemoryUnit()).io
val writeBackStage = Module(new WriteBackStage()).io
val writeBackUnit = Module(new WriteBackUnit()).io
// 取指单元
fetchUnit.instSram <> io.instSram
fetchUnit.decodeStage <> decodeStage.fetchUnit
// TODO: 完成Core模块的逻辑
// 在该模块中需要将各个模块连接起来形成一个完整的CPU核心
}

@ -0,0 +1,16 @@
package cpu
import chisel3.util._
import cpu.defines.Const._
case class CpuConfig(
// 指令集
val isRV32: Boolean = false, // 是否为RV32
val hasMExtension: Boolean = false, // 是否实现M扩展即乘除法指令
val hasZicsrExtension: Boolean = false, // 是否实现Zicsr扩展即CSR指令
val hasZifenceiExtension: Boolean = false, // 是否实现Zifencei扩展即FENCE.I指令
val hasAExtension: Boolean = false, // 是否实现A扩展即原子指令
// 特权模式
val hasSMode: Boolean = false, // 是否有S模式
val hasUMode: Boolean = false // 是否有U模式
)

@ -1,68 +0,0 @@
package gcd
import chisel3._
import chisel3.util.Decoupled
class GcdInputBundle(val w: Int) extends Bundle {
val value1 = UInt(w.W)
val value2 = UInt(w.W)
}
class GcdOutputBundle(val w: Int) extends Bundle {
val value1 = UInt(w.W)
val value2 = UInt(w.W)
val gcd = UInt(w.W)
}
/** Compute Gcd using subtraction method. Subtracts the smaller from the larger until register y is zero. value input
* register x is then the Gcd. Unless first input is zero then the Gcd is y. Can handle stalls on the producer or
* consumer side
*/
class DecoupledGcd(width: Int) extends Module {
val input = IO(Flipped(Decoupled(new GcdInputBundle(width))))
val output = IO(Decoupled(new GcdOutputBundle(width)))
val xInitial = Reg(UInt())
val yInitial = Reg(UInt())
val x = Reg(UInt())
val y = Reg(UInt())
val busy = RegInit(false.B)
val resultValid = RegInit(false.B)
input.ready := !busy
output.valid := resultValid
output.bits := DontCare
when(busy) {
when(x > y) {
x := x - y
}.otherwise {
y := y - x
}
when(x === 0.U || y === 0.U) {
when(x === 0.U) {
output.bits.gcd := y
}.otherwise {
output.bits.gcd := x
}
output.bits.value1 := xInitial
output.bits.value2 := yInitial
resultValid := true.B
when(output.ready && resultValid) {
busy := false.B
resultValid := false.B
}
}
}.otherwise {
when(input.valid) {
val bundle = input.deq()
x := bundle.value1
y := bundle.value2
xInitial := bundle.value1
yInitial := bundle.value2
busy := true.B
}
}
}

@ -1,12 +1,9 @@
import cpu._
import circt.stage._
object Elaborate extends App {
val firtoolOptions = Array(
"--lowering-options=" + List(
// make yosys happy
// see https://github.com/llvm/circt/blob/main/docs/VerilogGeneration.md
"disallowLocalVariables",
"disallowPackedArrays",
"locationInfoStyle=wrapInAtSquareBracket"
).reduce(_ + "," + _)
)
circt.stage.ChiselStage.emitSystemVerilogFile(new gcd.GCD(), args, firtoolOptions)
}
implicit val cpuConfig = new CpuConfig()
def top = new PuaCpu()
val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top))
(new ChiselStage).execute(args, generator :+ CIRCTTargetAnnotation(CIRCTTarget.Verilog))
}

@ -1,29 +0,0 @@
package gcd
import chisel3._
/** Compute GCD using subtraction method. Subtracts the smaller from the larger until register y is zero. value in
* register x is then the GCD
*/
class GCD extends Module {
val io = IO(new Bundle {
val value1 = Input(UInt(16.W))
val value2 = Input(UInt(16.W))
val loadingValues = Input(Bool())
val outputGCD = Output(UInt(16.W))
val outputValid = Output(Bool())
})
val x = Reg(UInt())
val y = Reg(UInt())
when(x > y) { x := x - y }.otherwise { y := y - x }
when(io.loadingValues) {
x := io.value1
y := io.value2
}
io.outputGCD := x
io.outputValid := y === 0.U
}

@ -0,0 +1,20 @@
import chisel3._
import chisel3.util._
import cpu._
import cpu.defines._
class PuaCpu extends Module {
val io = IO(new Bundle {
val ext_int = Input(new ExtInterrupt())
val inst_sram = new InstSram()
val data_sram = new DataSram()
val debug = new DEBUG()
})
val core = Module(new Core())
io.ext_int <> core.io.interrupt
io.inst_sram <> core.io.instSram
io.data_sram <> core.io.dataSram
io.debug <> core.io.debug
}

@ -0,0 +1,59 @@
package cpu.defines
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class ExtInterrupt extends Bundle {
val mei = Bool()
val mti = Bool()
val msi = Bool()
}
class SrcInfo extends Bundle {
val src1_data = UInt(XLEN.W)
val src2_data = UInt(XLEN.W)
}
class RdInfo extends Bundle {
val wdata = UInt(XLEN.W)
}
class Info extends Bundle {
val valid = Bool() // 用于标识当前流水级中的指令是否有效
val src1_raddr = UInt(REG_ADDR_WID.W)
val src2_raddr = UInt(REG_ADDR_WID.W)
val op = FuOpType()
val reg_wen = Bool()
val reg_waddr = UInt(REG_ADDR_WID.W)
}
class SrcReadSignal extends Bundle {
val ren = Bool()
val raddr = UInt(REG_ADDR_WID.W)
}
class InstSram extends Bundle {
val en = Output(Bool())
val addr = Output(UInt(SRAM_ADDR_WID.W))
val wdata = Output(UInt(INST_SRAM_DATA_WID.W))
val wen = Output(UInt(INST_SRAM_WEN_WID.W))
val rdata = Input(UInt(INST_SRAM_DATA_WID.W))
}
class DataSram extends Bundle {
val en = Output(Bool())
val addr = Output(UInt(SRAM_ADDR_WID.W))
val wdata = Output(UInt(DATA_SRAM_DATA_WID.W))
val wen = Output(UInt(DATA_SRAM_WEN_WID.W))
val rdata = Input(UInt(DATA_SRAM_DATA_WID.W))
}
class DEBUG extends Bundle {
val commit = Output(Bool()) // 写回阶段的commit信号仅在每条指令提交时置为true
val pc = Output(UInt(XLEN.W)) // 写回阶段的pc
val rf_wnum = Output(UInt(REG_ADDR_WID.W)) // 写回阶段的寄存器写地址
val rf_wdata = Output(UInt(XLEN.W)) // 写回阶段的寄存器写数据
}

@ -0,0 +1,42 @@
package cpu.defines
import chisel3._
import chisel3.util._
import cpu.CpuConfig
trait CoreParameter {
def cpuConfig = new CpuConfig
val XLEN = if (cpuConfig.isRV32) 32 else 64
val VADDR_WID = if (cpuConfig.isRV32) 32 else 39
val PADDR_WID = 32
}
trait Constants extends CoreParameter {
// 全局
val PC_INIT = "h80000000".U(XLEN.W)
val INT_WID = 12
val EXC_WID = 16
// inst rom
val INST_WID = 32
// GPR RegFile
val AREG_NUM = 32
val REG_ADDR_WID = 5
}
trait SRAMConst extends Constants {
val SRAM_ADDR_WID = PADDR_WID // 32
val DATA_SRAM_DATA_WID = XLEN
val DATA_SRAM_WEN_WID = XLEN / 8
val INST_SRAM_DATA_WID = INST_WID
val INST_SRAM_WEN_WID = INST_WID / 8
}
object Const extends Constants with SRAMConst
object Instructions extends HasInstrType with CoreParameter {
def NOP = 0x00000013.U
val DecodeDefault = List(InstrN, FuType.alu, ALUOpType.add)
def DecodeTable = RVIInstr.table
}

@ -0,0 +1,29 @@
package cpu.defines
import chisel3._
import chisel3.util._
object SignedExtend {
def apply(a: UInt, len: Int) = {
val aLen = a.getWidth
val signBit = a(aLen - 1)
if (aLen >= len) a(len - 1, 0) else Cat(Fill(len - aLen, signBit), a)
}
}
object ZeroExtend {
def apply(a: UInt, len: Int) = {
val aLen = a.getWidth
if (aLen >= len) a(len - 1, 0) else Cat(0.U((len - aLen).W), a)
}
}
object LookupTree {
def apply[T <: Data](key: UInt, mapping: Iterable[(UInt, T)]): T =
Mux1H(mapping.map(p => (p._1 === key, p._2)))
}
object LookupTreeDefault {
def apply[T <: Data](key: UInt, default: T, mapping: Iterable[(UInt, T)]): T =
MuxLookup(key, default)(mapping.toSeq)
}

@ -0,0 +1,36 @@
package cpu.defines
import chisel3._
import chisel3.util._
// 指令类型
trait HasInstrType {
def InstrN = "b000".U
def InstrI = "b100".U
def InstrR = "b101".U
def InstrS = "b010".U
def InstrB = "b001".U
def InstrU = "b110".U
def InstrJ = "b111".U
// IRUJ类型的指令都需要写寄存器
def isRegWen(instrType: UInt): Bool = instrType(2)
}
// 功能单元类型 Function Unit Type
object FuType {
def num = 1
def alu = 0.U // arithmetic logic unit
def apply() = UInt(log2Up(num).W)
}
// 功能单元操作类型 Function Unit Operation Type
object FuOpType {
def apply() = UInt(5.W) // 宽度与最大的功能单元操作类型宽度一致
}
// 算术逻辑单元操作类型 Arithmetic Logic Unit Operation Type
object ALUOpType {
def add = "b00000".U
// TODO: 定义更多的ALU操作类型
}

@ -0,0 +1,61 @@
package cpu.defines
import chisel3._
import chisel3.util._
object RV32I_ALUInstr extends HasInstrType with CoreParameter {
def ADDI = BitPat("b????????????_?????_000_?????_0010011")
def SLLI = if (XLEN == 32) BitPat("b0000000?????_?????_001_?????_0010011")
else BitPat("b000000??????_?????_001_?????_0010011")
def SLTI = BitPat("b????????????_?????_010_?????_0010011")
def SLTIU = BitPat("b????????????_?????_011_?????_0010011")
def XORI = BitPat("b????????????_?????_100_?????_0010011")
def SRLI = if (XLEN == 32) BitPat("b0000000?????_?????_101_?????_0010011")
else BitPat("b000000??????_?????_101_?????_0010011")
def ORI = BitPat("b????????????_?????_110_?????_0010011")
def ANDI = BitPat("b????????????_?????_111_?????_0010011")
def SRAI = if (XLEN == 32) BitPat("b0100000?????_?????_101_?????_0010011")
else BitPat("b010000??????_?????_101_?????_0010011")
def ADD = BitPat("b0000000_?????_?????_000_?????_0110011")
def SLL = BitPat("b0000000_?????_?????_001_?????_0110011")
def SLT = BitPat("b0000000_?????_?????_010_?????_0110011")
def SLTU = BitPat("b0000000_?????_?????_011_?????_0110011")
def XOR = BitPat("b0000000_?????_?????_100_?????_0110011")
def SRL = BitPat("b0000000_?????_?????_101_?????_0110011")
def OR = BitPat("b0000000_?????_?????_110_?????_0110011")
def AND = BitPat("b0000000_?????_?????_111_?????_0110011")
def SUB = BitPat("b0100000_?????_?????_000_?????_0110011")
def SRA = BitPat("b0100000_?????_?????_101_?????_0110011")
def AUIPC = BitPat("b????????????????????_?????_0010111")
def LUI = BitPat("b????????????????????_?????_0110111")
// 在Decoder模块中搭配ListLookup函数使用
val table = Array(
// ADD指令将被解析为InstrR类型的指令功能单元类型为alu功能单元操作类型为add
ADD -> List(InstrR, FuType.alu, ALUOpType.add)
// TODO: 完成其他指令的解析
)
}
object RV64IInstr extends HasInstrType {
def ADDIW = BitPat("b???????_?????_?????_000_?????_0011011")
def SLLIW = BitPat("b0000000_?????_?????_001_?????_0011011")
def SRLIW = BitPat("b0000000_?????_?????_101_?????_0011011")
def SRAIW = BitPat("b0100000_?????_?????_101_?????_0011011")
def SLLW = BitPat("b0000000_?????_?????_001_?????_0111011")
def SRLW = BitPat("b0000000_?????_?????_101_?????_0111011")
def SRAW = BitPat("b0100000_?????_?????_101_?????_0111011")
def ADDW = BitPat("b0000000_?????_?????_000_?????_0111011")
def SUBW = BitPat("b0100000_?????_?????_000_?????_0111011")
val table = Array(
// TODO: 完成RV64I指令集的解析
)
}
object RVIInstr extends CoreParameter {
val table = RV32I_ALUInstr.table ++
(if (XLEN == 64) RV64IInstr.table else Array.empty)
}

@ -0,0 +1,41 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class SrcRead extends Bundle {
val raddr = Output(UInt(REG_ADDR_WID.W))
val rdata = Input(UInt(XLEN.W))
}
class Src12Read extends Bundle {
val src1 = new SrcRead()
val src2 = new SrcRead()
}
class RegWrite extends Bundle {
val wen = Output(Bool())
val waddr = Output(UInt(REG_ADDR_WID.W))
val wdata = Output(UInt(XLEN.W))
}
class ARegFile extends Module {
val io = IO(new Bundle {
val read = Flipped(new Src12Read())
val write = Flipped(new RegWrite())
})
// 定义32个XLEN位寄存器
val regs = RegInit(VecInit(Seq.fill(AREG_NUM)(0.U(XLEN.W))))
// 写寄存器堆
// TODO:完成写寄存器堆逻辑
// 注意0号寄存器恒为0
// 读寄存器堆
// TODO:完成读寄存器堆逻辑
// 注意0号寄存器恒为0
}

@ -0,0 +1,30 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class IfIdData extends Bundle {
val inst = UInt(XLEN.W)
val valid = Bool()
val pc = UInt(XLEN.W)
}
class FetchUnitDecodeUnit extends Bundle {
val data = Output(new IfIdData())
}
class DecodeStage extends Module {
val io = IO(new Bundle {
val fetchUnit = Flipped(new FetchUnitDecodeUnit())
val decodeUnit = new FetchUnitDecodeUnit()
})
val data = RegInit(0.U.asTypeOf(new IfIdData()))
data := io.fetchUnit.data
io.decodeUnit.data := data
}

@ -0,0 +1,38 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
class DecodeUnit extends Module {
val io = IO(new Bundle {
// 输入
val decodeStage = Flipped(new FetchUnitDecodeUnit())
val regfile = new Src12Read()
// 输出
val executeStage = Output(new DecodeUnitExecuteUnit())
})
// 译码阶段完成指令的译码操作以及源操作数的准备
val decoder = Module(new Decoder()).io
decoder.in.inst := io.decodeStage.data.inst
val pc = io.decodeStage.data.pc
val info = Wire(new Info())
info := decoder.out.info
info.valid := io.decodeStage.data.valid
// TODO:完成寄存器堆的读取
// io.regfile.src1.raddr :=
// io.regfile.src2.raddr :=
// TODO: 完成DecodeUnit模块的逻辑
// io.executeStage.data.pc :=
// io.executeStage.data.info :=
// io.executeStage.data.src_info.src1_data :=
// io.executeStage.data.src_info.src2_data :=
}

@ -0,0 +1,36 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
class Decoder extends Module with HasInstrType {
val io = IO(new Bundle {
// inputs
val in = Input(new Bundle {
val inst = UInt(XLEN.W)
})
// outputs
val out = Output(new Bundle {
val info = new Info()
})
})
val inst = io.in.inst
// 根据输入的指令inst从Instructions.DecodeTable中查找对应的指令类型功能单元类型和功能单元操作类型
// 如果找不到匹配的指令则使用Instructions.DecodeDefault作为默认值
// instrTypefuType和fuOpType分别被赋值为Instructions.DecodeTable中的对应值
val instrType :: fuType :: fuOpType :: Nil =
ListLookup(inst, Instructions.DecodeDefault, Instructions.DecodeTable)
val (rs, rt, rd) = (inst(19, 15), inst(24, 20), inst(11, 7))
// TODO: 完成Decoder模块的逻辑
// io.out.info.valid :=
// io.out.info.src1_raddr :=
// io.out.info.src2_raddr :=
// io.out.info.op :=
// io.out.info.reg_wen :=
// io.out.info.reg_waddr :=
}

@ -0,0 +1,28 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class IdExeData extends Bundle {
val pc = UInt(XLEN.W)
val info = new Info()
val src_info = new SrcInfo()
}
class DecodeUnitExecuteUnit extends Bundle {
val data = new IdExeData()
}
class ExecuteStage extends Module {
val io = IO(new Bundle {
val decodeUnit = Input(new DecodeUnitExecuteUnit())
val executeUnit = Output(new DecodeUnitExecuteUnit())
})
val data = RegInit(0.U.asTypeOf(new IdExeData()))
// TODO: 完成ExecuteStage模块的逻辑
}

@ -0,0 +1,31 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.CpuConfig
import cpu.defines._
import cpu.defines.Const._
import chisel3.util.experimental.BoringUtils
class ExecuteUnit extends Module {
val io = IO(new Bundle {
val executeStage = Input(new DecodeUnitExecuteUnit())
val memoryStage = Output(new ExecuteUnitMemoryUnit())
val dataSram = new DataSram()
})
// 执行阶段完成指令的执行操作
val fu = Module(new Fu()).io
fu.data.pc := io.executeStage.data.pc
fu.data.info := io.executeStage.data.info
fu.data.src_info := io.executeStage.data.src_info
io.dataSram <> fu.dataSram
// TODO: 完成ExecuteUnit模块的逻辑
// io.memoryStage.data.pc :=
// io.memoryStage.data.info :=
// io.memoryStage.data.src_info :=
// io.memoryStage.data.rd_info :=
}

@ -0,0 +1,32 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class Fu extends Module {
val io = IO(new Bundle {
val data = new Bundle {
val pc = Input(UInt(XLEN.W))
val info = Input(new Info())
val src_info = Input(new SrcInfo())
val rd_info = Output(new RdInfo())
}
val dataSram = new DataSram()
})
val alu = Module(new Alu()).io
io.dataSram.en := false.B
io.dataSram.addr := DontCare
io.dataSram.wdata := DontCare
io.dataSram.wen := 0.U
alu.info := io.data.info
alu.src_info := io.data.src_info
io.data.rd_info.wdata := alu.result
}

@ -0,0 +1,15 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
class Alu extends Module {
val io = IO(new Bundle {
val info = Input(new Info())
val src_info = Input(new SrcInfo())
val result = Output(UInt(XLEN.W))
})
// TODO: 完成ALU模块的逻辑
}

@ -0,0 +1,41 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines.Const._
import cpu.CpuConfig
import cpu.defines._
class FetchUnit extends Module {
val io = IO(new Bundle {
val decodeStage = new FetchUnitDecodeUnit()
val instSram = new InstSram()
})
val boot :: send :: receive :: Nil = Enum(3)
val state = RegInit(boot)
switch(state) {
is(boot) {
state := send
}
is(send) {
state := receive
}
is(receive) {}
}
// 取指阶段完成指令的取指操作
val pc = RegEnable(io.instSram.addr, (PC_INIT - 4.U), state =/= boot)
io.instSram.addr := pc + 4.U
io.decodeStage.data.valid := state === receive
io.decodeStage.data.pc := pc
io.decodeStage.data.inst := io.instSram.rdata
io.instSram.en := !reset.asBool
io.instSram.wen := 0.U
io.instSram.wdata := 0.U
}

@ -0,0 +1,29 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class ExeMemData extends Bundle {
val pc = UInt(XLEN.W)
val info = new Info()
val rd_info = new RdInfo()
val src_info = new SrcInfo()
}
class ExecuteUnitMemoryUnit extends Bundle {
val data = new ExeMemData()
}
class MemoryStage extends Module {
val io = IO(new Bundle {
val executeUnit = Input(new ExecuteUnitMemoryUnit())
val memoryUnit = Output(new ExecuteUnitMemoryUnit())
})
val data = RegInit(0.U.asTypeOf(new ExeMemData()))
// TODO: 完成MemoryStage模块的逻辑
}

@ -0,0 +1,21 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class MemoryUnit extends Module {
val io = IO(new Bundle {
val memoryStage = Input(new ExecuteUnitMemoryUnit())
val writeBackStage = Output(new MemoryUnitWriteBackUnit())
})
// 访存阶段完成指令的访存操作
io.writeBackStage.data.pc := io.memoryStage.data.pc
io.writeBackStage.data.info := io.memoryStage.data.info
io.writeBackStage.data.rd_info.wdata := io.memoryStage.data.rd_info.wdata
}

@ -0,0 +1,27 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class MemWbData extends Bundle {
val pc = UInt(XLEN.W)
val info = new Info()
val rd_info = new RdInfo()
}
class MemoryUnitWriteBackUnit extends Bundle {
val data = new MemWbData()
}
class WriteBackStage extends Module {
val io = IO(new Bundle {
val memoryUnit = Input(new MemoryUnitWriteBackUnit())
val writeBackUnit = Output(new MemoryUnitWriteBackUnit())
})
val data = RegInit(0.U.asTypeOf(new MemWbData()))
// TODO: 完成WriteBackStage模块的逻辑
}

@ -0,0 +1,19 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class WriteBackUnit extends Module {
val io = IO(new Bundle {
val writeBackStage = Input(new MemoryUnitWriteBackUnit())
val regfile = Output(new RegWrite())
val debug = new DEBUG()
})
// 写回阶段完成数据的写回操作
// 同时该阶段还负责差分测试的比对工作
// TODO: 完成WriteBackUnit模块的逻辑
}

@ -1,68 +1,9 @@
// See README.md for license details.
package gcd
import chisel3._
import chisel3.experimental.BundleLiterals._
import chisel3.simulator.EphemeralSimulator._
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.must.Matchers
/** This is a trivial example of how to run this Specification From within sbt use:
* {{{
* testOnly gcd.GCDSpec
* }}}
* From a terminal shell use:
* {{{
* sbt 'testOnly gcd.GCDSpec'
* }}}
* Testing from mill:
* {{{
* mill %NAME%.test.testOnly gcd.GCDSpec
* }}}
*/
class GCDSpec extends AnyFreeSpec with Matchers {
"Gcd should calculate proper greatest common denominator" in {
simulate(new DecoupledGcd(16)) { dut =>
val testValues = for {
x <- 0 to 10
y <- 0 to 10
} yield (x, y)
val inputSeq = testValues.map { case (x, y) => (new GcdInputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U) }
val resultSeq = testValues.map { case (x, y) =>
(new GcdOutputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U, _.gcd -> BigInt(x).gcd(BigInt(y)).U)
}
dut.reset.poke(true.B)
dut.clock.step()
dut.reset.poke(false.B)
dut.clock.step()
var sent, received, cycles: Int = 0
while (sent != 100 && received != 100) {
assert(cycles <= 1000, "timeout reached")
if (sent < 100) {
dut.input.valid.poke(true.B)
dut.input.bits.value1.poke(testValues(sent)._1.U)
dut.input.bits.value2.poke(testValues(sent)._2.U)
if (dut.input.ready.peek().litToBoolean) {
sent += 1
}
}
if (received < 100) {
dut.output.ready.poke(true.B)
if (dut.output.valid.peekValue().asBigInt == 1) {
dut.output.bits.gcd.expect(BigInt(testValues(received)._1).gcd(testValues(received)._2))
received += 1
}
}
// Step the simulation forward.
dut.clock.step()
cycles += 1
}
}
}
}
// import cpu._
// import circt.stage._
// object TestMain extends App {
// implicit val cpuConfig = new CpuConfig()
// def top = new Top()
// val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top))
// (new ChiselStage).execute(args, generator :+ CIRCTTargetAnnotation(CIRCTTarget.Verilog))
// }

@ -1,4 +1,7 @@
*.vcd
obj_dir
core/*
!core/top_sram_wrapper.v
trace.*

@ -10,11 +10,6 @@ TESTBIN_DIR = ./test/bin/am-tests/add.bin
obj_dir/V$(TOP_NAME): src/* $(SRC_FILE)
verilator --cc -Wno-fatal --exe --trace-fst --trace-structs -LDFLAGS "-lpthread" --build src/sim_mycpu.cpp $(SRC_FILE) -I$(SRC_DIR) --top $(TOP_NAME) -j `nproc`
envtest:
$(call git_commit, "env test") # DO NOT REMOVE THIS LINE!!!
$(MAKE) -C $(CHISEL_DIR) verilog
$(MAKE) lab1
verilog:
$(MAKE) -C $(CHISEL_DIR) verilog
cp $(CHISEL_DIR)/build/PuaCpu.v $(SRC_DIR)
@ -28,7 +23,7 @@ test:
clean:
rm -rf obj_dir
rm -rf core/Puacpu.v
rm -rf core/PuaCpu.v
perf: obj_dir/V$(TOP_NAME)
$(call git_commit, "perf test RTL") # DO NOT REMOVE THIS LINE!!!
@ -39,6 +34,17 @@ perf: obj_dir/V$(TOP_NAME)
./obj_dir/V$(TOP_NAME) $$test -rvtest -pc -perf; \
done; \
qbench: obj_dir/V$(TOP_NAME)
@echo "==================================================================="
@echo "=========================quick benchmarks=========================="
@echo "==================================================================="
@count=0; \
for test in $$(find ./test/bin/riscv-test/benchmarks \( -name "*.bin" \) | sort | grep -vE "*dhrystone*|*mt-vvadd*"); do \
count=$$((count + 1)); \
echo "Running bench $$count: $$test"; \
./obj_dir/V$(TOP_NAME) $$test -rvtest -pc -perf; \
done; \
lab1: obj_dir/V$(TOP_NAME)
$(call git_commit, "test lab1") # DO NOT REMOVE THIS LINE!!!
./obj_dir/V$(TOP_NAME) ./test/bin/lab-test/lab1.bin -rvtest -initgprs -trace 10000000 -pc
@ -72,7 +78,7 @@ TRACE_TESTS67 := $(addprefix trace_,$(TEST67))
$(TEST67): obj_dir/V$(TOP_NAME)
$(call git_commit, "test $@") # DO NOT REMOVE THIS LINE!!!
count=0; \
for test in ./test/bin/am-tests/*; do \
for test in $$(ls ./test/bin/am-tests/* | sort); do \
count=$$((count + 1)); \
echo "Running test $$count: $$test"; \
./obj_dir/V$(TOP_NAME) $$test -rvtest -pc; \
@ -86,7 +92,7 @@ $(TRACE_TESTS67): obj_dir/V$(TOP_NAME)
$(call git_commit, "trace $*") # DO NOT REMOVE THIS LINE!!!
rm -rf ./trace.txt
count=0; \
for test in ./test/bin/am-tests/*; do \
for test in $$(ls ./test/bin/am-tests/* | sort); do \
count=$$((count + 1)); \
echo "Running test $$count: $$test"; \
./obj_dir/V$(TOP_NAME) $$test -rvtest -cpu_trace -writeappend; \
@ -108,21 +114,32 @@ trace_lab8: obj_dir/V$(TOP_NAME)
lab9: obj_dir/V$(TOP_NAME)
$(call git_commit, "test lab9") # DO NOT REMOVE THIS LINE!!!
count=0; \
for test in $$(find ./test/bin/riscv-test/ \( -name "*rv64ui-p-*" -o -name "*rv64um-p-*" -o -name "*rv64mi-p-*" \) | grep -vE "*rv64ui-p-fence_i|*rv64mi-p-access"); do \
for test in $$(find ./test/bin/riscv-test/ \( -name "*rv64ui-p-*" -o -name "*rv64um-p-*" -o -name "*rv64mi-p-*" \) | sort | grep -vE "*rv64ui-p-fence_i|*rv64mi-p-access"); do \
count=$$((count + 1)); \
echo "Running test $$count: $$test"; \
./obj_dir/V$(TOP_NAME) $$test -rvtest -pc; \
done; \
echo "Total tests run: $$count";
$(MAKE) qbench
trace_lab9: obj_dir/V$(TOP_NAME)
$(call git_commit, "trace lab9") # DO NOT REMOVE THIS LINE!!!
rm -rf ./trace.txt
count=0; \
for test in $$(find ./test/bin/riscv-test/ \( -name "*rv64ui-p-*" -o -name "*rv64um-p-*" -o -name "*rv64mi-p-*" \) | grep -vE "*rv64ui-p-fence_i|*rv64mi-p-access"); do \
for test in $$(find ./test/bin/riscv-test/ \( -name "*rv64ui-p-*" -o -name "*rv64um-p-*" -o -name "*rv64mi-p-*" \) | sort | grep -vE "*rv64ui-p-fence_i|*rv64mi-p-access"); do \
count=$$((count + 1)); \
echo "Running test $$count: $$test"; \
./obj_dir/V$(TOP_NAME) $$test -rvtest -cpu_trace -writeappend; \
done; \
echo "Total tests run: $$count";
help:
@echo "Usage: make [target]"
@echo "Available targets:"
@echo " clean - Remove build artifacts"
@echo " verilog - Generate verilog files"
@echo " perf - Run performance tests"
@echo " lab<number> - Run lab<number>, eg. lab1, lab2, ..."
@echo " trace_lab<number> - Run lab<number> with trace, eg. trace_lab1, trace_lab2, ..."
-include ../Makefile

@ -13,12 +13,12 @@
## 🔨 使用方法
1. 将 CPU 代码放置到相对于本文件夹的 `core` 文件夹中。
2. 在本文件夹下,使用 `make` 命令完成编译编译结果位于 `obj_dir/Vtop`
2. 在本文件夹下,使用 `make` 命令完成编译结果位于 `obj_dir/Vtop`
3. 每次修改 CPU 代码后,需要重新 `make`,如果引入了一些时间早于编译产物的代码,需要先 `make clean``make`
## 🧪 参数说明
`makefile` 中已经预置了常用命令
`makefile` 中已经预置了常用命令,使用 `make help` 查看命令使用方法
在命令 `./obj_dir/Vtop` 后面可以加上不同参数,可以实现不同的功能:
@ -31,3 +31,4 @@
- `-pc` 报错时将额外输出最近的 PC 历史记录
- `-delay` 行为不一致时将继续运行一段时间再停止
- `-cpu_trace` 记录被测试的处理器的程序运行历史信息,生成 trace.txt
- `-perf` 打印处理器运行的IPC数据

File diff suppressed because it is too large Load Diff

@ -39,15 +39,20 @@ public:
status = 0;
csr_mstatus_def *mstatus = (csr_mstatus_def *)&status;
csr_misa_def *isa = (csr_misa_def *)&misa;
if (only_modeM && run_riscv_test)
if (run_riscv_test)
{
isa->ext = rv_ext('i') | rv_ext('m') | rv_ext('u');
mstatus->mpp = M_MODE;
}
else
{
mstatus->uxl = 2;
isa->ext = rv_ext('i') | rv_ext('m') | rv_ext('u');
if (only_modeM)
{
// 只实现M-Mode的CPU
isa->ext = rv_ext('i') | rv_ext('m');
mstatus->mpp = M_MODE;
}
else
{
// 实现M-Mode和U-Mode的CPU
mstatus->uxl = 2;
isa->ext = rv_ext('i') | rv_ext('m') | rv_ext('u');
}
}
isa->mxl = 2; // rv64
isa->blank = 0;
@ -262,7 +267,7 @@ public:
assert(mstatus->spie != 2);
assert(mstatus->mpie != 2);
// mstatus->spp = nstatus->spp;
mstatus->mpp = (nstatus->mpp == 3 || nstatus->mpp == 0) ? nstatus->mpp : 0;
mstatus->mpp = (nstatus->mpp == 3 || nstatus->mpp == 0) ? nstatus->mpp : mstatus->mpp;
mstatus->mprv = nstatus->mprv;
// mstatus->sum = nstatus->sum; // always true
// mstatus->mxr = nstatus->mxr; // always true

Loading…
Cancel
Save