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 `Design` structure collects information necessary for the place and route steps.
//! This includes the netlist and layout, properties of cell instances, etc.
//! Between `Design` structures and place & route engines lies an abstraction layer
//! made by traits such as [`PlacementProblem`].
//!
//! [`SimpleDesign`] is an example of how place & route information can be encapsulated.

use libreda_db::prelude as db;

use std::collections::HashMap;

use super::place::placement_problem::{PlacementProblem, PlacementStatus};
use super::route::routing_problem::{RoutingProblem, GlobalRoutingProblem};
use db::{SimpleRPolygon, Rect, SimpleTransform};

/// Collection of data representing the chip during the place & route flow.
/// This struct owns the data. In contrast, [`SimpleDesignRef`] does only borrow
/// the data.
pub struct SimpleDesign<C: db::L2NBase> {
    /// Base layout and netlist data-structure.
    pub fused_layout_netlist: C,
    /// Cell which contains the instances to be placed.
    pub top_cell: C::CellId,
    /// Outline shapes of the cells to be placed.
    pub cell_outlines: HashMap<C::CellId, db::Rect<C::Coord>>,
    /// Regions where cells are allowed to be placed.
    pub placement_region: Vec<SimpleRPolygon<C::Coord>>,
    /// Placement status of the cell instances. Default is `Movable`.
    pub placement_status: HashMap<C::CellInstId, PlacementStatus>
}

impl<C: db::L2NBase> SimpleDesign<C> {
    /// Set the placement status of a cell instance.
    pub fn set_placement_status(&mut self, cell_inst: C::CellInstId, placement_status: PlacementStatus) {
        self.placement_status.insert(cell_inst, placement_status);
    }
}


impl<C: db::L2NBase> PlacementProblem<C> for SimpleDesign<C> {
    fn fused_layout_netlist(&self) -> &C {
        &self.fused_layout_netlist
    }

    fn top_cell(&self) -> C::CellId {
        self.top_cell.clone()
    }

    fn placement_region(&self) -> Vec<SimpleRPolygon<C::Coord>> {
        self.placement_region.clone()
    }

    fn initial_position(&self, cell_instance: &C::CellInstId) -> SimpleTransform<C::Coord> {
        self.fused_layout_netlist.get_transform(cell_instance)
    }

    fn placement_status(&self, cell_instance: &C::CellInstId) -> PlacementStatus {
        self.placement_status.get(cell_instance)
            .copied()
            .unwrap_or(PlacementStatus::Ignore)
    }

    fn cell_outline(&self, cell: &C::CellId) -> Option<Rect<C::Coord>> {
        self.cell_outlines.get(cell).copied()
    }
}

/// Collection of data representing the chip during the place & route flow.
/// This struct borrows the data. In contrast, [`SimpleDesign`] owns
/// the data.
pub struct SimpleDesignRef<'a, C: db::L2NBase> {
    /// Base layout and netlist data-structure.
    pub fused_layout_netlist: &'a C,
    /// Cell which contains the instances to be placed.
    pub top_cell: C::CellId,
    /// Outline shapes of the cells to be placed.
    pub cell_outlines: &'a HashMap<C::CellId, db::Rect<C::Coord>>,
    /// Regions where cells are allowed to be placed.
    pub placement_region: &'a Vec<SimpleRPolygon<C::Coord>>,
    /// Placement status of the cell instances. Default is `Movable`.
    pub placement_status: &'a HashMap<C::CellInstId, PlacementStatus>,
    /// Net weights. Default for nets which are not in the hash map is `1.0`.
    pub net_weights: &'a HashMap<C::NetId, f64>,
    /// Overwrite the location information from the `fused_layout_netlist`.
    pub placement_location: &'a HashMap<C::CellInstId, db::SimpleTransform<C::Coord>>
}


impl<'a, C: db::L2NBase> PlacementProblem<C> for SimpleDesignRef<'a, C> {
    fn fused_layout_netlist(&self) -> &C {
        self.fused_layout_netlist
    }

    fn top_cell(&self) -> C::CellId {
        self.top_cell.clone()
    }

    fn placement_region(&self) -> Vec<SimpleRPolygon<C::Coord>> {
        self.placement_region.to_vec()
    }

    fn initial_position(&self, cell_instance: &C::CellInstId) -> SimpleTransform<C::Coord> {
        self.placement_location.get(cell_instance)
            .cloned()
            .unwrap_or_else(|| self.fused_layout_netlist.get_transform(cell_instance))
    }

    fn placement_status(&self, cell_instance: &C::CellInstId) -> PlacementStatus {
        self.placement_status.get(cell_instance)
            .copied()
            .unwrap_or(PlacementStatus::Ignore)
    }

    fn cell_outline(&self, cell: &C::CellId) -> Option<Rect<C::Coord>> {
        self.cell_outlines.get(cell).copied()
    }

    fn net_weight(&self, net_id: &C::NetId) -> f64 {
        self.net_weights.get(net_id).copied().unwrap_or(1.0)
    }
}


impl<'a, C: db::L2NBase> RoutingProblem<C> for SimpleDesignRef<'a, C> {
    fn fused_layout_netlist(&self) -> &C {
        self.fused_layout_netlist
    }

    fn top_cell(&self) -> C::CellId {
        self.top_cell.clone()
    }

    fn nets(&self) -> Box<dyn Iterator<Item=C::NetId> + '_> {
        Box::new(self.fused_layout_netlist.each_internal_net(&self.top_cell))
    }

    fn net_weight(&self, net: &C::NetId) -> f64 {
        self.net_weights.get(net).copied().unwrap_or(1.0)
    }

    fn blockages(&self) -> Box<dyn Iterator<Item=(C::LayerId, db::SimpleRPolygon<C::Coord>)>> {
        Box::new(std::iter::empty())
    }


    fn boundary(&self) -> Option<db::SimpleRPolygon<C::Coord>> {
        unimplemented!("boundary")
    }
}

impl<'a, C: db::L2NBase> GlobalRoutingProblem<C> for SimpleDesignRef<'a, C> {

}