diff --git a/PlaceRouteHierFlow/PnR-pybind11.cpp b/PlaceRouteHierFlow/PnR-pybind11.cpp index fe25816052..de9d28b05a 100644 --- a/PlaceRouteHierFlow/PnR-pybind11.cpp +++ b/PlaceRouteHierFlow/PnR-pybind11.cpp @@ -469,6 +469,7 @@ PYBIND11_MODULE(PnR, m) { .def( "ReadPrimitiveOffsetPitch", &PnRdatabase::ReadPrimitiveOffsetPitch) .def_readwrite("hierTree", &PnRdatabase::hierTree) .def_readwrite("topidx", &PnRdatabase::topidx) + .def_readwrite("use_external_placement_info", &PnRdatabase::use_external_placement_info) .def_readwrite("gdsData2", &PnRdatabase::gdsData2) .def_readwrite("lefData", &PnRdatabase::lefData) .def_readwrite("DRC_info", &PnRdatabase::DRC_info) diff --git a/PlaceRouteHierFlow/PnRDB/PnRdatabase.cpp b/PlaceRouteHierFlow/PnRDB/PnRdatabase.cpp index c3e0a165c2..f074d1f9ac 100644 --- a/PlaceRouteHierFlow/PnRDB/PnRdatabase.cpp +++ b/PlaceRouteHierFlow/PnRDB/PnRdatabase.cpp @@ -119,7 +119,6 @@ PnRDB::hierNode PnRdatabase::CheckoutHierNode(int nodeID, int sel) { void PnRdatabase::AppendToHierTree(const PnRDB::hierNode& hN) { hierTree.push_back(hN); } - static void updateContact(PnRDB::contact& c) { c.originBox = c.placedBox; c.originCenter = c.placedCenter; @@ -272,7 +271,6 @@ void PnRdatabase::TransformContact(PnRDB::contact& contact, PnRDB::point transla TransformPoint(contact.originCenter, translate, width, height, ort, transform_type); } - void PnRdatabase::TransformBbox(PnRDB::bbox& box, PnRDB::point translate, int width, int height, PnRDB::Omark ort, PnRDB::TransformType transform_type) { int WW = width; int HH = height; @@ -502,7 +500,6 @@ void PnRdatabase::TransformNets(std::vector& nets, PnRDB::point tran } } - PnRDB::Omark PnRdatabase::RelOrt2AbsOrt(PnRDB::Omark current_node_ort, PnRDB::Omark childnode_ort) { /* Inputs: @@ -852,7 +849,10 @@ for(unsigned int i=0;idebug("Connected {0} {1} {2}", hierTree[i].Nets[k].connected[h].type, hierTree[i].Nets[k].connected[h].iter, - // hierTree[i].Nets[k].connected[h].iter2); + // hierTree[i].Nets[k].connected[h].iter2); for (unsigned int l = 0; l < temp_LinearConst.pins.size(); l++) { // logger->debug("LinearConst cont {0} {1} {2}", temp_LinearConst.pins[l].first, temp_LinearConst.pins[l].second, temp_LinearConst.alpha[l]); if (hierTree[i].Nets[k].connected[h].type == PnRDB::Block && hierTree[i].Nets[k].connected[h].iter2 == temp_LinearConst.pins[l].first && diff --git a/PlaceRouteHierFlow/PnRDB/PnRdatabase.h b/PlaceRouteHierFlow/PnRDB/PnRdatabase.h index 20aead7d22..fa84f84a3a 100644 --- a/PlaceRouteHierFlow/PnRDB/PnRdatabase.h +++ b/PlaceRouteHierFlow/PnRDB/PnRdatabase.h @@ -71,6 +71,7 @@ class PnRdatabase { public: int topidx; + bool use_external_placement_info = false; PnRDB::Drc_info DRC_info; vector hierTree; // each module in verilog file is a node int ScaleFactor = 1; @@ -96,7 +97,7 @@ class PnRdatabase { PnRDB::hierNode CheckoutHierNode(int nodeID, int sel = -1); // check out data of specific hierarchical node void AppendToHierTree(const PnRDB::hierNode &updatedNode); // append node to end of hierTree void CheckinHierNode(int nodeID, const PnRDB::hierNode &updatedNode); // check out data of specific hierarchical node - std::vector UsedInstancesIdx(int nodeID); // indices of used instances of a hiernode + std::vector UsedInstancesIdx(int nodeID); // indices of used instances of a hiernode void CheckinChildnodetoBlock(PnRDB::hierNode &parent, int blockID, const PnRDB::hierNode &updatedNode, PnRDB::Omark ort); void updatePowerPins(PnRDB::pin &temp_pin); @@ -171,7 +172,7 @@ class PnRdatabase { void Write_Router_Report(PnRDB::hierNode &node, const string &opath); void Write_Power_Mesh_Conf(std::string outputfile); void Write_Current_Workload(PnRDB::hierNode &node, double total_current, int current_number, std::string outputfile); - PnRDB::Metal Find_Top_Middle_Metal(PnRDB::hierNode& node, const PnRDB::Drc_info& drc_info, int index); + PnRDB::Metal Find_Top_Middle_Metal(PnRDB::hierNode &node, const PnRDB::Drc_info &drc_info, int index); }; #endif diff --git a/PlaceRouteHierFlow/placer/Placer.cpp b/PlaceRouteHierFlow/placer/Placer.cpp index 4db035066b..2cc5ce3ae6 100644 --- a/PlaceRouteHierFlow/placer/Placer.cpp +++ b/PlaceRouteHierFlow/placer/Placer.cpp @@ -73,7 +73,7 @@ void Placer::setPlacementInfoFromJson(std::vector& nodeVec, str design designData(nodeVec.back(), drcInfo); int idx = 0; //pad nodeVec to match the number of concretes in JSON file - for (const auto& m : modules) { + /**for (const auto& m : modules) { if (m["abstract_name"] == designData.name) { string concrete_template_name = m["concrete_name"]; unsigned int start = 0; @@ -83,7 +83,7 @@ void Placer::setPlacementInfoFromJson(std::vector& nodeVec, str idx = atoi(concrete_template_name.substr(start, end - start).c_str()); if (idx >= nodeVec.size()) nodeVec.insert(nodeVec.end(), idx + 1 - nodeVec.size(), nodeVec.back()); } - } + }**/ int nodeSize = nodeVec.size(); int mode = 0; // Read design netlist and constraints @@ -95,12 +95,14 @@ void Placer::setPlacementInfoFromJson(std::vector& nodeVec, str std::vector> spVec(nodeSize, make_pair(curr_sp, curr_sol)); for (const auto& m : modules) { if (m["abstract_name"] == designData.name) { + if (m["concrete_name"] != designData.concrete_name) continue; string concrete_template_name = m["concrete_name"]; unsigned int start = 0; unsigned int slash = concrete_template_name.find_last_of('_'); if (slash != string::npos) start = slash + 1; unsigned int end = concrete_template_name.size(); - idx = atoi(concrete_template_name.substr(start, end - start).c_str()); + //idx = atoi(concrete_template_name.substr(start, end - start).c_str()); + idx = 0; if (idx >= nodeSize) continue; auto& sol = spVec[idx].second; auto& sp = spVec[idx].first; diff --git a/PlaceRouteHierFlow/placer/design.cpp b/PlaceRouteHierFlow/placer/design.cpp index d5caddce17..1aa6a2da2e 100644 --- a/PlaceRouteHierFlow/placer/design.cpp +++ b/PlaceRouteHierFlow/placer/design.cpp @@ -23,6 +23,7 @@ design::design(PnRDB::hierNode& node, PnRDB::Drc_info& drcInfo, const int seed) _rng.seed(seed); is_first_ILP = node.isFirstILP; name = node.name; + concrete_name = node.concrete_name; placement_id = node.placement_id; bias_Vgraph = node.bias_Vgraph; // from node bias_Hgraph = node.bias_Hgraph; // from node diff --git a/PlaceRouteHierFlow/placer/design.h b/PlaceRouteHierFlow/placer/design.h index 46cf6de301..98ba9257dc 100644 --- a/PlaceRouteHierFlow/placer/design.h +++ b/PlaceRouteHierFlow/placer/design.h @@ -132,6 +132,7 @@ class design { double maxBlockAreaSum = 0.; double maxBlockHPWLSum = 0.; string name = ""; + string concrete_name = ""; // added by ya diff --git a/align/pnr/build_pnr_model.py b/align/pnr/build_pnr_model.py index 60e0f0f7fd..738d1994d6 100644 --- a/align/pnr/build_pnr_model.py +++ b/align/pnr/build_pnr_model.py @@ -21,6 +21,7 @@ def _ReadVerilogJson( DB, j, add_placement_info=False): temp_node = PnR.hierNode() temp_node.name = module['name'] if 'name' in module else module['abstract_name'] + temp_node.concrete_name = module['concrete_name'] if 'concrete_name' in module else module['name'] temp_node.isCompleted = 0 Terminals = [] diff --git a/align/pnr/checker.py b/align/pnr/checker.py index bedd1d911a..e85cdaa520 100644 --- a/align/pnr/checker.py +++ b/align/pnr/checker.py @@ -2,6 +2,7 @@ from ..schema import constraint, types from ..cell_fabric import transformation import json +import copy import pathlib import more_itertools logger = logging.getLogger(__name__) @@ -94,60 +95,60 @@ def _transform_leaf(module, instance, leaf): flat_leaf['concrete_name'] = leaf['concrete_name'] flat_leaf['name'] = instance['instance_name'] + '/' + name flat_leaf['transformation'] = transformation.Transformation.mult(tr_inst, tr_leaf).toDict() - module['leaves'].append(flat_leaf) + module['flat_leaves'].append(flat_leaf) def _flatten_leaves(placement, concrete_name): """ transform leaf coordinates to top level """ module = placement['modules'][concrete_name] - module['leaves'] = [] + module['flat_leaves'] = [] for instance in module['instances']: - leaf = placement['leaves'].get(instance['concrete_template_name'], False) + leaf = placement['flat_leaves'].get(instance['concrete_template_name'], False) if leaf: _transform_leaf(module, instance, leaf) else: leaves = _flatten_leaves(placement, instance['concrete_template_name']) for leaf in leaves: _transform_leaf(module, instance, leaf) - return module['leaves'] + return module['flat_leaves'] -def _check_place_on_grid(leaf, constraints): +def _check_place_on_grid(flat_leaf, constraints): for const in constraints: if const['direction'] == 'H': - o, s = leaf['transformation']['oY'], leaf['transformation']['sY'] + o, s = flat_leaf['transformation']['oY'], flat_leaf['transformation']['sY'] else: - o, s = leaf['transformation']['oX'], leaf['transformation']['sX'] + o, s = flat_leaf['transformation']['oX'], flat_leaf['transformation']['sX'] is_satisfied = False for term in const['ored_terms']: for offset in term['offsets']: if (o - offset) % const['pitch'] == 0 and s in term['scalings']: is_satisfied = True - logger.debug(f'{leaf["name"]} satisfied {term} in {const}') + logger.debug(f'{flat_leaf["name"]} satisfied {term} in {const}') break if is_satisfied: break - assert is_satisfied, f'{leaf} does not satisfy {const}' + assert is_satisfied, f'{flat_leaf} does not satisfy {const}' def check_place_on_grid(placement_verilog_d, concrete_name, opath): - if False: - # Load JSON file for easier debug - filename = (pathlib.Path(opath) / f'{concrete_name}.scaled_placement_verilog.json') - with (filename).open('rt') as fp: - placement_dict = json.load(fp) - else: - placement_dict = placement_verilog_d + # If we don't do the copy, then we get the 'flat_leaves" field filled in placement_verilog_d (can be large) + # We might want to use an auxillary data structure instead + + placement_verilog_d_copy = copy.deepcopy(placement_verilog_d) placement = dict() - placement['leaves'] = {x['concrete_name']: x for x in placement_dict['leaves']} - placement['modules'] = {x['concrete_name']: x for x in placement_dict['modules']} - leaves = _flatten_leaves(placement, concrete_name) + placement['flat_leaves'] = {x['concrete_name']: x for x in placement_verilog_d_copy['leaves']} + placement['modules'] = {x['concrete_name']: x for x in placement_verilog_d_copy['modules']} + + print(placement) + + flat_leaves = _flatten_leaves(placement, concrete_name) constrained_cns = dict() - all_cns = {x['concrete_name'] for x in leaves} + all_cns = {x['concrete_name'] for x in flat_leaves} for cn in all_cns: filename = pathlib.Path(opath) / '../inputs' / f'{cn}.json' if filename.exists() and filename.is_file(): @@ -158,7 +159,8 @@ def check_place_on_grid(placement_verilog_d, concrete_name, opath): if place_on_grids: constrained_cns[cn] = place_on_grids - if constrained_cns: - for leaf in leaves: - if leaf['concrete_name'] in constrained_cns: - _check_place_on_grid(leaf, constrained_cns[leaf['concrete_name']]) + for flat_leaf in flat_leaves: + if flat_leaf['concrete_name'] in constrained_cns: + _check_place_on_grid(flat_leaf, constrained_cns[flat_leaf['concrete_name']]) + + diff --git a/align/pnr/main.py b/align/pnr/main.py index 7d9976b2ed..51ccb0b9ed 100644 --- a/align/pnr/main.py +++ b/align/pnr/main.py @@ -340,10 +340,11 @@ def generate_pnr(topology_dir, primitive_dir, pdk_dir, output_dir, subckt, *, pr toplevel_args_d=toplevel_args_d, results_dir=None, placer_sa_iterations=placer_sa_iterations) - with open("__placer_dump__.json", "wt") as fp: + os.chdir(current_working_dir) + + with (working_dir / "__placer_dump__.json").open('wt') as fp: json.dump((top_level, leaf_map, [(nm, verilog_d.dict()) for nm, verilog_d in placement_verilog_alternatives.items()],metrics), fp=fp, indent=2) - os.chdir(current_working_dir) elif '3_pnr:gui' in steps_to_run or '3_pnr:route' in steps_to_run: with (working_dir / "__placer_dump__.json").open('rt') as fp: @@ -360,11 +361,11 @@ def generate_pnr(topology_dir, primitive_dir, pdk_dir, output_dir, subckt, *, pr else: placements_to_run = None - with open("__placements_to_run__.json", "wt") as fp: + with (working_dir / "__placements_to_run__.json").open("wt") as fp: json.dump(placements_to_run, fp=fp, indent=2) elif '3_pnr:route' in steps_to_run: - with open("__placements_to_run__.json", "rt") as fp: + with (working_dir / "__placements_to_run__.json").open("rt") as fp: placements_to_run = json.load(fp) variants = defaultdict(defaultdict) @@ -401,6 +402,8 @@ def generate_pnr(topology_dir, primitive_dir, pdk_dir, output_dir, subckt, *, pr verilog_ds_to_run=verilog_ds_to_run) + print(results_name_map) + os.chdir(current_working_dir) for variant, (path_name, layout_idx, DB) in results_name_map.items(): @@ -417,6 +420,8 @@ def generate_pnr(topology_dir, primitive_dir, pdk_dir, output_dir, subckt, *, pr toplevel=hN.isTop, pnr_const_ds=pnr_const_ds) + print(variant) + if hN.isTop: variants[variant].update(result) @@ -427,4 +432,6 @@ def generate_pnr(topology_dir, primitive_dir, pdk_dir, output_dir, subckt, *, pr variants[variant][tag] = path + print(variants) + return variants diff --git a/align/pnr/manipulate_hierarchy.py b/align/pnr/manipulate_hierarchy.py index fee4cb22da..7e7b0b29a2 100644 --- a/align/pnr/manipulate_hierarchy.py +++ b/align/pnr/manipulate_hierarchy.py @@ -112,7 +112,7 @@ def manipulate_hierarchy(verilog_d, subckt): clean_if_extra(verilog_d, subckt) check_modules(verilog_d) -def change_concrete_names_for_routing(scaled_placement_verilog_d): +def change_abstract_and_concrete_names_for_routing(scaled_placement_verilog_d): leaf_ctns = [leaf['concrete_name'] for leaf in scaled_placement_verilog_d['leaves']] p = re.compile(r'^(.+)_(\d+)$') @@ -133,8 +133,14 @@ def change_concrete_names_for_routing(scaled_placement_verilog_d): logger.debug(f'change_concrete_names_for_routing: {tr_tbl}') + an_cn_pairs = [] + for module in scaled_placement_verilog_d['modules']: - module['concrete_name'] = tr_tbl[module['concrete_name']] + cn = module['concrete_name'] + module['concrete_name'] = tr_tbl[cn] + an_cn_pairs.append((module['abstract_name'], module['concrete_name'])) + module['abstract_name'] = module['concrete_name'] + for instance in module['instances']: ctn = instance['concrete_template_name'] if ctn in leaf_ctns: @@ -143,17 +149,22 @@ def change_concrete_names_for_routing(scaled_placement_verilog_d): else: assert ctn in tr_tbl instance['concrete_template_name'] = tr_tbl[ctn] + instance['abstract_template_name'] = tr_tbl[ctn] + + if 'flat_leaves' in module: + del module['flat_leaves'] + for leaf in scaled_placement_verilog_d['leaves']: - leaf['abstract_name'] =leaf['concrete_name'] + leaf['abstract_name'] = leaf['concrete_name'] - return tr_tbl + return tr_tbl, an_cn_pairs def gen_abstract_verilog_d( verilog_d): new_verilog_d = copy.deepcopy(verilog_d) if 'leaves' in new_verilog_d: - new_verilog_d['leaves'] = None + del new_verilog_d['leaves'] for module in new_verilog_d['modules']: assert 'concrete_name' in module @@ -169,9 +180,12 @@ def gen_abstract_verilog_d( verilog_d): for instance in module['instances']: assert 'concrete_template_name' in instance del instance['concrete_template_name'] + assert 'transformation' in instance del instance['transformation'] + assert 'flat_leaves' not in module + return new_verilog_d def connectivity_change_for_partial_routing(scaled_placement_verilog_d, primitives): diff --git a/align/pnr/placer.py b/align/pnr/placer.py index 362617f118..cd0b3ab57a 100644 --- a/align/pnr/placer.py +++ b/align/pnr/placer.py @@ -44,7 +44,9 @@ def place( *, DB, opath, fpath, numLayout, effort, idx, lambda_coeff, select_in_ if modules_d is not None: hyper.use_external_placement_info = True + DB.use_external_placement_info = True hyper.placement_info_json = json.dumps(modules_d, indent=2) + print(hyper.placement_info_json) else: logger.info(f'Starting bottom-up placement on {DB.hierTree[idx].name} {idx}') @@ -275,7 +277,7 @@ def update_grid_constraints(grid_constraints, DB, idx, verilog_d, primitives, sc if 'constraints' not in leaf: leaf['constraints'] = [] - leaf['constraints'].extend(constraint for constraint in primitive['metadata']['constraints']) + leaf['constraints'].extend(primitive['metadata']['constraints']) top_name = f'{hN.name}_{sel}' gen_constraints(scaled_placement_verilog_d, top_name) @@ -326,7 +328,8 @@ def hierarchical_place(*, DB, opath, fpath, numLayout, effort, verilog_d, top_level, leaf_map, placement_verilog_alternatives, metrics = process_placements(DB=DB, verilog_d=verilog_d, - lambda_coeff=lambda_coeff, scale_factor=scale_factor, + lambda_coeff=lambda_coeff, + scale_factor=scale_factor, opath=opath) return top_level, leaf_map, placement_verilog_alternatives, metrics diff --git a/align/pnr/router.py b/align/pnr/router.py index 5954da8c7d..7809e67143 100644 --- a/align/pnr/router.py +++ b/align/pnr/router.py @@ -1,12 +1,14 @@ import logging import pathlib +from pathlib import Path import json import re +import copy from collections import defaultdict from .. import PnR -from .manipulate_hierarchy import change_concrete_names_for_routing, gen_abstract_verilog_d, connectivity_change_for_partial_routing +from .manipulate_hierarchy import change_abstract_and_concrete_names_for_routing, gen_abstract_verilog_d, connectivity_change_for_partial_routing from .build_pnr_model import gen_DB_verilog_d from .placer import hierarchical_place @@ -336,6 +338,10 @@ def router_driver(*, cap_map, cap_lef_s, router_mode, skipGDS, scale_factor, nroutings, primitives, toplevel_args_d, results_dir, verilog_ds_to_run): + toplevel_args_d = copy.deepcopy(toplevel_args_d) + + toplevel_args_d['subckt'] = toplevel_args_d['subckt'] + '_0' + fpath = toplevel_args_d['input_dir'] res_dict = {} @@ -343,9 +349,25 @@ def router_driver(*, cap_map, cap_lef_s, connectivity_change_for_partial_routing(scaled_placement_verilog_d, primitives) - tr_tbl = change_concrete_names_for_routing(scaled_placement_verilog_d) + tr_tbl, an_cn_pairs = change_abstract_and_concrete_names_for_routing(scaled_placement_verilog_d) abstract_verilog_d = gen_abstract_verilog_d(scaled_placement_verilog_d) + # + # Create links for the pnr constraints + # + for an, cn in an_cn_pairs: + new_file = Path(fpath) / f"{cn}.pnr.const.json" + old_file = Path(fpath) / f"{an}.pnr.const.json" + + if new_file.exists() and new_file.is_symlink(): + new_file.unlink() + + assert old_file.exists() + if not new_file.exists(): + new_file.symlink_to(old_file) + else: + logger.warning(f"{new_file} already exists. Can't add a symlink to {old_file}.") + # don't need to send this to disk; for debug only if True: logger.debug(f"updated verilog: {abstract_verilog_d}") @@ -372,7 +394,7 @@ def router_driver(*, cap_map, cap_lef_s, idir = pathlib.Path(fpath) cap_ctns = { str(pathlib.Path(gdsFile).stem) : gdsFile for atn, gdsFile in cap_map } - print(cap_ctns) + map_d_in = [] for leaf in scaled_placement_verilog_d['leaves']: ctn = leaf['concrete_name'] @@ -409,6 +431,8 @@ def router_driver(*, cap_map, cap_lef_s, primitives=primitives, placer_sa_iterations=10000) + print("got here") + placements_to_run = None res = route( DB=DB, idx=DB.TraverseHierTree()[-1], opath=opath, adr_mode=adr_mode, PDN_mode=PDN_mode, diff --git a/tests/pnr/test_check_place_on_grid.py b/tests/pnr/test_check_place_on_grid.py index 14690cd4c7..e87ba23d5d 100644 --- a/tests/pnr/test_check_place_on_grid.py +++ b/tests/pnr/test_check_place_on_grid.py @@ -53,7 +53,7 @@ def test_flatten_leaves(): {'concrete_name': 'INV', 'name': 'XI2/XI0/INV', 'transformation': {'oX': 0, 'oY': 10000, 'sX': 1, 'sY': -1}} ] - placement['leaves'] = {x['concrete_name']: x for x in placement['leaves']} + placement['flat_leaves'] = {x['concrete_name']: x for x in placement['leaves']} placement['modules'] = {x['concrete_name']: x for x in placement['modules']} leaves = _flatten_leaves(placement, 'CKT_TOP_0') assert leaves == leaves_gold, 'Value does not match golden'