226 lines
7.1 KiB
Scala
226 lines
7.1 KiB
Scala
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))
|
|
})
|
|
|
|
if (p.useOoOBackend) {
|
|
val frontend = Module(new Frontend(p))
|
|
val id = Module(new IDStage(p))
|
|
val backend = Module(new OoOBackend(p))
|
|
|
|
frontend.io.redirectValid := backend.io.flush
|
|
frontend.io.redirectPc := backend.io.redirectPc
|
|
frontend.io.invalidateICache := backend.io.invalidateICache
|
|
frontend.io.imemRespValid := io.imem_resp_valid
|
|
frontend.io.imemRespBits(0) := io.imem_resp_bits_0
|
|
frontend.io.imemRespBits(1) := io.imem_resp_bits_1
|
|
frontend.io.branchUpdate := 0.U.asTypeOf(new BranchUpdate(p))
|
|
|
|
val fetchValid = RegInit(false.B)
|
|
val fetchReg = Reg(new FetchPacket(p))
|
|
val fetchReady = !fetchValid || backend.io.decodeReady
|
|
frontend.io.outReady := fetchReady
|
|
when(backend.io.flush) {
|
|
fetchValid := false.B
|
|
}.elsewhen(fetchReady) {
|
|
fetchValid := frontend.io.outValid
|
|
fetchReg := frontend.io.out
|
|
}
|
|
|
|
id.io.inValid := fetchValid
|
|
id.io.in := fetchReg
|
|
|
|
backend.io.decodeValid := id.io.outValid
|
|
backend.io.decode := id.io.out
|
|
backend.io.dmemRespValid := io.dmem_resp_valid
|
|
backend.io.dmemRespData := io.dmem_resp_bits
|
|
backend.io.satp := 0.U
|
|
|
|
io.imem_req_valid := frontend.io.imemReqValid
|
|
io.imem_req_bits := frontend.io.imemReqAddr
|
|
io.dmem_req_valid := backend.io.dmemReqValid
|
|
io.dmem_req_bits_addr := backend.io.dmemReq.addr
|
|
io.dmem_req_bits_data := backend.io.dmemReq.data
|
|
io.dmem_req_bits_isStore := backend.io.dmemReq.isStore
|
|
io.dmem_req_bits_size := backend.io.dmemReq.size
|
|
} else {
|
|
|
|
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
|
|
csr.io.readAddr := instReg(31, 20)
|
|
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")
|
|
)
|
|
}
|
|
|
|
object CoreOoO extends App {
|
|
ChiselStage.emitSystemVerilogFile(
|
|
new Core(CoreParams(useOoOBackend = true)),
|
|
args = Array("--target-dir", "generated-ooo"),
|
|
firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
|
|
)
|
|
}
|