substrate_api_examples/
lib.rs

1#![allow(dead_code)]
2use arcstr::ArcStr;
3use rust_decimal::Decimal;
4use scir::schema::StringSchema;
5use substrate::block::Block;
6use substrate::schematic::{
7    CellBuilder, HasNestedView, InstancePath, NestedData, NestedView, Schematic,
8};
9use substrate::types::schematic::{DataView, IoNodeBundle, Node, NodeBundle};
10use substrate::types::{Array, BundleKind, Flipped, InOut, Input, Io, Output, Signal};
11
12#[derive(Clone)]
13pub enum ExamplePrimitive {}
14
15// begin-code-snippet diff-pair
16#[derive(BundleKind, Clone, Default, Debug, PartialEq, Eq)]
17pub struct DiffPair {
18    pub p: Signal,
19    pub n: Signal,
20}
21// end-code-snippet diff-pair
22
23// begin-code-snippet inverter
24#[derive(Io, Clone, Default, Debug)]
25pub struct InverterIo {
26    pub vdd: InOut<Signal>,
27    pub vss: InOut<Signal>,
28    pub din: Input<Signal>,
29    pub dout: Output<Signal>,
30}
31
32#[derive(Debug, Clone, Hash, PartialEq, Eq)]
33pub struct Inverter {
34    strength: usize,
35}
36
37// begin-hidden-code
38impl Inverter {
39    pub fn new(strength: usize) -> Self {
40        Self { strength }
41    }
42}
43
44// end-hidden-code
45impl Block for Inverter {
46    type Io = InverterIo;
47
48    fn name(&self) -> arcstr::ArcStr {
49        arcstr::format!("inverter_{}", self.strength)
50    }
51
52    fn io(&self) -> Self::Io {
53        Default::default()
54    }
55}
56// end-code-snippet inverter
57
58// begin-code-snippet buffer_io_simple
59#[derive(Io, Clone, Copy, Default)]
60pub struct BufferIo {
61    vdd: InOut<Signal>,
62    vss: InOut<Signal>,
63    din: Input<Signal>,
64    dout: Output<Signal>,
65}
66// end-code-snippet buffer_io_simple
67
68#[derive(Debug, Clone, Hash, PartialEq, Eq)]
69pub struct Buffer {
70    strength: usize,
71}
72
73impl Buffer {
74    pub fn new(strength: usize) -> Self {
75        Self { strength }
76    }
77}
78
79impl Block for Buffer {
80    type Io = BufferIo;
81
82    fn name(&self) -> ArcStr {
83        arcstr::format!("buffer_{}", self.strength)
84    }
85
86    fn io(&self) -> Self::Io {
87        Default::default()
88    }
89}
90
91fn io() {
92    // begin-code-snippet array-io
93    #[derive(Io, Clone, Debug)]
94    pub struct ArrayIo {
95        pub in_bus: Input<Array<Signal>>,
96        pub out_bus: Output<Array<Signal>>,
97    }
98
99    let io_type = ArrayIo {
100        in_bus: Input(Array::new(5, Signal::new())),
101        out_bus: Output(Array::new(5, Signal::new())),
102    };
103    // end-code-snippet array-io
104
105    // begin-code-snippet array-io-constructor
106    impl ArrayIo {
107        pub fn new(in_size: usize, m: usize) -> Self {
108            Self {
109                in_bus: Input(Array::new(in_size, Signal::new())),
110                out_bus: Output(Array::new(in_size * m, Signal::new())),
111            }
112        }
113    }
114    // end-code-snippet array-io-constructor
115
116    // begin-code-snippet mos-io
117    #[derive(Io, Clone, Default, Debug)]
118    pub struct ThreePortMosIo {
119        pub d: InOut<Signal>,
120        pub g: Input<Signal>,
121        pub s: InOut<Signal>,
122    }
123
124    #[derive(Io, Clone, Default, Debug)]
125    pub struct FourPortMosIo {
126        pub d: InOut<Signal>,
127        pub g: Input<Signal>,
128        pub s: InOut<Signal>,
129        pub b: InOut<Signal>,
130    }
131    // end-code-snippet mos-io
132
133    // begin-code-snippet mos-io-data-view
134    impl DataView<FourPortMosIoKind> for ThreePortMosIoKind {
135        fn view_nodes_as(nodes: &NodeBundle<Self>) -> NodeBundle<FourPortMosIoKind> {
136            NodeBundle::<FourPortMosIoKind> {
137                d: nodes.d,
138                g: nodes.g,
139                s: nodes.s,
140                b: nodes.s,
141            }
142        }
143    }
144    // end-code-snippet mos-io-data-view
145
146    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
147    #[substrate(io = "()")]
148    pub struct ExampleBlockA;
149
150    impl Schematic for ExampleBlockA {
151        type Schema = StringSchema;
152        type NestedData = ();
153        fn schematic(
154            &self,
155            _io: &IoNodeBundle<Self>,
156            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
157        ) -> substrate::error::Result<Self::NestedData> {
158            // begin-code-snippet connect-data-views
159            let three_port_signal = cell.signal("three_port_signal", ThreePortMosIo::default());
160            let four_port_signal = cell.signal("four_port_signal", FourPortMosIo::default());
161            cell.connect(
162                three_port_signal.view_as::<FourPortMosIo>(),
163                four_port_signal,
164            );
165            // end-code-snippet connect-data-views
166            Ok(())
167        }
168    }
169
170    // begin-code-snippet mos-io-data-view-advanced
171    #[derive(BundleKind, Clone, Default, Debug, PartialEq, Eq)]
172    pub struct WithBody<T> {
173        inner: T,
174        b: Signal,
175    }
176
177    impl DataView<FourPortMosIoKind> for WithBody<ThreePortMosIoKind> {
178        fn view_nodes_as(nodes: &NodeBundle<Self>) -> NodeBundle<FourPortMosIoKind> {
179            NodeBundle::<FourPortMosIoKind> {
180                d: nodes.inner.d,
181                g: nodes.inner.g,
182                s: nodes.inner.s,
183                b: nodes.b,
184            }
185        }
186    }
187    // end-code-snippet mos-io-data-view-advanced
188
189    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
190    #[substrate(io = "()")]
191    pub struct ExampleBlockB;
192
193    impl Schematic for ExampleBlockB {
194        type Schema = StringSchema;
195        type NestedData = ();
196        fn schematic(
197            &self,
198            _io: &IoNodeBundle<Self>,
199            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
200        ) -> substrate::error::Result<Self::NestedData> {
201            // begin-code-snippet connect-data-views-advanced
202            let three_port_signal = cell.signal("three_port_signal", ThreePortMosIo::default());
203            let body = cell.signal("body", Signal);
204            let four_port_signal = cell.signal("four_port_signal", FourPortMosIo::default());
205            cell.connect(
206                NodeBundle::<WithBody<ThreePortMosIoKind>> {
207                    inner: three_port_signal,
208                    b: body,
209                }
210                .view_as::<FourPortMosIo>(),
211                four_port_signal,
212            );
213            // end-code-snippet connect-data-views-advanced
214            Ok(())
215        }
216    }
217
218    mod arbitrary_connect {
219        use super::*;
220        // begin-code-snippet arbitrary-connect-ios
221        #[derive(Io, Clone, Default, Debug)]
222        pub struct ThreePortMosIo {
223            pub d: InOut<Signal>,
224            pub g: Input<Signal>,
225            pub s: InOut<Signal>,
226        }
227
228        #[derive(Io, Clone, Default, Debug)]
229        pub struct OtherThreePortMosIo {
230            pub drain: InOut<Signal>,
231            pub gate: Input<Signal>,
232            pub source: InOut<Signal>,
233        }
234        // end-code-snippet arbitrary-connect-ios
235
236        #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
237        #[substrate(io = "()")]
238        pub struct ExampleBlockC;
239
240        impl Schematic for ExampleBlockC {
241            type Schema = StringSchema;
242            type NestedData = ();
243            fn schematic(
244                &self,
245                _io: &IoNodeBundle<Self>,
246                cell: &mut CellBuilder<<Self as Schematic>::Schema>,
247            ) -> substrate::error::Result<Self::NestedData> {
248                // begin-code-snippet arbitrary-connect
249                let three_port_signal = cell.signal("three_port_signal", ThreePortMosIo::default());
250                let other_three_port_signal =
251                    cell.signal("other_three_port_signal", OtherThreePortMosIo::default());
252                cell.connect(
253                    three_port_signal.view_as::<Array<Signal>>(),
254                    other_three_port_signal.view_as::<Array<Signal>>(),
255                );
256                // end-code-snippet arbitrary-connect
257                Ok(())
258            }
259        }
260    }
261
262    // begin-code-snippet sram-io
263    #[derive(Io, Clone, Debug)]
264    pub struct SramIo {
265        pub clk: Input<Signal>,
266        pub we: Input<Signal>,
267        pub addr: Input<Array<Signal>>,
268        pub din: Input<Array<Signal>>,
269        pub dout: Output<Array<Signal>>,
270    }
271
272    pub type SramObserverIo = Input<SramIo>;
273    // end-code-snippet sram-io
274
275    // begin-code-snippet sram-driver-io
276    pub type SramDriverIo = Flipped<SramIo>;
277    // end-code-snippet sram-driver-io
278
279    // begin-code-snippet sram-block
280    #[derive(Debug, Clone, Hash, PartialEq, Eq)]
281    pub struct Sram {
282        num_words: usize,
283        data_width: usize,
284    }
285
286    impl Block for Sram {
287        type Io = SramIo;
288
289        fn name(&self) -> ArcStr {
290            arcstr::format!("sram{}x{}", self.num_words, self.data_width)
291        }
292
293        fn io(&self) -> Self::Io {
294            Self::Io {
295                clk: Default::default(),
296                we: Default::default(),
297                addr: Input(Array::new(
298                    (self.num_words - 1).ilog2() as usize + 1,
299                    Signal::new(),
300                )),
301                din: Input(Array::new(self.data_width, Signal::new())),
302                dout: Output(Array::new(self.data_width, Signal::new())),
303            }
304        }
305    }
306    // end-code-snippet sram-block
307
308    let _ = io_type;
309}
310
311#[derive(Io, Clone, Default, Debug)]
312pub struct VdividerIo {
313    pub vdd: InOut<Signal>,
314    pub vss: InOut<Signal>,
315    pub dout: Output<Signal>,
316}
317
318#[allow(clippy::derived_hash_with_manual_eq)]
319#[derive(Block, Debug, Copy, Clone, Hash, Eq)]
320#[substrate(io = "()")]
321pub struct Vdivider {
322    /// The top resistance.
323    pub r1: Decimal,
324    /// The bottom resistance.
325    pub r2: Decimal,
326}
327
328// begin-code-snippet vdivider-bad-eq
329impl PartialEq<Self> for Vdivider {
330    fn eq(&self, other: &Self) -> bool {
331        self.r1 == other.r1
332    }
333}
334// end-code-snippet vdivider-bad-eq
335
336pub mod nested_data {
337    use super::*;
338    use ::scir::schema::StringSchema;
339    use substrate::schematic::Instance;
340    use substrate::types::schematic::IoNodeBundle;
341
342    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
343    #[substrate(io = "()")]
344    pub struct Inverter;
345
346    impl Schematic for Inverter {
347        type Schema = StringSchema;
348        type NestedData = ();
349        fn schematic(
350            &self,
351            _io: &IoNodeBundle<Self>,
352            _cell: &mut CellBuilder<<Self as Schematic>::Schema>,
353        ) -> substrate::error::Result<Self::NestedData> {
354            Ok(())
355        }
356    }
357
358    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
359    #[substrate(io = "()")]
360    pub struct Buffer;
361
362    // begin-code-snippet buffer-nested-data
363    #[derive(NestedData)]
364    pub struct BufferData {
365        inv1: Instance<Inverter>,
366        inv2: Instance<Inverter>,
367        x: Node,
368    }
369    // end-code-snippet buffer-nested-data
370
371    // begin-code-snippet custom-nested-view
372    #[derive(Clone, Copy)]
373    pub struct MyMetadata {
374        my_calculated_value: i64,
375    }
376
377    impl HasNestedView for MyMetadata {
378        type NestedView = Self;
379
380        fn nested_view(&self, _parent: &InstancePath) -> Self::NestedView {
381            *self
382        }
383    }
384
385    #[derive(NestedData)]
386    pub struct BufferDataWithMetadata {
387        inv1: Instance<Inverter>,
388        inv2: Instance<Inverter>,
389        metadata: MyMetadata,
390    }
391    // end-code-snippet custom-nested-view
392
393    // begin-code-snippet custom-nested-view-2
394    pub struct BufferDataWithMetadataV2 {
395        inv1: Instance<Inverter>,
396        inv2: Instance<Inverter>,
397        metadata: i64,
398    }
399
400    pub struct NestedBufferDataWithMetadataV2 {
401        inv1: NestedView<Instance<Inverter>>,
402        inv2: NestedView<Instance<Inverter>>,
403        metadata: i64,
404    }
405
406    impl HasNestedView for BufferDataWithMetadataV2 {
407        type NestedView = NestedBufferDataWithMetadataV2;
408
409        fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
410            Self::NestedView {
411                inv1: self.inv1.nested_view(parent),
412                inv2: self.inv2.nested_view(parent),
413                metadata: self.metadata,
414            }
415        }
416    }
417
418    impl HasNestedView for NestedBufferDataWithMetadataV2 {
419        type NestedView = NestedBufferDataWithMetadataV2;
420
421        fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
422            Self::NestedView {
423                inv1: self.inv1.nested_view(parent),
424                inv2: self.inv2.nested_view(parent),
425                metadata: self.metadata,
426            }
427        }
428    }
429    // end-code-snippet custom-nested-view-2
430}
431
432#[derive(Io, Clone, Default, Debug)]
433pub struct ResistorIo {
434    pub p: InOut<Signal>,
435    pub n: InOut<Signal>,
436}
437
438#[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
439#[substrate(io = "ResistorIo")]
440pub struct Resistor(Decimal);
441
442impl Resistor {
443    pub fn new(val: impl Into<Decimal>) -> Self {
444        Self(val.into())
445    }
446}
447
448mod try_data {
449    use ::scir::schema::StringSchema;
450    use substrate::types::schematic::IoNodeBundle;
451
452    use super::*;
453
454    impl Schematic for Resistor {
455        type Schema = StringSchema;
456        type NestedData = ();
457
458        fn schematic(
459            &self,
460            _io: &IoNodeBundle<Resistor>,
461            _cell: &mut super::CellBuilder<<Self as Schematic>::Schema>,
462        ) -> substrate::error::Result<Self::NestedData> {
463            Ok(())
464        }
465    }
466
467    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
468    #[substrate(io = "super::VdividerIo")]
469    pub struct Vdivider {
470        /// The top resistance.
471        pub r1: Decimal,
472        /// The bottom resistance.
473        pub r2: Decimal,
474    }
475
476    // begin-code-snippet vdivider-try-data-error-handling
477    impl Schematic for Vdivider {
478        type Schema = StringSchema;
479        type NestedData = ();
480
481        fn schematic(
482            &self,
483            io: &IoNodeBundle<Self>,
484            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
485        ) -> substrate::error::Result<Self::NestedData> {
486            let r1 = cell.instantiate(Resistor::new(self.r1));
487            let r2 = cell.instantiate(Resistor::new(self.r2));
488            r1.try_data()?;
489            r2.try_data()?;
490
491            cell.connect(io.vdd, r1.io().p);
492            cell.connect(io.dout, r1.io().n);
493            cell.connect(io.dout, r2.io().p);
494            cell.connect(io.vss, r2.io().n);
495
496            Ok(())
497        }
498    }
499    // end-code-snippet vdivider-try-data-error-handling
500}
501
502mod instantiate_blocking {
503    use ::scir::schema::StringSchema;
504    use substrate::types::schematic::IoNodeBundle;
505
506    use super::*;
507
508    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
509    #[substrate(io = "super::VdividerIo")]
510    pub struct Vdivider {
511        /// The top resistance.
512        pub r1: Decimal,
513        /// The bottom resistance.
514        pub r2: Decimal,
515    }
516
517    // begin-code-snippet vdivider-instantiate-blocking-error-handling
518    impl Schematic for Vdivider {
519        type Schema = StringSchema;
520        type NestedData = ();
521        fn schematic(
522            &self,
523            io: &IoNodeBundle<Self>,
524            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
525        ) -> substrate::error::Result<Self::NestedData> {
526            let r1 = cell.instantiate_blocking(Resistor::new(self.r1))?;
527            let r2 = cell.instantiate_blocking(Resistor::new(self.r2))?;
528
529            cell.connect(io.vdd, r1.io().p);
530            cell.connect(io.dout, r1.io().n);
531            cell.connect(io.dout, r2.io().p);
532            cell.connect(io.vss, r2.io().n);
533
534            Ok(())
535        }
536    }
537    // end-code-snippet vdivider-instantiate-blocking-error-handling
538}
539
540mod instantiate_blocking_bad {
541    use ::scir::schema::StringSchema;
542
543    use super::*;
544
545    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
546    #[substrate(io = "super::VdividerIo")]
547    pub struct Vdivider {
548        /// The top resistance.
549        pub r1: Decimal,
550        /// The bottom resistance.
551        pub r2: Decimal,
552    }
553
554    // begin-code-snippet vdivider-instantiate-blocking-bad
555    impl Schematic for Vdivider {
556        type Schema = StringSchema;
557        type NestedData = ();
558        fn schematic(
559            &self,
560            io: &substrate::types::schematic::IoNodeBundle<Self>,
561            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
562        ) -> substrate::error::Result<Self::NestedData> {
563            if let Ok(r1) = cell.instantiate_blocking(Resistor::new(self.r1)) {
564                cell.connect(io.vdd, r1.io().p);
565                cell.connect(io.dout, r1.io().n);
566            } else {
567                cell.connect(io.vdd, io.dout);
568            }
569            let r2 = cell.instantiate_blocking(Resistor::new(self.r1))?;
570            cell.connect(io.dout, r2.io().p);
571            cell.connect(io.vss, r2.io().n);
572
573            Ok(())
574        }
575    }
576    // end-code-snippet vdivider-instantiate-blocking-bad
577}
578
579mod generate {
580    use ::scir::schema::StringSchema;
581    use substrate::types::schematic::IoNodeBundle;
582
583    use super::*;
584
585    #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)]
586    #[substrate(io = "super::VdividerIo")]
587    pub struct Vdivider {
588        /// The top resistance.
589        pub r1: Decimal,
590        /// The bottom resistance.
591        pub r2: Decimal,
592    }
593
594    // begin-code-snippet vdivider-generate-add-error-handling
595    impl Schematic for Vdivider {
596        type Schema = StringSchema;
597        type NestedData = ();
598        fn schematic(
599            &self,
600            io: &IoNodeBundle<Self>,
601            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
602        ) -> substrate::error::Result<Self::NestedData> {
603            let r1_cell = cell.generate(Resistor::new(self.r1));
604            let r2 = cell.instantiate_blocking(Resistor::new(self.r2))?;
605
606            // Block on generator to see if it succeeds.
607            if r1_cell.try_cell().is_ok() {
608                let r1 = cell.add(r1_cell);
609                cell.connect(io.vdd, r1.io().p);
610                cell.connect(io.dout, r1.io().n);
611            } else {
612                cell.connect(io.vdd, io.dout);
613            }
614
615            cell.connect(io.dout, r2.io().p);
616            cell.connect(io.vss, r2.io().n);
617
618            Ok(())
619        }
620    }
621    // end-code-snippet vdivider-generate-add-error-handling
622}
623
624mod scir_examples {
625    use scir::schema::{Schema, StringSchema};
626    use scir::{Cell, Direction, Instance, LibraryBuilder};
627    use substrate::block::Block;
628    use substrate::schematic::{CellBuilder, PrimitiveBinding, Schematic, ScirBinding};
629    use substrate::types::TwoTerminalIo;
630    use substrate::types::schematic::IoNodeBundle;
631
632    // begin-code-snippet scir-schema
633    pub struct MySchema;
634
635    #[derive(Debug, Copy, Clone)]
636    pub enum MyPrimitive {
637        Resistor(i64),
638        Capacitor(i64),
639    }
640
641    impl Schema for MySchema {
642        type Primitive = MyPrimitive;
643    }
644    // end-code-snippet scir-schema
645
646    // begin-code-snippet scir-primitive-binding
647    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Block)]
648    #[substrate(io = "TwoTerminalIo")]
649    pub struct Resistor(i64);
650
651    impl Schematic for Resistor {
652        type Schema = MySchema;
653        type NestedData = ();
654        fn schematic(
655            &self,
656            io: &IoNodeBundle<Self>,
657            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
658        ) -> substrate::error::Result<Self::NestedData> {
659            let mut prim = PrimitiveBinding::new(MyPrimitive::Resistor(self.0));
660
661            prim.connect("p", io.p);
662            prim.connect("n", io.n);
663
664            cell.set_primitive(prim);
665            Ok(())
666        }
667    }
668    // end-code-snippet scir-primitive-binding
669
670    // begin-code-snippet scir-scir-binding
671    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Block)]
672    #[substrate(io = "TwoTerminalIo")]
673    pub struct ParallelResistors(i64, i64);
674
675    impl Schematic for ParallelResistors {
676        type Schema = MySchema;
677        type NestedData = ();
678        fn schematic(
679            &self,
680            io: &IoNodeBundle<Self>,
681            cell: &mut CellBuilder<<Self as Schematic>::Schema>,
682        ) -> substrate::error::Result<Self::NestedData> {
683            // Creates a SCIR library containing the desired cell.
684            let mut lib = LibraryBuilder::<MySchema>::new();
685            let r1 = lib.add_primitive(MyPrimitive::Resistor(self.0));
686            let r2 = lib.add_primitive(MyPrimitive::Resistor(self.1));
687            let mut parallel_resistors = Cell::new("parallel_resistors");
688            let p = parallel_resistors.add_node("p");
689            let n = parallel_resistors.add_node("n");
690            parallel_resistors.expose_port(p, Direction::InOut);
691            parallel_resistors.expose_port(n, Direction::InOut);
692            let mut r1 = Instance::new("r1", r1);
693            r1.connect("p", p);
694            r1.connect("n", n);
695            parallel_resistors.add_instance(r1);
696            let mut r2 = Instance::new("r2", r2);
697            r2.connect("p", p);
698            r2.connect("n", n);
699            parallel_resistors.add_instance(r2);
700            let cell_id = lib.add_cell(parallel_resistors);
701
702            // Binds to the desired cell in the SCIR library.
703            let mut scir = ScirBinding::new(lib.build().unwrap(), cell_id);
704
705            scir.connect("p", io.p);
706            scir.connect("n", io.n);
707
708            cell.set_scir(scir);
709            Ok(())
710        }
711    }
712    // end-code-snippet scir-scir-binding
713
714    #[allow(unused_variables)]
715    fn library() {
716        // begin-code-snippet scir-library-builder
717        let mut lib = LibraryBuilder::<StringSchema>::new();
718        // end-code-snippet scir-library-builder
719        // begin-code-snippet scir-library-cell
720        let empty_cell = Cell::new("empty");
721        let empty_cell_id = lib.add_cell(empty_cell);
722        // end-code-snippet scir-library-cell
723        // begin-code-snippet scir-library-primitive
724        let resistor_id = lib.add_primitive(arcstr::literal!("resistor"));
725        // end-code-snippet scir-library-primitive
726        // begin-code-snippet scir-library-signals
727        let mut vdivider = Cell::new("vdivider");
728
729        let vdd = vdivider.add_node("vdd");
730        let vout = vdivider.add_node("vout");
731        let vss = vdivider.add_node("vss");
732
733        vdivider.expose_port(vdd, Direction::InOut);
734        vdivider.expose_port(vout, Direction::Output);
735        vdivider.expose_port(vss, Direction::InOut);
736        // end-code-snippet scir-library-signals
737        // begin-code-snippet scir-library-primitive-instances
738        let mut r1 = Instance::new("r1", resistor_id);
739
740        r1.connect("p", vdd);
741        r1.connect("n", vout);
742
743        vdivider.add_instance(r1);
744
745        let mut r2 = Instance::new("r2", resistor_id);
746
747        r2.connect("p", vout);
748        r2.connect("n", vss);
749
750        vdivider.add_instance(r2);
751
752        let vdivider_id = lib.add_cell(vdivider);
753        // end-code-snippet scir-library-primitive-instances
754        // begin-code-snippet scir-library-instances
755        let mut stacked_vdivider = Cell::new("stacked_vdivider");
756
757        let vdd = stacked_vdivider.add_node("vdd");
758        let v1 = stacked_vdivider.add_node("v1");
759        let v2 = stacked_vdivider.add_node("v2");
760        let v3 = stacked_vdivider.add_node("v3");
761        let vss = stacked_vdivider.add_node("vss");
762
763        let mut vdiv1 = Instance::new("vdiv1", vdivider_id);
764
765        vdiv1.connect("vdd", vdd);
766        vdiv1.connect("vout", v1);
767        vdiv1.connect("vss", v2);
768
769        stacked_vdivider.add_instance(vdiv1);
770
771        let mut vdiv2 = Instance::new("vdiv2", vdivider_id);
772
773        vdiv2.connect("vdd", v2);
774        vdiv2.connect("vout", v3);
775        vdiv2.connect("vss", vss);
776
777        stacked_vdivider.add_instance(vdiv2);
778
779        let stacked_vdivider_id = lib.add_cell(stacked_vdivider);
780        // end-code-snippet scir-library-instances
781    }
782}
783
784fn main() {}