fix: resolve OoO simulation timeout
This commit is contained in:
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")
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user