Skip to content

Commit 255af05

Browse files
authored
feat(codegen): codegen for layout types, example layouts (#469)
1 parent b285476 commit 255af05

9 files changed

Lines changed: 308 additions & 11 deletions

File tree

‎Cargo.lock‎

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ members = [
3737
"tools/quantus",
3838
"tools/spectre",
3939
"tools/magic-netgen",
40-
"examples2/colbuf",
40+
"examples2/colbuf", "examples2/via",
4141
]
4242

4343
exclude = ["tests", "pdks/sky130pdk", "libs/atoll", "examples"]

‎codegen/src/io.rs‎

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ fn impl_has_nested_view(
356356
let substrate = substrate_ident();
357357
let mut has_nested_view_helper = view_helper.clone();
358358
has_nested_view_helper.push_where_predicate_per_field(
359-
|ty, _| parse_quote! { #ty: #substrate::schematic ::HasNestedView },
359+
|ty, _| parse_quote! { #ty: #substrate::schematic::HasNestedView },
360360
);
361361

362362
let nested_view_full_ty = nested_view_helper.get_full_type();
@@ -405,6 +405,54 @@ fn impl_view_as(view_helper: &DeriveInputHelper, nodes: bool) -> TokenStream {
405405
}
406406
}
407407

408+
fn impl_translate_ref(view_helper: &DeriveInputHelper) -> TokenStream {
409+
let substrate = substrate_ident();
410+
let mut translate_ref_helper = view_helper.clone();
411+
translate_ref_helper.push_where_predicate_per_field(
412+
|ty, _| parse_quote! { #ty: #substrate::geometry::transform::TranslateRef },
413+
);
414+
415+
let body = translate_ref_helper.map_data(
416+
&translate_ref_helper.get_type(),
417+
|MapField { ty, refer, .. }| {
418+
quote! { <#ty as #substrate::geometry::transform::TranslateRef>::translate_ref(&#refer, __substrate_point) }
419+
});
420+
translate_ref_helper.impl_trait(&ImplTrait {
421+
trait_name: quote! { #substrate::geometry::transform::TranslateRef },
422+
trait_body: quote! {
423+
fn translate_ref(&self, __substrate_point: #substrate::geometry::point::Point) -> Self {
424+
#body
425+
}
426+
},
427+
extra_generics: vec![],
428+
extra_where_predicates: vec![],
429+
})
430+
}
431+
432+
fn impl_transform_ref(view_helper: &DeriveInputHelper) -> TokenStream {
433+
let substrate = substrate_ident();
434+
let mut transform_ref_helper = view_helper.clone();
435+
transform_ref_helper.push_where_predicate_per_field(
436+
|ty, _| parse_quote! { #ty: #substrate::geometry::transform::TransformRef },
437+
);
438+
439+
let body = transform_ref_helper.map_data(
440+
&transform_ref_helper.get_type(),
441+
|MapField { ty, refer, .. }| {
442+
quote! { <#ty as #substrate::geometry::transform::TransformRef>::transform_ref(&#refer, __substrate_transformation) }
443+
});
444+
transform_ref_helper.impl_trait(&ImplTrait {
445+
trait_name: quote! { #substrate::geometry::transform::TransformRef },
446+
trait_body: quote! {
447+
fn transform_ref(&self, __substrate_transformation: #substrate::geometry::transform::Transformation) -> Self {
448+
#body
449+
}
450+
},
451+
extra_generics: vec![],
452+
extra_where_predicates: vec![],
453+
})
454+
}
455+
408456
/// Derives `BundleKind` for the provided input and creates a struct representing views of this
409457
/// `BundleKind`.
410458
///
@@ -490,7 +538,7 @@ pub(crate) fn bundle_kind(input: &DeriveInput, io: bool) -> syn::Result<TokenStr
490538
// Implement schematic traits
491539
all_decls_impls.push(schematic_bundle_kind(&helper, &kind_helper, &view_helper));
492540
// Implement layout traits
493-
//
541+
all_decls_impls.push(layout_bundle_kind(&helper, &kind_helper, &view_helper));
494542
Ok(quote! {
495543
#( #all_decls_impls )*
496544
})
@@ -582,6 +630,23 @@ pub(crate) fn schematic_bundle_kind(
582630
#( #all_decls_impls )*
583631
}
584632
}
633+
634+
pub(crate) fn layout_bundle_kind(
635+
original_helper: &DeriveInputHelper,
636+
kind_helper: &DeriveInputHelper,
637+
view_helper: &DeriveInputHelper,
638+
) -> TokenStream {
639+
let substrate = substrate_ident();
640+
let mut all_decls_impls = Vec::new();
641+
let view_generic_ty = quote! { __substrate_V };
642+
643+
all_decls_impls.push(impl_translate_ref(view_helper));
644+
all_decls_impls.push(impl_transform_ref(view_helper));
645+
646+
quote! {
647+
#( #all_decls_impls )*
648+
}
649+
}
585650
//
586651
// // TODO: Signature might need to be modified to use macrotools.
587652
// pub(crate) fn layout_bundle(input: &DeriveInput) -> TokenStream {}

‎examples2/via/Cargo.toml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "via"
3+
version = "0.0.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
substrate = { version = "0.8.1", registry = "substrate", path = "../../substrate" }
8+
layir = { version = "0.1.0", registry = "substrate", path = "../../libs/layir" }

‎examples2/via/src/lib.rs‎

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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+
}

‎substrate/src/layout/conv.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl<L: Clone> RawCell<L> {
6666
/// to the same LayIR library.
6767
pub(crate) fn to_layir_lib(&self) -> Result<RawLib<L>, LayirExportError> {
6868
let mut lib_ctx = LayirLibExportContext::new();
69+
self.to_layir_cell(&mut lib_ctx)?;
6970

7071
Ok(RawLib {
7172
layir: lib_ctx.lib.build().map_err(|_| LayirExportError)?,

‎substrate/src/types/codegen.rs‎

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use crate::{
88
};
99

1010
use super::{
11-
layout::{PortGeometry, PortGeometryBundle},
11+
layout::{LayoutBundle, PortGeometry},
1212
schematic::{NestedNode, NestedTerminal, Node, SchematicBundleKind, Terminal},
13-
Array, Flatten, Flipped, HasBundleKind, InOut, Input, Output, Signal, Unflatten,
13+
Array, ArrayBundle, Flatten, Flipped, HasBundleKind, InOut, Input, Output, Signal, Unflatten,
1414
};
1515

1616
/// A type with an associated `V` view.
@@ -61,8 +61,8 @@ impl ViewSource for Signal {
6161
type Source = Self;
6262
}
6363

64-
impl<S> HasViewImpl<PortGeometryBundle<S>> for Signal {
65-
type View = PortGeometry<S>;
64+
impl<L> HasViewImpl<PortGeometryBundle<L>> for Signal {
65+
type View = PortGeometry<L>;
6666
}
6767

6868
impl ViewSource for Node {
@@ -218,3 +218,23 @@ impl<V, S: Simulator, A: Analysis, T: ViewSource + HasNestedView<V, NestedView:
218218
{
219219
type View = crate::simulation::data::Saved<NestedView<T, V>, S, A>;
220220
}
221+
222+
pub trait HasDefaultLayoutBundle: super::BundleKind {
223+
type Bundle<S: crate::layout::schema::Schema>: LayoutBundle<S>;
224+
}
225+
/// A port geometry bundle view.
226+
pub struct PortGeometryBundle<S>(PhantomData<S>);
227+
228+
impl<S: crate::layout::schema::Schema, T: ViewSource + HasDefaultLayoutBundle>
229+
HasViewImpl<PortGeometryBundle<S>> for Array<T>
230+
{
231+
type View = ArrayBundle<T::Bundle<S>>;
232+
}
233+
234+
impl<T: HasDefaultLayoutBundle> HasDefaultLayoutBundle for Array<T> {
235+
type Bundle<S: crate::layout::schema::Schema> = ArrayBundle<T::Bundle<S>>;
236+
}
237+
238+
impl HasDefaultLayoutBundle for Signal {
239+
type Bundle<S: crate::layout::schema::Schema> = PortGeometry<S::Layer>;
240+
}

‎substrate/src/types/impls.rs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,17 @@ impl<T: HasBundleKind> ArrayBundle<T> {
572572
pub fn num_elems(&self) -> usize {
573573
self.elems.len()
574574
}
575+
576+
/// Creates a new array bundle with the given elements.
577+
///
578+
/// All elements must have the same bundle kind, which must be equal to `kind`.
579+
/// Panics if this condition is not satisfied.
580+
pub fn new(kind: T::BundleKind, elems: Vec<T>) -> Self {
581+
for elem in elems.iter() {
582+
assert_eq!(kind, elem.kind());
583+
}
584+
Self { kind, elems }
585+
}
575586
}
576587

577588
#[cfg(test)]

0 commit comments

Comments
 (0)