Skip to content

Commit

Permalink
Merge branch 'rob-refactor' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
martonbognar committed Mar 15, 2023
2 parents 3aca3d4 + e5fff8a commit 819eb9a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 79 deletions.
6 changes: 4 additions & 2 deletions src/main/scala/riscv/Core.scala
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,10 @@ object createDynamicPipeline {
val intMul1 = new Stage("EX_MUL1")
override val passThroughStage: Stage = intAlu1
override val rsStages: Seq[Stage] = Seq(intAlu1, intAlu2, intAlu3, intAlu4, intMul1)
override val loadStages: Seq[Stage] =
Seq(new Stage("LOAD1"), new Stage("LOAD2"), new Stage("LOAD3"))
val loadStage1 = new Stage("LOAD1")
val loadStage2 = new Stage("LOAD2")
val loadStage3 = new Stage("LOAD3")
override val loadStages: Seq[Stage] = Seq(loadStage1, loadStage2, loadStage3)
override val retirementStage = new Stage("RET")
override val unorderedStages: Seq[Stage] = rsStages ++ loadStages
override val stages = issuePipeline.stages ++ unorderedStages :+ retirementStage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class LoadManager(
)(implicit config: Config)
extends Area
with Resettable {
setPartialName(s"LM_${loadStage.stageName}")

val storedMessage: RdbMessage = RegInit(RdbMessage(retirementRegisters, rob.indexBits).getZero)
val outputCache: RdbMessage = RegInit(RdbMessage(retirementRegisters, rob.indexBits).getZero)
val rdbStream: Stream[RdbMessage] = Stream(
Expand Down
146 changes: 93 additions & 53 deletions src/main/scala/riscv/plugins/scheduling/dynamic/ReorderBuffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,30 @@ case class RobEntry(retirementRegisters: DynBundle[PipelineData[Data]])(implicit
extends Bundle {
val registerMap: Bundle with DynBundleAccess[PipelineData[Data]] =
retirementRegisters.createBundle
val ready = Bool()
val hasValue = Bool()
val rdbUpdated = Bool()
val cdbUpdated = Bool()

override def clone(): RobEntry = {
RobEntry(retirementRegisters)
}
}

case class RsData(indexBits: BitCount)(implicit config: Config) extends Bundle {
val updatingInstructionFound = Bool()
val updatingInstructionFinished = Bool()
val updatingInstructionIndex = UInt(indexBits)
val updatingInstructionValue = UInt(config.xlen bits)
}

case class EntryMetadata(indexBits: BitCount)(implicit config: Config) extends Bundle {
val rs1Data = Flow(RsData(indexBits))
val rs2Data = Flow(RsData(indexBits))

override def clone(): EntryMetadata = {
EntryMetadata(indexBits)
}
}

/** Terminology:
* - absolute index: the actual index of an entry in the circular buffer
* - relative index: an index that shows the order of instructions inserted into the ROB, 0 being
Expand Down Expand Up @@ -54,7 +70,7 @@ class ReorderBuffer(
isFull := False
}

def isValidAbsoluteIndex(index: UInt): Bool = {
private def isValidAbsoluteIndex(index: UInt): Bool = {
val ret = Bool()

val oldest = UInt(indexBits)
Expand All @@ -74,7 +90,7 @@ class ReorderBuffer(
ret
}

def relativeIndexForAbsolute(absolute: UInt): UInt = {
private def relativeIndexForAbsolute(absolute: UInt): UInt = {
val adjustedIndex = UInt(32 bits)
when(absolute >= oldestIndex.value) {
adjustedIndex := (absolute.resized - oldestIndex.value).resized
Expand All @@ -85,7 +101,7 @@ class ReorderBuffer(
adjustedIndex
}

def absoluteIndexForRelative(relative: UInt): UInt = {
private def absoluteIndexForRelative(relative: UInt): UInt = {
val absolute = UInt(32 bits)
val adjusted = UInt(32 bits)
val oldestResized = UInt(32 bits)
Expand All @@ -99,63 +115,81 @@ class ReorderBuffer(
adjusted
}

def pushEntry(
rd: UInt,
rdType: SpinalEnumCraft[RegisterType.type],
lsuOperationType: SpinalEnumCraft[LsuOperationType.type],
pc: UInt
): UInt = {
def pushEntry(): (UInt, EntryMetadata) = {
val issueStage = pipeline.issuePipeline.stages.last

pushInCycle := True
pushedEntry.ready := False
pushedEntry.hasValue := False
pushedEntry.registerMap.element(pipeline.data.PC.asInstanceOf[PipelineData[Data]]) := pc
pushedEntry.registerMap.element(pipeline.data.RD.asInstanceOf[PipelineData[Data]]) := rd
pushedEntry.rdbUpdated := False
pushedEntry.cdbUpdated := False
pushedEntry.registerMap.element(pipeline.data.PC.asInstanceOf[PipelineData[Data]]) := issueStage
.output(pipeline.data.PC)
pushedEntry.registerMap.element(pipeline.data.RD.asInstanceOf[PipelineData[Data]]) := issueStage
.output(pipeline.data.RD)
pushedEntry.registerMap.element(
pipeline.data.RD_TYPE.asInstanceOf[PipelineData[Data]]
) := rdType
pipeline.service[LsuService].operationOfBundle(pushedEntry.registerMap) := lsuOperationType
) := issueStage.output(pipeline.data.RD_TYPE)
pipeline.service[LsuService].operationOfBundle(pushedEntry.registerMap) := pipeline
.service[LsuService]
.operationOutput(issueStage)
pipeline.service[LsuService].addressValidOfBundle(pushedEntry.registerMap) := False
newestIndex.value
}

override def onCdbMessage(cdbMessage: CdbMessage): Unit = {
robEntries(cdbMessage.robIndex).hasValue := True
robEntries(cdbMessage.robIndex).registerMap
.element(pipeline.data.RD_DATA.asInstanceOf[PipelineData[Data]]) := cdbMessage.writeValue
val rs1 = Flow(UInt(5 bits))
val rs2 = Flow(UInt(5 bits))

rs1.valid := issueStage.output(pipeline.data.RS1_TYPE) === RegisterType.GPR
rs1.payload := issueStage.output(pipeline.data.RS1)

rs2.valid := issueStage.output(pipeline.data.RS2_TYPE) === RegisterType.GPR
rs2.payload := issueStage.output(pipeline.data.RS2)

(newestIndex.value, bookkeeping(rs1, rs2))
}

def findRegisterValue(regId: UInt): (Bool, Flow[CdbMessage]) = {
val found = Bool()
val target = Flow(CdbMessage(metaRegisters, indexBits))
target.valid := False
target.payload.robIndex := 0
target.payload.writeValue := 0
found := False
private def bookkeeping(rs1Id: Flow[UInt], rs2Id: Flow[UInt]): EntryMetadata = {
val meta = EntryMetadata(indexBits)
meta.rs1Data.payload.assignDontCare()
meta.rs2Data.payload.assignDontCare()

// loop through valid values and return the freshest if present
for (relative <- 0 until capacity) {
val absolute = UInt(indexBits)
absolute := absoluteIndexForRelative(relative).resized
val entry = robEntries(absolute)
meta.rs1Data.valid := rs1Id.valid
meta.rs2Data.valid := rs2Id.valid

// last condition: prevent dependencies on x0
def rsUpdate(rsId: Flow[UInt], index: UInt, entry: RobEntry, rsMeta: RsData): Unit = {
when(
isValidAbsoluteIndex(absolute)
&& entry.registerMap.element(pipeline.data.RD.asInstanceOf[PipelineData[Data]]) === regId
&& regId =/= 0
rsId.valid
&& rsId.payload =/= 0
&& entry.registerMap.element(
pipeline.data.RD.asInstanceOf[PipelineData[Data]]
) === rsId.payload
&& entry.registerMap.element(
pipeline.data.RD_TYPE.asInstanceOf[PipelineData[Data]]
) === RegisterType.GPR
) {
found := True
target.valid := entry.hasValue
target.robIndex := absolute
target.writeValue := entry.registerMap.elementAs[UInt](
rsMeta.updatingInstructionFound := True
rsMeta.updatingInstructionFinished := (entry.cdbUpdated || entry.rdbUpdated)
rsMeta.updatingInstructionIndex := index
rsMeta.updatingInstructionValue := entry.registerMap.elementAs[UInt](
pipeline.data.RD_DATA.asInstanceOf[PipelineData[Data]]
)
}
}
(found, target)

// loop through valid values and return the freshest if present
for (relative <- 0 until capacity) {
val absolute = absoluteIndexForRelative(relative).resized
val entry = robEntries(absolute)

when(isValidAbsoluteIndex(absolute)) {
rsUpdate(rs1Id, absolute, entry, meta.rs1Data.payload)
rsUpdate(rs2Id, absolute, entry, meta.rs2Data.payload)
}
}
meta
}

override def onCdbMessage(cdbMessage: CdbMessage): Unit = {
robEntries(cdbMessage.robIndex).cdbUpdated := True
robEntries(cdbMessage.robIndex).registerMap
.element(pipeline.data.RD_DATA.asInstanceOf[PipelineData[Data]]) := cdbMessage.writeValue
}

def hasPendingStoreForEntry(robIndex: UInt, address: UInt): Bool = {
Expand Down Expand Up @@ -198,7 +232,7 @@ class ReorderBuffer(
.jumpOfBundle(robEntries(rdbMessage.robIndex).registerMap) := True
}

robEntries(rdbMessage.robIndex).ready := True
robEntries(rdbMessage.robIndex).rdbUpdated := True
}

def build(): Unit = {
Expand All @@ -220,16 +254,22 @@ class ReorderBuffer(
ret.connectOutputDefaults()
ret.connectLastValues()

when(!isEmpty && oldestEntry.ready) {
when(
!isEmpty && oldestEntry.rdbUpdated && (oldestEntry.cdbUpdated || (!oldestEntry.registerMap
.elementAs[Bool](pipeline.data.RD_DATA_VALID.asInstanceOf[PipelineData[Data]]) &&
pipeline
.service[LsuService]
.operationOfBundle(oldestEntry.registerMap) =/= LsuOperationType.LOAD))
) {
ret.arbitration.isValid := True
}

when(!isEmpty && oldestEntry.ready && ret.arbitration.isDone) {
// removing the oldest entry
updatedOldestIndex := oldestIndex.valueNext
oldestIndex.increment()
willRetire := True
isFullNext := False
when(ret.arbitration.isDone) {
// removing the oldest entry
updatedOldestIndex := oldestIndex.valueNext
oldestIndex.increment()
willRetire := True
isFullNext := False
}
}

when(pushInCycle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,7 @@ class ReservationStation(
def execute(): Unit = {
val issueStage = pipeline.issuePipeline.stages.last

val robIndex = UInt()
robIndex := rob.pushEntry(
issueStage.output(pipeline.data.RD),
issueStage.output(pipeline.data.RD_TYPE),
pipeline.service[LsuService].operationOutput(issueStage),
issueStage.output(pipeline.data.PC)
)
val (robIndex, entryMeta) = rob.pushEntry()

robEntryIndex := robIndex

Expand All @@ -227,34 +221,29 @@ class ReservationStation(

def dependencySetup(
metaRs: RegisterSource,
reg: PipelineData[UInt],
regData: PipelineData[UInt],
regType: PipelineData[SpinalEnumCraft[RegisterType.type]]
rsData: Flow[RsData],
regData: PipelineData[UInt]
): Unit = {
val rsUsed = issueStage.output(regType) === RegisterType.GPR

when(rsUsed) {
val rsReg = issueStage.output(reg)
val (rsInRob, rsValue) = rob.findRegisterValue(rsReg)

when(rsInRob) {
when(rsValue.valid) {
regs.setReg(regData, rsValue.payload.writeValue)
when(rsData.valid) {
when(rsData.payload.updatingInstructionFound) {
when(rsData.payload.updatingInstructionFinished) {
regs.setReg(regData, rsData.payload.updatingInstructionValue)
} otherwise {
metaRs.priorInstructionNext.push(rsValue.payload.robIndex)
metaRs.priorInstructionNext.push(rsData.payload.updatingInstructionIndex)
}
} otherwise {
regs.setReg(regData, issueStage.output(regData))
}

when((rsInRob && !rsValue.valid)) {
when(
rsData.payload.updatingInstructionFound && !rsData.payload.updatingInstructionFinished
) {
stateNext := State.WAITING_FOR_ARGS
}
}
}

dependencySetup(meta.rs1, pipeline.data.RS1, pipeline.data.RS1_DATA, pipeline.data.RS1_TYPE)
dependencySetup(meta.rs2, pipeline.data.RS2, pipeline.data.RS2_DATA, pipeline.data.RS2_TYPE)
dependencySetup(meta.rs1, entryMeta.rs1Data, pipeline.data.RS1_DATA)
dependencySetup(meta.rs2, entryMeta.rs2Data, pipeline.data.RS2_DATA)
}

override def pipelineReset(): Unit = {
Expand Down

0 comments on commit 819eb9a

Please sign in to comment.