纤程框架
警告
该框架设计目标不是用于一般 RTL 生成,而是针对大型系统设计管理和代码生成。它目前在 SaxonSoC 中用作顶级集成工具。
Currently in development.
纤程(Fiber)以乱序的方式运行硬件生成,有点类似于Makefile,您可以在其中定义规则和依赖关系,然后在运行make命令时解决这些依赖关系。这与Scala Future功能非常相似。
使用这个框架可能会使简单的事情复杂化,但为复杂的情况提供了一些强大的功能:
您甚至可以在知道所有要求之前就定义事物,例如:在知道需要多少中断信号线之前实例化中断控制器
Abstract/lazy/partial SoC architecture definition allowing the creation of SoC template for further specializations
以分散方式在多个代理之间自动进行需求协商,例如:内存总线的主设备和从设备之间
该框架主要由以下部分组成:
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准确报告问题所在。