diff --git a/libs/atoll/src/abs.rs b/libs/atoll/src/abs.rs index 1172a0d6..a980ba5c 100644 --- a/libs/atoll/src/abs.rs +++ b/libs/atoll/src/abs.rs @@ -11,13 +11,15 @@ use substrate::geometry::bbox::Bbox; use substrate::geometry::transform::Transformation; use substrate::layout::element::Text; +use substrate::context::PdkContext; use substrate::geometry::point::Point; use substrate::geometry::rect::Rect; use substrate::io::layout::Builder; +use substrate::layout::bbox::LayerBbox; use substrate::layout::element::Shape; use substrate::layout::element::{CellId, Element, RawCell}; use substrate::layout::{CellBuilder, Draw, DrawReceiver, ExportsLayoutData, Layout}; -use substrate::pdk::layers::HasPin; +use substrate::pdk::layers::{HasPin, Layer}; use substrate::pdk::Pdk; use substrate::schematic::ExportsNestedData; use substrate::{arcstr, layout}; @@ -148,6 +150,83 @@ impl AtollAbstract { pub fn physical_origin(&self) -> Point { self.lcm_bounds.lower_left() * self.slice().lcm_units() } + + /// Generates an abstract view of a layout cell. + pub fn generate( + ctx: &PdkContext, + layout: &layout::Cell, + ) -> AtollAbstract { + let stack = ctx + .get_installation::>() + .expect("must install ATOLL layer stack"); + let virtual_layers = ctx.install_layers::(); + + let cell = layout.raw(); + let bbox = cell + .layer_bbox(virtual_layers.outline.id()) + .expect("cell must provide an outline on ATOLL virtual layer"); + + let top = top_layer(cell, &*stack) + .expect("cell did not have any ATOLL routing layers; cannot produce an abstract"); + let top = if top == 0 { 1 } else { top }; + + let slice = stack.slice(0..top + 1); + + let xmin = div_floor(bbox.left(), slice.lcm_unit_width()); + let xmax = div_ceil(bbox.right(), slice.lcm_unit_width()); + let ymin = div_floor(bbox.bot(), slice.lcm_unit_height()); + let ymax = div_ceil(bbox.top(), slice.lcm_unit_height()); + let lcm_bounds = Rect::from_sides(xmin, ymin, xmax, ymax); + + let nx = lcm_bounds.width(); + let ny = lcm_bounds.height(); + + let grid = RoutingGrid::new((*stack).clone(), 0..top + 1); + let mut state = RoutingState::new((*stack).clone(), top, nx, ny); + let mut ports = Vec::new(); + for (i, (name, geom)) in cell.ports().enumerate() { + let net = NetId(i); + ports.push(net); + if let Some(layer) = stack.layer_idx(geom.primary.layer().drawing()) { + let rect = match geom.primary.shape() { + substrate::geometry::shape::Shape::Rect(r) => *r, + substrate::geometry::shape::Shape::Polygon(p) => { + 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); + let yofs = ymin * slice.lcm_unit_height() / grid.ypitch(layer); + state.layer_mut(layer)[((x - xofs) as usize, (y - yofs) as usize)] = + PointState::Routed { + net, + via_down: false, + via_up: false, + }; + } + } + } + } + } + + let layers = state + .layers + .into_iter() + .map(|states| LayerAbstract::Detailed { states }) + .collect(); + + AtollAbstract { + top_layer: top, + lcm_bounds, + grid: RoutingGrid::new((*stack).clone(), 0..top + 1), + ports, + layers, + } + } } /// The abstracted state of a single routing layer. @@ -197,76 +276,6 @@ fn top_layer_inner( top } -/// Generates an abstract view of a layout cell. -pub fn generate_abstract( - layout: &layout::Cell, - stack: &LayerStack, -) -> AtollAbstract { - let cell = layout.raw(); - let bbox = cell.bbox().unwrap(); - - let top = top_layer(cell, stack) - .expect("cell did not have any ATOLL routing layers; cannot produce an abstract"); - let top = if top == 0 { 1 } else { top }; - - let slice = stack.slice(0..top + 1); - - let xmin = div_floor(bbox.left(), slice.lcm_unit_width()); - let xmax = div_ceil(bbox.right(), slice.lcm_unit_width()); - let ymin = div_floor(bbox.bot(), slice.lcm_unit_height()); - let ymax = div_ceil(bbox.top(), slice.lcm_unit_height()); - let lcm_bounds = Rect::from_sides(xmin, ymin, xmax, ymax); - - let nx = lcm_bounds.width(); - let ny = lcm_bounds.height(); - - let grid = RoutingGrid::new(stack.clone(), 0..top + 1); - let mut state = RoutingState::new(stack.clone(), top, nx, ny); - let mut ports = Vec::new(); - for (i, (name, geom)) in cell.ports().enumerate() { - let net = NetId(i); - ports.push(net); - if let Some(layer) = stack.layer_idx(geom.primary.layer().drawing()) { - let rect = match geom.primary.shape() { - substrate::geometry::shape::Shape::Rect(r) => *r, - substrate::geometry::shape::Shape::Polygon(p) => { - 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); - let yofs = ymin * slice.lcm_unit_height() / grid.ypitch(layer); - state.layer_mut(layer)[((x - xofs) as usize, (y - yofs) as usize)] = - PointState::Routed { - net, - via_down: false, - via_up: false, - }; - } - } - } - } - } - - let layers = state - .layers - .into_iter() - .map(|states| LayerAbstract::Detailed { states }) - .collect(); - - AtollAbstract { - top_layer: top, - lcm_bounds, - grid: RoutingGrid::new(stack.clone(), 0..top + 1), - ports, - layers, - } -} - #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct DebugAbstract { pub abs: AtollAbstract, diff --git a/libs/atoll/src/lib.rs b/libs/atoll/src/lib.rs index fbceea91..106f776e 100644 --- a/libs/atoll/src/lib.rs +++ b/libs/atoll/src/lib.rs @@ -145,7 +145,7 @@ pub mod abs; pub mod grid; -use crate::abs::{generate_abstract, AtollAbstract}; +use crate::abs::AtollAbstract; use crate::grid::{LayerStack, PdkLayer}; use ::grid::Grid; use ena::unify::{UnifyKey, UnifyValue}; @@ -503,7 +503,7 @@ impl<'a, PDK: Pdk + Schema> AtollTileBuilder<'a, PDK> { ) -> Instance { let layout = self.layout.generate(block.clone()); let schematic = self.schematic.instantiate(block); - let abs = generate_abstract(layout.raw_cell(), self.layer_stack.as_ref()); + let abs = AtollAbstract::generate(&self.layout.ctx, layout.raw_cell()); let top = abs.top_layer; Instance { layout, @@ -522,7 +522,7 @@ impl<'a, PDK: Pdk + Schema> AtollTileBuilder<'a, PDK> { let layout = self.layout.generate(wrapper.clone()); let schematic = self.schematic.instantiate(wrapper); // todo: generate abstract from AtollTile trait directly - let abs = generate_abstract(layout.raw_cell(), self.layer_stack.as_ref()); + let abs = AtollAbstract::generate(&self.layout.ctx, layout.raw_cell()); let top = abs.top_layer; Instance { layout, diff --git a/tests/src/atoll/mod.rs b/tests/src/atoll/mod.rs index 8c7b4bfb..2edb7d8a 100644 --- a/tests/src/atoll/mod.rs +++ b/tests/src/atoll/mod.rs @@ -1,6 +1,6 @@ use crate::paths::get_path; use crate::shared::pdk::sky130_open_ctx; -use atoll::abs::{generate_abstract, DebugAbstract}; +use atoll::abs::{DebugAbstract, AtollAbstract}; use atoll::grid::{LayerStack, PdkLayer}; use atoll::{AtollIo, AtollTile, AtollTileBuilder, AtollTileWrapper}; use geometry::point::Point; @@ -59,7 +59,7 @@ fn sky130_atoll_nmos_tile() { // todo: add mechanism to have multiple ATOLL layer stacks (one per PDK) let stack = ctx.get_installation::>().unwrap(); - let abs = generate_abstract(handle.cell(), &*stack); + let abs = AtollAbstract::generate(&ctx, handle.cell()); ctx.write_layout( DebugAbstract { abs, @@ -100,7 +100,7 @@ fn sky130_atoll_pmos_tile() { let stack = ctx.get_installation::>().unwrap(); - let abs = generate_abstract(handle.cell(), &*stack); + let abs = AtollAbstract::generate(&ctx, handle.cell()); ctx.write_layout( DebugAbstract { abs, @@ -195,7 +195,7 @@ fn sky130_atoll_nmos_tile_autoroute() { let handle = ctx.generate_layout(block); let stack = ctx.get_installation::>().unwrap(); - let abs = generate_abstract(handle.cell(), &stack); + let abs = AtollAbstract::generate(&ctx, handle.cell()); ctx.write_layout( DebugAbstract { abs,