1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Copyright (c) 2020-2021 Thomas Kramer.
 *
 * This file is part of LibrEDA
 * (see https://codeberg.org/libreda).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

//! 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> {

}