From d89177a745b8465a22cecd3cc09db679a3c131f5 Mon Sep 17 00:00:00 2001 From: rohanku Date: Sun, 31 Dec 2023 12:47:48 -0800 Subject: [PATCH] basic routing api --- libs/atoll/src/abs.rs | 185 +++++++++++++++++++++- libs/atoll/src/grid.rs | 9 +- libs/atoll/src/lib.rs | 332 ++++++++++++++++++---------------------- libs/atoll/src/route.rs | 34 ++++ tests/src/atoll/mod.rs | 7 +- 5 files changed, 365 insertions(+), 202 deletions(-) create mode 100644 libs/atoll/src/route.rs diff --git a/libs/atoll/src/abs.rs b/libs/atoll/src/abs.rs index c12e1d56..34345fd4 100644 --- a/libs/atoll/src/abs.rs +++ b/libs/atoll/src/abs.rs @@ -1,6 +1,6 @@ //! 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}; @@ -8,9 +8,10 @@ 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::geometry::dir::Dir; use substrate::geometry::point::Point; use substrate::geometry::rect::Rect; use substrate::io::layout::Builder; @@ -29,6 +30,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, @@ -86,6 +88,27 @@ impl Abstract { ) } + pub fn routing_state(&self) -> RoutingState { + 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](Abstract#coordinates) for more information. @@ -150,6 +173,159 @@ impl Abstract { } } +#[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, +} + +impl InstanceAbstract { + pub(crate) fn new( + mut abs: Abstract, + loc: Point, + orientation: Orientation, + parent_net_ids: Vec, + ) -> 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) -> 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 { @@ -235,9 +411,7 @@ pub fn generate_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); @@ -309,6 +483,7 @@ impl Draw 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()))?; } diff --git a/libs/atoll/src/grid.rs b/libs/atoll/src/grid.rs index d2b51698..f5bb8f36 100644 --- a/libs/atoll/src/grid.rs +++ b/libs/atoll/src/grid.rs @@ -319,7 +319,7 @@ impl<'a, L: AtollLayer> LayerSlice<'a, L> { /// A fixed-size routing grid. #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct RoutingGrid { - pub(crate) stack: LayerStack, + pub stack: LayerStack, start: usize, end: usize, } @@ -595,13 +595,6 @@ impl RoutingState { 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(); diff --git a/libs/atoll/src/lib.rs b/libs/atoll/src/lib.rs index 91061069..5c838c7d 100644 --- a/libs/atoll/src/lib.rs +++ b/libs/atoll/src/lib.rs @@ -144,90 +144,39 @@ pub mod abs; pub mod grid; +pub mod route; -use crate::abs::{generate_abstract, Abstract}; -use crate::grid::{LayerStack, PdkLayer}; +use crate::abs::{generate_abstract, Abstract, DebugAbstract, InstanceAbstract}; +use crate::grid::{AtollLayer, LayerStack, PdkLayer}; +use crate::route::Router; use ena::unify::UnifyKey; use serde::{Deserialize, Serialize}; +use std::any::Any; use std::collections::HashMap; use std::ops::Deref; use std::sync::Arc; use substrate::arcstr::ArcStr; use substrate::block::Block; use substrate::context::{prepare_cell_builder, PdkContext}; +use substrate::geometry::corner::Corner; use substrate::geometry::polygon::Polygon; use substrate::geometry::prelude::{Bbox, Dir, Point}; -use substrate::geometry::transform::Translate; +use substrate::geometry::transform::{TransformMut, Transformation, Translate, TranslateMut}; use substrate::io::layout::{Builder, PortGeometry}; use substrate::io::schematic::{Bundle, Connect, Node, TerminalView}; -use substrate::io::Flatten; +use substrate::io::{FlatLen, Flatten}; use substrate::layout::element::Shape; use substrate::layout::{ExportsLayoutData, Layout}; use substrate::pdk::layers::HasPin; use substrate::pdk::Pdk; use substrate::schematic::schema::Schema; use substrate::schematic::{CellId, ExportsNestedData, Schematic}; -use substrate::{io, layout, schematic}; +use substrate::{geometry, io, layout, schematic}; /// Identifies nets in a routing solver. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)] pub struct NetId(pub(crate) usize); -/// Identifies a routing layer. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct LayerId(usize); - -impl From for LayerId { - #[inline] - fn from(value: usize) -> Self { - Self(value) - } -} - -/// A coordinate identifying a track position in a routing volume. -pub struct Coordinate { - /// The lower metal layer. - pub layer: LayerId, - /// The x-coordinate. - /// - /// Indexes the vertical-traveling tracks. - pub x: i64, - /// The y-coordinate. - /// - /// Indexes the horizontal-traveling tracks. - pub y: i64, -} - -/// A type that contains an x-y coordinate. -pub trait Xy { - /// Returns the coordinate represented by `self`. - fn xy(&self) -> (i64, i64); -} - -impl Xy for &T { - fn xy(&self) -> (i64, i64) { - (*self).xy() - } -} - -impl Xy for Coordinate { - fn xy(&self) -> (i64, i64) { - (self.x, self.y) - } -} - -impl Xy for Point { - fn xy(&self) -> (i64, i64) { - (self.x, self.y) - } -} - -impl Xy for (i64, i64) { - fn xy(&self) -> (i64, i64) { - *self - } -} - /// The state of a point on a routing grid. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum PointState { @@ -300,68 +249,6 @@ impl RoutingDir { } } -/// A position within a routing volume. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct Pos { - /// The routing layer. - layer: LayerId, - /// The x-coordinate. - x: i64, - /// The y-coordinate. - y: i64, -} - -impl Pos { - /// Create a new [`Pos`]. - pub fn new(layer: impl Into, x: i64, y: i64) -> Self { - Self { - layer: layer.into(), - x, - y, - } - } - - /// The index of the track going in the specified direction. - pub fn track_coord(&self, dir: Dir) -> i64 { - match dir { - Dir::Vert => self.x, - Dir::Horiz => self.y, - } - } - - /// The index of the coordinate in the given direction. - /// - /// [`Dir::Horiz`] gives the x-coordinate; - /// [`Dir::Vert`] gives the y-coordinate; - pub fn coord(&self, dir: Dir) -> i64 { - match dir { - Dir::Horiz => self.x, - Dir::Vert => self.y, - } - } - - /// Returns a new `Pos` with the given coordinate indexing tracks going in the given direction. - pub fn with_track_coord(&self, dir: Dir, coord: i64) -> Self { - let Pos { layer, x, y } = *self; - match dir { - Dir::Vert => Self { layer, x: coord, y }, - Dir::Horiz => Self { layer, x, y: coord }, - } - } - - /// Returns a new `Pos` with the given coordinate in the given direction. - /// - /// If `dir` is [`Dir::Horiz`], `coord` is taken as the new x coordinate. - /// If `dir` is [`Dir::Vert`], `coord` is taken as the new y coordinate. - pub fn with_coord(&self, dir: Dir, coord: i64) -> Self { - let Pos { layer, x, y } = *self; - match dir { - Dir::Horiz => Self { layer, x: coord, y }, - Dir::Vert => Self { layer, x, y: coord }, - } - } -} - // todo: how to connect by abutment (eg body terminals) #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -386,23 +273,40 @@ impl UnifyKey for NodeKey { #[derive(Clone, Debug)] struct NodeInfo { key: NodeKey, - geometry: Vec, + nets: Vec, } /// The orientation of an instance. /// -/// Orientations are applied relative to the child cell's coordinate frame. -#[derive(Clone, Copy, Debug, Default)] +/// Orientations are applied such that the bounding box of the instance is preserved. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Orientation { /// The default orientation. #[default] R0, /// Rotated 180 degrees. R180, - /// Mirrored about the x-axis. - MX, - /// Mirrored about the y-axis. - MY, + /// Reflect vertically (ie. about the x-axis). + ReflectVert, + /// Reflect horizontally (ie. about the y-axis). + ReflectHoriz, +} + +impl From for geometry::orientation::NamedOrientation { + fn from(value: Orientation) -> Self { + match value { + Orientation::R0 => geometry::orientation::NamedOrientation::R0, + Orientation::R180 => geometry::orientation::NamedOrientation::R180, + Orientation::ReflectVert => geometry::orientation::NamedOrientation::ReflectVert, + Orientation::ReflectHoriz => geometry::orientation::NamedOrientation::ReflectHoriz, + } + } +} + +impl From for geometry::orientation::Orientation { + fn from(value: Orientation) -> Self { + Into::::into(value).into() + } } /// An ATOLL instance representing both a schematic and layout instance. @@ -446,13 +350,6 @@ impl Instance { self.schematic.io() } - /// Decomposes this ATOLL instance into Substrate schematic and layout instances. - pub fn into_instances(self) -> (schematic::Instance, layout::Instance) { - // todo: apply loc and orientation to layout instance - let loc = self.physical_loc(); - (self.schematic, self.layout.translate(loc)) - } - /// Returns the physical location of this instance. pub fn physical_loc(&self) -> Point { let slice = self.abs.slice(); @@ -469,9 +366,23 @@ pub struct TileBuilder<'a, PDK: Pdk + Schema> { schematic: &'a mut schematic::CellBuilder, layout: &'a mut layout::CellBuilder, layer_stack: Arc>, + /// Abstracts of instantiated instances. + abs: Vec, + next_net_id: usize, + router: Option>, } impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { + fn register_bundle>(&mut self, bundle: &T) { + let nodes: Vec = bundle.flatten_vec(); + let keys: Vec = nodes.iter().map(|_| self.connections.new_key(())).collect(); + self.nodes.extend( + nodes + .into_iter() + .zip(keys.into_iter().map(|key| NodeInfo { key, nets: vec![] })), + ); + } + fn new( schematic_io: &'a T, schematic: &'a mut schematic::CellBuilder, @@ -479,29 +390,26 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { ) -> Self { let mut nodes = HashMap::new(); let mut connections = ena::unify::InPlaceUnificationTable::new(); - let io_nodes: Vec = schematic_io.flatten_vec(); - let keys: Vec = io_nodes.iter().map(|_| connections.new_key(())).collect(); - nodes.extend( - io_nodes - .into_iter() - .zip(keys.into_iter().map(|key| NodeInfo { - key, - geometry: vec![], - })), - ); // todo: fix how layer is provided let layer_stack = layout .ctx() .get_installation::>() .unwrap(); - Self { + let mut builder = Self { nodes, connections, schematic, layout, layer_stack, - } + abs: Vec::new(), + next_net_id: 0, + router: None, + }; + + builder.register_bundle(schematic_io); + + builder } /// Generates an ATOLL instance from a Substrate block that implements [`Schematic`] @@ -512,6 +420,7 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { ) -> Instance { let layout = self.layout.generate(block.clone()); let schematic = self.schematic.instantiate(block); + self.register_bundle(schematic.io()); let abs = generate_abstract(layout.raw_cell(), self.layer_stack.as_ref()); Instance { layout, @@ -527,6 +436,7 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { let wrapper = TileWrapper::new(block); let layout = self.layout.generate(wrapper.clone()); let schematic = self.schematic.instantiate(wrapper); + self.register_bundle(schematic.io()); // todo: generate abstract from AtollTile trait directly let abs = generate_abstract(layout.raw_cell(), self.layer_stack.as_ref()); Instance { @@ -541,12 +451,46 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { /// Draws an ATOLL instance in layout. pub fn draw>( &mut self, - instance: &Instance, - ) -> substrate::error::Result<()> { + instance: Instance, + ) -> substrate::error::Result<(schematic::Instance, layout::Instance)> { + let physical_loc = instance.physical_loc(); self.layout .draw(instance.layout.clone().translate(instance.physical_loc()))?; - Ok(()) + let parent_net_ids: Vec<_> = (0..instance.io().len()) + .map(|_| { + self.next_net_id += 1; + NetId(self.next_net_id) + }) + .collect(); + + instance + .io() + .flatten_vec() + .iter() + .zip(parent_net_ids.iter()) + .for_each(|(node, net)| self.nodes.get_mut(node).unwrap().nets.push(*net)); + + self.abs.push(InstanceAbstract::new( + instance.abs, + instance.loc, + instance.orientation, + parent_net_ids, + )); + + // todo: Use ATOLL virtual layer. + let mut layout = instance.layout; + let mut orig_bbox = layout.bbox().unwrap(); + layout.transform_mut(Transformation::from_offset_and_orientation( + Point::zero(), + instance.orientation, + )); + layout.translate_mut( + orig_bbox.corner(Corner::LowerLeft) - layout.bbox().unwrap().corner(Corner::LowerLeft) + + physical_loc, + ); + + Ok((instance.schematic, layout)) } /// Connect all signals in the given data instances. @@ -556,14 +500,13 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { D2: Flatten, D1: Connect, { - // todo: fix - // let s1f: Vec = s1.flatten_vec(); - // let s2f: Vec = s2.flatten_vec(); - // assert_eq!(s1f.len(), s2f.len()); - // s1f.into_iter().zip(s2f).for_each(|(a, b)| { - // self.connections - // .union(self.nodes[&a].key, self.nodes[&b].key); - // }); + let s1f: Vec = s1.flatten_vec(); + let s2f: Vec = s2.flatten_vec(); + assert_eq!(s1f.len(), s2f.len()); + s1f.into_iter().zip(s2f).for_each(|(a, b)| { + self.connections + .union(self.nodes[&a].key, self.nodes[&b].key); + }); self.schematic.connect(s1, s2); } @@ -578,11 +521,11 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { let nodes: Vec = bundle.flatten_vec(); let keys: Vec = nodes.iter().map(|_| self.connections.new_key(())).collect(); - self.nodes - .extend(nodes.into_iter().zip(keys.into_iter().map(|key| NodeInfo { - key, - geometry: vec![], - }))); + self.nodes.extend( + nodes + .into_iter() + .zip(keys.into_iter().map(|key| NodeInfo { key, nets: vec![] })), + ); bundle } @@ -593,6 +536,10 @@ impl<'a, PDK: Pdk + Schema> TileBuilder<'a, PDK> { pub fn ctx(&self) -> &PdkContext { self.layout.ctx() } + + pub fn set_router(&mut self, router: T) { + self.router = Some(Arc::new(router)); + } } /// A builder for an ATOLL tile's IOs. @@ -699,32 +646,45 @@ where let mut cell = TileBuilder::new(&schematic_io, &mut schematic_cell, cell); let (_, layout_data) = >::tile(&self.0, io, &mut cell)?; - let mut to_connect = HashMap::new(); - for (_, port) in cell.nodes { - to_connect - .entry(cell.connections.find(port.key)) - .or_insert(Vec::new()) - .extend(port.geometry); - } + let abs = InstanceAbstract::merge(cell.abs); - for (_, ports) in to_connect { - for pair in ports.windows(2) { - let a = &pair[0]; - let b = &pair[1]; - let a_center = a.primary.shape().bbox().unwrap().center(); - let b_center = b.primary.shape().bbox().unwrap().center(); - cell.layout.draw(Shape::new( - a.primary.layer().drawing(), - Polygon::from_verts(vec![ - a_center, - b_center, - b_center - Point::new(20, 20), - a_center - Point::new(20, 20), - ]), - ))?; + if let Some(router) = cell.router { + let mut to_connect = HashMap::new(); + for (_, info) in cell.nodes { + to_connect + .entry(cell.connections.find(info.key)) + .or_insert(Vec::new()) + .extend(info.nets); + } + let to_connect: Vec<_> = to_connect.into_values().collect(); + let paths = router.route(abs.routing_state(), to_connect); + + for path in paths { + for segment in path.windows(2) { + 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) + } else { + panic!("cannot have a diagonal segment"); + }, + ))?; + } + } } } + let debug = cell.layout.generate(DebugAbstract { + abs, + stack: (*cell.layer_stack).clone(), + }); + cell.layout.draw(debug)?; + Ok(layout_data) } } diff --git a/libs/atoll/src/route.rs b/libs/atoll/src/route.rs new file mode 100644 index 00000000..fb74c65a --- /dev/null +++ b/libs/atoll/src/route.rs @@ -0,0 +1,34 @@ +/// Routing interfaces and implementations. +use crate::abs::{Abstract, GridCoord}; +use crate::grid::{PdkLayer, RoutingState}; +use crate::NetId; + +pub type Path = Vec; + +pub trait Router { + // todo: perhaps add way to translate nodes to net IDs + fn route( + &self, + routing_state: RoutingState, + to_connect: Vec>, + ) -> Vec; +} + +pub struct GreedyBfsRouter; + +impl Router for GreedyBfsRouter { + fn route(&self, mut state: RoutingState, to_connect: Vec>) -> Vec { + vec![vec![ + GridCoord { + layer: 0, + x: 0, + y: 0, + }, + GridCoord { + layer: 0, + x: 0, + y: 4, + }, + ]] + } +} diff --git a/tests/src/atoll/mod.rs b/tests/src/atoll/mod.rs index 7c8e6497..562c1198 100644 --- a/tests/src/atoll/mod.rs +++ b/tests/src/atoll/mod.rs @@ -2,6 +2,7 @@ use crate::paths::get_path; use crate::shared::pdk::sky130_open_ctx; use atoll::abs::{generate_abstract, DebugAbstract}; use atoll::grid::{LayerStack, PdkLayer}; +use atoll::route::GreedyBfsRouter; use atoll::{IoBuilder, Tile, TileBuilder, TileWrapper}; use geometry::point::Point; use serde::{Deserialize, Serialize}; @@ -111,9 +112,7 @@ impl Tile for Sky130NmosTileAutoroute { for i in 0..3 { let mut inst = cell.generate_primitive(block.clone()); inst.translate_mut(Point::new(5 * i, 0)); - cell.draw(&inst)?; - - let (schematic, layout) = inst.into_instances(); + let (schematic, layout) = cell.draw(inst)?; for i in 0..4 { cell.connect(io.schematic.sd, schematic.io().sd[i]); @@ -127,6 +126,8 @@ impl Tile for Sky130NmosTileAutoroute { instances.push(schematic); } + cell.set_router(GreedyBfsRouter); + Ok((instances, ())) } }