在工作中经常需要对网表进行分析、统计、修改,而现有的EDA工具却往往不够灵活。其实我们自己也可以用python来实现这个功能。今天我们来实现第一步,先做一个Verilog网表Parser。
分析网表的结构和组成
下面是一个简化的网表,但是却包括完整的语法结构。
module xor4 (a , b , c);
input [3:0] a ;
input [3:0] b ;
output [3:0] c ;
XOR U0 (.A2 ( b[0] ) , .A1 ( a[0] ) , .Y ( c[0] ) ) ;
XOR U1 (.A2 ( b[1] ) , .A1 ( a[1] ) , .Y ( c[1] ) ) ;
XOR U2 (.A2 ( b[2] ) , .A1 ( a[2] ) , .Y ( c[2] ) ) ;
XOR U3 (.A2 ( b[3] ) , .A1 ( a[3] ) , .Y ( c[3] ) ) ;
endmodule
module xor8 (a, b, c);
input [7:0] a ;
input [7:0] b ;
output [7:0] c ;
xor4 U0 (.a(a[3:0]), .b(b[3:0]), .c(c[3:0]));
xor4 U0 (.a(b[7:4]), .b(b[7:4]), .c(c[7:4]));
endmodule
可以看到:
Verilog网表总是由若干个module组成
每个module由模块名字、端口、内部wire定义(可选)、实例化(其它设计模块或者标准单元库模块)等几部分组成
端口由端口列表、位宽、方向等信息组成
实例化由模块名、例化名、端口连接组成
定义网表数据结构
端口
端口的数据结构:端口名字、方向、类型、最高位、最低位。具体如下:
class t_port:
def __init__(self):
self.name = "default"
self.direction = "input"
self.wire_type = "wire"
self.msb = 0
self.lsb = 0
连线
连线的数据结构:连线的名字、连接关系。具体如下:
class t_wire:
def __init__(self, name):
self.name = name
self.conn = []
一根连线可以连接到多个pin或port,所以用列表来存储。
实例化
实例化的数据结构:实例化名字、模块名、端口映射关系。具体如下:
class t_inst:
def __inst__(self, name):
self.name = name
self.module_name = "default"
self.port_map = []
端口映射关系是多组"端口<->连线"对,因而也用列表存储。
模块
模块的数据结构:模块名、端口列表、连线列表、实例化列表。具体如下:
class t_module:
def __init__(self, name):
self.name = name
self.ports = []
self.wires = []
self.insts = []
顶层模块与普通的模块并无差异,只是没有被实例化而已。这个角度看,如果没有冗余模块时,就可以自动分析出顶层模块。否则就需要额外指定顶层模块名字。