前言
这两天在思考如何在自己的环境生成脚本中加入DUT端口的连接(这需要脚本能够解析module有哪些输入输出的端口)。在网上搜索资源的时候发现了pyverilog(https://github.com/PyHDI/Pyverilog.git)这一实用的python库。
pyverilog最主要的两个功能:
1. 实用python生成verilog 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. 端口定义的时候直接定义了方向,数据类型,端口名 这种情况下,Ioport中会有两种(方向+端口名、数据类型+端口名)
如果变量是多bit的类型,那么次一层还会出现Width(包含msb和lsb)
2. 端口定义的时候只定义了方向、端口名 这种情况下,Ioport中只会有一个内容(方向+端口名)
如果变量是数组的类型,那么次一层还会出现Dimensions(包含msb和lsb)
3. 端口定义的时候只定义了端口名 这种情况下,Ioport就会变为Port,并且只会存在端口名。
demo脚本内容分析
接下来,下面我们开始简单分析一些demo的脚本内容。
from __future__ import absolute_import
from __future__ import print_function
import sys
import os
from optparse import OptionParser
# the next line can be removed after installation
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import pyverilog
# 这是我们最主要要用的的解析verilog的库
from pyverilog.vparser.parser import parse
def 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()