diff --git a/Cargo.lock b/Cargo.lock index e3a61db..99b09b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,7 +156,7 @@ dependencies = [ [[package]] name = "pytv" -version = "0.3.0" +version = "0.3.1" dependencies = [ "clap", "regex", diff --git a/Cargo.toml b/Cargo.toml index 6376b0b..ca0cd49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "pytv" description = "Python Templated Verilog" repository = "https://github.com/autohdw/pytv" authors = ["Teddy van Jerry "] -version = "0.3.0" +version = "0.3.1" readme = "README.md" license = "GPL-3.0-or-later" keywords = ["verilog", "python", "template", "generation"] diff --git a/examples/test.pytv b/examples/test.pytv index 9547810..7a3a13a 100644 --- a/examples/test.pytv +++ b/examples/test.pytv @@ -5,17 +5,33 @@ Do nothing here! Do nothing here either! { some content } //! a = 2 `1 + 2` and how about here ` a * 2 ` +//! dyn_ports = [ +//! ("portA", "wire_a"), +//! ("portB", "wire_b"), +//! ("portC", "wire_c"), +//! ] +//! dyn_vparams = [] +//! for i in range(4): +//! dyn_vparams.append((f"param{i}", i)) +//! value_M = 32 +//! dyn_parameters = [] +//! for i in range(2): +//! dyn_parameters.append((f"name{i+10}", i + 10)) //! //! module: test //! name: inst_test //! vparams: //! N: 8 +//! !mystery: dyn_vparams +//! M: `value_M` //! parameters: //! name1: value1 //! name2: value2 //! name`1+2`: `a` +//! !other_parameters: dyn_parameters //! ports: //! port1: net1 +//! !other_name: dyn_ports //! wire x; assign x = y; diff --git a/src/convert.rs b/src/convert.rs index c4abc57..14c5e2c 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -197,7 +197,18 @@ impl Convert { #[cfg(feature = "inst")] writeln!( stream, - "_inst_file = open('{}', 'w')", + concat!( + "_inst_file = open('{}', 'w')\n", + "def _inst_var_map(tuples):\n", + " s = ['%s: %s\\n' % tuple for tuple in tuples]\n", + " return ' '.join(s)\n\n", + "def _verilog_ports_var_map(tuples, first_port):\n", + " s = [' .%s(%s)' % tuple for tuple in tuples]\n", + " return ('' if first_port else ',\\n') + ',\\n'.join(s)\n\n", + "def _verilog_vparams_var_map(tuples, first_vparam):\n", + " s = ['\\n parameter %s = %s' % tuple for tuple in tuples]\n", + " return ('#(' if first_vparam else ',') + ','.join(s)\n\n", + ), self.output_inst_file_name() )?; let mut line_type = LineType::default(); diff --git a/src/inst.rs b/src/inst.rs index d79fadb..aa78547 100644 --- a/src/inst.rs +++ b/src/inst.rs @@ -1,4 +1,5 @@ use super::Convert; +use regex::{self, Regex}; use std::error::Error; use std::io::Write; @@ -65,11 +66,34 @@ impl Convert { } } + fn apply_protected_inst_group_regex(inst_str: &str) -> String { + let re = Regex::new(r"!(\w+):(.*)[\r\n$]").unwrap(); + re.replace_all(inst_str, "__group_$1:$2\n").to_string() + } + + fn inst_group_print_to_dot_inst(inst_str: &str) -> String { + let re = Regex::new(r"__group_\w+:\s*(.*)[\r\n$]").unwrap(); + re.replace_all( + inst_str, + "''')\n_inst_file.write(f'{_inst_var_map($1)}')\n_inst_file.write(f'''", + ) + .to_string() + } + fn print_inst(&self, stream: &mut W, inst_str: &str) -> Result<(), Box> { + print!( + "{}", + Self::apply_protected_inst_group_regex(inst_str).as_str() + ); let inst_map: serde_yaml::Value = - serde_yaml::from_str(&self.apply_protected_verilog_regex(inst_str))?; + serde_yaml::from_str(&self.apply_protected_verilog_regex( + Self::apply_protected_inst_group_regex(inst_str).as_str(), + ))?; let mut inst_str_parsed = serde_yaml::to_string(&vec![&inst_map])?; - inst_str_parsed = self.undo_protected_brackets(inst_str_parsed.as_str()); + inst_str_parsed = Self::inst_group_print_to_dot_inst( + self.undo_protected_brackets(inst_str_parsed.as_str()) + .as_str(), + ); // print to .inst writeln!(stream, "_inst_file.write(f'''{}''')", inst_str_parsed)?; // print to .v @@ -86,18 +110,32 @@ impl Convert { for (key, value) in vparams.iter() { if let (Some(key_str), Some(value_str)) = (key.as_str(), yaml_value_as_str(value)) { let value_str = value_str.as_str(); - writeln!( - stream, - "print(f'{}\\n parameter {} = {}')", - if first_vparam { - first_vparam = false; - "#(" - } else { - "," - }, - self.escape_single_quote(self.undo_protected_brackets(key_str).as_str()), - self.escape_single_quote(self.undo_protected_brackets(value_str).as_str()) - )?; + if key_str.starts_with("__group_") { + writeln!( + stream, + "print(_verilog_vparams_var_map({}, {}), end='')", + value_str, + if first_vparam { + first_vparam = false; + "True" + } else { + "False" + }, + )?; + } else { + writeln!( + stream, + "print(f'{}\\n parameter {} = {}', end='')", + if first_vparam { + first_vparam = false; + "#(" + } else { + "," + }, + self.escape_single_quote(self.undo_protected_brackets(key_str).as_str()), + self.escape_single_quote(self.undo_protected_brackets(value_str).as_str()) + )?; + } } else { return Err("Invalid vparams found in the .".into()); } @@ -120,18 +158,36 @@ impl Convert { for (key, value) in ports.iter() { if let (Some(key_str), Some(value_str)) = (key.as_str(), yaml_value_as_str(value)) { let value_str = value_str.as_str(); - writeln!( - stream, - "print(f'{} .{}({})', end='')", - if first_port { - first_port = false; - "" - } else { - ",\\n" - }, - self.escape_single_quote(self.undo_protected_brackets(key_str).as_str()), - self.escape_single_quote(self.undo_protected_brackets(value_str).as_str()) - )?; + if key_str.starts_with("__group_") { + writeln!( + stream, + "print(_verilog_ports_var_map({}, {}), end='')", + value_str, + if first_port { + first_port = false; + "True" + } else { + "False" + }, + )?; + } else { + writeln!( + stream, + "print(f'{} .{}({})', end='')", + if first_port { + first_port = false; + "" + } else { + ",\\n" + }, + self.escape_single_quote( + self.undo_protected_brackets(key_str).as_str() + ), + self.escape_single_quote( + self.undo_protected_brackets(value_str).as_str() + ) + )?; + } } } }