Made timing graph more gate-level. Changed edges to be defined by inputs/ouputs and name based.

This commit is contained in:
Hunter Nichols 2019-05-07 00:52:27 -07:00
parent 5bfc42fdbb
commit d54074d68e
20 changed files with 205 additions and 151 deletions

View File

@ -120,7 +120,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
#Translate port names to external nets
if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1)
port_dict = {i:j for i,j in zip(self.pins, port_nets)}
port_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns):
if subinst in self.graph_inst_exclude:
@ -139,6 +139,20 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
converted_conns.append("{}.{}".format(inst_name, conn))
return converted_conns
def add_graph_edges(self, graph, port_nets):
"""For every input, adds an edge to every output.
Only intended to be used for gates and other simple modules."""
#The final pin names will depend on the spice hierarchy, so
#they are passed as an input.
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
input_pins = self.get_inputs()
output_pins = self.get_outputs()
inout_pins = self.get_inouts()
for inp in input_pins+inout_pins:
for out in output_pins+inout_pins:
if inp != out: #do not add self loops
graph.add_edge(pin_dict[inp], pin_dict[out])
def __str__(self):
""" override print function output """
return "design: " + self.name

View File

@ -58,6 +58,17 @@ class spice():
else:
debug.error("Mismatch in type and pin list lengths.", -1)
def add_pin_types(self, type_list):
"""Add pin types for all the cell's pins.
Typically, should only be used for handmade cells."""
#This only works if self.pins == bitcell.pin_names
if self.pin_names != self.pins:
debug.error("{} spice subcircuit port names do not match pin_names\
\n SPICE names={}\
\n Module names={}\
".format(self.name, self.pin_names, self.pins),1)
self.pin_type = {pin:type for pin,type in zip(self.pin_names, type_list)}
def get_pin_type(self, name):
""" Returns the type of the signal pin. """
return self.pin_type[name]
@ -87,6 +98,14 @@ class spice():
output_list.append(pin)
return output_list
def get_inouts(self):
""" These use pin types to determine pin lists. These
may be over-ridden by submodules that didn't use pin directions yet."""
inout_list = []
for pin in self.pins:
if self.pin_type[pin]=="INOUT":
inout_list.append(pin)
return inout_list
def add_mod(self, mod):
"""Adds a subckt/submodule to the subckt hierarchy"""

View File

@ -13,6 +13,7 @@ class bitcell(design.design):
"""
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
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"])
@ -24,6 +25,7 @@ class bitcell(design.design):
self.width = bitcell.width
self.height = bitcell.height
self.pin_map = bitcell.pin_map
self.add_pin_types(self.type_list)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
@ -76,10 +78,5 @@ class bitcell(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 5 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl->bl, wl->br.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[2],port_nets[0])
graph.add_edge(port_nets[2],port_nets[1])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -13,6 +13,7 @@ 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"]
(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"])
@ -24,6 +25,7 @@ class bitcell_1rw_1r(design.design):
self.width = bitcell_1rw_1r.width
self.height = bitcell_1rw_1r.height
self.pin_map = bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
@ -101,13 +103,13 @@ class bitcell_1rw_1r(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])

View File

@ -13,6 +13,7 @@ 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"]
(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"])
@ -24,6 +25,7 @@ class bitcell_1w_1r(design.design):
self.width = bitcell_1w_1r.width
self.height = bitcell_1w_1r.height
self.pin_map = bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
@ -101,12 +103,11 @@ class bitcell_1w_1r(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
# Port 1 is a write port, so its timing is not considered here.

View File

@ -91,40 +91,40 @@ class pbitcell(design.design):
port = 0
for k in range(self.num_rw_ports):
self.add_pin("bl{}".format(port))
self.add_pin("br{}".format(port))
self.add_pin("bl{}".format(port), "OUTPUT")
self.add_pin("br{}".format(port), "OUTPUT")
self.rw_bl_names.append("bl{}".format(port))
self.rw_br_names.append("br{}".format(port))
port += 1
for k in range(self.num_w_ports):
self.add_pin("bl{}".format(port))
self.add_pin("br{}".format(port))
self.add_pin("bl{}".format(port), "INPUT")
self.add_pin("br{}".format(port), "INPUT")
self.w_bl_names.append("bl{}".format(port))
self.w_br_names.append("br{}".format(port))
port += 1
for k in range(self.num_r_ports):
self.add_pin("bl{}".format(port))
self.add_pin("br{}".format(port))
self.add_pin("bl{}".format(port), "OUTPUT")
self.add_pin("br{}".format(port), "OUTPUT")
self.r_bl_names.append("bl{}".format(port))
self.r_br_names.append("br{}".format(port))
port += 1
port = 0
for k in range(self.num_rw_ports):
self.add_pin("wl{}".format(port))
self.add_pin("wl{}".format(port), "INPUT")
self.rw_wl_names.append("wl{}".format(port))
port += 1
for k in range(self.num_w_ports):
self.add_pin("wl{}".format(port))
self.add_pin("wl{}".format(port), "INPUT")
self.w_wl_names.append("wl{}".format(port))
port += 1
for k in range(self.num_r_ports):
self.add_pin("wl{}".format(port))
self.add_pin("wl{}".format(port), "INPUT")
self.r_wl_names.append("wl{}".format(port))
port += 1
self.add_pin("vdd")
self.add_pin("gnd")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
# if this is a replica bitcell, replace the instances of Q_bar with vdd
if self.replica_bitcell:
@ -894,14 +894,13 @@ class pbitcell(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Done manually to make the graph acyclic."""
#The base graph function can make this but it would contain loops and path
#searches would essentially be useless.
# Edges added wl->bl, wl->br for every port
"""Adds edges to graph for pbitcell. Only readwrite and read ports."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
# Edges added wl->bl, wl->br for every port except write ports
rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names)
r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names)
for pin_zip in zip(rw_pin_names, r_pin_names):
for wl,bl,br in pin_zip:
graph.add_edge(pin_dict[wl],pin_dict[bl])
graph.add_edge(pin_dict[wl],pin_dict[br])
num_wl = len(self.rw_wl_names) + len(self.w_wl_names) + len(self.r_wl_names)
wl_pos = 2*num_wl #there are this many bitlines nets before the wls in the port list
for i in range(num_wl):
bl_pos = i*2
graph.add_edge(port_nets[wl_pos+i],port_nets[bl_pos])
graph.add_edge(port_nets[wl_pos+i],port_nets[bl_pos+1])

View File

@ -11,6 +11,7 @@ class replica_bitcell(design.design):
the technology library. """
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"])
@ -22,6 +23,7 @@ class replica_bitcell(design.design):
self.width = replica_bitcell.width
self.height = replica_bitcell.height
self.pin_map = replica_bitcell.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
@ -31,10 +33,5 @@ class replica_bitcell(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 5 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl->bl, wl->br.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[2],port_nets[0])
graph.add_edge(port_nets[2],port_nets[1])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -11,6 +11,7 @@ class replica_bitcell_1rw_1r(design.design):
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"])
@ -22,6 +23,7 @@ class replica_bitcell_1rw_1r(design.design):
self.width = replica_bitcell_1rw_1r.width
self.height = replica_bitcell_1rw_1r.height
self.pin_map = replica_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
@ -32,12 +34,13 @@ class replica_bitcell_1rw_1r(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])

View File

@ -11,6 +11,7 @@ class replica_bitcell_1w_1r(design.design):
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1w_1r", GDS["unit"])
@ -22,6 +23,7 @@ class replica_bitcell_1w_1r(design.design):
self.width = replica_bitcell_1w_1r.width
self.height = replica_bitcell_1w_1r.height
self.pin_map = replica_bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
@ -32,12 +34,11 @@ class replica_bitcell_1w_1r(design.design):
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
# Port 1 is a write port, so its timing is not considered here.

View File

@ -31,7 +31,7 @@ class model_check(delay):
self.bl_meas_name, self.bl_slew_name = "bl_measures", "bl_slews"
self.power_name = "total_power"
def create_measurement_names(self):
def create_measurement_names(self, port):
"""Create measurement names. The names themselves currently define the type of measurement"""
#Create delay measurement names
wl_en_driver_delay_names = ["delay_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
@ -42,7 +42,10 @@ class model_check(delay):
else:
dc_delay_names = ["delay_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
self.wl_delay_meas_names = wl_en_driver_delay_names+["delay_wl_en", "delay_wl_bar"]+wl_driver_delay_names+["delay_wl"]
if port not in self.sram.readonly_ports:
self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names
else:
self.rbl_delay_meas_names = ["delay_gated_clk_nand"]+dc_delay_names
self.sae_delay_meas_names = ["delay_pre_sen"]+sen_driver_delay_names+["delay_sen"]
# if self.custom_delaychain:
@ -58,45 +61,54 @@ class model_check(delay):
else:
dc_slew_names = ["slew_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
self.wl_slew_meas_names = ["slew_wl_gated_clk_bar"]+wl_en_driver_slew_names+["slew_wl_en", "slew_wl_bar"]+wl_driver_slew_names+["slew_wl"]
if port not in self.sram.readonly_ports:
self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names
else:
self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar"]+dc_slew_names
self.sae_slew_meas_names = ["slew_replica_bl0", "slew_pre_sen"]+sen_driver_slew_names+["slew_sen"]
self.bitline_meas_names = ["delay_wl_to_bl", "delay_bl_to_dout"]
self.power_meas_names = ['read0_power']
def create_signal_names(self):
def create_signal_names(self, port):
"""Creates list of the signal names used in the spice file along the wl and sen paths.
Names are re-harded coded here; i.e. the names are hardcoded in most of OpenRAM and are
replicated here.
"""
delay.create_signal_names(self)
#Signal names are all hardcoded, need to update to make it work for probe address and different configurations.
wl_en_driver_signals = ["Xsram.Xcontrol0.Xbuf_wl_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver0.Xwl_driver_inv{}.Zb{}_int".format(self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())]
sen_driver_signals = ["Xsram.Xcontrol0.Xbuf_s_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
wl_en_driver_signals = ["Xsram.Xcontrol{}.Xbuf_wl_en.Zb{}_int".format('{}', stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver{}.Xwl_driver_inv{}.Zb{}_int".format('{}', self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())]
sen_driver_signals = ["Xsram.Xcontrol{}.Xbuf_s_en.Zb{}_int".format('{}',stage) for stage in range(1,self.get_num_sen_driver_stages())]
if self.custom_delaychain:
delay_chain_signal_names = []
else:
delay_chain_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.Xdelay_chain.dout_{}".format(stage) for stage in range(1,self.get_num_delay_stages())]
self.wl_signal_names = ["Xsram.Xcontrol0.gated_clk_bar"]+\
delay_chain_signal_names = ["Xsram.Xcontrol{}.Xreplica_bitline.Xdelay_chain.dout_{}".format('{}', stage) for stage in range(1,self.get_num_delay_stages())]
if len(self.sram.all_ports) > 1:
port_format = '{}'
else:
port_format = ''
self.wl_signal_names = ["Xsram.Xcontrol{}.gated_clk_bar".format('{}')]+\
wl_en_driver_signals+\
["Xsram.wl_en0", "Xsram.Xbank0.Xwordline_driver0.wl_bar_{}".format(self.wordline_row)]+\
["Xsram.wl_en{}".format('{}'), "Xsram.Xbank0.Xwordline_driver{}.wl_bar_{}".format('{}',self.wordline_row)]+\
wl_driver_signals+\
["Xsram.Xbank0.wl_{}".format(self.wordline_row)]
pre_delay_chain_names = ["Xsram.Xcontrol0.gated_clk_bar", "Xsram.Xcontrol0.Xand2_rbl_in.zb_int", "Xsram.Xcontrol0.rbl_in"]
["Xsram.Xbank0.wl{}_{}".format(port_format, self.wordline_row)]
pre_delay_chain_names = ["Xsram.Xcontrol{}.gated_clk_bar".format('{}')]
if port not in self.sram.readonly_ports:
pre_delay_chain_names+= ["Xsram.Xcontrol{}.Xand2_rbl_in.zb_int".format('{}'), "Xsram.Xcontrol{}.rbl_in".format('{}')]
self.rbl_en_signal_names = pre_delay_chain_names+\
delay_chain_signal_names+\
["Xsram.Xcontrol0.Xreplica_bitline.delayed_en"]
["Xsram.Xcontrol{}.Xreplica_bitline.delayed_en".format('{}')]
self.sae_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.bl0_0", "Xsram.Xcontrol0.pre_s_en"]+\
self.sae_signal_names = ["Xsram.Xcontrol{}.Xreplica_bitline.bl0_0".format('{}'), "Xsram.Xcontrol{}.pre_s_en".format('{}')]+\
sen_driver_signals+\
["Xsram.s_en0"]
["Xsram.s_en{}".format('{}')]
dout_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
self.bl_signal_names = ["Xsram.Xbank0.wl_{}".format(self.wordline_row),\
"Xsram.Xbank0.bl_{}".format(self.bitline_column),\
self.bl_signal_names = ["Xsram.Xbank0.wl{}_{}".format(port_format, self.wordline_row),\
"Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column),\
dout_name]
def create_measurement_objects(self):
@ -362,17 +374,18 @@ class model_check(delay):
errors = self.calculate_error_l2_norm(scaled_meas, scaled_model)
debug.info(1, "Errors:\n{}\n".format(errors))
def analyze(self, probe_address, probe_data, slews, loads):
def analyze(self, probe_address, probe_data, slews, loads, port):
"""Measures entire delay path along the wordline and sense amp enable and compare it to the model delays."""
self.load=max(loads)
self.slew=max(slews)
self.set_probe(probe_address, probe_data)
self.create_signal_names()
self.create_measurement_names()
self.create_signal_names(port)
self.create_measurement_names(port)
self.create_measurement_objects()
data_dict = {}
read_port = self.read_ports[0] #only test the first read port
read_port = port
self.targ_read_ports = [read_port]
self.targ_write_ports = [self.write_ports[0]]
debug.info(1,"Model test: corner {}".format(self.corner))

View File

@ -11,6 +11,7 @@ class dff(design.design):
"""
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
@ -20,6 +21,7 @@ class dff(design.design):
self.width = dff.width
self.height = dff.height
self.pin_map = dff.pin_map
self.add_pin_types(self.type_list)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
@ -51,10 +53,6 @@ class dff(design.design):
return parameter["dff_clk_cin"]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 5 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: clk->Q.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[2],port_nets[1])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -13,6 +13,7 @@ class sense_amp(design.design):
"""
pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"])
@ -23,6 +24,7 @@ class sense_amp(design.design):
self.width = sense_amp.width
self.height = sense_amp.height
self.pin_map = sense_amp.pin_map
self.add_pin_types(self.type_list)
def input_load(self):
#Input load for the bitlines which are connected to the source/drain of a TX. Not the selects.
@ -54,12 +56,6 @@ class sense_amp(design.design):
return 2*pmos_cin + nmos_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 6 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: en->dout, bl->dout
# br->dout not included to reduce complexity
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[0],port_nets[2])
graph.add_edge(port_nets[3],port_nets[2])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -11,6 +11,7 @@ class tri_gate(design.design):
"""
pin_names = ["in", "out", "en", "en_bar", "gnd", "vdd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"])
@ -26,6 +27,7 @@ class tri_gate(design.design):
self.width = tri_gate.width
self.height = tri_gate.height
self.pin_map = tri_gate.pin_map
self.add_pin_types(self.type_list)
def analytical_delay(self, corner, slew, load=0.0):
from tech import spice
@ -43,12 +45,5 @@ class tri_gate(design.design):
return 9*spice["min_tx_gate_c"]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 6 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: en->out, en_bar->out, in->out.
# A liberal amount of edges were added, may be reduced later for complexity.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[0],port_nets[1])
graph.add_edge(port_nets[2],port_nets[1])
graph.add_edge(port_nets[3],port_nets[1])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -11,7 +11,8 @@ class write_driver(design.design):
the technology library.
"""
pin_names = ["din", "bl", "br", "en", "gnd", "vdd"]
pin_names = ["din", "bl", "br", "en", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"])
@ -22,7 +23,7 @@ class write_driver(design.design):
self.width = write_driver.width
self.height = write_driver.height
self.pin_map = write_driver.pin_map
self.add_pin_types(self.type_list)
def get_w_en_cin(self):
"""Get the relative capacitance of a single input"""
@ -30,13 +31,5 @@ class write_driver(design.design):
return 5*3
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 6 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: din->bl, din->br, en->bl, en->br
# A liberal amount of edges were added, may be reduced later for complexity.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[0],port_nets[1])
graph.add_edge(port_nets[0],port_nets[2])
graph.add_edge(port_nets[3],port_nets[1])
graph.add_edge(port_nets[3],port_nets[2])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -216,4 +216,3 @@ class pgate(design.design):
# offset=implant_offset,
# width=implant_width,
# height=implant_height)

View File

@ -62,7 +62,9 @@ class pinv(pgate.pgate):
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "Z", "vdd", "gnd"])
pin_list = ["A", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'OUTPUT', 'POWER', 'GROUND']
self.add_pin_list(pin_list, dir_list)
def determine_tx_mults(self):
@ -283,7 +285,8 @@ class pinv(pgate.pgate):
return transition_prob*(c_load + c_para)
def get_cin(self):
"""Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
"""Return the capacitance of the gate connection in generic capacitive
units relative to the minimum width of a transistor"""
return self.nmos_size + self.pmos_size
def get_stage_effort(self, cout, inp_is_rise=True):
@ -291,4 +294,13 @@ class pinv(pgate.pgate):
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 1
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
return logical_effort.logical_effort(self.name,
self.size,
self.get_cin(),
cout,
parasitic_delay,
not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -33,7 +33,7 @@ class pnand2(pgate.pgate):
self.create_layout()
#For characterization purposes only
self.exclude_nmos_from_graph()
#self.exclude_nmos_from_graph()
def create_netlist(self):
self.add_pins()
@ -54,7 +54,9 @@ class pnand2(pgate.pgate):
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
pin_list = ["A", "B", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'INPUT', 'OUTPUT', 'POWER', 'GROUND']
self.add_pin_list(pin_list, dir_list)
def add_ptx(self):
@ -268,3 +270,7 @@ class pnand2(pgate.pgate):
#Removing them simplifies generic path searching.
self.graph_inst_exclude.add(self.nmos1_inst)
self.graph_inst_exclude.add(self.nmos2_inst)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -37,7 +37,9 @@ class pnand3(pgate.pgate):
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "B", "C", "Z", "vdd", "gnd"])
pin_list = ["A", "B", "C", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'INPUT', 'INPUT', 'OUTPUT', 'POWER', 'GROUND']
self.add_pin_list(pin_list, dir_list)
def create_netlist(self):
self.add_pins()
@ -272,3 +274,7 @@ class pnand3(pgate.pgate):
"""
parasitic_delay = 3
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -34,7 +34,9 @@ class pnor2(pgate.pgate):
def add_pins(self):
""" Adds pins for spice netlist """
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
pin_list = ["A", "B", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'INPUT', 'OUTPUT', 'INOUT', 'INOUT']
self.add_pin_list(pin_list, dir_list)
def create_netlist(self):
self.add_pins()
@ -234,3 +236,6 @@ class pnor2(pgate.pgate):
transition_prob = spice["nor2_transition_prob"]
return transition_prob*(c_load + c_para)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -60,7 +60,13 @@ class ptx(design.design):
#self.DRC()
def create_netlist(self):
self.add_pin_list(["D", "G", "S", "B"])
pin_list = ["D", "G", "S", "B"]
if self.tx_type=="nmos":
body_dir = 'GROUND'
else: #Assumed that the check for either pmos or nmos is done elsewhere.
body_dir = 'POWER'
dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
self.add_pin_list(pin_list, dir_list)
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
# " ".join(self.pins)))
@ -358,14 +364,6 @@ class ptx(design.design):
return self.tx_width/drc("minwidth_tx")
def build_graph(self, graph, inst_name, port_nets):
"""Adds ptx edges to graph. Lowest graph level."""
#The ptx has four connections: (S)ource, (G)ate, (D)rain, (B)ody. The positions in spice
#are hardcoded which is represented here as well.
#Edges are connected as follows: G->S, G->D, D<->S. Body not represented in graph.
if len(port_nets) != 4:
debug.error("Transistor has non-standard connections.",1)
graph.add_edge(port_nets[1],port_nets[0])
graph.add_edge(port_nets[1],port_nets[2])
graph.add_edge(port_nets[0],port_nets[2])
graph.add_edge(port_nets[2],port_nets[0])
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)