fix: resolve OoO simulation timeout

This commit is contained in:
abnerhexu
2026-06-27 03:38:34 +00:00
parent 502803c37f
commit a2e0126199
68 changed files with 78250 additions and 210 deletions

View File

@@ -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")
)
}

View 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")
)
}

View File

@@ -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))
}

View File

@@ -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()
}

View File

@@ -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")
}

View File

@@ -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) {

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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
}
}
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}

View File

@@ -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)
}
}
}
}