mod as_pascal_case;
mod as_snake_case;
mod convert_port_to_signal;
mod generate_verilog_body;
pub use generate_verilog_body::generate_verilog_body;
use itertools::Itertools;
use crate::{
extract_verilog_interface::{extract_verilog_interface, Direction},
verilog_parser::parse_verilog_string,
};
use self::as_pascal_case::as_pascal_case;
#[derive(Debug, PartialEq, Eq)]
pub struct RustHdlModule {
pub name: String,
pub signals: Vec<Signal>,
verilog_name: String,
external_verilog: String,
}
impl RustHdlModule {
pub fn new(verilog_name: String, signals: Vec<Signal>, verilog: String) -> Self {
RustHdlModule {
name: as_pascal_case(verilog_name.as_str()),
verilog_name,
signals,
external_verilog: verilog,
}
}
pub fn internal_verilog(&self) -> String {
return generate_verilog_body(&self.signals, &self.verilog_name);
}
pub fn external_verilog(&self) -> &str {
return self.external_verilog.as_str();
}
pub fn verilog_name(&self) -> &str {
return self.verilog_name.as_str();
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum SignalType {
Bit,
Clock,
Bits(u32),
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Signal {
pub name: String,
pub internal_name: String,
pub direction: Direction,
pub signal_type: SignalType,
pub driven: bool,
}
pub fn extract_rust_hdl_interface(
verilog: &str,
module_name: &str,
) -> Result<RustHdlModule, sv_parser::Error> {
let syntax_tree = parse_verilog_string(verilog)?;
let ports = extract_verilog_interface(&syntax_tree, Some(module_name));
let signals: Vec<Signal> = ports.iter().map_into().collect();
let external_verilog = String::from(verilog);
Ok(RustHdlModule {
name: as_pascal_case(module_name),
verilog_name: module_name.into(),
signals,
external_verilog,
})
}
#[cfg(test)]
mod tests {
use super::*;
const VERILOG_COUNTER: &str = r#"
module counter
(
input clock,
output [5:0] led
);
reg [23:0] clockCounter = 0;
localparam WAIT_TIME = 1000;
reg [5:0] ledCounter = 0;
always @(posedge clock) begin
clockCounter <= clockCounter + 1;
if (clockCounter == WAIT_TIME) begin
clockCounter <= 0;
ledCounter <= ledCounter + 1;
end
end
assign led = ~ledCounter;
endmodule
"#;
#[test]
fn generating_rust_hdl_module_struct_from_counter_works() {
let rust_hdl_module = extract_rust_hdl_interface(VERILOG_COUNTER, "counter").unwrap();
assert_eq!(
rust_hdl_module,
RustHdlModule {
name: "Counter".to_string(),
verilog_name: "counter".to_string(),
signals: vec![
Signal {
name: "clock".to_string(),
internal_name: "clock".to_string(),
direction: Direction::In,
signal_type: SignalType::Clock,
driven: false,
},
Signal {
name: "led".to_string(),
internal_name: "led".to_string(),
direction: Direction::Out,
signal_type: SignalType::Bits(6),
driven: true,
},
],
external_verilog: String::from(VERILOG_COUNTER)
}
);
assert_eq!(
rust_hdl_module.internal_verilog(),
"counter counter_inst(.clock(clock), .led(led));"
);
}
#[test]
fn renaming_interface_of_the_rusthdl_module_works() {
let mut rust_hdl_module = extract_rust_hdl_interface(VERILOG_COUNTER, "counter").unwrap();
rust_hdl_module.signals.first_mut().map(|first_signal| {
first_signal.name = "cool_external_name".to_string();
Some(())
});
assert_eq!(
rust_hdl_module,
RustHdlModule {
name: "Counter".to_string(),
verilog_name: "counter".to_string(),
signals: vec![
Signal {
name: "cool_external_name".to_string(),
internal_name: "clock".to_string(),
direction: Direction::In,
signal_type: SignalType::Clock,
driven: false,
},
Signal {
name: "led".to_string(),
internal_name: "led".to_string(),
direction: Direction::Out,
signal_type: SignalType::Bits(6),
driven: true,
},
],
external_verilog: String::from(VERILOG_COUNTER)
}
);
assert_eq!(
rust_hdl_module.internal_verilog(),
"counter counter_inst(.clock(cool_external_name), .led(led));"
);
}
}