spade_mir/
unit_name.rs

1use std::collections::{BTreeMap, HashMap};
2
3use derive_where::derive_where;
4use itertools::Itertools;
5use serde::{Deserialize, Serialize};
6use spade_common::name::{NameID, Path};
7
8/// Mapping between instances and the module it instantiates
9/// Example:
10/// ```rust
11/// entity y() {} // NameID: y_n0
12/// entity x() {inst y()} // NameID: x_n1
13/// entity main() { // NameID: main_n2
14///     inst y();
15///     inst x()
16/// }
17/// ```
18///
19/// Results in the following pseudo verilog:
20/// ```
21/// module main();
22///     x x_0();
23///     y y_0();
24/// endmodule
25///
26/// module x();
27///     y y_0();
28/// endmodule
29/// module y();
30/// endmodule
31/// ```
32///
33/// Which would have the following name map
34///
35/// (y has no modules, so no mapping)
36/// (x_n1, "x_0") -> y_n0
37/// (main_n2, "x_0") -> x_n1
38/// (main_n2, "y_0") -> y_n0
39#[derive(Serialize, Deserialize, Debug)]
40pub struct InstanceMap {
41    pub inner: HashMap<NameID, BTreeMap<String, NameID>>,
42}
43
44impl Default for InstanceMap {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl InstanceMap {
51    pub fn new() -> Self {
52        Self {
53            inner: HashMap::new(),
54        }
55    }
56}
57
58pub struct InstanceNameTracker {
59    previous_names: HashMap<String, usize>,
60}
61
62impl Default for InstanceNameTracker {
63    fn default() -> Self {
64        Self::new()
65    }
66}
67
68impl InstanceNameTracker {
69    pub fn new() -> Self {
70        Self {
71            previous_names: HashMap::new(),
72        }
73    }
74
75    pub fn use_name(
76        &mut self,
77        // The nameID of the monomorphized unit to be instantiated
78        unit_name: NameID,
79        // The requested human readable instance name, will be modified to
80        // make unique in this module
81        instance_name: &str,
82        // The unit in which this instantiation takes place
83        in_unit: NameID,
84        map: &mut InstanceMap,
85    ) -> String {
86        let e = self
87            .previous_names
88            .entry(instance_name.to_string())
89            .or_default();
90        let result = format!("{instance_name}_{e}");
91        *e += 1;
92
93        map.inner
94            .entry(in_unit)
95            .or_default()
96            .insert(result.clone(), unit_name);
97
98        result
99    }
100}
101
102#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
103/// The name of a verilog module
104pub enum UnitNameKind {
105    /// A string that will be directly emitted in verilog. Must be a valid verilog
106    /// identifier that does not clash with any keywords.
107    /// The path is the underlying path which results in this entity. This is used when generating
108    /// instance names to only emit the unit name and not the fully qualified path
109    Unescaped(String),
110    /// Any ASCII characters. Will be prepended with `\` and have ` ` appended at the
111    /// end to give a valid verilog identifier
112    Escaped { name: String, path: Vec<String> },
113}
114
115#[derive_where(PartialOrd, Ord, PartialEq, Eq, Hash)]
116#[derive(Clone, Debug)]
117pub struct UnitName {
118    pub kind: UnitNameKind,
119    #[derive_where(skip)]
120    pub source: NameID,
121}
122
123impl UnitName {
124    /// Creates a UnitName::Escaped from a list of strings making up a path.
125    /// Does not set `source` to a valid NameID
126    pub fn _test_from_strs(strs: &[&str]) -> Self {
127        UnitName {
128            source: NameID(0, Path::from_strs(strs)),
129            kind: UnitNameKind::Escaped {
130                name: strs.iter().join("::"),
131                path: strs.iter().map(|s| s.to_string()).collect(),
132            },
133        }
134    }
135    pub fn as_verilog(&self) -> String {
136        match &self.kind {
137            UnitNameKind::Unescaped(name) => name.clone(),
138            UnitNameKind::Escaped { name, path: _ } => format!("\\{name} "),
139        }
140    }
141
142    pub fn instance_name(
143        &self,
144        inside: NameID,
145        instance_map: &mut InstanceMap,
146        names: &mut InstanceNameTracker,
147    ) -> String {
148        let name = match &self.kind {
149            UnitNameKind::Escaped { name, path } => path.last().unwrap_or(name),
150            UnitNameKind::Unescaped(name) => name,
151        };
152        names.use_name(self.source.clone(), name, inside, instance_map)
153    }
154
155    /// The \ and ' ' are not part of the actual identifier when escaping. So when we check
156    /// for the top module, we don't want to include them
157    pub fn without_escapes(&self) -> &str {
158        match &self.kind {
159            UnitNameKind::Escaped { name, path: _ } => name,
160            UnitNameKind::Unescaped(s) => s,
161        }
162    }
163}
164
165impl std::fmt::Display for UnitName {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        write!(f, "{}", self.as_verilog())
168    }
169}
170
171pub trait IntoUnitName {
172    fn _test_into_unit_name(&self) -> UnitName;
173}
174
175impl<'a, T> IntoUnitName for T
176where
177    T: AsRef<[&'a str]>,
178{
179    fn _test_into_unit_name(&self) -> UnitName {
180        UnitName {
181            kind: UnitNameKind::Escaped {
182                name: self.as_ref().iter().join("::"),
183                path: self.as_ref().iter().map(|s| s.to_string()).collect(),
184            },
185            source: NameID(0, Path::from_strs(self.as_ref())),
186        }
187    }
188}
189
190impl IntoUnitName for str {
191    fn _test_into_unit_name(&self) -> UnitName {
192        UnitName {
193            kind: UnitNameKind::Unescaped(self.to_string()),
194            source: NameID(0, Path::from_strs(&[self])),
195        }
196    }
197}
198
199impl IntoUnitName for UnitName {
200    fn _test_into_unit_name(&self) -> UnitName {
201        self.clone()
202    }
203}