Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix route drawing logic #360

Merged
merged 3 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading