From c8697c4f3bda6f31fb74d4367ab3df20189ad023 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 21:08:24 -0400 Subject: [PATCH 01/47] [fud2] Make plugins optional Very minor fix: #2078 added plugins, controlled by a `plugins` key in `fud2.toml`. However, it inadvertently made this option required, i.e., fud2 would crash if this option was not present. Now it's optional! So we just silently proceed with no plugins if none are configured. --- fud2/fud-core/Cargo.toml | 2 +- fud2/fud-core/src/script/plugin.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fud2/fud-core/Cargo.toml b/fud2/fud-core/Cargo.toml index 52eae17012..ff0ae2cb8b 100644 --- a/fud2/fud-core/Cargo.toml +++ b/fud2/fud-core/Cargo.toml @@ -19,6 +19,6 @@ camino = "1.1.6" anyhow.workspace = true log.workspace = true env_logger.workspace = true -rhai = { version = "1.18.0" } +rhai = "1.18.0" once_cell = "1.19.0" ariadne = "0.4.1" diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index c42b4fa015..fd3bd3f1e3 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -47,8 +47,14 @@ impl LoadPlugins for DriverBuilder { fn load_plugins(self) -> Self { // get list of plugins let config = config::load_config(&self.name); - let plugin_files = - config.extract_inner::>("plugins").unwrap(); + let plugin_files = match config.extract_inner::>("plugins") + { + Ok(v) => v, + Err(_) => { + // No plugins to load. + return self; + } + }; // wrap driver in a ref cell, so that we can call it from a // Rhai context From da26bbcf0f9292c4e370622aed6462b22f825fd6 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 21:15:01 -0400 Subject: [PATCH 02/47] Fix a doc typo --- fud2/fud-core/src/exec/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index e5bed7ed60..8806f57d1b 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -124,7 +124,7 @@ impl Driver { } } - /// Concot a plan to carry out the requested build. + /// Concoct a plan to carry out the requested build. /// /// This works by searching for a path through the available operations from the input state /// to the output state. If no such path exists in the operation graph, we return None. From 83de16e7d8cd66d3916120a708b37aaea7201a23 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 21:22:03 -0400 Subject: [PATCH 03/47] Start refactoring plugin loading --- fud2/fud-core/src/script/plugin.rs | 36 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index fd3bd3f1e3..fcdf839166 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -40,22 +40,15 @@ fn to_setup_refs( } pub trait LoadPlugins { + /// Run the scripts in the given paths, adding them to the driver's configuration. + fn run_scripts(self, paths: &[PathBuf]) -> Self; + + /// Load all the plugins specified in the configuration file. fn load_plugins(self) -> Self; } impl LoadPlugins for DriverBuilder { - fn load_plugins(self) -> Self { - // get list of plugins - let config = config::load_config(&self.name); - let plugin_files = match config.extract_inner::>("plugins") - { - Ok(v) => v, - Err(_) => { - // No plugins to load. - return self; - } - }; - + fn run_scripts(self, paths: &[PathBuf]) -> Self { // wrap driver in a ref cell, so that we can call it from a // Rhai context let this = Rc::new(RefCell::new(self)); @@ -89,7 +82,7 @@ impl LoadPlugins for DriverBuilder { // go through each plugin file, and execute the script which adds a plugin // we need to define the following two functions in the loop because they // need the ast of the current file - for path in plugin_files { + for path in paths { // compile the file into an Ast let ast = engine.compile_file(path.clone()).unwrap(); @@ -153,4 +146,21 @@ impl LoadPlugins for DriverBuilder { Rc::into_inner(this).expect("Back into inner").into_inner() } + + fn load_plugins(self) -> Self { + // Get a list of plugins (paths to Rhai scripts) from the config file, if any. + // TODO: Let's try to avoid loading/parsing the configuration file here and + // somehow reusing it from wherever we do that elsewhere. + let config = config::load_config(&self.name); + let plugin_files = match config.extract_inner::>("plugins") + { + Ok(v) => v, + Err(_) => { + // No plugins to load. + return self; + } + }; + + self.run_scripts(&plugin_files) + } } From 28f51b14f0aea77eb0e1fc9437e7c58001b901c7 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 21:41:45 -0400 Subject: [PATCH 04/47] Start refactoring builder functions --- fud2/fud-core/src/script/plugin.rs | 50 +++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index fcdf839166..5e3ac117d1 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -39,6 +39,34 @@ fn to_setup_refs( .collect::>>() } +struct ScriptBuilder(Rc>); + +impl ScriptBuilder { + fn new(builder: DriverBuilder) -> Self { + Self(Rc::new(RefCell::new(builder))) + } + + /// Obtain the wrapped `DriverBuilder`. Panic if other references (from the + /// script, for example) still exist. + fn unwrap(self) -> DriverBuilder { + Rc::into_inner(self.0) + .expect("script references still live") + .into_inner() + } + + fn reg_state(&self, engine: &mut rhai::Engine) { + let t = self.0.clone(); + engine.register_fn( + "state", + move |name: &str, extensions: rhai::Array| { + let v = to_str_slice(&extensions); + let v = v.iter().map(|x| &**x).collect::>(); + t.borrow_mut().state(name, &v) + }, + ); + } +} + pub trait LoadPlugins { /// Run the scripts in the given paths, adding them to the driver's configuration. fn run_scripts(self, paths: &[PathBuf]) -> Self; @@ -51,7 +79,7 @@ impl LoadPlugins for DriverBuilder { fn run_scripts(self, paths: &[PathBuf]) -> Self { // wrap driver in a ref cell, so that we can call it from a // Rhai context - let this = Rc::new(RefCell::new(self)); + let bld = ScriptBuilder::new(self); // scope rhai engine code so that all references to `this` // are dropped before the end of the function @@ -59,22 +87,14 @@ impl LoadPlugins for DriverBuilder { let mut engine = rhai::Engine::new(); // register AST independent functions - let t = this.clone(); - engine.register_fn( - "state", - move |name: &str, extensions: rhai::Array| { - let v = to_str_slice(&extensions); - let v = v.iter().map(|x| &**x).collect::>(); - t.borrow_mut().state(name, &v) - }, - ); + bld.reg_state(&mut engine); - let t = Rc::clone(&this); + let t = Rc::clone(&bld.0); engine.register_fn("get_state", move |state_name: &str| { t.borrow().find_state(state_name).map_err(to_rhai_err) }); - let t = Rc::clone(&this); + let t = Rc::clone(&bld.0); engine.register_fn("get_setup", move |setup_name: &str| { t.borrow().find_setup(setup_name).map_err(to_rhai_err) }); @@ -86,7 +106,7 @@ impl LoadPlugins for DriverBuilder { // compile the file into an Ast let ast = engine.compile_file(path.clone()).unwrap(); - let t = Rc::clone(&this); + let t = Rc::clone(&bld.0); let rule_ast = ast.clone_functions_only(); let path_copy = path.clone(); engine.register_fn::<_, 4, true, OpRef, true, _>( @@ -108,7 +128,7 @@ impl LoadPlugins for DriverBuilder { }, ); - let t = Rc::clone(&this); + let t = Rc::clone(&bld.0); let rule_ast = ast.clone_functions_only(); let path_copy = path.clone(); engine.register_fn::<_, 5, true, OpRef, true, _>( @@ -144,7 +164,7 @@ impl LoadPlugins for DriverBuilder { } } - Rc::into_inner(this).expect("Back into inner").into_inner() + bld.unwrap() } fn load_plugins(self) -> Self { From 450260d180fd5ae412f8325072379179aa8ac09c Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 22:07:35 -0400 Subject: [PATCH 05/47] Refactor the rest of the functions --- fud2/fud-core/src/script/plugin.rs | 149 +++++++++++++++++------------ 1 file changed, 86 insertions(+), 63 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 5e3ac117d1..213d1093c4 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -65,6 +65,88 @@ impl ScriptBuilder { }, ); } + + fn reg_get_state(&self, engine: &mut rhai::Engine) { + let t = self.0.clone(); + engine.register_fn("get_state", move |state_name: &str| { + t.borrow().find_state(state_name).map_err(to_rhai_err) + }); + } + + fn reg_get_setup(&self, engine: &mut rhai::Engine) { + let t = self.0.clone(); + engine.register_fn("get_setup", move |setup_name: &str| { + t.borrow().find_setup(setup_name).map_err(to_rhai_err) + }); + } + + // TODO: Revisit whether these parameters can be in the struct. + fn reg_rule( + &self, + engine: &mut rhai::Engine, + path: &PathBuf, + ast: &rhai::AST, + ) { + let t = self.0.clone(); + let rule_ast = ast.clone_functions_only(); + let path_copy = path.clone(); + engine.register_fn::<_, 4, true, OpRef, true, _>( + "rule", + move |ctx: rhai::NativeCallContext, + setups: rhai::Array, + input: StateRef, + output: StateRef, + rule_name: &str| { + let setups = to_setup_refs( + &ctx, + setups, + path_copy.clone(), + rule_ast.clone(), + Rc::clone(&t), + )?; + Ok(t.borrow_mut().rule(&setups, input, output, rule_name)) + }, + ); + } + + fn reg_op( + &self, + engine: &mut rhai::Engine, + path: &PathBuf, + ast: &rhai::AST, + ) { + let t = self.0.clone(); + let rule_ast = ast.clone_functions_only(); + let path_copy = path.clone(); + engine.register_fn::<_, 5, true, OpRef, true, _>( + "op", + move |ctx: rhai::NativeCallContext, + name: &str, + setups: rhai::Array, + input: StateRef, + output: StateRef, + build: rhai::FnPtr| { + let setups = to_setup_refs( + &ctx, + setups, + path_copy.clone(), + rule_ast.clone(), + Rc::clone(&t), + )?; + Ok(t.borrow_mut().add_op( + name, + &setups, + input, + output, + RhaiSetupCtx { + path: path_copy.clone(), + ast: rule_ast.clone(), + name: build.fn_name().to_string(), + }, + )) + }, + ); + } } pub trait LoadPlugins { @@ -88,16 +170,8 @@ impl LoadPlugins for DriverBuilder { // register AST independent functions bld.reg_state(&mut engine); - - let t = Rc::clone(&bld.0); - engine.register_fn("get_state", move |state_name: &str| { - t.borrow().find_state(state_name).map_err(to_rhai_err) - }); - - let t = Rc::clone(&bld.0); - engine.register_fn("get_setup", move |setup_name: &str| { - t.borrow().find_setup(setup_name).map_err(to_rhai_err) - }); + bld.reg_get_state(&mut engine); + bld.reg_get_setup(&mut engine); // go through each plugin file, and execute the script which adds a plugin // we need to define the following two functions in the loop because they @@ -106,59 +180,8 @@ impl LoadPlugins for DriverBuilder { // compile the file into an Ast let ast = engine.compile_file(path.clone()).unwrap(); - let t = Rc::clone(&bld.0); - let rule_ast = ast.clone_functions_only(); - let path_copy = path.clone(); - engine.register_fn::<_, 4, true, OpRef, true, _>( - "rule", - move |ctx: rhai::NativeCallContext, - setups: rhai::Array, - input: StateRef, - output: StateRef, - rule_name: &str| { - let setups = to_setup_refs( - &ctx, - setups, - path_copy.clone(), - rule_ast.clone(), - Rc::clone(&t), - )?; - Ok(t.borrow_mut() - .rule(&setups, input, output, rule_name)) - }, - ); - - let t = Rc::clone(&bld.0); - let rule_ast = ast.clone_functions_only(); - let path_copy = path.clone(); - engine.register_fn::<_, 5, true, OpRef, true, _>( - "op", - move |ctx: rhai::NativeCallContext, - name: &str, - setups: rhai::Array, - input: StateRef, - output: StateRef, - build: rhai::FnPtr| { - let setups = to_setup_refs( - &ctx, - setups, - path_copy.clone(), - rule_ast.clone(), - Rc::clone(&t), - )?; - Ok(t.borrow_mut().add_op( - name, - &setups, - input, - output, - RhaiSetupCtx { - path: path_copy.clone(), - ast: rule_ast.clone(), - name: build.fn_name().to_string(), - }, - )) - }, - ); + bld.reg_rule(&mut engine, &path, &ast); + bld.reg_op(&mut engine, &path, &ast); engine.run_ast(&ast).report(&path); } From 9ee8d9a6bc6bec4b3bac96ea48b8c6485e64450c Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 22:10:34 -0400 Subject: [PATCH 06/47] Gather up a `register` function --- fud2/fud-core/src/script/plugin.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 213d1093c4..c510516b68 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -147,6 +147,20 @@ impl ScriptBuilder { }, ); } + + /// Register all the builder functions in the engine. + fn register( + &self, + engine: &mut rhai::Engine, + path: &PathBuf, + ast: &rhai::AST, + ) { + self.reg_state(engine); + self.reg_get_state(engine); + self.reg_get_setup(engine); + self.reg_rule(engine, &path, &ast); + self.reg_op(engine, &path, &ast); + } } pub trait LoadPlugins { @@ -168,20 +182,12 @@ impl LoadPlugins for DriverBuilder { { let mut engine = rhai::Engine::new(); - // register AST independent functions - bld.reg_state(&mut engine); - bld.reg_get_state(&mut engine); - bld.reg_get_setup(&mut engine); - // go through each plugin file, and execute the script which adds a plugin - // we need to define the following two functions in the loop because they - // need the ast of the current file for path in paths { // compile the file into an Ast let ast = engine.compile_file(path.clone()).unwrap(); - bld.reg_rule(&mut engine, &path, &ast); - bld.reg_op(&mut engine, &path, &ast); + bld.register(&mut engine, path, &ast); engine.run_ast(&ast).report(&path); } From 4e435f65e76893ac712a7a0c0525316bfd605068 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Jun 2024 22:13:47 -0400 Subject: [PATCH 07/47] Use a fresh engine for each plugin?? Maybe this is wasteful, but it simplifies things a lot. --- fud2/fud-core/src/script/plugin.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index c510516b68..fe3be8b595 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -177,20 +177,16 @@ impl LoadPlugins for DriverBuilder { // Rhai context let bld = ScriptBuilder::new(self); - // scope rhai engine code so that all references to `this` - // are dropped before the end of the function - { + // go through each plugin file, and execute the script which adds a plugin + for path in paths { let mut engine = rhai::Engine::new(); - // go through each plugin file, and execute the script which adds a plugin - for path in paths { - // compile the file into an Ast - let ast = engine.compile_file(path.clone()).unwrap(); + // compile the file into an Ast + let ast = engine.compile_file(path.clone()).unwrap(); - bld.register(&mut engine, path, &ast); + bld.register(&mut engine, path, &ast); - engine.run_ast(&ast).report(&path); - } + engine.run_ast(&ast).report(&path); } bld.unwrap() From 6d8f8a58930b0e1a5223dd132670acb049b3319d Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 07:39:03 -0400 Subject: [PATCH 08/47] Run one script at a time --- fud2/fud-core/src/script/plugin.rs | 34 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index fe3be8b595..ebefd69c1a 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -164,32 +164,36 @@ impl ScriptBuilder { } pub trait LoadPlugins { + fn load_script(self, path: &PathBuf) -> Self; + /// Run the scripts in the given paths, adding them to the driver's configuration. - fn run_scripts(self, paths: &[PathBuf]) -> Self; + fn load_scripts(self, paths: &[PathBuf]) -> Self; /// Load all the plugins specified in the configuration file. fn load_plugins(self) -> Self; } impl LoadPlugins for DriverBuilder { - fn run_scripts(self, paths: &[PathBuf]) -> Self { - // wrap driver in a ref cell, so that we can call it from a - // Rhai context - let bld = ScriptBuilder::new(self); + fn load_script(self, path: &PathBuf) -> Self { + let mut engine = rhai::Engine::new(); + let ast = engine.compile_file(path.clone()).unwrap(); // Compile script to AST. - // go through each plugin file, and execute the script which adds a plugin - for path in paths { - let mut engine = rhai::Engine::new(); + // Register all top-level functions. + let bld = ScriptBuilder::new(self); + bld.register(&mut engine, path, &ast); - // compile the file into an Ast - let ast = engine.compile_file(path.clone()).unwrap(); + engine.run_ast(&ast).report(&path); // Run the script. - bld.register(&mut engine, path, &ast); + std::mem::drop(engine); // Drop references to the context. + bld.unwrap() + } - engine.run_ast(&ast).report(&path); + fn load_scripts(mut self, paths: &[PathBuf]) -> Self { + // go through each plugin file, and execute the script which adds a plugin + for path in paths { + self = self.load_script(path); } - - bld.unwrap() + self } fn load_plugins(self) -> Self { @@ -206,6 +210,6 @@ impl LoadPlugins for DriverBuilder { } }; - self.run_scripts(&plugin_files) + self.load_scripts(&plugin_files) } } From c68814b24fea03304251e900ec6ae1c9eb83d5fa Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 08:05:21 -0400 Subject: [PATCH 09/47] Refector script contexts --- fud2/fud-core/src/script/plugin.rs | 171 ++++++++++++++--------------- 1 file changed, 82 insertions(+), 89 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index ebefd69c1a..2a643d926d 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -11,39 +11,60 @@ use super::{ report::RhaiReport, }; -fn to_setup_refs( - ctx: &rhai::NativeCallContext, - setups: rhai::Array, +struct ScriptContext { + builder: DriverBuilder, path: PathBuf, ast: rhai::AST, - this: Rc>, -) -> RhaiResult> { - setups - .into_iter() - .map(|s| match s.clone().try_cast::() { - Some(fnptr) => Ok(this.borrow_mut().add_setup( - &format!("{} (plugin)", fnptr.fn_name()), - RhaiSetupCtx { - path: path.clone(), - ast: ast.clone(), - name: fnptr.fn_name().to_string(), - }, - )), - // if we can't cast as a FnPtr, try casting as a SetupRef directly - None => s.clone().try_cast::().ok_or_else(move || { - RhaiSystemError::setup_ref(s) - .with_pos(ctx.position()) - .into() - }), - }) - .collect::>>() } -struct ScriptBuilder(Rc>); +impl ScriptContext { + /// Take a Rhai array value that is supposed to contain setups and produce + /// an array of actual references to setups. The array might contain string names + /// for the setups, or it might be function references that define those setups. + fn to_setup_refs( + &mut self, + ctx: &rhai::NativeCallContext, + setups: rhai::Array, + ) -> RhaiResult> { + setups + .into_iter() + .map(|s| match s.clone().try_cast::() { + Some(fnptr) => { + // TODO: Do we really need to clone stuff here, or can we continue to thread through + // the `Rc`? + let rctx = RhaiSetupCtx { + path: self.path.clone(), + ast: self.ast.clone(), + name: fnptr.fn_name().to_string(), + }; + Ok(self.builder.add_setup( + &format!("{} (plugin)", fnptr.fn_name()), + rctx, + )) + } + // if we can't cast as a FnPtr, try casting as a SetupRef directly + None => { + s.clone().try_cast::().ok_or_else(move || { + RhaiSystemError::setup_ref(s) + .with_pos(ctx.position()) + .into() + }) + } + }) + .collect::>>() + } +} + +struct ScriptContextRef(Rc>); -impl ScriptBuilder { - fn new(builder: DriverBuilder) -> Self { - Self(Rc::new(RefCell::new(builder))) +impl ScriptContextRef { + fn new(builder: DriverBuilder, path: &PathBuf, ast: &rhai::AST) -> Self { + // TODO: Consider removing the `clone`s here. We can probably just recover the stuff. + Self(Rc::new(RefCell::new(ScriptContext { + builder, + path: path.clone(), + ast: ast.clone(), + }))) } /// Obtain the wrapped `DriverBuilder`. Panic if other references (from the @@ -52,44 +73,43 @@ impl ScriptBuilder { Rc::into_inner(self.0) .expect("script references still live") .into_inner() + .builder } fn reg_state(&self, engine: &mut rhai::Engine) { - let t = self.0.clone(); + let this = self.0.clone(); engine.register_fn( "state", move |name: &str, extensions: rhai::Array| { let v = to_str_slice(&extensions); let v = v.iter().map(|x| &**x).collect::>(); - t.borrow_mut().state(name, &v) + this.borrow_mut().builder.state(name, &v) }, ); } fn reg_get_state(&self, engine: &mut rhai::Engine) { - let t = self.0.clone(); + let this = self.0.clone(); engine.register_fn("get_state", move |state_name: &str| { - t.borrow().find_state(state_name).map_err(to_rhai_err) + this.borrow() + .builder + .find_state(state_name) + .map_err(to_rhai_err) }); } fn reg_get_setup(&self, engine: &mut rhai::Engine) { - let t = self.0.clone(); + let this = self.0.clone(); engine.register_fn("get_setup", move |setup_name: &str| { - t.borrow().find_setup(setup_name).map_err(to_rhai_err) + this.borrow() + .builder + .find_setup(setup_name) + .map_err(to_rhai_err) }); } - // TODO: Revisit whether these parameters can be in the struct. - fn reg_rule( - &self, - engine: &mut rhai::Engine, - path: &PathBuf, - ast: &rhai::AST, - ) { - let t = self.0.clone(); - let rule_ast = ast.clone_functions_only(); - let path_copy = path.clone(); + fn reg_rule(&self, engine: &mut rhai::Engine) { + let this = self.0.clone(); engine.register_fn::<_, 4, true, OpRef, true, _>( "rule", move |ctx: rhai::NativeCallContext, @@ -97,27 +117,15 @@ impl ScriptBuilder { input: StateRef, output: StateRef, rule_name: &str| { - let setups = to_setup_refs( - &ctx, - setups, - path_copy.clone(), - rule_ast.clone(), - Rc::clone(&t), - )?; - Ok(t.borrow_mut().rule(&setups, input, output, rule_name)) + let mut sctx = this.borrow_mut(); + let setups = sctx.to_setup_refs(&ctx, setups)?; + Ok(sctx.builder.rule(&setups, input, output, rule_name)) }, ); } - fn reg_op( - &self, - engine: &mut rhai::Engine, - path: &PathBuf, - ast: &rhai::AST, - ) { - let t = self.0.clone(); - let rule_ast = ast.clone_functions_only(); - let path_copy = path.clone(); + fn reg_op(&self, engine: &mut rhai::Engine) { + let this = self.0.clone(); engine.register_fn::<_, 5, true, OpRef, true, _>( "op", move |ctx: rhai::NativeCallContext, @@ -126,40 +134,25 @@ impl ScriptBuilder { input: StateRef, output: StateRef, build: rhai::FnPtr| { - let setups = to_setup_refs( - &ctx, - setups, - path_copy.clone(), - rule_ast.clone(), - Rc::clone(&t), - )?; - Ok(t.borrow_mut().add_op( - name, - &setups, - input, - output, - RhaiSetupCtx { - path: path_copy.clone(), - ast: rule_ast.clone(), - name: build.fn_name().to_string(), - }, - )) + let mut sctx = this.borrow_mut(); + let setups = sctx.to_setup_refs(&ctx, setups)?; + let rctx = RhaiSetupCtx { + path: sctx.path.clone(), + ast: sctx.ast.clone(), + name: build.fn_name().to_string(), + }; + Ok(sctx.builder.add_op(name, &setups, input, output, rctx)) }, ); } /// Register all the builder functions in the engine. - fn register( - &self, - engine: &mut rhai::Engine, - path: &PathBuf, - ast: &rhai::AST, - ) { + fn register(&self, engine: &mut rhai::Engine) { self.reg_state(engine); self.reg_get_state(engine); self.reg_get_setup(engine); - self.reg_rule(engine, &path, &ast); - self.reg_op(engine, &path, &ast); + self.reg_rule(engine); + self.reg_op(engine); } } @@ -179,8 +172,8 @@ impl LoadPlugins for DriverBuilder { let ast = engine.compile_file(path.clone()).unwrap(); // Compile script to AST. // Register all top-level functions. - let bld = ScriptBuilder::new(self); - bld.register(&mut engine, path, &ast); + let bld = ScriptContextRef::new(self, path, &ast); + bld.register(&mut engine); engine.run_ast(&ast).report(&path); // Run the script. From 799ec5ce74b066e50314ebb6c02a937c42cceb2f Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 10:19:22 -0400 Subject: [PATCH 10/47] Refactor runner struct --- fud2/fud-core/src/script/plugin.rs | 46 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 2a643d926d..58409f37a4 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -55,43 +55,47 @@ impl ScriptContext { } } -struct ScriptContextRef(Rc>); +struct ScriptRunner { + ctx: Rc>, +} -impl ScriptContextRef { +impl ScriptRunner { fn new(builder: DriverBuilder, path: &PathBuf, ast: &rhai::AST) -> Self { // TODO: Consider removing the `clone`s here. We can probably just recover the stuff. - Self(Rc::new(RefCell::new(ScriptContext { - builder, - path: path.clone(), - ast: ast.clone(), - }))) + Self { + ctx: Rc::new(RefCell::new(ScriptContext { + builder, + path: path.clone(), + ast: ast.clone(), + })), + } } /// Obtain the wrapped `DriverBuilder`. Panic if other references (from the /// script, for example) still exist. - fn unwrap(self) -> DriverBuilder { - Rc::into_inner(self.0) + fn unwrap_builder(self) -> DriverBuilder { + Rc::into_inner(self.ctx) .expect("script references still live") .into_inner() .builder } fn reg_state(&self, engine: &mut rhai::Engine) { - let this = self.0.clone(); + let sctx = self.ctx.clone(); engine.register_fn( "state", move |name: &str, extensions: rhai::Array| { let v = to_str_slice(&extensions); let v = v.iter().map(|x| &**x).collect::>(); - this.borrow_mut().builder.state(name, &v) + sctx.borrow_mut().builder.state(name, &v) }, ); } fn reg_get_state(&self, engine: &mut rhai::Engine) { - let this = self.0.clone(); + let sctx = self.ctx.clone(); engine.register_fn("get_state", move |state_name: &str| { - this.borrow() + sctx.borrow() .builder .find_state(state_name) .map_err(to_rhai_err) @@ -99,9 +103,9 @@ impl ScriptContextRef { } fn reg_get_setup(&self, engine: &mut rhai::Engine) { - let this = self.0.clone(); + let sctx = self.ctx.clone(); engine.register_fn("get_setup", move |setup_name: &str| { - this.borrow() + sctx.borrow() .builder .find_setup(setup_name) .map_err(to_rhai_err) @@ -109,7 +113,7 @@ impl ScriptContextRef { } fn reg_rule(&self, engine: &mut rhai::Engine) { - let this = self.0.clone(); + let sctx = self.ctx.clone(); engine.register_fn::<_, 4, true, OpRef, true, _>( "rule", move |ctx: rhai::NativeCallContext, @@ -117,7 +121,7 @@ impl ScriptContextRef { input: StateRef, output: StateRef, rule_name: &str| { - let mut sctx = this.borrow_mut(); + let mut sctx = sctx.borrow_mut(); let setups = sctx.to_setup_refs(&ctx, setups)?; Ok(sctx.builder.rule(&setups, input, output, rule_name)) }, @@ -125,7 +129,7 @@ impl ScriptContextRef { } fn reg_op(&self, engine: &mut rhai::Engine) { - let this = self.0.clone(); + let sctx = self.ctx.clone(); engine.register_fn::<_, 5, true, OpRef, true, _>( "op", move |ctx: rhai::NativeCallContext, @@ -134,7 +138,7 @@ impl ScriptContextRef { input: StateRef, output: StateRef, build: rhai::FnPtr| { - let mut sctx = this.borrow_mut(); + let mut sctx = sctx.borrow_mut(); let setups = sctx.to_setup_refs(&ctx, setups)?; let rctx = RhaiSetupCtx { path: sctx.path.clone(), @@ -172,13 +176,13 @@ impl LoadPlugins for DriverBuilder { let ast = engine.compile_file(path.clone()).unwrap(); // Compile script to AST. // Register all top-level functions. - let bld = ScriptContextRef::new(self, path, &ast); + let bld = ScriptRunner::new(self, path, &ast); bld.register(&mut engine); engine.run_ast(&ast).report(&path); // Run the script. std::mem::drop(engine); // Drop references to the context. - bld.unwrap() + bld.unwrap_builder() } fn load_scripts(mut self, paths: &[PathBuf]) -> Self { From e3afb77fe74f27b1e77b50cbbc6eed4f358b127d Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 10:29:16 -0400 Subject: [PATCH 11/47] Further beef up the runner --- fud2/fud-core/src/script/plugin.rs | 93 +++++++++++++++++------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 58409f37a4..b456b25bf4 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -3,7 +3,11 @@ use crate::{ exec::{OpRef, SetupRef, StateRef}, DriverBuilder, }; -use std::{cell::RefCell, path::PathBuf, rc::Rc}; +use std::{ + cell::RefCell, + path::{Path, PathBuf}, + rc::Rc, +}; use super::{ error::RhaiSystemError, @@ -57,32 +61,39 @@ impl ScriptContext { struct ScriptRunner { ctx: Rc>, + engine: rhai::Engine, } impl ScriptRunner { - fn new(builder: DriverBuilder, path: &PathBuf, ast: &rhai::AST) -> Self { - // TODO: Consider removing the `clone`s here. We can probably just recover the stuff. + fn from_file(builder: DriverBuilder, path: &Path) -> Self { + // Compile the script's source code. + let engine = rhai::Engine::new(); + let ast = engine.compile_file(path.into()).unwrap(); + + // TODO: Consider removing the clones here. We can probably just recover the stuff. Self { ctx: Rc::new(RefCell::new(ScriptContext { builder, - path: path.clone(), + path: path.into(), ast: ast.clone(), })), + engine, } } /// Obtain the wrapped `DriverBuilder`. Panic if other references (from the /// script, for example) still exist. fn unwrap_builder(self) -> DriverBuilder { + std::mem::drop(self.engine); // Drop references to the context. Rc::into_inner(self.ctx) .expect("script references still live") .into_inner() .builder } - fn reg_state(&self, engine: &mut rhai::Engine) { + fn reg_state(&mut self) { let sctx = self.ctx.clone(); - engine.register_fn( + self.engine.register_fn( "state", move |name: &str, extensions: rhai::Array| { let v = to_str_slice(&extensions); @@ -92,29 +103,31 @@ impl ScriptRunner { ); } - fn reg_get_state(&self, engine: &mut rhai::Engine) { + fn reg_get_state(&mut self) { let sctx = self.ctx.clone(); - engine.register_fn("get_state", move |state_name: &str| { - sctx.borrow() - .builder - .find_state(state_name) - .map_err(to_rhai_err) - }); + self.engine + .register_fn("get_state", move |state_name: &str| { + sctx.borrow() + .builder + .find_state(state_name) + .map_err(to_rhai_err) + }); } - fn reg_get_setup(&self, engine: &mut rhai::Engine) { + fn reg_get_setup(&mut self) { let sctx = self.ctx.clone(); - engine.register_fn("get_setup", move |setup_name: &str| { - sctx.borrow() - .builder - .find_setup(setup_name) - .map_err(to_rhai_err) - }); + self.engine + .register_fn("get_setup", move |setup_name: &str| { + sctx.borrow() + .builder + .find_setup(setup_name) + .map_err(to_rhai_err) + }); } - fn reg_rule(&self, engine: &mut rhai::Engine) { + fn reg_rule(&mut self) { let sctx = self.ctx.clone(); - engine.register_fn::<_, 4, true, OpRef, true, _>( + self.engine.register_fn::<_, 4, true, OpRef, true, _>( "rule", move |ctx: rhai::NativeCallContext, setups: rhai::Array, @@ -128,9 +141,9 @@ impl ScriptRunner { ); } - fn reg_op(&self, engine: &mut rhai::Engine) { + fn reg_op(&mut self) { let sctx = self.ctx.clone(); - engine.register_fn::<_, 5, true, OpRef, true, _>( + self.engine.register_fn::<_, 5, true, OpRef, true, _>( "op", move |ctx: rhai::NativeCallContext, name: &str, @@ -151,12 +164,18 @@ impl ScriptRunner { } /// Register all the builder functions in the engine. - fn register(&self, engine: &mut rhai::Engine) { - self.reg_state(engine); - self.reg_get_state(engine); - self.reg_get_setup(engine); - self.reg_rule(engine); - self.reg_op(engine); + fn register(&mut self) { + self.reg_state(); + self.reg_get_state(); + self.reg_get_setup(); + self.reg_rule(); + self.reg_op(); + } + + /// Run the script. + fn run(&self) { + let sctx = self.ctx.borrow(); // TODO seems unnecessary? + self.engine.run_ast(&sctx.ast).report(&sctx.path); } } @@ -172,17 +191,11 @@ pub trait LoadPlugins { impl LoadPlugins for DriverBuilder { fn load_script(self, path: &PathBuf) -> Self { - let mut engine = rhai::Engine::new(); - let ast = engine.compile_file(path.clone()).unwrap(); // Compile script to AST. - // Register all top-level functions. - let bld = ScriptRunner::new(self, path, &ast); - bld.register(&mut engine); - - engine.run_ast(&ast).report(&path); // Run the script. - - std::mem::drop(engine); // Drop references to the context. - bld.unwrap_builder() + let mut runner = ScriptRunner::from_file(self, path); + runner.register(); + runner.run(); + runner.unwrap_builder() } fn load_scripts(mut self, paths: &[PathBuf]) -> Self { From a6e235ef60a62bb450208f12d2bd4c8003a10ff0 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 10:39:19 -0400 Subject: [PATCH 12/47] Further simplify interface --- fud2/fud-core/src/script/plugin.rs | 35 +++++++++++------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index b456b25bf4..c3bf0f2c28 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -177,35 +177,22 @@ impl ScriptRunner { let sctx = self.ctx.borrow(); // TODO seems unnecessary? self.engine.run_ast(&sctx.ast).report(&sctx.path); } + + /// Execute a script from a file, adding to the builder. + fn run_file(builder: DriverBuilder, path: &Path) -> DriverBuilder { + let mut runner = ScriptRunner::from_file(builder, path); + runner.register(); + runner.run(); + runner.unwrap_builder() + } } pub trait LoadPlugins { - fn load_script(self, path: &PathBuf) -> Self; - - /// Run the scripts in the given paths, adding them to the driver's configuration. - fn load_scripts(self, paths: &[PathBuf]) -> Self; - /// Load all the plugins specified in the configuration file. fn load_plugins(self) -> Self; } impl LoadPlugins for DriverBuilder { - fn load_script(self, path: &PathBuf) -> Self { - // Register all top-level functions. - let mut runner = ScriptRunner::from_file(self, path); - runner.register(); - runner.run(); - runner.unwrap_builder() - } - - fn load_scripts(mut self, paths: &[PathBuf]) -> Self { - // go through each plugin file, and execute the script which adds a plugin - for path in paths { - self = self.load_script(path); - } - self - } - fn load_plugins(self) -> Self { // Get a list of plugins (paths to Rhai scripts) from the config file, if any. // TODO: Let's try to avoid loading/parsing the configuration file here and @@ -220,6 +207,10 @@ impl LoadPlugins for DriverBuilder { } }; - self.load_scripts(&plugin_files) + let mut bld = self; + for path in plugin_files { + bld = ScriptRunner::run_file(bld, path.as_path()); + } + bld } } From 2978ff3fb03d05f26608db2c39b06c2a0f516fd9 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 10:41:23 -0400 Subject: [PATCH 13/47] Fix a borrow that lasts too long --- fud2/fud-core/src/script/plugin.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index c3bf0f2c28..383d0c08da 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -174,8 +174,12 @@ impl ScriptRunner { /// Run the script. fn run(&self) { - let sctx = self.ctx.borrow(); // TODO seems unnecessary? - self.engine.run_ast(&sctx.ast).report(&sctx.path); + // TODO this whole dance feels unnecessary... + let (ast, path) = { + let sctx = self.ctx.borrow(); + (sctx.ast.clone(), sctx.path.clone()) + }; + self.engine.run_ast(&ast).report(path); } /// Execute a script from a file, adding to the builder. From f9b97e12d17440d8aba3381bbc61dd9524191e0f Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 10:45:45 -0400 Subject: [PATCH 14/47] Fix a method name Clippy was thrown for a loop because of the `to_*` name. --- fud2/fud-core/src/script/plugin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 383d0c08da..559daea25c 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -25,7 +25,7 @@ impl ScriptContext { /// Take a Rhai array value that is supposed to contain setups and produce /// an array of actual references to setups. The array might contain string names /// for the setups, or it might be function references that define those setups. - fn to_setup_refs( + fn setups_array( &mut self, ctx: &rhai::NativeCallContext, setups: rhai::Array, @@ -135,7 +135,7 @@ impl ScriptRunner { output: StateRef, rule_name: &str| { let mut sctx = sctx.borrow_mut(); - let setups = sctx.to_setup_refs(&ctx, setups)?; + let setups = sctx.setups_array(&ctx, setups)?; Ok(sctx.builder.rule(&setups, input, output, rule_name)) }, ); @@ -152,7 +152,7 @@ impl ScriptRunner { output: StateRef, build: rhai::FnPtr| { let mut sctx = sctx.borrow_mut(); - let setups = sctx.to_setup_refs(&ctx, setups)?; + let setups = sctx.setups_array(&ctx, setups)?; let rctx = RhaiSetupCtx { path: sctx.path.clone(), ast: sctx.ast.clone(), From 242372b6a98302943cf5a7b36f77e9a36b8c58b2 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 3 Jun 2024 10:52:03 -0400 Subject: [PATCH 15/47] Move plugin loading to DriverBuilder? Now the top-level thing is in the builder itself... no need for an extra trait? Not sure this is a good idea. --- fud2/fud-core/src/exec/driver.rs | 24 +++++++++++++++++++++- fud2/fud-core/src/lib.rs | 1 - fud2/fud-core/src/script/mod.rs | 2 +- fud2/fud-core/src/script/plugin.rs | 33 ++---------------------------- fud2/src/main.rs | 2 +- 5 files changed, 27 insertions(+), 35 deletions(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 8806f57d1b..8d50df3aef 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -1,5 +1,5 @@ use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef}; -use crate::{run, utils}; +use crate::{config, run, script, utils}; use camino::{Utf8Path, Utf8PathBuf}; use cranelift_entity::{PrimaryMap, SecondaryMap}; use std::{collections::HashMap, error::Error, fmt::Display}; @@ -358,6 +358,28 @@ impl DriverBuilder { self.rsrc_files = Some(files); } + /// Load any plugin scripts specified in the configuration file. + pub fn load_plugins(self) -> Self { + // Get a list of plugins (paths to Rhai scripts) from the config file, if any. + // TODO: Let's try to avoid loading/parsing the configuration file here and + // somehow reusing it from wherever we do that elsewhere. + let config = config::load_config(&self.name); + let plugin_files = + match config.extract_inner::>("plugins") { + Ok(v) => v, + Err(_) => { + // No plugins to load. + return self; + } + }; + + let mut bld = self; + for path in plugin_files { + bld = script::ScriptRunner::run_file(bld, path.as_path()); + } + bld + } + pub fn build(self) -> Driver { Driver { name: self.name, diff --git a/fud2/fud-core/src/lib.rs b/fud2/fud-core/src/lib.rs index 632bfa3f7f..161b8463f1 100644 --- a/fud2/fud-core/src/lib.rs +++ b/fud2/fud-core/src/lib.rs @@ -6,4 +6,3 @@ pub mod script; pub mod utils; pub use exec::{Driver, DriverBuilder}; -pub use script::LoadPlugins; diff --git a/fud2/fud-core/src/script/mod.rs b/fud2/fud-core/src/script/mod.rs index f2529c4304..680571f6f1 100644 --- a/fud2/fud-core/src/script/mod.rs +++ b/fud2/fud-core/src/script/mod.rs @@ -3,4 +3,4 @@ mod exec_scripts; mod plugin; mod report; -pub use plugin::LoadPlugins; +pub use plugin::ScriptRunner; diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 559daea25c..3f3ddc483f 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -1,5 +1,4 @@ use crate::{ - config, exec::{OpRef, SetupRef, StateRef}, DriverBuilder, }; @@ -59,7 +58,7 @@ impl ScriptContext { } } -struct ScriptRunner { +pub struct ScriptRunner { ctx: Rc>, engine: rhai::Engine, } @@ -183,38 +182,10 @@ impl ScriptRunner { } /// Execute a script from a file, adding to the builder. - fn run_file(builder: DriverBuilder, path: &Path) -> DriverBuilder { + pub fn run_file(builder: DriverBuilder, path: &Path) -> DriverBuilder { let mut runner = ScriptRunner::from_file(builder, path); runner.register(); runner.run(); runner.unwrap_builder() } } - -pub trait LoadPlugins { - /// Load all the plugins specified in the configuration file. - fn load_plugins(self) -> Self; -} - -impl LoadPlugins for DriverBuilder { - fn load_plugins(self) -> Self { - // Get a list of plugins (paths to Rhai scripts) from the config file, if any. - // TODO: Let's try to avoid loading/parsing the configuration file here and - // somehow reusing it from wherever we do that elsewhere. - let config = config::load_config(&self.name); - let plugin_files = match config.extract_inner::>("plugins") - { - Ok(v) => v, - Err(_) => { - // No plugins to load. - return self; - } - }; - - let mut bld = self; - for path in plugin_files { - bld = ScriptRunner::run_file(bld, path.as_path()); - } - bld - } -} diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 68a1f49243..27bf8e8132 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -1,5 +1,5 @@ use fud2::build_driver; -use fud_core::{cli, DriverBuilder, LoadPlugins}; +use fud_core::{cli, DriverBuilder}; fn main() -> anyhow::Result<()> { let mut bld = DriverBuilder::new("fud2"); From e08ca9e3f486f2ab339e199700cbbd44a2d23e5c Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 3 Jun 2024 11:55:44 -0500 Subject: [PATCH 16/47] translate a bulk of operations into rhai --- fud2/plugins/cider.rhai | 108 +++++++++++++++++++ fud2/plugins/firrtl.rhai | 172 +++++++++++++++++++++++++++++++ fud2/plugins/primitive_uses.rhai | 12 +++ fud2/plugins/verilator.rhai | 54 ++++++++++ fud2/plugins/xilinx.rhai | 142 +++++++++++++++++++++++++ 5 files changed, 488 insertions(+) create mode 100644 fud2/plugins/cider.rhai create mode 100644 fud2/plugins/firrtl.rhai create mode 100644 fud2/plugins/primitive_uses.rhai create mode 100644 fud2/plugins/verilator.rhai create mode 100644 fud2/plugins/xilinx.rhai diff --git a/fud2/plugins/cider.rhai b/fud2/plugins/cider.rhai new file mode 100644 index 0000000000..b8cc91e3aa --- /dev/null +++ b/fud2/plugins/cider.rhai @@ -0,0 +1,108 @@ +let dbg = state("debug2", []); + +fn cider_setup(e) { + e.config_var_or( + "cider-exe", + "cider.exe", + "$calyx-base/target/debug/cider", + ); + e.config_var_or( + "cider-converter", + "cider-converter.exe", + "$calyx-base/target/debug/cider-data-converter", + ); + e.rule( + "cider", + "$cider-exe -l $calyx-base --raw --data data.json $in > $out", + ); + e.rule( + "cider-debug", + "$cider-exe -l $calyx-base --data data.json $in debug || true", + ); + e.arg("pool", "console"); + + // TODO Can we reduce the duplication around and `$python`? + e.rsrc("interp-dat.py"); + e.config_var_or("python", "python", "python3"); + e.rule("dat-to-interp", "$python interp-dat.py --to-interp $in"); + e.rule( + "interp-to-dat", + "$python interp-dat.py --from-interp $in $sim_data > $out", + ); + e.build_cmd( + ["data.json"], + "dat-to-interp", + ["$sim_data"], + ["interp-dat.py"], + ); + + e.rule( + "cider2", + "$cider-exe -l $calyx-base --data data.dump $in flat > $out", + ); + + e.rule("dump-to-interp", "$cider-converter --to cider $in > $out"); + e.rule("interp-to-dump", "$cider-converter --to json $in > $out"); + e.build_cmd( + ["data.dump"], + "dump-to-interp", + ["$sim_data"], + ["$cider-converter"], + ); +} + +let sim_setup = get_setup("RTL simulation"); +let tb_setup = get_setup("Standalone Testbench Setup"); +let calyx_setup = get_setup("Calyx compiler"); + +op( + "interp2", + [ + sim_setup, + tb_setup, + calyx_setup, + cider_setup, + ], + get_state("calyx"), + get_state("dat"), + |e, input, output| { + let out_file = "interp_out.json"; + e.build_cmd([out_file], "cider", [input], ["data.json"]); + e.build_cmd( + [output], + "interp-to-dat", + [out_file], + ["$sim_data", "interp-dat.py"], + ); + }, +); +op( + "interp-flat2", + [sim_setup, calyx_setup, cider_setup], + get_state("calyx"), + get_state("dat"), + |e, input, output| { + let out_file = "interp_out.dump"; + e.build_cmd([out_file], "cider2", [input], ["data.dump"]); + e.build_cmd( + [output], + "interp-to-dump", + [out_file], + ["$sim_data", "$cider-converter"], + ); + }, +); +op( + "debug2", + [ + sim_setup, + tb_setup, + calyx_setup, + cider_setup, + ], + get_state("calyx"), + dbg, + |e, input, output| { + e.build_cmd([output], "cider-debug", [input], ["data.json"]); + }, +); diff --git a/fud2/plugins/firrtl.rhai b/fud2/plugins/firrtl.rhai new file mode 100644 index 0000000000..7059863db2 --- /dev/null +++ b/fud2/plugins/firrtl.rhai @@ -0,0 +1,172 @@ +// setup for FIRRTL-implemented primitives +fn firrtl_primitives_setup(e) { + // Produce FIRRTL with FIRRTL-defined primitives. + e.var_( + "gen-firrtl-primitives-script", + "$calyx-base/tools/firrtl/generate-firrtl-with-primitives.py", + ); + e.rule( + "generate-firrtl-with-primitives", + "python3 $gen-firrtl-primitives-script $in > $out", + ); +} + +fn calyx_to_firrtl_helper(e, input, output, firrtl_primitives) { + // Temporary Calyx where all refs are converted into external (FIXME: fix YXI to emit for ref as well?) + let only_externals_calyx = "external.futil"; + // Temporary Calyx where all externals are converted into refs (for FIRRTL backend) + let only_refs_calyx = "ref.futil"; + // JSON with memory information created by YXI + let memories_json = "memory-info.json"; + // Custom testbench (same name as standalone testbench) + let testbench = "tb.sv"; + // Holds contents of file we want to output. Gets cat-ed via final dummy command + let tmp_out = "tmp-out.fir"; + // Convert ref into external to get YXI working (FIXME: fix YXI to emit for ref as well?) + e.build_cmd([only_externals_calyx], "ref-to-external", [input], []); + // Convert external to ref to get FIRRTL backend working + e.build_cmd([only_refs_calyx], "external-to-ref", [input], []); + + // Get YXI to generate JSON for testbench generation + e.build_cmd([memories_json], "calyx", [only_externals_calyx], []); + e.arg("backend", "yxi"); + // generate custom testbench + e.build_cmd( + [testbench], + "generate-refmem-testbench", + [memories_json], + [], + ); + + if firrtl_primitives { + let core_program_firrtl = "core.fir"; + + // Obtain FIRRTL of core program + e.build_cmd( + [core_program_firrtl], + "calyx", + [only_refs_calyx], + [], + ); + e.arg("backend", "firrtl"); + e.arg("args", "--synthesis"); + + // Obtain primitive uses JSON for metaprogramming + let primitive_uses_json = "primitive-uses.json"; + e.build_cmd( + [primitive_uses_json], + "calyx", + [only_refs_calyx], + [], + ); + e.arg("backend", "primitive-uses"); + e.arg("args", "--synthesis"); + + // run metaprogramming script to get FIRRTL with primitives + e.build_cmd( + [tmp_out], + "generate-firrtl-with-primitives", + [core_program_firrtl, primitive_uses_json], + [], + ); + } else { + // emit extmodule declarations to use Verilog primitive implementations + e.build_cmd([tmp_out], "calyx", [only_refs_calyx], []); + e.arg("backend", "firrtl"); + e.arg("args", "--emit-primitive-extmodules"); + } + + // dummy command to make sure custom testbench is created but not emitted as final answer + e.build_cmd([output], "dummy", [tmp_out, testbench], []); +} + +// Calyx to FIRRTL. +let firrtl = state("firrtl", ["fir"]); // using Verilog primitives +let firrtl_with_primitives = state("firrtl-with-primitives", ["fir"]); // using FIRRTL primitives + +let calyx = get_state("calyx"); +let calyx_setup = get_setup("Calyx compiler"); +let custom_testbench_setup = get_setup("Custom Testbench Setup"); + +op( + // use Verilog + "calyx-to-firrtl", + [calyx_setup, custom_testbench_setup], + calyx, + firrtl, + |e, input, output| calyx_to_firrtl_helper(e, input, output, false), +); + +op( + "firrtl-with-primitives", + [calyx_setup, firrtl_primitives_setup, custom_testbench_setup], + calyx, + firrtl_with_primitives, + |e, input, output| calyx_to_firrtl_helper(e, input, output, true), +); + +// The FIRRTL compiler. +fn firrtl_setup(e) { + e.config_var("firrtl-exe", "firrtl.exe"); + e.rule("firrtl", "$firrtl-exe -i $in -o $out -X sverilog"); + + e.rsrc("primitives-for-firrtl.sv"); + // adding Verilog implementations of primitives to FIRRTL --> Verilog compiled code + e.rule( + "add-verilog-primitives", + "cat primitives-for-firrtl.sv $in > $out", + ); +} + +fn firrtl_compile_helper(e, input, output, firrtl_primitives) { + if firrtl_primitives { + e.build_cmd([output], "firrtl", [input], []); + } else { + let tmp_verilog = "partial.sv"; + e.build_cmd([tmp_verilog], "firrtl", [input], []); + e.build_cmd( + [output], + "add-verilog-primitives", + [tmp_verilog], + ["primitives-for-firrtl.sv"], + ); + } +} + +// FIRRTL --> Verilog compilation using Verilog primitive implementations for Verilator +op( + "firrtl", + [firrtl_setup], + firrtl, + get_state("verilog-refmem"), + |e, input, output| firrtl_compile_helper(e, input, output, false), +); + +// FIRRTL --> Verilog compilation using Verilog primitive implementations for Icarus +// This is a bit of a hack, but the Icarus-friendly "noverify" state is identical for this path +// (since FIRRTL compilation doesn't come with verification). +op( + "firrtl-noverify", + [firrtl_setup], + firrtl, + get_state("verilog-refmem-noverify"), + |e, input, output| firrtl_compile_helper(e, input, output, false), +); + +// FIRRTL --> Verilog compilation using FIRRTL primitive implementations for Verilator +op( + "firrtl-with-primitives", + [firrtl_setup], + firrtl_with_primitives, + get_state("verilog-refmem"), + |e, input, output| firrtl_compile_helper(e, input, output, true), +); + +// FIRRTL --> Verilog compilation using FIRRTL primitive implementations for Icarus +op( + "firrtl-with-primitives-noverify", + [firrtl_setup], + firrtl_with_primitives, + get_state("verilog-refmem-noverify"), + |e, input, output| firrtl_compile_helper(e, input, output, true), +); diff --git a/fud2/plugins/primitive_uses.rhai b/fud2/plugins/primitive_uses.rhai new file mode 100644 index 0000000000..0f5cdd66b7 --- /dev/null +++ b/fud2/plugins/primitive_uses.rhai @@ -0,0 +1,12 @@ +let primitive_uses_json = state("primitive-uses-json2", ["json"]); + +op( + "primitive-uses2", + [get_setup("Calyx compiler")], + get_state("calyx"), + primitive_uses_json, + |e, input, output| { + e.build_cmd([output], "calyx", [input], []); + e.arg("backend", "primitive-uses"); + }, +); diff --git a/fud2/plugins/verilator.rhai b/fud2/plugins/verilator.rhai new file mode 100644 index 0000000000..f5de7b4a61 --- /dev/null +++ b/fud2/plugins/verilator.rhai @@ -0,0 +1,54 @@ +fn verilator_setup(e) { + e.config_var_or("verilator", "verilator.exe", "verilator"); + e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); + e.rule( + "verilator-compile-standalone-tb", + "$verilator $in tb.sv --trace --binary --top-module TOP -fno-inline -Mdir $out-dir", + ); + e.rule( + "verilator-compile-custom-tb", + "$verilator $in tb.sv memories.sv --trace --binary --top-module TOP -fno-inline -Mdir $out-dir", + ); + e.rule("cp", "cp $in $out"); +} + +fn verilator_build(e, input, output, standalone_tb) { + let out_dir = "verilator-out"; + let sim_bin = `${out_dir}/VTOP`; + if standalone_testbench { + e.build_cmd( + [sim_bin], + "verilator-compile-standalone-tb", + [input], + ["tb.sv"], + ); + } else { + e.build_cmd( + [sim_bin], + "verilator-compile-custom-tb", + [input], + ["tb.sv", "memories.sv"], + ); + } + e.arg("out-dir", out_dir); + e.build("cp", sim_bin, output); +} + +let sim_setup = get_setup("RTL simulation"); +let standalone_tb_setup = get_setup("Standalone Testbench Setup"); + +op( + "verilator2", + [sim_setup, standalone_tb_setup, verilator_setup], + get_state("verilog"), + get_state("sim"), + |e, input, output| { verilator_build(e, input, output, true) } +); + +op( + "verilator-refmem2", + [sim_setup, standalone_tb_setup, verilator_setup], + get_state("verilog-refmem"), + get_state("sim"), + |e, input, output| { verilator_build(e, input, output, false) } +); diff --git a/fud2/plugins/xilinx.rhai b/fud2/plugins/xilinx.rhai new file mode 100644 index 0000000000..a42b661a8e --- /dev/null +++ b/fud2/plugins/xilinx.rhai @@ -0,0 +1,142 @@ +let xo = state("xo", ["xo"]); +let xclbin = state("xclbin", ["xclbin"]); + +fn xilinx_setup(e) { + // Locations for Vivado and Vitis installations. + e.config_var("vivado-dir", "xilinx.vivado"); + e.config_var("vitis-dir", "xilinx.vitis"); + + // Package a Verilog program as an `.xo` file. + e.rsrc("gen_xo.tcl"); + e.rsrc("get-ports.py"); + e.config_var_or("python", "python", "python3"); + e.rule( + "gen-xo", + "$vivado-dir/bin/vivado -mode batch -source gen_xo.tcl -tclargs $out `$python get-ports.py kernel.xml`" + ); + e.arg("pool", "console"); // Lets Ninja stream the tool output "live." + + // Compile an `.xo` file to an `.xclbin` file, which is where the actual EDA work occurs. + e.config_var_or("xilinx-mode", "xilinx.mode", "hw_emu"); + e.config_var_or("platform", "xilinx.device", "xilinx_u50_gen3x16_xdma_201920_3"); + e.rule( + "compile-xclbin", + "$vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in" + ); + e.arg("pool", "console"); +}; + +let calyx = get_state("calyx"); +let calyx_setup = get_setup("Calyx compiler"); + +op( + "xo2", + [calyx_setup, xilinx_setup], + calyx, + xo, + |e, input, output| { + // Emit the Verilog itself in "synthesis mode." + e.build_cmd(["main.sv"], "calyx", [input], []); + e.arg("backend", "verilog"); + e.arg("args", "--synthesis -p external"); + + // Extra ingredients for the `.xo` package. + e.build_cmd(["toplevel.v"], "calyx", [input], []); + e.arg("backend", "xilinx"); + e.build_cmd(["kernel.xml"], "calyx", [input], []); + e.arg("backend", "xilinx-xml"); + + // Package the `.xo`. + e.build_cmd( + [output], + "gen-xo", + [], + [ + "main.sv", + "toplevel.v", + "kernel.xml", + "gen_xo.tcl", + "get-ports.py", + ], + ); + }, +); + +op("xclbin2", [xilinx_setup], xo, xclbin, |e, input, output| { + e.build_cmd([output], "compile-xclbin", [input], []); +}); + +let tb_setup = get_setup("Standalone Testbench Setup"); +let sim_setup = get_setup("RTL simulation"); + +// Xilinx execution. +// TODO Only does `hw_emu` for now... +fn xrt_setup(e) { + // Generate `emconfig.json`. + e.rule("emconfig", "$vitis-dir/bin/emconfigutil --platform $platform"); + e.build_cmd(["emconfig.json"], "emconfig", [], []); + + // Execute via the `xclrun` tool. + e.config_var("xrt-dir", "xilinx.xrt"); + e.rule( + "xclrun", + "bash -c 'source $vitis-dir/settings64.sh ; source $xrt-dir/setup.sh ; XRT_INI_PATH=$xrt_ini EMCONFIG_PATH=. XCL_EMULATION_MODE=$xilinx-mode $python -m fud.xclrun --out $out $in'" + ); + e.arg("pool", "console"); + + // "Pre-sim" and "post-sim" scripts for simulation. + e.rule("echo", "echo $contents > $out"); + e.build_cmd(["pre_sim.tcl"], "echo", [""], [""]); + e.arg("contents", "open_vcd\\\\nlog_vcd *\\\\n"); + e.build_cmd(["post_sim.tcl"], "echo", [""], [""]); + e.arg("contents", "close_vcd\\\\n"); +}; + +op( + "xrt2", + [ + xilinx_setup, + sim_setup, + tb_setup, + xrt_setup, + ], + xclbin, + get_state("dat"), + |e, input, output| { + e.rsrc("xrt.ini"); + e.build_cmd( + [output], + "xclrun", + [input, "$sim_data"], + ["emconfig.json", "xrt.ini"], + ); + e.arg("xrt_ini", "xrt.ini"); + }, +); + +op( + "xrt-trace2", + [ + xilinx_setup, + sim_setup, + tb_setup, + xrt_setup, + ], + xclbin, + get_state("vcd"), + |e, input, output| { + e.rsrc("xrt_trace.ini"); + e.build_cmd( + [output], // TODO not the VCD, yet... + "xclrun", + [input, "$sim_data"], + [ + "emconfig.json", + "pre_sim.tcl", + "post_sim.tcl", + "xrt_trace.ini", + ], + ); + e.arg("xrt_ini", "xrt_trace.ini"); + }, +); From 648d8b6bbfa6af0eae4ed9a8ffcedeb62cae3e49 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 12:21:34 -0500 Subject: [PATCH 17/47] use single engine to module resolution caching, enabling imports --- fud2/fud-core/src/exec/driver.rs | 6 +- fud2/fud-core/src/script/exec_scripts.rs | 10 +- fud2/fud-core/src/script/plugin.rs | 126 ++++++++++------------- 3 files changed, 63 insertions(+), 79 deletions(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 8d50df3aef..2d775ee4a7 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -373,11 +373,11 @@ impl DriverBuilder { } }; - let mut bld = self; + let mut runner = script::ScriptRunner::new(self); for path in plugin_files { - bld = script::ScriptRunner::run_file(bld, path.as_path()); + runner.run_file(path.as_path()); } - bld + runner.into_builder() } pub fn build(self) -> Driver { diff --git a/fud2/fud-core/src/script/exec_scripts.rs b/fud2/fud-core/src/script/exec_scripts.rs index f35afa3dff..5a0c80c860 100644 --- a/fud2/fud-core/src/script/exec_scripts.rs +++ b/fud2/fud-core/src/script/exec_scripts.rs @@ -162,10 +162,10 @@ thread_local! { }); } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(super) struct RhaiSetupCtx { - pub path: PathBuf, - pub ast: rhai::AST, + pub path: Rc, + pub ast: Rc, pub name: String, } @@ -179,7 +179,7 @@ impl EmitSetup for RhaiSetupCtx { &self.name, (rhai_emit.clone(),), ) - .report(&self.path) + .report(self.path.as_ref()) }); })?; @@ -202,7 +202,7 @@ impl EmitBuild for RhaiSetupCtx { &self.name, (rhai_emit.clone(), input.to_string(), output.to_string()), ) - .report(&self.path) + .report(self.path.as_ref()) }); })?; diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 3f3ddc483f..4bd1b3484b 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -14,10 +14,11 @@ use super::{ report::RhaiReport, }; +#[derive(Clone)] struct ScriptContext { - builder: DriverBuilder, - path: PathBuf, - ast: rhai::AST, + builder: Rc>, + path: Rc, + ast: Rc, } impl ScriptContext { @@ -25,7 +26,7 @@ impl ScriptContext { /// an array of actual references to setups. The array might contain string names /// for the setups, or it might be function references that define those setups. fn setups_array( - &mut self, + &self, ctx: &rhai::NativeCallContext, setups: rhai::Array, ) -> RhaiResult> { @@ -33,14 +34,12 @@ impl ScriptContext { .into_iter() .map(|s| match s.clone().try_cast::() { Some(fnptr) => { - // TODO: Do we really need to clone stuff here, or can we continue to thread through - // the `Rc`? let rctx = RhaiSetupCtx { - path: self.path.clone(), - ast: self.ast.clone(), + path: Rc::clone(&self.path), + ast: Rc::clone(&self.ast), name: fnptr.fn_name().to_string(), }; - Ok(self.builder.add_setup( + Ok(self.builder.borrow_mut().add_setup( &format!("{} (plugin)", fnptr.fn_name()), rctx, )) @@ -59,73 +58,59 @@ impl ScriptContext { } pub struct ScriptRunner { - ctx: Rc>, + builder: Rc>, engine: rhai::Engine, } impl ScriptRunner { - fn from_file(builder: DriverBuilder, path: &Path) -> Self { - // Compile the script's source code. - let engine = rhai::Engine::new(); - let ast = engine.compile_file(path.into()).unwrap(); - - // TODO: Consider removing the clones here. We can probably just recover the stuff. - Self { - ctx: Rc::new(RefCell::new(ScriptContext { - builder, - path: path.into(), - ast: ast.clone(), - })), - engine, - } + pub fn new(builder: DriverBuilder) -> Self { + let mut this = Self { + builder: Rc::new(RefCell::new(builder)), + engine: rhai::Engine::new(), + }; + this.reg_state(); + this.reg_get_state(); + this.reg_get_setup(); + this } - /// Obtain the wrapped `DriverBuilder`. Panic if other references (from the - /// script, for example) still exist. - fn unwrap_builder(self) -> DriverBuilder { + pub fn into_builder(self) -> DriverBuilder { std::mem::drop(self.engine); // Drop references to the context. - Rc::into_inner(self.ctx) + Rc::into_inner(self.builder) .expect("script references still live") .into_inner() - .builder } fn reg_state(&mut self) { - let sctx = self.ctx.clone(); + let bld = Rc::clone(&self.builder); self.engine.register_fn( "state", move |name: &str, extensions: rhai::Array| { let v = to_str_slice(&extensions); let v = v.iter().map(|x| &**x).collect::>(); - sctx.borrow_mut().builder.state(name, &v) + bld.borrow_mut().state(name, &v) }, ); } fn reg_get_state(&mut self) { - let sctx = self.ctx.clone(); + let bld = Rc::clone(&self.builder); self.engine .register_fn("get_state", move |state_name: &str| { - sctx.borrow() - .builder - .find_state(state_name) - .map_err(to_rhai_err) + bld.borrow().find_state(state_name).map_err(to_rhai_err) }); } fn reg_get_setup(&mut self) { - let sctx = self.ctx.clone(); + let bld = Rc::clone(&self.builder); self.engine .register_fn("get_setup", move |setup_name: &str| { - sctx.borrow() - .builder - .find_setup(setup_name) - .map_err(to_rhai_err) + bld.borrow().find_setup(setup_name).map_err(to_rhai_err) }); } - fn reg_rule(&mut self) { - let sctx = self.ctx.clone(); + fn reg_rule(&mut self, sctx: ScriptContext) { + let bld = Rc::clone(&self.builder); self.engine.register_fn::<_, 4, true, OpRef, true, _>( "rule", move |ctx: rhai::NativeCallContext, @@ -133,15 +118,14 @@ impl ScriptRunner { input: StateRef, output: StateRef, rule_name: &str| { - let mut sctx = sctx.borrow_mut(); let setups = sctx.setups_array(&ctx, setups)?; - Ok(sctx.builder.rule(&setups, input, output, rule_name)) + Ok(bld.borrow_mut().rule(&setups, input, output, rule_name)) }, ); } - fn reg_op(&mut self) { - let sctx = self.ctx.clone(); + fn reg_op(&mut self, sctx: ScriptContext) { + let bld = Rc::clone(&self.builder); self.engine.register_fn::<_, 5, true, OpRef, true, _>( "op", move |ctx: rhai::NativeCallContext, @@ -150,42 +134,42 @@ impl ScriptRunner { input: StateRef, output: StateRef, build: rhai::FnPtr| { - let mut sctx = sctx.borrow_mut(); + // let mut sctx = sctx.borrow_mut(); let setups = sctx.setups_array(&ctx, setups)?; let rctx = RhaiSetupCtx { path: sctx.path.clone(), ast: sctx.ast.clone(), name: build.fn_name().to_string(), }; - Ok(sctx.builder.add_op(name, &setups, input, output, rctx)) + Ok(bld.borrow_mut().add_op(name, &setups, input, output, rctx)) }, ); } - /// Register all the builder functions in the engine. - fn register(&mut self) { - self.reg_state(); - self.reg_get_state(); - self.reg_get_setup(); - self.reg_rule(); - self.reg_op(); - } + fn script_context(&self, path: &Path) -> ScriptContext { + let ast = self.engine.compile_file(path.into()).unwrap(); - /// Run the script. - fn run(&self) { - // TODO this whole dance feels unnecessary... - let (ast, path) = { - let sctx = self.ctx.borrow(); - (sctx.ast.clone(), sctx.path.clone()) - }; - self.engine.run_ast(&ast).report(path); + ScriptContext { + builder: Rc::clone(&self.builder), + path: Rc::new(path.to_path_buf()), + ast: Rc::new(ast.clone_functions_only()), + } } - /// Execute a script from a file, adding to the builder. - pub fn run_file(builder: DriverBuilder, path: &Path) -> DriverBuilder { - let mut runner = ScriptRunner::from_file(builder, path); - runner.register(); - runner.run(); - runner.unwrap_builder() + pub fn run_file(&mut self, path: &Path) { + let sctx = self.script_context(path); + + self.reg_rule(sctx.clone()); + self.reg_op(sctx); + + self.engine + .module_resolver() + .resolve( + &self.engine, + None, + path.to_str().unwrap(), + rhai::Position::NONE, + ) + .report(path); } } From 979b34f2aa0aa8fa1370564dc58f65067b7c4316 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 16:30:22 -0500 Subject: [PATCH 18/47] switched all plugins to use import system --- fud2/fud-core/src/script/plugin.rs | 53 ++++++++++++----------- fud2/fud-core/src/script/report.rs | 69 +++++++++++++++++------------- fud2/plugins/axi.rhai | 23 +++++++--- fud2/plugins/calyx.rhai | 27 ++++++++++-- fud2/plugins/cider.rhai | 40 ++++++++--------- fud2/plugins/dahlia-to-calyx.rhai | 6 ++- fud2/plugins/firrtl.rhai | 25 ++++++----- fud2/plugins/icarus.rhai | 46 ++++++++++++++++++++ fud2/plugins/mrxl.rhai | 6 ++- fud2/plugins/primitive_uses.rhai | 10 +++-- fud2/plugins/rtl_sim.rhai | 67 +++++++++++++++++++++++++++++ fud2/plugins/sim.rhai | 50 ---------------------- fud2/plugins/testbench.rhai | 34 +++++++++++++++ fud2/plugins/verilator.rhai | 23 +++++----- fud2/plugins/xilinx.rhai | 34 +++++++-------- 15 files changed, 333 insertions(+), 180 deletions(-) create mode 100644 fud2/plugins/icarus.rhai create mode 100644 fud2/plugins/rtl_sim.rhai delete mode 100644 fud2/plugins/sim.rhai create mode 100644 fud2/plugins/testbench.rhai diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 4bd1b3484b..721e670205 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -36,7 +36,7 @@ impl ScriptContext { Some(fnptr) => { let rctx = RhaiSetupCtx { path: Rc::clone(&self.path), - ast: Rc::clone(&self.ast), + ast: Rc::new(self.ast.clone_functions_only()), name: fnptr.fn_name().to_string(), }; Ok(self.builder.borrow_mut().add_setup( @@ -134,11 +134,10 @@ impl ScriptRunner { input: StateRef, output: StateRef, build: rhai::FnPtr| { - // let mut sctx = sctx.borrow_mut(); let setups = sctx.setups_array(&ctx, setups)?; let rctx = RhaiSetupCtx { path: sctx.path.clone(), - ast: sctx.ast.clone(), + ast: Rc::new(sctx.ast.clone_functions_only()), name: build.fn_name().to_string(), }; Ok(bld.borrow_mut().add_op(name, &setups, input, output, rctx)) @@ -146,30 +145,36 @@ impl ScriptRunner { ); } - fn script_context(&self, path: &Path) -> ScriptContext { - let ast = self.engine.compile_file(path.into()).unwrap(); - - ScriptContext { - builder: Rc::clone(&self.builder), - path: Rc::new(path.to_path_buf()), - ast: Rc::new(ast.clone_functions_only()), + fn script_context(&self, path: &Path) -> Option { + let ast = self.engine.compile_file(path.into()); + + match ast { + Ok(ast) => Some(ScriptContext { + builder: Rc::clone(&self.builder), + path: Rc::new(path.to_path_buf()), + ast: Rc::new(ast), + }), + Err(_) => { + ast.report(path); + None + } } } pub fn run_file(&mut self, path: &Path) { - let sctx = self.script_context(path); - - self.reg_rule(sctx.clone()); - self.reg_op(sctx); - - self.engine - .module_resolver() - .resolve( - &self.engine, - None, - path.to_str().unwrap(), - rhai::Position::NONE, - ) - .report(path); + if let Some(sctx) = self.script_context(path) { + self.reg_rule(sctx.clone()); + self.reg_op(sctx.clone()); + + self.engine + .module_resolver() + .resolve( + &self.engine, + None, + path.to_str().unwrap(), + rhai::Position::NONE, + ) + .report(path); + } } } diff --git a/fud2/fud-core/src/script/report.rs b/fud2/fud-core/src/script/report.rs index a44b5278dc..a7f11aafcc 100644 --- a/fud2/fud-core/src/script/report.rs +++ b/fud2/fud-core/src/script/report.rs @@ -59,42 +59,53 @@ impl RhaiReport for rhai::Position { } } -impl RhaiReport for RhaiResult { +impl RhaiReport for EvalAltResult { fn report_raw, S: AsRef>( &self, path: P, _len: usize, _msg: S, ) { - if let Err(e) = self { - match &**e { - EvalAltResult::ErrorVariableNotFound(variable, pos) => { - pos.report_raw(&path, variable.len(), "Undefined variable") - } - EvalAltResult::ErrorFunctionNotFound(msg, pos) => { - let (fn_name, args) = - msg.split_once(' ').unwrap_or((msg, "")); - pos.report_raw( - &path, - fn_name.len(), - format!("{fn_name} {args}"), - ) - } - EvalAltResult::ErrorSystem(msg, err) - if err.is::() => - { - let e = err.downcast_ref::().unwrap(); - let msg = if msg.is_empty() { - format!("{err}") - } else { - format!("{msg}: {err}") - }; - e.position.report_raw(&path, 0, msg) - } - // for errors that we don't have custom processing, just point - // to the beginning of the error, and use the error Display as message - e => e.position().report_raw(&path, 0, format!("{e}")), + match &self { + EvalAltResult::ErrorVariableNotFound(variable, pos) => { + pos.report_raw(&path, variable.len(), "Undefined variable") + } + EvalAltResult::ErrorFunctionNotFound(msg, pos) => { + let (fn_name, args) = msg.split_once(' ').unwrap_or((msg, "")); + pos.report_raw( + &path, + fn_name.len(), + format!("{fn_name} {args}"), + ) + } + EvalAltResult::ErrorSystem(msg, err) + if err.is::() => + { + let e = err.downcast_ref::().unwrap(); + let msg = if msg.is_empty() { + format!("{err}") + } else { + format!("{msg}: {err}") + }; + e.position.report_raw(&path, 0, msg) } + EvalAltResult::ErrorInModule(path, err, _) => err.report(path), + // for errors that we don't have custom processing, just point + // to the beginning of the error, and use the error Display as message + e => e.position().report_raw(&path, 0, format!("{e}")), + } + } +} + +impl RhaiReport for RhaiResult { + fn report_raw, S: AsRef>( + &self, + path: P, + len: usize, + msg: S, + ) { + if let Err(e) = self { + (**e).report_raw(path, len, msg); } } } diff --git a/fud2/plugins/axi.rhai b/fud2/plugins/axi.rhai index d37f6e6601..afdc416def 100644 --- a/fud2/plugins/axi.rhai +++ b/fud2/plugins/axi.rhai @@ -1,4 +1,17 @@ -let calyx = get_state("calyx"); +import "calyx.rhai" as c; + +export const yxi = state("yxi", ["yxi"]); + +op( + "calyx-to-yxi", + [c::calyx_setup], + c::calyx_state, + yxi, + |e, input, output| { + e.build_cmd([output], "calyx", [input], []); + e.arg("backend", "yxi"); + }, +); fn wrapper_setup(e) { e.config_var_or("axi-generator", "axi.generator", "$calyx-base/yxi/axi-calyx/axi-generator.py"); @@ -41,9 +54,9 @@ fn axi_wrapped_op(e, input, output) { } op( - "axi-wrapped2", - [get_setup("Calyx compiler"), wrapper_setup], - calyx, - calyx, + "axi-wrapped", + [c::calyx_setup, wrapper_setup], + c::calyx_state, + c::calyx_state, axi_wrapped_op ); diff --git a/fud2/plugins/calyx.rhai b/fud2/plugins/calyx.rhai index 1ac3147581..13829e2e24 100644 --- a/fud2/plugins/calyx.rhai +++ b/fud2/plugins/calyx.rhai @@ -1,3 +1,8 @@ +export const verilog_state = state("verilog", ["sv", "v"]); +export const verilog_noverify = state("verilog-noverify", ["sv"]); +export const calyx_state = state("calyx", ["futil"]); + +export let calyx_setup = calyx_setup; fn calyx_setup(e) { e.config_var("calyx-base", "calyx.base"); e.config_var_or("calyx-exe", "calyx.exe", "$calyx-base/target/debug/calyx"); @@ -7,12 +12,26 @@ fn calyx_setup(e) { } op( - "calyx2-to-verilog", + "calyx-to-verilog", [calyx_setup], - get_state("calyx"), - get_state("verilog"), + calyx_state, + verilog_state, |e, input, output| { e.build_cmd([output], "calyx", [input], []) ; e.arg("backend", "verilog"); } -) +); + + +op( + "calyx-noverify", + [calyx_setup], + calyx_state, + verilog_noverify, + |e, input, output| { + // Icarus requires a special --disable-verify version of Calyx code. + e.build_cmd([output], "calyx", [input], []); + e.arg("backend", "verilog"); + e.arg("args", "--disable-verify"); + }, +); diff --git a/fud2/plugins/cider.rhai b/fud2/plugins/cider.rhai index b8cc91e3aa..904faa188c 100644 --- a/fud2/plugins/cider.rhai +++ b/fud2/plugins/cider.rhai @@ -1,4 +1,8 @@ -let dbg = state("debug2", []); +import "rtl_sim.rhai" as sim; +import "testbench.rhai" as tb; +import "calyx.rhai" as c; + +let dbg = state("debug", []); fn cider_setup(e) { e.config_var_or( @@ -51,20 +55,16 @@ fn cider_setup(e) { ); } -let sim_setup = get_setup("RTL simulation"); -let tb_setup = get_setup("Standalone Testbench Setup"); -let calyx_setup = get_setup("Calyx compiler"); - op( - "interp2", + "interp", [ - sim_setup, - tb_setup, - calyx_setup, + sim::sim_setup, + tb::standalone_setup, + c::calyx_setup, cider_setup, ], - get_state("calyx"), - get_state("dat"), + c::calyx_state, + sim::dat, |e, input, output| { let out_file = "interp_out.json"; e.build_cmd([out_file], "cider", [input], ["data.json"]); @@ -77,10 +77,10 @@ op( }, ); op( - "interp-flat2", - [sim_setup, calyx_setup, cider_setup], - get_state("calyx"), - get_state("dat"), + "interp-flat", + [sim::sim_setup, c::calyx_setup, cider_setup], + c::calyx_state, + sim::dat, |e, input, output| { let out_file = "interp_out.dump"; e.build_cmd([out_file], "cider2", [input], ["data.dump"]); @@ -93,14 +93,14 @@ op( }, ); op( - "debug2", + "debug", [ - sim_setup, - tb_setup, - calyx_setup, + sim::sim_setup, + tb::standalone_setup, + c::calyx_setup, cider_setup, ], - get_state("calyx"), + c::calyx_state, dbg, |e, input, output| { e.build_cmd([output], "cider-debug", [input], ["data.json"]); diff --git a/fud2/plugins/dahlia-to-calyx.rhai b/fud2/plugins/dahlia-to-calyx.rhai index 0db0247ac7..95ba89f5d7 100644 --- a/fud2/plugins/dahlia-to-calyx.rhai +++ b/fud2/plugins/dahlia-to-calyx.rhai @@ -1,8 +1,10 @@ -let dahlia = state("dahlia", ["fuse"]); +import "calyx.rhai" as c; + +export const dahlia = state("dahlia", ["fuse"]); fn dahlia_setup(e) { e.config_var("dahlia-exe", "dahlia"); e.rule("dahlia-to-calyx", "$dahlia-exe -b calyx --lower -l error $in -o $out"); } -rule([dahlia_setup], dahlia, get_state("calyx"), "dahlia-to-calyx"); +rule([dahlia_setup], dahlia, c::calyx_state, "dahlia-to-calyx"); diff --git a/fud2/plugins/firrtl.rhai b/fud2/plugins/firrtl.rhai index 7059863db2..29bfc6d304 100644 --- a/fud2/plugins/firrtl.rhai +++ b/fud2/plugins/firrtl.rhai @@ -1,3 +1,6 @@ +import "calyx.rhai" as c; +import "testbench.rhai" as tb; + // setup for FIRRTL-implemented primitives fn firrtl_primitives_setup(e) { // Produce FIRRTL with FIRRTL-defined primitives. @@ -84,23 +87,23 @@ fn calyx_to_firrtl_helper(e, input, output, firrtl_primitives) { let firrtl = state("firrtl", ["fir"]); // using Verilog primitives let firrtl_with_primitives = state("firrtl-with-primitives", ["fir"]); // using FIRRTL primitives -let calyx = get_state("calyx"); -let calyx_setup = get_setup("Calyx compiler"); -let custom_testbench_setup = get_setup("Custom Testbench Setup"); +// let calyx = get_state("calyx"); +// let calyx_setup = get_setup("Calyx compiler"); +// let custom_testbench_setup = get_setup("Custom Testbench Setup"); op( // use Verilog "calyx-to-firrtl", - [calyx_setup, custom_testbench_setup], - calyx, + [c::calyx_setup, tb::custom_setup], + c::calyx_state, firrtl, |e, input, output| calyx_to_firrtl_helper(e, input, output, false), ); op( "firrtl-with-primitives", - [calyx_setup, firrtl_primitives_setup, custom_testbench_setup], - calyx, + [c::calyx_setup, firrtl_primitives_setup, tb::custom_setup], + c::calyx_state, firrtl_with_primitives, |e, input, output| calyx_to_firrtl_helper(e, input, output, true), ); @@ -138,7 +141,7 @@ op( "firrtl", [firrtl_setup], firrtl, - get_state("verilog-refmem"), + tb::verilog_refmem, |e, input, output| firrtl_compile_helper(e, input, output, false), ); @@ -149,7 +152,7 @@ op( "firrtl-noverify", [firrtl_setup], firrtl, - get_state("verilog-refmem-noverify"), + tb::verilog_refmem_noverify, |e, input, output| firrtl_compile_helper(e, input, output, false), ); @@ -158,7 +161,7 @@ op( "firrtl-with-primitives", [firrtl_setup], firrtl_with_primitives, - get_state("verilog-refmem"), + tb::verilog_refmem, |e, input, output| firrtl_compile_helper(e, input, output, true), ); @@ -167,6 +170,6 @@ op( "firrtl-with-primitives-noverify", [firrtl_setup], firrtl_with_primitives, - get_state("verilog-refmem-noverify"), + tb::verilog_refmem_noverify, |e, input, output| firrtl_compile_helper(e, input, output, true), ); diff --git a/fud2/plugins/icarus.rhai b/fud2/plugins/icarus.rhai new file mode 100644 index 0000000000..5d0dbc2a47 --- /dev/null +++ b/fud2/plugins/icarus.rhai @@ -0,0 +1,46 @@ +import "calyx.rhai" as c; +import "rtl_sim.rhai" as sim; +import "testbench.rhai" as tb; + +fn icarus_setup(e) { + e.var_("iverilog", "iverilog"); + e.rule( + "icarus-compile-standalone-tb", + "$iverilog -g2012 -o $out tb.sv $in", + ); + e.rule( + "icarus-compile-custom-tb", + "$iverilog -g2012 -o $out tb.sv memories.sv $in", + ); +} + + +op( + "icarus", + [sim::sim_setup, tb::standalone_setup, icarus_setup], + c::verilog_noverify, + sim::simulator, + |e, input, output| { + e.build_cmd( + [output], + "icarus-compile-standalone-tb", + [input], + ["tb.sv"], + ); + }, +); + +op( + "icarus-refmem", + [sim::sim_setup, icarus_setup], + tb::verilog_refmem_noverify, + sim::simulator, + |e, input, output| { + e.build_cmd( + [output], + "icarus-compile-custom-tb", + [input], + ["tb.sv", "memories.sv"], + ); + }, +); diff --git a/fud2/plugins/mrxl.rhai b/fud2/plugins/mrxl.rhai index 54487f4884..53d5cdfb36 100644 --- a/fud2/plugins/mrxl.rhai +++ b/fud2/plugins/mrxl.rhai @@ -1,8 +1,10 @@ -let mrxl = state("mrxl", ["mrxl"]); +import "calyx.rhai" as c; + +export const mrxl_state = state("mrxl", ["mrxl"]); fn mrxl_setup(e) { e.var_("mrxl-exe", "mrxl"); e.rule("mrxl-to-calyx", "$mrxl-exe $in > $out"); } -rule([mrxl_setup], mrxl, get_state("calyx"), "mrxl-to-calyx"); +rule([mrxl_setup], mrxl_state, c::calyx_state, "mrxl-to-calyx"); diff --git a/fud2/plugins/primitive_uses.rhai b/fud2/plugins/primitive_uses.rhai index 0f5cdd66b7..511a731723 100644 --- a/fud2/plugins/primitive_uses.rhai +++ b/fud2/plugins/primitive_uses.rhai @@ -1,9 +1,11 @@ -let primitive_uses_json = state("primitive-uses-json2", ["json"]); +import "calyx.rhai" as c; + +let primitive_uses_json = state("primitive-uses-json", ["json"]); op( - "primitive-uses2", - [get_setup("Calyx compiler")], - get_state("calyx"), + "primitive-uses", + [c::calyx_setup], + c::calyx_state, primitive_uses_json, |e, input, output| { e.build_cmd([output], "calyx", [input], []); diff --git a/fud2/plugins/rtl_sim.rhai b/fud2/plugins/rtl_sim.rhai new file mode 100644 index 0000000000..039c371467 --- /dev/null +++ b/fud2/plugins/rtl_sim.rhai @@ -0,0 +1,67 @@ +// This file provides fud2 operations for simulating Calyx + +export const dat = state("dat", ["json"]); +export const vcd = state("vcd", ["vcd"]); +export const simulator = state("sim", ["exe"]); + +export const sim_setup = sim_setup; + +fn sim_setup(e) { + // Data conversion to and from JSON. + e.config_var_or("python", "python", "python3"); + e.rsrc("json-dat.py"); + e.rule("hex-data", "$python json-dat.py --from-json $in $out"); + e.rule("json-data", "$python json-dat.py --to-json $out $in"); + + // The input data file. `sim.data` is required. + let data_name = e.config_val("sim.data"); + let data_path = e.external_path(data_name.as_ref()); + e.var_("sim_data", data_path.as_str()); + + // Produce the data directory. + e.var_("datadir", "sim_data"); + e.build_cmd( + ["$datadir"], + "hex-data", + ["$sim_data"], + ["json-dat.py"], + ); + + // Rule for simulation execution. + e.rule( + "sim-run", + "./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out", + ); + + // More shared configuration. + e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); +} + +op( + "simulate", + [sim_setup], + simulator, + dat, + |e, input, output| { + e.build_cmd(["sim.log"], "sim-run", [input, "$datadir"], []); + e.arg("bin", input); + e.arg("args", "+NOTRACE=1"); + e.build_cmd( + [output], + "json-data", + ["$datadir", "sim.log"], + ["json-dat.py"], + ); + }, +); + +op("trace", [sim_setup], simulator, vcd, |e, input, output| { + e.build_cmd( + ["sim.log", output], + "sim-run", + [input, "$datadir"], + [], + ); + e.arg("bin", input); + e.arg("args", `+NOTRACE=0 +OUT=${output}`); +}); diff --git a/fud2/plugins/sim.rhai b/fud2/plugins/sim.rhai deleted file mode 100644 index effcc7dc11..0000000000 --- a/fud2/plugins/sim.rhai +++ /dev/null @@ -1,50 +0,0 @@ -// This file provides fud2 operations for simulating Calyx - -fn sim_setup(e) { - e.config_var_or("python", "python", "python3"); - e.rsrc("json-dat.py"); - e.rule("hex-data", "$python json-dat.py --from-json $in $out"); - e.rule("json-data", "$python json-dat.py --to-json $out $in"); - - // The input data file. `sim.data` is a required option. - let data_name = e.config_val("sim.data"); - let data_path = e.external_path(data_name); - e.var_("sim_data", data_path); - - e.var_("datadir", "sim_data"); - e.build_cmd(["$datadir"], "hex-data", ["$sim_data"], ["json-dat.py"]); - - // Rule for simulation execution - e.rule("sim-run", "./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out"); - - e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); -} - -let simulator = get_state("sim"); -let dat = get_state("dat"); -let vcd = get_state("vcd"); - -op( - "simulate2", - [sim_setup], - simulator, - dat, - |e, input, output| { - e.build_cmd(["sim.log"], "sim-run", [input, "$datadir"], []); - e.arg("bin", input); - e.arg("args", "+NOTRACE=1"); - e.build_cmd([output], "json-data", ["$datadir", "sim.log"], ["json-dat.py"]); - } -); - -op( - "trace2", - [sim_setup], - simulator, - vcd, - |e, input, output| { - e.build_cmd(["sim.log", output], "sim-run", [input, "$datadir"], []); - e.arg("bin", input); - e.arg("args", `+NOTRACE=0 +OUT=${output}`); - } -); diff --git a/fud2/plugins/testbench.rhai b/fud2/plugins/testbench.rhai new file mode 100644 index 0000000000..c489d65e9f --- /dev/null +++ b/fud2/plugins/testbench.rhai @@ -0,0 +1,34 @@ +// Defines testbenches +export const verilog_refmem = state("verilog-refmem", ["sv"]); +export const verilog_refmem_noverify = state("verilog-refmem-noverify", ["sv"]); + +// [Default] Setup for using rsrc/tb.sv as testbench (and managing memories within the design) +export const standalone_setup = standalone_testbench_setup; +fn standalone_testbench_setup(e) { + // Standalone Verilog testbench. + e.rsrc("tb.sv"); +} + +// [Needs YXI backend compiled] Setup for creating a custom testbench (needed for FIRRTL) +export const custom_setup = custom_testbench_setup; +fn custom_testbench_setup(e) { + // Convert all ref cells to @external (FIXME: YXI should work for both?) + e.rule("ref-to-external", "sed 's/ref /@external /g' $in > $out"); + + // Convert all @external cells to ref (FIXME: we want to deprecate @external) + e.rule("external-to-ref", "sed 's/@external([0-9]*)/ref/g' $in | sed 's/@external/ref/g' > $out"); + + e.var_( + "gen-testbench-script", + "$calyx-base/tools/firrtl/generate-testbench.py", + ); + e.rsrc("memories.sv"); // Memory primitives. + + e.rule( + "generate-refmem-testbench", + "python3 $gen-testbench-script $in > $out", + ); + + // dummy rule to force ninja to build the testbench + e.rule("dummy", "sh -c 'cat $$0' $in > $out"); +}; diff --git a/fud2/plugins/verilator.rhai b/fud2/plugins/verilator.rhai index f5de7b4a61..c5cc286fb7 100644 --- a/fud2/plugins/verilator.rhai +++ b/fud2/plugins/verilator.rhai @@ -1,3 +1,7 @@ +import "rtl_sim.rhai" as sim; +import "testbench.rhai" as tb; +import "calyx.rhai" as c; + fn verilator_setup(e) { e.config_var_or("verilator", "verilator.exe", "verilator"); e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); @@ -34,21 +38,18 @@ fn verilator_build(e, input, output, standalone_tb) { e.build("cp", sim_bin, output); } -let sim_setup = get_setup("RTL simulation"); -let standalone_tb_setup = get_setup("Standalone Testbench Setup"); - op( - "verilator2", - [sim_setup, standalone_tb_setup, verilator_setup], - get_state("verilog"), - get_state("sim"), + "verilator", + [sim::sim_setup, tb::standalone_setup, verilator_setup], + c::verilog_state, + sim::simulator, |e, input, output| { verilator_build(e, input, output, true) } ); op( - "verilator-refmem2", - [sim_setup, standalone_tb_setup, verilator_setup], - get_state("verilog-refmem"), - get_state("sim"), + "verilator-refmem", + [sim::sim_setup, tb::standalone_setup, verilator_setup], + tb::verilog_refmem, + sim::simulator, |e, input, output| { verilator_build(e, input, output, false) } ); diff --git a/fud2/plugins/xilinx.rhai b/fud2/plugins/xilinx.rhai index a42b661a8e..13c3d4aeaf 100644 --- a/fud2/plugins/xilinx.rhai +++ b/fud2/plugins/xilinx.rhai @@ -1,3 +1,7 @@ +import "calyx.rhai" as c; +import "rtl_sim.rhai" as sim; +import "testbench.rhai" as tb; + let xo = state("xo", ["xo"]); let xclbin = state("xclbin", ["xclbin"]); @@ -26,13 +30,10 @@ fn xilinx_setup(e) { e.arg("pool", "console"); }; -let calyx = get_state("calyx"); -let calyx_setup = get_setup("Calyx compiler"); - op( - "xo2", - [calyx_setup, xilinx_setup], - calyx, + "xo", + [c::calyx_setup, xilinx_setup], + c::calyx_state, xo, |e, input, output| { // Emit the Verilog itself in "synthesis mode." @@ -62,13 +63,10 @@ op( }, ); -op("xclbin2", [xilinx_setup], xo, xclbin, |e, input, output| { +op("xclbin", [xilinx_setup], xo, xclbin, |e, input, output| { e.build_cmd([output], "compile-xclbin", [input], []); }); -let tb_setup = get_setup("Standalone Testbench Setup"); -let sim_setup = get_setup("RTL simulation"); - // Xilinx execution. // TODO Only does `hw_emu` for now... fn xrt_setup(e) { @@ -93,15 +91,15 @@ fn xrt_setup(e) { }; op( - "xrt2", + "xrt", [ xilinx_setup, - sim_setup, - tb_setup, + sim::sim_setup, + tb::standalone_setup, xrt_setup, ], xclbin, - get_state("dat"), + sim::dat, |e, input, output| { e.rsrc("xrt.ini"); e.build_cmd( @@ -115,15 +113,15 @@ op( ); op( - "xrt-trace2", + "xrt-trace", [ xilinx_setup, - sim_setup, - tb_setup, + sim::sim_setup, + tb::standalone_setup, xrt_setup, ], xclbin, - get_state("vcd"), + sim::dat, |e, input, output| { e.rsrc("xrt_trace.ini"); e.build_cmd( From c75e8f64e2af44054300f9875581c5edfcf7d1b6 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 16:58:35 -0500 Subject: [PATCH 19/47] include plugins in debug build --- fud2/fud-core/src/exec/driver.rs | 49 ++++++++++++++++++++++++++------ fud2/src/main.rs | 29 +++++++++++++------ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 2d775ee4a7..d9035094d5 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -2,7 +2,9 @@ use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef}; use crate::{config, run, script, utils}; use camino::{Utf8Path, Utf8PathBuf}; use cranelift_entity::{PrimaryMap, SecondaryMap}; -use std::{collections::HashMap, error::Error, fmt::Display}; +use std::{ + collections::HashMap, error::Error, ffi::OsStr, fmt::Display, path::PathBuf, +}; #[derive(PartialEq)] enum Destination { @@ -231,6 +233,8 @@ pub struct DriverBuilder { ops: PrimaryMap, rsrc_dir: Option, rsrc_files: Option, + plugin_dir: Option, + plugin_files: Option, } #[derive(Debug)] @@ -263,6 +267,8 @@ impl DriverBuilder { ops: Default::default(), rsrc_dir: None, rsrc_files: None, + plugin_dir: None, + plugin_files: None, } } @@ -358,21 +364,46 @@ impl DriverBuilder { self.rsrc_files = Some(files); } + pub fn plugin_dir(&mut self, path: &str) { + self.plugin_dir = Some(path.into()); + } + + pub fn plugin_files(&mut self, files: FileData) { + self.plugin_files = Some(files); + } + /// Load any plugin scripts specified in the configuration file. pub fn load_plugins(self) -> Self { + let mut plugin_files: Vec = vec![]; + + // load included plugins first + if let Some(plugin_dir) = &self.plugin_dir { + let paths = std::fs::read_dir(plugin_dir).unwrap(); + plugin_files.extend( + paths + // filter out invalid paths + .filter_map(|dir_entry| dir_entry.map(|p| p.path()).ok()) + // filter out paths that don't have `.rhai` extension + .filter(|p| p.extension() == Some(OsStr::new("rhai"))), + ); + } + // Get a list of plugins (paths to Rhai scripts) from the config file, if any. // TODO: Let's try to avoid loading/parsing the configuration file here and // somehow reusing it from wherever we do that elsewhere. let config = config::load_config(&self.name); - let plugin_files = - match config.extract_inner::>("plugins") { - Ok(v) => v, - Err(_) => { - // No plugins to load. - return self; - } - }; + plugin_files.extend_from_slice( + &config + .extract_inner::>("plugins") + .unwrap_or_default(), + ); + + // if we don't have any plugins, return early + if plugin_files.is_empty() { + return self; + } + // load and run plugins let mut runner = script::ScriptRunner::new(self); for path in plugin_files { runner.run_file(path.as_path()); diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 27bf8e8132..c3c49e869b 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -7,17 +7,30 @@ fn main() -> anyhow::Result<()> { // In debug mode, get resources from the source directory. #[cfg(debug_assertions)] - bld.rsrc_dir(manifest_dir_macros::directory_path!("rsrc")); + { + bld.rsrc_dir(manifest_dir_macros::directory_path!("rsrc")); + bld.plugin_dir(manifest_dir_macros::directory_path!("plugins")); + } // In release mode, embed resources into the binary. #[cfg(not(debug_assertions))] - bld.rsrc_files({ - const DIR: include_dir::Dir = - include_dir::include_dir!("$CARGO_MANIFEST_DIR/rsrc"); - DIR.files() - .map(|file| (file.path().to_str().unwrap(), file.contents())) - .collect() - }); + { + bld.rsrc_files({ + const DIR: include_dir::Dir = + include_dir::include_dir!("$CARGO_MANIFEST_DIR/rsrc"); + DIR.files() + .map(|file| (file.path().to_str().unwrap(), file.contents())) + .collect() + }); + + bld.plugin_files({ + const DIR: include_dir::Dir = + include_dir::include_dir!("$CARGO_MANIFEST_DIR/plugins"); + DIR.files() + .map(|file| (file.path().to_str().unwrap(), file.contents())) + .collect() + }); + } let driver = bld.load_plugins().build(); cli::cli(&driver) From 06838bbf00452477a68211ad46f066b49e077f84 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 20:04:41 -0500 Subject: [PATCH 20/47] we can now load scripts embedded in the binary --- fud2/fud-core/src/exec/driver.rs | 52 ++++++++------- fud2/fud-core/src/script/mod.rs | 1 + fud2/fud-core/src/script/plugin.rs | 95 ++++++++++++++++++++-------- fud2/fud-core/src/script/report.rs | 8 +-- fud2/fud-core/src/script/resolver.rs | 50 +++++++++++++++ 5 files changed, 147 insertions(+), 59 deletions(-) create mode 100644 fud2/fud-core/src/script/resolver.rs diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index d9035094d5..63b0b26dd8 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -2,9 +2,7 @@ use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef}; use crate::{config, run, script, utils}; use camino::{Utf8Path, Utf8PathBuf}; use cranelift_entity::{PrimaryMap, SecondaryMap}; -use std::{ - collections::HashMap, error::Error, ffi::OsStr, fmt::Display, path::PathBuf, -}; +use std::{collections::HashMap, error::Error, ffi::OsStr, fmt::Display}; #[derive(PartialEq)] enum Destination { @@ -374,13 +372,21 @@ impl DriverBuilder { /// Load any plugin scripts specified in the configuration file. pub fn load_plugins(self) -> Self { - let mut plugin_files: Vec = vec![]; + // pull out things from self that we need + let plugin_dir = self.plugin_dir.clone(); + // TODO: find a way around this clone + let plugin_files = self.plugin_files.clone(); + // TODO: Let's try to avoid loading/parsing the configuration file here and + // somehow reusing it from wherever we do that elsewhere. + let config = config::load_config(&self.name); + + let mut runner = script::ScriptRunner::new(self); - // load included plugins first - if let Some(plugin_dir) = &self.plugin_dir { - let paths = std::fs::read_dir(plugin_dir).unwrap(); - plugin_files.extend( - paths + // add system plugins + if let Some(plugin_dir) = plugin_dir { + runner.add_files( + std::fs::read_dir(plugin_dir) + .unwrap() // filter out invalid paths .filter_map(|dir_entry| dir_entry.map(|p| p.path()).ok()) // filter out paths that don't have `.rhai` extension @@ -388,27 +394,19 @@ impl DriverBuilder { ); } - // Get a list of plugins (paths to Rhai scripts) from the config file, if any. - // TODO: Let's try to avoid loading/parsing the configuration file here and - // somehow reusing it from wherever we do that elsewhere. - let config = config::load_config(&self.name); - plugin_files.extend_from_slice( - &config - .extract_inner::>("plugins") - .unwrap_or_default(), - ); - - // if we don't have any plugins, return early - if plugin_files.is_empty() { - return self; + // add static plugins (where string is included in binary) + if let Some(plugin_files) = plugin_files { + runner.add_static_files(plugin_files.into_iter()); } - // load and run plugins - let mut runner = script::ScriptRunner::new(self); - for path in plugin_files { - runner.run_file(path.as_path()); + // add user plugins defined in config + if let Ok(plugins) = + config.extract_inner::>("plugins") + { + runner.add_files(plugins.into_iter()); } - runner.into_builder() + + runner.run() } pub fn build(self) -> Driver { diff --git a/fud2/fud-core/src/script/mod.rs b/fud2/fud-core/src/script/mod.rs index 680571f6f1..23e4244777 100644 --- a/fud2/fud-core/src/script/mod.rs +++ b/fud2/fud-core/src/script/mod.rs @@ -2,5 +2,6 @@ mod error; mod exec_scripts; mod plugin; mod report; +mod resolver; pub use plugin::ScriptRunner; diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 721e670205..813f5dc553 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -4,6 +4,7 @@ use crate::{ }; use std::{ cell::RefCell, + collections::HashMap, path::{Path, PathBuf}, rc::Rc, }; @@ -12,6 +13,7 @@ use super::{ error::RhaiSystemError, exec_scripts::{to_rhai_err, to_str_slice, RhaiResult, RhaiSetupCtx}, report::RhaiReport, + resolver::Resolver, }; #[derive(Clone)] @@ -60,6 +62,7 @@ impl ScriptContext { pub struct ScriptRunner { builder: Rc>, engine: rhai::Engine, + files: HashMap, } impl ScriptRunner { @@ -67,6 +70,7 @@ impl ScriptRunner { let mut this = Self { builder: Rc::new(RefCell::new(builder)), engine: rhai::Engine::new(), + files: HashMap::default(), }; this.reg_state(); this.reg_get_state(); @@ -74,7 +78,35 @@ impl ScriptRunner { this } - pub fn into_builder(self) -> DriverBuilder { + pub fn add_files( + &mut self, + files: impl Iterator, + ) -> &mut Self { + self.files.extend(files.map(|f| { + ( + f.file_name().unwrap().into(), + self.engine.compile_file(f).unwrap(), + ) + })); + self + } + + pub fn add_static_files( + &mut self, + static_files: impl Iterator, + ) -> &mut Self { + self.files.extend(static_files.map(|(name, data)| { + ( + PathBuf::from(name), + self.engine + .compile(String::from_utf8(data.to_vec()).unwrap()) + .unwrap(), + ) + })); + self + } + + fn into_builder(self) -> DriverBuilder { std::mem::drop(self.engine); // Drop references to the context. Rc::into_inner(self.builder) .expect("script references still live") @@ -145,36 +177,43 @@ impl ScriptRunner { ); } - fn script_context(&self, path: &Path) -> Option { - let ast = self.engine.compile_file(path.into()); - - match ast { - Ok(ast) => Some(ScriptContext { - builder: Rc::clone(&self.builder), - path: Rc::new(path.to_path_buf()), - ast: Rc::new(ast), - }), - Err(_) => { - ast.report(path); - None - } + fn script_context(&self, path: PathBuf, ast: rhai::AST) -> ScriptContext { + ScriptContext { + builder: Rc::clone(&self.builder), + path: Rc::new(path), + ast: Rc::new(ast), } } - pub fn run_file(&mut self, path: &Path) { - if let Some(sctx) = self.script_context(path) { - self.reg_rule(sctx.clone()); - self.reg_op(sctx.clone()); - - self.engine - .module_resolver() - .resolve( - &self.engine, - None, - path.to_str().unwrap(), - rhai::Position::NONE, - ) - .report(path); + fn run_file(&mut self, path: &Path, ast: rhai::AST) { + let sctx = self.script_context(path.to_path_buf(), ast); + self.reg_rule(sctx.clone()); + self.reg_op(sctx.clone()); + + self.engine + .module_resolver() + .resolve( + &self.engine, + None, + path.to_str().unwrap(), + rhai::Position::NONE, + ) + .report(path); + } + + pub fn run(mut self) -> DriverBuilder { + self.engine + .set_module_resolver(Resolver::new(self.files.clone())); + + let files: Vec<_> = self + .files + .iter() + .map(|(p, a)| (p.clone(), a.clone())) + .collect(); + for (p, ast) in files { + self.run_file(p.as_path(), ast); } + + self.into_builder() } } diff --git a/fud2/fud-core/src/script/report.rs b/fud2/fud-core/src/script/report.rs index a7f11aafcc..c4bee181b9 100644 --- a/fud2/fud-core/src/script/report.rs +++ b/fud2/fud-core/src/script/report.rs @@ -24,11 +24,11 @@ impl RhaiReport for rhai::Position { len: usize, msg: S, ) { - let source = - fs::read_to_string(path.as_ref()).expect("Failed to open file"); + println!("path: {:?}", path.as_ref()); + let source = fs::read_to_string(path.as_ref()); let name = path.as_ref().to_str().unwrap(); - if let Some(line) = self.line() { + if let (Some(line), Ok(source)) = (self.line(), source) { let position = self.position().unwrap_or(1); // translate a line offset into a char offset let line_offset = source @@ -54,7 +54,7 @@ impl RhaiReport for rhai::Position { .unwrap() } else { eprintln!("Failed to load plugin {name}"); - eprintln!(" {}", msg.as_ref()); + eprintln!(" {} @ {}", msg.as_ref(), self); } } } diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs new file mode 100644 index 0000000000..5af3009c80 --- /dev/null +++ b/fud2/fud-core/src/script/resolver.rs @@ -0,0 +1,50 @@ +use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc}; + +use super::{exec_scripts::RhaiResult, report::RhaiReport}; + +pub(super) struct Resolver { + files: HashMap, + modules: RefCell>>, +} + +impl Resolver { + pub(super) fn new(files: HashMap) -> Self { + Self { + files, + modules: RefCell::new(HashMap::default()), + } + } + + fn get(&self, path: &PathBuf) -> Option> { + self.modules.borrow().get(path).map(Rc::clone) + } +} + +impl rhai::ModuleResolver for Resolver { + fn resolve( + &self, + engine: &rhai::Engine, + _source: Option<&str>, + path: &str, + _pos: rhai::Position, + ) -> RhaiResult> { + let path_buf = PathBuf::from(path); + + if let Some(module) = self.get(&path_buf) { + Ok(module) + } else { + let new_module = rhai::Module::eval_ast_as_new( + rhai::Scope::new(), + &self.files[&path_buf], + engine, + ) + .map(Rc::new) + .inspect_err(|e| e.report(&path_buf))?; + + self.modules + .borrow_mut() + .insert(path_buf, Rc::clone(&new_module)); + Ok(new_module) + } + } +} From 0c1705c04cac5ea7f6ec3ac03296ff0e5f48290f Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 20:26:47 -0500 Subject: [PATCH 21/47] if a module fails once, don't retry it --- fud2/fud-core/src/script/report.rs | 8 ++- fud2/fud-core/src/script/resolver.rs | 74 ++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/fud2/fud-core/src/script/report.rs b/fud2/fud-core/src/script/report.rs index c4bee181b9..b8a35824cf 100644 --- a/fud2/fud-core/src/script/report.rs +++ b/fud2/fud-core/src/script/report.rs @@ -24,7 +24,6 @@ impl RhaiReport for rhai::Position { len: usize, msg: S, ) { - println!("path: {:?}", path.as_ref()); let source = fs::read_to_string(path.as_ref()); let name = path.as_ref().to_str().unwrap(); @@ -54,7 +53,12 @@ impl RhaiReport for rhai::Position { .unwrap() } else { eprintln!("Failed to load plugin {name}"); - eprintln!(" {} @ {}", msg.as_ref(), self); + let pos_str = if self.is_none() { + "".to_string() + } else { + format!(" @ {self}") + }; + eprintln!(" {}{pos_str}", msg.as_ref()); } } } diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs index 5af3009c80..8fc18449f0 100644 --- a/fud2/fud-core/src/script/resolver.rs +++ b/fud2/fud-core/src/script/resolver.rs @@ -1,23 +1,70 @@ -use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc}; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + error::Error, + fmt::Display, + path::PathBuf, + rc::Rc, +}; + +use rhai::EvalAltResult; use super::{exec_scripts::RhaiResult, report::RhaiReport}; +#[derive(Default)] pub(super) struct Resolver { files: HashMap, modules: RefCell>>, + failed: RefCell>, +} + +#[derive(Debug)] +enum ResolverError { + Failed(String), } +impl Display for ResolverError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ResolverError::Failed(m) => write!(f, "Loading {m} failed."), + } + } +} + +impl Error for ResolverError {} + impl Resolver { pub(super) fn new(files: HashMap) -> Self { Self { files, - modules: RefCell::new(HashMap::default()), + ..Default::default() } } fn get(&self, path: &PathBuf) -> Option> { self.modules.borrow().get(path).map(Rc::clone) } + + fn insert(&self, path: PathBuf, module: rhai::Module) -> Rc { + let rc_mod = Rc::new(module); + self.modules.borrow_mut().insert(path, Rc::clone(&rc_mod)); + rc_mod + } + + fn did_fail(&self, path: &PathBuf) -> RhaiResult<()> { + if self.failed.borrow().contains(path) { + Err(Box::new(EvalAltResult::ErrorSystem( + "Failed module loading".to_string(), + Box::new(ResolverError::Failed(format!("{path:?}"))), + ))) + } else { + Ok(()) + } + } + + fn add_failed(&self, path: PathBuf) { + self.failed.borrow_mut().insert(path); + } } impl rhai::ModuleResolver for Resolver { @@ -30,21 +77,28 @@ impl rhai::ModuleResolver for Resolver { ) -> RhaiResult> { let path_buf = PathBuf::from(path); + // if this path has already failed, don't try loading it again + self.did_fail(&path_buf)?; + + // return the module of a path if we have already loaded it if let Some(module) = self.get(&path_buf) { Ok(module) } else { + // otherwise, make a new module, cache it, and return it let new_module = rhai::Module::eval_ast_as_new( rhai::Scope::new(), &self.files[&path_buf], engine, - ) - .map(Rc::new) - .inspect_err(|e| e.report(&path_buf))?; - - self.modules - .borrow_mut() - .insert(path_buf, Rc::clone(&new_module)); - Ok(new_module) + ); + + match new_module { + Ok(n) => Ok(self.insert(path_buf, n)), + Err(e) => { + e.report(&path_buf); + self.add_failed(path_buf); + Err(e) + } + } } } } From 36524bd775b8f5f0f52bfde6efc06811f7e5404b Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 20:34:58 -0500 Subject: [PATCH 22/47] sort states and operations in list mode --- Cargo.lock | 1 + fud2/fud-core/Cargo.toml | 1 + fud2/fud-core/src/exec/driver.rs | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ede71d979..3cf9bd5413 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,6 +1160,7 @@ dependencies = [ "cranelift-entity", "env_logger", "figment", + "itertools 0.11.0", "log", "once_cell", "pathdiff", diff --git a/fud2/fud-core/Cargo.toml b/fud2/fud-core/Cargo.toml index ff0ae2cb8b..97b5107a24 100644 --- a/fud2/fud-core/Cargo.toml +++ b/fud2/fud-core/Cargo.toml @@ -22,3 +22,4 @@ env_logger.workspace = true rhai = "1.18.0" once_cell = "1.19.0" ariadne = "0.4.1" +itertools.workspace = true diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 63b0b26dd8..8de8dd4c7b 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -2,6 +2,7 @@ use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef}; use crate::{config, run, script, utils}; use camino::{Utf8Path, Utf8PathBuf}; use cranelift_entity::{PrimaryMap, SecondaryMap}; +use itertools::Itertools; use std::{collections::HashMap, error::Error, ffi::OsStr, fmt::Display}; #[derive(PartialEq)] @@ -203,7 +204,9 @@ impl Driver { /// Print a list of registered states and operations to stdout. pub fn print_info(&self) { println!("States:"); - for (_, state) in self.states.iter() { + for (_, state) in + self.states.iter().sorted_by_key(|(_, state)| &state.name) + { print!(" {}:", state.name); for ext in &state.extensions { print!(" .{}", ext); @@ -213,7 +216,7 @@ impl Driver { println!(); println!("Operations:"); - for (_, op) in self.ops.iter() { + for (_, op) in self.ops.iter().sorted_by_key(|(_, op)| &op.name) { println!( " {}: {} -> {}", op.name, From 503d42b1690e9fd85d679abde7918cd56c77fb65 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 4 Jun 2024 20:35:32 -0500 Subject: [PATCH 23/47] migrate entirely to plugins --- fud2/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fud2/src/main.rs b/fud2/src/main.rs index c3c49e869b..40404a7d94 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -1,9 +1,8 @@ -use fud2::build_driver; use fud_core::{cli, DriverBuilder}; fn main() -> anyhow::Result<()> { let mut bld = DriverBuilder::new("fud2"); - build_driver(&mut bld); + // build_driver(&mut bld); // In debug mode, get resources from the source directory. #[cfg(debug_assertions)] From ea67bb837eb75b3de143dca088b0b6a62ef3e3c5 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Wed, 5 Jun 2024 09:28:25 -0500 Subject: [PATCH 24/47] gate migration behind a feature --- fud2/Cargo.toml | 4 ++++ fud2/src/main.rs | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/fud2/Cargo.toml b/fud2/Cargo.toml index 85d9af2a51..86a5e070ea 100644 --- a/fud2/Cargo.toml +++ b/fud2/Cargo.toml @@ -12,6 +12,10 @@ readme = "README.md" categories = ["build-tool"] description = "Compiler driver for the Calyx infrastructure" +[features] +migrate_to_scripts = [] +default = [] + [dependencies] fud-core = { path = "fud-core", version = "0.0.2" } anyhow.workspace = true diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 40404a7d94..85d17ee052 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -2,12 +2,16 @@ use fud_core::{cli, DriverBuilder}; fn main() -> anyhow::Result<()> { let mut bld = DriverBuilder::new("fud2"); - // build_driver(&mut bld); + + #[cfg(not(feature = "migrate_to_scripts"))] + fud2::build_driver(&mut bld); // In debug mode, get resources from the source directory. #[cfg(debug_assertions)] { bld.rsrc_dir(manifest_dir_macros::directory_path!("rsrc")); + + #[cfg(feature = "migrate_to_scripts")] bld.plugin_dir(manifest_dir_macros::directory_path!("plugins")); } @@ -22,6 +26,7 @@ fn main() -> anyhow::Result<()> { .collect() }); + #[cfg(feature = "migrate_to_scripts")] bld.plugin_files({ const DIR: include_dir::Dir = include_dir::include_dir!("$CARGO_MANIFEST_DIR/plugins"); @@ -31,6 +36,11 @@ fn main() -> anyhow::Result<()> { }); } - let driver = bld.load_plugins().build(); + #[cfg(feature = "migrate_to_scripts")] + { + bld = bld.load_plugins(); + } + + let driver = bld.build(); cli::cli(&driver) } From 51f78e9beb77cae5780b7485656e811cf295c28d Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Wed, 5 Jun 2024 09:29:06 -0500 Subject: [PATCH 25/47] move sorting to when we run files --- fud2/fud-core/src/exec/driver.rs | 7 ++----- fud2/fud-core/src/script/plugin.rs | 3 +++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 8de8dd4c7b..63b0b26dd8 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -2,7 +2,6 @@ use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef}; use crate::{config, run, script, utils}; use camino::{Utf8Path, Utf8PathBuf}; use cranelift_entity::{PrimaryMap, SecondaryMap}; -use itertools::Itertools; use std::{collections::HashMap, error::Error, ffi::OsStr, fmt::Display}; #[derive(PartialEq)] @@ -204,9 +203,7 @@ impl Driver { /// Print a list of registered states and operations to stdout. pub fn print_info(&self) { println!("States:"); - for (_, state) in - self.states.iter().sorted_by_key(|(_, state)| &state.name) - { + for (_, state) in self.states.iter() { print!(" {}:", state.name); for ext in &state.extensions { print!(" .{}", ext); @@ -216,7 +213,7 @@ impl Driver { println!(); println!("Operations:"); - for (_, op) in self.ops.iter().sorted_by_key(|(_, op)| &op.name) { + for (_, op) in self.ops.iter() { println!( " {}: {} -> {}", op.name, diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index 813f5dc553..a709d088d9 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -1,3 +1,5 @@ +use itertools::Itertools; + use crate::{ exec::{OpRef, SetupRef, StateRef}, DriverBuilder, @@ -208,6 +210,7 @@ impl ScriptRunner { let files: Vec<_> = self .files .iter() + .sorted_by_key(|&(p, _)| p) .map(|(p, a)| (p.clone(), a.clone())) .collect(); for (p, ast) in files { From 86e2b58dde0d5bb211c107aae009c1dec5c5feaa Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Wed, 5 Jun 2024 09:31:29 -0500 Subject: [PATCH 26/47] rename plugins to scripts internally --- fud2/fud-core/src/exec/driver.rs | 20 ++++++++++---------- fud2/src/main.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 63b0b26dd8..72e7242488 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -231,8 +231,8 @@ pub struct DriverBuilder { ops: PrimaryMap, rsrc_dir: Option, rsrc_files: Option, - plugin_dir: Option, - plugin_files: Option, + scripts_dir: Option, + scripts_files: Option, } #[derive(Debug)] @@ -265,8 +265,8 @@ impl DriverBuilder { ops: Default::default(), rsrc_dir: None, rsrc_files: None, - plugin_dir: None, - plugin_files: None, + scripts_dir: None, + scripts_files: None, } } @@ -362,20 +362,20 @@ impl DriverBuilder { self.rsrc_files = Some(files); } - pub fn plugin_dir(&mut self, path: &str) { - self.plugin_dir = Some(path.into()); + pub fn scripts_dir(&mut self, path: &str) { + self.scripts_dir = Some(path.into()); } - pub fn plugin_files(&mut self, files: FileData) { - self.plugin_files = Some(files); + pub fn scripts_files(&mut self, files: FileData) { + self.scripts_files = Some(files); } /// Load any plugin scripts specified in the configuration file. pub fn load_plugins(self) -> Self { // pull out things from self that we need - let plugin_dir = self.plugin_dir.clone(); + let plugin_dir = self.scripts_dir.clone(); // TODO: find a way around this clone - let plugin_files = self.plugin_files.clone(); + let plugin_files = self.scripts_files.clone(); // TODO: Let's try to avoid loading/parsing the configuration file here and // somehow reusing it from wherever we do that elsewhere. let config = config::load_config(&self.name); diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 85d17ee052..fc86c86503 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -12,7 +12,7 @@ fn main() -> anyhow::Result<()> { bld.rsrc_dir(manifest_dir_macros::directory_path!("rsrc")); #[cfg(feature = "migrate_to_scripts")] - bld.plugin_dir(manifest_dir_macros::directory_path!("plugins")); + bld.scripts_dir(manifest_dir_macros::directory_path!("plugins")); } // In release mode, embed resources into the binary. From 65edb8b8b9f9a362d0c6e0bf2e2a88ee104f0caf Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Wed, 5 Jun 2024 11:01:13 -0500 Subject: [PATCH 27/47] refactored to have more things live in the resolver --- fud2/fud-core/src/exec/driver.rs | 16 +-- fud2/fud-core/src/script/exec_scripts.rs | 4 +- fud2/fud-core/src/script/plugin.rs | 68 ++++++------- fud2/fud-core/src/script/report.rs | 2 +- fud2/fud-core/src/script/resolver.rs | 124 ++++++++++++++++------- fud2/plugins/axi.rhai | 2 +- fud2/plugins/cider.rhai | 6 +- fud2/plugins/dahlia-to-calyx.rhai | 2 +- fud2/plugins/firrtl.rhai | 4 +- fud2/plugins/icarus.rhai | 6 +- fud2/plugins/mrxl.rhai | 2 +- fud2/plugins/primitive_uses.rhai | 2 +- fud2/plugins/rtl_sim.rhai | 4 +- fud2/plugins/verilator.rhai | 6 +- fud2/plugins/xilinx.rhai | 6 +- fud2/src/main.rs | 2 +- 16 files changed, 156 insertions(+), 100 deletions(-) diff --git a/fud2/fud-core/src/exec/driver.rs b/fud2/fud-core/src/exec/driver.rs index 72e7242488..fa5ee2adca 100644 --- a/fud2/fud-core/src/exec/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -232,7 +232,7 @@ pub struct DriverBuilder { rsrc_dir: Option, rsrc_files: Option, scripts_dir: Option, - scripts_files: Option, + script_files: Option, } #[derive(Debug)] @@ -266,7 +266,7 @@ impl DriverBuilder { rsrc_dir: None, rsrc_files: None, scripts_dir: None, - scripts_files: None, + script_files: None, } } @@ -366,16 +366,16 @@ impl DriverBuilder { self.scripts_dir = Some(path.into()); } - pub fn scripts_files(&mut self, files: FileData) { - self.scripts_files = Some(files); + pub fn script_files(&mut self, files: FileData) { + self.script_files = Some(files); } /// Load any plugin scripts specified in the configuration file. - pub fn load_plugins(self) -> Self { + pub fn load_plugins(mut self) -> Self { // pull out things from self that we need - let plugin_dir = self.scripts_dir.clone(); - // TODO: find a way around this clone - let plugin_files = self.scripts_files.clone(); + let plugin_dir = self.scripts_dir.take(); + let plugin_files = self.script_files.take(); + // TODO: Let's try to avoid loading/parsing the configuration file here and // somehow reusing it from wherever we do that elsewhere. let config = config::load_config(&self.name); diff --git a/fud2/fud-core/src/script/exec_scripts.rs b/fud2/fud-core/src/script/exec_scripts.rs index 5a0c80c860..c12a54118f 100644 --- a/fud2/fud-core/src/script/exec_scripts.rs +++ b/fud2/fud-core/src/script/exec_scripts.rs @@ -119,9 +119,9 @@ impl RhaiEmitter { todo!() } - fn external_path(&mut self, path: &str) -> Utf8PathBuf { + fn external_path(&mut self, path: &str) -> String { let utf8_path = Utf8PathBuf::from(path); - self.0.borrow().external_path(&utf8_path) + self.0.borrow().external_path(&utf8_path).into_string() } fn arg(&mut self, name: &str, value: &str) -> RhaiResult<()> { diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index a709d088d9..c55ef00efd 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -1,12 +1,9 @@ -use itertools::Itertools; - use crate::{ exec::{OpRef, SetupRef, StateRef}, DriverBuilder, }; use std::{ cell::RefCell, - collections::HashMap, path::{Path, PathBuf}, rc::Rc, }; @@ -64,7 +61,8 @@ impl ScriptContext { pub struct ScriptRunner { builder: Rc>, engine: rhai::Engine, - files: HashMap, + rhai_functions: rhai::AST, + resolver: Option, } impl ScriptRunner { @@ -72,7 +70,8 @@ impl ScriptRunner { let mut this = Self { builder: Rc::new(RefCell::new(builder)), engine: rhai::Engine::new(), - files: HashMap::default(), + rhai_functions: rhai::AST::empty(), + resolver: Some(Resolver::default()), }; this.reg_state(); this.reg_get_state(); @@ -84,12 +83,12 @@ impl ScriptRunner { &mut self, files: impl Iterator, ) -> &mut Self { - self.files.extend(files.map(|f| { - ( - f.file_name().unwrap().into(), - self.engine.compile_file(f).unwrap(), - ) - })); + for f in files { + let ast = self.engine.compile_file(f.clone()).unwrap(); + let functions = + self.resolver.as_mut().unwrap().register_path(f, ast); + self.rhai_functions = self.rhai_functions.merge(&functions); + } self } @@ -97,14 +96,15 @@ impl ScriptRunner { &mut self, static_files: impl Iterator, ) -> &mut Self { - self.files.extend(static_files.map(|(name, data)| { - ( - PathBuf::from(name), - self.engine - .compile(String::from_utf8(data.to_vec()).unwrap()) - .unwrap(), - ) - })); + for (name, data) in static_files { + let ast = self + .engine + .compile(String::from_utf8(data.to_vec()).unwrap()) + .unwrap(); + let functions = + self.resolver.as_mut().unwrap().register_data(name, ast); + self.rhai_functions = self.rhai_functions.merge(&functions); + } self } @@ -179,16 +179,16 @@ impl ScriptRunner { ); } - fn script_context(&self, path: PathBuf, ast: rhai::AST) -> ScriptContext { + fn script_context(&self, path: PathBuf) -> ScriptContext { ScriptContext { builder: Rc::clone(&self.builder), path: Rc::new(path), - ast: Rc::new(ast), + ast: Rc::new(self.rhai_functions.clone()), } } - fn run_file(&mut self, path: &Path, ast: rhai::AST) { - let sctx = self.script_context(path.to_path_buf(), ast); + fn run_file(&mut self, path: &Path) { + let sctx = self.script_context(path.to_path_buf()); self.reg_rule(sctx.clone()); self.reg_op(sctx.clone()); @@ -204,19 +204,19 @@ impl ScriptRunner { } pub fn run(mut self) -> DriverBuilder { - self.engine - .set_module_resolver(Resolver::new(self.files.clone())); - - let files: Vec<_> = self - .files - .iter() - .sorted_by_key(|&(p, _)| p) - .map(|(p, a)| (p.clone(), a.clone())) - .collect(); - for (p, ast) in files { - self.run_file(p.as_path(), ast); + // take ownership of the resolver + let resolver = self.resolver.take().unwrap(); + // grab the paths from the resolver + let paths = resolver.paths(); + // set our engine to use this resolver + self.engine.set_module_resolver(resolver); + + // run all the paths we've registered + for p in paths { + self.run_file(p.as_path()); } + // transform self back into a DriverBuilder self.into_builder() } } diff --git a/fud2/fud-core/src/script/report.rs b/fud2/fud-core/src/script/report.rs index b8a35824cf..98d2bab69d 100644 --- a/fud2/fud-core/src/script/report.rs +++ b/fud2/fud-core/src/script/report.rs @@ -52,7 +52,7 @@ impl RhaiReport for rhai::Position { .eprint((name, Source::from(source))) .unwrap() } else { - eprintln!("Failed to load plugin {name}"); + eprintln!("Failed to load plugin: {name}"); let pos_str = if self.is_none() { "".to_string() } else { diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs index 8fc18449f0..023dd73f1f 100644 --- a/fud2/fud-core/src/script/resolver.rs +++ b/fud2/fud-core/src/script/resolver.rs @@ -7,52 +7,107 @@ use std::{ rc::Rc, }; +use itertools::Itertools; use rhai::EvalAltResult; use super::{exec_scripts::RhaiResult, report::RhaiReport}; #[derive(Default)] pub(super) struct Resolver { - files: HashMap, - modules: RefCell>>, - failed: RefCell>, + files: Vec<(PathBuf, rhai::AST)>, + modules: RefCell>>, + failed: RefCell>, } #[derive(Debug)] enum ResolverError { Failed(String), + Unknown(String), } impl Display for ResolverError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ResolverError::Failed(m) => write!(f, "Loading {m} failed."), + ResolverError::Failed(m) => write!(f, "Loading `{m}` failed."), + ResolverError::Unknown(m) => write!(f, "`{m}` was not found."), } } } impl Error for ResolverError {} +impl From for Box { + fn from(value: ResolverError) -> Box { + Box::new(EvalAltResult::ErrorSystem(String::new(), Box::new(value))) + } +} + impl Resolver { - pub(super) fn new(files: HashMap) -> Self { - Self { - files, - ..Default::default() - } + pub fn register_path( + &mut self, + path: PathBuf, + ast: rhai::AST, + ) -> rhai::AST { + // let stem = path.file_stem().unwrap().into(); + let functions = ast.clone_functions_only(); + self.files.push((path, ast)); + + functions + } + + pub fn register_data( + &mut self, + name: &'static str, + ast: rhai::AST, + ) -> rhai::AST { + // TODO: normalize the name somehow + self.register_path(PathBuf::from(name), ast) + } + + pub fn paths(&self) -> Vec { + self.files + .iter() + .map(|(path, _)| path.clone()) + .sorted() + .collect() + } + + fn resolve_name(&self, name: &str) -> Option<&rhai::AST> { + self.files + .iter() + .find(|(path, _)| { + // if name is directly equal to registered path + // or name is equal to the path stem, then return + // that ast + Some(name) == path.to_str() + || Some(name) == path.file_stem().and_then(|os| os.to_str()) + }) + .map(|(_, ast)| ast) + } + + fn normalize_name(&self, name: &str) -> String { + PathBuf::from(name) + .file_stem() + .and_then(|x| x.to_str()) + .map(ToString::to_string) + .unwrap() } - fn get(&self, path: &PathBuf) -> Option> { - self.modules.borrow().get(path).map(Rc::clone) + fn get(&self, path: &str) -> Option> { + let name = self.normalize_name(path); + self.modules.borrow().get(&name).map(Rc::clone) } - fn insert(&self, path: PathBuf, module: rhai::Module) -> Rc { + fn insert(&self, path: &str, module: rhai::Module) -> Rc { let rc_mod = Rc::new(module); - self.modules.borrow_mut().insert(path, Rc::clone(&rc_mod)); + let name = self.normalize_name(path); + self.modules.borrow_mut().insert(name, Rc::clone(&rc_mod)); rc_mod } - fn did_fail(&self, path: &PathBuf) -> RhaiResult<()> { - if self.failed.borrow().contains(path) { + fn did_fail(&self, path: &str) -> RhaiResult<()> { + let name = self.normalize_name(path); + if self.failed.borrow().contains(&name) { Err(Box::new(EvalAltResult::ErrorSystem( "Failed module loading".to_string(), Box::new(ResolverError::Failed(format!("{path:?}"))), @@ -62,8 +117,9 @@ impl Resolver { } } - fn add_failed(&self, path: PathBuf) { - self.failed.borrow_mut().insert(path); + fn add_failed(&self, path: &str) { + let name = self.normalize_name(path); + self.failed.borrow_mut().insert(name); } } @@ -72,33 +128,33 @@ impl rhai::ModuleResolver for Resolver { &self, engine: &rhai::Engine, _source: Option<&str>, - path: &str, + name: &str, _pos: rhai::Position, ) -> RhaiResult> { - let path_buf = PathBuf::from(path); + let path_buf = PathBuf::from(name); // if this path has already failed, don't try loading it again - self.did_fail(&path_buf)?; + self.did_fail(name)?; // return the module of a path if we have already loaded it - if let Some(module) = self.get(&path_buf) { + if let Some(module) = self.get(name) { Ok(module) } else { // otherwise, make a new module, cache it, and return it - let new_module = rhai::Module::eval_ast_as_new( - rhai::Scope::new(), - &self.files[&path_buf], - engine, - ); - - match new_module { - Ok(n) => Ok(self.insert(path_buf, n)), - Err(e) => { + self.resolve_name(name) + .ok_or(ResolverError::Unknown(name.to_string()).into()) + .and_then(|ast| { + rhai::Module::eval_ast_as_new( + rhai::Scope::new(), + ast, + engine, + ) + }) + .map(|m| self.insert(name, m)) + .inspect_err(|e| { e.report(&path_buf); - self.add_failed(path_buf); - Err(e) - } - } + self.add_failed(name) + }) } } } diff --git a/fud2/plugins/axi.rhai b/fud2/plugins/axi.rhai index afdc416def..3f225efd6f 100644 --- a/fud2/plugins/axi.rhai +++ b/fud2/plugins/axi.rhai @@ -1,4 +1,4 @@ -import "calyx.rhai" as c; +import "calyx" as c; export const yxi = state("yxi", ["yxi"]); diff --git a/fud2/plugins/cider.rhai b/fud2/plugins/cider.rhai index 904faa188c..ee7ed505ee 100644 --- a/fud2/plugins/cider.rhai +++ b/fud2/plugins/cider.rhai @@ -1,6 +1,6 @@ -import "rtl_sim.rhai" as sim; -import "testbench.rhai" as tb; -import "calyx.rhai" as c; +import "rtl_sim" as sim; +import "testbench" as tb; +import "calyx" as c; let dbg = state("debug", []); diff --git a/fud2/plugins/dahlia-to-calyx.rhai b/fud2/plugins/dahlia-to-calyx.rhai index 95ba89f5d7..f3cefd073a 100644 --- a/fud2/plugins/dahlia-to-calyx.rhai +++ b/fud2/plugins/dahlia-to-calyx.rhai @@ -1,4 +1,4 @@ -import "calyx.rhai" as c; +import "calyx" as c; export const dahlia = state("dahlia", ["fuse"]); diff --git a/fud2/plugins/firrtl.rhai b/fud2/plugins/firrtl.rhai index 29bfc6d304..401d92cf9a 100644 --- a/fud2/plugins/firrtl.rhai +++ b/fud2/plugins/firrtl.rhai @@ -1,5 +1,5 @@ -import "calyx.rhai" as c; -import "testbench.rhai" as tb; +import "calyx" as c; +import "testbench" as tb; // setup for FIRRTL-implemented primitives fn firrtl_primitives_setup(e) { diff --git a/fud2/plugins/icarus.rhai b/fud2/plugins/icarus.rhai index 5d0dbc2a47..4ca954a96e 100644 --- a/fud2/plugins/icarus.rhai +++ b/fud2/plugins/icarus.rhai @@ -1,6 +1,6 @@ -import "calyx.rhai" as c; -import "rtl_sim.rhai" as sim; -import "testbench.rhai" as tb; +import "calyx" as c; +import "rtl_sim" as sim; +import "testbench" as tb; fn icarus_setup(e) { e.var_("iverilog", "iverilog"); diff --git a/fud2/plugins/mrxl.rhai b/fud2/plugins/mrxl.rhai index 53d5cdfb36..efc0aaff9d 100644 --- a/fud2/plugins/mrxl.rhai +++ b/fud2/plugins/mrxl.rhai @@ -1,4 +1,4 @@ -import "calyx.rhai" as c; +import "calyx" as c; export const mrxl_state = state("mrxl", ["mrxl"]); diff --git a/fud2/plugins/primitive_uses.rhai b/fud2/plugins/primitive_uses.rhai index 511a731723..9c96ae1e14 100644 --- a/fud2/plugins/primitive_uses.rhai +++ b/fud2/plugins/primitive_uses.rhai @@ -1,4 +1,4 @@ -import "calyx.rhai" as c; +import "calyx" as c; let primitive_uses_json = state("primitive-uses-json", ["json"]); diff --git a/fud2/plugins/rtl_sim.rhai b/fud2/plugins/rtl_sim.rhai index 039c371467..0882292d38 100644 --- a/fud2/plugins/rtl_sim.rhai +++ b/fud2/plugins/rtl_sim.rhai @@ -15,8 +15,8 @@ fn sim_setup(e) { // The input data file. `sim.data` is required. let data_name = e.config_val("sim.data"); - let data_path = e.external_path(data_name.as_ref()); - e.var_("sim_data", data_path.as_str()); + let data_path = e.external_path(data_name); + e.var_("sim_data", data_path); // Produce the data directory. e.var_("datadir", "sim_data"); diff --git a/fud2/plugins/verilator.rhai b/fud2/plugins/verilator.rhai index c5cc286fb7..574e4cb958 100644 --- a/fud2/plugins/verilator.rhai +++ b/fud2/plugins/verilator.rhai @@ -1,6 +1,6 @@ -import "rtl_sim.rhai" as sim; -import "testbench.rhai" as tb; -import "calyx.rhai" as c; +import "rtl_sim" as sim; +import "testbench" as tb; +import "calyx" as c; fn verilator_setup(e) { e.config_var_or("verilator", "verilator.exe", "verilator"); diff --git a/fud2/plugins/xilinx.rhai b/fud2/plugins/xilinx.rhai index 13c3d4aeaf..79515e9f99 100644 --- a/fud2/plugins/xilinx.rhai +++ b/fud2/plugins/xilinx.rhai @@ -1,6 +1,6 @@ -import "calyx.rhai" as c; -import "rtl_sim.rhai" as sim; -import "testbench.rhai" as tb; +import "calyx" as c; +import "rtl_sim" as sim; +import "testbench" as tb; let xo = state("xo", ["xo"]); let xclbin = state("xclbin", ["xclbin"]); diff --git a/fud2/src/main.rs b/fud2/src/main.rs index fc86c86503..cc6b3e44c0 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -27,7 +27,7 @@ fn main() -> anyhow::Result<()> { }); #[cfg(feature = "migrate_to_scripts")] - bld.plugin_files({ + bld.script_files({ const DIR: include_dir::Dir = include_dir::include_dir!("$CARGO_MANIFEST_DIR/plugins"); DIR.files() From 856e2b07e9a5e01d7c53e1f46f1b12f41802f677 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Wed, 5 Jun 2024 11:04:25 -0500 Subject: [PATCH 28/47] rename plugins/ to scripts/ --- fud2/{plugins => scripts}/axi.rhai | 0 fud2/{plugins => scripts}/calyx.rhai | 0 fud2/{plugins => scripts}/cider.rhai | 0 fud2/{plugins => scripts}/dahlia-to-calyx.rhai | 0 fud2/{plugins => scripts}/firrtl.rhai | 0 fud2/{plugins => scripts}/icarus.rhai | 0 fud2/{plugins => scripts}/mrxl.rhai | 0 fud2/{plugins => scripts}/primitive_uses.rhai | 0 fud2/{plugins => scripts}/rtl_sim.rhai | 0 fud2/{plugins => scripts}/testbench.rhai | 0 fud2/{plugins => scripts}/verilator.rhai | 0 fud2/{plugins => scripts}/xilinx.rhai | 0 fud2/src/main.rs | 4 ++-- 13 files changed, 2 insertions(+), 2 deletions(-) rename fud2/{plugins => scripts}/axi.rhai (100%) rename fud2/{plugins => scripts}/calyx.rhai (100%) rename fud2/{plugins => scripts}/cider.rhai (100%) rename fud2/{plugins => scripts}/dahlia-to-calyx.rhai (100%) rename fud2/{plugins => scripts}/firrtl.rhai (100%) rename fud2/{plugins => scripts}/icarus.rhai (100%) rename fud2/{plugins => scripts}/mrxl.rhai (100%) rename fud2/{plugins => scripts}/primitive_uses.rhai (100%) rename fud2/{plugins => scripts}/rtl_sim.rhai (100%) rename fud2/{plugins => scripts}/testbench.rhai (100%) rename fud2/{plugins => scripts}/verilator.rhai (100%) rename fud2/{plugins => scripts}/xilinx.rhai (100%) diff --git a/fud2/plugins/axi.rhai b/fud2/scripts/axi.rhai similarity index 100% rename from fud2/plugins/axi.rhai rename to fud2/scripts/axi.rhai diff --git a/fud2/plugins/calyx.rhai b/fud2/scripts/calyx.rhai similarity index 100% rename from fud2/plugins/calyx.rhai rename to fud2/scripts/calyx.rhai diff --git a/fud2/plugins/cider.rhai b/fud2/scripts/cider.rhai similarity index 100% rename from fud2/plugins/cider.rhai rename to fud2/scripts/cider.rhai diff --git a/fud2/plugins/dahlia-to-calyx.rhai b/fud2/scripts/dahlia-to-calyx.rhai similarity index 100% rename from fud2/plugins/dahlia-to-calyx.rhai rename to fud2/scripts/dahlia-to-calyx.rhai diff --git a/fud2/plugins/firrtl.rhai b/fud2/scripts/firrtl.rhai similarity index 100% rename from fud2/plugins/firrtl.rhai rename to fud2/scripts/firrtl.rhai diff --git a/fud2/plugins/icarus.rhai b/fud2/scripts/icarus.rhai similarity index 100% rename from fud2/plugins/icarus.rhai rename to fud2/scripts/icarus.rhai diff --git a/fud2/plugins/mrxl.rhai b/fud2/scripts/mrxl.rhai similarity index 100% rename from fud2/plugins/mrxl.rhai rename to fud2/scripts/mrxl.rhai diff --git a/fud2/plugins/primitive_uses.rhai b/fud2/scripts/primitive_uses.rhai similarity index 100% rename from fud2/plugins/primitive_uses.rhai rename to fud2/scripts/primitive_uses.rhai diff --git a/fud2/plugins/rtl_sim.rhai b/fud2/scripts/rtl_sim.rhai similarity index 100% rename from fud2/plugins/rtl_sim.rhai rename to fud2/scripts/rtl_sim.rhai diff --git a/fud2/plugins/testbench.rhai b/fud2/scripts/testbench.rhai similarity index 100% rename from fud2/plugins/testbench.rhai rename to fud2/scripts/testbench.rhai diff --git a/fud2/plugins/verilator.rhai b/fud2/scripts/verilator.rhai similarity index 100% rename from fud2/plugins/verilator.rhai rename to fud2/scripts/verilator.rhai diff --git a/fud2/plugins/xilinx.rhai b/fud2/scripts/xilinx.rhai similarity index 100% rename from fud2/plugins/xilinx.rhai rename to fud2/scripts/xilinx.rhai diff --git a/fud2/src/main.rs b/fud2/src/main.rs index cc6b3e44c0..4f05686a71 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -12,7 +12,7 @@ fn main() -> anyhow::Result<()> { bld.rsrc_dir(manifest_dir_macros::directory_path!("rsrc")); #[cfg(feature = "migrate_to_scripts")] - bld.scripts_dir(manifest_dir_macros::directory_path!("plugins")); + bld.scripts_dir(manifest_dir_macros::directory_path!("scripts")); } // In release mode, embed resources into the binary. @@ -29,7 +29,7 @@ fn main() -> anyhow::Result<()> { #[cfg(feature = "migrate_to_scripts")] bld.script_files({ const DIR: include_dir::Dir = - include_dir::include_dir!("$CARGO_MANIFEST_DIR/plugins"); + include_dir::include_dir!("$CARGO_MANIFEST_DIR/scripts"); DIR.files() .map(|file| (file.path().to_str().unwrap(), file.contents())) .collect() From 5e47823b766faca8d8e5414f0bf264de409e213d Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Wed, 5 Jun 2024 15:57:11 -0500 Subject: [PATCH 29/47] improve error reporting for errors in submodules --- fud2/fud-core/src/script/report.rs | 64 +++++++++++++++++++++------- fud2/fud-core/src/script/resolver.rs | 33 ++++++++++---- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/fud2/fud-core/src/script/report.rs b/fud2/fud-core/src/script/report.rs index 98d2bab69d..cd144200c2 100644 --- a/fud2/fud-core/src/script/report.rs +++ b/fud2/fud-core/src/script/report.rs @@ -1,19 +1,28 @@ use ariadne::{Color, Fmt, Label, Report, ReportKind, Source}; use rhai::EvalAltResult; -use std::{fs, path::Path}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use super::{error::RhaiSystemError, exec_scripts::RhaiResult}; +/// A small hack to improve error messages. These are known function names +/// so that we can say that arguments are incorrect when a user calls +/// one of these functions. +const KNOWN_FNS: [&str; 4] = ["state", "op", "get_state", "get_setup"]; + pub(super) trait RhaiReport { fn report_raw, S: AsRef>( &self, path: P, len: usize, + header: Option, msg: S, ); fn report>(&self, path: P) { - self.report_raw(path, 0, "") + self.report_raw(path, 0, None, "") } } @@ -22,6 +31,7 @@ impl RhaiReport for rhai::Position { &self, path: P, len: usize, + header: Option, msg: S, ) { let source = fs::read_to_string(path.as_ref()); @@ -43,7 +53,9 @@ impl RhaiReport for rhai::Position { let err_offset = line_offset + (position - 1); Report::build(ReportKind::Error, name, err_offset) - .with_message("Failed to load plugin") + .with_message( + header.unwrap_or("Failed to load plugin".to_string()), + ) .with_label( Label::new((name, err_offset..err_offset + len)) .with_message(msg.as_ref().fg(Color::Red)), @@ -68,19 +80,25 @@ impl RhaiReport for EvalAltResult { &self, path: P, _len: usize, + header: Option, _msg: S, ) { match &self { - EvalAltResult::ErrorVariableNotFound(variable, pos) => { - pos.report_raw(&path, variable.len(), "Undefined variable") - } + EvalAltResult::ErrorVariableNotFound(variable, pos) => pos + .report_raw( + &path, + variable.len(), + header, + "Undefined variable", + ), EvalAltResult::ErrorFunctionNotFound(msg, pos) => { let (fn_name, args) = msg.split_once(' ').unwrap_or((msg, "")); - pos.report_raw( - &path, - fn_name.len(), - format!("{fn_name} {args}"), - ) + let msg = if KNOWN_FNS.contains(&fn_name) { + format!("Invalid arguments. Expected {args}") + } else { + format!("Unknown function: {fn_name} {args}") + }; + pos.report_raw(&path, fn_name.len(), header, msg) } EvalAltResult::ErrorSystem(msg, err) if err.is::() => @@ -91,12 +109,27 @@ impl RhaiReport for EvalAltResult { } else { format!("{msg}: {err}") }; - e.position.report_raw(&path, 0, msg) + e.position.report_raw(&path, 0, header, msg) + } + EvalAltResult::ErrorInModule(submod_path, err, _) + if path.as_ref().to_str() == Some(submod_path) => + { + err.report(submod_path) } - EvalAltResult::ErrorInModule(path, err, _) => err.report(path), + EvalAltResult::ErrorInModule(submod_path, err, _) => err + .report_raw( + submod_path, + 0, + Some(format!( + "Error in submodule {:?} while loading {:?}", + PathBuf::from(submod_path).file_stem().unwrap(), + path.as_ref().file_stem().unwrap() + )), + "", + ), // for errors that we don't have custom processing, just point // to the beginning of the error, and use the error Display as message - e => e.position().report_raw(&path, 0, format!("{e}")), + e => e.position().report_raw(&path, 0, header, format!("{e}")), } } } @@ -106,10 +139,11 @@ impl RhaiReport for RhaiResult { &self, path: P, len: usize, + header: Option, msg: S, ) { if let Err(e) = self { - (**e).report_raw(path, len, msg); + (**e).report_raw(path, len, header, msg); } } } diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs index 023dd73f1f..81a54488d3 100644 --- a/fud2/fud-core/src/script/resolver.rs +++ b/fud2/fud-core/src/script/resolver.rs @@ -10,7 +10,7 @@ use std::{ use itertools::Itertools; use rhai::EvalAltResult; -use super::{exec_scripts::RhaiResult, report::RhaiReport}; +use super::exec_scripts::RhaiResult; #[derive(Default)] pub(super) struct Resolver { @@ -72,7 +72,7 @@ impl Resolver { .collect() } - fn resolve_name(&self, name: &str) -> Option<&rhai::AST> { + fn find_ast(&self, name: &str) -> Option<&rhai::AST> { self.files .iter() .find(|(path, _)| { @@ -85,6 +85,16 @@ impl Resolver { .map(|(_, ast)| ast) } + fn resolve_filename(&self, name: &str) -> Option<&PathBuf> { + self.files + .iter() + .find(|(path, _)| { + Some(name) == path.to_str() + || Some(name) == path.file_stem().and_then(|os| os.to_str()) + }) + .map(|(path, _)| path) + } + fn normalize_name(&self, name: &str) -> String { PathBuf::from(name) .file_stem() @@ -129,9 +139,12 @@ impl rhai::ModuleResolver for Resolver { engine: &rhai::Engine, _source: Option<&str>, name: &str, - _pos: rhai::Position, + pos: rhai::Position, ) -> RhaiResult> { - let path_buf = PathBuf::from(name); + let path_buf = self + .resolve_filename(name) + .map(|x| x.clone()) + .unwrap_or(PathBuf::from(name)); // if this path has already failed, don't try loading it again self.did_fail(name)?; @@ -141,7 +154,7 @@ impl rhai::ModuleResolver for Resolver { Ok(module) } else { // otherwise, make a new module, cache it, and return it - self.resolve_name(name) + self.find_ast(name) .ok_or(ResolverError::Unknown(name.to_string()).into()) .and_then(|ast| { rhai::Module::eval_ast_as_new( @@ -151,10 +164,14 @@ impl rhai::ModuleResolver for Resolver { ) }) .map(|m| self.insert(name, m)) - .inspect_err(|e| { - e.report(&path_buf); - self.add_failed(name) + .map_err(|e| { + Box::new(EvalAltResult::ErrorInModule( + path_buf.as_os_str().to_str().unwrap().to_string(), + e, + pos, + )) }) + .inspect_err(|_| self.add_failed(name)) } } } From 58347a4501c627d7001743984caa42234a68f5a3 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 13:02:00 -0500 Subject: [PATCH 30/47] slightly improved error messages --- fud2/fud-core/src/script/resolver.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs index 81a54488d3..0f86b28cdd 100644 --- a/fud2/fud-core/src/script/resolver.rs +++ b/fud2/fud-core/src/script/resolver.rs @@ -28,8 +28,8 @@ enum ResolverError { impl Display for ResolverError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ResolverError::Failed(m) => write!(f, "Loading `{m}` failed."), - ResolverError::Unknown(m) => write!(f, "`{m}` was not found."), + ResolverError::Failed(m) => write!(f, "Loading {m} failed."), + ResolverError::Unknown(m) => write!(f, "{m} was not found."), } } } @@ -119,7 +119,7 @@ impl Resolver { let name = self.normalize_name(path); if self.failed.borrow().contains(&name) { Err(Box::new(EvalAltResult::ErrorSystem( - "Failed module loading".to_string(), + "".to_string(), Box::new(ResolverError::Failed(format!("{path:?}"))), ))) } else { From dedbf1fe16ebae7cd41a2ab0b2cbafeaffc61f71 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 14:43:38 -0500 Subject: [PATCH 31/47] remove comments from snapshot testing + add plugin testing (feature gated) --- .../snapshots/tests__emit@calyx_debug.snap | 5 ----- ...sts__emit@calyx_firrtl_verilog-refmem.snap | 4 ---- .../tests__emit@calyx_icarus_dat.snap | 5 ----- .../tests__emit@calyx_icarus_vcd.snap | 5 ----- .../tests__emit@calyx_interp_dat.snap | 5 ----- .../tests__emit@calyx_verilator_dat.snap | 5 ----- .../tests__emit@calyx_verilator_vcd.snap | 5 ----- .../snapshots/tests__emit@calyx_verilog.snap | 2 -- .../tests__emit@calyx_xrt-trace_vcd.snap | 6 ------ .../snapshots/tests__emit@calyx_xrt_dat.snap | 6 ------ .../snapshots/tests__emit@dahlia_calyx.snap | 2 -- .../snapshots/tests__emit@mrxl_calyx.snap | 2 -- fud2/tests/tests.rs | 19 ++++++++++++++++--- 13 files changed, 16 insertions(+), 55 deletions(-) diff --git a/fud2/tests/snapshots/tests__emit@calyx_debug.snap b/fud2/tests/snapshots/tests__emit@calyx_debug.snap index 87bde0344b..881a924b3f 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_debug.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_debug.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -20,10 +19,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -32,7 +29,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# Cider interpreter cider-exe = $calyx-base/target/debug/cider cider-converter = $calyx-base/target/debug/cider-data-converter rule cider @@ -55,7 +51,6 @@ rule interp-to-dump command = $cider-converter --to json $in > $out build data.dump: dump-to-interp $sim_data | $cider-converter -# build targets build _pseudo_debug: cider-debug stdin | data.json default _pseudo_debug diff --git a/fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap b/fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap index fc3b42190f..4e3a2aa5fd 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# Custom Testbench Setup rule ref-to-external command = sed 's/ref /@external /g' $in > $out rule external-to-ref @@ -27,7 +25,6 @@ rule generate-refmem-testbench rule dummy command = sh -c 'cat $$0' $in > $out -# Firrtl to Verilog compiler firrtl-exe = /test/bin/firrtl rule firrtl command = $firrtl-exe -i $in -o $out -X sverilog @@ -35,7 +32,6 @@ build primitives-for-firrtl.sv: get-rsrc rule add-verilog-primitives command = cat primitives-for-firrtl.sv $in > $out -# build targets build external.futil: ref-to-external stdin build ref.futil: external-to-ref stdin build memory-info.json: calyx external.futil diff --git a/fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap b/fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap index 7c3278eefc..6b2d670e94 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -29,17 +27,14 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Icarus Verilog iverilog = iverilog rule icarus-compile-standalone-tb command = $iverilog -g2012 -o $out tb.sv $in rule icarus-compile-custom-tb command = $iverilog -g2012 -o $out tb.sv memories.sv $in -# build targets build stdin.sv: calyx stdin backend = verilog args = --disable-verify diff --git a/fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap b/fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap index e96ecc4384..e93721ae80 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -29,17 +27,14 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Icarus Verilog iverilog = iverilog rule icarus-compile-standalone-tb command = $iverilog -g2012 -o $out tb.sv $in rule icarus-compile-custom-tb command = $iverilog -g2012 -o $out tb.sv memories.sv $in -# build targets build stdin.sv: calyx stdin backend = verilog args = --disable-verify diff --git a/fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap b/fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap index 6097c4c2b9..a634f96932 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -20,10 +19,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -32,7 +29,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# Cider interpreter cider-exe = $calyx-base/target/debug/cider cider-converter = $calyx-base/target/debug/cider-data-converter rule cider @@ -55,7 +51,6 @@ rule interp-to-dump command = $cider-converter --to json $in > $out build data.dump: dump-to-interp $sim_data | $cider-converter -# build targets build interp_out.json: cider stdin | data.json build stdin.json: interp-to-dat interp_out.json | $sim_data interp-dat.py diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap b/fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap index bf595d2de8..1d30feedd8 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -29,10 +27,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Verilator verilator = verilator cycle-limit = 500000000 rule verilator-compile-standalone-tb @@ -42,7 +38,6 @@ rule verilator-compile-custom-tb rule cp command = cp $in $out -# build targets build stdin.sv: calyx stdin backend = verilog build verilator-out/VTOP: verilator-compile-standalone-tb stdin.sv | tb.sv diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap b/fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap index 50ba7adf62..25da89a06c 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -29,10 +27,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Verilator verilator = verilator cycle-limit = 500000000 rule verilator-compile-standalone-tb @@ -42,7 +38,6 @@ rule verilator-compile-custom-tb rule cp command = cp $in $out -# build targets build stdin.sv: calyx stdin backend = verilog build verilator-out/VTOP: verilator-compile-standalone-tb stdin.sv | tb.sv diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilog.snap b/fud2/tests/snapshots/tests__emit@calyx_verilog.snap index de7b7f66f2..06fbe4462c 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilog.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_verilog.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# build targets build stdin.sv: calyx stdin backend = verilog diff --git a/fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap b/fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap index a0e57b2fef..bcec9ce14e 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# Xilinx tools vivado-dir = /test/xilinx/vivado vitis-dir = /test/xilinx/vitis build gen_xo.tcl: get-rsrc @@ -30,7 +28,6 @@ rule compile-xclbin command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in pool = console -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -44,10 +41,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Xilinx execution via XRT rule emconfig command = $vitis-dir/bin/emconfigutil --platform $platform build emconfig.json: emconfig @@ -62,7 +57,6 @@ build pre_sim.tcl: echo | build post_sim.tcl: echo | contents = close_vcd\\n -# build targets build main.sv: calyx stdin backend = verilog args = --synthesis -p external diff --git a/fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap b/fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap index 0be68b7fb4..120233e737 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap +++ b/fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap @@ -6,7 +6,6 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Calyx compiler calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -15,7 +14,6 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -# Xilinx tools vivado-dir = /test/xilinx/vivado vitis-dir = /test/xilinx/vitis build gen_xo.tcl: get-rsrc @@ -30,7 +28,6 @@ rule compile-xclbin command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in pool = console -# RTL simulation python = python3 build json-dat.py: get-rsrc rule hex-data @@ -44,10 +41,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -# Standalone Testbench Setup build tb.sv: get-rsrc -# Xilinx execution via XRT rule emconfig command = $vitis-dir/bin/emconfigutil --platform $platform build emconfig.json: emconfig @@ -62,7 +57,6 @@ build pre_sim.tcl: echo | build post_sim.tcl: echo | contents = close_vcd\\n -# build targets build main.sv: calyx stdin backend = verilog args = --synthesis -p external diff --git a/fud2/tests/snapshots/tests__emit@dahlia_calyx.snap b/fud2/tests/snapshots/tests__emit@dahlia_calyx.snap index 03b0bf21b5..0377d85d62 100644 --- a/fud2/tests/snapshots/tests__emit@dahlia_calyx.snap +++ b/fud2/tests/snapshots/tests__emit@dahlia_calyx.snap @@ -6,12 +6,10 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# Dahlia compiler dahlia-exe = /test/bin/dahlia rule dahlia-to-calyx command = $dahlia-exe -b calyx --lower -l error $in -o $out -# build targets build stdin.futil: dahlia-to-calyx stdin default stdin.futil diff --git a/fud2/tests/snapshots/tests__emit@mrxl_calyx.snap b/fud2/tests/snapshots/tests__emit@mrxl_calyx.snap index 4002ab7f46..74b84a8f95 100644 --- a/fud2/tests/snapshots/tests__emit@mrxl_calyx.snap +++ b/fud2/tests/snapshots/tests__emit@mrxl_calyx.snap @@ -6,12 +6,10 @@ build-tool = fud2 rule get-rsrc command = $build-tool get-rsrc $out -# MrXL compiler mrxl-exe = mrxl rule mrxl-to-calyx command = $mrxl-exe $in > $out -# build targets build stdin.futil: mrxl-to-calyx stdin default stdin.futil diff --git a/fud2/tests/tests.rs b/fud2/tests/tests.rs index eafa1e2eef..1abc4948a9 100644 --- a/fud2/tests/tests.rs +++ b/fud2/tests/tests.rs @@ -1,14 +1,21 @@ -use fud2::build_driver; use fud_core::{ config::default_config, exec::Request, run::Run, Driver, DriverBuilder, }; +#[cfg(not(feature = "migrate_to_scripts"))] fn test_driver() -> Driver { let mut bld = DriverBuilder::new("fud2"); - build_driver(&mut bld); + fud2::build_driver(&mut bld); bld.build() } +#[cfg(feature = "migrate_to_scripts")] +fn test_driver() -> Driver { + let mut bld = DriverBuilder::new("fud2-plugins"); + bld.scripts_dir(manifest_dir_macros::directory_path!("scripts")); + bld.load_plugins().build() +} + fn request( driver: &Driver, start: &str, @@ -39,7 +46,13 @@ fn emit_ninja(driver: &Driver, req: Request) -> String { let run = Run::with_config(driver, plan, config); let mut buf = vec![]; run.emit(&mut buf).unwrap(); - String::from_utf8(buf).unwrap() + // turn into string, and remove comments + String::from_utf8(buf) + .unwrap() + .lines() + .filter(|line| !line.starts_with('#')) + .collect::>() + .join("\n") } /// Get a human-readable description of a request. From ee53a5ca163ad5323ea894b716d61857c2943012 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 14:44:04 -0500 Subject: [PATCH 32/47] remove comment --- fud2/fud-core/src/script/resolver.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs index 0f86b28cdd..a1a8027745 100644 --- a/fud2/fud-core/src/script/resolver.rs +++ b/fud2/fud-core/src/script/resolver.rs @@ -48,7 +48,6 @@ impl Resolver { path: PathBuf, ast: rhai::AST, ) -> rhai::AST { - // let stem = path.file_stem().unwrap().into(); let functions = ast.clone_functions_only(); self.files.push((path, ast)); From 898898ec4f61c522056c7bfed7919574940194a5 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 17:55:54 -0500 Subject: [PATCH 33/47] plugins should only load each setup_fn once --- fud2/fud-core/src/script/plugin.rs | 41 ++++++++++++++++++++++-------- fud2/scripts/verilator.rhai | 2 +- fud2/scripts/xilinx.rhai | 2 +- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/fud2/fud-core/src/script/plugin.rs b/fud2/fud-core/src/script/plugin.rs index c55ef00efd..40473ad4dc 100644 --- a/fud2/fud-core/src/script/plugin.rs +++ b/fud2/fud-core/src/script/plugin.rs @@ -4,6 +4,7 @@ use crate::{ }; use std::{ cell::RefCell, + collections::HashMap, path::{Path, PathBuf}, rc::Rc, }; @@ -20,6 +21,7 @@ struct ScriptContext { builder: Rc>, path: Rc, ast: Rc, + setups: Rc>>, } impl ScriptContext { @@ -34,17 +36,7 @@ impl ScriptContext { setups .into_iter() .map(|s| match s.clone().try_cast::() { - Some(fnptr) => { - let rctx = RhaiSetupCtx { - path: Rc::clone(&self.path), - ast: Rc::new(self.ast.clone_functions_only()), - name: fnptr.fn_name().to_string(), - }; - Ok(self.builder.borrow_mut().add_setup( - &format!("{} (plugin)", fnptr.fn_name()), - rctx, - )) - } + Some(fnptr) => Ok(self.make_or_get_setupref(fnptr)), // if we can't cast as a FnPtr, try casting as a SetupRef directly None => { s.clone().try_cast::().ok_or_else(move || { @@ -56,6 +48,30 @@ impl ScriptContext { }) .collect::>>() } + + /// Construct a SetupRef for a rhai function. If we already have a SetupRef, + /// return the previously constructed version, otherwise make a new one, cache it + /// and return that. + fn make_or_get_setupref(&self, fnptr: rhai::FnPtr) -> SetupRef { + // if we haven't seen this fnptr before, make a new setup context + // for this function + if !self.setups.borrow().contains_key(fnptr.fn_name()) { + let rctx = RhaiSetupCtx { + path: Rc::clone(&self.path), + ast: Rc::new(self.ast.clone_functions_only()), + name: fnptr.fn_name().to_string(), + }; + let setup_ref = self + .builder + .borrow_mut() + .add_setup(&format!("{} (plugin)", fnptr.fn_name()), rctx); + self.setups + .borrow_mut() + .insert(fnptr.fn_name().to_string(), setup_ref); + } + + *self.setups.borrow().get(fnptr.fn_name()).unwrap() + } } pub struct ScriptRunner { @@ -63,6 +79,7 @@ pub struct ScriptRunner { engine: rhai::Engine, rhai_functions: rhai::AST, resolver: Option, + setups: Rc>>, } impl ScriptRunner { @@ -72,6 +89,7 @@ impl ScriptRunner { engine: rhai::Engine::new(), rhai_functions: rhai::AST::empty(), resolver: Some(Resolver::default()), + setups: Rc::default(), }; this.reg_state(); this.reg_get_state(); @@ -184,6 +202,7 @@ impl ScriptRunner { builder: Rc::clone(&self.builder), path: Rc::new(path), ast: Rc::new(self.rhai_functions.clone()), + setups: Rc::clone(&self.setups), } } diff --git a/fud2/scripts/verilator.rhai b/fud2/scripts/verilator.rhai index 574e4cb958..19fc43155d 100644 --- a/fud2/scripts/verilator.rhai +++ b/fud2/scripts/verilator.rhai @@ -19,7 +19,7 @@ fn verilator_setup(e) { fn verilator_build(e, input, output, standalone_tb) { let out_dir = "verilator-out"; let sim_bin = `${out_dir}/VTOP`; - if standalone_testbench { + if standalone_tb { e.build_cmd( [sim_bin], "verilator-compile-standalone-tb", diff --git a/fud2/scripts/xilinx.rhai b/fud2/scripts/xilinx.rhai index 79515e9f99..6d625fb2f8 100644 --- a/fud2/scripts/xilinx.rhai +++ b/fud2/scripts/xilinx.rhai @@ -121,7 +121,7 @@ op( xrt_setup, ], xclbin, - sim::dat, + sim::vcd, |e, input, output| { e.rsrc("xrt_trace.ini"); e.build_cmd( From 5cc50e7b2d31d16e767733ce78af758972cbe400 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 18:27:37 -0500 Subject: [PATCH 34/47] test every operation in fud2 with insta --- ...sts__emit@calyx_calyx__op_axi-wrapped.snap | 10 ++++ ...tests__emit@calyx_dat__op_interp-flat.snap | 57 +++++++++++++++++++ .../tests__emit@calyx_dat__op_interp.snap | 57 +++++++++++++++++++ .../tests__emit@calyx_debug__op_debug.snap | 56 ++++++++++++++++++ ...primitives__op_firrtl-with-primitives.snap | 46 +++++++++++++++ ...emit@calyx_firrtl__op_calyx-to-firrtl.snap | 38 +++++++++++++ ...rimitive-uses-json__op_primitive-uses.snap | 20 +++++++ ...x_verilog-noverify__op_calyx-noverify.snap | 21 +++++++ ...it@calyx_verilog__op_calyx-to-verilog.snap | 20 +++++++ .../tests__emit@calyx_xo__op_xo.snap | 40 +++++++++++++ ...ests__emit@calyx_yxi__op_calyx-to-yxi.snap | 20 +++++++ ...emit@dahlia_calyx__op_dahlia-to-calyx.snap | 15 +++++ ...y__op_firrtl-with-primitives-noverify.snap | 18 ++++++ ...log-refmem__op_firrtl-with-primitives.snap | 18 ++++++ ...g-refmem-noverify__op_firrtl-noverify.snap | 19 +++++++ ...emit@firrtl_verilog-refmem__op_firrtl.snap | 19 +++++++ ...ts__emit@mrxl_calyx__op_mrxl-to-calyx.snap | 15 +++++ .../tests__emit@sim_dat__op_simulate.snap | 27 +++++++++ .../tests__emit@sim_vcd__op_trace.snap | 26 +++++++++ ..._emit@verilog-noverify_sim__op_icarus.snap | 32 +++++++++++ ...refmem-noverify_sim__op_icarus-refmem.snap | 30 ++++++++++ ...rilog-refmem_sim__op_verilator-refmem.snap | 46 +++++++++++++++ ...tests__emit@verilog_sim__op_verilator.snap | 37 ++++++++++++ .../tests__emit@xclbin_dat__op_xrt.snap | 56 ++++++++++++++++++ .../tests__emit@xclbin_vcd__op_xrt-trace.snap | 56 ++++++++++++++++++ .../tests__emit@xo_xclbin__op_xclbin.snap | 25 ++++++++ fud2/tests/tests.rs | 39 ++++++++++--- 27 files changed, 854 insertions(+), 9 deletions(-) create mode 100644 fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap create mode 100644 fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap create mode 100644 fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap create mode 100644 fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap create mode 100644 fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap create mode 100644 fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap create mode 100644 fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap create mode 100644 fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap create mode 100644 fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap create mode 100644 fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap create mode 100644 fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap create mode 100644 fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap create mode 100644 fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap create mode 100644 fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap create mode 100644 fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap create mode 100644 fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap create mode 100644 fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap diff --git a/fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap b/fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap new file mode 100644 index 0000000000..c57a11e204 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap @@ -0,0 +1,10 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> calyx +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + + +default stdin diff --git a/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap b/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap new file mode 100644 index 0000000000..ce2207e4c1 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap @@ -0,0 +1,57 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> dat +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +cider-exe = $calyx-base/target/debug/cider +cider-converter = $calyx-base/target/debug/cider-data-converter +rule cider + command = $cider-exe -l $calyx-base --raw --data data.json $in > $out +rule cider-debug + command = $cider-exe -l $calyx-base --data data.json $in debug || true + pool = console +build interp-dat.py: get-rsrc +python = python3 +rule dat-to-interp + command = $python interp-dat.py --to-interp $in +rule interp-to-dat + command = $python interp-dat.py --from-interp $in $sim_data > $out +build data.json: dat-to-interp $sim_data | interp-dat.py +rule cider2 + command = $cider-exe -l $calyx-base --data data.dump $in flat > $out +rule dump-to-interp + command = $cider-converter --to cider $in > $out +rule interp-to-dump + command = $cider-converter --to json $in > $out +build data.dump: dump-to-interp $sim_data | $cider-converter + +build interp_out.json: cider stdin | data.json +build stdin.json: interp-to-dat interp_out.json | $sim_data interp-dat.py + +default stdin.json diff --git a/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap b/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap new file mode 100644 index 0000000000..ce2207e4c1 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap @@ -0,0 +1,57 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> dat +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +cider-exe = $calyx-base/target/debug/cider +cider-converter = $calyx-base/target/debug/cider-data-converter +rule cider + command = $cider-exe -l $calyx-base --raw --data data.json $in > $out +rule cider-debug + command = $cider-exe -l $calyx-base --data data.json $in debug || true + pool = console +build interp-dat.py: get-rsrc +python = python3 +rule dat-to-interp + command = $python interp-dat.py --to-interp $in +rule interp-to-dat + command = $python interp-dat.py --from-interp $in $sim_data > $out +build data.json: dat-to-interp $sim_data | interp-dat.py +rule cider2 + command = $cider-exe -l $calyx-base --data data.dump $in flat > $out +rule dump-to-interp + command = $cider-converter --to cider $in > $out +rule interp-to-dump + command = $cider-converter --to json $in > $out +build data.dump: dump-to-interp $sim_data | $cider-converter + +build interp_out.json: cider stdin | data.json +build stdin.json: interp-to-dat interp_out.json | $sim_data interp-dat.py + +default stdin.json diff --git a/fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap b/fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap new file mode 100644 index 0000000000..881a924b3f --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap @@ -0,0 +1,56 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> debug +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +cider-exe = $calyx-base/target/debug/cider +cider-converter = $calyx-base/target/debug/cider-data-converter +rule cider + command = $cider-exe -l $calyx-base --raw --data data.json $in > $out +rule cider-debug + command = $cider-exe -l $calyx-base --data data.json $in debug || true + pool = console +build interp-dat.py: get-rsrc +python = python3 +rule dat-to-interp + command = $python interp-dat.py --to-interp $in +rule interp-to-dat + command = $python interp-dat.py --from-interp $in $sim_data > $out +build data.json: dat-to-interp $sim_data | interp-dat.py +rule cider2 + command = $cider-exe -l $calyx-base --data data.dump $in flat > $out +rule dump-to-interp + command = $cider-converter --to cider $in > $out +rule interp-to-dump + command = $cider-converter --to json $in > $out +build data.dump: dump-to-interp $sim_data | $cider-converter + +build _pseudo_debug: cider-debug stdin | data.json + +default _pseudo_debug diff --git a/fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap b/fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap new file mode 100644 index 0000000000..24de1967d3 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap @@ -0,0 +1,46 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> firrtl-with-primitives +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +gen-firrtl-primitives-script = $calyx-base/tools/firrtl/generate-firrtl-with-primitives.py +rule generate-firrtl-with-primitives + command = python3 $gen-firrtl-primitives-script $in > $out + +rule ref-to-external + command = sed 's/ref /@external /g' $in > $out +rule external-to-ref + command = sed 's/@external([0-9]*)/ref/g' $in | sed 's/@external/ref/g' > $out +gen-testbench-script = $calyx-base/tools/firrtl/generate-testbench.py +build memories.sv: get-rsrc +rule generate-refmem-testbench + command = python3 $gen-testbench-script $in > $out +rule dummy + command = sh -c 'cat $$0' $in > $out + +build external.futil: ref-to-external stdin +build ref.futil: external-to-ref stdin +build memory-info.json: calyx external.futil + backend = yxi +build tb.sv: generate-refmem-testbench memory-info.json +build core.fir: calyx ref.futil + backend = firrtl + args = --synthesis +build primitive-uses.json: calyx ref.futil + backend = primitive-uses + args = --synthesis +build tmp-out.fir: generate-firrtl-with-primitives core.fir primitive-uses.json +build stdin.fir: dummy tmp-out.fir tb.sv + +default stdin.fir diff --git a/fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap b/fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap new file mode 100644 index 0000000000..c6fb982661 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap @@ -0,0 +1,38 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> firrtl +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +rule ref-to-external + command = sed 's/ref /@external /g' $in > $out +rule external-to-ref + command = sed 's/@external([0-9]*)/ref/g' $in | sed 's/@external/ref/g' > $out +gen-testbench-script = $calyx-base/tools/firrtl/generate-testbench.py +build memories.sv: get-rsrc +rule generate-refmem-testbench + command = python3 $gen-testbench-script $in > $out +rule dummy + command = sh -c 'cat $$0' $in > $out + +build external.futil: ref-to-external stdin +build ref.futil: external-to-ref stdin +build memory-info.json: calyx external.futil + backend = yxi +build tb.sv: generate-refmem-testbench memory-info.json +build tmp-out.fir: calyx ref.futil + backend = firrtl + args = --emit-primitive-extmodules +build stdin.fir: dummy tmp-out.fir tb.sv + +default stdin.fir diff --git a/fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap b/fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap new file mode 100644 index 0000000000..8f8b606b8c --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap @@ -0,0 +1,20 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> primitive-uses-json +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +build stdin.json: calyx stdin + backend = primitive-uses + +default stdin.json diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap b/fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap new file mode 100644 index 0000000000..18ba73d9df --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap @@ -0,0 +1,21 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> verilog-noverify +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +build stdin.sv: calyx stdin + backend = verilog + args = --disable-verify + +default stdin.sv diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap b/fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap new file mode 100644 index 0000000000..06fbe4462c --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap @@ -0,0 +1,20 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> verilog +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +build stdin.sv: calyx stdin + backend = verilog + +default stdin.sv diff --git a/fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap b/fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap new file mode 100644 index 0000000000..da86307f8c --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap @@ -0,0 +1,40 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> xo +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +vivado-dir = /test/xilinx/vivado +vitis-dir = /test/xilinx/vitis +build gen_xo.tcl: get-rsrc +build get-ports.py: get-rsrc +python = python3 +rule gen-xo + command = $vivado-dir/bin/vivado -mode batch -source gen_xo.tcl -tclargs $out `$python get-ports.py kernel.xml` + pool = console +xilinx-mode = hw_emu +platform = xilinx_u50_gen3x16_xdma_201920_3 +rule compile-xclbin + command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in + pool = console + +build main.sv: calyx stdin + backend = verilog + args = --synthesis -p external +build toplevel.v: calyx stdin + backend = xilinx +build kernel.xml: calyx stdin + backend = xilinx-xml +build stdin.xo: gen-xo | main.sv toplevel.v kernel.xml gen_xo.tcl get-ports.py + +default stdin.xo diff --git a/fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap b/fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap new file mode 100644 index 0000000000..70717dfbcd --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap @@ -0,0 +1,20 @@ +--- +source: fud2/tests/tests.rs +description: emit calyx -> yxi +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +build stdin.yxi: calyx stdin + backend = yxi + +default stdin.yxi diff --git a/fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap b/fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap new file mode 100644 index 0000000000..0377d85d62 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap @@ -0,0 +1,15 @@ +--- +source: fud2/tests/tests.rs +description: emit dahlia -> calyx +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +dahlia-exe = /test/bin/dahlia +rule dahlia-to-calyx + command = $dahlia-exe -b calyx --lower -l error $in -o $out + +build stdin.futil: dahlia-to-calyx stdin + +default stdin.futil diff --git a/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap b/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap new file mode 100644 index 0000000000..a0f2817b3b --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap @@ -0,0 +1,18 @@ +--- +source: fud2/tests/tests.rs +description: emit firrtl-with-primitives -> verilog-refmem-noverify +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +firrtl-exe = /test/bin/firrtl +rule firrtl + command = $firrtl-exe -i $in -o $out -X sverilog +build primitives-for-firrtl.sv: get-rsrc +rule add-verilog-primitives + command = cat primitives-for-firrtl.sv $in > $out + +build stdin.sv: firrtl stdin + +default stdin.sv diff --git a/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap b/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap new file mode 100644 index 0000000000..50a3566cff --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap @@ -0,0 +1,18 @@ +--- +source: fud2/tests/tests.rs +description: emit firrtl-with-primitives -> verilog-refmem +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +firrtl-exe = /test/bin/firrtl +rule firrtl + command = $firrtl-exe -i $in -o $out -X sverilog +build primitives-for-firrtl.sv: get-rsrc +rule add-verilog-primitives + command = cat primitives-for-firrtl.sv $in > $out + +build stdin.sv: firrtl stdin + +default stdin.sv diff --git a/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap b/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap new file mode 100644 index 0000000000..a84875896f --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap @@ -0,0 +1,19 @@ +--- +source: fud2/tests/tests.rs +description: emit firrtl -> verilog-refmem-noverify +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +firrtl-exe = /test/bin/firrtl +rule firrtl + command = $firrtl-exe -i $in -o $out -X sverilog +build primitives-for-firrtl.sv: get-rsrc +rule add-verilog-primitives + command = cat primitives-for-firrtl.sv $in > $out + +build partial.sv: firrtl stdin +build stdin.sv: add-verilog-primitives partial.sv | primitives-for-firrtl.sv + +default stdin.sv diff --git a/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap b/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap new file mode 100644 index 0000000000..fe8fa49fbb --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap @@ -0,0 +1,19 @@ +--- +source: fud2/tests/tests.rs +description: emit firrtl -> verilog-refmem +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +firrtl-exe = /test/bin/firrtl +rule firrtl + command = $firrtl-exe -i $in -o $out -X sverilog +build primitives-for-firrtl.sv: get-rsrc +rule add-verilog-primitives + command = cat primitives-for-firrtl.sv $in > $out + +build partial.sv: firrtl stdin +build stdin.sv: add-verilog-primitives partial.sv | primitives-for-firrtl.sv + +default stdin.sv diff --git a/fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap b/fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap new file mode 100644 index 0000000000..74b84a8f95 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap @@ -0,0 +1,15 @@ +--- +source: fud2/tests/tests.rs +description: emit mrxl -> calyx +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +mrxl-exe = mrxl +rule mrxl-to-calyx + command = $mrxl-exe $in > $out + +build stdin.futil: mrxl-to-calyx stdin + +default stdin.futil diff --git a/fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap b/fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap new file mode 100644 index 0000000000..c9a7c4c9e3 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap @@ -0,0 +1,27 @@ +--- +source: fud2/tests/tests.rs +description: emit sim -> dat +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build sim.log: sim-run stdin $datadir + bin = stdin + args = +NOTRACE=1 +build stdin.json: json-data $datadir sim.log | json-dat.py + +default stdin.json diff --git a/fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap b/fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap new file mode 100644 index 0000000000..b8d0f0b31c --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap @@ -0,0 +1,26 @@ +--- +source: fud2/tests/tests.rs +description: emit sim -> vcd +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build sim.log stdin.vcd: sim-run stdin $datadir + bin = stdin + args = +NOTRACE=0 +OUT=stdin.vcd + +default stdin.vcd diff --git a/fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap b/fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap new file mode 100644 index 0000000000..1d67e00053 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap @@ -0,0 +1,32 @@ +--- +source: fud2/tests/tests.rs +description: emit verilog-noverify -> sim +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +iverilog = iverilog +rule icarus-compile-standalone-tb + command = $iverilog -g2012 -o $out tb.sv $in +rule icarus-compile-custom-tb + command = $iverilog -g2012 -o $out tb.sv memories.sv $in + +build stdin.exe: icarus-compile-standalone-tb stdin | tb.sv + +default stdin.exe diff --git a/fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap b/fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap new file mode 100644 index 0000000000..2a899db36b --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap @@ -0,0 +1,30 @@ +--- +source: fud2/tests/tests.rs +description: emit verilog-refmem-noverify -> sim +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +iverilog = iverilog +rule icarus-compile-standalone-tb + command = $iverilog -g2012 -o $out tb.sv $in +rule icarus-compile-custom-tb + command = $iverilog -g2012 -o $out tb.sv memories.sv $in + +build stdin.exe: icarus-compile-custom-tb stdin | tb.sv memories.sv + +default stdin.exe diff --git a/fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap b/fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap new file mode 100644 index 0000000000..28f45ce0cb --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap @@ -0,0 +1,46 @@ +--- +source: fud2/tests/tests.rs +description: emit verilog-refmem -> sim +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +rule ref-to-external + command = sed 's/ref /@external /g' $in > $out +rule external-to-ref + command = sed 's/@external([0-9]*)/ref/g' $in | sed 's/@external/ref/g' > $out +gen-testbench-script = $calyx-base/tools/firrtl/generate-testbench.py +build memories.sv: get-rsrc +rule generate-refmem-testbench + command = python3 $gen-testbench-script $in > $out +rule dummy + command = sh -c 'cat $$0' $in > $out + +verilator = verilator +cycle-limit = 500000000 +rule verilator-compile-standalone-tb + command = $verilator $in tb.sv --trace --binary --top-module TOP -fno-inline -Mdir $out-dir +rule verilator-compile-custom-tb + command = $verilator $in tb.sv memories.sv --trace --binary --top-module TOP -fno-inline -Mdir $out-dir +rule cp + command = cp $in $out + +build verilator-out/VTOP: verilator-compile-custom-tb stdin | tb.sv memories.sv + out-dir = verilator-out +build stdin.exe: cp verilator-out/VTOP + +default stdin.exe diff --git a/fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap b/fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap new file mode 100644 index 0000000000..8fcbed609e --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap @@ -0,0 +1,37 @@ +--- +source: fud2/tests/tests.rs +description: emit verilog -> sim +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +verilator = verilator +cycle-limit = 500000000 +rule verilator-compile-standalone-tb + command = $verilator $in tb.sv --trace --binary --top-module TOP -fno-inline -Mdir $out-dir +rule verilator-compile-custom-tb + command = $verilator $in tb.sv memories.sv --trace --binary --top-module TOP -fno-inline -Mdir $out-dir +rule cp + command = cp $in $out + +build verilator-out/VTOP: verilator-compile-standalone-tb stdin | tb.sv + out-dir = verilator-out +build stdin.exe: cp verilator-out/VTOP + +default stdin.exe diff --git a/fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap b/fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap new file mode 100644 index 0000000000..7c3e09f9e7 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap @@ -0,0 +1,56 @@ +--- +source: fud2/tests/tests.rs +description: emit xclbin -> dat +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +vivado-dir = /test/xilinx/vivado +vitis-dir = /test/xilinx/vitis +build gen_xo.tcl: get-rsrc +build get-ports.py: get-rsrc +python = python3 +rule gen-xo + command = $vivado-dir/bin/vivado -mode batch -source gen_xo.tcl -tclargs $out `$python get-ports.py kernel.xml` + pool = console +xilinx-mode = hw_emu +platform = xilinx_u50_gen3x16_xdma_201920_3 +rule compile-xclbin + command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in + pool = console + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +rule emconfig + command = $vitis-dir/bin/emconfigutil --platform $platform +build emconfig.json: emconfig +xrt-dir = /test/xilinx/xrt +rule xclrun + command = bash -c 'source $vitis-dir/settings64.sh ; source $xrt-dir/setup.sh ; XRT_INI_PATH=$xrt_ini EMCONFIG_PATH=. XCL_EMULATION_MODE=$xilinx-mode $python -m fud.xclrun --out $out $in' + pool = console +rule echo + command = echo $contents > $out +build pre_sim.tcl: echo | + contents = open_vcd\\nlog_vcd *\\n +build post_sim.tcl: echo | + contents = close_vcd\\n + +build xrt.ini: get-rsrc +build stdin.json: xclrun stdin $sim_data | emconfig.json xrt.ini + xrt_ini = xrt.ini + +default stdin.json diff --git a/fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap b/fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap new file mode 100644 index 0000000000..f10cf524a1 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap @@ -0,0 +1,56 @@ +--- +source: fud2/tests/tests.rs +description: emit xclbin -> vcd +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +vivado-dir = /test/xilinx/vivado +vitis-dir = /test/xilinx/vitis +build gen_xo.tcl: get-rsrc +build get-ports.py: get-rsrc +python = python3 +rule gen-xo + command = $vivado-dir/bin/vivado -mode batch -source gen_xo.tcl -tclargs $out `$python get-ports.py kernel.xml` + pool = console +xilinx-mode = hw_emu +platform = xilinx_u50_gen3x16_xdma_201920_3 +rule compile-xclbin + command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in + pool = console + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build tb.sv: get-rsrc + +rule emconfig + command = $vitis-dir/bin/emconfigutil --platform $platform +build emconfig.json: emconfig +xrt-dir = /test/xilinx/xrt +rule xclrun + command = bash -c 'source $vitis-dir/settings64.sh ; source $xrt-dir/setup.sh ; XRT_INI_PATH=$xrt_ini EMCONFIG_PATH=. XCL_EMULATION_MODE=$xilinx-mode $python -m fud.xclrun --out $out $in' + pool = console +rule echo + command = echo $contents > $out +build pre_sim.tcl: echo | + contents = open_vcd\\nlog_vcd *\\n +build post_sim.tcl: echo | + contents = close_vcd\\n + +build xrt_trace.ini: get-rsrc +build stdin.vcd: xclrun stdin $sim_data | emconfig.json pre_sim.tcl post_sim.tcl xrt_trace.ini + xrt_ini = xrt_trace.ini + +default stdin.vcd diff --git a/fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap b/fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap new file mode 100644 index 0000000000..711653c100 --- /dev/null +++ b/fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap @@ -0,0 +1,25 @@ +--- +source: fud2/tests/tests.rs +description: emit xo -> xclbin +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +vivado-dir = /test/xilinx/vivado +vitis-dir = /test/xilinx/vitis +build gen_xo.tcl: get-rsrc +build get-ports.py: get-rsrc +python = python3 +rule gen-xo + command = $vivado-dir/bin/vivado -mode batch -source gen_xo.tcl -tclargs $out `$python get-ports.py kernel.xml` + pool = console +xilinx-mode = hw_emu +platform = xilinx_u50_gen3x16_xdma_201920_3 +rule compile-xclbin + command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in + pool = console + +build stdin.xclbin: compile-xclbin stdin + +default stdin.xclbin diff --git a/fud2/tests/tests.rs b/fud2/tests/tests.rs index 1abc4948a9..0d35f3d63e 100644 --- a/fud2/tests/tests.rs +++ b/fud2/tests/tests.rs @@ -83,23 +83,39 @@ fn req_slug(driver: &Driver, req: &Request) -> String { desc } -fn test_emit(driver: &Driver, req: Request) { +fn test_emit(driver: &Driver, req: Request, tag: &str) { let desc = req_desc(driver, &req); let slug = req_slug(driver, &req); let ninja = emit_ninja(driver, req); insta::with_settings!({ description => desc, omit_expression => true, - snapshot_suffix => slug, + snapshot_suffix => format!("{slug}{tag}"), }, { insta::assert_snapshot!(ninja); }); } +#[test] +fn all_ops() { + let driver = test_driver(); + for op in driver.ops.values() { + let req = fud_core::exec::Request { + start_file: None, + start_state: op.input, + end_file: None, + end_state: op.output, + through: vec![], + workdir: ".".into(), + }; + test_emit(&driver, req, &format!("__op_{}", op.name)); + } +} + #[test] fn calyx_to_verilog() { let driver = test_driver(); - test_emit(&driver, request(&driver, "calyx", "verilog", &[])); + test_emit(&driver, request(&driver, "calyx", "verilog", &[]), ""); } #[test] @@ -108,6 +124,7 @@ fn calyx_via_firrtl() { test_emit( &driver, request(&driver, "calyx", "verilog-refmem", &["firrtl"]), + "", ); } @@ -116,7 +133,7 @@ fn sim_tests() { let driver = test_driver(); for dest in &["dat", "vcd"] { for sim in &["icarus", "verilator"] { - test_emit(&driver, request(&driver, "calyx", dest, &[sim])); + test_emit(&driver, request(&driver, "calyx", dest, &[sim]), ""); } } } @@ -124,21 +141,25 @@ fn sim_tests() { #[test] fn cider_tests() { let driver = test_driver(); - test_emit(&driver, request(&driver, "calyx", "dat", &["interp"])); - test_emit(&driver, request(&driver, "calyx", "debug", &[])); + test_emit(&driver, request(&driver, "calyx", "dat", &["interp"]), ""); + test_emit(&driver, request(&driver, "calyx", "debug", &[]), ""); } #[test] fn xrt_tests() { let driver = test_driver(); - test_emit(&driver, request(&driver, "calyx", "dat", &["xrt"])); - test_emit(&driver, request(&driver, "calyx", "vcd", &["xrt-trace"])); + test_emit(&driver, request(&driver, "calyx", "dat", &["xrt"]), ""); + test_emit( + &driver, + request(&driver, "calyx", "vcd", &["xrt-trace"]), + "", + ); } #[test] fn frontend_tests() { let driver = test_driver(); for frontend in &["dahlia", "mrxl"] { - test_emit(&driver, request(&driver, frontend, "calyx", &[])); + test_emit(&driver, request(&driver, frontend, "calyx", &[]), ""); } } From d60687539a2538d493bf19b5d711a48b0f5c1824 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 18:28:03 -0500 Subject: [PATCH 35/47] fix verilator.rhai to use correct testbench for refmem --- fud2/scripts/verilator.rhai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fud2/scripts/verilator.rhai b/fud2/scripts/verilator.rhai index 19fc43155d..3396ec20ce 100644 --- a/fud2/scripts/verilator.rhai +++ b/fud2/scripts/verilator.rhai @@ -48,7 +48,7 @@ op( op( "verilator-refmem", - [sim::sim_setup, tb::standalone_setup, verilator_setup], + [sim::sim_setup, tb::custom_setup, verilator_setup], tb::verilog_refmem, sim::simulator, |e, input, output| { verilator_build(e, input, output, false) } From fd167db236d971b87616c5de64daa0334f2a0e24 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 10 Jun 2024 18:34:30 -0500 Subject: [PATCH 36/47] use .cloned() instead of .map(|x| x.clone()) --- fud2/fud-core/src/script/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fud2/fud-core/src/script/resolver.rs b/fud2/fud-core/src/script/resolver.rs index a1a8027745..92d0a58728 100644 --- a/fud2/fud-core/src/script/resolver.rs +++ b/fud2/fud-core/src/script/resolver.rs @@ -142,7 +142,7 @@ impl rhai::ModuleResolver for Resolver { ) -> RhaiResult> { let path_buf = self .resolve_filename(name) - .map(|x| x.clone()) + .cloned() .unwrap_or(PathBuf::from(name)); // if this path has already failed, don't try loading it again From 34df918db09b7946fe74f4380a81fb2803f984b7 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Thu, 13 Jun 2024 11:05:44 -0500 Subject: [PATCH 37/47] refactor + construct plan directly to exactly specify the op --- ...sts__emit@calyx_calyx__op_axi-wrapped.snap | 10 - ...ebug.snap => tests__test@calyx_debug.snap} | 2 +- ...ts__test@calyx_firrtl_verilog-refmem.snap} | 2 +- ...snap => tests__test@calyx_icarus_dat.snap} | 2 +- ...snap => tests__test@calyx_icarus_vcd.snap} | 2 +- ...snap => tests__test@calyx_interp_dat.snap} | 2 +- ...p => tests__test@calyx_verilator_dat.snap} | 2 +- ...p => tests__test@calyx_verilator_vcd.snap} | 2 +- ...og.snap => tests__test@calyx_verilog.snap} | 2 +- ...p => tests__test@calyx_xrt-trace_vcd.snap} | 2 +- ...at.snap => tests__test@calyx_xrt_dat.snap} | 2 +- ...lyx.snap => tests__test@dahlia_calyx.snap} | 2 +- ...calyx.snap => tests__test@mrxl_calyx.snap} | 2 +- .../tests__test@plan_axi-wrapped.snap | 34 +++ ...p => tests__test@plan_calyx-noverify.snap} | 6 +- ...tests__test@plan_calyx-to-cocotb-axi.snap} | 8 +- ... => tests__test@plan_calyx-to-firrtl.snap} | 10 +- ...=> tests__test@plan_calyx-to-verilog.snap} | 6 +- ...nap => tests__test@plan_calyx-to-yxi.snap} | 6 +- ... => tests__test@plan_dahlia-to-calyx.snap} | 6 +- ...debug.snap => tests__test@plan_debug.snap} | 6 +- ... => tests__test@plan_firrtl-noverify.snap} | 8 +- ...__test@plan_firrtl-with-primitives-2.snap} | 6 +- ...plan_firrtl-with-primitives-noverify.snap} | 6 +- ...ts__test@plan_firrtl-with-primitives.snap} | 10 +- ...rrtl.snap => tests__test@plan_firrtl.snap} | 8 +- ...ap => tests__test@plan_icarus-refmem.snap} | 6 +- ...arus.snap => tests__test@plan_icarus.snap} | 6 +- ...snap => tests__test@plan_interp-flat.snap} | 10 +- ...flat.snap => tests__test@plan_interp.snap} | 8 +- ...ap => tests__test@plan_mrxl-to-calyx.snap} | 6 +- ...p => tests__test@plan_primitive-uses.snap} | 6 +- ...te.snap => tests__test@plan_simulate.snap} | 10 +- ...trace.snap => tests__test@plan_trace.snap} | 10 +- ...=> tests__test@plan_verilator-refmem.snap} | 8 +- ...r.snap => tests__test@plan_verilator.snap} | 8 +- ...lbin.snap => tests__test@plan_xclbin.snap} | 6 +- ...o__op_xo.snap => tests__test@plan_xo.snap} | 12 +- ...e.snap => tests__test@plan_xrt-trace.snap} | 6 +- ..._op_xrt.snap => tests__test@plan_xrt.snap} | 6 +- fud2/tests/tests.rs | 211 ++++++++++-------- 41 files changed, 264 insertions(+), 209 deletions(-) delete mode 100644 fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap rename fud2/tests/snapshots/{tests__emit@calyx_debug__op_debug.snap => tests__test@calyx_debug.snap} (97%) rename fud2/tests/snapshots/{tests__emit@calyx_firrtl_verilog-refmem.snap => tests__test@calyx_firrtl_verilog-refmem.snap} (95%) rename fud2/tests/snapshots/{tests__emit@calyx_icarus_dat.snap => tests__test@calyx_icarus_dat.snap} (95%) rename fud2/tests/snapshots/{tests__emit@calyx_icarus_vcd.snap => tests__test@calyx_icarus_vcd.snap} (95%) rename fud2/tests/snapshots/{tests__emit@calyx_interp_dat.snap => tests__test@calyx_interp_dat.snap} (96%) rename fud2/tests/snapshots/{tests__emit@calyx_verilator_dat.snap => tests__test@calyx_verilator_dat.snap} (96%) rename fud2/tests/snapshots/{tests__emit@calyx_verilator_vcd.snap => tests__test@calyx_verilator_vcd.snap} (95%) rename fud2/tests/snapshots/{tests__emit@calyx_verilog.snap => tests__test@calyx_verilog.snap} (89%) rename fud2/tests/snapshots/{tests__emit@calyx_xrt-trace_vcd.snap => tests__test@calyx_xrt-trace_vcd.snap} (97%) rename fud2/tests/snapshots/{tests__emit@calyx_xrt_dat.snap => tests__test@calyx_xrt_dat.snap} (97%) rename fud2/tests/snapshots/{tests__emit@dahlia_calyx.snap => tests__test@dahlia_calyx.snap} (86%) rename fud2/tests/snapshots/{tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap => tests__test@mrxl_calyx.snap} (84%) create mode 100644 fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap rename fud2/tests/snapshots/{tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap => tests__test@plan_calyx-noverify.snap} (80%) rename fud2/tests/snapshots/{tests__emit@verilog-noverify_cocotb-axi__op_calyx-to-cocotb-axi.snap => tests__test@plan_calyx-to-cocotb-axi.snap} (81%) rename fud2/tests/snapshots/{tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap => tests__test@plan_calyx-to-firrtl.snap} (82%) rename fud2/tests/snapshots/{tests__emit@calyx_verilog__op_calyx-to-verilog.snap => tests__test@plan_calyx-to-verilog.snap} (78%) rename fud2/tests/snapshots/{tests__emit@calyx_yxi__op_calyx-to-yxi.snap => tests__test@plan_calyx-to-yxi.snap} (79%) rename fud2/tests/snapshots/{tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap => tests__test@plan_dahlia-to-calyx.snap} (67%) rename fud2/tests/snapshots/{tests__emit@calyx_debug.snap => tests__test@plan_debug.snap} (93%) rename fud2/tests/snapshots/{tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap => tests__test@plan_firrtl-noverify.snap} (64%) rename fud2/tests/snapshots/{tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap => tests__test@plan_firrtl-with-primitives-2.snap} (75%) rename fud2/tests/snapshots/{tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap => tests__test@plan_firrtl-with-primitives-noverify.snap} (73%) rename fud2/tests/snapshots/{tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap => tests__test@plan_firrtl-with-primitives.snap} (86%) rename fud2/tests/snapshots/{tests__emit@firrtl_verilog-refmem__op_firrtl.snap => tests__test@plan_firrtl.snap} (65%) rename fud2/tests/snapshots/{tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap => tests__test@plan_icarus-refmem.snap} (83%) rename fud2/tests/snapshots/{tests__emit@verilog-noverify_sim__op_icarus.snap => tests__test@plan_icarus.snap} (85%) rename fud2/tests/snapshots/{tests__emit@calyx_dat__op_interp.snap => tests__test@plan_interp-flat.snap} (89%) rename fud2/tests/snapshots/{tests__emit@calyx_dat__op_interp-flat.snap => tests__test@plan_interp.snap} (89%) rename fud2/tests/snapshots/{tests__emit@mrxl_calyx.snap => tests__test@plan_mrxl-to-calyx.snap} (62%) rename fud2/tests/snapshots/{tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap => tests__test@plan_primitive-uses.snap} (79%) rename fud2/tests/snapshots/{tests__emit@sim_dat__op_simulate.snap => tests__test@plan_simulate.snap} (74%) rename fud2/tests/snapshots/{tests__emit@sim_vcd__op_trace.snap => tests__test@plan_trace.snap} (75%) rename fud2/tests/snapshots/{tests__emit@verilog-refmem_sim__op_verilator-refmem.snap => tests__test@plan_verilator-refmem.snap} (87%) rename fud2/tests/snapshots/{tests__emit@verilog_sim__op_verilator.snap => tests__test@plan_verilator.snap} (83%) rename fud2/tests/snapshots/{tests__emit@xo_xclbin__op_xclbin.snap => tests__test@plan_xclbin.snap} (86%) rename fud2/tests/snapshots/{tests__emit@calyx_xo__op_xo.snap => tests__test@plan_xo.snap} (80%) rename fud2/tests/snapshots/{tests__emit@xclbin_vcd__op_xrt-trace.snap => tests__test@plan_xrt-trace.snap} (91%) rename fud2/tests/snapshots/{tests__emit@xclbin_dat__op_xrt.snap => tests__test@plan_xrt.snap} (93%) diff --git a/fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap b/fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap deleted file mode 100644 index c57a11e204..0000000000 --- a/fud2/tests/snapshots/tests__emit@calyx_calyx__op_axi-wrapped.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: fud2/tests/tests.rs -description: emit calyx -> calyx ---- -build-tool = fud2 -rule get-rsrc - command = $build-tool get-rsrc $out - - -default stdin diff --git a/fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap b/fud2/tests/snapshots/tests__test@calyx_debug.snap similarity index 97% rename from fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap rename to fud2/tests/snapshots/tests__test@calyx_debug.snap index 881a924b3f..c93339cc9b 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_debug__op_debug.snap +++ b/fud2/tests/snapshots/tests__test@calyx_debug.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> debug +description: "emit request: calyx -> debug" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap b/fud2/tests/snapshots/tests__test@calyx_firrtl_verilog-refmem.snap similarity index 95% rename from fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap rename to fud2/tests/snapshots/tests__test@calyx_firrtl_verilog-refmem.snap index 4e3a2aa5fd..fa8e62c728 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_firrtl_verilog-refmem.snap +++ b/fud2/tests/snapshots/tests__test@calyx_firrtl_verilog-refmem.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> verilog-refmem through firrtl +description: "emit request: calyx -> verilog-refmem through firrtl" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap b/fud2/tests/snapshots/tests__test@calyx_icarus_dat.snap similarity index 95% rename from fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap rename to fud2/tests/snapshots/tests__test@calyx_icarus_dat.snap index 6b2d670e94..805fc16fae 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_icarus_dat.snap +++ b/fud2/tests/snapshots/tests__test@calyx_icarus_dat.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> dat through icarus +description: "emit request: calyx -> dat through icarus" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap b/fud2/tests/snapshots/tests__test@calyx_icarus_vcd.snap similarity index 95% rename from fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap rename to fud2/tests/snapshots/tests__test@calyx_icarus_vcd.snap index e93721ae80..14280a0cf7 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_icarus_vcd.snap +++ b/fud2/tests/snapshots/tests__test@calyx_icarus_vcd.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> vcd through icarus +description: "emit request: calyx -> vcd through icarus" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap b/fud2/tests/snapshots/tests__test@calyx_interp_dat.snap similarity index 96% rename from fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap rename to fud2/tests/snapshots/tests__test@calyx_interp_dat.snap index a634f96932..228919ba7c 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_interp_dat.snap +++ b/fud2/tests/snapshots/tests__test@calyx_interp_dat.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> dat through interp +description: "emit request: calyx -> dat through interp" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap b/fud2/tests/snapshots/tests__test@calyx_verilator_dat.snap similarity index 96% rename from fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap rename to fud2/tests/snapshots/tests__test@calyx_verilator_dat.snap index 1d30feedd8..151806b1c1 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilator_dat.snap +++ b/fud2/tests/snapshots/tests__test@calyx_verilator_dat.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> dat through verilator +description: "emit request: calyx -> dat through verilator" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap b/fud2/tests/snapshots/tests__test@calyx_verilator_vcd.snap similarity index 95% rename from fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap rename to fud2/tests/snapshots/tests__test@calyx_verilator_vcd.snap index 25da89a06c..89528e6df7 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilator_vcd.snap +++ b/fud2/tests/snapshots/tests__test@calyx_verilator_vcd.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> vcd through verilator +description: "emit request: calyx -> vcd through verilator" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilog.snap b/fud2/tests/snapshots/tests__test@calyx_verilog.snap similarity index 89% rename from fud2/tests/snapshots/tests__emit@calyx_verilog.snap rename to fud2/tests/snapshots/tests__test@calyx_verilog.snap index 06fbe4462c..056dd94f43 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilog.snap +++ b/fud2/tests/snapshots/tests__test@calyx_verilog.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> verilog +description: "emit request: calyx -> verilog" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap b/fud2/tests/snapshots/tests__test@calyx_xrt-trace_vcd.snap similarity index 97% rename from fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap rename to fud2/tests/snapshots/tests__test@calyx_xrt-trace_vcd.snap index bcec9ce14e..fe92f184c0 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_xrt-trace_vcd.snap +++ b/fud2/tests/snapshots/tests__test@calyx_xrt-trace_vcd.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> vcd through xrt-trace +description: "emit request: calyx -> vcd through xrt-trace" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap b/fud2/tests/snapshots/tests__test@calyx_xrt_dat.snap similarity index 97% rename from fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap rename to fud2/tests/snapshots/tests__test@calyx_xrt_dat.snap index 120233e737..ecefaffde7 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_xrt_dat.snap +++ b/fud2/tests/snapshots/tests__test@calyx_xrt_dat.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> dat through xrt +description: "emit request: calyx -> dat through xrt" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@dahlia_calyx.snap b/fud2/tests/snapshots/tests__test@dahlia_calyx.snap similarity index 86% rename from fud2/tests/snapshots/tests__emit@dahlia_calyx.snap rename to fud2/tests/snapshots/tests__test@dahlia_calyx.snap index 0377d85d62..b4fb83da93 100644 --- a/fud2/tests/snapshots/tests__emit@dahlia_calyx.snap +++ b/fud2/tests/snapshots/tests__test@dahlia_calyx.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit dahlia -> calyx +description: "emit request: dahlia -> calyx" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap b/fud2/tests/snapshots/tests__test@mrxl_calyx.snap similarity index 84% rename from fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap rename to fud2/tests/snapshots/tests__test@mrxl_calyx.snap index 74b84a8f95..6516c15f8f 100644 --- a/fud2/tests/snapshots/tests__emit@mrxl_calyx__op_mrxl-to-calyx.snap +++ b/fud2/tests/snapshots/tests__test@mrxl_calyx.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit mrxl -> calyx +description: "emit request: mrxl -> calyx" --- build-tool = fud2 rule get-rsrc diff --git a/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap b/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap new file mode 100644 index 0000000000..975e3bb755 --- /dev/null +++ b/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap @@ -0,0 +1,34 @@ +--- +source: fud2/tests/tests.rs +description: "emit plan: axi-wrapped" +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out + +axi-generator = $calyx-base/yxi/axi-calyx/axi-generator.py +python = python3 +rule gen-axi + command = $python $axi-generator $in > $out +rule combine + command = cat $in > $out +rule remove-imports + command = sed '1,/component main/{/component main/!d}' $in > $out + +build input.yxi: calyx /input.ext + backend = yxi +build refified_input.futil: calyx-pass /input.ext + pass = external-to-ref +build axi_wrapper.futil: gen-axi input.yxi +build no_imports_refified_input.futil: remove-imports refified_input.futil +build /output.ext: combine axi_wrapper.futil no_imports_refified_input.futil + +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap b/fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap similarity index 80% rename from fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap rename to fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap index 18ba73d9df..9b23ee70d4 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilog-noverify__op_calyx-noverify.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> verilog-noverify +description: "emit plan: calyx-noverify" --- build-tool = fud2 rule get-rsrc @@ -14,8 +14,8 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -build stdin.sv: calyx stdin +build /output.ext: calyx /input.ext backend = verilog args = --disable-verify -default stdin.sv +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@verilog-noverify_cocotb-axi__op_calyx-to-cocotb-axi.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap similarity index 81% rename from fud2/tests/snapshots/tests__emit@verilog-noverify_cocotb-axi__op_calyx-to-cocotb-axi.snap rename to fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap index 918c4e8703..845bd10ca6 100644 --- a/fud2/tests/snapshots/tests__emit@verilog-noverify_cocotb-axi__op_calyx-to-cocotb-axi.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit verilog-noverify -> cocotb-axi +description: "emit plan: calyx-to-cocotb-axi" --- build-tool = fud2 rule get-rsrc @@ -26,7 +26,7 @@ rule cleanup-cocotb build Makefile: copy $cocotb-makefile-dir/Makefile build axi_test.py: copy $cocotb-makefile-dir/axi_test.py build run_axi_test.py: copy $cocotb-makefile-dir/run_axi_test.py -build tmp.dat: make-cocotb stdin | Makefile axi_test.py run_axi_test.py -build stdin.dat: cleanup-cocotb tmp.dat +build tmp.dat: make-cocotb /input.ext | Makefile axi_test.py run_axi_test.py +build /output.ext: cleanup-cocotb tmp.dat -default stdin.dat +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap similarity index 82% rename from fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap rename to fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap index c6fb982661..9b5d99e388 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_firrtl__op_calyx-to-firrtl.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> firrtl +description: "emit plan: calyx-to-firrtl" --- build-tool = fud2 rule get-rsrc @@ -25,14 +25,14 @@ rule generate-refmem-testbench rule dummy command = sh -c 'cat $$0' $in > $out -build external.futil: ref-to-external stdin -build ref.futil: external-to-ref stdin +build external.futil: ref-to-external /input.ext +build ref.futil: external-to-ref /input.ext build memory-info.json: calyx external.futil backend = yxi build tb.sv: generate-refmem-testbench memory-info.json build tmp-out.fir: calyx ref.futil backend = firrtl args = --emit-primitive-extmodules -build stdin.fir: dummy tmp-out.fir tb.sv +build /output.ext: dummy tmp-out.fir tb.sv -default stdin.fir +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap similarity index 78% rename from fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap rename to fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap index 06fbe4462c..4748d039c4 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_verilog__op_calyx-to-verilog.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> verilog +description: "emit plan: calyx-to-verilog" --- build-tool = fud2 rule get-rsrc @@ -14,7 +14,7 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -build stdin.sv: calyx stdin +build /output.ext: calyx /input.ext backend = verilog -default stdin.sv +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap similarity index 79% rename from fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap rename to fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap index 70717dfbcd..2884ee94fa 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_yxi__op_calyx-to-yxi.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> yxi +description: "emit plan: calyx-to-yxi" --- build-tool = fud2 rule get-rsrc @@ -14,7 +14,7 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -build stdin.yxi: calyx stdin +build /output.ext: calyx /input.ext backend = yxi -default stdin.yxi +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap b/fud2/tests/snapshots/tests__test@plan_dahlia-to-calyx.snap similarity index 67% rename from fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap rename to fud2/tests/snapshots/tests__test@plan_dahlia-to-calyx.snap index 0377d85d62..b6ebd043e6 100644 --- a/fud2/tests/snapshots/tests__emit@dahlia_calyx__op_dahlia-to-calyx.snap +++ b/fud2/tests/snapshots/tests__test@plan_dahlia-to-calyx.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit dahlia -> calyx +description: "emit plan: dahlia-to-calyx" --- build-tool = fud2 rule get-rsrc @@ -10,6 +10,6 @@ dahlia-exe = /test/bin/dahlia rule dahlia-to-calyx command = $dahlia-exe -b calyx --lower -l error $in -o $out -build stdin.futil: dahlia-to-calyx stdin +build /output.ext: dahlia-to-calyx /input.ext -default stdin.futil +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_debug.snap b/fud2/tests/snapshots/tests__test@plan_debug.snap similarity index 93% rename from fud2/tests/snapshots/tests__emit@calyx_debug.snap rename to fud2/tests/snapshots/tests__test@plan_debug.snap index 881a924b3f..ea83ec8cbc 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_debug.snap +++ b/fud2/tests/snapshots/tests__test@plan_debug.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> debug +description: "emit plan: debug" --- build-tool = fud2 rule get-rsrc @@ -51,6 +51,6 @@ rule interp-to-dump command = $cider-converter --to json $in > $out build data.dump: dump-to-interp $sim_data | $cider-converter -build _pseudo_debug: cider-debug stdin | data.json +build /output.ext: cider-debug /input.ext | data.json -default _pseudo_debug +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap b/fud2/tests/snapshots/tests__test@plan_firrtl-noverify.snap similarity index 64% rename from fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap rename to fud2/tests/snapshots/tests__test@plan_firrtl-noverify.snap index a84875896f..63333b0431 100644 --- a/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem-noverify__op_firrtl-noverify.snap +++ b/fud2/tests/snapshots/tests__test@plan_firrtl-noverify.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit firrtl -> verilog-refmem-noverify +description: "emit plan: firrtl-noverify" --- build-tool = fud2 rule get-rsrc @@ -13,7 +13,7 @@ build primitives-for-firrtl.sv: get-rsrc rule add-verilog-primitives command = cat primitives-for-firrtl.sv $in > $out -build partial.sv: firrtl stdin -build stdin.sv: add-verilog-primitives partial.sv | primitives-for-firrtl.sv +build partial.sv: firrtl /input.ext +build /output.ext: add-verilog-primitives partial.sv | primitives-for-firrtl.sv -default stdin.sv +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives-2.snap similarity index 75% rename from fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap rename to fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives-2.snap index 50a3566cff..ad304ba392 100644 --- a/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem__op_firrtl-with-primitives.snap +++ b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives-2.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit firrtl-with-primitives -> verilog-refmem +description: "emit plan: firrtl-with-primitives" --- build-tool = fud2 rule get-rsrc @@ -13,6 +13,6 @@ build primitives-for-firrtl.sv: get-rsrc rule add-verilog-primitives command = cat primitives-for-firrtl.sv $in > $out -build stdin.sv: firrtl stdin +build /output.ext: firrtl /input.ext -default stdin.sv +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives-noverify.snap similarity index 73% rename from fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap rename to fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives-noverify.snap index a0f2817b3b..22171f9429 100644 --- a/fud2/tests/snapshots/tests__emit@firrtl-with-primitives_verilog-refmem-noverify__op_firrtl-with-primitives-noverify.snap +++ b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives-noverify.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit firrtl-with-primitives -> verilog-refmem-noverify +description: "emit plan: firrtl-with-primitives-noverify" --- build-tool = fud2 rule get-rsrc @@ -13,6 +13,6 @@ build primitives-for-firrtl.sv: get-rsrc rule add-verilog-primitives command = cat primitives-for-firrtl.sv $in > $out -build stdin.sv: firrtl stdin +build /output.ext: firrtl /input.ext -default stdin.sv +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap similarity index 86% rename from fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap rename to fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap index 24de1967d3..619ca4bcb8 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_firrtl-with-primitives__op_firrtl-with-primitives.snap +++ b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> firrtl-with-primitives +description: "emit plan: firrtl-with-primitives" --- build-tool = fud2 rule get-rsrc @@ -29,8 +29,8 @@ rule generate-refmem-testbench rule dummy command = sh -c 'cat $$0' $in > $out -build external.futil: ref-to-external stdin -build ref.futil: external-to-ref stdin +build external.futil: ref-to-external /input.ext +build ref.futil: external-to-ref /input.ext build memory-info.json: calyx external.futil backend = yxi build tb.sv: generate-refmem-testbench memory-info.json @@ -41,6 +41,6 @@ build primitive-uses.json: calyx ref.futil backend = primitive-uses args = --synthesis build tmp-out.fir: generate-firrtl-with-primitives core.fir primitive-uses.json -build stdin.fir: dummy tmp-out.fir tb.sv +build /output.ext: dummy tmp-out.fir tb.sv -default stdin.fir +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap b/fud2/tests/snapshots/tests__test@plan_firrtl.snap similarity index 65% rename from fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap rename to fud2/tests/snapshots/tests__test@plan_firrtl.snap index fe8fa49fbb..da2114436a 100644 --- a/fud2/tests/snapshots/tests__emit@firrtl_verilog-refmem__op_firrtl.snap +++ b/fud2/tests/snapshots/tests__test@plan_firrtl.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit firrtl -> verilog-refmem +description: "emit plan: firrtl" --- build-tool = fud2 rule get-rsrc @@ -13,7 +13,7 @@ build primitives-for-firrtl.sv: get-rsrc rule add-verilog-primitives command = cat primitives-for-firrtl.sv $in > $out -build partial.sv: firrtl stdin -build stdin.sv: add-verilog-primitives partial.sv | primitives-for-firrtl.sv +build partial.sv: firrtl /input.ext +build /output.ext: add-verilog-primitives partial.sv | primitives-for-firrtl.sv -default stdin.sv +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap b/fud2/tests/snapshots/tests__test@plan_icarus-refmem.snap similarity index 83% rename from fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap rename to fud2/tests/snapshots/tests__test@plan_icarus-refmem.snap index 2a899db36b..e136366e25 100644 --- a/fud2/tests/snapshots/tests__emit@verilog-refmem-noverify_sim__op_icarus-refmem.snap +++ b/fud2/tests/snapshots/tests__test@plan_icarus-refmem.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit verilog-refmem-noverify -> sim +description: "emit plan: icarus-refmem" --- build-tool = fud2 rule get-rsrc @@ -25,6 +25,6 @@ rule icarus-compile-standalone-tb rule icarus-compile-custom-tb command = $iverilog -g2012 -o $out tb.sv memories.sv $in -build stdin.exe: icarus-compile-custom-tb stdin | tb.sv memories.sv +build /output.ext: icarus-compile-custom-tb /input.ext | tb.sv memories.sv -default stdin.exe +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap b/fud2/tests/snapshots/tests__test@plan_icarus.snap similarity index 85% rename from fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap rename to fud2/tests/snapshots/tests__test@plan_icarus.snap index 1d67e00053..b24cc2196e 100644 --- a/fud2/tests/snapshots/tests__emit@verilog-noverify_sim__op_icarus.snap +++ b/fud2/tests/snapshots/tests__test@plan_icarus.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit verilog-noverify -> sim +description: "emit plan: icarus" --- build-tool = fud2 rule get-rsrc @@ -27,6 +27,6 @@ rule icarus-compile-standalone-tb rule icarus-compile-custom-tb command = $iverilog -g2012 -o $out tb.sv memories.sv $in -build stdin.exe: icarus-compile-standalone-tb stdin | tb.sv +build /output.ext: icarus-compile-standalone-tb /input.ext | tb.sv -default stdin.exe +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap b/fud2/tests/snapshots/tests__test@plan_interp-flat.snap similarity index 89% rename from fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap rename to fud2/tests/snapshots/tests__test@plan_interp-flat.snap index ce2207e4c1..5fd1a3956e 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp.snap +++ b/fud2/tests/snapshots/tests__test@plan_interp-flat.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> dat +description: "emit plan: interp-flat" --- build-tool = fud2 rule get-rsrc @@ -19,8 +19,6 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -build tb.sv: get-rsrc - calyx-base = /test/calyx calyx-exe = $calyx-base/target/debug/calyx args = @@ -51,7 +49,7 @@ rule interp-to-dump command = $cider-converter --to json $in > $out build data.dump: dump-to-interp $sim_data | $cider-converter -build interp_out.json: cider stdin | data.json -build stdin.json: interp-to-dat interp_out.json | $sim_data interp-dat.py +build interp_out.dump: cider2 /input.ext | data.dump +build /output.ext: interp-to-dump interp_out.dump | $sim_data $cider-converter -default stdin.json +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap b/fud2/tests/snapshots/tests__test@plan_interp.snap similarity index 89% rename from fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap rename to fud2/tests/snapshots/tests__test@plan_interp.snap index ce2207e4c1..a7ab43d288 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_dat__op_interp-flat.snap +++ b/fud2/tests/snapshots/tests__test@plan_interp.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> dat +description: "emit plan: interp" --- build-tool = fud2 rule get-rsrc @@ -51,7 +51,7 @@ rule interp-to-dump command = $cider-converter --to json $in > $out build data.dump: dump-to-interp $sim_data | $cider-converter -build interp_out.json: cider stdin | data.json -build stdin.json: interp-to-dat interp_out.json | $sim_data interp-dat.py +build interp_out.json: cider /input.ext | data.json +build /output.ext: interp-to-dat interp_out.json | $sim_data interp-dat.py -default stdin.json +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@mrxl_calyx.snap b/fud2/tests/snapshots/tests__test@plan_mrxl-to-calyx.snap similarity index 62% rename from fud2/tests/snapshots/tests__emit@mrxl_calyx.snap rename to fud2/tests/snapshots/tests__test@plan_mrxl-to-calyx.snap index 74b84a8f95..8addc1809d 100644 --- a/fud2/tests/snapshots/tests__emit@mrxl_calyx.snap +++ b/fud2/tests/snapshots/tests__test@plan_mrxl-to-calyx.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit mrxl -> calyx +description: "emit plan: mrxl-to-calyx" --- build-tool = fud2 rule get-rsrc @@ -10,6 +10,6 @@ mrxl-exe = mrxl rule mrxl-to-calyx command = $mrxl-exe $in > $out -build stdin.futil: mrxl-to-calyx stdin +build /output.ext: mrxl-to-calyx /input.ext -default stdin.futil +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap b/fud2/tests/snapshots/tests__test@plan_primitive-uses.snap similarity index 79% rename from fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap rename to fud2/tests/snapshots/tests__test@plan_primitive-uses.snap index 8f8b606b8c..a6a281e573 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_primitive-uses-json__op_primitive-uses.snap +++ b/fud2/tests/snapshots/tests__test@plan_primitive-uses.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> primitive-uses-json +description: "emit plan: primitive-uses" --- build-tool = fud2 rule get-rsrc @@ -14,7 +14,7 @@ rule calyx rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out -build stdin.json: calyx stdin +build /output.ext: calyx /input.ext backend = primitive-uses -default stdin.json +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap b/fud2/tests/snapshots/tests__test@plan_simulate.snap similarity index 74% rename from fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap rename to fud2/tests/snapshots/tests__test@plan_simulate.snap index c9a7c4c9e3..fdcbbd590d 100644 --- a/fud2/tests/snapshots/tests__emit@sim_dat__op_simulate.snap +++ b/fud2/tests/snapshots/tests__test@plan_simulate.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit sim -> dat +description: "emit plan: simulate" --- build-tool = fud2 rule get-rsrc @@ -19,9 +19,9 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -build sim.log: sim-run stdin $datadir - bin = stdin +build sim.log: sim-run /input.ext $datadir + bin = /input.ext args = +NOTRACE=1 -build stdin.json: json-data $datadir sim.log | json-dat.py +build /output.ext: json-data $datadir sim.log | json-dat.py -default stdin.json +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap b/fud2/tests/snapshots/tests__test@plan_trace.snap similarity index 75% rename from fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap rename to fud2/tests/snapshots/tests__test@plan_trace.snap index b8d0f0b31c..37cb1b881a 100644 --- a/fud2/tests/snapshots/tests__emit@sim_vcd__op_trace.snap +++ b/fud2/tests/snapshots/tests__test@plan_trace.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit sim -> vcd +description: "emit plan: trace" --- build-tool = fud2 rule get-rsrc @@ -19,8 +19,8 @@ rule sim-run command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out cycle-limit = 500000000 -build sim.log stdin.vcd: sim-run stdin $datadir - bin = stdin - args = +NOTRACE=0 +OUT=stdin.vcd +build sim.log /output.ext: sim-run /input.ext $datadir + bin = /input.ext + args = +NOTRACE=0 +OUT=/output.ext -default stdin.vcd +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap b/fud2/tests/snapshots/tests__test@plan_verilator-refmem.snap similarity index 87% rename from fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap rename to fud2/tests/snapshots/tests__test@plan_verilator-refmem.snap index 28f45ce0cb..e217d36c24 100644 --- a/fud2/tests/snapshots/tests__emit@verilog-refmem_sim__op_verilator-refmem.snap +++ b/fud2/tests/snapshots/tests__test@plan_verilator-refmem.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit verilog-refmem -> sim +description: "emit plan: verilator-refmem" --- build-tool = fud2 rule get-rsrc @@ -39,8 +39,8 @@ rule verilator-compile-custom-tb rule cp command = cp $in $out -build verilator-out/VTOP: verilator-compile-custom-tb stdin | tb.sv memories.sv +build verilator-out/VTOP: verilator-compile-custom-tb /input.ext | tb.sv memories.sv out-dir = verilator-out -build stdin.exe: cp verilator-out/VTOP +build /output.ext: cp verilator-out/VTOP -default stdin.exe +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap b/fud2/tests/snapshots/tests__test@plan_verilator.snap similarity index 83% rename from fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap rename to fud2/tests/snapshots/tests__test@plan_verilator.snap index 8fcbed609e..ff6bf736ce 100644 --- a/fud2/tests/snapshots/tests__emit@verilog_sim__op_verilator.snap +++ b/fud2/tests/snapshots/tests__test@plan_verilator.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit verilog -> sim +description: "emit plan: verilator" --- build-tool = fud2 rule get-rsrc @@ -30,8 +30,8 @@ rule verilator-compile-custom-tb rule cp command = cp $in $out -build verilator-out/VTOP: verilator-compile-standalone-tb stdin | tb.sv +build verilator-out/VTOP: verilator-compile-standalone-tb /input.ext | tb.sv out-dir = verilator-out -build stdin.exe: cp verilator-out/VTOP +build /output.ext: cp verilator-out/VTOP -default stdin.exe +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap b/fud2/tests/snapshots/tests__test@plan_xclbin.snap similarity index 86% rename from fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap rename to fud2/tests/snapshots/tests__test@plan_xclbin.snap index 711653c100..c2be705dc0 100644 --- a/fud2/tests/snapshots/tests__emit@xo_xclbin__op_xclbin.snap +++ b/fud2/tests/snapshots/tests__test@plan_xclbin.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit xo -> xclbin +description: "emit plan: xclbin" --- build-tool = fud2 rule get-rsrc @@ -20,6 +20,6 @@ rule compile-xclbin command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in pool = console -build stdin.xclbin: compile-xclbin stdin +build /output.ext: compile-xclbin /input.ext -default stdin.xclbin +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap b/fud2/tests/snapshots/tests__test@plan_xo.snap similarity index 80% rename from fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap rename to fud2/tests/snapshots/tests__test@plan_xo.snap index da86307f8c..4d4257484e 100644 --- a/fud2/tests/snapshots/tests__emit@calyx_xo__op_xo.snap +++ b/fud2/tests/snapshots/tests__test@plan_xo.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit calyx -> xo +description: "emit plan: xo" --- build-tool = fud2 rule get-rsrc @@ -28,13 +28,13 @@ rule compile-xclbin command = $vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in pool = console -build main.sv: calyx stdin +build main.sv: calyx /input.ext backend = verilog args = --synthesis -p external -build toplevel.v: calyx stdin +build toplevel.v: calyx /input.ext backend = xilinx -build kernel.xml: calyx stdin +build kernel.xml: calyx /input.ext backend = xilinx-xml -build stdin.xo: gen-xo | main.sv toplevel.v kernel.xml gen_xo.tcl get-ports.py +build /output.ext: gen-xo | main.sv toplevel.v kernel.xml gen_xo.tcl get-ports.py -default stdin.xo +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap b/fud2/tests/snapshots/tests__test@plan_xrt-trace.snap similarity index 91% rename from fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap rename to fud2/tests/snapshots/tests__test@plan_xrt-trace.snap index f10cf524a1..921110b2b0 100644 --- a/fud2/tests/snapshots/tests__emit@xclbin_vcd__op_xrt-trace.snap +++ b/fud2/tests/snapshots/tests__test@plan_xrt-trace.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit xclbin -> vcd +description: "emit plan: xrt-trace" --- build-tool = fud2 rule get-rsrc @@ -50,7 +50,7 @@ build post_sim.tcl: echo | contents = close_vcd\\n build xrt_trace.ini: get-rsrc -build stdin.vcd: xclrun stdin $sim_data | emconfig.json pre_sim.tcl post_sim.tcl xrt_trace.ini +build /output.ext: xclrun /input.ext $sim_data | emconfig.json pre_sim.tcl post_sim.tcl xrt_trace.ini xrt_ini = xrt_trace.ini -default stdin.vcd +default /output.ext diff --git a/fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap b/fud2/tests/snapshots/tests__test@plan_xrt.snap similarity index 93% rename from fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap rename to fud2/tests/snapshots/tests__test@plan_xrt.snap index 7c3e09f9e7..fd2d9433e6 100644 --- a/fud2/tests/snapshots/tests__emit@xclbin_dat__op_xrt.snap +++ b/fud2/tests/snapshots/tests__test@plan_xrt.snap @@ -1,6 +1,6 @@ --- source: fud2/tests/tests.rs -description: emit xclbin -> dat +description: "emit plan: xrt" --- build-tool = fud2 rule get-rsrc @@ -50,7 +50,7 @@ build post_sim.tcl: echo | contents = close_vcd\\n build xrt.ini: get-rsrc -build stdin.json: xclrun stdin $sim_data | emconfig.json xrt.ini +build /output.ext: xclrun /input.ext $sim_data | emconfig.json xrt.ini xrt_ini = xrt.ini -default stdin.json +default /output.ext diff --git a/fud2/tests/tests.rs b/fud2/tests/tests.rs index 8e08a46af1..7180d391d6 100644 --- a/fud2/tests/tests.rs +++ b/fud2/tests/tests.rs @@ -1,5 +1,8 @@ use fud_core::{ - config::default_config, exec::Request, run::Run, Driver, DriverBuilder, + config::default_config, + exec::{Plan, Request}, + run::Run, + Driver, DriverBuilder, }; use itertools::Itertools; @@ -17,6 +20,109 @@ fn test_driver() -> Driver { bld.load_plugins().build() } +trait InstaTest: Sized { + /// Get a human-readable description of Self. + fn desc(&self, driver: &Driver) -> String; + + /// Get a short string uniquely identifying Self. + fn slug(&self, driver: &Driver) -> String; + + /// Emit the string that will be snapshot tested. + fn emit(self, driver: &Driver) -> String; + + /// Run snapshap test + fn test(self, driver: &Driver) { + let desc = self.desc(driver); + let slug = self.slug(driver); + let snapshot = self.emit(driver); + insta::with_settings!({ + description => desc, + omit_expression => true, + snapshot_suffix => format!("{slug}"), + }, { + insta::assert_snapshot!(snapshot); + }); + } +} + +impl InstaTest for Plan { + fn desc(&self, driver: &Driver) -> String { + let ops = self + .steps + .iter() + .map(|(opref, _path)| driver.ops[*opref].name.to_string()) + .collect_vec() + .join(" -> "); + format!("emit plan: {ops}") + } + + fn slug(&self, driver: &Driver) -> String { + let ops = self + .steps + .iter() + .map(|(opref, _path)| driver.ops[*opref].name.to_string()) + .collect_vec() + .join("_"); + format!("plan_{ops}") + } + + fn emit(self, driver: &Driver) -> String { + let config = default_config() + .merge(("exe", "fud2")) + .merge(("calyx.base", "/test/calyx")) + .merge(("firrtl.exe", "/test/bin/firrtl")) + .merge(("sim.data", "/test/data.json")) + .merge(("xilinx.vivado", "/test/xilinx/vivado")) + .merge(("xilinx.vitis", "/test/xilinx/vitis")) + .merge(("xilinx.xrt", "/test/xilinx/xrt")) + .merge(("dahlia", "/test/bin/dahlia")); + let run = Run::with_config(driver, self, config); + let mut buf = vec![]; + run.emit(&mut buf).unwrap(); + // turn into string, and remove comments + String::from_utf8(buf) + .unwrap() + .lines() + .filter(|line| !line.starts_with('#')) + .collect::>() + .join("\n") + } +} + +impl InstaTest for Request { + fn desc(&self, driver: &Driver) -> String { + let mut desc = format!( + "emit request: {} -> {}", + driver.states[self.start_state].name, + driver.states[self.end_state].name + ); + if !self.through.is_empty() { + desc.push_str(" through"); + for op in &self.through { + desc.push(' '); + desc.push_str(&driver.ops[*op].name); + } + } + desc + } + + fn slug(&self, driver: &Driver) -> String { + let mut desc = driver.states[self.start_state].name.to_string(); + for op in &self.through { + desc.push('_'); + desc.push_str(&driver.ops[*op].name); + } + desc.push('_'); + desc.push_str(&driver.states[self.end_state].name); + desc + } + + fn emit(self, driver: &Driver) -> String { + let plan = driver.plan(self).unwrap(); + plan.emit(driver) + } +} + fn request( driver: &Driver, start: &str, @@ -33,83 +139,18 @@ fn request( } } -fn emit_ninja(driver: &Driver, req: Request) -> String { - let plan = driver.plan(req).unwrap(); - let config = default_config() - .merge(("exe", "fud2")) - .merge(("calyx.base", "/test/calyx")) - .merge(("firrtl.exe", "/test/bin/firrtl")) - .merge(("sim.data", "/test/data.json")) - .merge(("xilinx.vivado", "/test/xilinx/vivado")) - .merge(("xilinx.vitis", "/test/xilinx/vitis")) - .merge(("xilinx.xrt", "/test/xilinx/xrt")) - .merge(("dahlia", "/test/bin/dahlia")); - let run = Run::with_config(driver, plan, config); - let mut buf = vec![]; - run.emit(&mut buf).unwrap(); - // turn into string, and remove comments - String::from_utf8(buf) - .unwrap() - .lines() - .filter(|line| !line.starts_with('#')) - .collect::>() - .join("\n") -} - -/// Get a human-readable description of a request. -fn req_desc(driver: &Driver, req: &Request) -> String { - let mut desc = format!( - "emit {} -> {}", - driver.states[req.start_state].name, driver.states[req.end_state].name - ); - if !req.through.is_empty() { - desc.push_str(" through"); - for op in &req.through { - desc.push(' '); - desc.push_str(&driver.ops[*op].name); - } - } - desc -} - -/// Get a short string uniquely identifying a request. -fn req_slug(driver: &Driver, req: &Request) -> String { - let mut desc = driver.states[req.start_state].name.to_string(); - for op in &req.through { - desc.push('_'); - desc.push_str(&driver.ops[*op].name); - } - desc.push('_'); - desc.push_str(&driver.states[req.end_state].name); - desc -} - -fn test_emit(driver: &Driver, req: Request, tag: &str) { - let desc = req_desc(driver, &req); - let slug = req_slug(driver, &req); - let ninja = emit_ninja(driver, req); - insta::with_settings!({ - description => desc, - omit_expression => true, - snapshot_suffix => format!("{slug}{tag}"), - }, { - insta::assert_snapshot!(ninja); - }); -} - #[test] fn all_ops() { let driver = test_driver(); - for op in driver.ops.values() { - let req = fud_core::exec::Request { - start_file: None, - start_state: op.input, - end_file: None, - end_state: op.output, - through: vec![], + for op in driver.ops.keys() { + let plan = Plan { + start: "/input.ext".into(), + steps: vec![(op, "/output.ext".into())], workdir: ".".into(), + stdin: false, + stdout: false, }; - test_emit(&driver, req, &format!("__op_{}", op.name)); + plan.test(&driver); } } @@ -154,17 +195,13 @@ fn list_ops() { #[test] fn calyx_to_verilog() { let driver = test_driver(); - test_emit(&driver, request(&driver, "calyx", "verilog", &[]), ""); + request(&driver, "calyx", "verilog", &[]).test(&driver); } #[test] fn calyx_via_firrtl() { let driver = test_driver(); - test_emit( - &driver, - request(&driver, "calyx", "verilog-refmem", &["firrtl"]), - "", - ); + request(&driver, "calyx", "verilog-refmem", &["firrtl"]).test(&driver); } #[test] @@ -172,7 +209,7 @@ fn sim_tests() { let driver = test_driver(); for dest in &["dat", "vcd"] { for sim in &["icarus", "verilator"] { - test_emit(&driver, request(&driver, "calyx", dest, &[sim]), ""); + request(&driver, "calyx", dest, &[sim]).test(&driver); } } } @@ -180,25 +217,21 @@ fn sim_tests() { #[test] fn cider_tests() { let driver = test_driver(); - test_emit(&driver, request(&driver, "calyx", "dat", &["interp"]), ""); - test_emit(&driver, request(&driver, "calyx", "debug", &[]), ""); + request(&driver, "calyx", "dat", &["interp"]).test(&driver); + request(&driver, "calyx", "debug", &[]).test(&driver); } #[test] fn xrt_tests() { let driver = test_driver(); - test_emit(&driver, request(&driver, "calyx", "dat", &["xrt"]), ""); - test_emit( - &driver, - request(&driver, "calyx", "vcd", &["xrt-trace"]), - "", - ); + request(&driver, "calyx", "dat", &["xrt"]).test(&driver); + request(&driver, "calyx", "vcd", &["xrt-trace"]).test(&driver); } #[test] fn frontend_tests() { let driver = test_driver(); for frontend in &["dahlia", "mrxl"] { - test_emit(&driver, request(&driver, frontend, "calyx", &[]), ""); + request(&driver, frontend, "calyx", &[]).test(&driver); } } From 5ceb1a526c5b0f71df6baae58272f0bfaaf86dce Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Thu, 13 Jun 2024 11:15:13 -0500 Subject: [PATCH 38/47] fix axi.rhai to match axi-wrapped in lib.rs --- fud2/scripts/axi.rhai | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fud2/scripts/axi.rhai b/fud2/scripts/axi.rhai index 3f225efd6f..15c6725fde 100644 --- a/fud2/scripts/axi.rhai +++ b/fud2/scripts/axi.rhai @@ -20,7 +20,7 @@ fn wrapper_setup(e) { // Define a simple `combine` rule that just concats any number of files. e.rule("combine", "cat $in > $out"); - e.rule("remove-imports", "sed '1,/component main/{/component main/!d; }' $in > $out"); + e.rule("remove-imports", "sed '1,/component main/{/component main/!d}' $in > $out"); } /// Replace the extension in `path` with `new_ext` @@ -40,7 +40,7 @@ fn axi_wrapped_op(e, input, output) { e.build_cmd([tmp_yxi], "calyx", [input], []); e.arg("backend", "yxi"); - let refified_calyx = `refified_${file_name}.futil`; + let refified_calyx = replace_ext(`refified_${file_name}`, "futil"); e.build_cmd([refified_calyx], "calyx-pass", [input], []); e.arg("pass", "external-to-ref"); From f602e83dadaf25c08c2916378ce5a78dd16d2854 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Thu, 13 Jun 2024 11:16:08 -0500 Subject: [PATCH 39/47] export setup fns for verilator.rhai and icarus.rhai --- fud2/scripts/icarus.rhai | 1 + fud2/scripts/verilator.rhai | 2 ++ 2 files changed, 3 insertions(+) diff --git a/fud2/scripts/icarus.rhai b/fud2/scripts/icarus.rhai index 4ca954a96e..a0c3be7c66 100644 --- a/fud2/scripts/icarus.rhai +++ b/fud2/scripts/icarus.rhai @@ -2,6 +2,7 @@ import "calyx" as c; import "rtl_sim" as sim; import "testbench" as tb; +export let icarus_setup = icarus_setup; fn icarus_setup(e) { e.var_("iverilog", "iverilog"); e.rule( diff --git a/fud2/scripts/verilator.rhai b/fud2/scripts/verilator.rhai index 3396ec20ce..891b9f93ba 100644 --- a/fud2/scripts/verilator.rhai +++ b/fud2/scripts/verilator.rhai @@ -2,6 +2,7 @@ import "rtl_sim" as sim; import "testbench" as tb; import "calyx" as c; +export const verilator_setup = verilator_setup; fn verilator_setup(e) { e.config_var_or("verilator", "verilator.exe", "verilator"); e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); @@ -16,6 +17,7 @@ fn verilator_setup(e) { e.rule("cp", "cp $in $out"); } +export const verilator_build = verilator_build; fn verilator_build(e, input, output, standalone_tb) { let out_dir = "verilator-out"; let sim_bin = `${out_dir}/VTOP`; From 90658f6cd141a70662c94e66ea107ec9a074493a Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Thu, 13 Jun 2024 11:20:01 -0500 Subject: [PATCH 40/47] update snapshots for changes in ops --- fud2/tests/snapshots/tests__list_ops.snap | 15 +++-- fud2/tests/snapshots/tests__list_states.snap | 1 + .../tests__test@plan_axi-wrapped.snap | 10 +++- .../tests__test@plan_calyx-noverify.snap | 3 + .../tests__test@plan_calyx-to-cider.snap | 35 +++++++++++ .../tests__test@plan_calyx-to-cocotb-axi.snap | 3 + .../tests__test@plan_calyx-to-firrtl.snap | 6 +- .../tests__test@plan_calyx-to-verilog.snap | 3 + .../tests__test@plan_calyx-to-yxi.snap | 10 +++- .../snapshots/tests__test@plan_cider.snap | 58 +++++++++++++++++++ .../snapshots/tests__test@plan_debug.snap | 5 +- ...sts__test@plan_firrtl-with-primitives.snap | 6 +- .../snapshots/tests__test@plan_interp.snap | 5 +- .../tests__test@plan_primitive-uses.snap | 3 + fud2/tests/snapshots/tests__test@plan_xo.snap | 3 + 15 files changed, 151 insertions(+), 15 deletions(-) create mode 100644 fud2/tests/snapshots/tests__test@plan_calyx-to-cider.snap create mode 100644 fud2/tests/snapshots/tests__test@plan_cider.snap diff --git a/fud2/tests/snapshots/tests__list_ops.snap b/fud2/tests/snapshots/tests__list_ops.snap index 609b5db977..d780efc2e9 100644 --- a/fud2/tests/snapshots/tests__list_ops.snap +++ b/fud2/tests/snapshots/tests__list_ops.snap @@ -12,6 +12,11 @@ source: fud2/tests/tests.rs "calyx", "verilog-noverify", ), + ( + "calyx-to-cider", + "calyx", + "cider", + ), ( "calyx-to-cocotb-axi", "verilog-noverify", @@ -32,6 +37,11 @@ source: fud2/tests/tests.rs "calyx", "yxi", ), + ( + "cider", + "cider", + "dat", + ), ( "dahlia-to-calyx", "dahlia", @@ -82,11 +92,6 @@ source: fud2/tests/tests.rs "calyx", "dat", ), - ( - "interp-flat", - "calyx", - "dat", - ), ( "mrxl-to-calyx", "mrxl", diff --git a/fud2/tests/snapshots/tests__list_states.snap b/fud2/tests/snapshots/tests__list_states.snap index 69937c1b9d..d7f6f169a6 100644 --- a/fud2/tests/snapshots/tests__list_states.snap +++ b/fud2/tests/snapshots/tests__list_states.snap @@ -3,6 +3,7 @@ source: fud2/tests/tests.rs --- [ "calyx", + "cider", "cocotb-axi", "dahlia", "dat", diff --git a/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap b/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap index 975e3bb755..b155363e99 100644 --- a/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap +++ b/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap @@ -13,6 +13,13 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out + +yxi = $calyx-base/target/debug/yxi +rule yxi + command = $yxi -l $calyx-base $in > $out axi-generator = $calyx-base/yxi/axi-calyx/axi-generator.py python = python3 @@ -23,8 +30,7 @@ rule combine rule remove-imports command = sed '1,/component main/{/component main/!d}' $in > $out -build input.yxi: calyx /input.ext - backend = yxi +build input.yxi: yxi /input.ext build refified_input.futil: calyx-pass /input.ext pass = external-to-ref build axi_wrapper.futil: gen-axi input.yxi diff --git a/fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap b/fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap index 9b23ee70d4..826c669cf1 100644 --- a/fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-noverify.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out build /output.ext: calyx /input.ext backend = verilog diff --git a/fud2/tests/snapshots/tests__test@plan_calyx-to-cider.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-cider.snap new file mode 100644 index 0000000000..b39fb7066f --- /dev/null +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-cider.snap @@ -0,0 +1,35 @@ +--- +source: fud2/tests/tests.rs +description: "emit plan: calyx-to-cider" +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out + +build cider-input.futil: calyx-with-flags /input.ext + +default /output.ext diff --git a/fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap index 845bd10ca6..59b6022570 100644 --- a/fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-cocotb-axi.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out cocotb-makefile-dir = $calyx-base/yxi/axi-calyx/cocotb sim_data = /test/data.json diff --git a/fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap index 9b5d99e388..72960c1404 100644 --- a/fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-firrtl.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out rule ref-to-external command = sed 's/ref /@external /g' $in > $out @@ -27,8 +30,7 @@ rule dummy build external.futil: ref-to-external /input.ext build ref.futil: external-to-ref /input.ext -build memory-info.json: calyx external.futil - backend = yxi +build memory-info.json: yxi external.futil build tb.sv: generate-refmem-testbench memory-info.json build tmp-out.fir: calyx ref.futil backend = firrtl diff --git a/fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap index 4748d039c4..2082b62aa2 100644 --- a/fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-verilog.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out build /output.ext: calyx /input.ext backend = verilog diff --git a/fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap b/fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap index 2884ee94fa..50bf573b57 100644 --- a/fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap +++ b/fud2/tests/snapshots/tests__test@plan_calyx-to-yxi.snap @@ -13,8 +13,14 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out -build /output.ext: calyx /input.ext - backend = yxi +yxi = $calyx-base/target/debug/yxi +rule yxi + command = $yxi -l $calyx-base $in > $out + +build /output.ext: yxi /input.ext default /output.ext diff --git a/fud2/tests/snapshots/tests__test@plan_cider.snap b/fud2/tests/snapshots/tests__test@plan_cider.snap new file mode 100644 index 0000000000..055ff2fac7 --- /dev/null +++ b/fud2/tests/snapshots/tests__test@plan_cider.snap @@ -0,0 +1,58 @@ +--- +source: fud2/tests/tests.rs +description: "emit plan: cider" +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +args = +rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out + +cider-exe = $calyx-base/target/debug/cider +cider-converter = $calyx-base/target/debug/cider-data-converter +rule cider + command = $cider-exe -l $calyx-base --raw --data data.json $in > $out +rule cider-debug + command = $cider-exe -l $calyx-base --data data.json $in debug || true + pool = console +build interp-dat.py: get-rsrc +python = python3 +rule dat-to-interp + command = $python interp-dat.py --to-interp $in +rule interp-to-dat + command = $python interp-dat.py --from-interp $in $sim_data > $out +build data.json: dat-to-interp $sim_data | interp-dat.py +rule run-cider + command = $cider-exe -l $calyx-base --data data.dump $in flat > $out +rule dump-to-interp + command = $cider-converter --to cider $in > $out +rule interp-to-dump + command = $cider-converter --to json $in > $out +build data.dump: dump-to-interp $sim_data | $cider-converter + +build interp_out.dump: run-cider cider-input.futil | data.dump +build /output.ext: interp-to-dump interp_out.dump | $sim_data $cider-converter + +default /output.ext diff --git a/fud2/tests/snapshots/tests__test@plan_debug.snap b/fud2/tests/snapshots/tests__test@plan_debug.snap index ea83ec8cbc..13f7f949b1 100644 --- a/fud2/tests/snapshots/tests__test@plan_debug.snap +++ b/fud2/tests/snapshots/tests__test@plan_debug.snap @@ -28,6 +28,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out cider-exe = $calyx-base/target/debug/cider cider-converter = $calyx-base/target/debug/cider-data-converter @@ -43,7 +46,7 @@ rule dat-to-interp rule interp-to-dat command = $python interp-dat.py --from-interp $in $sim_data > $out build data.json: dat-to-interp $sim_data | interp-dat.py -rule cider2 +rule run-cider command = $cider-exe -l $calyx-base --data data.dump $in flat > $out rule dump-to-interp command = $cider-converter --to cider $in > $out diff --git a/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap index 619ca4bcb8..8070441b5e 100644 --- a/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap +++ b/fud2/tests/snapshots/tests__test@plan_firrtl-with-primitives.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out gen-firrtl-primitives-script = $calyx-base/tools/firrtl/generate-firrtl-with-primitives.py rule generate-firrtl-with-primitives @@ -31,8 +34,7 @@ rule dummy build external.futil: ref-to-external /input.ext build ref.futil: external-to-ref /input.ext -build memory-info.json: calyx external.futil - backend = yxi +build memory-info.json: yxi external.futil build tb.sv: generate-refmem-testbench memory-info.json build core.fir: calyx ref.futil backend = firrtl diff --git a/fud2/tests/snapshots/tests__test@plan_interp.snap b/fud2/tests/snapshots/tests__test@plan_interp.snap index a7ab43d288..d0dcaeaa16 100644 --- a/fud2/tests/snapshots/tests__test@plan_interp.snap +++ b/fud2/tests/snapshots/tests__test@plan_interp.snap @@ -28,6 +28,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out cider-exe = $calyx-base/target/debug/cider cider-converter = $calyx-base/target/debug/cider-data-converter @@ -43,7 +46,7 @@ rule dat-to-interp rule interp-to-dat command = $python interp-dat.py --from-interp $in $sim_data > $out build data.json: dat-to-interp $sim_data | interp-dat.py -rule cider2 +rule run-cider command = $cider-exe -l $calyx-base --data data.dump $in flat > $out rule dump-to-interp command = $cider-converter --to cider $in > $out diff --git a/fud2/tests/snapshots/tests__test@plan_primitive-uses.snap b/fud2/tests/snapshots/tests__test@plan_primitive-uses.snap index a6a281e573..b831f243c5 100644 --- a/fud2/tests/snapshots/tests__test@plan_primitive-uses.snap +++ b/fud2/tests/snapshots/tests__test@plan_primitive-uses.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out build /output.ext: calyx /input.ext backend = primitive-uses diff --git a/fud2/tests/snapshots/tests__test@plan_xo.snap b/fud2/tests/snapshots/tests__test@plan_xo.snap index 4d4257484e..3255dbca6b 100644 --- a/fud2/tests/snapshots/tests__test@plan_xo.snap +++ b/fud2/tests/snapshots/tests__test@plan_xo.snap @@ -13,6 +13,9 @@ rule calyx command = $calyx-exe -l $calyx-base -b $backend $args $in > $out rule calyx-pass command = $calyx-exe -l $calyx-base -p $pass $args $in > $out +flags = -p none +rule calyx-with-flags + command = $calyx-exe -l $calyx-base $flags $args $in > $out vivado-dir = /test/xilinx/vivado vitis-dir = /test/xilinx/vitis From 407735a7ac498bf185f647ae71f60ae326dc7a0d Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Thu, 13 Jun 2024 11:21:37 -0500 Subject: [PATCH 41/47] remove old snapshot --- .../tests__test@plan_interp-flat.snap | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 fud2/tests/snapshots/tests__test@plan_interp-flat.snap diff --git a/fud2/tests/snapshots/tests__test@plan_interp-flat.snap b/fud2/tests/snapshots/tests__test@plan_interp-flat.snap deleted file mode 100644 index 5fd1a3956e..0000000000 --- a/fud2/tests/snapshots/tests__test@plan_interp-flat.snap +++ /dev/null @@ -1,55 +0,0 @@ ---- -source: fud2/tests/tests.rs -description: "emit plan: interp-flat" ---- -build-tool = fud2 -rule get-rsrc - command = $build-tool get-rsrc $out - -python = python3 -build json-dat.py: get-rsrc -rule hex-data - command = $python json-dat.py --from-json $in $out -rule json-data - command = $python json-dat.py --to-json $out $in -sim_data = /test/data.json -datadir = sim_data -build $datadir: hex-data $sim_data | json-dat.py -rule sim-run - command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out -cycle-limit = 500000000 - -calyx-base = /test/calyx -calyx-exe = $calyx-base/target/debug/calyx -args = -rule calyx - command = $calyx-exe -l $calyx-base -b $backend $args $in > $out -rule calyx-pass - command = $calyx-exe -l $calyx-base -p $pass $args $in > $out - -cider-exe = $calyx-base/target/debug/cider -cider-converter = $calyx-base/target/debug/cider-data-converter -rule cider - command = $cider-exe -l $calyx-base --raw --data data.json $in > $out -rule cider-debug - command = $cider-exe -l $calyx-base --data data.json $in debug || true - pool = console -build interp-dat.py: get-rsrc -python = python3 -rule dat-to-interp - command = $python interp-dat.py --to-interp $in -rule interp-to-dat - command = $python interp-dat.py --from-interp $in $sim_data > $out -build data.json: dat-to-interp $sim_data | interp-dat.py -rule cider2 - command = $cider-exe -l $calyx-base --data data.dump $in flat > $out -rule dump-to-interp - command = $cider-converter --to cider $in > $out -rule interp-to-dump - command = $cider-converter --to json $in > $out -build data.dump: dump-to-interp $sim_data | $cider-converter - -build interp_out.dump: cider2 /input.ext | data.dump -build /output.ext: interp-to-dump interp_out.dump | $sim_data $cider-converter - -default /output.ext From 2f2ff9366fb8fcccd9d68553f62856f186adc55b Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Thu, 13 Jun 2024 11:35:15 -0500 Subject: [PATCH 42/47] updated rhai scripts to match changes to main --- fud2/scripts/axi.rhai | 15 +++++++++------ fud2/scripts/calyx.rhai | 6 ++++++ fud2/scripts/cider.rhai | 33 ++++++++++++++++++++++++++++----- fud2/scripts/firrtl.rhai | 3 +-- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/fud2/scripts/axi.rhai b/fud2/scripts/axi.rhai index 15c6725fde..e7e795b084 100644 --- a/fud2/scripts/axi.rhai +++ b/fud2/scripts/axi.rhai @@ -2,14 +2,18 @@ import "calyx" as c; export const yxi = state("yxi", ["yxi"]); +fn yxi_setup(e) { + e.config_var_or("yxi", "yxi", "$calyx-base/target/debug/yxi"); + e.rule("yxi", "$yxi -l $calyx-base $in > $out"); +} + op( "calyx-to-yxi", - [c::calyx_setup], + [c::calyx_setup, yxi_setup], c::calyx_state, yxi, |e, input, output| { - e.build_cmd([output], "calyx", [input], []); - e.arg("backend", "yxi"); + e.build_cmd([output], "yxi", [input], []); }, ); @@ -37,8 +41,7 @@ fn axi_wrapped_op(e, input, output) { let file_name = input.split("/")[-1]; let tmp_yxi = replace_ext(file_name, "yxi"); - e.build_cmd([tmp_yxi], "calyx", [input], []); - e.arg("backend", "yxi"); + e.build_cmd([tmp_yxi], "yxi", [input], []); let refified_calyx = replace_ext(`refified_${file_name}`, "futil"); e.build_cmd([refified_calyx], "calyx-pass", [input], []); @@ -55,7 +58,7 @@ fn axi_wrapped_op(e, input, output) { op( "axi-wrapped", - [c::calyx_setup, wrapper_setup], + [c::calyx_setup, yxi_setup, wrapper_setup], c::calyx_state, c::calyx_state, axi_wrapped_op diff --git a/fud2/scripts/calyx.rhai b/fud2/scripts/calyx.rhai index 13829e2e24..83162e51cf 100644 --- a/fud2/scripts/calyx.rhai +++ b/fud2/scripts/calyx.rhai @@ -9,6 +9,12 @@ fn calyx_setup(e) { e.config_var_or("args", "calyx.args", ""); e.rule("calyx", "$calyx-exe -l $calyx-base -b $backend $args $in > $out"); e.rule("calyx-pass", "$calyx-exe -l $calyx-base -p $pass $args $in > $out"); + + e.config_var_or("flags", "calyx.flags", "-p none"); + e.rule( + "calyx-with-flags", + "$calyx-exe -l $calyx-base $flags $args $in > $out", + ); } op( diff --git a/fud2/scripts/cider.rhai b/fud2/scripts/cider.rhai index ee7ed505ee..2bb9f0ef75 100644 --- a/fud2/scripts/cider.rhai +++ b/fud2/scripts/cider.rhai @@ -3,6 +3,7 @@ import "testbench" as tb; import "calyx" as c; let dbg = state("debug", []); +let cider_state = state("cider", []); fn cider_setup(e) { e.config_var_or( @@ -41,7 +42,7 @@ fn cider_setup(e) { ); e.rule( - "cider2", + "run-cider", "$cider-exe -l $calyx-base --data data.dump $in flat > $out", ); @@ -55,6 +56,21 @@ fn cider_setup(e) { ); } +op( + "calyx-to-cider", + [sim::sim_setup, c::calyx_setup], + c::calyx_state, + cider_state, + |e, input, _output| { + e.build_cmd( + ["cider-input.futil"], + "calyx-with-flags", + [input], + [], + ); + }, +); + op( "interp", [ @@ -76,14 +92,20 @@ op( ); }, ); + op( - "interp-flat", + "cider", [sim::sim_setup, c::calyx_setup, cider_setup], - c::calyx_state, + cider_state, sim::dat, - |e, input, output| { + |e, _input, output| { let out_file = "interp_out.dump"; - e.build_cmd([out_file], "cider2", [input], ["data.dump"]); + e.build_cmd( + [out_file], + "run-cider", + ["cider-input.futil"], + ["data.dump"], + ); e.build_cmd( [output], "interp-to-dump", @@ -92,6 +114,7 @@ op( ); }, ); + op( "debug", [ diff --git a/fud2/scripts/firrtl.rhai b/fud2/scripts/firrtl.rhai index 401d92cf9a..8895622c7e 100644 --- a/fud2/scripts/firrtl.rhai +++ b/fud2/scripts/firrtl.rhai @@ -31,8 +31,7 @@ fn calyx_to_firrtl_helper(e, input, output, firrtl_primitives) { e.build_cmd([only_refs_calyx], "external-to-ref", [input], []); // Get YXI to generate JSON for testbench generation - e.build_cmd([memories_json], "calyx", [only_externals_calyx], []); - e.arg("backend", "yxi"); + e.build_cmd([memories_json], "yxi", [only_externals_calyx], []); // generate custom testbench e.build_cmd( [testbench], From 3df2a83d568e0cf84f584900c4451d745770369d Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Mon, 17 Jun 2024 12:15:23 -0500 Subject: [PATCH 43/47] some Rhai scripting documentation --- docs/SUMMARY.md | 3 +- docs/running-calyx/fud2.md | 160 +---------------------------- docs/running-calyx/fud2/index.md | 159 ++++++++++++++++++++++++++++ docs/running-calyx/fud2/scripts.md | 126 +++++++++++++++++++++++ fud2/Cargo.toml | 2 +- 5 files changed, 289 insertions(+), 161 deletions(-) create mode 100644 docs/running-calyx/fud2/index.md create mode 100644 docs/running-calyx/fud2/scripts.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 07bb1b96a4..bd19291978 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -22,7 +22,8 @@ - [Multiple Paths](./running-calyx/fud/multiple-paths.md) - [CIRCT](./running-calyx/fud/circt.md) - [Resource Estimation](./running-calyx/fud/resource-estimation.md) -- [fud2: Experimental Driver](./running-calyx/fud2.md) +- [fud2: Experimental Driver](./running-calyx/fud2/index.md) + - [Scripting](./running-calyx/fud2/scripts.md) - [Interfacing with Calyx RTL](./running-calyx/interfacing.md) - [The Calyx Interpreter](./running-calyx/interpreter.md) diff --git a/docs/running-calyx/fud2.md b/docs/running-calyx/fud2.md index 6ae9088bff..893b283c17 100644 --- a/docs/running-calyx/fud2.md +++ b/docs/running-calyx/fud2.md @@ -1,159 +1 @@ -# fud2: An Experimental Successor to fud - -[fud][] is the compiler driver tool for orchestrating the Calyx ecosystem. -fud2 is an experiment in building a new driver that works like fud that adds some fundamental new capabilities and resolves some underlying problems. - -"Original" fud is still the right tool for almost all jobs; fud2 is in an experimental phase and does not support everything fud can do. -Someday, fud2 may supplant fud, but it needs more work before it is ready to do that. -Until then, fud remains your first choice for all your build-related needs. - -[fud]: ./fud/index.md - -## Set Up - -fud2 is a Rust tool, so you can build it along with everything else in this monorepo with `cargo build`. -You might then want to do something like ``ln -s `pwd`/target/debug/fud2 ~/.local/bin`` for easy access to the `fud2` binary. - -fud2 depends on [Ninja][]. -Install it using your OS package manager or by downloading a binary. - -### Configuration - -Run the following command to edit `fud2`'s configuration file (usually `~/.config/fud2.toml`): - - $ fud2 edit-config - -Add these lines: - -```toml -[calyx] -base = "" -``` - -Now you're ready to use fud2. - -[ninja]: https://ninja-build.org - -## General Use - -You can see complete command-line documentation with `fud2 --help`. -But generally, you want to do something like this: - - $ fud2 -o - -For example, use this to compile a Calyx program to Verilog: - - $ fud2 foo.futil -o bar.sv - -fud2 tries to automatically guess the input and output formats using filename extensions. -If that doesn't work, you can choose for it with `--from ` and `--to `; -for example, this is a more explicit version of the above: - - $ fud2 foo.futil -o bar.sv --from calyx --to verilog - -You can also omit the input and output filenames to instead use stdin and stdout. -In that case, `--from` and `--to` respectively are required. -So here's yet another way to do the same thing: - - $ fud2 --from calyx --to verilog < foo.futil > bar.sv - -This is handy if you just want to print the result of a build to the console: - - $ fud2 foo.futil --to verilog - -Some operations use other configuration options, which can come from either your `fud2.toml` or the command line. -Use `--set key=value` to override any such option. - -## Advanced Options - -Use `fud2 --help` for an overview of the command-line interface. -Here are some options you might need: - -* By default, fud2 runs the build in a directory called `.fud2` within the working directory. It automatically deletes this directory when the build is done. - * It can be useful to keep this build directory around for debugging or as a "cache" for future builds. Use `--keep` to prevent fud2 from deleting the build directory. - * You can also tell fud2 to use a different build directory with `--dir`. If you give it an existing directory, it will never be deleted, even without `--keep`. (Only "fresh" build directories are automatically cleaned up.) -* If you don't like the operation path that fud2 selected for your build, you can control it with `--through `. fud2 will search the operation graph for a path that contains that op. You can provide this option multiple times; fud2 will look for paths that contain *all* these operations, in order. -* You can choose one of several modes with `-m `: - * `run`: Actually execute a build. The default. - * `gen`: Generate the Ninja build file in the build directory, but don't actually run the build. The default `run` mode is therefore approximately like doing `fud2 -m gen && ninja -C .fud2`. - * `emit`: Just print the Ninja build file to stdout. The `gen` mode is therefore approximately `fud2 -m emit > .fud2/build.ninja`. - * `plan`: Print a brief description of the plan, i.e., the sequence of operations that the build would run. - * `dot`: Print a [GraphViz][] depiction of the plan. Try `fud2 -m dot | dot -Tpdf > graph.pdf` and take a look. - -There are also some subcommands for doing things other than building stuff: - -* `fud2 edit-config`: Open the fud2 configuration file in `$EDITOR`. -* `fud2 list`: Print out all the available states and operations. -* `fud2 get-rsrc FILE`: Fetch a *resource file* and place it in the working directory. You typically do not need to use this interactively; it is used during builds to obtain files included with fud2 that are necessary for a given build. - -[graphviz]: https://graphviz.org - -## The Design of fud2 - -
- -This section is about the *implementation* of fud2; it is only relevant if you want to work on it yourself. -No need to read any farther if all you want is to *use* fud2. - -
- -### fud2 is a Command Orchestrator - -fud2 consists of two pieces, which are two separate Rust crates: - -* FudCore (the `fud-core` crate): is a *generic compiler driver* library. This library is not specific to Calyx and could hypothetically be used to build a fud2-like driver for any compiler ecosystem. Clients of the `fud-core` library work by constructing a `Driver` object that encapsulates a set of *states* and *operations* that define the driver's behavior. -* fud2 itself is a program that uses the FudCore library. All of the Calyx-specific logic lives in `fud2`. For the most part, all of the code in the `fud2` crate consists of declaring a bunch of states and operations. The `main` function does little more than dispatch to the resulting `Driver` object's generic command-line interface. - -The central design philosophy of FudCore (and by extension, fud2 itself) is that its sole job is to orchestrate external functionality. -All that functionality must be available as separate tools that can be invoked via the command line. -This is an important goal because it means the driver has a clear, discrete goal: *all it does* is decide on a list of commands to execute to perform a build. -All the "interesting work" must be delegated to separate tools outside of the driver. -This philosophy has both advantages and disadvantages: - -* On the positive side, it forces all the interesting logic to be invokable via a command that you, the user, can run equally well yourself. So if something is going wrong, there is *always* a command line you can copy and paste into your terminal to reproduce the problem at that particular step. It also means that the input and output of every step must be written to files in the filesystem, so you can easily inspect the intermediate state between every command. This file-based operation also means that fud2 builds are parallel and incremental by default. -* On the other hand, requiring everything to be separate commands means that fud2 has a complicated dependency story. It is not a monolith: to get meaningful work done, you currently have to install a bunch of Python components (among other things) so fud2 can invoke them. (We hope to mitigate the logistical pain this incurs over time, but we're not there yet.) Also, writing everything to a file in between each step comes at a performance cost. Someday, it may be a performance bottleneck that two steps in a build cannot simply exchange their data directly, through memory, and must serialize everything to disk first. (This has not been a problem in practice yet.) - -If you want to extend fud2 to do something new, the consequence is that you first need to come up with a sequence of commands that do that thing. -If necessary, you may find that you need to create new executables to do some minor glue tasks that would otherwise be implicit. -Then "all you need to do" is teach fud2 to execute those commands. - -### States, Operations, and Setups - -You can think of a FudCore driver as a graph, where the vertices are *states* and the edges are *operations*. -(In fact, this is literally the graph you can visualize with `-m dot`.) -Any build is a transformation from one state to another, traversing a path through this graph. -The operations (edges) along this path are the commands that must be executed to transform a file from the initial state to the final state. - -To make fud2 do something new, you probably want to add one or more operations, and you may need to add new states. -Aside from declaring the source and destination states, -operations generate chunks of [Ninja][] code. -So to implement an operation, you write a Rust function with this signature: - - fn build(emitter: &mut Emitter, input: &str, output: &str) - -Here, `emitter` is a wrapper around an output stream with a bunch of utility functions for printing out lines of Ninja code. -`input` and `output` are filenames. -So your job in this function is to print (at least) a Ninja `build` command that produces `output` as a target and uses `input` as a dependency. -For example, the Calyx-to-Verilog compiler operation might emit this chunk of Ninja code: - - build bar.sv: calyx foo.futil - backend = verilog - -when the `input` argument above is `"foo.futil"` and the `output` is `"bar.sv"`. -(The FudCore library will conjure these filenames for you; your job in this operation is just to use them as is.) - -Notice here that the generated Ninja chunk is using a build rule called `calyx`. -This also needs to be defined. -To set up things like variables and build rules that operations can use, FudCore has a separate concept called *setups*. -A setup is a function that generates some Ninja code that might be shared among multiple operations (or multiple instances of the same operation). -For example, our setup for Calyx compilation generates code like this: - - calyx-base = /path/to/calyx - calyx-exe = $calyx-base/target/debug/calyx - rule calyx - command = $calyx-exe -l $calyx-base -b $backend $args $in > $out - -That is, it defines two Ninja variables and one Ninja rule—the one that our build command above uses. -We *could* have designed FudCore without a separation between setups and operations, so this rule would get declared right next to the `build` command above. -But that would end up duplicating a lot of setup code that really only needs to appear once. -So that's why setups exist: to share a single stanza of Ninja scaffolding code between multiple operations. +# fud2: Experimental Driver diff --git a/docs/running-calyx/fud2/index.md b/docs/running-calyx/fud2/index.md new file mode 100644 index 0000000000..6ae9088bff --- /dev/null +++ b/docs/running-calyx/fud2/index.md @@ -0,0 +1,159 @@ +# fud2: An Experimental Successor to fud + +[fud][] is the compiler driver tool for orchestrating the Calyx ecosystem. +fud2 is an experiment in building a new driver that works like fud that adds some fundamental new capabilities and resolves some underlying problems. + +"Original" fud is still the right tool for almost all jobs; fud2 is in an experimental phase and does not support everything fud can do. +Someday, fud2 may supplant fud, but it needs more work before it is ready to do that. +Until then, fud remains your first choice for all your build-related needs. + +[fud]: ./fud/index.md + +## Set Up + +fud2 is a Rust tool, so you can build it along with everything else in this monorepo with `cargo build`. +You might then want to do something like ``ln -s `pwd`/target/debug/fud2 ~/.local/bin`` for easy access to the `fud2` binary. + +fud2 depends on [Ninja][]. +Install it using your OS package manager or by downloading a binary. + +### Configuration + +Run the following command to edit `fud2`'s configuration file (usually `~/.config/fud2.toml`): + + $ fud2 edit-config + +Add these lines: + +```toml +[calyx] +base = "" +``` + +Now you're ready to use fud2. + +[ninja]: https://ninja-build.org + +## General Use + +You can see complete command-line documentation with `fud2 --help`. +But generally, you want to do something like this: + + $ fud2 -o + +For example, use this to compile a Calyx program to Verilog: + + $ fud2 foo.futil -o bar.sv + +fud2 tries to automatically guess the input and output formats using filename extensions. +If that doesn't work, you can choose for it with `--from ` and `--to `; +for example, this is a more explicit version of the above: + + $ fud2 foo.futil -o bar.sv --from calyx --to verilog + +You can also omit the input and output filenames to instead use stdin and stdout. +In that case, `--from` and `--to` respectively are required. +So here's yet another way to do the same thing: + + $ fud2 --from calyx --to verilog < foo.futil > bar.sv + +This is handy if you just want to print the result of a build to the console: + + $ fud2 foo.futil --to verilog + +Some operations use other configuration options, which can come from either your `fud2.toml` or the command line. +Use `--set key=value` to override any such option. + +## Advanced Options + +Use `fud2 --help` for an overview of the command-line interface. +Here are some options you might need: + +* By default, fud2 runs the build in a directory called `.fud2` within the working directory. It automatically deletes this directory when the build is done. + * It can be useful to keep this build directory around for debugging or as a "cache" for future builds. Use `--keep` to prevent fud2 from deleting the build directory. + * You can also tell fud2 to use a different build directory with `--dir`. If you give it an existing directory, it will never be deleted, even without `--keep`. (Only "fresh" build directories are automatically cleaned up.) +* If you don't like the operation path that fud2 selected for your build, you can control it with `--through `. fud2 will search the operation graph for a path that contains that op. You can provide this option multiple times; fud2 will look for paths that contain *all* these operations, in order. +* You can choose one of several modes with `-m `: + * `run`: Actually execute a build. The default. + * `gen`: Generate the Ninja build file in the build directory, but don't actually run the build. The default `run` mode is therefore approximately like doing `fud2 -m gen && ninja -C .fud2`. + * `emit`: Just print the Ninja build file to stdout. The `gen` mode is therefore approximately `fud2 -m emit > .fud2/build.ninja`. + * `plan`: Print a brief description of the plan, i.e., the sequence of operations that the build would run. + * `dot`: Print a [GraphViz][] depiction of the plan. Try `fud2 -m dot | dot -Tpdf > graph.pdf` and take a look. + +There are also some subcommands for doing things other than building stuff: + +* `fud2 edit-config`: Open the fud2 configuration file in `$EDITOR`. +* `fud2 list`: Print out all the available states and operations. +* `fud2 get-rsrc FILE`: Fetch a *resource file* and place it in the working directory. You typically do not need to use this interactively; it is used during builds to obtain files included with fud2 that are necessary for a given build. + +[graphviz]: https://graphviz.org + +## The Design of fud2 + +
+ +This section is about the *implementation* of fud2; it is only relevant if you want to work on it yourself. +No need to read any farther if all you want is to *use* fud2. + +
+ +### fud2 is a Command Orchestrator + +fud2 consists of two pieces, which are two separate Rust crates: + +* FudCore (the `fud-core` crate): is a *generic compiler driver* library. This library is not specific to Calyx and could hypothetically be used to build a fud2-like driver for any compiler ecosystem. Clients of the `fud-core` library work by constructing a `Driver` object that encapsulates a set of *states* and *operations* that define the driver's behavior. +* fud2 itself is a program that uses the FudCore library. All of the Calyx-specific logic lives in `fud2`. For the most part, all of the code in the `fud2` crate consists of declaring a bunch of states and operations. The `main` function does little more than dispatch to the resulting `Driver` object's generic command-line interface. + +The central design philosophy of FudCore (and by extension, fud2 itself) is that its sole job is to orchestrate external functionality. +All that functionality must be available as separate tools that can be invoked via the command line. +This is an important goal because it means the driver has a clear, discrete goal: *all it does* is decide on a list of commands to execute to perform a build. +All the "interesting work" must be delegated to separate tools outside of the driver. +This philosophy has both advantages and disadvantages: + +* On the positive side, it forces all the interesting logic to be invokable via a command that you, the user, can run equally well yourself. So if something is going wrong, there is *always* a command line you can copy and paste into your terminal to reproduce the problem at that particular step. It also means that the input and output of every step must be written to files in the filesystem, so you can easily inspect the intermediate state between every command. This file-based operation also means that fud2 builds are parallel and incremental by default. +* On the other hand, requiring everything to be separate commands means that fud2 has a complicated dependency story. It is not a monolith: to get meaningful work done, you currently have to install a bunch of Python components (among other things) so fud2 can invoke them. (We hope to mitigate the logistical pain this incurs over time, but we're not there yet.) Also, writing everything to a file in between each step comes at a performance cost. Someday, it may be a performance bottleneck that two steps in a build cannot simply exchange their data directly, through memory, and must serialize everything to disk first. (This has not been a problem in practice yet.) + +If you want to extend fud2 to do something new, the consequence is that you first need to come up with a sequence of commands that do that thing. +If necessary, you may find that you need to create new executables to do some minor glue tasks that would otherwise be implicit. +Then "all you need to do" is teach fud2 to execute those commands. + +### States, Operations, and Setups + +You can think of a FudCore driver as a graph, where the vertices are *states* and the edges are *operations*. +(In fact, this is literally the graph you can visualize with `-m dot`.) +Any build is a transformation from one state to another, traversing a path through this graph. +The operations (edges) along this path are the commands that must be executed to transform a file from the initial state to the final state. + +To make fud2 do something new, you probably want to add one or more operations, and you may need to add new states. +Aside from declaring the source and destination states, +operations generate chunks of [Ninja][] code. +So to implement an operation, you write a Rust function with this signature: + + fn build(emitter: &mut Emitter, input: &str, output: &str) + +Here, `emitter` is a wrapper around an output stream with a bunch of utility functions for printing out lines of Ninja code. +`input` and `output` are filenames. +So your job in this function is to print (at least) a Ninja `build` command that produces `output` as a target and uses `input` as a dependency. +For example, the Calyx-to-Verilog compiler operation might emit this chunk of Ninja code: + + build bar.sv: calyx foo.futil + backend = verilog + +when the `input` argument above is `"foo.futil"` and the `output` is `"bar.sv"`. +(The FudCore library will conjure these filenames for you; your job in this operation is just to use them as is.) + +Notice here that the generated Ninja chunk is using a build rule called `calyx`. +This also needs to be defined. +To set up things like variables and build rules that operations can use, FudCore has a separate concept called *setups*. +A setup is a function that generates some Ninja code that might be shared among multiple operations (or multiple instances of the same operation). +For example, our setup for Calyx compilation generates code like this: + + calyx-base = /path/to/calyx + calyx-exe = $calyx-base/target/debug/calyx + rule calyx + command = $calyx-exe -l $calyx-base -b $backend $args $in > $out + +That is, it defines two Ninja variables and one Ninja rule—the one that our build command above uses. +We *could* have designed FudCore without a separation between setups and operations, so this rule would get declared right next to the `build` command above. +But that would end up duplicating a lot of setup code that really only needs to appear once. +So that's why setups exist: to share a single stanza of Ninja scaffolding code between multiple operations. diff --git a/docs/running-calyx/fud2/scripts.md b/docs/running-calyx/fud2/scripts.md new file mode 100644 index 0000000000..b164d759d7 --- /dev/null +++ b/docs/running-calyx/fud2/scripts.md @@ -0,0 +1,126 @@ +# Scripting `fud2` with `Rhai` + +You can add functionality to `fud2` with functionality written in [Rhai][rhai]. Rhai is a scripting language designed to work well with Rust. + +All functionality included with `fud2` is written in Rhai. They can be found [here][fud2-scripts]. These provide a good example of how to add states and operations with Rhai. + +## Loading Scripts + +You can tell `fud2` to load a script by including a `plugins` key in your `fud2.toml` file. + +```toml +plugins = ["/my/fancy/plugin.rhai"] + +[calyx] +base = "..." +``` + +## Example Script + +We'll walk through how to write a script that adds support for using the `calyx` compiler. + +First, we need to define some states: + +```rust,ignore +export const calyx_state = state("calyx", ["futil"]); +export const verilog_state = state("verilog", ["sv", "v"]); +``` + +These two lines define a `calyx` state and a `verilog` state. The `export` prefix means that these variables will be accessible to other scripts that `import "calyx"`. + +Next we'll define a setup procedure to define some rules that will be useful. + +```rust,ignore +// allows calyx_setup to be used in other scripts +export const calyx_setup = calyx_setup; + +// a setup function is just a normal Rhai function that takes in an emitter +// we can use the emitter in the same way that we use it from rust +fn calyx_setup(e) { + // define a Ninja var from the fud2.toml config + e.config_var("calyx-base", "calyx.base"); + // define a Ninja var from either the config, or a default derived from calyx-base + e.config_var_or("calyx-exe", "calyx.exe", "$calyx-base/target/debug/calyx"); + // define a Ninja var from cli options, or with a default + e.config_var_or("args", "calyx.args", ""); + // define a rule to run the Calyx compiler + e.rule("calyx", "$calyx-exe -l $calyx-base -b $backend $args $in > $out"); +} +``` + +And now we can define the actual operation that will transform `calyx` files into `verilog` files. + +```rust,ignore +op( + "calyx-to-verilog", // operation name + [calyx_setup], // required setup functions + calyx_state, // input state + verilog_state, // output state + |e, input, output| { // function to construct Ninja build command + e.build_cmd([output], "calyx", [input], []) ; + e.arg("backend", "verilog"); + } +); +``` + +## Rhai Specifics + +### String Templates + +Rhai has a string templating feature, similar to the `format!` macro in rust. Templated strings are marked with backticks (`` `path/${some_var}.ext` ``) and variables are included with `$`. You can include expressions that will be evaluated by using brackets: `${1 + 2}`. + +### String Functions + +Rhai includes standard string operations. They are described in the [documentation][rhai-strings]. These are useful for constructing more complicated paths. + +### Export Rules + +In Rhai, all top-level variable declarations are private by default. If you want them to be available from other files, you need to `export` them explicitly. + +All functions are exported by default. However, they are only exported in a callable format. If you want to use the function as a variable (when passing them as a setup function or build function), you need to export them explicitly as well. + +This is how that looks: +```rust,ignore +export const my_fancy_setup = my_fancy_setup; +fn my_fancy_setup(e) { + ... +} +``` + +### Imports + +You can import another Rhai script file like so: + +```rust,ignore +import "calyx" as c; +``` + +All exported symbols defined in `calyx.rhai` will be available under `c`. + +```rust,ignore +print(c::calyx_state); +print(c::calyx_setup); +``` + +
+ +The name for an import is always just the basename of the script file, without any extension. + +
+ +## API + +Currently, the Rhai API is almost identical to the Rust API. However `Emitter::add_file` is not currently supported. And `Emitter::var` is renamed to `_var` because `var` is a reserved keyword in Rhai. + +### Adding to the API + +If there is something that is hard to do in Rhai, it is straightforward to [register a Rust function][rhai-rust-fn] so that it is available from Rhai. + +Rust functions are registered in [`ScriptRunner::new`][fud-core-scriptrunner]. Refer to [`ScriptRunner::reg_get_state`][fud-core-reg_get_state] to see a simple example of how to register a function. + +[rhai]: https://rhai.rs/book/index.html +[rhai-strings]: https://rhai.rs/book/ref/string-fn.html?highlight=String#standard-string-functions +[rhai-rust-fn]: https://rhai.rs/book/rust/functions.html +[fud2-scripts]: https://github.com/calyxir/calyx/tree/main/fud2/scripts +[fud-core-scriptrunner]: https://github.com/calyxir/calyx/blob/6f895a1353020ce254860c3aa0fcfa2ba1abf4c4/fud2/fud-core/src/script/plugin.rs#L68 +[fud-core-reg_get_state]: https://github.com/calyxir/calyx/blob/6f895a1353020ce254860c3aa0fcfa2ba1abf4c4/fud2/fud-core/src/script/plugin.rs#L152 diff --git a/fud2/Cargo.toml b/fud2/Cargo.toml index a436f6ccc5..6d79ed550b 100644 --- a/fud2/Cargo.toml +++ b/fud2/Cargo.toml @@ -14,7 +14,7 @@ description = "Compiler driver for the Calyx infrastructure" [features] migrate_to_scripts = [] -default = [] +default = ["migrate_to_scripts"] [dependencies] fud-core = { path = "fud-core", version = "0.0.2" } From 55d4e2477c95bb97c1b281650207e80ca7f8acae Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 18 Jun 2024 11:57:47 -0500 Subject: [PATCH 44/47] disable migrate_to_scripts for now --- fud2/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fud2/Cargo.toml b/fud2/Cargo.toml index 6d79ed550b..a436f6ccc5 100644 --- a/fud2/Cargo.toml +++ b/fud2/Cargo.toml @@ -14,7 +14,7 @@ description = "Compiler driver for the Calyx infrastructure" [features] migrate_to_scripts = [] -default = ["migrate_to_scripts"] +default = [] [dependencies] fud-core = { path = "fud-core", version = "0.0.2" } From 1b6162f97a3ad3608a46fa0128adfc1779f7f065 Mon Sep 17 00:00:00 2001 From: Sammy Thomas Date: Tue, 18 Jun 2024 12:07:22 -0500 Subject: [PATCH 45/47] update axi.rhai + Rhai API to match Rust API --- fud2/Cargo.toml | 2 +- fud2/fud-core/src/script/exec_scripts.rs | 38 ++++++++++++++++++++++++ fud2/scripts/axi.rhai | 26 ++++++++++++---- fud2/src/lib.rs | 2 +- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/fud2/Cargo.toml b/fud2/Cargo.toml index a436f6ccc5..6d79ed550b 100644 --- a/fud2/Cargo.toml +++ b/fud2/Cargo.toml @@ -14,7 +14,7 @@ description = "Compiler driver for the Calyx infrastructure" [features] migrate_to_scripts = [] -default = [] +default = ["migrate_to_scripts"] [dependencies] fud-core = { path = "fud-core", version = "0.0.2" } diff --git a/fud2/fud-core/src/script/exec_scripts.rs b/fud2/fud-core/src/script/exec_scripts.rs index c12a54118f..03c6101392 100644 --- a/fud2/fud-core/src/script/exec_scripts.rs +++ b/fud2/fud-core/src/script/exec_scripts.rs @@ -43,10 +43,46 @@ impl RhaiEmitter { self.0.borrow().config_val(key).map_err(to_rhai_err) } + fn config_constrained_val( + &mut self, + key: &str, + valid_values: rhai::Array, + ) -> RhaiResult { + self.0 + .borrow() + .config_constrained_val( + key, + to_str_slice(&valid_values) + .iter() + .map(|x| &**x) + .collect::>(), + ) + .map_err(to_rhai_err) + } + fn config_or(&mut self, key: &str, default: &str) -> String { self.0.borrow().config_or(key, default) } + fn config_constrained_or( + &mut self, + key: &str, + valid_values: rhai::Array, + default: &str, + ) -> RhaiResult { + self.0 + .borrow() + .config_constrained_or( + key, + to_str_slice(&valid_values) + .iter() + .map(|x| &**x) + .collect::>(), + default, + ) + .map_err(to_rhai_err) + } + fn config_var(&mut self, name: &str, key: &str) -> RhaiResult<()> { self.0 .borrow_mut() @@ -145,7 +181,9 @@ thread_local! { engine .register_type_with_name::("RhaiEmitter") .register_fn("config_val", RhaiEmitter::config_val) + .register_fn("config_constrained_val", RhaiEmitter::config_constrained_val) .register_fn("config_or", RhaiEmitter::config_or) + .register_fn("config_constrained_or", RhaiEmitter::config_constrained_or) .register_fn("config_var", RhaiEmitter::config_var) .register_fn("config_var_or", RhaiEmitter::config_var_or) .register_fn("var_", RhaiEmitter::var) diff --git a/fud2/scripts/axi.rhai b/fud2/scripts/axi.rhai index e7e795b084..9505c9ffc6 100644 --- a/fud2/scripts/axi.rhai +++ b/fud2/scripts/axi.rhai @@ -18,13 +18,27 @@ op( ); fn wrapper_setup(e) { - e.config_var_or("axi-generator", "axi.generator", "$calyx-base/yxi/axi-calyx/axi-generator.py"); - e.config_var_or("python", "python", "python3"); - e.rule("gen-axi", "$python $axi-generator $in > $out"); + // Define a `gen-axi` rule that invokes our Python code generator program. + // For now point to standalone axi-generator.py. Can maybe turn this into a rsrc file? + let dynamic = + e.config_constrained_or("dynamic", ["true", "false"], "false"); + let generator_path = if dynamic == "true" { + "$calyx-base/yxi/axi-calyx/dynamic-axi-generator.py" + } else { + "$calyx-base/yxi/axi-calyx/axi-generator.py" + }; + e.config_var_or("axi-generator", "axi.generator", generator_path); + e.config_var_or("python", "python", "python3"); - // Define a simple `combine` rule that just concats any number of files. - e.rule("combine", "cat $in > $out"); - e.rule("remove-imports", "sed '1,/component main/{/component main/!d}' $in > $out"); + e.rule("gen-axi", "$python $axi-generator $in > $out"); + + // Define a simple `combine` rule that just concatenates any numer of files. + e.rule("combine", "cat $in > $out"); + + e.rule( + "remove-imports", + "sed '1,/component main/{/component main/!d; }' $in > $out", + ); } /// Replace the extension in `path` with `new_ext` diff --git a/fud2/src/lib.rs b/fud2/src/lib.rs index 93d4b21f0f..860693205d 100644 --- a/fud2/src/lib.rs +++ b/fud2/src/lib.rs @@ -813,7 +813,7 @@ pub fn build_driver(bld: &mut DriverBuilder) { e.rule( "remove-imports", - "sed '1,/component main/{/component main/!d}' $in > $out", + "sed '1,/component main/{/component main/!d; }' $in > $out", )?; Ok(()) }); From 548fac5315f5818a577af032bc933a2652b7af68 Mon Sep 17 00:00:00 2001 From: Samuel Thomas Date: Tue, 18 Jun 2024 12:15:36 -0500 Subject: [PATCH 46/47] update snapshot --- fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap b/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap index b155363e99..98d04f45ed 100644 --- a/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap +++ b/fud2/tests/snapshots/tests__test@plan_axi-wrapped.snap @@ -28,7 +28,7 @@ rule gen-axi rule combine command = cat $in > $out rule remove-imports - command = sed '1,/component main/{/component main/!d}' $in > $out + command = sed '1,/component main/{/component main/!d; }' $in > $out build input.yxi: yxi /input.ext build refified_input.futil: calyx-pass /input.ext From d849b9e55788a5f13179c34d03c3f7860ba41ee9 Mon Sep 17 00:00:00 2001 From: Samuel Thomas Date: Wed, 19 Jun 2024 12:06:01 -0500 Subject: [PATCH 47/47] fix typo --- fud2/tests/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fud2/tests/tests.rs b/fud2/tests/tests.rs index 7180d391d6..f39b422643 100644 --- a/fud2/tests/tests.rs +++ b/fud2/tests/tests.rs @@ -21,16 +21,16 @@ fn test_driver() -> Driver { } trait InstaTest: Sized { - /// Get a human-readable description of Self. + /// Get a human-readable description of Self fn desc(&self, driver: &Driver) -> String; - /// Get a short string uniquely identifying Self. + /// Get a short string uniquely identifying Self fn slug(&self, driver: &Driver) -> String; - /// Emit the string that will be snapshot tested. + /// Emit the string that will be snapshot tested fn emit(self, driver: &Driver) -> String; - /// Run snapshap test + /// Run snapshot test fn test(self, driver: &Driver) { let desc = self.desc(driver); let slug = self.slug(driver);