一 进度条
有时候我们在编写代码时希望能够查看运行时间,最简单的方法:
1 | def main(args: Array[String]) { |
但这个方法显然不是那么优雅。如果你在使用Scala的时候注意运行log,你会发下进度条更漂亮直观的。
1 | [Runtime] SpinalHDL v1.3.9 git head : a4cb4aadf0820174c1b48023bfcd3e9981de1d4a |
实现非常简单,首先得创建一个单例对象,单例对象一旦被实例化以后,startTime就会确定,不管Driver后面被调用多少次只会用到第一次被实例化的对象,startTime也不会改变。
1 | object Driver { |
再创建一个名叫“MyProgress”的用户接口, 每次执行“MyProgress”时调用单例对象Driver的executionTime打印当前时刻。
1 | object MyProgress { |
以下是一个基带仿真的case,每个关键节点调用MyProgress, 每步耗费的时间一目了然(单位s)。
1 | [Progress] at 0.000 : Coherence correlation start |
我也听到有人抱怨Rocket生成时间巨长,自己也搞不清楚时间到底耗费在什么地方,有可能是编译,也有可能是逻辑代码,也有可能是firrtl的解析生成。 现在你就可以用MyProgress来诊断瓶颈到底出在哪儿。
我自己用Scala编写算法参考平台时就遇到一个怪异的问题,按理说Scala是静态语言比Python更快,但是大致相同的算法,运行时间奇慢无比,后来就用MyProgress的进行二分法,找到问题的症结,我在打印文件时代用折叠的方式拼接字符串,foldLeft在功能上并没有问题,但是在字符串拼接是时间复杂度应该不是线性的(具体我没有深究,有兴趣的同学可以研究一下),导致很慢。
1 | fp.write(content.foldLeft("")(_+"\n"+_)) |
正确的方法是用mkString,速度回复正常,问题解决
1 | fp.write(content.mkString("("\n"))) |
最后这里的MyProgress正是SpinalHDL的SpinalProgress,有兴趣可以阅读其源码
二 开关
开关应用还是比较广泛,用过Matlab你就会比较熟悉
1 | grid on |
我举另外一个例子,算法在设计完功能和性能仿真以后要做定点性能仿真,定点的过程是需要修改代码,但是算法需要经常在全精度和定点之间切换调试,因为有时候性能不过,我们不清楚是逻辑的问题还是定点的问题。
当一个很大的project中定点地方可能非常多,我们不可能每次去来回修改定点代码,优雅的方式应该设置一个开关,而不是去修改代码。
首先设置一个开关单例对象
1 | protected object FixSwitch { |
然后设置2个开关动作来改变单例对象的状态。
1 | object FixOn{ |
定点源码中加入开关状态
1 | class FixData(...){ |
性能仿真
1 | object PerformanceRegression extends App{ |
有些人发现本质上这就是设置了一个全局可变的变量而已,
1 | var FixSwitchState: Boolean = true |
但是我们为什么不用全局变量, 而是单例对象,留给大家思考。
三 全局默认参数
同样也是定点上的一个例子,SpinalHDL提供定点工厂函数
1 | val wire5bit = wire10bit.fixTo( 6 downto 2, roundType = FLOOR, symmetric = true) |
但是一个Project可能有成百上千的定点处理, 每个定点都添加roundType, symmetric显然很累赘,当然你可以选择默认参数
1 | val wire5bit = wire10bit.fixTo( 6 downto 2) |
不同的团队,不同的项目,可能使用不同的Round方式还有对称方式,我们希望默认参数也是可配置的。SpinalHDL UInt/SInt定点源码:
1 | def fixTo(x: Range.Inclusive): IQ = |
默认的round,和 symmetric 参数通过getFixRound, getFixSym从全局获得。
一般一个工程种round 和 symmetric都是固定的,直接在SpinalConfig种设置即可。
1 | SpinalConfig(mode = Verilog, |
当然也可以在通过以下方式来刷新默认配置。
1 | FixPointConfig(ROUNDUP, true).flush() |
具体实现参见源码