Spyglass 生成的sgdc文件使用python进行分析

Spyglass 是一个重要的CDC检查工具,主要的功能是对SOC进行抽象,生成sgdc文件帮助进行RTL分析,CDC分析,功耗分析等。一个完整的SOC工程 可能会生成 数十个sgdc文件,每一个文件 行数达到上万行,人工分析sgdc文件过于麻烦, 需要借助于脚本辅助分析。
python版本: python 3.7
用到的工具:正则表达式
任务目标:分析所有的sdgc文件,生成同名的csv文件,csv文件中详细表述抽象端口的信息

文件的预处理

首先需要以只读模式打开Spyglass生成的sgdc文件,不可以破坏原有的sgdc文件,打开sgdc文件后有大量的约束换行情况,具体如下:

clock -name "xxx" -tag xxx -domain d7 -period 40000 -edge "0" \
  "20000"
clock -name "xxx" -tag xxx \
  -domain d0 -period 1666.666626 -edge "0" "833.333313"
clock -name "xxx" -tag xxx \
  -domain d1 -period 1250 -edge "0" "625"
clock -name "xxx" -tag xxx -domain d8 -period 1000 -edge "0" \
  "500"

为了方便处理,需要将一句约束放到同一行,也就是将 "\\n"更换为一个空格’ ',具体代码如下:

def sgdc_func(path,file_name):
    file1 = open(path + '/' + file_name,'r')
    file1_temp_name = file_name[:-5] + '_revised' + '.sgdc'
    file1_temp = open(file1_temp_name,'w+')

    for line in file1:
        file1_temp.write(line.replace('\\\n',' ')) # replace \ and \n with ' '
    file1_temp.seek(0,0) # relocate the file pointer to file head
    file1_lines = file1_temp.readlines() 

从上述代码可以看到创建了一个新文件,用w+模式打开,这个文件用于存储 去掉约束换行后的新文件。
file1_lines是一个列表,元素是sgdc文件每一行的约束,元素类型是字符串。

关键字匹配

最重要的部分就是根据 sgdc文件中的关键字来进行抽取,csv文件的表头信息如下:

file2_name = file_name[:-5] + '.csv'
    file2 = open(file2_name,"w")
    file2.write(','.join(("name","width/clk/reset","module/tag","clock/domain/source","direction/period/divide/value")) + '\n')

name是端口名,有端口、时钟、复位三种情况;
width/clk/reset标注端口的位宽,区别clk与generated_clk,标注reset;
module/tag标注端口所属的模块,标注时钟的tag;
clock/domain/source标注端口受到哪个时钟约束,标注时钟所属的时钟域,标注generated_clk的source;
direction/period/divide/value标注端口的方向,标注时钟的周期,标注分频的系数,标注复位的值;

abstract_port

默认一个sdgc文件中所有的端口属于同一个module;
关键字abstract_port表明这句话在约束一个端口,代码如下:

num = 0
if file1_lines: # file1_lines is a list
	for item in range(len(file1_lines)):
        if(re.search("abstract_port -ports",file1_lines[item])):   # key word abstract_port

匹配模式是 abstract_port -ports,这是因为一些注释中也会出现abstract_port,-ports 后面跟着端口的名字;
计算位宽比较麻烦,因为 sgdc文件 的端口位宽有多种写法,如下:

abstract_port -ports "xxx" -clock "xxx" -module "xxx"
abstract_port -ports "xxx[0]" -clock "xxx" -module "xxx"
abstract_port -ports "xxxx[1:3]" -clock "xxxx" -module "xxx"
abstract_port -ports "xxx[6:4]" -clock "xxx" -module "xxx" -related_ports xxx[0] xxx[1]

总结规律: 多位宽一定会有[],但是有[]不一定是多位宽,因为-related_ports的参数 也可能包含[],不带[]一定是单位宽,带了[]也可能是单位宽;
python处理时将多位宽和单位宽分开处理,一个关键的匹配模式是:

if re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:?(\d*)?\][^ \b]",file1_lines[item]):  # need to merge the port [A:B] and [A]

这个匹配模式 将related_ports中的中括号忽略了,不识别单位宽,识别了多位宽的所有形式;
将带 : 的形式与 不带 : 的形式分开处理, 带 : 的形式 分别提取出 : 左右两边的 数字, 作差以后取绝对值再加1,作为此行语句的对应位宽, 不带 : 位宽直接加1;
同时需要提取出当前行 和下一行的端口名字, 如果端口名字是一样的, 表明当前的端口描述还未结束,需要继续分析下一行,如果不一样,表明当前端口描述结束,计算出端口的位宽即可,具体代码如下:

 if(re.search("abstract_port -ports",file1_lines[item])):   # key word abstract_port
     list1 = []                         
     if re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:?(\d*)?\][^ \b]",file1_lines[item]):  # need to merge the port [A:B] and [A]
     	if re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:(\d*)?\][^ \b]",file1_lines[item]): # in the form of A:B
             str1 = re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:(\d*)?\][^ \b]",file1_lines[item]).group()
             str1 = str1.strip().strip('\"')
             str2 = re.search(r"(?<=(\[))[^:]*",str1).group()
             str3 = re.search(r"(?<=(:))[^\]]*",str1).group()
             num_temp = abs(int(str3) - int(str2)) + 1   
             num += num_temp
     	else:
             num += 1  # in the form of [A]
         str1 = re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:?(\d*)?\][^ \b]",file1_lines[item]).group() # str1 needs to be deassigned
         str1 = str1.strip().strip('\"')                    
         str1 = re.match(r"[A-Za-z0-9_]*[^\[:\]]",str1).group()  # the port name match not search
         if re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:?(\d*)?\][^ \b]",file1_lines[item+1]):
             str2 = re.search(r"(?<=(-ports ))\s*\"?\w*\[\d*:?(\d*)?\][^ \b]",file1_lines[item+1]).group()
             str2 = str2.strip().strip('\"')
             str2 = re.match(r"[A-Za-z0-9_]*[^\[:\]]",str2).group()
         else:
             str2 = ' '
         if(str1 == str2):
             continue
         else:
             list1.append(str1)
             list1.append(str(num))
             num = 0    

单位宽语句的处理,直接将位宽加1即可!

多余空格和引号的处理

实际分析sgdc文件时,发现 -ports等所有关键词与后面的参数之间,未必是固定一个空格,可能存在若干个不定数量的空格,且参数有可能用引号包裹,也有可能没有引号包裹,所以匹配模式的通用形式是

(?<=(-module ))\s*\"?[^ \"\b]*

-xxx表明关键字,但是 后面必须要有\s*,否则会漏匹配一些语句,且python的正则表达式不支持将 不定长的内容用 ?<= 修饰,其实一般的正则表达式解释器是支持的,\"?也很重要,因为参数可能用 " 包裹,也有可能没有引号!
匹配完成后一定要去掉多余的空格和引号,方法为:

str2 = str2.strip().strip('\"')

output与clock -name与 reset

这两个的处理方法与abstract_port接近,但是clock -name关键字会同时匹配到clock -name与generated_clock -name,所以还需要再次进行区分

多文件处理

import re
import os
from sgdc_func import sgdc_func

path = 'your_path'
path_list = os.listdir(path)
path_list_sgdc = []

for item in path_list:
    if re.search(r'(.*\.sgdc)[^ \.swp]?',item):	
        if re.search(r'(.*\.sgdc)[^ \.swp]?',item).group() == item:
            path_list_sgdc.append(item)
print("There are %d sgdc files!\n" %len(path_list_sgdc))
path_list_sgdc.sort()

首先使用os.listdir()函数获取指定路径下所有的 文件名列表,注意区别sgdc格式的文件和sgdc.swp格式的文件。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值