1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
//! Procedural macros for the Substrate analog circuit generator framework.
#![warn(missing_docs)]

mod block;
mod io;
mod pdk;
mod sim;

use darling::FromDeriveInput;
use examples::get_snippets;
use io::{io_core_impl, layout_io, schematic_io, IoInputReceiver};
use pdk::layers::{
    DerivedLayerFamilyInputReceiver, DerivedLayersInputReceiver, LayerFamilyInputReceiver,
    LayerInputReceiver, LayersInputReceiver,
};
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro_error::proc_macro_error;
use quote::quote;
use syn::Ident;
use syn::{parse_macro_input, DeriveInput};

use crate::sim::simulator_tuples_impl;

macro_rules! handle_error {
    ($expression:expr) => {
        match $expression {
            Ok(value) => value,
            Err(err) => {
                return err.write_errors().into();
            }
        }
    };
}

/// Derives a layer implementation on a tuple struct containing only an ID.
///
/// # Examples
///
/// ```
/// # use substrate::pdk::layers::{Layer, LayerId};
/// #[derive(Layer, Clone, Copy)]
/// #[layer(name = "poly", gds = "66/20")]
/// pub struct Poly(LayerId);
/// ```
#[proc_macro_derive(Layer, attributes(layer))]
pub fn derive_layer(input: TokenStream) -> TokenStream {
    let receiver = handle_error!(LayerInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    )));
    quote!(
        #receiver
    )
    .into()
}

/// Derives a layer family implementation on a struct.
///
/// See the [`Layers` derive macro](`derive_layers`) for a full example.
#[proc_macro_derive(LayerFamily, attributes(layer))]
pub fn derive_layer_family(input: TokenStream) -> TokenStream {
    let receiver = handle_error!(LayerFamilyInputReceiver::from_derive_input(
        &parse_macro_input!(input as DeriveInput)
    ));
    quote!(
        #receiver
    )
    .into()
}

/// Derives a layer set implementation on a struct.
///
/// # Examples
///
#[doc = get_snippets!("core", "layers")]
#[proc_macro_derive(Layers, attributes(layer, layer_family))]
pub fn derive_layers(input: TokenStream) -> TokenStream {
    let receiver = handle_error!(LayersInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    )));
    quote!(
        #receiver
    )
    .into()
}

/// Derives a derived layer family implementation on a struct.
///
/// See the [`DerivedLayers` derive macro](`derive_derived_layers`) for a full example.
#[proc_macro_derive(DerivedLayerFamily, attributes(layer))]
pub fn derive_derived_layer_family(input: TokenStream) -> TokenStream {
    let receiver = DerivedLayerFamilyInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    ));
    let receiver = handle_error!(receiver);
    quote!(
        #receiver
    )
    .into()
}

/// Derives a derived layer set implementation on a struct.
///
/// # Examples
///
#[doc = get_snippets!("core", "derived_layers")]
#[proc_macro_derive(DerivedLayers, attributes(layer_family))]
pub fn derive_derived_layers(input: TokenStream) -> TokenStream {
    let receiver = handle_error!(DerivedLayersInputReceiver::from_derive_input(
        &parse_macro_input!(input as DeriveInput)
    ));
    quote!(
        #receiver
    )
    .into()
}

/// Derives `Io` for a struct.
///
/// # Examples
///
/// By default, deriving `Io` for a struct creates general purpose schematic and layout IO structs by suffixing the
/// provided identifier with `Schematic` and `Layout`.
///
/// In the example below, `BufferIoSchematic` and `BufferIoLayout` are automatically created with default
/// settings. These are the structs that users interact with when generating schematics and layout
/// views, respectively.
///
#[doc = get_snippets!("core", "buffer_io_simple")]
///
#[doc = get_snippets!("core", "buffer_io_autogenerated")]
///
/// However, the general purpose `PortGeometry` structs that represent the geometry of single net ports in
/// `BufferIoLayout` are often unecessary since they contain multiple shapes, whereas most
/// circuits often have a single shape for several of their ports.
///
/// Substrate allows you to customize the type of the ports you interact with when setting up IO in
/// the layout view of a block using the `#[substrate(layout_type = "...")]` attribute.
///
#[doc = get_snippets!("core", "buffer_io")]
///
/// This indicates that the `din` and `dout` of the buffer only have a single shape, making the
/// ports easier to interact with when instantiating the buffer in other blocks.
///
/// If desired, you can even replace the whole IO struct with a layout type of your own (See
/// the [`LayoutType` derive macro](`derive_layout_type`)).
///
#[proc_macro_derive(Io, attributes(substrate))]
pub fn derive_io(input: TokenStream) -> TokenStream {
    let parsed = parse_macro_input!(input as DeriveInput);
    let input = handle_error!(IoInputReceiver::from_derive_input(&parsed));
    let schematic = schematic_io(&input);
    let layout = layout_io(&input);
    let io_core_impl = io_core_impl(&input);
    quote!(
        #io_core_impl
        #schematic
        #layout
    )
    .into()
}

/// Derives `LayoutType` for a struct.
///
/// # Examples
///
/// You can create your own layout types and use them as your layout IO to customize the API for
/// accessing shapes within your port. This will work as long as the flattened lengths (i.e. the
/// number of nets) of the original IO and the custom IO are the same.
///
#[doc = get_snippets!("core", "buffer_io_custom_layout")]
#[proc_macro_derive(LayoutType)]
pub fn derive_layout_type(input: TokenStream) -> TokenStream {
    let parsed = parse_macro_input!(input as DeriveInput);
    let input = handle_error!(IoInputReceiver::from_derive_input(&parsed));
    let layout = layout_io(&input);
    let io_core_impl = io_core_impl(&input);
    quote!(
        #io_core_impl
        #layout
    )
    .into()
}

/// Derives `substrate::layout::Data` for a struct.
///
/// # Examples
///
/// This example stores the individual buffer instances within a buffer chain.
///
#[doc = get_snippets!("core", "buffern_data")]
#[proc_macro_derive(LayoutData, attributes(substrate))]
pub fn derive_layout_data(input: TokenStream) -> TokenStream {
    let receiver = block::layout::DataInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    ));
    let receiver = handle_error!(receiver);
    quote!(
        #receiver
    )
    .into()
}

/// Derives `substrate::schematic::NestedData` for a struct.
#[proc_macro_derive(NestedData, attributes(substrate))]
pub fn derive_nested_data(input: TokenStream) -> TokenStream {
    let receiver = block::schematic::DataInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    ));
    let receiver = handle_error!(receiver);
    quote!(
        #receiver
    )
    .into()
}

/// Derives `substrate::block::Block` for a struct or enum.
///
/// You must specify the block's IO by adding a `#[substrate(io = "IoType")]` attribute:
/// ```
/// use serde::{Serialize, Deserialize};
/// use substrate::block::Block;
///
/// #[derive(Block, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Debug)]
/// #[substrate(io = "substrate::io::TestbenchIo")]
/// pub struct MyBlock {
///   // ...
/// }
/// ```
///
/// This derive macro only works if you want to use the default value of the IO.
/// If the IO type does not implement [`Default`], or you want to use a non-default
/// value, you must implement `Block` manually.
///
/// The ID value generated by this macro will have the form
/// `mycrate::mymodule::MyBlock`. The block name function will return
/// the name of the struct/enum converted to snake case. For example, the name
/// of a block called `MyBlock` will be `my_block`.
/// If you wish to customize this behavior, consider implementing `Block` manually.
#[proc_macro_derive(Block, attributes(substrate))]
pub fn derive_block(input: TokenStream) -> TokenStream {
    let receiver =
        block::BlockInputReceiver::from_derive_input(&parse_macro_input!(input as DeriveInput));
    let receiver = handle_error!(receiver);
    quote!(
        #receiver
    )
    .into()
}

/// Implements `substrate::simulation::Supports<Tuple> for Simulator`
/// for all tuples up to a specified max size.
#[proc_macro]
pub fn simulator_tuples(input: TokenStream) -> TokenStream {
    simulator_tuples_impl(input)
}

/// Derives `substrate::layout::Layout` for any Substrate block.
///
/// This turns the block into a layout hard macro.
/// You must add a `#[substrate(layout(...))]` attribute to configure this macro;
/// see the examples below.
/// Using multiple `#[substrate(layout(...))]` attributes allows you to
/// generate `Layout` implementations for multiple PDKs.
///
/// This macro only works on Substrate blocks,
/// so you must also add a `#[derive(Block)]` attribute
/// or implement `Block` manually.
///
/// # Arguments
///
/// This macro requires the following arguments (see [Supported formats](#supported-formats) for more details):
/// * `source`: The source from which to read the contents of this block's layout.
/// * `name`: The name of the block's contents in `source`. For example, if
///   source is a GDS library file, name should be set to the name of the desired
///   cell in that file.
/// * `fmt`: The layout source format.
/// * `pdk`: The PDK to which source corresponds.
///
/// # Supported formats
///
/// The following formats are supported:
///
/// * `gds`: Source should be an expression that evaluates to the file path of a GDSII library.
///
/// Note that expressions can be arbitrary Rust expressions. Here are some examples:
/// * `fmt = "\"/path/to/layout.gds\""` (note that you need the escaped quotes to make this a
/// string literal).
/// * `fmt = "function_that_returns_path()"`
/// * `fmt = "function_with_arguments_that_returns_path(\"my_argument\")"`
#[proc_macro_error]
#[proc_macro_derive(Layout, attributes(substrate))]
pub fn derive_has_layout_impl(input: TokenStream) -> TokenStream {
    let receiver = block::layout::HasLayoutInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    ));
    let receiver = handle_error!(receiver);
    quote!(
        #receiver
    )
    .into()
}

/// Generates an implementation of `FromSaved<Sim, Analysis>` for a type.
///
/// All fields of the type must implement `FromSaved`.
/// Unit structs are not supported. Enums that do not embed a field in at least
/// one variant are also not supported.
///
/// # Examples
///
#[doc = get_snippets!("core", "sim_from_saved")]
#[proc_macro_error]
#[proc_macro_derive(FromSaved, attributes(substrate))]
pub fn derive_from_saved(input: TokenStream) -> TokenStream {
    let receiver = sim::save::FromSavedInputReceiver::from_derive_input(&parse_macro_input!(
        input as DeriveInput
    ));
    let receiver = handle_error!(receiver);
    quote!(
        #receiver
    )
    .into()
}

pub(crate) fn substrate_ident() -> TokenStream2 {
    match crate_name("substrate").expect("substrate is present in `Cargo.toml`") {
        FoundCrate::Itself => quote!(::substrate),
        FoundCrate::Name(name) => {
            let ident = Ident::new(&name, Span::call_site());
            quote!(::#ident)
        }
    }
}