0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

在SpinalHDL里在顶层一键优化Stream/Flow代码生成

Spinal FPGA 来源:Spinal FPGA 2023-12-14 09:05 次阅读

在SpinalHDL里在顶层一键优化代码中Stream/Flow代码生成的payload,fragment。

难看的代码

来看一段代码:

importspinal.core._
importspinal.lib._
caseclassDataPort() extendsBundle{
val data0=UInt(8bits)
val data1=UInt(8bits)
}

caseclassDemo() extendsComponent{
val io=newBundle{
val sink=slave(Stream(Fragment(DataPort())))
val source=master(Stream(Fragment(DataPort())))
}
noIoPrefix()
io.source<

很简单的功能,一个Stream接口Pipeline打拍。在生成RTL代码时会看到下面这种有点儿“不太舒服”的结构命名:

 wiresink_s2mPipe_payload_last;
wire[7:0] sink_s2mPipe_payload_fragment_data0;
wire[7:0] sink_s2mPipe_payload_fragment_data1;
regsink_rValidN;
regsink_rData_last;
reg[7:0] sink_rData_fragment_data0;
reg[7:0] sink_rData_fragment_data1;
wiresink_s2mPipe_m2sPipe_valid;
wiresink_s2mPipe_m2sPipe_ready;
wiresink_s2mPipe_m2sPipe_payload_last;
wire[7:0] sink_s2mPipe_m2sPipe_payload_fragment_data0;
wire[7:0] sink_s2mPipe_m2sPipe_payload_fragment_data1;

虽然说不怎么看生成的代码,但有时候别人看这里信号命名中间夹杂了一堆_payload_fragment_的信号还是略觉有点儿啰嗦。

尤其在用一些Axi/AxiLite总线时,当使用cloneOf时,会发现大量的信号名中间夹着一些paylaod字段,略觉不雅~

虽然这是Stream类的定义所导致,但如果去修改设计中的每一处总归还是比较麻烦的~

StreamRenameUtil

这里提供一个DIY的工具StreamRenameUtil,用于在设计的顶层一键让这种场景下的代码生成稍微优雅一些:

object StreamRenameUtil {
def apply(topLevel:Component) = {
Rename(topLevel,true)
}

def Rename(toplevel:Component,isCurrentComponentBoolean={
//current component process
if(!isCurrentComponent){
toplevel.dslBody.foreachStatements{
casebt:BaseType ifbt.parent.isInstanceOf[Stream[_]] => streamRename( bt.parent.asInstanceOf[Stream[_]])
casebt:BaseType ifbt.parent.isInstanceOf[Flow[_]] => flowRename( bt.parent.asInstanceOf[Flow[_]])
case_ =>
}
}else{
toplevel.dslBody.foreachStatements{
casebt:BaseType ifbt.parent.isInstanceOf[Stream[_]] => toplevel.addPrePopTask(()=>{streamRename( bt.parent.asInstanceOf[Stream[_]])})
casebt:BaseType ifbt.parent.isInstanceOf[Flow[_]] => toplevel.addPrePopTask(()=>{flowRename( bt.parent.asInstanceOf[Flow[_]])})
case_ =>
}
}

for(child<-toplevel.children){
      Rename(child,false)
    }
    true
  }

  def streamRename(streamPort:Stream[_])={
    streamPort.flatten.foreach((bt)=>{
val signalName=bt.getName()
if(signalName.contains("fragment")){
bt.setName(signalName.replace("_payload_fragment_","_"))
}else{
bt.setName(signalName.replace("_payload_","_"))
}
})
}

def flowRename(flowPort:Flow[_])={
flowPort.flatten.foreach((bt)=>{
val signalName=bt.getName()
if(signalName.contains("fragment")){
bt.setName(signalName.replace("_payload_fragment_","_"))
}else{
bt.setName(signalName.replace("_payload_","_"))
}
})
}

}

使用时仅需在顶层调用该方法,其会遍历设计中各模块的Stream、Flow类变量定义统一做修改:

caseclassDemo() extendsComponent{
val io=newBundle{
val sink=slave(Stream(Fragment(DataPort())))
val source=master(Stream(Fragment(DataPort())))
}
noIoPrefix()
io.source<

最终代码生成会优雅一些:

 wiresink_s2mPipe_valid;
regsink_s2mPipe_ready;
wiresink_s2mPipe_last;
wire[7:0] sink_s2mPipe_data0;
wire[7:0] sink_s2mPipe_data1;
regsink_rValidN;
regsink_rData_last;
reg[7:0] sink_rData_fragment_data0;
reg[7:0] sink_rData_fragment_data1;
wiresink_s2mPipe_m2sPipe_valid;
wiresink_s2mPipe_m2sPipe_ready;
wiresink_s2mPipe_m2sPipe_last;
wire[7:0] sink_s2mPipe_m2sPipe_data0;
wire[7:0] sink_s2mPipe_m2sPipe_data1;
regsink_s2mPipe_rValid;
regsink_s2mPipe_rData_last;
reg[7:0] sink_s2mPipe_rData_fragment_data0;
reg[7:0] sink_s2mPipe_rData_fragment_data1;
wirewhen_Stream_l369;

这里的sink_s2mPipe_rData_fragment_data0、sink_s2mPipe_rData_fragment_data1为在打拍时生命的Fragment类型,非Stream类型,如果你实在看不惯也可以依样画葫芦添加一个对Fragment类型的Rename~

审核编辑:彭菁

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

    关注

    8

    文章

    324

    浏览量

    47107
  • RTL
    RTL
    +关注

    关注

    1

    文章

    377

    浏览量

    59077
  • 代码
    +关注

    关注

    30

    文章

    4557

    浏览量

    66826
  • Stream
    +关注

    关注

    0

    文章

    20

    浏览量

    7923

原文标题:逼死强迫症—优化Stream/Flow代码生成

文章出处:【微信号:Spinal FPGA,微信公众号:Spinal FPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于Simulink的STM32工具箱外设一键代码该如何去生成

    Simulink中的STM32工具箱该怎样去安装呢?基于Simulink的STM32工具箱外设一键代码该如何去生成呢?
    发表于 11-18 06:00

    SpinalHDLswitch方法有何用处呢

    ,当我们需要根据tkeep信号来计算这拍有多少有效数据时这里的代码会是什么样子……这种代码写的手有点儿累(又没啥技术含量)……SpinalHDL
    发表于 06-22 14:25

    SpinalHDL实现优雅的添加待跟踪波形信号

    SpinalHDL,我们样可以实现优雅的添加待跟踪波形信号。姿势一在Verilog代码,我
    发表于 06-22 14:37

    个小的example来对比SpinalHDL Lib库的强大

    SpinalHDL的世界,它基于core提供了丰富的Lib库,包含了StreamFlow、Fragment、State Machine
    发表于 06-22 14:44

    SpinalHDL的设计中集成现有RTL设计(IP)的渠道——BlackBox

    我们SpinalHDL的设计中提供了集成现有RTL设计(IP)的渠道——BlackBox。BlackBox顾名思义,SpinalHDL将待集成的RTL设计当作个黑盒对待,不关心内部
    发表于 06-22 14:59

    介绍下不带数据的Stream—Event

    SpinalHDL中,Stream的抽象可谓诸多设计的核心,今天,同来看下不带数据的Stream——Event。》不带数据的
    发表于 06-27 16:07

    SpinalHDL中关于casez的使用

    SpinalHDL中的switch之前的文章中曾提到过SpinalHDL中switch的使用:通常情况下,switch对应着我们日常Verilog代码中的case。像下面的
    发表于 07-06 10:59

    以slaveFactory库为例看看如何一键生成整个设计的寄存器文档

    在做逻辑实现及后期调试维护维护文档中的寄存器列表和真实设计中的唯性往往是件令人“痛苦”的事情(个字,懒)。
    发表于 07-08 16:05

    使用SpinalHDL状态机生成的Verilog代码如何导入到quartus工程中去呢

    Spinal状态机使用SpinalHDL的状态机时,生成的Verilog代码状态机中状态的定义全都是由宏定义来实现的。
    发表于 07-08 16:13

    分享SpinalHDLapply的有趣用法

    个例子,SpinalHDL的example关于UDP设计的代码看到了这么
    发表于 07-19 15:08

    SpinalHDL中的代码组织结构如何实现Component参数化设计呢

    方式:some.where.else.theSignal.pull()在生成RTL代码时,会讲该信号声明个端口链接偷穿到我们这级的Component。Component参数化设计与
    发表于 07-21 14:20

    SpinalHDL将功能封装抽象成库函数供Stream总线接口快速调用

    io_dataIn 做拍总线握手延迟即可但现在需要在输出io_dataIn* 之前插入拍数据先输出。insertHeaderSpinalHDL
    发表于 07-21 14:31

    如何在SpinalHDL启动个仿真

    前言安装完成Verilator、GtkWave后,我们即可在IDEA通过SpinalHDL提供的仿真接口来对我们的设计进行仿真。Spinal
    发表于 07-26 16:59

    SpinalHDL有没有什么好的方式实现个接口位宽转换呢

    下午微信群有个小伙伴问了这么道题:将个为UInt(128 bits)的Stream接口连接到个UInt(32 bits)的Strea
    发表于 07-27 14:52

    SpinalHDL中常用的Stream总线

    在于SpinalHDL中,Stream/Flow这种类型映射生成Verilog
    发表于 01-31 16:38