1use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::marker::PhantomData;
6use std::path::{Path, PathBuf};
7use std::sync::{Arc, RwLock};
8
9use config::Config;
10use gds::GdsUnits;
11use gdsconv::GdsLayer;
12use gdsconv::export::GdsExportOpts;
13use indexmap::IndexMap;
14use substrate::schematic::{CellBuilder, ConvCacheKey, RawCellContentsBuilder};
15use tracing::{Level, span};
16
17use crate::block::Block;
18use crate::cache::Cache;
19use crate::diagnostics::SourceInfo;
20use crate::error::Result;
21use crate::execute::{Executor, LocalExecutor};
22use crate::layout::conv::export_multi_top_layir_lib;
23use crate::layout::element::{Element, NamedPorts, RawCell};
24use crate::layout::error::LayoutError;
25use crate::layout::{Cell as LayoutCell, CellHandle as LayoutCellHandle};
26use crate::layout::{CellBuilder as LayoutCellBuilder, CellLayer};
27use crate::layout::{Layout, LayoutContext};
28use crate::schematic::conv::{ConvError, RawLib, export_multi_top_scir_lib};
29use crate::schematic::schema::{FromSchema, Schema};
30use crate::schematic::{
31 Cell as SchematicCell, CellCacheKey, CellHandle as SchematicCellHandle, CellId, CellMetadata,
32 RawCellInnerBuilder, SchemaCellCacheValue, SchemaCellHandle, Schematic, SchematicContext,
33};
34use crate::simulation::{SimController, SimulationContext, Simulator, Testbench};
35use crate::types::layout::PortGeometryBuilder;
36use crate::types::schematic::{IoNodeBundle, NodeContext, NodePriority, Port, SchematicBundleKind};
37use crate::types::{FlatLen, Flatten, Flipped, HasBundleKind, HasNameTree, NameBuf};
38
39#[derive(Clone)]
46pub struct Context {
47 pub(crate) inner: Arc<RwLock<ContextInner>>,
48 installations: Arc<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
49 pub executor: Arc<dyn Executor>,
51 pub cache: Cache,
53}
54impl Default for Context {
57 fn default() -> Self {
58 let cfg = Config::default().expect("requires valid Substrate configuration");
59
60 Self {
61 inner: Default::default(),
62 installations: Default::default(),
63 executor: Arc::new(LocalExecutor),
64 cache: Cache::new(
65 cfg.cache
66 .into_cache()
67 .expect("requires valid Substrate cache configuration"),
68 ),
69 }
70 }
71}
72
73impl Context {
74 pub fn new() -> Self {
76 Self::default()
77 }
78}
79
80pub trait Installation: Any + Send + Sync {
82 #[allow(unused_variables)]
88 fn post_install(&self, ctx: &mut ContextBuilder) {}
89}
90
91pub trait PrivateInstallation: Any + Send + Sync {}
93
94pub struct ContextBuilder {
96 installations: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
97 executor: Arc<dyn Executor>,
98 cache: Option<Cache>,
99}
100
101impl Default for ContextBuilder {
102 fn default() -> Self {
103 Self {
104 installations: Default::default(),
105 executor: Arc::new(LocalExecutor),
106 cache: None,
107 }
108 }
109}
110
111impl ContextBuilder {
112 #[inline]
114 pub fn new() -> Self {
115 Self::default()
116 }
117
118 pub fn executor<E: Executor>(&mut self, executor: E) -> &mut Self {
120 self.executor = Arc::new(executor);
121 self
122 }
123
124 #[inline]
129 pub fn install<I>(&mut self, installation: I) -> &mut Self
130 where
131 I: Installation,
132 {
133 let installation = Arc::new(installation);
134 self.installations
135 .insert(TypeId::of::<I>(), installation.clone());
136 installation.post_install(self);
137 self
138 }
139
140 pub fn cache(&mut self, cache: Cache) -> &mut Self {
142 self.cache = Some(cache);
143 self
144 }
145
146 pub fn build(&mut self) -> Context {
148 let cfg = Config::default().expect("requires valid Substrate configuration");
149
150 Context {
151 inner: Arc::new(RwLock::new(ContextInner::new())),
152 installations: Arc::new(self.installations.clone()),
153 executor: self.executor.clone(),
154 cache: self.cache.clone().unwrap_or_else(|| {
155 Cache::new(
156 cfg.cache
157 .into_cache()
158 .expect("requires valid Substrate cache configuration"),
159 )
160 }),
161 }
162 }
163
164 pub fn get_installation<I: Installation>(&self) -> Option<Arc<I>> {
166 retrieve_installation(&self.installations)
167 }
168}
169
170#[derive(Debug, Default)]
171pub(crate) struct ContextInner {
172 pub(crate) schematic: SchematicContext,
173 layout: LayoutContext,
174 private_installations: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
175}
176
177impl ContextInner {
178 fn new() -> Self {
179 Self::default()
180 }
181}
182
183impl Context {
184 pub fn builder() -> ContextBuilder {
186 Default::default()
187 }
188
189 fn alloc_cell_id(&self) -> CellId {
191 let mut inner = self.inner.write().unwrap();
192 let SchematicContext { next_id, .. } = &mut inner.schematic;
193 next_id.increment();
194 *next_id
195 }
196
197 pub(crate) fn generate_schematic_inner<B: Schematic>(
207 &self,
208 block: Arc<B>,
209 ) -> SchemaCellHandle<B::Schema, B> {
210 let key = CellCacheKey {
211 block: block.clone(),
212 phantom: PhantomData::<B::Schema>,
213 };
214 let block_clone = block.clone();
215 let mut inner = self.inner.write().unwrap();
216 let context = self.clone();
217 let SchematicContext {
218 next_id,
219 cell_cache,
220 ..
221 } = &mut inner.schematic;
222 let (metadata, handle) = cell_cache.generate_partial_blocking(
223 key,
224 |key| {
225 next_id.increment();
226 let (cell_builder, io_data) =
227 prepare_cell_builder(Some(*next_id), context, key.block.as_ref());
228 let io_data = Arc::new(io_data);
229 (
230 CellMetadata::<B> {
231 id: *next_id,
232 io_data: io_data.clone(),
233 },
234 (*next_id, cell_builder, io_data),
235 )
236 },
237 move |_key, (id, mut cell_builder, io_data)| {
238 let res = B::schematic(block_clone.as_ref(), io_data.as_ref(), &mut cell_builder);
239 let fatal = cell_builder.fatal_error;
240 let raw = Arc::new(cell_builder.finish());
241 (!fatal)
242 .then_some(())
243 .ok_or(crate::error::Error::CellBuildFatal)
244 .and(res.map(|data| SchemaCellCacheValue {
245 raw: raw.clone(),
246 cell: Arc::new(SchematicCell::new(
247 id,
248 io_data,
249 block_clone,
250 raw,
251 Arc::new(data),
252 )),
253 }))
254 },
255 );
256
257 SchemaCellHandle {
258 handle: handle.clone(),
259 cell: SchematicCellHandle {
260 id: metadata.id,
261 block,
262 io_data: metadata.io_data.clone(),
263 cell: handle.map(|res| {
264 Ok(res?
265 .as_ref()
266 .map_err(|e| e.clone())
267 .map(|SchemaCellCacheValue { cell, .. }| cell.clone()))
268 }),
269 },
270 }
271 }
272
273 fn generate_cross_schematic_inner<B: Schematic, S2: FromSchema<B::Schema> + ?Sized>(
274 &self,
275 block: Arc<B>,
276 ) -> SchemaCellHandle<S2, B> {
277 let handle = self.generate_schematic_inner(block);
278 let mut inner = self.inner.write().unwrap();
279 SchemaCellHandle {
280 handle: inner.schematic.cell_cache.generate(
281 ConvCacheKey::<B, S2, B::Schema> {
282 block: handle.cell.block.clone(),
283 phantom: PhantomData,
284 },
285 move |_| {
286 let SchemaCellCacheValue { raw, cell } = handle
287 .handle
288 .try_get()
289 .unwrap()
290 .as_ref()
291 .map_err(|e| e.clone())?;
292 Ok(SchemaCellCacheValue {
293 raw: Arc::new((**raw).clone().convert_schema::<S2>()?),
294 cell: cell.clone(),
295 })
296 },
297 ),
298 cell: handle.cell,
299 }
300 }
301
302 pub fn generate_cross_schematic<B: Schematic, S2: FromSchema<B::Schema> + ?Sized>(
306 &self,
307 block: B,
308 ) -> SchemaCellHandle<S2, B> {
309 self.generate_cross_schematic_inner(Arc::new(block))
310 }
311
312 pub fn generate_schematic<T: Schematic>(&self, block: T) -> SchemaCellHandle<T::Schema, T> {
316 let block = Arc::new(block);
317 self.generate_schematic_inner(block)
318 }
319
320 pub fn export_scir<T: Schematic>(&self, block: T) -> Result<RawLib<T::Schema>, ConvError> {
324 let cell = self.generate_schematic(block);
325 let SchemaCellCacheValue { raw, .. } = cell.handle.unwrap_inner();
327 raw.to_scir_lib()
328 }
329
330 pub fn export_scir_all<S: Schema + ?Sized>(
334 &self,
335 cells: &[&crate::schematic::RawCell<S>],
336 ) -> Result<RawLib<S>, ConvError> {
337 export_multi_top_scir_lib(cells)
338 }
339
340 pub fn get_sim_controller<S, T>(
342 &self,
343 block: T,
344 work_dir: impl Into<PathBuf>,
345 ) -> Result<SimController<S, T>>
346 where
347 S: Simulator,
348 T: Testbench<S>,
349 {
350 let simulator = self
351 .get_installation::<S>()
352 .expect("Simulator must be installed");
353 let block = Arc::new(block);
354 let cell = self.generate_schematic_inner(block.clone());
355 let SchemaCellCacheValue { raw, cell } = cell.handle.unwrap_inner();
357 let lib = raw.to_scir_lib()?;
358 let ctx = SimulationContext {
359 lib: Arc::new(lib),
360 work_dir: work_dir.into(),
361 ctx: self.clone(),
362 };
363 Ok(SimController {
364 tb: cell.clone(),
365 simulator,
366 ctx,
367 })
368 }
369
370 #[inline]
375 pub fn install<I>(&mut self, installation: I) -> Arc<I>
376 where
377 I: PrivateInstallation,
378 {
379 let installation = Arc::new(installation);
380 self.inner
381 .write()
382 .unwrap()
383 .private_installations
384 .insert(TypeId::of::<I>(), installation.clone());
385 installation
386 }
387
388 #[inline]
392 pub fn get_or_install<I>(&self, installation: I) -> Arc<I>
393 where
394 I: PrivateInstallation,
395 {
396 let installation = Arc::new(installation);
397 self.inner
398 .write()
399 .unwrap()
400 .private_installations
401 .entry(TypeId::of::<I>())
402 .or_insert(installation.clone())
403 .clone()
404 .downcast()
405 .unwrap()
406 }
407
408 pub fn get_private_installation<I: PrivateInstallation>(&self) -> Option<Arc<I>> {
410 retrieve_installation(&self.inner.read().unwrap().private_installations)
411 }
412
413 pub fn get_installation<I: Installation>(&self) -> Option<Arc<I>> {
415 retrieve_installation(&self.installations)
416 }
417
418 pub fn generate_layout<T: Layout>(&self, block: T) -> LayoutCellHandle<T> {
422 let context_clone = self.clone();
423 let mut inner_mut = self.inner.write().unwrap();
424 let id = inner_mut.layout.get_id();
425 let block = Arc::new(block);
426
427 let span = span!(
428 Level::INFO,
429 "generating layout",
430 block = %block.name(),
431 )
432 .or_current();
433
434 LayoutCellHandle {
435 block: block.clone(),
436 cell: inner_mut.layout.cell_cache.generate(block, move |block| {
437 let block_io = block.io();
438 let mut cell_builder = LayoutCellBuilder::new(context_clone);
439 let _guard = span.enter();
440 let (io, data) = block.layout(&mut cell_builder)?;
441 if block_io.kind() != io.kind() || block_io.kind().len() != io.len() {
442 tracing::event!(
443 Level::ERROR,
444 "layout IO and block IO have different bundle kinds or flattened lengths"
445 );
446 return Err(LayoutError::IoDefinition.into());
447 }
448 let ports = IndexMap::from_iter(
449 block
450 .io()
451 .kind()
452 .flat_names(None)
453 .into_iter()
454 .zip(io.flatten_vec()),
455 );
456 Ok(LayoutCell::new(
457 block.clone(),
458 data,
459 io,
460 Arc::new(cell_builder.finish(id, block.name()).with_ports(ports)),
461 ))
462 }),
463 }
464 }
465
466 pub fn export_layir<T: Layout>(
468 &self,
469 block: T,
470 ) -> Result<crate::layout::conv::RawLib<<T::Schema as crate::layout::schema::Schema>::Layer>>
471 {
472 let handle = self.generate_layout(block);
473 let cell = handle.try_cell()?;
474 let lib = cell.raw().to_layir_lib()?;
475 Ok(lib)
476 }
477
478 pub fn export_layir_all<'a, L: Clone + 'a>(
480 &self,
481 cells: impl IntoIterator<Item = &'a RawCell<L>>,
482 ) -> Result<crate::layout::conv::RawLib<L>> {
483 let cells = cells.into_iter().collect::<Vec<_>>();
484 let lib = export_multi_top_layir_lib(&cells)?;
485 Ok(lib)
486 }
487
488 pub fn import_layir<S: crate::layout::schema::Schema>(
490 &self,
491 lib: layir::Library<S::Layer>,
492 top: layir::CellId,
493 ) -> Result<Arc<crate::layout::element::RawCell<S::Layer>>> {
494 use crate::layout::element::{RawCell, RawInstance};
495 let mut inner = self.inner.write().unwrap();
496 let mut cells: HashMap<layir::CellId, Arc<RawCell<S::Layer>>> = HashMap::new();
497 for id in lib.topological_order() {
498 let cell = lib.cell(id);
499 let sid = inner.layout.get_id();
500 let mut raw = RawCell::new(sid, cell.name());
501 raw.elements
502 .extend(cell.elements().map(|elt| Element::from(elt.clone())));
503 raw.elements.extend(cell.instances().map(|(_, inst)| {
504 Element::Instance(RawInstance::new(
505 cells[&inst.child()].clone(),
506 inst.transformation(),
507 ))
508 }));
509 let mut ports = NamedPorts::new();
510 for (name, port) in cell.ports() {
511 let mut pg = PortGeometryBuilder::default();
512 for elt in port.elements() {
513 if let layir::Element::Shape(s) = elt {
514 pg.push(s.clone());
515 }
516 }
517 let pg = pg.build()?;
518 ports.insert(NameBuf::from(name), pg);
519 }
520 raw = raw.with_ports(ports);
521 let cell = Arc::new(raw);
522 cells.insert(id, cell);
523 }
524 Ok(cells.get(&top).unwrap().clone())
525 }
526
527 pub fn write_layout<B: Layout>(
529 &self,
530 block: B,
531 to_gds: impl FnOnce(&layir::Library<CellLayer<B>>) -> (layir::Library<GdsLayer>, GdsUnits),
532 path: impl AsRef<Path>,
533 ) -> Result<()> {
534 let name = block.name();
535 let layir = self.export_layir(block)?;
536 let (layir, units) = to_gds(&layir.layir);
537 let gds = gdsconv::export::export_gds(
538 layir,
539 GdsExportOpts {
540 name,
541 units: Some(units),
542 },
543 );
544 gds.save(path)?;
545 Ok(())
546 }
547
548 pub fn write_layout_all<'a, L: Clone + 'a>(
550 &self,
551 cells: impl IntoIterator<Item = &'a RawCell<L>>,
552 to_gds: impl FnOnce(&layir::Library<L>) -> (layir::Library<GdsLayer>, GdsUnits),
553 path: impl AsRef<Path>,
554 ) -> Result<()> {
555 let name = arcstr::literal!("TOP");
556 let layir = self.export_layir_all(cells)?;
557 let (layir, units) = to_gds(&layir.layir);
558 let gds = gdsconv::export::export_gds(
559 layir,
560 GdsExportOpts {
561 name,
562 units: Some(units),
563 },
564 );
565 gds.save(path)?;
566 Ok(())
567 }
568}
569
570fn retrieve_installation<I: Any + Send + Sync>(
571 map: &HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
572) -> Option<Arc<I>> {
573 map.get(&TypeId::of::<I>())
574 .map(|arc| arc.clone().downcast().unwrap())
575}
576
577#[doc(hidden)]
582pub fn prepare_cell_builder<
583 T: Block<Io: HasBundleKind<BundleKind: SchematicBundleKind>>,
584 S: substrate::schematic::schema::Schema,
585>(
586 id: Option<CellId>,
587 context: Context,
588 block: &T,
589) -> (CellBuilder<S>, IoNodeBundle<T>) {
590 let id = id.unwrap_or_else(|| context.alloc_cell_id());
591 let mut node_ctx = NodeContext::new();
592 let io_outward = block.io();
594 let io_internal = Flipped(io_outward.clone());
597 let (nodes, io_data) =
599 node_ctx.instantiate_directed(&io_internal, NodePriority::Io, SourceInfo::from_caller());
600 let cell_name = block.name();
601
602 let names = <<T as Block>::Io as HasBundleKind>::kind(&io_outward).flat_names(None);
603 let outward_dirs = io_outward.flatten_vec();
604 assert_eq!(nodes.len(), names.len());
605 assert_eq!(nodes.len(), outward_dirs.len());
606
607 let ports = nodes
608 .iter()
609 .copied()
610 .zip(outward_dirs)
611 .map(|(node, direction)| Port::new(node, direction))
612 .collect();
613
614 let node_names = HashMap::from_iter(nodes.into_iter().zip(names));
615
616 (
617 CellBuilder {
618 id,
619 cell_name,
620 ctx: context,
621 node_ctx,
622 node_names,
623 fatal_error: false,
624 ports,
625 flatten: false,
626 contents: RawCellContentsBuilder::Cell(RawCellInnerBuilder::default()),
627 },
628 io_data,
629 )
630}