-
Notifications
You must be signed in to change notification settings - Fork 218
/
Copy pathhierarchy_design.py
217 lines (192 loc) · 9.7 KB
/
hierarchy_design.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import os
from openram import debug
from openram import OPTS
from .hierarchy_layout import layout
from .hierarchy_spice import spice
class hierarchy_design(spice, layout):
"""
Design Class for all modules to inherit the base features.
Class consisting of a set of modules and instances of these modules
"""
name_map = []
def __init__(self, name, cell_name):
self.drc_errors = "skipped"
self.lvs_errors = "skipped"
# Flag for library cells which is recomputed in hierachy_layout
gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds"
is_library_cell = os.path.isfile(gds_file)
# Uniquify names to address the flat GDS namespace
# except for the top/output name
if not is_library_cell and name != OPTS.output_name and not name.startswith(OPTS.output_name):
name = OPTS.output_name + "_" + name
cell_name = name
spice.__init__(self, name, cell_name)
layout.__init__(self, name, cell_name)
self.init_graph_params()
def get_layout_pins(self, inst):
""" Return a map of pin locations of the instance offset """
# find the instance
for i in self.insts:
if i.name == inst.name:
break
else:
debug.error("Couldn't find instance {0}".format(inst.name), -1)
inst_map = inst.mod.pin_map
return inst_map
def DRC_LVS(self, final_verification=False, force_check=False):
"""Checks both DRC and LVS for a module"""
from openram import verify
# No layout to check
if OPTS.netlist_only:
return
# Unit tests will check themselves.
elif not force_check and OPTS.is_unit_test:
return
elif not force_check and not OPTS.check_lvsdrc:
return
# Do not run if disabled in options.
elif (OPTS.inline_lvsdrc or force_check or final_verification):
tempspice = "{}.sp".format(self.name)
self.sp_write("{0}{1}".format(OPTS.openram_temp, tempspice), lvs=True)
tempgds = "{}.gds".format(self.name)
self.gds_write("{0}{1}".format(OPTS.openram_temp, tempgds))
# Final verification option does not allow nets to be connected by label.
self.drc_errors = verify.run_drc(self.cell_name, tempgds, tempspice, extract=True, final_verification=final_verification)
self.lvs_errors = verify.run_lvs(self.cell_name, tempgds, tempspice, final_verification=final_verification)
# force_check is used to determine decoder height and other things, so we shouldn't fail
# if that flag is set
if OPTS.inline_lvsdrc and not force_check:
debug.check(self.drc_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.cell_name,
self.drc_errors))
debug.check(self.lvs_errors == 0,
"LVS failed for {0} with {1} errors(s)".format(self.cell_name,
self.lvs_errors))
def DRC(self, final_verification=False):
"""Checks DRC for a module"""
from openram import verify
# Unit tests will check themselves.
# Do not run if disabled in options.
# No layout to check
if OPTS.netlist_only:
return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = "{}.sp".format(self.name)
self.sp_write("{0}{1}".format(OPTS.openram_temp, tempspice), lvs=True)
tempgds = "{}.gds".format(self.cell_name)
self.gds_write("{0}{1}".format(OPTS.openram_temp, tempgds))
num_errors = verify.run_drc(self.cell_name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.cell_name,
num_errors))
def LVS(self, final_verification=False):
"""Checks LVS for a module"""
from openram import verify
# Unit tests will check themselves.
# Do not run if disabled in options.
# No layout to check
if OPTS.netlist_only:
return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = "{}.sp".format(self.cell_name)
self.sp_write("{0}{1}".format(OPTS.openram_temp, tempspice), lvs=True)
tempgds = "{}.gds".format(self.name)
self.gds_write("{0}{1}".format(OPTS.openram_temp, tempgds))
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0,
"LVS failed for {0} with {1} error(s)".format(self.cell_name,
num_errors))
def init_graph_params(self):
"""
Initializes parameters relevant to the graph creation
"""
# Only initializes a set for checking instances which should not be added
self.graph_inst_exclude = set()
def build_graph(self, graph, inst_name, port_nets):
"""
Recursively create graph from instances in module.
"""
# Translate port names to external nets
if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
list(self.pins)),
1)
port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)}
debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.get_instance_connections()):
if subinst in self.graph_inst_exclude:
continue
subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
subinst.mod.build_graph(graph, subinst_name, subinst_ports)
def build_names(self, name_dict, inst_name, port_nets):
"""
Collects all the nets and the parent inst of that net.
"""
# Translate port names to external nets
if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
list(self.pins)),
1)
port_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)}
debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.get_instance_connections()):
subinst_name = inst_name + "{}x".format(OPTS.hier_seperator) + subinst.name
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
for si_port, conn in zip(subinst_ports, conns):
# Only add for first occurrence
if si_port.lower() not in name_dict:
mod_info = {'mod': self, 'int_net': conn}
name_dict[si_port.lower()] = mod_info
subinst.mod.build_names(name_dict, subinst_name, subinst_ports)
def translate_nets(self, subinst_ports, port_dict, inst_name):
"""
Converts connection names to their spice hierarchy equivalent
"""
converted_conns = []
for conn in subinst_ports:
if conn in port_dict:
converted_conns.append(port_dict[conn])
else:
converted_conns.append("{0}{2}{1}".format(inst_name, conn, OPTS.hier_seperator))
return converted_conns
def add_graph_edges(self, graph, port_nets):
"""
For every input, adds an edge to every output.
Only intended to be used for gates and other simple modules.
"""
# The final pin names will depend on the spice hierarchy, so
# they are passed as an input.
pin_dict = {pin: port for pin, port in zip(list(self.pins), port_nets)}
input_pins = self.get_inputs()
output_pins = self.get_outputs()
inout_pins = self.get_inouts()
for inp in input_pins + inout_pins:
for out in output_pins + inout_pins:
if inp != out: # do not add self loops
graph.add_edge(pin_dict[inp], pin_dict[out], self)
def __str__(self):
""" override print function output """
pins = ",".join(list(self.pins))
insts = [" {}".format(x) for x in self.insts]
objs = [" {}".format(x) for x in self.objs]
s = "********** design {0} **********".format(self.cell_name)
s += "\n pins ({0})={1}\n".format(len(self.pins), pins)
s += "\n objs ({0})=\n{1}\n".format(len(self.objs), "\n".join(objs))
s += "\n insts ({0})=\n{1}\n".format(len(self.insts), "\n".join(insts))
return s
def __repr__(self):
""" override print function output """
text="( design: " + self.name + " pins=" + str(list(self.pins)) + " " + str(self.width) + "x" + str(self.height) + " )\n"
for i in self.objs:
text+=str(i) + ",\n"
for i in self.insts:
text+=str(i) + ",\n"
return text