Parser的实现
所谓Parser就是根据Verilog语法规则解析网表,把解析到的信息存入上面定义的数据结构中。这个数据结构叫做抽象语法树(AST)。
第一步,读入Verilog网表,并把网表拆分成多个单独的module。如下,判断是否遇到endmodule。
def read_netlist(self, file_name):
self.file_name = file_name
f = open(self.file_name, "r")
self.nl = f.readlines()
def split_netlist(self):
m = []
t1 = len(self.nl)
for i in range(t1):
l = self.nl[i]
m.append(l)
if l.startswith('endmodule'):
self.read_module(m)
第二步,解析module。先去除注释,合并所有行,再按分号来重新分行。根据module xxx来读取模块名。根据input/output/inout来读取端口。根据wire来读取连线。根据xxx yyy (...)。读到这些信息后,存储进上面定义的数据结构。详细代码如下,注意各个正则的用法。
def read_module(self, m):
m1 = []
for l in m:
if re.match(r'^\s*\/\/', l) or re.match(r'^\s*\n$', l):
pass
else:
m1.append(l)
n = ''.join(m1)
m1 = n.split(';')
for i in range(len(m1)):
ret = re.match(r'^module\s+(\w+)\s+', m1[i], re.S)
if ret:
module_name = ret.group(1)
module_temp = t_module(module_name)
self.designs.append(module_temp)
continue
found = 0
m1_temp = re.sub(r'\n', '', m1[i], re.S)
ret = re.match(r'^(input|output|inout)\s+\[(\d+):(\d+)\]\s+(\w+)', m1_temp, re.S)
if ret:
port_direction = ret.group(1)
port_msb = ret.group(2)
port_lsb = ret.group(3)
port_name = ret.group(4)
found = 1
else:
ret = re.match(r'^(input|output|inout)\s+\[(\d+)\]\s+(\w+)', m1_temp, re.S)
if ret:
port_direction = ret.group(1)
port_msb = ret.group(2)
port_lsb = ret.group(2)
port_name = ret.group(3)
found = 1
else:
ret = re.match(r'^(input|output|inout)\s+(\w+)', m1_temp, re.S)
if ret:
port_direction = ret.group(1)
port_msb = '0'
port_lsb = '0'
port_name = ret.group(2)
found = 1
if found == 1:
port_msb = int(port_msb)
port_lsb = int(port_lsb)
port_temp = t_port()
port_temp.new_port(port_name, port_direction, "wire", port_msb, port_lsb)
module_temp.add_port(port_temp)
for i in range(port_lsb, port_msb):
wire_temp = t_wire("{}{}".format(port_name, i))
wire_temp.add_conn(None, "{}[{}]".format(port_name, i))
module_temp.add_wire(wire_temp)
continue
ret = re.match(r'^wire\s+\[(\d+):(\d+)\]\s+(\w+)', m1_temp, re.S)
if ret:
port_direction = "input"
port_msb = ret.group(1)
port_lsb = ret.group(2)
port_name = ret.group(3)
port_msb = int(port_msb)
port_lsb = int(port_lsb)
for i in range(port_lsb, port_msb):
wire_temp = t_wire("{}{}".format(port_name, i))
wire_temp.add_conn(None, "{}[{}]".format(port_name, i))
module_temp.add_wire(wire_temp)
continue
ret = re.match(r'^\s*endmodule', m1_temp, re.S)
if ret:
continue
ret = re.match(r'^\s*(\w+)\s+(\w+)\s+\((.*)\)\s*$', m1_temp, re.S)
if ret:
mod_name = ret.group(1)
inst_name = ret.group(2)
port_map_s = ret.group(3)
inst_temp = t_inst(inst_name);
inst_temp.new_inst(mod_name, inst_name);
port_map_s = re.sub(r'\n', '', port_map_s, re.S)
port_map_s = re.sub(r'\s', '', port_map_s, re.S)
port_map_l = port_map_s.split(',')
for pm in port_map_l:
r = re.match(r'\.(\w+)\((.*)\)', pm)
if r:
inst_temp.add_port_map(r.group(1), r.group(2))
if module_temp.exist_wire(r.group(2)):
i = module_temp.find_wire(r.group(2))
module_temp.wires[i].add_conn(inst_name, r.group(1))
else:
wire_temp = t_wire(r.group(2))
wire_temp.add_conn(inst_name, r.group(1))
module_temp.add_wire(wire_temp)
module_temp.add_inst(inst_temp)
else:
print(m1_temp)
第三步,抽象语法树AST的顶层,定义如下,网表文件名和module AST列表。这样应用层就可以从上而下遍历整个数据结构。
class parser:
def __init__(self):
self.file_name = ""
self.designs = []
应用层测试:打印子模块名
读入并解析Verilog测试网表test.v,然后print出相关信息。
from netlist import t_port, t_wire, t_inst, t_module
import parser
if __name__ == '__main__':
parser = parser.parser()
parser.read_netlist("test.v")
parser.designs[0].print_this()
parser.designs[1].print_this()
下一步
本示例用正则和字符串函数实现了解析Verilog网表,并构建了网表的AST,方便应用层进一步处理。基于本示例可以很方便地实现网表分析、统计、修改等高级应用。