forked from libre-chip/fayalite
		
	add command line options for selecting which transforms to apply when generating firrtl
This commit is contained in:
		
							parent
							
								
									efc3a539ed
								
							
						
					
					
						commit
						bb860d54cc
					
				
					 3 changed files with 137 additions and 12 deletions
				
			
		|  | @ -2,7 +2,7 @@ | |||
| // See Notices.txt for copyright information
 | ||||
| use crate::{ | ||||
|     bundle::{Bundle, BundleType}, | ||||
|     firrtl, | ||||
|     firrtl::{self, ExportOptions}, | ||||
|     intern::Interned, | ||||
|     module::Module, | ||||
|     util::streaming_read_utf8::streaming_read_utf8, | ||||
|  | @ -98,6 +98,8 @@ impl BaseArgs { | |||
| pub struct FirrtlArgs { | ||||
|     #[command(flatten)] | ||||
|     pub base: BaseArgs, | ||||
|     #[command(flatten)] | ||||
|     pub export_options: ExportOptions, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  | @ -118,7 +120,7 @@ impl FirrtlArgs { | |||
|     fn run_impl(&self, top_module: Module<Bundle>) -> Result<FirrtlOutput> { | ||||
|         let firrtl::FileBackend { | ||||
|             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 { | ||||
|             file_stem: top_fir_file_stem.expect( | ||||
|                 "export is known to set the file stem from the circuit name if not provided", | ||||
|  |  | |||
|  | @ -18,10 +18,14 @@ use crate::{ | |||
|     intern::{Intern, Interned}, | ||||
|     memory::{Mem, PortKind, PortName, ReadUnderWrite}, | ||||
|     module::{ | ||||
|         transform::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_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, | ||||
|     }, | ||||
|     reset::{AsyncReset, Reset, SyncReset}, | ||||
|     source_location::SourceLocation, | ||||
|  | @ -32,6 +36,7 @@ use crate::{ | |||
|     }, | ||||
| }; | ||||
| use bitvec::slice::BitSlice; | ||||
| use clap::value_parser; | ||||
| use hashbrown::{HashMap, HashSet}; | ||||
| use num_traits::Signed; | ||||
| use serde::Serialize; | ||||
|  | @ -476,6 +481,7 @@ trait WrappedFileBackendTrait { | |||
|         circuit_name: String, | ||||
|         contents: String, | ||||
|     ) -> Result<(), WrappedError>; | ||||
|     fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError; | ||||
| } | ||||
| 
 | ||||
| struct WrappedFileBackend<B: FileBackendTrait> { | ||||
|  | @ -533,6 +539,11 @@ impl<B: FileBackendTrait> WrappedFileBackendTrait for WrappedFileBackend<B> { | |||
|                 WrappedError | ||||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError { | ||||
|         self.error = Err(error.into()); | ||||
|         WrappedError | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
|  | @ -2225,7 +2236,7 @@ impl<'a> Exporter<'a> { | |||
| } | ||||
| 
 | ||||
| pub trait FileBackendTrait { | ||||
|     type Error; | ||||
|     type Error: From<SimplifyEnumsError>; | ||||
|     type Path: AsRef<Self::Path> + fmt::Debug + ?Sized; | ||||
|     type PathBuf: AsRef<Self::Path> + fmt::Debug; | ||||
|     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 files: BTreeMap<String, String>, | ||||
|     pub error_after: Option<i64>, | ||||
|     pub options: ExportOptions, | ||||
|     #[doc(hidden)] | ||||
|     /// `#[non_exhaustive]` except allowing struct update syntax
 | ||||
|     pub __private: TestBackendPrivate, | ||||
|  | @ -2380,6 +2392,7 @@ impl fmt::Debug for TestBackend { | |||
|         let Self { | ||||
|             files, | ||||
|             error_after, | ||||
|             options, | ||||
|             __private: TestBackendPrivate { module_var_name }, | ||||
|         } = self; | ||||
|         writeln!( | ||||
|  | @ -2394,6 +2407,9 @@ 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, "    }};") | ||||
|     } | ||||
| } | ||||
|  | @ -2409,6 +2425,12 @@ impl fmt::Display for TestBackendError { | |||
| 
 | ||||
| impl Error for TestBackendError {} | ||||
| 
 | ||||
| impl From<SimplifyEnumsError> 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> { | ||||
|  | @ -2465,9 +2487,20 @@ impl FileBackendTrait for TestBackend { | |||
| 
 | ||||
| fn export_impl( | ||||
|     file_backend: &mut dyn WrappedFileBackendTrait, | ||||
|     top_module: Interned<Module<Bundle>>, | ||||
|     mut top_module: Interned<Module<Bundle>>, | ||||
|     options: ExportOptions, | ||||
| ) -> 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 mut global_ns = Namespace::default(); | ||||
|     let circuit_name = global_ns.get(top_module.name_id()); | ||||
|  | @ -2488,20 +2521,102 @@ 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<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>( | ||||
|     file_backend: B, | ||||
|     top_module: &Module<T>, | ||||
|     options: ExportOptions, | ||||
| ) -> Result<B, B::Error> { | ||||
|     let top_module = Intern::intern_sized(top_module.canonical()); | ||||
|     WrappedFileBackend::with(file_backend, |file_backend| { | ||||
|         export_impl(file_backend, top_module) | ||||
|         export_impl(file_backend, top_module, options) | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| #[doc(hidden)] | ||||
| #[track_caller] | ||||
| 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 { | ||||
|         panic!( | ||||
|             "assert_export_firrtl failed:\nyou can update the expected output by using:\n-------START-------\n{result:?}\n-------END-------" | ||||
|  |  | |||
|  | @ -41,6 +41,12 @@ impl fmt::Display 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] | ||||
| struct TagAndBody<T, BodyWidth: Size> { | ||||
|     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 { | ||||
|     SimplifyToEnumsWithNoBody, | ||||
|     #[clap(name = "replace-with-bundle-of-uints")] | ||||
|     ReplaceWithBundleOfUInts, | ||||
|     #[clap(name = "replace-with-uint")] | ||||
|     ReplaceWithUInt, | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue