#include "coloquinte/detailed.hxx" #include "coloquinte/circuit_helper.hxx" #include namespace coloquinte{ namespace dp{ namespace{ // Tries to swap two cells; inline bool try_swap(netlist const & circuit, detailed_placement & pl, index_t c1, index_t c2, bool try_flip, std::function const &)> get_nets_cost){ assert(pl.cell_height(c1) == 1 and pl.cell_height(c2) == 1); assert( (circuit.get_cell(c1).attributes & XMovable) != 0 and (circuit.get_cell(c1).attributes & YMovable) != 0); assert( (circuit.get_cell(c2).attributes & XMovable) != 0 and (circuit.get_cell(c2).attributes & YMovable) != 0); auto c1_bnds = pl.get_limit_positions(circuit, c1), c2_bnds = pl.get_limit_positions(circuit, c2); // Get the possible positions for a swap int_t swp_min_c1 = c2_bnds.first, swp_min_c2 = c1_bnds.first, swp_max_c1 = c2_bnds.second - circuit.get_cell(c1).size.x, swp_max_c2 = c1_bnds.second - circuit.get_cell(c2).size.x; if(swp_max_c1 >= swp_min_c1 and swp_max_c2 >= swp_min_c2){ // Check both orientations of the cell // Get all the nets involved and uniquify them (nets with more than one pin on the cells) std::vector involved_nets; for(netlist::pin_t p : circuit.get_cell(c1)){ involved_nets.push_back(p.net_ind); } for(netlist::pin_t p : circuit.get_cell(c2)){ involved_nets.push_back(p.net_ind); } std::sort(involved_nets.begin(), involved_nets.end()); involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end()))); // Test the cost for the old position and the cost swapping the cells std::int64_t old_cost = get_nets_cost(circuit, pl, involved_nets); // Save the old values point p1 = pl.plt_.positions_[c1]; point p2 = pl.plt_.positions_[c2]; point o1 = pl.plt_.orientations_[c1]; point o2 = pl.plt_.orientations_[c2]; // Warning: won't work if the two cells don't have the same height pl.plt_.positions_[c1].x = (swp_min_c1 + swp_max_c1) / 2; pl.plt_.positions_[c2].x = (swp_min_c2 + swp_max_c2) / 2; pl.plt_.positions_[c1].y = p2.y; pl.plt_.positions_[c2].y = p1.y; // For standard cell placement, we want all the rows to be aligned in the same way if( (circuit.get_cell(c1).attributes & YFlippable) != 0 and (circuit.get_cell(c2).attributes & YFlippable) != 0) std::swap(pl.plt_.orientations_[c1].y, pl.plt_.orientations_[c2].y); if(try_flip and (circuit.get_cell(c1).attributes & XFlippable) != 0 and (circuit.get_cell(c2).attributes & XFlippable) != 0){ index_t bst_ind = 4; for(index_t i=0; i<4; ++i){ pl.plt_.orientations_[c1].x = i % 2; pl.plt_.orientations_[c2].x = i / 2; std::int64_t new_cost = get_nets_cost(circuit, pl, involved_nets); if(new_cost < old_cost){ old_cost = new_cost; bst_ind = i; } } // One of the orientations with the new positions was better if(bst_ind < 4){ pl.swap_standard_cell_topologies(c1, c2); pl.plt_.orientations_[c1].x = bst_ind % 2; pl.plt_.orientations_[c2].x = bst_ind / 2; // We kept the swap return true; } else{ pl.plt_.positions_[c1] = p1; pl.plt_.positions_[c2] = p2; pl.plt_.orientations_[c1] = o1; pl.plt_.orientations_[c2] = o2; return false; } } else if(get_nets_cost(circuit, pl, involved_nets) < old_cost){ pl.swap_standard_cell_topologies(c1, c2); return true; } else{ // Reset the old values since we didn't swap anything pl.plt_.positions_[c1] = p1; pl.plt_.positions_[c2] = p2; pl.plt_.orientations_[c1] = o1; pl.plt_.orientations_[c2] = o2; return false; } // A better solution would be // Check the cost on y depending on the position (extremely simple: two positions for each cell) // Check the cost on x depending on the position: piecewise linear and relatively complex // * Get all external pins // * Get all nets involving only one of the cells: piecewise linear cost for each of them // * For nets involving the two cells, we have an additional cost } else{ // We just cannot swap those two cells without pushing anything return false; } } inline void generic_swaps_global(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip, std::function const &)> get_nets_cost){ for(index_t main_row = 0; main_row < pl.row_cnt(); ++main_row){ for(index_t other_row = main_row+1; other_row <= std::min(pl.row_cnt()-1, main_row+row_extent) ; ++other_row){ index_t first_oc = pl.get_first_standard_cell_on_row(other_row); // The first candidate cell to be examined for(index_t c = pl.get_first_standard_cell_on_row(main_row); c != null_ind; c = pl.get_next_standard_cell_on_row(c, main_row)){ assert(pl.cell_rows_[c] == main_row); if( (circuit.get_cell(c).attributes & XMovable) == 0) continue; // Don't touch fixed cells // Number of cells after/before the end of the cell index_t nb_after = 0; index_t nb_before = 0; int_t pos_low = pl.plt_.positions_[c].x - circuit.get_cell(c).size.x, pos_hgh = pl.plt_.positions_[c].x + 2*circuit.get_cell(c).size.x; for(index_t oc=first_oc; oc != null_ind and nb_after <= row_extent; oc = pl.get_next_standard_cell_on_row(oc, other_row)){ assert(pl.cell_rows_[oc] == other_row); if( (circuit.get_cell(oc).attributes & XMovable) == 0) continue; // Don't touche fixed cells // Count the cells which should trigger stop or shouldn't be used at the next iteration if(pl.plt_.positions_[oc].x >= pos_hgh) ++nb_after; if(pl.plt_.positions_[oc].x + circuit.get_cell(oc).size.x <= pos_low) ++ nb_before; if(try_swap(circuit, pl, c, oc, try_flip, get_nets_cost)){ std::swap(c, oc); if(c == first_oc) first_oc = oc; } } while(nb_before > cell_extent){ nb_before--; first_oc = pl.get_next_standard_cell_on_row(first_oc, other_row); } } } } pl.selfcheck(); } } // End anonymous namespace void swaps_global_HPWL(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip){ generic_swaps_global(circuit, pl, row_extent, cell_extent, try_flip, [](netlist const & circuit, detailed_placement const & pl, std::vector const & involved_nets) -> std::int64_t{ std::int64_t sum = 0; for(index_t n : involved_nets){ if(circuit.get_net(n).pin_cnt <= 1) continue; sum += get_HPWL_length(circuit, pl.plt_, n); } return sum; }); } void swaps_global_RSMT(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip){ generic_swaps_global(circuit, pl, row_extent, cell_extent, try_flip, [](netlist const & circuit, detailed_placement const & pl, std::vector const & involved_nets) -> std::int64_t{ std::int64_t sum = 0; for(index_t n : involved_nets){ if(circuit.get_net(n).pin_cnt <= 1) continue; sum += get_RSMT_length(circuit, pl.plt_, n); } return sum; }); } } // namespace dp } // namespace coloquinte