有同学想看看综合网表里某模块里and、or、inv等cell的个数,谁最多谁最少。虽然用dc的各种命令组合也可以实现,但今天我们用python来实现。
因为verilog网表非常有规律,很容易用正则来匹配,所以用python来做统计正合适。之前写过一篇文章:《用Python提取Verilog网表层次和实例化关系》,这篇文章已经实现了网表parser,基于这个脚本做统计就非常简单了。
网表parser
用三条正则'module\s+(\w+)','\s*(\w+)\s+(\w+)\s*\(','endmodule'来解析和拆分module、识别模块名、读取cell的类型和例化名。
# netlistparser.py
import sys
import json
import re
def read_vlog_netlist(vlog_file):
"""
get insts by module
"""
vlog_lines = open(vlog_file, 'r').readlines()
module_start = 0
modules = {}
for line in vlog_lines:
module_start_m = re.search('module\s+(\w+)', line)
inst_m = re.search('\s*(\w+)\s+(\w+)\s*\(', line)
module_end_m = re.search('endmodule', line)
if module_start_m:
module_start = 1
module = {}
module_name = module_start_m.group(1)
module['module_name'] = module_name
insts = {}
module['insts'] = insts
modules[module_name] = module
elif module_end_m:
module_start = 0
elif module_start and inst_m:
module_name = inst_m.group(1)
inst_name = inst_m.group(2)
insts[inst_name] = module_name
return modules
if __name__ == '__main__':
modules = read_vlog_netlist(sys.argv[1])
print(json.dumps(modules, indent=4))
解析完成后,我们把数据放到dict里,方便存储成json,和进一步处理。格式如下:
{
"moduleA": {
"module_name": "moduleA",
"insts": {
"u_AND2_01": "AND2X1",
"u_AND2_02": "AND2X1",
"u_OR2_01": "OR2X1",
"u_INV_01": "INVX1"
}
},
"moduleB": {
"module_name": "moduleB",
"insts": {
"u_AND2_01": "AND2X1",
"u_AND2_02": "AND2X1",
"u_OR2_01": "OR2X1",
"u_INV_01": "INVX1"
}
},
}
统计cell类型和个数
从网表parser的数据dict里分模块取出module,遍历insts,在字典cell_count用cell类型做key存放cell的计数。
# cellinfo.py
import sys
import netlistparser as nlparser
import re
import json
def count_cells(modules):
cells_info = []
module_names = modules.keys()
for module_name in module_names:
cell_count = {}
insts = modules[module_name]['insts']
for inst in insts:
cell_inst = inst
cell_type = insts[inst]
if cell_type in cell_count:
cell_count[cell_type] = cell_count[cell_type] + 1
else:
cell_count[cell_type] = 1
# sort by cell_type
cell_count2 = dict_sort_by_val(cell_count)
cells_info_module = {module_name : cell_count2}
cells_info.append(cells_info_module)
return cells_info
其中用了一个函数,按字典的value排序:dict_sort_by_val(),如下,先把dict转成list,用sorted对list排序,排序后再转为dict。
def dict_sort_by_val(d):
keys = d.keys()
values = d.values()
l = [(key, val) for key, val in zip(keys, values)]
l2 = sorted(l, key=lambda x:x[1], reverse=True)
d2 = {}
for k,v in l2:
d2[k] = v
return d2
写顶层调用:
if __name__ == '__main__':
vlog_netlist_file = sys.argv[1]
print('Read {} ...'.format(vlog_netlist_file))
modules = nlparser.read_vlog_netlist(vlog_netlist_file)
cells_info = count_cells(modules)
print(json.dumps(cells_info, indent=4))
最终效果如下:
[
{
"cv32e40p_clock_gate": {
"CKLNQD12BWP": 1
}
},
{
"cv32e40p_sleep_unit_PULP_CLUSTER0": {
"DFCNQD1BWP": 2,
"OR2D1BWP": 1,
"OR4D1BWP": 1,
"OA21D1BWP": 1,
"cv32e40p_clock_gate": 1,
"INR3D0BWP": 1
}
},
{
"cv32e40p_prefetch_controller_PULP_OBI0_PULP_XPULP0_DEPTH2_DW01_add_1": {
"CKND2D1BWP": 23,
"NR2XD0BWP": 18,
"INVD1BWP": 17,
"XOR2D1BWP": 15,
"XNR2D1BWP": 9,
"HA1D0BWP": 4,
"HICIND1BWP": 1
}
},
{
"cv32e40p_prefetch_controller_PULP_OBI0_PULP_XPULP0_DEPTH2": {
"INVD1BWP": 38,
"DEL100D1BWP": 24,
"AO32D0BWP": 13,
"AOI32D0BWP": 10,
"CKND2BWP": 9,
"ND3D3BWP": 9,
"OAI221D1BWP": 8,
"ND2D1BWP": 8,
...
},
...
]