》出于监控的需求
从校园毕业从事逻辑设计也有三年时光了,对于逻辑设计,最大的感受就是在设计中DFX的重要性。无论你自己的设计多么牛逼,仿真多么到位,全面的DFX仍旧是必不可少,尤其是跨部门多团队合作里,好的DFX能够在系统上线及运维上有极大的帮助。在一些系统设计里,我们往往会对模块的各路数据接口添加状态信息DFX以及一些辅助性能分析的工具。这里以Axiite4为例,我们以如下模块作为待监控模块:
![1.jpg](//file.elecfans.com/web2/M00/6F/3B/poYBAGNFFuOAbIccAAEXd9GejRg862.jpg)
这里我们假定对inPort端口添加一些监控信息,我们设计如下模块作为AxiLite4总线的一个通用监控模块(只是举例说明,非真实应用):
![1.jpg](//file.elecfans.com/web2/M00/6F/3B/poYBAGNFFvaAEONSAABncbQPuc0853.jpg)
这里我们定义了一个AxiLite4Mon的Component,监控aw,w,b,ar,r五路通路的状态。这里值得注意的是对于AxiLite4Mon而言,alite接口的所有信号都是输入。故其书写形式为in(AxiLite4(32,32))。也正因如此,当我们在BundleTest中去例化AxiLite4Mon时你会发现采用<>对alite接口进行连线时生成RTL时会报错:
![1.jpg](//file.elecfans.com/web2/M00/6F/D0/pYYBAGNFFw-AOK0dAAFWAbKNMNM415.jpg)
原因无他,对于AxiLite4Mon的aite接口而言,其全部为输入信号,而对于inPort接口而言,其既有输出信号又有输入信号,从而导致工具无法推断具体的连接关系。
对于SpinalHDL了解的小伙伴也许能够想到,这里把AxiLite4Mon定义扩展为Area而非Component:
case class AxiLite4Mon(alite:AxiLite4,state:Bits) extends Area{
state:=alite.aw.fire##alite.w.fire##alite.b.fire##alite.ar.fire##alite.r.fire
}
此时在BundleTest中例化就可以写成:
AxiLite4Mon(io.inPort,io.state)
诚然,这种方式从SpinalHDL的角度来讲更简洁,但对接口做一个好的DFX监控不是像这里的这么简单一行代码。而且尤其当合作中有人采用Verilog来作为开发语言时最终你生成的代码功能代码和这些DFX代码混合在一起给人看起来代码过长,难以阅读(当然我基本不直接阅读生成的RTL代码)。因此像这种总线接口的DFX代码,个人还是倾向于采用Component进行封装。
》assignAllByName
像上面的问题,如果你手动对alite接口展开赋值那我也不拦着,只能说没学好SpinalHDL。在SpinalHDL里这些复杂的接口都集成扩展于Bundle。但凡你打开过Bundle的代码实现,你就会发现这里面有一个assignAllByName的方法实现很符合我们的需求:
![1.jpg](//file.elecfans.com/web2/M00/6F/D0/pYYBAGNFFyWAVjrdAACUSqNglEM500.jpg)
我们在Bundle中声明的信号接口都存储于elements中,elements的定义形式为:ArrayBuffer[(String, Data)]。这里仅需要根据定义的信号名字找到对应的接口信号进行连接即可,这也是assignAllByName所做的事情,相信有点儿Scala基础上面的代码并不难理解。此时像上面的代码我们就可以轻松实现了:
![1.jpg](//file.elecfans.com/web2/M00/6F/3B/poYBAGNFFzqAcPg3AAEyNY8IEtA357.jpg)
这才是SpinalHDL的正确书写形式。
除了assignAllByName,Bundle中也定义了下面两种用于连线赋值的API:
![1.jpg](//file.elecfans.com/web2/M00/6F/D0/pYYBAGNFF1KAFbCJAACSFt2sIUA525.jpg)
assignSomeByName相比于assignAllByName,其允许that中的部分信号为null,而bundleAssign则可以让我们自定义连接赋值函数。
通过这些,相信能基本满足日常代码设计需求。
原作者:玉骐
|