aboutsummaryrefslogtreecommitdiff
path: root/VexRiscv/src/main/scala/vexriscv/plugin/VfuPlugin.scala
blob: a2c09304fffb0c784b7079eb4c8133d0949c16af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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)))
  }
}