rust_sfq 1.0.4

DSL for designing SFQ circuits in Rust.
Documentation
use super::{format_ps, physical_event_time_ps, port_declarations};
use crate::testbench::{Testbench, TestbenchBackend};

pub struct RsfqlibVerilogTestbench;

impl TestbenchBackend for RsfqlibVerilogTestbench {
    fn generate(&self, testbench: &Testbench<'_>) -> String {
        let tb = testbench.normalize();
        let (inputs, outputs) = port_declarations(&tb);
        let mut events = Vec::new();
        let mut res = Vec::new();

        for signal in &tb.signals {
            for (cycle, value) in signal.values.iter().enumerate() {
                if *value == 1 {
                    let start = physical_event_time_ps(cycle, signal, tb.period_ps);
                    events.push((start, signal.name.clone()));
                }
            }
        }
        events.sort_by(|a, b| a.0.total_cmp(&b.0).then(a.1.cmp(&b.1)));

        res.push("`timescale 1ps / 100fs".to_string());
        res.push("`include \"all.v\"".to_string());
        res.push("`include \"modules.v\"".to_string());
        res.push(String::new());
        res.push("module top;".to_string());
        res.push("  // Inputs".to_string());
        if !inputs.is_empty() {
            res.push(format!("  reg {};", inputs.join(", ")));
        }
        res.push("  // Outputs".to_string());
        if !outputs.is_empty() {
            res.push(format!("  wire {};", outputs.join(", ")));
        }
        res.push(String::new());
        res.push(format!("  {} dut (.*);", tb.circuit.name()));
        res.push(String::new());
        res.push("  // Input pulses".to_string());
        res.push("  initial begin".to_string());
        for signal in &tb.signals {
            res.push(format!("    {} = 0;", signal.name));
        }

        let mut current_time = 0.0;
        for (time, name) in events {
            let delay = time - current_time;
            if delay > 0.0 {
                res.push(format!("    #{};", format_ps(delay)));
            }
            res.push(format!("    {} ^= 1;", name));
            current_time = time;
        }

        let finish_time = (tb.cycles as f64 + 1.0) * tb.period_ps;
        let delay = finish_time - current_time;
        if delay > 0.0 {
            res.push(format!("    #{};", format_ps(delay)));
        }
        res.push("    $finish;".to_string());
        res.push("  end".to_string());
        res.push(String::new());
        res.push("  initial begin".to_string());
        res.push(format!("    $dumpfile(\"{}.vcd\");", tb.name));
        res.push("    $dumpvars(0, top);".to_string());
        res.push("  end".to_string());
        res.push("endmodule".to_string());

        res.join("\n")
    }
}