Skip to content

Commit

Permalink
Implementing inst Feature for Module Instantiation
Browse files Browse the repository at this point in the history
This is only half-done.
  • Loading branch information
Teddy-van-Jerry committed Mar 16, 2024
1 parent 449512d commit 9d1d114
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 12 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"rust-analyzer.cargo.features": "all",
"cSpell.words": [
"pytv"
]
Expand Down
75 changes: 75 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ categories = ["template-engine", "compilers", "development-tools"]
exclude = ["examples/*", "target/*", "Cargo.lock", ".github/*", ".vscode/*", ".DS_Store"]
edition = "2021"

[features]
default = ["inst"]
inst = ["dep:serde", "dep:serde_yaml"]

[dependencies]
clap = { version = "4.5.2", features = ["derive"] }
regex = "1.10.3"
utf8_slice = "1.0.0"
serde = { version = "1.0", optional = true }
serde_yaml = { version = "0.9", optional = true }
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pytv
Python Templated Verilog
# PyTV
**Py**thon **T**emplated **V**erilog

## Package
The package `pytv` is available on [crates.io](https://crates.io/crates/pytv).
Expand Down
4 changes: 2 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::Parser;
use regex::Regex;

/// Represents the configuration options for PYTV.
/// Represents the configuration options for PyTV.
#[derive(Debug)]
pub struct Config {
/// The magic comment string used to identify template sections in the input file.
Expand All @@ -16,7 +16,7 @@ pub struct Config {
pub tab_size: u32,
}

/// Represents the options for input and output file for PYTV.
/// Represents the options for input and output file for PyTV.
#[derive(Debug, Default)]
pub struct FileOptions {
/// The input file path.
Expand Down
36 changes: 28 additions & 8 deletions src/convert.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::Config;
use crate::FileOptions;
use std::io::{Result, Write};
use std::error::Error;
use std::io::{Result as IoResult, Write};
use std::path;
use std::result::Result;

/// Represents a converter that converts PYTV script to Python script to generate Verilog.
/// Represents a converter that converts PyTV script to Python script to generate Verilog.
///
/// It is also possible to run the Python script after conversion and optionally delete it after running it.
/// It contains methods for converting code and managing input/output files.
Expand All @@ -15,6 +17,7 @@ pub struct Convert {

impl Convert {
/// Creates a new `Convert` instance with the given configuration and file options.
// #[cfg(not(feature = "inst"))]
pub fn new(config: Config, file_options: FileOptions) -> Convert {
Convert {
config,
Expand All @@ -23,19 +26,20 @@ impl Convert {
}

/// Creates a new `Convert` instance by parsing command line arguments.
// #[cfg(not(feature = "inst"))]
pub fn from_args() -> Convert {
let (config, file_options) = Config::from_args();
Convert::new(config, file_options)
}

/// Opens the input file and reads its contents as a string.
fn open_input(&self) -> Result<String> {
fn open_input(&self) -> IoResult<String> {
std::fs::read_to_string(&self.file_options.input)
}

/// Opens the output Python file and returns a file handle.
/// Note: This will overwrite the existing file.
fn open_output(&self) -> Result<std::fs::File> {
fn open_output(&self) -> IoResult<std::fs::File> {
std::fs::File::create(&self.output_python_file_name())
}

Expand Down Expand Up @@ -101,7 +105,7 @@ impl Convert {
/// Runs the Python code to generate verilog.
///
/// The command `python3` should be available to call.
fn run_python(&self) -> Result<()> {
fn run_python(&self) -> IoResult<()> {
let py_file = self.output_python_file_name();
let v_file = self.output_file_name();
let v_file_f = std::fs::File::create(&v_file)?;
Expand All @@ -127,11 +131,24 @@ impl Convert {
Ok(())
}

#[cfg(not(feature = "inst"))]
fn process_python_line<W: Write>(
&self,
line: &str,
py_indent_space: usize,
stream: &mut W,
) -> Result<()> {
writeln!(stream, "{}", utf8_slice::from(&line, py_indent_space))
}

/// Converts the code and writes the converted code to the given stream.
pub fn convert<W: Write>(&self, mut stream: W) -> Result<()> {
pub fn convert<W: Write>(&self, mut stream: W) -> Result<(), Box<dyn Error>> {
let mut first_py_line = false;
let mut py_indent_space = 0usize;
let magic_string_len = 2 + self.config.magic_comment_str.len();
#[cfg(feature = "inst")]
let mut within_inst = false;
let mut inst_str = String::new();
// parse line by line
for line in self.open_input()?.lines() {
let line = self.pre_process_line(&line);
Expand All @@ -141,7 +158,10 @@ impl Convert {
first_py_line = true;
py_indent_space = line.chars().position(|c| !c.is_whitespace()).unwrap_or(0);
}
writeln!(stream, "{}", utf8_slice::from(&line, py_indent_space))?;
#[cfg(feature = "inst")]
self.process_python_line(&line, py_indent_space, &mut stream, &mut within_inst, &mut inst_str)?;
#[cfg(not(feature = "inst"))]
self.process_python_line(&line, py_indent_space, &mut stream)?;
} else {
let line = self.apply_verilog_regex(self.escape_verilog(&line).as_str());
writeln!(stream, "print(f'{line}')")?;
Expand All @@ -153,7 +173,7 @@ impl Convert {
/// Converts the code and writes the converted code to a file.
///
/// With default `Config`, the output will be a Python file.
pub fn convert_to_file(&self) -> Result<()> {
pub fn convert_to_file(&self) -> Result<(), Box<dyn Error>> {
let out_f = self.open_output()?;
self.convert(out_f)?;
if self.config.run_python {
Expand Down
62 changes: 62 additions & 0 deletions src/inst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::error::Error;
use std::io::Write;
// use std::io::{Write, Result as IoResult};
use super::Convert;

enum InstState {
None,
Begin,
End,
}

impl Convert {
pub(crate) fn process_python_line<W: Write>(
&self,
line: &str,
py_indent_space: usize,
stream: &mut W,
within_inst: &mut bool,
inst_str: &str,
) -> Result<(), Box<dyn Error>> {
match self.inst_state(line) {
InstState::Begin => {
if *within_inst {
return Err("Nested <INST> is not allowed.".into());
}
*within_inst = true;
writeln!(stream, "print('// INST')")?;
}
InstState::End => {
if !*within_inst {
return Err("Encountering </INST> with no <INST> to end.".into());
}
*within_inst = false;
self.print_inst(stream, inst_str)?;
writeln!(stream, "print('// END of INST')")?;
}
_ => {
if *within_inst {
inst_str.to_string().push_str(&format!("{line}\n"));
} else {
writeln!(stream, "{}", utf8_slice::from(&line, py_indent_space))?;
// normal Python line
}
}
}
Ok(())
}

fn inst_state(&self, line: &str) -> InstState {
match line.trim() {
"<INST>" => InstState::Begin,
"</INST>" => InstState::End,
_ => InstState::None,
}
}

fn print_inst<W: Write>(&self, stream: &mut W, inst_str: &str) -> Result<(), Box<dyn Error>> {
// TODO: process YML and write to file
writeln!(stream, "{}", inst_str)?;
Ok(())
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
//! - **AHDW**: a DSL, the predecessor of this project
//! [[paper at IEEE](https://ieeexplore.ieee.org/document/10396119)]
//! [[paper PDF](https://wqzhao.org/assets/zhao2023automatic.pdf)]
mod config;
mod convert;

#[cfg(feature = "inst")]
mod inst;

pub use config::Config;
pub use config::FileOptions;
pub use convert::Convert;

0 comments on commit 9d1d114

Please sign in to comment.