Skip to content

Commit

Permalink
fix route drawing logic (#360)
Browse files Browse the repository at this point in the history
* fix route drawing logic

* remove tiling
  • Loading branch information
rohanku authored Jan 2, 2024
1 parent 84acd2f commit b141210
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 44 deletions.
55 changes: 25 additions & 30 deletions libs/atoll/src/abs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ impl GridCoord {
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Abstract {
/// The topmost ATOLL layer used within the tile.
top_layer: usize,
pub(crate) 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.
lcm_bounds: Rect,
pub(crate) lcm_bounds: Rect,
/// The state of each layer, up to and including `top_layer`.
///
/// Ports on layers not supported by ATOLL are ignored.
Expand Down Expand Up @@ -235,9 +235,7 @@ impl Abstract {
p.bbox().expect("empty polygons are unsupported")
}
};
println!("source rect = {rect:?}");
if let Some(rect) = grid.shrink_to_grid(rect, layer) {
println!("grid rect = {rect:?}");
for x in rect.left()..=rect.right() {
for y in rect.bot()..=rect.top() {
let xofs = xmin * slice.lcm_unit_width() / grid.xpitch(layer);
Expand Down Expand Up @@ -299,36 +297,30 @@ impl InstanceAbstract {
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);
}
}
pub fn merge(mut abstracts: Vec<Self>, mut top_layer: usize) -> Abstract {
assert!(!abstracts.is_empty());

let stack = &primary.abs.grid.stack;
let physical_bounds = others
for abs in &abstracts {
top_layer = std::cmp::max(top_layer, abs.abs.top_layer);
}
let physical_bounds = abstracts
.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);
.map(|abs| abs.physical_bounds())
.reduce(|acc, next| acc.union(next))
.unwrap();

let grid = RoutingGrid::new(abstracts[0].abs.grid.stack.clone(), 0..top_layer + 1);

let new_bounds = grid.slice().expand_to_lcm_units(physical_bounds);
let new_physical_bounds = grid.slice().lcm_to_physical_rect(new_bounds);
let mut state = RoutingState::new(
stack.clone(),
primary.abs.top_layer,
grid.stack.clone(),
top_layer,
new_bounds.width(),
new_bounds.height(),
);

for inst in std::iter::once(&primary).chain(&others) {
for inst in &abstracts {
let net_translation: HashMap<_, _> = inst
.abs
.ports
Expand All @@ -337,9 +329,9 @@ impl InstanceAbstract {
.zip(inst.parent_net_ids.iter().copied())
.collect();
for i in 0..=inst.abs.top_layer {
let layer = stack.layer(i);
let layer = grid.stack.layer(i);
let parallel_pitch = layer.pitch();
let perp_pitch = stack.layer(primary.abs.grid.grid_defining_layer(i)).pitch();
let perp_pitch = grid.stack.layer(grid.grid_defining_layer(i)).pitch();

let (xpitch, ypitch) = match layer.dir().track_dir() {
Dir::Horiz => (perp_pitch, parallel_pitch),
Expand Down Expand Up @@ -401,14 +393,17 @@ impl InstanceAbstract {
}
}

// todo: handle ports
Abstract {
top_layer,
lcm_bounds: new_bounds,
layers: state
.layers
.into_iter()
.map(|states| LayerAbstract::Detailed { states })
.collect(),
..primary.abs
ports: Vec::new(),
grid,
}
}
}
Expand Down
105 changes: 94 additions & 11 deletions libs/atoll/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ pub mod abs;
pub mod grid;
pub mod route;

use crate::abs::{Abstract, DebugAbstract, InstanceAbstract};
use crate::abs::{Abstract, DebugAbstract, InstanceAbstract, TrackCoord};
use crate::grid::{AtollLayer, LayerStack, PdkLayer};
use crate::route::Router;
use crate::route::{Router, ViaMaker};
use ena::unify::UnifyKey;
use serde::{Deserialize, Serialize};
use std::any::Any;
Expand All @@ -168,6 +168,7 @@ use substrate::io::schematic::{Bundle, Connect, Node, TerminalView};
use substrate::io::{FlatLen, Flatten};
use substrate::layout::element::Shape;

use substrate::geometry::rect::Rect;
use substrate::layout::{ExportsLayoutData, Layout};
use substrate::pdk::layers::{HasPin, Layers};
use substrate::pdk::Pdk;
Expand Down Expand Up @@ -373,6 +374,18 @@ impl<T: ExportsNestedData + ExportsLayoutData> Instance<T> {
let h = slice.lcm_unit_height();
Point::new(self.loc.x * w, self.loc.y * h)
}

pub fn top_layer(&self) -> usize {
self.abs.top_layer
}

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

pub fn physical_bounds(&self) -> Rect {
self.abs.physical_bounds().translate(self.physical_loc())
}
}

/// A builder for ATOLL tiles.
Expand All @@ -384,8 +397,10 @@ pub struct TileBuilder<'a, PDK: Pdk + Schema> {
layer_stack: Arc<LayerStack<PdkLayer>>,
/// Abstracts of instantiated instances.
abs: Vec<InstanceAbstract>,
top_layer: usize,
next_net_id: usize,
router: Option<Arc<dyn Router>>,
via_maker: Option<Arc<dyn ViaMaker<PDK>>>,
}

impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> {
Expand Down Expand Up @@ -418,9 +433,11 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> {
schematic,
layout,
layer_stack,
top_layer: 0,
abs: Vec::new(),
next_net_id: 0,
router: None,
via_maker: None,
};

builder.register_bundle(schematic_io);
Expand Down Expand Up @@ -488,6 +505,8 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> {
.zip(parent_net_ids.iter())
.for_each(|(node, net)| self.nodes.get_mut(node).unwrap().nets.push(*net));

self.set_top_layer(instance.abs.top_layer);

self.abs.push(InstanceAbstract::new(
instance.abs,
instance.loc,
Expand Down Expand Up @@ -554,9 +573,21 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> {
self.layout.ctx()
}

/// Sets the top layer of this tile, dictating the layers available for routing.
///
/// If the top layer is set to below the top layer of a constituent tile, it will be
/// overwritten to the top layer of the constituent tile with the highest top layer.
pub fn set_top_layer(&mut self, top_layer: usize) {
self.top_layer = std::cmp::max(self.top_layer, top_layer);
}

pub fn set_router<T: Any + Router>(&mut self, router: T) {
self.router = Some(Arc::new(router));
}

pub fn set_via_maker<T: Any + ViaMaker<PDK>>(&mut self, via_maker: T) {
self.via_maker = Some(Arc::new(via_maker));
}
}

/// A builder for an ATOLL tile's IOs.
Expand Down Expand Up @@ -663,7 +694,7 @@ where
let mut cell = TileBuilder::new(&schematic_io, &mut schematic_cell, cell);
let (_, layout_data) = <T as Tile<PDK>>::tile(&self.0, io, &mut cell)?;

let abs = InstanceAbstract::merge(cell.abs);
let abs = InstanceAbstract::merge(cell.abs, cell.top_layer);

if let Some(router) = cell.router {
let mut to_connect = HashMap::new();
Expand All @@ -681,16 +712,68 @@ where
let (a, b) = (abs.grid_to_track(segment[0]), abs.grid_to_track(segment[1]));
if a.layer == b.layer {
// todo: handle multiple routing directions
cell.layout.draw(Shape::new(
abs.grid.stack.layer(a.layer).id,
if a.x == b.x {
abs.grid.track(a.layer, a.x, a.y, b.y)
} else if a.y == b.y {
abs.grid.track(a.layer, a.y, a.x, b.x)
assert!(a.x == b.x || a.y == b.y);
let layer = abs.grid.stack.layer(a.layer);
let (start_track, start_cross_track, end_track, end_cross_track) =
if layer.dir().track_dir() == Dir::Vert {
(a.x, a.y, b.x, b.y)
} else {
(a.y, a.x, b.y, b.x)
};
let start = abs
.grid
.track_point(a.layer, start_track, start_cross_track);
let end = abs.grid.track_point(b.layer, end_track, end_cross_track);
let track = Rect::from_point(start)
.union(Rect::from_point(end))
.expand_dir(
if a.x == b.x { Dir::Horiz } else { Dir::Vert },
abs.grid.stack.layer(a.layer).line() / 2,
)
.expand_dir(
if a.y == b.y { Dir::Horiz } else { Dir::Vert },
abs.grid.stack.layer(a.layer).endcap(),
);

cell.layout
.draw(Shape::new(abs.grid.stack.layer(a.layer).id, track))?;
} else if a.layer == b.layer + 1 || b.layer == a.layer + 1 {
let (a, b) = if b.layer > a.layer { (b, a) } else { (a, b) };
let (in_track, out_track) =
if abs.grid.stack.layer(a.layer).dir().track_dir() == Dir::Horiz
&& a.x == b.x
{
(
abs.grid.track(b.layer, b.x, b.y, b.y),
abs.grid.track_point(a.layer, a.y, a.x),
)
} else if abs.grid.stack.layer(a.layer).dir().track_dir() == Dir::Vert
&& a.y == b.y
{
(
abs.grid.track(b.layer, b.y, b.x, b.x),
abs.grid.track_point(a.layer, a.x, a.y),
)
} else {
panic!("cannot have a diagonal segment");
},
))?;
};

let track = Rect::from_spans(
in_track.hspan().add_point(out_track.x),
in_track.vspan().add_point(out_track.y),
);
cell.layout
.draw(Shape::new(abs.grid.stack.layer(b.layer).id, track))?;
if let Some(maker) = &cell.via_maker {
maker.draw_via(
cell.layout,
TrackCoord {
layer: a.layer,
x: a.x,
y: a.y,
},
)?;
}
}
}
}
Expand Down
12 changes: 11 additions & 1 deletion libs/atoll/src/route.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/// Routing interfaces and implementations.
use crate::abs::{Abstract, GridCoord};
use crate::abs::{Abstract, GridCoord, TrackCoord};
use crate::grid::{PdkLayer, RoutingState};
use crate::{NetId, PointState};
use pathfinding::prelude::dijkstra;
use std::collections::HashMap;
use substrate::layout;
use substrate::pdk::Pdk;

pub type Path = Vec<GridCoord>;

Expand Down Expand Up @@ -57,3 +59,11 @@ impl Router for GreedyBfsRouter {
paths
}
}

pub trait ViaMaker<PDK: Pdk> {
fn draw_via(
&self,
cell: &mut layout::CellBuilder<PDK>,
track_coord: TrackCoord,
) -> substrate::error::Result<()>;
}
48 changes: 47 additions & 1 deletion pdks/sky130pdk/src/atoll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::layers::Sky130Layers;
use crate::mos::{MosParams, Nfet01v8, Pfet01v8};
use crate::Sky130Pdk;
use arcstr::ArcStr;
use atoll::abs::TrackCoord;
use atoll::grid::{AbstractLayer, LayerStack, PdkLayer, RoutingGrid};
use atoll::route::ViaMaker;
use atoll::RoutingDir;
use serde::{Deserialize, Serialize};

Expand All @@ -13,6 +15,7 @@ use substrate::geometry::bbox::Bbox;
use substrate::geometry::dir::Dir;
use substrate::geometry::rect::Rect;
use substrate::geometry::span::Span;
use substrate::geometry::transform::Translate;
use substrate::io::layout::IoShape;
use substrate::io::{Array, InOut, Input, Io, MosIoSchematic, Signal};
use substrate::layout::element::Shape;
Expand All @@ -35,7 +38,7 @@ impl Sky130Layers {
line: 170,
space: 260,
offset: 85,
endcap: 0,
endcap: 85,
},
},
PdkLayer {
Expand Down Expand Up @@ -95,6 +98,49 @@ impl Sky130Layers {
}
}

pub struct Sky130ViaMaker;

impl ViaMaker<Sky130Pdk> for Sky130ViaMaker {
fn draw_via(
&self,
cell: &mut CellBuilder<Sky130Pdk>,
track_coord: TrackCoord,
) -> substrate::error::Result<()> {
let stack = cell.ctx.get_installation::<LayerStack<PdkLayer>>().unwrap();
let grid = RoutingGrid::new((*stack).clone(), 0..track_coord.layer + 1);
let top_layer = stack.layer(track_coord.layer);
let bot_layer = stack.layer(track_coord.layer - 1);

let via_center = grid.xy_track_point(track_coord.layer, track_coord.x, track_coord.y);

let (via_layer, bot_rect, via_rect, top_rect) = match track_coord.layer {
1 => (
cell.ctx.layers.mcon.drawing.id(),
Rect::from_sides(0, 0, 170, 170),
Rect::from_sides(0, 0, 170, 170),
Rect::from_sides(-60, -45, 230, 215),
),
2 => (
cell.ctx.layers.via.drawing.id(),
Rect::from_sides(-125, -55, 275, 205),
Rect::from_sides(0, 0, 150, 150),
Rect::from_sides(-125, -55, 275, 205),
),
_ => todo!(),
};
let translation = via_center - via_rect.center();

for (layer, shape) in [
(bot_layer.id, bot_rect),
(via_layer, via_rect),
(top_layer.id, top_rect),
] {
cell.draw(Shape::new(layer, shape).translate(translation))?;
}
Ok(())
}
}

/// The set of supported gate lengths.
#[derive(
Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Default, Serialize, Deserialize,
Expand Down
Loading

0 comments on commit b141210

Please sign in to comment.