aboutsummaryrefslogtreecommitdiff
path: root/VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala
diff options
context:
space:
mode:
Diffstat (limited to 'VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala')
-rw-r--r--VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala136
1 files changed, 136 insertions, 0 deletions
diff --git a/VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala b/VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala
new file mode 100644
index 0000000..a2c0930
--- /dev/null
+++ b/VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala
@@ -0,0 +1,136 @@
+package vexriscv.plugin
+
+import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv}
+import spinal.core._
+import spinal.lib._
+import spinal.lib.bus.bmb.WeakConnector
+import spinal.lib.bus.misc.{AddressMapping, DefaultMapping}
+import vexriscv.Riscv.IMM
+
+
+object VfuPlugin{
+ val ROUND_MODE_WIDTH = 3
+
+}
+
+
+case class VfuParameter() //Empty for now
+
+case class VfuCmd( p : VfuParameter ) extends Bundle{
+ val instruction = Bits(32 bits)
+ val inputs = Vec(Bits(32 bits), 2)
+ val rounding = Bits(VfuPlugin.ROUND_MODE_WIDTH bits)
+}
+
+case class VfuRsp(p : VfuParameter) extends Bundle{
+ val output = Bits(32 bits)
+}
+
+case class VfuBus(p : VfuParameter) extends Bundle with IMasterSlave{
+ val cmd = Stream(VfuCmd(p))
+ val rsp = Stream(VfuRsp(p))
+
+ def <<(m : VfuBus) : Unit = {
+ val s = this
+ s.cmd << m.cmd
+ m.rsp << s.rsp
+ }
+
+ override def asMaster(): Unit = {
+ master(cmd)
+ slave(rsp)
+ }
+}
+
+
+
+class VfuPlugin(val stageCount : Int,
+ val allowZeroLatency : Boolean,
+ val parameter : VfuParameter) extends Plugin[VexRiscv]{
+ def p = parameter
+
+ var bus : VfuBus = null
+
+ lazy val forkStage = pipeline.execute
+ lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount))
+
+
+ object VFU_ENABLE extends Stageable(Bool())
+ object VFU_IN_FLIGHT extends Stageable(Bool())
+
+ override def setup(pipeline: VexRiscv): Unit = {
+ import pipeline._
+ import pipeline.config._
+
+ bus = master(VfuBus(p))
+
+ val decoderService = pipeline.service(classOf[DecoderService])
+ decoderService.addDefault(VFU_ENABLE, False)
+
+ decoderService.add(
+ key = M"-------------------------0001011",
+ values = List(
+ VFU_ENABLE -> True,
+ REGFILE_WRITE_VALID -> True, //If you want to write something back into the integer register file
+ BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0),
+ BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1),
+ RS1_USE -> True,
+ RS2_USE -> True
+ )
+ )
+ }
+
+ override def build(pipeline: VexRiscv): Unit = {
+ import pipeline._
+ import pipeline.config._
+
+ val csr = pipeline plug new Area{
+ val factory = pipeline.service(classOf[CsrInterface])
+ val rounding = Reg(Bits(VfuPlugin.ROUND_MODE_WIDTH bits))
+
+ factory.rw(csrAddress = 0xBC0, bitOffset = 0, that = rounding)
+ }
+
+
+ forkStage plug new Area{
+ import forkStage._
+ val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR
+ val scheduleWish = arbitration.isValid && input(VFU_ENABLE)
+ val schedule = scheduleWish && !hazard
+ arbitration.haltItself setWhen(scheduleWish && hazard)
+
+ val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready)
+ val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuck)
+ insert(VFU_IN_FLIGHT) := schedule || hold || fired
+
+ bus.cmd.valid := (schedule || hold) && !fired
+ arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready)
+
+ bus.cmd.instruction := input(INSTRUCTION)
+ bus.cmd.inputs(0) := input(RS1)
+ bus.cmd.inputs(1) := input(RS2)
+ bus.cmd.rounding := csr.rounding
+ }
+
+ joinStage plug new Area{
+ import joinStage._
+
+ val rsp = if(forkStage != joinStage && allowZeroLatency) {
+ bus.rsp.s2mPipe()
+ } else {
+ bus.rsp.combStage()
+ }
+
+ rsp.ready := False
+ when(input(VFU_IN_FLIGHT) && input(REGFILE_WRITE_VALID)){
+ arbitration.haltItself setWhen(!bus.rsp.valid)
+ rsp.ready := !arbitration.isStuckByOthers
+ output(REGFILE_WRITE_DATA) := bus.rsp.output
+ }
+ }
+
+ pipeline.stages.drop(1).foreach(s => s.output(VFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck))
+ addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(VFU_IN_FLIGHT).init(False)))
+ }
+}
+