ARM技术论坛
直播中

h1654155275.5916

7年用户 993经验值
私信 关注
[经验]

分享一个在SpinalHDL里apply的有趣用法

SpinalHDL和Chisel都是基于scala来实现的,而在SpinalHDL的example里,偶然看到一个apply的有趣用法。

“神奇”的逻辑,"奇葩"的写法

偶然看到一个例子,在SpinalHDL里的example关于UDP设计的代码里看到了这么一段代码:

初见这段代码,按照我的理解,flushRx所描述的是一段电路,然而我通篇代码看下来active信号的拉高也仅仅在其中的apply函数,而在代码的其他地方,倒是见到了不少flushRx()的调用,等等,调用电路单元flushRx难道是把电路一遍遍复制么,这也有点儿太不靠谱儿了,太奇葩了吧。

矛盾的指向——apply

在上面的那段代码里,active拉高仅出现在apply函数里,而从整体代码的设计意图来看,状态机里调用flushRx的初衷在于拉高active,而apply是scala中经常遇到的函数,那么这里是否采用了scala的语法功能来描述电路呢?

先看一段scala的普通代码:

执行结果如下:

这里首先声明了一个trait a 类型变量,并为该变量生命了两个applu方法,随后分别对变量进行调用aa(),aa(3),而从执行结果来看,在声明变量a时,打印了“hello”,而当我们调用aa()时,打印了world函数,而在我们调用aa(3)时,其打印了world 3。而apply的妙用也就在此:

用括号传递给变量(对象)一个或多个参数时,Scala 会把它转换成对 apply 方法的调用。

进一步逻辑解耦合

像本篇开始提到的那个例子,在状态机里调用flushRx(),相当于执行了拉高active操作。这里我们将与接口相关的时序操作均封装在flushRx中并将接口的赋值封装成函数的形式供其他人调用,从而将算法设计与接口时序分离。

这里看一个简单的例子:

代码本身意义不大,这里我们将对接口c的时序操作均放置在cSetCtrl中,并为其定义一个apply方法,在apply方法中将c拉高。而在逻辑处理里,当a或者b有一个为高电平时调用cSetCtrl。其生成的RTL代码如下:

也许有小伙伴看到第15行至18行代码或许感觉有些奇怪,这段代码会综合生成一个两输入LUT和一个寄存器锁存输出,相当于一个或门加一个寄存器输出。至于为什么就留给小伙伴们自己去思考了。

原作者: 玉骐

更多回帖

发帖
×
20
完善资料,
赚取积分