pyverilog:可以解析verilog和生成verilog的python库

乐活   2025-01-11 12:06   北京  

前言

这两天在思考如何在自己的环境生成脚本中加入DUT端口的连接(这需要脚本能够解析module有哪些输入输出的端口)。在网上搜索资源的时候发现了pyverilog(https://github.com/PyHDI/Pyverilog.git这一实用的python库。

pyverilog最主要的两个功能:

  1. 1. 实用python生成verilog
  2. 2. 读取verilog文件,解析module中所有的端口、内部变量定义、always块、子module的例化等

解析module模块

    今天要给大家介绍的是我所用到的第二个功能:解析module模块

demo verilog

    从github中对这个项目的介绍,我们可以看到有一个例子;其中verilog module如下图所示。

图1、demo DUT

demo脚本

    对verilog解析的脚本,以及对应的结果如下图所示。

图2、demo脚本及解析结果

脚本输出结果分析

    从上述结果,我们可以看出,代码解析的顺序依次的Source(我的理解是文件本身)→Description(文件中所有的描述,估计不限于module)→ModuleDef(文件中其中一个module模块)→接下来解析的就是module中的所有相关内容了。

        Paramlist:module的参数化

        Portlist:module的端口列表

        Ioport:这里由于verilog的多种端口定义方式,其实分三种情况。

  1.         1. 端口定义的时候直接定义了方向,数据类型,端口名

                这种情况下,Ioport中会有两种(方向+端口名、数据类型+端口名)

                如果变量是多bit的类型,那么次一层还会出现Width(包含msb和lsb)

  2.         2. 端口定义的时候只定义了方向、端口名

                这种情况下,Ioport中只会有一个内容(方向+端口名)

                    如果变量是数组的类型,那么次一层还会出现Dimensions(包含msb和lsb)

  3.         3. 端口定义的时候只定义了端口名

                这种情况下,Ioport就会变为Port,并且只会存在端口名。

demo脚本内容分析

    接下来,下面我们开始简单分析一些demo的脚本内容。

from __future__ import absolute_importfrom __future__ import print_functionimport sysimport osfrom optparse import OptionParser# the next line can be removed after installationsys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))import pyverilog# 这是我们最主要要用的的解析verilog的库from pyverilog.vparser.parser import parsedef main():    INFO = "Verilog code parser"    VERSION = pyverilog.__version__    USAGE = "Usage: python example_parser.py file ..."    def showVersion():        print(INFO)        print(VERSION)        print(USAGE)        sys.exit()    # 这是在命令行给参数用的用的,因为demo没用到,所以我们可以不关心    optparser = OptionParser()    optparser.add_option("-v""--version", action="store_true", dest="showversion",                         default=False, help="Show the version")    optparser.add_option("-I""--include", dest="include", action="append",                         default=[], help="Include path")    optparser.add_option("-D", dest="define", action="append",                         default=[], help="Macro Definition")    (options, args) = optparser.parse_args()    # 获取命令刚给进来的参数    filelist = args    if options.showversion:        showVersion()    # 这里解析输入的文件是不是存在    for f in filelist:        if not os.path.exists(f):            raise IOError("file not found: " + f)    # 如果输入文件不存在,打印一些信息就结束退出    if len(filelist) == 0:        showVersion()    # 这个是核心代码,将输入的文件列表实用parse做解析,后面两个参数可有可无    ast, directives = parse(filelist,                            preprocess_include=options.include,                            preprocess_define=options.define)    # 这个就是前面图中看到的信息了    ast.show()    for lineno, directive in directives:        print('Line %d : %s' % (lineno, directive))if __name__ == '__main__':    main()
    对其中解析到的ast对象进一步的解析已经在星球中介绍,有兴趣的同学可以加入星球一起交流学习。加入星球可以提供VNC端口,上面可以看到我目前在anytype上持续更新的笔记内容。

芯时代青年
专心数字前端全流程,芯时代有为青年的自我修养
 最新文章