diff --git a/Cargo.lock b/Cargo.lock index fa6fb6b..1c17ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,7 +56,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -218,7 +218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -249,10 +249,8 @@ dependencies = [ "hashbrown", "num-bigint", "num-traits", - "os_pipe", "serde", "serde_json", - "tempfile", "trybuild", "which", ] @@ -336,7 +334,7 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -415,16 +413,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "prettyplease" version = "0.2.20" @@ -469,7 +457,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -553,7 +541,7 @@ dependencies = [ "cfg-if", "fastrand", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -676,25 +664,15 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", - "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -703,51 +681,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winsafe" diff --git a/Cargo.toml b/Cargo.toml index 15d13b6..1608a79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,10 @@ fayalite-proc-macros-impl = { version = "=0.2.0", path = "crates/fayalite-proc-m fayalite-visit-gen = { version = "=0.2.0", path = "crates/fayalite-visit-gen" } base16ct = "0.2.0" bitvec = { version = "1.0.1", features = ["serde"] } -clap = { version = "4.5.9", features = ["derive", "env", "string"] } -eyre = "0.6.12" hashbrown = "0.14.3" indexmap = { version = "2.2.6", features = ["serde"] } num-bigint = "0.4.4" num-traits = "0.2.16" -os_pipe = "1.2.1" prettyplease = "0.2.20" proc-macro2 = "1.0.83" quote = "1.0.36" @@ -36,4 +33,3 @@ syn = { version = "2.0.66", features = ["full", "fold", "visit", "extra-traits"] tempfile = "3.10.1" thiserror = "1.0.61" trybuild = "1.0" -which = "6.0.1" diff --git a/crates/fayalite-proc-macros-impl/Cargo.toml b/crates/fayalite-proc-macros-impl/Cargo.toml index d56f03d..31c4465 100644 --- a/crates/fayalite-proc-macros-impl/Cargo.toml +++ b/crates/fayalite-proc-macros-impl/Cargo.toml @@ -13,11 +13,11 @@ rust-version.workspace = true version.workspace = true [dependencies] -base16ct.workspace = true -num-bigint.workspace = true -prettyplease.workspace = true -proc-macro2.workspace = true -quote.workspace = true -sha2.workspace = true -syn.workspace = true -tempfile.workspace = true +base16ct = { workspace = true } +num-bigint = { workspace = true } +prettyplease = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +sha2 = { workspace = true } +syn = { workspace = true } +tempfile = { workspace = true } diff --git a/crates/fayalite-proc-macros/Cargo.toml b/crates/fayalite-proc-macros/Cargo.toml index 6941d12..08c630a 100644 --- a/crates/fayalite-proc-macros/Cargo.toml +++ b/crates/fayalite-proc-macros/Cargo.toml @@ -16,4 +16,4 @@ version.workspace = true proc-macro = true [dependencies] -fayalite-proc-macros-impl.workspace = true +fayalite-proc-macros-impl = { workspace = true } diff --git a/crates/fayalite-visit-gen/Cargo.toml b/crates/fayalite-visit-gen/Cargo.toml index 5a98947..6da95d2 100644 --- a/crates/fayalite-visit-gen/Cargo.toml +++ b/crates/fayalite-visit-gen/Cargo.toml @@ -13,11 +13,11 @@ rust-version.workspace = true version.workspace = true [dependencies] -indexmap.workspace = true -prettyplease.workspace = true -proc-macro2.workspace = true -quote.workspace = true -serde.workspace = true -serde_json.workspace = true -syn.workspace = true -thiserror.workspace = true +indexmap = { workspace = true } +prettyplease = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +syn = { workspace = true } +thiserror = { workspace = true } diff --git a/crates/fayalite/Cargo.toml b/crates/fayalite/Cargo.toml index 21089c0..555f7f5 100644 --- a/crates/fayalite/Cargo.toml +++ b/crates/fayalite/Cargo.toml @@ -14,24 +14,22 @@ rust-version.workspace = true version.workspace = true [dependencies] -bitvec.workspace = true -clap.workspace = true -eyre.workspace = true -fayalite-proc-macros.workspace = true -hashbrown.workspace = true -num-bigint.workspace = true -num-traits.workspace = true -os_pipe.workspace = true -serde_json.workspace = true -serde.workspace = true -tempfile.workspace = true -which.workspace = true +bitvec = { workspace = true } +hashbrown = { workspace = true } +num-bigint = { workspace = true } +num-traits = { workspace = true } +fayalite-proc-macros = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +clap = { version = "4.5.9", features = ["derive", "env"] } +eyre = "0.6.12" +which = "6.0.1" [dev-dependencies] -trybuild.workspace = true +trybuild = { workspace = true } [build-dependencies] -fayalite-visit-gen.workspace = true +fayalite-visit-gen = { workspace = true } [features] unstable-doc = [] diff --git a/crates/fayalite/src/cli.rs b/crates/fayalite/src/cli.rs index a771de6..5071279 100644 --- a/crates/fayalite/src/cli.rs +++ b/crates/fayalite/src/cli.rs @@ -2,18 +2,16 @@ // See Notices.txt for copyright information use crate::{ bundle::{Bundle, BundleType}, - firrtl::{self, ExportOptions}, + firrtl, intern::Interned, module::Module, - util::streaming_read_utf8::streaming_read_utf8, }; use clap::{ builder::{OsStringValueParser, TypedValueParser}, - Parser, Subcommand, ValueEnum, ValueHint, + Args, Parser, Subcommand, ValueEnum, ValueHint, }; use eyre::{eyre, Report}; use std::{error, ffi::OsString, fmt, io, path::PathBuf, process}; -use tempfile::TempDir; pub type Result = std::result::Result; @@ -44,119 +42,56 @@ pub trait RunPhase { fn run(&self, arg: Arg) -> Result; } -#[derive(Parser, Debug, Clone)] +#[derive(Args, Debug)] #[non_exhaustive] pub struct BaseArgs { /// the directory to put the generated main output file and associated files in - #[arg(short, long, value_hint = ValueHint::DirPath, required = true)] - pub output: Option, + #[arg(short, long, value_hint = ValueHint::DirPath)] + pub output: PathBuf, /// the stem of the generated main output file, e.g. to get foo.v, pass --file-stem=foo #[arg(long)] pub file_stem: Option, - #[arg(long, env = "FAYALITE_KEEP_TEMP_DIR")] - pub keep_temp_dir: bool, - #[arg(skip = false)] - pub redirect_output_for_rust_test: bool, } impl BaseArgs { - fn make_firrtl_file_backend(&self) -> Result<(firrtl::FileBackend, Option)> { - let (dir_path, temp_dir) = match &self.output { - Some(output) => (output.clone(), None), - None => { - let temp_dir = TempDir::new()?; - if self.keep_temp_dir { - let temp_dir = temp_dir.into_path(); - println!("created temporary directory: {}", temp_dir.display()); - (temp_dir, None) - } else { - (temp_dir.path().to_path_buf(), Some(temp_dir)) - } - } - }; - Ok(( - firrtl::FileBackend { - dir_path, - top_fir_file_stem: self.file_stem.clone(), - circuit_name: None, - }, - temp_dir, - )) - } - /// handles possibly redirecting the command's output for Rust tests - pub fn run_external_command( - &self, - mut command: process::Command, - ) -> io::Result { - if self.redirect_output_for_rust_test { - let (reader, writer) = os_pipe::pipe()?; - let mut reader = io::BufReader::new(reader); - command.stderr(writer.try_clone()?); - command.stdout(writer); // must not leave writer around after spawning child - command.stdin(process::Stdio::null()); - let mut child = command.spawn()?; - drop(command); // close writers - Ok(loop { - let status = child.try_wait()?; - streaming_read_utf8(&mut reader, |s| { - // use print! so output goes to Rust test output capture - print!("{s}"); - io::Result::Ok(()) - })?; - if let Some(status) = status { - break status; - } - }) - } else { - command.status() + pub fn to_firrtl_file_backend(&self) -> firrtl::FileBackend { + firrtl::FileBackend { + dir_path: self.output.clone(), + top_fir_file_stem: self.file_stem.clone(), } } } -#[derive(Parser, Debug, Clone)] +#[derive(Args, Debug)] #[non_exhaustive] pub struct FirrtlArgs { #[command(flatten)] pub base: BaseArgs, - #[command(flatten)] - pub export_options: ExportOptions, } #[derive(Debug)] #[non_exhaustive] pub struct FirrtlOutput { pub file_stem: String, - pub top_module: String, - pub output_dir: PathBuf, - pub temp_dir: Option, } impl FirrtlOutput { - pub fn file_with_ext(&self, ext: &str) -> PathBuf { - let mut retval = self.output_dir.join(&self.file_stem); - retval.set_extension(ext); + pub fn firrtl_file(&self, args: &FirrtlArgs) -> PathBuf { + let mut retval = args.base.output.join(&self.file_stem); + retval.set_extension("fir"); retval } - pub fn firrtl_file(&self) -> PathBuf { - self.file_with_ext("fir") - } } impl FirrtlArgs { fn run_impl(&self, top_module: Module) -> Result { - let (file_backend, temp_dir) = self.base.make_firrtl_file_backend()?; let firrtl::FileBackend { - top_fir_file_stem, - circuit_name, - dir_path, - } = firrtl::export(file_backend, &top_module, self.export_options)?; + top_fir_file_stem, .. + } = firrtl::export(self.base.to_firrtl_file_backend(), &top_module)?; Ok(FirrtlOutput { file_stem: top_fir_file_stem.expect( "export is known to set the file stem from the circuit name if not provided", ), - top_module: circuit_name.expect("export is known to set the circuit name"), - output_dir: dir_path, - temp_dir, }) } } @@ -187,22 +122,7 @@ pub enum VerilogDialect { Yosys, } -impl fmt::Display for VerilogDialect { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - impl VerilogDialect { - pub fn as_str(self) -> &'static str { - match self { - VerilogDialect::Questa => "questa", - VerilogDialect::Spyglass => "spyglass", - VerilogDialect::Verilator => "verilator", - VerilogDialect::Vivado => "vivado", - VerilogDialect::Yosys => "yosys", - } - } pub fn firtool_extra_args(self) -> &'static [&'static str] { match self { VerilogDialect::Questa => &["--lowering-options=emitWireInPorts"], @@ -220,7 +140,7 @@ impl VerilogDialect { } } -#[derive(Parser, Debug, Clone)] +#[derive(Args, Debug)] #[non_exhaustive] pub struct VerilogArgs { #[command(flatten)] @@ -238,8 +158,6 @@ pub struct VerilogArgs { /// adapt the generated Verilog for a particular toolchain #[arg(long)] pub verilog_dialect: Option, - #[arg(long, short = 'g')] - pub debug: bool, } #[derive(Debug)] @@ -249,37 +167,28 @@ pub struct VerilogOutput { } impl VerilogOutput { - pub fn verilog_file(&self) -> PathBuf { - self.firrtl.file_with_ext("v") + pub fn verilog_file(&self, args: &VerilogArgs) -> PathBuf { + let mut retval = args.firrtl.base.output.join(&self.firrtl.file_stem); + retval.set_extension("v"); + retval } } impl VerilogArgs { fn run_impl(&self, firrtl_output: FirrtlOutput) -> Result { - let Self { - firrtl, - firtool, - firtool_extra_args, - verilog_dialect, - debug, - } = self; let output = VerilogOutput { firrtl: firrtl_output, }; - let mut cmd = process::Command::new(firtool); - cmd.arg(output.firrtl.firrtl_file()); + let mut cmd = process::Command::new(&self.firtool); + cmd.arg(output.firrtl.firrtl_file(&self.firrtl)); cmd.arg("-o"); - cmd.arg(output.verilog_file()); - if *debug { - cmd.arg("-g"); - cmd.arg("--preserve-values=named"); - } - if let Some(dialect) = verilog_dialect { + cmd.arg(output.verilog_file(self)); + if let Some(dialect) = self.verilog_dialect { cmd.args(dialect.firtool_extra_args()); } - cmd.args(firtool_extra_args); - cmd.current_dir(&output.firrtl.output_dir); - let status = firrtl.base.run_external_command(cmd)?; + cmd.args(&self.firtool_extra_args); + cmd.current_dir(&self.firrtl.base.output); + let status = cmd.status()?; if status.success() { Ok(output) } else { @@ -302,217 +211,12 @@ where } } -#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq, Hash, Default)] -#[non_exhaustive] -pub enum FormalMode { - #[default] - BMC, - Prove, - Live, - Cover, -} - -impl FormalMode { - pub fn as_str(self) -> &'static str { - match self { - FormalMode::BMC => "bmc", - FormalMode::Prove => "prove", - FormalMode::Live => "live", - FormalMode::Cover => "cover", - } - } -} - -impl fmt::Display for FormalMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -#[derive(Clone)] -struct FormalAdjustArgs; - -impl clap::FromArgMatches for FormalAdjustArgs { - fn from_arg_matches(_matches: &clap::ArgMatches) -> Result { - Ok(Self) - } - - fn update_from_arg_matches(&mut self, _matches: &clap::ArgMatches) -> Result<(), clap::Error> { - Ok(()) - } -} - -impl clap::Args for FormalAdjustArgs { - fn augment_args(cmd: clap::Command) -> clap::Command { - cmd.mut_arg("output", |arg| arg.required(false)) - .mut_arg("verilog_dialect", |arg| { - arg.default_value(VerilogDialect::Yosys.to_string()) - .hide(true) - }) - } - - fn augment_args_for_update(cmd: clap::Command) -> clap::Command { - Self::augment_args(cmd) - } -} - -#[derive(Parser, Clone)] -#[non_exhaustive] -pub struct FormalArgs { - #[command(flatten)] - pub verilog: VerilogArgs, - #[arg( - long, - default_value = "sby", - env = "SBY", - value_hint = ValueHint::CommandName, - value_parser = OsStringValueParser::new().try_map(which::which) - )] - pub sby: PathBuf, - #[arg(long)] - pub sby_extra_args: Vec, - #[arg(long, default_value_t)] - pub mode: FormalMode, - #[arg(long, default_value_t = Self::DEFAULT_DEPTH)] - pub depth: u64, - #[arg(long)] - pub solver: Option, - #[arg(long)] - pub smtbmc_extra_args: Vec, - #[command(flatten)] - _formal_adjust_args: FormalAdjustArgs, -} - -impl fmt::Debug for FormalArgs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - verilog, - sby, - sby_extra_args, - mode, - depth, - solver, - smtbmc_extra_args, - _formal_adjust_args: _, - } = self; - f.debug_struct("FormalArgs") - .field("verilog", &verilog) - .field("sby", &sby) - .field("sby_extra_args", &sby_extra_args) - .field("mode", &mode) - .field("depth", &depth) - .field("solver", &solver) - .field("smtbmc_extra_args", &smtbmc_extra_args) - .finish_non_exhaustive() - } -} - -impl FormalArgs { - pub const DEFAULT_DEPTH: u64 = 20; -} - -#[derive(Debug)] -#[non_exhaustive] -pub struct FormalOutput { - pub verilog: VerilogOutput, -} - -impl FormalOutput { - pub fn sby_file(&self) -> PathBuf { - self.verilog.firrtl.file_with_ext("sby") - } -} - -impl FormalArgs { - fn sby_contents(&self, output: &FormalOutput) -> String { - let Self { - verilog: _, - sby: _, - sby_extra_args: _, - mode, - depth, - smtbmc_extra_args, - solver, - _formal_adjust_args: _, - } = self; - struct OptArg(Option); - impl fmt::Display for OptArg { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(v) = &self.0 { - f.write_str(" ")?; - v.fmt(f) - } else { - Ok(()) - } - } - } - let space_solver = OptArg(solver.as_ref()); - let smtbmc_options = smtbmc_extra_args.join(" "); - let verilog_file = output - .verilog - .verilog_file() - .into_os_string() - .into_string() - .ok() - .expect("verilog file path is not UTF-8"); - let top_module = &output.verilog.firrtl.top_module; - format!( - "[options]\n\ - mode {mode}\n\ - depth {depth}\n\ - wait on\n\ - \n\ - [engines]\n\ - smtbmc{space_solver} -- -- {smtbmc_options}\n\ - \n\ - [script]\n\ - read_verilog -sv -formal {verilog_file}\n\ - prep -top {top_module}\n - " - ) - } - fn run_impl(&self, verilog_output: VerilogOutput) -> Result { - let output = FormalOutput { - verilog: verilog_output, - }; - let sby_file = output.sby_file(); - std::fs::write(&sby_file, self.sby_contents(&output))?; - let mut cmd = process::Command::new(&self.sby); - cmd.arg("-f"); - cmd.arg(sby_file); - cmd.args(&self.sby_extra_args); - cmd.current_dir(&output.verilog.firrtl.output_dir); - let status = self.verilog.firrtl.base.run_external_command(cmd)?; - if status.success() { - Ok(output) - } else { - Err(CliError(eyre!( - "running {} failed: {status}", - self.sby.display() - ))) - } - } -} - -impl RunPhase for FormalArgs -where - VerilogArgs: RunPhase, -{ - type Output = FormalOutput; - fn run(&self, arg: Arg) -> Result { - let verilog_output = self.verilog.run(arg)?; - self.run_impl(verilog_output) - } -} - #[derive(Subcommand, Debug)] enum CliCommand { /// Generate FIRRTL Firrtl(FirrtlArgs), /// Generate Verilog Verilog(VerilogArgs), - /// Run a formal proof - Formal(FormalArgs), } /// a simple CLI @@ -598,9 +302,6 @@ where CliCommand::Verilog(c) => { c.run(arg)?; } - CliCommand::Formal(c) => { - c.run(arg)?; - } } Ok(()) } diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 4a1547d..b8ba89a 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -18,14 +18,10 @@ use crate::{ intern::{Intern, Interned}, memory::{Mem, PortKind, PortName, ReadUnderWrite}, module::{ - transform::{ - simplify_enums::{simplify_enums, SimplifyEnumsError, SimplifyEnumsKind}, - simplify_memories::simplify_memories, - }, - AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter, - ExternModuleParameterValue, Module, ModuleBody, NameId, NormalModuleBody, Stmt, - StmtConnect, StmtDeclaration, StmtFormal, StmtFormalKind, StmtIf, StmtInstance, StmtMatch, - StmtReg, StmtWire, + transform::simplify_memories::simplify_memories, AnnotatedModuleIO, Block, + ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Module, ModuleBody, + NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtFormalKind, + StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, }, reset::{AsyncReset, Reset, SyncReset}, source_location::SourceLocation, @@ -36,7 +32,6 @@ use crate::{ }, }; use bitvec::slice::BitSlice; -use clap::value_parser; use hashbrown::{HashMap, HashSet}; use num_traits::Signed; use serde::Serialize; @@ -481,7 +476,6 @@ trait WrappedFileBackendTrait { circuit_name: String, contents: String, ) -> Result<(), WrappedError>; - fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError; } struct WrappedFileBackend { @@ -539,11 +533,6 @@ impl WrappedFileBackendTrait for WrappedFileBackend { WrappedError }) } - - fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError { - self.error = Err(error.into()); - WrappedError - } } #[derive(Clone)] @@ -2236,7 +2225,7 @@ impl<'a> Exporter<'a> { } pub trait FileBackendTrait { - type Error: From; + type Error; type Path: AsRef + fmt::Debug + ?Sized; type PathBuf: AsRef + fmt::Debug; fn path_to_string(&mut self, path: &Self::Path) -> Result; @@ -2311,7 +2300,6 @@ impl FileBackendTrait for &'_ mut T { #[non_exhaustive] pub struct FileBackend { pub dir_path: PathBuf, - pub circuit_name: Option, pub top_fir_file_stem: Option, } @@ -2319,7 +2307,6 @@ impl FileBackend { pub fn new(dir_path: impl AsRef) -> Self { Self { dir_path: dir_path.as_ref().to_owned(), - circuit_name: None, top_fir_file_stem: None, } } @@ -2355,10 +2342,7 @@ impl FileBackendTrait for FileBackend { circuit_name: String, contents: String, ) -> Result<(), Self::Error> { - let top_fir_file_stem = self - .top_fir_file_stem - .get_or_insert_with(|| circuit_name.clone()); - self.circuit_name = Some(circuit_name); + let top_fir_file_stem = self.top_fir_file_stem.get_or_insert(circuit_name); let mut path = self.dir_path.join(top_fir_file_stem); if let Some(parent) = path.parent().filter(|v| !v.as_os_str().is_empty()) { fs::create_dir_all(parent)?; @@ -2386,7 +2370,6 @@ impl Default for TestBackendPrivate { pub struct TestBackend { pub files: BTreeMap, pub error_after: Option, - pub options: ExportOptions, #[doc(hidden)] /// `#[non_exhaustive]` except allowing struct update syntax pub __private: TestBackendPrivate, @@ -2397,7 +2380,6 @@ impl fmt::Debug for TestBackend { let Self { files, error_after, - options, __private: TestBackendPrivate { module_var_name }, } = self; writeln!( @@ -2412,9 +2394,6 @@ impl fmt::Debug for TestBackend { if *error_after != Option::default() { writeln!(f, " error_after: {error_after:?},")?; } - if *options != ExportOptions::default() { - writeln!(f, " options: {options:?},")?; - } write!(f, " }};") } } @@ -2430,12 +2409,6 @@ impl fmt::Display for TestBackendError { impl Error for TestBackendError {} -impl From for TestBackendError { - fn from(value: SimplifyEnumsError) -> Self { - TestBackendError(value.to_string()) - } -} - impl TestBackend { #[track_caller] pub fn step_error_after(&mut self, args: &dyn fmt::Debug) -> Result<(), TestBackendError> { @@ -2492,20 +2465,9 @@ impl FileBackendTrait for TestBackend { fn export_impl( file_backend: &mut dyn WrappedFileBackendTrait, - mut top_module: Interned>, - options: ExportOptions, + top_module: Interned>, ) -> Result<(), WrappedError> { - let ExportOptions { - simplify_memories: do_simplify_memories, - simplify_enums: do_simplify_enums, - } = options; - if let Some(kind) = do_simplify_enums { - top_module = - simplify_enums(top_module, kind).map_err(|e| file_backend.simplify_enums_error(e))?; - } - if do_simplify_memories { - top_module = simplify_memories(top_module); - } + let top_module = simplify_memories(top_module); let indent_depth = Cell::new(0); let mut global_ns = Namespace::default(); let circuit_name = global_ns.get(top_module.name_id()); @@ -2526,102 +2488,20 @@ fn export_impl( .run(top_module) } -#[derive(Clone)] -struct OptionSimplifyEnumsKindValueParser; - -impl OptionSimplifyEnumsKindValueParser { - const NONE_NAME: &'static str = "off"; -} - -impl clap::builder::TypedValueParser for OptionSimplifyEnumsKindValueParser { - type Value = Option; - - fn parse_ref( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: &std::ffi::OsStr, - ) -> Result { - if value == Self::NONE_NAME { - Ok(None) - } else { - Ok(Some( - value_parser!(SimplifyEnumsKind).parse_ref(cmd, arg, value)?, - )) - } - } - - fn possible_values( - &self, - ) -> Option + '_>> { - Some(Box::new( - [Self::NONE_NAME.into()] - .into_iter() - .chain(value_parser!(SimplifyEnumsKind).possible_values()?) - .collect::>() - .into_iter(), - )) - } -} - -#[derive(clap::Parser, Copy, Clone, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub struct ExportOptions { - #[clap(long = "no-simplify-memories", action = clap::ArgAction::SetFalse)] - pub simplify_memories: bool, - #[clap(long, value_parser = OptionSimplifyEnumsKindValueParser, default_value = OptionSimplifyEnumsKindValueParser::NONE_NAME)] - pub simplify_enums: std::option::Option, -} - -impl fmt::Debug for ExportOptions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("ExportOptions {")?; - if f.alternate() { - f.write_str("\n")?; - } - let mut sep = if f.alternate() { "\n " } else { " " }; - let comma_sep = if f.alternate() { ",\n " } else { ", " }; - let default = ExportOptions::default(); - if self.simplify_memories != default.simplify_memories { - write!(f, "{sep}simplify_memories: {:?}", self.simplify_memories)?; - sep = comma_sep; - } - if self.simplify_enums != default.simplify_enums { - write!(f, "{sep}simplify_enums: {:?}", self.simplify_enums)?; - sep = comma_sep; - } - write!( - f, - "{sep}..ExportOptions::default(){}", - if f.alternate() { "\n}" } else { " }" } - ) - } -} - -impl Default for ExportOptions { - fn default() -> Self { - Self { - simplify_memories: true, - simplify_enums: None, - } - } -} - pub fn export( file_backend: B, top_module: &Module, - options: ExportOptions, ) -> Result { let top_module = Intern::intern_sized(top_module.canonical()); WrappedFileBackend::with(file_backend, |file_backend| { - export_impl(file_backend, top_module, options) + export_impl(file_backend, top_module) }) } #[doc(hidden)] #[track_caller] pub fn assert_export_firrtl_impl(top_module: &Module, expected: TestBackend) { - let result = export(TestBackend::default(), top_module, expected.options).unwrap(); + let result = export(TestBackend::default(), top_module).unwrap(); if result != expected { panic!( "assert_export_firrtl failed:\nyou can update the expected output by using:\n-------START-------\n{result:?}\n-------END-------" diff --git a/crates/fayalite/src/lib.rs b/crates/fayalite/src/lib.rs index 70ce724..83b61b2 100644 --- a/crates/fayalite/src/lib.rs +++ b/crates/fayalite/src/lib.rs @@ -50,5 +50,4 @@ pub mod ty; pub mod util; //pub mod valueless; pub mod prelude; -pub mod testing; pub mod wire; diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index cf85875..c817e45 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -41,12 +41,6 @@ impl fmt::Display for SimplifyEnumsError { impl std::error::Error for SimplifyEnumsError {} -impl From for std::io::Error { - fn from(value: SimplifyEnumsError) -> Self { - std::io::Error::new(std::io::ErrorKind::Other, value) - } -} - #[hdl] struct TagAndBody { tag: T, @@ -601,12 +595,10 @@ impl Folder for State { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, clap::ValueEnum)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum SimplifyEnumsKind { SimplifyToEnumsWithNoBody, - #[clap(name = "replace-with-bundle-of-uints")] ReplaceWithBundleOfUInts, - #[clap(name = "replace-with-uint")] ReplaceWithUInt, } diff --git a/crates/fayalite/src/testing.rs b/crates/fayalite/src/testing.rs deleted file mode 100644 index f887941..0000000 --- a/crates/fayalite/src/testing.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::{ - cli::{FormalArgs, FormalMode, FormalOutput, RunPhase}, - firrtl::ExportOptions, -}; -use clap::Parser; -use std::sync::OnceLock; - -fn assert_formal_helper() -> FormalArgs { - static FORMAL_ARGS: OnceLock = OnceLock::new(); - // ensure we only run parsing once, so errors from env vars don't produce overlapping output if we're called on multiple threads - FORMAL_ARGS - .get_or_init(|| FormalArgs::parse_from(["fayalite::testing::assert_formal"])) - .clone() -} - -#[track_caller] -pub fn assert_formal( - module: M, - mode: FormalMode, - depth: u64, - solver: Option<&str>, - export_options: ExportOptions, -) where - FormalArgs: RunPhase, -{ - let mut args = assert_formal_helper(); - args.verilog.firrtl.base.redirect_output_for_rust_test = true; - args.verilog.firrtl.export_options = export_options; - args.verilog.debug = true; - args.mode = mode; - args.depth = depth; - args.solver = solver.map(String::from); - args.run(module).expect("testing::assert_formal() failed"); -} diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 95f5793..5b97e3b 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -6,7 +6,6 @@ mod const_cmp; mod const_usize; mod misc; mod scoped_ref; -pub(crate) mod streaming_read_utf8; #[doc(inline)] pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool}; diff --git a/crates/fayalite/src/util/streaming_read_utf8.rs b/crates/fayalite/src/util/streaming_read_utf8.rs deleted file mode 100644 index 8de0a6a..0000000 --- a/crates/fayalite/src/util/streaming_read_utf8.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::{ - io::{self, BufRead}, - str, -}; - -pub(crate) fn streaming_read_utf8>( - reader: R, - mut callback: impl FnMut(&str) -> Result<(), E>, -) -> Result<(), E> { - let mut buf = [0; 4]; - let mut buf_len = 0; - for byte in reader.bytes() { - buf[buf_len] = byte?; - buf_len += 1; - match str::from_utf8(&buf[..buf_len]) { - Ok(buf) => { - callback(buf)?; - buf_len = 0; - } - Err(e) => { - if e.error_len().is_some() { - callback("\u{FFFD}")?; // replacement character - buf_len = 0; - } - } - } - } - Ok(()) -}