Exemplo n.º 1
0
    def place_instances(self):
        """
        Compute the offsets and place the instances.
        """

        row_decoder_offset = vector(0, 0)
        self.row_decoder_inst.place(row_decoder_offset)

        wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
        self.wordline_driver_array_inst.place(wordline_driver_array_offset)

        # The wordline driver also had an extra gap on the right, so use this offset
        well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
        x_offset = self.wordline_driver_array_inst.rx(
        ) - well_gap - self.rbl_driver.width

        if self.port == 0:
            rbl_driver_offset = vector(x_offset, 0)
            self.rbl_driver_inst.place(rbl_driver_offset, "MX")
        else:
            rbl_driver_offset = vector(x_offset,
                                       self.wordline_driver_array.height)
            self.rbl_driver_inst.place(rbl_driver_offset)

        # Pass this up
        self.predecoder_height = self.row_decoder.predecoder_height

        self.height = self.row_decoder.height
        self.width = self.wordline_driver_array_inst.rx()
Exemplo n.º 2
0
    def setup_layout_constants(self):
        """ Pre-compute some handy layout parameters. """

        # metal spacing to allow contacts on any layer
        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
        self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin(
            "S").ll()

        # Two PMOS devices and a well contact. Separation between each.
        # Enclosure space on the sides.
        self.well_width = 2 * self.pmos.active_width \
                          + self.pmos.active_contact.width \
                          + 2 * drc("active_to_body_active") \
                          + 2 * drc("well_enclosure_active")

        self.width = self.well_width
        # Height is an input parameter, so it is not recomputed.

        # This is the extra space needed to ensure DRC rules
        # to the active contacts
        extra_contact_space = max(-self.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,
            drc("poly_extend_active"), self.poly_space)
Exemplo n.º 3
0
    def setup_layers(self):

        (horiz_layer, via_layer, vert_layer) = self.layer_stack
        self.via_layer_name = via_layer

        self.vert_layer_name = vert_layer
        self.vert_layer_width = drc("minwidth_{0}".format(vert_layer))

        self.horiz_layer_name = horiz_layer
        self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer))
        via_connect = factory.create(module_type="contact",
                                     layer_stack=self.layer_stack,
                                     dimensions=(1, 1))

        # This is used for short connections to avoid via-to-via spacing errors
        self.vert_layer_contact_width = max(via_connect.second_layer_width,
                                            via_connect.first_layer_width)
        self.horiz_layer_contact_width = max(via_connect.second_layer_height,
                                             via_connect.first_layer_height)

        self.node_to_node = [
            drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
            drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height
        ]
        self.pitch = self.compute_pitch(self.layer_stack)
Exemplo n.º 4
0
 def analytical_delay(self, corner, slew, load):
     #Delay of the sense amp will depend on the size of the amp and the output load.
     parasitic_delay = 1
     cin = (parameter["sa_inv_pmos_size"] + parameter["sa_inv_nmos_size"])/drc("minwidth_tx")
     sa_size = parameter["sa_inv_nmos_size"]/drc("minwidth_tx")
     cc_inv_cin = cin
     return logical_effort.logical_effort('column_mux', sa_size, cin, load+cc_inv_cin, parasitic_delay, False)
Exemplo n.º 5
0
    def create_implant_well_enclosures(self):
        implant_position = self.first_layer_position - [
            drc("implant_enclose_active")
        ] * 2
        implant_width = self.first_layer_width + 2 * drc(
            "implant_enclose_active")
        implant_height = self.first_layer_height + 2 * drc(
            "implant_enclose_active")
        self.add_rect(layer="{}implant".format(self.implant_type),
                      offset=implant_position,
                      width=implant_width,
                      height=implant_height)

        # Optionally implant well if layer exists
        well_layer = "{}well".format(self.well_type)
        if well_layer in tech.layer:
            well_width_rule = drc("minwidth_" + well_layer)
            self.well_enclose_active = drc(well_layer + "_enclose_active")
            self.well_width = max(
                self.first_layer_width + 2 * self.well_enclose_active,
                well_width_rule)
            self.well_height = max(
                self.first_layer_height + 2 * self.well_enclose_active,
                well_width_rule)
            center_pos = vector(0.5 * self.width, 0.5 * self.height)
            well_position = center_pos - vector(0.5 * self.well_width,
                                                0.5 * self.well_height)
            self.add_rect(layer=well_layer,
                          offset=well_position,
                          width=self.well_width,
                          height=self.well_height)
Exemplo n.º 6
0
    def extend_wells(self, middle_position):
        """ Extend the n/p wells to cover whole cell """

        # Add a rail width to extend the well to the top of the rail
        max_y_offset = self.height + 0.5 * self.m1_width
        self.nwell_position = middle_position
        nwell_height = max_y_offset - middle_position.y
        if drc("has_nwell"):
            self.add_rect(layer="nwell",
                          offset=middle_position,
                          width=self.well_width,
                          height=nwell_height)
        self.add_rect(layer="vtg",
                      offset=self.nwell_position,
                      width=self.well_width,
                      height=nwell_height)

        pwell_position = vector(0, -0.5 * self.m1_width)
        pwell_height = middle_position.y - pwell_position.y
        if drc("has_pwell"):
            self.add_rect(layer="pwell",
                          offset=pwell_position,
                          width=self.well_width,
                          height=pwell_height)
        self.add_rect(layer="vtg",
                      offset=pwell_position,
                      width=self.well_width,
                      height=pwell_height)
Exemplo n.º 7
0
    def precompute_constants(self):
        """  Get some preliminary data ready """

        # The central bus is the column address (one hot) and row address (binary)
        if self.col_addr_size > 0:
            self.num_col_addr_lines = 2**self.col_addr_size
        else:
            self.num_col_addr_lines = 0

        # A space for wells or jogging m2 between modules
        self.m2_gap = max(
            2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
            3 * self.m2_pitch)

        # create arrays of bitline and bitline_bar names for read, write, or all ports
        self.bitcell = factory.create(module_type="bitcell")
        self.bl_names = self.bitcell.get_all_bl_names()
        self.br_names = self.bitcell.get_all_br_names()
        self.wl_names = self.bitcell.get_all_wl_names()
        # used for bl/br names
        self.precharge = factory.create(module_type="precharge",
                                        bitcell_bl=self.bl_names[0],
                                        bitcell_br=self.br_names[0])
        # We create a dummy here to get bl/br names to add those pins to this
        # module, which happens before we create the real precharge_array
        self.precharge_array = factory.create(
            module_type="precharge_array",
            columns=self.num_cols + 1,
            bitcell_bl=self.bl_names[self.port],
            bitcell_br=self.br_names[self.port])
Exemplo n.º 8
0
    def add_layout_pins(self):

        self.add_layout_pin(text="en_bar",
                            layer="metal1",
                            offset=self.pc_cell.get_pin("en_bar").ll(),
                            width=self.width,
                            height=drc("minwidth_metal1"))

        for inst in self.local_insts:
            self.copy_layout_pin(inst, "vdd")
            
        for i in range(len(self.local_insts)):
            inst = self.local_insts[i]
            bl_pin = inst.get_pin("bl")
            self.add_layout_pin(text="bl_{0}".format(i),
                                layer="metal2",
                                offset=bl_pin.ll(),
                                width=drc("minwidth_metal2"),
                                height=bl_pin.height())
            br_pin = inst.get_pin("br") 
            self.add_layout_pin(text="br_{0}".format(i),
                                layer="metal2",
                                offset=br_pin.ll(),
                                width=drc("minwidth_metal2"),
                                height=bl_pin.height())
Exemplo n.º 9
0
    def setup_layout_constants(self):
        """ Pre-compute some handy layout parameters. """

        # Compute the overlap of the source and drain pins
        self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin(
            "S").ll()

        # Two PMOS devices and a well contact. Separation between each.
        # Enclosure space on the sides.
        self.well_width = 3*self.pmos.active_width + self.pmos.active_contact.width \
                          + 2*drc("active_to_body_active") + 2*drc("well_enclosure_active") \
                          - self.overlap_offset.x
        self.width = self.well_width
        # Height is an input parameter, so it is not recomputed.

        # This will help with the wells and the input/output placement
        self.output_pos = vector(0, 0.5 * self.height)

        # This is the extra space needed to ensure DRC rules to the active contacts
        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,
            drc("poly_extend_active"), self.poly_space)
Exemplo n.º 10
0
    def scaled_bins(tx_type, target_width):
        """
        Determine a set of widths and multiples that could be close to the right size
        sorted by the fewest number of fingers.
        """
        if tx_type == "nmos":
            bins = nmos_bins[drc("minwidth_poly")]
        elif tx_type == "pmos":
            bins = pmos_bins[drc("minwidth_poly")]
        else:
            debug.error("invalid tx type")

        # Prune out bins that are too big, except for one bigger
        bins = bins[0:bisect_left(bins, target_width) + 1]

        # Determine multiple of target width for each bin
        if len(bins) == 1:
            scaled_bins = [(bins[0], math.ceil(target_width / bins[0]))]
        else:
            scaled_bins = []
            # Add the biggest size as 1x multiple
            scaled_bins.append((bins[-1], 1))
            # Compute discrete multiple of other sizes
            for width in reversed(bins[:-1]):
                multiple = math.ceil(target_width / width)
                scaled_bins.append((multiple * width, multiple))

        return (scaled_bins)
Exemplo n.º 11
0
 def calculate_module_offsets(self):
     
     self.xoffset_nand = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
     self.xoffset_nor = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
     self.xoffset_bank_sel_inv = 0
     self.xoffset_inputs = 0
     self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
Exemplo n.º 12
0
    def __init__(self, name, size=1, height=None, add_wells=True):
        """ Creates a cell for a simple 3 input nand """

        debug.info(2,
                   "creating pnand4 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.
        self.size = size
        self.nmos_size = 2 * size
        self.pmos_size = parameter["beta"] * size
        self.nmos_width = self.nmos_size * drc("minwidth_tx")
        self.pmos_width = self.pmos_size * drc("minwidth_tx")

        # FIXME: Allow these to be sized
        debug.check(size == 1,
                    "Size 1 pnand4 is only supported now.")
        self.tx_mults = 1

        if OPTS.tech_name == "sky130":
            self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
            self.pmos_width = self.nearest_bin("pmos", self.pmos_width)

        # Creates the netlist and layout
        super().__init__(name, height, add_wells)
Exemplo n.º 13
0
    def __init__(self, name="nand4_dec", height=None):
        super().__init__(name, prop=props.nand4_dec)

        # FIXME: For now...
        size = 1
        self.size = size
        self.nmos_size = 2 * size
        self.pmos_size = parameter["beta"] * size
        self.nmos_width = self.nmos_size * drc("minwidth_tx")
        self.pmos_width = self.pmos_size * drc("minwidth_tx")
Exemplo n.º 14
0
    def setup_layout_constants(self):
        """
        Pre-compute some handy layout parameters.
        """

        # the well width is determined the multi-finger PMOS device width plus
        # the well contact width and half well enclosure on both sides
        self.well_width = self.pmos.active_width + self.pmos.active_contact.width \
                          + drc("active_to_body_active") + 2*drc("well_enclosure_active")
        self.width = self.well_width
Exemplo n.º 15
0
    def calculate_module_offsets(self):
        
        self.xoffset_nand =  self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
        self.xoffset_nor =  self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
        self.xoffset_inv = max(self.xoffset_nand + self.nand2.width, self.xoffset_nor + self.nor2.width) 
        self.xoffset_bank_sel_inv = 0 
        self.xoffset_inputs = 0

        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
Exemplo n.º 16
0
    def create_netlist(self):
        self.add_pin_list(["D", "G", "S", "B"])

        # self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
        #                                              " ".join(self.pins)))
        # Just make a guess since these will actually be decided in the layout later.
        area_sd = 2.5 * drc("minwidth_poly") * self.tx_width
        perimeter_sd = 2 * drc("minwidth_poly") + 2 * self.tx_width
        self.spice_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u pd={4:.2f}u ps={4:.2f}u as={5:.2f}p ad={5:.2f}p".format(
            spice[self.tx_type], self.mults, self.tx_width,
            drc("minwidth_poly"), perimeter_sd, area_sd)
        self.spice.append("\n* ptx " + self.spice_device)
Exemplo n.º 17
0
    def create_netlist(self):
        pin_list = ["D", "G", "S", "B"]
        if self.tx_type == "nmos":
            body_dir = "GROUND"
        else:
            body_dir = "POWER"
        dir_list = ["INOUT", "INPUT", "INOUT", body_dir]
        self.add_pin_list(pin_list, dir_list)

        # Just make a guess since these will actually
        # be decided in the layout later.
        area_sd = 2.5 * self.poly_width * self.tx_width
        perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
        if cell_props.ptx.model_is_subckt:
            # sky130
            main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(
                spice[self.tx_type], self.mults, self.tx_width,
                drc("minwidth_poly"))
            # Perimeters are in microns
            # Area is in u since it is microns square
            area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(
                perimeter_sd, area_sd)
        else:
            main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(
                spice[self.tx_type], self.mults, self.tx_width,
                drc("minwidth_poly"))
            area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(
                perimeter_sd, area_sd)
        self.spice_device = main_str + area_str
        self.spice.append("\n* spice ptx " + self.spice_device)

        if cell_props.ptx.model_is_subckt and OPTS.lvs_exe and OPTS.lvs_exe[
                0] == "calibre":
            # sky130 requires mult parameter too. It is not the same as m, but I don't understand it.
            # self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2} l={3} mult=1".format(spice[self.tx_type],
            #                                                                        self.mults,
            #                                                                        self.tx_width,
            #                                                                        drc("minwidth_poly"))
            # TEMP FIX: Use old device names if using Calibre.

            self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult=1".format(
                "nshort" if self.tx_type == "nmos" else "pshort", self.mults,
                self.tx_width, drc("minwidth_poly"))
        elif cell_props.ptx.model_is_subckt:
            # sky130 requires mult parameter too
            self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(
                spice[self.tx_type], self.mults, self.tx_width,
                drc("minwidth_poly"))
        else:
            self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(
                spice[self.tx_type], self.mults, self.tx_width,
                drc("minwidth_poly"))
Exemplo n.º 18
0
    def determine_tx_mults(self):
        """
        Determines the number of fingers needed to achieve the size within
        the height constraint. This may fail if the user has a tight height.
        """

        # This is always 1 tx, because we have horizontal transistors.
        self.tx_mults = 1
        self.nmos_width = self.nmos_size * drc("minwidth_tx")
        self.pmos_width = self.pmos_size * drc("minwidth_tx")
        if cell_props.ptx.bin_spice_models:
            self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
            self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
Exemplo n.º 19
0
    def setup_layers(self):
        (horiz_layer, via_layer, vert_layer) = self.layer_stack
        self.via_layer_name = via_layer

        self.vert_layer_name = vert_layer
        self.vert_layer_width = drc("minwidth_{0}".format(vert_layer))

        self.horiz_layer_name = horiz_layer
        self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer))
        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]
Exemplo n.º 20
0
    def __init__(self, name="nand3_dec", height=None):
        design.design.__init__(self, name)

        self.width = nand3_dec.width
        self.height = nand3_dec.height
        self.pin_map = nand3_dec.pin_map
        self.add_pin_types(self.type_list)

        # FIXME: For now...
        size = 1
        self.size = size
        self.nmos_size = 2 * size
        self.pmos_size = parameter["beta"] * size
        self.nmos_width = self.nmos_size * drc("minwidth_tx")
        self.pmos_width = self.pmos_size * drc("minwidth_tx")
Exemplo n.º 21
0
    def determine_tx_mults(self):
        """
        Determines the number of fingers needed to achieve the size within
        the height constraint. This may fail if the user has a tight height.
        """

        # This is always 1 tx, because we have horizontal transistors.
        self.tx_mults = 1
        self.nmos_width = self.nmos_size * drc("minwidth_tx")
        self.pmos_width = self.pmos_size * drc("minwidth_tx")
        if OPTS.tech_name == "sky130":
            (self.nmos_width,
             self.tx_mults) = self.bin_width("nmos", self.nmos_width)
            (self.pmos_width,
             self.tx_mults) = self.bin_width("pmos", self.pmos_width)
            return
Exemplo n.º 22
0
    def route_inputs(self):
        """ Route the A and B inputs """
        # wire space or wire and one contact space
        metal_spacing = max(
            self.m1_space + self.m1_width, self.m2_space + self.m2_width,
            self.m1_space + 0.5 * contact.poly.width + 0.5 * self.m1_width)

        active_spacing = max(
            self.m1_space,
            0.5 * contact.poly.first_layer_width + drc("poly_to_active"))
        inputC_yoffset = self.nmos3_pos.y + self.nmos.active_height + active_spacing
        self.route_input_gate(self.pmos3_inst,
                              self.nmos3_inst,
                              inputC_yoffset,
                              "C",
                              position="center")

        inputB_yoffset = inputC_yoffset + metal_spacing
        self.route_input_gate(self.pmos2_inst,
                              self.nmos2_inst,
                              inputB_yoffset,
                              "B",
                              position="center")

        self.inputA_yoffset = inputB_yoffset + metal_spacing
        self.route_input_gate(self.pmos1_inst,
                              self.nmos1_inst,
                              self.inputA_yoffset,
                              "A",
                              position="center")
Exemplo n.º 23
0
    def place_ptx(self):
        """
        """
        # center the transistors in the y-dimension (it is rotated, so use the width)
        y_offset = 0.5 * (self.height - self.nmos.width) + self.nmos.width

        if OPTS.tech_name == "sky130":
            # make room for well contacts between cells
            y_offset = (0.5 * (self.height - self.nmos.width) +
                        self.nmos.width) * 0.9

        # offset so that the input contact is over from the left edge by poly spacing
        x_offset = self.nmos.active_offset.y + contact.poly_contact.width + self.poly_space
        self.nmos_pos = vector(x_offset, y_offset)
        self.nmos_inst.place(self.nmos_pos, rotate=270)
        # place PMOS so it is half a poly spacing down from the top
        well_offsets = 2 * self.poly_extend_active + 2 * self.well_extend_active + drc(
            "pwell_to_nwell")
        # This is to provide spacing for the vdd rails
        metal_offsets = 2 * self.m3_pitch
        xoffset = self.nmos_inst.rx() + max(well_offsets, metal_offsets)
        self.pmos_pos = vector(xoffset, y_offset)
        self.pmos_inst.place(self.pmos_pos, rotate=270)

        # Output position will be in between the PMOS and NMOS drains
        pmos_drain_pos = self.pmos_inst.get_pin("D").center()
        nmos_drain_pos = self.nmos_inst.get_pin("D").center()
        self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x),
                                 nmos_drain_pos.y)

        if cell_props.pgate.add_implants:
            self.extend_implants()
Exemplo n.º 24
0
    def route_inputs(self):
        """ Route the A and B inputs """

        # Top of NMOS drain
        nmos_pin = self.nmos2_inst.get_pin("D")
        bottom_pin_offset = nmos_pin.uy()
        self.inputB_yoffset = bottom_pin_offset + self.m1_nonpref_pitch
        self.inputA_yoffset = self.inputB_yoffset + self.m1_nonpref_pitch

        bpin = self.route_input_gate(self.pmos2_inst,
                                     self.nmos2_inst,
                                     self.inputB_yoffset,
                                     "B",
                                     position="right",
                                     directions=("V", "V"))

        # This will help with the wells and the input/output placement
        apin = self.route_input_gate(self.pmos1_inst,
                                     self.nmos1_inst,
                                     self.inputA_yoffset,
                                     "A",
                                     directions=("V", "V"))

        self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch

        if cell_props.pgate.add_implants:
            self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
Exemplo n.º 25
0
    def add_pwell_contact(self, nmos, nmos_pos):
        """ Add an pwell contact next to the given nmos device. """

        layer_stack = ("active", "contact", "metal1")

        pwell_position = vector(0, -0.5 * self.m1_width)

        # To the right a spacing away from the nmos right active edge
        contact_xoffset = nmos_pos.x + nmos.active_width \
                          + drc("active_to_body_active")
        # Must be at least an well enclosure of active up
        # from the bottom of the well
        contact_yoffset = max(nmos_pos.y,
                              self.well_enclose_active \
                              - nmos.active_contact.first_layer_height / 2)
        contact_offset = vector(contact_xoffset, contact_yoffset)

        # Offset by half a contact
        contact_offset += vector(0.5 * nmos.active_contact.first_layer_width,
                                 0.5 * nmos.active_contact.first_layer_height)
        self.pwell_contact = self.add_via_center(layers=layer_stack,
                                                 offset=contact_offset,
                                                 directions=("H", "V"),
                                                 implant_type="p",
                                                 well_type="p")
        self.add_rect_center(layer="metal1",
                             offset=contact_offset.scale(1, 0.5),
                             width=self.pwell_contact.mod.second_layer_width,
                             height=contact_offset.y)
Exemplo n.º 26
0
    def add_nwell_contact(self, pmos, pmos_pos):
        """ Add an nwell contact next to the given pmos device. """

        layer_stack = ("active", "contact", "metal1")

        # To the right a spacing away from the pmos right active edge
        contact_xoffset = pmos_pos.x + pmos.active_width \
                          + drc("active_to_body_active")

        # Must be at least an well enclosure of active down
        # from the top of the well
        # OR align the active with the top of PMOS active.
        max_y_offset = self.height + 0.5 * self.m1_width
        contact_yoffset = min(
            pmos_pos.y + pmos.active_height -
            pmos.active_contact.first_layer_height,
            max_y_offset - pmos.active_contact.first_layer_height / 2 -
            self.well_enclose_active)
        contact_offset = vector(contact_xoffset, contact_yoffset)
        # Offset by half a contact in x and y
        contact_offset += vector(0.5 * pmos.active_contact.first_layer_width,
                                 0.5 * pmos.active_contact.first_layer_height)
        self.nwell_contact = self.add_via_center(layers=layer_stack,
                                                 offset=contact_offset,
                                                 directions=("H", "V"),
                                                 implant_type="n",
                                                 well_type="n")
        self.add_rect_center(layer="metal1",
                             offset=contact_offset +
                             vector(0, 0.5 * (self.height - contact_offset.y)),
                             width=self.nwell_contact.mod.second_layer_width,
                             height=self.height - contact_offset.y)
Exemplo n.º 27
0
    def create_layout(self):

        # We increase it by a well enclosure so the precharges don't overlap our wells
        self.height = self.row_size * self.cell.height + drc(
            "well_enclosure_active") + self.m1_width
        self.width = self.column_size * self.cell.width + self.m1_width

        xoffset = 0.0
        for col in range(self.column_size):
            yoffset = 0.0
            for row in range(self.row_size):
                name = "bit_r{0}_c{1}".format(row, col)

                if row % 2:
                    tempy = yoffset + self.cell.height
                    dir_key = "MX"
                else:
                    tempy = yoffset
                    dir_key = ""

                self.cell_inst[row, col].place(offset=[xoffset, tempy],
                                               mirror=dir_key)
                yoffset += self.cell.height
            xoffset += self.cell.width

        self.add_layout_pins()

        self.DRC_LVS()
Exemplo n.º 28
0
    def route_vdd_rail(self):
        """
        Adds a vdd rail at the top of the cell
        """

        # Adds the rail across the width of the cell
        vdd_position = vector(0.5 * self.width, self.height)
        layer_width = drc("minwidth_" + self.en_layer)
        self.add_rect_center(layer=self.en_layer,
                             offset=vdd_position,
                             width=self.width,
                             height=layer_width)

        pmos_pin = self.upper_pmos2_inst.get_pin("S")

        # center of vdd rail
        pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y)
        self.add_path(self.en_layer, [pmos_pin.center(), pmos_vdd_pos])

        self.add_power_pin("vdd", self.well_contact_pos, directions=("V", "V"))

        self.add_via_stack_center(from_layer=pmos_pin.layer,
                                  to_layer=self.en_layer,
                                  offset=pmos_pin.center(),
                                  directions=("V", "V"))
Exemplo n.º 29
0
    def add_modules(self):
        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 = factory.create(module_type="ptx", width=self.ptx_width)
        self.add_mod(self.nmos)
Exemplo n.º 30
0
    def input_load(self):
        """
        Returns the relative gate cin of the tx
        """

        # FIXME: this will be applied for the loads of the drain/source
        return self.mults * self.tx_width / drc("minwidth_tx")