Beispiel #1
0
    def add_wordline_pins(self):

        # Wordlines to ground
        self.gnd_wordline_names = []

        for port in self.all_ports:
            for bit in self.all_ports:
                self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit))
                if bit != port:
                    self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(port, bit))

        self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl]

        self.wordline_names = self.bitcell_array.wordline_names
        self.all_wordline_names = self.bitcell_array.all_wordline_names
 

        # All wordlines including dummy and RBL
        self.replica_array_wordline_names = []
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names()))
        for bit in range(self.rbl[0]):
            self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]])
        self.replica_array_wordline_names.extend(self.all_wordline_names)
        for bit in range(self.rbl[1]):
            self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]])
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names()))

        for port in range(self.rbl[0]):
            self.add_pin(self.rbl_wordline_names[port][port], "INPUT")
        self.add_pin_list(self.all_wordline_names, "INPUT")
        for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]):
            self.add_pin(self.rbl_wordline_names[port][port], "INPUT")
Beispiel #2
0
    def add_layout_pins(self):
        """ Add the layout pins """

        # Add the bitline metal, but not as pins since they are going to just be floating
        # For some reason, LVS has an issue if we don't add this metal
        bitline_names = self.cell.get_all_bitline_names()
        for col in range(self.column_size):
            for port in self.all_ports:
                bl_pin = self.cell_inst[0,
                                        col].get_pin(bitline_names[2 * port])
                self.add_rect(layer=bl_pin.layer,
                              offset=bl_pin.ll().scale(1, 0),
                              width=bl_pin.width(),
                              height=self.height)
                br_pin = self.cell_inst[0, col].get_pin(
                    bitline_names[2 * port + 1])
                self.add_rect(layer=br_pin.layer,
                              offset=br_pin.ll().scale(1, 0),
                              width=br_pin.width(),
                              height=self.height)

        wl_names = self.cell.get_all_wl_names()
        if not props.compare_ports(props.bitcell.split_wl):
            for row in range(self.row_size):
                for port in self.all_ports:
                    wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port])
                    self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
                                        layer=wl_pin.layer,
                                        offset=wl_pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=wl_pin.height())
        else:
            for row in range(self.row_size):
                for port in self.all_ports:
                    for wl in range(len(wl_names)):
                        wl_pin = self.cell_inst[row,
                                                0].get_pin("wl{}".format(wl))
                        self.add_layout_pin(text="wl{0}_{1}_{2}".format(
                            wl, port, row),
                                            layer=wl_pin.layer,
                                            offset=wl_pin.ll().scale(0, 1),
                                            width=self.width,
                                            height=wl_pin.height())

        # Copy a vdd/gnd layout pin from every cell
        if not props.compare_ports(
                props.bitcell_array.use_custom_cell_arrangement):
            for row in range(self.row_size):
                for col in range(self.column_size):
                    inst = self.cell_inst[row, col]
                    for pin_name in ["vdd", "gnd"]:
                        self.copy_layout_pin(inst, pin_name)
        else:
            for row in range(self.row_size):
                for col in range(self.column_size):
                    inst = self.cell_inst[row, col]
                    for pin_name in ["vpwr", "vgnd"]:
                        self.copy_layout_pin(inst, pin_name)
Beispiel #3
0
    def create_layout(self):

        # We will need unused wordlines grounded, so we need to know their layer
        pin = self.cell.get_pin(self.cell.get_all_wl_names()[0])
        pin_layer = pin.layer
        self.unused_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
        self.unused_offset = vector(self.unused_pitch, 0)

        # Add extra width on the left and right for the unused WLs
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.height = (self.row_size + self.extra_rows) * self.dummy_row.height
            self.width = (self.column_size + self.extra_cols) * self.cell.width + 2 * self.unused_pitch
        else:
            self.width = self.row_cap_left.width + self.row_cap_right.width + self.col_cap_top.width
            for rbl in range(self.rbl[0] + self.rbl[1]):
                self.width += self.replica_col_insts[rbl].width
            self.height = self.row_cap_left.height


        # This is a bitcell x bitcell offset to scale
        self.bitcell_offset = vector(self.cell.width, self.cell.height)
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.strap_offset = vector(0, 0)
            self.col_end_offset = vector(self.cell.width, self.cell.height)
            self.row_end_offset = vector(self.cell.width, self.cell.height)
        else:
            self.strap_offset = vector(self.replica_col_insts[0].mod.strap1.width, self.replica_col_insts[0].mod.strap1.height)
            self.col_end_offset = vector(self.dummy_row_insts[0].mod.colend1.width, self.dummy_row_insts[0].mod.colend1.height)
            self.row_end_offset = vector(self.dummy_col_insts[0].mod.rowend1.width, self.dummy_col_insts[0].mod.rowend1.height)

        # Everything is computed with the main array at (self.unused_pitch, 0) to start
        self.bitcell_array_inst.place(offset=self.unused_offset)

        self.add_replica_columns()
        
        self.add_end_caps()


        # Array was at (0, 0) but move everything so it is at the lower left
        # We move DOWN the number of left RBL even if we didn't add the column to this bitcell array
        array_offset = self.bitcell_offset.scale(1 + len(self.left_rbl), 1 + self.rbl[0])
        self.translate_all(array_offset.scale(-1, -1))

        self.add_layout_pins()

        self.route_unused_wordlines()
        
        self.add_boundary()

        self.DRC_LVS()
Beispiel #4
0
 def get_wl_name(self, port=0):
     """Get wl name"""
     if props.compare_ports(props.bitcell.split_wl):
         return "wl{}".format(port)
     else:
         debug.check(port == 0, "One port for bitcell only.")
         return props.bitcell.cell_6t.pin.wl
Beispiel #5
0
 def get_all_wl_names(self):
     """ Creates a list of all wordline pin names """
     if props.compare_ports(props.bitcell.split_wl):
         row_pins = ["wl0", "wl1"]
     else:
         row_pins = [props.bitcell.cell_6t.pin.wl]
     return row_pins
    def __init__(self, name, rows, cols, column_offset):
        super().__init__(name)
        debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))

        self.column_size = cols
        self.row_size = rows
        self.column_offset = column_offset

        # Bitcell for port names only
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.cell = factory.create(module_type="bitcell")
        else:
            self.cell = factory.create(module_type="s8_bitcell", version="opt1")
            self.cell2 = factory.create(module_type="s8_bitcell", version="opt1a")
            self.strap = factory.create(module_type="s8_internal", version="wlstrap")
            self.strap2 = factory.create(module_type="s8_internal", version="wlstrap_p")

        self.wordline_names = [[] for port in self.all_ports]
        self.all_wordline_names = []
        self.bitline_names = [[] for port in self.all_ports]
        self.all_bitline_names = []
        self.rbl_bitline_names = [[] for port in self.all_ports]
        self.all_rbl_bitline_names = []
        self.rbl_wordline_names = [[] for port in self.all_ports]
        self.all_rbl_wordline_names = []
Beispiel #7
0
class s8_dummy_bitcell(bitcell_base.bitcell_base):
    """
    A single bit cell (6T, 8T, etc.)  This module implements the
    single memory cell used in the design. It is a hand-made cell, so
    the layout and netlist should be available in the technology
    library.
    """
    if props.compare_ports(props.bitcell.split_wl):
        pin_names = ["bl", "br", "wl0", "wl1", "vdd", "gnd"]
        type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
    else:
        pin_names = [
            props.bitcell.cell_s8_6t.pin.bl, props.bitcell.cell_s8_6t.pin.br,
            props.bitcell.cell_s8_6t.pin.wl, "vpwr", "vgnd"
        ]

    def __init__(self, version, name=""):
        # Ignore the name argument

        if version == "opt1":
            self.name = "s8sram_cell_opt1"
            self.border_structure = "s8sram_cell"
        elif version == "opt1a":
            self.name = "s8sram_cell_opt1a"
            self.border_structure = "s8sram_cell"
        bitcell_base.bitcell_base.__init__(self, self.name)
        debug.info(2, "Create dummy bitcell")
        (self.width,
         self.height) = utils.get_libcell_size(self.name, GDS["unit"],
                                               layer["mem"], "s8sram_cell\x00")
        self.pin_map = utils.get_libcell_pins(self.pin_names, self.name,
                                              GDS["unit"])
Beispiel #8
0
    def __init__(self, name, rows, rbl, replica_bit, column_offset=0):
        super().__init__(rows=sum(rbl) + rows + 2,
                         cols=1,
                         column_offset=column_offset,
                         name=name)

        self.rows = rows
        self.left_rbl = rbl[0]
        self.right_rbl = rbl[1]
        self.replica_bit = replica_bit
        # left, right, regular rows plus top/bottom dummy cells
        if not cell_properties.compare_ports(
                cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.total_size = self.left_rbl + rows + self.right_rbl + 2
        else:
            self.total_size = self.left_rbl + rows + self.right_rbl + 2
        self.column_offset = column_offset

        debug.check(replica_bit != 0 and replica_bit != rows,
                    "Replica bit cannot be the dummy row.")
        debug.check(
            replica_bit <= self.left_rbl
            or replica_bit >= self.total_size - self.right_rbl - 1,
            "Replica bit cannot be in the regular array.")
        if OPTS.tech_name == "sky130":
            debug.check(
                rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0,
                "sky130 currently requires rows to be even and to start with X mirroring"
                + " (left_rbl must be odd) for LVS.")

        self.create_netlist()
        if not OPTS.netlist_only:
            self.create_layout()
    def place_array(self, name_template, row_offset=0):
        # We increase it by a well enclosure so the precharges don't overlap our wells
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.height = self.row_size * self.cell.height
            self.width = self.column_size * self.cell.width

            xoffset = 0.0
            for col in range(self.column_size):
                yoffset = 0.0
                tempx, dir_y = self._adjust_x_offset(xoffset, col, self.column_offset)

                for row in range(self.row_size):
                    tempy, dir_x = self._adjust_y_offset(yoffset, row, row_offset)

                    if dir_x and dir_y:
                        dir_key = "XY"
                    elif dir_x:
                        dir_key = "MX"
                    elif dir_y:
                        dir_key = "MY"
                    else:
                        dir_key = ""

                    self.cell_inst[row, col].place(offset=[tempx, tempy],
                                                mirror=dir_key)
                    yoffset += self.cell.height
                xoffset += self.cell.width
        else:
            from tech import custom_cell_placement
            custom_cell_placement(self)
Beispiel #10
0
    def create_all_wordline_names(self, num_remove_wordline=0):
        for row in range(self.row_size - num_remove_wordline):
            for port in self.all_ports:
                if not cell_properties.compare_ports(cell_properties.bitcell.split_wl):
                    self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
                else:
                    self.wordline_names[port].append("wl0_{0}_{1}".format(port, row))
                    self.wordline_names[port].append("wl1_{0}_{1}".format(port, row))

        self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl]
Beispiel #11
0
 def add_pins(self):
     for bl_name in self.get_bitline_names():
         self.add_pin(bl_name, "INOUT")
     for wl_name in self.get_wordline_names():
         self.add_pin(wl_name, "INPUT")
     if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
         self.add_pin("vdd", "POWER")
         self.add_pin("gnd", "GROUND")
     else:
         self.add_pin("vpwr", "POWER")
         self.add_pin("vgnd", "GROUND")
Beispiel #12
0
    def add_modules(self):
        if not cell_properties.compare_ports(
                cell_properties.bitcell_array.use_custom_cell_arrangement):
            self.replica_cell = factory.create(
                module_type="replica_{}".format(OPTS.bitcell))
            self.add_mod(self.replica_cell)
            self.dummy_cell = factory.create(
                module_type="dummy_{}".format(OPTS.bitcell))
            self.add_mod(self.dummy_cell)
            try:
                edge_module_type = (
                    "col_cap" if cell_properties.bitcell.end_caps else "dummy")
            except AttributeError:
                edge_module_type = "dummy"
            self.edge_cell = factory.create(module_type=edge_module_type +
                                            "_" + OPTS.bitcell)
            self.add_mod(self.edge_cell)
            # Used for pin names only
            self.cell = factory.create(module_type="bitcell")
        else:
            self.replica_cell = factory.create(module_type="s8_bitcell",
                                               version="opt1")
            self.add_mod(self.replica_cell)
            self.cell = self.replica_cell
            self.replica_cell2 = factory.create(module_type="s8_bitcell",
                                                version="opt1a")
            self.add_mod(self.replica_cell2)

            self.dummy_cell = factory.create(module_type="s8_bitcell",
                                             version="opt1")
            self.dummy_cell2 = factory.create(module_type="s8_bitcell",
                                              version="opt1")

            self.strap1 = factory.create(module_type="s8_internal",
                                         version="wlstrap")
            self.add_mod(self.strap1)
            self.strap2 = factory.create(module_type="s8_internal",
                                         version="wlstrap_p")
            self.add_mod(self.strap2)

            self.colend = factory.create(module_type="s8_col_end",
                                         version="colenda")
            self.edge_cell = self.colend
            self.add_mod(self.colend)
            self.colenda = factory.create(module_type="s8_col_end",
                                          version="colenda")
            self.add_mod(self.colenda)
            self.colend_p_cent = factory.create(module_type="s8_col_end",
                                                version="colend_p_cent")
            self.add_mod(self.colend_p_cent)
            self.colenda_p_cent = factory.create(module_type="s8_col_end",
                                                 version="colenda_p_cent")
            self.add_mod(self.colenda_p_cent)
Beispiel #13
0
    def create_instances(self):
        """ Create the module instances used in this design """
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):

            self.supplies = ["vdd", "gnd"]

            # Used for names/dimensions only
            self.cell = factory.create(module_type="bitcell")

            # Main array
            self.bitcell_array_inst=self.add_inst(name="bitcell_array",
                                                    mod=self.bitcell_array)
            self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies)

            # Replica columns
            self.replica_col_insts = []
            for port in self.all_ports:
                if port in self.rbls:
                    self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port),
                                                                mod=self.replica_columns[port]))
                    self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies)
                else:
                    self.replica_col_insts.append(None)
                    
            # Dummy rows under the bitcell array (connected with with the replica cell wl)
            self.dummy_row_replica_insts = []
            # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array!
            for port in self.all_ports:
                self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
                                                                    mod=self.dummy_row))
                self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies)

            # Top/bottom dummy rows or col caps
            self.dummy_row_insts = []
            self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot",
                                                      mod=self.col_cap))
            self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies)
            self.dummy_row_insts.append(self.add_inst(name="dummy_row_top",
                                                      mod=self.col_cap))
            self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies)

            # Left/right Dummy columns
            self.dummy_col_insts = []
            self.dummy_col_insts.append(self.add_inst(name="dummy_col_left",
                                                      mod=self.row_cap_left))
            self.connect_inst(self.replica_array_wordline_names + self.supplies)
            self.dummy_col_insts.append(self.add_inst(name="dummy_col_right",
                                                      mod=self.row_cap_right))
            self.connect_inst(self.replica_array_wordline_names + self.supplies)
        else:
            from tech import custom_replica_bitcell_array_arrangement
            custom_replica_bitcell_array_arrangement(self)
Beispiel #14
0
    def route_unused_wordlines(self):
        """ Connect the unused RBL and dummy wordlines to gnd """
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):
            # This grounds all the dummy row word lines
            for inst in self.dummy_row_insts:
                for wl_name in self.col_cap.get_wordline_names():
                    self.ground_pin(inst, wl_name)

            # Ground the unused replica wordlines
            for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
                for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
                    if wl_name in self.gnd_wordline_names:
                        self.ground_pin(inst, pin_name)
Beispiel #15
0
 def create_instances(self):
     """ Create the module instances used in this design """
     self.cell_inst = {}
     if not props.compare_ports(
             props.bitcell_array.use_custom_cell_arrangement):
         for col in range(self.column_size):
             for row in range(self.row_size):
                 name = "bit_r{0}_c{1}".format(row, col)
                 self.cell_inst[row, col] = self.add_inst(name=name,
                                                          mod=self.cell)
                 self.connect_inst(self.get_bitcell_pins(row, col))
     else:
         from tech import custom_cell_arrangement
         custom_cell_arrangement(self)
Beispiel #16
0
    def add_layout_pins(self):
        """ Add the layout pins """
        bitline_names = self.cell.get_all_bitline_names()
        for col in range(self.column_size):
            for port in self.all_ports:
                bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
                self.add_layout_pin(text="bl_{0}_{1}".format(port, col),
                                    layer=bl_pin.layer,
                                    offset=bl_pin.ll().scale(1, 0),
                                    width=bl_pin.width(),
                                    height=self.height)
                br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1])
                self.add_layout_pin(text="br_{0}_{1}".format(port, col),
                                    layer=br_pin.layer,
                                    offset=br_pin.ll().scale(1, 0),
                                    width=br_pin.width(),
                                    height=self.height)

        wl_names = self.cell.get_all_wl_names()
        for row in range(self.row_size):
            for port in self.all_ports:
                wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port])
                self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
                                    layer=wl_pin.layer,
                                    offset=wl_pin.ll().scale(0, 1),
                                    width=self.width,
                                    height=wl_pin.height())
                                    
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):

            # Copy a vdd/gnd layout pin from every cell
            for row in range(self.row_size):
                for col in range(self.column_size):
                    inst = self.cell_inst[row, col]
                    for pin_name in ["vdd", "gnd"]:
                        self.copy_layout_pin(inst, pin_name)
        else:


            # Copy a vdd/gnd layout pin from every cell
            for row in range(self.row_size):
                for col in range(self.column_size):
                    inst = self.cell_inst[row, col]
                    for pin_name in ["vpwr", "vgnd"]:

                        self.copy_layout_pin(inst, pin_name)
Beispiel #17
0
    def add_modules(self):
        """ Add the modules used in this design """
        if not props.compare_ports(
                props.bitcell_array.use_custom_cell_arrangement):
            self.cell = factory.create(module_type="bitcell")
            self.add_mod(self.cell)

        else:
            self.cell = factory.create(module_type="s8_bitcell",
                                       version="opt1")
            self.add_mod(self.cell)
            self.add_mod(
                factory.create(module_type="s8_bitcell", version="opt1a"))

            self.add_mod(
                factory.create(module_type="s8_internal", version="wlstrap"))
            self.add_mod(
                factory.create(module_type="s8_internal", version="wlstrap_p"))
Beispiel #18
0
    def create_instances(self):
        self.cell_inst = {}
        if not cell_properties.compare_ports(
                cell_properties.bitcell_array.use_custom_cell_arrangement):
            try:
                end_caps_enabled = cell_properties.bitcell.end_caps
            except AttributeError:
                end_caps_enabled = False

            for row in range(self.total_size):
                name = "rbc_{0}".format(row)
                # Top/bottom cell are always dummy cells.
                # Regular array cells are replica cells (>left_rbl and <rows-right_rbl)
                # Replic bit specifies which other bit (in the full range (0,rows) to make a replica cell.
                if (row > self.left_rbl
                        and row < self.total_size - self.right_rbl - 1):
                    self.cell_inst[row] = self.add_inst(name=name,
                                                        mod=self.replica_cell)
                    self.connect_inst(self.get_bitcell_pins(row, 0))
                elif row == self.replica_bit:
                    self.cell_inst[row] = self.add_inst(name=name,
                                                        mod=self.replica_cell)
                    self.connect_inst(self.get_bitcell_pins(row, 0))
                elif (row == 0 or row == self.total_size - 1):
                    self.cell_inst[row] = self.add_inst(name=name,
                                                        mod=self.edge_cell)
                    if end_caps_enabled:
                        self.connect_inst(self.get_bitcell_pins_col_cap(
                            row, 0))
                    else:
                        self.connect_inst(self.get_bitcell_pins(row, 0))
                else:
                    self.cell_inst[row] = self.add_inst(name=name,
                                                        mod=self.dummy_cell)
                    self.connect_inst(self.get_bitcell_pins(row, 0))
        else:
            from tech import custom_replica_column_arrangement
            custom_replica_column_arrangement(self)
Beispiel #19
0
    def place_instances(self):
        if not cell_properties.compare_ports(
                cell_properties.bitcell_array.use_custom_cell_arrangement):

            # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom
            # so that we will start with mirroring rather than not mirroring
            rbl_offset = (self.left_rbl + 1) % 2

            # if our bitcells are mirrored on the y axis, check if we are in global
            # column that needs to be flipped.
            dir_y = False
            xoffset = 0
            if cell_properties.bitcell.mirror.y and self.column_offset % 2:
                dir_y = True
                xoffset = self.replica_cell.width

            for row in range(self.total_size):
                # name = "bit_r{0}_{1}".format(row, "rbl")
                dir_x = cell_properties.bitcell.mirror.x and (row +
                                                              rbl_offset) % 2

                offset = vector(
                    xoffset, self.cell.height * (row + (row + rbl_offset) % 2))

                if dir_x and dir_y:
                    dir_key = "XY"
                elif dir_x:
                    dir_key = "MX"
                elif dir_y:
                    dir_key = "MY"
                else:
                    dir_key = ""

                self.cell_inst[row].place(offset=offset, mirror=dir_key)
        else:
            from tech import custom_replica_cell_placement
            custom_replica_cell_placement(self)
Beispiel #20
0
class bitcell(bitcell_base.bitcell_base):
    """
    A single bit cell (6T, 8T, etc.)  This module implements the
    single memory cell used in the design. It is a hand-made cell, so
    the layout and netlist should be available in the technology
    library.
    """

    # If we have a split WL bitcell, if not be backwards
    # compatible in the tech file

    if props.compare_ports(props.bitcell.split_wl):
        pin_names = ["bl", "br", "wl0", "wl1", "vdd", "gnd"]
        type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
    else:
        pin_names = [
            props.bitcell.cell_6t.pin.bl, props.bitcell.cell_6t.pin.br,
            props.bitcell.cell_6t.pin.wl, props.bitcell.cell_6t.pin.vdd,
            props.bitcell.cell_6t.pin.gnd
        ]
        type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
    storage_nets = ['Q', 'Q_bar']

    (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, name=""):
        # Ignore the name argument
        bitcell_base.bitcell_base.__init__(self, "cell_6t")
        debug.info(2, "Create bitcell")

        self.width = bitcell.width
        self.height = bitcell.height
        self.pin_map = bitcell.pin_map
        self.add_pin_types(self.type_list)
        self.nets_match = self.do_nets_exist(self.storage_nets)

        #debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells")

    def get_all_wl_names(self):
        """ Creates a list of all wordline pin names """
        if props.compare_ports(props.bitcell.split_wl):
            row_pins = ["wl0", "wl1"]
        else:
            row_pins = [props.bitcell.cell_6t.pin.wl]
        return row_pins

    def get_all_bitline_names(self):
        """ Creates a list of all bitline pin names (both bl and br) """
        pin = props.bitcell.cell_6t.pin
        column_pins = [pin.bl, pin.br]
        return column_pins

    def get_all_bl_names(self):
        """ Creates a list of all bl pins names """
        return [props.bitcell.cell_6t.pin.bl]

    def get_all_br_names(self):
        """ Creates a list of all br pins names """
        return [props.bitcell.cell_6t.pin.br]

    def get_bl_name(self, port=0):
        """Get bl name"""
        debug.check(port == 0, "One port for bitcell only.")
        return props.bitcell.cell_6t.pin.bl

    def get_br_name(self, port=0):
        """Get bl name"""
        debug.check(port == 0, "One port for bitcell only.")
        return props.bitcell.cell_6t.pin.br

    def get_wl_name(self, port=0):
        """Get wl name"""
        if props.compare_ports(props.bitcell.split_wl):
            return "wl{}".format(port)
        else:
            debug.check(port == 0, "One port for bitcell only.")
            return props.bitcell.cell_6t.pin.wl

    def build_graph(self, graph, inst_name, port_nets):
        """
        Adds edges based on inputs/outputs.
        Overrides base class function.
        """
        self.add_graph_edges(graph, port_nets)
Beispiel #21
0
    def add_modules(self):
        """  Array and dummy/replica columns

        d or D = dummy cell (caps to distinguish grouping)
        r or R = replica cell (caps to distinguish grouping)
        b or B = bitcell
         replica columns 1
         v              v
        bdDDDDDDDDDDDDDDdb <- Dummy row
        bdDDDDDDDDDDDDDDrb <- Dummy row
        br--------------rb
        br|   Array    |rb
        br| row x col  |rb
        br--------------rb
        brDDDDDDDDDDDDDDdb <- Dummy row
        bdDDDDDDDDDDDDDDdb <- Dummy row

          ^^^^^^^^^^^^^^^
          dummy rows cols x 1

        ^ dummy columns  ^
          1 x (rows + 4)
        """
        # Bitcell array
        self.bitcell_array = factory.create(module_type="bitcell_array",
                                            column_offset=1 + len(self.left_rbl),
                                            cols=self.column_size,
                                            rows=self.row_size)
        self.add_mod(self.bitcell_array)

        # Replica bitlines
        self.replica_columns = {}
        
        for port in self.all_ports:
            if port in self.left_rbl:
                # We will always have self.rbl[0] rows of replica wordlines below
                # the array.
                # These go from the top (where the bitcell array starts ) down
                replica_bit = self.rbl[0] - port
            elif port in self.right_rbl:
                
                # We will always have self.rbl[0] rows of replica wordlines below
                # the array.
                # These go from the bottom up
                replica_bit = self.rbl[0] + self.row_size + port
            else:
                continue
            
            # If we have an odd numer on the bottom
            column_offset = self.rbl[0] + 1
                
            self.replica_columns[port] = factory.create(module_type="replica_column",
                                                        rows=self.row_size,
                                                        rbl=self.rbl,
                                                        column_offset=column_offset,
                                                        replica_bit=replica_bit)
            self.add_mod(self.replica_columns[port])
        try:
            end_caps_enabled = cell_properties.bitcell.end_caps
        except AttributeError:
            end_caps_enabled = False

        # Dummy row
        self.dummy_row = factory.create(module_type="dummy_array",
                                            cols=self.column_size,
                                            rows=1,
                                            # dummy column + left replica column
                                            column_offset=1 + len(self.left_rbl),
                                            mirror=0)
        self.add_mod(self.dummy_row)
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):

            # Dummy Row or Col Cap, depending on bitcell array properties
            col_cap_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array")
            self.col_cap = factory.create(module_type=col_cap_module_type,
                                          cols=self.column_size,
                                          rows=1,
                                          # dummy column + left replica column
                                          column_offset=1 + len(self.left_rbl),
                                          mirror=0)
            self.add_mod(self.col_cap)

            # Dummy Col or Row Cap, depending on bitcell array properties
            row_cap_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array")

            self.row_cap_left = factory.create(module_type=row_cap_module_type,
                                                cols=1,
                                                column_offset=0,
                                                rows=self.row_size + self.extra_rows,
                                                mirror=(self.rbl[0] + 1) % 2)
            self.add_mod(self.row_cap_left)

            self.row_cap_right = factory.create(module_type=row_cap_module_type,
                                                cols=1,
                                                #   dummy column
                                                # + left replica column(s)
                                                # + bitcell columns
                                                # + right replica column(s)
                                                column_offset = 1 + len(self.left_rbl) + self.column_size + self.rbl[0],
                                                rows=self.row_size + self.extra_rows,
                                                mirror=(self.rbl[0] + 1) %2)
            self.add_mod(self.row_cap_right)
        else:
            # Dummy Row or Col Cap, depending on bitcell array properties
            col_cap_module_type = ("s8_col_cap_array" if end_caps_enabled else "dummy_array")
            self.col_cap_top = factory.create(module_type=col_cap_module_type,
                                        cols=self.column_size,
                                        rows=1,
                                        # dummy column + left replica column(s)
                                        column_offset=1 + len(self.left_rbl),
                                        mirror=0,
                                        location="top")
            self.add_mod(self.col_cap_top)

            self.col_cap_bottom = factory.create(module_type=col_cap_module_type,
                                                 cols=self.column_size,
                                                 rows=1,
                                                 # dummy column + left replica column(s)
                                                 column_offset=1 + len(self.left_rbl),
                                                 mirror=0,
                                                 location="bottom")
            self.add_mod(self.col_cap_bottom)
            # Dummy Col or Row Cap, depending on bitcell array properties
            row_cap_module_type = ("s8_row_cap_array" if end_caps_enabled else "dummy_array")

            self.row_cap_left = factory.create(module_type=row_cap_module_type,
                                                cols=1,
                                                column_offset=0,
                                                rows=self.row_size + self.extra_rows,
                                                mirror=0)
            self.add_mod(self.row_cap_left)

            self.row_cap_right = factory.create(module_type=row_cap_module_type,
                                                cols=1,
                                                #   dummy column
                                                # + left replica column(s)
                                                # + bitcell columns
                                                # + right replica column(s)
                                                column_offset = 1 + len(self.left_rbl) + self.column_size + self.rbl[0],
                                                rows=self.row_size + self.extra_rows,
                                                mirror=0)
            self.add_mod(self.row_cap_right)
Beispiel #22
0
    def add_layout_pins(self):
        """ Add the layout pins """
        
        #All wordlines
        #Main array wl and bl/br
        if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement):

            for pin_name in self.all_wordline_names:
                pin_list = self.bitcell_array_inst.get_pins(pin_name)
                for pin in pin_list:
                    self.add_layout_pin(text=pin_name,
                                        layer=pin.layer,
                                        offset=pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=pin.height())
            # Replica wordlines (go by the row instead of replica column because we may have to add a pin
            # even though the column is in another local bitcell array)
            for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
                for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
                    if wl_name in self.gnd_wordline_names:
                        continue
                    pin = inst.get_pin(pin_name)
                    self.add_layout_pin(text=wl_name,
                                        layer=pin.layer,
                                        offset=pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=pin.height())
        else:
            for pin_name in self.all_wordline_names:
                pin_list = self.dummy_col_insts[0].get_pins(pin_name)
                for pin in pin_list:
                    self.add_layout_pin(text=pin_name,
                                        layer=pin.layer,
                                        offset=pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=pin.height())
            # Replica wordlines (go by the row instead of replica column because we may have to add a pin
            # even though the column is in another local bitcell array)
            for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
                for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
                    if wl_name in self.gnd_wordline_names:
                        continue
                    pin = inst.get_pin(pin_name)
                    self.add_layout_pin(text=wl_name,
                                        layer=pin.layer,
                                        offset=pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=pin.height())
                                        
        for pin_name in self.all_bitline_names:
            pin_list = self.bitcell_array_inst.get_pins(pin_name)
            for pin in pin_list:
                self.add_layout_pin(text=pin_name,
                                    layer=pin.layer,
                                    offset=pin.ll().scale(1, 0),
                                    width=pin.width(),
                                    height=self.height)

        # Replica bitlines
        if len(self.rbls) > 0:
            for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts):
                pin_names = self.replica_columns[self.rbls[0]].all_bitline_names
                for (bl_name, pin_name) in zip(names, pin_names):
                    pin = inst.get_pin(pin_name)
                    self.add_layout_pin(text=bl_name,
                                        layer=pin.layer,
                                        offset=pin.ll().scale(1, 0),
                                        width=pin.width(),
                                        height=self.height)

        # vdd/gnd are only connected in the perimeter cells
        # replica column should only have a vdd/gnd in the dummy cell on top/bottom
        supply_insts = self.dummy_col_insts + self.dummy_row_insts
        
        for pin_name in  self.supplies:
            for inst in supply_insts:
                pin_list = inst.get_pins(pin_name)
                for pin in pin_list:
                    self.add_power_pin(name=pin_name,
                                       loc=pin.center(),
                                       start_layer=pin.layer)

            for inst in self.replica_col_insts:
                if inst:
                    self.copy_layout_pin(inst, pin_name)
Beispiel #23
0
    def add_layout_pins(self):
        """ Add the layout pins """
        if not cell_properties.compare_ports(
                cell_properties.bitcell_array.use_custom_cell_arrangement):
            for port in self.all_ports:
                bl_pin = self.cell_inst[0].get_pin(self.cell.get_bl_name(port))
                self.add_layout_pin(text="bl_{0}_{1}".format(port, 0),
                                    layer=bl_pin.layer,
                                    offset=bl_pin.ll().scale(1, 0),
                                    width=bl_pin.width(),
                                    height=self.height)
                bl_pin = self.cell_inst[0].get_pin(self.cell.get_br_name(port))
                self.add_layout_pin(text="br_{0}_{1}".format(port, 0),
                                    layer=bl_pin.layer,
                                    offset=bl_pin.ll().scale(1, 0),
                                    width=bl_pin.width(),
                                    height=self.height)

            try:
                end_caps_enabled = cell_properties.bitcell.end_caps
            except AttributeError:
                end_caps_enabled = False

            if end_caps_enabled:
                row_range_max = self.total_size - 1
                row_range_min = 1
            else:
                row_range_max = self.total_size
                row_range_min = 0

            for port in self.all_ports:
                for row in range(row_range_min, row_range_max):
                    wl_pin = self.cell_inst[row].get_pin(
                        self.cell.get_wl_name(port))
                    self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
                                        layer=wl_pin.layer,
                                        offset=wl_pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=wl_pin.height())

            # Supplies are only connected in the ends
            for (index, inst) in self.cell_inst.items():
                for pin_name in ["vdd", "gnd"]:
                    if inst in [
                            self.cell_inst[0],
                            self.cell_inst[self.total_size - 1]
                    ]:
                        self.copy_power_pins(inst, pin_name)
                    else:
                        self.copy_layout_pin(inst, pin_name)
        else:
            for port in self.all_ports:
                bl_pin = self.cell_inst[2].get_pin(self.cell.get_bl_name(port))
                self.add_layout_pin(text="bl_{0}_{1}".format(port, 0),
                                    layer=bl_pin.layer,
                                    offset=bl_pin.ll().scale(1, 0),
                                    width=bl_pin.width(),
                                    height=self.height)
                bl_pin = self.cell_inst[2].get_pin(self.cell.get_br_name(port))
                self.add_layout_pin(text="br_{0}_{1}".format(port, 0),
                                    layer=bl_pin.layer,
                                    offset=bl_pin.ll().scale(1, 0),
                                    width=bl_pin.width(),
                                    height=self.height)

            row_range_max = self.total_size - 1
            row_range_min = 1

            for port in self.all_ports:
                for row in range(row_range_min, row_range_max):
                    wl_pin = self.cell_inst[row].get_pin(
                        self.cell.get_wl_name(port))
                    self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
                                        layer=wl_pin.layer,
                                        offset=wl_pin.ll().scale(0, 1),
                                        width=self.width,
                                        height=wl_pin.height())

            # Supplies are only connected in the ends
            for (index, inst) in self.cell_inst.items():
                for pin_name in ["vpwr", "vgnd"]:
                    if inst in [
                            self.cell_inst[0],
                            self.cell_inst[self.total_size - 1]
                    ]:
                        self.copy_power_pins(inst, pin_name)
                    else:
                        self.copy_layout_pin(inst, pin_name)
Beispiel #24
0
class replica_bitcell(design.design):
    """
    A single bit cell (6T, 8T, etc.)
    This module implements the single memory cell used in the design. It
    is a hand-made cell, so the layout and netlist should be available in
    the technology library. """

    if props.compare_ports(props.bitcell.split_wl):
        pin_names = ["bl", "br", "wl0", "wl1", "vdd", "gnd"]
        type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
    else:
        pin_names = [
            props.bitcell.cell_6t.pin.bl, props.bitcell.cell_6t.pin.br,
            props.bitcell.cell_6t.pin.wl, props.bitcell.cell_6t.pin.vdd,
            props.bitcell.cell_6t.pin.gnd
        ]

        type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]

    def __init__(self, version, name=""):
        # Ignore the name argument

        if version == "opt1":
            self.name = "s8sram_cell_opt1"
            self.border_structure = "s8sram_cell"
        elif version == "opt1a":
            self.name = "s8sram_cell_opt1a"
            self.border_structure = "s8sram_cell"

        self.pin_map = utils.get_libcell_pins(self.pin_names, self.name,
                                              GDS["unit"])
        design.design.__init__(self, "replica_cell_6t")
        debug.info(2, "Create replica bitcell object")

        self.pin_map = utils.get_libcell_pins(self.pin_names, self.name,
                                              GDS["unit"])

        self.add_pin_types(self.type_list)

        (self.width,
         self.height) = utils.get_libcell_size(self.name, GDS["unit"],
                                               layer["mem"])

    def get_stage_effort(self, load):
        parasitic_delay = 1
        size = 0.5  #This accounts for bitline being drained thought the access TX and internal node
        cin = 3  #Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
        read_port_load = 0.5  #min size NMOS gate load
        return logical_effort.logical_effort('bitline', size, cin,
                                             load + read_port_load,
                                             parasitic_delay, False)

    def input_load(self):
        """Return the relative capacitance of the access transistor gates"""

        # FIXME: This applies to bitline capacitances as well.
        access_tx_cin = parameter["6T_access_size"] / drc["minwidth_tx"]
        return 2 * access_tx_cin

    def analytical_power(self, corner, load):
        """Bitcell power in nW. Only characterizes leakage."""
        from tech import spice
        leakage = spice["bitcell_leakage"]
        dynamic = 0  #temporary
        total_power = self.return_power(dynamic, leakage)
        return total_power

    def build_graph(self, graph, inst_name, port_nets):
        """Adds edges based on inputs/outputs. Overrides base class function."""
        self.add_graph_edges(graph, port_nets)