Skip to main content

logicaffeine_compile/codegen_ana/
ontology.rs

1//! The typed ontology of analog circuits.
2//!
3//! The 10,000-year framing: encode what analog circuits ARE — every element class physics
4//! builds — not merely what this compiler lowers today. Three layers, one direction of
5//! reference:
6//!
7//! ```text
8//! Element (what physics builds)  ←— realized_by —  ComputeOp (what the compiler lowers)
9//!         |                                                |
10//!    EffectRow (effects.rs)                     AnalogCellKind (today's realized tile IR,
11//!    [Element × PhysicsEffect]                   unchanged — injects via cell_kind_op)
12//! ```
13//!
14//! The pit of success is the Rust exhaustive match: adding an `Element` variant breaks every
15//! classifying `fn` at compile time until the classification is consciously written, and the
16//! ledgers in `analog_ontology_lock` make the DIRECTION of change monotone — an element can
17//! only move Unrealized → ComputeMapped (a witnessed lowering, celebrated), never silently
18//! back. Nothing in the existing lanes moves: [`AnalogCellKind`] is untouched and injects
19//! into the vocabulary totally.
20
21use super::target::AnalogCellKind;
22
23/// Two-terminal and passive network elements.
24#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
25pub enum Passive {
26    Resistor,
27    Capacitor,
28    Inductor,
29    MutualInductor,
30    TransmissionLine,
31    Varactor,
32    Memristor,
33    AnalogSwitch,
34    Crystal,
35}
36
37/// Independent and controlled sources — the linear-network vocabulary.
38#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
39pub enum SourceElement {
40    IndependentV,
41    IndependentI,
42    /// Voltage-controlled current source — the transconductor, the linear tile's soul.
43    Vccs,
44    Vcvs,
45    Cccs,
46    Ccvs,
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
50pub enum DiodeRegion {
51    ForwardExp,
52    Reverse,
53    Breakdown,
54}
55
56#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
57pub enum BjtRegion {
58    ForwardActive,
59    Saturation,
60    Cutoff,
61    ReverseActive,
62}
63
64#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
65pub enum MosRegion {
66    SubthresholdExp,
67    SaturationSquareLaw,
68    Triode,
69    Cutoff,
70}
71
72/// Semiconductor primitives, by device × operating region (the region IS the mathematical
73/// law the element contributes — subthreshold is exp, saturation is square-law).
74#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
75pub enum Semiconductor {
76    Diode(DiodeRegion),
77    Bjt(BjtRegion),
78    Mosfet(MosRegion),
79    Jfet,
80    PhotoDiode,
81    /// The Hasler programming substrate (the sourced <1% figure's home).
82    FloatingGate,
83}
84
85/// Functional macros — the characterized, replicated blocks a chip is actually built from.
86#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
87pub enum FunctionalMacro {
88    // The compute-mapped present (the V1 chip):
89    LinearCombTile,
90    GilbertMultiplier,
91    OtaIntegrator,
92    Comparator,
93    SampleHold,
94    // The compute-mapped future (each arrives with its planned op):
95    DiffPair,
96    TranslinearLoop,
97    WinnerTakeAll,
98    Chopper,
99    AnalogSelect,
100    // Support / interface macros:
101    Ota,
102    OpAmp,
103    CurrentMirror,
104    BandgapReference,
105    BiasGenerator,
106    VoltageReference,
107    ClockDistribution,
108    Dac,
109    Adc,
110    // Recognized, unrealized:
111    FilterBiquad,
112    Oscillator,
113    Vco,
114    Pll,
115    Lna,
116    Pga,
117    LdoRegulator,
118}
119
120/// One element of the analog universe.
121#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
122pub enum Element {
123    Passive(Passive),
124    Source(SourceElement),
125    Semiconductor(Semiconductor),
126    Macro(FunctionalMacro),
127}
128
129/// Every element, exactly once, in canonical order — the census surface.
130pub const ALL_ELEMENTS: &[Element] = &[
131    Element::Passive(Passive::Resistor),
132    Element::Passive(Passive::Capacitor),
133    Element::Passive(Passive::Inductor),
134    Element::Passive(Passive::MutualInductor),
135    Element::Passive(Passive::TransmissionLine),
136    Element::Passive(Passive::Varactor),
137    Element::Passive(Passive::Memristor),
138    Element::Passive(Passive::AnalogSwitch),
139    Element::Passive(Passive::Crystal),
140    Element::Source(SourceElement::IndependentV),
141    Element::Source(SourceElement::IndependentI),
142    Element::Source(SourceElement::Vccs),
143    Element::Source(SourceElement::Vcvs),
144    Element::Source(SourceElement::Cccs),
145    Element::Source(SourceElement::Ccvs),
146    Element::Semiconductor(Semiconductor::Diode(DiodeRegion::ForwardExp)),
147    Element::Semiconductor(Semiconductor::Diode(DiodeRegion::Reverse)),
148    Element::Semiconductor(Semiconductor::Diode(DiodeRegion::Breakdown)),
149    Element::Semiconductor(Semiconductor::Bjt(BjtRegion::ForwardActive)),
150    Element::Semiconductor(Semiconductor::Bjt(BjtRegion::Saturation)),
151    Element::Semiconductor(Semiconductor::Bjt(BjtRegion::Cutoff)),
152    Element::Semiconductor(Semiconductor::Bjt(BjtRegion::ReverseActive)),
153    Element::Semiconductor(Semiconductor::Mosfet(MosRegion::SubthresholdExp)),
154    Element::Semiconductor(Semiconductor::Mosfet(MosRegion::SaturationSquareLaw)),
155    Element::Semiconductor(Semiconductor::Mosfet(MosRegion::Triode)),
156    Element::Semiconductor(Semiconductor::Mosfet(MosRegion::Cutoff)),
157    Element::Semiconductor(Semiconductor::Jfet),
158    Element::Semiconductor(Semiconductor::PhotoDiode),
159    Element::Semiconductor(Semiconductor::FloatingGate),
160    Element::Macro(FunctionalMacro::LinearCombTile),
161    Element::Macro(FunctionalMacro::GilbertMultiplier),
162    Element::Macro(FunctionalMacro::OtaIntegrator),
163    Element::Macro(FunctionalMacro::Comparator),
164    Element::Macro(FunctionalMacro::SampleHold),
165    Element::Macro(FunctionalMacro::DiffPair),
166    Element::Macro(FunctionalMacro::TranslinearLoop),
167    Element::Macro(FunctionalMacro::WinnerTakeAll),
168    Element::Macro(FunctionalMacro::Chopper),
169    Element::Macro(FunctionalMacro::AnalogSelect),
170    Element::Macro(FunctionalMacro::Ota),
171    Element::Macro(FunctionalMacro::OpAmp),
172    Element::Macro(FunctionalMacro::CurrentMirror),
173    Element::Macro(FunctionalMacro::BandgapReference),
174    Element::Macro(FunctionalMacro::BiasGenerator),
175    Element::Macro(FunctionalMacro::VoltageReference),
176    Element::Macro(FunctionalMacro::ClockDistribution),
177    Element::Macro(FunctionalMacro::Dac),
178    Element::Macro(FunctionalMacro::Adc),
179    Element::Macro(FunctionalMacro::FilterBiquad),
180    Element::Macro(FunctionalMacro::Oscillator),
181    Element::Macro(FunctionalMacro::Vco),
182    Element::Macro(FunctionalMacro::Pll),
183    Element::Macro(FunctionalMacro::Lna),
184    Element::Macro(FunctionalMacro::Pga),
185    Element::Macro(FunctionalMacro::LdoRegulator),
186];
187
188/// Layer 2: the compute vocabulary — the ops the ontology recognizes. The REALIZED subset is
189/// bijective with today's tile IR; the rest are named-future (the `KNOWN_PLANNED` ledger).
190#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
191pub enum ComputeOp {
192    // Realized today (bijective with AnalogCellKind):
193    Sum,
194    Mul,
195    GainConst,
196    Integrate,
197    Compare,
198    SampleHold,
199    DacIn,
200    AdcOut,
201    // Named-future (each arrives with its campaign phase):
202    Select,
203    Div,
204    Sqrt,
205    Exp,
206    Log,
207    Tanh,
208    ArgMax,
209}
210
211pub const ALL_COMPUTE_OPS: &[ComputeOp] = &[
212    ComputeOp::Sum,
213    ComputeOp::Mul,
214    ComputeOp::GainConst,
215    ComputeOp::Integrate,
216    ComputeOp::Compare,
217    ComputeOp::SampleHold,
218    ComputeOp::DacIn,
219    ComputeOp::AdcOut,
220    ComputeOp::Select,
221    ComputeOp::Div,
222    ComputeOp::Sqrt,
223    ComputeOp::Exp,
224    ComputeOp::Log,
225    ComputeOp::Tanh,
226    ComputeOp::ArgMax,
227];
228
229/// The ops whose tile kinds exist in the ADL today (`ALL_ANALOG_CELL_KINDS`) — the anchor of
230/// the realized/planned split.
231pub const REALIZED_OPS: &[ComputeOp] = &[
232    ComputeOp::Sum,
233    ComputeOp::Mul,
234    ComputeOp::GainConst,
235    ComputeOp::Integrate,
236    ComputeOp::Compare,
237    ComputeOp::SampleHold,
238    ComputeOp::DacIn,
239    ComputeOp::AdcOut,
240    ComputeOp::Select,
241    ComputeOp::Exp,
242    ComputeOp::Log,
243    ComputeOp::Tanh,
244    ComputeOp::Sqrt,
245    ComputeOp::Div,
246];
247
248/// Total injection of today's tile IR into the vocabulary — no wildcard, so a new cell kind
249/// cannot escape the ontology.
250pub fn cell_kind_op(k: AnalogCellKind) -> ComputeOp {
251    match k {
252        AnalogCellKind::Sum => ComputeOp::Sum,
253        AnalogCellKind::Mul => ComputeOp::Mul,
254        AnalogCellKind::GainConst => ComputeOp::GainConst,
255        AnalogCellKind::Integrate => ComputeOp::Integrate,
256        AnalogCellKind::Compare => ComputeOp::Compare,
257        AnalogCellKind::Select => ComputeOp::Select,
258        AnalogCellKind::Exp => ComputeOp::Exp,
259        AnalogCellKind::Log => ComputeOp::Log,
260        AnalogCellKind::Tanh => ComputeOp::Tanh,
261        AnalogCellKind::Sqrt => ComputeOp::Sqrt,
262        AnalogCellKind::Div => ComputeOp::Div,
263        AnalogCellKind::SampleHold => ComputeOp::SampleHold,
264        AnalogCellKind::DacIn => ComputeOp::DacIn,
265        AnalogCellKind::AdcOut => ComputeOp::AdcOut,
266    }
267}
268
269/// What a non-compute element does for the chip.
270#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
271pub enum SupportFunction {
272    Bias,
273    Reference,
274    Clock,
275    Regulation,
276    Programming,
277    Routing,
278}
279
280/// Layer 3: an element's role — the total classification the ledgers pin.
281#[derive(Clone, Copy, Debug, PartialEq, Eq)]
282pub enum ElementRole {
283    /// A lowering exists NOW for these ops (or the element is a realized constituent of one).
284    ComputeMapped(&'static [ComputeOp]),
285    /// Bias / reference / clock / regulation / programming / routing — never carries signal math.
286    Support(SupportFunction),
287    /// The plane boundary (converters).
288    Interface(ComputeOp),
289    /// In the ontology, no realization yet — ledgered shrink-only.
290    Unrealized,
291}
292
293/// THE role classification — exhaustive over every leaf, no `_` arm anywhere.
294pub fn role(e: Element) -> ElementRole {
295    use ComputeOp as Op;
296    use ElementRole::{ComputeMapped as Mapped, Interface, Support, Unrealized};
297    use SupportFunction as Sf;
298    match e {
299        // ── Passives ──
300        Element::Passive(p) => match p {
301            // State storage IS realized: the S&H and the OTA-C integrator hold charge on caps.
302            Passive::Capacitor => Mapped(&[Op::SampleHold, Op::Integrate]),
303            Passive::AnalogSwitch => Support(Sf::Routing),
304            Passive::Crystal => Support(Sf::Clock),
305            Passive::Resistor
306            | Passive::Inductor
307            | Passive::MutualInductor
308            | Passive::TransmissionLine
309            | Passive::Varactor
310            | Passive::Memristor => Unrealized,
311        },
312        // ── Sources ──
313        Element::Source(s) => match s {
314            // The transconductor is the linear tile's physical mechanism.
315            SourceElement::Vccs => Mapped(&[Op::Sum, Op::GainConst]),
316            SourceElement::IndependentV | SourceElement::IndependentI => Support(Sf::Reference),
317            SourceElement::Vcvs | SourceElement::Cccs | SourceElement::Ccvs => Unrealized,
318        },
319        // ── Semiconductors: regions are future realizers (translinear/subthreshold lanes) —
320        //    Unrealized until their ops lower; the ledger records each by name. ──
321        Element::Semiconductor(s) => match s {
322            Semiconductor::FloatingGate => Support(Sf::Programming),
323            // The O6 promotions: the operating regions whose mathematical laws the
324            // translinear tiles witness.
325            Semiconductor::Mosfet(MosRegion::SubthresholdExp) => {
326                Mapped(&[Op::Exp, Op::Tanh, Op::Div, Op::Sqrt])
327            }
328            Semiconductor::Bjt(BjtRegion::ForwardActive) => Mapped(&[Op::Div, Op::Sqrt]),
329            Semiconductor::Diode(DiodeRegion::ForwardExp) => Mapped(&[Op::Log]),
330            Semiconductor::Diode(_)
331            | Semiconductor::Bjt(_)
332            | Semiconductor::Mosfet(_)
333            | Semiconductor::Jfet
334            | Semiconductor::PhotoDiode => Unrealized,
335        },
336        // ── Macros ──
337        Element::Macro(m) => match m {
338            FunctionalMacro::LinearCombTile => Mapped(&[Op::Sum, Op::GainConst]),
339            FunctionalMacro::GilbertMultiplier => Mapped(&[Op::Mul]),
340            FunctionalMacro::OtaIntegrator => Mapped(&[Op::Integrate]),
341            FunctionalMacro::Comparator => Mapped(&[Op::Compare, Op::Select]),
342            FunctionalMacro::SampleHold => Mapped(&[Op::SampleHold]),
343            FunctionalMacro::Dac => Interface(Op::DacIn),
344            FunctionalMacro::Adc => Interface(Op::AdcOut),
345            FunctionalMacro::CurrentMirror | FunctionalMacro::BiasGenerator => Support(Sf::Bias),
346            FunctionalMacro::BandgapReference | FunctionalMacro::VoltageReference => {
347                Support(Sf::Reference)
348            }
349            FunctionalMacro::ClockDistribution => Support(Sf::Clock),
350            FunctionalMacro::Ota | FunctionalMacro::OpAmp | FunctionalMacro::LdoRegulator => {
351                Support(Sf::Regulation)
352            }
353            FunctionalMacro::AnalogSelect => Mapped(&[Op::Select]),
354            FunctionalMacro::TranslinearLoop => Mapped(&[Op::Div, Op::Sqrt, Op::Log]),
355            FunctionalMacro::DiffPair => Mapped(&[Op::Exp, Op::Tanh]),
356            FunctionalMacro::WinnerTakeAll
357            | FunctionalMacro::Chopper
358            | FunctionalMacro::FilterBiquad
359            | FunctionalMacro::Oscillator
360            | FunctionalMacro::Vco
361            | FunctionalMacro::Pll
362            | FunctionalMacro::Lna
363            | FunctionalMacro::Pga => Unrealized,
364        },
365    }
366}
367
368/// Which elements realize each compute op — exhaustive, non-empty. For REALIZED ops every
369/// listed realizer is itself `ComputeMapped`/`Interface` (the lock proves it); for PLANNED
370/// ops the realizers are the elements whose lowering phase will promote them.
371pub fn realizing_elements(op: ComputeOp) -> &'static [Element] {
372    match op {
373        ComputeOp::Sum | ComputeOp::GainConst => &[
374            Element::Macro(FunctionalMacro::LinearCombTile),
375            Element::Source(SourceElement::Vccs),
376        ],
377        ComputeOp::Mul => &[Element::Macro(FunctionalMacro::GilbertMultiplier)],
378        ComputeOp::Integrate => &[
379            Element::Macro(FunctionalMacro::OtaIntegrator),
380            Element::Passive(Passive::Capacitor),
381        ],
382        ComputeOp::Compare => &[Element::Macro(FunctionalMacro::Comparator)],
383        ComputeOp::SampleHold => &[
384            Element::Macro(FunctionalMacro::SampleHold),
385            Element::Passive(Passive::Capacitor),
386        ],
387        ComputeOp::DacIn => &[Element::Macro(FunctionalMacro::Dac)],
388        ComputeOp::AdcOut => &[Element::Macro(FunctionalMacro::Adc)],
389        ComputeOp::Select => &[
390            Element::Macro(FunctionalMacro::AnalogSelect),
391            Element::Macro(FunctionalMacro::Comparator),
392        ],
393        ComputeOp::Div | ComputeOp::Sqrt => &[
394            Element::Macro(FunctionalMacro::TranslinearLoop),
395            Element::Semiconductor(Semiconductor::Bjt(BjtRegion::ForwardActive)),
396            Element::Semiconductor(Semiconductor::Mosfet(MosRegion::SubthresholdExp)),
397        ],
398        ComputeOp::Exp | ComputeOp::Tanh => &[
399            Element::Macro(FunctionalMacro::DiffPair),
400            Element::Semiconductor(Semiconductor::Mosfet(MosRegion::SubthresholdExp)),
401        ],
402        ComputeOp::Log => &[
403            Element::Macro(FunctionalMacro::TranslinearLoop),
404            Element::Semiconductor(Semiconductor::Diode(DiodeRegion::ForwardExp)),
405        ],
406        ComputeOp::ArgMax => &[
407            Element::Macro(FunctionalMacro::WinnerTakeAll),
408            Element::Macro(FunctionalMacro::CurrentMirror),
409        ],
410    }
411}
412
413/// The census device: a stable name per element — exhaustive by construction (delegates to
414/// the leaf enums' `Debug`, which the census lock pins for duplicates and coverage).
415pub fn element_name(e: Element) -> String {
416    match e {
417        Element::Passive(p) => format!("Passive::{p:?}"),
418        Element::Source(s) => format!("Source::{s:?}"),
419        Element::Semiconductor(s) => format!("Semi::{s:?}"),
420        Element::Macro(m) => format!("Macro::{m:?}"),
421    }
422}