Added multiport bitcell support for storage node checks

This commit is contained in:
Hunter Nichols 2019-05-20 22:50:03 -07:00
parent 099bc4e258
commit d08181455c
5 changed files with 50 additions and 23 deletions

View File

@ -197,7 +197,12 @@ class spice():
return True
return False
def do_nets_exist(self, nets):
"""For handmade cell, checks sp file contains the storage nodes."""
nets_match = True
for net in nets:
nets_match = nets_match and self.check_net_in_spice(net)
return nets_match
def contains(self, mod, modlist):
for x in modlist:

View File

@ -20,7 +20,7 @@ class bitcell(design.design):
"""
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
internal_nets = ['Q', 'Qbar']
storage_nets = ['Q', 'Qbar']
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
@ -34,7 +34,7 @@ class bitcell(design.design):
self.height = bitcell.height
self.pin_map = bitcell.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.check_internal_nets()
self.nets_match = self.do_nets_exist(self.storage_nets)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
@ -78,21 +78,14 @@ class bitcell(design.design):
dynamic = 0 #temporary
total_power = self.return_power(dynamic, leakage)
return total_power
def check_internal_nets(self):
"""For handmade cell, checks sp file contains the storage nodes."""
nets_match = True
for net in self.internal_nets:
nets_match = nets_match and self.check_net_in_spice(net)
return nets_match
def get_storage_net_names(self):
"""Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
#Checks that they do exist
if self.nets_match:
return self.internal_nets
return self.storage_nets
else:
debug.info(1,"Storage nodes={} not found in spice file.".format(self.internal_nets))
debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
return None
def get_wl_cin(self):

View File

@ -20,7 +20,8 @@ class bitcell_1rw_1r(design.design):
"""
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar']
(width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"])
@ -33,6 +34,7 @@ class bitcell_1rw_1r(design.design):
self.height = bitcell_1rw_1r.height
self.pin_map = bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
@ -109,6 +111,15 @@ class bitcell_1rw_1r(design.design):
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def get_storage_net_names(self):
"""Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
#Checks that they do exist
if self.nets_match:
return self.storage_nets
else:
debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
return None
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""

View File

@ -20,7 +20,8 @@ class bitcell_1w_1r(design.design):
"""
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar']
(width,height) = utils.get_libcell_size("cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1w_1r", GDS["unit"])
@ -33,6 +34,7 @@ class bitcell_1w_1r(design.design):
self.height = bitcell_1w_1r.height
self.pin_map = bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
@ -109,6 +111,15 @@ class bitcell_1w_1r(design.design):
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def get_storage_net_names(self):
"""Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
#Checks that they do exist
if self.nets_match:
return self.storage_nets
else:
debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
return None
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""

View File

@ -138,7 +138,9 @@ class pbitcell(design.design):
self.Q_bar = "vdd"
else:
self.Q_bar = "Q_bar"
self.Q = "Q"
self.storage_nets = [self.Q, self.Q_bar]
def add_modules(self):
""" Determine size of transistors and add ptx modules """
# if there are any read/write ports, then the inverter nmos is sized based the number of read/write ports
@ -258,20 +260,20 @@ class pbitcell(design.design):
# create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos)
self.connect_inst(["Q", self.Q_bar, "gnd", "gnd"])
self.connect_inst([self.Q, self.Q_bar, "gnd", "gnd"])
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos)
self.connect_inst(["gnd", "Q", self.Q_bar, "gnd"])
self.connect_inst(["gnd", self.Q, self.Q_bar, "gnd"])
# create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos)
self.connect_inst(["Q", self.Q_bar, "vdd", "vdd"])
self.connect_inst([self.Q, self.Q_bar, "vdd", "vdd"])
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos)
self.connect_inst(["vdd", "Q", self.Q_bar, "vdd"])
self.connect_inst(["vdd", self.Q, self.Q_bar, "vdd"])
def place_storage(self):
""" Places the transistors for the crossed coupled inverters in the bitcell """
@ -363,7 +365,7 @@ class pbitcell(design.design):
# add read/write transistors
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
mod=self.readwrite_nmos)
self.connect_inst([self.rw_bl_names[k], self.rw_wl_names[k], "Q", "gnd"])
self.connect_inst([self.rw_bl_names[k], self.rw_wl_names[k], self.Q, "gnd"])
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
mod=self.readwrite_nmos)
@ -437,7 +439,7 @@ class pbitcell(design.design):
# add write transistors
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
mod=self.write_nmos)
self.connect_inst([self.w_bl_names[k], self.w_wl_names[k], "Q", "gnd"])
self.connect_inst([self.w_bl_names[k], self.w_wl_names[k], self.Q, "gnd"])
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
mod=self.write_nmos)
@ -522,7 +524,7 @@ class pbitcell(design.design):
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
mod=self.read_nmos)
self.connect_inst(["gnd", "Q", "RA_to_R_right{}".format(k), "gnd"])
self.connect_inst(["gnd", self.Q, "RA_to_R_right{}".format(k), "gnd"])
# add read transistors
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k),
@ -866,6 +868,11 @@ class pbitcell(design.design):
Q_bar_pos = self.inverter_pmos_right.get_pin("S").center()
vdd_pos = self.inverter_pmos_right.get_pin("D").center()
self.add_path("metal1", [Q_bar_pos, vdd_pos])
def get_storage_net_names(self):
"""Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
return self.storage_nets
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1