-
Notifications
You must be signed in to change notification settings - Fork 28
Description
Hi, I'm writing because I'm trying to implement a pattern recognizer in Rust that generates code in Verilog and at the same time I can run the test with the command "cargo test -- --nocapture". But the machine isn't updating the state and I've been struggling with this for easily 20 hours and I can't get it to work. I'm attaching the main.rs code and what the command returns to see if you can help me. I think it's not updating the state correctly and most likely I'm creating the state machine incorrectly but it could also be that it doesn't support the creation of it. I'm waiting for a response.
----------------------Code Rust --------------------------------
use rust_hdl::prelude::*;
use std::fs;
use std::fs::File;
use std::io::Write;
use anyhow::anyhow;
#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
enum State {
S0, // Estado inicial
S1, // Detecta '1'
S2, // Detecta '10'
S3, // Detecta '101'
S4, // Detecta '1011' (estado de éxito)
}
#[derive(LogicBlock, Clone)]
struct ReconocedorPatrones {
pub clk: Signal<In, Clock>,
pub rst: Signal<In, Bit>,
pub entrada: Signal<In, Bit>,
pub salida: Signal<Out, Bit>,
state: DFF,
}
impl Default for ReconocedorPatrones {
fn default() -> Self {
let mut instance = Self {
clk: Default::default(),
rst: Default::default(),
entrada: Default::default(),
salida: Default::default(),
state: DFF::default(),
};
instance.state.d.next = State::S0;
instance
}
}
impl Logic for ReconocedorPatrones {
#[hdl_gen]
fn update(&mut self) {
dff_setup!(self, clk, state); //Conecta el DFF al reloj
if self.rst.val() {
//Si activas el reset volemos al estado inicial
self.state.d.next = State::S0;
self.salida.next = false;
} else {
println!(
"Estado actual: {:?}, Entrada: {}, Salida: {}",
self.state.q.val(), self.entrada.val(), self.salida.val()
);
match self.state.q.val() {
State::S0 => { // Estado S0
println!("En S0, Entrada: {}", self.entrada.val());
if self.entrada.val() {
println!("S0 dentro");
self.state.d.next = State::S1;
}
else {
self.state.d.next = State::S0;
}
self.salida.next = false;
}
State::S1 => { // Estado S1
println!("En S1, Entrada: {}", self.entrada.val());
if !self.entrada.val() {
self.state.d.next = State::S2;
} else {
self.state.d.next = State::S1;
}
}
State::S2 => { // Estado S2
println!("En S2, Entrada: {}", self.entrada.val());
if self.entrada.val() {
self.state.d.next = State::S3;
} else {
self.state.d.next = State::S0;
}
}
State::S3 => { // Estado S3
println!("En S3, Entrada: {}", self.entrada.val());
if self.entrada.val() {
self.state.d.next = State::S4;
} else {
self.state.d.next = State::S2;
}
}
State::S4 => { // Estado S4 (Patrón detectado)
println!("En S4, Entrada: {}", self.entrada.val());
self.salida.next = true;
self.state.d.next = State::S0;
}
}
}
}
}
fn main() {
// Generar código Verilog y guardarlo en sumadorRust.v
let mut uut = ReconocedorPatrones::default();
uut.connect_all();
let verilog_code = generate_verilog(&uut);
let code = verilog_code.replace("module top(", "module reconocedorPatrones(");
let file_path = "reconocedorPatronesRust.v";
let mut file = File::create(file_path).expect("No se pudo crear el archivo");
file.write_all(code.as_bytes()).expect("Error al escribir en el archivo");
println!("Código Verilog generado y guardado en {}", file_path);
}
// Función para obtener la salida de Icarus Verilog
#[cfg(test)]
fn get_icarus_verilog_output(tb: &str) -> anyhow::Result {
std::fs::write("test_reconocedorPatrones_tb.v", tb).unwrap();
let output = std::process::Command::new("iverilog")
.args(["-tvvp", "-o", "test_tb.vvp", "test_reconocedorPatrones_tb.v"])
.output()?;
println!("\niverilog output: {:?}", output);
let output = std::process::Command::new("vvp")
.arg("test_tb.vvp")
.output()?;
Ok(String::from_utf8_lossy(&output.stdout).into())
}
// Test con RustHDL y comparación con Verilog
#[test]
fn test_reconocedor_patrones() -> anyhow::Result<()> {
let mut uut = ReconocedorPatrones::default();
uut.connect_all();
//Prueba del codigo en verilog para pasarlo al iverilog
let verilog_tb = r#"
module test;
reg clk, rst, entrada;
wire salida;
reconocedorPatrones uut(.clk(clk), .rst(rst), .entrada(entrada), .salida(salida));
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
$monitor("entrada=%d, salida=%d, rst=%d", entrada, salida, rst);
entrada = 0; rst = 0;
#10 entrada = 0;
#10 entrada = 1;
#10 entrada = 0;
#10 entrada = 1;
#10 entrada = 0;
#10 entrada = 1;
#10 entrada = 1;
#10 $finish;
end
endmodule
"#;
//Esto es para concatenar el testbench y el codigo en verilog del sumador
let tb = format!("{verilog_tb} {}", generate_verilog(&uut));
//Remplazamos el nombre module top que tiene por defecto y se lo pasamos al iverilog
let code = tb.replace("module top(", "module reconocedorPatrones(");
//Esto le pasa al iverilog el testbench y luego nos muestra la salida
let sim_output = get_icarus_verilog_output(&code)?;
println!("(iverilog) Salida de Verilog:\n{}", sim_output);
// Generamos la simulación y le añadimos el testbench
let mut sim = Simulation::::new();
sim.add_testbench(move |mut ep| {
// Iniciamos
let mut x = ep.init()?;
// 1. Verificar el estado inicial (salida debe ser 0)
x.rst.next = true;
ep.wait(1, x.clone())?;
println!("Test Reset: salida={}\n", x.salida.val());
sim_assert_eq!(ep, x.salida.val(), false, x);
// 2. Desactivamos Reset y verificamos que la salida siga en 0
x.rst.next = false;
ep.wait(1, x.clone())?;
println!("Test Post-Reset: salida={}\n", x.salida.val());
sim_assert_eq!(ep, x.salida.val(), false, x);
// 3. Probamos las combinaciones de 4 bits. Vamos a probar específicamente el patrón "1011"
let test_cases = vec![
vec![1, 0, 1, 1], // Patrón correcto
vec![0, 1, 0, 1], // No es el patrón "1011"
vec![1, 1, 0, 1], // No es el patrón "1011"
vec![1, 0, 0, 1], // No es el patrón "1011"
vec![0, 0, 1, 1], // No es el patrón "1011"
];
// Ejecutamos los casos de prueba
println!("Ejecutando {} casos de prueba...", test_cases.len());
for case in test_cases.iter() {
println!("Probando secuencia: {:?}", case);
for (i, &bit) in case.iter().enumerate() {
x.entrada.next = bit == 1; // Alimentamos un bit
x.clk.next = Clock { clk: true};
ep.wait(1, x.clone())?;
x.clk.next = Clock { clk: false};
let x = ep.wait(1, x.clone())?; //flanco de subida
// El expected_output debe ser true solo cuando detectamos el patrón "1011"
let expected_output = if case == &vec![1, 0, 1, 1] && i == 3 {
true // El patrón "1011" debe dar true en el último bit
} else {
false // Los demás casos deben ser false
};
// Imprimimos la entrada y la salida esperada
println!("Entrada: {}, Iteración: {}, Salida esperada: {}, Salida actual: {}",
bit, i + 1, expected_output, x.salida.val());
// Verificamos que la salida es la esperada
sim_assert_eq!(ep, x.salida.val(), expected_output, x);
}
println!(""); // Fin de la secuencia de prueba
// Reiniciamos la máquina de estados
x.rst.next = true;
ep.wait(1, x.clone())?;
x.rst.next = false;
ep.wait(1, x.clone())?;
}
// Terminamos la simulación si no hubo fallos
ep.done(x)?;
Ok(())
});
//Esto es para eliminar el fichero .vvp
let _e = fs::remove_file("test_tb.vvp");
sim.run_to_file(Box::new(uut), 1000, "reconocedorPatronesWave.vcd")
.map_err(|err| anyhow!("{:?}", err))?;
Ok(())
}
Log
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.03s
warning: the following packages contain code that will be rejected by a future version of Rust: svg v0.10.0
note: to see what the problems were, use the option --future-incompat-report, or run cargo report future-incompatibilities --id 1
Running unittests src/main.rs (target/debug/deps/reconocedorPatrones-5a449bd2fd3e14ea)
running 1 test
test test_reconocedor_patrones ...
iverilog output: Output { status: ExitStatus(unix_wait_status(6912)), stdout: "", stderr: "test_reconocedorPatrones_tb.v:67: syntax error\ntest_reconocedorPatrones_tb.v:75: Syntax in assignment statement l-value.\ntest_reconocedorPatrones_tb.v:77: syntax error\ntest_reconocedorPatrones_tb.v:78: Syntax in assignment statement l-value.\ntest_reconocedorPatrones_tb.v:80: syntax error\ntest_reconocedorPatrones_tb.v:80: error: Invalid module instantiation\ntest_reconocedorPatrones_tb.v:86: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:87: syntax error\ntest_reconocedorPatrones_tb.v:89: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:90: syntax error\ntest_reconocedorPatrones_tb.v:96: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:97: syntax error\ntest_reconocedorPatrones_tb.v:99: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:100: syntax error\ntest_reconocedorPatrones_tb.v:106: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:107: syntax error\ntest_reconocedorPatrones_tb.v:109: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:110: syntax error\ntest_reconocedorPatrones_tb.v:115: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:116: syntax error\ntest_reconocedorPatrones_tb.v:116: error: Invalid module instantiation\ntest_reconocedorPatrones_tb.v:125: error: Invalid module item.\ntest_reconocedorPatrones_tb.v:133: error: 'State$S0' has already been declared in this scope.\ntest_reconocedorPatrones_tb.v:39: : It was declared here as a parameter.\ntest_reconocedorPatrones_tb.v:134: error: 'State$S1' has already been declared in this scope.\ntest_reconocedorPatrones_tb.v:40: : It was declared here as a parameter.\ntest_reconocedorPatrones_tb.v:135: error: 'State$S2' has already been declared in this scope.\ntest_reconocedorPatrones_tb.v:41: : It was declared here as a parameter.\ntest_reconocedorPatrones_tb.v:136: error: 'State$S3' has already been declared in this scope.\ntest_reconocedorPatrones_tb.v:42: : It was declared here as a parameter.\ntest_reconocedorPatrones_tb.v:137: error: 'State$S4' has already been declared in this scope.\ntest_reconocedorPatrones_tb.v:43: : It was declared here as a parameter.\n" }
(iverilog) Salida de Verilog:
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Test Reset: salida=false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Test Post-Reset: salida=false
Ejecutando 5 casos de prueba...
Probando secuencia: [1, 0, 1, 1]
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S1, Entrada: true, Salida: false
En S1, Entrada: true
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Entrada: 1, Iteración: 1, Salida esperada: false, Salida actual: false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Entrada: 0, Iteración: 2, Salida esperada: false, Salida actual: false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S1, Entrada: true, Salida: false
En S1, Entrada: true
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Entrada: 1, Iteración: 3, Salida esperada: false, Salida actual: false
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S1, Entrada: true, Salida: false
En S1, Entrada: true
Estado actual: S0, Entrada: false, Salida: false
En S0, Entrada: false
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Entrada: 1, Iteración: 4, Salida esperada: true, Salida actual: false
HALT x.salida.val() != expected_output, false != true
Estado actual: S0, Entrada: true, Salida: false
En S0, Entrada: true
S0 dentro
Error: SimHalted
FAILED
failures:
failures:
test_reconocedor_patrones
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
error: test failed, to rerun pass --bin reconocedorPatrones