474 lines
23 KiB
Scala
474 lines
23 KiB
Scala
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 invalidateICache = Output(Bool())
|
|
val sfenceVma = Output(Bool())
|
|
val setPriv = Output(Bool())
|
|
val targetPriv = Output(UInt(2.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 satpOut = Output(UInt(p.xlen.W))
|
|
val currentPriv = Input(UInt(2.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 completeFenceI = Wire(Vec(p.issueWidth, Bool()))
|
|
val completeSfenceVma = Wire(Vec(p.issueWidth, Bool()))
|
|
val completeXret = Wire(Vec(p.issueWidth, Bool()))
|
|
val completeXretIsMret = Wire(Vec(p.issueWidth, Bool()))
|
|
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)))
|
|
dontTouch(completeValid)
|
|
dontTouch(completeIdx)
|
|
dontTouch(completeException)
|
|
dontTouch(completeCause)
|
|
dontTouch(completeRedirectPc)
|
|
|
|
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.completeFenceI := completeFenceI
|
|
rename.io.completeSfenceVma := completeSfenceVma
|
|
rename.io.completeXret := completeXret
|
|
rename.io.completeXretIsMret := completeXretIsMret
|
|
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
|
|
issue.io.robHeadValid := rename.io.commitEntry(0).valid
|
|
issue.io.robHeadIdx := rename.io.commitEntry(0).robIdx
|
|
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 forwardPending = RegInit(false.B)
|
|
val forwardPendingRob = Reg(UInt(robBits.W))
|
|
val forwardPendingPhys = Reg(UInt(physBits.W))
|
|
val forwardPendingLq = Reg(UInt(log2Ceil(p.loadQueueEntries).W))
|
|
val forwardPendingData = Reg(UInt(p.xlen.W))
|
|
val loadRespValid = (lsu.io.respValid && loadPending) || forwardPending
|
|
val loadRespData = Mux(forwardPending, forwardPendingData, lsu.io.respData)
|
|
val loadRespFault = !forwardPending && (lsu.io.pageFault || lsu.io.accessFault || lsu.io.misaligned)
|
|
val storeCheckPending = RegInit(false.B)
|
|
val storeCheckPendingRob = Reg(UInt(robBits.W))
|
|
dontTouch(storeCheckPending)
|
|
val storeCheckRespNow = Wire(Bool())
|
|
val storeCheckRespPending = storeCheckPending && lsu.io.respValid
|
|
val storeCheckResp = storeCheckRespNow || storeCheckRespPending
|
|
val storeCheckFault = storeCheckResp && (lsu.io.pageFault || lsu.io.accessFault || lsu.io.misaligned)
|
|
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 && !forwardPending && !storeCheckPending
|
|
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 serializing0 = issue.io.out(0).decoded.isSystem || issue.io.out(0).decoded.isFenceI ||
|
|
issue.io.out(0).decoded.isSfenceVma || issue.io.out(0).decoded.isWfi
|
|
val serializing1 = issue.io.out(1).decoded.isSystem || issue.io.out(1).decoded.isFenceI ||
|
|
issue.io.out(1).decoded.isSfenceVma || issue.io.out(1).decoded.isWfi
|
|
val serializingReady0 = !serializing0 ||
|
|
(rename.io.commitEntry(0).valid && rename.io.commitEntry(0).robIdx === issue.io.out(0).robIdx)
|
|
val serializingReady1 = !serializing1 ||
|
|
(rename.io.commitEntry(0).valid && rename.io.commitEntry(0).robIdx === issue.io.out(1).robIdx)
|
|
dontTouch(serializingReady0)
|
|
dontTouch(serializingReady1)
|
|
val loadBlocked0 = issue.io.out(0).decoded.isLoad && sq.io.forwardBlock
|
|
val loadBlocked1 = issue.io.out(1).decoded.isLoad && sq.io.forwardBlock
|
|
val amoBlocked0 = issue.io.out(0).decoded.isAmo && (sq.io.olderStoreValid || sq.io.drainValid)
|
|
val amoBlocked1 = issue.io.out(1).decoded.isAmo && (sq.io.olderStoreValid || sq.io.drainValid)
|
|
val robHeadValid = rename.io.commitEntry(0).valid
|
|
val issue0AtHead = robHeadValid && rename.io.commitEntry(0).robIdx === issue.io.out(0).robIdx
|
|
val issue1AtHead = robHeadValid && rename.io.commitEntry(0).robIdx === issue.io.out(1).robIdx
|
|
val olderSerializingAtHead0 = robHeadValid && !issue0AtHead &&
|
|
(rename.io.commitEntry(0).csrValid || rename.io.commitEntry(0).fenceI ||
|
|
rename.io.commitEntry(0).sfenceVma || rename.io.commitEntry(0).xret)
|
|
val olderSerializingAtHead1 = robHeadValid && !issue1AtHead &&
|
|
(rename.io.commitEntry(0).csrValid || rename.io.commitEntry(0).fenceI ||
|
|
rename.io.commitEntry(0).sfenceVma || rename.io.commitEntry(0).xret)
|
|
val memReady0 = (!isMem0 || (lsu.io.reqReady && canIssueMem && !amoBlocked0 && !loadBlocked0)) &&
|
|
!loadPending && !forwardPending && serializingReady0 && !olderSerializingAtHead0
|
|
val memReady1 = (!isMem1 || (lsu.io.reqReady && canIssueMem && !memSlot0 && !amoBlocked1 && !loadBlocked1)) &&
|
|
serializingReady1 && !olderSerializingAtHead1
|
|
val baseIssueReady0 = memReady0 && !storeCheckPending
|
|
val baseIssueReady1 = memReady1 && !storeCheckPending
|
|
val slot0WouldIssueSerializing = issue.io.outValid(0) && baseIssueReady0 && serializing0
|
|
val slot1WouldIssueSerializing = issue.io.outValid(1) && baseIssueReady1 && serializing1
|
|
issue_io_outReady_0 := baseIssueReady0 && !slot1WouldIssueSerializing
|
|
issue_io_outReady_1 := baseIssueReady1 && !slot0WouldIssueSerializing &&
|
|
!(stallSecondCsrRead && issue_io_outReady_0)
|
|
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.isAmo, 0.U, Mux(memDecoded.isStore, memDecoded.immS, memDecoded.immI))
|
|
def accessBytes(size: UInt): UInt = MuxLookup(size, 8.U(4.W))(Seq(
|
|
0.U -> 1.U(4.W),
|
|
1.U -> 2.U(4.W),
|
|
2.U -> 4.U(4.W),
|
|
3.U -> 8.U(4.W)
|
|
))
|
|
|
|
val loadEnq = (memSlot0 || memSlot1) && memDecoded.isLoad && issue.io.outReady(memSlot)
|
|
val storeEnq = (memSlot0 || memSlot1) && memDecoded.isStore && issue.io.outReady(memSlot)
|
|
val sqForwardValid = sq.io.forwardValid && !memDecoded.isAmo
|
|
val forwardLoad = loadEnq && sqForwardValid
|
|
val lsuLoadReq = loadEnq && !sqForwardValid
|
|
val lsuStoreCheckReq = storeEnq
|
|
val forwardByte = sq.io.forwardData(7, 0)
|
|
val forwardHalf = sq.io.forwardData(15, 0)
|
|
val forwardWord = sq.io.forwardData(31, 0)
|
|
val forwardSelected = MuxLookup(memDecoded.memWidth, sq.io.forwardData)(Seq(
|
|
0.U -> Mux(memDecoded.memSigned, Consts.signExtend(forwardByte, 8), forwardByte),
|
|
1.U -> Mux(memDecoded.memSigned, Consts.signExtend(forwardHalf, 16), forwardHalf),
|
|
2.U -> Mux(memDecoded.memSigned, Consts.signExtend(forwardWord, 32), forwardWord),
|
|
3.U -> sq.io.forwardData
|
|
))
|
|
|
|
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 := Mux(forwardPending, forwardPendingLq, loadPendingLq)
|
|
lq.io.commitValid := VecInit((0 until p.issueWidth).map(i =>
|
|
commit.io.commitReady(i) && rename.io.commitValid(i) &&
|
|
rename.io.commitEntry(i).opClass === Consts.OP_LOAD))
|
|
lq.io.commitRobIdx := VecInit((0 until p.issueWidth).map(i => rename.io.commitEntry(i).robIdx))
|
|
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)
|
|
val storeDrainFire = sq.io.drainValid && !lsuLoadReq && !lsuStoreCheckReq && lsu.io.reqReady
|
|
sq.io.drainReady := storeDrainFire
|
|
sq.io.flush := commit.io.flush
|
|
|
|
lsu.io.reqValid := lsuLoadReq || lsuStoreCheckReq || storeDrainFire
|
|
lsu.io.checkOnly := lsuStoreCheckReq
|
|
lsu.io.sfenceVma := commit.io.sfenceVma
|
|
lsu.io.currentPriv := io.currentPriv
|
|
lsu.io.mstatus := csr.io.mstatus
|
|
val loadReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
|
|
loadReq.addr := memAddr
|
|
loadReq.data := memSrc2
|
|
loadReq.isStore := false.B
|
|
loadReq.isSigned := memDecoded.memSigned || memDecoded.isAmo
|
|
loadReq.isAmo := memDecoded.isAmo
|
|
loadReq.amoOp := memDecoded.amoOp
|
|
loadReq.size := memDecoded.memWidth
|
|
val storeCheckReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
|
|
storeCheckReq.addr := memAddr
|
|
storeCheckReq.data := memSrc2
|
|
storeCheckReq.isStore := true.B
|
|
storeCheckReq.isSigned := false.B
|
|
storeCheckReq.isAmo := false.B
|
|
storeCheckReq.amoOp := 0.U
|
|
storeCheckReq.size := memDecoded.memWidth
|
|
lsu.io.req := Mux(lsuLoadReq, loadReq, Mux(lsuStoreCheckReq, storeCheckReq, sq.io.drain))
|
|
storeCheckRespNow := lsuStoreCheckReq && lsu.io.respValid
|
|
lsu.io.dmemRespValid := io.dmemRespValid
|
|
lsu.io.dmemRespData := io.dmemRespData
|
|
lsu.io.satp := csr.io.satp
|
|
io.satpOut := 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))
|
|
csr.io.currentPriv := io.currentPriv
|
|
csrRData(0) := csr.io.rdata
|
|
csrRData(1) := csr.io.rdata
|
|
csr.io.trap := commit.io.flush && commit.io.exception
|
|
csr.io.trapPc := commit.io.trapPc
|
|
csr.io.trapCause := commit.io.exceptionCause
|
|
csr.io.trapTval := commit.io.badAddr
|
|
val trapTargetPriv = PrivilegeTransitions.trapTargetPriv(
|
|
io.currentPriv,
|
|
commit.io.exceptionCause,
|
|
false.B,
|
|
csr.io.medeleg,
|
|
csr.io.mideleg)
|
|
csr.io.trapTargetPriv := trapTargetPriv
|
|
csr.io.trapIsInterrupt := false.B
|
|
csr.io.xret := commit.io.flush && commit.io.xret
|
|
csr.io.xretIsMret := commit.io.xretIsMret
|
|
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
|
|
forwardPending := false.B
|
|
storeCheckPending := false.B
|
|
}.elsewhen(forwardLoad) {
|
|
forwardPending := true.B
|
|
forwardPendingRob := issue.io.out(memSlot).robIdx
|
|
forwardPendingPhys := issue.io.out(memSlot).prd
|
|
forwardPendingLq := lq.io.enqIdx
|
|
forwardPendingData := forwardSelected
|
|
}.elsewhen(forwardPending) {
|
|
forwardPending := false.B
|
|
}.elsewhen(loadEnq && !sqForwardValid) {
|
|
loadPending := true.B
|
|
loadPendingRob := issue.io.out(memSlot).robIdx
|
|
loadPendingPhys := issue.io.out(memSlot).prd
|
|
loadPendingLq := lq.io.enqIdx
|
|
}.elsewhen(loadRespValid) {
|
|
loadPending := false.B
|
|
}
|
|
when(!commit.io.flush) {
|
|
when(storeCheckRespPending) {
|
|
storeCheckPending := false.B
|
|
}.elsewhen(lsuStoreCheckReq && !storeCheckRespNow) {
|
|
storeCheckPending := true.B
|
|
storeCheckPendingRob := issue.io.out(memSlot).robIdx
|
|
}
|
|
}
|
|
|
|
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 src1Raw = prf.io.rdata(2 * i)
|
|
val rs2Raw = prf.io.rdata(2 * i + 1)
|
|
val src1 = MuxCase(src1Raw, (0 until p.issueWidth).map(w =>
|
|
(wakeupReg(w).valid && wakeupReg(w).phys =/= 0.U && wakeupReg(w).phys === issue.io.out(i).prs1) -> wakeupReg(w).data))
|
|
val rs2Val = MuxCase(rs2Raw, (0 until p.issueWidth).map(w =>
|
|
(wakeupReg(w).valid && wakeupReg(w).phys =/= 0.U && wakeupReg(w).phys === issue.io.out(i).prs2) -> wakeupReg(w).data))
|
|
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 branchTarget = decoded.pc + decoded.immB
|
|
val jalTarget = decoded.pc + decoded.immJ
|
|
val jalrTarget = (src1 + decoded.immI) & (~1.U(p.xlen.W))
|
|
val controlTarget = Mux(decoded.isJal, jalTarget,
|
|
Mux(decoded.isJalr, jalrTarget, branchTarget))
|
|
val controlTargetMisaligned = issueFire(i) &&
|
|
(decoded.isJal || decoded.isJalr || (decoded.isBranch && exec(i).io.branchTaken)) &&
|
|
controlTarget(1, 0) =/= 0.U
|
|
dontTouch(controlTargetMisaligned)
|
|
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.isEcall
|
|
val isEbreak = decoded.isEbreak
|
|
val isMret = decoded.isMret
|
|
val illegalPriv = (decoded.isMret && io.currentPriv =/= Privileged.PRV_M) ||
|
|
(decoded.isSret && io.currentPriv === Privileged.PRV_U) ||
|
|
(decoded.isSfenceVma && io.currentPriv === Privileged.PRV_U)
|
|
val csrReadIllegal = csrReadFire(i) && csr.io.readIllegal
|
|
val csrWrites = decoded.isSystem && decoded.funct3 =/= 0.U &&
|
|
!(decoded.funct3(1) && decoded.rs1 === 0.U)
|
|
val csrWriteIllegal = csrWrites && !CSRPermission.writeAllowed(decoded.inst(31, 20), io.currentPriv)
|
|
val illegalInst = !decoded.fetchException && (decoded.illegal || illegalPriv || csrReadIllegal || csrWriteIllegal)
|
|
val dataAddr = src1 + Mux(decoded.isStore, decoded.immS, decoded.immI)
|
|
val dataMisaligned = (dataAddr(2, 0) & (accessBytes(decoded.memWidth) - 1.U)) =/= 0.U
|
|
val storeMisaligned = issueFire(i) && decoded.isStore && dataMisaligned
|
|
|
|
val loadFaultNow = lsuLoadReq && lsu.io.respValid && (lsu.io.misaligned || lsu.io.pageFault || lsu.io.accessFault)
|
|
val issueRaisesException = issueFire(i) &&
|
|
(decoded.fetchException || illegalInst || isEcall || isEbreak || lq.io.violation || storeMisaligned ||
|
|
controlTargetMisaligned)
|
|
val loadRespHasFault = loadRespFault || loadFaultNow
|
|
val isLoadRespSlot = i.U === 0.U && loadRespValid && !loadRespHasFault
|
|
val useExecWb = exec(i).io.outValid && decoded.writesRd && !decoded.isLoad && !issueRaisesException
|
|
wb(i).io.valid := useExecWb || isLoadRespSlot
|
|
wb(i).io.physDest := Mux(isLoadRespSlot, Mux(forwardPending, forwardPendingPhys, loadPendingPhys), issue.io.out(i).prd)
|
|
wb(i).io.data := Mux(isLoadRespSlot, loadRespData, 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 completeLoadResp = i.U === 0.U && (loadRespValid || loadFaultNow)
|
|
val completeStoreResp = (i.U === 0.U && storeCheckRespPending) ||
|
|
(storeCheckRespNow && issueFire(i) && decoded.isStore)
|
|
completeValid(i) := (issueFire(i) && !decoded.isLoad && !decoded.isStore) || completeLoadResp || completeStoreResp
|
|
val storeCompleteIdx = Mux(storeCheckRespPending, storeCheckPendingRob, issue.io.out(i).robIdx)
|
|
completeIdx(i) := Mux(completeStoreResp, storeCompleteIdx,
|
|
Mux(completeLoadResp, Mux(loadFaultNow, issue.io.out(memSlot).robIdx, Mux(forwardPending, forwardPendingRob, loadPendingRob)),
|
|
issue.io.out(i).robIdx))
|
|
val issueException = issueRaisesException
|
|
val thisStoreCheckFault = completeStoreResp && storeCheckFault
|
|
completeException(i) := issueException || (completeLoadResp && (loadRespFault || loadFaultNow)) || thisStoreCheckFault
|
|
completeCause(i) := Mux(thisStoreCheckFault || (completeLoadResp && (loadRespFault || loadFaultNow)), lsu.io.faultCause,
|
|
Mux(issueFire(i) && decoded.fetchException, decoded.fetchExceptionCause,
|
|
Mux(issueFire(i) && isEbreak, Privileged.CAUSE_BREAKPOINT,
|
|
Mux(issueFire(i) && isEcall, ExceptionSource.ecallCause(io.currentPriv),
|
|
Mux(storeMisaligned, Privileged.CAUSE_STORE_ADDR_MISALIGNED,
|
|
Mux(controlTargetMisaligned, Privileged.CAUSE_INSTR_ADDR_MISALIGNED,
|
|
Mux(issueFire(i) && illegalInst, Privileged.CAUSE_ILLEGAL_INSTRUCTION, 0.U)))))))
|
|
completeBadAddr(i) := Mux(thisStoreCheckFault || (completeLoadResp && (loadRespFault || loadFaultNow)), lsu.io.faultAddr,
|
|
Mux(storeMisaligned, dataAddr,
|
|
Mux(issueFire(i) && decoded.fetchException, decoded.fetchExceptionTval,
|
|
Mux(controlTargetMisaligned, controlTarget,
|
|
Mux(issueFire(i) && illegalInst, decoded.inst.pad(p.xlen), 0.U)))))
|
|
completeMispredict(i) := issueFire(i) &&
|
|
(decoded.isJal || decoded.isJalr || decoded.isXret || decoded.isFenceI || decoded.isSfenceVma || decoded.isWfi ||
|
|
(decoded.isBranch && exec(i).io.branchTaken))
|
|
completeRedirectPc(i) := Mux(isEcall || isEbreak,
|
|
csr.io.trapVector,
|
|
Mux(decoded.isXret,
|
|
PrivilegeTransitions.xretTargetPc(decoded.isMret, csr.io.mepc, csr.io.sepc),
|
|
Mux(decoded.isWfi, decoded.pc + 4.U, branchRedirect)))
|
|
completeCsrValid(i) := issueFire(i) && decoded.isSystem && decoded.funct3 =/= 0.U &&
|
|
!(decoded.funct3(1) && decoded.rs1 === 0.U) && !illegalInst
|
|
completeCsrAddr(i) := decoded.inst(31, 20)
|
|
completeCsrCmd(i) := decoded.funct3
|
|
completeCsrRs1(i) := src1
|
|
completeCsrZimm(i) := decoded.rs1
|
|
completeFenceI(i) := issueFire(i) && decoded.isFenceI
|
|
completeSfenceVma(i) := issueFire(i) && decoded.isSfenceVma
|
|
completeXret(i) := issueFire(i) && decoded.isXret
|
|
completeXretIsMret(i) := issueFire(i) && decoded.isMret
|
|
}
|
|
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
|
|
val xretRedirectPc = PrivilegeTransitions.xretTargetPc(commit.io.xretIsMret, csr.io.mepc, csr.io.sepc)
|
|
dontTouch(xretRedirectPc)
|
|
io.redirectPc := Mux(commit.io.exception, csr.io.trapVector,
|
|
Mux(commit.io.xret, xretRedirectPc, commit.io.redirectPc))
|
|
io.invalidateICache := commit.io.fenceI
|
|
io.sfenceVma := commit.io.sfenceVma
|
|
io.setPriv := commit.io.setPriv
|
|
io.targetPriv := Mux(commit.io.exception,
|
|
trapTargetPriv,
|
|
Mux(commit.io.xret, PrivilegeTransitions.xretNextPriv(commit.io.xretIsMret, csr.io.mstatus), io.currentPriv))
|
|
}
|
|
|
|
object OoOBackend extends App {
|
|
ChiselStage.emitSystemVerilogFile(
|
|
new OoOBackend(),
|
|
args = Array("--target-dir", "generated"),
|
|
firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
|
|
)
|
|
}
|