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

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