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)))
}
}
|