Tcl自定义排序的方法

在之前的文章中我们介绍了一种PR之后直接获取ROM mmi信息的一个脚本,mmi脚本可以用于修改FPGA生成Bit的ROM初始化数据,这种技术在MCU的验证中非常重要,因为往往在测试MCU ROM代码的时候,我们就需要这种重新Load程序的方式。相比于动则十几个小时生成Bit的时间,我们直接修改bitfile则会快很多。

虽然之前脚本中已经有生成MMI的功能,可以直接找出芯片ROM在FPGA内部的分布信息。但是Vivado命令默认出来的是按照字符串排序的(这个是猜测),顺序不符合我们的mmi的需求,所以我们还是要手动去做一些调整,这种调整对于比较小的设计还是可行的,但是对于比较大的设计,比如动则几十上百个ramloop,这种调整就有些力不从心了。所以为了简化这个流程,我们要对输出进行一个排序。

首先我们来模拟一下Vivado的输出:

{soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[10].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[1].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram 
soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[20].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram 
soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[2].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram}

上面就是一个简化的输出数组,我们最终结果要按照ramloop的值进行递增排序,这个对于并不熟悉tcl编程的我是很有挑战的,网上查了一些资料之后,我得到了如下的解决方法。

首先,tcl本身是支持对数组进行排序的,比如lsort $brams,这样就可以对$brams数组进行排序,默认猜测也是字符串排序,比如对上面数组之后我们得到:

set brams [split $bram_results " "]
set brams [lsort $brams]

{
soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[20].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram} {
soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[2].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram} {soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[10].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram} {soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[1].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram}

嗯,这个结果,明显不是我们需要的,好在lsort还支持自定义比较命令的方式进行排序,这个时候我们要自定义一个比较函数,这里我们定义的如下的一个函数:

proc byramloop {a b} {
  regexp {ramloop\[(\d+)\]} $a m num_a ;
  regexp {ramloop\[(\d+)\]} $b m num_b ;
  #puts [expr $num_a - $num_b]
  return [expr $num_a - $num_b]
}

这里用到了正则表达式匹配, 正则表达式会去找像ramloop[10]这种单词加[数字]的匹配,然后我们将里面的数字作为子匹配,这样我们就得到了我们最为关心的ramloop序号。得到序号只有我们可以进行比较,然后排序了,tcl里面字符串和数字的区别没有那么明显,主要是取决于你怎么使用,这里我们要当成数字进行运算,那么就需要用到expr语句了,return [expr $num_a - $num_b]是指直接将两个数值相减返回结果。

终于我们可以对我们的数据进行自定义排序了,新的排序命令和结果如下:

set brams [lsort -command byramloop $brams]
{soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[1].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram} {
soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[2].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram} {soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[10].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram} {
soc/rom/bram/U0/inst_blk_mem_gen/gnbram.gnativebmg.native_blk_mem_gen/valid.cstr/ramloop[20].ram.r/prim_init.ram/DEVICE_8SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram}

我们可以看到,自定义之后的排序结果已经可以满足我们的需求了,Oh-Yeah!


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

相关文章

发表新评论