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}