Flow

规范

数据流接口是一个简单的有效/负载协议,这意味着从端无法终止总线。它可用于表示来自UART控制器的数据、写入片上存储器的请求等。

信号

类型

驱动

描述

何时忽略

valid

Bool

Master

当为高时 => 接口上存在有效负载(payload)

payload

T

Master

传输任务内容

valid为低

函数

语法

描述

返回类型

延迟

Flow(type : Data)

创建给定类型的流

Flow[T]

master/slave Flow(type : Data)

创建给定类型的流
通过相应的输入/输出设置进行初始化

Flow[T]

x.m2sPipe()

返回一个由 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为高时,该寄存器将加载 payload

T

x.setIdle()

将流量设置为闲置状态: valid 设为 False ,且不关心 payload

x.push(newPayload: T)

为流设置新的有效payload。 valid 被设为 True

代码示例

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