diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 6d9de53c..898ac918 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -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 diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index cb2799f3..f2535f86 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -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""" diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 798ee3f9..76ecfb0a 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -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]) \ No newline at end of file + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) \ No newline at end of file diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py index 58b0ca98..d10d03b6 100644 --- a/compiler/bitcells/bitcell_1rw_1r.py +++ b/compiler/bitcells/bitcell_1rw_1r.py @@ -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,7 +25,8 @@ 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 size = 0.5 #This accounts for bitline being drained thought the access TX and internal node @@ -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"]) diff --git a/compiler/bitcells/bitcell_1w_1r.py b/compiler/bitcells/bitcell_1w_1r.py index 3d1febdd..e8865dcf 100644 --- a/compiler/bitcells/bitcell_1w_1r.py +++ b/compiler/bitcells/bitcell_1w_1r.py @@ -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. diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index cff7b5cf..f9c49709 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -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 - - 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]) + """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]) + diff --git a/compiler/bitcells/replica_bitcell.py b/compiler/bitcells/replica_bitcell.py index 8d77ff7b..deb71e40 100644 --- a/compiler/bitcells/replica_bitcell.py +++ b/compiler/bitcells/replica_bitcell.py @@ -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]) \ No newline at end of file + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) \ No newline at end of file diff --git a/compiler/bitcells/replica_bitcell_1rw_1r.py b/compiler/bitcells/replica_bitcell_1rw_1r.py index 67871525..14e10ee6 100644 --- a/compiler/bitcells/replica_bitcell_1rw_1r.py +++ b/compiler/bitcells/replica_bitcell_1rw_1r.py @@ -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]) \ No newline at end of file + """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"]) \ No newline at end of file diff --git a/compiler/bitcells/replica_bitcell_1w_1r.py b/compiler/bitcells/replica_bitcell_1w_1r.py index 1f5c3266..0b1b598f 100644 --- a/compiler/bitcells/replica_bitcell_1w_1r.py +++ b/compiler/bitcells/replica_bitcell_1w_1r.py @@ -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]) \ No newline at end of file + """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. \ No newline at end of file diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py index ff8bbdfa..b9446639 100644 --- a/compiler/characterizer/model_check.py +++ b/compiler/characterizer/model_check.py @@ -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"] - self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names + 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"] - self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names + 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)) diff --git a/compiler/modules/dff.py b/compiler/modules/dff.py index 9b9dd0fe..3ba3f5c8 100644 --- a/compiler/modules/dff.py +++ b/compiler/modules/dff.py @@ -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) \ No newline at end of file diff --git a/compiler/modules/sense_amp.py b/compiler/modules/sense_amp.py index 431fc1b5..5ee208cd 100644 --- a/compiler/modules/sense_amp.py +++ b/compiler/modules/sense_amp.py @@ -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,7 +24,8 @@ 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. from tech import spice, parameter @@ -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) \ No newline at end of file diff --git a/compiler/modules/tri_gate.py b/compiler/modules/tri_gate.py index 6a1efdea..4b7501dd 100644 --- a/compiler/modules/tri_gate.py +++ b/compiler/modules/tri_gate.py @@ -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]) \ No newline at end of file + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) \ No newline at end of file diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py index d20a0135..c31e8a4b 100644 --- a/compiler/modules/write_driver.py +++ b/compiler/modules/write_driver.py @@ -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]) \ No newline at end of file + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) \ No newline at end of file diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 2f641da9..eaabdfe5 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -216,4 +216,3 @@ class pgate(design.design): # offset=implant_offset, # width=implant_width, # height=implant_height) - diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index c66c944c..4a7e0820 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -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) \ No newline at end of file diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index eb2484af..e1dccf7e 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -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) \ No newline at end of file diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index d0c37b55..18fc2ed0 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -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) \ No newline at end of file diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 8a5c80d4..64a75b44 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -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) \ No newline at end of file diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 7e80a7c9..81ff54a3 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -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) \ No newline at end of file