Skip to content

Commit

Permalink
Fix Python Indentation for Verilog Bug
Browse files Browse the repository at this point in the history
Also add `D1.pytv` Example
  • Loading branch information
Teddy-van-Jerry committed Mar 29, 2024
1 parent c10a5f8 commit 3d21eb4
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -3,7 +3,7 @@ name = "pytv"
description = "Python Templated Verilog"
repository = "https://github.com/autohdw/pytv"
authors = ["Teddy van Jerry <me@teddy-van-jerry.org>"]
version = "0.3.3"
version = "0.4.0"
readme = "README.md"
license = "GPL-3.0-or-later"
keywords = ["verilog", "python", "template", "generation"]
Expand Down
58 changes: 58 additions & 0 deletions examples/D1.pytv
@@ -0,0 +1,58 @@
//! # port enable settings
//! if_rst = True
//! if_en = True
// Delay by 1 clock
`timescale 1ns / 1ps

module `OUTPUT_VERILOG_FILE_STEM`#(
parameter dwt = 16
)(
op_in, clk
//! if (if_rst):
, rst_n
//! if (if_en):
, en
//! #
, op_out
);

input [dwt-1:0] op_in;
input clk;
//! if (if_rst):
input rst_n;
//! if (if_en):
input en;
//! #
output reg [dwt-1:0] op_out;

//! if (if_rst and if_en):
always @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
op_out <= 'b0;
end
else if (en) begin
op_out <= op_in;
end
end
//! elif (if_rst and (not if_en)):
always @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
op_out <= 'b0;
end
else begin
op_out <= op_in;
end
end
//! elif ((not if_rst) and if_en):
always @(posedge clk, negedge rst_n) begin
if (en) begin
op_out <= op_in;
end
end
//! else:
always @(posedge clk) begin
op_out <= op_in;
end
//! #

endmodule
3 changes: 2 additions & 1 deletion examples/test.pytv
Expand Up @@ -4,7 +4,8 @@ module `OUTPUT_VERILOG_FILE_STEM`;

Do nothing here!
//! for i in range(5):
//! print("Teddy bear!")
Teddy Bears!
//! # <- mark the end of group
Do nothing here either! { some content }
//! a = 2
`1 + 2` and how about here ` a * 2 `
Expand Down
65 changes: 43 additions & 22 deletions src/convert.rs
Expand Up @@ -58,20 +58,24 @@ impl Convert {

/// Generates the output file name based on the input file name and configuration.
fn output_file_name(&self) -> String {
self.file_options.output.clone().unwrap_or_else(|| {
if self.file_options.output.is_some() {
return self.file_options.input.clone();
}
let mut output = self.file_options.input.clone();
// change extension to .v if there is extension
let ext = path::Path::new(&output).extension().unwrap_or_default();
if ext.is_empty() {
output.push_str(".v");
} else {
output = output.replace(ext.to_str().unwrap(), "v");
}
output
}).replace("\\", "/")
self.file_options
.output
.clone()
.unwrap_or_else(|| {
if self.file_options.output.is_some() {
return self.file_options.input.clone();
}
let mut output = self.file_options.input.clone();
// change extension to .v if there is extension
let ext = path::Path::new(&output).extension().unwrap_or_default();
if ext.is_empty() {
output.push_str(".v");
} else {
output = output.replace(ext.to_str().unwrap(), "v");
}
output
})
.replace("\\", "/")
}

/// Generates the output Python file name based on the input file name and configuration.
Expand Down Expand Up @@ -183,10 +187,10 @@ impl Convert {
fn process_python_line<W: Write>(
&self,
line: &str,
py_indent_space: usize,
py_indent_prior: usize,
stream: &mut W,
) -> Result<()> {
writeln!(stream, "{}", utf8_slice::from(&line, py_indent_space))
writeln!(stream, "{}", utf8_slice::from(&line, py_indent_prior))
}

#[cfg(feature = "macro")]
Expand Down Expand Up @@ -214,9 +218,24 @@ impl Convert {
Ok(())
}

fn update_py_indent_space(&self, line: &str, py_indent_space: usize) -> usize {
if !line.is_empty() {
let re = regex::Regex::new(r":\s*(#|$)").unwrap();
line.chars().position(|c| !c.is_whitespace()).unwrap_or(0)
+ if re.is_match(line) {
self.config.tab_size as usize
} else {
0usize
}
} else {
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<(), Box<dyn Error>> {
let mut first_py_line = false;
let mut py_indent_prior = 0usize;
let mut py_indent_space = 0usize;
let magic_string_len = 2 + self.config.magic_comment_str.len();
#[cfg(feature = "inst")]
Expand Down Expand Up @@ -248,6 +267,7 @@ impl Convert {
self.switch_line_type(&mut line_type, line.as_str());
match line_type {
LineType::PythonBlock(true) => {
py_indent_space = self.update_py_indent_space(&line, py_indent_space);
#[cfg(feature = "inst")]
self.process_python_line(
&line,
Expand All @@ -263,29 +283,30 @@ impl Convert {
let line = utf8_slice::from(line.trim_start(), magic_string_len);
if !first_py_line && !line.is_empty() {
first_py_line = true;
py_indent_space =
py_indent_prior =
line.chars().position(|c| !c.is_whitespace()).unwrap_or(0);
}
if !utf8_slice::till(&line, py_indent_space).trim().is_empty() {
if !utf8_slice::till(&line, py_indent_prior).trim().is_empty() {
Err(format!(
"Python line should start with {} spaces.\nUnexpected line: {}",
py_indent_space, &line
py_indent_prior, &line
))?;
}
py_indent_space = self.update_py_indent_space(&line, py_indent_space) - py_indent_prior;
#[cfg(feature = "inst")]
self.process_python_line(
&line,
py_indent_space,
py_indent_prior,
&mut stream,
&mut within_inst,
&mut inst_str,
)?;
#[cfg(not(feature = "inst"))]
self.process_python_line(&line, py_indent_space, &mut stream)?;
self.process_python_line(&line, py_indent_prior, &mut stream)?;
}
LineType::Verilog => {
let line = self.apply_verilog_regex(self.escape_verilog(&line).as_str());
writeln!(stream, "print(f'{line}')")?;
writeln!(stream, "{}print(f'{line}')", " ".repeat(py_indent_space))?;
}
_ => {}
}
Expand Down
4 changes: 2 additions & 2 deletions src/inst.rs
Expand Up @@ -23,7 +23,7 @@ impl Convert {
pub(crate) fn process_python_line<W: Write>(
&self,
line: &str,
py_indent_space: usize,
py_indent_prior: usize,
stream: &mut W,
within_inst: &mut bool,
inst_str: &mut String,
Expand All @@ -46,7 +46,7 @@ impl Convert {
writeln!(stream, "print('// END of INST')")?;
}
_ => {
let useful_str = utf8_slice::from(&line, py_indent_space);
let useful_str = utf8_slice::from(&line, py_indent_prior);
if *within_inst {
inst_str.push_str(&format!("{useful_str}\n"));
} else {
Expand Down

0 comments on commit 3d21eb4

Please sign in to comment.