diff --git a/Cargo.lock b/Cargo.lock index 649f0fa85..02b257be5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3066,6 +3066,7 @@ dependencies = [ "approx", "arcstr", "cache", + "indexmap", "itertools", "lazy_static", "num", diff --git a/tools/spectre/Cargo.toml b/tools/spectre/Cargo.toml index d1e64da31..c71104dd0 100644 --- a/tools/spectre/Cargo.toml +++ b/tools/spectre/Cargo.toml @@ -14,6 +14,7 @@ serde = { version = "1", features = ["derive"] } tracing = "0.1" itertools = "0.14" regex = "1" +indexmap = "2" num = { version = "0.4", features = ["serde"] } cache = { version = "0.7.2", registry = "substrate", path = "../../libs/cache" } diff --git a/tools/spectre/src/lib.rs b/tools/spectre/src/lib.rs index 5b26924aa..e0e2797be 100644 --- a/tools/spectre/src/lib.rs +++ b/tools/spectre/src/lib.rs @@ -1,7 +1,7 @@ //! Spectre plugin for Substrate. #![warn(missing_docs)] -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::io::Write; #[cfg(any(unix, target_os = "redox"))] @@ -22,6 +22,7 @@ use arcstr::ArcStr; use cache::CacheableWithState; use cache::error::TryInnerError; use error::*; +use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use lazy_static::lazy_static; use num::complex::Complex64; @@ -194,9 +195,9 @@ pub struct Spectre {} /// A single simulation contains zero or more analyses. #[derive(Debug, Clone, Default)] pub struct Options { - includes: HashSet, - saves: HashMap, - ics: HashMap, + includes: IndexSet, + saves: IndexMap, + ics: IndexMap, next_save_key: u64, /// The simulation temperature. temp: Option, @@ -438,7 +439,7 @@ impl CachedData { self, ctx: &SimulationContext, conv: &NetlistLibConversion, - saves: &HashMap, + saves: &IndexMap, ) -> Output { match self { CachedData::Tran(mut raw_values) => tran::Output { @@ -582,19 +583,13 @@ impl Spectre { let mut f = std::fs::File::create(&netlist)?; let mut w = Vec::new(); - let mut includes = options.includes.into_iter().collect::>(); - let mut saves = options.saves.keys().cloned().collect::>(); - let mut ics = options + let includes = options.includes.into_iter().collect::>(); + let saves = options.saves.keys().cloned().collect::>(); + let ics = options .ics .iter() .map(|(k, v)| (k.clone(), *v)) .collect::>(); - // Sorting the include list makes repeated netlist invocations - // produce the same output. If we were to iterate over the HashSet directly, - // the order of includes may change even if the contents of the set did not change. - includes.sort(); - saves.sort(); - ics.sort(); let conv = self.write_scir_netlist( &ctx.lib.scir, @@ -1087,9 +1082,8 @@ impl HasSpiceLikeNetlist for Spectre { None } }) - .collect::>(); - // sort paths before including them to ensure stable output - for ibis_path in ibis.iter().sorted() { + .collect::>(); + for ibis_path in ibis.iter() { writeln!(out, "ibis_include {:?}", ibis_path)?; } @@ -1103,9 +1097,8 @@ impl HasSpiceLikeNetlist for Spectre { None } }) - .collect::>(); - // sort paths before including them to ensure stable output - for spf_path in spfs.iter().sorted() { + .collect::>(); + for spf_path in spfs.iter() { writeln!(out, "dspf_include {:?}", spf_path)?; } @@ -1122,9 +1115,8 @@ impl HasSpiceLikeNetlist for Spectre { None } }) - .collect::>(); - // sort paths before including them to ensure stable output - for include in includes.iter().sorted() { + .collect::>(); + for include in includes.iter() { writeln!(out, "include {:?}", include)?; }