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())
# 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)
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)
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)
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.")