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
//! An enumeration of supported corners.

use crate::Sky130Pdk;
use ngspice::Ngspice;
use serde::{Deserialize, Serialize};
use spectre::Spectre;
use substrate::simulation::options::SimOption;
use substrate::simulation::{SimulationContext, Simulator};

/// An enumeration of supported corners.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Sky130Corner {
    /// Typical.
    #[default]
    Tt,
    /// Slow-fast.
    Sf,
    /// Fast-slow.
    Fs,
    /// Fast-fast.
    Ff,
    /// Slow-slow.
    Ss,
}

impl Sky130Corner {
    /// Returns the name of the corner.
    pub fn name(&self) -> arcstr::ArcStr {
        match *self {
            Self::Tt => arcstr::literal!("tt"),
            Self::Fs => arcstr::literal!("fs"),
            Self::Sf => arcstr::literal!("sf"),
            Self::Ff => arcstr::literal!("ff"),
            Self::Ss => arcstr::literal!("ss"),
        }
    }
}

impl SimOption<Spectre> for Sky130Corner {
    fn set_option(
        self,
        opts: &mut <Spectre as Simulator>::Options,
        ctx: &SimulationContext<Spectre>,
    ) {
        let pdk = ctx
            .ctx
            .get_installation::<Sky130Pdk>()
            .expect("Sky130 PDK must be installed");
        let design_wrapper_path = pdk
            .commercial_root_dir
            .as_ref()
            .expect("Commercial root directory must be specified")
            .join("MODELS/SPECTRE/s8phirs_10r/Models/design_wrapper.lib.scs");
        opts.include_section(&design_wrapper_path, format!("{}_fet", self.name()));
        opts.include_section(&design_wrapper_path, format!("{}_cell", self.name()));
        opts.include_section(&design_wrapper_path, format!("{}_parRC", self.name()));
        opts.include_section(&design_wrapper_path, format!("{}_rc", self.name()));
    }
}

impl SimOption<Ngspice> for Sky130Corner {
    fn set_option(
        self,
        opts: &mut <Ngspice as Simulator>::Options,
        ctx: &SimulationContext<Ngspice>,
    ) {
        let pdk = ctx
            .ctx
            .get_installation::<Sky130Pdk>()
            .expect("Sky130 PDK must be installed");
        opts.include_section(
            pdk.open_root_dir
                .as_ref()
                .expect("Commercial root directory must be specified")
                .join("libraries/sky130_fd_pr/latest/models/sky130.lib.spice"),
            self.name(),
        )
    }
}