pub mod conv;
pub mod netlist;
pub mod primitives;
pub mod schema;
use cache::mem::TypeCache;
use cache::CacheHandle;
pub use codegen::NestedData;
use pathtree::PathTree;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::collections::HashMap;
use std::fmt::Formatter;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use arcstr::ArcStr;
use once_cell::sync::OnceCell;
use crate::block::Block;
use crate::context::Context;
use crate::diagnostics::SourceInfo;
use crate::error::{Error, Result};
use crate::io::schematic::{
Bundle, Connect, HardwareType, HasTerminalView, IsBundle, Node, NodeContext, NodePriority,
NodeUf, Port, TerminalView,
};
use crate::io::{Flatten, HasNameTree, NameBuf};
use crate::schematic::conv::ConvError;
use crate::schematic::schema::{FromSchema, Schema};
pub trait ExportsNestedData: Block {
type NestedData: NestedData;
}
pub trait Schematic<S: Schema + ?Sized>: ExportsNestedData {
fn schematic(
&self,
io: &Bundle<<Self as Block>::Io>,
cell: &mut CellBuilder<S>,
) -> Result<Self::NestedData>;
}
impl<T: ExportsNestedData> ExportsNestedData for Arc<T> {
type NestedData = T::NestedData;
}
impl<S: Schema, T: Schematic<S>> Schematic<S> for Arc<T> {
fn schematic(
&self,
io: &Bundle<<Self as Block>::Io>,
cell: &mut CellBuilder<S>,
) -> Result<Self::NestedData> {
T::schematic(self.as_ref(), io, cell)
}
}
pub struct CellBuilder<S: Schema + ?Sized> {
pub(crate) ctx: Context,
pub(crate) id: CellId,
pub(crate) cell_name: ArcStr,
pub(crate) flatten: bool,
pub(crate) root: InstancePath,
pub(crate) node_ctx: NodeContext,
pub(crate) node_names: HashMap<Node, NameBuf>,
pub(crate) ports: Vec<Port>,
pub(crate) contents: RawCellContentsBuilder<S>,
}
impl<S: Schema + ?Sized> CellBuilder<S> {
pub(crate) fn finish(self) -> RawCell<S> {
let mut roots = HashMap::with_capacity(self.node_names.len());
let mut uf = self.node_ctx.into_uf();
for &node in self.node_names.keys() {
let root = uf.probe_value(node).unwrap().source;
roots.insert(node, root);
}
RawCell {
id: self.id,
name: self.cell_name,
node_names: self.node_names,
ports: self.ports,
flatten: self.flatten,
uf,
roots,
contents: self.contents.build(),
}
}
pub fn flatten(&mut self) {
self.flatten = true;
}
#[track_caller]
pub fn signal<TY: HardwareType>(
&mut self,
name: impl Into<ArcStr>,
ty: TY,
) -> <TY as HardwareType>::Bundle {
let (nodes, data) = self.node_ctx.instantiate_undirected(
&ty,
NodePriority::Named,
SourceInfo::from_caller(),
);
let names = ty.flat_names(Some(name.into().into()));
assert_eq!(nodes.len(), names.len());
self.node_names.extend(nodes.iter().copied().zip(names));
data
}
pub fn connect<D1, D2>(&mut self, s1: D1, s2: D2)
where
D1: Flatten<Node>,
D2: Flatten<Node>,
D1: Connect<D2>,
{
let s1f: Vec<Node> = s1.flatten_vec();
let s2f: Vec<Node> = s2.flatten_vec();
assert_eq!(s1f.len(), s2f.len());
s1f.into_iter().zip(s2f).for_each(|(a, b)| {
let res = self.node_ctx.connect(a, b);
if let Err(err) = res {
tracing::warn!(?err, "connection failed");
}
});
}
pub fn connect_multiple<D>(&mut self, s2: &[D])
where
D: Flatten<Node>,
{
if s2.len() > 1 {
for s in &s2[1..] {
self.connect(&s2[0], s);
}
}
}
pub fn set_scir(&mut self, scir: ScirBinding<S>) {
self.contents = RawCellContentsBuilder::Scir(scir);
}
pub fn set_primitive(&mut self, primitive: PrimitiveBinding<S>) {
self.contents = RawCellContentsBuilder::Primitive(primitive);
}
pub fn ctx(&self) -> &Context {
&self.ctx
}
pub fn generate<B: Schematic<S>>(&mut self, block: B) -> SchemaCellHandle<S, B> {
self.ctx().generate_schematic(block)
}
pub fn generate_blocking<B: Schematic<S>>(
&mut self,
block: B,
) -> Result<SchemaCellHandle<S, B>> {
let handle = self.ctx().generate_schematic(block);
handle.cell.try_cell()?;
Ok(handle)
}
#[track_caller]
pub fn add<B: ExportsNestedData>(&mut self, cell: SchemaCellHandle<S, B>) -> Instance<B> {
self.post_instantiate(cell, SourceInfo::from_caller(), None)
}
#[track_caller]
pub fn instantiate<B: Schematic<S>>(&mut self, block: B) -> Instance<B> {
let cell = self.ctx().generate_schematic(block);
self.post_instantiate(cell, SourceInfo::from_caller(), None)
}
#[track_caller]
pub fn instantiate_named<B: Schematic<S>>(
&mut self,
block: B,
name: impl Into<ArcStr>,
) -> Instance<B> {
let cell = self.ctx().generate_schematic(block);
self.post_instantiate(cell, SourceInfo::from_caller(), Some(name.into()))
}
#[track_caller]
pub fn instantiate_blocking<B: Schematic<S>>(&mut self, block: B) -> Result<Instance<B>> {
let inst = self.instantiate(block);
inst.try_data()?;
Ok(inst)
}
pub fn instantiate_connected<B, C>(&mut self, block: B, io: C)
where
B: Schematic<S>,
C: IsBundle,
<B::Io as HardwareType>::Bundle: Connect<C>,
{
let inst = self.instantiate(block);
self.connect(inst.io, io);
}
pub fn instantiate_connected_named<B, C>(&mut self, block: B, io: C, name: impl Into<ArcStr>)
where
B: Schematic<S>,
C: IsBundle,
<B::Io as HardwareType>::Bundle: Connect<C>,
{
let inst = self.instantiate_named(block, name);
self.connect(inst.io, io);
}
fn post_instantiate<B: ExportsNestedData>(
&mut self,
cell: SchemaCellHandle<S, B>,
source_info: SourceInfo,
name: Option<ArcStr>,
) -> Instance<B> {
let io = cell.cell.block.io();
let cell_contents = self.contents.as_mut().unwrap_cell();
cell_contents.next_instance_id.increment();
let inst_name =
name.unwrap_or_else(|| arcstr::format!("xinst{}", cell_contents.instances.len()));
let (nodes, io_data) =
self.node_ctx
.instantiate_directed(&io, NodePriority::Auto, source_info);
let names = io.flat_names(Some(inst_name.clone().into()));
assert_eq!(nodes.len(), names.len());
self.node_names.extend(nodes.iter().copied().zip(names));
let inst = Instance {
id: cell_contents.next_instance_id,
parent: self.root.clone(),
path: self
.root
.append_segment(cell_contents.next_instance_id, cell.cell.id),
cell: cell.cell,
io: io_data,
terminal_view: OnceCell::new(),
nested_data: OnceCell::new(),
};
cell_contents.instances.push(RawInstanceBuilder {
id: inst.id,
name: inst_name.clone(),
connections: nodes,
child: cell.handle.map(|handle| match handle {
Ok(Ok(SchemaCellCacheValue { raw, .. })) => Ok(raw.clone()),
Ok(Err(e)) => {
tracing::error!("{:?}", e);
panic!("cell generator failed")
}
Err(e) => {
tracing::error!("{:?}", e);
panic!("cache failed")
}
}),
});
inst
}
pub fn sub_builder<S2: Schema + ?Sized>(&mut self) -> SubCellBuilder<S, S2>
where
S: FromSchema<S2>,
{
SubCellBuilder(self, PhantomData)
}
}
pub struct SubCellBuilder<'a, S: Schema + ?Sized, S2: Schema + ?Sized>(
&'a mut CellBuilder<S>,
PhantomData<S2>,
);
impl<'a, S: FromSchema<S2> + ?Sized, S2: Schema + ?Sized> SubCellBuilder<'a, S, S2> {
#[track_caller]
pub fn signal<TY: HardwareType>(
&mut self,
name: impl Into<ArcStr>,
ty: TY,
) -> <TY as HardwareType>::Bundle {
self.0.signal(name, ty)
}
pub fn connect<D1, D2>(&mut self, s1: D1, s2: D2)
where
D1: Flatten<Node>,
D2: Flatten<Node>,
D1: Connect<D2>,
{
self.0.connect(s1, s2)
}
pub fn ctx(&self) -> &Context {
&self.0.ctx
}
pub fn generate<B: Schematic<S2>>(&mut self, block: B) -> SchemaCellHandle<S, B> {
self.ctx().generate_cross_schematic(block)
}
pub fn generate_blocking<B: Schematic<S2>>(
&mut self,
block: B,
) -> Result<SchemaCellHandle<S, B>> {
let handle = self.ctx().generate_cross_schematic(block);
handle.cell.try_cell()?;
Ok(handle)
}
#[track_caller]
pub fn add<B: ExportsNestedData>(&mut self, cell: SchemaCellHandle<S, B>) -> Instance<B> {
self.0.add(cell)
}
#[track_caller]
pub fn instantiate<B: Schematic<S2>>(&mut self, block: B) -> Instance<B> {
let cell = self.ctx().generate_cross_schematic(block);
self.post_instantiate(cell, SourceInfo::from_caller(), None)
}
#[track_caller]
pub fn instantiate_named<B: Schematic<S2>>(
&mut self,
block: B,
name: impl Into<ArcStr>,
) -> Instance<B> {
let cell = self.ctx().generate_cross_schematic(block);
self.post_instantiate(cell, SourceInfo::from_caller(), Some(name.into()))
}
#[track_caller]
pub fn instantiate_blocking<B: Schematic<S2>>(&mut self, block: B) -> Result<Instance<B>> {
let inst = self.instantiate(block);
inst.try_data()?;
Ok(inst)
}
pub fn instantiate_connected<B, C>(&mut self, block: B, io: C)
where
B: Schematic<S2>,
C: IsBundle,
<B::Io as HardwareType>::Bundle: Connect<C>,
{
let inst = self.instantiate(block);
self.connect(inst.io, io);
}
pub fn instantiate_connected_named<B, C>(&mut self, block: B, io: C, name: impl Into<ArcStr>)
where
B: Schematic<S2>,
C: IsBundle,
<B::Io as HardwareType>::Bundle: Connect<C>,
{
let inst = self.instantiate_named(block, name);
self.connect(inst.io, io);
}
fn post_instantiate<B: ExportsNestedData>(
&mut self,
cell: SchemaCellHandle<S, B>,
source_info: SourceInfo,
name: Option<ArcStr>,
) -> Instance<B> {
self.0.post_instantiate(cell, source_info, name)
}
}
pub struct Cell<T: ExportsNestedData> {
block: Arc<T>,
nodes: Arc<T::NestedData>,
io: Arc<<T::Io as HardwareType>::Bundle>,
path: InstancePath,
nested_data: OnceCell<Arc<NestedView<T::NestedData>>>,
}
impl<T: ExportsNestedData> Deref for Cell<T> {
type Target = NestedView<T::NestedData>;
fn deref(&self) -> &Self::Target {
self.nested_data
.get_or_init(|| Arc::new(self.data()))
.as_ref()
}
}
impl<T: ExportsNestedData> Clone for Cell<T> {
fn clone(&self) -> Self {
Self {
block: self.block.clone(),
nodes: self.nodes.clone(),
io: self.io.clone(),
path: self.path.clone(),
nested_data: self.nested_data.clone(),
}
}
}
impl<T: ExportsNestedData> Cell<T> {
pub(crate) fn new(
id: CellId,
io: Arc<<T::Io as HardwareType>::Bundle>,
block: Arc<T>,
data: Arc<T::NestedData>,
) -> Self {
Self {
io,
block,
nodes: data,
path: InstancePath::new(id),
nested_data: OnceCell::new(),
}
}
pub fn block(&self) -> &T {
&self.block
}
pub fn data(&self) -> NestedView<T::NestedData> {
self.nodes.nested_view(&self.path)
}
pub fn raw_data(&self) -> &Arc<<T as ExportsNestedData>::NestedData> {
&self.nodes
}
pub fn io(&self) -> NestedView<<T::Io as HardwareType>::Bundle> {
self.io.nested_view(&self.path)
}
}
pub struct CellHandle<T: ExportsNestedData> {
pub(crate) id: CellId,
pub(crate) block: Arc<T>,
pub(crate) io_data: Arc<<T::Io as HardwareType>::Bundle>,
pub(crate) cell: CacheHandle<Result<Arc<Cell<T>>>>,
}
impl<T: ExportsNestedData> Clone for CellHandle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
block: self.block.clone(),
io_data: self.io_data.clone(),
cell: self.cell.clone(),
}
}
}
impl<T: ExportsNestedData> CellHandle<T> {
pub fn try_cell(&self) -> Result<&Cell<T>> {
self.cell
.try_get()
.as_ref()
.map_err(|_| Error::Internal)?
.as_ref()
.map(|cell| cell.as_ref())
.map_err(|e| e.clone())
}
pub fn cell(&self) -> &Cell<T> {
self.try_cell().expect("cell generation failed")
}
}
pub(crate) struct SchemaCellCacheValue<S: Schema + ?Sized, B: ExportsNestedData> {
pub(crate) raw: Arc<RawCell<S>>,
pub(crate) cell: Arc<Cell<B>>,
}
pub struct SchemaCellHandle<S: Schema + ?Sized, B: ExportsNestedData> {
pub(crate) handle: CacheHandle<Result<SchemaCellCacheValue<S, B>>>,
pub(crate) cell: CellHandle<B>,
}
impl<S: Schema, B: ExportsNestedData> SchemaCellHandle<S, B> {
pub fn try_cell(&self) -> Result<&Cell<B>> {
self.cell.try_cell()
}
pub fn cell(&self) -> &Cell<B> {
self.cell.cell()
}
pub fn raw(&self) -> Arc<RawCell<S>> {
let val = self.handle.unwrap_inner();
val.raw.clone()
}
}
impl<S: Schema + ?Sized, B: ExportsNestedData> Deref for SchemaCellHandle<S, B> {
type Target = CellHandle<B>;
fn deref(&self) -> &Self::Target {
&self.cell
}
}
impl<S: Schema + ?Sized, B: ExportsNestedData> Clone for SchemaCellHandle<S, B> {
fn clone(&self) -> Self {
Self {
handle: self.handle.clone(),
cell: self.cell.clone(),
}
}
}
#[allow(dead_code)]
pub struct Instance<T: ExportsNestedData> {
id: InstanceId,
parent: InstancePath,
path: InstancePath,
io: <T::Io as HardwareType>::Bundle,
cell: CellHandle<T>,
terminal_view: OnceCell<Arc<TerminalView<<T::Io as HardwareType>::Bundle>>>,
nested_data: OnceCell<Arc<NestedView<T::NestedData>>>,
}
impl<T: ExportsNestedData> Deref for Instance<T> {
type Target = NestedView<T::NestedData>;
fn deref(&self) -> &Self::Target {
self.nested_data
.get_or_init(|| Arc::new(self.data()))
.as_ref()
}
}
impl<B: ExportsNestedData> Clone for Instance<B> {
fn clone(&self) -> Self {
Self {
id: self.id,
parent: self.parent.clone(),
path: self.path.clone(),
io: self.io.clone(),
cell: self.cell.clone(),
terminal_view: self.terminal_view.clone(),
nested_data: self.nested_data.clone(),
}
}
}
impl<B: ExportsNestedData> HasNestedView for Instance<B> {
type NestedView = NestedInstance<B>;
fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
let mut inst = (*self).clone();
inst.path = self.path.prepend(parent);
inst.parent = self.parent.prepend(parent);
inst.nested_data = OnceCell::new();
inst.terminal_view = OnceCell::new();
NestedInstance(inst)
}
}
impl<T: ExportsNestedData> Instance<T> {
pub fn io(&self) -> &TerminalView<<T::Io as HardwareType>::Bundle> {
self.terminal_view
.get_or_init(|| {
Arc::new(HasTerminalView::terminal_view(
self.cell.id,
self.cell.io_data.as_ref(),
self.id,
&self.io,
))
})
.as_ref()
}
pub fn try_data(&self) -> Result<NestedView<T::NestedData>> {
self.cell
.try_cell()
.map(|data| data.nodes.nested_view(&self.path))
}
pub fn data(&self) -> NestedView<T::NestedData> {
self.cell.cell().nodes.nested_view(&self.path)
}
pub fn block(&self) -> &T {
&self.cell.block
}
pub fn path(&self) -> &InstancePath {
&self.path
}
}
pub struct NestedInstance<T: ExportsNestedData>(Instance<T>);
impl<T: ExportsNestedData> Deref for NestedInstance<T> {
type Target = NestedView<T::NestedData>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<B: ExportsNestedData> Clone for NestedInstance<B> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<B: ExportsNestedData> HasNestedView for NestedInstance<B> {
type NestedView = NestedInstance<B>;
fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
let mut inst = (*self).clone();
inst.0.path = self.0.path.prepend(parent);
inst.0.parent = self.0.parent.prepend(parent);
inst.0.nested_data = OnceCell::new();
inst.0.terminal_view = OnceCell::new();
inst
}
}
impl<T: ExportsNestedData> NestedInstance<T> {
pub fn io(&self) -> NestedView<TerminalView<<T::Io as HardwareType>::Bundle>> {
self.0.io().nested_view(&self.0.parent)
}
pub fn try_data(&self) -> Result<NestedView<T::NestedData>> {
self.0.try_data()
}
pub fn data(&self) -> NestedView<T::NestedData> {
self.0.data()
}
pub fn block(&self) -> &T {
self.0.block()
}
pub fn path(&self) -> &InstancePath {
&self.0.path
}
}
#[derive(Debug)]
pub struct SchematicContext {
pub(crate) next_id: CellId,
pub(crate) cell_cache: TypeCache,
}
impl Default for SchematicContext {
fn default() -> Self {
Self {
next_id: CellId(0),
cell_cache: Default::default(),
}
}
}
impl SchematicContext {
#[allow(dead_code)]
pub(crate) fn new() -> Self {
Self::default()
}
}
pub(crate) struct CellMetadata<B: Block> {
pub(crate) id: CellId,
pub(crate) io_data: Arc<<B::Io as HardwareType>::Bundle>,
}
impl<B: Block> Clone for CellMetadata<B> {
fn clone(&self) -> Self {
Self {
id: self.id,
io_data: self.io_data.clone(),
}
}
}
pub(crate) struct CellCacheKey<B, S: ?Sized> {
pub(crate) block: Arc<B>,
pub(crate) phantom: PhantomData<S>,
}
impl<B, S: ?Sized> Clone for CellCacheKey<B, S> {
fn clone(&self) -> Self {
Self {
block: self.block.clone(),
phantom: PhantomData,
}
}
}
impl<B: PartialEq, S: ?Sized> PartialEq for CellCacheKey<B, S> {
fn eq(&self, other: &Self) -> bool {
self.block.eq(&other.block)
}
}
impl<B: Eq, S: ?Sized> Eq for CellCacheKey<B, S> {}
impl<B: Hash, S: ?Sized> Hash for CellCacheKey<B, S> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.block.hash(state)
}
}
pub(crate) type ConvCacheKey<B, S1, S2> = CellCacheKey<B, (PhantomData<S1>, S2)>;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct InstancePath {
pub(crate) top: CellId,
pub(crate) bot: Option<CellId>,
pub(crate) path: PathTree<InstanceId>,
}
impl InstancePath {
pub(crate) fn new(top: CellId) -> Self {
Self {
top,
bot: None,
path: PathTree::empty(),
}
}
#[allow(dead_code)]
pub(crate) fn append(&self, other: &Self) -> Self {
if let Some(bot) = self.bot {
assert_eq!(
bot, other.top,
"path to append must start with the cell ID that the current path ends with"
);
} else {
assert_eq!(
self.top, other.top,
"path to append must start with the cell ID that the current path ends with"
);
}
Self {
top: self.top,
bot: other.bot,
path: self.path.append(&other.path),
}
}
pub fn prepend(&self, other: &Self) -> Self {
if let Some(bot) = other.bot {
assert_eq!(
bot, self.top,
"path to prepend must end with the cell ID that the current path starts with"
);
} else {
assert_eq!(
other.top, self.top,
"path to prepend must end with the cell ID that the current path starts with"
);
}
Self {
top: other.top,
bot: self.bot,
path: self.path.prepend(&other.path),
}
}
pub(crate) fn append_segment(&self, id: InstanceId, cell_id: CellId) -> Self {
Self {
top: self.top,
bot: Some(cell_id),
path: self.path.append_segment(id),
}
}
#[allow(dead_code)]
pub(crate) fn is_empty(&self) -> bool {
self.bot.is_none()
}
}
pub trait NestedData: HasNestedView + Send + Sync {}
impl<T: HasNestedView + Send + Sync> NestedData for T {}
pub trait HasNestedView {
type NestedView: Send + Sync;
fn nested_view(&self, parent: &InstancePath) -> Self::NestedView;
}
pub type NestedView<T> = <T as HasNestedView>::NestedView;
impl HasNestedView for () {
type NestedView = ();
fn nested_view(&self, _parent: &InstancePath) -> Self::NestedView {}
}
impl<T> HasNestedView for &T
where
T: HasNestedView,
{
type NestedView = T::NestedView;
fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
(*self).nested_view(parent)
}
}
impl<T: HasNestedView> HasNestedView for Vec<T> {
type NestedView = Vec<NestedView<T>>;
fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
self.iter().map(|elem| elem.nested_view(parent)).collect()
}
}
impl<T: HasNestedView> HasNestedView for Option<T> {
type NestedView = Option<NestedView<T>>;
fn nested_view(&self, parent: &InstancePath) -> Self::NestedView {
self.as_ref().map(|inner| inner.nested_view(parent))
}
}
#[allow(dead_code)]
pub(crate) struct RawInstanceBuilder<S: Schema + ?Sized> {
id: InstanceId,
name: ArcStr,
connections: Vec<Node>,
child: CacheHandle<Arc<RawCell<S>>>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug
for RawInstanceBuilder<S>
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("RawInstanceBuilder");
let _ = builder.field("id", &self.id);
let _ = builder.field("name", &self.name);
let _ = builder.field("connections", &self.connections);
let _ = builder.field("child", &self.child);
builder.finish()
}
}
impl<S: Schema + ?Sized> RawInstanceBuilder<S> {
fn build(self) -> RawInstance<S> {
RawInstance {
id: self.id,
name: self.name,
connections: self.connections,
child: self.child.get().clone(),
}
}
}
#[allow(dead_code)]
pub(crate) struct RawInstance<S: Schema + ?Sized> {
id: InstanceId,
name: ArcStr,
connections: Vec<Node>,
child: Arc<RawCell<S>>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for RawInstance<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("RawInstance");
let _ = builder.field("id", &self.id);
let _ = builder.field("name", &self.name);
let _ = builder.field("connections", &self.connections);
let _ = builder.field("child", &self.child);
builder.finish()
}
}
impl<S: Schema + ?Sized> Clone for RawInstance<S> {
fn clone(&self) -> Self {
Self {
id: self.id,
name: self.name.clone(),
connections: self.connections.clone(),
child: self.child.clone(),
}
}
}
impl<S: Schema + ?Sized> RawInstance<S> {
fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawInstance<S2>> {
Ok(RawInstance {
id: self.id,
name: self.name,
connections: self.connections,
child: Arc::new((*self.child).clone().convert_schema()?),
})
}
}
#[allow(dead_code)]
#[doc(hidden)]
pub struct RawCell<S: Schema + ?Sized> {
id: CellId,
pub(crate) name: ArcStr,
ports: Vec<Port>,
uf: NodeUf,
node_names: HashMap<Node, NameBuf>,
roots: HashMap<Node, Node>,
flatten: bool,
contents: RawCellContents<S>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for RawCell<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("RawCell");
let _ = builder.field("id", &self.id);
let _ = builder.field("name", &self.name);
let _ = builder.field("ports", &self.ports);
let _ = builder.field("uf", &self.uf);
let _ = builder.field("node_names", &self.node_names);
let _ = builder.field("roots", &self.roots);
let _ = builder.field("contents", &self.contents);
let _ = builder.field("flatten", &self.flatten);
builder.finish()
}
}
impl<S: Schema + ?Sized> Clone for RawCell<S> {
fn clone(&self) -> Self {
Self {
id: self.id,
name: self.name.clone(),
ports: self.ports.clone(),
uf: self.uf.clone(),
node_names: self.node_names.clone(),
roots: self.roots.clone(),
contents: self.contents.clone(),
flatten: self.flatten,
}
}
}
impl<S: Schema + ?Sized> RawCell<S> {
pub(crate) fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawCell<S2>> {
Ok(RawCell {
id: self.id,
name: self.name,
ports: self.ports,
uf: self.uf,
node_names: self.node_names,
roots: self.roots,
flatten: self.flatten,
contents: self.contents.convert_schema()?,
})
}
}
pub(crate) type RawCellContentsBuilder<S> =
RawCellKind<RawCellInnerBuilder<S>, ScirBinding<S>, PrimitiveBinding<S>, ConvertedPrimitive<S>>;
impl<S: Schema + ?Sized> RawCellContentsBuilder<S> {
fn build(self) -> RawCellContents<S> {
match self {
RawCellContentsBuilder::Cell(b) => RawCellContents::Cell(b.build()),
RawCellContentsBuilder::Scir(s) => RawCellContents::Scir(s),
RawCellContentsBuilder::Primitive(s) => RawCellContents::Primitive(s),
RawCellContentsBuilder::ConvertedPrimitive(s) => RawCellContents::ConvertedPrimitive(s),
}
}
}
pub(crate) type RawCellContents<S> =
RawCellKind<RawCellInner<S>, ScirBinding<S>, PrimitiveBinding<S>, ConvertedPrimitive<S>>;
impl<S: Schema + ?Sized> RawCellContents<S> {
fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawCellContents<S2>> {
Ok(match self {
RawCellContents::Cell(c) => RawCellContents::Cell(c.convert_schema()?),
RawCellContents::Scir(s) => RawCellContents::Scir(ScirBinding {
lib: s
.lib
.convert_schema()
.map_err(|_| Error::UnsupportedPrimitive)?
.build()
.map_err(ConvError::from)?,
cell: s.cell,
port_map: s.port_map,
}),
RawCellContents::Primitive(p) => {
RawCellContents::ConvertedPrimitive(ConvertedPrimitive {
converted: <S2 as scir::schema::FromSchema<S>>::convert_primitive(
p.primitive.clone(),
)
.map_err(|_| Error::UnsupportedPrimitive)?,
original: Arc::new(p),
})
}
RawCellContents::ConvertedPrimitive(p) => {
RawCellContents::ConvertedPrimitive(ConvertedPrimitive {
converted: <S2 as scir::schema::FromSchema<S>>::convert_primitive(
p.converted.clone(),
)
.map_err(|_| Error::UnsupportedPrimitive)?,
original: Arc::new(p),
})
}
})
}
}
pub(crate) trait ConvertPrimitive<S: Schema + ?Sized>: Any + Send + Sync {
fn convert_primitive(&self) -> Result<<S as Schema>::Primitive>;
fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()>;
fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>>;
}
impl<S1: FromSchema<S2> + ?Sized, S2: Schema + ?Sized> ConvertPrimitive<S1>
for PrimitiveBinding<S2>
{
fn convert_primitive(&self) -> Result<<S1 as Schema>::Primitive> {
<S1 as scir::schema::FromSchema<S2>>::convert_primitive(self.primitive.clone())
.map_err(|_| Error::UnsupportedPrimitive)
}
fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()> {
<S1 as scir::schema::FromSchema<S2>>::convert_instance(inst, &self.primitive)
.map_err(|_| Error::UnsupportedPrimitive)
}
fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
&self.port_map
}
}
impl<S1: FromSchema<S2> + ?Sized, S2: Schema + ?Sized> ConvertPrimitive<S1>
for ConvertedPrimitive<S2>
{
fn convert_primitive(&self) -> Result<<S1 as Schema>::Primitive> {
<S1 as scir::schema::FromSchema<S2>>::convert_primitive(self.original.convert_primitive()?)
.map_err(|_| Error::UnsupportedPrimitive)
}
fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()> {
self.original.convert_instance(inst)?;
<S1 as scir::schema::FromSchema<S2>>::convert_instance(inst, &self.converted)
.map_err(|_| Error::UnsupportedPrimitive)
}
fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
self.original.port_map()
}
}
pub struct PrimitiveBinding<S: Schema + ?Sized> {
pub(crate) primitive: <S as Schema>::Primitive,
pub(crate) port_map: HashMap<ArcStr, Vec<Node>>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for PrimitiveBinding<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("Primitive");
let _ = builder.field("primitive", &self.primitive);
let _ = builder.field("port_map", &self.port_map);
builder.finish()
}
}
impl<S: Schema + ?Sized> Clone for PrimitiveBinding<S> {
fn clone(&self) -> Self {
Self {
primitive: self.primitive.clone(),
port_map: self.port_map.clone(),
}
}
}
impl<S: Schema> PrimitiveBinding<S> {
pub fn new(primitive: <S as Schema>::Primitive) -> Self {
Self {
primitive,
port_map: Default::default(),
}
}
pub fn connect(&mut self, port: impl Into<ArcStr>, s: impl Flatten<Node>) {
self.port_map.insert(port.into(), s.flatten_vec());
}
}
pub(crate) struct ConvertedPrimitive<S: Schema + ?Sized> {
converted: <S as Schema>::Primitive,
original: Arc<dyn ConvertPrimitive<S>>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug
for ConvertedPrimitive<S>
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("ConvertedPrimitive");
let _ = builder.field("converted", &self.converted);
builder.finish()
}
}
impl<S: Schema + ?Sized> Clone for ConvertedPrimitive<S> {
fn clone(&self) -> Self {
Self {
converted: self.converted.clone(),
original: self.original.clone(),
}
}
}
impl<S: Schema + ?Sized> ConvertedPrimitive<S> {
pub(crate) fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
self.original.port_map()
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[enumify::enumify(generics_only)]
pub(crate) enum RawCellKind<C, S, P, CP> {
Cell(C),
Scir(S),
Primitive(P),
ConvertedPrimitive(CP),
}
pub(crate) struct RawCellInnerBuilder<S: Schema + ?Sized> {
pub(crate) next_instance_id: InstanceId,
instances: Vec<RawInstanceBuilder<S>>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug
for RawCellInnerBuilder<S>
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("RawCellInnerBuilder");
let _ = builder.field("next_instance_id", &self.next_instance_id);
let _ = builder.field("instances", &self.instances);
builder.finish()
}
}
impl<S: Schema + ?Sized> Default for RawCellInnerBuilder<S> {
fn default() -> Self {
Self {
next_instance_id: Default::default(),
instances: Default::default(),
}
}
}
impl<S: Schema + ?Sized> RawCellInnerBuilder<S> {
fn build(self) -> RawCellInner<S> {
RawCellInner {
instances: self
.instances
.into_iter()
.map(|builder| builder.build())
.collect(),
}
}
}
pub(crate) struct RawCellInner<S: Schema + ?Sized> {
pub(crate) instances: Vec<RawInstance<S>>,
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for RawCellInner<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("RawCellInner");
let _ = builder.field("instances", &self.instances);
builder.finish()
}
}
impl<S: Schema + ?Sized> Clone for RawCellInner<S> {
fn clone(&self) -> Self {
Self {
instances: self.instances.clone(),
}
}
}
impl<S: Schema + ?Sized> RawCellInner<S> {
fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawCellInner<S2>> {
Ok(RawCellInner {
instances: self
.instances
.into_iter()
.map(|instance| instance.convert_schema())
.collect::<Result<_>>()?,
})
}
}
pub struct ScirBinding<S: Schema + ?Sized> {
pub(crate) lib: scir::Library<S>,
pub(crate) cell: scir::CellId,
pub(crate) port_map: HashMap<ArcStr, Vec<Node>>,
}
impl<S: Schema<Primitive = impl Clone> + ?Sized> Clone for ScirBinding<S> {
fn clone(&self) -> Self {
Self {
lib: self.lib.clone(),
cell: self.cell,
port_map: self.port_map.clone(),
}
}
}
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for ScirBinding<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("ScirCellInner");
let _ = builder.field("lib", &self.lib);
let _ = builder.field("cell", &self.cell);
builder.finish()
}
}
impl<S: Schema + ?Sized> ScirBinding<S> {
pub fn new(lib: scir::Library<S>, cell: scir::CellId) -> Self {
assert!(lib.try_cell(cell).is_some());
Self {
lib,
cell,
port_map: HashMap::new(),
}
}
pub fn connect(&mut self, port: impl Into<ArcStr>, s: impl Flatten<Node>) {
self.port_map.insert(port.into(), s.flatten_vec());
}
pub fn cell(&self) -> &scir::Cell {
self.lib.cell(self.cell)
}
pub fn ports(&self) -> impl Iterator<Item = &ArcStr> {
let cell = self.cell();
cell.ports().map(|port| &cell.signal(port.signal()).name)
}
fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
&self.port_map
}
pub fn convert_schema<S2: FromSchema<S> + ?Sized>(
self,
) -> substrate::error::Result<ScirBinding<S2>> {
Ok(ScirBinding {
lib: self
.lib
.convert_schema::<S2>()
.map_err(|_| Error::UnsupportedPrimitive)?
.build()
.unwrap(),
cell: self.cell,
port_map: self.port_map,
})
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
pub struct CellId(u64);
impl CellId {
pub(crate) fn increment(&mut self) {
let next = self.0.checked_add(1).expect("integer overflow");
*self = CellId(next)
}
}
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
pub struct InstanceId(pub(crate) u64);
impl InstanceId {
pub(crate) fn increment(&mut self) {
let next = self.0.checked_add(1).expect("integer overflow");
*self = InstanceId(next)
}
}