diff --git a/cpp_to_py/io_parser/BindHelper.cpp b/cpp_to_py/io_parser/BindHelper.cpp index 4b17dd0..cf0cbb9 100644 --- a/cpp_to_py/io_parser/BindHelper.cpp +++ b/cpp_to_py/io_parser/BindHelper.cpp @@ -66,6 +66,7 @@ void bindGPDatabase(pybind11::module& m) { .def("hyperedge_info_tensor", &gp::GPDatabase::getHyperedgeInfoTensor, py::return_value_policy::move) .def("node2pin_info_tensor", &gp::GPDatabase::getNode2PinInfoTensor, py::return_value_policy::move) .def("region_info_tensor", &gp::GPDatabase::getRegionInfoTensor, py::return_value_policy::move) + .def("snet_info_tensor", &gp::GPDatabase::getSnetInfoTensor, py::return_value_policy::move) .def("apply_node_cpos", &gp::GPDatabase::applyNodeCPos) .def("apply_node_lpos", &gp::GPDatabase::applyNodeLPos) .def("write_placement", &gp::GPDatabase::writePlacement); diff --git a/cpp_to_py/io_parser/gp/GPDatabase.cpp b/cpp_to_py/io_parser/gp/GPDatabase.cpp index 2f0144e..4717d88 100644 --- a/cpp_to_py/io_parser/gp/GPDatabase.cpp +++ b/cpp_to_py/io_parser/gp/GPDatabase.cpp @@ -562,6 +562,42 @@ std::vector GPDatabase::getRegionInfoTensor() { return {node_id2region_id, region_boxes, region_boxes_end}; } +std::vector GPDatabase::getSnetInfoTensor() { + auto options_int = torch::TensorOptions().dtype(torch::kInt64); + + unsigned num_snetshapes = 0; + for (size_t snetId = 0; snetId < database.snets.size(); snetId++) { + db::SNet* snet = database.snets[snetId]; + for (size_t shapeIdx = 0; shapeIdx < snet->shapes.size(); shapeIdx++) { + num_snetshapes++; + } + } + + torch::Tensor snet_lpos = torch::zeros({num_snetshapes, 2}); + torch::Tensor snet_size = torch::zeros({num_snetshapes, 2}); + torch::Tensor snet_layer = torch::zeros({num_snetshapes}, options_int); + + auto snet_lpos_a = snet_lpos.accessor(); + auto snet_size_a = snet_size.accessor(); + auto snet_layer_a = snet_layer.accessor(); + + int ptr = 0; + for (size_t snetId = 0; snetId < database.snets.size(); snetId++) { + db::SNet* snet = database.snets[snetId]; + for (size_t shapeIdx = 0; shapeIdx < snet->shapes.size(); shapeIdx++) { + auto& shape = snet->shapes[shapeIdx]; + snet_lpos_a[ptr][0] = shape.lx; + snet_lpos_a[ptr][1] = shape.ly; + snet_size_a[ptr][0] = shape.hx - shape.lx; + snet_size_a[ptr][1] = shape.hy - shape.ly; + snet_layer_a[ptr] = shape.layer.rIndex; + ptr++; + } + } + + return {snet_lpos, snet_size, snet_layer}; +} + void GPDatabase::applyOneNodeOrient(int node_id) { auto& node = nodes[node_id]; int rowId; diff --git a/cpp_to_py/io_parser/gp/GPDatabase.h b/cpp_to_py/io_parser/gp/GPDatabase.h index a16ad61..6b3cac5 100644 --- a/cpp_to_py/io_parser/gp/GPDatabase.h +++ b/cpp_to_py/io_parser/gp/GPDatabase.h @@ -217,6 +217,7 @@ public: std::vector getHyperedgeInfoTensor(); // hyperedge_index, hyperedge_list, hyperedge_list_end std::vector getNode2PinInfoTensor(); // node2pin_index, node2pin_list, node2pin_list_end std::vector getRegionInfoTensor(); // node_id2region_id, region_boxes, region_boxes_end + std::vector getSnetInfoTensor(); // snet_lpos, snet_size, snet_layer (0 for M1, 1 for M2, ...) void applyOneNodeOrient(int node_id); void applyNodeCPos(torch::Tensor node_cpos); void applyNodeLPos(torch::Tensor node_lpos); diff --git a/cpp_to_py/routedp/PyBindCppMain.cpp b/cpp_to_py/routedp/PyBindCppMain.cpp index 095f6f1..31ae01c 100644 --- a/cpp_to_py/routedp/PyBindCppMain.cpp +++ b/cpp_to_py/routedp/PyBindCppMain.cpp @@ -20,7 +20,8 @@ torch::Tensor dp_route_opt(torch::Tensor node_lpos_init_, float site_width, float row_height, std::shared_ptr rawdb_, - std::shared_ptr gpdb_) { + std::shared_ptr gpdb_, + int K) { // We found that placing cells under M2 SNet will easily cause DRVs // this function will shift cells outside the SNet within an acceptable range db::Database& rawdb = *rawdb_; @@ -226,7 +227,7 @@ torch::Tensor dp_route_opt(torch::Tensor node_lpos_init_, float displaceL = dieHX; doMoveL = doMoveL && (snetLx > dieLX); if (doMoveL && blank_width_l < src_width_l) { - for (ptrOffsetL = -1; ptrOffsetL >= -5; ptrOffsetL--) { + for (ptrOffsetL = -1; ptrOffsetL >= -K; ptrOffsetL--) { int targetPtr = cellPtrL + ptrOffsetL; if (targetPtr >= 0) { auto [node_id1, node_lx1, node_hx1] = currBin2cells[targetPtr]; @@ -296,7 +297,7 @@ torch::Tensor dp_route_opt(torch::Tensor node_lpos_init_, int ptrOffsetR = 0; doMoveR = doMoveR && (snetHx < dieHX); if (doMoveR && blank_width_r < src_width_r) { - for (ptrOffsetR = 1; ptrOffsetR <= 5; ptrOffsetR++) { + for (ptrOffsetR = 1; ptrOffsetR <= K; ptrOffsetR++) { int targetPtr = cellPtrR + ptrOffsetR; if (targetPtr < currBin2cells.size()) { auto [node_id1, node_lx1, node_hx1] = currBin2cells[targetPtr]; diff --git a/data/README.md b/data/README.md new file mode 100644 index 0000000..3d60c92 --- /dev/null +++ b/data/README.md @@ -0,0 +1,4 @@ +The following script will automatically download `ispd2005`, `ispd2015`, and `iccad2019` benchmarks in `./data/raw`. It also preprocesses `ispd2015` benchmark to fix some errors when routing them by InnovusĀ®. +```bash +./download_data.sh +``` \ No newline at end of file diff --git a/src/detail_placement.py b/src/detail_placement.py index 9392edb..05084d6 100644 --- a/src/detail_placement.py +++ b/src/detail_placement.py @@ -422,7 +422,7 @@ def run_dp(node_pos: torch.Tensor, data: PlaceData, args, logger): def run_dp_route_opt(node_pos: torch.Tensor, gpdb, rawdb, ps, data: PlaceData, args, logger): # NOTE: we suppose M1's prefer routing direction is 0 (horizontal) if ps.enable_route and gpdb.m1direction() == 0: - func_name = "routedp" + func_name = "PA-Refine" logger.info("Start running %s" % func_name) start_time = time.time() node_pos_bk = node_pos.clone() @@ -445,9 +445,10 @@ def run_dp_route_opt(node_pos: torch.Tensor, gpdb, rawdb, ps, data: PlaceData, a dieHX = die_info[1].item() dieLY = die_info[2].item() dieHY = die_info[3].item() + K = 5 new_node_lpos = routedp.dp_route_opt( node_lpos, node_size, dieLX, dieHX, dieLY, dieHY, - site_width, row_height, rawdb, gpdb + site_width, row_height, rawdb, gpdb, K ) new_mov_cpos = new_node_lpos.to(node_pos.device)[mov_lhs:mov_rhs] + data.node_size[mov_lhs:mov_rhs] / 2 node_pos[mov_lhs:mov_rhs].data.copy_(new_mov_cpos) diff --git a/src/initializer.py b/src/initializer.py index dc6751f..54e0c30 100644 --- a/src/initializer.py +++ b/src/initializer.py @@ -5,7 +5,7 @@ from .core import WAWirelengthLossAndHPWL from .calculator import calc_grad -def get_init_density_map(data: PlaceData, args, logger): +def get_init_density_map(rawdb, gpdb, data: PlaceData, args, logger): lhs, rhs = data.fixed_index device = data.node_size.get_device() dtype = data.node_size.dtype @@ -13,6 +13,7 @@ def get_init_density_map(data: PlaceData, args, logger): (data.num_bin_x, data.num_bin_y), device=device, dtype=dtype, ) if lhs == rhs: + data.init_density_map = zeros_density_map return zeros_density_map # get fix nodes which are located inside die node_pos = data.node_pos[lhs:rhs] @@ -28,9 +29,40 @@ def get_init_density_map(data: PlaceData, args, logger): logger.warning("Some bins in init_density_map are overflow. Clamp them.") if (init_density_map < 0).sum() > 0: logger.error("init_density_map has negative value. Please check.") + if args.use_route_force or args.use_cell_inflate: + # reduce the cell density near the fixed macro + init_density_map += density_map_cuda.forward_naive( + node_pos, node_size * 1.025, node_weight, data.unit_len, zeros_density_map, + data.num_bin_x, data.num_bin_y, node_pos.shape[0], -1.0, -1.0, 1e-4, False, + args.deterministic + ).contiguous() * 0.5 + # consider snet as plaement blkg in density map to resolve M2 Vertical + # SNet pin access problem + if gpdb is not None and gpdb.m1direction() == 0: + # TODO: only include snet density when util is small + snet_lpos, snet_size, snet_layer = gpdb.snet_info_tensor() + + snet_lpos = snet_lpos.to(device) + snet_size = snet_size.to(device) + snet_layer = snet_layer.to(device) + m2_mask = snet_layer == 1 + snet_lpos = snet_lpos[m2_mask, :] + snet_size = snet_size[m2_mask, :] + snet_lpos -= data.die_shift + snet_lpos /= data.die_scale + snet_size /= data.die_scale + + snet_pos = snet_lpos + snet_size / 2 + snet_weight = snet_size.new_ones(snet_size.shape[0]) + snet_density_map = density_map_cuda.forward_naive( + snet_pos, snet_size, snet_weight, data.unit_len, zeros_density_map, + data.num_bin_x, data.num_bin_y, snet_pos.shape[0], -1.0, -1.0, 1e-4, False, + args.deterministic + ) + init_density_map += snet_density_map.contiguous() init_density_map.clamp_(min=0.0, max=1.0).mul_(args.target_density) if args.use_route_force or args.use_cell_inflate: - # enable route, inflate connected IOPins + # inflate connected IOPins _, fix_rhs, _ = data.node_type_indices[2] _, iopin_rhs, _ = data.node_type_indices[3] if fix_rhs != iopin_rhs: @@ -40,7 +72,6 @@ def get_init_density_map(data: PlaceData, args, logger): iopin_pos = data.node_pos[fix_rhs:iopin_rhs] iopin_size = data.node_size[fix_rhs:iopin_rhs] iopin_weight = iopin_size.new_ones(iopin_size.shape[0]) - row_height = data.row_height / data.site_width iopin_density_map = density_map_cuda.forward_naive( iopin_pos, iopin_size, iopin_weight, data.unit_len, zeros_density_map, data.num_bin_x, data.num_bin_y, iopin_pos.shape[0], -1.0, -1.0, 1e-4, False, diff --git a/src/run_placement_nesterov.py b/src/run_placement_nesterov.py index 4df2428..60ca586 100644 --- a/src/run_placement_nesterov.py +++ b/src/run_placement_nesterov.py @@ -27,7 +27,7 @@ def run_placement_main_nesterov(args, logger): logger.info(data.node_type_indices) # args.num_bin_x = args.num_bin_y = 2 ** math.ceil(math.log2(max(data.die_info).item() // 25)) - init_density_map = get_init_density_map(data, args, logger) + init_density_map = get_init_density_map(rawdb, gpdb, data, args, logger) data.init_filler() mov_lhs, mov_rhs = data.movable_index mov_node_pos, mov_node_size, expand_ratio = data.get_mov_node_info()