纤程框架

警告

该框架设计目标不是用于一般 RTL 生成,而是针对大型系统设计管理和代码生成。它目前在 SaxonSoC 中用作顶级集成工具。

目前正在开发中。

纤程(Fiber)以乱序的方式运行硬件生成,有点类似于Makefile,您可以在其中定义规则和依赖关系,然后在运行make命令时解决这些依赖关系。这与Scala Future功能非常相似。

使用这个框架可能会使简单的事情复杂化,但为复杂的情况提供了一些强大的功能:

  • 您甚至可以在知道所有要求之前就定义事物,例如:在知道需要多少中断信号线之前实例化中断控制器

  • 抽象/懒惰化/部分化SoC架构定义,允许创建SoC模板以供进一步专门化

  • 以分散方式在多个代理之间自动进行需求协商,例如:内存总线的主设备和从设备之间

该框架主要由以下部分组成:

  • Handle[T],稍后可用于存储 T 类型的值。

  • handle.load 允许设置句柄的值(将启动等待它的所有任务)

  • handle.get,返回给定句柄的值。如果尚未加载该句柄,将阻止任务执行进入等待

  • Handle{ /*code*/ },它派生一个新任务来执行给定的代码。该代码的结果将被加载到句柄中

  • soon(handle),允许当前任务宣称它将加载 一个 handle 句柄(用于调度)

简单的示例

这是一个简单的例子:

import spinal.core.fiber._

// Create two empty Handles
val a, b = Handle[Int]

// Create a Handle which will be loaded asynchronously by the given body result
val calculator = Handle {
    a.get + b.get // .get will block until they are loaded
}

// Same as above
val printer = Handle {
    println(s"a + b = ${calculator.get}") // .get is blocking until the calculator body is done
}

// Synchronously load a and b, this will unblock a.get and b.get
a.load(3)
b.load(4)

它的运行步骤会是:

  • 创建a和b

  • 创建计算器任务分支,但在执行a.get时被阻塞

  • 创建打印任务分支,但在执行calculator.get时被阻塞

  • 加载a和b,这会重新调度计算器任务(因为它正在等待 a)

  • 计算器执行a+b求和操作,并将结果加载到其句柄,这将重新调度打印任务

  • 打印任务打印其结果

  • 完成所有任务

因此,该示例的要点是表明我们在某种程度上克服了顺序执行,因为a和b可以在计算器定义之后被加载。

Handle[T]

Handle[T]有点像scala的Future[T],它们允许在某个对象存在之前就谈及它,并等待它。

val x,y = Handle[Int]
val xPlus2 : Handle[Int] = x.produce(x.get + 2) //x.produce can be used to generate a new Handle when x is loaded
val xPlus3 : Handle[Int] = x.derivate(_ + 3)    //x.derivate is as x.produce, but also provide the x.get as argument of the lambda function
x.load(3) //x will now contain the value 3

soon(handle)

为了维护任务和句柄之间正确的依赖关系图,任务可以预先指明它将加载给定的句柄。在生成饥饿(starvation)/死锁的情况下非常有用,以便SpinalHDL准确报告问题所在。