mirror of https://github.com/VLSIDA/OpenRAM.git
Merged with dev, fixed conflict in ptx
This commit is contained in:
commit
4103745de2
|
|
@ -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,118 +24,155 @@ 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)
|
||||||
self.init_graph_params()
|
self.init_graph_params()
|
||||||
|
|
||||||
def get_layout_pins(self,inst):
|
def get_layout_pins(self, inst):
|
||||||
""" Return a map of pin locations of the instance offset """
|
""" Return a map of pin locations of the instance offset """
|
||||||
# find the instance
|
# find the instance
|
||||||
for i in self.insts:
|
for i in self.insts:
|
||||||
if i.name == inst.name:
|
if i.name == inst.name:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
debug.error("Couldn't find instance {0}".format(inst_name),-1)
|
debug.error("Couldn't find instance {0}".format(inst_name), -1)
|
||||||
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
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
||||||
global total_lvs_errors
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp,self.name)
|
self.lvs_write(tempspice)
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
|
||||||
self.sp_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.lvs_write(tempspice)
|
||||||
self.sp_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
|
||||||
self.graph_inst_exclude = set()
|
self.graph_inst_exclude = set()
|
||||||
|
|
||||||
def build_graph(self, graph, inst_name, port_nets):
|
def build_graph(self, graph, inst_name, port_nets):
|
||||||
"""Recursively create graph from instances in module."""
|
"""Recursively create graph from instances in module."""
|
||||||
|
|
||||||
#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,
|
||||||
port_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
|
self.pins),
|
||||||
|
1)
|
||||||
|
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):
|
||||||
if subinst in self.graph_inst_exclude:
|
if subinst in self.graph_inst_exclude:
|
||||||
continue
|
continue
|
||||||
subinst_name = inst_name+'.X'+subinst.name
|
subinst_name = inst_name + '.X' + subinst.name
|
||||||
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
|
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
|
||||||
subinst.mod.build_graph(graph, subinst_name, subinst_ports)
|
subinst.mod.build_graph(graph, subinst_name, subinst_ports)
|
||||||
|
|
||||||
def build_names(self, name_dict, inst_name, port_nets):
|
def build_names(self, name_dict, inst_name, port_nets):
|
||||||
"""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,
|
||||||
port_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
|
self.pins),
|
||||||
|
1)
|
||||||
|
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):
|
||||||
subinst_name = inst_name+'.X'+subinst.name
|
subinst_name = inst_name + '.X' + subinst.name
|
||||||
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
|
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
|
||||||
for si_port, conn in zip(subinst_ports, conns):
|
for si_port, conn in zip(subinst_ports, conns):
|
||||||
#Only add for first occurrence
|
# Only add for first occurrence
|
||||||
if si_port.lower() not in name_dict:
|
if si_port.lower() not in name_dict:
|
||||||
mod_info = {'mod':self, 'int_net':conn}
|
mod_info = {'mod': self, 'int_net': conn}
|
||||||
name_dict[si_port.lower()] = mod_info
|
name_dict[si_port.lower()] = mod_info
|
||||||
subinst.mod.build_names(name_dict, subinst_name, subinst_ports)
|
subinst.mod.build_names(name_dict, subinst_name, subinst_ports)
|
||||||
|
|
||||||
|
|
@ -167,11 +200,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
"""Checks if the alias_net in input mod is the same as the input net for this mod (self)."""
|
"""Checks if the alias_net in input mod is the same as the input net for this mod (self)."""
|
||||||
if self in exclusion_set:
|
if self in exclusion_set:
|
||||||
return False
|
return False
|
||||||
#Check ports of this mod
|
# Check ports of this mod
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
if self.is_net_alias_name_check(known_net, pin, net_alias, mod):
|
if self.is_net_alias_name_check(known_net, pin, net_alias, mod):
|
||||||
return True
|
return True
|
||||||
#Check connections of all other subinsts
|
# Check connections of all other subinsts
|
||||||
mod_set = set()
|
mod_set = set()
|
||||||
for subinst, inst_conns in zip(self.insts, self.conns):
|
for subinst, inst_conns in zip(self.insts, self.conns):
|
||||||
for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins):
|
for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins):
|
||||||
|
|
@ -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
|
||||||
|
|
@ -210,15 +245,15 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
def add_graph_edges(self, graph, port_nets):
|
def add_graph_edges(self, graph, port_nets):
|
||||||
"""For every input, adds an edge to every output.
|
"""For every input, adds an edge to every output.
|
||||||
Only intended to be used for gates and other simple modules."""
|
Only intended to be used for gates and other simple modules."""
|
||||||
#The final pin names will depend on the spice hierarchy, so
|
# The final pin names will depend on the spice hierarchy, so
|
||||||
#they are passed as an input.
|
# they are passed as an input.
|
||||||
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
|
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
|
||||||
input_pins = self.get_inputs()
|
input_pins = self.get_inputs()
|
||||||
output_pins = self.get_outputs()
|
output_pins = self.get_outputs()
|
||||||
inout_pins = self.get_inouts()
|
inout_pins = self.get_inouts()
|
||||||
for inp in input_pins+inout_pins:
|
for inp in input_pins + inout_pins:
|
||||||
for out in output_pins+inout_pins:
|
for out in output_pins + inout_pins:
|
||||||
if inp != out: #do not add self loops
|
if inp != out: # do not add self loops
|
||||||
graph.add_edge(pin_dict[inp], pin_dict[out], self)
|
graph.add_edge(pin_dict[inp], pin_dict[out], self)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
@ -236,8 +271,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n"
|
text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n"
|
||||||
for i in self.objs:
|
for i in self.objs:
|
||||||
text+=str(i)+",\n"
|
text+=str(i) + ",\n"
|
||||||
for i in self.insts:
|
for i in self.insts:
|
||||||
text+=str(i)+",\n"
|
text+=str(i) + ",\n"
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,36 +76,43 @@ 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,
|
||||||
self.add_pin(pin,pin_type)
|
"Invalid signaltype for {0}: {1}".format(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,
|
||||||
self.add_pin(pin,ptype)
|
"Invalid signaltype for {0}: {1}".format(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.
|
||||||
#This only works if self.pins == bitcell.pin_names
|
Typically, should only be used for handmade cells.
|
||||||
|
"""
|
||||||
|
# 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\
|
||||||
\n SPICE names={}\
|
\n SPICE names={}\
|
||||||
\n Module names={}\
|
\n Module names={}\
|
||||||
".format(self.name, self.pin_names, self.pins),1)
|
".format(self.name, self.pin_names, self.pins), 1)
|
||||||
self.pin_type = {pin:type for pin,type in zip(self.pin_names, type_list)}
|
self.pin_type = {pin: type for pin, type in zip(self.pin_names, type_list)}
|
||||||
|
|
||||||
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):
|
||||||
""" Returns the direction of the pin. (Supply/ground are INOUT). """
|
""" Returns the direction of the pin. (Supply/ground are INOUT). """
|
||||||
if self.pin_type[name] in ["POWER","GROUND"]:
|
if self.pin_type[name] in ["POWER", "GROUND"]:
|
||||||
return "INOUT"
|
return "INOUT"
|
||||||
else:
|
else:
|
||||||
return self.pin_type[name]
|
return self.pin_type[name]
|
||||||
|
|
@ -125,11 +135,10 @@ 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:
|
||||||
self.add_pin(pin+suffix, other_module.get_pin_type(pin))
|
self.add_pin(pin + suffix, other_module.get_pin_type(pin))
|
||||||
|
|
||||||
def get_inouts(self):
|
def get_inouts(self):
|
||||||
""" These use pin types to determine pin lists. These
|
""" These use pin types to determine pin lists. These
|
||||||
|
|
@ -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
|
||||||
|
|
@ -169,21 +177,23 @@ class spice():
|
||||||
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
||||||
len(self.insts),
|
len(self.insts),
|
||||||
len(self.conns)))
|
len(self.conns)))
|
||||||
debug.error("Instances: \n"+str(insts_string))
|
debug.error("Instances: \n" + str(insts_string))
|
||||||
debug.error("-----")
|
debug.error("-----")
|
||||||
debug.error("Connections: \n"+str(conns_string),1)
|
debug.error("Connections: \n" + str(conns_string), 1)
|
||||||
|
|
||||||
def get_conns(self, inst):
|
def get_conns(self, inst):
|
||||||
"""Returns the connections of a given instance."""
|
"""Returns the connections of a given instance."""
|
||||||
for i in range(len(self.insts)):
|
for i in range(len(self.insts)):
|
||||||
if inst is self.insts[i]:
|
if inst is self.insts[i]:
|
||||||
return self.conns[i]
|
return self.conns[i]
|
||||||
#If not found, returns None
|
# If not found, returns None
|
||||||
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,15 +210,34 @@ 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.
|
||||||
net_formatted = ' '+net_name.lstrip().rstrip().lower()+' '
|
# Nets are separated by spaces.
|
||||||
|
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.
|
||||||
line = line.lower().split('*')[0]
|
line = line.lower().split('*')[0]
|
||||||
|
|
||||||
#Skip .subckt or .ENDS lines
|
# Skip .subckt or .ENDS lines
|
||||||
if line.find('.') == 0:
|
if line.find('.') == 0:
|
||||||
continue
|
continue
|
||||||
if net_formatted in line:
|
if net_formatted in line:
|
||||||
|
|
@ -228,54 +257,56 @@ 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)))
|
||||||
|
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
sp.write("* {1:6}: {0} \n".format(pin,self.pin_type[pin]))
|
sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin]))
|
||||||
|
|
||||||
for line in self.comments:
|
for line in self.comments:
|
||||||
sp.write("* {}\n".format(line))
|
sp.write("* {}\n".format(line))
|
||||||
|
|
||||||
# every instance must have a set of connections, even if it is empty.
|
# every instance must have a set of connections, even if it is empty.
|
||||||
if len(self.insts)!=len(self.conns):
|
if len(self.insts) != len(self.conns):
|
||||||
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
||||||
len(self.insts),
|
len(self.insts),
|
||||||
len(self.conns)))
|
len(self.conns)))
|
||||||
debug.error("Instances: \n"+str(self.insts))
|
debug.error("Instances: \n" + str(self.insts))
|
||||||
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]),
|
||||||
|
|
@ -286,9 +317,12 @@ class spice():
|
||||||
else:
|
else:
|
||||||
# write the subcircuit itself
|
# write the subcircuit itself
|
||||||
# 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))
|
||||||
sp.write("\n".join(self.spice))
|
if lvs_netlist and hasattr(self, "lvs"):
|
||||||
|
sp.write("\n".join(self.lvs))
|
||||||
|
else:
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
@ -316,7 +361,7 @@ class spice():
|
||||||
abs_delay = stage_effort.get_absolute_delay()
|
abs_delay = stage_effort.get_absolute_delay()
|
||||||
corner_delay = self.apply_corners_analytically(abs_delay, corner)
|
corner_delay = self.apply_corners_analytically(abs_delay, corner)
|
||||||
SLEW_APPROXIMATION = 0.1
|
SLEW_APPROXIMATION = 0.1
|
||||||
corner_slew = SLEW_APPROXIMATION*corner_delay
|
corner_slew = SLEW_APPROXIMATION * corner_delay
|
||||||
return delay_data(corner_delay, corner_slew)
|
return delay_data(corner_delay, corner_slew)
|
||||||
|
|
||||||
def get_stage_effort(self, cout, inp_is_rise=True):
|
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||||
|
|
@ -346,15 +391,15 @@ class spice():
|
||||||
self.name))
|
self.name))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def cal_delay_with_rc(self, corner, r, c ,slew, swing = 0.5):
|
def cal_delay_with_rc(self, corner, r, c, slew, swing=0.5):
|
||||||
"""
|
"""
|
||||||
Calculate the delay of a mosfet by
|
Calculate the delay of a mosfet by
|
||||||
modeling it as a resistance driving a capacitance
|
modeling it as a resistance driving a capacitance
|
||||||
"""
|
"""
|
||||||
swing_factor = abs(math.log(1-swing)) # time constant based on swing
|
swing_factor = abs(math.log(1 - swing)) # time constant based on swing
|
||||||
delay = swing_factor * r * c #c is in ff and delay is in fs
|
delay = swing_factor * r * c # c is in ff and delay is in fs
|
||||||
delay = self.apply_corners_analytically(delay, corner)
|
delay = self.apply_corners_analytically(delay, corner)
|
||||||
delay = delay * 0.001 #make the unit to ps
|
delay = delay * 0.001 # make the unit to ps
|
||||||
|
|
||||||
# Output slew should be linear to input slew which is described
|
# Output slew should be linear to input slew which is described
|
||||||
# as 0.005* slew.
|
# as 0.005* slew.
|
||||||
|
|
@ -364,12 +409,12 @@ class spice():
|
||||||
# The mimum slew should be the time to charge RC.
|
# The mimum slew should be the time to charge RC.
|
||||||
# Delay * 2 is from 0 to 100% swing. 0.6*2*delay is from 20%-80%.
|
# Delay * 2 is from 0 to 100% swing. 0.6*2*delay is from 20%-80%.
|
||||||
slew = delay * 0.6 * 2 + 0.005 * slew
|
slew = delay * 0.6 * 2 + 0.005 * slew
|
||||||
return delay_data(delay = delay, slew = slew)
|
return delay_data(delay=delay, slew=slew)
|
||||||
|
|
||||||
def apply_corners_analytically(self, delay, corner):
|
def apply_corners_analytically(self, delay, corner):
|
||||||
"""Multiply delay by corner factors"""
|
"""Multiply delay by corner factors"""
|
||||||
proc,vdd,temp = corner
|
proc, vdd, temp = corner
|
||||||
#FIXME: type of delay is needed to know which process to use.
|
# FIXME: type of delay is needed to know which process to use.
|
||||||
proc_mult = max(self.get_process_delay_factor(proc))
|
proc_mult = max(self.get_process_delay_factor(proc))
|
||||||
volt_mult = self.get_voltage_delay_factor(vdd)
|
volt_mult = self.get_voltage_delay_factor(vdd)
|
||||||
temp_mult = self.get_temp_delay_factor(temp)
|
temp_mult = self.get_temp_delay_factor(temp)
|
||||||
|
|
@ -392,39 +437,42 @@ class spice():
|
||||||
"""Returns delay increase due to voltage.
|
"""Returns delay increase due to voltage.
|
||||||
Implemented as linear factor based off nominal voltage.
|
Implemented as linear factor based off nominal voltage.
|
||||||
"""
|
"""
|
||||||
return tech.spice["nom_supply_voltage"]/voltage
|
return tech.spice["nom_supply_voltage"] / voltage
|
||||||
|
|
||||||
def get_temp_delay_factor(self, temp):
|
def get_temp_delay_factor(self, temp):
|
||||||
"""Returns delay increase due to temperature (in C).
|
"""Returns delay increase due to temperature (in C).
|
||||||
Determines effect on threshold voltage and then linear factor is estimated.
|
Determines effect on threshold voltage and then linear factor is estimated.
|
||||||
"""
|
"""
|
||||||
#Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
|
# Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
|
||||||
#(k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
|
# (k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
|
||||||
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.
|
||||||
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"])/(tech.spice["nom_supply_voltage"]-vthresh)
|
# 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)
|
||||||
|
|
||||||
def return_delay(self, delay, slew):
|
def return_delay(self, delay, slew):
|
||||||
return delay_data(delay, slew)
|
return delay_data(delay, slew)
|
||||||
|
|
||||||
def generate_rc_net(self,lump_num, wire_length, wire_width):
|
def generate_rc_net(self, lump_num, wire_length, wire_width):
|
||||||
return wire_spice_model(lump_num, wire_length, wire_width)
|
return wire_spice_model(lump_num, wire_length, wire_width)
|
||||||
|
|
||||||
def calc_dynamic_power(self, corner, c, freq, swing=1.0):
|
def calc_dynamic_power(self, corner, c, freq, swing=1.0):
|
||||||
"""
|
"""
|
||||||
Calculate dynamic power using effective capacitance, frequency, and corner (PVT)
|
Calculate dynamic power using effective capacitance, frequency, and corner (PVT)
|
||||||
"""
|
"""
|
||||||
proc,vdd,temp = corner
|
proc, vdd, temp = corner
|
||||||
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.
|
||||||
#No other estimations are currently used. Increased delay->slower freq.->less power
|
# Roughly, process and Vdd affect the delay which affects the 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)
|
||||||
power_dyn = power_dyn/(proc_div*temp_div)
|
power_dyn = power_dyn / (proc_div * temp_div)
|
||||||
|
|
||||||
return power_dyn
|
return power_dyn
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,42 +975,44 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
"""
|
"""
|
||||||
Connects wells between ptx modules and places well contacts
|
Connects wells between ptx modules and places well contacts
|
||||||
"""
|
"""
|
||||||
# extend pwell to encompass entire nmos region of the cell up to the
|
if "pwell" in layer:
|
||||||
# height of the tallest nmos transistor
|
# extend pwell to encompass entire nmos region of the cell up to the
|
||||||
max_nmos_well_height = max(self.inverter_nmos.well_height,
|
# height of the tallest nmos transistor
|
||||||
self.readwrite_nmos.well_height,
|
max_nmos_well_height = max(self.inverter_nmos.well_height,
|
||||||
self.write_nmos.well_height,
|
self.readwrite_nmos.well_height,
|
||||||
self.read_nmos.well_height)
|
self.write_nmos.well_height,
|
||||||
well_height = max_nmos_well_height + self.port_ypos \
|
self.read_nmos.well_height)
|
||||||
- self.nwell_enclose_active - self.gnd_position.y
|
well_height = max_nmos_well_height + self.port_ypos \
|
||||||
# FIXME fudge factor xpos
|
- self.nwell_enclose_active - self.gnd_position.y
|
||||||
well_width = self.width + 2*self.nwell_enclose_active
|
# FIXME fudge factor xpos
|
||||||
offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos)
|
well_width = self.width + 2*self.nwell_enclose_active
|
||||||
self.add_rect(layer="pwell",
|
offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos)
|
||||||
offset=offset,
|
self.add_rect(layer="pwell",
|
||||||
width=well_width,
|
offset=offset,
|
||||||
height=well_height)
|
width=well_width,
|
||||||
|
height=well_height)
|
||||||
|
|
||||||
# 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
|
||||||
inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
|
if "nwell" in layer:
|
||||||
- self.nwell_enclose_active
|
inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
|
||||||
inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \
|
- self.nwell_enclose_active
|
||||||
+ self.inverter_gap - self.nwell_enclose_active
|
inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \
|
||||||
|
+ self.inverter_gap - self.nwell_enclose_active
|
||||||
|
|
||||||
# calculate width of the two combined nwells
|
# calculate width of the two combined nwells
|
||||||
# calculate height to encompass nimplant connected to vdd
|
# calculate height to encompass nimplant connected to vdd
|
||||||
well_width = 2 * (self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
|
well_width = 2 * (self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \
|
||||||
+ 2 * self.nwell_enclose_active
|
+ 2 * self.nwell_enclose_active
|
||||||
well_height = self.vdd_position.y - inverter_well_ypos \
|
well_height = self.vdd_position.y - inverter_well_ypos \
|
||||||
+ self.nwell_enclose_active + drc["minwidth_tx"]
|
+ self.nwell_enclose_active + drc["minwidth_tx"]
|
||||||
|
|
||||||
# FIXME fudge factor xpos
|
# FIXME fudge factor xpos
|
||||||
offset = [inverter_well_xpos + 2*self.nwell_enclose_active, inverter_well_ypos]
|
offset = [inverter_well_xpos + 2*self.nwell_enclose_active, inverter_well_ypos]
|
||||||
self.add_rect(layer="nwell",
|
self.add_rect(layer="nwell",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=well_width,
|
width=well_width,
|
||||||
height=well_height)
|
height=well_height)
|
||||||
|
|
||||||
# add well contacts
|
# add well contacts
|
||||||
# connect pimplants to gnd
|
# connect pimplants to gnd
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,21 +103,38 @@ 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
|
||||||
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
|
if OPTS.tech_name == "s8":
|
||||||
self.mults,
|
print("here {0}".format(self.name))
|
||||||
self.tx_width,
|
# s8 technology is in microns
|
||||||
drc("minwidth_poly"))
|
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||||
area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_sd,
|
self.mults,
|
||||||
area_sd)
|
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],
|
||||||
|
self.mults,
|
||||||
|
self.tx_width,
|
||||||
|
drc("minwidth_poly"))
|
||||||
|
area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_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,
|
||||||
|
|
@ -354,10 +375,10 @@ class ptx(design.design):
|
||||||
if not (well_name in layer or "vtg" in layer):
|
if not (well_name in layer or "vtg" in layer):
|
||||||
return
|
return
|
||||||
|
|
||||||
center_pos = self.active_offset + vector(0.5*self.active_width,
|
center_pos = self.active_offset + vector(0.5 * self.active_width,
|
||||||
0.5*self.active_height)
|
0.5 * self.active_height)
|
||||||
well_ll = center_pos - vector(0.5*self.well_width,
|
well_ll = center_pos - vector(0.5 * self.well_width,
|
||||||
0.5*self.well_height)
|
0.5 * self.well_height)
|
||||||
if well_name in layer:
|
if well_name in layer:
|
||||||
self.add_rect(layer=well_name,
|
self.add_rect(layer=well_name,
|
||||||
offset=well_ll,
|
offset=well_ll,
|
||||||
|
|
@ -471,7 +492,7 @@ class ptx(design.design):
|
||||||
contact=self.add_via_center(layers=self.active_stack,
|
contact=self.add_via_center(layers=self.active_stack,
|
||||||
offset=pos,
|
offset=pos,
|
||||||
size=(1, self.num_contacts),
|
size=(1, self.num_contacts),
|
||||||
directions=("V","V"),
|
directions=("V", "V"),
|
||||||
implant_type=self.implant_type,
|
implant_type=self.implant_type,
|
||||||
well_type=self.well_type)
|
well_type=self.well_type)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 = []
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,9 @@ 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 + "/sp_lib"
|
sp_dir = OPTS.openram_tech + "/lvs_lib"
|
||||||
|
if not os.path.exists(sp_dir):
|
||||||
|
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)
|
||||||
gds_files = list(filter(nametest.search, files))
|
gds_files = list(filter(nametest.search, files))
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue