用python实现网表分模块统计面积

ExASIC 2022-07-04

pythonlib文件text函数

850 字丨阅读本文需 2 分钟

虽然dc也有report_area -hier命令来报告各级模块的面积,本python方案看似有点造轮子,但还是有一定的便利性。一、不受网表类型的限制,综合网表、DFT网表、APR都可以。二、可以过滤面积小于指定值的小模块,比如工具自动插入的ICG模块。三、还可以根据面积占比做排序,方便分析面积的瓶颈。

一、读入网表

下面先读入网表,并分模块识别每个模块内部的stdcell和子模块。这部分与《用python实现分模块按cell类型统计cell个数并降序排列》的方法相同,所以这里直接导入netlistparser.py。

import netlistparser as nlparser

import sys


vlog_netlist_file = sys.argv[2]

modules = nlparser.read_vlog_netlist(vlog_netlist_file)

这样网表就读到了内部python字典里,结构如下:

"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"   

         }

},

二、读入lib库

stdcell的面积信息存储在fab提供的lib文件里,所以我们需要从lib里读到每种cell的面积,方法如下:

# libparser.py

import sys

import re

import json


def read_library(file_name):

    cells = {}


    lib_lines = open(file_name, 'r').readlines()
   

    cell_start = 0 

    pin_start = 0
   

    total_lines = len(lib_lines

    print('')


    for i in range(total_lines)

        line = lib_lines[i]

        print(' {}%'.format(round(100 * i / total_lines)))                

        cell_s_m = re.search(r'cells*((w+))s+{', line)        

        area_m   = re.search(r'sareas+:s+(S+)s*;', line)       

        pin_s_m  = re.search(r'spin((w+))s+{', line)

        dir_m    = re.search(r'sdirections+:s+(w+)', line)

        func_m   = re.search(r'sfunctions+:s+"(.*)"', line)

        end_m    = re.search(r'}', line)

     

        if cell_s_m:

            cell_start = 1

            cell = {}

            cell_name = cell_s_m.group(1)

            cell['cell_name'] = cell_name 

            pins = []

            cell['pins'] = pins

            cells[cell_name] = cell
      

      if cell_start and area_m:

            area = area_m.group(1)

            cell['area'] = round(float(area), 4)


      if cell_start and pin_s_m:

            pin_start = 1

            pin = {}

            pin_name = pin_s_m.group(1)

            pin['pin_name'] = pin_name
      

       if cell_start and dir_m:

            pin_dir = dir_m.group(1)

            pin['pin_dir'] = pin_dir
       

      if cell_start and func_m:

            pin_func = func_m.group(1)

            pin['pin_func'] = pin_func
      

      if cell_start and pin_start and end_m:

            pin_start = 0

            pins.append(pin


return cells

def get_cell_area(cells, cell_name):

    if cell_name in cells:

        return cells[cell_name]['area']

    else:

        return 0


def is_libcell(cells, cell_name):

    if cell_name in cells:

        return True

    else:

        return False


def write_lib_info(lib_info, file_name):

    f = open(file_name, 'w')

    f.write(json.dumps(lib_info, indent=4))

    f.close()

其中,read_library()函数实现了用正则读取lib文件里的cell名字、area、pin、pin方向、function等信息。今天只需要用到cell名字和面积。其它信息是为了后续扩展其它功能做准备。

get_cell_area()提供了读取指定cell面积的接口。is_libcell()实现了判断是libcell还是一般的设计上的子模块。

write_lib_info()可以将lib库的字典写到json文件里,方便调试。

接下来,用这个libparser读入lib库:

import libparser

import sys

lib_file = sys.argv[1]

lib_info = libparser.read_library(lib_file)

三、面积递归统计

我们从top design开始,当遇到stdcell中的cell则累加,当遇到子模块则递归。直到子模块不再含有其它子模块(仅由stdcell组成)时,则返回。

area_info = {}

def report_area(modules, lib_info, module_name):

    global area_info

    area = 0 


    insts = modules[module_name]['insts']

    for inst in insts:

        cell_inst = inst

        cell_type = insts[inst]

        if cell_type in area_info

            area = area + area_info[cell_type]

        elif libparser.is_libcell(lib_info, cell_type):

            area = area + libparser.get_cell_area(lib_info, cell_type)

        else:

            # 递归 

            report_area(modules, lib_info, cell_type)

            area = area + area_info[cell_type]


        area_info[module_name] = area

四、打印面积

打印的同时,可以做一些过滤或者排序。

for module in area_info:

        if not re.search(r'CLOCK_GATE', module):

            print(module, round(area_info[module], 4))

效果如下:

免责声明:凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处本网。非本网作品均来自其他媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如您发现有任何侵权内容,请依照下方联系方式进行沟通,我们将第一时间进行处理。

0赞 好资讯,需要你的鼓励
来自:ExASIC
0

参与评论

登录后参与讨论 0/1000

为你推荐

加载中...