Skip to content

Commit

Permalink
routing api (#359)
Browse files Browse the repository at this point in the history
* fix warnings, start working on abstract merging

* basic routing api
  • Loading branch information
rohanku authored Dec 31, 2023
1 parent 4019d4d commit 62a9514
Show file tree
Hide file tree
Showing 5 changed files with 464 additions and 272 deletions.
215 changes: 197 additions & 18 deletions libs/atoll/src/abs.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
//! Generate abstract views of layout cells.
use crate::grid::{LayerSlice, LayerStack, PdkLayer, RoutingGrid, RoutingState};
use crate::{NetId, PointState};
use crate::grid::{AtollLayer, LayerSlice, LayerStack, PdkLayer, RoutingGrid, RoutingState};
use crate::{NetId, Orientation, PointState};
use grid::Grid;
use num::integer::{div_ceil, div_floor};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use substrate::arcstr::ArcStr;
use substrate::block::Block;
use substrate::geometry::bbox::Bbox;
use substrate::geometry::transform::Transformation;
use substrate::geometry::transform::{Transformation, Translate, TranslateMut};
use substrate::layout::element::Text;

use substrate::context::PdkContext;
use substrate::geometry::dir::Dir;
use substrate::geometry::point::Point;
use substrate::geometry::rect::Rect;
use substrate::io::layout::Builder;
Expand All @@ -31,6 +32,7 @@ pub struct TrackCoord {
pub y: i64,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct GridCoord {
pub layer: usize,
pub x: usize,
Expand All @@ -47,18 +49,18 @@ pub struct GridCoord {
/// * Grid coordinates: these have the same spacing as track coordinates, but are shifted so that (0, 0) is always at the lower left. These are used to index [`LayerAbstract`]s.
///
/// ATOLL provides the following utilities for converting between these coordinate systems:
/// * Grid to physical: [`AtollAbstract::grid_to_physical`]
/// * Track to physical: [`AtollAbstract::track_to_physical`]
/// * Grid to track: [`AtollAbstract::grid_to_track`]
/// * Track to grid: [`AtollAbstract::track_to_grid`]
/// * Grid to physical: [`Abstract::grid_to_physical`]
/// * Track to physical: [`Abstract::track_to_physical`]
/// * Grid to track: [`Abstract::grid_to_track`]
/// * Track to grid: [`Abstract::track_to_grid`]
/// * Physical to track: [`RoutingGrid::point_to_grid`]
///
/// For converting physical to grid: convert the physical coordinates to track coordinates,
/// then convert track coordinates to physical coordinates.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct AtollAbstract {
pub struct Abstract {
/// The topmost ATOLL layer used within the tile.
pub(crate) top_layer: usize,
top_layer: usize,
/// The bounds of the tile, in LCM units with respect to `top_layer`.
///
/// The "origin" of the tile, in LCM units, is the lower left of this rectangle.
Expand All @@ -75,7 +77,7 @@ pub struct AtollAbstract {
pub(crate) grid: RoutingGrid<PdkLayer>,
}

impl AtollAbstract {
impl Abstract {
pub fn physical_bounds(&self) -> Rect {
let slice = self.slice();
let w = slice.lcm_unit_width();
Expand All @@ -88,17 +90,38 @@ impl AtollAbstract {
)
}

pub fn routing_state(&self) -> RoutingState<PdkLayer> {
let mut state = RoutingState::new(
self.grid.stack.clone(),
self.top_layer,
self.lcm_bounds.width(),
self.lcm_bounds.height(),
);
for (i, layer) in self.layers.iter().enumerate() {
match layer {
LayerAbstract::Available => {}
LayerAbstract::Blocked => {
state.layer_mut(i).fill(PointState::Blocked);
}
LayerAbstract::Detailed { states } => {
*state.layer_mut(i) = states.clone();
}
}
}
state
}

/// Converts a grid point to a physical point in the coordinates of the cell.
///
/// See [coordinate systems](AtollAbstract#coordinates) for more information.
/// See [coordinate systems](Abstract#coordinates) for more information.
pub fn grid_to_physical(&self, coord: GridCoord) -> Point {
let coord = self.grid_to_track(coord);
self.track_to_physical(coord)
}

/// Converts a track point to a physical point in the coordinates of the cell.
///
/// See [coordinate systems](AtollAbstract#coordinates) for more information.
/// See [coordinate systems](Abstract#coordinates) for more information.
pub fn track_to_physical(&self, coord: TrackCoord) -> Point {
self.grid.xy_track_point(coord.layer, coord.x, coord.y)
}
Expand All @@ -113,7 +136,7 @@ impl AtollAbstract {

/// Converts a grid point to a track point in the coordinates of the cell.
///
/// See [coordinate systems](AtollAbstract#coordinates) for more information.
/// See [coordinate systems](Abstract#coordinates) for more information.
pub fn grid_to_track(&self, coord: GridCoord) -> TrackCoord {
TrackCoord {
layer: coord.layer,
Expand All @@ -124,7 +147,7 @@ impl AtollAbstract {

/// Converts a track point to a grid point in the coordinates of the cell.
///
/// See [coordinate systems](AtollAbstract#coordinates) for more information.
/// See [coordinate systems](Abstract#coordinates) for more information.
pub fn track_to_grid(&self, coord: TrackCoord) -> GridCoord {
let x = coord.x - self.xofs(coord.layer);
let y = coord.y - self.yofs(coord.layer);
Expand Down Expand Up @@ -155,7 +178,7 @@ impl AtollAbstract {
pub fn generate<PDK: Pdk, T: ExportsNestedData + ExportsLayoutData>(
ctx: &PdkContext<PDK>,
layout: &layout::Cell<T>,
) -> AtollAbstract {
) -> Abstract {
let stack = ctx
.get_installation::<LayerStack<PdkLayer>>()
.expect("must install ATOLL layer stack");
Expand Down Expand Up @@ -219,7 +242,7 @@ impl AtollAbstract {
.map(|states| LayerAbstract::Detailed { states })
.collect();

AtollAbstract {
Abstract {
top_layer: top,
lcm_bounds,
grid: RoutingGrid::new((*stack).clone(), 0..top + 1),
Expand All @@ -229,9 +252,164 @@ impl AtollAbstract {
}
}

#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct InstanceAbstract {
// todo: Arc and have instances reference same abstract if corresponding to same cell.
abs: Abstract,
orientation: Orientation,
parent_net_ids: Vec<NetId>,
}

impl InstanceAbstract {
pub(crate) fn new(
mut abs: Abstract,
loc: Point,
orientation: Orientation,
parent_net_ids: Vec<NetId>,
) -> Self {
abs.lcm_bounds.translate_mut(loc);
Self {
abs,
orientation,
parent_net_ids,
}
}
}

impl InstanceAbstract {
pub fn physical_bounds(&self) -> Rect {
self.abs.physical_bounds()
}

pub fn lcm_bounds(&self) -> Rect {
self.abs.lcm_bounds
}

pub fn merge(mut others: Vec<Self>) -> Abstract {
assert!(!others.is_empty());
// Guarantee that `primary` always has the max top layer.
let mut primary = others.pop().unwrap();
for other in &mut others {
if other.abs.top_layer > primary.abs.top_layer {
std::mem::swap(&mut primary, other);
}
}

let stack = &primary.abs.grid.stack;
let physical_bounds = others
.iter()
.fold(primary.physical_bounds(), |bounds, other| {
bounds.union(other.physical_bounds())
});
let new_bounds = primary
.abs
.grid
.slice()
.expand_to_lcm_units(physical_bounds);
let new_physical_bounds = primary.abs.grid.slice().lcm_to_physical_rect(new_bounds);
let mut state = RoutingState::new(
stack.clone(),
primary.abs.top_layer,
new_bounds.width(),
new_bounds.height(),
);

for inst in std::iter::once(&primary).chain(&others) {
let net_translation: HashMap<_, _> = inst
.abs
.ports
.iter()
.copied()
.zip(inst.parent_net_ids.iter().copied())
.collect();
for i in 0..=inst.abs.top_layer {
let layer = stack.layer(i);
let parallel_pitch = layer.pitch();
let perp_pitch = stack.layer(primary.abs.grid.grid_defining_layer(i)).pitch();

let (xpitch, ypitch) = match layer.dir().track_dir() {
Dir::Horiz => (perp_pitch, parallel_pitch),
Dir::Vert => (parallel_pitch, perp_pitch),
};

let left_offset =
(inst.physical_bounds().left() - new_physical_bounds.left()) / xpitch;
let bot_offset =
(inst.physical_bounds().bot() - new_physical_bounds.bot()) / ypitch;
let track_width = inst.physical_bounds().width() / xpitch;
let track_height = inst.physical_bounds().height() / ypitch;

for x in left_offset..left_offset + track_width {
for y in bot_offset..bot_offset + track_height {
let point_state = &mut state.layer_mut(i)[(x as usize, y as usize)];
match &inst.abs.layers[i] {
LayerAbstract::Available => {}
abs @ LayerAbstract::Blocked => {
assert_eq!(point_state, &PointState::Available);
*point_state = PointState::Blocked;
}
LayerAbstract::Detailed { states } => {
let new_state = states[match inst.orientation {
Orientation::R0 => {
((x - left_offset) as usize, (y - bot_offset) as usize)
}
Orientation::R180 => (
(2 * left_offset + track_width - x) as usize,
(2 * bot_offset + track_height - y) as usize,
),
Orientation::ReflectVert => (
(x - left_offset) as usize,
(2 * bot_offset + track_height - y) as usize,
),
Orientation::ReflectHoriz => (
(2 * left_offset + track_width - x) as usize,
(y - bot_offset) as usize,
),
}];

match new_state {
PointState::Available => {}
PointState::Blocked => {
assert_eq!(point_state, &PointState::Available);
*point_state = PointState::Blocked;
}
PointState::Routed {
net,
via_up,
via_down,
} => {
assert_eq!(point_state, &PointState::Available);
*point_state = PointState::Routed {
net: net_translation[&net],
via_up,
via_down,
};
}
}
}
}
}
}
}
}

Abstract {
lcm_bounds: new_bounds,
layers: state
.layers
.into_iter()
.map(|states| LayerAbstract::Detailed { states })
.collect(),
..primary.abs
}
}
}

/// The abstracted state of a single routing layer.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum LayerAbstract {
/// The layer is fully available.
Available,
/// The layer is fully blocked.
///
/// No routing on this layer is permitted.
Expand Down Expand Up @@ -278,7 +456,7 @@ fn top_layer_inner(

#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct DebugAbstract {
pub abs: AtollAbstract,
pub abs: Abstract,
pub stack: LayerStack<PdkLayer>,
}

Expand Down Expand Up @@ -316,6 +494,7 @@ impl<PDK: Pdk> Draw<PDK> for &DebugAbstract {
for (i, layer) in self.abs.layers.iter().enumerate() {
let layer_id = self.abs.grid.stack.layer(i).id;
match layer {
LayerAbstract::Available => {}
LayerAbstract::Blocked => {
recv.draw(Shape::new(layer_id, self.abs.physical_bounds()))?;
}
Expand All @@ -326,7 +505,7 @@ impl<PDK: Pdk> Draw<PDK> for &DebugAbstract {
let pt = self.abs.grid_to_physical(GridCoord { layer: i, x, y });
let rect = match states[(x, y)] {
PointState::Available => Rect::from_point(pt).expand_all(20),
PointState::Obstructed => Rect::from_point(pt).expand_all(40),
PointState::Blocked => Rect::from_point(pt).expand_all(40),
PointState::Routed { .. } => Rect::from_point(pt).expand_all(30),
};
recv.draw(Shape::new(layer_id, rect))?;
Expand Down
9 changes: 1 addition & 8 deletions libs/atoll/src/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ impl<'a, L: AtollLayer> LayerSlice<'a, L> {
/// A fixed-size routing grid.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct RoutingGrid<L> {
pub(crate) stack: LayerStack<L>,
pub stack: LayerStack<L>,
start: usize,
end: usize,
}
Expand Down Expand Up @@ -614,13 +614,6 @@ impl<L: AtollLayer + Clone> RoutingState<L> {
let layer = stack.layer(i);
let dim = slice.lcm_unit(!layer.dir().track_dir());
let num_tracks = dim / layer.pitch();
println!(
"dim = {dim}, layer pitch = {}, num tracks = {}, nx = {}, ny = {}",
layer.pitch(),
num_tracks,
nx,
ny
);
let perp_layer = stack.layer(grid.grid_defining_layer(i));
let perp_dim = slice.lcm_unit(!perp_layer.dir().track_dir());
let perp_tracks = perp_dim / perp_layer.pitch();
Expand Down
Loading

0 comments on commit 62a9514

Please sign in to comment.