rust_hdl_fpga_support/lattice/ecp5/
io_delay.rs

1use rust_hdl_core::prelude::*;
2
3#[derive(Clone, Debug, LogicBlock)]
4pub struct IODelay<T: Synth> {
5    pub a: Signal<In, T>,
6    pub z: Signal<Out, T>,
7    _delay: u8,
8}
9
10impl<T: Synth> IODelay<T> {
11    pub fn new(delay: u8) -> Self {
12        Self {
13            a: Default::default(),
14            z: Default::default(),
15            _delay: delay,
16        }
17    }
18}
19
20fn wrapper_once(delay: u8) -> String {
21    format!(
22        r##"
23defparam udel_dataini0.DEL_VALUE = {delay} ;
24defparam udel_dataini0.DEL_MODE = "USER_DEFINED" ;
25DELAYG udel_dataini0 (.A(buf_dataini0), .Z(dataini_t0));
26    "##,
27        delay = delay
28    )
29}
30
31fn wrapper_multiple(count: usize, delay: u8) -> String {
32    (0..count)
33        .map(|x| {
34            format!(
35                r##"
36defparam udel_datain_{x}.DEL_VALUE = {delay} ;
37defparam udel_datain_{x}.DEL_MODE = "USER_DEFINED" ;
38DELAYG udel_datain_{x} (.A(a[{x}]), .Z(z[{x}]));
39    "##,
40                x = x,
41                delay = delay
42            )
43        })
44        .collect::<Vec<_>>()
45        .join("\n")
46}
47
48impl<T: Synth> Logic for IODelay<T> {
49    fn update(&mut self) {
50        self.z.next = self.a.val();
51    }
52    fn connect(&mut self) {
53        self.z.connect();
54    }
55    fn hdl(&self) -> Verilog {
56        Verilog::Wrapper(Wrapper {
57            code: if T::BITS == 1 {
58                wrapper_once(self._delay)
59            } else {
60                wrapper_multiple(T::BITS, self._delay)
61            },
62            cores: r##"
63(* blackbox *)
64module DELAYG(input A, output Z);
65parameter DEL_MODE = "USER_DEFINED";
66parameter DEL_VALUE = 0;
67endmodule
68            "##
69            .to_string(),
70        })
71    }
72}
73
74#[test]
75fn test_iodelay_synthesizes() {
76    let mut uut = IODelay::<Bits<8>>::new(25);
77    uut.connect_all();
78    yosys_validate("iodelay", &generate_verilog(&uut)).unwrap();
79}