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 True
return False 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): def contains(self, mod, modlist):
for x in modlist: for x in modlist:

View File

@ -20,7 +20,7 @@ class bitcell(design.design):
""" """
pin_names = ["bl", "br", "wl", "vdd", "gnd"] pin_names = ["bl", "br", "wl", "vdd", "gnd"]
internal_nets = ['Q', 'Qbar'] storage_nets = ['Q', 'Qbar']
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"]) 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.height = bitcell.height
self.pin_map = bitcell.pin_map self.pin_map = bitcell.pin_map
self.add_pin_types(self.type_list) 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): def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1 parasitic_delay = 1
@ -78,21 +78,14 @@ class bitcell(design.design):
dynamic = 0 #temporary dynamic = 0 #temporary
total_power = self.return_power(dynamic, leakage) total_power = self.return_power(dynamic, leakage)
return total_power 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): def get_storage_net_names(self):
"""Returns names of storage nodes in bitcell in [non-inverting, inverting] format.""" """Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
#Checks that they do exist #Checks that they do exist
if self.nets_match: if self.nets_match:
return self.internal_nets return self.storage_nets
else: 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 return None
def get_wl_cin(self): 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"] 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"]) (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"]) 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.height = bitcell_1rw_1r.height
self.pin_map = bitcell_1rw_1r.pin_map self.pin_map = bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list) 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): def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1 parasitic_delay = 1
@ -109,6 +111,15 @@ class bitcell_1rw_1r(design.design):
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin 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): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex """Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function.""" 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"] 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"]) (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"]) 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.height = bitcell_1w_1r.height
self.pin_map = bitcell_1w_1r.pin_map self.pin_map = bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list) 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): def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1 parasitic_delay = 1
@ -109,6 +111,15 @@ class bitcell_1w_1r(design.design):
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin 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): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex """Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function.""" to use the add_graph_edges function."""

View File

@ -138,7 +138,9 @@ class pbitcell(design.design):
self.Q_bar = "vdd" self.Q_bar = "vdd"
else: else:
self.Q_bar = "Q_bar" self.Q_bar = "Q_bar"
self.Q = "Q"
self.storage_nets = [self.Q, self.Q_bar]
def add_modules(self): def add_modules(self):
""" Determine size of transistors and add ptx modules """ """ 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 # 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 # create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left", self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos) 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", self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos) 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 # create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left", self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos) 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", self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos) 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): def place_storage(self):
""" Places the transistors for the crossed coupled inverters in the bitcell """ """ Places the transistors for the crossed coupled inverters in the bitcell """
@ -363,7 +365,7 @@ class pbitcell(design.design):
# add read/write transistors # add read/write transistors
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
mod=self.readwrite_nmos) 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), self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
mod=self.readwrite_nmos) mod=self.readwrite_nmos)
@ -437,7 +439,7 @@ class pbitcell(design.design):
# add write transistors # add write transistors
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
mod=self.write_nmos) 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), self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
mod=self.write_nmos) 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), self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
mod=self.read_nmos) 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 # add read transistors
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k), 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() Q_bar_pos = self.inverter_pmos_right.get_pin("S").center()
vdd_pos = self.inverter_pmos_right.get_pin("D").center() vdd_pos = self.inverter_pmos_right.get_pin("D").center()
self.add_path("metal1", [Q_bar_pos, vdd_pos]) 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): def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1 parasitic_delay = 1