1use std::env::temp_dir;
2use std::fs::{create_dir_all, remove_dir_all, File};
3use std::io::{Error, Write};
4use std::process::Command;
5
6#[derive(Debug)]
7pub enum SynthError {
8 SynthesisFailed { stdout: String, stderr: String },
9 LatchingWriteToSignal(Vec<String>),
10 ImplicitlyDeclared(Vec<String>),
11 DuplicateModule(Vec<String>),
12 IOError(std::io::Error),
13 WireHasNoDriver(Vec<String>),
14 MissingModule(Vec<String>),
15}
16
17impl From<std::io::Error> for SynthError {
18 fn from(x: Error) -> Self {
19 SynthError::IOError(x)
20 }
21}
22
23pub fn yosys_validate(prefix: &str, translation: &str) -> Result<(), SynthError> {
24 let dir = temp_dir().as_path().join(prefix);
25 let _ = remove_dir_all(&dir);
26 let _ = create_dir_all(&dir);
27 let mut v_file = File::create(dir.clone().join("top.v")).unwrap();
28 write!(v_file, "{}", translation).unwrap();
29 let output = Command::new("yosys")
30 .current_dir(dir.clone())
31 .arg(format!(
32 "-p read -vlog95 top.v; hierarchy -check -top top; proc",
33 ))
34 .output()
35 .unwrap();
36 let stdout = String::from_utf8(output.stdout).unwrap();
37 let stderr = String::from_utf8(output.stderr).unwrap();
38 {
39 let mut debug = File::create(dir.join("yosys.stdout"))?;
40 write!(debug, "{}", stdout).unwrap();
41 write!(debug, "{}", stderr).unwrap();
42 let mut dump = File::create(dir.join("yosys.v"))?;
43 write!(dump, "{}", translation).unwrap();
44 }
45 fn capture(stdout: &str, reg_exp: &str) -> Vec<String> {
46 let regex = regex::Regex::new(reg_exp).unwrap();
47 let mut signal_name = vec![];
48 if regex.is_match(&stdout) {
49 for capture in regex.captures(&stdout).unwrap().iter() {
50 signal_name.push(capture.unwrap().as_str().to_string());
51 }
52 }
53 signal_name
54 }
55 if stdout.contains("Re-definition of") {
56 return Err(SynthError::DuplicateModule(capture(
57 &stdout,
58 r#"Re-definition of module (\S*)"#,
59 )));
60 }
61 if stdout.contains("implicitly declared.") {
62 return Err(SynthError::ImplicitlyDeclared(capture(
63 &stdout,
64 r#"Identifier (\S*) is implicitly declared"#,
65 )));
66 }
67 if stdout.contains("Latch inferred for") {
68 return Err(SynthError::LatchingWriteToSignal(capture(
69 &stdout,
70 r#"Latch inferred for signal (\S*)"#,
71 )));
72 }
73 if stdout.contains("is used but has no driver") {
74 return Err(SynthError::WireHasNoDriver(capture(
75 &stdout,
76 r#"Wire (\S*) .*? is used but has no driver."#,
77 )));
78 }
79 if stderr.contains("is not part of the design") {
80 return Err(SynthError::MissingModule(capture(
81 &stderr,
82 r#"Module (\S*) .*? is not part of the design"#,
83 )));
84 }
85 if !stdout.contains("End of script.") {
86 return Err(SynthError::SynthesisFailed { stdout, stderr });
87 }
88 Ok(())
89}