logicaffeine_compile/spatial/lower/
mod.rs1pub mod cuda;
5pub mod fabric;
6pub mod fabric_board;
7pub mod rdu;
8pub mod rdu_lanes;
9pub mod rdu_sdk;
10pub mod sambaflow;
11pub mod spatial_lang;
12pub mod tensix;
13
14use serde::{Deserialize, Serialize};
15
16use super::certificate::ChoreographyCertificate;
17use super::eval::ChoreoFault;
18use super::ir::*;
19use super::target::SpatialTarget;
20
21#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23pub struct Census {
24 pub buffer_templates: usize,
26 pub fifos: usize,
27 pub semaphores: usize,
28 pub barrier_semaphores: usize,
29 pub mcast_groups: usize,
30 pub kernels: usize,
31 pub sites: usize,
32}
33
34impl Census {
35 pub fn of_verilog(rtl: &str) -> Census {
39 let count = |prefix: &str| {
40 rtl.lines()
41 .filter(|l| l.trim_start().starts_with(prefix))
42 .count()
43 };
44 let sem_ids: std::collections::BTreeSet<&str> = rtl
46 .lines()
47 .filter_map(|l| {
48 let l = l.trim_start();
49 l.strip_prefix("sem_prim sem_")
50 .or_else(|| l.strip_prefix("barrier_prim sem_"))
51 })
52 .filter_map(|r| r.split('_').next())
53 .collect();
54 Census {
55 buffer_templates: count("module fifo_tpl_"),
56 fifos: count("fifo_tpl_"),
57 semaphores: sem_ids.len(),
58 barrier_semaphores: count("barrier_prim "),
59 mcast_groups: count("mcast_bus_prim_"),
60 kernels: count("module engine_"),
61 sites: count("site_"),
62 }
63 }
64
65 pub fn of(p: &SpatialProgram) -> Census {
66 let templates: std::collections::BTreeSet<_> =
67 p.buffers.iter().map(|b| b.origin.unwrap_or(b.id)).collect();
68 Census {
69 buffer_templates: templates.len(),
70 fifos: p
74 .buffers
75 .iter()
76 .filter(|b| matches!(b.kind, BufferKind::Fifo { .. } | BufferKind::Interm { .. }))
77 .count(),
78 semaphores: p.semaphores.len(),
79 barrier_semaphores: p
80 .semaphores
81 .iter()
82 .filter(|s| matches!(s.role, SemRole::Barrier { .. }))
83 .count(),
84 mcast_groups: p.placement.as_ref().map(|pl| pl.groups.len()).unwrap_or(0),
85 kernels: p.summary().engine_program_classes,
86 sites: p.sites().len(),
87 }
88 }
89}
90
91#[derive(Clone, Debug, PartialEq)]
92pub enum SpatialLowerError {
93 NotVerified {
94 phase: Phase,
95 },
96 Unsupported(&'static str),
97 GroupSpansSites {
98 group: GroupId,
99 },
100 NotNearestNeighbour {
101 buffer: BufferId,
102 },
103 TooBig {
104 what: &'static str,
105 need: usize,
106 have: usize,
107 },
108 Precision {
109 needed: crate::codegen_sva::fabric_target::Precision,
110 },
111 OverCapacity(CapacityRefusal),
114 Uncertified(ChoreoFault),
115}
116
117#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119pub enum FabricResource {
120 UltraRam,
121 BlockRam18,
122 LutRam,
123 Flops,
124 Dsp,
125}
126
127impl FabricResource {
128 pub fn label(self) -> &'static str {
129 match self {
130 FabricResource::UltraRam => "UltraRAM blocks",
131 FabricResource::BlockRam18 => "18Kb block RAMs",
132 FabricResource::LutRam => "LUT-RAM LUTs",
133 FabricResource::Flops => "flip-flops",
134 FabricResource::Dsp => "DSP slices",
135 }
136 }
137}
138
139#[derive(Clone, Debug, PartialEq, Eq)]
141pub struct Over {
142 pub resource: FabricResource,
143 pub need: u64,
145 pub have: u64,
147 pub largest: Vec<(String, u64)>,
149}
150
151#[derive(Clone, Debug, PartialEq, Eq)]
153pub struct CapacityRefusal {
154 pub part: &'static str,
155 pub over: Vec<Over>,
156}
157
158#[derive(Clone, Debug)]
160pub struct NeutralArtifact {
161 pub json: String,
162 pub pretty: String,
163 pub reason: &'static str,
164 pub certificate: ChoreographyCertificate,
165 pub rechecked: bool,
168 pub census: Census,
169}
170
171#[derive(Clone, Debug)]
172pub enum SpatialArtifact {
173 Tensix(tensix::TensixArtifact),
174 Verilog(fabric::VerilogArtifact),
175 Cuda(cuda::CudaArtifact),
176 SdkGated(NeutralArtifact),
177}
178
179pub trait SpatialBackend {
180 fn name(&self) -> &str;
181 fn target(&self) -> &SpatialTarget;
182 fn lower(&self, p: &SpatialProgram) -> Result<SpatialArtifact, SpatialLowerError>;
183}
184
185pub fn require_verified(p: &SpatialProgram) -> Result<(), SpatialLowerError> {
187 if p.phase() != Phase::Verified {
188 return Err(SpatialLowerError::NotVerified { phase: p.phase() });
189 }
190 Ok(())
191}
192
193pub fn require_one_plan(p: &SpatialProgram) -> Result<(), SpatialLowerError> {
197 if p.sections.iter().any(|s| s.plan != p.work.plan) {
198 return Err(SpatialLowerError::Unsupported("a composition whose sections run under different plans — this printer emits one kernel from one plan"));
199 }
200 Ok(())
201}