diff --git a/compiler/modules/sram_base.py b/compiler/modules/sram_base.py deleted file mode 100644 index 5e4d8280..00000000 --- a/compiler/modules/sram_base.py +++ /dev/null @@ -1,782 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 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 datetime -import debug -from globals import OPTS, print_time -from math import log, ceil -import importlib -from base.vector import vector -from base.design import design -from base.verilog import verilog -from base.lef import lef -from sram_factory import factory -from tech import spice - - -class sram_base(design, verilog, lef): - """ - Dynamically generated SRAM by connecting banks to control logic. The - number of banks should be 1 , 2 or 4 - """ - def __init__(self, name, sram_config): - design.__init__(self, name) - lef.__init__(self, ["m1", "m2", "m3", "m4"]) - verilog.__init__(self) - - self.sram_config = sram_config - sram_config.set_local_config(self) - - self.bank_insts = [] - - if self.write_size: - self.num_wmasks = int(ceil(self.word_size / self.write_size)) - else: - self.num_wmasks = 0 - - if not self.num_spare_cols: - self.num_spare_cols = 0 - - - def add_pins(self): - """ Add pins for entire SRAM. """ - - for port in self.write_ports: - for bit in range(self.word_size + self.num_spare_cols): - self.add_pin("din{0}[{1}]".format(port, bit), "INPUT") - - for port in self.all_ports: - for bit in range(self.bank_addr_size): - self.add_pin("addr{0}[{1}]".format(port, bit), "INPUT") - - # These are used to create the physical pins - self.control_logic_inputs = [] - self.control_logic_outputs = [] - for port in self.all_ports: - if port in self.readwrite_ports: - self.control_logic_inputs.append(self.control_logic_rw.get_inputs()) - self.control_logic_outputs.append(self.control_logic_rw.get_outputs()) - elif port in self.write_ports: - self.control_logic_inputs.append(self.control_logic_w.get_inputs()) - self.control_logic_outputs.append(self.control_logic_w.get_outputs()) - else: - self.control_logic_inputs.append(self.control_logic_r.get_inputs()) - self.control_logic_outputs.append(self.control_logic_r.get_outputs()) - - for port in self.all_ports: - self.add_pin("csb{}".format(port), "INPUT") - for port in self.readwrite_ports: - self.add_pin("web{}".format(port), "INPUT") - for port in self.all_ports: - self.add_pin("clk{}".format(port), "INPUT") - # add the optional write mask pins - for port in self.write_ports: - for bit in range(self.num_wmasks): - self.add_pin("wmask{0}[{1}]".format(port, bit), "INPUT") - if self.num_spare_cols == 1: - self.add_pin("spare_wen{0}".format(port), "INPUT") - else: - for bit in range(self.num_spare_cols): - self.add_pin("spare_wen{0}[{1}]".format(port, bit), "INPUT") - for port in self.read_ports: - for bit in range(self.word_size + self.num_spare_cols): - self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT") - - # Standard supply and ground names - try: - self.vdd_name = spice["power"] - except KeyError: - self.vdd_name = "vdd" - try: - self.gnd_name = spice["ground"] - except KeyError: - self.gnd_name = "gnd" - - self.add_pin(self.vdd_name, "POWER") - self.add_pin(self.gnd_name, "GROUND") - self.ext_supplies = [self.vdd_name, self.gnd_name] - self.ext_supply = {"vdd" : self.vdd_name, "gnd" : self.gnd_name} - - def add_global_pex_labels(self): - """ - Add pex labels at the sram level for spice analysis - """ - - - - # add pex labels for bitcells - for bank_num in range(len(self.bank_insts)): - bank = self.bank_insts[bank_num] - pex_data = bank.reverse_transformation_bitcell(self.bitcell.name) - - bank_offset = pex_data[0] # offset bank relative to sram - Q_offset = pex_data[1] # offset of storage relative to bank - Q_bar_offset = pex_data[2] # offset of storage relative to bank - bl_offsets = pex_data[3] - br_offsets = pex_data[4] - bl_meta = pex_data[5] - br_meta = pex_data[6] - - bl = [] - br = [] - - storage_layer_name = "m1" - bitline_layer_name = self.bitcell.get_pin("bl").layer - - for cell in range(len(bank_offset)): - Q = [bank_offset[cell][0] + Q_offset[cell][0], - bank_offset[cell][1] + Q_offset[cell][1]] - Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], - bank_offset[cell][1] + Q_bar_offset[cell][1]] - OPTS.words_per_row = self.words_per_row - row = int(cell % (OPTS.num_words / self.words_per_row)) - col = int(cell / (OPTS.num_words)) - self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, - row, - col), - storage_layer_name, - Q) - self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, - row, - col), - storage_layer_name, - Q_bar) - - for cell in range(len(bl_offsets)): - col = bl_meta[cell][0][2] - for bitline in range(len(bl_offsets[cell])): - bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], - float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]] - bl.append([bitline_location, bl_meta[cell][bitline][3], col]) - - for cell in range(len(br_offsets)): - col = br_meta[cell][0][2] - for bitline in range(len(br_offsets[cell])): - bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], - float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] - br.append([bitline_location, br_meta[cell][bitline][3], col]) - - for i in range(len(bl)): - self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), - bitline_layer_name, bl[i][0]) - - for i in range(len(br)): - self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), - bitline_layer_name, br[i][0]) - - # add pex labels for control logic - for i in range(len(self.control_logic_insts)): - instance = self.control_logic_insts[i] - control_logic_offset = instance.offset - for output in instance.mod.output_list: - pin = instance.mod.get_pin(output) - pin.transform([0, 0], instance.mirror, instance.rotate) - offset = [control_logic_offset[0] + pin.center()[0], - control_logic_offset[1] + pin.center()[1]] - self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i), - storage_layer_name, - offset) - - def create_netlist(self): - """ Netlist creation """ - - start_time = datetime.datetime.now() - - # Must create the control logic before pins to get the pins - self.add_modules() - self.add_pins() - self.create_modules() - - # This is for the lib file if we don't create layout - self.width=0 - self.height=0 - - if not OPTS.is_unit_test: - print_time("Submodules", datetime.datetime.now(), start_time) - - def create_layout(self): - """ Layout creation """ - start_time = datetime.datetime.now() - self.place_instances() - if not OPTS.is_unit_test: - print_time("Placement", datetime.datetime.now(), start_time) - - start_time = datetime.datetime.now() - self.route_layout() - - if not OPTS.is_unit_test: - print_time("Routing", datetime.datetime.now(), start_time) - - self.add_lvs_correspondence_points() - - self.offset_all_coordinates() - - highest_coord = self.find_highest_coords() - self.width = highest_coord[0] - self.height = highest_coord[1] - if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": - debug.info(2, "adding global pex labels") - self.add_global_pex_labels() - self.add_boundary(ll=vector(0, 0), - ur=vector(self.width, self.height)) - - start_time = datetime.datetime.now() - if not OPTS.is_unit_test: - # We only enable final verification if we have routed the design - # Only run this if not a unit test, because unit test will also verify it. - self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=OPTS.check_lvsdrc) - print_time("Verification", datetime.datetime.now(), start_time) - - def create_modules(self): - debug.error("Must override pure virtual function.", -1) - - def route_supplies(self, bbox=None): - """ Route the supply grid and connect the pins to them. """ - - # Copy the pins to the top level - # This will either be used to route or left unconnected. - for pin_name in ["vdd", "gnd"]: - for inst in self.insts: - self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name]) - - # Pick the router type - if not OPTS.route_supplies: - # Do not route the power supply (leave as must-connect pins) - return - elif OPTS.route_supplies == "grid": - from router import supply_grid_router as router - else: - from router import supply_tree_router as router - - rtr=router(layers=self.supply_stack, - design=self, - bbox=bbox, - pin_type=OPTS.supply_pin_type) - - rtr.route() - - # This removes the original pre-supply routing pins and replaces them - # with the ring or peripheral power pins - if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]: - # Find the lowest leftest pin for vdd and gnd - for pin_name in ["vdd", "gnd"]: - # Copy the pin shape(s) to rectangles - for pin in self.get_pins(pin_name): - self.add_rect(pin.layer, - pin.ll(), - pin.width(), - pin.height()) - - # Remove the pin shape(s) - self.remove_layout_pin(pin_name) - - # Get new pins - pins = rtr.get_new_pins(pin_name) - for pin in pins: - self.add_layout_pin(self.ext_supply[pin_name], - pin.layer, - pin.ll(), - pin.width(), - pin.height()) - - elif OPTS.route_supplies and OPTS.supply_pin_type == "single": - # Update these as we may have routed outside the region (perimeter pins) - lowest_coord = self.find_lowest_coords() - - # Find the lowest leftest pin for vdd and gnd - for pin_name in ["vdd", "gnd"]: - # Copy the pin shape(s) to rectangles - for pin in self.get_pins(pin_name): - self.add_rect(pin.layer, - pin.ll(), - pin.width(), - pin.height()) - - # Remove the pin shape(s) - self.remove_layout_pin(pin_name) - - # Get the lowest, leftest pin - pin = rtr.get_ll_pin(pin_name) - - pin_width = 2 * getattr(self, "{}_width".format(pin.layer)) - - # Add it as an IO pin to the perimeter - route_width = pin.rx() - lowest_coord.x - pin_offset = vector(lowest_coord.x, pin.by()) - self.add_rect(pin.layer, - pin_offset, - route_width, - pin.height()) - - self.add_layout_pin(self.ext_supply[pin_name], - pin.layer, - pin_offset, - pin_width, - pin.height()) - else: - # Grid is left with many top level pins - pass - - def route_escape_pins(self, bbox): - """ - Add the top-level pins for a single bank SRAM with control. - """ - - # List of pin to new pin name - pins_to_route = [] - for port in self.all_ports: - # Connect the control pins as inputs - for signal in self.control_logic_inputs[port]: - if signal.startswith("rbl"): - continue - if signal=="clk": - pins_to_route.append("{0}{1}".format(signal, port)) - else: - pins_to_route.append("{0}{1}".format(signal, port)) - - if port in self.write_ports: - for bit in range(self.word_size + self.num_spare_cols): - pins_to_route.append("din{0}[{1}]".format(port, bit)) - - if port in self.readwrite_ports or port in self.read_ports: - for bit in range(self.word_size + self.num_spare_cols): - pins_to_route.append("dout{0}[{1}]".format(port, bit)) - - for bit in range(self.col_addr_size): - pins_to_route.append("addr{0}[{1}]".format(port, bit)) - - for bit in range(self.row_addr_size): - pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size)) - - if port in self.write_ports: - if self.write_size: - for bit in range(self.num_wmasks): - pins_to_route.append("wmask{0}[{1}]".format(port, bit)) - - if port in self.write_ports: - if self.num_spare_cols == 1: - pins_to_route.append("spare_wen{0}".format(port)) - else: - for bit in range(self.num_spare_cols): - pins_to_route.append("spare_wen{0}[{1}]".format(port, bit)) - - from router import signal_escape_router as router - rtr=router(layers=self.m3_stack, - design=self, - bbox=bbox) - rtr.escape_route(pins_to_route) - - def compute_bus_sizes(self): - """ Compute the independent bus widths shared between two and four bank SRAMs """ - - # address size + control signals + one-hot bank select signals - self.num_vertical_line = self.bank_addr_size + self.control_size + log(self.num_banks, 2) + 1 - # data bus size - self.num_horizontal_line = self.word_size - - self.vertical_bus_width = self.m2_pitch * self.num_vertical_line - # vertical bus height depends on 2 or 4 banks - - self.data_bus_height = self.m3_pitch * self.num_horizontal_line - self.data_bus_width = 2 * (self.bank.width + self.bank_to_bus_distance) + self.vertical_bus_width - - self.control_bus_height = self.m1_pitch * (self.control_size + 2) - self.control_bus_width = self.bank.width + self.bank_to_bus_distance + self.vertical_bus_width - - self.supply_bus_height = self.m1_pitch * 2 # 2 for vdd/gnd placed with control bus - self.supply_bus_width = self.data_bus_width - - # Sanity check to ensure we can fit the control logic above a single bank (0.9 is a hack really) - debug.check(self.bank.width + self.vertical_bus_width > 0.9 * self.control_logic.width, - "Bank is too small compared to control logic.") - - def add_busses(self): - """ Add the horizontal and vertical busses """ - # Vertical bus - # The order of the control signals on the control bus: - self.control_bus_names = [] - for port in self.all_ports: - self.control_bus_names[port] = ["clk_buf{}".format(port)] - wen = "w_en{}".format(port) - sen = "s_en{}".format(port) - pen = "p_en_bar{}".format(port) - if self.port_id[port] == "r": - self.control_bus_names[port].extend([sen, pen]) - elif self.port_id[port] == "w": - self.control_bus_names[port].extend([wen, pen]) - else: - self.control_bus_names[port].extend([sen, wen, pen]) - self.vert_control_bus_positions = self.create_vertical_bus(layer="m2", - pitch=self.m2_pitch, - offset=self.vertical_bus_offset, - names=self.control_bus_names[port], - length=self.vertical_bus_height) - - self.addr_bus_names=["A{0}[{1}]".format(port, i) for i in range(self.bank_addr_size)] - self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="m2", - pitch=self.m2_pitch, - offset=self.addr_bus_offset, - names=self.addr_bus_names, - length=self.addr_bus_height)) - - self.bank_sel_bus_names = ["bank_sel{0}_{1}".format(port, i) for i in range(self.num_banks)] - self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="m2", - pitch=self.m2_pitch, - offset=self.bank_sel_bus_offset, - names=self.bank_sel_bus_names, - length=self.vertical_bus_height)) - - # Horizontal data bus - self.data_bus_names = ["DATA{0}[{1}]".format(port, i) for i in range(self.word_size)] - self.data_bus_positions = self.create_horizontal_pin_bus(layer="m3", - pitch=self.m3_pitch, - offset=self.data_bus_offset, - names=self.data_bus_names, - length=self.data_bus_width) - - # Horizontal control logic bus - # vdd/gnd in bus go along whole SRAM - # FIXME: Fatten these wires? - self.horz_control_bus_positions = self.create_horizontal_bus(layer="m1", - pitch=self.m1_pitch, - offset=self.supply_bus_offset, - names=["vdd"], - length=self.supply_bus_width) - # The gnd rail must not be the entire width since we protrude the right-most vdd rail up for - # the decoder in 4-bank SRAMs - self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="m1", - pitch=self.m1_pitch, - offset=self.supply_bus_offset + vector(0, self.m1_pitch), - names=["gnd"], - length=self.supply_bus_width)) - self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="m1", - pitch=self.m1_pitch, - offset=self.control_bus_offset, - names=self.control_bus_names[port], - length=self.control_bus_width)) - - def add_multi_bank_modules(self): - """ Create the multibank address flops and bank decoder """ - from dff_buf_array import dff_buf_array - self.msb_address = dff_buf_array(name="msb_address", - rows=1, - columns=self.num_banks / 2) - - if self.num_banks>2: - self.msb_decoder = self.bank.decoder.pre2_4 - - def add_modules(self): - self.bitcell = factory.create(module_type=OPTS.bitcell) - self.dff = factory.create(module_type="dff") - - # Create the bank module (up to four are instantiated) - self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank") - - self.num_spare_cols = self.bank.num_spare_cols - - # Create the address and control flops (but not the clk) - self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1) - - if self.col_addr_size > 0: - self.col_addr_dff = factory.create("dff_array", module_name="col_addr_dff", rows=1, columns=self.col_addr_size) - else: - self.col_addr_dff = None - - self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size + self.num_spare_cols) - - if self.write_size: - self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks) - - if self.num_spare_cols: - self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols) - - # Create bank decoder - if(self.num_banks > 1): - self.add_multi_bank_modules() - - self.bank_count = 0 - - c = importlib.import_module("modules." + OPTS.control_logic) - self.mod_control_logic = getattr(c, OPTS.control_logic) - - # Create the control logic module for each port type - if len(self.readwrite_ports) > 0: - self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, - words_per_row=self.words_per_row, - word_size=self.word_size, - spare_columns=self.num_spare_cols, - sram=self, - port_type="rw") - if len(self.writeonly_ports) > 0: - self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, - words_per_row=self.words_per_row, - word_size=self.word_size, - spare_columns=self.num_spare_cols, - sram=self, - port_type="w") - if len(self.readonly_ports) > 0: - self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, - words_per_row=self.words_per_row, - word_size=self.word_size, - spare_columns=self.num_spare_cols, - sram=self, - port_type="r") - - def create_bank(self, bank_num): - """ Create a bank """ - self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num), - mod=self.bank)) - - temp = [] - for port in self.read_ports: - for bit in range(self.word_size + self.num_spare_cols): - temp.append("dout{0}[{1}]".format(port, bit)) - for port in self.all_ports: - temp.append("rbl_bl{0}".format(port)) - for port in self.write_ports: - for bit in range(self.word_size + self.num_spare_cols): - temp.append("bank_din{0}_{1}".format(port, bit)) - for port in self.all_ports: - for bit in range(self.bank_addr_size): - temp.append("a{0}_{1}".format(port, bit)) - if(self.num_banks > 1): - for port in self.all_ports: - temp.append("bank_sel{0}_{1}".format(port, bank_num)) - for port in self.read_ports: - temp.append("s_en{0}".format(port)) - for port in self.all_ports: - temp.append("p_en_bar{0}".format(port)) - for port in self.write_ports: - temp.append("w_en{0}".format(port)) - for bit in range(self.num_wmasks): - temp.append("bank_wmask{0}_{1}".format(port, bit)) - for bit in range(self.num_spare_cols): - temp.append("bank_spare_wen{0}_{1}".format(port, bit)) - for port in self.all_ports: - temp.append("wl_en{0}".format(port)) - temp.extend(self.ext_supplies) - self.connect_inst(temp) - - return self.bank_insts[-1] - - def place_bank(self, bank_inst, position, x_flip, y_flip): - """ Place a bank at the given position with orientations """ - - # x_flip == 1 --> no flip in x_axis - # x_flip == -1 --> flip in x_axis - # y_flip == 1 --> no flip in y_axis - # y_flip == -1 --> flip in y_axis - - # x_flip and y_flip are used for position translation - - if x_flip == -1 and y_flip == -1: - bank_rotation = 180 - else: - bank_rotation = 0 - - if x_flip == y_flip: - bank_mirror = "R0" - elif x_flip == -1: - bank_mirror = "MX" - elif y_flip == -1: - bank_mirror = "MY" - else: - bank_mirror = "R0" - - bank_inst.place(offset=position, - mirror=bank_mirror, - rotate=bank_rotation) - - return bank_inst - - def create_row_addr_dff(self): - """ Add all address flops for the main decoder """ - insts = [] - for port in self.all_ports: - insts.append(self.add_inst(name="row_address{}".format(port), - mod=self.row_addr_dff)) - - # inputs, outputs/output/bar - inputs = [] - outputs = [] - for bit in range(self.row_addr_size): - inputs.append("addr{}[{}]".format(port, bit + self.col_addr_size)) - outputs.append("a{}_{}".format(port, bit + self.col_addr_size)) - - self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies) - - return insts - - def create_col_addr_dff(self): - """ Add and place all address flops for the column decoder """ - insts = [] - for port in self.all_ports: - insts.append(self.add_inst(name="col_address{}".format(port), - mod=self.col_addr_dff)) - - # inputs, outputs/output/bar - inputs = [] - outputs = [] - for bit in range(self.col_addr_size): - inputs.append("addr{}[{}]".format(port, bit)) - outputs.append("a{}_{}".format(port, bit)) - - self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies) - - return insts - - def create_data_dff(self): - """ Add and place all data flops """ - insts = [] - for port in self.all_ports: - if port in self.write_ports: - insts.append(self.add_inst(name="data_dff{}".format(port), - mod=self.data_dff)) - else: - insts.append(None) - continue - - # inputs, outputs/output/bar - inputs = [] - outputs = [] - for bit in range(self.word_size + self.num_spare_cols): - inputs.append("din{}[{}]".format(port, bit)) - outputs.append("bank_din{}_{}".format(port, bit)) - - self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies) - - return insts - - def create_wmask_dff(self): - """ Add and place all wmask flops """ - insts = [] - for port in self.all_ports: - if port in self.write_ports: - insts.append(self.add_inst(name="wmask_dff{}".format(port), - mod=self.wmask_dff)) - else: - insts.append(None) - continue - - # inputs, outputs/output/bar - inputs = [] - outputs = [] - for bit in range(self.num_wmasks): - inputs.append("wmask{}[{}]".format(port, bit)) - outputs.append("bank_wmask{}_{}".format(port, bit)) - - self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies) - - return insts - - def create_spare_wen_dff(self): - """ Add all spare write enable flops """ - insts = [] - for port in self.all_ports: - if port in self.write_ports: - insts.append(self.add_inst(name="spare_wen_dff{}".format(port), - mod=self.spare_wen_dff)) - else: - insts.append(None) - continue - - # inputs, outputs/output/bar - inputs = [] - outputs = [] - for bit in range(self.num_spare_cols): - if self.num_spare_cols == 1: - inputs.append("spare_wen{0}".format(port)) - else: - inputs.append("spare_wen{0}[{1}]".format(port, bit)) - outputs.append("bank_spare_wen{}_{}".format(port, bit)) - - self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies) - - return insts - - def create_control_logic(self): - """ Add control logic instances """ - - insts = [] - for port in self.all_ports: - if port in self.readwrite_ports: - mod = self.control_logic_rw - elif port in self.write_ports: - mod = self.control_logic_w - else: - mod = self.control_logic_r - - insts.append(self.add_inst(name="control{}".format(port), mod=mod)) - - # Inputs - temp = ["csb{}".format(port)] - if port in self.readwrite_ports: - temp.append("web{}".format(port)) - temp.append("clk{}".format(port)) - temp.append("rbl_bl{}".format(port)) - - # Outputs - if port in self.read_ports: - temp.append("s_en{}".format(port)) - if port in self.write_ports: - temp.append("w_en{}".format(port)) - temp.append("p_en_bar{}".format(port)) - temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port)] + self.ext_supplies) - self.connect_inst(temp) - - return insts - - def sp_write(self, sp_name, lvs=False, trim=False): - # Write the entire spice of the object to the file - ############################################################ - # Spice circuit - ############################################################ - sp = open(sp_name, 'w') - - sp.write("**************************************************\n") - sp.write("* OpenRAM generated memory.\n") - sp.write("* Words: {}\n".format(self.num_words)) - sp.write("* Data bits: {}\n".format(self.word_size)) - sp.write("* Banks: {}\n".format(self.num_banks)) - sp.write("* Column mux: {}:1\n".format(self.words_per_row)) - sp.write("* Trimmed: {}\n".format(trim)) - sp.write("* LVS: {}\n".format(lvs)) - sp.write("**************************************************\n") - # This causes unit test mismatch - - # sp.write("* Created: {0}\n".format(datetime.datetime.now())) - # sp.write("* User: {0}\n".format(getpass.getuser())) - # sp.write(".global {0} {1}\n".format(spice["vdd_name"], - # spice["gnd_name"])) - usedMODS = list() - self.sp_write_file(sp, usedMODS, lvs=lvs, trim=trim) - del usedMODS - sp.close() - - def graph_exclude_bits(self, targ_row, targ_col): - """ - Excludes bits in column from being added to graph except target - """ - self.bank.graph_exclude_bits(targ_row, targ_col) - - def clear_exclude_bits(self): - """ - Clears the bit exclusions - """ - self.bank.clear_exclude_bits() - - def graph_exclude_column_mux(self, column_include_num, port): - """ - Excludes all columns muxes unrelated to the target bit being simulated. - """ - self.bank.graph_exclude_column_mux(column_include_num, port) - - def graph_clear_column_mux(self, port): - """ - Clear mux exclusions to allow different bit tests. - """ - self.bank.graph_clear_column_mux(port)