commit 130ed6345c58fc5580b0588ca28ce438c49caeeb Author: Dolu1990 Date: Wed Mar 8 22:17:48 2017 +0100 boot diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..938d762 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +*.class +*.log +*.bak + +# sbt specific +.cache/ +.history/ +.lib/ +dist/* +target +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet + +.idea +out + +# Eclipse +bin/ +.classpath +.project +.settings +.cache-main + +#User +/*.vhd +/*.v +*.cf +*.json +*.vcd +!tester/src/test/resources/*.vhd + diff --git a/README.md b/README.md new file mode 100644 index 0000000..6d3f665 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +WIP \ No newline at end of file diff --git a/backup b/backup new file mode 100644 index 0000000..45265b7 --- /dev/null +++ b/backup @@ -0,0 +1,54 @@ +class PcManagerSimple(resetVector : BigInt,pcWidth : Int,fastFetchCmdPcCalculation : Boolean) extends Plugin[SpinalRiscv] with PcManagerService{ + import StandardStageables._ + + //FetchService interface + case class JumpInfo(pc: UInt, cond: Bool, stage: Stage) + val jumpInfos = ArrayBuffer[JumpInfo]() + override def jumpTo(pc: UInt, cond: Bool, stage: Stage): Unit = jumpInfos += JumpInfo(pc,cond,stage) + + override def build(pipeline: SpinalRiscv): Unit = { + import pipeline.prefetch + + prefetch.plug(new Area { + import prefetch._ + + //PC calculation without Jump + val pcReg = Reg(UInt(pcWidth bit)) init(resetVector) + val inc = RegInit(False) + val pc = if(fastFetchCmdPcCalculation){ + val pcPlus4 = pcReg + 4 + pcPlus4.addAttribute("keep") + Mux(inc,pcPlus4,pcReg) + }else{ + pcReg + (inc ? U(4) | U(0)) + } + + //Stage always valid + arbitration.isValid := True + + //FetchService hardware implementation + val jumpInfoSorted = jumpInfos.sortWith((a,b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) + val jumpRequestValids = jumpInfoSorted.map(_.cond) + val jumpRequestPcs = jumpInfoSorted.map(_.pc) + + val pcLoad = Flow(pcReg) + pcLoad.valid := jumpInfos.foldLeft(False)(_ || _.cond) + pcLoad.payload := MuxOH(jumpRequestValids,jumpRequestPcs) + + //Register managments + when(pcLoad.valid){ + pc := pcLoad.payload + inc := False + pcReg := pc + } + + when(arbitration.isFiring){ + inc := True + pcReg := pc + } + + //Pipeline insertions + insert(PC) := pc + }) + } +} \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..fcdd64f --- /dev/null +++ b/build.sbt @@ -0,0 +1,12 @@ +name := "SpinalBaseProject" + +version := "1.0" + +scalaVersion := "2.11.6" + +EclipseKeys.withSource := true + +libraryDependencies ++= Seq( + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "latest.release", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "latest.release" +) \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..ef6ceea --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,2 @@ +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0") + diff --git a/src/main/scala/SpinalRiscv/Pipeline.scala b/src/main/scala/SpinalRiscv/Pipeline.scala new file mode 100644 index 0000000..2ee8780 --- /dev/null +++ b/src/main/scala/SpinalRiscv/Pipeline.scala @@ -0,0 +1,108 @@ +package SpinalRiscv + +import spinal.core._ + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer + + +trait Pipeline { + type T <: Pipeline + val plugins = ArrayBuffer[Plugin[T]]() + var stages = ArrayBuffer[Stage]() + val services = ArrayBuffer[Any]() + + def indexOf(stage : Stage) = stages.indexOf(stage) + + def service[T](clazz : Class[T]) = { + val filtered = services.filter(_.getClass == clazz) + assert(filtered.length == 1) + filtered.head.asInstanceOf[T] + } + + def build(): Unit ={ + //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) + if(stageId != insertStageId) lastInputStageId = Math.min(lastInputStageId,stageId) + lastOutputStageId = Math.max(lastOutputStageId,stageId) + } + + def setInsertStageId(stageId : Int) = insertStageId = stageId + } + + val inputOutputKeys = mutable.HashMap[Stageable[Data],KeyInfo]() + for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){ + stage.inserts.keysIterator.foreach(signal => inputOutputKeys.getOrElseUpdate(signal,new KeyInfo).setInsertStageId(stageIndex)) + } + + 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) { + if (stageIndex == info.insertStageId) { + outputDefault := stage.inserts(key) + } else { + outputDefault := stage.input(key) + } + } + } + + //Interconnect outputs -> inputs + for(stageIndex <- info.insertStageId + 1 to info.lastInputStageId) { + val stageBefore = stages(stageIndex - 1) + val stage = stages(stageIndex) + stage.input(key) + val inputDefault = stage.inputsDefault.getOrElse(key, null) + if (inputDefault != null) { + inputDefault := RegNextWhen(stageBefore.output(key),!stageBefore.arbitration.isStuck) //!stage.input.valid || stage.input.ready + } + } + + //Arbitration + for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){ + stage.arbitration.isStuck := stages.takeRight(stages.length - stageIndex).map(_.arbitration.haltIt).reduce(_ || _) + 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.isStuck := stages.takeRight(stages.length-stageIndex).map(_.arbitration.haltIt).reduce(_ || _) + when(!stageBefore.arbitration.isStuck) { + stage.arbitration.isValid := stage.arbitration.isValid && !stage.arbitration.removeIt + } + when(stage.arbitration.removeIt){ + stage.arbitration.isValid := False + } + } + } + } + + + Component.current.addPrePopTask(() => build()) +} diff --git a/src/main/scala/SpinalRiscv/Plugin.scala b/src/main/scala/SpinalRiscv/Plugin.scala new file mode 100644 index 0000000..9eb515b --- /dev/null +++ b/src/main/scala/SpinalRiscv/Plugin.scala @@ -0,0 +1,17 @@ +package SpinalRiscv + +import spinal.core.Area + +/** + * Created by PIC32F_USER on 03/03/2017. + */ +trait Plugin[T <: Pipeline] { + def getName() = this.getClass.getSimpleName.replace("$","") + + def setup(pipeline: T) : Unit = {} + def build(pipeline: T) : Unit + + implicit class implicits(stage: Stage){ + def plug(area : Area) = area.setCompositeName(stage,getName()).reflectNames() + } +} diff --git a/src/main/scala/SpinalRiscv/Stage.scala b/src/main/scala/SpinalRiscv/Stage.scala new file mode 100644 index 0000000..a43d26f --- /dev/null +++ b/src/main/scala/SpinalRiscv/Stage.scala @@ -0,0 +1,73 @@ +package SpinalRiscv + +import spinal.core._ +import spinal.lib._ + +import scala.collection.mutable + + +class Stageable[T <: Data](dataType : T) extends HardType[T](dataType) with Nameable{ + setWeakName(this.getClass.getSimpleName.replace("$","")) +} + +class Stage() extends Area{ + def input[T <: Data](key : Stageable[T]) : T = { + inputs.getOrElseUpdate(key.asInstanceOf[Stageable[Data]],{ + val input,inputDefault = key() + inputsDefault(key.asInstanceOf[Stageable[Data]]) = inputDefault + input := inputDefault + input.setPartialName(this,"input_" + key.getName()) + }).asInstanceOf[T] + } + + def output[T <: Data](key : Stageable[T]) : T = { + outputs.getOrElseUpdate(key.asInstanceOf[Stageable[Data]],{ + val output,outputDefault = key() + outputsDefault(key.asInstanceOf[Stageable[Data]]) = outputDefault + output := outputDefault + output.setPartialName(this,"output_" + key.getName()) + }).asInstanceOf[T] + } + + def insert[T <: Data](key : Stageable[T]) : T = inserts.getOrElseUpdate(key.asInstanceOf[Stageable[Data]],key()).asInstanceOf[T].setPartialName(this,key.getName()) + def apply[T <: Data](key : Stageable[T]) : T = ??? + + + val arbitration = new Bundle{ + val haltIt = False + val removeIt = False + val isValid = RegInit(False) + val isStuck = Bool + val isFiring = Bool + } + + + val inputs = mutable.HashMap[Stageable[Data],Data]() + val outputs = mutable.HashMap[Stageable[Data],Data]() + val signals = mutable.HashMap[Stageable[Data],Data]() + val inserts = mutable.HashMap[Stageable[Data],Data]() + + val inputsDefault = mutable.HashMap[Stageable[Data],Data]() + val outputsDefault = mutable.HashMap[Stageable[Data],Data]() +} + + +//object StageMain{ +// +// object OpEnum extends SpinalEnum{ +// val AND,OR = newElement() +// } +// object OP extends Stageable(OpEnum()) +// object SRC1 extends Stageable(Bits(32 bits)) +// object SRC2 extends Stageable(Bits(32 bits)) +// object RESULT extends Stageable(Bits(32 bits)) +// def main(args: Array[String]) { +// val E = List.fill(2)(new Stage(9)) +// val E0 = E(0) +// import E0._ +// output(RESULT) := E(0).input(OP).mux( +// OpEnum.AND -> (E(0).input(SRC1) & E(0).input(SRC2)), +// OpEnum.OR -> (E(0).input(SRC1) | E(0).input(SRC2)) +// ) +// } +//} diff --git a/src/main/scala/SpinalRiscv/TopLevel.scala b/src/main/scala/SpinalRiscv/TopLevel.scala new file mode 100644 index 0000000..20ec14c --- /dev/null +++ b/src/main/scala/SpinalRiscv/TopLevel.scala @@ -0,0 +1,170 @@ +/* + * SpinalHDL + * Copyright (c) Dolu, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ + +package SpinalRiscv + +import spinal.core._ +import spinal.lib._ + +import scala.collection.mutable.ArrayBuffer + +object StandardStageables{ + object Execute0Bypass extends Stageable(Bool) + object Execute1Bypass extends Stageable(Bool) + object SRC1 extends Stageable(UInt(32 bits)) + object SRC2 extends Stageable(UInt(32 bits)) + object RESULT extends Stageable(UInt(32 bits)) + object PC extends Stageable(UInt()) + object INST extends Stageable(Bits(32 bits)) +} + +class SpinalRiscv(pluginConfig : Seq[Plugin[SpinalRiscv]]) extends Component with Pipeline{ + type T = SpinalRiscv + + stages ++= List.fill(6)(new Stage()) + val prefetch :: fetch :: decode :: execute :: memory :: writeBack :: Nil = stages.toList + plugins ++= pluginConfig +} + + +trait DecoderService{ + def add(key : MaskedLiteral,values : Seq[(Stageable[_],BaseType)]) + def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_],BaseType)])]) +} + +class DecoderSimplePlugin extends Plugin[SpinalRiscv] with DecoderService { + override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_], BaseType)])]): Unit = encoding.foreach(e => this.add(e._1,e._2)) + override def add(key: MaskedLiteral, values: Seq[(Stageable[_], BaseType)]): Unit = { + ??? + } + + override def build(pipeline: SpinalRiscv): Unit = ??? +} + +trait PcManagerService{ + def jumpTo(pc : UInt,cond : Bool,stage : Stage) : Unit +} + +class PcManagerSimplePlugin(resetVector : BigInt,pcWidth : Int,fastFetchCmdPcCalculation : Boolean) extends Plugin[SpinalRiscv] with PcManagerService{ + import StandardStageables._ + + //FetchService interface + case class JumpInfo(pc: UInt, cond: Bool, stage: Stage) + val jumpInfos = ArrayBuffer[JumpInfo]() + override def jumpTo(pc: UInt, cond: Bool, stage: Stage): Unit = jumpInfos += JumpInfo(pc,cond,stage) + + + override def build(pipeline: SpinalRiscv): Unit = { + import pipeline.prefetch + + prefetch.plug(new Area { + import prefetch._ + //Stage always valid + arbitration.isValid := True + + //PC calculation without Jump + val pc = Reg(UInt(pcWidth bits)) init(resetVector) + when(arbitration.isValid && !arbitration.isStuck){ + val pcPlus4 = pc + 4 + if(fastFetchCmdPcCalculation) pcPlus4.addAttribute("keep") //Disallow to use the carry in as enable + pc := pcPlus4 + } + + //FetchService hardware implementation + val jump = if(jumpInfos.length != 0) { + val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) + val valids = sortedByStage.map(_.cond) + val pcs = sortedByStage.map(_.pc) + + val pcLoad = Flow(UInt(pcWidth bits)) + pcLoad.valid := jumpInfos.foldLeft(False)(_ || _.cond) + pcLoad.payload := MuxOH(valids, pcs) + + //Register managments + when(pcLoad.valid) { + pc := pcLoad.payload + arbitration.removeIt := True + } + } + + //Pipeline insertions + insert(PC) := pc + }) + } +} + +case class IBusSimpleCmd() extends Bundle{ + val pc = UInt(32 bits) +} + +case class IBusSimpleRsp() extends Bundle{ + val inst = Bits(32 bits) +} + +class IBusSimplePlugin extends Plugin[SpinalRiscv]{ + import StandardStageables._ + var iCmd : Stream[IBusSimpleCmd] = null + var iRsp : IBusSimpleRsp = null + + override def build(pipeline: SpinalRiscv): Unit = { + import pipeline._ + + iCmd = master(Stream(IBusSimpleCmd())) + iCmd.valid := prefetch.arbitration.isFiring + iCmd.pc := prefetch.output(PC) + + iRsp = IBusSimpleRsp() + fetch.insert(INST) := iRsp.inst + } +} + +class IntAluPlugin extends Plugin[SpinalRiscv]{ + import StandardStageables._ + + + override def setup(pipeline: SpinalRiscv): Unit = { + pipeline.service(classOf[DecoderService]).add(List( + M"0101010---" -> + List( + Execute0Bypass -> True, + Execute1Bypass -> True + ) + ) + ) + } + + override def build(pipeline: SpinalRiscv): Unit = { + import pipeline._ + + + } + + +} + + +object MyTopLevel { + def main(args: Array[String]) { + SpinalVhdl(new SpinalRiscv(List( +// new IntAluPlugin + new PcManagerSimplePlugin(0,32,true), + new IBusSimplePlugin + ))) + } +} +