Exemplo n.º 1
0
    def insert_diode(self, it, src_pos, force_true=False):
        # Get information about the instance
        inst = it.getInst()
        inst_name = inst.getConstName()
        inst_site = (inst.getMaster().getSite().getConstName() if
                     (inst.getMaster().getSite() is not None) else None)

        # Find where the pin is
        px, py = self.pin_position(it)

        # Apply standard cell or macro placement ?
        if inst_site == self.diode_site:
            dx, dy, do = self.place_diode_stdcell(it, px, py, src_pos)
        else:
            dx, dy, do = self.place_diode_macro(it, px, py, src_pos)

        # Insert instance and wire it up
        diode_inst_name = "ANTENNA_" + inst_name + "_" + it.getMTerm(
        ).getConstName()
        diode_master = self.true_diode_master if force_true else self.diode_master

        diode_inst = odb.dbInst_create(self.block, diode_master,
                                       diode_inst_name)

        diode_inst.setOrient(do)
        diode_inst.setLocation(dx, dy)
        diode_inst.setPlacementStatus("PLACED")

        ait = diode_inst.findITerm(self.diode_pin)
        ait.connect(it.getNet())
Exemplo n.º 2
0
# print(to_connect)

nets_macro = block_macro.getNets()
created_macros = {}
for net in nets_macro:
    iterms = net.getITerms()  # asssumption: no pins (bterms) on top level
    if not keep_flag:
        for iterm in iterms:
            iterm.disconnect()
    if net.getName() in to_connect:
        for node_iterm in to_connect[net.getName()]:
            node_master = node_iterm.getMTerm().getMaster()
            node_inst = node_iterm.getInst()
            node_inst_name = node_iterm.getInst().getName()
            if node_inst_name not in created_macros:
                created_macros[node_inst_name] = 1
                print("Creating: ", node_master.getName(), node_inst_name)
                new_inst = odb.dbInst_create(block_macro, node_master,
                                             node_inst_name)
                new_inst.setOrient(node_inst.getOrient())
                new_inst.setLocation(
                    node_inst.getLocation()[0] - MACRO_TOP_PLACEMENT_X,
                    node_inst.getLocation()[1] - MACRO_TOP_PLACEMENT_Y)
                new_inst.setPlacementStatus("FIRM")
            else:
                new_inst = block_macro.findInst(node_inst_name)
            new_inst.findITerm(node_iterm.getMTerm().getName()).connect(net)

odb.write_def(block_macro, output_def_file_name)
Exemplo n.º 3
0
    master_name = master.getName()
    x, y = inst.getLocation()
    orient = inst.getOrient()

    if (inst_name, master_name) in used_pads + used_corner_pads:
        original_inst = block_top.findInst(inst_name)
        assert original_inst is not None, "Failed to find " + inst_name
        assert original_inst.getPlacementStatus(
        ) == "NONE", inst_name + " is already placed"
        original_inst.setOrient(orient)
        original_inst.setLocation(x, y)
        original_inst.setPlacementStatus("FIRM")
        placed_cells_count += 1
    else:
        # must be a filler cell
        new_inst = odb.dbInst_create(block_top, db_top.findMaster(master_name),
                                     inst_name)
        assert new_inst is not None, "Failed to create " + inst_name
        new_inst.setOrient(orient)
        new_inst.setLocation(x, y)
        new_inst.setPlacementStatus("FIRM")
        created_cells_count += 1

# TODO: place the core macros within the padframe (chip floorplan)
for inst in block_top.getInsts():
    if inst.isPlaced() or inst.isFixed():
        continue
    print("Placing", inst.getName())
    master = inst.getMaster()
    master_width = master.getWidth()
    master_height = master.getHeight()
    print(master_width, master_height)
Exemplo n.º 4
0
def contextualize(
    output, input_lef, top_def, top_lef, keep_inner_connections, input_def
):
    top = OdbReader(top_lef, top_def)
    macro = OdbReader([top_lef, input_lef], input_def)

    print("Block design name:", macro.name)
    print("Top-level design name:", top.name)

    nets_top = top.block.getNets()
    to_connect = {}
    MACRO_TOP_PLACEMENT_X = 0
    MACRO_TOP_PLACEMENT_Y = 0

    assert macro.name in [
        inst.getMaster().getName() for inst in top.block.getInsts()
    ], "%s not found in %s" % (macro.name, top.name)

    for net in nets_top:
        iterms = net.getITerms()  # asssumption: no pins (bterms) on top level
        block_net_name = None
        for iterm in iterms:
            macro_name = iterm.getMTerm().getMaster().getName()
            if macro_name == macro.name:
                block_net_name = iterm.getMTerm().getName()
                macro_top_inst = iterm.getInst()
                (
                    MACRO_TOP_PLACEMENT_X,
                    MACRO_TOP_PLACEMENT_Y,
                ) = macro_top_inst.getLocation()
                print("Block net name: ", block_net_name)
                break
        if block_net_name is not None:
            to_connect[block_net_name] = []
            for iterm in iterms:
                macro_name = iterm.getMTerm().getMaster().getName()
                if macro_name != macro.name:
                    to_connect[block_net_name].append(iterm)
            block_net_name = None

            # print(macro_name, inst_name, end= ' ')
            # print(iterm.getMTerm().getName())

    # print(to_connect)

    nets_macro = macro.block.getNets()
    created_macros = {}
    for net in nets_macro:
        iterms = net.getITerms()  # asssumption: no pins (bterms) on top level
        if not keep_inner_connections:
            for iterm in iterms:
                iterm.disconnect()
        if net.getName() in to_connect:
            for node_iterm in to_connect[net.getName()]:
                node_master = node_iterm.getMTerm().getMaster()
                node_inst = node_iterm.getInst()
                node_inst_name = node_iterm.getInst().getName()
                if node_inst_name not in created_macros:
                    created_macros[node_inst_name] = 1
                    print("Creating: ", node_master.getName(), node_inst_name)
                    new_inst = odb.dbInst_create(
                        macro.block, node_master, node_inst_name
                    )
                    new_inst.setOrient(node_inst.getOrient())
                    new_inst.setLocation(
                        node_inst.getLocation()[0] - MACRO_TOP_PLACEMENT_X,
                        node_inst.getLocation()[1] - MACRO_TOP_PLACEMENT_Y,
                    )
                    new_inst.setPlacementStatus("FIRM")
                else:
                    new_inst = macro.block.findInst(node_inst_name)
                new_inst.findITerm(node_iterm.getMTerm().getName()).connect(net)

    odb.write_def(macro.block, output)
Exemplo n.º 5
0
def padringer(
    output,
    verilog_netlist,
    def_netlist,
    input_lef,
    width,
    height,
    padframe_config,
    pad_name_prefixes,
    init_only,
    working_dir,
    special_nets,
    design,
):
    """
    Reads in a structural verilog containing pads and a LEF file that
    contains at least those pads and produces a DEF file with the padframe.
    TODO:
    core placement
    config init,
    external config
    """

    config_file_name = padframe_config
    output_file_name = output
    lefs = [input_lef]

    working_def = f"{working_dir}/{design}.pf.def"
    working_cfg = f"{working_dir}/{design}.pf.cfg"

    for lef in lefs:
        assert os.path.exists(lef), lef + " doesn't exist"

    # hard requirement of a user netlist either as a DEF or verilog
    # this is to ensure that the padframe will contain all pads in the design
    # whether the config is autogenerated or user-provided
    assert (verilog_netlist is not None or def_netlist is not None
            ), "One of --verilog_netlist or --def-netlist is required"

    # Step 1: create an openDB database from the verilog/def using OpenSTA's read_verilog
    if verilog_netlist is not None:
        assert (def_netlist is None
                ), "Only one of --verilog_netlist or --def-netlist is required"
        assert design is not None, "--design is required"

        openroad_script = []
        for lef in lefs:
            openroad_script.append(f"read_lef {lef}")
        openroad_script.append(f"read_verilog {verilog_netlist}")
        openroad_script.append(f"link_design {design}")
        openroad_script.append(f"write_def {working_def}")
        # openroad_script.append(f"write_db {design}.pf.db")
        openroad_script.append("exit")

        p = Popen(["openroad"],
                  stdout=PIPE,
                  stdin=PIPE,
                  stderr=PIPE,
                  encoding="utf8")

        openroad_script = "\n".join(openroad_script)
        # print(openroad_script)

        output = p.communicate(openroad_script)
        print("STDOUT:")
        print(output[0].strip())
        print("STDERR:")
        print(output[1].strip())
        print("openroad exit code:", p.returncode)
        assert p.returncode == 0, p.returncode
        # TODO: check for errors
    else:
        assert def_netlist is not None
        working_def = def_netlist

    assert os.path.exists(working_def), "DEF file doesn't exist"

    top = OdbReader(lefs, working_def)

    print(f"Top-level design name: {top.name}")

    ## Step 2: create a simple data structure with pads from the library
    # types: corner, power, other
    pads = {}
    libs = top.db.getLibs()
    for lib in libs:
        masters = lib.getMasters()
        for m in masters:
            name = m.getName()
            if m.isPad():
                assert any(name.startswith(p) for p in pad_name_prefixes), name
                print("Found pad:", name)
                pad_type = m.getType()
                pads[name] = pad_type
                if pad_type == "PAD_SPACER":
                    print("Found PAD_SPACER:", name)
                elif pad_type == "PAD_AREAIO":
                    # using this for special bus fillers...
                    print("Found PAD_AREAIO", name)
            if m.isEndCap():
                # FIXME: regular endcaps
                assert any(name.startswith(p) for p in pad_name_prefixes), name
                assert not m.isPad(), name + " is both pad and endcap?"
                print("Found corner pad:", name)
                pads[name] = "corner"

    print()
    print("The I/O library contains", len(pads), "cells")
    print()

    assert len(pads) != 0, "^"

    ## Step 3: Go over instances in the design and extract the used pads
    used_pads = []
    used_corner_pads = []
    other_instances = []
    for inst in top.block.getInsts():
        inst_name = inst.getName()
        master_name = inst.getMaster().getName()
        if inst.isPad():
            assert any(master_name.startswith(p)
                       for p in pad_name_prefixes), master_name
            print("Found pad instance", inst_name, "of type", master_name)
            used_pads.append((inst_name, master_name))
        elif inst.isEndCap():
            # FIXME: regular endcaps
            assert any(master_name.startswith(p)
                       for p in pad_name_prefixes), master_name
            print("Found pad instance", inst_name, "of type", master_name)
            print("Found corner pad instance", inst_name, "of type",
                  master_name)
            used_corner_pads.append((inst_name, master_name))
        else:
            assert not any(
                master_name.startswith(p)
                for p in pad_name_prefixes), master_name
            other_instances.append(inst_name)

    # FIXME: if used_corner_pads aren't supposed to be instantiated
    assert len(used_corner_pads) == 4, used_corner_pads

    print()
    print(
        "The user design contains",
        len(used_pads),
        "pads, 4 corner pads, and",
        len(other_instances),
        "other instances",
    )
    print()
    assert len(used_pads) != 0, "^"

    ## Step 4: Generate a CFG or verify a user-provided config

    if config_file_name is not None:
        assert os.path.exists(
            config_file_name), config_file_name + " doesn't exist"
        with open(config_file_name, "r") as f:
            lines = f.readlines()
        user_config_pads = []
        for line in lines:
            if line.startswith("CORNER") or line.startswith("PAD"):
                tokens = line.split()
                assert len(tokens) == 5, tokens
                inst_name, master_name = tokens[1], tokens[3]
                if (not pads[master_name] == "PAD_SPACER"
                        and not pads[master_name] == "PAD_AREAIO"):
                    user_config_pads.append((inst_name, master_name))
            elif line.startswith("AREA"):
                tokens = line.split()
                assert len(tokens) == 4, tokens
                width = int(tokens[1])
                height = int(tokens[2])

        assert sorted(user_config_pads) == sorted(
            used_pads + used_corner_pads
        ), (
            "Mismatch between the provided config and the provided netlist. Diff:",
            diff_lists(user_config_pads, used_pads + used_corner_pads),
        )

        print("User config verified")
        working_cfg = config_file_name
    else:
        # TODO: get minimum width/height so that --width and --height aren't required
        assert width is not None, "--width is required"
        assert height is not None, "--height is required"

        # auto generate a configuration

        # TODO: after calssification, center power pads on each side
        north, east, south, west = chunker(used_pads, 4)

        with open(working_cfg, "w") as f:
            f.write(
                generate_cfg(north, east, south, west, used_corner_pads, width,
                             height))

    if not init_only:
        invoke_padring(working_cfg, working_def, lefs)
    else:
        print(
            "Padframe config generated at",
            working_cfg,
            f"Modify it and re-run this program with the '-cfg {working_cfg}' option",
        )
        sys.exit()

    print("Applying pad placements to the design DEF")

    padframe = OdbReader(lefs, working_def)

    assert padframe.name == "PADRING", padframe.name

    print("Padframe design name:", padframe.name)

    # Mark special nets
    if special_nets is not None:
        for net in top.block.getNets():
            net_name = net.getName()
            if net_name in special_nets:
                print("Marking", net_name, "as a special net")
                net.setSpecial()
                for iterm in net.getITerms():
                    iterm.setSpecial()

    # get minimum width/height (core-bounded)

    placed_cells_count = 0
    created_cells_count = 0
    for inst in padframe.block.getInsts():
        assert inst.isPad() or inst.isEndCap(), (
            inst.getName() + " is neither a pad nor corner pad")

        inst_name = inst.getName()
        master = inst.getMaster()
        master_name = master.getName()
        x, y = inst.getLocation()
        orient = inst.getOrient()

        if (inst_name, master_name) in used_pads + used_corner_pads:
            original_inst = top.block.findInst(inst_name)
            assert original_inst is not None, "Failed to find " + inst_name
            assert original_inst.getPlacementStatus() == "NONE", (
                inst_name + " is already placed")
            original_inst.setOrient(orient)
            original_inst.setLocation(x, y)
            original_inst.setPlacementStatus("FIRM")
            placed_cells_count += 1
        else:
            # must be a filler cell
            new_inst = odb.dbInst_create(top.block,
                                         top.db.findMaster(master_name),
                                         inst_name)
            assert new_inst is not None, "Failed to create " + inst_name
            new_inst.setOrient(orient)
            new_inst.setLocation(x, y)
            new_inst.setPlacementStatus("FIRM")
            created_cells_count += 1

    # TODO: place the core macros within the padframe (chip floorplan)
    for inst in top.block.getInsts():
        if inst.isPlaced() or inst.isFixed():
            continue
        print("Placing", inst.getName())
        master = inst.getMaster()
        master_width = master.getWidth()
        master_height = master.getHeight()
        print(master_width, master_height)
        print(width, height)

        inst.setLocation(
            width * 1000 // 2 - master_width // 2,
            height * 1000 // 2 - master_height // 2,
        )
        inst.setPlacementStatus("PLACED")

    odb.write_def(top.block, output_file_name)
    print("Done.")