Merged with dev, fixed conflict in ptx

This commit is contained in:
Hunter Nichols 2020-04-08 02:33:05 -07:00
commit 4103745de2
22 changed files with 553 additions and 317 deletions

View File

@ -7,15 +7,11 @@
# #
import hierarchy_layout import hierarchy_layout
import hierarchy_spice import hierarchy_spice
import globals
import verify import verify
import debug import debug
import os import os
from globals import OPTS from globals import OPTS
import graph_util
total_drc_errors = 0
total_lvs_errors = 0
class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
""" """
@ -28,6 +24,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
# If we have a separate lvs directory, then all the lvs files
# should be in there (all or nothing!)
lvs_dir = OPTS.openram_tech + "lvs_lib/"
if os.path.exists(lvs_dir):
self.lvs_file = lvs_dir + name + ".sp"
else:
self.lvs_file = self.sp_file
self.name = name self.name = name
hierarchy_spice.spice.__init__(self, name) hierarchy_spice.spice.__init__(self, name)
hierarchy_layout.layout.__init__(self, name) hierarchy_layout.layout.__init__(self, name)
@ -44,68 +48,93 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
inst_map = inst.mod.pin_map inst_map = inst.mod.pin_map
return inst_map return inst_map
def DRC_LVS(self, final_verification=False, force_check=False):
def DRC_LVS(self, final_verification=False, top_level=False):
"""Checks both DRC and LVS for a module""" """Checks both DRC and LVS for a module"""
# Final verification option does not allow nets to be connected by label. # No layout to check
if OPTS.netlist_only:
return ("skipped", "skipped")
# Unit tests will check themselves. # Unit tests will check themselves.
if OPTS.is_unit_test: if not force_check and OPTS.is_unit_test:
return return ("skipped", "skipped")
if not OPTS.check_lvsdrc: if not force_check and not OPTS.check_lvsdrc:
return return ("skipped", "skipped")
# Do not run if disabled in options. # Do not run if disabled in options.
if (OPTS.inline_lvsdrc or top_level): if (OPTS.inline_lvsdrc or force_check or final_verification):
global total_drc_errors
global total_lvs_errors
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name) tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.sp_write(tempspice) self.lvs_write(tempspice)
self.gds_write(tempgds) self.gds_write(tempgds)
# Final verification option does not allow nets to be connected by label.
num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification) num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification) num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors))
debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors)) # force_check is used to determine decoder height and other things, so we shouldn't fail
total_drc_errors += num_drc_errors # if that flag is set
total_lvs_errors += num_lvs_errors if OPTS.inline_lvsdrc and not force_check:
debug.check(num_drc_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.name,
num_drc_errors))
debug.check(num_lvs_errors == 0,
"LVS failed for {0} with {1} errors(s)".format(self.name,
num_lvs_errors))
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)
return (num_drc_errors, num_lvs_errors)
else:
return ("skipped", "skipped")
def DRC(self, final_verification=False): def DRC(self, final_verification=False):
"""Checks DRC for a module""" """Checks DRC for a module"""
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.
# No layout to check
if OPTS.netlist_only:
return "skipped"
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)): if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
global total_drc_errors
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification) num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
total_drc_errors += num_errors debug.check(num_errors == 0,
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error)) "DRC failed for {0} with {1} error(s)".format(self.name,
num_errors))
os.remove(tempgds) os.remove(tempgds)
return num_errors
else:
return "skipped"
def LVS(self, final_verification=False): def LVS(self, final_verification=False):
"""Checks LVS for a module""" """Checks LVS for a module"""
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.
# No layout to check
if OPTS.netlist_only:
return "skipped"
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)): if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
global total_lvs_errors
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name) tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.sp_write(tempspice) self.lvs_write(tempspice)
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification) num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
total_lvs_errors += num_errors debug.check(num_errors == 0,
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors)) "LVS failed for {0} with {1} error(s)".format(self.name,
num_errors))
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)
return num_errors
else:
return "skipped"
def init_graph_params(self): def init_graph_params(self):
"""Initializes parameters relevant to the graph creation""" """Initializes parameters relevant to the graph creation"""
# Only initializes a set for checking instances which should not be added # Only initializes a set for checking instances which should not be added
@ -116,7 +145,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# Translate port names to external nets # Translate port names to external nets
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1) debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
self.pins),
1)
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} port_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
debug.info(3, "Instance name={}".format(inst_name)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.conns):
@ -130,7 +161,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"""Collects all the nets and the parent inst of that net.""" """Collects all the nets and the parent inst of that net."""
# Translate port names to external nets # Translate port names to external nets
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1) debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,
self.pins),
1)
port_dict = {pin: port for pin, port in zip(self.pins, port_nets)} port_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
debug.info(3, "Instance name={}".format(inst_name)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.conns):
@ -190,8 +223,10 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
parent_net.lower() == alias_net.lower() parent_net.lower() == alias_net.lower()
def get_mod_net(self, parent_net, child_inst, child_conns): def get_mod_net(self, parent_net, child_inst, child_conns):
"""Given an instance and net, returns the internal net in the mod """
corresponding to input net.""" Given an instance and net, returns the internal net in the mod
corresponding to input net.
"""
for conn, pin in zip(child_conns, child_inst.mod.pins): for conn, pin in zip(child_conns, child_inst.mod.pins):
if parent_net.lower() == conn.lower(): if parent_net.lower() == conn.lower():
return pin return pin

View File

@ -15,6 +15,7 @@ from wire_spice_model import *
from power_data import * from power_data import *
import logical_effort import logical_effort
class spice(): class spice():
""" """
This provides a set of useful generic types for hierarchy This provides a set of useful generic types for hierarchy
@ -42,7 +43,7 @@ class spice():
# Keep track of any comments to add the the spice # Keep track of any comments to add the the spice
try: try:
self.commments self.commments
except: except AttributeError:
self.comments = [] self.comments = []
self.sp_read() self.sp_read()
@ -56,7 +57,7 @@ class spice():
try: try:
self.commments self.commments
except: except AttributeError:
self.comments = [] self.comments = []
self.comments.append(comment) self.comments.append(comment)
@ -65,7 +66,9 @@ class spice():
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name) self.pins.append(name)
self.pin_type[name]=pin_type self.pin_type[name]=pin_type
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type)) debug.check(pin_type in self.valid_signal_types,
"Invalid signaltype for {0}: {1}".format(name,
pin_type))
def add_pin_list(self, pin_list, pin_type="INOUT"): def add_pin_list(self, pin_list, pin_type="INOUT"):
""" Adds a pin_list to the pins list """ """ Adds a pin_list to the pins list """
@ -73,19 +76,25 @@ class spice():
# or a list that is the same length as the pin list. # or a list that is the same length as the pin list.
if type(pin_type)==str: if type(pin_type)==str:
for pin in pin_list: for pin in pin_list:
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type)) debug.check(pin_type in self.valid_signal_types,
"Invalid signaltype for {0}: {1}".format(pin,
pin_type))
self.add_pin(pin, pin_type) self.add_pin(pin, pin_type)
elif len(pin_type)==len(pin_list): elif len(pin_type)==len(pin_list):
for (pin, ptype) in zip(pin_list, pin_type): for (pin, ptype) in zip(pin_list, pin_type):
debug.check(ptype in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,ptype)) debug.check(ptype in self.valid_signal_types,
"Invalid signaltype for {0}: {1}".format(pin,
ptype))
self.add_pin(pin, ptype) self.add_pin(pin, ptype)
else: else:
debug.error("Mismatch in type and pin list lengths.", -1) debug.error("Mismatch in type and pin list lengths.", -1)
def add_pin_types(self, type_list): def add_pin_types(self, type_list):
"""Add pin types for all the cell's pins. """
Typically, should only be used for handmade cells.""" Add pin types for all the cell's pins.
Typically, should only be used for handmade cells.
"""
# This only works if self.pins == bitcell.pin_names # This only works if self.pins == bitcell.pin_names
if self.pin_names != self.pins: if self.pin_names != self.pins:
debug.error("{} spice subcircuit port names do not match pin_names\ debug.error("{} spice subcircuit port names do not match pin_names\
@ -97,7 +106,8 @@ class spice():
def get_pin_type(self, name): def get_pin_type(self, name):
""" Returns the type of the signal pin. """ """ Returns the type of the signal pin. """
pin_type = self.pin_type[name] pin_type = self.pin_type[name]
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type)) debug.check(pin_type in self.valid_signal_types,
"Invalid signaltype for {0}: {1}".format(name, pin_type))
return pin_type return pin_type
def get_pin_dir(self, name): def get_pin_dir(self, name):
@ -125,7 +135,6 @@ class spice():
output_list.append(pin) output_list.append(pin)
return output_list return output_list
def copy_pins(self, other_module, suffix=""): def copy_pins(self, other_module, suffix=""):
""" This will copy all of the pins from the other module and add an optional suffix.""" """ This will copy all of the pins from the other module and add an optional suffix."""
for pin in other_module.pins: for pin in other_module.pins:
@ -144,7 +153,6 @@ class spice():
"""Adds a subckt/submodule to the subckt hierarchy""" """Adds a subckt/submodule to the subckt hierarchy"""
self.mods.append(mod) self.mods.append(mod)
def connect_inst(self, args, check=True): def connect_inst(self, args, check=True):
"""Connects the pins of the last instance added """Connects the pins of the last instance added
It is preferred to use the function with the check to find if It is preferred to use the function with the check to find if
@ -182,8 +190,10 @@ class spice():
return None return None
def sp_read(self): def sp_read(self):
"""Reads the sp file (and parse the pins) from the library """
Otherwise, initialize it to null for dynamic generation""" Reads the sp file (and parse the pins) from the library
Otherwise, initialize it to null for dynamic generation
"""
if self.sp_file and os.path.isfile(self.sp_file): if self.sp_file and os.path.isfile(self.sp_file):
debug.info(3, "opening {0}".format(self.sp_file)) debug.info(3, "opening {0}".format(self.sp_file))
f = open(self.sp_file) f = open(self.sp_file)
@ -200,9 +210,28 @@ class spice():
else: else:
self.spice = [] self.spice = []
# We don't define self.lvs and will use self.spice if dynamically created
# or they are the same file
if self.lvs_file!=self.sp_file and os.path.isfile(self.lvs_file):
debug.info(3, "opening {0}".format(self.lvs_file))
f = open(self.lvs_file)
self.lvs = f.readlines()
for i in range(len(self.lvs)):
self.lvs[i] = self.lvs[i].rstrip(" \n")
f.close()
# pins and subckt should be the same
# find the correct subckt line in the file
subckt = re.compile("^.subckt {}".format(self.name), re.IGNORECASE)
subckt_line = list(filter(subckt.search, self.lvs))[0]
# parses line into ports and remove subckt
lvs_pins = subckt_line.split(" ")[2:]
debug.check(lvs_pins == self.pins, "LVS and spice file pin mismatch.")
def check_net_in_spice(self, net_name): def check_net_in_spice(self, net_name):
"""Checks if a net name exists in the current. Intended to be check nets in hand-made cells.""" """Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
#Remove spaces and lower case then add spaces. Nets are separated by spaces. # Remove spaces and lower case then add spaces.
# Nets are separated by spaces.
net_formatted = ' ' + net_name.lstrip().rstrip().lower() + ' ' net_formatted = ' ' + net_name.lstrip().rstrip().lower() + ' '
for line in self.spice: for line in self.spice:
# Lowercase the line and remove any part of the line that is a comment. # Lowercase the line and remove any part of the line that is a comment.
@ -228,23 +257,24 @@ class spice():
return True return True
return False return False
def sp_write_file(self, sp, usedMODS): def sp_write_file(self, sp, usedMODS, lvs_netlist=False):
""" Recursive spice subcircuit write; """
Writes the spice subcircuit from the library or the dynamically generated one""" Recursive spice subcircuit write;
Writes the spice subcircuit from the library or the dynamically generated one
"""
if not self.spice: if not self.spice:
# recursively write the modules # recursively write the modules
for i in self.mods: for i in self.mods:
if self.contains(i, usedMODS): if self.contains(i, usedMODS):
continue continue
usedMODS.append(i) usedMODS.append(i)
i.sp_write_file(sp, usedMODS) i.sp_write_file(sp, usedMODS, lvs_netlist)
if len(self.insts) == 0: if len(self.insts) == 0:
return return
if self.pins == []: if self.pins == []:
return return
# write out the first spice line (the subcircuit) # write out the first spice line (the subcircuit)
sp.write("\n.SUBCKT {0} {1}\n".format(self.name, sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
" ".join(self.pins))) " ".join(self.pins)))
@ -264,18 +294,19 @@ class spice():
debug.error("-----") debug.error("-----")
debug.error("Connections: \n" + str(self.conns), 1) debug.error("Connections: \n" + str(self.conns), 1)
for i in range(len(self.insts)): for i in range(len(self.insts)):
# we don't need to output connections of empty instances. # we don't need to output connections of empty instances.
# these are wires and paths # these are wires and paths
if self.conns[i] == []: if self.conns[i] == []:
continue continue
if hasattr(self.insts[i].mod,"spice_device"): if lvs_netlist and hasattr(self.insts[i].mod, "lvs_device"):
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name,
" ".join(self.conns[i])))
sp.write("\n")
elif hasattr(self.insts[i].mod, "spice_device"):
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name, sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name,
" ".join(self.conns[i]))) " ".join(self.conns[i])))
sp.write("\n") sp.write("\n")
else: else:
sp.write("X{0} {1} {2}\n".format(self.insts[i].name, sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
" ".join(self.conns[i]), " ".join(self.conns[i]),
@ -288,6 +319,9 @@ class spice():
# Including the file path makes the unit test fail for other users. # Including the file path makes the unit test fail for other users.
# if os.path.isfile(self.sp_file): # if os.path.isfile(self.sp_file):
# sp.write("\n* {0}\n".format(self.sp_file)) # sp.write("\n* {0}\n".format(self.sp_file))
if lvs_netlist and hasattr(self, "lvs"):
sp.write("\n".join(self.lvs))
else:
sp.write("\n".join(self.spice)) sp.write("\n".join(self.spice))
sp.write("\n") sp.write("\n")
@ -302,10 +336,21 @@ class spice():
del usedMODS del usedMODS
spfile.close() spfile.close()
def lvs_write(self, spname):
"""Writes the lvs to files"""
debug.info(3, "Writing to {0}".format(spname))
spfile = open(spname, 'w')
spfile.write("*FIRST LINE IS A COMMENT\n")
usedMODS = list()
self.sp_write_file(spfile, usedMODS, True)
del usedMODS
spfile.close()
def analytical_delay(self, corner, slew, load=0.0): def analytical_delay(self, corner, slew, load=0.0):
"""Inform users undefined delay module while building new modules""" """Inform users undefined delay module while building new modules"""
# FIXME: Slew is not used in the model right now. Can be added heuristically as linear factor # FIXME: Slew is not used in the model right now.
# Can be added heuristically as linear factor
relative_cap = logical_effort.convert_farad_to_relative_c(load) relative_cap = logical_effort.convert_farad_to_relative_c(load)
stage_effort = self.get_stage_effort(relative_cap) stage_effort = self.get_stage_effort(relative_cap)
@ -403,7 +448,9 @@ class spice():
thermal_voltage_nom = 0.008625 * tech.spice["nom_temperature"] thermal_voltage_nom = 0.008625 * tech.spice["nom_temperature"]
thermal_voltage = 0.008625 * temp thermal_voltage = 0.008625 * temp
vthresh = (tech.spice["nom_threshold"] + 2 * (thermal_voltage - thermal_voltage_nom)) vthresh = (tech.spice["nom_threshold"] + 2 * (thermal_voltage - thermal_voltage_nom))
#Calculate effect on Vdd-Vth. The current vdd is not used here. A separate vdd factor is calculated. # Calculate effect on Vdd-Vth.
# The current vdd is not used here.
# A separate vdd factor is calculated.
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"]) / (tech.spice["nom_supply_voltage"] - vthresh) return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"]) / (tech.spice["nom_supply_voltage"] - vthresh)
def return_delay(self, delay, slew): def return_delay(self, delay, slew):
@ -420,7 +467,8 @@ class spice():
net_vswing = vdd * swing net_vswing = vdd * swing
power_dyn = c * vdd * net_vswing * freq power_dyn = c * vdd * net_vswing * freq
#Apply process and temperature factors. Roughly, process and Vdd affect the delay which affects the power. # A pply process and temperature factors.
# Roughly, process and Vdd affect the delay which affects the power.
# No other estimations are currently used. Increased delay->slower freq.->less power # No other estimations are currently used. Increased delay->slower freq.->less power
proc_div = max(self.get_process_delay_factor(proc)) proc_div = max(self.get_process_delay_factor(proc))
temp_div = self.get_temp_delay_factor(temp) temp_div = self.get_temp_delay_factor(temp)

View File

@ -7,7 +7,7 @@
# #
import contact import contact
import debug import debug
from tech import drc, parameter from tech import drc, parameter, layer
from vector import vector from vector import vector
from ptx import ptx from ptx import ptx
from globals import OPTS from globals import OPTS
@ -975,6 +975,7 @@ class pbitcell(bitcell_base.bitcell_base):
""" """
Connects wells between ptx modules and places well contacts Connects wells between ptx modules and places well contacts
""" """
if "pwell" in layer:
# extend pwell to encompass entire nmos region of the cell up to the # extend pwell to encompass entire nmos region of the cell up to the
# height of the tallest nmos transistor # height of the tallest nmos transistor
max_nmos_well_height = max(self.inverter_nmos.well_height, max_nmos_well_height = max(self.inverter_nmos.well_height,
@ -993,6 +994,7 @@ class pbitcell(bitcell_base.bitcell_base):
# extend nwell to encompass inverter_pmos # extend nwell to encompass inverter_pmos
# calculate offset of the left pmos well # calculate offset of the left pmos well
if "nwell" in layer:
inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \ inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
- self.nwell_enclose_active - self.nwell_enclose_active
inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \ inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \

View File

@ -45,7 +45,7 @@ class lib:
""" Determine the load/slews if they aren't specified in the config file. """ """ Determine the load/slews if they aren't specified in the config file. """
# These are the parameters to determine the table sizes # These are the parameters to determine the table sizes
#self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8]) #self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
self.load_scales = np.array([0.25, 1, 8]) self.load_scales = np.array([0.25, 1, 4])
#self.load_scales = np.array([0.25, 1]) #self.load_scales = np.array([0.25, 1])
self.load = tech.spice["dff_in_cap"] self.load = tech.spice["dff_in_cap"]
self.loads = self.load_scales*self.load self.loads = self.load_scales*self.load
@ -621,17 +621,12 @@ class lib:
)) ))
# information of checks # information of checks
from hierarchy_design import total_drc_errors (drc_errors, lvs_errors) = self.sram.DRC_LVS(final_verification=True)
from hierarchy_design import total_lvs_errors datasheet.write("{0},{1},".format(drc_errors, lvs_errors))
DRC = 'skipped'
LVS = 'skipped'
if OPTS.check_lvsdrc:
DRC = str(total_drc_errors)
LVS = str(total_lvs_errors)
datasheet.write("{0},{1},".format(DRC, LVS))
# write area # write area
datasheet.write(str(self.sram.width * self.sram.height) + ',') datasheet.write(str(self.sram.width * self.sram.height) + ',')
# write timing information for all ports # write timing information for all ports
for port in self.all_ports: for port in self.all_ports:
#din timings #din timings

View File

@ -91,8 +91,8 @@ class dff_buf(design.design):
def create_instances(self): def create_instances(self):
self.dff_inst=self.add_inst(name="dff_buf_dff", self.dff_inst=self.add_inst(name="dff_buf_dff",
mod=self.dff) mod=self.dff)
self.connect_inst(props.dff_buff.buf_ports)
#self.connect_inst(["D", "qint", "clk", "vdd", "gnd"]) self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
self.inv1_inst=self.add_inst(name="dff_buf_inv1", self.inv1_inst=self.add_inst(name="dff_buf_inv1",
mod=self.inv1) mod=self.inv1)

View File

@ -25,8 +25,7 @@ class hierarchical_decoder(design.design):
self.pre2x4_inst = [] self.pre2x4_inst = []
self.pre3x8_inst = [] self.pre3x8_inst = []
b = factory.create(module_type="bitcell") (self.cell_height, self.cell_multiple) = self.find_decoder_height()
self.cell_height = b.height
self.rows = rows self.rows = rows
self.num_inputs = math.ceil(math.log(self.rows, 2)) self.num_inputs = math.ceil(math.log(self.rows, 2))
(self.no_of_pre2x4, self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs) (self.no_of_pre2x4, self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
@ -35,6 +34,24 @@ class hierarchical_decoder(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def find_decoder_height(self):
b = factory.create(module_type="bitcell")
# Old behavior
return (b.height, 1)
# Search for the smallest multiple that works
cell_multiple = 1
while cell_multiple < 3:
cell_height = cell_multiple * b.height
and3 = factory.create(module_type="pand3",
height=cell_height)
(drc_errors, lvs_errors) = and3.DRC_LVS(force_check=True)
if drc_errors + lvs_errors == 0:
return (cell_height, cell_multiple)
cell_multiple += 1
else:
debug.error("Couldn't find a valid decoder height multiple.", -1)
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
self.setup_netlist_constants() self.setup_netlist_constants()

View File

@ -73,11 +73,12 @@ class precharge_array(design.design):
def add_layout_pins(self): def add_layout_pins(self):
en_bar_pin = self.pc_cell.get_pin("en_bar")
self.add_layout_pin(text="en_bar", self.add_layout_pin(text="en_bar",
layer="m1", layer=en_bar_pin.layer,
offset=self.pc_cell.get_pin("en_bar").ll(), offset=en_bar_pin.ll(),
width=self.width, width=self.width,
height=drc("minwidth_m1")) height=en_bar_pin.height())
for inst in self.local_insts: for inst in self.local_insts:
self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "vdd")

View File

@ -215,7 +215,7 @@ class pnand3(pgate.pgate):
position="center") position="center")
# FIXME: constant hack # FIXME: constant hack
self.inputC_yoffset = self.inputB_yoffset - 1.1 * m1_pitch self.inputC_yoffset = self.inputB_yoffset - 1.15 * m1_pitch
self.route_input_gate(self.pmos3_inst, self.route_input_gate(self.pmos3_inst,
self.nmos3_inst, self.nmos3_inst,
self.inputC_yoffset, self.inputC_yoffset,
@ -223,7 +223,7 @@ class pnand3(pgate.pgate):
position="center") position="center")
# FIXME: constant hack # FIXME: constant hack
self.inputA_yoffset = self.inputB_yoffset + 1.1 * m1_pitch self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
self.route_input_gate(self.pmos1_inst, self.route_input_gate(self.pmos1_inst,
self.nmos1_inst, self.nmos1_inst,
self.inputA_yoffset, self.inputA_yoffset,

View File

@ -111,7 +111,7 @@ class precharge(design.design):
vertical=True) vertical=True)
# Hack for li layers # Hack for li layers
if OPTS.tech_name == "s8": if hasattr(self, "li_stack"):
self.add_via_center(layers=self.li_stack, self.add_via_center(layers=self.li_stack,
offset=self.well_contact_pos) offset=self.well_contact_pos)
@ -166,7 +166,7 @@ class precharge(design.design):
Connects the upper and lower pmos together Connects the upper and lower pmos together
""" """
offset = self.lower_pmos_inst.get_pin("G").ll() offset = self.lower_pmos_inst.get_pin("G").ul()
# connects the top and bottom pmos' gates together # connects the top and bottom pmos' gates together
ylength = self.upper_pmos1_inst.get_pin("G").ll().y - offset.y ylength = self.upper_pmos1_inst.get_pin("G").ll().y - offset.y
self.add_rect(layer="poly", self.add_rect(layer="poly",
@ -198,6 +198,9 @@ class precharge(design.design):
if self.en_layer == "m2": if self.en_layer == "m2":
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=offset) offset=offset)
if hasattr(self, "li_stack"):
self.add_via_center(layers=self.li_stack,
offset=offset)
# adds the en rail on metal1 # adds the en rail on metal1
self.add_layout_pin_segment_center(text="en_bar", self.add_layout_pin_segment_center(text="en_bar",
@ -220,6 +223,9 @@ class precharge(design.design):
offset=self.well_contact_pos, offset=self.well_contact_pos,
implant_type="n", implant_type="n",
well_type="n") well_type="n")
if hasattr(self, "li_stack"):
self.add_via_center(layers=self.li_stack,
offset=self.well_contact_pos)
self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space

View File

@ -12,6 +12,8 @@ from vector import vector
from sram_factory import factory from sram_factory import factory
import contact import contact
import logical_effort import logical_effort
import os
from globals import OPTS
class ptx(design.design): class ptx(design.design):
@ -101,12 +103,22 @@ class ptx(design.design):
dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir] dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
self.add_pin_list(pin_list, dir_list) self.add_pin_list(pin_list, dir_list)
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
# " ".join(self.pins)))
# Just make a guess since these will actually # Just make a guess since these will actually
# be decided in the layout later. # be decided in the layout later.
area_sd = 2.5 * self.poly_width * self.tx_width area_sd = 2.5 * self.poly_width * self.tx_width
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
if OPTS.tech_name == "s8":
print("here {0}".format(self.name))
# s8 technology is in microns
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
# Perimeters are in microns
# Area is in u since it is microns square
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
area_sd)
else:
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type], main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults, self.mults,
self.tx_width, self.tx_width,
@ -115,7 +127,14 @@ class ptx(design.design):
area_sd) area_sd)
self.spice_device = main_str + area_str self.spice_device = main_str + area_str
self.spice.append("\n* ptx " + self.spice_device) self.spice.append("\n* ptx " + self.spice_device)
# self.spice.append(".ENDS {0}".format(self.name))
# LVS lib is always in SI units
if os.path.exists(OPTS.openram_tech + "lvs_lib"):
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
def setup_layout_constants(self): def setup_layout_constants(self):
""" """
@ -197,6 +216,8 @@ class ptx(design.design):
# The well is not included in the height and width # The well is not included in the height and width
self.height = self.poly_height self.height = self.poly_height
self.width = self.active_width self.width = self.active_width
self.well_height = self.height
self.well_width = self.width
# This is the center of the first active contact offset (centered vertically) # This is the center of the first active contact offset (centered vertically)
self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width, self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width,

View File

@ -51,6 +51,9 @@ class sram():
def sp_write(self, name): def sp_write(self, name):
self.s.sp_write(name) self.s.sp_write(name)
def lvs_write(self, name):
self.s.lvs_write(name)
def lef_write(self, name): def lef_write(self, name):
self.s.lef_write(name) self.s.lef_write(name)

View File

@ -121,7 +121,7 @@ class sram_base(design, verilog, lef):
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
# We only enable final verification if we have routed the design # We only enable final verification if we have routed the design
self.DRC_LVS(final_verification=OPTS.route_supplies, top_level=True) self.DRC_LVS(final_verification=OPTS.route_supplies)
if not OPTS.is_unit_test: if not OPTS.is_unit_test:
print_time("Verification", datetime.datetime.now(), start_time) print_time("Verification", datetime.datetime.now(), start_time)
@ -561,7 +561,7 @@ class sram_base(design, verilog, lef):
self.add_via_center(layers=self.m2_stack, self.add_via_center(layers=self.m2_stack,
offset=out_pos) offset=out_pos)
def sp_write(self, sp_name): def sp_write(self, sp_name, lvs_netlist=False):
# Write the entire spice of the object to the file # Write the entire spice of the object to the file
############################################################ ############################################################
# Spice circuit # Spice circuit
@ -581,10 +581,13 @@ class sram_base(design, verilog, lef):
# sp.write(".global {0} {1}\n".format(spice["vdd_name"], # sp.write(".global {0} {1}\n".format(spice["vdd_name"],
# spice["gnd_name"])) # spice["gnd_name"]))
usedMODS = list() usedMODS = list()
self.sp_write_file(sp, usedMODS) self.sp_write_file(sp, usedMODS, lvs_netlist=lvs_netlist)
del usedMODS del usedMODS
sp.close() sp.close()
def lvs_write(self, sp_name):
self.sp_write(sp_name, lvs_netlist=True)
def get_wordline_stage_efforts(self, inp_is_rise=True): def get_wordline_stage_efforts(self, inp_is_rise=True):
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline""" """Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
stage_effort_list = [] stage_effort_list = []

View File

@ -45,6 +45,8 @@ class library_lvs_test(openram_test):
def setup_files(): def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib" gds_dir = OPTS.openram_tech + "/gds_lib"
sp_dir = OPTS.openram_tech + "/lvs_lib"
if not os.path.exists(sp_dir):
sp_dir = OPTS.openram_tech + "/sp_lib" sp_dir = OPTS.openram_tech + "/sp_lib"
files = os.listdir(gds_dir) files = os.listdir(gds_dir)
nametest = re.compile("\.gds$", re.IGNORECASE) nametest = re.compile("\.gds$", re.IGNORECASE)

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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 unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class precharge_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check precharge in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(tx)
factory.reset()
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -15,6 +15,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class precharge_test(openram_test): class precharge_test(openram_test):
def runTest(self): def runTest(self):
@ -26,27 +27,6 @@ class precharge_test(openram_test):
tx = factory.create(module_type="precharge", size=1) tx = factory.create(module_type="precharge", size=1)
self.local_check(tx) self.local_check(tx)
# check precharge in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(tx)
factory.reset()
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -0,0 +1,73 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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 unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class hierarchical_decoder_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check hierarchical decoder for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
factory.reset()
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=17)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=23)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=65)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=341)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -63,49 +63,6 @@ class hierarchical_decoder_test(openram_test):
a = factory.create(module_type="hierarchical_decoder", rows=512) a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a) self.local_check(a)
# check hierarchical decoder for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
factory.reset()
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=17)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=23)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=65)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=341)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 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 unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class precharge_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check precharge array in multi-port
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
# pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0")
# self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
# pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2")
# self.local_check(pc)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -26,25 +26,6 @@ class precharge_test(openram_test):
pc = factory.create(module_type="precharge_array", columns=3) pc = factory.create(module_type="precharge_array", columns=3)
self.local_check(pc) self.local_check(pc)
# check precharge array in multi-port
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
# pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0")
# self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
# pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2")
# self.local_check(pc)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -19,7 +19,9 @@ class verilog_test(openram_test):
def runTest(self): def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.route_supplies=False
OPTS.check_lvsdrc=False
OPTS.netlist_only=True
from sram import sram from sram import sram
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=2, c = sram_config(word_size=2,

View File

@ -39,7 +39,7 @@ class openram_test(unittest.TestCase):
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name) tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
a.sp_write(tempspice) a.lvs_write(tempspice)
# cannot write gds in netlist_only mode # cannot write gds in netlist_only mode
if not OPTS.netlist_only: if not OPTS.netlist_only:
a.gds_write(tempgds) a.gds_write(tempgds)

View File

@ -16,6 +16,7 @@ drc_warned = False
lvs_warned = False lvs_warned = False
pex_warned = False pex_warned = False
def run_drc(cell_name, gds_name, extract=False, final_verification=False): def run_drc(cell_name, gds_name, extract=False, final_verification=False):
global drc_warned global drc_warned
if not drc_warned: if not drc_warned:
@ -24,6 +25,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
# Since we warned, return a failing test. # Since we warned, return a failing test.
return 1 return 1
def run_lvs(cell_name, gds_name, sp_name, final_verification=False): def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global lvs_warned global lvs_warned
if not lvs_warned: if not lvs_warned:
@ -32,6 +34,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
# Since we warned, return a failing test. # Since we warned, return a failing test.
return 1 return 1
def run_pex(name, gds_name, sp_name, output=None, final_verification=False): def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
global pex_warned global pex_warned
if not pex_warned: if not pex_warned:
@ -40,9 +43,14 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
# Since we warned, return a failing test. # Since we warned, return a failing test.
return 1 return 1
def print_drc_stats(): def print_drc_stats():
pass pass
def print_lvs_stats(): def print_lvs_stats():
pass pass
def print_pex_stats(): def print_pex_stats():
pass pass