Initial Chisel core implementation
This commit is contained in:
173
src/main/scala/Core.scala
Normal file
173
src/main/scala/Core.scala
Normal file
@@ -0,0 +1,173 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import _root_.circt.stage.ChiselStage
|
||||
|
||||
class Core(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val imem_req_valid = Output(Bool())
|
||||
val imem_req_bits = Output(UInt(p.xlen.W))
|
||||
val imem_resp_valid = Input(Bool())
|
||||
val imem_resp_bits_0 = Input(UInt(32.W))
|
||||
val imem_resp_bits_1 = Input(UInt(32.W))
|
||||
|
||||
val dmem_req_valid = Output(Bool())
|
||||
val dmem_req_bits_addr = Output(UInt(p.xlen.W))
|
||||
val dmem_req_bits_data = Output(UInt(p.xlen.W))
|
||||
val dmem_req_bits_isStore = Output(Bool())
|
||||
val dmem_req_bits_size = Output(UInt(3.W))
|
||||
val dmem_resp_valid = Input(Bool())
|
||||
val dmem_resp_bits = Input(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
val sFetch :: sExec :: sLoadWait :: Nil = Enum(3)
|
||||
val state = RegInit(sFetch)
|
||||
val pc = RegInit(Consts.ResetVector)
|
||||
val instReg = RegInit(0.U(32.W))
|
||||
val pcReg = RegInit(Consts.ResetVector)
|
||||
|
||||
val regs = RegInit(VecInit(Seq.fill(32)(0.U(p.xlen.W))))
|
||||
|
||||
val decoder = Module(new Decoder(p))
|
||||
decoder.io.pc := pcReg
|
||||
decoder.io.inst := instReg
|
||||
val dec = decoder.io.out
|
||||
|
||||
val alu = Module(new ALU(p))
|
||||
val branch = Module(new BranchUnit(p))
|
||||
val csr = Module(new CSRFile(p))
|
||||
|
||||
def regRead(addr: UInt): UInt = Mux(addr === 0.U, 0.U, regs(addr))
|
||||
def lowLoad(data: UInt, size: UInt, signed: Bool): UInt = {
|
||||
val b = data(7, 0)
|
||||
val h = data(15, 0)
|
||||
val w = data(31, 0)
|
||||
MuxLookup(size, data)(Seq(
|
||||
0.U -> Mux(signed, Consts.signExtend(b, 8), b),
|
||||
1.U -> Mux(signed, Consts.signExtend(h, 16), h),
|
||||
2.U -> Mux(signed, Consts.signExtend(w, 32), w),
|
||||
3.U -> data
|
||||
))
|
||||
}
|
||||
|
||||
val src1 = regRead(dec.rs1)
|
||||
val src2 = regRead(dec.rs2)
|
||||
val aluB = Mux(dec.isOpImm || dec.isJalr || dec.isLoad, dec.immI, src2)
|
||||
|
||||
alu.io.fn := dec.aluFn
|
||||
alu.io.a := src1
|
||||
alu.io.b := aluB
|
||||
alu.io.isWord := dec.isWord
|
||||
branch.io.funct3 := dec.funct3
|
||||
branch.io.a := src1
|
||||
branch.io.b := src2
|
||||
|
||||
csr.io.cmd.valid := state === sExec && dec.isSystem && dec.funct3 =/= 0.U &&
|
||||
!(dec.funct3(1) && dec.rs1 === 0.U)
|
||||
csr.io.cmd.addr := instReg(31, 20)
|
||||
csr.io.cmd.cmd := dec.funct3
|
||||
csr.io.cmd.rs1 := src1
|
||||
csr.io.cmd.zimm := dec.rs1
|
||||
val isEcall = instReg === "h00000073".U
|
||||
val isEbreak = instReg === "h00100073".U
|
||||
val isMret = instReg === "h30200073".U
|
||||
val takeTrap = state === sExec && (isEcall || isEbreak)
|
||||
csr.io.trap := takeTrap
|
||||
csr.io.trapPc := pcReg
|
||||
csr.io.trapCause := Mux(isEbreak, 3.U, 11.U)
|
||||
|
||||
val loadAddr = src1 + dec.immI
|
||||
val storeAddr = src1 + dec.immS
|
||||
val pendingLoadAddr = Reg(UInt(p.xlen.W))
|
||||
val pendingLoadRd = Reg(UInt(5.W))
|
||||
val pendingLoadSize = Reg(UInt(3.W))
|
||||
val pendingLoadSigned = Reg(Bool())
|
||||
|
||||
val isAmo = instReg(6, 0) === "b0101111".U
|
||||
val amoOp = instReg(31, 27)
|
||||
val amoLoadLike = isAmo && amoOp === "b00010".U
|
||||
val amoStoreLike = isAmo && amoOp === "b00011".U
|
||||
|
||||
val memReqInExec = state === sExec && (dec.isLoad || dec.isStore)
|
||||
io.imem_req_valid := state === sFetch
|
||||
io.imem_req_bits := pc
|
||||
io.dmem_req_valid := memReqInExec || state === sLoadWait
|
||||
io.dmem_req_bits_addr := Mux(state === sLoadWait, pendingLoadAddr, Mux(dec.isStore, storeAddr, loadAddr))
|
||||
io.dmem_req_bits_data := src2
|
||||
io.dmem_req_bits_isStore := state === sExec && Mux(isAmo, !amoLoadLike, dec.isStore)
|
||||
io.dmem_req_bits_size := Mux(state === sLoadWait, pendingLoadSize, dec.memWidth)
|
||||
|
||||
val branchTarget = pcReg + dec.immB
|
||||
val jalTarget = pcReg + dec.immJ
|
||||
val jalrTarget = (src1 + dec.immI) & (~1.U(p.xlen.W))
|
||||
val branchTaken = dec.isBranch && branch.io.taken
|
||||
val nextPc = Mux(dec.isJal, jalTarget,
|
||||
Mux(dec.isJalr, jalrTarget,
|
||||
Mux(branchTaken, branchTarget, pcReg + 4.U)))
|
||||
|
||||
val execWriteData = WireDefault(alu.io.out)
|
||||
when(dec.isLui) {
|
||||
execWriteData := dec.immU
|
||||
}.elsewhen(dec.isAuipc) {
|
||||
execWriteData := pcReg + dec.immU
|
||||
}.elsewhen(dec.isJal || dec.isJalr) {
|
||||
execWriteData := pcReg + 4.U
|
||||
}.elsewhen(dec.isSystem && dec.funct3 =/= 0.U) {
|
||||
execWriteData := csr.io.rdata
|
||||
}
|
||||
|
||||
when(state === sFetch) {
|
||||
when(io.imem_resp_valid) {
|
||||
instReg := io.imem_resp_bits_0
|
||||
pcReg := pc
|
||||
state := sExec
|
||||
}
|
||||
}.elsewhen(state === sExec) {
|
||||
when(takeTrap) {
|
||||
pc := csr.io.mtvec
|
||||
state := sFetch
|
||||
}.elsewhen(isMret) {
|
||||
pc := csr.io.mepc
|
||||
state := sFetch
|
||||
}.elsewhen(dec.isLoad && !amoStoreLike) {
|
||||
when(io.dmem_resp_valid) {
|
||||
when(dec.rd =/= 0.U) {
|
||||
regs(dec.rd) := lowLoad(io.dmem_resp_bits, dec.memWidth, dec.memSigned)
|
||||
}
|
||||
pc := pcReg + 4.U
|
||||
state := sFetch
|
||||
}.otherwise {
|
||||
pendingLoadAddr := loadAddr
|
||||
pendingLoadRd := dec.rd
|
||||
pendingLoadSize := dec.memWidth
|
||||
pendingLoadSigned := dec.memSigned
|
||||
state := sLoadWait
|
||||
}
|
||||
}.elsewhen(dec.isStore || amoStoreLike) {
|
||||
pc := pcReg + 4.U
|
||||
state := sFetch
|
||||
}.otherwise {
|
||||
when(dec.writesRd && dec.rd =/= 0.U) {
|
||||
regs(dec.rd) := execWriteData
|
||||
}
|
||||
pc := nextPc
|
||||
state := sFetch
|
||||
}
|
||||
}.elsewhen(state === sLoadWait) {
|
||||
when(io.dmem_resp_valid) {
|
||||
when(pendingLoadRd =/= 0.U) {
|
||||
regs(pendingLoadRd) := lowLoad(io.dmem_resp_bits, pendingLoadSize, pendingLoadSigned)
|
||||
}
|
||||
pc := pcReg + 4.U
|
||||
state := sFetch
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object Core extends App {
|
||||
ChiselStage.emitSystemVerilogFile(
|
||||
new Core(),
|
||||
args = Array("--target-dir", "generated"),
|
||||
firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
|
||||
)
|
||||
}
|
||||
18
src/main/scala/commit/CommitStage.scala
Normal file
18
src/main/scala/commit/CommitStage.scala
Normal file
@@ -0,0 +1,18 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class CommitStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val robValid = Input(Bool())
|
||||
val robEntry = Input(new RobEntry(p))
|
||||
val commitReady = Output(Bool())
|
||||
val freeOldPhys = Output(Bool())
|
||||
val oldPhys = Output(UInt(log2Ceil(p.physRegs).W))
|
||||
val flush = Output(Bool())
|
||||
})
|
||||
|
||||
io.commitReady := io.robValid
|
||||
io.freeOldPhys := io.robValid && io.robEntry.oldDest =/= io.robEntry.dest
|
||||
io.oldPhys := io.robEntry.oldDest
|
||||
io.flush := io.robValid && (io.robEntry.exception || io.robEntry.branchMispredict)
|
||||
}
|
||||
76
src/main/scala/common/Bundles.scala
Normal file
76
src/main/scala/common/Bundles.scala
Normal file
@@ -0,0 +1,76 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class FetchPacket(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val pc = UInt(p.xlen.W)
|
||||
val inst = Vec(p.fetchWidth, UInt(32.W))
|
||||
val predictedTaken = Bool()
|
||||
val predictedTarget = UInt(p.xlen.W)
|
||||
}
|
||||
|
||||
class BranchUpdate(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val pc = UInt(p.xlen.W)
|
||||
val taken = Bool()
|
||||
val target = UInt(p.xlen.W)
|
||||
val isCall = Bool()
|
||||
val isReturn = Bool()
|
||||
}
|
||||
|
||||
class DecodedInst(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val pc = UInt(p.xlen.W)
|
||||
val inst = UInt(32.W)
|
||||
val rs1 = UInt(5.W)
|
||||
val rs2 = UInt(5.W)
|
||||
val rd = UInt(5.W)
|
||||
val funct3 = UInt(3.W)
|
||||
val funct7 = UInt(7.W)
|
||||
val immI = UInt(p.xlen.W)
|
||||
val immS = UInt(p.xlen.W)
|
||||
val immB = UInt(p.xlen.W)
|
||||
val immU = UInt(p.xlen.W)
|
||||
val immJ = UInt(p.xlen.W)
|
||||
val opClass = UInt(Consts.OpClassWidth.W)
|
||||
val aluFn = UInt(5.W)
|
||||
val memWidth = UInt(3.W)
|
||||
val memSigned = Bool()
|
||||
val isLoad = Bool()
|
||||
val isStore = Bool()
|
||||
val isBranch = Bool()
|
||||
val isJal = Bool()
|
||||
val isJalr = Bool()
|
||||
val isLui = Bool()
|
||||
val isAuipc = Bool()
|
||||
val isOpImm = Bool()
|
||||
val isOp = Bool()
|
||||
val isWord = Bool()
|
||||
val isSystem = Bool()
|
||||
val writesRd = Bool()
|
||||
val illegal = Bool()
|
||||
}
|
||||
|
||||
class RenamePacket(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val decoded = new DecodedInst(p)
|
||||
val prs1 = UInt(log2Ceil(p.physRegs).W)
|
||||
val prs2 = UInt(log2Ceil(p.physRegs).W)
|
||||
val prd = UInt(log2Ceil(p.physRegs).W)
|
||||
val oldPrd = UInt(log2Ceil(p.physRegs).W)
|
||||
val robIdx = UInt(log2Ceil(p.robEntries).W)
|
||||
}
|
||||
|
||||
class MemRequest(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val addr = UInt(p.xlen.W)
|
||||
val data = UInt(p.xlen.W)
|
||||
val isStore = Bool()
|
||||
val size = UInt(3.W)
|
||||
}
|
||||
|
||||
class CsrCommand(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val addr = UInt(12.W)
|
||||
val cmd = UInt(3.W)
|
||||
val rs1 = UInt(p.xlen.W)
|
||||
val zimm = UInt(5.W)
|
||||
}
|
||||
35
src/main/scala/common/Consts.scala
Normal file
35
src/main/scala/common/Consts.scala
Normal file
@@ -0,0 +1,35 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
object Consts {
|
||||
val ResetVector = "h80000000".U(64.W)
|
||||
|
||||
val OpClassWidth = 4
|
||||
val OP_NONE = 0.U(OpClassWidth.W)
|
||||
val OP_ALU = 1.U(OpClassWidth.W)
|
||||
val OP_BRANCH = 2.U(OpClassWidth.W)
|
||||
val OP_LOAD = 3.U(OpClassWidth.W)
|
||||
val OP_STORE = 4.U(OpClassWidth.W)
|
||||
val OP_SYSTEM = 5.U(OpClassWidth.W)
|
||||
val OP_FP = 6.U(OpClassWidth.W)
|
||||
|
||||
val ALU_ADD = 0.U(5.W)
|
||||
val ALU_SUB = 1.U(5.W)
|
||||
val ALU_SLL = 2.U(5.W)
|
||||
val ALU_SLT = 3.U(5.W)
|
||||
val ALU_SLTU = 4.U(5.W)
|
||||
val ALU_XOR = 5.U(5.W)
|
||||
val ALU_SRL = 6.U(5.W)
|
||||
val ALU_SRA = 7.U(5.W)
|
||||
val ALU_OR = 8.U(5.W)
|
||||
val ALU_AND = 9.U(5.W)
|
||||
val ALU_MUL = 10.U(5.W)
|
||||
val ALU_DIV = 11.U(5.W)
|
||||
val ALU_DIVU = 12.U(5.W)
|
||||
val ALU_REM = 13.U(5.W)
|
||||
val ALU_REMU = 14.U(5.W)
|
||||
val ALU_COPY_B = 15.U(5.W)
|
||||
|
||||
def signExtend(value: UInt, from: Int, to: Int = 64): UInt =
|
||||
Cat(Fill(to - from, value(from - 1)), value(from - 1, 0))
|
||||
}
|
||||
28
src/main/scala/common/Parameters.scala
Normal file
28
src/main/scala/common/Parameters.scala
Normal file
@@ -0,0 +1,28 @@
|
||||
case class CoreParams(
|
||||
xlen: Int = 64,
|
||||
fetchWidth: Int = 2,
|
||||
issueWidth: Int = 2,
|
||||
archRegs: Int = 32,
|
||||
physRegs: Int = 64,
|
||||
robEntries: Int = 64,
|
||||
intRsEntries: Int = 16,
|
||||
lsuRsEntries: Int = 12,
|
||||
fpRsEntries: Int = 16,
|
||||
loadQueueEntries: Int = 16,
|
||||
storeQueueEntries: Int = 16,
|
||||
btbEntries: Int = 512,
|
||||
rasEntries: Int = 16,
|
||||
ghrBits: Int = 12,
|
||||
iCacheBytes: Int = 32 * 1024,
|
||||
iCacheWays: Int = 4,
|
||||
dCacheBytes: Int = 32 * 1024,
|
||||
dCacheWays: Int = 8,
|
||||
cacheLineBytes: Int = 64,
|
||||
itlbEntries: Int = 32,
|
||||
dtlbEntries: Int = 32
|
||||
) {
|
||||
require(xlen == 64, "this implementation targets RV64")
|
||||
require(fetchWidth == 2, "frontend is parameterized around dual fetch")
|
||||
require(issueWidth == 2, "backend structures are parameterized around dual issue")
|
||||
}
|
||||
|
||||
99
src/main/scala/csr/CSRFile.scala
Normal file
99
src/main/scala/csr/CSRFile.scala
Normal file
@@ -0,0 +1,99 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class CSRFile(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val cmd = Input(new CsrCommand(p))
|
||||
val rdata = Output(UInt(p.xlen.W))
|
||||
val trap = Input(Bool())
|
||||
val trapPc = Input(UInt(p.xlen.W))
|
||||
val trapCause = Input(UInt(p.xlen.W))
|
||||
val satp = Output(UInt(p.xlen.W))
|
||||
val mtvec = Output(UInt(p.xlen.W))
|
||||
val mepc = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
val cycle = RegInit(0.U(p.xlen.W))
|
||||
val instret = RegInit(0.U(p.xlen.W))
|
||||
val mstatus = RegInit(0.U(p.xlen.W))
|
||||
val misa = RegInit("h800000000014112d".U(p.xlen.W))
|
||||
val mtvecReg = RegInit(0.U(p.xlen.W))
|
||||
val mepcReg = RegInit(0.U(p.xlen.W))
|
||||
val mcause = RegInit(0.U(p.xlen.W))
|
||||
val mtval = RegInit(0.U(p.xlen.W))
|
||||
val medeleg = RegInit(0.U(p.xlen.W))
|
||||
val mideleg = RegInit(0.U(p.xlen.W))
|
||||
val mie = RegInit(0.U(p.xlen.W))
|
||||
val mip = RegInit(0.U(p.xlen.W))
|
||||
val sstatus = RegInit(0.U(p.xlen.W))
|
||||
val stvec = RegInit(0.U(p.xlen.W))
|
||||
val sepc = RegInit(0.U(p.xlen.W))
|
||||
val scause = RegInit(0.U(p.xlen.W))
|
||||
val stval = RegInit(0.U(p.xlen.W))
|
||||
val sscratch = RegInit(0.U(p.xlen.W))
|
||||
val satpReg = RegInit(0.U(p.xlen.W))
|
||||
|
||||
cycle := cycle + 1.U
|
||||
io.satp := satpReg
|
||||
io.mtvec := mtvecReg
|
||||
io.mepc := mepcReg
|
||||
|
||||
val r = WireDefault(0.U(p.xlen.W))
|
||||
switch(io.cmd.addr) {
|
||||
is("h300".U) { r := mstatus }
|
||||
is("h301".U) { r := misa }
|
||||
is("h302".U) { r := medeleg }
|
||||
is("h303".U) { r := mideleg }
|
||||
is("h304".U) { r := mie }
|
||||
is("h305".U) { r := mtvecReg }
|
||||
is("h341".U) { r := mepcReg }
|
||||
is("h342".U) { r := mcause }
|
||||
is("h343".U) { r := mtval }
|
||||
is("h344".U) { r := mip }
|
||||
is("h100".U) { r := sstatus }
|
||||
is("h105".U) { r := stvec }
|
||||
is("h140".U) { r := sscratch }
|
||||
is("h141".U) { r := sepc }
|
||||
is("h142".U) { r := scause }
|
||||
is("h143".U) { r := stval }
|
||||
is("h180".U) { r := satpReg }
|
||||
is("hf14".U) { r := 0.U }
|
||||
is("hc00".U) { r := cycle }
|
||||
is("hc01".U) { r := 0.U }
|
||||
is("hc02".U) { r := instret }
|
||||
}
|
||||
io.rdata := r
|
||||
|
||||
val operand = Mux(io.cmd.cmd(2), io.cmd.zimm, io.cmd.rs1)
|
||||
val next = MuxLookup(io.cmd.cmd(1, 0), r)(Seq(
|
||||
1.U -> operand,
|
||||
2.U -> (r | operand),
|
||||
3.U -> (r & ~operand)
|
||||
))
|
||||
|
||||
when(io.cmd.valid && io.cmd.cmd =/= 0.U) {
|
||||
switch(io.cmd.addr) {
|
||||
is("h300".U) { mstatus := next }
|
||||
is("h302".U) { medeleg := next }
|
||||
is("h303".U) { mideleg := next }
|
||||
is("h304".U) { mie := next }
|
||||
is("h305".U) { mtvecReg := next }
|
||||
is("h341".U) { mepcReg := next }
|
||||
is("h342".U) { mcause := next }
|
||||
is("h343".U) { mtval := next }
|
||||
is("h344".U) { mip := next }
|
||||
is("h100".U) { sstatus := next }
|
||||
is("h105".U) { stvec := next }
|
||||
is("h140".U) { sscratch := next }
|
||||
is("h141".U) { sepc := next }
|
||||
is("h142".U) { scause := next }
|
||||
is("h143".U) { stval := next }
|
||||
is("h180".U) { satpReg := next }
|
||||
}
|
||||
}
|
||||
|
||||
when(io.trap) {
|
||||
mepcReg := io.trapPc
|
||||
mcause := io.trapCause
|
||||
}
|
||||
}
|
||||
21
src/main/scala/csr/PrivilegeControl.scala
Normal file
21
src/main/scala/csr/PrivilegeControl.scala
Normal file
@@ -0,0 +1,21 @@
|
||||
import chisel3._
|
||||
|
||||
class PrivilegeControl(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val trap = Input(Bool())
|
||||
val mret = Input(Bool())
|
||||
val sret = Input(Bool())
|
||||
val privilege = Output(UInt(2.W))
|
||||
})
|
||||
|
||||
val mode = RegInit(3.U(2.W))
|
||||
when(io.trap) {
|
||||
mode := 3.U
|
||||
}.elsewhen(io.mret) {
|
||||
mode := 0.U
|
||||
}.elsewhen(io.sret) {
|
||||
mode := 0.U
|
||||
}
|
||||
io.privilege := mode
|
||||
}
|
||||
|
||||
150
src/main/scala/decode/Decoder.scala
Normal file
150
src/main/scala/decode/Decoder.scala
Normal file
@@ -0,0 +1,150 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class Decoder(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val pc = Input(UInt(p.xlen.W))
|
||||
val inst = Input(UInt(32.W))
|
||||
val out = Output(new DecodedInst(p))
|
||||
})
|
||||
|
||||
val opcode = io.inst(6, 0)
|
||||
val rd = io.inst(11, 7)
|
||||
val funct3 = io.inst(14, 12)
|
||||
val rs1 = io.inst(19, 15)
|
||||
val rs2 = io.inst(24, 20)
|
||||
val funct7 = io.inst(31, 25)
|
||||
|
||||
val immI = Consts.signExtend(io.inst(31, 20), 12)
|
||||
val immS = Consts.signExtend(Cat(io.inst(31, 25), io.inst(11, 7)), 12)
|
||||
val immB = Consts.signExtend(Cat(io.inst(31), io.inst(7), io.inst(30, 25), io.inst(11, 8), 0.U(1.W)), 13)
|
||||
val immU = Consts.signExtend(Cat(io.inst(31, 12), 0.U(12.W)), 32)
|
||||
val immJ = Consts.signExtend(Cat(io.inst(31), io.inst(19, 12), io.inst(20), io.inst(30, 21), 0.U(1.W)), 21)
|
||||
|
||||
val d = WireDefault(0.U.asTypeOf(new DecodedInst(p)))
|
||||
d.valid := true.B
|
||||
d.pc := io.pc
|
||||
d.inst := io.inst
|
||||
d.rs1 := rs1
|
||||
d.rs2 := rs2
|
||||
d.rd := rd
|
||||
d.funct3 := funct3
|
||||
d.funct7 := funct7
|
||||
d.immI := immI
|
||||
d.immS := immS
|
||||
d.immB := immB
|
||||
d.immU := immU
|
||||
d.immJ := immJ
|
||||
d.memWidth := MuxLookup(funct3, 3.U)(Seq(
|
||||
"b000".U -> 0.U,
|
||||
"b001".U -> 1.U,
|
||||
"b010".U -> 2.U,
|
||||
"b011".U -> 3.U,
|
||||
"b100".U -> 0.U,
|
||||
"b101".U -> 1.U,
|
||||
"b110".U -> 2.U
|
||||
))
|
||||
d.memSigned := !funct3(2)
|
||||
d.illegal := false.B
|
||||
|
||||
switch(opcode) {
|
||||
is("b0110111".U) {
|
||||
d.isLui := true.B
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_ALU
|
||||
d.aluFn := Consts.ALU_COPY_B
|
||||
}
|
||||
is("b0010111".U) {
|
||||
d.isAuipc := true.B
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_ALU
|
||||
d.aluFn := Consts.ALU_ADD
|
||||
}
|
||||
is("b1101111".U) {
|
||||
d.isJal := true.B
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_BRANCH
|
||||
}
|
||||
is("b1100111".U) {
|
||||
d.isJalr := true.B
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_BRANCH
|
||||
}
|
||||
is("b1100011".U) {
|
||||
d.isBranch := true.B
|
||||
d.opClass := Consts.OP_BRANCH
|
||||
}
|
||||
is("b0000011".U) {
|
||||
d.isLoad := true.B
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_LOAD
|
||||
}
|
||||
is("b0100011".U) {
|
||||
d.isStore := true.B
|
||||
d.opClass := Consts.OP_STORE
|
||||
}
|
||||
is("b0010011".U, "b0011011".U) {
|
||||
d.isOpImm := true.B
|
||||
d.isWord := opcode === "b0011011".U
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_ALU
|
||||
d.aluFn := MuxLookup(funct3, Consts.ALU_ADD)(Seq(
|
||||
"b000".U -> Consts.ALU_ADD,
|
||||
"b001".U -> Consts.ALU_SLL,
|
||||
"b010".U -> Consts.ALU_SLT,
|
||||
"b011".U -> Consts.ALU_SLTU,
|
||||
"b100".U -> Consts.ALU_XOR,
|
||||
"b101".U -> Mux(funct7(5), Consts.ALU_SRA, Consts.ALU_SRL),
|
||||
"b110".U -> Consts.ALU_OR,
|
||||
"b111".U -> Consts.ALU_AND
|
||||
))
|
||||
}
|
||||
is("b0110011".U, "b0111011".U) {
|
||||
d.isOp := true.B
|
||||
d.isWord := opcode === "b0111011".U
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.opClass := Consts.OP_ALU
|
||||
d.aluFn := Mux(funct7 === "b0000001".U, MuxLookup(funct3, Consts.ALU_MUL)(Seq(
|
||||
"b000".U -> Consts.ALU_MUL,
|
||||
"b100".U -> Consts.ALU_DIV,
|
||||
"b101".U -> Consts.ALU_DIVU,
|
||||
"b110".U -> Consts.ALU_REM,
|
||||
"b111".U -> Consts.ALU_REMU
|
||||
)), MuxLookup(funct3, Consts.ALU_ADD)(Seq(
|
||||
"b000".U -> Mux(funct7(5), Consts.ALU_SUB, Consts.ALU_ADD),
|
||||
"b001".U -> Consts.ALU_SLL,
|
||||
"b010".U -> Consts.ALU_SLT,
|
||||
"b011".U -> Consts.ALU_SLTU,
|
||||
"b100".U -> Consts.ALU_XOR,
|
||||
"b101".U -> Mux(funct7(5), Consts.ALU_SRA, Consts.ALU_SRL),
|
||||
"b110".U -> Consts.ALU_OR,
|
||||
"b111".U -> Consts.ALU_AND
|
||||
)))
|
||||
}
|
||||
is("b0001111".U) {
|
||||
d.opClass := Consts.OP_SYSTEM
|
||||
}
|
||||
is("b1110011".U) {
|
||||
d.isSystem := true.B
|
||||
d.writesRd := rd =/= 0.U && funct3 =/= 0.U
|
||||
d.opClass := Consts.OP_SYSTEM
|
||||
}
|
||||
is("b0101111".U) {
|
||||
d.isLoad := true.B
|
||||
d.isStore := true.B
|
||||
d.writesRd := rd =/= 0.U
|
||||
d.memWidth := Mux(funct3 === "b010".U, 2.U, 3.U)
|
||||
d.opClass := Consts.OP_LOAD
|
||||
}
|
||||
}
|
||||
|
||||
when(opcode =/= "b0110111".U && opcode =/= "b0010111".U && opcode =/= "b1101111".U &&
|
||||
opcode =/= "b1100111".U && opcode =/= "b1100011".U && opcode =/= "b0000011".U &&
|
||||
opcode =/= "b0100011".U && opcode =/= "b0010011".U && opcode =/= "b0011011".U &&
|
||||
opcode =/= "b0110011".U && opcode =/= "b0111011".U && opcode =/= "b0001111".U &&
|
||||
opcode =/= "b1110011".U && opcode =/= "b0101111".U) {
|
||||
d.illegal := true.B
|
||||
}
|
||||
|
||||
io.out := d
|
||||
}
|
||||
20
src/main/scala/decode/IDStage.scala
Normal file
20
src/main/scala/decode/IDStage.scala
Normal file
@@ -0,0 +1,20 @@
|
||||
import chisel3._
|
||||
|
||||
class IDStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val inValid = Input(Bool())
|
||||
val in = Input(new FetchPacket(p))
|
||||
val outValid = Output(Vec(p.fetchWidth, Bool()))
|
||||
val out = Output(Vec(p.fetchWidth, new DecodedInst(p)))
|
||||
})
|
||||
|
||||
val decoders = Seq.fill(p.fetchWidth)(Module(new Decoder(p)))
|
||||
for (i <- 0 until p.fetchWidth) {
|
||||
decoders(i).io.pc := io.in.pc + (4 * i).U
|
||||
decoders(i).io.inst := io.in.inst(i)
|
||||
io.out(i) := decoders(i).io.out
|
||||
io.out(i).valid := io.inValid
|
||||
io.outValid(i) := io.inValid
|
||||
}
|
||||
}
|
||||
|
||||
36
src/main/scala/execute/ALU.scala
Normal file
36
src/main/scala/execute/ALU.scala
Normal file
@@ -0,0 +1,36 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ALU(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val fn = Input(UInt(5.W))
|
||||
val a = Input(UInt(p.xlen.W))
|
||||
val b = Input(UInt(p.xlen.W))
|
||||
val isWord = Input(Bool())
|
||||
val out = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
val shamt = Mux(io.isWord, io.b(4, 0), io.b(5, 0))
|
||||
val raw = WireDefault(0.U(p.xlen.W))
|
||||
switch(io.fn) {
|
||||
is(Consts.ALU_ADD) { raw := io.a + io.b }
|
||||
is(Consts.ALU_SUB) { raw := io.a - io.b }
|
||||
is(Consts.ALU_SLL) { raw := io.a << shamt }
|
||||
is(Consts.ALU_SLT) { raw := (io.a.asSInt < io.b.asSInt).asUInt }
|
||||
is(Consts.ALU_SLTU) { raw := io.a < io.b }
|
||||
is(Consts.ALU_XOR) { raw := io.a ^ io.b }
|
||||
is(Consts.ALU_SRL) { raw := io.a >> shamt }
|
||||
is(Consts.ALU_SRA) { raw := (io.a.asSInt >> shamt).asUInt }
|
||||
is(Consts.ALU_OR) { raw := io.a | io.b }
|
||||
is(Consts.ALU_AND) { raw := io.a & io.b }
|
||||
is(Consts.ALU_MUL) { raw := (io.a * io.b)(p.xlen - 1, 0) }
|
||||
is(Consts.ALU_DIV) { raw := Mux(io.b === 0.U, Fill(p.xlen, 1.U), (io.a.asSInt / io.b.asSInt).asUInt) }
|
||||
is(Consts.ALU_DIVU) { raw := Mux(io.b === 0.U, Fill(p.xlen, 1.U), io.a / io.b) }
|
||||
is(Consts.ALU_REM) { raw := Mux(io.b === 0.U, io.a, (io.a.asSInt % io.b.asSInt).asUInt) }
|
||||
is(Consts.ALU_REMU) { raw := Mux(io.b === 0.U, io.a, io.a % io.b) }
|
||||
is(Consts.ALU_COPY_B) { raw := io.b }
|
||||
}
|
||||
|
||||
io.out := Mux(io.isWord, Consts.signExtend(raw(31, 0), 32), raw)
|
||||
}
|
||||
|
||||
21
src/main/scala/execute/BranchUnit.scala
Normal file
21
src/main/scala/execute/BranchUnit.scala
Normal file
@@ -0,0 +1,21 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class BranchUnit(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val funct3 = Input(UInt(3.W))
|
||||
val a = Input(UInt(p.xlen.W))
|
||||
val b = Input(UInt(p.xlen.W))
|
||||
val taken = Output(Bool())
|
||||
})
|
||||
|
||||
io.taken := MuxLookup(io.funct3, false.B)(Seq(
|
||||
"b000".U -> (io.a === io.b),
|
||||
"b001".U -> (io.a =/= io.b),
|
||||
"b100".U -> (io.a.asSInt < io.b.asSInt),
|
||||
"b101".U -> (io.a.asSInt >= io.b.asSInt),
|
||||
"b110".U -> (io.a < io.b),
|
||||
"b111".U -> (io.a >= io.b)
|
||||
))
|
||||
}
|
||||
|
||||
14
src/main/scala/execute/Divider.scala
Normal file
14
src/main/scala/execute/Divider.scala
Normal file
@@ -0,0 +1,14 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class Divider(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val signed = Input(Bool())
|
||||
val a = Input(UInt(p.xlen.W))
|
||||
val b = Input(UInt(p.xlen.W))
|
||||
val quotient = Output(UInt(p.xlen.W))
|
||||
val remainder = Output(UInt(p.xlen.W))
|
||||
})
|
||||
io.quotient := Mux(io.b === 0.U, Fill(p.xlen, 1.U), Mux(io.signed, (io.a.asSInt / io.b.asSInt).asUInt, io.a / io.b))
|
||||
io.remainder := Mux(io.b === 0.U, io.a, Mux(io.signed, (io.a.asSInt % io.b.asSInt).asUInt, io.a % io.b))
|
||||
}
|
||||
29
src/main/scala/execute/ExecStage.scala
Normal file
29
src/main/scala/execute/ExecStage.scala
Normal file
@@ -0,0 +1,29 @@
|
||||
import chisel3._
|
||||
|
||||
class ExecStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val inValid = Input(Bool())
|
||||
val in = Input(new DecodedInst(p))
|
||||
val src1 = Input(UInt(p.xlen.W))
|
||||
val src2 = Input(UInt(p.xlen.W))
|
||||
val outValid = Output(Bool())
|
||||
val result = Output(UInt(p.xlen.W))
|
||||
val branchTaken = Output(Bool())
|
||||
})
|
||||
|
||||
val alu = Module(new ALU(p))
|
||||
val branch = Module(new BranchUnit(p))
|
||||
|
||||
alu.io.fn := io.in.aluFn
|
||||
alu.io.a := io.src1
|
||||
alu.io.b := io.src2
|
||||
alu.io.isWord := io.in.isWord
|
||||
branch.io.funct3 := io.in.funct3
|
||||
branch.io.a := io.src1
|
||||
branch.io.b := io.src2
|
||||
|
||||
io.outValid := io.inValid
|
||||
io.result := alu.io.out
|
||||
io.branchTaken := branch.io.taken
|
||||
}
|
||||
|
||||
16
src/main/scala/execute/FPU.scala
Normal file
16
src/main/scala/execute/FPU.scala
Normal file
@@ -0,0 +1,16 @@
|
||||
import chisel3._
|
||||
|
||||
class FPU(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val inValid = Input(Bool())
|
||||
val op = Input(UInt(4.W))
|
||||
val a = Input(UInt(p.xlen.W))
|
||||
val b = Input(UInt(p.xlen.W))
|
||||
val outValid = Output(Bool())
|
||||
val out = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
io.outValid := io.inValid
|
||||
io.out := 0.U
|
||||
}
|
||||
|
||||
11
src/main/scala/execute/Multiplier.scala
Normal file
11
src/main/scala/execute/Multiplier.scala
Normal file
@@ -0,0 +1,11 @@
|
||||
import chisel3._
|
||||
|
||||
class Multiplier(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val a = Input(UInt(p.xlen.W))
|
||||
val b = Input(UInt(p.xlen.W))
|
||||
val out = Output(UInt(p.xlen.W))
|
||||
})
|
||||
io.out := (io.a * io.b)(p.xlen - 1, 0)
|
||||
}
|
||||
|
||||
32
src/main/scala/frontend/BTB.scala
Normal file
32
src/main/scala/frontend/BTB.scala
Normal file
@@ -0,0 +1,32 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class BTB(p: CoreParams = CoreParams()) extends Module {
|
||||
private val idxBits = log2Ceil(p.btbEntries)
|
||||
private val tagBits = 20
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val pc = Input(UInt(p.xlen.W))
|
||||
val hit = Output(Bool())
|
||||
val target = Output(UInt(p.xlen.W))
|
||||
val update = Input(new BranchUpdate(p))
|
||||
})
|
||||
|
||||
val valid = RegInit(VecInit(Seq.fill(p.btbEntries)(false.B)))
|
||||
val tags = Reg(Vec(p.btbEntries, UInt(tagBits.W)))
|
||||
val targets = Reg(Vec(p.btbEntries, UInt(p.xlen.W)))
|
||||
|
||||
val idx = io.pc(idxBits + 1, 2)
|
||||
val tag = io.pc(idxBits + tagBits + 1, idxBits + 2)
|
||||
|
||||
io.hit := valid(idx) && tags(idx) === tag
|
||||
io.target := targets(idx)
|
||||
|
||||
when(io.update.valid && io.update.taken) {
|
||||
val uidx = io.update.pc(idxBits + 1, 2)
|
||||
valid(uidx) := true.B
|
||||
tags(uidx) := io.update.pc(idxBits + tagBits + 1, idxBits + 2)
|
||||
targets(uidx) := io.update.target
|
||||
}
|
||||
}
|
||||
|
||||
38
src/main/scala/frontend/BranchPredictor.scala
Normal file
38
src/main/scala/frontend/BranchPredictor.scala
Normal file
@@ -0,0 +1,38 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class BranchPredictor(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val pc = Input(UInt(p.xlen.W))
|
||||
val taken = Output(Bool())
|
||||
val target = Output(UInt(p.xlen.W))
|
||||
val update = Input(new BranchUpdate(p))
|
||||
})
|
||||
|
||||
val ghr = RegInit(0.U(p.ghrBits.W))
|
||||
val pht = RegInit(VecInit(Seq.fill(1 << p.ghrBits)(1.U(2.W))))
|
||||
val btb = Module(new BTB(p))
|
||||
val ras = Module(new RAS(p))
|
||||
|
||||
val idx = io.pc(p.ghrBits + 1, 2) ^ ghr
|
||||
btb.io.pc := io.pc
|
||||
btb.io.update := io.update
|
||||
|
||||
ras.io.push := io.update.valid && io.update.isCall
|
||||
ras.io.pop := io.update.valid && io.update.isReturn
|
||||
ras.io.pushAddr := io.update.pc + 4.U
|
||||
|
||||
io.taken := pht(idx)(1) && btb.io.hit
|
||||
io.target := Mux(io.update.isReturn && !ras.io.empty, ras.io.top, btb.io.target)
|
||||
|
||||
when(io.update.valid) {
|
||||
val uidx = io.update.pc(p.ghrBits + 1, 2) ^ ghr
|
||||
when(io.update.taken && pht(uidx) =/= 3.U) {
|
||||
pht(uidx) := pht(uidx) + 1.U
|
||||
}.elsewhen(!io.update.taken && pht(uidx) =/= 0.U) {
|
||||
pht(uidx) := pht(uidx) - 1.U
|
||||
}
|
||||
ghr := Cat(ghr(p.ghrBits - 2, 0), io.update.taken)
|
||||
}
|
||||
}
|
||||
|
||||
43
src/main/scala/frontend/Frontend.scala
Normal file
43
src/main/scala/frontend/Frontend.scala
Normal file
@@ -0,0 +1,43 @@
|
||||
import chisel3._
|
||||
|
||||
class Frontend(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val redirectValid = Input(Bool())
|
||||
val redirectPc = Input(UInt(p.xlen.W))
|
||||
val imemReqValid = Output(Bool())
|
||||
val imemReqAddr = Output(UInt(p.xlen.W))
|
||||
val imemRespValid = Input(Bool())
|
||||
val imemRespBits = Input(Vec(p.fetchWidth, UInt(32.W)))
|
||||
val outValid = Output(Bool())
|
||||
val out = Output(new FetchPacket(p))
|
||||
val branchUpdate = Input(new BranchUpdate(p))
|
||||
})
|
||||
|
||||
val pc = RegInit(Consts.ResetVector)
|
||||
val predictor = Module(new BranchPredictor(p))
|
||||
val itlb = Module(new ITLB(p))
|
||||
val icache = Module(new ICache(p))
|
||||
|
||||
predictor.io.pc := pc
|
||||
predictor.io.update := io.branchUpdate
|
||||
itlb.io.vaddr := pc
|
||||
|
||||
icache.io.reqValid := true.B
|
||||
icache.io.reqAddr := itlb.io.paddr
|
||||
icache.io.memRespValid := io.imemRespValid
|
||||
icache.io.memRespBits := io.imemRespBits
|
||||
|
||||
io.imemReqValid := icache.io.memReqValid
|
||||
io.imemReqAddr := icache.io.memReqAddr
|
||||
io.outValid := icache.io.respValid
|
||||
io.out := icache.io.resp
|
||||
io.out.predictedTaken := predictor.io.taken
|
||||
io.out.predictedTarget := predictor.io.target
|
||||
|
||||
when(io.redirectValid) {
|
||||
pc := io.redirectPc
|
||||
}.elsewhen(icache.io.respValid) {
|
||||
pc := Mux(predictor.io.taken, predictor.io.target, pc + (4 * p.fetchWidth).U)
|
||||
}
|
||||
}
|
||||
|
||||
23
src/main/scala/frontend/ICache.scala
Normal file
23
src/main/scala/frontend/ICache.scala
Normal file
@@ -0,0 +1,23 @@
|
||||
import chisel3._
|
||||
|
||||
class ICache(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val reqAddr = Input(UInt(p.xlen.W))
|
||||
val memReqValid = Output(Bool())
|
||||
val memReqAddr = Output(UInt(p.xlen.W))
|
||||
val memRespValid = Input(Bool())
|
||||
val memRespBits = Input(Vec(p.fetchWidth, UInt(32.W)))
|
||||
val respValid = Output(Bool())
|
||||
val resp = Output(new FetchPacket(p))
|
||||
})
|
||||
|
||||
io.memReqValid := io.reqValid
|
||||
io.memReqAddr := io.reqAddr
|
||||
io.respValid := io.memRespValid
|
||||
io.resp.pc := io.reqAddr
|
||||
io.resp.inst := io.memRespBits
|
||||
io.resp.predictedTaken := false.B
|
||||
io.resp.predictedTarget := io.reqAddr + (4 * p.fetchWidth).U
|
||||
}
|
||||
|
||||
16
src/main/scala/frontend/ITLB.scala
Normal file
16
src/main/scala/frontend/ITLB.scala
Normal file
@@ -0,0 +1,16 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ITLB(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val vaddr = Input(UInt(p.xlen.W))
|
||||
val paddr = Output(UInt(p.xlen.W))
|
||||
val hit = Output(Bool())
|
||||
val miss = Output(Bool())
|
||||
})
|
||||
|
||||
io.paddr := io.vaddr
|
||||
io.hit := true.B
|
||||
io.miss := false.B
|
||||
}
|
||||
|
||||
31
src/main/scala/frontend/RAS.scala
Normal file
31
src/main/scala/frontend/RAS.scala
Normal file
@@ -0,0 +1,31 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class RAS(p: CoreParams = CoreParams()) extends Module {
|
||||
private val ptrBits = log2Ceil(p.rasEntries)
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val push = Input(Bool())
|
||||
val pop = Input(Bool())
|
||||
val pushAddr = Input(UInt(p.xlen.W))
|
||||
val top = Output(UInt(p.xlen.W))
|
||||
val empty = Output(Bool())
|
||||
})
|
||||
|
||||
val stack = Reg(Vec(p.rasEntries, UInt(p.xlen.W)))
|
||||
val sp = RegInit(0.U(ptrBits.W))
|
||||
val count = RegInit(0.U(log2Ceil(p.rasEntries + 1).W))
|
||||
|
||||
io.empty := count === 0.U
|
||||
io.top := stack(Mux(sp === 0.U, (p.rasEntries - 1).U, sp - 1.U))
|
||||
|
||||
when(io.push) {
|
||||
stack(sp) := io.pushAddr
|
||||
sp := Mux(sp === (p.rasEntries - 1).U, 0.U, sp + 1.U)
|
||||
when(count =/= p.rasEntries.U) { count := count + 1.U }
|
||||
}.elsewhen(io.pop && count =/= 0.U) {
|
||||
sp := Mux(sp === 0.U, (p.rasEntries - 1).U, sp - 1.U)
|
||||
count := count - 1.U
|
||||
}
|
||||
}
|
||||
|
||||
24
src/main/scala/issue/IssueQueue.scala
Normal file
24
src/main/scala/issue/IssueQueue.scala
Normal file
@@ -0,0 +1,24 @@
|
||||
import chisel3._
|
||||
|
||||
class IssueQueue(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val enqValid = Input(Bool())
|
||||
val enq = Input(new RenamePacket(p))
|
||||
val enqReady = Output(Bool())
|
||||
val issueValid = Output(Bool())
|
||||
val issue = Output(new RenamePacket(p))
|
||||
val issueReady = Input(Bool())
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val intRs = Module(new ReservationStation(p, p.intRsEntries))
|
||||
intRs.io.enqValid := io.enqValid
|
||||
intRs.io.enq := io.enq
|
||||
intRs.io.issueReady := io.issueReady
|
||||
intRs.io.flush := io.flush
|
||||
|
||||
io.enqReady := intRs.io.enqReady
|
||||
io.issueValid := intRs.io.issueValid
|
||||
io.issue := intRs.io.issue
|
||||
}
|
||||
|
||||
24
src/main/scala/issue/IssueStage.scala
Normal file
24
src/main/scala/issue/IssueStage.scala
Normal file
@@ -0,0 +1,24 @@
|
||||
import chisel3._
|
||||
|
||||
class IssueStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val inValid = Input(Bool())
|
||||
val in = Input(new RenamePacket(p))
|
||||
val inReady = Output(Bool())
|
||||
val outValid = Output(Bool())
|
||||
val out = Output(new RenamePacket(p))
|
||||
val outReady = Input(Bool())
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val queue = Module(new IssueQueue(p))
|
||||
queue.io.enqValid := io.inValid
|
||||
queue.io.enq := io.in
|
||||
queue.io.issueReady := io.outReady
|
||||
queue.io.flush := io.flush
|
||||
|
||||
io.inReady := queue.io.enqReady
|
||||
io.outValid := queue.io.issueValid
|
||||
io.out := queue.io.issue
|
||||
}
|
||||
|
||||
24
src/main/scala/issue/ReservationStation.scala
Normal file
24
src/main/scala/issue/ReservationStation.scala
Normal file
@@ -0,0 +1,24 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ReservationStation(p: CoreParams = CoreParams(), entries: Int = 16) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val enqValid = Input(Bool())
|
||||
val enq = Input(new RenamePacket(p))
|
||||
val enqReady = Output(Bool())
|
||||
val issueValid = Output(Bool())
|
||||
val issue = Output(new RenamePacket(p))
|
||||
val issueReady = Input(Bool())
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val q = Module(new Queue(new RenamePacket(p), entries, flow = false, pipe = true))
|
||||
q.io.enq.valid := io.enqValid
|
||||
q.io.enq.bits := io.enq
|
||||
q.io.deq.ready := io.issueReady || io.flush
|
||||
|
||||
io.enqReady := q.io.enq.ready
|
||||
io.issueValid := q.io.deq.valid && !io.flush
|
||||
io.issue := q.io.deq.bits
|
||||
}
|
||||
|
||||
20
src/main/scala/memory/DCache.scala
Normal file
20
src/main/scala/memory/DCache.scala
Normal file
@@ -0,0 +1,20 @@
|
||||
import chisel3._
|
||||
|
||||
class DCache(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val req = Input(new MemRequest(p))
|
||||
val memReqValid = Output(Bool())
|
||||
val memReq = Output(new MemRequest(p))
|
||||
val memRespValid = Input(Bool())
|
||||
val memRespData = Input(UInt(p.xlen.W))
|
||||
val respValid = Output(Bool())
|
||||
val respData = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
io.memReqValid := io.reqValid
|
||||
io.memReq := io.req
|
||||
io.respValid := io.memRespValid
|
||||
io.respData := io.memRespData
|
||||
}
|
||||
|
||||
15
src/main/scala/memory/DTLB.scala
Normal file
15
src/main/scala/memory/DTLB.scala
Normal file
@@ -0,0 +1,15 @@
|
||||
import chisel3._
|
||||
|
||||
class DTLB(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val vaddr = Input(UInt(p.xlen.W))
|
||||
val paddr = Output(UInt(p.xlen.W))
|
||||
val hit = Output(Bool())
|
||||
val miss = Output(Bool())
|
||||
})
|
||||
|
||||
io.paddr := io.vaddr
|
||||
io.hit := true.B
|
||||
io.miss := false.B
|
||||
}
|
||||
|
||||
30
src/main/scala/memory/LSU.scala
Normal file
30
src/main/scala/memory/LSU.scala
Normal file
@@ -0,0 +1,30 @@
|
||||
import chisel3._
|
||||
|
||||
class LSU(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val req = Input(new MemRequest(p))
|
||||
val dmemReqValid = Output(Bool())
|
||||
val dmemReq = Output(new MemRequest(p))
|
||||
val dmemRespValid = Input(Bool())
|
||||
val dmemRespData = Input(UInt(p.xlen.W))
|
||||
val respValid = Output(Bool())
|
||||
val respData = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
val dtlb = Module(new DTLB(p))
|
||||
val dcache = Module(new DCache(p))
|
||||
|
||||
dtlb.io.vaddr := io.req.addr
|
||||
dcache.io.reqValid := io.reqValid
|
||||
dcache.io.req := io.req
|
||||
dcache.io.req.addr := dtlb.io.paddr
|
||||
dcache.io.memRespValid := io.dmemRespValid
|
||||
dcache.io.memRespData := io.dmemRespData
|
||||
|
||||
io.dmemReqValid := dcache.io.memReqValid
|
||||
io.dmemReq := dcache.io.memReq
|
||||
io.respValid := dcache.io.respValid
|
||||
io.respData := dcache.io.respData
|
||||
}
|
||||
|
||||
23
src/main/scala/memory/LoadQueue.scala
Normal file
23
src/main/scala/memory/LoadQueue.scala
Normal file
@@ -0,0 +1,23 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class LoadQueue(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val enqValid = Input(Bool())
|
||||
val enqAddr = Input(UInt(p.xlen.W))
|
||||
val enqReady = Output(Bool())
|
||||
val complete = Input(Bool())
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val count = RegInit(0.U(log2Ceil(p.loadQueueEntries + 1).W))
|
||||
io.enqReady := count =/= p.loadQueueEntries.U
|
||||
|
||||
when(io.flush) {
|
||||
count := 0.U
|
||||
}.otherwise {
|
||||
when(io.enqValid && io.enqReady) { count := count + 1.U }
|
||||
when(io.complete && count =/= 0.U) { count := count - 1.U }
|
||||
}
|
||||
}
|
||||
|
||||
15
src/main/scala/memory/MMU.scala
Normal file
15
src/main/scala/memory/MMU.scala
Normal file
@@ -0,0 +1,15 @@
|
||||
import chisel3._
|
||||
|
||||
class MMU(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val satp = Input(UInt(p.xlen.W))
|
||||
val vaddr = Input(UInt(p.xlen.W))
|
||||
val isStore = Input(Bool())
|
||||
val paddr = Output(UInt(p.xlen.W))
|
||||
val pageFault = Output(Bool())
|
||||
})
|
||||
|
||||
io.paddr := io.vaddr
|
||||
io.pageFault := false.B
|
||||
}
|
||||
|
||||
26
src/main/scala/memory/MemStage.scala
Normal file
26
src/main/scala/memory/MemStage.scala
Normal file
@@ -0,0 +1,26 @@
|
||||
import chisel3._
|
||||
|
||||
class MemStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val req = Input(new MemRequest(p))
|
||||
val dmemReqValid = Output(Bool())
|
||||
val dmemReq = Output(new MemRequest(p))
|
||||
val dmemRespValid = Input(Bool())
|
||||
val dmemRespData = Input(UInt(p.xlen.W))
|
||||
val respValid = Output(Bool())
|
||||
val respData = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
val lsu = Module(new LSU(p))
|
||||
lsu.io.reqValid := io.reqValid
|
||||
lsu.io.req := io.req
|
||||
lsu.io.dmemRespValid := io.dmemRespValid
|
||||
lsu.io.dmemRespData := io.dmemRespData
|
||||
|
||||
io.dmemReqValid := lsu.io.dmemReqValid
|
||||
io.dmemReq := lsu.io.dmemReq
|
||||
io.respValid := lsu.io.respValid
|
||||
io.respData := lsu.io.respData
|
||||
}
|
||||
|
||||
24
src/main/scala/memory/StoreQueue.scala
Normal file
24
src/main/scala/memory/StoreQueue.scala
Normal file
@@ -0,0 +1,24 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class StoreQueue(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val enqValid = Input(Bool())
|
||||
val enq = Input(new MemRequest(p))
|
||||
val enqReady = Output(Bool())
|
||||
val drainValid = Output(Bool())
|
||||
val drain = Output(new MemRequest(p))
|
||||
val drainReady = Input(Bool())
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val q = Module(new Queue(new MemRequest(p), p.storeQueueEntries))
|
||||
q.io.enq.valid := io.enqValid && !io.flush
|
||||
q.io.enq.bits := io.enq
|
||||
q.io.deq.ready := io.drainReady || io.flush
|
||||
|
||||
io.enqReady := q.io.enq.ready
|
||||
io.drainValid := q.io.deq.valid && !io.flush
|
||||
io.drain := q.io.deq.bits
|
||||
}
|
||||
|
||||
23
src/main/scala/regfile/PhysicalRegFile.scala
Normal file
23
src/main/scala/regfile/PhysicalRegFile.scala
Normal file
@@ -0,0 +1,23 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class PhysicalRegFile(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val raddr = Input(Vec(4, UInt(log2Ceil(p.physRegs).W)))
|
||||
val rdata = Output(Vec(4, UInt(p.xlen.W)))
|
||||
val wen = Input(Vec(2, Bool()))
|
||||
val waddr = Input(Vec(2, UInt(log2Ceil(p.physRegs).W)))
|
||||
val wdata = Input(Vec(2, UInt(p.xlen.W)))
|
||||
})
|
||||
|
||||
val regs = RegInit(VecInit(Seq.fill(p.physRegs)(0.U(p.xlen.W))))
|
||||
for (i <- 0 until 4) {
|
||||
io.rdata(i) := Mux(io.raddr(i) === 0.U, 0.U, regs(io.raddr(i)))
|
||||
}
|
||||
for (i <- 0 until 2) {
|
||||
when(io.wen(i) && io.waddr(i) =/= 0.U) {
|
||||
regs(io.waddr(i)) := io.wdata(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
src/main/scala/rename/FreeList.scala
Normal file
26
src/main/scala/rename/FreeList.scala
Normal file
@@ -0,0 +1,26 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class FreeList(p: CoreParams = CoreParams()) extends Module {
|
||||
private val physBits = log2Ceil(p.physRegs)
|
||||
val io = IO(new Bundle {
|
||||
val alloc = Input(Bool())
|
||||
val allocPhys = Output(UInt(physBits.W))
|
||||
val canAlloc = Output(Bool())
|
||||
val free = Input(Bool())
|
||||
val freePhys = Input(UInt(physBits.W))
|
||||
})
|
||||
|
||||
val freeBits = RegInit(VecInit((0 until p.physRegs).map(i => (i >= p.archRegs).B)))
|
||||
val chosen = PriorityEncoder(freeBits)
|
||||
io.canAlloc := freeBits.asUInt.orR
|
||||
io.allocPhys := chosen
|
||||
|
||||
when(io.alloc && io.canAlloc) {
|
||||
freeBits(chosen) := false.B
|
||||
}
|
||||
when(io.free && io.freePhys >= p.archRegs.U) {
|
||||
freeBits(io.freePhys) := true.B
|
||||
}
|
||||
}
|
||||
|
||||
71
src/main/scala/rename/ROB.scala
Normal file
71
src/main/scala/rename/ROB.scala
Normal file
@@ -0,0 +1,71 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class RobEntry(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val pc = UInt(p.xlen.W)
|
||||
val opClass = UInt(Consts.OpClassWidth.W)
|
||||
val dest = UInt(log2Ceil(p.physRegs).W)
|
||||
val oldDest = UInt(log2Ceil(p.physRegs).W)
|
||||
val completed = Bool()
|
||||
val exception = Bool()
|
||||
val branchMispredict = Bool()
|
||||
}
|
||||
|
||||
class ROB(p: CoreParams = CoreParams()) extends Module {
|
||||
private val idxBits = log2Ceil(p.robEntries)
|
||||
val io = IO(new Bundle {
|
||||
val allocate = Input(Bool())
|
||||
val allocatePc = Input(UInt(p.xlen.W))
|
||||
val allocateClass = Input(UInt(Consts.OpClassWidth.W))
|
||||
val allocateDest = Input(UInt(log2Ceil(p.physRegs).W))
|
||||
val allocateOldDest = Input(UInt(log2Ceil(p.physRegs).W))
|
||||
val allocateIdx = Output(UInt(idxBits.W))
|
||||
val canAllocate = Output(Bool())
|
||||
val complete = Input(Bool())
|
||||
val completeIdx = Input(UInt(idxBits.W))
|
||||
val commitValid = Output(Bool())
|
||||
val commit = Output(new RobEntry(p))
|
||||
val commitReady = Input(Bool())
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val entries = RegInit(VecInit(Seq.fill(p.robEntries)(0.U.asTypeOf(new RobEntry(p)))))
|
||||
val head = RegInit(0.U(idxBits.W))
|
||||
val tail = RegInit(0.U(idxBits.W))
|
||||
val count = RegInit(0.U(log2Ceil(p.robEntries + 1).W))
|
||||
|
||||
io.canAllocate := count =/= p.robEntries.U
|
||||
io.allocateIdx := tail
|
||||
io.commit := entries(head)
|
||||
io.commitValid := count =/= 0.U && entries(head).valid && entries(head).completed
|
||||
|
||||
when(io.flush) {
|
||||
entries.foreach(_.valid := false.B)
|
||||
head := 0.U
|
||||
tail := 0.U
|
||||
count := 0.U
|
||||
}.otherwise {
|
||||
when(io.allocate && io.canAllocate) {
|
||||
entries(tail).valid := true.B
|
||||
entries(tail).pc := io.allocatePc
|
||||
entries(tail).opClass := io.allocateClass
|
||||
entries(tail).dest := io.allocateDest
|
||||
entries(tail).oldDest := io.allocateOldDest
|
||||
entries(tail).completed := false.B
|
||||
entries(tail).exception := false.B
|
||||
entries(tail).branchMispredict := false.B
|
||||
tail := tail + 1.U
|
||||
count := count + 1.U
|
||||
}
|
||||
when(io.complete) {
|
||||
entries(io.completeIdx).completed := true.B
|
||||
}
|
||||
when(io.commitValid && io.commitReady) {
|
||||
entries(head).valid := false.B
|
||||
head := head + 1.U
|
||||
count := count - 1.U
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
49
src/main/scala/rename/RenameStage.scala
Normal file
49
src/main/scala/rename/RenameStage.scala
Normal file
@@ -0,0 +1,49 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class RenameStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val inValid = Input(Bool())
|
||||
val in = Input(new DecodedInst(p))
|
||||
val outValid = Output(Bool())
|
||||
val out = Output(new RenamePacket(p))
|
||||
val commitFree = Input(Bool())
|
||||
val commitOldPhys = Input(UInt(log2Ceil(p.physRegs).W))
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val table = Module(new RenameTable(p))
|
||||
val freeList = Module(new FreeList(p))
|
||||
val rob = Module(new ROB(p))
|
||||
|
||||
table.io.rs1 := io.in.rs1
|
||||
table.io.rs2 := io.in.rs2
|
||||
table.io.rd := io.in.rd
|
||||
table.io.newPhys := freeList.io.allocPhys
|
||||
table.io.wen := io.inValid && io.in.writesRd && freeList.io.canAlloc && rob.io.canAllocate
|
||||
table.io.recover := io.flush
|
||||
|
||||
freeList.io.alloc := table.io.wen
|
||||
freeList.io.free := io.commitFree
|
||||
freeList.io.freePhys := io.commitOldPhys
|
||||
|
||||
rob.io.allocate := io.inValid && rob.io.canAllocate && (!io.in.writesRd || freeList.io.canAlloc)
|
||||
rob.io.allocatePc := io.in.pc
|
||||
rob.io.allocateClass := io.in.opClass
|
||||
rob.io.allocateDest := Mux(io.in.writesRd, freeList.io.allocPhys, table.io.oldPrd)
|
||||
rob.io.allocateOldDest := table.io.oldPrd
|
||||
rob.io.complete := false.B
|
||||
rob.io.completeIdx := 0.U
|
||||
rob.io.commitReady := false.B
|
||||
rob.io.flush := io.flush
|
||||
|
||||
io.outValid := rob.io.allocate
|
||||
io.out.valid := io.outValid
|
||||
io.out.decoded := io.in
|
||||
io.out.prs1 := table.io.prs1
|
||||
io.out.prs2 := table.io.prs2
|
||||
io.out.prd := Mux(io.in.writesRd, freeList.io.allocPhys, table.io.oldPrd)
|
||||
io.out.oldPrd := table.io.oldPrd
|
||||
io.out.robIdx := rob.io.allocateIdx
|
||||
}
|
||||
|
||||
32
src/main/scala/rename/RenameTable.scala
Normal file
32
src/main/scala/rename/RenameTable.scala
Normal file
@@ -0,0 +1,32 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class RenameTable(p: CoreParams = CoreParams()) extends Module {
|
||||
private val physBits = log2Ceil(p.physRegs)
|
||||
val io = IO(new Bundle {
|
||||
val rs1 = Input(UInt(5.W))
|
||||
val rs2 = Input(UInt(5.W))
|
||||
val rd = Input(UInt(5.W))
|
||||
val newPhys = Input(UInt(physBits.W))
|
||||
val wen = Input(Bool())
|
||||
val prs1 = Output(UInt(physBits.W))
|
||||
val prs2 = Output(UInt(physBits.W))
|
||||
val oldPrd = Output(UInt(physBits.W))
|
||||
val recover = Input(Bool())
|
||||
})
|
||||
|
||||
val init = VecInit((0 until p.archRegs).map(_.U(physBits.W)))
|
||||
val speculative = RegInit(init)
|
||||
val committed = RegInit(init)
|
||||
|
||||
io.prs1 := speculative(io.rs1)
|
||||
io.prs2 := speculative(io.rs2)
|
||||
io.oldPrd := speculative(io.rd)
|
||||
|
||||
when(io.recover) {
|
||||
speculative := committed
|
||||
}.elsewhen(io.wen && io.rd =/= 0.U) {
|
||||
speculative(io.rd) := io.newPhys
|
||||
}
|
||||
}
|
||||
|
||||
18
src/main/scala/writeback/WriteBackStage.scala
Normal file
18
src/main/scala/writeback/WriteBackStage.scala
Normal file
@@ -0,0 +1,18 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class WriteBackStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val valid = Input(Bool())
|
||||
val physDest = Input(UInt(log2Ceil(p.physRegs).W))
|
||||
val data = Input(UInt(p.xlen.W))
|
||||
val wen = Output(Bool())
|
||||
val waddr = Output(UInt(log2Ceil(p.physRegs).W))
|
||||
val wdata = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
io.wen := io.valid
|
||||
io.waddr := io.physDest
|
||||
io.wdata := io.data
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user