#include "coloquinte/circuit_helper.hxx" #include "coloquinte/circuit.hxx" #include namespace coloquinte{ std::int64_t get_HPWL_length(netlist const & circuit, placement_t const & pl, index_t net_ind){ if(circuit.get_net(net_ind).pin_cnt <= 1) return 0; auto pins = get_pins_1D(circuit, pl, net_ind); auto minmaxX = std::minmax_element(pins.x.begin(), pins.x.end()), minmaxY = std::minmax_element(pins.y.begin(), pins.y.end()); return ((minmaxX.second->pos - minmaxX.first->pos) + (minmaxY.second->pos - minmaxY.first->pos)); } std::int64_t get_RSMT_length(netlist const & circuit, placement_t const & pl, index_t net_ind){ if(circuit.get_net(net_ind).pin_cnt <= 1) return 0; auto pins = get_pins_2D(circuit, pl, net_ind); std::vector > points; for(pin_2D const p : pins){ points.push_back(p.pos); } return RSMT_length(points, 8); } namespace gp{ void add_force(pin_1D const p1, pin_1D const p2, linear_system & L, float_t force){ if(p1.movable && p2.movable){ L.add_force( force, p1.cell_ind, p2.cell_ind, p1.offs, p2.offs ); } else if(p1.movable){ L.add_fixed_force( force, p1.cell_ind, p2.pos, p1.offs ); } else if(p2.movable){ L.add_fixed_force( force, p2.cell_ind, p1.pos, p2.offs ); } } void add_force(pin_1D const p1, pin_1D const p2, linear_system & L, float_t tol, float_t scale){ add_force(p1, p2, L, scale/std::max(tol, static_cast(std::abs((float)(p2.pos-p1.pos))))); } point empty_linear_systems(netlist const & circuit, placement_t const & pl){ point ret = point(linear_system(circuit.cell_cnt()), linear_system(circuit.cell_cnt())); for(index_t i=0; i 1){ found_true_net = true; break; } } if( (XMovable & circuit.get_cell(i).attributes) == 0 or not found_true_net){ ret.x.add_triplet(i, i, 1.0f); ret.x.add_doublet(i, pl.positions_[i].x); } if( (YMovable & circuit.get_cell(i).attributes) == 0 or not found_true_net){ ret.y.add_triplet(i, i, 1.0f); ret.y.add_doublet(i, pl.positions_[i].y); } } return ret; } namespace{ // Anonymous namespace for helper functions void get_HPWLF(std::vector const & pins, linear_system & L, float_t tol){ if(pins.size() >= 2){ auto min_elt = std::min_element(pins.begin(), pins.end()), max_elt = std::max_element(pins.begin(), pins.end()); for(auto it = pins.begin(); it != pins.end(); ++it){ // Just comparing the iterator is poorer due to redundancies in the benchmarks! if(it != min_elt){ add_force(*it, *min_elt, L, tol, 1.0f/(pins.size()-1)); if(it != max_elt){ // Hopefully only one connexion between the min and max pins add_force(*it, *max_elt, L, tol, 1.0f/(pins.size()-1)); } } } } } void get_HPWLR(std::vector const & pins, linear_system & L, float_t tol){ std::vector sorted_pins = pins; std::sort(sorted_pins.begin(), sorted_pins.end()); // Pins are connected to the pin two places away for(index_t i=0; i+2 1){ add_force(sorted_pins[0], sorted_pins[1], L, tol, 0.5f); add_force(sorted_pins[sorted_pins.size()-1], sorted_pins[sorted_pins.size()-2], L, tol, 0.5f); } } void get_star(std::vector const & pins, linear_system & L, float_t tol, index_t star_index){ // The net is empty, but we still populate the diagonal to avoid divide by zeros if(pins.size() < 2){ L.add_triplet(star_index, star_index, 1.0f); return; } for(pin_1D p : pins){ pin_1D star_pin = pin_1D(star_index, 0, 0, true); add_force(p, star_pin, L, 1.0/pins.size()); } } void get_clique(std::vector const & pins, linear_system & L, float_t tol){ // Pins are connected to the pin two places away for(index_t i=0; i+1 get_HPWLF_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){ point L = empty_linear_systems(circuit, pl); for(index_t i=0; i= max_s) continue; auto pins = get_pins_1D(circuit, pl, i); get_HPWLF(pins.x, L.x, tol); get_HPWLF(pins.y, L.y, tol); } return L; } point get_HPWLR_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){ point L = empty_linear_systems(circuit, pl); for(index_t i=0; i= max_s) continue; auto pins = get_pins_1D(circuit, pl, i); get_HPWLR(pins.x, L.x, tol); get_HPWLR(pins.y, L.y, tol); } return L; } point get_star_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){ point L = empty_linear_systems(circuit, pl); L.x.add_variables(circuit.net_cnt()); L.y.add_variables(circuit.net_cnt()); for(index_t i=0; i= max_s){ // Put a one in the intermediate variable in order to avoid non-invertible matrices L.x.add_triplet(i+circuit.cell_cnt(), i+circuit.cell_cnt(), 1.0f); L.y.add_triplet(i+circuit.cell_cnt(), i+circuit.cell_cnt(), 1.0f); continue; } auto pins = get_pins_1D(circuit, pl, i); // Provide the index of the star's central pin in the linear system get_star(pins.x, L.x, tol, i+circuit.cell_cnt()); get_star(pins.y, L.y, tol, i+circuit.cell_cnt()); } return L; } point get_clique_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){ point L = empty_linear_systems(circuit, pl); for(index_t i=0; i= max_s) continue; auto pins = get_pins_1D(circuit, pl, i); get_clique(pins.x, L.x, tol); get_clique(pins.y, L.y, tol); } return L; } point get_MST_linear_system(netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){ point L = empty_linear_systems(circuit, pl); for(index_t i=0; i= max_s or pin_cnt <= 1) continue; auto pins = get_pins_2D(circuit, pl, i); std::vector > points; for(pin_2D const p : pins){ points.push_back(p.pos); } auto const edges = get_MST_topology(points); for(auto E : edges){ add_force(pins[E.first].x(), pins[E.second].x(), L.x, tol, 1.0f); add_force(pins[E.first].y(), pins[E.second].y(), L.y, tol, 1.0f); } } return L; } point get_RSMT_linear_system(netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){ point L = empty_linear_systems(circuit, pl); for(index_t i=0; i= max_s or pin_cnt <= 1) continue; auto pins = get_pins_2D(circuit, pl, i); std::vector > points; for(pin_2D const p : pins){ points.push_back(p.pos); } auto const edges = get_RSMT_topology(points, 8); for(auto E : edges.x){ add_force(pins[E.first].x(), pins[E.second].x(), L.x, tol, 1.0f); } for(auto E : edges.y){ add_force(pins[E.first].y(), pins[E.second].y(), L.y, tol, 1.0f); } } return L; } std::int64_t get_HPWL_wirelength(netlist const & circuit, placement_t const & pl){ std::int64_t sum = 0; for(index_t i=0; i > points; for(pin_2D const p : pins){ points.push_back(p.pos); } sum += MST_length(points); } return sum; } std::int64_t get_RSMT_wirelength(netlist const & circuit, placement_t const & pl){ std::int64_t sum = 0; for(index_t i=0; i & L, index_t nbr_iter){ std::vector x_sol, y_sol; std::vector x_guess(pl.cell_cnt()), y_guess(pl.cell_cnt()); assert(L.x.internal_size() == x_guess.size()); assert(L.y.internal_size() == y_guess.size()); for(index_t i=0; i(pl.positions_[i].x); y_guess[i] = static_cast(pl.positions_[i].y); } #pragma omp parallel sections num_threads(2) { #pragma omp section x_sol = L.x.solve_CG(x_guess, nbr_iter); #pragma omp section y_sol = L.y.solve_CG(y_guess, nbr_iter); } for(index_t i=0; i(x_sol[i]); } if( (circuit.get_cell(i).attributes & YMovable) != 0){ assert(std::isfinite(y_sol[i])); pl.positions_[i].y = static_cast(y_sol[i]); } } } // Intended to be used by pulling forces to adapt the forces to the cell's areas std::vector get_area_scales(netlist const & circuit){ std::vector ret(circuit.cell_cnt()); capacity_t int_tot_area = 0; for(index_t i=0; i(A); int_tot_area += A; } float_t inv_average_area = circuit.cell_cnt() / static_cast(int_tot_area); for(index_t i=0; i get_pulling_forces (netlist const & circuit, placement_t const & pl, float_t typical_distance){ point L = empty_linear_systems(circuit, pl); float_t typical_force = 1.0f / typical_distance; std::vector scaling = get_area_scales(circuit); for(index_t i=0; i get_linear_pulling_forces (netlist const & circuit, placement_t const & UB_pl, placement_t const & LB_pl, float_t force, float_t min_distance){ point L = empty_linear_systems(circuit, UB_pl); assert(LB_pl.cell_cnt() == UB_pl.cell_cnt()); std::vector scaling = get_area_scales(circuit); for(index_t i=0; i(std::abs((float)(UB_pl.positions_[i].x - LB_pl.positions_[i].x))), min_distance)), i, UB_pl.positions_[i].x ); L.y.add_anchor( force * scaling[i] / (std::max(static_cast(std::abs((float)(UB_pl.positions_[i].y - LB_pl.positions_[i].y))), min_distance)), i, UB_pl.positions_[i].y ); } return L; } region_distribution get_rough_legalizer(netlist const & circuit, placement_t const & pl, box surface){ return region_distribution::uniform_density_distribution(surface, circuit, pl); } void get_rough_legalization(netlist const & circuit, placement_t & pl, region_distribution const & legalizer){ auto exportation = legalizer.export_spread_positions_linear(); for(auto const C : exportation){ pl.positions_[C.index_in_placement_] = static_cast >(C.pos_ - 0.5f * static_cast >(circuit.get_cell(C.index_in_placement_).size)); } } float_t get_mean_linear_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl){ float_t tot_cost = 0.0; float_t tot_area = 0.0; for(index_t i=0; i(circuit.get_cell(i).area); point diff = LB_pl.positions_[i] - UB_pl.positions_[i]; if( (circuit.get_cell(i).attributes & XMovable) == 0) assert(diff.x == 0); if( (circuit.get_cell(i).attributes & YMovable) == 0) assert(diff.y == 0); tot_cost += area * (std::abs((float)diff.x) + std::abs((float)diff.y)); tot_area += area; } return tot_cost / tot_area; } float_t get_mean_quadratic_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl){ float_t tot_cost = 0.0; float_t tot_area = 0.0; for(index_t i=0; i(circuit.get_cell(i).area); point diff = LB_pl.positions_[i] - UB_pl.positions_[i]; if( (circuit.get_cell(i).attributes & XMovable) == 0) assert(diff.x == 0); if( (circuit.get_cell(i).attributes & YMovable) == 0) assert(diff.y == 0); float_t manhattan = (std::abs((float)diff.x) + std::abs((float)diff.y)); tot_cost += area * manhattan * manhattan; tot_area += area; } return std::sqrt(tot_cost / tot_area); } } // namespace gp } // namespace coloquinte