Skip to main content

minroot_cat/
target.rs

1//! FPGA/ASIC target abstraction.
2//!
3//! The `MinRoot` hardware generates target-agnostic Verilog via hdl-cat.
4//! Technology-specific cells (clock gating, multiplier hints) are
5//! parameterized by the [`Target`] trait, allowing a single design
6//! to produce correct output for both FPGA prototyping and ASIC
7//! fabrication.
8//!
9//! Categorically, this is an **adjunction** between the specification
10//! category (target-independent pipeline) and the implementation
11//! category (target-specific hardware).  The left adjoint maps
12//! abstract pipeline stages to concrete cells; the right adjoint
13//! forgets implementation details back to the spec.
14
15/// A synthesis target with technology-specific cell selection.
16///
17/// Implementations provide the concrete cell choices for clock gating,
18/// multiplier inference, and other technology-dependent features.
19pub trait Target {
20    /// Human-readable name for this target (e.g., `"Xilinx UltraScale+"`, `"TSMC 12nm"`).
21    fn name(&self) -> &str;
22
23    /// Clock gating strategy for this target.
24    fn clock_gating(&self) -> ClockGating;
25
26    /// Multiplier implementation strategy.
27    fn multiplier_strategy(&self) -> MultiplierStrategy;
28}
29
30/// Clock gating approach.
31///
32/// FPGA and ASIC handle clock gating differently at the cell level.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub enum ClockGating {
35    /// Use a clock enable signal (FPGA style).
36    ///
37    /// The clock runs continuously; a CE pin on the flip-flop
38    /// controls whether it captures new data.
39    ClockEnable,
40
41    /// Use an integrated clock gating cell (ASIC style).
42    ///
43    /// A dedicated ICG cell gates the clock tree, reducing
44    /// dynamic power consumption.
45    IntegratedClockGate,
46}
47
48/// Multiplier implementation strategy.
49///
50/// FPGAs have dedicated DSP blocks; ASICs use standard cell logic.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum MultiplierStrategy {
53    /// Infer DSP blocks (FPGA).
54    ///
55    /// The synthesis tool maps multiplications to hard DSP slices.
56    DspInference,
57
58    /// Use standard cell logic (ASIC).
59    ///
60    /// Multiplications are synthesized from standard gates.
61    StandardCell,
62
63    /// Behavioral (let the synthesis tool decide).
64    ///
65    /// No technology-specific hints; the tool chooses.
66    Behavioral,
67}
68
69/// FPGA target configuration.
70#[derive(Debug, Clone)]
71pub struct Fpga {
72    family: &'static str,
73}
74
75impl Fpga {
76    /// Creates a new FPGA target for the given device family.
77    #[must_use]
78    pub fn new(family: &'static str) -> Self {
79        Self { family }
80    }
81
82    /// Returns the device family name.
83    #[must_use]
84    pub fn family(&self) -> &str {
85        self.family
86    }
87}
88
89impl Target for Fpga {
90    fn name(&self) -> &str {
91        self.family
92    }
93
94    fn clock_gating(&self) -> ClockGating {
95        ClockGating::ClockEnable
96    }
97
98    fn multiplier_strategy(&self) -> MultiplierStrategy {
99        MultiplierStrategy::DspInference
100    }
101}
102
103/// ASIC target configuration.
104#[derive(Debug, Clone)]
105pub struct Asic {
106    process_node: &'static str,
107}
108
109impl Asic {
110    /// Creates a new ASIC target for the given process node.
111    #[must_use]
112    pub fn new(process_node: &'static str) -> Self {
113        Self { process_node }
114    }
115
116    /// Returns the process node name.
117    #[must_use]
118    pub fn process_node(&self) -> &str {
119        self.process_node
120    }
121}
122
123impl Target for Asic {
124    fn name(&self) -> &str {
125        self.process_node
126    }
127
128    fn clock_gating(&self) -> ClockGating {
129        ClockGating::IntegratedClockGate
130    }
131
132    fn multiplier_strategy(&self) -> MultiplierStrategy {
133        MultiplierStrategy::StandardCell
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn fpga_uses_clock_enable() {
143        let fpga = Fpga::new("Xilinx UltraScale+");
144        assert_eq!(fpga.clock_gating(), ClockGating::ClockEnable);
145        assert_eq!(fpga.multiplier_strategy(), MultiplierStrategy::DspInference);
146    }
147
148    #[test]
149    fn asic_uses_icg() {
150        let asic = Asic::new("TSMC 12nm");
151        assert_eq!(asic.clock_gating(), ClockGating::IntegratedClockGate);
152        assert_eq!(asic.multiplier_strategy(), MultiplierStrategy::StandardCell);
153    }
154}