Flow
Specification
The Flow interface is a simple valid/payload protocol which means the slave can’t halt the bus. It could be used to represent data coming from an UART controller, requests to write an on-chip memory, etc.
Signal |
Type |
Driver |
Description |
Don’t care when |
---|---|---|---|---|
valid |
Bool |
Master |
When high => payload present on the interface |
|
payload |
T |
Master |
Content of the transaction |
valid is low |
Functions
Syntax |
Description |
Return |
Latency |
---|---|---|---|
Flow(type : Data) |
Create a Flow of a given type |
Flow[T] |
|
master/slave Flow(type : Data) |
Create a Flow of a given type
Initialized with corresponding in/out setup
|
Flow[T] |
|
x.m2sPipe() |
Return a Flow driven by x
through a register stage that cut valid/payload paths
|
Flow[T] |
1 |
x.stage() |
Equivalent to x.m2sPipe() |
Flow[T] |
1 |
x << y
y >> x
|
Connect y to x |
0 |
|
x <-< y
y >-> x
|
Connect y to x through a m2sPipe |
1 |
|
x.throwWhen(cond : Bool) |
Return a Flow connected to x
When cond is high, transaction are dropped
|
Flow[T] |
0 |
x.toReg() |
Return a register which is loaded with |
T |
|
x.setIdle() |
Set the Flow in an Idle state: |
||
x.push(newPayload: T) |
Assign a new valid payload to the Flow. |
Code example
case class FlowExample() extends Component {
val io = new Bundle {
val request = slave(Flow(Bits(8 bit)))
val answer = master(Flow(Bits(8 bit)))
}
val storage = Reg(Bits(8 bit))
val fsm = new StateMachine {
io.answer.setIdle()
val idle: State = new State with EntryPoint {
whenIsActive {
when(io.request.valid) {
storage := io.request.payload
goto(sendEcho)
}
}
}
val sendEcho: State = new State {
whenIsActive {
io.answer.push(storage)
goto(idle)
}
}
}
// This StateMachine behaves equivalently to
// io.answer <-< io.request
}
Simulation Support
Class |
Usage |
---|---|
FlowMonitor |
Used for both master and slave sides, calls function with payload if Flow transmits data. |
FlowDriver |
Testbench master side, drives values by calling function to apply value (if available). Function must return if value was available. Supports random delays. |
ScoreboardInOrder |
Often used to compare reference/dut data |
package spinaldoc.libraries.flow
import spinal.core._
import spinal.core.sim._
import spinal.lib._
import spinal.lib.sim.{FlowDriver, FlowMonitor, ScoreboardInOrder}
import scala.language.postfixOps
case class SomeDUT() extends Component {
val io = new Bundle {
val input = slave(Flow(UInt(8 bit)))
val output = master(Flow(UInt(8 bit)))
}
io.output <-< io.input
}
object Example extends App {
val dut = SimConfig.withWave.compile(SomeDUT())
dut.doSim("simple test") { dut =>
SimTimeout(10000)
val scoreboard = ScoreboardInOrder[Int]()
// drive random data at random intervals, and add inputted data to scoreboard
FlowDriver(dut.io.input, dut.clockDomain) { payload =>
payload.randomize()
true
}
FlowMonitor(dut.io.input, dut.clockDomain) { payload =>
scoreboard.pushRef(payload.toInt)
}
// add all data coming out of DUT to scoreboard
FlowMonitor(dut.io.output, dut.clockDomain) { payload =>
scoreboard.pushDut(payload.toInt)
}
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitActiveEdgeWhere(scoreboard.matches == 100)
}
}