You're reading an pre-release version of this documentation.
For the latest stable release version, please have a look at master.

纤程框架

警告

This framework is not expected to be used for general RTL generation and targets large system design management and code generation. It is currently used as toplevel integration tool in SaxonSoC and VexiiRiscv.

Currently in development.

Fiber is a framework to run the hardware elaboration in an out of order manner, a bit similarly to Makefile, where you can define rules and dependencies which will then be solved when you run a make command. It is very similar to the Scala Future feature.

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

  • You can define things before even knowing all their requirements, for example : instantiating an interruption controller, before knowing how many interrupt signal lines you need

  • Abstract/lazy/partial SoC architecture definition allowing the creation of SoC template for further specializations

  • Automatic requirement negotiation between multiple agents in a decentralized way, for example : between masters and slaves of a memory bus

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

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

  • handle.load, which allow to set the value of a handle (will reschedule all tasks waiting on it)

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

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

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

简单的示例

Here is a simple example :

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]

// x.produce can be used to generate a new Handle when x is loaded
val xPlus2 : Handle[Int] = x.produce(x.get + 2)

// x.derivate is as x.produce, but also provide the x.get as argument of the lambda function
val xPlus3 : Handle[Int] = x.derivate(_ + 3)

x.load(3) // x will now contain the value 3

soon(handle)

In order to maintain a proper graph of dependencies between tasks and Handle, a task can specify in advance that it will load a given handle. This is very useful in case of a generation starvation/deadlock for SpinalHDL to report accurately where is the issue.