Spinal 仿真相关

toBoolean() 函数

waitUntil(cond), cond不能是函数的返回值的toBoolean

1
2
3
4
waitUntil(axi4.aw.fire.toBoolean) // Wrong
//Exception in thread "main" java.util.NoSuchElementException: next on empty iterator

waitUnitl(axi4.aw.valid.toBoolean && axi4.aw.ready.toBoolean) // Correct

亦或者说,由于fire的定义如下:

1
def fire: Bool = aw.valid & aw.ready

因此,不能对这一无括号的函数使用toBoolean函数。

软件的归软件,硬件的归硬件

在Testbench里,不能调用那些用于做硬件描述的函数,比如上面的 fire() 函数,这个函数的本质是一段硬件描述,只能出现在component里面。再比如对Bits,UInt类等等,索引它的某一位,这一段依旧是硬件描述,不能出现在component之外的地方,比如testbench中。

我们只能对已经定义好的变量,使用 toBoolean() 这样的函数将其代表的数值结果读取到软件域。这一点是它和Verilog这类HVL所完全不同的特点。

waitUnitl()

类似于sv中的 @(event) 等待某个事件的触发。

大部分时候并不需要使用到这个函数。通常使用的是

1
clockDomain.waitActiveEdgeWhere(cond :=> Boolean)

这个函数的语义:一直等待到cond成立,并在成立后的第一个active edge退出等待。

所有的wait函数,只能在thread中使用,不能再callback中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// right
fork {
dut.clockDomain.waitActiveEdge(3)
}

// right
fork {
waitUntil(row_addr == fft_config.row)
}

// wrong
dut.clockDomain.onSamplings {
dut.clockDomain.waitActiveEdge(3)
}

等待某个延时 #10ps

可以使用函数sleep()

1
sleep(10)

fork

尽量不在 clockDomain.onsampling {…} 内部使用 fork

使用toX()函数,将硬件域的数据转换至软件域

做定点数相关的转换时,注意数据类型本身的位宽问题。比如

1
2
val a_sint = 1 << bitCounts // when bit counts < 32 
val a_slong = 1L << bitCounts // when 32 <= bit counts < 64

性能问题

SpinalSim使用Verilator仿真,分为三个阶段:

  1. verilate阶段:将Verilog文件翻译为cpp
  2. compile阶段:将cpp文件加上testbench的cpp文件编译为可执行文件
  3. simulation阶段:运行可执行文件,开始仿真过程

对于大设计,会导致以上三个阶段的运行速度不合理的慢,因此需要合理优化

1 Verilate阶段

数量巨大的register,以及Mux的sel信号的位宽太大(两位数)以及其他的一些问题可能会导致这一阶段所消耗的时间太长。

生成的Verilog网表大小太大也会导致这一阶段时间冗长。

解决办法:1. 改变你的电路结构,规避上面的问题。这些问题往往意味设计的不合理性。2. 使用层次化的verilate流程,但是spinalsim对此没有支持,不好做。

2 Compile阶段

默认情况下,spinalsim使用g++进行多线程编译,因此这一阶段的运行时间与工作站的CPU核数密切相关。尽量在多核系统上跑。

对于可能需要重复多次编译同样设计的问题,安装ccache,并将环境变量OBJCACHE指向ccache。这样可以缓存上次编译过的cpp内容,有效避免重复编译。

3 simulation阶段

默认情况下,spinalsim不会使用verilator的多线程仿真。需要使用simulation flag: --threads <cpu_num> --trace-threads <cpu_num> 。具体设置如下:

1
SimConfig.addSimulationFlag("--threads 32 --trace-threads 32")

这样可以使仿真可执行文件以多线程的形式运行。