Flow
规范
数据流接口是一个简单的有效/负载协议,这意味着从端无法终止总线。它可用于表示来自UART控制器的数据、写入片上存储器的请求等。
| 信号 | 类型 | 驱动 | 描述 | 何时忽略 | 
|---|---|---|---|---|
| valid | Bool | Master | 当为高时 => 接口上存在有效负载(payload) | |
| payload | T | Master | 传输任务内容 | valid为低 | 
函数
| 语法 | 描述 | 返回类型 | 延迟 | 
|---|---|---|---|
| Flow(type : Data) | 创建给定类型的流 | Flow[T] | |
| master/slave Flow(type : Data) | 创建给定类型的流 通过相应的输入/输出设置进行初始化 | Flow[T] | |
| x.m2sPipe() | Return a Flow driven by x 通过寄存器,切断valid/payload路径 | Flow[T] | 1 | 
| x.stage() | 等价于 x.m2sPipe() | Flow[T] | 1 | 
| x << y y >> x | 将 y 连接到 x | 0 | |
| x <-< y y >-> x | 通过 m2sPipe 将 y 连接到 x | 1 | |
| x.throwWhen(cond : Bool) | 返回连接到 x 的流 当 cond 为高时,放弃传输的事务 | Flow[T] | 0 | 
| x.toReg() | 返回一个寄存器,当valid为高时,该寄存器将加载  | T | |
| x.setIdle() | 将流量设置为闲置状态:  | ||
| x.push(newPayload: T) | 为流设置新的有效payload。  | 
代码示例
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
}
仿真支持
| 类 | 用法 | 
|---|---|
| FlowMonitor | 用于主端和从端,如果数据流传输数据,则调用带有负载的函数。 | 
| FlowDriver | Testbench中主端通过调用函数来应用值(如果可用)以驱动值。如果值可用,则函数必须返回。支持随机的延迟。 | 
| ScoreboardInOrder | 通常用于比较参考/dut数据 | 
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)
  }
}