fix: resolve OoO simulation timeout
This commit is contained in:
@@ -19,6 +19,47 @@ class Core(p: CoreParams = CoreParams()) extends Module {
|
||||
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.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)
|
||||
@@ -67,6 +108,7 @@ class Core(p: CoreParams = CoreParams()) extends Module {
|
||||
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
|
||||
@@ -162,6 +204,7 @@ class Core(p: CoreParams = CoreParams()) extends Module {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
object Core extends App {
|
||||
@@ -171,3 +214,11 @@ object Core extends App {
|
||||
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")
|
||||
)
|
||||
}
|
||||
|
||||
282
src/main/scala/OoOBackend.scala
Normal file
282
src/main/scala/OoOBackend.scala
Normal file
@@ -0,0 +1,282 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import _root_.circt.stage.ChiselStage
|
||||
|
||||
class OoOBackend(p: CoreParams = CoreParams()) extends Module {
|
||||
private val physBits = log2Ceil(p.physRegs)
|
||||
private val robBits = log2Ceil(p.robEntries)
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val decodeValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val decode = Input(Vec(p.issueWidth, new DecodedInst(p)))
|
||||
val decodeReady = Output(Bool())
|
||||
|
||||
val commitValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val commitEntry = Output(Vec(p.issueWidth, new RobEntry(p)))
|
||||
val flush = Output(Bool())
|
||||
val redirectPc = Output(UInt(p.xlen.W))
|
||||
|
||||
val dmemReqValid = Output(Bool())
|
||||
val dmemReq = Output(new MemRequest(p))
|
||||
val dmemRespValid = Input(Bool())
|
||||
val dmemRespData = Input(UInt(p.xlen.W))
|
||||
val satp = Input(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
val rename = Module(new RenameStage(p))
|
||||
val issue = Module(new IssueStage(p))
|
||||
val prf = Module(new PhysicalRegFile(p))
|
||||
val exec = Seq.fill(p.issueWidth)(Module(new ExecStage(p)))
|
||||
val wb = Seq.fill(p.issueWidth)(Module(new WriteBackStage(p)))
|
||||
val commit = Module(new CommitStage(p))
|
||||
val lq = Module(new LoadQueue(p))
|
||||
val sq = Module(new StoreQueue(p))
|
||||
val lsu = Module(new LSU(p))
|
||||
val csr = Module(new CSRFile(p))
|
||||
|
||||
val completeValid = Wire(Vec(p.issueWidth, Bool()))
|
||||
val completeIdx = Wire(Vec(p.issueWidth, UInt(robBits.W)))
|
||||
val completeException = Wire(Vec(p.issueWidth, Bool()))
|
||||
val completeCause = Wire(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeBadAddr = Wire(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeMispredict = Wire(Vec(p.issueWidth, Bool()))
|
||||
val completeRedirectPc = Wire(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeCsrValid = Wire(Vec(p.issueWidth, Bool()))
|
||||
val completeCsrAddr = Wire(Vec(p.issueWidth, UInt(12.W)))
|
||||
val completeCsrCmd = Wire(Vec(p.issueWidth, UInt(3.W)))
|
||||
val completeCsrRs1 = Wire(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeCsrZimm = Wire(Vec(p.issueWidth, UInt(5.W)))
|
||||
val wakeup = Wire(Vec(p.issueWidth, new Wakeup(p)))
|
||||
val wakeupReg = RegInit(VecInit(Seq.fill(p.issueWidth)(0.U.asTypeOf(new Wakeup(p)))))
|
||||
val csrRData = Wire(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
|
||||
rename.io.inValid := VecInit((0 until p.issueWidth).map(i => io.decodeValid(i) && issue.io.inReady(i)))
|
||||
rename.io.in := io.decode
|
||||
rename.io.wbValid := VecInit(wb.map(_.io.wen))
|
||||
rename.io.wbPhys := VecInit(wb.map(_.io.waddr))
|
||||
rename.io.completeValid := completeValid
|
||||
rename.io.completeIdx := completeIdx
|
||||
rename.io.completeException := completeException
|
||||
rename.io.completeCause := completeCause
|
||||
rename.io.completeBadAddr := completeBadAddr
|
||||
rename.io.completeMispredict := completeMispredict
|
||||
rename.io.completeRedirectPc := completeRedirectPc
|
||||
rename.io.completeCsrValid := completeCsrValid
|
||||
rename.io.completeCsrAddr := completeCsrAddr
|
||||
rename.io.completeCsrCmd := completeCsrCmd
|
||||
rename.io.completeCsrRs1 := completeCsrRs1
|
||||
rename.io.completeCsrZimm := completeCsrZimm
|
||||
rename.io.commitReady := commit.io.commitReady
|
||||
rename.io.commitMapValid := commit.io.commitMapValid
|
||||
rename.io.commitArch := commit.io.commitArch
|
||||
rename.io.commitPhys := commit.io.commitPhys
|
||||
rename.io.commitFreeOld := commit.io.freeOldPhys
|
||||
rename.io.commitOldPhys := commit.io.oldPhys
|
||||
rename.io.flush := commit.io.flush
|
||||
|
||||
issue.io.inValid := rename.io.outValid
|
||||
issue.io.in := rename.io.out
|
||||
issue.io.wakeup := wakeupReg
|
||||
val loadPending = RegInit(false.B)
|
||||
val loadPendingRob = Reg(UInt(robBits.W))
|
||||
val loadPendingPhys = Reg(UInt(physBits.W))
|
||||
val loadPendingLq = Reg(UInt(log2Ceil(p.loadQueueEntries).W))
|
||||
val loadRespValid = lsu.io.respValid && loadPending
|
||||
val memIssue = Wire(Vec(p.issueWidth, Bool()))
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
memIssue(i) := issue.io.outValid(i) && (issue.io.out(i).decoded.isLoad || issue.io.out(i).decoded.isStore)
|
||||
}
|
||||
val csrReadReq = Wire(Vec(p.issueWidth, Bool()))
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
val decoded = issue.io.out(i).decoded
|
||||
csrReadReq(i) := issue.io.outValid(i) && decoded.isSystem && decoded.funct3 =/= 0.U
|
||||
}
|
||||
val stallSecondCsrRead = csrReadReq(0) && csrReadReq(1)
|
||||
val memSlot0 = memIssue(0)
|
||||
val memSlot1 = !memSlot0 && memIssue(1)
|
||||
val memSlot = Mux(memSlot0, 0.U, 1.U)
|
||||
val canIssueMem = !loadPending
|
||||
val issue_io_outReady_0 = Wire(Bool())
|
||||
val issue_io_outReady_1 = Wire(Bool())
|
||||
dontTouch(issue_io_outReady_0)
|
||||
dontTouch(issue_io_outReady_1)
|
||||
val isMem0 = issue.io.out(0).decoded.isLoad || issue.io.out(0).decoded.isStore
|
||||
val isMem1 = issue.io.out(1).decoded.isLoad || issue.io.out(1).decoded.isStore
|
||||
val memReady0 = !isMem0 || (lsu.io.reqReady && canIssueMem)
|
||||
val memReady1 = !isMem1 || (lsu.io.reqReady && canIssueMem && !memSlot0)
|
||||
issue_io_outReady_0 := memReady0
|
||||
issue_io_outReady_1 := memReady1 && !stallSecondCsrRead
|
||||
issue.io.outReady := VecInit(Seq(issue_io_outReady_0, issue_io_outReady_1))
|
||||
val issueFire = Wire(Vec(p.issueWidth, Bool()))
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
issueFire(i) := issue.io.outValid(i) && issue.io.outReady(i)
|
||||
}
|
||||
issue.io.flush := commit.io.flush
|
||||
|
||||
io.decodeReady := rename.io.canAccept && issue.io.inReady.asUInt.andR
|
||||
|
||||
val memDecoded = issue.io.out(memSlot).decoded
|
||||
val memSrc1 = Mux(memSlot0, prf.io.rdata(0), prf.io.rdata(2))
|
||||
val memSrc2 = Mux(memSlot0, prf.io.rdata(1), prf.io.rdata(3))
|
||||
val memAddr = memSrc1 + Mux(memDecoded.isStore, memDecoded.immS, memDecoded.immI)
|
||||
|
||||
val loadEnq = (memSlot0 || memSlot1) && memDecoded.isLoad && issue.io.outReady(memSlot)
|
||||
val storeEnq = (memSlot0 || memSlot1) && memDecoded.isStore && issue.io.outReady(memSlot)
|
||||
val lsuLoadReq = loadEnq && !sq.io.forwardValid
|
||||
|
||||
lq.io.enqValid := loadEnq
|
||||
lq.io.enqRobIdx := issue.io.out(memSlot).robIdx
|
||||
lq.io.addrValid := loadEnq
|
||||
lq.io.addrIdx := lq.io.enqIdx
|
||||
lq.io.addr := memAddr
|
||||
lq.io.size := memDecoded.memWidth
|
||||
lq.io.complete := loadRespValid
|
||||
lq.io.completeIdx := loadPendingLq
|
||||
lq.io.storeAddrValid := storeEnq
|
||||
lq.io.storeRobIdx := issue.io.out(memSlot).robIdx
|
||||
lq.io.storeAddr := memAddr
|
||||
lq.io.storeSize := memDecoded.memWidth
|
||||
lq.io.flush := commit.io.flush
|
||||
|
||||
sq.io.enqValid := storeEnq
|
||||
sq.io.enqRobIdx := issue.io.out(memSlot).robIdx
|
||||
sq.io.writeAddr := storeEnq
|
||||
sq.io.writeData := storeEnq
|
||||
sq.io.writeIdx := sq.io.enqIdx
|
||||
sq.io.addr := memAddr
|
||||
sq.io.data := memSrc2
|
||||
sq.io.size := memDecoded.memWidth
|
||||
sq.io.loadAddr := memAddr
|
||||
sq.io.loadSize := memDecoded.memWidth
|
||||
sq.io.loadRobIdx := issue.io.out(memSlot).robIdx
|
||||
val commitStore0 = commit.io.commitReady(0) && rename.io.commitValid(0) &&
|
||||
rename.io.commitEntry(0).opClass === Consts.OP_STORE
|
||||
val commitStore1 = commit.io.commitReady(1) && rename.io.commitValid(1) &&
|
||||
rename.io.commitEntry(1).opClass === Consts.OP_STORE
|
||||
sq.io.commitValid := commitStore0 || commitStore1
|
||||
sq.io.commitRobIdx := Mux(commitStore0, rename.io.commitEntry(0).robIdx, rename.io.commitEntry(1).robIdx)
|
||||
sq.io.drainReady := !lsuLoadReq && lsu.io.reqReady
|
||||
sq.io.flush := commit.io.flush
|
||||
|
||||
lsu.io.reqValid := lsuLoadReq || sq.io.drainValid
|
||||
lsu.io.req := Mux(sq.io.drainValid, sq.io.drain, 0.U.asTypeOf(new MemRequest(p)))
|
||||
when(lsuLoadReq) {
|
||||
lsu.io.req.addr := memAddr
|
||||
lsu.io.req.data := 0.U
|
||||
lsu.io.req.isStore := false.B
|
||||
lsu.io.req.size := memDecoded.memWidth
|
||||
}
|
||||
lsu.io.dmemRespValid := io.dmemRespValid
|
||||
lsu.io.dmemRespData := io.dmemRespData
|
||||
lsu.io.satp := csr.io.satp
|
||||
io.dmemReqValid := lsu.io.dmemReqValid
|
||||
io.dmemReq := lsu.io.dmemReq
|
||||
|
||||
val csrReadFire = VecInit((0 until p.issueWidth).map(i => csrReadReq(i) && issue.io.outReady(i)))
|
||||
csr.io.readAddr := Mux(csrReadFire(0), issue.io.out(0).decoded.inst(31, 20), issue.io.out(1).decoded.inst(31, 20))
|
||||
csrRData(0) := csr.io.rdata
|
||||
csrRData(1) := csr.io.rdata
|
||||
csr.io.trap := commit.io.flush && commit.io.exception
|
||||
csr.io.trapPc := commit.io.badAddr
|
||||
csr.io.trapCause := commit.io.exceptionCause
|
||||
val commitCsr0 = commit.io.commitReady(0) && rename.io.commitValid(0) && rename.io.commitEntry(0).csrValid
|
||||
val commitCsr1 = commit.io.commitReady(1) && rename.io.commitValid(1) && rename.io.commitEntry(1).csrValid
|
||||
val commitCsrEntry = Mux(commitCsr0, rename.io.commitEntry(0), rename.io.commitEntry(1))
|
||||
csr.io.cmd.valid := commitCsr0 || commitCsr1
|
||||
csr.io.cmd.addr := commitCsrEntry.csrAddr
|
||||
csr.io.cmd.cmd := commitCsrEntry.csrCmd
|
||||
csr.io.cmd.rs1 := commitCsrEntry.csrRs1
|
||||
csr.io.cmd.zimm := commitCsrEntry.csrZimm
|
||||
|
||||
when(commit.io.flush) {
|
||||
loadPending := false.B
|
||||
}.elsewhen(loadEnq && !sq.io.forwardValid) {
|
||||
loadPending := true.B
|
||||
loadPendingRob := issue.io.out(memSlot).robIdx
|
||||
loadPendingPhys := issue.io.out(memSlot).prd
|
||||
loadPendingLq := lq.io.enqIdx
|
||||
}.elsewhen(loadRespValid) {
|
||||
loadPending := false.B
|
||||
}
|
||||
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
prf.io.raddr(2 * i) := issue.io.out(i).prs1
|
||||
prf.io.raddr(2 * i + 1) := issue.io.out(i).prs2
|
||||
}
|
||||
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
val decoded = issue.io.out(i).decoded
|
||||
val src1 = prf.io.rdata(2 * i)
|
||||
val rs2Val = prf.io.rdata(2 * i + 1)
|
||||
val src2 = Mux(decoded.isOpImm || decoded.isLoad || decoded.isJalr, decoded.immI, rs2Val)
|
||||
|
||||
exec(i).io.inValid := issueFire(i)
|
||||
exec(i).io.in := decoded
|
||||
exec(i).io.src1 := src1
|
||||
exec(i).io.src2 := src2
|
||||
|
||||
val isLoadRespSlot = i.U === 0.U && loadRespValid
|
||||
val useExecWb = exec(i).io.outValid && decoded.writesRd && !decoded.isLoad
|
||||
wb(i).io.valid := useExecWb || isLoadRespSlot
|
||||
wb(i).io.physDest := Mux(isLoadRespSlot, loadPendingPhys, issue.io.out(i).prd)
|
||||
wb(i).io.data := Mux(isLoadRespSlot, lsu.io.respData, Mux(decoded.isLui, decoded.immU,
|
||||
Mux(decoded.isAuipc, decoded.pc + decoded.immU,
|
||||
Mux(decoded.isJal || decoded.isJalr, decoded.pc + 4.U,
|
||||
Mux(decoded.isSystem && decoded.funct3 =/= 0.U, csrRData(i), exec(i).io.result)))))
|
||||
|
||||
prf.io.wen(i) := wb(i).io.wen
|
||||
prf.io.waddr(i) := wb(i).io.waddr
|
||||
prf.io.wdata(i) := wb(i).io.wdata
|
||||
|
||||
wakeup(i).valid := wb(i).io.wen
|
||||
wakeup(i).phys := wb(i).io.waddr
|
||||
wakeup(i).data := wb(i).io.wdata
|
||||
|
||||
val branchTarget = decoded.pc + decoded.immB
|
||||
val jalTarget = decoded.pc + decoded.immJ
|
||||
val jalrTarget = (src1 + decoded.immI) & (~1.U(p.xlen.W))
|
||||
val branchRedirect = Mux(decoded.isJal, jalTarget,
|
||||
Mux(decoded.isJalr, jalrTarget,
|
||||
Mux(decoded.isBranch && exec(i).io.branchTaken, branchTarget, decoded.pc + 4.U)))
|
||||
val isEcall = decoded.inst === "h00000073".U
|
||||
val isEbreak = decoded.inst === "h00100073".U
|
||||
val isMret = decoded.inst === "h30200073".U
|
||||
|
||||
val completeLoadResp = i.U === 0.U && loadRespValid
|
||||
completeValid(i) := (issueFire(i) && !decoded.isLoad) || completeLoadResp
|
||||
completeIdx(i) := Mux(completeLoadResp, loadPendingRob, issue.io.out(i).robIdx)
|
||||
completeException(i) := (issueFire(i) && (decoded.illegal || isEcall || isEbreak || lq.io.violation)) ||
|
||||
(completeLoadResp && lsu.io.pageFault)
|
||||
completeCause(i) := Mux(completeLoadResp && lsu.io.pageFault, 13.U,
|
||||
Mux(issueFire(i) && isEbreak, 3.U,
|
||||
Mux(issueFire(i) && isEcall, 11.U,
|
||||
Mux(issueFire(i) && decoded.illegal, 2.U, 0.U))))
|
||||
completeBadAddr(i) := decoded.pc
|
||||
completeMispredict(i) := issueFire(i) &&
|
||||
(decoded.isJal || decoded.isJalr || isMret || (decoded.isBranch && exec(i).io.branchTaken))
|
||||
completeRedirectPc(i) := Mux(isEcall || isEbreak, csr.io.mtvec, Mux(isMret, csr.io.mepc, branchRedirect))
|
||||
completeCsrValid(i) := issueFire(i) && decoded.isSystem && decoded.funct3 =/= 0.U &&
|
||||
!(decoded.funct3(1) && decoded.rs1 === 0.U)
|
||||
completeCsrAddr(i) := decoded.inst(31, 20)
|
||||
completeCsrCmd(i) := decoded.funct3
|
||||
completeCsrRs1(i) := src1
|
||||
completeCsrZimm(i) := decoded.rs1
|
||||
}
|
||||
wakeupReg := wakeup
|
||||
|
||||
commit.io.robValid := rename.io.commitValid
|
||||
commit.io.robEntry := rename.io.commitEntry
|
||||
|
||||
io.commitValid := VecInit((0 until p.issueWidth).map(i => rename.io.commitValid(i) && commit.io.commitReady(i)))
|
||||
io.commitEntry := rename.io.commitEntry
|
||||
io.flush := commit.io.flush
|
||||
io.redirectPc := Mux(commit.io.exception, csr.io.mtvec, commit.io.redirectPc)
|
||||
}
|
||||
|
||||
object OoOBackend extends App {
|
||||
ChiselStage.emitSystemVerilogFile(
|
||||
new OoOBackend(),
|
||||
args = Array("--target-dir", "generated"),
|
||||
firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
|
||||
)
|
||||
}
|
||||
@@ -2,17 +2,51 @@ import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class CommitStage(p: CoreParams = CoreParams()) extends Module {
|
||||
private val physBits = log2Ceil(p.physRegs)
|
||||
|
||||
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 robValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val robEntry = Input(Vec(p.issueWidth, new RobEntry(p)))
|
||||
val commitReady = Output(Vec(p.issueWidth, Bool()))
|
||||
val freeOldPhys = Output(Vec(p.issueWidth, Bool()))
|
||||
val oldPhys = Output(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val commitMapValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val commitArch = Output(Vec(p.issueWidth, UInt(5.W)))
|
||||
val commitPhys = Output(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val flush = Output(Bool())
|
||||
val redirectPc = Output(UInt(p.xlen.W))
|
||||
val exception = Output(Bool())
|
||||
val exceptionCause = Output(UInt(p.xlen.W))
|
||||
val badAddr = Output(UInt(p.xlen.W))
|
||||
})
|
||||
|
||||
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)
|
||||
val firstTrap = io.robValid(0) && (io.robEntry(0).exception || io.robEntry(0).branchMispredict)
|
||||
val secondTrap = io.robValid(1) && (io.robEntry(1).exception || io.robEntry(1).branchMispredict)
|
||||
val twoCsrWrites = io.robValid(0) && io.robValid(1) &&
|
||||
io.robEntry(0).csrValid && io.robEntry(1).csrValid
|
||||
val firstStore = io.robValid(0) && io.robEntry(0).opClass === Consts.OP_STORE
|
||||
io.commitReady(0) := io.robValid(0)
|
||||
io.commitReady(1) := io.robValid(1) && !firstTrap && !secondTrap && !twoCsrWrites && !firstStore
|
||||
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
val doCommit = io.commitReady(i)
|
||||
io.freeOldPhys(i) := doCommit && io.robEntry(i).writesDest &&
|
||||
io.robEntry(i).oldDest =/= io.robEntry(i).dest
|
||||
io.oldPhys(i) := io.robEntry(i).oldDest
|
||||
io.commitMapValid(i) := doCommit && io.robEntry(i).writesDest &&
|
||||
io.robEntry(i).archDest =/= 0.U
|
||||
io.commitArch(i) := io.robEntry(i).archDest
|
||||
io.commitPhys(i) := io.robEntry(i).dest
|
||||
}
|
||||
|
||||
val secondTrapSelected = !io.robValid(0) && secondTrap
|
||||
val selectedTrap = firstTrap || secondTrapSelected
|
||||
io.flush := selectedTrap
|
||||
io.redirectPc := Mux(firstTrap, io.robEntry(0).redirectPc, io.robEntry(1).redirectPc)
|
||||
io.exception := Mux(firstTrap, io.robEntry(0).exception,
|
||||
Mux(secondTrapSelected, io.robEntry(1).exception, false.B))
|
||||
io.exceptionCause := Mux(firstTrap, io.robEntry(0).exceptionCause,
|
||||
Mux(secondTrapSelected, io.robEntry(1).exceptionCause, 0.U))
|
||||
io.badAddr := Mux(firstTrap, io.robEntry(0).badAddr,
|
||||
Mux(secondTrapSelected, io.robEntry(1).badAddr, 0.U))
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ 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 laneValid = Vec(p.fetchWidth, Bool())
|
||||
val predictedTaken = Bool()
|
||||
val predictedTarget = UInt(p.xlen.W)
|
||||
}
|
||||
@@ -55,11 +56,19 @@ class RenamePacket(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val decoded = new DecodedInst(p)
|
||||
val prs1 = UInt(log2Ceil(p.physRegs).W)
|
||||
val prs2 = UInt(log2Ceil(p.physRegs).W)
|
||||
val src1Ready = Bool()
|
||||
val src2Ready = Bool()
|
||||
val prd = UInt(log2Ceil(p.physRegs).W)
|
||||
val oldPrd = UInt(log2Ceil(p.physRegs).W)
|
||||
val robIdx = UInt(log2Ceil(p.robEntries).W)
|
||||
}
|
||||
|
||||
class Wakeup(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val phys = UInt(log2Ceil(p.physRegs).W)
|
||||
val data = UInt(p.xlen.W)
|
||||
}
|
||||
|
||||
class MemRequest(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val addr = UInt(p.xlen.W)
|
||||
val data = UInt(p.xlen.W)
|
||||
@@ -74,3 +83,57 @@ class CsrCommand(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val rs1 = UInt(p.xlen.W)
|
||||
val zimm = UInt(5.W)
|
||||
}
|
||||
|
||||
class TlbReq(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val vaddr = UInt(p.xlen.W)
|
||||
val isStore = Bool()
|
||||
val isFetch = Bool()
|
||||
}
|
||||
|
||||
class TlbResp(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val hit = Bool()
|
||||
val miss = Bool()
|
||||
val paddr = UInt(p.xlen.W)
|
||||
val pageFault = Bool()
|
||||
val accessFault = Bool()
|
||||
}
|
||||
|
||||
class TlbRefill(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val vpn = UInt(27.W)
|
||||
val ppn = UInt(44.W)
|
||||
val level = UInt(2.W)
|
||||
val flags = UInt(8.W)
|
||||
}
|
||||
|
||||
class PtwMemReq(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val addr = UInt(p.xlen.W)
|
||||
}
|
||||
|
||||
class PtwMemResp(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val data = UInt(p.xlen.W)
|
||||
}
|
||||
|
||||
class LoadQueueEntry(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val robIdx = UInt(log2Ceil(p.robEntries).W)
|
||||
val addrValid = Bool()
|
||||
val addr = UInt(p.xlen.W)
|
||||
val size = UInt(3.W)
|
||||
val completed = Bool()
|
||||
val violation = Bool()
|
||||
}
|
||||
|
||||
class StoreQueueEntry(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val robIdx = UInt(log2Ceil(p.robEntries).W)
|
||||
val addrValid = Bool()
|
||||
val dataValid = Bool()
|
||||
val addr = UInt(p.xlen.W)
|
||||
val data = UInt(p.xlen.W)
|
||||
val size = UInt(3.W)
|
||||
val committed = Bool()
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ case class CoreParams(
|
||||
dCacheWays: Int = 8,
|
||||
cacheLineBytes: Int = 64,
|
||||
itlbEntries: Int = 32,
|
||||
dtlbEntries: Int = 32
|
||||
dtlbEntries: Int = 32,
|
||||
useOoOBackend: Boolean = false
|
||||
) {
|
||||
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")
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import chisel3.util._
|
||||
class CSRFile(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val cmd = Input(new CsrCommand(p))
|
||||
val readAddr = Input(UInt(12.W))
|
||||
val rdata = Output(UInt(p.xlen.W))
|
||||
val trap = Input(Bool())
|
||||
val trapPc = Input(UInt(p.xlen.W))
|
||||
@@ -39,7 +40,7 @@ class CSRFile(p: CoreParams = CoreParams()) extends Module {
|
||||
io.mepc := mepcReg
|
||||
|
||||
val r = WireDefault(0.U(p.xlen.W))
|
||||
switch(io.cmd.addr) {
|
||||
switch(io.readAddr) {
|
||||
is("h300".U) { r := mstatus }
|
||||
is("h301".U) { r := misa }
|
||||
is("h302".U) { r := medeleg }
|
||||
@@ -64,11 +65,36 @@ class CSRFile(p: CoreParams = CoreParams()) extends Module {
|
||||
}
|
||||
io.rdata := r
|
||||
|
||||
val writeOld = WireDefault(0.U(p.xlen.W))
|
||||
switch(io.cmd.addr) {
|
||||
is("h300".U) { writeOld := mstatus }
|
||||
is("h301".U) { writeOld := misa }
|
||||
is("h302".U) { writeOld := medeleg }
|
||||
is("h303".U) { writeOld := mideleg }
|
||||
is("h304".U) { writeOld := mie }
|
||||
is("h305".U) { writeOld := mtvecReg }
|
||||
is("h341".U) { writeOld := mepcReg }
|
||||
is("h342".U) { writeOld := mcause }
|
||||
is("h343".U) { writeOld := mtval }
|
||||
is("h344".U) { writeOld := mip }
|
||||
is("h100".U) { writeOld := sstatus }
|
||||
is("h105".U) { writeOld := stvec }
|
||||
is("h140".U) { writeOld := sscratch }
|
||||
is("h141".U) { writeOld := sepc }
|
||||
is("h142".U) { writeOld := scause }
|
||||
is("h143".U) { writeOld := stval }
|
||||
is("h180".U) { writeOld := satpReg }
|
||||
is("hf14".U) { writeOld := 0.U }
|
||||
is("hc00".U) { writeOld := cycle }
|
||||
is("hc01".U) { writeOld := 0.U }
|
||||
is("hc02".U) { writeOld := instret }
|
||||
}
|
||||
|
||||
val operand = Mux(io.cmd.cmd(2), io.cmd.zimm, io.cmd.rs1)
|
||||
val next = MuxLookup(io.cmd.cmd(1, 0), r)(Seq(
|
||||
val next = MuxLookup(io.cmd.cmd(1, 0), writeOld)(Seq(
|
||||
1.U -> operand,
|
||||
2.U -> (r | operand),
|
||||
3.U -> (r & ~operand)
|
||||
2.U -> (writeOld | operand),
|
||||
3.U -> (writeOld & ~operand)
|
||||
))
|
||||
|
||||
when(io.cmd.valid && io.cmd.cmd =/= 0.U) {
|
||||
|
||||
@@ -13,8 +13,7 @@ class IDStage(p: CoreParams = CoreParams()) extends Module {
|
||||
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
|
||||
io.out(i).valid := io.inValid && io.in.laneValid(i)
|
||||
io.outValid(i) := io.inValid && io.in.laneValid(i)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class Frontend(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
@@ -8,6 +9,7 @@ class Frontend(p: CoreParams = CoreParams()) extends Module {
|
||||
val imemReqAddr = Output(UInt(p.xlen.W))
|
||||
val imemRespValid = Input(Bool())
|
||||
val imemRespBits = Input(Vec(p.fetchWidth, UInt(32.W)))
|
||||
val outReady = Input(Bool())
|
||||
val outValid = Output(Bool())
|
||||
val out = Output(new FetchPacket(p))
|
||||
val branchUpdate = Input(new BranchUpdate(p))
|
||||
@@ -20,10 +22,21 @@ class Frontend(p: CoreParams = CoreParams()) extends Module {
|
||||
|
||||
predictor.io.pc := pc
|
||||
predictor.io.update := io.branchUpdate
|
||||
itlb.io.vaddr := pc
|
||||
itlb.io.req.valid := true.B
|
||||
itlb.io.req.vaddr := pc
|
||||
itlb.io.req.isStore := false.B
|
||||
itlb.io.req.isFetch := true.B
|
||||
itlb.io.refill.valid := false.B
|
||||
itlb.io.refill.vpn := 0.U
|
||||
itlb.io.refill.ppn := 0.U
|
||||
itlb.io.refill.level := 0.U
|
||||
itlb.io.refill.flags := 0.U
|
||||
|
||||
icache.io.reqValid := true.B
|
||||
icache.io.reqAddr := itlb.io.paddr
|
||||
icache.io.reqAddr := Mux(itlb.io.resp.hit, itlb.io.resp.paddr, pc)
|
||||
icache.io.reqPc := pc
|
||||
icache.io.flush := io.redirectValid
|
||||
icache.io.respReady := io.outReady
|
||||
icache.io.memRespValid := io.imemRespValid
|
||||
icache.io.memRespBits := io.imemRespBits
|
||||
|
||||
@@ -34,10 +47,11 @@ class Frontend(p: CoreParams = CoreParams()) extends Module {
|
||||
io.out.predictedTaken := predictor.io.taken
|
||||
io.out.predictedTarget := predictor.io.target
|
||||
|
||||
val sequentialNextPc = icache.io.resp.pc + (PopCount(icache.io.resp.laneValid) << 2)
|
||||
|
||||
when(io.redirectValid) {
|
||||
pc := io.redirectPc
|
||||
}.elsewhen(icache.io.respValid) {
|
||||
pc := Mux(predictor.io.taken, predictor.io.target, pc + (4 * p.fetchWidth).U)
|
||||
}.elsewhen(icache.io.respValid && io.outReady) {
|
||||
pc := Mux(predictor.io.taken, predictor.io.target, sequentialNextPc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,180 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ICache(p: CoreParams = CoreParams()) extends Module {
|
||||
private val lineInsts = p.fetchWidth
|
||||
private val lineBytes = lineInsts * 4
|
||||
private val sets = p.iCacheBytes / (p.iCacheWays * lineBytes)
|
||||
private val setBits = log2Ceil(sets)
|
||||
private val instBits = log2Ceil(lineInsts)
|
||||
private val offsetBits = log2Ceil(lineBytes)
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val reqAddr = Input(UInt(p.xlen.W))
|
||||
val reqPc = Input(UInt(p.xlen.W))
|
||||
val flush = Input(Bool())
|
||||
val respReady = Input(Bool())
|
||||
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))
|
||||
val miss = Output(Bool())
|
||||
})
|
||||
|
||||
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
|
||||
}
|
||||
def setIndex(addr: UInt): UInt = addr(offsetBits + setBits - 1, offsetBits)
|
||||
def instIndex(addr: UInt): UInt = addr(offsetBits - 1, 2)
|
||||
def tag(addr: UInt): UInt = addr(p.xlen - 1, offsetBits + setBits)
|
||||
def alignedFetchAddr(addr: UInt): UInt = Cat(addr(p.xlen - 1, offsetBits), 0.U(offsetBits.W))
|
||||
|
||||
val valid = RegInit(VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.iCacheWays)(
|
||||
VecInit(Seq.fill(lineInsts)(false.B)))))))
|
||||
val tags = SyncReadMem(sets, Vec(p.iCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
||||
val data = SyncReadMem(sets, Vec(p.iCacheWays, Vec(lineInsts, UInt(32.W))))
|
||||
val repl = RegInit(VecInit(Seq.fill(sets)(0.U(log2Ceil(p.iCacheWays).W))))
|
||||
|
||||
val sIdle :: sLookup :: sResp :: sMiss :: Nil = Enum(4)
|
||||
val state = RegInit(sIdle)
|
||||
|
||||
val lookupAddr = Reg(UInt(p.xlen.W))
|
||||
val lookupPc = Reg(UInt(p.xlen.W))
|
||||
val lookupSet = Reg(UInt(setBits.W))
|
||||
val lookupInst = Reg(UInt(instBits.W))
|
||||
val lookupValidRow = Reg(Vec(p.iCacheWays, Vec(lineInsts, Bool())))
|
||||
|
||||
val missAddr = Reg(UInt(p.xlen.W))
|
||||
val missPc = Reg(UInt(p.xlen.W))
|
||||
val missSet = Reg(UInt(setBits.W))
|
||||
val missInst = Reg(UInt(instBits.W))
|
||||
val missWay = Reg(UInt(log2Ceil(p.iCacheWays).W))
|
||||
val missRefillExisting = Reg(Bool())
|
||||
val missTagRow = Reg(Vec(p.iCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
||||
val missDataRow = Reg(Vec(p.iCacheWays, Vec(lineInsts, UInt(32.W))))
|
||||
val missValidRow = Reg(Vec(p.iCacheWays, Vec(lineInsts, Bool())))
|
||||
val missReqSent = RegInit(false.B)
|
||||
|
||||
val respReg = Reg(new FetchPacket(p))
|
||||
|
||||
val reqSet = setIndex(io.reqAddr)
|
||||
val reqInst = instIndex(io.reqAddr)
|
||||
val readFire = state === sIdle && io.reqValid && !io.flush
|
||||
val readTags = tags.read(reqSet, readFire)
|
||||
val readData = data.read(reqSet, readFire)
|
||||
|
||||
val tagHitVec = VecInit((0 until p.iCacheWays).map(w => lookupValidRow(w).asUInt.orR && readTags(w) === tag(lookupAddr)))
|
||||
val hitVec = VecInit((0 until p.iCacheWays).map(w => tagHitVec(w) && lookupValidRow(w)(lookupInst)))
|
||||
val hit = hitVec.asUInt.orR
|
||||
val hitWay = OHToUInt(hitVec)
|
||||
val tagHit = tagHitVec.asUInt.orR
|
||||
val tagHitWay = OHToUInt(tagHitVec)
|
||||
val lastInst = (lineInsts - 1).U(instBits.W)
|
||||
val nextInst = lookupInst + 1.U
|
||||
val lookupCanFetchPair = lookupInst =/= lastInst
|
||||
val lookupLane1Valid = lookupCanFetchPair && lookupValidRow(hitWay)(nextInst)
|
||||
|
||||
val lookupResp = WireDefault(0.U.asTypeOf(new FetchPacket(p)))
|
||||
lookupResp.pc := lookupPc
|
||||
lookupResp.inst(0) := readData(hitWay)(lookupInst)
|
||||
lookupResp.inst(1) := Mux(lookupLane1Valid, readData(hitWay)(nextInst), 0.U)
|
||||
lookupResp.laneValid(0) := true.B
|
||||
lookupResp.laneValid(1) := lookupLane1Valid
|
||||
lookupResp.predictedTaken := false.B
|
||||
lookupResp.predictedTarget := lookupPc + (4 * p.fetchWidth).U
|
||||
|
||||
val missCanFetchPair = missInst =/= lastInst
|
||||
val missResp = WireDefault(0.U.asTypeOf(new FetchPacket(p)))
|
||||
missResp.pc := missPc
|
||||
missResp.inst(0) := io.memRespBits(0)
|
||||
missResp.inst(1) := Mux(missCanFetchPair, io.memRespBits(1), 0.U)
|
||||
missResp.laneValid(0) := true.B
|
||||
missResp.laneValid(1) := missCanFetchPair
|
||||
missResp.predictedTaken := false.B
|
||||
missResp.predictedTarget := missPc + (4 * p.fetchWidth).U
|
||||
|
||||
io.memReqValid := state === sMiss && !missReqSent
|
||||
io.memReqAddr := Mux(state === sMiss,
|
||||
Mux(missCanFetchPair, alignedFetchAddr(missAddr), missAddr),
|
||||
Mux(reqInst =/= lastInst, alignedFetchAddr(io.reqAddr), io.reqAddr))
|
||||
io.respValid := (state === sLookup && hit) || state === sResp || (state === sMiss && io.memRespValid)
|
||||
io.resp := Mux(state === sResp, respReg,
|
||||
Mux(state === sMiss && io.memRespValid, missResp, lookupResp))
|
||||
io.miss := state === sLookup && !hit || state === sMiss
|
||||
|
||||
when(io.flush) {
|
||||
state := sIdle
|
||||
missReqSent := false.B
|
||||
}.elsewhen(state === sIdle) {
|
||||
when(io.reqValid) {
|
||||
lookupAddr := io.reqAddr
|
||||
lookupPc := io.reqPc
|
||||
lookupSet := reqSet
|
||||
lookupInst := reqInst
|
||||
lookupValidRow := valid(reqSet)
|
||||
state := sLookup
|
||||
}
|
||||
}.elsewhen(state === sLookup) {
|
||||
when(hit) {
|
||||
repl(lookupSet) := hitWay
|
||||
when(io.respReady) {
|
||||
state := sIdle
|
||||
}.otherwise {
|
||||
respReg := lookupResp
|
||||
state := sResp
|
||||
}
|
||||
}.otherwise {
|
||||
missAddr := lookupAddr
|
||||
missPc := lookupPc
|
||||
missSet := lookupSet
|
||||
missInst := lookupInst
|
||||
missWay := Mux(tagHit, tagHitWay, repl(lookupSet))
|
||||
missRefillExisting := tagHit
|
||||
missTagRow := readTags
|
||||
missDataRow := readData
|
||||
missValidRow := lookupValidRow
|
||||
missReqSent := false.B
|
||||
state := sMiss
|
||||
}
|
||||
}.elsewhen(state === sResp) {
|
||||
when(io.respReady) {
|
||||
state := sIdle
|
||||
}
|
||||
}.elsewhen(state === sMiss) {
|
||||
when(!missReqSent) {
|
||||
missReqSent := true.B
|
||||
}
|
||||
when(io.memRespValid) {
|
||||
val tagWrite = Wire(Vec(p.iCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
||||
val dataWrite = Wire(Vec(p.iCacheWays, Vec(lineInsts, UInt(32.W))))
|
||||
val validWrite = Wire(Vec(p.iCacheWays, Vec(lineInsts, Bool())))
|
||||
tagWrite := missTagRow
|
||||
dataWrite := missDataRow
|
||||
validWrite := missValidRow
|
||||
tagWrite(missWay) := tag(missAddr)
|
||||
when(!missRefillExisting) {
|
||||
for (i <- 0 until lineInsts) {
|
||||
validWrite(missWay)(i) := false.B
|
||||
}
|
||||
}
|
||||
dataWrite(missWay)(missInst) := io.memRespBits(0)
|
||||
validWrite(missWay)(missInst) := true.B
|
||||
when(missCanFetchPair) {
|
||||
dataWrite(missWay)(missInst + 1.U) := io.memRespBits(1)
|
||||
validWrite(missWay)(missInst + 1.U) := true.B
|
||||
}
|
||||
valid(missSet) := validWrite
|
||||
tags.write(missSet, tagWrite)
|
||||
data.write(missSet, dataWrite)
|
||||
when(!missRefillExisting) {
|
||||
repl(missSet) := missWay + 1.U
|
||||
}
|
||||
when(io.respReady) {
|
||||
state := sIdle
|
||||
}.otherwise {
|
||||
respReg := missResp
|
||||
state := sResp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,45 @@ import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ITLB(p: CoreParams = CoreParams()) extends Module {
|
||||
private val vpnBits = 27
|
||||
private val ppnBits = 44
|
||||
private val idxBits = log2Ceil(p.itlbEntries)
|
||||
|
||||
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())
|
||||
val req = Input(new TlbReq(p))
|
||||
val resp = Output(new TlbResp(p))
|
||||
val refill = Input(new TlbRefill(p))
|
||||
val missVpn = Output(UInt(vpnBits.W))
|
||||
})
|
||||
|
||||
io.paddr := io.vaddr
|
||||
io.hit := true.B
|
||||
io.miss := false.B
|
||||
}
|
||||
val valid = RegInit(VecInit(Seq.fill(p.itlbEntries)(false.B)))
|
||||
val vpn = Reg(Vec(p.itlbEntries, UInt(vpnBits.W)))
|
||||
val ppn = Reg(Vec(p.itlbEntries, UInt(ppnBits.W)))
|
||||
val level = Reg(Vec(p.itlbEntries, UInt(2.W)))
|
||||
val flags = Reg(Vec(p.itlbEntries, UInt(8.W)))
|
||||
val repl = RegInit(0.U(idxBits.W))
|
||||
|
||||
val reqVpn = io.req.vaddr(38, 12)
|
||||
val pageOff = io.req.vaddr(11, 0)
|
||||
val hitVec = VecInit((0 until p.itlbEntries).map(i => valid(i) && vpn(i) === reqVpn))
|
||||
val hit = io.req.valid && hitVec.asUInt.orR
|
||||
val hitIdx = OHToUInt(hitVec)
|
||||
val x = flags(hitIdx)(3)
|
||||
val pageFault = hit && !x
|
||||
|
||||
io.resp.hit := hit && !pageFault
|
||||
io.resp.miss := io.req.valid && !hit
|
||||
io.resp.paddr := Cat(ppn(hitIdx), pageOff)
|
||||
io.resp.pageFault := pageFault
|
||||
io.resp.accessFault := false.B
|
||||
io.missVpn := reqVpn
|
||||
|
||||
when(io.refill.valid) {
|
||||
valid(repl) := true.B
|
||||
vpn(repl) := io.refill.vpn
|
||||
ppn(repl) := io.refill.ppn
|
||||
level(repl) := io.refill.level
|
||||
flags(repl) := io.refill.flags
|
||||
repl := repl + 1.U
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,20 @@ 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 enqValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val enq = Input(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val enqReady = Output(Vec(p.issueWidth, Bool()))
|
||||
val wakeup = Input(Vec(p.issueWidth, new Wakeup(p)))
|
||||
val issueValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val issue = Output(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val issueReady = Input(Vec(p.issueWidth, 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.wakeup := io.wakeup
|
||||
intRs.io.issueReady := io.issueReady
|
||||
intRs.io.flush := io.flush
|
||||
|
||||
@@ -21,4 +23,3 @@ class IssueQueue(p: CoreParams = CoreParams()) extends Module {
|
||||
io.issueValid := intRs.io.issueValid
|
||||
io.issue := intRs.io.issue
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,20 @@ 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 inValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val in = Input(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val inReady = Output(Vec(p.issueWidth, Bool()))
|
||||
val wakeup = Input(Vec(p.issueWidth, new Wakeup(p)))
|
||||
val outValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val out = Output(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val outReady = Input(Vec(p.issueWidth, Bool()))
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val queue = Module(new IssueQueue(p))
|
||||
queue.io.enqValid := io.inValid
|
||||
queue.io.enq := io.in
|
||||
queue.io.wakeup := io.wakeup
|
||||
queue.io.issueReady := io.outReady
|
||||
queue.io.flush := io.flush
|
||||
|
||||
@@ -21,4 +23,3 @@ class IssueStage(p: CoreParams = CoreParams()) extends Module {
|
||||
io.outValid := queue.io.issueValid
|
||||
io.out := queue.io.issue
|
||||
}
|
||||
|
||||
|
||||
@@ -3,22 +3,69 @@ 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 enqValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val enq = Input(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val enqReady = Output(Vec(p.issueWidth, Bool()))
|
||||
val wakeup = Input(Vec(p.issueWidth, new Wakeup(p)))
|
||||
val issueValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val issue = Output(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val issueReady = Input(Vec(p.issueWidth, 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
|
||||
val valid = RegInit(VecInit(Seq.fill(entries)(false.B)))
|
||||
val slots = Reg(Vec(entries, new RenamePacket(p)))
|
||||
|
||||
io.enqReady := q.io.enq.ready
|
||||
io.issueValid := q.io.deq.valid && !io.flush
|
||||
io.issue := q.io.deq.bits
|
||||
val freeMask = VecInit(valid.map(!_.asBool)).asUInt
|
||||
val enq0OH = PriorityEncoderOH(freeMask)
|
||||
val enq1OH = PriorityEncoderOH(freeMask & ~enq0OH)
|
||||
io.enqReady(0) := freeMask.orR
|
||||
io.enqReady(1) := (freeMask & ~enq0OH).orR
|
||||
|
||||
val readyVec = Wire(Vec(entries, Bool()))
|
||||
for (i <- 0 until entries) {
|
||||
val src1Wake = io.wakeup.map(w => w.valid && w.phys === slots(i).prs1).reduce(_ || _)
|
||||
val src2Wake = io.wakeup.map(w => w.valid && w.phys === slots(i).prs2).reduce(_ || _)
|
||||
val src1ReadyNow = slots(i).src1Ready || src1Wake || slots(i).decoded.rs1 === 0.U
|
||||
val src2ReadyNow = slots(i).src2Ready || src2Wake || slots(i).decoded.rs2 === 0.U
|
||||
readyVec(i) := valid(i) && src1ReadyNow && src2ReadyNow
|
||||
}
|
||||
|
||||
val issue0OH = PriorityEncoderOH(readyVec.asUInt)
|
||||
val issue1OH = PriorityEncoderOH(readyVec.asUInt & ~issue0OH)
|
||||
io.issueValid(0) := readyVec.asUInt.orR
|
||||
io.issueValid(1) := (readyVec.asUInt & ~issue0OH).orR
|
||||
io.issue(0) := Mux1H(issue0OH, slots)
|
||||
io.issue(1) := Mux1H(issue1OH, slots)
|
||||
|
||||
when(io.flush) {
|
||||
valid := VecInit(Seq.fill(entries)(false.B))
|
||||
}.otherwise {
|
||||
for (i <- 0 until entries) {
|
||||
when(valid(i)) {
|
||||
for (w <- 0 until p.issueWidth) {
|
||||
when(io.wakeup(w).valid && io.wakeup(w).phys === slots(i).prs1) {
|
||||
slots(i).src1Ready := true.B
|
||||
}
|
||||
when(io.wakeup(w).valid && io.wakeup(w).phys === slots(i).prs2) {
|
||||
slots(i).src2Ready := true.B
|
||||
}
|
||||
}
|
||||
}
|
||||
when(issue0OH(i) && io.issueReady(0)) {
|
||||
valid(i) := false.B
|
||||
}
|
||||
when(issue1OH(i) && io.issueReady(1)) {
|
||||
valid(i) := false.B
|
||||
}
|
||||
when(enq0OH(i) && io.enqValid(0) && io.enqReady(0)) {
|
||||
valid(i) := true.B
|
||||
slots(i) := io.enq(0)
|
||||
}
|
||||
when(enq1OH(i) && io.enqValid(1) && io.enqReady(1)) {
|
||||
valid(i) := true.B
|
||||
slots(i) := io.enq(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,124 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class DCache(p: CoreParams = CoreParams()) extends Module {
|
||||
private val lineWords = p.cacheLineBytes / (p.xlen / 8)
|
||||
private val sets = p.dCacheBytes / (p.dCacheWays * p.cacheLineBytes)
|
||||
private val setBits = log2Ceil(sets)
|
||||
private val wordBits = log2Ceil(lineWords)
|
||||
private val byteBits = log2Ceil(p.xlen / 8)
|
||||
private val offsetBits = log2Ceil(p.cacheLineBytes)
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val req = Input(new MemRequest(p))
|
||||
val reqReady = Output(Bool())
|
||||
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))
|
||||
val miss = Output(Bool())
|
||||
})
|
||||
|
||||
io.memReqValid := io.reqValid
|
||||
io.memReq := io.req
|
||||
io.respValid := io.memRespValid
|
||||
io.respData := io.memRespData
|
||||
}
|
||||
def lineAddr(addr: UInt): UInt = Cat(addr(p.xlen - 1, offsetBits), 0.U(offsetBits.W))
|
||||
def setIndex(addr: UInt): UInt = addr(offsetBits + setBits - 1, offsetBits)
|
||||
def wordIndex(addr: UInt): UInt = addr(offsetBits - 1, byteBits)
|
||||
def tag(addr: UInt): UInt = addr(p.xlen - 1, offsetBits + setBits)
|
||||
|
||||
def loadSelect(word: UInt, addr: UInt, size: UInt, signed: Bool = true.B): UInt = {
|
||||
val byteShift = addr(byteBits - 1, 0) << 3
|
||||
val shifted = word >> byteShift
|
||||
val b = shifted(7, 0)
|
||||
val h = shifted(15, 0)
|
||||
val w = shifted(31, 0)
|
||||
MuxLookup(size, word)(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 -> word
|
||||
))
|
||||
}
|
||||
|
||||
val valid = RegInit(VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.dCacheWays)(false.B)))))
|
||||
val tags = SyncReadMem(sets, Vec(p.dCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
||||
val data = SyncReadMem(sets, Vec(p.dCacheWays, Vec(lineWords, UInt(p.xlen.W))))
|
||||
val repl = RegInit(VecInit(Seq.fill(sets)(0.U(log2Ceil(p.dCacheWays).W))))
|
||||
|
||||
val sIdle :: sLookup :: sMiss :: Nil = Enum(3)
|
||||
val state = RegInit(sIdle)
|
||||
val reqReg = Reg(new MemRequest(p))
|
||||
val reqSet = Reg(UInt(setBits.W))
|
||||
val reqWord = Reg(UInt(wordBits.W))
|
||||
val reqValidRow = Reg(Vec(p.dCacheWays, Bool()))
|
||||
val missWay = Reg(UInt(log2Ceil(p.dCacheWays).W))
|
||||
val missTagRow = Reg(Vec(p.dCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
||||
val missDataRow = Reg(Vec(p.dCacheWays, Vec(lineWords, UInt(p.xlen.W))))
|
||||
|
||||
val set = setIndex(io.req.addr)
|
||||
val word = wordIndex(io.req.addr)
|
||||
val readFire = state === sIdle && io.reqValid && !io.req.isStore
|
||||
val readTags = tags.read(set, readFire)
|
||||
val readData = data.read(set, readFire)
|
||||
|
||||
val hitVec = VecInit((0 until p.dCacheWays).map(w => reqValidRow(w) && readTags(w) === tag(reqReg.addr)))
|
||||
val hit = hitVec.asUInt.orR
|
||||
val hitWay = OHToUInt(hitVec)
|
||||
val hitWord = readData(hitWay)(reqWord)
|
||||
val hitResp = loadSelect(hitWord, reqReg.addr, reqReg.size)
|
||||
|
||||
val storeBypass = state === sIdle && io.reqValid && io.req.isStore
|
||||
val memReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
|
||||
memReq.addr := lineAddr(reqReg.addr) + (reqWord << byteBits)
|
||||
memReq.data := reqReg.data
|
||||
memReq.isStore := reqReg.isStore
|
||||
memReq.size := 3.U
|
||||
|
||||
io.reqReady := state === sIdle
|
||||
io.memReqValid := state === sMiss || storeBypass
|
||||
io.memReq := Mux(storeBypass, io.req, memReq)
|
||||
io.respValid := state === sLookup && hit && !reqReg.isStore ||
|
||||
state === sMiss && io.memRespValid && !reqReg.isStore
|
||||
io.respData := Mux(state === sMiss, loadSelect(io.memRespData, reqReg.addr, reqReg.size), hitResp)
|
||||
io.miss := state === sLookup && !hit || state === sMiss
|
||||
|
||||
when(storeBypass) {
|
||||
valid(set) := VecInit(Seq.fill(p.dCacheWays)(false.B))
|
||||
}
|
||||
|
||||
when(state === sIdle) {
|
||||
when(io.reqValid && !io.req.isStore) {
|
||||
reqReg := io.req
|
||||
reqSet := set
|
||||
reqWord := word
|
||||
reqValidRow := valid(set)
|
||||
state := sLookup
|
||||
}
|
||||
}.elsewhen(state === sLookup) {
|
||||
when(hit) {
|
||||
repl(reqSet) := hitWay
|
||||
state := sIdle
|
||||
}.otherwise {
|
||||
val way = repl(reqSet)
|
||||
missWay := way
|
||||
missTagRow := readTags
|
||||
missDataRow := readData
|
||||
state := sMiss
|
||||
}
|
||||
}.elsewhen(state === sMiss) {
|
||||
when(io.memRespValid) {
|
||||
val tagWrite = Wire(Vec(p.dCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
||||
val dataWrite = Wire(Vec(p.dCacheWays, Vec(lineWords, UInt(p.xlen.W))))
|
||||
tagWrite := missTagRow
|
||||
dataWrite := missDataRow
|
||||
tagWrite(missWay) := tag(reqReg.addr)
|
||||
dataWrite(missWay)(reqWord) := io.memRespData
|
||||
valid(reqSet)(missWay) := true.B
|
||||
tags.write(reqSet, tagWrite)
|
||||
data.write(reqSet, dataWrite)
|
||||
repl(reqSet) := missWay + 1.U
|
||||
state := sIdle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,47 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class DTLB(p: CoreParams = CoreParams()) extends Module {
|
||||
private val vpnBits = 27
|
||||
private val ppnBits = 44
|
||||
private val idxBits = log2Ceil(p.dtlbEntries)
|
||||
|
||||
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())
|
||||
val req = Input(new TlbReq(p))
|
||||
val resp = Output(new TlbResp(p))
|
||||
val refill = Input(new TlbRefill(p))
|
||||
val missVpn = Output(UInt(vpnBits.W))
|
||||
})
|
||||
|
||||
io.paddr := io.vaddr
|
||||
io.hit := true.B
|
||||
io.miss := false.B
|
||||
}
|
||||
val valid = RegInit(VecInit(Seq.fill(p.dtlbEntries)(false.B)))
|
||||
val vpn = Reg(Vec(p.dtlbEntries, UInt(vpnBits.W)))
|
||||
val ppn = Reg(Vec(p.dtlbEntries, UInt(ppnBits.W)))
|
||||
val level = Reg(Vec(p.dtlbEntries, UInt(2.W)))
|
||||
val flags = Reg(Vec(p.dtlbEntries, UInt(8.W)))
|
||||
val repl = RegInit(0.U(idxBits.W))
|
||||
|
||||
val reqVpn = io.req.vaddr(38, 12)
|
||||
val pageOff = io.req.vaddr(11, 0)
|
||||
val hitVec = VecInit((0 until p.dtlbEntries).map(i => valid(i) && vpn(i) === reqVpn))
|
||||
val hit = io.req.valid && hitVec.asUInt.orR
|
||||
val hitIdx = OHToUInt(hitVec)
|
||||
val r = flags(hitIdx)(1)
|
||||
val w = flags(hitIdx)(2)
|
||||
val pageFault = hit && Mux(io.req.isStore, !w, !r)
|
||||
|
||||
io.resp.hit := hit && !pageFault
|
||||
io.resp.miss := io.req.valid && !hit
|
||||
io.resp.paddr := Cat(ppn(hitIdx), pageOff)
|
||||
io.resp.pageFault := pageFault
|
||||
io.resp.accessFault := false.B
|
||||
io.missVpn := reqVpn
|
||||
|
||||
when(io.refill.valid) {
|
||||
valid(repl) := true.B
|
||||
vpn(repl) := io.refill.vpn
|
||||
ppn(repl) := io.refill.ppn
|
||||
level(repl) := io.refill.level
|
||||
flags(repl) := io.refill.flags
|
||||
repl := repl + 1.U
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,68 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class LSU(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val req = Input(new MemRequest(p))
|
||||
val reqReady = Output(Bool())
|
||||
val satp = Input(UInt(p.xlen.W))
|
||||
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 pageFault = Output(Bool())
|
||||
})
|
||||
|
||||
val dtlb = Module(new DTLB(p))
|
||||
val mmu = Module(new MMU(p))
|
||||
val dcache = Module(new DCache(p))
|
||||
val bare = io.satp(63, 60) === 0.U
|
||||
|
||||
dtlb.io.vaddr := io.req.addr
|
||||
dcache.io.reqValid := io.reqValid
|
||||
dtlb.io.req.valid := io.reqValid && !bare
|
||||
dtlb.io.req.vaddr := io.req.addr
|
||||
dtlb.io.req.isStore := io.req.isStore
|
||||
dtlb.io.req.isFetch := false.B
|
||||
|
||||
mmu.io.satp := io.satp
|
||||
mmu.io.req.valid := io.reqValid && !bare && dtlb.io.resp.miss
|
||||
mmu.io.req.vaddr := io.req.addr
|
||||
mmu.io.req.isStore := io.req.isStore
|
||||
mmu.io.req.isFetch := false.B
|
||||
dtlb.io.refill := mmu.io.refill
|
||||
|
||||
val ptwOutstanding = RegInit(false.B)
|
||||
when(mmu.io.ptwMemReq.valid) {
|
||||
ptwOutstanding := true.B
|
||||
}.elsewhen(io.dmemRespValid && ptwOutstanding) {
|
||||
ptwOutstanding := false.B
|
||||
}
|
||||
|
||||
mmu.io.ptwMemResp.valid := io.dmemRespValid && ptwOutstanding
|
||||
mmu.io.ptwMemResp.data := io.dmemRespData
|
||||
|
||||
val translatedAddr = Mux(bare, io.req.addr, dtlb.io.resp.paddr)
|
||||
val translationReady = bare || dtlb.io.resp.hit
|
||||
val translationFault = dtlb.io.resp.pageFault || mmu.io.resp.pageFault
|
||||
io.reqReady := dcache.io.reqReady && !ptwOutstanding
|
||||
|
||||
dcache.io.reqValid := io.reqValid && translationReady && !translationFault
|
||||
dcache.io.req := io.req
|
||||
dcache.io.req.addr := dtlb.io.paddr
|
||||
dcache.io.memRespValid := io.dmemRespValid
|
||||
dcache.io.req.addr := translatedAddr
|
||||
dcache.io.memRespValid := io.dmemRespValid && !ptwOutstanding
|
||||
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
|
||||
}
|
||||
val ptwReqAsMem = WireDefault(0.U.asTypeOf(new MemRequest(p)))
|
||||
ptwReqAsMem.addr := mmu.io.ptwMemReq.addr
|
||||
ptwReqAsMem.data := 0.U
|
||||
ptwReqAsMem.isStore := false.B
|
||||
ptwReqAsMem.size := 3.U
|
||||
|
||||
io.dmemReqValid := mmu.io.ptwMemReq.valid || dcache.io.memReqValid
|
||||
io.dmemReq := Mux(mmu.io.ptwMemReq.valid, ptwReqAsMem, dcache.io.memReq)
|
||||
io.respValid := dcache.io.respValid || translationFault
|
||||
io.respData := dcache.io.respData
|
||||
io.pageFault := translationFault
|
||||
}
|
||||
|
||||
@@ -2,22 +2,78 @@ import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class LoadQueue(p: CoreParams = CoreParams()) extends Module {
|
||||
private val idxBits = log2Ceil(p.loadQueueEntries)
|
||||
private val robBits = log2Ceil(p.robEntries)
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val enqValid = Input(Bool())
|
||||
val enqAddr = Input(UInt(p.xlen.W))
|
||||
val enqRobIdx = Input(UInt(robBits.W))
|
||||
val enqReady = Output(Bool())
|
||||
val enqIdx = Output(UInt(idxBits.W))
|
||||
|
||||
val addrValid = Input(Bool())
|
||||
val addrIdx = Input(UInt(idxBits.W))
|
||||
val addr = Input(UInt(p.xlen.W))
|
||||
val size = Input(UInt(3.W))
|
||||
|
||||
val complete = Input(Bool())
|
||||
val completeIdx = Input(UInt(idxBits.W))
|
||||
|
||||
val storeAddrValid = Input(Bool())
|
||||
val storeRobIdx = Input(UInt(robBits.W))
|
||||
val storeAddr = Input(UInt(p.xlen.W))
|
||||
val storeSize = Input(UInt(3.W))
|
||||
val violation = Output(Bool())
|
||||
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
val count = RegInit(0.U(log2Ceil(p.loadQueueEntries + 1).W))
|
||||
io.enqReady := count =/= p.loadQueueEntries.U
|
||||
val entries = RegInit(VecInit(Seq.fill(p.loadQueueEntries)(0.U.asTypeOf(new LoadQueueEntry(p)))))
|
||||
val freeMask = VecInit(entries.map(e => !e.valid)).asUInt
|
||||
val enqOH = PriorityEncoderOH(freeMask)
|
||||
val enqIdx = OHToUInt(enqOH)
|
||||
|
||||
def overlap(a: UInt, as: UInt, b: UInt, bs: UInt): Bool = {
|
||||
val am = MuxLookup(as, 7.U)(Seq(0.U -> 0.U, 1.U -> 1.U, 2.U -> 3.U, 3.U -> 7.U))
|
||||
val bm = MuxLookup(bs, 7.U)(Seq(0.U -> 0.U, 1.U -> 1.U, 2.U -> 3.U, 3.U -> 7.U))
|
||||
val a0 = a(p.xlen - 1, 3)
|
||||
val b0 = b(p.xlen - 1, 3)
|
||||
a0 === b0 && ((a(2, 0) | am) >= b(2, 0)) && ((b(2, 0) | bm) >= a(2, 0))
|
||||
}
|
||||
|
||||
io.enqReady := freeMask.orR
|
||||
io.enqIdx := enqIdx
|
||||
|
||||
val violationVec = Wire(Vec(p.loadQueueEntries, Bool()))
|
||||
for (i <- 0 until p.loadQueueEntries) {
|
||||
val youngerLoad = entries(i).robIdx > io.storeRobIdx
|
||||
violationVec(i) := io.storeAddrValid && entries(i).valid && entries(i).completed &&
|
||||
entries(i).addrValid && youngerLoad && overlap(entries(i).addr, entries(i).size, io.storeAddr, io.storeSize)
|
||||
}
|
||||
io.violation := violationVec.asUInt.orR
|
||||
|
||||
when(io.flush) {
|
||||
count := 0.U
|
||||
entries.foreach(_ := 0.U.asTypeOf(new LoadQueueEntry(p)))
|
||||
}.otherwise {
|
||||
when(io.enqValid && io.enqReady) { count := count + 1.U }
|
||||
when(io.complete && count =/= 0.U) { count := count - 1.U }
|
||||
when(io.enqValid && io.enqReady) {
|
||||
entries(enqIdx).valid := true.B
|
||||
entries(enqIdx).robIdx := io.enqRobIdx
|
||||
entries(enqIdx).addrValid := false.B
|
||||
entries(enqIdx).completed := false.B
|
||||
entries(enqIdx).violation := false.B
|
||||
}
|
||||
when(io.addrValid) {
|
||||
entries(io.addrIdx).addrValid := true.B
|
||||
entries(io.addrIdx).addr := io.addr
|
||||
entries(io.addrIdx).size := io.size
|
||||
}
|
||||
when(io.complete) {
|
||||
entries(io.completeIdx).completed := true.B
|
||||
}
|
||||
for (i <- 0 until p.loadQueueEntries) {
|
||||
when(violationVec(i)) {
|
||||
entries(i).violation := true.B
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,124 @@
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class PageTableWalker(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val reqVpn = Input(UInt(27.W))
|
||||
val isStore = Input(Bool())
|
||||
val isFetch = Input(Bool())
|
||||
val satp = Input(UInt(p.xlen.W))
|
||||
val memReq = Output(new PtwMemReq(p))
|
||||
val memResp = Input(new PtwMemResp(p))
|
||||
val respValid = Output(Bool())
|
||||
val refill = Output(new TlbRefill(p))
|
||||
val pageFault = Output(Bool())
|
||||
})
|
||||
|
||||
val sIdle :: sL2 :: sL1 :: sL0 :: sDone :: Nil = Enum(5)
|
||||
val state = RegInit(sIdle)
|
||||
val vpnReg = Reg(UInt(27.W))
|
||||
val isStoreReg = Reg(Bool())
|
||||
val isFetchReg = Reg(Bool())
|
||||
val rootPpn = io.satp(43, 0)
|
||||
val pte = io.memResp.data
|
||||
val pteV = pte(0)
|
||||
val pteR = pte(1)
|
||||
val pteW = pte(2)
|
||||
val pteX = pte(3)
|
||||
val pteU = pte(4)
|
||||
val pteG = pte(5)
|
||||
val pteA = pte(6)
|
||||
val pteD = pte(7)
|
||||
val pteFlags = pte(7, 0)
|
||||
val ptePpn = pte(53, 10)
|
||||
val pteIsLeaf = pteR || pteX
|
||||
val invalidPte = !pteV || (!pteR && pteW)
|
||||
val permFault = Mux(isFetchReg, !pteX, Mux(isStoreReg, !pteW || !pteD, !pteR)) || !pteA
|
||||
val walkFault = RegInit(false.B)
|
||||
val nextPpn = Reg(UInt(44.W))
|
||||
|
||||
def vpnPart(vpn: UInt, level: Int): UInt =
|
||||
vpn(9 * level + 8, 9 * level)
|
||||
|
||||
val level = Wire(UInt(2.W))
|
||||
level := Mux(state === sL2, 2.U, Mux(state === sL1, 1.U, 0.U))
|
||||
val curPpn = Reg(UInt(44.W))
|
||||
val pteAddr = Cat(curPpn, vpnPart(vpnReg, 0), 0.U(3.W))
|
||||
val pteAddrL1 = Cat(curPpn, vpnPart(vpnReg, 1), 0.U(3.W))
|
||||
val pteAddrL2 = Cat(rootPpn, vpnPart(vpnReg, 2), 0.U(3.W))
|
||||
|
||||
io.memReq.valid := state === sL2 || state === sL1 || state === sL0
|
||||
io.memReq.addr := Mux(state === sL2, pteAddrL2, Mux(state === sL1, pteAddrL1, pteAddr))
|
||||
io.respValid := state === sDone
|
||||
io.pageFault := walkFault
|
||||
io.refill.valid := state === sDone && !walkFault
|
||||
io.refill.vpn := vpnReg
|
||||
io.refill.level := level
|
||||
io.refill.flags := pteFlags
|
||||
io.refill.ppn := nextPpn
|
||||
|
||||
when(state === sIdle) {
|
||||
walkFault := false.B
|
||||
when(io.reqValid) {
|
||||
vpnReg := io.reqVpn
|
||||
isStoreReg := io.isStore
|
||||
isFetchReg := io.isFetch
|
||||
state := sL2
|
||||
}
|
||||
}.elsewhen((state === sL2 || state === sL1 || state === sL0) && io.memResp.valid) {
|
||||
when(invalidPte) {
|
||||
walkFault := true.B
|
||||
state := sDone
|
||||
}.elsewhen(pteIsLeaf) {
|
||||
when(permFault) {
|
||||
walkFault := true.B
|
||||
}
|
||||
val ppn0 = Mux(level === 0.U, ptePpn(8, 0), vpnReg(8, 0))
|
||||
val ppn1 = Mux(level <= 1.U, ptePpn(17, 9), vpnReg(17, 9))
|
||||
val ppn2 = ptePpn(43, 18)
|
||||
nextPpn := Cat(ppn2, ppn1, ppn0)
|
||||
state := sDone
|
||||
}.otherwise {
|
||||
curPpn := ptePpn
|
||||
when(state === sL2) {
|
||||
state := sL1
|
||||
}.elsewhen(state === sL1) {
|
||||
state := sL0
|
||||
}.otherwise {
|
||||
walkFault := true.B
|
||||
state := sDone
|
||||
}
|
||||
}
|
||||
}.elsewhen(state === sDone) {
|
||||
state := sIdle
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
val req = Input(new TlbReq(p))
|
||||
val resp = Output(new TlbResp(p))
|
||||
val ptwMemReq = Output(new PtwMemReq(p))
|
||||
val ptwMemResp = Input(new PtwMemResp(p))
|
||||
val refill = Output(new TlbRefill(p))
|
||||
})
|
||||
|
||||
io.paddr := io.vaddr
|
||||
io.pageFault := false.B
|
||||
}
|
||||
val bare = io.satp(63, 60) === 0.U
|
||||
val walker = Module(new PageTableWalker(p))
|
||||
walker.io.reqValid := io.req.valid && !bare
|
||||
walker.io.reqVpn := io.req.vaddr(38, 12)
|
||||
walker.io.isStore := io.req.isStore
|
||||
walker.io.isFetch := io.req.isFetch
|
||||
walker.io.satp := io.satp
|
||||
walker.io.memResp := io.ptwMemResp
|
||||
|
||||
io.ptwMemReq := walker.io.memReq
|
||||
io.refill := walker.io.refill
|
||||
io.resp.hit := bare
|
||||
io.resp.miss := io.req.valid && !bare && !walker.io.respValid
|
||||
io.resp.paddr := io.req.vaddr
|
||||
io.resp.pageFault := walker.io.respValid && walker.io.pageFault
|
||||
io.resp.accessFault := false.B
|
||||
}
|
||||
|
||||
@@ -4,17 +4,20 @@ class MemStage(p: CoreParams = CoreParams()) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reqValid = Input(Bool())
|
||||
val req = Input(new MemRequest(p))
|
||||
val satp = Input(UInt(p.xlen.W))
|
||||
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 pageFault = Output(Bool())
|
||||
})
|
||||
|
||||
val lsu = Module(new LSU(p))
|
||||
lsu.io.reqValid := io.reqValid
|
||||
lsu.io.req := io.req
|
||||
lsu.io.satp := io.satp
|
||||
lsu.io.dmemRespValid := io.dmemRespValid
|
||||
lsu.io.dmemRespData := io.dmemRespData
|
||||
|
||||
@@ -22,5 +25,5 @@ class MemStage(p: CoreParams = CoreParams()) extends Module {
|
||||
io.dmemReq := lsu.io.dmemReq
|
||||
io.respValid := lsu.io.respValid
|
||||
io.respData := lsu.io.respData
|
||||
io.pageFault := lsu.io.pageFault
|
||||
}
|
||||
|
||||
|
||||
@@ -2,23 +2,94 @@ import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class StoreQueue(p: CoreParams = CoreParams()) extends Module {
|
||||
private val idxBits = log2Ceil(p.storeQueueEntries)
|
||||
private val robBits = log2Ceil(p.robEntries)
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val enqValid = Input(Bool())
|
||||
val enq = Input(new MemRequest(p))
|
||||
val enqRobIdx = Input(UInt(robBits.W))
|
||||
val enqReady = Output(Bool())
|
||||
val enqIdx = Output(UInt(idxBits.W))
|
||||
|
||||
val writeAddr = Input(Bool())
|
||||
val writeData = Input(Bool())
|
||||
val writeIdx = Input(UInt(idxBits.W))
|
||||
val addr = Input(UInt(p.xlen.W))
|
||||
val data = Input(UInt(p.xlen.W))
|
||||
val size = Input(UInt(3.W))
|
||||
|
||||
val loadAddr = Input(UInt(p.xlen.W))
|
||||
val loadSize = Input(UInt(3.W))
|
||||
val loadRobIdx = Input(UInt(robBits.W))
|
||||
val forwardValid = Output(Bool())
|
||||
val forwardData = Output(UInt(p.xlen.W))
|
||||
|
||||
val commitValid = Input(Bool())
|
||||
val commitRobIdx = Input(UInt(robBits.W))
|
||||
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
|
||||
val entries = RegInit(VecInit(Seq.fill(p.storeQueueEntries)(0.U.asTypeOf(new StoreQueueEntry(p)))))
|
||||
val freeMask = VecInit(entries.map(e => !e.valid)).asUInt
|
||||
val enqOH = PriorityEncoderOH(freeMask)
|
||||
val enqIdx = OHToUInt(enqOH)
|
||||
|
||||
io.enqReady := q.io.enq.ready
|
||||
io.drainValid := q.io.deq.valid && !io.flush
|
||||
io.drain := q.io.deq.bits
|
||||
def sameWord(a: UInt, b: UInt): Bool = a(p.xlen - 1, 3) === b(p.xlen - 1, 3)
|
||||
|
||||
io.enqReady := freeMask.orR
|
||||
io.enqIdx := enqIdx
|
||||
|
||||
val forwardVec = Wire(Vec(p.storeQueueEntries, Bool()))
|
||||
for (i <- 0 until p.storeQueueEntries) {
|
||||
forwardVec(i) := entries(i).valid && entries(i).addrValid && entries(i).dataValid &&
|
||||
entries(i).robIdx < io.loadRobIdx && sameWord(entries(i).addr, io.loadAddr)
|
||||
}
|
||||
io.forwardValid := forwardVec.asUInt.orR
|
||||
io.forwardData := Mux1H(forwardVec, entries.map(_.data))
|
||||
|
||||
val drainVec = Wire(Vec(p.storeQueueEntries, Bool()))
|
||||
for (i <- 0 until p.storeQueueEntries) {
|
||||
drainVec(i) := entries(i).valid && entries(i).committed && entries(i).addrValid && entries(i).dataValid
|
||||
}
|
||||
val drainOH = PriorityEncoderOH(drainVec.asUInt)
|
||||
val drainIdx = OHToUInt(drainOH)
|
||||
io.drainValid := drainVec.asUInt.orR
|
||||
io.drain.addr := entries(drainIdx).addr
|
||||
io.drain.data := entries(drainIdx).data
|
||||
io.drain.isStore := true.B
|
||||
io.drain.size := entries(drainIdx).size
|
||||
|
||||
when(io.flush) {
|
||||
entries.foreach(_ := 0.U.asTypeOf(new StoreQueueEntry(p)))
|
||||
}.otherwise {
|
||||
when(io.enqValid && io.enqReady) {
|
||||
entries(enqIdx).valid := true.B
|
||||
entries(enqIdx).robIdx := io.enqRobIdx
|
||||
entries(enqIdx).addrValid := false.B
|
||||
entries(enqIdx).dataValid := false.B
|
||||
entries(enqIdx).committed := false.B
|
||||
}
|
||||
when(io.writeAddr) {
|
||||
entries(io.writeIdx).addrValid := true.B
|
||||
entries(io.writeIdx).addr := io.addr
|
||||
entries(io.writeIdx).size := io.size
|
||||
}
|
||||
when(io.writeData) {
|
||||
entries(io.writeIdx).dataValid := true.B
|
||||
entries(io.writeIdx).data := io.data
|
||||
}
|
||||
when(io.commitValid) {
|
||||
for (i <- 0 until p.storeQueueEntries) {
|
||||
when(entries(i).valid && entries(i).robIdx === io.commitRobIdx) {
|
||||
entries(i).committed := true.B
|
||||
}
|
||||
}
|
||||
}
|
||||
when(io.drainValid && io.drainReady) {
|
||||
entries(drainIdx).valid := false.B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,23 +4,50 @@ 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 allocReq = Input(Vec(p.issueWidth, Bool()))
|
||||
val allocPhys = Output(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val allocValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val canAllocate = Output(Bool())
|
||||
val freeReq = Input(Vec(p.issueWidth, Bool()))
|
||||
val freePhys = Input(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val recover = Input(Bool())
|
||||
val committedPhys = Input(Vec(p.archRegs, 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
|
||||
val freeMask = freeBits.asUInt
|
||||
val firstOH = PriorityEncoderOH(freeMask)
|
||||
val secondMask = freeMask & ~firstOH
|
||||
val secondOH = PriorityEncoderOH(secondMask)
|
||||
val freeCount = PopCount(freeMask)
|
||||
dontTouch(freeMask)
|
||||
dontTouch(freeCount)
|
||||
|
||||
when(io.alloc && io.canAlloc) {
|
||||
freeBits(chosen) := false.B
|
||||
io.canAllocate := freeCount >= p.issueWidth.U
|
||||
io.allocPhys(0) := OHToUInt(firstOH)
|
||||
io.allocPhys(1) := OHToUInt(secondOH)
|
||||
io.allocValid(0) := io.allocReq(0) && freeMask.orR
|
||||
io.allocValid(1) := io.allocReq(1) && secondMask.orR
|
||||
|
||||
val nextFree = Wire(Vec(p.physRegs, Bool()))
|
||||
nextFree := freeBits
|
||||
when(io.allocReq(0) && io.allocValid(0)) {
|
||||
nextFree(io.allocPhys(0)) := false.B
|
||||
}
|
||||
when(io.free && io.freePhys >= p.archRegs.U) {
|
||||
freeBits(io.freePhys) := true.B
|
||||
when(io.allocReq(1) && io.allocValid(1)) {
|
||||
nextFree(io.allocPhys(1)) := false.B
|
||||
}
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
when(io.freeReq(i) && io.freePhys(i) =/= 0.U) {
|
||||
nextFree(io.freePhys(i)) := true.B
|
||||
}
|
||||
}
|
||||
when(io.recover) {
|
||||
for (i <- 0 until p.physRegs) {
|
||||
val isCommitted = io.committedPhys.map(_ === i.U).foldLeft(false.B)(_ || _)
|
||||
freeBits(i) := !isCommitted
|
||||
}
|
||||
}.otherwise {
|
||||
freeBits := nextFree
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,69 +3,184 @@ import chisel3.util._
|
||||
|
||||
class RobEntry(p: CoreParams = CoreParams()) extends Bundle {
|
||||
val valid = Bool()
|
||||
val robIdx = UInt(log2Ceil(p.robEntries).W)
|
||||
val pc = UInt(p.xlen.W)
|
||||
val archDest = UInt(5.W)
|
||||
val writesDest = Bool()
|
||||
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 exceptionCause = UInt(p.xlen.W)
|
||||
val badAddr = UInt(p.xlen.W)
|
||||
val branchMispredict = Bool()
|
||||
val redirectPc = UInt(p.xlen.W)
|
||||
val csrValid = Bool()
|
||||
val csrAddr = UInt(12.W)
|
||||
val csrCmd = UInt(3.W)
|
||||
val csrRs1 = UInt(p.xlen.W)
|
||||
val csrZimm = UInt(5.W)
|
||||
}
|
||||
|
||||
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 allocateValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val allocateEntry = Input(Vec(p.issueWidth, new RobEntry(p)))
|
||||
val allocateIdx = Output(Vec(p.issueWidth, 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 completeValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeIdx = Input(Vec(p.issueWidth, UInt(idxBits.W)))
|
||||
val completeException = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeCause = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeBadAddr = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeMispredict = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeRedirectPc = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeCsrValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeCsrAddr = Input(Vec(p.issueWidth, UInt(12.W)))
|
||||
val completeCsrCmd = Input(Vec(p.issueWidth, UInt(3.W)))
|
||||
val completeCsrRs1 = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeCsrZimm = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
val commitValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val commit = Output(Vec(p.issueWidth, new RobEntry(p)))
|
||||
val commitReady = Input(Vec(p.issueWidth, Bool()))
|
||||
val flush = Input(Bool())
|
||||
val empty = Output(Bool())
|
||||
})
|
||||
|
||||
val entries = RegInit(VecInit(Seq.fill(p.robEntries)(0.U.asTypeOf(new RobEntry(p)))))
|
||||
val valid = RegInit(VecInit(Seq.fill(p.robEntries)(false.B)))
|
||||
val completed = RegInit(VecInit(Seq.fill(p.robEntries)(false.B)))
|
||||
val exception = RegInit(VecInit(Seq.fill(p.robEntries)(false.B)))
|
||||
val exceptionCause = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(p.xlen.W))))
|
||||
val badAddr = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(p.xlen.W))))
|
||||
val branchMispredict = RegInit(VecInit(Seq.fill(p.robEntries)(false.B)))
|
||||
val redirectPc = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(p.xlen.W))))
|
||||
val csrValid = RegInit(VecInit(Seq.fill(p.robEntries)(false.B)))
|
||||
val csrAddr = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(12.W))))
|
||||
val csrCmd = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(3.W))))
|
||||
val csrRs1 = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(p.xlen.W))))
|
||||
val csrZimm = RegInit(VecInit(Seq.fill(p.robEntries)(0.U(5.W))))
|
||||
val head = RegInit(0.U(idxBits.W))
|
||||
val tail = RegInit(0.U(idxBits.W))
|
||||
val count = RegInit(0.U(log2Ceil(p.robEntries + 1).W))
|
||||
val allocCount = PopCount(io.allocateValid)
|
||||
|
||||
io.canAllocate := count =/= p.robEntries.U
|
||||
io.allocateIdx := tail
|
||||
io.commit := entries(head)
|
||||
io.commitValid := count =/= 0.U && entries(head).valid && entries(head).completed
|
||||
val head0 = head
|
||||
val head1 = head + 1.U
|
||||
val tail0 = tail
|
||||
val tail1 = tail + 1.U
|
||||
val headEntry0 = Wire(new RobEntry(p))
|
||||
val headEntry1 = Wire(new RobEntry(p))
|
||||
headEntry0 := entries(head0)
|
||||
headEntry0.valid := valid(head0)
|
||||
headEntry0.completed := completed(head0)
|
||||
headEntry0.exception := exception(head0)
|
||||
headEntry0.exceptionCause := exceptionCause(head0)
|
||||
headEntry0.badAddr := badAddr(head0)
|
||||
headEntry0.branchMispredict := branchMispredict(head0)
|
||||
headEntry0.redirectPc := redirectPc(head0)
|
||||
headEntry0.csrValid := csrValid(head0)
|
||||
headEntry0.csrAddr := csrAddr(head0)
|
||||
headEntry0.csrCmd := csrCmd(head0)
|
||||
headEntry0.csrRs1 := csrRs1(head0)
|
||||
headEntry0.csrZimm := csrZimm(head0)
|
||||
headEntry1 := entries(head1)
|
||||
headEntry1.valid := valid(head1)
|
||||
headEntry1.completed := completed(head1)
|
||||
headEntry1.exception := exception(head1)
|
||||
headEntry1.exceptionCause := exceptionCause(head1)
|
||||
headEntry1.badAddr := badAddr(head1)
|
||||
headEntry1.branchMispredict := branchMispredict(head1)
|
||||
headEntry1.redirectPc := redirectPc(head1)
|
||||
headEntry1.csrValid := csrValid(head1)
|
||||
headEntry1.csrAddr := csrAddr(head1)
|
||||
headEntry1.csrCmd := csrCmd(head1)
|
||||
headEntry1.csrRs1 := csrRs1(head1)
|
||||
headEntry1.csrZimm := csrZimm(head1)
|
||||
|
||||
io.empty := count === 0.U
|
||||
io.canAllocate := (p.robEntries.U - count) >= p.issueWidth.U
|
||||
io.allocateIdx(0) := tail0
|
||||
io.allocateIdx(1) := tail1
|
||||
io.commit(0) := headEntry0
|
||||
io.commit(1) := headEntry1
|
||||
io.commitValid(0) := count =/= 0.U && valid(head0) && completed(head0)
|
||||
io.commitValid(1) := count > 1.U && io.commitValid(0) && !headEntry0.exception &&
|
||||
!headEntry0.branchMispredict && valid(head1) && completed(head1)
|
||||
|
||||
when(io.flush) {
|
||||
entries.foreach(_.valid := false.B)
|
||||
valid := VecInit(Seq.fill(p.robEntries)(false.B))
|
||||
completed := VecInit(Seq.fill(p.robEntries)(false.B))
|
||||
exception := VecInit(Seq.fill(p.robEntries)(false.B))
|
||||
branchMispredict := VecInit(Seq.fill(p.robEntries)(false.B))
|
||||
csrValid := VecInit(Seq.fill(p.robEntries)(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.allocateValid(0) && io.canAllocate) {
|
||||
entries(tail0) := io.allocateEntry(0)
|
||||
entries(tail0).robIdx := tail0
|
||||
valid(tail0) := true.B
|
||||
completed(tail0) := false.B
|
||||
exception(tail0) := false.B
|
||||
exceptionCause(tail0) := 0.U
|
||||
badAddr(tail0) := 0.U
|
||||
branchMispredict(tail0) := false.B
|
||||
redirectPc(tail0) := 0.U
|
||||
csrValid(tail0) := false.B
|
||||
csrAddr(tail0) := 0.U
|
||||
csrCmd(tail0) := 0.U
|
||||
csrRs1(tail0) := 0.U
|
||||
csrZimm(tail0) := 0.U
|
||||
}
|
||||
when(io.complete) {
|
||||
entries(io.completeIdx).completed := true.B
|
||||
when(io.allocateValid(1) && io.canAllocate) {
|
||||
entries(tail1) := io.allocateEntry(1)
|
||||
entries(tail1).robIdx := tail1
|
||||
valid(tail1) := true.B
|
||||
completed(tail1) := false.B
|
||||
exception(tail1) := false.B
|
||||
exceptionCause(tail1) := 0.U
|
||||
badAddr(tail1) := 0.U
|
||||
branchMispredict(tail1) := false.B
|
||||
redirectPc(tail1) := 0.U
|
||||
csrValid(tail1) := false.B
|
||||
csrAddr(tail1) := 0.U
|
||||
csrCmd(tail1) := 0.U
|
||||
csrRs1(tail1) := 0.U
|
||||
csrZimm(tail1) := 0.U
|
||||
}
|
||||
when(io.commitValid && io.commitReady) {
|
||||
entries(head).valid := false.B
|
||||
head := head + 1.U
|
||||
count := count - 1.U
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
when(io.completeValid(i)) {
|
||||
completed(io.completeIdx(i)) := true.B
|
||||
exception(io.completeIdx(i)) := io.completeException(i)
|
||||
exceptionCause(io.completeIdx(i)) := io.completeCause(i)
|
||||
badAddr(io.completeIdx(i)) := io.completeBadAddr(i)
|
||||
branchMispredict(io.completeIdx(i)) := io.completeMispredict(i)
|
||||
redirectPc(io.completeIdx(i)) := io.completeRedirectPc(i)
|
||||
csrValid(io.completeIdx(i)) := io.completeCsrValid(i)
|
||||
csrAddr(io.completeIdx(i)) := io.completeCsrAddr(i)
|
||||
csrCmd(io.completeIdx(i)) := io.completeCsrCmd(i)
|
||||
csrRs1(io.completeIdx(i)) := io.completeCsrRs1(i)
|
||||
csrZimm(io.completeIdx(i)) := io.completeCsrZimm(i)
|
||||
}
|
||||
}
|
||||
val commit0 = io.commitValid(0) && io.commitReady(0)
|
||||
val commit1 = io.commitValid(1) && io.commitReady(1)
|
||||
when(commit0) { valid(head0) := false.B }
|
||||
when(commit1) { valid(head1) := false.B }
|
||||
|
||||
val committed = PopCount(VecInit(Seq(commit0, commit1)))
|
||||
val allocated = Mux(io.canAllocate, allocCount, 0.U)
|
||||
head := head + committed
|
||||
tail := tail + allocated
|
||||
count := count + allocated - committed
|
||||
when(!commit0 && !commit1 && allocated === 0.U) {
|
||||
head := head
|
||||
tail := tail
|
||||
count := count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,43 @@ import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class RenameStage(p: CoreParams = CoreParams()) extends Module {
|
||||
private val physBits = log2Ceil(p.physRegs)
|
||||
private val robBits = log2Ceil(p.robEntries)
|
||||
|
||||
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 inValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val in = Input(Vec(p.issueWidth, new DecodedInst(p)))
|
||||
val outValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val out = Output(Vec(p.issueWidth, new RenamePacket(p)))
|
||||
val canAccept = Output(Bool())
|
||||
|
||||
val wbValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val wbPhys = Input(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
|
||||
val completeValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeIdx = Input(Vec(p.issueWidth, UInt(robBits.W)))
|
||||
val completeException = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeCause = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeBadAddr = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeMispredict = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeRedirectPc = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeCsrValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val completeCsrAddr = Input(Vec(p.issueWidth, UInt(12.W)))
|
||||
val completeCsrCmd = Input(Vec(p.issueWidth, UInt(3.W)))
|
||||
val completeCsrRs1 = Input(Vec(p.issueWidth, UInt(p.xlen.W)))
|
||||
val completeCsrZimm = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
|
||||
val commitReady = Input(Vec(p.issueWidth, Bool()))
|
||||
val commitValid = Output(Vec(p.issueWidth, Bool()))
|
||||
val commitEntry = Output(Vec(p.issueWidth, new RobEntry(p)))
|
||||
val robEmpty = Output(Bool())
|
||||
|
||||
val commitMapValid = Input(Vec(p.issueWidth, Bool()))
|
||||
val commitArch = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
val commitPhys = Input(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val commitFreeOld = Input(Vec(p.issueWidth, Bool()))
|
||||
val commitOldPhys = Input(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
|
||||
val flush = Input(Bool())
|
||||
})
|
||||
|
||||
@@ -16,34 +46,97 @@ class RenameStage(p: CoreParams = CoreParams()) extends Module {
|
||||
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
|
||||
val needsPhys = Wire(Vec(p.issueWidth, Bool()))
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
needsPhys(i) := io.inValid(i) && io.in(i).writesRd
|
||||
}
|
||||
|
||||
table.io.rs1 := VecInit(io.in.map(_.rs1))
|
||||
table.io.rs2 := VecInit(io.in.map(_.rs2))
|
||||
table.io.rd := VecInit(io.in.map(_.rd))
|
||||
table.io.newPhys := freeList.io.allocPhys
|
||||
table.io.wen := io.inValid && io.in.writesRd && freeList.io.canAlloc && rob.io.canAllocate
|
||||
table.io.wen := VecInit((0 until p.issueWidth).map(i => io.outValid(i) && io.in(i).writesRd))
|
||||
table.io.commitWen := io.commitMapValid
|
||||
table.io.commitRd := io.commitArch
|
||||
table.io.commitPhys := io.commitPhys
|
||||
table.io.recover := io.flush
|
||||
|
||||
freeList.io.alloc := table.io.wen
|
||||
freeList.io.free := io.commitFree
|
||||
freeList.io.allocReq := needsPhys
|
||||
freeList.io.freeReq := io.commitFreeOld
|
||||
freeList.io.freePhys := io.commitOldPhys
|
||||
freeList.io.recover := io.flush
|
||||
freeList.io.committedPhys := table.io.committedPhys
|
||||
|
||||
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
|
||||
val requested = PopCount(io.inValid)
|
||||
val canRename = freeList.io.canAllocate && rob.io.canAllocate
|
||||
io.canAccept := canRename
|
||||
|
||||
val readyReg = RegInit(VecInit(Seq.fill(p.physRegs)(true.B)))
|
||||
when(io.flush) {
|
||||
readyReg := VecInit(Seq.fill(p.physRegs)(true.B))
|
||||
}.otherwise {
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
when(io.wbValid(i)) {
|
||||
readyReg(io.wbPhys(i)) := true.B
|
||||
}
|
||||
when(io.outValid(i) && io.in(i).writesRd) {
|
||||
readyReg(freeList.io.allocPhys(i)) := false.B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rob.io.allocateValid := VecInit((0 until p.issueWidth).map(i => io.inValid(i) && canRename))
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
val e = WireDefault(0.U.asTypeOf(new RobEntry(p)))
|
||||
e.valid := io.inValid(i) && canRename
|
||||
e.pc := io.in(i).pc
|
||||
e.archDest := io.in(i).rd
|
||||
e.writesDest := io.in(i).writesRd
|
||||
e.opClass := io.in(i).opClass
|
||||
e.dest := Mux(io.in(i).writesRd, freeList.io.allocPhys(i), table.io.oldPrd(i))
|
||||
e.oldDest := table.io.oldPrd(i)
|
||||
rob.io.allocateEntry(i) := e
|
||||
}
|
||||
rob.io.completeValid := io.completeValid
|
||||
rob.io.completeIdx := io.completeIdx
|
||||
rob.io.completeException := io.completeException
|
||||
rob.io.completeCause := io.completeCause
|
||||
rob.io.completeBadAddr := io.completeBadAddr
|
||||
rob.io.completeMispredict := io.completeMispredict
|
||||
rob.io.completeRedirectPc := io.completeRedirectPc
|
||||
rob.io.completeCsrValid := io.completeCsrValid
|
||||
rob.io.completeCsrAddr := io.completeCsrAddr
|
||||
rob.io.completeCsrCmd := io.completeCsrCmd
|
||||
rob.io.completeCsrRs1 := io.completeCsrRs1
|
||||
rob.io.completeCsrZimm := io.completeCsrZimm
|
||||
rob.io.commitReady := io.commitReady
|
||||
rob.io.flush := io.flush
|
||||
io.commitValid := rob.io.commitValid
|
||||
io.commitEntry := rob.io.commit
|
||||
io.robEmpty := rob.io.empty
|
||||
|
||||
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
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
val src1FromOlder = (0 until i).map(j =>
|
||||
io.outValid(j) && io.in(j).writesRd && io.in(j).rd =/= 0.U && io.in(j).rd === io.in(i).rs1
|
||||
).foldLeft(false.B)(_ || _)
|
||||
val src2FromOlder = (0 until i).map(j =>
|
||||
io.outValid(j) && io.in(j).writesRd && io.in(j).rd =/= 0.U && io.in(j).rd === io.in(i).rs2
|
||||
).foldLeft(false.B)(_ || _)
|
||||
|
||||
io.outValid(i) := io.inValid(i) && canRename
|
||||
io.out(i).valid := io.outValid(i)
|
||||
io.out(i).decoded := io.in(i)
|
||||
io.out(i).prs1 := table.io.prs1(i)
|
||||
io.out(i).prs2 := table.io.prs2(i)
|
||||
io.out(i).src1Ready := io.in(i).rs1 === 0.U || (!src1FromOlder && readyReg(table.io.prs1(i)))
|
||||
io.out(i).src2Ready := io.in(i).rs2 === 0.U || (!src2FromOlder && readyReg(table.io.prs2(i)))
|
||||
io.out(i).prd := Mux(io.in(i).writesRd, freeList.io.allocPhys(i), table.io.oldPrd(i))
|
||||
io.out(i).oldPrd := table.io.oldPrd(i)
|
||||
io.out(i).robIdx := rob.io.allocateIdx(i)
|
||||
|
||||
}
|
||||
|
||||
when(requested === 0.U) {
|
||||
io.canAccept := true.B
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,29 +4,45 @@ 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 rs1 = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
val rs2 = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
val rd = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
val newPhys = Input(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val wen = Input(Vec(p.issueWidth, Bool()))
|
||||
val prs1 = Output(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val prs2 = Output(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val oldPrd = Output(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val commitWen = Input(Vec(p.issueWidth, Bool()))
|
||||
val commitRd = Input(Vec(p.issueWidth, UInt(5.W)))
|
||||
val commitPhys = Input(Vec(p.issueWidth, UInt(physBits.W)))
|
||||
val recover = Input(Bool())
|
||||
val committedPhys = Output(Vec(p.archRegs, UInt(physBits.W)))
|
||||
})
|
||||
|
||||
val init = VecInit((0 until p.archRegs).map(_.U(physBits.W)))
|
||||
val speculative = RegInit(init)
|
||||
val committed = RegInit(init)
|
||||
io.committedPhys := committed
|
||||
|
||||
io.prs1 := speculative(io.rs1)
|
||||
io.prs2 := speculative(io.rs2)
|
||||
io.oldPrd := speculative(io.rd)
|
||||
io.prs1(0) := speculative(io.rs1(0))
|
||||
io.prs2(0) := speculative(io.rs2(0))
|
||||
io.oldPrd(0) := speculative(io.rd(0))
|
||||
|
||||
val slot0Writes = io.wen(0) && io.rd(0) =/= 0.U
|
||||
io.prs1(1) := Mux(slot0Writes && io.rd(0) === io.rs1(1), io.newPhys(0), speculative(io.rs1(1)))
|
||||
io.prs2(1) := Mux(slot0Writes && io.rd(0) === io.rs2(1), io.newPhys(0), speculative(io.rs2(1)))
|
||||
io.oldPrd(1) := Mux(slot0Writes && io.rd(0) === io.rd(1), io.newPhys(0), speculative(io.rd(1)))
|
||||
|
||||
when(io.recover) {
|
||||
speculative := committed
|
||||
}.elsewhen(io.wen && io.rd =/= 0.U) {
|
||||
speculative(io.rd) := io.newPhys
|
||||
}.otherwise {
|
||||
for (i <- 0 until p.issueWidth) {
|
||||
when(io.wen(i) && io.rd(i) =/= 0.U) {
|
||||
speculative(io.rd(i)) := io.newPhys(i)
|
||||
}
|
||||
when(io.commitWen(i) && io.commitRd(i) =/= 0.U) {
|
||||
committed(io.commitRd(i)) := io.commitPhys(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user