|
| 1 | +use layir::Shape; |
| 2 | +use substrate::types::codegen::PortGeometryBundle; |
| 3 | +use substrate::types::layout::PortGeometry; |
| 4 | +use substrate::types::ArrayBundle; |
| 5 | +use substrate::{ |
| 6 | + block::Block, |
| 7 | + geometry::rect::Rect, |
| 8 | + layout::{schema::Schema, Layout}, |
| 9 | + types::{layout::PortGeometryBuilder, Array, InOut, Io, Signal}, |
| 10 | +}; |
| 11 | + |
| 12 | +#[derive(Clone, Debug, Default, Io)] |
| 13 | +pub struct ViaIo { |
| 14 | + pub x: InOut<Signal>, |
| 15 | +} |
| 16 | + |
| 17 | +#[derive(Clone, Debug, Io)] |
| 18 | +pub struct RectsIo { |
| 19 | + pub x: InOut<Array<Signal>>, |
| 20 | +} |
| 21 | + |
| 22 | +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Block)] |
| 23 | +#[substrate(io = "ViaIo")] |
| 24 | +pub struct Via; |
| 25 | + |
| 26 | +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] |
| 27 | +pub enum Layer { |
| 28 | + MetBot, |
| 29 | + Cut, |
| 30 | + MetTop, |
| 31 | +} |
| 32 | + |
| 33 | +impl Schema for Layer { |
| 34 | + type Layer = Layer; |
| 35 | +} |
| 36 | + |
| 37 | +impl Layout for Via { |
| 38 | + type Data = (); |
| 39 | + type Schema = Layer; |
| 40 | + type Bundle = ViaIoView<PortGeometryBundle<Layer>>; |
| 41 | + fn layout( |
| 42 | + &self, |
| 43 | + cell: &mut substrate::layout::CellBuilder<Self::Schema>, |
| 44 | + ) -> substrate::error::Result<(Self::Bundle, Self::Data)> { |
| 45 | + cell.draw(Shape::new(Layer::MetTop, Rect::from_sides(0, 0, 100, 100)))?; |
| 46 | + let cut = Shape::new(Layer::Cut, Rect::from_sides(40, 40, 60, 60)); |
| 47 | + cell.draw(cut.clone())?; |
| 48 | + cell.draw(Shape::new(Layer::MetBot, Rect::from_sides(20, 20, 80, 80)))?; |
| 49 | + let mut x = PortGeometryBuilder::default(); |
| 50 | + x.push(cut); |
| 51 | + Ok((ViaIoView { x: x.build()? }, ())) |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] |
| 56 | +pub struct Rects { |
| 57 | + n_io: usize, |
| 58 | + n_drawn: usize, |
| 59 | +} |
| 60 | + |
| 61 | +impl Block for Rects { |
| 62 | + type Io = RectsIo; |
| 63 | + |
| 64 | + fn io(&self) -> Self::Io { |
| 65 | + RectsIo { |
| 66 | + x: InOut(Array::new(self.n_io, Signal)), |
| 67 | + } |
| 68 | + } |
| 69 | + fn name(&self) -> substrate::arcstr::ArcStr { |
| 70 | + substrate::arcstr::literal!("rects") |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +impl Layout for Rects { |
| 75 | + type Data = (); |
| 76 | + type Schema = Layer; |
| 77 | + type Bundle = RectsIoView<PortGeometryBundle<Layer>>; |
| 78 | + fn layout( |
| 79 | + &self, |
| 80 | + cell: &mut substrate::layout::CellBuilder<Self::Schema>, |
| 81 | + ) -> substrate::error::Result<(Self::Bundle, Self::Data)> { |
| 82 | + let ports = (0..self.n_drawn) |
| 83 | + .map(|i| { |
| 84 | + let i = i as i64; |
| 85 | + let cut = Shape::new( |
| 86 | + Layer::Cut, |
| 87 | + Rect::from_sides(40 + 100 * i, 40, 60 + 100 * i, 60), |
| 88 | + ); |
| 89 | + cell.draw(cut.clone()).expect("failed to draw geometry"); |
| 90 | + PortGeometry::new(cut) |
| 91 | + }) |
| 92 | + .collect(); |
| 93 | + let x = ArrayBundle::new(Signal, ports); |
| 94 | + Ok((RectsIoView { x }, ())) |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +#[cfg(test)] |
| 99 | +mod tests { |
| 100 | + use super::*; |
| 101 | + use layir::Element; |
| 102 | + use substrate::context::Context; |
| 103 | + |
| 104 | + #[test] |
| 105 | + fn export_via_layout() { |
| 106 | + let ctx = Context::builder().build(); |
| 107 | + let lib = ctx.export_layir(Via).expect("failed to export layout"); |
| 108 | + assert_eq!(lib.layir.cells().count(), 1); |
| 109 | + let cell = lib.layir.cells().next().unwrap().1; |
| 110 | + assert_eq!(cell.name(), "via"); |
| 111 | + assert_eq!(cell.elements().count(), 3); |
| 112 | + assert_eq!(cell.ports().count(), 1); |
| 113 | + let port = cell.ports().next().unwrap(); |
| 114 | + let mut iter = port.1.elements(); |
| 115 | + let x = iter.next().unwrap(); |
| 116 | + assert_eq!( |
| 117 | + *x, |
| 118 | + Element::Shape(Shape::new(Layer::Cut, Rect::from_sides(40, 40, 60, 60))) |
| 119 | + ); |
| 120 | + } |
| 121 | + |
| 122 | + #[test] |
| 123 | + fn export_rects_layout() { |
| 124 | + let ctx = Context::builder().build(); |
| 125 | + let lib = ctx |
| 126 | + .export_layir(Rects { |
| 127 | + n_io: 12, |
| 128 | + n_drawn: 12, |
| 129 | + }) |
| 130 | + .expect("failed to export layout"); |
| 131 | + assert_eq!(lib.layir.cells().count(), 1); |
| 132 | + let cell = lib.layir.cells().next().unwrap().1; |
| 133 | + assert_eq!(cell.name(), "rects"); |
| 134 | + assert_eq!(cell.elements().count(), 12); |
| 135 | + assert_eq!(cell.ports().count(), 12); |
| 136 | + let mut ports = cell.ports(); |
| 137 | + let port = ports.next().unwrap(); |
| 138 | + let mut iter = port.1.elements(); |
| 139 | + let x = iter.next().unwrap(); |
| 140 | + assert_eq!( |
| 141 | + *x, |
| 142 | + Element::Shape(Shape::new(Layer::Cut, Rect::from_sides(40, 40, 60, 60))) |
| 143 | + ); |
| 144 | + let port = ports.next().unwrap(); |
| 145 | + let mut iter = port.1.elements(); |
| 146 | + let x = iter.next().unwrap(); |
| 147 | + assert_eq!( |
| 148 | + *x, |
| 149 | + Element::Shape(Shape::new(Layer::Cut, Rect::from_sides(140, 40, 160, 60))) |
| 150 | + ); |
| 151 | + } |
| 152 | + |
| 153 | + #[test] |
| 154 | + fn export_rects_layout_mismatched_io_length() { |
| 155 | + let ctx = Context::builder().build(); |
| 156 | + assert!(ctx |
| 157 | + .export_layir(Rects { |
| 158 | + n_io: 12, |
| 159 | + n_drawn: 16, |
| 160 | + }) |
| 161 | + .is_err()); |
| 162 | + } |
| 163 | +} |
0 commit comments