diff --git a/compiler/base/contact.py b/compiler/base/contact.py index 16c671d4..60d3c840 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -51,8 +51,8 @@ class contact(hierarchy_design.hierarchy_design): # Non-preferred directions if directions == "nonpref": - first_dir = "H" if self.get_preferred_direction(layer_stack[0])=="V" else "V" - second_dir = "H" if self.get_preferred_direction(layer_stack[2])=="V" else "V" + first_dir = "H" if tech.preferred_directions[layer_stack[0]]=="V" else "V" + second_dir = "H" if tech.preferred_directions[layer_stack[2]]=="V" else "V" self.directions = (first_dir, second_dir) # Preferred directions elif directions == "pref": diff --git a/compiler/base/custom_cell_properties.py b/compiler/base/custom_cell_properties.py index 25c720ef..43c84206 100644 --- a/compiler/base/custom_cell_properties.py +++ b/compiler/base/custom_cell_properties.py @@ -7,13 +7,15 @@ # from globals import OPTS + class _pins: def __init__(self, pin_dict): # make the pins elements of the class to allow "." access. # For example: props.bitcell.cell_6t.pin.bl = "foobar" - for k,v in pin_dict.items(): + for k, v in pin_dict.items(): self.__dict__[k] = v + class _cell: def __init__(self, pin_dict): pin_dict.update(self._default_power_pins()) @@ -24,13 +26,27 @@ class _cell: return self._pins def _default_power_pins(self): - return { 'vdd' : 'vdd', 'gnd' : 'gnd' } + return {'vdd': 'vdd', + 'gnd': 'gnd'} + class _mirror_axis: def __init__(self, x, y): self.x = x self.y = y + +class _ptx: + def __init__(self, model_is_subckt, bin_spice_models): + self.model_is_subckt = model_is_subckt + self.bin_spice_models = bin_spice_models + + +class _pgate: + def __init__(self, add_implants): + self.add_implants = add_implants + + class _bitcell: def __init__(self, mirror, cell_s8_6t, cell_6t, cell_1rw1r, cell_1w1r): self.mirror = mirror @@ -42,27 +58,27 @@ class _bitcell: def _default(): axis = _mirror_axis(True, False) - cell_s8_6t = _cell({'bl' : 'bl', - 'br' : 'br', + cell_s8_6t = _cell({'bl': 'bl', + 'br': 'br', 'wl': 'wl'}) - cell_6t = _cell({'bl' : 'bl', - 'br' : 'br', - 'wl' : 'wl'}) + cell_6t = _cell({'bl': 'bl', + 'br': 'br', + 'wl': 'wl'}) - cell_1rw1r = _cell({'bl0' : 'bl0', - 'br0' : 'br0', - 'bl1' : 'bl1', - 'br1' : 'br1', - 'wl0' : 'wl0', - 'wl1' : 'wl1'}) + cell_1rw1r = _cell({'bl0': 'bl0', + 'br0': 'br0', + 'bl1': 'bl1', + 'br1': 'br1', + 'wl0': 'wl0', + 'wl1': 'wl1'}) - cell_1w1r = _cell({'bl0' : 'bl0', - 'br0' : 'br0', - 'bl1' : 'bl1', - 'br1' : 'br1', - 'wl0' : 'wl0', - 'wl1' : 'wl1'}) + cell_1w1r = _cell({'bl0': 'bl0', + 'br0': 'br0', + 'bl1': 'bl1', + 'br1': 'br1', + 'wl0': 'wl0', + 'wl1': 'wl1'}) return _bitcell(cell_s8_6t=cell_s8_6t, cell_6t=cell_6t, @@ -94,21 +110,25 @@ class _dff: self.custom_type_list = custom_type_list self.clk_pin = clk_pin + class _dff_buff: def __init__(self, use_custom_ports, custom_buff_ports, add_body_contacts): self.use_custom_ports = use_custom_ports self.buf_ports = custom_buff_ports self.add_body_contacts = add_body_contacts + class _dff_buff_array: def __init__(self, use_custom_ports, add_body_contacts): self.use_custom_ports = use_custom_ports self.add_body_contacts = add_body_contacts + class _bitcell_array: def __init__(self, use_custom_cell_arrangement): self.use_custom_cell_arrangement = use_custom_cell_arrangement + class cell_properties(): """ This contains meta information about the custom designed cells. For @@ -119,35 +139,48 @@ class cell_properties(): self.names = {} self._bitcell = _bitcell._default() - - self._dff = _dff(use_custom_ports = False, - custom_port_list = ["D", "Q", "clk", "vdd", "gnd"], - custom_type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"], - clk_pin= "clk") - - self._dff_buff = _dff_buff(use_custom_ports = False, - custom_buff_ports = ["D", "qint", "clk", "vdd", "gnd"], - add_body_contacts = False) - self._dff_buff_array = _dff_buff_array(use_custom_ports = False, - add_body_contacts = False) + self._ptx = _ptx(model_is_subckt=False, + bin_spice_models=False) + + self._pgate = _pgate(add_implants=False) + + self._dff = _dff(use_custom_ports=False, + custom_port_list=["D", "Q", "clk", "vdd", "gnd"], + custom_type_list=["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"], + clk_pin="clk") + + self._dff_buff = _dff_buff(use_custom_ports=False, + custom_buff_ports=["D", "qint", "clk", "vdd", "gnd"], + add_body_contacts=False) + + self._dff_buff_array = _dff_buff_array(use_custom_ports=False, + add_body_contacts=False) self._write_driver = _cell({'din': 'din', - 'bl' : 'bl', - 'br' : 'br', - 'en' : 'en'}) + 'bl': 'bl', + 'br': 'br', + 'en': 'en'}) - self._sense_amp = _cell({'bl' : 'bl', - 'br' : 'br', - 'dout' : 'dout', - 'en' : 'en'}) + self._sense_amp = _cell({'bl': 'bl', + 'br': 'br', + 'dout': 'dout', + 'en': 'en'}) - self._bitcell_array = _bitcell_array(use_custom_cell_arrangement = []) + self._bitcell_array = _bitcell_array(use_custom_cell_arrangement=[]) @property def bitcell(self): return self._bitcell + @property + def ptx(self): + return self._ptx + + @property + def pgate(self): + return self._pgate + @property def dff(self): return self._dff diff --git a/compiler/base/custom_layer_properties.py b/compiler/base/custom_layer_properties.py new file mode 100644 index 00000000..36e044c5 --- /dev/null +++ b/compiler/base/custom_layer_properties.py @@ -0,0 +1,193 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2020 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. +# + + +class _bank: + def __init__(self, stack, pitch): + # bank + # column address route: stack, pitch + # m1_stack, m2_pitch (default) + # m2_stack, m3_pitch (sky130) + self.stack = stack + self.pitch = pitch + + +class _hierarchical_decoder: + def __init__(self, + bus_layer, + bus_directions, + input_layer, + output_layer, + vertical_supply): + # hierarchical_decoder + # bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch + # m2, pref, m2_pitch, m2_space, m1, m3, m3_pitch + # m1, nonpref, m1_pitch, m2_space, m2, li, li_pitch (sky130) + # + # vertical vdd/gnd + # special jogging + self.bus_layer = bus_layer + self.bus_directions = bus_directions + self.input_layer = input_layer + self.output_layer = output_layer + self.vertical_supply = vertical_supply + + +class _hierarchical_predecode: + def __init__(self, + bus_layer, + bus_directions, + bus_space_factor, + input_layer, + output_layer, + vertical_supply): + # hierarchical_predecode + # bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch + # m2, pref, m2_pitch, m2_space, m1, m1, m1_pitch + # m1, nonpref, m1_pitch, 1`.5*m1_space, m2, li, li_pitch (sky130) + # + # vertical vdd/gnd + # special jogging + self.bus_layer = bus_layer + self.bus_directions = bus_directions + self.bus_space_factor = bus_space_factor + self.input_layer = input_layer + self.output_layer = output_layer + self.vertical_supply = vertical_supply + + +class _column_mux_array: + def __init__(self, + select_layer, + select_pitch, + bitline_layer): + # column_mux_array + # sel_layer, sel_pitch, bitline_layer + # m1, m2_pitch, m2 + # m3, m3_pitch, m1 (sky130) + self.select_layer = select_layer + self.select_pitch= select_pitch + self.bitline_layer = bitline_layer + + +class _port_address: + def __init__(self, + supply_offset): + # port_adress + # special supply offset + self.supply_offset = supply_offset + + +class _port_data: + def __init__(self, + channel_route_bitlines, + enable_layer): + # port_data + # connect bitlines instead of chanel route + + # sense_amp_array + # en_layer + # m1 + # m3 (sky130) + + # precharge_array + # en_bar_layer + # m1 + # m3 (sky130) + self.channel_route_bitlines = channel_route_bitlines + self.enable_layer = enable_layer + + +class _replica_column: + def __init__(self, + even_rows): + # replica_column + # even row check (sky130) + self.even_rows = even_rows + + +class _wordline_driver: + def __init__(self, + vertical_supply): + # wordline_buffer_array + # vertical vdd/gnd (sky130) + # wordline_driver_array + # vertical vdd/gnd (sky130) + # wordline_driver + # vertical vdd/gnd (sky130) + self.vertical_supply = vertical_supply + + +class layer_properties(): + """ + This contains meta information about the module routing layers. These + can be overriden in the tech.py file. + """ + def __init__(self): + + self._bank = _bank(stack="m1_stack", + pitch="m2_pitch") + + self._hierarchical_decoder = _hierarchical_decoder(bus_layer="m2", + bus_directions="pref", + input_layer="m1", + output_layer="m3", + vertical_supply=False) + + self._hierarchical_predecode = _hierarchical_predecode(bus_layer="m2", + bus_directions="pref", + bus_space_factor=1, + input_layer="m1", + output_layer="m1", + vertical_supply=False) + + self._column_mux_array = _column_mux_array(select_layer="m1", + select_pitch="m2_pitch", + bitline_layer="m2") + + self._port_address = _port_address(supply_offset=False) + + self._port_data = _port_data(channel_route_bitlines=True, + enable_layer="m1") + + self._replica_column = _replica_column(even_rows=False) + + self._wordline_driver = _wordline_driver(vertical_supply=False) + + @property + def bank(self): + return self._bank + + @property + def column_mux_array(self): + return self._column_mux_array + + @property + def hierarchical_decoder(self): + return self._hierarchical_decoder + + @property + def hierarchical_predecode(self): + return self._hierarchical_predecode + + @property + def port_address(self): + return self._port_address + + @property + def port_data(self): + return self._port_data + + @property + def replica_column(self): + return self._replica_column + + @property + def wordline_driver(self): + return self._wordline_driver + diff --git a/compiler/base/design.py b/compiler/base/design.py index 96e5f26b..90364658 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -8,6 +8,7 @@ from hierarchy_design import hierarchy_design from utils import round_to_grid import contact +from tech import preferred_directions from globals import OPTS import re @@ -18,21 +19,110 @@ class design(hierarchy_design): some DRC/layer constants and analytical models for other modules to reuse. """ - + def __init__(self, name): super().__init__(name) - - self.setup_drc_constants() - self.setup_layer_constants() - self.setup_multiport_constants() + self.setup_multiport_constants() + def check_pins(self): for pin_name in self.pins: pins = self.get_pins(pin_name) for pin in pins: print(pin_name, pin) + + @classmethod + def setup_drc_constants(design): + """ + These are some DRC constants used in many places + in the compiler. + """ + # Make some local rules for convenience + from tech import drc + for rule in drc.keys(): + # Single layer width rules + match = re.search(r"minwidth_(.*)", rule) + if match: + if match.group(1) == "active_contact": + setattr(design, "contact_width", drc(match.group(0))) + else: + setattr(design, match.group(1) + "_width", drc(match.group(0))) + + # Single layer area rules + match = re.search(r"minarea_(.*)", rule) + if match: + setattr(design, match.group(0), drc(match.group(0))) + + # Single layer spacing rules + match = re.search(r"(.*)_to_(.*)", rule) + if match and match.group(1) == match.group(2): + setattr(design, match.group(1) + "_space", drc(match.group(0))) + elif match and match.group(1) != match.group(2): + if match.group(2) == "poly_active": + setattr(design, match.group(1) + "_to_contact", + drc(match.group(0))) + else: + setattr(design, match.group(0), drc(match.group(0))) + + match = re.search(r"(.*)_enclose_(.*)", rule) + if match: + setattr(design, match.group(0), drc(match.group(0))) + + match = re.search(r"(.*)_extend_(.*)", rule) + if match: + setattr(design, match.group(0), drc(match.group(0))) + + # Create the maximum well extend active that gets used + # by cells to extend the wells for interaction with other cells + from tech import layer + design.well_extend_active = 0 + if "nwell" in layer: + design.well_extend_active = max(design.well_extend_active, design.nwell_extend_active) + if "pwell" in layer: + design.well_extend_active = max(design.well_extend_active, design.pwell_extend_active) + + # The active offset is due to the well extension + if "pwell" in layer: + design.pwell_enclose_active = drc("pwell_enclose_active") + else: + design.pwell_enclose_active = 0 + if "nwell" in layer: + design.nwell_enclose_active = drc("nwell_enclose_active") + else: + design.nwell_enclose_active = 0 + # Use the max of either so that the poly gates will align properly + design.well_enclose_active = max(design.pwell_enclose_active, + design.nwell_enclose_active, + design.active_space) - def setup_layer_constants(self): + # These are for debugging previous manual rules + if False: + print("poly_width", design.poly_width) + print("poly_space", design.poly_space) + print("m1_width", design.m1_width) + print("m1_space", design.m1_space) + print("m2_width", design.m2_width) + print("m2_space", design.m2_space) + print("m3_width", design.m3_width) + print("m3_space", design.m3_space) + print("m4_width", design.m4_width) + print("m4_space", design.m4_space) + print("active_width", design.active_width) + print("active_space", design.active_space) + print("contact_width", design.contact_width) + print("poly_to_active", design.poly_to_active) + print("poly_extend_active", design.poly_extend_active) + print("poly_to_contact", design.poly_to_contact) + print("active_contact_to_gate", design.active_contact_to_gate) + print("poly_contact_to_gate", design.poly_contact_to_gate) + print("well_enclose_active", design.well_enclose_active) + print("implant_enclose_active", design.implant_enclose_active) + print("implant_space", design.implant_space) + import sys + sys.exit(1) + + @classmethod + def setup_layer_constants(design): """ These are some layer constants used in many places in the compiler. @@ -46,7 +136,7 @@ class design(hierarchy_design): # Set the stack as a local helper try: layer_stack = getattr(tech, key) - setattr(self, key, layer_stack) + setattr(design, key, layer_stack) except AttributeError: pass @@ -55,14 +145,14 @@ class design(hierarchy_design): continue # Add the pitch - setattr(self, + setattr(design, "{}_pitch".format(layer), - self.compute_pitch(layer, True)) + design.compute_pitch(layer, True)) # Add the non-preferrd pitch (which has vias in the "wrong" way) - setattr(self, + setattr(design, "{}_nonpref_pitch".format(layer), - self.compute_pitch(layer, False)) + design.compute_pitch(layer, False)) if False: from tech import preferred_directions @@ -73,17 +163,18 @@ class design(hierarchy_design): continue try: print("{0} width {1} space {2}".format(name, - getattr(self, "{}_width".format(name)), - getattr(self, "{}_space".format(name)))) + getattr(design, "{}_width".format(name)), + getattr(design, "{}_space".format(name)))) - print("pitch {0} nonpref {1}".format(getattr(self, "{}_pitch".format(name)), - getattr(self, "{}_nonpref_pitch".format(name)))) + print("pitch {0} nonpref {1}".format(getattr(design, "{}_pitch".format(name)), + getattr(design, "{}_nonpref_pitch".format(name)))) except AttributeError: pass import sys sys.exit(1) - def compute_pitch(self, layer, preferred=True): + @staticmethod + def compute_pitch(layer, preferred=True): """ This is the preferred direction pitch @@ -95,13 +186,18 @@ class design(hierarchy_design): for stack in layer_stacks: # Compute the pitch with both vias above and below (if they exist) if stack[0] == layer: - pitches.append(self.compute_layer_pitch(stack, preferred)) + pitches.append(design.compute_layer_pitch(stack, preferred)) if stack[2] == layer: - pitches.append(self.compute_layer_pitch(stack[::-1], True)) + pitches.append(design.compute_layer_pitch(stack[::-1], True)) return max(pitches) - def compute_layer_pitch(self, layer_stack, preferred): + @staticmethod + def get_preferred_direction(layer): + return preferred_directions[layer] + + @staticmethod + def compute_layer_pitch(layer_stack, preferred): (layer1, via, layer2) = layer_stack try: @@ -113,112 +209,24 @@ class design(hierarchy_design): contact1 = getattr(contact, layer2 + "_via") if preferred: - if self.get_preferred_direction(layer1) == "V": + if preferred_directions[layer1] == "V": contact_width = contact1.first_layer_width else: contact_width = contact1.first_layer_height else: - if self.get_preferred_direction(layer1) == "V": + if preferred_directions[layer1] == "V": contact_width = contact1.first_layer_height else: contact_width = contact1.first_layer_width - layer_space = getattr(self, layer1 + "_space") + layer_space = getattr(design, layer1 + "_space") #print(layer_stack) #print(contact1) pitch = contact_width + layer_space return round_to_grid(pitch) - - def setup_drc_constants(self): - """ - These are some DRC constants used in many places - in the compiler. - """ - # Make some local rules for convenience - from tech import drc - for rule in drc.keys(): - # Single layer width rules - match = re.search(r"minwidth_(.*)", rule) - if match: - if match.group(1) == "active_contact": - setattr(self, "contact_width", drc(match.group(0))) - else: - setattr(self, match.group(1) + "_width", drc(match.group(0))) - # Single layer area rules - match = re.search(r"minarea_(.*)", rule) - if match: - setattr(self, match.group(0), drc(match.group(0))) - - # Single layer spacing rules - match = re.search(r"(.*)_to_(.*)", rule) - if match and match.group(1) == match.group(2): - setattr(self, match.group(1) + "_space", drc(match.group(0))) - elif match and match.group(1) != match.group(2): - if match.group(2) == "poly_active": - setattr(self, match.group(1) + "_to_contact", - drc(match.group(0))) - else: - setattr(self, match.group(0), drc(match.group(0))) - - match = re.search(r"(.*)_enclose_(.*)", rule) - if match: - setattr(self, match.group(0), drc(match.group(0))) - match = re.search(r"(.*)_extend_(.*)", rule) - if match: - setattr(self, match.group(0), drc(match.group(0))) - - # Create the maximum well extend active that gets used - # by cells to extend the wells for interaction with other cells - from tech import layer - self.well_extend_active = 0 - if "nwell" in layer: - self.well_extend_active = max(self.well_extend_active, self.nwell_extend_active) - if "pwell" in layer: - self.well_extend_active = max(self.well_extend_active, self.pwell_extend_active) - - # The active offset is due to the well extension - if "pwell" in layer: - self.pwell_enclose_active = drc("pwell_enclose_active") - else: - self.pwell_enclose_active = 0 - if "nwell" in layer: - self.nwell_enclose_active = drc("nwell_enclose_active") - else: - self.nwell_enclose_active = 0 - # Use the max of either so that the poly gates will align properly - self.well_enclose_active = max(self.pwell_enclose_active, - self.nwell_enclose_active, - self.active_space) - - # These are for debugging previous manual rules - if False: - print("poly_width", self.poly_width) - print("poly_space", self.poly_space) - print("m1_width", self.m1_width) - print("m1_space", self.m1_space) - print("m2_width", self.m2_width) - print("m2_space", self.m2_space) - print("m3_width", self.m3_width) - print("m3_space", self.m3_space) - print("m4_width", self.m4_width) - print("m4_space", self.m4_space) - print("active_width", self.active_width) - print("active_space", self.active_space) - print("contact_width", self.contact_width) - print("poly_to_active", self.poly_to_active) - print("poly_extend_active", self.poly_extend_active) - print("poly_to_contact", self.poly_to_contact) - print("active_contact_to_gate", self.active_contact_to_gate) - print("poly_contact_to_gate", self.poly_contact_to_gate) - print("well_enclose_active", self.well_enclose_active) - print("implant_enclose_active", self.implant_enclose_active) - print("implant_space", self.implant_space) - import sys - sys.exit(1) - def setup_multiport_constants(self): """ These are contants and lists that aid multiport design. @@ -266,3 +274,6 @@ class design(hierarchy_design): total_module_power += inst.mod.analytical_power(corner, load) return total_module_power +design.setup_drc_constants() +design.setup_layer_constants() + diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index e4830226..7fe838cb 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -13,7 +13,6 @@ from tech import drc, GDS from tech import layer as techlayer from tech import layer_indices from tech import layer_stacks -from tech import preferred_directions import os from globals import OPTS from vector import vector @@ -537,10 +536,6 @@ class layout(): position_list=coordinates, widen_short_wires=widen_short_wires) - def get_preferred_direction(self, layer): - """ Return the preferred routing directions """ - return preferred_directions[layer] - def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None): """ Add a three layer via structure. """ from sram_factory import factory diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 5694a64d..5a987ca4 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -10,7 +10,7 @@ import utils from tech import GDS, layer from tech import cell_properties as props import bitcell_base -from globals import OPTS + class bitcell(bitcell_base.bitcell_base): """ @@ -46,8 +46,6 @@ class bitcell(bitcell_base.bitcell_base): self.add_pin_types(self.type_list) self.nets_match = self.do_nets_exist(self.storage_nets) - #debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells") - def get_all_wl_names(self): """ Creates a list of all wordline pin names """ row_pins = [props.bitcell.cell_6t.pin.wl] diff --git a/compiler/example_configs/big_config_scn4m_subm.py b/compiler/example_configs/big_config_scn4m_subm.py index b90a9b1a..15d8634e 100644 --- a/compiler/example_configs/big_config_scn4m_subm.py +++ b/compiler/example_configs/big_config_scn4m_subm.py @@ -2,7 +2,7 @@ word_size = 32 num_words = 128 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py b/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py index 7f2e6059..46722ac9 100644 --- a/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py +++ b/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py @@ -6,7 +6,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/example_configs/example_config_1rw_1w_scn4m_subm.py b/compiler/example_configs/example_config_1rw_1w_scn4m_subm.py new file mode 100644 index 00000000..360447e9 --- /dev/null +++ b/compiler/example_configs/example_config_1rw_1w_scn4m_subm.py @@ -0,0 +1,21 @@ +word_size = 4 +num_words = 16 +write_size = 2 + +num_rw_ports = 1 +num_r_ports = 0 +num_w_ports = 1 + +tech_name = "scn4m_subm" +nominal_corner_only = False +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] + +route_supplies = False +check_lvsdrc = True + +output_path = "temp" +output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size, + num_words, + tech_name) diff --git a/compiler/example_configs/example_config_1rw_2mux_scn4m_subm.py b/compiler/example_configs/example_config_1rw_2mux_scn4m_subm.py index a09edfdb..5f20b336 100644 --- a/compiler/example_configs/example_config_1rw_2mux_scn4m_subm.py +++ b/compiler/example_configs/example_config_1rw_2mux_scn4m_subm.py @@ -7,7 +7,7 @@ num_r_ports = 0 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py b/compiler/example_configs/example_config_1w_1r_scn4m_subm.py index 7698f1a3..9fe143a5 100644 --- a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py +++ b/compiler/example_configs/example_config_1w_1r_scn4m_subm.py @@ -6,7 +6,7 @@ num_r_ports = 1 num_w_ports = 1 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/example_configs/example_config_2rw_scn4m_subm.py b/compiler/example_configs/example_config_2rw_scn4m_subm.py new file mode 100644 index 00000000..3d0721cc --- /dev/null +++ b/compiler/example_configs/example_config_2rw_scn4m_subm.py @@ -0,0 +1,21 @@ +word_size = 2 +num_words = 16 + +num_rw_ports = 2 +num_r_ports = 0 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corner_only = False +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] + +route_supplies = False +check_lvsdrc = True + +output_path = "temp" +output_name = "sram_1w_1r_{0}_{1}_{2}".format(word_size, + num_words, + tech_name) + diff --git a/compiler/example_configs/example_config_freepdk45.py b/compiler/example_configs/example_config_freepdk45.py index 9c536bc6..27b4c79a 100644 --- a/compiler/example_configs/example_config_freepdk45.py +++ b/compiler/example_configs/example_config_freepdk45.py @@ -2,14 +2,14 @@ word_size = 2 num_words = 16 tech_name = "freepdk45" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [1.0] temperatures = [25] route_supplies = False check_lvsdrc = True -# nominal_corners_only = True +# nominal_corner_only = True load_scales = [0.5, 1, 4] slew_scales = [0.5, 1] diff --git a/compiler/example_configs/example_config_scn4m_subm.py b/compiler/example_configs/example_config_scn4m_subm.py index 71ef328b..4cfe2c07 100644 --- a/compiler/example_configs/example_config_scn4m_subm.py +++ b/compiler/example_configs/example_config_scn4m_subm.py @@ -2,7 +2,7 @@ word_size = 2 num_words = 16 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/example_configs/giant_config_scn4m_subm.py b/compiler/example_configs/giant_config_scn4m_subm.py index 56751a9c..7d683088 100644 --- a/compiler/example_configs/giant_config_scn4m_subm.py +++ b/compiler/example_configs/giant_config_scn4m_subm.py @@ -2,7 +2,7 @@ word_size = 64 num_words = 1024 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [ 5.0 ] temperatures = [ 25 ] diff --git a/compiler/example_configs/medium_config_scn4m_subm.py b/compiler/example_configs/medium_config_scn4m_subm.py index ac4af8b4..dc3ec36f 100644 --- a/compiler/example_configs/medium_config_scn4m_subm.py +++ b/compiler/example_configs/medium_config_scn4m_subm.py @@ -2,7 +2,7 @@ word_size = 16 num_words = 256 tech_name = "scn4m_subm" -nominal_corners_only = False +nominal_corner_only = False process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/example_configs/riscv-freepdk45-8kbyte.py b/compiler/example_configs/riscv-freepdk45-8kbyte.py index b0ebf764..ad7d6072 100644 --- a/compiler/example_configs/riscv-freepdk45-8kbyte.py +++ b/compiler/example_configs/riscv-freepdk45-8kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "freepdk45" -nominal_corners_only = True +nominal_corner_only = True route_supplies = False check_lvsdrc = False diff --git a/compiler/example_configs/riscv-scn4m_subm-16kbyte.py b/compiler/example_configs/riscv-scn4m_subm-16kbyte.py index befe49fb..5ca44842 100644 --- a/compiler/example_configs/riscv-scn4m_subm-16kbyte.py +++ b/compiler/example_configs/riscv-scn4m_subm-16kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = True +nominal_corner_only = True route_supplies = False check_lvsdrc = False diff --git a/compiler/example_configs/riscv-scn4m_subm-1kbyte.py b/compiler/example_configs/riscv-scn4m_subm-1kbyte.py index 1ab9f5fe..9572aeaf 100644 --- a/compiler/example_configs/riscv-scn4m_subm-1kbyte.py +++ b/compiler/example_configs/riscv-scn4m_subm-1kbyte.py @@ -7,7 +7,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = True +nominal_corner_only = True route_supplies = True check_lvsdrc = True diff --git a/compiler/example_configs/riscv-scn4m_subm-2kbyte.py b/compiler/example_configs/riscv-scn4m_subm-2kbyte.py index 267e31ef..814d77e1 100644 --- a/compiler/example_configs/riscv-scn4m_subm-2kbyte.py +++ b/compiler/example_configs/riscv-scn4m_subm-2kbyte.py @@ -7,7 +7,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = True +nominal_corner_only = True route_supplies = True check_lvsdrc = True diff --git a/compiler/example_configs/riscv-scn4m_subm-32kbyte.py b/compiler/example_configs/riscv-scn4m_subm-32kbyte.py index 98cb8808..dc9a31b7 100644 --- a/compiler/example_configs/riscv-scn4m_subm-32kbyte.py +++ b/compiler/example_configs/riscv-scn4m_subm-32kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = True +nominal_corner_only = True route_supplies = False check_lvsdrc = False diff --git a/compiler/example_configs/riscv-scn4m_subm-4kbyte.py b/compiler/example_configs/riscv-scn4m_subm-4kbyte.py index 87cf4a71..5f374655 100644 --- a/compiler/example_configs/riscv-scn4m_subm-4kbyte.py +++ b/compiler/example_configs/riscv-scn4m_subm-4kbyte.py @@ -7,7 +7,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = True +nominal_corner_only = True route_supplies = True check_lvsdrc = True diff --git a/compiler/example_configs/riscv-scn4m_subm-8kbyte.py b/compiler/example_configs/riscv-scn4m_subm-8kbyte.py index 8b1715ff..01dd6e7a 100644 --- a/compiler/example_configs/riscv-scn4m_subm-8kbyte.py +++ b/compiler/example_configs/riscv-scn4m_subm-8kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "scn4m_subm" -nominal_corners_only = True +nominal_corner_only = True route_supplies = False check_lvsdrc = False diff --git a/compiler/example_configs/riscv-sky130-1kbyte.py b/compiler/example_configs/riscv-sky130-1kbyte.py index c4a298d2..637505dd 100644 --- a/compiler/example_configs/riscv-sky130-1kbyte.py +++ b/compiler/example_configs/riscv-sky130-1kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "sky130" -nominal_corners_only = True +nominal_corner_only = True route_supplies = True check_lvsdrc = True diff --git a/compiler/example_configs/riscv-sky130-2kbyte.py b/compiler/example_configs/riscv-sky130-2kbyte.py index d50d532e..cb520b48 100644 --- a/compiler/example_configs/riscv-sky130-2kbyte.py +++ b/compiler/example_configs/riscv-sky130-2kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "sky130" -nominal_corners_only = True +nominal_corner_only = True route_supplies = True check_lvsdrc = True diff --git a/compiler/example_configs/riscv-sky130-4kbyte.py b/compiler/example_configs/riscv-sky130-4kbyte.py index 2d870e88..815f2105 100644 --- a/compiler/example_configs/riscv-sky130-4kbyte.py +++ b/compiler/example_configs/riscv-sky130-4kbyte.py @@ -9,7 +9,7 @@ num_r_ports = 1 num_w_ports = 0 tech_name = "sky130" -nominal_corners_only = True +nominal_corner_only = True route_supplies = True check_lvsdrc = True diff --git a/compiler/example_configs/run1.py b/compiler/example_configs/run1.py deleted file mode 100644 index f0b2d753..00000000 --- a/compiler/example_configs/run1.py +++ /dev/null @@ -1,19 +0,0 @@ -word_size = 2 -num_words = 16 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [5.0] -temperatures = [25] - -#netlist_only = True -route_supplies = True -check_lvsdrc = True - -output_name = "sram_{0}_{1}_{2}".format(word_size, - num_words, - tech_name) - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" diff --git a/compiler/example_configs/run2.py b/compiler/example_configs/run2.py deleted file mode 100644 index c70009ed..00000000 --- a/compiler/example_configs/run2.py +++ /dev/null @@ -1,19 +0,0 @@ -word_size = 8 -num_words = 128 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [5.0] -temperatures = [25] - -route_supplies = True -check_lvsdrc = True - -netlist_only = True -output_name = "sram_{0}_{1}_{2}".format(word_size, - num_words, - tech_name) - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" diff --git a/compiler/example_configs/run3.py b/compiler/example_configs/run3.py deleted file mode 100644 index 9c18c76e..00000000 --- a/compiler/example_configs/run3.py +++ /dev/null @@ -1,18 +0,0 @@ -word_size = 16 -num_words = 256 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [5.0] -temperatures = [25] - -route_supplies = True -check_lvsdrc = True -netlist_only = True -output_name = "sram_{0}_{1}_{2}".format(word_size, - num_words, - tech_name) - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" diff --git a/compiler/example_configs/run4.py b/compiler/example_configs/run4.py deleted file mode 100644 index 5b2ba5b4..00000000 --- a/compiler/example_configs/run4.py +++ /dev/null @@ -1,18 +0,0 @@ -word_size = 32 -num_words = 128 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [5.0] -temperatures = [25] - -route_supplies = True -check_lvsdrc = True -netlist_only = True -output_name = "sram_{0}_{1}_{2}".format(word_size, - num_words, - tech_name) - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" diff --git a/compiler/example_configs/run5.py b/compiler/example_configs/run5.py deleted file mode 100644 index 49416807..00000000 --- a/compiler/example_configs/run5.py +++ /dev/null @@ -1,19 +0,0 @@ -word_size = 64 -num_words = 128 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [5.0] -temperatures = [25] - -route_supplies = True -check_lvsdrc = True - -output_path = "/home/jesse/thesis/outputs/run5" -output_name = "sram_{0}_{1}_{2}".format(word_size, - num_words, - tech_name) - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" diff --git a/compiler/example_configs/s8config.py b/compiler/example_configs/s8config.py deleted file mode 100644 index 7c0de527..00000000 --- a/compiler/example_configs/s8config.py +++ /dev/null @@ -1,31 +0,0 @@ -word_size = 16 -num_words = 16 - -num_rw_ports = 1 -num_r_ports = 1 -num_w_ports = 0 - -tech_name = "sky130" - - - -accuracy_requirement = 0.05 -magic_exe = ("magic", "magic") -nominal_corners_only = False -process_corners = ["TT"] -supply_voltages = [5.0] -temperatures = [25] - -netlist_only = False -route_supplies = "grid" -check_lvsdrc = False - -#replica_bitcell_array = "/home/jesse/openram/technology/sky130/modules/replica_bitcell_array.py" - -output_path = "sram_" + str(accuracy_requirement) -output_name = "sram_{0}_{1}_{2}_{3}".format(word_size, - num_words, - tech_name, - accuracy_requirement - ) -write_size=8 diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a1c6c251..bede24a1 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -9,9 +9,10 @@ import debug import design from sram_factory import factory from math import log, ceil, floor -from tech import drc, layer +from tech import drc from vector import vector from globals import OPTS +from tech import layer_properties as layer_props class bank(design.design): @@ -906,18 +907,13 @@ class bank(design.design): offset=mid2) self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) - def route_column_address_lines(self, port): """ Connecting the select lines of column mux to the address bus """ if not self.col_addr_size>0: return - if OPTS.tech_name == "sky130": - stack = self.m2_stack - pitch = self.m3_pitch - else: - stack = self.m1_stack - pitch = self.m2_pitch + stack = getattr(self, layer_props.bank.stack) + pitch = getattr(self, layer_props.bank.pitch) if self.col_addr_size == 1: diff --git a/compiler/modules/column_mux_array.py b/compiler/modules/column_mux_array.py index 87e750cf..61c71672 100644 --- a/compiler/modules/column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -11,7 +11,8 @@ from tech import layer, preferred_directions from vector import vector from sram_factory import factory from globals import OPTS -from tech import cell_properties +from tech import cell_properties as cell_props +from tech import layer_properties as layer_props class column_mux_array(design.design): @@ -33,14 +34,18 @@ class column_mux_array(design.design): self.bitcell_br = bitcell_br self.column_offset = column_offset - if OPTS.tech_name == "sky130": - self.sel_layer = "m3" - self.sel_pitch = self.m3_pitch - self.bitline_layer = "m1" - else: - self.sel_layer = "m1" - self.sel_pitch = self.m2_pitch - self.bitline_layer = "m2" + self.sel_layer = layer_props.column_mux_array.select_layer + self.sel_pitch = getattr(self, layer_props.column_mux_array.select_pitch) + self.bitline_layer = layer_props.column_mux_array.bitline_layer + + # if OPTS.tech_name == "sky130": + # self.sel_layer = "m3" + # self.sel_pitch = self.m3_pitch + # self.bitline_layer = "m1" + # else: + # self.sel_layer = "m1" + # self.sel_pitch = self.m2_pitch + # self.bitline_layer = "m2" if preferred_directions[self.sel_layer] == "V": self.via_directions = ("H", "H") @@ -123,7 +128,7 @@ class column_mux_array(design.design): # For every column, add a pass gate for col_num, xoffset in enumerate(self.offsets[0:self.columns]): - if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2: + if cell_props.bitcell.mirror.y and (col_num + self.column_offset) % 2: mirror = "MY" xoffset = xoffset + self.mux.width else: diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index e99d7b89..7f9035d9 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -85,8 +85,8 @@ class control_logic(design.design): def add_modules(self): """ Add all the required modules """ - dff = factory.create(module_type="dff_buf") - dff_height = dff.height + self.dff = factory.create(module_type="dff_buf") + dff_height = self.dff.height self.ctrl_dff_array = factory.create(module_type="dff_buf_array", rows=self.num_control_signals, @@ -119,7 +119,7 @@ class control_logic(design.design): # We will use the maximum since this same value is used to size the wl_en # and the p_en_bar drivers - max_fanout = max(self.num_rows, self.num_cols) + # max_fanout = max(self.num_rows, self.num_cols) # wl_en drives every row in the bank self.wl_en_driver = factory.create(module_type="pdriver", @@ -162,7 +162,7 @@ class control_logic(design.design): self.delay_chain=factory.create(module_type="delay_chain", fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ]) self.add_mod(self.delay_chain) - + def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout): """Determine the size of the delay chain used for the Sense Amp Enable using path delays""" from math import ceil @@ -721,10 +721,8 @@ class control_logic(design.design): def route_supply(self): """ Add vdd and gnd to the instance cells """ - if OPTS.tech_name == "sky130": - supply_layer = "li" - else: - supply_layer = "m1" + supply_layer = self.dff.get_pin("vdd").layer + max_row_x_loc = max([inst.rx() for inst in self.row_end_inst]) for inst in self.row_end_inst: pins = inst.get_pins("vdd") diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f022a048..a5a63fc8 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -11,6 +11,7 @@ import math from sram_factory import factory from vector import vector from globals import OPTS +from tech import layer_properties as layer_props class hierarchical_decoder(design.design): @@ -181,25 +182,15 @@ class hierarchical_decoder(design.design): # Inputs to cells are on input layer # Outputs from cells are on output layer - if OPTS.tech_name == "sky130": - self.bus_layer = "m1" - self.bus_directions = "nonpref" - self.bus_pitch = self.m1_pitch - self.bus_space = self.m2_space - self.input_layer = "m2" - self.output_layer = "li" - self.output_layer_pitch = self.li_pitch - else: - self.bus_layer = "m2" - self.bus_directions = "pref" - self.bus_pitch = self.m2_pitch - self.bus_space = self.m2_space - # These two layers being the same requires a special jog - # to ensure to conflicts with the output layers - self.input_layer = "m1" - self.output_layer = "m3" - self.output_layer_pitch = self.m3_pitch + self.bus_layer = layer_props.hierarchical_decoder.bus_layer + self.bus_directions = layer_props.hierarchical_decoder.bus_directions + self.bus_pitch = getattr(self, self.bus_layer + "_pitch") + self.bus_space = getattr(self, self.bus_layer + "_space") + self.input_layer = layer_props.hierarchical_decoder.input_layer + self.output_layer = layer_props.hierarchical_decoder.output_layer + self.output_layer_pitch = getattr(self, self.output_layer + "_pitch") + # Two extra pitches between modules on left and right self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + self.bus_pitch self.row_decoder_height = self.and2.height * self.num_outputs @@ -606,7 +597,7 @@ class hierarchical_decoder(design.design): must-connects next level up. """ - if OPTS.tech_name == "sky130": + if layer_props.hierarchical_decoder.vertical_supply: for n in ["vdd", "gnd"]: pins = self.and_inst[0].get_pins(n) for pin in pins: @@ -678,9 +669,9 @@ class hierarchical_decoder(design.design): mid_point2 = vector(x_offset, y_offset) rail_pos = vector(self.predecode_bus[rail_name].cx(), mid_point2.y) self.add_path(self.output_layer, [pin_pos, mid_point1, mid_point2, rail_pos]) - if OPTS.tech_name == "sky130": - above_rail = vector(self.predecode_bus[rail_name].cx(), mid_point2.y + (self.cell_height/2)) - self.add_path(self.bus_layer, [rail_pos, above_rail], width = self.li_width + self.m1_enclose_mcon * 2) + if layer_props.hierarchical_decoder.vertical_supply: + above_rail = vector(self.predecode_bus[rail_name].cx(), mid_point2.y + (self.cell_height / 2)) + self.add_path(self.bus_layer, [rail_pos, above_rail], width=self.li_width + self.m1_enclose_mcon * 2) # pin_pos = pin.center() # rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y) diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index f5bff640..3c19910f 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -11,6 +11,7 @@ import math from vector import vector from sram_factory import factory from globals import OPTS +from tech import layer_properties as layer_props class hierarchical_predecode(design.design): @@ -83,24 +84,15 @@ class hierarchical_predecode(design.design): # Inputs to cells are on input layer # Outputs from cells are on output layer - if OPTS.tech_name == "sky130": - self.bus_layer = "m1" - self.bus_directions = "nonpref" - self.bus_pitch = self.m1_pitch - self.bus_space = 1.5 * self.m1_space - self.input_layer = "m2" - self.output_layer = "li" - self.output_layer_pitch = self.li_pitch - else: - self.bus_layer = "m2" - self.bus_directions = "pref" - self.bus_pitch = self.m2_pitch - self.bus_space = self.m2_space - # This requires a special jog to ensure to conflicts with the output layers - self.input_layer = "m1" - self.output_layer = "m1" - self.output_layer_pitch = self.m1_pitch - + + self.bus_layer = layer_props.hierarchical_predecode.bus_layer + self.bus_directions = layer_props.hierarchical_predecode.bus_directions + self.bus_pitch = getattr(self, self.bus_layer + "_pitch") + self.bus_space = layer_props.hierarchical_predecode.bus_space_factor * getattr(self, self.bus_layer + "_space") + self.input_layer = layer_props.hierarchical_predecode.input_layer + self.output_layer = layer_props.hierarchical_predecode.output_layer + self.output_layer_pitch = getattr(self, self.output_layer + "_pitch") + self.height = self.number_of_outputs * self.and_mod.height # x offset for input inverters @@ -276,9 +268,9 @@ class hierarchical_predecode(design.design): height=via.mod.second_layer_height, width=via.mod.second_layer_width) - if OPTS.tech_name == "sky130": - below_rail = vector(self.decode_rails[out_pin].cx(), y_offset - (self.cell_height/2)) - self.add_path(self.bus_layer, [rail_pos, below_rail], width = self.li_width + self.m1_enclose_mcon * 2) + if layer_props.hierarchical_predecode.vertical_supply: + below_rail = vector(self.decode_rails[out_pin].cx(), y_offset - (self.cell_height / 2)) + self.add_path(self.bus_layer, [rail_pos, below_rail], width=self.li_width + self.m1_enclose_mcon * 2) def route_and_to_rails(self): # This 2D array defines the connection mapping @@ -319,8 +311,8 @@ class hierarchical_predecode(design.design): def route_vdd_gnd(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ - # In sky130, we use hand-made decoder cells with vertical power - if OPTS.tech_name == "sky130" and not self.column_decoder: + # We may ahve vertical power supply rails + if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder: for n in ["vdd", "gnd"]: # This makes a wire from top to bottom for both inv and and gates for i in [self.inv_inst, self.and_inst]: diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index e416eb43..14d0b833 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -10,6 +10,7 @@ from sram_factory import factory from vector import vector from tech import layer from globals import OPTS +from tech import layer_properties as layer_props class port_address(design.design): @@ -80,7 +81,7 @@ class port_address(design.design): self.copy_power_pins(inst, "gnd") for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): - if OPTS.tech_name == "sky130": + if layer_props.port_address.supply_offset: self.add_power_pin("vdd", rbl_vdd_pin.center()) else: self.add_power_pin("vdd", rbl_vdd_pin.lc()) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index c013bc4a..636f4b44 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -11,6 +11,7 @@ from sram_factory import factory from collections import namedtuple from vector import vector from globals import OPTS +from tech import layer_properties as layer_props class port_data(design.design): @@ -580,20 +581,20 @@ class port_data(design.design): inst1_start_bit=self.num_cols + off, inst2_start_bit=self.word_size) - # This could be a channel route, but in some techs the bitlines - # are too close together. - elif OPTS.tech_name == "sky130": - self.connect_bitlines(inst1=inst1, - inst1_bls_template=inst1_bls_templ, - inst2=inst2, - num_bits=self.word_size, - inst1_start_bit=start_bit) - else: + elif layer_props.port_data.channel_route_bitlines: self.channel_route_bitlines(inst1=inst1, inst1_bls_template=inst1_bls_templ, inst2=inst2, num_bits=self.word_size + self.num_spare_cols, inst1_start_bit=start_bit) + # This could be a channel route, but in some techs the bitlines + # are too close together. + else: + self.connect_bitlines(inst1=inst1, + inst1_bls_template=inst1_bls_templ, + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) def route_write_driver_to_column_mux_or_precharge_array(self, port): """ Routing of BL and BR between sense_amp and column mux or precharge array """ @@ -640,17 +641,16 @@ class port_data(design.design): # This could be a channel route, but in some techs the bitlines # are too close together. - elif OPTS.tech_name == "sky130": + elif layer_props.port_data.channel_route_bitlines: + self.channel_route_bitlines(inst1=inst1, inst2=inst2, + num_bits=self.word_size + self.num_spare_cols, + inst1_bls_template=inst1_bls_templ, + inst1_start_bit=start_bit) + else: self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, inst1_bls_template=inst1_bls_templ, inst1_start_bit=start_bit) - else: - self.channel_route_bitlines(inst1=inst1, inst2=inst2, - num_bits=self.word_size+self.num_spare_cols, - inst1_bls_template=inst1_bls_templ, - inst1_start_bit=start_bit) - def route_write_driver_to_sense_amp(self, port): """ Routing of BL and BR between write driver and sense amp """ diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index d7e36fce..0ce472c3 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -9,6 +9,7 @@ from tech import cell_properties from sram_factory import factory from vector import vector from globals import OPTS +from tech import layer_properties as layer_props class replica_column(bitcell_base_array): @@ -41,7 +42,7 @@ class replica_column(bitcell_base_array): "Replica bit cannot be the dummy row.") debug.check(replica_bit <= self.left_rbl or replica_bit >= self.total_size - self.right_rbl - 1, "Replica bit cannot be in the regular array.") - if OPTS.tech_name == "sky130": + if layer_props.replica_column.even_rows: debug.check(rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0, "sky130 currently requires rows to be even and to start with X mirroring" + " (left_rbl must be odd) for LVS.") diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 45f3ef33..3b83b5eb 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -7,10 +7,11 @@ # import debug import design -from tech import drc, layer +from tech import layer from vector import vector from sram_factory import factory from globals import OPTS +from tech import layer_properties as layer_props class wordline_buffer_array(design.design): @@ -70,7 +71,7 @@ class wordline_buffer_array(design.design): Add a pin for each row of vdd/gnd which are must-connects next level up. """ - if OPTS.tech_name == "sky130": + if layer_props.wordline_driver.vertical_supply: for name in ["vdd", "gnd"]: supply_pins = self.wld_inst[0].get_pins(name) for pin in supply_pins: diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index c334404e..c8d22260 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -11,6 +11,7 @@ from tech import drc, layer from vector import vector from sram_factory import factory from globals import OPTS +from tech import layer_properties as layer_props class wordline_driver_array(design.design): @@ -71,7 +72,7 @@ class wordline_driver_array(design.design): Add a pin for each row of vdd/gnd which are must-connects next level up. """ - if OPTS.tech_name == "sky130": + if layer_props.wordline_driver.vertical_supply: for name in ["vdd", "gnd"]: supply_pins = self.wld_inst[0].get_pins(name) for pin in supply_pins: diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index 20616115..18092b4d 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -10,7 +10,7 @@ import debug from tech import drc, layer from vector import vector from sram_factory import factory -from globals import OPTS +from tech import cell_properties as cell_props class column_mux(pgate.pgate): @@ -124,8 +124,8 @@ class column_mux(pgate.pgate): + vector(0, self.nmos.active_height + max(self.active_space, self.poly_space)) self.nmos_upper.place(nmos_upper_position) - if OPTS.tech_name == "sky130": - self.add_implants() + if cell_props.pgate.add_implants: + self.extend_implants() def connect_poly(self): """ Connect the poly gate of the two pass transistors """ @@ -198,7 +198,7 @@ class column_mux(pgate.pgate): self.add_path(self.col_mux_stack[2], [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) - def add_implants(self): + def extend_implants(self): """ Add top-to-bottom implants for adjacency issues in s8. """ diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 082ef7b8..468f367e 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -13,8 +13,8 @@ from bisect import bisect_left from tech import layer, drc from vector import vector from globals import OPTS - -if(OPTS.tech_name == "sky130"): +from tech import cell_properties as cell_props +if cell_props.ptx.bin_spice_models: from tech import nmos_bins, pmos_bins @@ -192,7 +192,7 @@ class pgate(design.design): width=self.width + 2 * self.well_extend_active, height=pwell_height) - if OPTS.tech_name == "sky130": + if cell_props.pgate.add_implants: self.extend_implants() def add_nwell_contact(self, pmos, pmos_pos): diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index eca2d22c..2546f833 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -17,6 +17,7 @@ from utils import round_to_grid import logical_effort from sram_factory import factory from errors import drc_error +from tech import cell_properties as cell_props class pinv(pgate.pgate): @@ -87,7 +88,7 @@ class pinv(pgate.pgate): self.tx_mults = 1 self.nmos_width = self.nmos_size * drc("minwidth_tx") self.pmos_width = self.pmos_size * drc("minwidth_tx") - if OPTS.tech_name == "sky130": + if cell_props.ptx.bin_spice_models: (self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width) (self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width) return @@ -132,7 +133,7 @@ class pinv(pgate.pgate): # Determine the number of mults for each to fit width # into available space - if OPTS.tech_name != "sky130": + if not cell_props.ptx.bin_spice_models: self.nmos_width = self.nmos_size * drc("minwidth_tx") self.pmos_width = self.pmos_size * drc("minwidth_tx") nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1) diff --git a/compiler/pgates/pinv_dec.py b/compiler/pgates/pinv_dec.py index 028fe954..b8fc8fe0 100644 --- a/compiler/pgates/pinv_dec.py +++ b/compiler/pgates/pinv_dec.py @@ -12,6 +12,7 @@ from tech import drc, parameter, layer from vector import vector from globals import OPTS from sram_factory import factory +from tech import cell_properties as cell_props class pinv_dec(pinv.pinv): @@ -50,7 +51,7 @@ class pinv_dec(pinv.pinv): self.tx_mults = 1 self.nmos_width = self.nmos_size * drc("minwidth_tx") self.pmos_width = self.pmos_size * drc("minwidth_tx") - if OPTS.tech_name == "sky130": + if cell_props.ptx.bin_spice_models: self.nmos_width = self.nearest_bin("nmos", self.nmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width) @@ -140,10 +141,10 @@ class pinv_dec(pinv.pinv): nmos_drain_pos = self.nmos_inst.get_pin("D").center() self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x), nmos_drain_pos.y) - if OPTS.tech_name == "sky130": - self.add_implants() + if cell_props.pgate.add_implants: + self.extend_implants() - def add_implants(self): + def extend_implants(self): """ Add top-to-bottom implants for adjacency issues in s8. """ diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index c1295a1b..b2dead7e 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -8,11 +8,11 @@ import pgate import debug from tech import drc, parameter, spice -from globals import OPTS from vector import vector import logical_effort from sram_factory import factory import contact +from tech import cell_properties as cell_props class pnand2(pgate.pgate): @@ -38,7 +38,7 @@ class pnand2(pgate.pgate): debug.check(size == 1, "Size 1 pnand2 is only supported now.") self.tx_mults = 1 - if OPTS.tech_name == "sky130": + if cell_props.ptx.bin_spice_models: self.nmos_width = self.nearest_bin("nmos", self.nmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width) @@ -212,9 +212,8 @@ class pnand2(pgate.pgate): "B", position="center") - if OPTS.tech_name == "sky130": + if cell_props.pgate.add_implants: self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly")) - def route_output(self): """ Route the Z output """ diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index db5a1f28..de7e3e68 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -11,8 +11,8 @@ from tech import drc, parameter, spice from vector import vector import logical_effort from sram_factory import factory -from globals import OPTS import contact +from tech import cell_properties as cell_props class pnand3(pgate.pgate): @@ -41,7 +41,7 @@ class pnand3(pgate.pgate): "Size 1 pnand3 is only supported now.") self.tx_mults = 1 - if OPTS.tech_name == "sky130": + if cell_props.ptx.bin_spice_models: self.nmos_width = self.nearest_bin("nmos", self.nmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width) @@ -246,7 +246,7 @@ class pnand3(pgate.pgate): "C", position="right") - if OPTS.tech_name == "sky130": + if cell_props.pgate.add_implants: self.add_enclosure([apin, bpin, cpin], "npc", drc("npc_enclose_poly")) def route_output(self): diff --git a/compiler/pgates/pnand4.py b/compiler/pgates/pnand4.py index 5a812799..a71f2f52 100644 --- a/compiler/pgates/pnand4.py +++ b/compiler/pgates/pnand4.py @@ -11,8 +11,8 @@ from tech import drc, parameter, spice from vector import vector import logical_effort from sram_factory import factory -from globals import OPTS import contact +from tech import cell_properties as cell_props class pnand4(pgate.pgate): @@ -41,7 +41,7 @@ class pnand4(pgate.pgate): "Size 1 pnand4 is only supported now.") self.tx_mults = 1 - if OPTS.tech_name == "sky130": + if cell_props.ptx.bin_spice_models: self.nmos_width = self.nearest_bin("nmos", self.nmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width) @@ -268,7 +268,7 @@ class pnand4(pgate.pgate): "D", position="right") - if OPTS.tech_name == "sky130": + if cell_props.pgate.add_implants: self.add_enclosure([apin, bpin, cpin, dpin], "npc", drc("npc_enclose_poly")) def route_output(self): diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 331a0745..3a17be30 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -5,13 +5,12 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact import pgate import debug -from globals import OPTS from tech import drc, parameter, spice from vector import vector from sram_factory import factory +from tech import cell_properties as cell_props class pnor2(pgate.pgate): @@ -37,7 +36,7 @@ class pnor2(pgate.pgate): debug.check(size==1, "Size 1 pnor2 is only supported now.") self.tx_mults = 1 - if OPTS.tech_name == "sky130": + if cell_props.ptx.bin_spice_models: self.nmos_width = self.nearest_bin("nmos", self.nmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width) @@ -211,7 +210,7 @@ class pnor2(pgate.pgate): self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch - if OPTS.tech_name == "sky130": + if cell_props.pgate.add_implants: self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly")) def route_output(self): diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 4ae48167..feb9eca6 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -13,6 +13,7 @@ from tech import parameter, drc from vector import vector from globals import OPTS from sram_factory import factory +from tech import cell_properties as cell_props class precharge(design.design): @@ -79,7 +80,7 @@ class precharge(design.design): """ Initializes the upper and lower pmos """ - if(OPTS.tech_name == "sky130"): + if cell_props.ptx.bin_spice_models: self.ptx_width = pgate.nearest_bin("pmos", self.ptx_width) self.pmos = factory.create(module_type="ptx", width=self.ptx_width, @@ -300,4 +301,4 @@ class precharge(design.design): self.add_path(self.bitline_layer, [left_pos, right_pos], width=pmos_pin.height()) - \ No newline at end of file + diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 67368ce9..e445cbcd 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -14,6 +14,7 @@ import contact import logical_effort from globals import OPTS from pgate import pgate +from tech import cell_properties as cell_props class ptx(design.design): @@ -129,9 +130,8 @@ class ptx(design.design): # be decided in the layout later. area_sd = 2.5 * self.poly_width * self.tx_width perimeter_sd = 2 * self.poly_width + 2 * self.tx_width - if OPTS.tech_name == "sky130": - # sky130 simulation cannot use the mult parameter in simulation - (self.tx_width, self.mults) = pgate.best_bin(self.tx_type, self.tx_width) + if cell_props.ptx.model_is_subckt: + # sky130 main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], self.mults, self.tx_width, @@ -150,12 +150,13 @@ class ptx(design.design): self.spice_device = main_str + area_str self.spice.append("\n* spice ptx " + self.spice_device) - if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre": + if cell_props.ptx.model_is_subckt and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre": # sky130 requires mult parameter too # self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type], # self.mults, # self.tx_width, # drc("minwidth_poly")) + # TEMP FIX: Use old device names if using Calibre. self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format("nshort" if self.tx_type == "nmos" else "pshort", self.mults, self.tx_width, diff --git a/compiler/pgates/wordline_driver.py b/compiler/pgates/wordline_driver.py index 6abf7b20..458f19f3 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/pgates/wordline_driver.py @@ -11,6 +11,7 @@ import design from sram_factory import factory from globals import OPTS from tech import layer +from tech import layer_properties as layer_props class wordline_driver(design.design): @@ -104,7 +105,7 @@ class wordline_driver(design.design): def route_supply_rails(self): """ Add vdd/gnd rails to the top, (middle), and bottom. """ - if OPTS.tech_name == "sky130": + if layer_props.wordline_driver.vertical_supply: for name in ["vdd", "gnd"]: for inst in [self.nand_inst, self.driver_inst]: self.copy_layout_pin(inst, name) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 8a1362c2..7f30226a 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -552,7 +552,7 @@ class pin_group: Add the enclosure shape to the given cell. """ for enclosure in self.enclosures: - debug.info(2, "Adding enclosure {0} {1}".format(self.name, + debug.info(4, "Adding enclosure {0} {1}".format(self.name, enclosure)) cell.add_rect(layer=enclosure.layer, offset=enclosure.ll(), @@ -612,7 +612,7 @@ class pin_group: blockage_set = set() for pin in self.pins: - debug.info(2, " Converting {0}".format(pin)) + debug.info(4, " Converting {0}".format(pin)) # Determine which tracks the pin overlaps (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name, pin) @@ -628,15 +628,15 @@ class pin_group: # Remember, this excludes the pin blockages already shared_set = pin_set & self.router.blocked_grids if len(shared_set) > 0: - debug.info(2, "Removing pins {}".format(shared_set)) + debug.info(4, "Removing pins {}".format(shared_set)) pin_set.difference_update(shared_set) shared_set = partial_set & self.router.blocked_grids if len(shared_set) > 0: - debug.info(2, "Removing pins {}".format(shared_set)) + debug.info(4, "Removing pins {}".format(shared_set)) partial_set.difference_update(shared_set) shared_set = blockage_set & self.router.blocked_grids if len(shared_set) > 0: - debug.info(2, "Removing blocks {}".format(shared_set)) + debug.info(4, "Removing blocks {}".format(shared_set)) blockage_set.difference_update(shared_set) # At least one of the groups must have some valid tracks @@ -666,5 +666,5 @@ class pin_group: # Remember the secondary grids for removing adjacent pins self.secondary_grids = partial_set - debug.info(2, " pins {}".format(self.grids)) - debug.info(2, " secondary {}".format(self.secondary_grids)) + debug.info(4, " pins {}".format(self.grids)) + debug.info(4, " secondary {}".format(self.secondary_grids)) diff --git a/compiler/router/router.py b/compiler/router/router.py index cacd5117..ba678215 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -301,7 +301,6 @@ class router(router_tech): adj_grids)) self.remove_adjacent_grid(pg1, pg2, adj_grids) - debug.info(1, "Removed {} adjacent grids.".format(removed_grids)) def remove_adjacent_grid(self, pg1, pg2, adj_grids): @@ -539,7 +538,7 @@ class router(router_tech): sufficient_list.update([full_overlap]) if partial_overlap: insufficient_list.update([partial_overlap]) - debug.info(2, + debug.info(3, "Converting [ {0} , {1} ] full={2}".format(x, y, full_overlap)) @@ -632,26 +631,26 @@ class router(router_tech): pin.layer) overlap_length = pin.overlap_length(track_pin) - debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, + debug.info(4,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length)) inflated_overlap_length = inflated_pin.overlap_length(track_pin) - debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, + debug.info(4,"Check overlap: {0} {1} . {2} = {3}".format(coord, inflated_pin.rect, track_pin, inflated_overlap_length)) # If it overlaps with the pin, it is sufficient if overlap_length == math.inf or overlap_length > 0: - debug.info(2," Overlap: {0} >? {1}".format(overlap_length, 0)) + debug.info(4," Overlap: {0} >? {1}".format(overlap_length, 0)) return (coord, None) # If it overlaps with the inflated pin, it is partial elif inflated_overlap_length == math.inf or inflated_overlap_length > 0: - debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0)) + debug.info(4," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0)) return (None, coord) else: - debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0)) + debug.info(4, " No overlap: {0} {1}".format(overlap_length, 0)) return (None, None) def convert_track_to_pin(self, track): @@ -846,7 +845,7 @@ class router(router_tech): "Pin component index too large.") pin_in_tracks = self.pin_groups[pin_name][index].grids - debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks)) + debug.info(3,"Set source: " + str(pin_name) + " " + str(pin_in_tracks)) self.rg.add_source(pin_in_tracks) def add_path_target(self, paths): @@ -914,7 +913,7 @@ class router(router_tech): """ path = self.prepare_path(path) - debug.info(2, "Adding route: {}".format(str(path))) + debug.info(4, "Adding route: {}".format(str(path))) # If it is only a square, add an enclosure to the track if len(path) == 1: self.add_single_enclosure(path[0][0]) @@ -1007,8 +1006,7 @@ class router(router_tech): # returns the path in tracks (path, cost) = self.rg.route(detour_scale) if path: - debug.info(1, "Found path: cost={0} ".format(cost)) - debug.info(1, str(path)) + debug.info(2, "Found path: cost={0} {1}".format(cost, str(path))) self.paths.append(path) self.add_route(path) diff --git a/compiler/tests/skip_tests_sky130.txt b/compiler/tests/skip_tests_sky130.txt index 68a6549b..827c2cc7 100644 --- a/compiler/tests/skip_tests_sky130.txt +++ b/compiler/tests/skip_tests_sky130.txt @@ -2,7 +2,7 @@ 04_pbitcell_test.py 04_precharge_pbitcell_test.py 04_replica_pbitcell_test.py -04_single_level_column_mux_pbitcell_test.py +04_column_mux_pbitcell_test.py 05_bitcell_1rw_1r_array_test.py 05_bitcell_array_test.py 05_dummy_array_test.py @@ -14,7 +14,7 @@ 06_hierarchical_predecode3x8_pbitcell_test.py 06_hierarchical_predecode3x8_test.py 06_hierarchical_predecode4x16_test.py -07_single_level_column_mux_array_pbitcell_test.py +07_column_mux_array_pbitcell_test.py 08_wordline_driver_array_pbitcell_test.py 08_wordline_driver_array_test.py 09_sense_amp_array_test_pbitcell.py diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index abe09e34..7aeb3e21 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -9,6 +9,7 @@ import os from design_rules import * from module_type import * from custom_cell_properties import cell_properties +from custom_layer_properties import layer_properties """ File containing the process technology parameters for FreePDK 45nm. @@ -34,6 +35,11 @@ cell_properties.bitcell.mirror.x = True cell_properties.bitcell.mirror.y = False cell_properties.bitcell_power_pin_directions = ("V", "V") +################################################### +# Custom cell properties +################################################### +layer_properties = layer_properties() + ################################################### # GDS file info ################################################### diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 41801566..f9a99a86 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -9,6 +9,7 @@ import os from design_rules import * from module_type import * from custom_cell_properties import cell_properties +from custom_layer_properties import layer_properties """ File containing the process technology parameters for SCMOS 4m, 0.35um @@ -32,6 +33,11 @@ cell_properties = cell_properties() cell_properties.bitcell.mirror.x = True cell_properties.bitcell.mirror.y = False +################################################### +# Custom cell properties +################################################### +layer_properties = layer_properties() + ################################################### # GDS file info ###################################################