✎ 编 者 按
在SpinalHDL里在顶层一键优化代码中Stream/Flow代码生成的payload,fragment。
难看的代码
来看一段代码:
import spinal.core._
import spinal.lib._
case class DataPort() extends Bundle{
val data0=UInt(8 bits)
val data1=UInt(8 bits)
}
case class Demo() extends Component{
val io=new Bundle{
val sink=slave(Stream(Fragment(DataPort())))
val source=master(Stream(Fragment(DataPort())))
}
noIoPrefix()
io.source<<io.sink.pipelined(true,true)
}
很简单的功能,一个Stream接口的Pipeline打拍。在生成RTL代码时会看到下面这种有点儿“不太舒服”的结构命名:
wire sink_s2mPipe_payload_last;
wire [7:0] sink_s2mPipe_payload_fragment_data0;
wire [7:0] sink_s2mPipe_payload_fragment_data1;
reg sink_rValidN;
reg sink_rData_last;
reg [7:0] sink_rData_fragment_data0;
reg [7:0] sink_rData_fragment_data1;
wire sink_s2mPipe_m2sPipe_valid;
wire sink_s2mPipe_m2sPipe_ready;
wire sink_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,isCurrentComponent:Boolean):Boolean={
//current component process
if(!isCurrentComponent){
toplevel.dslBody.foreachStatements{
case bt:BaseType if bt.parent.isInstanceOf[Stream[_]] => streamRename( bt.parent.asInstanceOf[Stream[_]])
case bt:BaseType if bt.parent.isInstanceOf[Flow[_]] => flowRename( bt.parent.asInstanceOf[Flow[_]])
case _ =>
}
}else{
toplevel.dslBody.foreachStatements{
case bt:BaseType if bt.parent.isInstanceOf[Stream[_]] => toplevel.addPrePopTask(()=>{streamRename( bt.parent.asInstanceOf[Stream[_]])})
case bt:BaseType if bt.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类变量定义统一做修改:
case class Demo() extends Component{
val io=new Bundle{
val sink=slave(Stream(Fragment(DataPort())))
val source=master(Stream(Fragment(DataPort())))
}
noIoPrefix()
io.source<<io.sink.pipelined(true,true)
StreamRenameUtil(this)
}
最终代码生成会优雅一些:
wire sink_s2mPipe_valid;
reg sink_s2mPipe_ready;
wire sink_s2mPipe_last;
wire [7:0] sink_s2mPipe_data0;
wire [7:0] sink_s2mPipe_data1;
reg sink_rValidN;
reg sink_rData_last;
reg [7:0] sink_rData_fragment_data0;
reg [7:0] sink_rData_fragment_data1;
wire sink_s2mPipe_m2sPipe_valid;
wire sink_s2mPipe_m2sPipe_ready;
wire sink_s2mPipe_m2sPipe_last;
wire [7:0] sink_s2mPipe_m2sPipe_data0;
wire [7:0] sink_s2mPipe_m2sPipe_data1;
reg sink_s2mPipe_rValid;
reg sink_s2mPipe_rData_last;
reg [7:0] sink_s2mPipe_rData_fragment_data0;
reg [7:0] sink_s2mPipe_rData_fragment_data1;
wire when_Stream_l369;
这里的sink_s2mPipe_rData_fragment_data0、sink_s2mPipe_rData_fragment_data1为在打拍时生命的Fragment类型,非Stream类型,如果你实在看不惯也可以依样画葫芦添加一个对Fragment类型的Rename~
☆ END ☆
作者:玉骐
原文链接:Spinal FPGA
微信公众号:
推荐阅读
更多SpinalHDL技术干货请关注[Spinal FPGA]欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。