coriolis/coloquinte/src/orientation.cxx

167 lines
7.1 KiB
C++

#include "coloquinte/circuit_helper.hxx"
#include <stack>
#include <functional>
#include <algorithm>
namespace coloquinte{
namespace gp{
namespace{
//index_t const null_ind = std::numeric_limits<index_t>::max();
inline void opt_orient(netlist const & circuit, placement_t & pl, std::function<int_t (point<int_t>)> i_coor, std::function<bool & (point<bool> &)> b_coor,mask_t FLIPPABLE){
std::stack<index_t> opt_cells;
for(index_t cell_ind = 0; cell_ind < circuit.cell_cnt(); ++cell_ind){
if( (circuit.get_cell(cell_ind).attributes & FLIPPABLE) != 0)
opt_cells.push(cell_ind);
}
while(not opt_cells.empty()){
index_t cell_ind = opt_cells.top(); opt_cells.pop();
assert((circuit.get_cell(cell_ind).attributes & FLIPPABLE) != 0);
// What is the current orientation?
bool old_orientation = b_coor(pl.orientations_[cell_ind]);
int_t pos = i_coor(pl.positions_[cell_ind]);
int_t size = i_coor(circuit.get_cell(cell_ind).size);
// Check both orientations of the cell
std::vector<index_t> involved_nets;
for(netlist::pin_t p : circuit.get_cell(cell_ind)){
involved_nets.push_back(p.net_ind);
}
// Deal with cells with multiple pins in one net (uniquify)
std::sort(involved_nets.begin(), involved_nets.end());
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
std::int64_t p_cost = 0, n_cost = 0;
std::vector<index_t> extreme_elements;
for(index_t n : involved_nets){
std::vector<pin_1D> other_pins;
std::vector<int_t> offsets;
for(auto p : circuit.get_net(n)){
if(p.cell_ind != cell_ind){
other_pins.push_back(pin_1D(
p.cell_ind,
i_coor(pl.positions_[p.cell_ind])
+ (b_coor(pl.orientations_[p.cell_ind]) ? i_coor(p.offset) : i_coor(circuit.get_cell(p.cell_ind).size) - i_coor(p.offset)),
0, // Don't care about the offset
(circuit.get_cell(p.cell_ind).attributes & FLIPPABLE) != 0)
);
}
else{
offsets.push_back(i_coor(p.offset));
}
}
assert(offsets.size() > 0);
if(other_pins.size() > 0){ // Else the orientation of the cell doesn't change anything
auto minmaxC = std::minmax_element(other_pins.begin(), other_pins.end());
auto minmaxO = std::minmax_element(offsets.begin(), offsets.end());
p_cost += std::max(pos + *minmaxO.second, minmaxC.second->pos) - std::min(pos + *minmaxO.first, minmaxC.first->pos);
n_cost += std::max(pos + size - *minmaxO.first, minmaxC.second->pos) - std::min(pos + size - *minmaxO.second, minmaxC.first->pos);
int_t min_pin_pos = std::min(pos + *minmaxO.second, pos + size - *minmaxO.first),
max_pin_pos = std::max(pos + *minmaxO.second, pos + size - *minmaxO.first);
// Do the extreme elements change between the two positions?
if(minmaxC.second->movable
and (minmaxC.second->pos < max_pin_pos)
and (minmaxC.second->pos > min_pin_pos) ){
extreme_elements.push_back(minmaxC.second->cell_ind);
}
if(minmaxC.first->movable
and (minmaxC.first->pos < max_pin_pos)
and (minmaxC.first->pos > min_pin_pos) ){
extreme_elements.push_back(minmaxC.first->cell_ind);
}
}
}
if(p_cost < n_cost)
b_coor(pl.orientations_[cell_ind]) = true;
if(p_cost > n_cost)
b_coor(pl.orientations_[cell_ind]) = false;
// If we changed the orientation, check the extreme pins which changed and try their cells again
if(b_coor(pl.orientations_[cell_ind]) != old_orientation){
std::sort(extreme_elements.begin(), extreme_elements.end());
extreme_elements.resize(std::distance(extreme_elements.begin(), std::unique(extreme_elements.begin(), extreme_elements.end())));
for(index_t extreme_cell : extreme_elements){
if( (circuit.get_cell(extreme_cell).attributes & FLIPPABLE) != 0)
opt_cells.push(extreme_cell);
}
}
}
}
/*
inline void spread_orient(netlist const & circuit, placement_t & pl, std::function<float_t & (point<float_t> &)> coor, mask_t FLIPPABLE){
std::vector<float_t> weights(circuit.cell_cnt(), 0.0);
for(index_t n=0; n<circuit.net_cnt(); ++n){
float_t min_pos=INF, max_pos=-INF;
float_t min_offs=INF, max_offs=-INF;
index_t min_ind=null_ind, max_ind=null_ind;
for(netlist::pin_t p : circuit.get_net(n)){
if( (circuit.get_cell(p.cell_ind).attributes & FLIPPABLE) != 0){
float_t pos = coor(pl.positions_[p.cell_ind]);
if(pos < min_pos){
min_pos = pos;
min_ind = p.cell_ind;
min_offs = coor(p.offset);
}
if(pos > max_pos){
max_pos = pos;
max_ind = p.cell_ind;
max_offs = coor(p.offset);
}
}
else{
float_t pos = coor(pl.positions_[p.cell_ind]) + coor(pl.orientations_[p.cell_ind]) * coor(p.offset);
if(pos < min_pos){
min_pos = pos;
min_ind = null_ind;
}
if(pos > max_pos){
max_pos = pos;
max_ind = null_ind;
}
}
}
float_t net_weight = circuit.get_net(n).weight;
if(min_ind != null_ind) weights[min_ind] += net_weight * min_offs;
if(max_ind != null_ind) weights[max_ind] -= net_weight * max_offs;
}
for(index_t c=0; c<circuit.cell_cnt(); ++c){
coor(pl.orientations_[c]) = (weights[c] >= 0.0) ? 1.0 : -1.0;
}
}
*/
} // End anonymous namespace
void optimize_x_orientations(netlist const & circuit, placement_t & pl){
opt_orient(circuit, pl, [](point<int_t> p) -> int_t { return p.x; }, [](point<bool> & p) -> bool & { return p.x; }, XFlippable);
}
void optimize_y_orientations(netlist const & circuit, placement_t & pl){
opt_orient(circuit, pl, [](point<int_t> p) -> int_t { return p.y; }, [](point<bool> & p) -> bool & { return p.y; }, YFlippable);
}
// Iteratively optimize feasible orientations; performs only one pass
void optimize_exact_orientations(netlist const & circuit, placement_t & pl){
optimize_x_orientations(circuit, pl);
optimize_y_orientations(circuit, pl);
}
/*
void spread_orientations(netlist const & circuit, placement_t & pl){
spread_orient(circuit, pl, [](point<float_t> & p) -> float_t & { return p.x; }, XFlippable);
spread_orient(circuit, pl, [](point<float_t> & p) -> float_t & { return p.y; }, YFlippable);
}
*/
} // namespace gp
} // namespace coloquinte