-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathverilog_parser.py
executable file
·153 lines (95 loc) · 3.85 KB
/
verilog_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
"""verilog_parser.py
A quick and dirty parser of a *subset* of the Verilog standard.
"""
import re
import json
def create_circuit():
"""Return a blank new circuit."""
return { "name": None, "modules": {}, "initial_state": {},
"assignments": {}, "outputs": [], "inputs": [] }
def add_module(circuit, module_type, module_name, connections_str):
"""Add a module defined in tuple 'module_def' to JSON object 'circuit'."""
if module_type == "module":
# circuit definition
circuit["name"] = module_name
else:
# module instantiation
module = {
"type": module_type,
"connections": {}
}
con_reg = r".(?P<pin>\w+)[\s]*\([\s]*(?P<net>\w+)[\s]*\)[\s]*"
matches = re.compile(con_reg).findall(connections_str)
for item in matches:
pin, net = item
module["connections"][pin] = net
circuit["modules"][module_name] = module
def add_initial_state(circuit, state_str):
"""Add circuit initial state information."""
words = re.compile("([!\w]+)").findall(state_str)
for item in words:
inverted = item[0] == "!"
state = 0 if inverted else 1
net = item[1:] if inverted else item
circuit["initial_state"][net] = state
def add_inputs(circuit, nets_str):
nets = re.compile("(\w+)").findall(nets_str)
circuit["inputs"] += list(nets)
def add_outputs(circuit, nets_str):
nets = re.compile("(\w+)").findall(nets_str)
circuit["outputs"] += list(nets)
def add_delay_pragma(circuit, instance):
circuit["modules"][instance]["short_delay"] = True
def add_assign(circuit, out, inp):
# Assign statements are treated as virtual modules. Their instance names are
# prefixed with * to make them non-compliant with the Verilog standard (and
# thus obviously in need of special treatment).
instance = "ASSIGN_%s" % out
circuit["modules"][instance] = {
"type": "BUF_BUILTIN",
"connections": { "inp": inp, "out": out },
"virtual": True
}
def load_verilog(file):
# Read file content
with open(file, "r") as fid:
content = fid.read().replace("\r", "")
# Generate a blank circuit
circuit = create_circuit()
# Define an array of 'mini_parsers'; tuples of (regex, func). All matches
# of 'regex' are passed, alongside the current circuit definition, to
# 'func' to update the circuit.
# reg_module : matches the top module definition and module instantiations
# reg_state : matches the initial state comments generated by Workcraft
# reg_inputs : matches input statements
# reg_outputs : matches output statements
# reg_delay : matches short delay pragmas
reg_module = r"^\s*(\w+)\s+(\w+)\s+\(([^;]+)\);"
reg_initial1 = r"\/\/ signal values at the initial state:\s*\/\/\s*(.+)$"
reg_initial2 = r"\/\/ Initial state:\s*\/\/\s*(.+)$"
reg_inputs = r"\s*input\s+(.+);$"
reg_outputs = r"\s*output\s+(.+);$"
reg_delay = r"^\s*\/\/ This inverter should have a short delay\s*INV (\S*)"
reg_assign = r"^\s*assign (\S+) = (\S+);$"
mini_parsers = [
(reg_module , add_module),
(reg_initial1 , add_initial_state),
(reg_initial2 , add_initial_state),
(reg_inputs , add_inputs),
(reg_outputs , add_outputs),
(reg_delay , add_delay_pragma),
(reg_assign , add_assign)
]
# Parse and return result
for reg, parse_ in mini_parsers:
matches = re.compile(reg, flags=re.MULTILINE).findall(content)
for item in matches:
args = [item] if type(item) is str else item
parse_(circuit, *args)
return circuit
def main():
circuit = load_verilog("examples/uvh/circuit.v")
print(json.dumps(circuit, indent=4))
if __name__ == '__main__':
main()