浅析Stream里的隐式转换

描述

Stream、Flow是在电路描述里经常用到的对象。较早时间有小伙伴问关于Stream里Fragment嵌套的问题,当时没有去深入的研究,最近重新review下这个问题,特来做个总结。

》开篇立问     

先来看看下面的这个场景:     

我们定义如下接口:

HDL语言

这里定义了一个Stream接口,如果我们想引用这里面的data,那么下面两种方法是等价的:    

 b.data    

 b.payload.data     

估计大多数人不深究的话基本上就采用第一种写法了,简单快捷(我也是)。

》深入一步

显而易见,这里b的定义是一个Stream接口。按照Stream接口的定义,其所包含的信号只有三个:

HDL语言

    从直观上来看,那么采用b.data这种形式显然是没有直接的方法或调用关系的。

    那么剩下的一种可能就是隐式转换了~

    Stream类在定义时其继承关系如下:

HDL语言

    这里的隐式转换存在于trait DataCarrier中:

HDL语言

    这里为DataCarrier定义了两个隐式转换函数toImplicit和toImplicit2。根据DataCarrier的数据类型,分别返回不同的对象:

如果数据类型是普通类型,则直接返回dataCarrier.payload

如果数据类型是Fragment类型,则会返回dataCarrier.fragment(同样,会调用到toImplicit函数)。

    如果你在toImplicit函数上打断点,执行上面的接口定义相关的代码,你就会发现会在toImplicit函数上暂停。也就意味着当我们调用b.data时会调用隐式转换函数toImplicit返回b.payload后再执行b.payload.data~

》乱花渐欲迷人眼

    理解了上面的代码,接下来的场景可能让你眼花缭乱了。

    先来看下面的这段代码:

HDL语言

    上面这段代码是不是觉得fire0和fire1是表达相同的功能?然而,生成的RTL代码会让你怀疑自己:

HDL语言

    再来看看一个Fragment嵌套的场景:

HDL语言

    一眼看去是不是觉得fire0和fire1的作用是一样的?

    然而,生成的RTL代码却是这样的:

HDL语言

    给你一分钟,你先品着。等品完之后再来看一个三层Fragment嵌套的代码:

HDL语言

    对应的RTL代码:

HDL语言

    看看对应的RTL代码是不是和你想的又不一样了?

    我们调用函数实现和我们自己实现大相径庭!

    先晕一会儿~

》拨云见雾

    是否又到了怀疑TM这SpinalHDL有Bug吧……

    我也思索了两三天~

    回归正题。接下来的内容好好品。这一切的一切均还是在于隐式转换。





审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分