aboutsummaryrefslogtreecommitdiff
path: root/VexRiscv/src/main/scala/vexriscv/Pipeline.scala
diff options
context:
space:
mode:
Diffstat (limited to 'VexRiscv/src/main/scala/vexriscv/Pipeline.scala')
-rw-r--r--VexRiscv/src/main/scala/vexriscv/Pipeline.scala162
1 files changed, 162 insertions, 0 deletions
diff --git a/VexRiscv/src/main/scala/vexriscv/Pipeline.scala b/VexRiscv/src/main/scala/vexriscv/Pipeline.scala
new file mode 100644
index 0000000..e9d93c2
--- /dev/null
+++ b/VexRiscv/src/main/scala/vexriscv/Pipeline.scala
@@ -0,0 +1,162 @@
+package vexriscv
+
+import vexriscv.plugin._
+import spinal.core._
+import spinal.lib._
+
+import scala.collection.mutable
+import scala.collection.mutable.ArrayBuffer
+
+trait PipelineThing[T]
+
+trait Pipeline {
+ type T <: Pipeline
+ val plugins = ArrayBuffer[Plugin[T]]()
+ var stages = ArrayBuffer[Stage]()
+ var unremovableStages = mutable.Set[Stage]()
+ val things = mutable.LinkedHashMap[PipelineThing[_], Any]()
+// val services = ArrayBuffer[Any]()
+
+ def stageBefore(stage : Stage) = stages(indexOf(stage)-1)
+
+ def indexOf(stage : Stage) = stages.indexOf(stage)
+
+ def service[T](clazz : Class[T]) = {
+ val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass))
+ assert(filtered.length == 1, s"??? ${clazz.getName}")
+ filtered.head.asInstanceOf[T]
+ }
+
+ def serviceExist[T](clazz : Class[T]) = {
+ val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass))
+ filtered.length != 0
+ }
+
+ def serviceElse[T](clazz : Class[T], default : => T) : T = {
+ if(!serviceExist(clazz)) return default
+ val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass))
+ assert(filtered.length == 1)
+ filtered.head.asInstanceOf[T]
+ }
+
+ def update[T](that : PipelineThing[T], value : T) : Unit = things(that) = value
+ def apply[T](that : PipelineThing[T]) : T = things(that).asInstanceOf[T]
+
+ def build(): Unit ={
+ plugins.foreach(_.pipeline = this.asInstanceOf[T])
+ plugins.foreach(_.setup(this.asInstanceOf[T]))
+
+ plugins.foreach{ p =>
+ p.parentScope = Component.current.dslBody //Put the given plugin as a child of the current component
+ p.reflectNames()
+ }
+
+ //Build plugins
+ plugins.foreach(_.build(this.asInstanceOf[T]))
+
+
+
+ //Interconnect stages
+ class KeyInfo{
+ var insertStageId = Int.MaxValue
+ var lastInputStageId = Int.MinValue
+ var lastOutputStageId = Int.MinValue
+
+ def addInputStageIndex(stageId : Int): Unit = {
+ require(stageId >= insertStageId)
+ lastInputStageId = Math.max(lastInputStageId,stageId)
+ lastOutputStageId = Math.max(lastOutputStageId,stageId-1)
+ }
+
+
+ def addOutputStageIndex(stageId : Int): Unit = {
+ require(stageId >= insertStageId)
+ lastInputStageId = Math.max(lastInputStageId,stageId)
+ lastOutputStageId = Math.max(lastOutputStageId,stageId)
+ }
+
+ def setInsertStageId(stageId : Int) = insertStageId = stageId
+ }
+
+ val inputOutputKeys = mutable.LinkedHashMap[Stageable[Data],KeyInfo]()
+ val insertedStageable = mutable.Set[Stageable[Data]]()
+ for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
+ stage.inserts.keysIterator.foreach(signal => inputOutputKeys.getOrElseUpdate(signal,new KeyInfo).setInsertStageId(stageIndex))
+ stage.inserts.keysIterator.foreach(insertedStageable += _)
+ }
+
+ val missingInserts = mutable.Set[Stageable[Data]]()
+ for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
+ stage.inputs.keysIterator.foreach(key => if(!insertedStageable.contains(key)) missingInserts += key)
+ stage.outputs.keysIterator.foreach(key => if(!insertedStageable.contains(key)) missingInserts += key)
+ }
+
+ if(missingInserts.nonEmpty){
+ throw new Exception("Missing inserts : " + missingInserts.map(_.getName()).mkString(", "))
+ }
+
+ for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
+ stage.inputs.keysIterator.foreach(key => inputOutputKeys.getOrElseUpdate(key,new KeyInfo).addInputStageIndex(stageIndex))
+ stage.outputs.keysIterator.foreach(key => inputOutputKeys.getOrElseUpdate(key,new KeyInfo).addOutputStageIndex(stageIndex))
+ }
+
+ for((key,info) <- inputOutputKeys) {
+ //Interconnect inputs -> outputs
+ for (stageIndex <- info.insertStageId to info.lastOutputStageId;
+ stage = stages(stageIndex)) {
+ stage.output(key)
+ val outputDefault = stage.outputsDefault.getOrElse(key, null)
+ if (outputDefault != null) {
+ outputDefault := stage.input(key)
+ }
+ }
+
+ //Interconnect outputs -> inputs
+ for (stageIndex <- info.insertStageId to info.lastInputStageId) {
+ val stage = stages(stageIndex)
+ stage.input(key)
+ val inputDefault = stage.inputsDefault.getOrElse(key, null)
+ if (inputDefault != null) {
+ if (stageIndex == info.insertStageId) {
+ inputDefault := stage.inserts(key)
+ } else {
+ val stageBefore = stages(stageIndex - 1)
+ inputDefault := RegNextWhen(stageBefore.output(key), stage.dontSample.getOrElse(key, Nil).foldLeft(!stage.arbitration.isStuck)(_ && !_)).setName(s"${stageBefore.getName()}_to_${stage.getName()}_${key.getName()}")
+ }
+ }
+ }
+ }
+
+ //Arbitration
+ for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)) {
+ stage.arbitration.isFlushed := stages.drop(stageIndex+1).map(_.arbitration.flushNext).orR || stages.drop(stageIndex).map(_.arbitration.flushIt).orR
+ if(!unremovableStages.contains(stage))
+ stage.arbitration.removeIt setWhen stage.arbitration.isFlushed
+ else
+ assert(stage.arbitration.removeIt === False,"removeIt should never be asserted on this stage")
+
+ }
+
+ for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
+ stage.arbitration.isStuckByOthers := stage.arbitration.haltByOther || stages.takeRight(stages.length - stageIndex - 1).map(s => s.arbitration.isStuck/* && !s.arbitration.removeIt*/).foldLeft(False)(_ || _)
+ stage.arbitration.isStuck := stage.arbitration.haltItself || stage.arbitration.isStuckByOthers
+ stage.arbitration.isMoving := !stage.arbitration.isStuck && !stage.arbitration.removeIt
+ stage.arbitration.isFiring := stage.arbitration.isValid && !stage.arbitration.isStuck && !stage.arbitration.removeIt
+ }
+
+ for(stageIndex <- 1 until stages.length){
+ val stageBefore = stages(stageIndex - 1)
+ val stage = stages(stageIndex)
+ stage.arbitration.isValid.setAsReg() init(False)
+ when(!stage.arbitration.isStuck || stage.arbitration.removeIt) {
+ stage.arbitration.isValid := False
+ }
+ when(!stageBefore.arbitration.isStuck && !stageBefore.arbitration.removeIt) {
+ stage.arbitration.isValid := stageBefore.arbitration.isValid
+ }
+ }
+ }
+
+
+ Component.current.addPrePopTask(() => build())
+}