diff --git a/LICENSE b/LICENSE index 9a86ca1f..761f6e8b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,31 +1,31 @@ -Copyright 2018 Regents of the University of California and The Board +BSD 3-Clause License + +Copyright (c) 2019 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. Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/README.md b/README.md index 5b875971..0d4a7866 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ To increase the verbosity of the test, add one (or more) -v options: python3 tests/00_code_format_check_test.py -v -t freepdk45 ``` To specify a particular technology use "-t " such as -"-t freepdk45" or "-t scn4m\_subm". The default for a unit test is scn4m_subm. +"-t freepdk45". The default for a unit test is scn4m_subm. The default for openram.py is specified in the configuration file. @@ -163,7 +163,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory * replica\_cell\_6t.gds * sp_lib folder with all the .sp (premade) library netlists for the above cells. * layers.map -* A valid tech Python module (tech directory with __init__.py and tech.py) with: +* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with: * References in tech.py to spice models * DRC/LVS rules needed for dynamic cells and routing * Layer information diff --git a/compiler/base/contact.py b/compiler/base/contact.py index db415179..f5cfcb0b 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -16,7 +16,9 @@ class contact(hierarchy_design.hierarchy_design): hierarchy as the contact. """ - def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None): + def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None, name=""): + # This will ignore the name parameter since we can guarantee a unique name here + if implant_type or well_type: name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0], layer_stack[1], @@ -164,13 +166,13 @@ class contact(hierarchy_design.hierarchy_design): """ Get total power of a module """ return self.return_power() - +from sram_factory import factory # This is not instantiated and used for calculations only. # These are static 1x1 contacts to reuse in all the design modules. -well = contact(layer_stack=("active", "contact", "metal1")) -active = contact(layer_stack=("active", "contact", "poly")) -poly = contact(layer_stack=("poly", "contact", "metal1")) -m1m2 = contact(layer_stack=("metal1", "via1", "metal2")) -m2m3 = contact(layer_stack=("metal2", "via2", "metal3")) -m3m4 = contact(layer_stack=("metal3", "via3", "metal4")) +well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1")) +active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly")) +poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1")) +m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2")) +m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3")) +m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4")) diff --git a/compiler/base/design.py b/compiler/base/design.py index f52aa100..d07e392a 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -6,7 +6,6 @@ import debug import os from globals import OPTS - class design(hierarchy_design): """ This is the same as the hierarchy_design class except it contains diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 6031fe2f..7f30fb1c 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -17,20 +17,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): name_map = [] def __init__(self, name): - try: - self.gds_file - except AttributeError: - self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" - try: - self.sp_file - except AttributeError: - self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" + self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" + self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.name = name hierarchy_layout.layout.__init__(self, name) hierarchy_spice.spice.__init__(self, name) - + # Check if the name already exists, if so, give an error # because each reference must be a unique name. # These modules ensure unique names or have no changes if they diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index c35f0709..7c998176 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -320,17 +320,17 @@ class layout(): def add_path(self, layer, coordinates, width=None): """Connects a routing path on given layer,coordinates,width.""" debug.info(4,"add path " + str(layer) + " " + str(coordinates)) - import path + import wire_path # NOTE: (UNTESTED) add_path(...) is currently not used # negative layers indicate "unused" layers in a given technology #layer_num = techlayer[layer] #if layer_num >= 0: # self.objs.append(geometry.path(layer_num, coordinates, width)) - path.path(obj=self, - layer=layer, - position_list=coordinates, - width=width) + wire_path.wire_path(obj=self, + layer=layer, + position_list=coordinates, + width=width) def add_route(self, layers, coordinates, layer_widths): """Connects a routing path on given layer,coordinates,width. The @@ -378,11 +378,12 @@ class layout(): def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): """ Add a three layer via structure. """ - import contact - via = contact.contact(layer_stack=layers, - dimensions=size, - implant_type=implant_type, - well_type=well_type) + from sram_factory import factory + via = factory.create(module_type="contact", + layer_stack=layers, + dimensions=size, + implant_type=implant_type, + well_type=well_type) self.add_mod(via) inst=self.add_inst(name=via.name, mod=via, @@ -395,11 +396,12 @@ class layout(): def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """ - import contact - via = contact.contact(layer_stack=layers, - dimensions=size, - implant_type=implant_type, - well_type=well_type) + from sram_factory import factory + via = factory.create(module_type="contact", + layer_stack=layers, + dimensions=size, + implant_type=implant_type, + well_type=well_type) height = via.height width = via.width debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.") @@ -1039,9 +1041,11 @@ class layout(): # Find the number of vias for this pitch self.supply_vias = 1 - import contact + from sram_factory import factory while True: - c=contact.contact(("metal1","via1","metal2"), (self.supply_vias, self.supply_vias)) + c=factory.create(module_type="contact", + layer_stack=("metal1","via1","metal2"), + dimensions=(self.supply_vias, self.supply_vias)) if c.second_layer_width < self.supply_rail_width and c.second_layer_height < self.supply_rail_width: self.supply_vias += 1 else: diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 3fda8598..424e4d94 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -16,13 +16,18 @@ class spice(): def __init__(self, name): self.name = name - self.mods = [] # Holds subckts/mods for this module - self.pins = [] # Holds the pins for this module - self.pin_type = {} # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND + # Holds subckts/mods for this module + self.mods = [] + # Holds the pins for this module + self.pins = [] + # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND # for each instance, this is the set of nets/nodes that map to the pins for this instance - # THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the + self.pin_type = {} + # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # Spice format) self.conns = [] + # Keep track of any comments to add the the spice + self.comments = [] self.sp_read() @@ -30,6 +35,10 @@ class spice(): # Spice circuit ############################################################ + def add_comment(self, comment): + """ Add a comment to the spice file """ + self.comments.append(comment) + def add_pin(self, name, pin_type="INOUT"): """ Adds a pin to the pins list. Default type is INOUT signal. """ self.pins.append(name) @@ -93,8 +102,8 @@ class spice(): from pprint import pformat modpins_string=pformat(self.insts[-1].mod.pins) argpins_string=pformat(args) - debug.error("Connections: {}".format(modpins_string)) - debug.error("Connections: {}".format(argpins_string)) + debug.error("Mod connections: {}".format(modpins_string)) + debug.error("Inst connections: {}".format(argpins_string)) debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins), len(args)), 1) self.conns.append(args) @@ -159,6 +168,9 @@ class spice(): sp.write("\n.SUBCKT {0} {1}\n".format(self.name, " ".join(self.pins))) + for line in self.comments: + sp.write("* {}\n".format(line)) + # every instance must have a set of connections, even if it is empty. if len(self.insts)!=len(self.conns): debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, diff --git a/compiler/base/route.py b/compiler/base/route.py index 09925e07..c6ce906b 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -1,10 +1,10 @@ from tech import drc import debug from design import design -from contact import contact from itertools import tee from vector import vector from vector3d import vector3d +from sram_factory import factory class route(design): """ @@ -45,7 +45,9 @@ class route(design): self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name)) # offset this by 1/2 the via size - self.c=contact(self.layer_stack, (self.num_vias, self.num_vias)) + self.c=factory.create(module_type="contact", + layer_stack=self.layer_stack, + dimensions=(self.num_vias, self.num_vias)) def create_wires(self): diff --git a/compiler/base/wire.py b/compiler/base/wire.py index 1565d10e..8bc250fa 100644 --- a/compiler/base/wire.py +++ b/compiler/base/wire.py @@ -1,9 +1,9 @@ from tech import drc import debug -from contact import contact -from path import path +from wire_path import wire_path +from sram_factory import factory -class wire(path): +class wire(wire_path): """ Object metal wire; given the layer type Add a wire of minimium metal width between a set of points. @@ -26,7 +26,7 @@ class wire(path): self.create_rectilinear() self.create_vias() self.create_rectangles() - # wires and paths should not be offset to (0,0) + # wires and wire_paths should not be offset to (0,0) def setup_layers(self): (horiz_layer, via_layer, vert_layer) = self.layer_stack @@ -37,15 +37,18 @@ class wire(path): self.horiz_layer_name = horiz_layer self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer)) - via_connect = contact(self.layer_stack, - (1, 1)) + via_connect = factory.create(module_type="contact", + layer_stack=self.layer_stack, + dimensions=(1, 1)) self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width, drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height] # create a 1x1 contact def create_vias(self): """ Add a via and corner square at every corner of the path.""" - self.c=contact(self.layer_stack, (1, 1)) + self.c=factory.create(module_type="contact", + layer_stack=self.layer_stack, + dimensions=(1, 1)) c_width = self.c.width c_height = self.c.height diff --git a/compiler/base/path.py b/compiler/base/wire_path.py similarity index 94% rename from compiler/base/path.py rename to compiler/base/wire_path.py index ed058fef..ec5d01bf 100644 --- a/compiler/base/path.py +++ b/compiler/base/wire_path.py @@ -18,12 +18,12 @@ def create_rectilinear_route(my_list): my_list.append(vector(pl[-1])) return my_list -class path(): +class wire_path(): """ - Object metal path; given the layer type - Add a path of minimium metal width between a set of points. + Object metal wire_path; given the layer type + Add a wire_path of minimium metal width between a set of points. The points should be rectilinear to control the bend points. If - not, it will always go down first. The points are the center of the path. + not, it will always go down first. The points are the center of the wire_path. If width is not given, it uses minimum layer width. """ def __init__(self, obj, layer, position_list, width=None): @@ -44,7 +44,7 @@ class path(): self.create_rectilinear() self.connect_corner() self.create_rectangles() - # wires and paths should not be offset to (0,0) + # wires and wire_paths should not be offset to (0,0) def create_rectilinear(self): """ Add intermediate nodes if it isn't rectilinear. Also skip @@ -52,7 +52,7 @@ class path(): self.position_list = create_rectilinear_route(self.position_list) def connect_corner(self): - """ Add a corner square at every corner of the path.""" + """ Add a corner square at every corner of the wire_path.""" from itertools import tee,islice nwise = lambda g,n=2: zip(*(islice(g,i,None) for i,g in enumerate(tee(g,n)))) threewise=nwise(self.position_list,3) diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 0ac1c207..3c49a959 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -15,14 +15,15 @@ class bitcell(design.design): (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "cell_6t") debug.info(2, "Create bitcell") self.width = bitcell.width self.height = bitcell.height self.pin_map = bitcell.pin_map - + def analytical_delay(self, slew, load=0, swing = 0.5): # delay of bit cell is not like a driver(from WL) # so the slew used should be 0 diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py index 2d740d2b..79dc734c 100644 --- a/compiler/bitcells/bitcell_1rw_1r.py +++ b/compiler/bitcells/bitcell_1rw_1r.py @@ -15,7 +15,8 @@ class bitcell_1rw_1r(design.design): (width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "cell_1rw_1r") debug.info(2, "Create bitcell with 1RW and 1R Port") @@ -102,4 +103,4 @@ class bitcell_1rw_1r(design.design): #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin \ No newline at end of file + return 2*access_tx_cin diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 52156b39..b241471d 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -12,8 +12,7 @@ class pbitcell(design.design): with a variable number of read/write, write, and read ports """ - def __init__(self, replica_bitcell=False): - + def __init__(self, name, replica_bitcell=False): self.num_rw_ports = OPTS.num_rw_ports self.num_w_ports = OPTS.num_w_ports self.num_r_ports = OPTS.num_r_ports @@ -21,11 +20,6 @@ class pbitcell(design.design): self.replica_bitcell = replica_bitcell - if self.replica_bitcell: - name = "replica_pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports) - else: - name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports) - design.design.__init__(self, name) debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, self.num_w_ports, diff --git a/compiler/bitcells/replica_bitcell.py b/compiler/bitcells/replica_bitcell.py index d896e29e..d8b8b76e 100644 --- a/compiler/bitcells/replica_bitcell.py +++ b/compiler/bitcells/replica_bitcell.py @@ -14,7 +14,8 @@ class replica_bitcell(design.design): (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "replica_cell_6t") debug.info(2, "Create replica bitcell object") @@ -27,4 +28,4 @@ class replica_bitcell(design.design): #This is a handmade cell so the value must be entered in the tech.py file or estimated. #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin \ No newline at end of file + return 2*access_tx_cin diff --git a/compiler/bitcells/replica_bitcell_1rw_1r.py b/compiler/bitcells/replica_bitcell_1rw_1r.py index f5151958..8f7b3b38 100644 --- a/compiler/bitcells/replica_bitcell_1rw_1r.py +++ b/compiler/bitcells/replica_bitcell_1rw_1r.py @@ -14,7 +14,8 @@ class replica_bitcell_1rw_1r(design.design): (width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "replica_cell_1rw_1r") debug.info(2, "Create replica bitcell 1rw+1r object") @@ -28,4 +29,4 @@ class replica_bitcell_1rw_1r(design.design): #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin \ No newline at end of file + return 2*access_tx_cin diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py index 666d3646..4d2ecd70 100644 --- a/compiler/bitcells/replica_pbitcell.py +++ b/compiler/bitcells/replica_pbitcell.py @@ -3,21 +3,20 @@ import design from tech import drc, spice,parameter from vector import vector from globals import OPTS -from pbitcell import pbitcell +from sram_factory import factory class replica_pbitcell(design.design): """ Creates a replica bitcell using pbitcell """ - def __init__(self): - + def __init__(self, name): self.num_rw_ports = OPTS.num_rw_ports self.num_w_ports = OPTS.num_w_ports self.num_r_ports = OPTS.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports - design.design.__init__(self, "replica_pbitcell") + design.design.__init__(self, name) debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)) @@ -47,7 +46,7 @@ class replica_pbitcell(design.design): self.add_pin("gnd") def add_modules(self): - self.prbc = pbitcell(replica_bitcell=True) + self.prbc = factory.create(module_type="pbitcell",replica_bitcell=True) self.add_mod(self.prbc) self.height = self.prbc.height @@ -83,4 +82,4 @@ class replica_pbitcell(design.design): def get_wl_cin(self): """Return the relative capacitance of the access transistor gates""" #This module is made using a pbitcell. Get the cin from that module - return self.prbc.get_wl_cin() \ No newline at end of file + return self.prbc.get_wl_cin() diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 7b10eb8f..156481ce 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -530,7 +530,7 @@ class lib: "sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name), OPTS.num_words, OPTS.num_banks, - OPTS.num_rw_ports, + OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports, OPTS.tech_name, @@ -555,7 +555,7 @@ class lib: LVS = str(total_lvs_errors) datasheet.write("{0},{1},".format(DRC, LVS)) - + datasheet.write(str(self.sram.width * self.sram.height)+',') for port in self.all_ports: #DIN timings if port in self.write_ports: diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py index ce84c22c..d15733d5 100644 --- a/compiler/datasheet/datasheet.py +++ b/compiler/datasheet/datasheet.py @@ -1,62 +1,60 @@ from table_gen import * import os -import csv import base64 from globals import OPTS + class datasheet(): """ Defines the layout,but not the data, of the html datasheet """ - def __init__(self,identifier): + + def __init__(self, identifier): self.name = identifier self.html = "" - def generate_html(self): """ Generates html tables using flask-table """ with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/datasheet.css', 'r') as datasheet_css: - #css styling is kept in a seperate file + # css styling is kept in a seperate file self.html += datasheet_css.read() - -# with open(OPTS.openram_temp + "/datasheet.info") as info: + with open(OPTS.openram_temp + "/datasheet.info") as info: self.html += '' - + for row in info: + self.html += row +# for item in self.description: +# self.html += item + ',' + self.html += '-->' + vlsi_logo = 0 - with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png' , "rb") as image_file: + with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png', "rb") as image_file: vlsi_logo = base64.b64encode(image_file.read()) openram_logo = 0 - with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png' , "rb") as image_file: + with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png', "rb") as image_file: openram_logo = base64.b64encode(image_file.read()) + self.html += 'VLSIDA'.format(str(vlsi_logo)[ + 2:-1]) - self.html += 'VLSIDA'.format(str(vlsi_logo)[2:-1]) - + self.html += '

' + \ + self.name + '.html' + '

' + self.html += '

Compiled at: ' + self.time + '

' + self.html += '

' + \ + 'DRC errors: ' + str(self.DRC) + '

' + self.html += '

' + \ + 'LVS errors: ' + str(self.LVS) + '

' + self.html += '

' + \ + 'Git commit id: ' + str(self.git_id) + '

' - - - - self.html +='

'+ self.name + '.html' + '

' - self.html +='

Compiled at: '+ self.time + '

' - self.html +='

'+ 'DRC errors: ' + str(self.DRC) + '

' - self.html +='

'+ 'LVS errors: ' + str(self.LVS) + '

' - self.html += '

'+ 'Git commit id: ' + str(self.git_id) + '

' - - self.html +='

Ports and Configuration

' + self.html += '

Ports and Configuration

' # self.html += in_out(self.io,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">") self.html += self.io_table.to_html() - - self.html +='

Operating Conditions

' + + self.html += '

Operating Conditions

' # self.html += operating_conditions(self.operating,table_id='data').__html__() self.html += self.operating_table.to_html() @@ -68,9 +66,6 @@ class datasheet(): # self.html += characterization_corners(self.corners,table_id='data').__html__() self.html += self.corners_table.to_html() - self.html +='

Deliverables

' + self.html += '

Deliverables

' # self.html += deliverables(self.dlv,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">") self.html += self.dlv_table.to_html() - - - diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index db03216b..6786c7bf 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -1,21 +1,21 @@ #!/usr/bin/env python3 """ -This is a script to load data from the characterization and layout processes into +This is a script to load data from the characterization and layout processes into a web friendly html datasheet. """ -#TODO: -#include log file -#Diagram generation -#Improve css +# TODO: +# include power +# Diagram generation +# Improve css -import debug from globals import OPTS -import os, math -import optparse +import os +import math import csv -from datasheet import * -from table_gen import * +import datasheet +import table_gen + def process_name(corner): """ @@ -30,20 +30,20 @@ def process_name(corner): else: return "custom" -def parse_characterizer_csv(sram,f,pages): + +def parse_characterizer_csv(f, pages): """ Parses output data of the Liberty file generator in order to construct the timing and current table """ with open(f) as csv_file: csv_reader = csv.reader(csv_file, delimiter=',') - line_count = 0 for row in csv_reader: found = 0 col = 0 - #defines layout of csv file + # defines layout of csv file NAME = row[col] col += 1 @@ -85,29 +85,30 @@ def parse_characterizer_csv(sram,f,pages): WORD_SIZE = row[col] col += 1 - + ORIGIN_ID = row[col] col += 1 DATETIME = row[col] - col+= 1 + col += 1 DRC = row[col] col += 1 LVS = row[col] col += 1 - - for sheet in pages: + AREA = row[col] + col += 1 + for sheet in pages: if sheet.name == NAME: found = 1 - #if the .lib information is for an existing datasheet compare timing data + # if the .lib information is for an existing datasheet compare timing data for item in sheet.operating_table.rows: - #check if the new corner data is worse than the previous worse corner data + # check if the new corner data is worse than the previous worse corner data if item[0] == 'Operating Temperature': if float(TEMP) > float(item[3]): @@ -128,14 +129,13 @@ def parse_characterizer_csv(sram,f,pages): if item[0] == 'Operating Frequncy (F)': try: if float(math.floor(1000/float(MIN_PERIOD)) < float(item[3])): - item[3] = str(math.floor(1000/float(MIN_PERIOD))) + item[3] = str(math.floor( + 1000/float(MIN_PERIOD))) except Exception: pass - while(True): - - + col_start = col if(row[col].startswith('DIN')): start = col for item in sheet.timing_table.rows: @@ -253,7 +253,6 @@ def parse_characterizer_csv(sram,f,pages): col += 1 - elif(row[col].startswith('WEb')): start = col for item in sheet.timing_table.rows: @@ -293,7 +292,6 @@ def parse_characterizer_csv(sram,f,pages): col += 1 - elif(row[col].startswith('ADDR')): start = col for item in sheet.timing_table.rows: @@ -333,196 +331,225 @@ def parse_characterizer_csv(sram,f,pages): col += 1 - - else: + for element in row[col_start: col - 1]: + sheet.description.append(str(element)) break - - new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')]) - new_sheet.dlv_table.add_row(['.lib','Synthesis models','{1}'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))]) + new_sheet.corners_table.add_row([PROC, process_name( + PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) + new_sheet.dlv_table.add_row( + ['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))]) if found == 0: - - #if this is the first corner for this sram, run first time configuration and set up tables - new_sheet = datasheet(NAME) + + # if this is the first corner for this sram, run first time configuration and set up tables + new_sheet = datasheet.datasheet(NAME) pages.append(new_sheet) new_sheet.git_id = ORIGIN_ID new_sheet.time = DATETIME new_sheet.DRC = DRC new_sheet.LVS = LVS - new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS, NUM_R_PORTS, TECH_NAME, WORD_SIZE, ORIGIN_ID, DATETIME] + new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS, + NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME] - new_sheet.corners_table = table_gen("corners") - new_sheet.corners_table.add_row(['Corner Name','Process','Power Supply','Temperature','Library Name Suffix']) - new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')]) - new_sheet.operating_table = table_gen("operating_table") - new_sheet.operating_table.add_row(['Parameter','Min','Typ','Max','Units']) - new_sheet.operating_table.add_row(['Power supply (VDD) range',VOLT,VOLT,VOLT,'Volts']) - new_sheet.operating_table.add_row(['Operating Temperature',TEMP,TEMP,TEMP,'Celsius']) + new_sheet.corners_table = table_gen.table_gen("corners") + new_sheet.corners_table.add_row( + ['Corner Name', 'Process', 'Power Supply', 'Temperature', 'Library Name Suffix']) + new_sheet.corners_table.add_row([PROC, process_name( + PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) + new_sheet.operating_table = table_gen.table_gen( + "operating_table") + new_sheet.operating_table.add_row( + ['Parameter', 'Min', 'Typ', 'Max', 'Units']) + new_sheet.operating_table.add_row( + ['Power supply (VDD) range', VOLT, VOLT, VOLT, 'Volts']) + new_sheet.operating_table.add_row( + ['Operating Temperature', TEMP, TEMP, TEMP, 'Celsius']) try: - new_sheet.operating_table.add_row(['Operating Frequency (F)','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz']) + new_sheet.operating_table.add_row(['Operating Frequency (F)', '', '', str( + math.floor(1000/float(MIN_PERIOD))), 'MHz']) except Exception: - new_sheet.operating_table.add_row(['Operating Frequency (F)','','',"not available in netlist only",'MHz']) #failed to provide non-zero MIN_PERIOD - new_sheet.timing_table = table_gen("timing") - new_sheet.timing_table.add_row(['Parameter','Min','Max','Units']) + # failed to provide non-zero MIN_PERIOD + new_sheet.operating_table.add_row( + ['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz']) + new_sheet.timing_table = table_gen.table_gen("timing") + new_sheet.timing_table.add_row( + ['Parameter', 'Min', 'Max', 'Units']) while(True): + col_start = col if(row[col].startswith('DIN')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('DOUT')): start = col - - new_sheet.timing_table.add_row(['{0} cell rise'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} cell rise'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} cell fall'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} rise transition'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} cell fall'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} fall transition'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} rise transition'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} fall transition'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('CSb')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('WEb')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('ADDR')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 else: + for element in row[col_start:col-1]: + sheet.description.append(str(element)) break + new_sheet.dlv_table = table_gen.table_gen("dlv") + new_sheet.dlv_table.add_row(['Type', 'Description', 'Link']) - - new_sheet.dlv_table = table_gen("dlv") - new_sheet.dlv_table.add_row(['Type','Description','Link']) - - new_sheet.io_table = table_gen("io") + new_sheet.io_table = table_gen.table_gen("io") new_sheet.io_table.add_row(['Type', 'Value']) if not OPTS.netlist_only: - #physical layout files should not be generated in netlist only mode - new_sheet.dlv_table.add_row(['.gds','GDSII layout views','{0}.{1}'.format(OPTS.output_name,'gds')]) - new_sheet.dlv_table.add_row(['.lef','LEF files','{0}.{1}'.format(OPTS.output_name,'lef')]) - - - new_sheet.dlv_table.add_row(['.sp','SPICE netlists','{0}.{1}'.format(OPTS.output_name,'sp')]) - new_sheet.dlv_table.add_row(['.v','Verilog simulation models','{0}.{1}'.format(OPTS.output_name,'v')]) - new_sheet.dlv_table.add_row(['.html','This datasheet','{0}.{1}'.format(OPTS.output_name,'html')]) - new_sheet.dlv_table.add_row(['.lib','Synthesis models','{1}'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))]) - new_sheet.dlv_table.add_row(['.py','OpenRAM configuration file','{0}.{1}'.format(OPTS.output_name,'py')]) - - new_sheet.io_table.add_row(['WORD_SIZE',WORD_SIZE]) - new_sheet.io_table.add_row(['NUM_WORDS',NUM_WORDS]) - new_sheet.io_table.add_row(['NUM_BANKS',NUM_BANKS]) - new_sheet.io_table.add_row(['NUM_RW_PORTS',NUM_RW_PORTS]) - new_sheet.io_table.add_row(['NUM_R_PORTS',NUM_R_PORTS]) - new_sheet.io_table.add_row(['NUM_W_PORTS',NUM_W_PORTS]) - new_sheet.io_table.add_row(['Area',sram.width * sram.height]) - - + # physical layout files should not be generated in netlist only mode + new_sheet.dlv_table.add_row( + ['.gds', 'GDSII layout views', '{0}.{1}'.format(OPTS.output_name, 'gds')]) + new_sheet.dlv_table.add_row( + ['.lef', 'LEF files', '{0}.{1}'.format(OPTS.output_name, 'lef')]) + new_sheet.dlv_table.add_row( + ['.log', 'OpenRAM compile log', '{0}.{1}'.format(OPTS.output_name, 'log')]) + new_sheet.dlv_table.add_row( + ['.v', 'Verilog simulation models', '{0}.{1}'.format(OPTS.output_name, 'v')]) + new_sheet.dlv_table.add_row( + ['.html', 'This datasheet', '{0}.{1}'.format(OPTS.output_name, 'html')]) + new_sheet.dlv_table.add_row( + ['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))]) + new_sheet.dlv_table.add_row( + ['.py', 'OpenRAM configuration file', '{0}.{1}'.format(OPTS.output_name, 'py')]) + new_sheet.dlv_table.add_row( + ['.sp', 'SPICE netlists', '{0}.{1}'.format(OPTS.output_name, 'sp')]) + new_sheet.io_table.add_row(['WORD_SIZE', WORD_SIZE]) + new_sheet.io_table.add_row(['NUM_WORDS', NUM_WORDS]) + new_sheet.io_table.add_row(['NUM_BANKS', NUM_BANKS]) + new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS]) + new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS]) + new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS]) + new_sheet.io_table.add_row(['Area', AREA]) class datasheet_gen(): - def datasheet_write(sram,name): - + def datasheet_write(name): in_dir = OPTS.openram_temp if not (os.path.isdir(in_dir)): os.mkdir(in_dir) - datasheets = [] - parse_characterizer_csv(sram, in_dir + "/datasheet.info", datasheets) - + parse_characterizer_csv(in_dir + "/datasheet.info", datasheets) for sheets in datasheets: with open(name, 'w+') as f: diff --git a/compiler/debug.py b/compiler/debug.py index 1bf46db0..271b874b 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -9,23 +9,56 @@ import sys # 2 = verbose # n = custom setting -def check(check,str): + +def check(check, str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] if not check: - sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + log("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + assert 0 -def error(str,return_value=0): + +def error(str, return_value=0): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] - sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) - assert return_value==0 + sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + log("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + + assert return_value == 0 + def warning(str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] - sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + log("WARNING: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + + +def print_raw(str): + print(str) + log(str) + + +def log(str): + if log.create_file: + compile_log = open(globals.OPTS.output_path + + globals.OPTS.output_name + '.log', "w") + log.create_file = 0 + else: + compile_log = open(globals.OPTS.output_path + + globals.OPTS.output_name + '.log', "a") + compile_log.write(str + '\n') +log.create_file = 1 + + def info(lev, str): @@ -33,9 +66,10 @@ def info(lev, str): if (OPTS.debug_level >= lev): frm = inspect.stack()[1] mod = inspect.getmodule(frm[0]) - #classname = frm.f_globals['__name__'] + # classname = frm.f_globals['__name__'] if mod.__name__ == None: - class_name="" + class_name = "" else: - class_name=mod.__name__ - print("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str)) + class_name = mod.__name__ + print_raw("[{0}/{1}]: {2}".format(class_name, frm[0].f_code.co_name, str)) + diff --git a/compiler/gdsMill/LICENSE b/compiler/gdsMill/LICENSE deleted file mode 100644 index 6d8a8921..00000000 --- a/compiler/gdsMill/LICENSE +++ /dev/null @@ -1,78 +0,0 @@ -Delivered-To: mrg@ucsc.edu -Received: by 10.216.164.197 with SMTP id c47cs36474wel; - Sat, 19 Nov 2011 21:23:28 -0800 (PST) -Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080; - Sat, 19 Nov 2011 21:21:53 -0800 (PST) -Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32; -Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5; - Sat, 19 Nov 2011 21:21:53 -0800 (PST) -X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus -Delivered-To: mguthaus@gmail.com -Received: by 10.231.207.15 with SMTP id fw15cs52829ibb; - Thu, 14 Oct 2010 12:49:35 -0700 (PDT) -Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723; - Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -Return-Path: -Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32]) - by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34; - Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32; -Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu -Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10]) - by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C - for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9]) - by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705 - (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) - for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V -Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for ; Thu, 14 Oct 2010 12:49:33 -0700 (PDT) -X-Barracuda-Envelope-From: wieckows@umich.edu -X-Barracuda-Apparent-Source-IP: 141.211.14.82 -Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169]) - By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ; - Authuser wieckows; - 14 Oct 2010 15:49:30 EDT -Content-Type: text/plain; charset=us-ascii -Mime-Version: 1.0 (Apple Message framework v1081) -Subject: Re: GDS Mill -From: Michael Wieckowski -X-ASG-Orig-Subj: Re: GDS Mill -In-Reply-To: -Date: Thu, 14 Oct 2010 15:49:29 -0400 -Content-Transfer-Encoding: quoted-printable -Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu> -References: -To: Matthew Guthaus -X-Mailer: Apple Mail (2.1081) -X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82] -X-Barracuda-Start-Time: 1287085773 -X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi -X-Virus-Scanned: by bsmtpd at soe.ucsc.edu - -Hi Matt, - -Feel free to use / modify / distribute the code as you like. - --Mike - - -On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote: - -> Hi Michael (& Dennis), ->=20 -> A student and I were looking at your GDS tools, but we noticed that = -there is no license. What is the license? ->=20 -> Thanks, ->=20 -> Matt ->=20 -> --- -> Matthew Guthaus -> Assistant Professor, Computer Engineering -> University of California Santa Cruz -> http://vlsida.soe.ucsc.edu/ ->=20 ->=20 ->=20 diff --git a/compiler/gdsMill/README b/compiler/gdsMill/README index ce21dfdd..8d89b149 100644 --- a/compiler/gdsMill/README +++ b/compiler/gdsMill/README @@ -1,30 +1,81 @@ -README BY TOM GOLUBEV - gdsMill was adapted from gdsMill by Michael Wieckowski. -gdsMill allows one to work with GDS files, opening, reading, writing and altering. -It is a library and does not work by itself. To get started, refer to ExampleUserDir. -To look at sram compiler related example, refer to the sram_examples subdir. -gdsMill takes a layermap, in a standard format (virtuoso .map files). This is necessary -for drawing text and rectangles, since those functions take layernames, and gdsMill needs layer numbers. +Delivered-To: mrg@ucsc.edu +Received: by 10.216.164.197 with SMTP id c47cs36474wel; + Sat, 19 Nov 2011 21:23:28 -0800 (PST) +Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080; + Sat, 19 Nov 2011 21:21:53 -0800 (PST) +Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32; +Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5; + Sat, 19 Nov 2011 21:21:53 -0800 (PST) +X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus +Delivered-To: mguthaus@gmail.com +Received: by 10.231.207.15 with SMTP id fw15cs52829ibb; + Thu, 14 Oct 2010 12:49:35 -0700 (PDT) +Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723; + Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +Return-Path: +Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32]) + by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34; + Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32; +Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu +Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10]) + by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C + for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9]) + by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) + for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V +Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for ; Thu, 14 Oct 2010 12:49:33 -0700 (PDT) +X-Barracuda-Envelope-From: wieckows@umich.edu +X-Barracuda-Apparent-Source-IP: 141.211.14.82 +Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169]) + By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ; + Authuser wieckows; + 14 Oct 2010 15:49:30 EDT +Content-Type: text/plain; charset=us-ascii +Mime-Version: 1.0 (Apple Message framework v1081) +Subject: Re: GDS Mill +From: Michael Wieckowski +X-ASG-Orig-Subj: Re: GDS Mill +In-Reply-To: +Date: Thu, 14 Oct 2010 15:49:29 -0400 +Content-Transfer-Encoding: quoted-printable +Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu> +References: +To: Matthew Guthaus +X-Mailer: Apple Mail (2.1081) +X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82] +X-Barracuda-Start-Time: 1287085773 +X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi +X-Virus-Scanned: by bsmtpd at soe.ucsc.edu + +Hi Matt, + +Feel free to use / modify / distribute the code as you like. + +-Mike -gdsMill funcionality: +On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote: -The main functions are from vlsilayout. They allow creating a new layout, fill in a box, text, and instancing other structures. - -Files: - - sram_examples: - - gdsMill.sh: Adds gdsMill to python path. - Source this before working - - printGDS.py: will dump a text version structures within the gds file. - usage: python printGDS.py file - - cell6tDemo.py: Will tile cell6t from sram_lib2.gds and output into layoutB.gds. All cells from source are copied into layoutB.gds. - usage: python ./cell6tDemo.py - - +> Hi Michael (& Dennis), +>=20 +> A student and I were looking at your GDS tools, but we noticed that = +there is no license. What is the license? +>=20 +> Thanks, +>=20 +> Matt +>=20 +> --- +> Matthew Guthaus +> Assistant Professor, Computer Engineering +> University of California Santa Cruz +> http://vlsida.soe.ucsc.edu/ +>=20 +>=20 +>=20 diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index 42921812..8d4816f6 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -1,7 +1,8 @@ from .gdsPrimitives import * from datetime import * #from mpmath import matrix -from numpy import matrix +#from numpy import matrix +import numpy as np #import gdsPrimitives import debug @@ -170,21 +171,20 @@ class VlsiLayout: else: # MRG: Added negative to make CCW rotate 8/29/18 angle = math.radians(float(rotateAngle)) - mRotate = matrix([[math.cos(angle),-math.sin(angle),0.0], + mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0], [math.sin(angle),math.cos(angle),0.0], [0.0,0.0,1.0]]) #set up the translation matrix translateX = float(coordinates[0]) translateY = float(coordinates[1]) - mTranslate = matrix([[1.0,0.0,translateX],[0.0,1.0,translateY],[0.0,0.0,1.0]]) + mTranslate = np.array([[1.0,0.0,translateX],[0.0,1.0,translateY],[0.0,0.0,1.0]]) #set up the scale matrix (handles mirror X) scaleX = 1.0 if(transFlags[0]): scaleY = -1.0 else: scaleY = 1.0 - mScale = matrix([[scaleX,0.0,0.0],[0.0,scaleY,0.0],[0.0,0.0,1.0]]) - + mScale = np.array([[scaleX,0.0,0.0],[0.0,scaleY,0.0],[0.0,0.0,1.0]]) #we need to keep track of all transforms in the hierarchy #when we add an element to the xy tree, we apply all transforms from the bottom up transformPath.append((mRotate,mScale,mTranslate)) @@ -219,27 +219,26 @@ class VlsiLayout: def populateCoordinateMap(self): def addToXyTree(startingStructureName = None,transformPath = None): - #print("populateCoordinateMap") - uVector = matrix([1.0,0.0,0.0]).transpose() #start with normal basis vectors - vVector = matrix([0.0,1.0,0.0]).transpose() - origin = matrix([0.0,0.0,1.0]).transpose() #and an origin (Z component is 1.0 to indicate position instead of vector) + uVector = np.array([[1.0],[0.0],[0.0]]) #start with normal basis vectors + vVector = np.array([[0.0],[1.0],[0.0]]) + origin = np.array([[0.0],[0.0],[1.0]]) #and an origin (Z component is 1.0 to indicate position instead of vector) #make a copy of all the transforms and reverse it reverseTransformPath = transformPath[:] if len(reverseTransformPath) > 1: - reverseTransformPath.reverse() + reverseTransformPath.reverse() #now go through each transform and apply them to our basis and origin in succession for transform in reverseTransformPath: - origin = transform[0] * origin #rotate - uVector = transform[0] * uVector #rotate - vVector = transform[0] * vVector #rotate - origin = transform[1] * origin #scale - uVector = transform[1] * uVector #scale - vVector = transform[1] * vVector #scale - origin = transform[2] * origin #translate + origin = np.dot(transform[0], origin) #rotate + uVector = np.dot(transform[0], uVector) #rotate + vVector = np.dot(transform[0], vVector) #rotate + origin = np.dot(transform[1], origin) #scale + uVector = np.dot(transform[1], uVector) #scale + vVector = np.dot(transform[1], vVector) #scale + origin = np.dot(transform[2], origin) #translate #we don't need to do a translation on the basis vectors #uVector = transform[2] * uVector #translate #vVector = transform[2] * vVector #translate - #populate the xyTree with each structureName and coordinate space + #populate the xyTree with each structureName and coordinate space self.xyTree.append((startingStructureName,origin,uVector,vVector)) self.traverseTheHierarchy(delegateFunction = addToXyTree) @@ -522,8 +521,7 @@ class VlsiLayout: return True - def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, - minSpacing = 0.22, blockSize = 1.0): + def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, minSpacing = 0.22, blockSize = 1.0): effectiveBlock = blockSize+minSpacing widthInBlocks = int(coverageWidth/effectiveBlock) heightInBlocks = int(coverageHeight/effectiveBlock) @@ -810,8 +808,8 @@ class VlsiLayout: # This is fixed to be: # |u[0] v[0]| |x| |x'| # |u[1] v[1]|x|y|=|y'| - x=coordinate[0]*uVector[0].item()+coordinate[1]*vVector[0].item() - y=coordinate[0]*uVector[1].item()+coordinate[1]*vVector[1].item() + x=coordinate[0]*uVector[0][0]+coordinate[1]*vVector[0][0] + y=coordinate[0]*uVector[1][0]+coordinate[1]*vVector[1][0] transformCoordinate=[x,y] return transformCoordinate @@ -836,5 +834,3 @@ def boundaryArea(A): area_A=(A[2]-A[0])*(A[3]-A[1]) return area_A - - diff --git a/compiler/globals.py b/compiler/globals.py index a6360e24..f162edda 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -71,26 +71,26 @@ def print_banner(): if OPTS.is_unit_test: return - print("|==============================================================================|") + debug.print_raw("|==============================================================================|") name = "OpenRAM Compiler" - print("|=========" + name.center(60) + "=========|") - print("|=========" + " ".center(60) + "=========|") - print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") - print("|=========" + "Computer Science and Engineering Department".center(60) + "=========|") - print("|=========" + "University of California Santa Cruz".center(60) + "=========|") - print("|=========" + " ".center(60) + "=========|") - print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|") - print("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|") - print("|=========" + "Oklahoma State University".center(60) + "=========|") - print("|=========" + " ".center(60) + "=========|") + debug.print_raw("|=========" + name.center(60) + "=========|") + debug.print_raw("|=========" + " ".center(60) + "=========|") + debug.print_raw("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") + debug.print_raw("|=========" + "Computer Science and Engineering Department".center(60) + "=========|") + debug.print_raw("|=========" + "University of California Santa Cruz".center(60) + "=========|") + debug.print_raw("|=========" + " ".center(60) + "=========|") + debug.print_raw("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|") + debug.print_raw("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|") + debug.print_raw("|=========" + "Oklahoma State University".center(60) + "=========|") + debug.print_raw("|=========" + " ".center(60) + "=========|") user_info = "Usage help: openram-user-group@ucsc.edu" - print("|=========" + user_info.center(60) + "=========|") + debug.print_raw("|=========" + user_info.center(60) + "=========|") dev_info = "Development help: openram-dev-group@ucsc.edu" - print("|=========" + dev_info.center(60) + "=========|") + debug.print_raw("|=========" + dev_info.center(60) + "=========|") temp_info = "Temp dir: {}".format(OPTS.openram_temp) - print("|=========" + temp_info.center(60) + "=========|") - print("|=========" + "See LICENSE for license info".center(60) + "=========|") - print("|==============================================================================|") + debug.print_raw("|=========" + temp_info.center(60) + "=========|") + debug.print_raw("|=========" + "See LICENSE for license info".center(60) + "=========|") + debug.print_raw("|==============================================================================|") def check_versions(): @@ -130,6 +130,9 @@ def init_openram(config_file, is_unit_test=True): init_paths() + from sram_factory import factory + factory.reset() + # Reset the static duplicate name checker for unit tests. import hierarchy_design hierarchy_design.hierarchy_design.name_map=[] @@ -397,7 +400,7 @@ def print_time(name, now_time, last_time=None, indentation=2): time = str(round((now_time-last_time).total_seconds(),1)) + " seconds" else: time = now_time.strftime('%m/%d/%Y %H:%M:%S') - print("{0} {1}: {2}".format("*"*indentation,name,time)) + debug.print_raw("{0} {1}: {2}".format("*"*indentation,name,time)) def report_status(): @@ -413,20 +416,20 @@ def report_status(): if not OPTS.tech_name: debug.error("Tech name must be specified in config file.") - print("Technology: {0}".format(OPTS.tech_name)) - print("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks)) - print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, + debug.print_raw("Technology: {0}".format(OPTS.tech_name)) + debug.print_raw("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks)) + debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, OPTS.num_words, OPTS.num_banks)) - print("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, + debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, OPTS.num_r_ports, OPTS.num_w_ports)) if OPTS.netlist_only: - print("Netlist only mode (no physical design is being done).") + debug.print_raw("Netlist only mode (no physical design is being done).") if not OPTS.inline_lvsdrc: - print("DRC/LVS/PEX is only run on the top-level design.") + debug.print_raw("DRC/LVS/PEX is only run on the top-level design.") if not OPTS.check_lvsdrc: - print("DRC/LVS/PEX is completely disabled.") + debug.print_raw("DRC/LVS/PEX is completely disabled.") diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a0508b51..5d4e9739 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -6,9 +6,7 @@ import math from math import log,sqrt,ceil import contact import pgates -from pinv import pinv -from pnand2 import pnand2 -from pnor2 import pnor2 +from sram_factory import factory from vector import vector from globals import OPTS @@ -396,25 +394,14 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - mod_list = ["bitcell", "decoder", "wordline_driver", - "bitcell_array", "sense_amp_array", "precharge_array", - "column_mux_array", "write_driver_array", - "dff", "bank_select"] - from importlib import reload - for mod_name in mod_list: - config_mod_name = getattr(OPTS, mod_name) - class_file = reload(__import__(config_mod_name)) - mod_class = getattr(class_file , config_mod_name) - setattr (self, "mod_"+mod_name, mod_class) - - - self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, - rows=self.num_rows) + self.bitcell_array = factory.create(module_type="bitcell_array", + cols=self.num_cols, + rows=self.num_rows) self.add_mod(self.bitcell_array) # create arrays of bitline and bitline_bar names for read, write, or all ports - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") self.bl_names = self.bitcell.list_all_bl_names() self.br_names = self.bitcell.list_all_br_names() self.wl_names = self.bitcell.list_all_wl_names() @@ -423,7 +410,11 @@ class bank(design.design): self.precharge_array = [] for port in self.all_ports: if port in self.read_ports: - self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.bl_names[port], bitcell_br=self.br_names[port])) + temp_pre = factory.create(module_type="precharge_array", + columns=self.num_cols, + bitcell_bl=self.bl_names[port], + bitcell_br=self.br_names[port]) + self.precharge_array.append(temp_pre) self.add_mod(self.precharge_array[port]) else: self.precharge_array.append(None) @@ -431,32 +422,39 @@ class bank(design.design): if self.col_addr_size > 0: self.column_mux_array = [] for port in self.all_ports: - self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols, - word_size=self.word_size, - bitcell_bl=self.bl_names[port], - bitcell_br=self.br_names[port])) + temp_col = factory.create(module_type="column_mux_array", + columns=self.num_cols, + word_size=self.word_size, + bitcell_bl=self.bl_names[port], + bitcell_br=self.br_names[port]) + self.column_mux_array.append(temp_col) self.add_mod(self.column_mux_array[port]) - self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size, - words_per_row=self.words_per_row) + self.sense_amp_array = factory.create(module_type="sense_amp_array", + word_size=self.word_size, + words_per_row=self.words_per_row) self.add_mod(self.sense_amp_array) - self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, - word_size=self.word_size) + self.write_driver_array = factory.create(module_type="write_driver_array", + columns=self.num_cols, + word_size=self.word_size) self.add_mod(self.write_driver_array) - self.row_decoder = self.mod_decoder(rows=self.num_rows) + self.row_decoder = factory.create(module_type="decoder", + rows=self.num_rows) self.add_mod(self.row_decoder) - self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows) + self.wordline_driver = factory.create(module_type="wordline_driver", + rows=self.num_rows, + cols=self.num_cols) self.add_mod(self.wordline_driver) - self.inv = pinv() + self.inv = factory.create(module_type="pinv") self.add_mod(self.inv) if(self.num_banks > 1): - self.bank_select = self.mod_bank_select() + self.bank_select = factory.create(module_type="bank_select") self.add_mod(self.bank_select) @@ -693,18 +691,17 @@ class bank(design.design): """ Create a 2:4 or 3:8 column address decoder. """ + + dff = factory.create(module_type="dff") if self.col_addr_size == 0: return elif self.col_addr_size == 1: - from pinvbuf import pinvbuf - self.column_decoder = pinvbuf(height=self.mod_dff.height) + self.column_decoder = factory.create(module_type="pinvbuf", height=dff.height) elif self.col_addr_size == 2: - from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4 - self.column_decoder = pre2x4(height=self.mod_dff.height) + self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=dff.height) elif self.col_addr_size == 3: - from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8 - self.column_decoder = pre3x8(height=self.mod_dff.height) + self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=dff.height) else: # No error checking before? debug.error("Invalid column decoder?",-1) @@ -1071,8 +1068,8 @@ class bank(design.design): # The mid guarantees we exit the input cell to the right. driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc() - mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) - mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) + mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0) + mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) @@ -1090,8 +1087,8 @@ class bank(design.design): # The mid guarantees we exit the input cell to the right. driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() - mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) - mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) + mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) + mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) def route_column_address_lines(self, port): @@ -1257,20 +1254,22 @@ class bank(design.design): def get_wl_en_cin(self): """Get the relative capacitance of all the clk connections in the bank""" #wl_en only used in the wordline driver. - total_clk_cin = self.wordline_driver.get_wl_en_cin() - return total_clk_cin - + return self.wordline_driver.get_wl_en_cin() + + def get_w_en_cin(self): + """Get the relative capacitance of all the clk connections in the bank""" + #wl_en only used in the wordline driver. + return self.write_driver.get_w_en_cin() + def get_clk_bar_cin(self): """Get the relative capacitance of all the clk_bar connections in the bank""" #Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array. #Precharges are the all the same in Mulitport, one is picked port = self.read_ports[0] - total_clk_bar_cin = self.precharge_array[port].get_en_cin() - return total_clk_bar_cin + return self.precharge_array[port].get_en_cin() def get_sen_cin(self): """Get the relative capacitance of all the sense amp enable connections in the bank""" #Current bank only uses sen as an enable for the sense amps. - total_sen_cin = self.sense_amp_array.get_en_cin() - return total_sen_cin \ No newline at end of file + return self.sense_amp_array.get_en_cin() diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index 7141de2a..8e44dfa2 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -7,6 +7,7 @@ from pinv import pinv from pnand2 import pnand2 from pnor2 import pnor2 from vector import vector +from sram_factory import factory from globals import OPTS class bank_select(design.design): @@ -62,28 +63,25 @@ class bank_select(design.design): def add_modules(self): """ Create modules for later instantiation """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") height = self.bitcell.height + drc("poly_to_active") # 1x Inverter - self.inv_sel = pinv(height=height) + self.inv_sel = factory.create(module_type="pinv", height=height) self.add_mod(self.inv_sel) # 4x Inverter - self.inv = self.inv4x = pinv(4) + self.inv4x = factory.create(module_type="pinv", height=height, size=4) self.add_mod(self.inv4x) - self.nor2 = pnor2(height=height) + self.nor2 = factory.create(module_type="pnor2", height=height) self.add_mod(self.nor2) - self.inv4x_nor = pinv(size=4, height=height) + self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4) self.add_mod(self.inv4x_nor) - self.nand2 = pnand2() + self.nand2 = factory.create(module_type="pnand2") self.add_mod(self.nand2) def calculate_module_offsets(self): @@ -94,7 +92,7 @@ class bank_select(design.design): self.xoffset_bank_sel_inv = 0 self.xoffset_inputs = 0 - self.yoffset_maxpoint = self.num_control_lines * self.inv.height + self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height # Include the M1 pitches for the supply rails and spacing self.height = self.yoffset_maxpoint + 2*self.m1_pitch self.width = self.xoffset_inv + self.inv4x.width @@ -170,10 +168,10 @@ class bank_select(design.design): if i == 0: y_offset = 0 else: - y_offset = self.inv4x_nor.height + self.inv.height * (i-1) + y_offset = self.inv4x_nor.height + self.inv4x.height * (i-1) if i%2: - y_offset += self.inv.height + y_offset += self.inv4x.height mirror = "MX" else: mirror = "" @@ -223,7 +221,7 @@ class bank_select(design.design): self.add_label_pin(text="bank_sel_bar", layer="metal2", offset=vector(xoffset_bank_sel_bar, 0), - height=self.inv.height) + height=self.inv4x.height) self.add_via_center(layers=("metal1","via1","metal2"), offset=bank_sel_bar_pin.rc()) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 6032fc19..67e5a9da 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -3,8 +3,7 @@ import design from tech import drc, spice from vector import vector from globals import OPTS - -unique_id = 1 +from sram_factory import factory class bitcell_array(design.design): """ @@ -12,16 +11,10 @@ class bitcell_array(design.design): and word line is connected by abutment. Connects the word lines and bit lines. """ - unique_id = 1 - - def __init__(self, cols, rows, name=""): - - if name == "": - name = "bitcell_array_{0}x{1}_{2}".format(rows,cols,bitcell_array.unique_id) - bitcell_array.unique_id += 1 + def __init__(self, cols, rows, name): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) - + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.column_size = cols self.row_size = rows @@ -83,11 +76,7 @@ class bitcell_array(design.design): def add_modules(self): """ Add the modules used in this design """ - - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.cell = self.mod_bitcell() + self.cell = factory.create(module_type="bitcell") self.add_mod(self.cell) def create_instances(self): @@ -210,4 +199,4 @@ class bitcell_array(design.design): #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns bitcell_wl_cin = self.cell.get_wl_cin() total_cin = bitcell_wl_cin * self.column_size - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index c30d91a0..d4597cf9 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -3,13 +3,7 @@ import design from tech import drc, parameter import debug import contact -from pinv import pinv -from pbuf import pbuf -from pand2 import pand2 -from pnand2 import pnand2 -from pinvbuf import pinvbuf -from dff_buf import dff_buf -from dff_buf_array import dff_buf_array +from sram_factory import factory import math from vector import vector from globals import OPTS @@ -20,20 +14,26 @@ class control_logic(design.design): Dynamically generated Control logic for the total SRAM circuit. """ - def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"): + def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw"): """ Constructor """ name = "control_logic_" + port_type design.design.__init__(self, name) debug.info(1, "Creating {}".format(name)) + self.add_comment("num_rows: {0}".format(num_rows)) + self.add_comment("words_per_row: {0}".format(words_per_row)) + self.add_comment("word_size {0}".format(word_size)) + self.sram=sram self.num_rows = num_rows self.words_per_row = words_per_row + self.word_size = word_size self.port_type = port_type + + self.num_cols = word_size*words_per_row + self.num_words = num_rows * words_per_row self.enable_delay_chain_resizing = False - #This is needed to resize the delay chain. Likely to be changed at some point. - self.sram=sram #self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic. self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model. self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing. @@ -73,46 +73,69 @@ class control_logic(design.design): def add_modules(self): """ Add all the required modules """ - dff = dff_buf() + dff = factory.create(module_type="dff_buf") dff_height = dff.height - self.ctrl_dff_array = dff_buf_array(rows=self.num_control_signals,columns=1) + self.ctrl_dff_array = factory.create(module_type="dff_buf_array", + rows=self.num_control_signals, + columns=1) + self.add_mod(self.ctrl_dff_array) - self.and2 = pand2(size=4,height=dff_height) + self.and2 = factory.create(module_type="pand2", + size=4, + height=dff_height) self.add_mod(self.and2) - # Special gates: inverters for buffering - # Size the clock for the number of rows (fanout) - clock_driver_size = max(1,int(self.num_rows/4)) - self.clkbuf = pbuf(size=clock_driver_size, height=dff_height) - self.add_mod(self.clkbuf) - - self.buf16 = pbuf(size=16, height=dff_height) - self.add_mod(self.buf16) - - self.buf8 = pbuf(size=8, height=dff_height) - self.add_mod(self.buf8) + # clk_buf drives a flop for every address and control bit + # plus about 5 fanouts for the control logic + # each flop internally has a FO 4 approximately + clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \ + + self.num_control_signals) + 5 + self.clk_buf_driver = factory.create(module_type="pdriver", + fanout=clock_fanout, + height=dff_height) - self.inv = self.inv1 = pinv(size=1, height=dff_height) - self.add_mod(self.inv1) - - self.inv8 = pinv(size=8, height=dff_height) - self.add_mod(self.inv8) - - # self.inv2 = pinv(size=4, height=dff_height) - # self.add_mod(self.inv2) - #self.inv16 = pinv(size=16, height=dff_height) - #self.add_mod(self.inv16) + self.add_mod(self.clk_buf_driver) + # wl_en drives every row in the bank + self.wl_en_driver = factory.create(module_type="pdriver", + fanout=self.num_rows, + height=dff_height) + self.add_mod(self.wl_en_driver) + + # w_en drives every write driver + self.w_en_driver = factory.create(module_type="pdriver", + fanout=self.word_size+8, + height=dff_height) + self.add_mod(self.w_en_driver) + + # s_en drives every sense amp + self.s_en_driver = factory.create(module_type="pdriver", + fanout=self.word_size, + height=dff_height) + self.add_mod(self.s_en_driver) + + # used to generate inverted signals with low fanout + self.inv = factory.create(module_type="pinv", + size=1, + height=dff_height) + self.add_mod(self.inv) + + # p_en_bar drives every column in the bicell array + self.p_en_bar_driver = factory.create(module_type="pdriver", + neg_polarity=True, + fanout=self.num_cols, + height=dff_height) + self.add_mod(self.p_en_bar_driver) + if (self.port_type == "rw") or (self.port_type == "r"): - from importlib import reload - c = reload(__import__(OPTS.replica_bitline)) - replica_bitline = getattr(c, OPTS.replica_bitline) - delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() bitcell_loads = int(math.ceil(self.num_rows / 2.0)) - self.replica_bitline = replica_bitline([delay_fanout_heuristic]*delay_stages_heuristic, bitcell_loads, name="replica_bitline_"+self.port_type) + self.replica_bitline = factory.create(module_type="replica_bitline", + delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic, + bitcell_loads=bitcell_loads) + if self.sram != None: self.set_sen_wl_delays() @@ -124,8 +147,10 @@ class control_logic(design.design): #This resizes based on total delay. delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic) - self.replica_bitline = replica_bitline([delay_fanout]*delay_stages, bitcell_loads, name="replica_bitline_resized_"+self.port_type) - + self.replica_bitline = factory.create(module_type="replica_bitline", + delay_fanout_list=[delay_fanout]*delay_stages, + bitcell_loads=bitcell_loads) + self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing self.add_mod(self.replica_bitline) @@ -393,8 +418,8 @@ class control_logic(design.design): def create_clk_buf_row(self): """ Create the multistage and gated clock buffer """ - self.clkbuf_inst = self.add_inst(name="clkbuf", - mod=self.clkbuf) + self.clk_buf_inst = self.add_inst(name="clkbuf", + mod=self.clk_buf_driver) self.connect_inst(["clk","clk_buf","vdd","gnd"]) def place_clk_buf_row(self,row): @@ -403,12 +428,12 @@ class control_logic(design.design): (y_off,mirror)=self.get_offset(row) offset = vector(x_off,y_off) - self.clkbuf_inst.place(offset, mirror) + self.clk_buf_inst.place(offset, mirror) - self.row_end_inst.append(self.clkbuf_inst) + self.row_end_inst.append(self.clk_buf_inst) def route_clk_buf(self): - clk_pin = self.clkbuf_inst.get_pin("A") + clk_pin = self.clk_buf_inst.get_pin("A") clk_pos = clk_pin.center() self.add_layout_pin_segment_center(text="clk", layer="metal2", @@ -418,14 +443,17 @@ class control_logic(design.design): offset=clk_pos) - clkbuf_map = zip(["Z"], ["clk_buf"]) - self.connect_vertical_bus(clkbuf_map, self.clkbuf_inst, self.rail_offsets, ("metal3", "via2", "metal2")) + # Connect this at the bottom of the buffer + out_pos = self.clk_buf_inst.get_pin("Z").center() + mid1 = vector(out_pos.x,2*self.m2_pitch) + mid2 = vector(self.rail_offsets["clk_buf"].x, mid1.y) + bus_pos = self.rail_offsets["clk_buf"] + self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, mid2, bus_pos]) # The pin is on M1, so we need another via as well self.add_via_center(layers=("metal1","via1","metal2"), - offset=self.clkbuf_inst.get_pin("Z").center()) - + offset=self.clk_buf_inst.get_pin("Z").center()) - self.connect_output(self.clkbuf_inst, "Z", "clk_buf") + self.connect_output(self.clk_buf_inst, "Z", "clk_buf") def create_gated_clk_bar_row(self): self.clk_bar_inst = self.add_inst(name="inv_clk_bar", @@ -504,7 +532,7 @@ class control_logic(design.design): def create_wlen_row(self): # input pre_p_en, output: wl_en self.wl_en_inst=self.add_inst(name="buf_wl_en", - mod=self.buf16) + mod=self.wl_en_driver) self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"]) def place_wlen_row(self, row): @@ -574,7 +602,7 @@ class control_logic(design.design): # input: pre_p_en, output: p_en_bar self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar", - mod=self.inv8) + mod=self.p_en_bar_driver) self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"]) @@ -614,7 +642,7 @@ class control_logic(design.design): # BUFFER FOR S_EN # input: pre_s_en, output: s_en self.s_en_inst=self.add_inst(name="buf_s_en", - mod=self.buf8) + mod=self.s_en_driver) self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"]) def place_sen_row(self,row): @@ -651,7 +679,7 @@ class control_logic(design.design): # BUFFER FOR W_EN self.w_en_inst = self.add_inst(name="buf_w_en_buf", - mod=self.buf8) + mod=self.w_en_driver) self.connect_inst([input_name, "w_en", "vdd", "gnd"]) @@ -808,7 +836,7 @@ class control_logic(design.design): #Calculate the load on wl_en within the module and add it to external load external_cout = self.sram.get_wl_en_cin() #First stage is the clock buffer - stage_effort_list += self.clkbuf.get_output_stage_efforts(external_cout, is_clk_bar_rise) + stage_effort_list += self.clk_buf_driver.get_stage_efforts(external_cout, is_clk_bar_rise) last_stage_is_rise = stage_effort_list[-1].is_rise #Then ask the sram for the other path delays (from the bank) @@ -839,18 +867,18 @@ class control_logic(design.design): #First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports. if self.port_type == "rw": stage1_cout = self.replica_bitline.get_en_cin() - stage_effort_list += self.and2.get_output_stage_efforts(stage1_cout, last_stage_rise) + stage_effort_list += self.and2.get_stage_efforts(stage1_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise #Replica bitline stage, rbl_in -(rbl)-> pre_s_en - stage2_cout = self.buf8.get_cin() + stage2_cout = self.s_en_driver.get_cin() stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise #buffer stage, pre_s_en -(buffer)-> s_en stage3_cout = self.sram.get_sen_cin() - stage_effort_list += self.buf8.get_output_stage_efforts(stage3_cout, last_stage_rise) + stage_effort_list += self.s_en_driver.get_stage_efforts(stage3_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise return stage_effort_list - \ No newline at end of file + diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 722328d1..f3d15ba3 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -1,10 +1,10 @@ import debug import design from tech import drc -from pinv import pinv from contact import contact from vector import vector from globals import OPTS +from sram_factory import factory class delay_chain(design.design): """ @@ -13,14 +13,12 @@ class delay_chain(design.design): Usually, this will be constant, but it could have varied fanout. """ - unique_id = 1 - - def __init__(self, fanout_list, name="delay_chain"): + def __init__(self, name, fanout_list): """init function""" - name = name+"_{}".format(delay_chain.unique_id) - delay_chain.unique_id += 1 design.design.__init__(self, name) - + debug.info(1, "creating delay chain {0}".format(str(fanout_list))) + self.add_comment("fanouts: {0}".format(str(fanout_list))) + # Two fanouts are needed so that we can route the vdd/gnd connections for f in fanout_list: debug.check(f>=2,"Must have >=2 fanouts for each stage.") @@ -57,7 +55,7 @@ class delay_chain(design.design): self.add_pin("gnd") def add_modules(self): - self.inv = pinv(route_output=False) + self.inv = factory.create(module_type="pinv", route_output=False) self.add_mod(self.inv) def create_inverters(self): @@ -234,8 +232,8 @@ class delay_chain(design.design): stage_cout = self.inv.get_cin()*(stage_fanout+1) if len(stage_effort_list) == len(self.fanout_list)-1: #last stage stage_cout+=ext_delayed_en_cout - stage = self.inv.get_effort_stage(stage_cout, last_stage_is_rise) + stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise) stage_effort_list.append(stage) last_stage_is_rise = stage.is_rise - return stage_effort_list \ No newline at end of file + return stage_effort_list diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 25ef3090..5d728205 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -3,6 +3,7 @@ import design from tech import drc from math import log from vector import vector +from sram_factory import factory from globals import OPTS class dff_array(design.design): @@ -11,7 +12,7 @@ class dff_array(design.design): Unlike the data flops, these are never spaced out. """ - def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""): + def __init__(self, rows, columns, name=""): self.rows = rows self.columns = columns @@ -19,7 +20,8 @@ class dff_array(design.design): name = "dff_array_{0}x{1}".format(rows, columns) design.design.__init__(self, name) debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns)) - + self.add_comment("rows: {0} cols: {1}".format(rows, columns)) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -38,10 +40,7 @@ class dff_array(design.design): self.DRC_LVS() def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.dff)) - self.mod_dff = getattr(c, OPTS.dff) - self.dff = self.mod_dff("dff") + self.dff = factory.create(module_type="dff") self.add_mod(self.dff) def add_pins(self): @@ -61,7 +60,7 @@ class dff_array(design.design): for col in range(self.columns): name = "dff_r{0}_c{1}".format(row,col) self.dff_insts[row,col]=self.add_inst(name=name, - mod=self.dff) + mod=self.dff) self.connect_inst([self.get_din_name(row,col), self.get_dout_name(row,col), "clk", @@ -162,4 +161,4 @@ class dff_array(design.design): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 9ff89603..42d37bd1 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -4,7 +4,7 @@ from tech import drc,parameter from math import log from vector import vector from globals import OPTS -from pinv import pinv +from sram_factory import factory class dff_buf(design.design): """ @@ -21,7 +21,8 @@ class dff_buf(design.design): dff_buf.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) - + self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size)) + # This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width. # This causes a DRC in the pinv which assumes min width rails. This ensures the output # contact does not violate spacing to the rail in the NMOS. @@ -50,16 +51,17 @@ class dff_buf(design.design): self.DRC_LVS() def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.dff)) - self.mod_dff = getattr(c, OPTS.dff) - self.dff = self.mod_dff("dff") + self.dff = factory.create(module_type="dff") self.add_mod(self.dff) - self.inv1 = pinv(size=self.inv1_size,height=self.dff.height) + self.inv1 = factory.create(module_type="pinv", + size=self.inv1_size, + height=self.dff.height) self.add_mod(self.inv1) - self.inv2 = pinv(size=self.inv2_size,height=self.dff.height) + self.inv2 = factory.create(module_type="pinv", + size=self.inv2_size, + height=self.dff.height) self.add_mod(self.inv2) @@ -182,4 +184,4 @@ class dff_buf(design.design): #This is a handmade cell so the value must be entered in the tech.py file or estimated. #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. #FIXME: Dff changed in a past commit. The parameter need to be updated. - return parameter["dff_clk_cin"] \ No newline at end of file + return parameter["dff_clk_cin"] diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 8097f207..b179b1c3 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -4,7 +4,7 @@ from tech import drc from math import log from vector import vector from globals import OPTS -import dff_buf +from sram_factory import factory class dff_buf_array(design.design): """ @@ -22,6 +22,9 @@ class dff_buf_array(design.design): dff_buf_array.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, columns)) + self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size)) + self.inv1_size = inv1_size self.inv2_size = inv2_size @@ -54,7 +57,9 @@ class dff_buf_array(design.design): self.add_pin("gnd") def add_modules(self): - self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size) + self.dff = factory.create(module_type="dff_buf", + inv1_size=self.inv1_size, + inv2_size=self.inv2_size) self.add_mod(self.dff) def create_dff_array(self): @@ -189,4 +194,4 @@ class dff_buf_array(design.design): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index aebe49c2..436026bb 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -20,6 +20,8 @@ class dff_inv(design.design): dff_inv.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("inv: {0}".format(inv_size)) + self.inv_size = inv_size # This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width. @@ -55,13 +57,12 @@ class dff_inv(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.dff)) - self.mod_dff = getattr(c, OPTS.dff) - self.dff = self.mod_dff("dff") + self.dff = dff_inv.dff_inv(self.inv_size) self.add_mod(self.dff) - self.inv1 = pinv(size=self.inv_size,height=self.dff.height) + self.inv1 = factory.create(module_type="pinv", + size=self.inv_size, + height=self.dff.height) self.add_mod(self.inv1) def create_modules(self): @@ -152,4 +153,4 @@ class dff_inv(design.design): def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" - return self.dff.get_clk_cin() \ No newline at end of file + return self.dff.get_clk_cin() diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 8985b99a..91ccfa92 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -22,6 +22,9 @@ class dff_inv_array(design.design): dff_inv_array.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, columns)) + self.add_comment("inv1: {0}".format(inv1_size)) + self.inv_size = inv_size self.create_netlist() @@ -42,7 +45,7 @@ class dff_inv_array(design.design): self.DRC_LVS() def add_modules(self): - self.dff = dff_inv.dff_inv(self.inv_size) + self.dff = factory.create(module_type="dff") self.add_mod(self.dff) def add_pins(self): @@ -189,4 +192,4 @@ class dff_inv_array(design.design): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 32ed6d7c..4bbb6aca 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -4,12 +4,8 @@ import design from math import log from math import sqrt import math -import contact -from pnand2 import pnand2 -from pnand3 import pnand3 -from pinv import pinv -from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4 -from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8 +import contact +from sram_factory import factory from vector import vector from globals import OPTS @@ -17,11 +13,8 @@ class hierarchical_decoder(design.design): """ Dynamically generated hierarchical decoder. """ - unique_id = 1 - - def __init__(self, rows, height=None): - design.design.__init__(self, "hierarchical_decoder_{0}rows_{1}".format(rows,hierarchical_decoder.unique_id)) - hierarchical_decoder.unique_id += 1 + def __init__(self, name, rows, height=None): + design.design.__init__(self, name) self.NAND_FORMAT = "DEC_NAND_{0}" self.INV_FORMAT = "DEC_INV_{0}" @@ -57,21 +50,26 @@ class hierarchical_decoder(design.design): self.DRC_LVS() def add_modules(self): - self.inv = pinv(height=self.cell_height) + self.inv = factory.create(module_type="pinv", + height=self.cell_height) self.add_mod(self.inv) - self.nand2 = pnand2(height=self.cell_height) + self.nand2 = factory.create(module_type="pnand2", + height=self.cell_height) self.add_mod(self.nand2) - self.nand3 = pnand3(height=self.cell_height) + self.nand3 = factory.create(module_type="pnand3", + height=self.cell_height) self.add_mod(self.nand3) self.add_decoders() def add_decoders(self): """ Create the decoders based on the number of pre-decodes """ - self.pre2_4 = pre2x4(height=self.cell_height) + self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4", + height=self.cell_height) self.add_mod(self.pre2_4) - self.pre3_8 = pre3x8(height=self.cell_height) + self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8", + height=self.cell_height) self.add_mod(self.pre3_8) def determine_predecodes(self,num_inputs): diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 7dfd443d..147c3018 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -3,24 +3,19 @@ import design import math from tech import drc import contact -from pinv import pinv from vector import vector from globals import OPTS -from pnand2 import pnand2 -from pnand3 import pnand3 +from sram_factory import factory class hierarchical_predecode(design.design): """ Pre 2x4 and 3x8 decoder shared code. """ - unique_id = 1 - - def __init__(self, input_number, height=None): + def __init__(self, name, input_number, height=None): self.number_of_inputs = input_number self.cell_height = height self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) - design.design.__init__(self, name="pre{0}x{1}_{2}".format(self.number_of_inputs,self.number_of_outputs,hierarchical_predecode.unique_id)) - hierarchical_predecode.unique_id += 1 + design.design.__init__(self, name) def add_pins(self): for k in range(self.number_of_inputs): @@ -33,7 +28,8 @@ class hierarchical_predecode(design.design): def add_modules(self): """ Add the INV and NAND gate modules """ - self.inv = pinv(height=self.cell_height) + self.inv = factory.create(module_type="pinv", + height=self.cell_height) self.add_mod(self.inv) self.add_nand(self.number_of_inputs) @@ -42,9 +38,11 @@ class hierarchical_predecode(design.design): def add_nand(self,inputs): """ Create the NAND for the predecode input stage """ if inputs==2: - self.nand = pnand2(height=self.cell_height) + self.nand = factory.create(module_type="pnand2", + height=self.cell_height) elif inputs==3: - self.nand = pnand3(height=self.cell_height) + self.nand = factory.create(module_type="pnand3", + height=self.cell_height) else: debug.error("Invalid number of predecode inputs: {}".format(inputs),-1) diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py index 918172ea..83e93f85 100644 --- a/compiler/modules/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -9,8 +9,8 @@ class hierarchical_predecode2x4(hierarchical_predecode): """ Pre 2x4 decoder used in hierarchical_decoder. """ - def __init__(self, height=None): - hierarchical_predecode.__init__(self, 2, height) + def __init__(self, name, height=None): + hierarchical_predecode.__init__(self, name, 2, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py index 88bbbcd7..109e8160 100644 --- a/compiler/modules/hierarchical_predecode3x8.py +++ b/compiler/modules/hierarchical_predecode3x8.py @@ -9,8 +9,8 @@ class hierarchical_predecode3x8(hierarchical_predecode): """ Pre 3x8 decoder used in hierarchical_decoder. """ - def __init__(self, height=None): - hierarchical_predecode.__init__(self, 3, height) + def __init__(self, name, height=None): + hierarchical_predecode.__init__(self, name, 3, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index d402b145..1b9e6194 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -5,12 +5,8 @@ import design import math from math import log,sqrt,ceil import contact -from pinv import pinv -from pnand2 import pnand2 -from pnor2 import pnor2 from vector import vector -from pinvbuf import pinvbuf - +from sram_factory import factory from globals import OPTS class multibank(design.design): @@ -21,21 +17,8 @@ class multibank(design.design): This module includes the tristate and bank select logic. """ - def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""): + def __init__(self, name, word_size, num_words, words_per_row, num_banks=1): - mod_list = ["tri_gate", "bitcell", "decoder", "wordline_driver", - "bitcell_array", "sense_amp_array", "precharge_array", - "column_mux_array", "write_driver_array", "tri_gate_array", - "dff", "bank_select"] - from importlib import reload - for mod_name in mod_list: - config_mod_name = getattr(OPTS, mod_name) - class_file = reload(__import__(config_mod_name)) - mod_class = getattr(class_file , config_mod_name) - setattr (self, "mod_"+mod_name, mod_class) - - if name == "": - name = "bank_{0}_{1}".format(word_size, num_words) design.design.__init__(self, name) debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words)) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 8bb66cda..67581e1a 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -2,7 +2,7 @@ import design import debug from tech import drc from vector import vector -from precharge import precharge +from sram_factory import factory from globals import OPTS class precharge_array(design.design): @@ -11,14 +11,11 @@ class precharge_array(design.design): of bit line columns, height is the height of the bit-cell array. """ - unique_id = 1 - - def __init__(self, columns, size=1, bitcell_bl="bl", bitcell_br="br"): - name = "precharge_array_{}".format(precharge_array.unique_id) - precharge_array.unique_id += 1 + def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) - + self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br)) + self.columns = columns self.size = size self.bitcell_bl = bitcell_bl @@ -50,10 +47,12 @@ class precharge_array(design.design): self.DRC_LVS() def add_modules(self): - self.pc_cell = precharge(name="precharge", - size=self.size, - bitcell_bl=self.bitcell_bl, - bitcell_br=self.bitcell_br) + self.pc_cell = factory.create(module_type="precharge", + size=self.size, + bitcell_bl=self.bitcell_bl, + bitcell_br=self.bitcell_br) + + self.add_mod(self.pc_cell) @@ -107,4 +106,4 @@ class precharge_array(design.design): """Get the relative capacitance of all the clk connections in the precharge array""" #Assume single port precharge_en_cin = self.pc_cell.get_en_cin() - return precharge_en_cin*self.columns \ No newline at end of file + return precharge_en_cin*self.columns diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index 8538fbee..8d93b257 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -1,10 +1,8 @@ import debug import design from tech import drc -from pinv import pinv import contact -from bitcell_array import bitcell_array -from ptx import ptx +from sram_factory import factory from vector import vector from globals import OPTS @@ -15,7 +13,7 @@ class replica_bitline(design.design): line and rows is the height of the replica bit loads. """ - def __init__(self, delay_fanout_list, bitcell_loads, name="replica_bitline"): + def __init__(self, name, delay_fanout_list, bitcell_loads): design.design.__init__(self, name) self.bitcell_loads = bitcell_loads @@ -78,29 +76,25 @@ class replica_bitline(design.design): def add_modules(self): """ Add the modules for later usage """ - from importlib import reload - #g = reload(__import__(OPTS.delay_chain)) - #self.mod_delay_chain = getattr(g, OPTS.delay_chain) - - g = reload(__import__(OPTS.replica_bitcell)) - self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell) - - self.bitcell = self.replica_bitcell = self.mod_replica_bitcell() - self.add_mod(self.bitcell) + self.replica_bitcell = factory.create(module_type="replica_bitcell") + self.add_mod(self.replica_bitcell) # This is the replica bitline load column that is the height of our array - self.rbl = bitcell_array(cols=1, rows=self.bitcell_loads) + self.rbl = factory.create(module_type="bitcell_array", + cols=1, + rows=self.bitcell_loads) self.add_mod(self.rbl) # FIXME: The FO and depth of this should be tuned - from delay_chain import delay_chain - self.delay_chain = delay_chain(self.delay_fanout_list) + self.delay_chain = factory.create(module_type="delay_chain", + fanout_list=self.delay_fanout_list) self.add_mod(self.delay_chain) - self.inv = pinv() + self.inv = factory.create(module_type="pinv") self.add_mod(self.inv) - self.access_tx = ptx(tx_type="pmos") + self.access_tx = factory.create(module_type="ptx", + tx_type="pmos") self.add_mod(self.access_tx) def create_instances(self): @@ -132,7 +126,6 @@ class replica_bitline(design.design): temp.append("vdd") temp.append("gnd") self.connect_inst(temp) - #self.connect_inst(["bl_0", "br_0", "delayed_en", "vdd", "gnd"]) self.rbl_inst=self.add_inst(name="load", mod=self.rbl) @@ -621,7 +614,7 @@ class replica_bitline(design.design): #The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this #model is intended to track every but that. Therefore, the next stage is the inverter after the rbl. - stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise) + stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list @@ -631,4 +624,4 @@ class replica_bitline(design.design): access_tx_cin = self.access_tx.get_cin() rbc_cin = self.replica_bitcell.get_wl_cin() return access_tx_cin + rbc_cin - \ No newline at end of file + diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 806acf71..ebf95c95 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -1,6 +1,7 @@ import design from tech import drc from vector import vector +from sram_factory import factory import debug from globals import OPTS @@ -10,9 +11,11 @@ class sense_amp_array(design.design): Dynamically generated sense amp array for all bitlines. """ - def __init__(self, word_size, words_per_row): - design.design.__init__(self, "sense_amp_array") + def __init__(self, name, word_size, words_per_row): + design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("word_size {0}".format(word_size)) + self.add_comment("words_per_row: {0}".format(words_per_row)) self.word_size = word_size self.words_per_row = words_per_row @@ -51,17 +54,13 @@ class sense_amp_array(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.sense_amp)) - self.mod_sense_amp = getattr(c, OPTS.sense_amp) - self.amp = self.mod_sense_amp("sense_amp") + self.amp = factory.create(module_type="sense_amp") + self.add_mod(self.amp) # This is just used for measurements, # so don't add the module - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") def create_sense_amp_array(self): self.local_insts = [] @@ -143,4 +142,4 @@ class sense_amp_array(design.design): def get_en_cin(self): """Get the relative capacitance of all the sense amp enable connections in the array""" sense_amp_en_cin = self.amp.get_en_cin() - return sense_amp_en_cin * self.words_per_row \ No newline at end of file + return sense_amp_en_cin * self.words_per_row diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 699e1d85..49293568 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -1,11 +1,11 @@ from math import log import design -from single_level_column_mux import single_level_column_mux import contact from tech import drc import debug import math from vector import vector +from sram_factory import factory from globals import OPTS class single_level_column_mux_array(design.design): @@ -14,13 +14,11 @@ class single_level_column_mux_array(design.design): Array of column mux to read the bitlines through the 6T. """ - unique_id = 1 - - def __init__(self, columns, word_size, bitcell_bl="bl", bitcell_br="br"): - name="single_level_column_mux_array_{}".format(single_level_column_mux_array.unique_id) - single_level_column_mux_array.unique_id += 1 + def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br)) + self.columns = columns self.word_size = word_size self.words_per_row = int(self.columns / self.word_size) @@ -61,7 +59,9 @@ class single_level_column_mux_array(design.design): def add_modules(self): - self.mux = single_level_column_mux(bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) + self.mux = factory.create(module_type="single_level_column_mux", + bitcell_bl=self.bitcell_bl, + bitcell_br=self.bitcell_br) self.add_mod(self.mux) diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index 5ca992b3..d56e9c96 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -2,6 +2,7 @@ import debug from tech import drc import design from vector import vector +from sram_factory import factory from globals import OPTS class tri_gate_array(design.design): @@ -36,10 +37,7 @@ class tri_gate_array(design.design): self.DRC_LVS() def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.tri_gate)) - self.mod_tri_gate = getattr(c, OPTS.tri_gate) - self.tri = self.mod_tri_gate("tri_gate") + self.tri = factory.create(module_type="tri_gate") self.add_mod(self.tri) def add_pins(self): diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index af82fbc5..830c28de 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -5,9 +5,8 @@ import contact from math import log from math import sqrt import math -from pinv import pinv -from pnand2 import pnand2 from vector import vector +from sram_factory import factory from globals import OPTS class wordline_driver(design.design): @@ -16,10 +15,13 @@ class wordline_driver(design.design): Generates the wordline-driver to drive the bitcell """ - def __init__(self, rows): - design.design.__init__(self, "wordline_driver") - + def __init__(self, name, rows, cols): + design.design.__init__(self, name) + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + self.rows = rows + self.cols = cols self.create_netlist() if not OPTS.netlist_only: @@ -53,13 +55,16 @@ class wordline_driver(design.design): # This is just used for measurements, # so don't add the module - self.inv = pinv() + self.inv = factory.create(module_type="pdriver", + fanout=self.cols, + neg_polarity=True) self.add_mod(self.inv) - self.inv_no_output = pinv(route_output=False) + self.inv_no_output = factory.create(module_type="pinv", + route_output=False) self.add_mod(self.inv_no_output) - self.nand2 = pnand2() + self.nand2 = factory.create(module_type="pnand2") self.add_mod(self.nand2) @@ -224,12 +229,12 @@ class wordline_driver(design.design): stage_effort_list = [] stage1_cout = self.inv.get_cin() - stage1 = self.nand2.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise) - stage_effort_list.append(stage2) + stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise) + stage_effort_list.extend(stage2) return stage_effort_list @@ -237,4 +242,4 @@ class wordline_driver(design.design): """Get the relative capacitance of all the enable connections in the bank""" #The enable is connected to a nand2 for every row. total_cin = self.nand2.get_cin() * self.rows - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py index 8d1291a7..34c51245 100644 --- a/compiler/modules/write_driver.py +++ b/compiler/modules/write_driver.py @@ -23,3 +23,8 @@ class write_driver(design.design): self.height = write_driver.height self.pin_map = write_driver.pin_map + + def get_w_en_cin(self): + """Get the relative capacitance of a single input""" + # This is approximated from SCMOS. It has roughly 5 3x transistor gates. + return 5*3 diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 3b5e75d9..3367cc00 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -2,6 +2,7 @@ from math import log import design from tech import drc import debug +from sram_factory import factory from vector import vector from globals import OPTS @@ -11,9 +12,11 @@ class write_driver_array(design.design): Dynamically generated write driver array of all bitlines. """ - def __init__(self, columns, word_size): - design.design.__init__(self, "write_driver_array") + def __init__(self, name, columns, word_size): + design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("columns: {0}".format(columns)) + self.add_comment("word_size {0}".format(word_size)) self.columns = columns self.word_size = word_size @@ -53,17 +56,12 @@ class write_driver_array(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.write_driver)) - self.mod_write_driver = getattr(c, OPTS.write_driver) - self.driver = self.mod_write_driver("write_driver") + self.driver = factory.create(module_type="write_driver") self.add_mod(self.driver) # This is just used for measurements, # so don't add the module - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") def create_write_array(self): self.driver_insts = {} @@ -134,3 +132,7 @@ class write_driver_array(design.design): + def get_w_en_cin(self): + """Get the relative capacitance of all the enable connections in the bank""" + #The enable is connected to a nand2 for every row. + return self.driver.get_w_en_cin() * len(self.driver_insts) diff --git a/compiler/openram.py b/compiler/openram.py index 78241f6a..0fe3f7cd 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -44,15 +44,16 @@ from sram_config import sram_config # Configure the SRAM organization c = sram_config(word_size=OPTS.word_size, num_words=OPTS.num_words) -print("Words per row: {}".format(c.words_per_row)) +debug.print_raw("Words per row: {}".format(c.words_per_row)) #from parser import * -output_extensions = ["sp","v","lib","py","html"] +output_extensions = ["sp","v","lib","py","html","log"] if not OPTS.netlist_only: output_extensions.extend(["gds","lef"]) output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions] -print("Output files are: ") -print(*output_files,sep="\n") +debug.print_raw("Output files are: ") +for path in output_files: + debug.print_raw(path) from sram import sram diff --git a/compiler/options.py b/compiler/options.py index bd4bf607..fc1eb7d1 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -72,23 +72,24 @@ class options(optparse.Values): num_banks = 1 # These are the default modules that can be over-riden + bank_select = "bank_select" + bitcell_array = "bitcell_array" + bitcell = "bitcell" + column_mux_array = "single_level_column_mux_array" + control_logic = "control_logic" decoder = "hierarchical_decoder" + delay_chain = "delay_chain" dff_array = "dff_array" dff = "dff" - control_logic = "control_logic" - bitcell_array = "bitcell_array" - sense_amp = "sense_amp" - sense_amp_array = "sense_amp_array" precharge_array = "precharge_array" - column_mux_array = "single_level_column_mux_array" - write_driver = "write_driver" - write_driver_array = "write_driver_array" - tri_gate = "tri_gate" - tri_gate_array = "tri_gate_array" - wordline_driver = "wordline_driver" - replica_bitline = "replica_bitline" + ptx = "ptx" replica_bitcell = "replica_bitcell" - bitcell = "bitcell" - delay_chain = "delay_chain" - bank_select = "bank_select" + replica_bitline = "replica_bitline" + sense_amp_array = "sense_amp_array" + sense_amp = "sense_amp" + tri_gate_array = "tri_gate_array" + tri_gate = "tri_gate" + wordline_driver = "wordline_driver" + write_driver_array = "write_driver_array" + write_driver = "write_driver" diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 5eb1ceb9..a5805728 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -3,31 +3,19 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pnand2 import pnand2 -from pinv import pinv import pgate +from sram_factory import factory class pand2(pgate.pgate): """ This is a simple buffer used for driving loads. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - - unique_id = 1 - - def __init__(self, size=1, height=None, name=""): - + def __init__(self, name, size=1, height=None): self.size = size - if name=="": - name = "pand2_{0}_{1}".format(size, pand2.unique_id) - pand2.unique_id += 1 - pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) - + self.add_comment("size: {}".format(size)) self.create_netlist() if not OPTS.netlist_only: @@ -41,10 +29,10 @@ class pand2(pgate.pgate): def create_modules(self): # Shield the cap, but have at least a stage effort of 4 - self.nand = pnand2(height=self.height) + self.nand = factory.create(module_type="pnand2",height=self.height) self.add_mod(self.nand) - self.inv = pinv(size=self.size, height=self.height) + self.inv = factory.create(module_type="pinv", size=self.size, height=self.height) self.add_mod(self.inv) def create_layout(self): @@ -125,15 +113,15 @@ class pand2(pgate.pgate): inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load) return nand_delay + inv_delay - def get_output_stage_efforts(self, external_cout, inp_is_rise=False): + def get_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the A or B -> Z path""" stage_effort_list = [] stage1_cout = self.inv.get_cin() - stage1 = self.nand.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 9b6c59ff..a0b36111 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -3,32 +3,23 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pinv import pinv import pgate +from sram_factory import factory class pbuf(pgate.pgate): """ This is a simple buffer used for driving loads. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - - unique_id = 1 - - def __init__(self, size=4, height=None, name=""): - + def __init__(self, name, size=4, height=None): + self.stage_effort = 4 self.size = size self.height = height - if name=="": - name = "pbuf_{0}_{1}".format(self.size, pbuf.unique_id) - pbuf.unique_id += 1 - pgate.pgate.__init__(self, name, height) debug.info(1, "creating {0} with size of {1}".format(self.name,self.size)) - + self.add_comment("size: {}".format(size)) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -54,10 +45,10 @@ class pbuf(pgate.pgate): def create_modules(self): # Shield the cap, but have at least a stage effort of 4 input_size = max(1,int(self.size/self.stage_effort)) - self.inv1 = pinv(size=input_size, height=self.height) + self.inv1 = factory.create(module_type="pinv", size=input_size, height=self.height) self.add_mod(self.inv1) - self.inv2 = pinv(size=self.size, height=self.height) + self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.height) self.add_mod(self.inv2) def create_insts(self): @@ -125,15 +116,15 @@ class pbuf(pgate.pgate): inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load) return inv1_delay + inv2_delay - def get_output_stage_efforts(self, external_cout, inp_is_rise=False): + def get_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the A -> Z path""" stage_effort_list = [] stage1_cout = self.inv2.get_cin() - stage1 = self.inv1.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.inv1.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list @@ -141,4 +132,4 @@ class pbuf(pgate.pgate): def get_cin(self): """Returns the relative capacitance of the input""" input_cin = self.inv1.get_cin() - return input_cin \ No newline at end of file + return input_cin diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 5da68032..3a0e4e78 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -5,112 +5,74 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pinv import pinv +from sram_factory import factory class pdriver(pgate.pgate): """ This instantiates an even or odd number of inverters sized for driving a load. """ - unique_id = 1 + def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None): - def __init__(self, neg_polarity=False, fanout_size=8, size_list = [], height=None, name=""): - - self.stage_effort = 4 + self.stage_effort = 3 self.height = height self.neg_polarity = neg_polarity self.size_list = size_list - self.fanout_size = fanout_size + self.fanout = fanout - if len(self.size_list) > 0 and (self.fanout_size != 8 or self.neg_polarity): - debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1) + if self.size_list and self.fanout != 0: + debug.error("Cannot specify both size_list and fanout.", -1) + if self.size_list and self.neg_polarity: + debug.error("Cannot specify both size_list and neg_polarity.", -1) - if name=="": - name = "pdriver_{}".format(pdriver.unique_id) - pdriver.unique_id += 1 - pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) self.compute_sizes() + self.add_comment("sizes: {}".format(str(self.size_list))) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() def compute_sizes(self): # size_list specified - if len(self.size_list) > 0: - if not len(self.size_list) % 2: - neg_polarity = True - self.num_inv = len(self.size_list) + if self.size_list: + self.num_stages = len(self.size_list) else: - # find the number of stages - #fanout_size is a unit inverter fanout, not a capacitance so c_in=1 - num_stages = max(1,int(round(log(self.fanout_size)/log(4)))) + # Find the optimal number of stages for the given effort + self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort)))) - # find inv_num and compute sizes - if self.neg_polarity: - if (num_stages % 2 == 0): # if num_stages is even - self.diff_polarity(num_stages=num_stages) - else: # if num_stages is odd - self.same_polarity(num_stages=num_stages) - else: # positive polarity - if (num_stages % 2 == 0): - self.same_polarity(num_stages=num_stages) - else: - self.diff_polarity(num_stages=num_stages) - + # Increase the number of stages if we need to fix polarity + if self.neg_polarity and (self.num_stages%2==0): + self.num_stages += 1 + elif not self.neg_polarity and (self.num_stages%2): + self.num_stages += 1 - def same_polarity(self, num_stages): - self.calc_size_list = [] - self.num_inv = num_stages - # compute sizes - fanout_size_prev = self.fanout_size - for x in range(self.num_inv-1,-1,-1): - fanout_size_prev = int(round(fanout_size_prev/self.stage_effort)) - self.calc_size_list.append(fanout_size_prev) + self.size_list = [] + # compute sizes backwards from the fanout + fanout_prev = self.fanout + for x in range(self.num_stages): + fanout_prev = max(round(fanout_prev/self.stage_effort),1) + self.size_list.append(fanout_prev) - - def diff_polarity(self, num_stages): - self.calc_size_list = [] - # find which delay is smaller - if (num_stages > 1): - delay_below = ((num_stages-1)*(self.fanout_size**(1/num_stages-1))) + num_stages-1 - delay_above = ((num_stages+1)*(self.fanout_size**(1/num_stages+1))) + num_stages+1 - if (delay_above < delay_below): - # recompute stage_effort for this delay - self.num_inv = num_stages+1 - polarity_stage_effort = self.fanout_size**(1/self.num_inv) - else: - self.num_inv = num_stages-1 - polarity_stage_effort = self.fanout_size**(1/self.num_inv) - else: # num_stages is 1, can't go to 0 - self.num_inv = num_stages+1 - polarity_stage_effort = self.fanout_size**(1/self.num_inv) - - - # compute sizes - fanout_size_prev = self.fanout_size - for x in range(self.num_inv-1,-1,-1): - fanout_size_prev = int(round(fanout_size_prev/polarity_stage_effort)) - self.calc_size_list.append(fanout_size_prev) + # reverse the sizes to be from input to output + self.size_list.reverse() def create_netlist(self): - inv_list = [] - self.add_pins() self.add_modules() self.create_insts() def create_layout(self): - self.width = self.num_inv * self.inv_list[0].width - self.height = self.inv_list[0].height - self.place_modules() self.route_wires() self.add_layout_pins() - + + self.width = self.inv_inst_list[-1].rx() + self.height = self.inv_inst_list[0].height + self.DRC_LVS() def add_pins(self): @@ -121,31 +83,27 @@ class pdriver(pgate.pgate): def add_modules(self): self.inv_list = [] - if len(self.size_list) > 0: # size list specified - for x in range(len(self.size_list)): - self.inv_list.append(pinv(size=self.size_list[x], height=self.height)) - self.add_mod(self.inv_list[x]) - else: # find inv sizes - for x in range(len(self.calc_size_list)): - self.inv_list.append(pinv(size=self.calc_size_list[x], height=self.height)) - self.add_mod(self.inv_list[x]) + for size in self.size_list: + temp_inv = factory.create(module_type="pinv", size=size, height=self.height) + self.inv_list.append(temp_inv) + self.add_mod(temp_inv) def create_insts(self): self.inv_inst_list = [] - for x in range(1,self.num_inv+1): + for x in range(1,self.num_stages+1): # Create first inverter if x == 1: zbx_int = "Zb{}_int".format(x); self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x), mod=self.inv_list[x-1])) - if self.num_inv == 1: + if self.num_stages == 1: self.connect_inst(["A", "Z", "vdd", "gnd"]) else: self.connect_inst(["A", zbx_int, "vdd", "gnd"]) # Create last inverter - elif x == self.num_inv: + elif x == self.num_stages: zbn_int = "Zb{}_int".format(x-1); self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x), mod=self.inv_list[x-1])) @@ -161,10 +119,10 @@ class pdriver(pgate.pgate): def place_modules(self): - # Add INV1 to the left + # Add the first inverter at the origin self.inv_inst_list[0].place(vector(0,0)) - # Add inverters to the right of INV1 + # Add inverters to the right of the previous inverter for x in range(1,len(self.inv_inst_list)): self.inv_inst_list[x].place(vector(self.inv_inst_list[x-1].rx(),0)) @@ -211,22 +169,49 @@ class pdriver(pgate.pgate): width = a_pin.width(), height = a_pin.height()) + def input_load(self): + return self.inv_list[0].input_load() + def analytical_delay(self, slew, load=0.0): """Calculate the analytical delay of INV1 -> ... -> INVn""" - delay = 0; - if len(self.inv_inst_list) == 1: - delay = self.inv_inst_list[x].analytical_delay(slew=slew); - else: - for x in range(len(self.inv_inst_list-1)): - load_next = 0.0 - for n in range(x,len(self.inv_inst_list+1)): - load_next += self.inv_inst_list[x+1] - if x == 1: - delay += self.inv_inst_list[x].analytical_delay(slew=slew, - load=load_next) - else: - delay += self.inv_inst_list[x+1].analytical_delay(slew=delay.slew, - load=load_next) + + cout_list = [] + for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): + cout_list.append(inv.input_load()) + cout_list.append(load) + + input_slew = slew + + delays = [] + for inv,cout in zip(self.inv_list,cout_list): + delays.append(inv.analytical_delay(slew=input_slew, load=cout)) + input_slew = delays[-1].slew + + delay = delays[0] + for i in range(len(delays)-1): + delay += delays[i] + return delay + def get_stage_efforts(self, external_cout, inp_is_rise=False): + """Get the stage efforts of the A -> Z path""" + + cout_list = {} + for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): + cout_list[prev_inv]=inv.get_cin() + + cout_list[self.inv_list[-1]]=external_cout + + stage_effort_list = [] + last_inp_is_rise = inp_is_rise + for inv in self.inv_list: + stage = inv.get_stage_effort(cout_list[inv], last_inp_is_rise) + stage_effort_list.append(stage) + last_inp_is_rise = stage.is_rise + + return stage_effort_list + + def get_cin(self): + """Returns the relative capacitance of the input""" + return self.inv_list[0].get_cin() diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index fc839270..2f641da9 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -2,9 +2,9 @@ import contact import design import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class pgate(design.design): """ @@ -18,15 +18,12 @@ class pgate(design.design): if height: self.height = height elif not height: - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - b = bitcell() + b = factory.create(module_type="bitcell") self.height = b.height def connect_pin_to_rail(self,inst,pin,supply): - """ Conencts a ptx pin to a supply rail. """ + """ Connects a ptx pin to a supply rail. """ source_pin = inst.get_pin(pin) supply_pin = self.get_pin(supply) if supply_pin.overlaps(source_pin): diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 31682360..aa16ab54 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -2,12 +2,12 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from math import ceil from globals import OPTS from utils import round_to_grid import logical_effort +from sram_factory import factory class pinv(pgate.pgate): """ @@ -19,17 +19,14 @@ class pinv(pgate.pgate): output to the right side of the cell for easier access. """ - unique_id = 1 - - def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True): + def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True): # We need to keep unique names because outputting to GDSII # will use the last record with a given name. I.e., you will # over-write a design in GDS if one has and the other doesn't # have poly connected, for example. - name = "pinv_{}".format(pinv.unique_id) - pinv.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) self.size = size self.nmos_size = size @@ -86,8 +83,8 @@ class pinv(pgate.pgate): # Sanity check. can we make an inverter in the height with minimum tx sizes? # Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain) # plus the tx height - nmos = ptx(tx_type="nmos") - pmos = ptx(width=drc("minwidth_tx"), tx_type="pmos") + nmos = factory.create(module_type="ptx", tx_type="nmos") + pmos = factory.create(module_type="ptx", width=drc("minwidth_tx"), tx_type="pmos") tx_height = nmos.poly_height + pmos.poly_height # rotated m1 pitch or poly to active spacing min_channel = max(contact.poly.width + self.m1_space, @@ -147,18 +144,20 @@ class pinv(pgate.pgate): def add_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def route_supply_rails(self): @@ -288,7 +287,7 @@ class pinv(pgate.pgate): """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor""" return self.nmos_size + self.pmos_size - def get_effort_stage(self, cout, inp_is_rise=True): + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 13c376cf..e950bd3f 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -4,16 +4,14 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pinv import pinv +from sram_factory import factory class pinvbuf(design.design): """ This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. """ - unique_id = 1 - - def __init__(self, driver_size=4, height=None, name=""): + def __init__(self, name, size=4, height=None): self.stage_effort = 4 self.row_height = height @@ -22,14 +20,12 @@ class pinvbuf(design.design): # stage effort of 4 or less # The pinvbuf has a FO of 2 for the first stage, so the second stage # should be sized "half" to prevent loading of the first stage - self.driver_size = driver_size - self.predriver_size = max(int(self.driver_size/(self.stage_effort/2)),1) - if name=="": - name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id) - pinvbuf.unique_id += 1 + self.size = size + self.predriver_size = max(int(self.size/(self.stage_effort/2)),1) design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("size: {}".format(size)) self.create_netlist() if not OPTS.netlist_only: @@ -65,13 +61,13 @@ class pinvbuf(design.design): # Shield the cap, but have at least a stage effort of 4 input_size = max(1,int(self.predriver_size/self.stage_effort)) - self.inv = pinv(size=input_size, height=self.row_height) + self.inv = factory.create(module_type="pinv", size=input_size, height=self.row_height) self.add_mod(self.inv) - self.inv1 = pinv(size=self.predriver_size, height=self.row_height) + self.inv1 = factory.create(module_type="pinv", size=self.predriver_size, height=self.row_height) self.add_mod(self.inv1) - self.inv2 = pinv(size=self.driver_size, height=self.row_height) + self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.row_height) self.add_mod(self.inv2) def create_insts(self): @@ -191,11 +187,11 @@ class pinvbuf(design.design): """Get the stage efforts of the clk -> clk_buf path""" stage_effort_list = [] stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() - stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list @@ -205,16 +201,16 @@ class pinvbuf(design.design): #After (almost) every stage, the direction of the signal inverts. stage_effort_list = [] stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() - stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage_effort_list[-1].is_rise stage2_cout = self.inv2.get_cin() - stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise) + stage2 = self.inv1.get_stage_effort(stage2_cout, last_stage_is_rise) stage_effort_list.append(stage2) last_stage_is_rise = stage_effort_list[-1].is_rise - stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) + stage3 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage3) - return stage_effort_list \ No newline at end of file + return stage_effort_list diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index e767b87e..d196bf15 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -2,25 +2,21 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS import logical_effort +from sram_factory import factory class pnand2(pgate.pgate): """ This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. """ - - unique_id = 1 - - def __init__(self, size=1, height=None): + def __init__(self, name, size=1, height=None): """ Creates a cell for a simple 2 input nand """ - name = "pnand2_{0}".format(pnand2.unique_id) - pnand2.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) self.size = size self.nmos_size = 2*size @@ -61,18 +57,20 @@ class pnand2(pgate.pgate): def add_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def setup_layout_constants(self): @@ -255,9 +253,9 @@ class pnand2(pgate.pgate): """Return the relative input capacitance of a single input""" return self.nmos_size+self.pmos_size - def get_effort_stage(self, cout, inp_is_rise=True): + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) \ No newline at end of file + return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 4dab5264..29ae98c0 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -2,24 +2,20 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class pnand3(pgate.pgate): """ This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. """ - - unique_id = 1 - - def __init__(self, size=1, height=None): + def __init__(self, name, size=1, height=None): """ Creates a cell for a simple 3 input nand """ - name = "pnand3_{0}".format(pnand3.unique_id) - pnand3.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) # We have trouble pitch matching a 3x sizes to the bitcell... # If we relax this, we could size this better. @@ -61,18 +57,20 @@ class pnand3(pgate.pgate): def add_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def setup_layout_constants(self): @@ -93,7 +91,7 @@ class pnand3(pgate.pgate): self.output_pos = vector(0,0.5*self.height) # This is the extra space needed to ensure DRC rules to the active contacts - nmos = ptx(tx_type="nmos") + nmos = factory.create(module_type="ptx", tx_type="nmos") extra_contact_space = max(-nmos.get_pin("D").by(),0) # This is a poly-to-poly of a flipped cell self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space, @@ -267,9 +265,9 @@ class pnand3(pgate.pgate): """Return the relative input capacitance of a single input""" return self.nmos_size+self.pmos_size - def get_effort_stage(self, cout, inp_is_rise=True): + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 3 - return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) \ No newline at end of file + return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 65aaf7f8..d1be51f3 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -1,25 +1,21 @@ -import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS +import contact +from sram_factory import factory class pnor2(pgate.pgate): """ This module generates gds of a parametrically sized 2-input nor. This model use ptx to generate a 2-input nor within a cetrain height. """ - - unique_id = 1 - - def __init__(self, size=1, height=None): + def __init__(self, name, size=1, height=None): """ Creates a cell for a simple 2 input nor """ - name = "pnor2_{0}".format(pnor2.unique_id) - pnor2.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) self.nmos_size = size # We will just make this 1.5 times for now. NORs are not ideal anyhow. @@ -58,32 +54,30 @@ class pnor2(pgate.pgate): def create_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ - poly_contact = contact.contact(("poly","contact","metal1")) - m1m2_via = contact.contact(("metal1","via1","metal2")) - m2m3_via = contact.contact(("metal2","via2","metal3")) - # metal spacing to allow contacts on any layer - self.input_spacing = max(self.poly_space + poly_contact.first_layer_width, - self.m1_space + m1m2_via.first_layer_width, - self.m2_space + m2m3_via.first_layer_width, - self.m3_space + m2m3_via.second_layer_width) + self.input_spacing = max(self.poly_space + contact.poly.first_layer_width, + self.m1_space + contact.m1m2.first_layer_width, + self.m2_space + contact.m2m3.first_layer_width, + self.m3_space + contact.m2m3.second_layer_width) # Compute the other pmos2 location, but determining offset to overlap the # source and drain pins diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index a1422cb2..cea9c845 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -2,28 +2,20 @@ import contact import pgate import debug from tech import drc, parameter -from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class precharge(pgate.pgate): """ Creates a single precharge cell This module implements the precharge bitline cell used in the design. """ - - unique_id = 1 - def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"): - name = name+"_{}".format(precharge.unique_id) - precharge.unique_id += 1 pgate.pgate.__init__(self, name) debug.info(2, "create single precharge cell: {0}".format(name)) - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") self.beta = parameter["beta"] self.ptx_width = self.beta*parameter["min_tx_size"] @@ -57,8 +49,9 @@ class precharge(pgate.pgate): """ Initializes the upper and lower pmos """ - self.pmos = ptx(width=self.ptx_width, - tx_type="pmos") + self.pmos = factory.create(module_type="ptx", + width=self.ptx_width, + tx_type="pmos") self.add_mod(self.pmos) @@ -268,4 +261,4 @@ class precharge(pgate.pgate): #The enable connect to three pmos gates. They all use the same size pmos. pmos_cin = self.pmos.get_cin() return 3*pmos_cin - \ No newline at end of file + diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 82c79aed..3a127454 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -2,9 +2,8 @@ import design import debug from tech import drc, spice from vector import vector -from contact import contact from globals import OPTS -import path +from sram_factory import factory class ptx(design.design): """ @@ -15,7 +14,7 @@ class ptx(design.design): you to connect the fingered gates and active for parallel devices. """ - def __init__(self, width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None): + def __init__(self, name="", width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None): # We need to keep unique names because outputting to GDSII # will use the last record with a given name. I.e., you will # over-write a design in GDS if one has and the other doesn't @@ -97,8 +96,9 @@ class ptx(design.design): # This is not actually instantiated but used for calculations - self.active_contact = contact(layer_stack=("active", "contact", "metal1"), - dimensions=(1, self.num_contacts)) + self.active_contact = factory.create(module_type="contact", + layer_stack=("active", "contact", "metal1"), + dimensions=(1, self.num_contacts)) # The contacted poly pitch (or uncontacted in an odd technology) @@ -355,4 +355,4 @@ class ptx(design.design): def get_cin(self): """Returns the relative gate cin of the tx""" - return self.tx_width/drc("minwidth_tx") \ No newline at end of file + return self.tx_width/drc("minwidth_tx") diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 197164f3..f03a22e8 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -3,8 +3,8 @@ import debug from tech import drc from vector import vector import contact -from ptx import ptx from globals import OPTS +from sram_factory import factory class single_level_column_mux(design.design): """ @@ -13,14 +13,10 @@ class single_level_column_mux(design.design): to minimum size. Default is 8x. Per Samira and Hodges-Jackson book: Column-mux transistors driven by the decoder must be sized for optimal speed """ + def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"): - # This is needed for different bitline spacings - unique_id = 1 - - def __init__(self, tx_size=8, bitcell_bl="bl", bitcell_br="br"): self.tx_size = int(tx_size) - name="single_level_column_mux_{}_{}".format(self.tx_size,single_level_column_mux.unique_id) - single_level_column_mux.unique_id += 1 + design.design.__init__(self, name) debug.info(2, "create single column mux cell: {0}".format(name)) @@ -47,16 +43,11 @@ class single_level_column_mux(design.design): self.add_wells() def add_modules(self): - # This is just used for measurements, - # so don't add the module - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") # Adds nmos_lower,nmos_upper to the module self.ptx_width = self.tx_size*drc("minwidth_tx") - self.nmos = ptx(width=self.ptx_width) + self.nmos = factory.create(module_type="ptx", width=self.ptx_width) self.add_mod(self.nmos) diff --git a/compiler/sram.py b/compiler/sram.py index 4971de08..5ff28d47 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -65,21 +65,21 @@ class sram(): # Write the layout start_time = datetime.datetime.now() gdsname = OPTS.output_path + self.s.name + ".gds" - print("GDS: Writing to {0}".format(gdsname)) + debug.print_raw("GDS: Writing to {0}".format(gdsname)) self.gds_write(gdsname) print_time("GDS", datetime.datetime.now(), start_time) # Create a LEF physical model start_time = datetime.datetime.now() lefname = OPTS.output_path + self.s.name + ".lef" - print("LEF: Writing to {0}".format(lefname)) + debug.print_raw("LEF: Writing to {0}".format(lefname)) self.lef_write(lefname) print_time("LEF", datetime.datetime.now(), start_time) # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" - print("SP: Writing to {0}".format(spname)) + debug.print_raw("SP: Writing to {0}".format(spname)) self.sp_write(spname) print_time("Spice writing", datetime.datetime.now(), start_time) @@ -98,14 +98,14 @@ class sram(): # Characterize the design start_time = datetime.datetime.now() from characterizer import lib - print("LIB: Characterizing... ") + debug.print_raw("LIB: Characterizing... ") if OPTS.analytical_delay: - print("Using analytical delay models (no characterization)") + debug.print_raw("Using analytical delay models (no characterization)") else: if OPTS.spice_name!="": - print("Performing simulation-based characterization with {}".format(OPTS.spice_name)) + debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name)) if OPTS.trim_netlist: - print("Trimming netlist to speed up characterization.") + debug.print_raw("Trimming netlist to speed up characterization.") lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file) print_time("Characterization", datetime.datetime.now(), start_time) @@ -114,20 +114,20 @@ class sram(): start_time = datetime.datetime.now() from shutil import copyfile copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py') - print("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) + debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) print_time("Config", datetime.datetime.now(), start_time) # Write the datasheet start_time = datetime.datetime.now() from datasheet_gen import datasheet_gen dname = OPTS.output_path + self.s.name + ".html" - print("Datasheet: Writing to {0}".format(dname)) - datasheet_gen.datasheet_write(self.s,dname) + debug.print_raw("Datasheet: Writing to {0}".format(dname)) + datasheet_gen.datasheet_write(dname) print_time("Datasheet", datetime.datetime.now(), start_time) # Write a verilog model start_time = datetime.datetime.now() vname = OPTS.output_path + self.s.name + ".v" - print("Verilog: Writing to {0}".format(vname)) + debug.print_raw("Verilog: Writing to {0}".format(vname)) self.verilog_write(vname) print_time("Verilog", datetime.datetime.now(), start_time) diff --git a/compiler/sram_base.py b/compiler/sram_base.py index b51ebae9..61d3639d 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -10,6 +10,7 @@ import logical_effort from design import design from verilog import verilog from lef import lef +from sram_factory import factory class sram_base(design, verilog, lef): """ @@ -239,10 +240,7 @@ class sram_base(design, verilog, lef): def add_modules(self): - """ Create all the modules that will be used """ - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type=OPTS.bitcell) # Create the address and control flops (but not the clk) from dff_array import dff_array @@ -281,20 +279,23 @@ class sram_base(design, verilog, lef): # 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, + 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, sram=self, port_type="rw") self.add_mod(self.control_logic_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, sram=self, port_type="w") self.add_mod(self.control_logic_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, sram=self, port_type="r") self.add_mod(self.control_logic_r) @@ -514,25 +515,30 @@ class sram_base(design, verilog, lef): def get_wl_en_cin(self): """Gets the capacitive load the of clock (clk_buf) for the sram""" - #As clk_buf is an output of the control logic. The cap for that module is not determined here. #Only the wordline drivers within the bank use this signal - bank_clk_cin = self.bank.get_wl_en_cin() - - return bank_clk_cin - + return self.bank.get_wl_en_cin() + + def get_w_en_cin(self): + """Gets the capacitive load the of write enable (w_en) for the sram""" + #Only the write drivers within the bank use this signal + return self.bank.get_w_en_cin() + + + def get_p_en_bar_cin(self): + """Gets the capacitive load the of precharge enable (p_en_bar) for the sram""" + #Only the precharges within the bank use this signal + return self.bank.get_p_en_bar_cin() + def get_clk_bar_cin(self): """Gets the capacitive load the of clock (clk_buf_bar) for the sram""" #As clk_buf_bar is an output of the control logic. The cap for that module is not determined here. #Only the precharge cells use this signal (other than the control logic) - bank_clk_cin = self.bank.get_clk_bar_cin() - return bank_clk_cin + return self.bank.get_clk_bar_cin() def get_sen_cin(self): """Gets the capacitive load the of sense amp enable for the sram""" - #As clk_buf_bar is an output of the control logic. The cap for that module is not determined here. #Only the sense_amps use this signal (other than the control logic) - bank_sen_cin = self.bank.get_sen_cin() - return bank_sen_cin + return self.bank.get_sen_cin() diff --git a/compiler/sram_config.py b/compiler/sram_config.py index e4f94b4a..24e3cbc9 100644 --- a/compiler/sram_config.py +++ b/compiler/sram_config.py @@ -2,6 +2,7 @@ import debug from math import log,sqrt,ceil from importlib import reload from globals import OPTS +from sram_factory import factory class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ @@ -29,10 +30,7 @@ class sram_config: def compute_sizes(self): """ Computes the organization of the memory using bitcell size by trying to make it square.""" - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - # pass a copy of myself for the port numbers - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py new file mode 100644 index 00000000..7b420a6b --- /dev/null +++ b/compiler/sram_factory.py @@ -0,0 +1,78 @@ +import debug +from globals import OPTS +from importlib import reload + + +class sram_factory: + """ + This is a factory pattern to create modules for usage in an SRAM. + Since GDSII has a flat namespace, it requires modules to have unique + names if their layout differs. This module ensures that any module + with different layouts will have different names. It also ensures that + identical layouts will share the same name to reduce file size and promote + hierarchical sharing. + """ + + def __init__(self): + # A dictionary of modules indexed by module type + self.modules = {} + # These are the indices to append to name to make unique object names + self.module_indices = {} + # A dictionary of instance lists indexed by module type + self.objects = {} + + def reset(self): + """ + Clear the factory instances for testing. + """ + self.__init__() + + def create(self, module_type, **kwargs): + """ + A generic function to create a module with a given module_type. The args + are passed directly to the module constructor. + """ + # if name!="": + # # This is a special case where the name and type don't match + # # Can't be overridden in the config file + # module_name = name + if hasattr(OPTS, module_type): + # Retrieve the name from OPTS if it exists, + # otherwise just use the name + module_name = getattr(OPTS, module_type) + else: + module_name = module_type + + # Either retrieve the already loaded module or load it + try: + mod = self.modules[module_type] + except KeyError: + c = reload(__import__(module_name)) + mod = getattr(c, module_name) + self.modules[module_type] = mod + self.module_indices[module_type] = 0 + self.objects[module_type] = [] + + # Either retreive a previous object or create a new one + for obj in self.objects[module_type]: + (obj_kwargs, obj_item) = obj + # Must have the same dictionary exactly (conservative) + if obj_kwargs == kwargs: + #debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs))) + return obj_item + + # Use the default name if there are default arguments + # This is especially for library cells so that the spice and gds files can be found. + if len(kwargs)>0: + # Create a unique name and increment the index + module_name = "{0}_{1}".format(module_name, self.module_indices[module_type]) + self.module_indices[module_type] += 1 + #debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs))) + obj = mod(name=module_name,**kwargs) + self.objects[module_type].append((kwargs,obj)) + return obj + + +# Make a factory +factory = sram_factory() + diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py index 869e81bd..98799ee8 100755 --- a/compiler/tests/00_code_format_check_test.py +++ b/compiler/tests/00_code_format_check_test.py @@ -25,17 +25,11 @@ class code_format_test(openram_test): for code in source_codes: if re.search("gdsMill", code): continue - if re.search("options.py$", code): - continue if re.search("debug.py$", code): continue - if re.search("testutils.py$", code): - continue - if re.search("globals.py$", code): - continue if re.search("openram.py$", code): continue - if re.search("sram.py$", code): + if re.search("testutils.py$", code): continue if re.search("gen_stimulus.py$", code): continue diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index 915c5c78..f0fc2299 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -13,7 +13,7 @@ class path_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - import path + import wire_path import tech import design @@ -27,7 +27,7 @@ class path_test(openram_test): [0, 3 * min_space ], [0, 6 * min_space ]] w = design.design("path_test0") - path.path(w,layer_stack, position_list) + wire_path.wire_path(w,layer_stack, position_list) self.local_drc_check(w) @@ -44,7 +44,7 @@ class path_test(openram_test): [-1 * min_space, 0]] position_list = [[x+min_space, y+min_space] for x,y in old_position_list] w = design.design("path_test1") - path.path(w,layer_stack, position_list) + wire_path.wire_path(w,layer_stack, position_list) self.local_drc_check(w) min_space = 2 * tech.drc["minwidth_metal2"] @@ -60,7 +60,7 @@ class path_test(openram_test): [-1 * min_space, 0]] position_list = [[x-min_space, y-min_space] for x,y in old_position_list] w = design.design("path_test2") - path.path(w, layer_stack, position_list) + wire_path.wire_path(w, layer_stack, position_list) self.local_drc_check(w) min_space = 2 * tech.drc["minwidth_metal3"] @@ -77,7 +77,7 @@ class path_test(openram_test): # run on the reverse list position_list.reverse() w = design.design("path_test3") - path.path(w, layer_stack, position_list) + wire_path.wire_path(w, layer_stack, position_list) self.local_drc_check(w) globals.end_openram() diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index 68433e96..91b3458e 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -21,7 +21,7 @@ class pand2_test(openram_test): import pand2 debug.info(2, "Testing pand2 gate 4x") - a = pand2.pand2(4) + a = pand2.pand2(name="pand2x4", size=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index e5dbbc5e..96e6bba8 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -10,8 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug - -OPTS = globals.OPTS +from sram_factory import factory #@unittest.skip("SKIPPING 04_pbitcell_test") class pbitcell_test(openram_test): @@ -19,75 +18,85 @@ class pbitcell_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) from pbitcell import pbitcell - import tech + OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=1 + factory.reset() debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=0 OPTS.num_w_ports=1 OPTS.num_r_ports=1 + factory.reset() debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=1 OPTS.num_w_ports=0 OPTS.num_r_ports=1 + factory.reset() debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=1 OPTS.num_w_ports=0 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=2 OPTS.num_r_ports=2 + factory.reset() debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=0 OPTS.num_w_ports=2 OPTS.num_r_ports=2 + factory.reset() debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=0 OPTS.num_r_ports=2 + factory.reset() debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=2 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=0 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py index f784c671..ed5b8627 100755 --- a/compiler/tests/04_pbuf_test.py +++ b/compiler/tests/04_pbuf_test.py @@ -21,7 +21,7 @@ class pbuf_test(openram_test): import pbuf debug.info(2, "Testing inverter/buffer 4x 8x") - a = pbuf.pbuf(8) + a = pbuf.pbuf(name="pbufx8", size=8) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py index 8db39d8c..ba89961f 100755 --- a/compiler/tests/04_pdriver_test.py +++ b/compiler/tests/04_pdriver_test.py @@ -22,17 +22,22 @@ class pdriver_test(openram_test): debug.info(2, "Testing inverter/buffer 4x 8x") # a tests the error message for specifying conflicting conditions - #a = pdriver.pdriver(fanout_size = 4,size_list = [1,2,4,8]) - b = pdriver.pdriver(size_list = [1,2,4,8]) - c = pdriver.pdriver(fanout_size = 50) - d = pdriver.pdriver(fanout_size = 50, neg_polarity = True) - e = pdriver.pdriver(fanout_size = 64) - f = pdriver.pdriver(fanout_size = 64, neg_polarity = True) + #a = pdriver.pdriver(fanout = 4,size_list = [1,2,4,8]) #self.local_check(a) + + b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8]) self.local_check(b) + + c = pdriver.pdriver(name="pdriver2", fanout = 50) self.local_check(c) + + d = pdriver.pdriver(name="pdriver3", fanout = 50, neg_polarity = True) self.local_check(d) + + e = pdriver.pdriver(name="pdriver4", fanout = 64) self.local_check(e) + + f = pdriver.pdriver(name="pdriver5", fanout = 64, neg_polarity = True) self.local_check(f) globals.end_openram() diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index d457d2a9..42c38ca1 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -19,7 +19,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 10x inverter") - tx = pinv.pinv(size=8) + tx = pinv.pinv(name="pinvx10",size=8) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index 77ff5454..9ac66a65 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -19,7 +19,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 1x beta=3 size inverter") - tx = pinv.pinv(size=1, beta=3) + tx = pinv.pinv(name="pinvx1b", size=1, beta=3) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index 49cb1cb1..850aa78e 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -18,7 +18,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 1x size inverter") - tx = pinv.pinv(size=1) + tx = pinv.pinv(name="pinvx1", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index 84bc55ee..33950da9 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -19,7 +19,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 2x size inverter") - tx = pinv.pinv(size=2) + tx = pinv.pinv(name="pinvx2", size=2) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index d35f1ec7..53814628 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -18,7 +18,7 @@ class pinvbuf_test(openram_test): import pinvbuf debug.info(2, "Testing inverter/buffer 4x 8x") - a = pinvbuf.pinvbuf(8) + a = pinvbuf.pinvbuf(name="pinvufx8", size=8) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index a2ac9288..cb0b65c6 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -21,7 +21,7 @@ class pnand2_test(openram_test): import tech debug.info(2, "Checking 2-input nand gate") - tx = pnand2.pnand2(size=1) + tx = pnand2.pnand2(name="pnand2", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index f6daedda..f3bbdb73 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -21,7 +21,7 @@ class pnand3_test(openram_test): import tech debug.info(2, "Checking 3-input nand gate") - tx = pnand3.pnand3(size=1) + tx = pnand3.pnand3(name="pnand3", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index ce4b19ae..32214ded 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -21,7 +21,7 @@ class pnor2_test(openram_test): import tech debug.info(2, "Checking 2-input nor gate") - tx = pnor2.pnor2(size=1) + tx = pnor2.pnor2(name="pnor2", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 6c0cfe56..a73595eb 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class precharge_test(openram_test): @@ -28,7 +29,8 @@ class precharge_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(2, "Checking precharge for pbitcell (innermost connections)") tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index ce9f00b9..9a672419 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -10,29 +10,31 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class replica_pbitcell_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import replica_pbitcell - import tech OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - + + factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (small cell)") - tx = replica_pbitcell.replica_pbitcell() + tx = replica_pbitcell.replica_pbitcell(name="rpbc") self.local_check(tx) OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (large cell)") - tx = replica_pbitcell.replica_pbitcell() + tx = replica_pbitcell.replica_pbitcell(name="rpbc") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index c43b15fd..2a107b9a 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory #@unittest.skip("SKIPPING 04_driver_test") @@ -22,7 +23,7 @@ class single_level_column_mux_test(openram_test): # check single level column mux in single port debug.info(2, "Checking column mux") - tx = single_level_column_mux.single_level_column_mux(tx_size=8) + tx = single_level_column_mux.single_level_column_mux(name="mux8", tx_size=8) self.local_check(tx) # check single level column mux in multi-port @@ -30,13 +31,15 @@ class single_level_column_mux_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(2, "Checking column mux for pbitcell (innermost connections)") - tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0") + tx = single_level_column_mux.single_level_column_mux(name="mux8_2", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) + factory.reset() debug.info(2, "Checking column mux for pbitcell (outermost connections)") - tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2") + tx = single_level_column_mux.single_level_column_mux(name="mux8_3", tx_size=8, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index 09201149..2400d3c2 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class hierarchical_decoder_test(openram_test): @@ -20,29 +21,29 @@ class hierarchical_decoder_test(openram_test): # Doesn't require hierarchical decoder # debug.info(1, "Testing 4 row sample for hierarchical_decoder") - # a = hierarchical_decoder.hierarchical_decoder(rows=4) + # a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4) # self.local_check(a) # Doesn't require hierarchical decoder # debug.info(1, "Testing 8 row sample for hierarchical_decoder") - # a = hierarchical_decoder.hierarchical_decoder(rows=8) + # a = hierarchical_decoder.hierarchical_decoder(name="hd2", rows=8) # self.local_check(a) # check hierarchical decoder for single port debug.info(1, "Testing 16 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=16) + a = hierarchical_decoder.hierarchical_decoder(name="hd3", rows=16) self.local_check(a) debug.info(1, "Testing 32 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=32) + a = hierarchical_decoder.hierarchical_decoder(name="hd4", rows=32) self.local_check(a) debug.info(1, "Testing 128 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=128) + a = hierarchical_decoder.hierarchical_decoder(name="hd5", rows=128) self.local_check(a) debug.info(1, "Testing 512 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=512) + a = hierarchical_decoder.hierarchical_decoder(name="hd6", rows=512) self.local_check(a) # check hierarchical decoder for multi-port @@ -50,21 +51,22 @@ class hierarchical_decoder_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=16) + a = hierarchical_decoder.hierarchical_decoder(name="hd7", rows=16) self.local_check(a) debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=32) + a = hierarchical_decoder.hierarchical_decoder(name="hd8", rows=32) self.local_check(a) debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=128) + a = hierarchical_decoder.hierarchical_decoder(name="hd9", rows=128) self.local_check(a) debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=512) + a = hierarchical_decoder.hierarchical_decoder(name="hd10", rows=512) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index e16916d6..6fbba350 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -20,7 +20,7 @@ class hierarchical_predecode2x4_test(openram_test): # checking hierarchical precode 2x4 for single port debug.info(1, "Testing sample for hierarchy_predecode2x4") - a = pre.hierarchical_predecode2x4() + a = pre.hierarchical_predecode2x4(name="pre1") self.local_check(a) # checking hierarchical precode 2x4 for multi-port @@ -30,7 +30,7 @@ class hierarchical_predecode2x4_test(openram_test): OPTS.num_r_ports = 0 debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)") - a = pre.hierarchical_predecode2x4() + a = pre.hierarchical_predecode2x4(name="pre2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index ed5da57c..b704a50d 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -20,7 +20,7 @@ class hierarchical_predecode3x8_test(openram_test): # checking hierarchical precode 3x8 for single port debug.info(1, "Testing sample for hierarchy_predecode3x8") - a = pre.hierarchical_predecode3x8() + a = pre.hierarchical_predecode3x8(name="pre1") self.local_check(a) # checking hierarchical precode 3x8 for multi-port @@ -30,7 +30,7 @@ class hierarchical_predecode3x8_test(openram_test): OPTS.num_r_ports = 0 debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)") - a = pre.hierarchical_predecode3x8() + a = pre.hierarchical_predecode3x8(name="pre2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index 800292b6..8cc16f56 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -9,6 +9,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class single_level_column_mux_test(openram_test): @@ -18,15 +19,15 @@ class single_level_column_mux_test(openram_test): # check single level column mux array in single port debug.info(1, "Testing sample for 2-way column_mux_array") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8) + a = single_level_column_mux_array.single_level_column_mux_array(name="mux1", columns=16, word_size=8) self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4) + a = single_level_column_mux_array.single_level_column_mux_array(name="mux2", columns=16, word_size=4) self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array") - a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4) + a = single_level_column_mux_array.single_level_column_mux_array(name="mux3", columns=32, word_size=4) self.local_check(a) # check single level column mux array in multi-port @@ -34,21 +35,22 @@ class single_level_column_mux_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux4", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux5", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") - a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux6", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") - a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux7", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index cdf6100e..c31f133a 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -10,17 +10,17 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class precharge_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import precharge_array - import tech # check precharge array in single port debug.info(2, "Checking 3 column precharge") - pc = precharge_array.precharge_array(columns=3) + pc = precharge_array.precharge_array(name="pre1", columns=3) self.local_check(pc) # check precharge array in multi-port @@ -28,17 +28,18 @@ class precharge_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 - + + factory.reset() debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell") - pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") + pc = precharge_array.precharge_array(name="pre2", columns=3, bitcell_bl="bl0", bitcell_br="br0") self.local_check(pc) # debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)") - # pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") + # pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0") # self.local_check(pc) # debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)") - # pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2") + # pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2") # self.local_check(pc) globals.end_openram() diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 369b6774..bc69c776 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory #@unittest.skip("SKIPPING 04_driver_test") @@ -18,11 +19,10 @@ class wordline_driver_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import wordline_driver - import tech # check wordline driver for single port debug.info(2, "Checking driver") - tx = wordline_driver.wordline_driver(rows=8) + tx = wordline_driver.wordline_driver(name="wld1", rows=8, cols=32) self.local_check(tx) # check wordline driver for multi-port @@ -30,9 +30,10 @@ class wordline_driver_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(2, "Checking driver (multi-port case)") - tx = wordline_driver.wordline_driver(rows=8) + tx = wordline_driver.wordline_driver(name="wld2", rows=8, cols=64) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index a18631f9..c144b12b 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class sense_amp_test(openram_test): @@ -19,11 +20,11 @@ class sense_amp_test(openram_test): # check sense amp array for single port debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) + a = sense_amp_array.sense_amp_array(name="sa1", word_size=4, words_per_row=2) self.local_check(a) debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) + a = sense_amp_array.sense_amp_array(name="sa2", word_size=4, words_per_row=4) self.local_check(a) # check sense amp array for multi-port @@ -31,13 +32,14 @@ class sense_amp_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) + a = sense_amp_array.sense_amp_array(name="sa3", word_size=4, words_per_row=2) self.local_check(a) debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) + a = sense_amp_array.sense_amp_array(name="sa4", word_size=4, words_per_row=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index fa374181..98507b60 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class write_driver_test(openram_test): @@ -19,11 +20,11 @@ class write_driver_test(openram_test): # check write driver array for single port debug.info(2, "Testing write_driver_array for columns=8, word_size=8") - a = write_driver_array.write_driver_array(columns=8, word_size=8) + a = write_driver_array.write_driver_array(name="wd1", columns=8, word_size=8) self.local_check(a) debug.info(2, "Testing write_driver_array for columns=16, word_size=8") - a = write_driver_array.write_driver_array(columns=16, word_size=8) + a = write_driver_array.write_driver_array(name="wd2", columns=16, word_size=8) self.local_check(a) # check write driver array for multi-port @@ -31,13 +32,14 @@ class write_driver_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)") - a = write_driver_array.write_driver_array(columns=8, word_size=8) + a = write_driver_array.write_driver_array(name="wd3", columns=8, word_size=8) self.local_check(a) debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)") - a = write_driver_array.write_driver_array(columns=16, word_size=8) + a = write_driver_array.write_driver_array(name="wd4", columns=16, word_size=8) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index 1052f0de..bfe2b3ff 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -18,7 +18,7 @@ class delay_chain_test(openram_test): import delay_chain debug.info(2, "Testing delay_chain") - a = delay_chain.delay_chain(fanout_list=[4, 4, 4, 4]) + a = delay_chain.delay_chain(name="dc", fanout_list=[4, 4, 4, 4]) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/14_replica_bitline_multiport_test.py b/compiler/tests/14_replica_bitline_multiport_test.py index 41c3aa51..f379e0d2 100755 --- a/compiler/tests/14_replica_bitline_multiport_test.py +++ b/compiler/tests/14_replica_bitline_multiport_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class replica_bitline_multiport_test(openram_test): @@ -26,9 +27,10 @@ class replica_bitline_multiport_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 - + + factory.reset() debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) # check replica bitline in pbitcell multi-port @@ -38,16 +40,18 @@ class replica_bitline_multiport_test(openram_test): OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 + factory.reset() debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) OPTS.num_rw_ports = 1 OPTS.num_w_ports = 1 OPTS.num_r_ports = 1 + factory.reset() debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl3", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/14_replica_bitline_test.py b/compiler/tests/14_replica_bitline_test.py index 94a49f55..ca213d5c 100755 --- a/compiler/tests/14_replica_bitline_test.py +++ b/compiler/tests/14_replica_bitline_test.py @@ -22,14 +22,14 @@ class replica_bitline_test(openram_test): fanout=4 rows=13 debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) #debug.error("Exiting...", 1) stages=8 rows=100 debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py index 818c2eaf..91ad0500 100755 --- a/compiler/tests/16_control_logic_test.py +++ b/compiler/tests/16_control_logic_test.py @@ -20,7 +20,7 @@ class control_logic_test(openram_test): # check control logic for single port debug.info(1, "Testing sample for control_logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1) + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=32) self.local_check(a) # check control logic for multi-port @@ -31,7 +31,7 @@ class control_logic_test(openram_test): OPTS.num_r_ports = 0 debug.info(1, "Testing sample for control_logic for multiport") - a = control_logic.control_logic(num_rows=128, words_per_row=1) + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8) self.local_check(a) # Check port specific control logic @@ -40,15 +40,15 @@ class control_logic_test(openram_test): OPTS.num_r_ports = 1 debug.info(1, "Testing sample for control_logic for multiport, only write control logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="rw") + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw") self.local_check(a) debug.info(1, "Testing sample for control_logic for multiport, only write control logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="w") + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w") self.local_check(a) debug.info(1, "Testing sample for control_logic for multiport, only read control logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="r") + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index ff19ac15..8e462318 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -10,15 +10,13 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory #@unittest.skip("SKIPPING 19_psingle_bank_test") class psingle_bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - global verify - import verify - from bank import bank from sram_config import sram_config OPTS.bitcell = "pbitcell" @@ -31,6 +29,7 @@ class psingle_bank_test(openram_test): num_words=16) c.words_per_row=1 + factory.reset() c.recompute_sizes() debug.info(1, "No column mux") name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) @@ -39,6 +38,7 @@ class psingle_bank_test(openram_test): c.num_words=32 c.words_per_row=2 + factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) @@ -47,6 +47,7 @@ class psingle_bank_test(openram_test): c.num_words=64 c.words_per_row=4 + factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) @@ -56,6 +57,7 @@ class psingle_bank_test(openram_test): c.word_size=2 c.num_words=128 c.words_per_row=8 + factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index edbd6a55..d412d42f 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -53,27 +53,27 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.2011], - 'delay_lh': [0.2011], - 'leakage_power': 0.002, - 'min_period': 0.41, - 'read0_power': [0.63604], - 'read1_power': [0.6120599999999999], - 'slew_hl': [0.10853], - 'slew_lh': [0.10853], - 'write0_power': [0.51742], - 'write1_power': [0.51095]} + golden_data = {'delay_hl': [0.2152017], + 'delay_lh': [0.2152017], + 'leakage_power': 0.0022907, + 'min_period': 0.488, + 'read0_power': [0.47437749999999995], + 'read1_power': [0.45026109999999997], + 'slew_hl': [0.0846786], + 'slew_lh': [0.0846786], + 'write0_power': [0.40809259999999997], + 'write1_power': [0.4078904]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.3911], - 'delay_lh': [1.3911], - 'leakage_power': 0.0278488, - 'min_period': 2.812, - 'read0_power': [22.1183], - 'read1_power': [21.4388], - 'slew_hl': [0.7397553], - 'slew_lh': [0.7397553], - 'write0_power': [19.4103], - 'write1_power': [20.1167]} + golden_data = {'delay_hl': [1.4333000000000002], + 'delay_lh': [1.4333000000000002], + 'leakage_power': 0.0271847, + 'min_period': 2.891, + 'read0_power': [15.714200000000002], + 'read1_power': [14.9848], + 'slew_hl': [0.6819276999999999], + 'slew_lh': [0.6819276999999999], + 'write0_power': [13.9658], + 'write1_power': [14.8422]} else: self.assertTrue(False) # other techs fail # Check if no too many or too few results diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 20ba14cc..aac42fa6 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -51,27 +51,27 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.20443139999999999], - 'delay_lh': [0.20443139999999999], - 'leakage_power': 0.0017840640000000001, - 'min_period': 0.41, - 'read0_power': [0.6435831], - 'read1_power': [0.6233463], - 'slew_hl': [0.1138734], - 'slew_lh': [0.1138734], - 'write0_power': [0.5205761], - 'write1_power': [0.5213689]} + golden_data = {'delay_hl': [0.221699], + 'delay_lh': [0.221699], + 'leakage_power': 0.001467648, + 'min_period': 0.605, + 'read0_power': [0.3879335], + 'read1_power': [0.3662724], + 'slew_hl': [0.08562444999999999], + 'slew_lh': [0.08562444999999999], + 'write0_power': [0.3362456], + 'write1_power': [0.3372035]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.610911], - 'delay_lh': [1.610911], - 'leakage_power': 0.0023593859999999998, - 'min_period': 3.281, - 'read0_power': [20.763569999999998], - 'read1_power': [20.32745], - 'slew_hl': [0.7986348999999999], - 'slew_lh': [0.7986348999999999], - 'write0_power': [17.58272], - 'write1_power': [18.523419999999998]} + golden_data = {'delay_hl': [1.7951730000000001], + 'delay_lh': [1.7951730000000001], + 'leakage_power': 0.001669513, + 'min_period': 3.594, + 'read0_power': [17.03022], + 'read1_power': [16.55897], + 'slew_hl': [0.7079951], + 'slew_lh': [0.7079951], + 'write0_power': [15.16726], + 'write1_power': [16.13527]} else: self.assertTrue(False) # other techs fail diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 7510b340..a1bbbc3e 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -182,7 +182,6 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): # FIXME: Remove when vdd/gnd connected #'lvsAbortOnSupplyError' : 0 - # This should be removed for final verification if not final_verification: lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectNamesState']='SOME' diff --git a/lib/Makefile b/lib/Makefile deleted file mode 100644 index d9debb2c..00000000 --- a/lib/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -SUBDIRS := $(wildcard */.) -SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS)) - -all: $(SUBDIRS) - -$(SUBDIRS): - $(MAKE) -k -C $@ - -clean: - for dir in $(SUBDIRS); do \ - $(MAKE) -C $$dir $@; \ - done - -.PHONY: all $(SUBDIRS) $(SUBDIRSCLEAN) diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index b284ec12..00000000 --- a/lib/README.md +++ /dev/null @@ -1,5 +0,0 @@ -This directory contains a set of common sizes based on -discussions with users. All of the files are pre-computed -to that common-case users don't need to setup/use OpenRAM. -The results will be updated automatically as improvements -are made to OpenRAM. \ No newline at end of file diff --git a/lib/freepdk45/Makefile b/lib/freepdk45/Makefile deleted file mode 100644 index cf883d4c..00000000 --- a/lib/freepdk45/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -CUR_DIR = $(shell pwd) -TEST_DIR = ${CUR_DIR}/tests - -#MAKEFLAGS += -j 2 - -CONFIG_DIR = configs -OUT_DIRS = sp lib lef gds verilog -$(shell mkdir -p $(OUT_DIRS)) - -SRCS=$(wildcard $(CONFIG_DIR)/*.py) -SPICES=$(SRCS:.py=.sp) -all : $(SPICES) - -# Characterize and perform DRC/LVS -OPTS = -c -# Do not characterize or perform DRC/LVS -#OPTS += -n -# Verbosity -OPTS += -v -%.sp : %.py - $(eval bname=$(basename $(notdir $<))) - openram.py $(OPTS) $< 2>&1 > $(bname).log - mv $(bname).lef lef - mv $(bname).v verilog - mv $(bname).sp sp - mv $(bname).gds gds - mv $(bname)*.lib lib - -clean: - rm -f *.log configs/*.pyc *~ *.gds *.lib *.sp *.v *.lef - rm -f gds/* lef/* lib/* sp/* verilog/* - diff --git a/lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py deleted file mode 100644 index 1d131e16..00000000 --- a/lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,8 +0,0 @@ -word_size = 128 -num_words = 1024 -num_banks = 1 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py deleted file mode 100644 index 1085a755..00000000 --- a/lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 1024 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py deleted file mode 100644 index e96bac37..00000000 --- a/lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 2048 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py deleted file mode 100644 index 7ca6be89..00000000 --- a/lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 256 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py deleted file mode 100644 index 960e9f73..00000000 --- a/lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 512 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py deleted file mode 100644 index bb421711..00000000 --- a/lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 64 -num_words = 1024 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py deleted file mode 100644 index 838d49d7..00000000 --- a/lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 8 -num_words = 1024 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py b/lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py deleted file mode 100644 index 84daa8f0..00000000 --- a/lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 8 -num_words = 256 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py b/lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py deleted file mode 100644 index ab85aaa4..00000000 --- a/lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 8 -num_words = 512 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/scn4m_subm/Makefile b/lib/scn4m_subm/Makefile deleted file mode 100644 index f833836a..00000000 --- a/lib/scn4m_subm/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -CUR_DIR = $(shell pwd) -TEST_DIR = ${CUR_DIR}/tests - -#MAKEFLAGS += -j 2 - -CONFIG_DIR = configs -OUT_DIRS = sp lib lef gds verilog -$(shell mkdir -p $(OUT_DIRS)) - -SRCS=$(wildcard $(CONFIG_DIR)/*.py) -SPICES=$(SRCS:.py=.sp) -all : $(SPICES) - -OPTS = -# Characterize and perform DRC/LVS -#OPTS = -c -# Do not characterize or perform DRC/LVS -#OPTS += -n -# Verbosity -OPTS += -v -%.sp : %.py - $(eval bname=$(basename $(notdir $<))) - openram.py $(OPTS) $< 2>&1 > $(bname).log - mv $(bname).lef lef - mv $(bname).v verilog - mv $(bname).sp sp - mv $(bname).gds gds - mv $(bname)*.lib lib - -clean: - rm -f *.log configs/*.pyc *~ *.gds *.lib *.sp *.v *.lef - rm -f gds/* lef/* lib/* sp/* verilog/* - diff --git a/lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py deleted file mode 100644 index aad83344..00000000 --- a/lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 128 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py deleted file mode 100644 index 162eaa6e..00000000 --- a/lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py deleted file mode 100644 index 7ce98b2e..00000000 --- a/lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 2048 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py deleted file mode 100644 index 33547f16..00000000 --- a/lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 256 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py deleted file mode 100644 index 88d5fc96..00000000 --- a/lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 512 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py deleted file mode 100644 index c9d7d116..00000000 --- a/lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 64 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py deleted file mode 100644 index 3770c138..00000000 --- a/lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 8 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py deleted file mode 100644 index 37e4bf50..00000000 --- a/lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 8 -num_words = 256 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py deleted file mode 100644 index 5f4676d7..00000000 --- a/lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 8 -num_words = 512 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/technology/scn3me_subm/tf/LICENSE b/technology/scn3me_subm/tf/LICENSE deleted file mode 100644 index 8d22c4be..00000000 --- a/technology/scn3me_subm/tf/LICENSE +++ /dev/null @@ -1,4 +0,0 @@ -The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004, -2006. Users are free to use or modify the NCSU CDK as appropriate as long -as this notice appears in the modified package. The NCSU CDK is -provided with NO WARRANTY. diff --git a/technology/scn4m_subm/mag_lib/setup.tcl b/technology/scn4m_subm/mag_lib/setup.tcl index caf7550b..084428b5 100644 --- a/technology/scn4m_subm/mag_lib/setup.tcl +++ b/technology/scn4m_subm/mag_lib/setup.tcl @@ -4,11 +4,12 @@ equate class {-circuit1 nfet} {-circuit2 n} equate class {-circuit1 pfet} {-circuit2 p} # This circuit has symmetries and needs to be flattened to resolve them # or the banks won't pass -flatten class {-circuit1 bitcell_array} +flatten class {-circuit1 bitcell_array_0} +flatten class {-circuit1 bitcell_array_1} +flatten class {-circuit1 precharge_array_0} flatten class {-circuit1 precharge_array_1} flatten class {-circuit1 precharge_array_2} flatten class {-circuit1 precharge_array_3} -flatten class {-circuit1 precharge_array_4} property {-circuit1 nfet} remove as ad ps pd property {-circuit1 pfet} remove as ad ps pd property {-circuit2 n} remove as ad ps pd diff --git a/technology/scn4m_subm/tf/LICENSE b/technology/scn4m_subm/tf/LICENSE deleted file mode 100644 index 8d22c4be..00000000 --- a/technology/scn4m_subm/tf/LICENSE +++ /dev/null @@ -1,4 +0,0 @@ -The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004, -2006. Users are free to use or modify the NCSU CDK as appropriate as long -as this notice appears in the modified package. The NCSU CDK is -provided with NO WARRANTY.