add command line options for selecting which transforms to apply when generating firrtl

This commit is contained in:
Jacob Lifshay 2024-09-25 01:47:48 -07:00
parent efc3a539ed
commit bb860d54cc
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
3 changed files with 137 additions and 12 deletions

View file

@ -2,7 +2,7 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
bundle::{Bundle, BundleType}, bundle::{Bundle, BundleType},
firrtl, firrtl::{self, ExportOptions},
intern::Interned, intern::Interned,
module::Module, module::Module,
util::streaming_read_utf8::streaming_read_utf8, util::streaming_read_utf8::streaming_read_utf8,
@ -98,6 +98,8 @@ impl BaseArgs {
pub struct FirrtlArgs { pub struct FirrtlArgs {
#[command(flatten)] #[command(flatten)]
pub base: BaseArgs, pub base: BaseArgs,
#[command(flatten)]
pub export_options: ExportOptions,
} }
#[derive(Debug)] #[derive(Debug)]
@ -118,7 +120,7 @@ impl FirrtlArgs {
fn run_impl(&self, top_module: Module<Bundle>) -> Result<FirrtlOutput> { fn run_impl(&self, top_module: Module<Bundle>) -> Result<FirrtlOutput> {
let firrtl::FileBackend { let firrtl::FileBackend {
top_fir_file_stem, .. top_fir_file_stem, ..
} = firrtl::export(self.base.to_firrtl_file_backend(), &top_module)?; } = firrtl::export(self.base.to_firrtl_file_backend(), &top_module, self.export_options)?;
Ok(FirrtlOutput { Ok(FirrtlOutput {
file_stem: top_fir_file_stem.expect( file_stem: top_fir_file_stem.expect(
"export is known to set the file stem from the circuit name if not provided", "export is known to set the file stem from the circuit name if not provided",

View file

@ -18,10 +18,14 @@ use crate::{
intern::{Intern, Interned}, intern::{Intern, Interned},
memory::{Mem, PortKind, PortName, ReadUnderWrite}, memory::{Mem, PortKind, PortName, ReadUnderWrite},
module::{ module::{
transform::simplify_memories::simplify_memories, AnnotatedModuleIO, Block, transform::{
ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Module, ModuleBody, simplify_enums::{simplify_enums, SimplifyEnumsError, SimplifyEnumsKind},
NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtFormalKind, simplify_memories::simplify_memories,
StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, },
AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter,
ExternModuleParameterValue, Module, ModuleBody, NameId, NormalModuleBody, Stmt,
StmtConnect, StmtDeclaration, StmtFormal, StmtFormalKind, StmtIf, StmtInstance, StmtMatch,
StmtReg, StmtWire,
}, },
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, SyncReset},
source_location::SourceLocation, source_location::SourceLocation,
@ -32,6 +36,7 @@ use crate::{
}, },
}; };
use bitvec::slice::BitSlice; use bitvec::slice::BitSlice;
use clap::value_parser;
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use num_traits::Signed; use num_traits::Signed;
use serde::Serialize; use serde::Serialize;
@ -476,6 +481,7 @@ trait WrappedFileBackendTrait {
circuit_name: String, circuit_name: String,
contents: String, contents: String,
) -> Result<(), WrappedError>; ) -> Result<(), WrappedError>;
fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError;
} }
struct WrappedFileBackend<B: FileBackendTrait> { struct WrappedFileBackend<B: FileBackendTrait> {
@ -533,6 +539,11 @@ impl<B: FileBackendTrait> WrappedFileBackendTrait for WrappedFileBackend<B> {
WrappedError WrappedError
}) })
} }
fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError {
self.error = Err(error.into());
WrappedError
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -2225,7 +2236,7 @@ impl<'a> Exporter<'a> {
} }
pub trait FileBackendTrait { pub trait FileBackendTrait {
type Error; type Error: From<SimplifyEnumsError>;
type Path: AsRef<Self::Path> + fmt::Debug + ?Sized; type Path: AsRef<Self::Path> + fmt::Debug + ?Sized;
type PathBuf: AsRef<Self::Path> + fmt::Debug; type PathBuf: AsRef<Self::Path> + fmt::Debug;
fn path_to_string(&mut self, path: &Self::Path) -> Result<String, Self::Error>; fn path_to_string(&mut self, path: &Self::Path) -> Result<String, Self::Error>;
@ -2370,6 +2381,7 @@ impl Default for TestBackendPrivate {
pub struct TestBackend { pub struct TestBackend {
pub files: BTreeMap<String, String>, pub files: BTreeMap<String, String>,
pub error_after: Option<i64>, pub error_after: Option<i64>,
pub options: ExportOptions,
#[doc(hidden)] #[doc(hidden)]
/// `#[non_exhaustive]` except allowing struct update syntax /// `#[non_exhaustive]` except allowing struct update syntax
pub __private: TestBackendPrivate, pub __private: TestBackendPrivate,
@ -2380,6 +2392,7 @@ impl fmt::Debug for TestBackend {
let Self { let Self {
files, files,
error_after, error_after,
options,
__private: TestBackendPrivate { module_var_name }, __private: TestBackendPrivate { module_var_name },
} = self; } = self;
writeln!( writeln!(
@ -2394,6 +2407,9 @@ impl fmt::Debug for TestBackend {
if *error_after != Option::default() { if *error_after != Option::default() {
writeln!(f, " error_after: {error_after:?},")?; writeln!(f, " error_after: {error_after:?},")?;
} }
if *options != ExportOptions::default() {
writeln!(f, " options: {options:?},")?;
}
write!(f, " }};") write!(f, " }};")
} }
} }
@ -2409,6 +2425,12 @@ impl fmt::Display for TestBackendError {
impl Error for TestBackendError {} impl Error for TestBackendError {}
impl From<SimplifyEnumsError> for TestBackendError {
fn from(value: SimplifyEnumsError) -> Self {
TestBackendError(value.to_string())
}
}
impl TestBackend { impl TestBackend {
#[track_caller] #[track_caller]
pub fn step_error_after(&mut self, args: &dyn fmt::Debug) -> Result<(), TestBackendError> { pub fn step_error_after(&mut self, args: &dyn fmt::Debug) -> Result<(), TestBackendError> {
@ -2465,9 +2487,20 @@ impl FileBackendTrait for TestBackend {
fn export_impl( fn export_impl(
file_backend: &mut dyn WrappedFileBackendTrait, file_backend: &mut dyn WrappedFileBackendTrait,
top_module: Interned<Module<Bundle>>, mut top_module: Interned<Module<Bundle>>,
options: ExportOptions,
) -> Result<(), WrappedError> { ) -> Result<(), WrappedError> {
let top_module = simplify_memories(top_module); 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 indent_depth = Cell::new(0); let indent_depth = Cell::new(0);
let mut global_ns = Namespace::default(); let mut global_ns = Namespace::default();
let circuit_name = global_ns.get(top_module.name_id()); let circuit_name = global_ns.get(top_module.name_id());
@ -2488,20 +2521,102 @@ fn export_impl(
.run(top_module) .run(top_module)
} }
#[derive(Clone)]
struct OptionSimplifyEnumsKindValueParser;
impl OptionSimplifyEnumsKindValueParser {
const NONE_NAME: &'static str = "off";
}
impl clap::builder::TypedValueParser for OptionSimplifyEnumsKindValueParser {
type Value = Option<SimplifyEnumsKind>;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
if value == Self::NONE_NAME {
Ok(None)
} else {
Ok(Some(
value_parser!(SimplifyEnumsKind).parse_ref(cmd, arg, value)?,
))
}
}
fn possible_values(
&self,
) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
Some(Box::new(
[Self::NONE_NAME.into()]
.into_iter()
.chain(value_parser!(SimplifyEnumsKind).possible_values()?)
.collect::<Vec<_>>()
.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<SimplifyEnumsKind>,
}
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<T: BundleType, B: FileBackendTrait>( pub fn export<T: BundleType, B: FileBackendTrait>(
file_backend: B, file_backend: B,
top_module: &Module<T>, top_module: &Module<T>,
options: ExportOptions,
) -> Result<B, B::Error> { ) -> Result<B, B::Error> {
let top_module = Intern::intern_sized(top_module.canonical()); let top_module = Intern::intern_sized(top_module.canonical());
WrappedFileBackend::with(file_backend, |file_backend| { WrappedFileBackend::with(file_backend, |file_backend| {
export_impl(file_backend, top_module) export_impl(file_backend, top_module, options)
}) })
} }
#[doc(hidden)] #[doc(hidden)]
#[track_caller] #[track_caller]
pub fn assert_export_firrtl_impl<T: BundleType>(top_module: &Module<T>, expected: TestBackend) { pub fn assert_export_firrtl_impl<T: BundleType>(top_module: &Module<T>, expected: TestBackend) {
let result = export(TestBackend::default(), top_module).unwrap(); let result = export(TestBackend::default(), top_module, expected.options).unwrap();
if result != expected { if result != expected {
panic!( panic!(
"assert_export_firrtl failed:\nyou can update the expected output by using:\n-------START-------\n{result:?}\n-------END-------" "assert_export_firrtl failed:\nyou can update the expected output by using:\n-------START-------\n{result:?}\n-------END-------"

View file

@ -41,6 +41,12 @@ impl fmt::Display for SimplifyEnumsError {
impl std::error::Error for SimplifyEnumsError {} impl std::error::Error for SimplifyEnumsError {}
impl From<SimplifyEnumsError> for std::io::Error {
fn from(value: SimplifyEnumsError) -> Self {
std::io::Error::new(std::io::ErrorKind::Other, value)
}
}
#[hdl] #[hdl]
struct TagAndBody<T, BodyWidth: Size> { struct TagAndBody<T, BodyWidth: Size> {
tag: T, tag: T,
@ -595,10 +601,12 @@ impl Folder for State {
} }
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, clap::ValueEnum)]
pub enum SimplifyEnumsKind { pub enum SimplifyEnumsKind {
SimplifyToEnumsWithNoBody, SimplifyToEnumsWithNoBody,
#[clap(name = "replace-with-bundle-of-uints")]
ReplaceWithBundleOfUInts, ReplaceWithBundleOfUInts,
#[clap(name = "replace-with-uint")]
ReplaceWithUInt, ReplaceWithUInt,
} }