libreda-pnr 0.0.4

Algorithm interface definitions of the LibrEDA place-and-route framework.
Documentation
// Copyright (c) 2020-2021 Thomas Kramer.
// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

//! A cascade placer uses a chain of placement algorithms to subsequently refine
//! the placement. For example the first stage finds a rough initial placement that will
//! be used as the initial state for the optimization in the second stage.

use super::stdcell_placer::SimpleStdCellPlacer;
use std::collections::{HashMap, HashSet};
use libreda_db::prelude::{SimplePolygon, Point};
use libreda_db::prelude as db;
use log::debug;
use libreda_db::netlist::traits::NetlistBase;

/// A pipeline of placers. The result of the first stage is
/// used as the initial placement for the next stage.
pub struct SimpleStdCellPlacerCascade<N: NetlistBase> {
    stages: Vec<Box<dyn SimpleStdCellPlacer<N>>>
}

impl<N: NetlistBase> SimpleStdCellPlacerCascade<N> {
    /// Create a new placer cascade.
    pub fn new(placers: Vec<Box<dyn SimpleStdCellPlacer<N>>>) -> Self {
        SimpleStdCellPlacerCascade {
            stages: placers
        }
    }
}

impl<N: NetlistBase> SimpleStdCellPlacer<N> for SimpleStdCellPlacerCascade<N> {
    fn name(&self) -> &str {
        "SimpleCascadePlacer"
    }

    fn find_cell_positions_impl(&self,
                                netlist: &N,
                                circuit_id: &N::CellId,
                                core_area: &SimplePolygon<db::Coord>,
                                initial_positions: &HashMap<N::CellInstId, Point<db::Coord>>,
                                fixed_instances: &HashSet<N::CellInstId>,
                                cell_outlines: &HashMap<N::CellId, db::Rect<db::Coord>>,
                                net_weights: &HashMap<N::NetId, f64>,
    ) -> HashMap<N::CellInstId, Point<i32>> {
        debug!("Placer cascade contains {} placers.", self.stages.len());

        let mut initial_pos = initial_positions.clone();

        // Use each placer after the other.
        for placer in &self.stages {
            let mut result = placer.find_cell_positions(
                netlist,
                circuit_id,
                core_area,
                &initial_pos,
                fixed_instances,
                cell_outlines,
                net_weights
            );

            // Carry-on positions of fixed instances.
            for inst in fixed_instances {
                result.insert(inst.clone(), initial_positions[inst]);
            }

            // Update the initial positions.
            initial_pos = result;
        }

        // Return the last placement result.
        initial_pos
    }
}