rust_hdl_fpga_support/lattice/ecp5/
edge_tristate_buffer.rs

1use rust_hdl_core::prelude::*;
2use rust_hdl_widgets::prelude::*;
3
4#[derive(LogicBlock, Default)]
5pub struct EdgeTristateBuffer<T: Synth> {
6    pub to_pin: Signal<In, T>,
7    pub from_pin: Signal<Out, T>,
8    pub output_enable: Signal<In, Bit>,
9    pub clock: Signal<In, Clock>,
10    pub reset: Signal<In, Bit>,
11    pub pin: Signal<InOut, T>,
12    dff_out: DFF<T>,
13    dff_in: DFF<T>,
14    buffer: TristateBuffer<T>,
15}
16
17fn wrapper_once() -> String {
18    format!(
19        r##"
20    wire bb_to_pin;
21    wire bb_from_pin;
22
23    OFS1P3DX obuf(.D(to_pin), .CD(reset), .SP(1'b1), .SCLK(clock), .Q(bb_to_pin));
24    IFS1P3DX ibuf(.D(bb_from_pin), .CD(reset), .SP(1'b1), .SCLK(clock), .Q(from_pin));
25    BB bb(.I(bb_to_pin), .O(bb_from_pin), .B(pin), .T(~output_enable));
26"##
27    )
28}
29
30fn wrapper_multiple(count: usize) -> String {
31    let bufs = (0..count)
32        .map(|x| {
33            format!(
34                r#"
35    OFS1P3DX obuf_{x}(.D(to_pin[{x}]), .CD(reset), .SP(1'b1), .SCLK(clock), .Q(bb_to_pin[{x}]));
36    IFS1P3DX ibuf_{x}(.D(bb_from_pin[{x}]), .CD(reset), .SP(1'b1), .SCLK(clock), .Q(from_pin[{x}]));
37    BB bb_{x}(.I(bb_to_pin[{x}]), .O(bb_from_pin[{x}]), .B(pin[{x}]), .T(~output_enable));
38        "#,
39                x = x
40            )
41        })
42        .collect::<Vec<_>>()
43        .join("\n");
44    format!(
45        r##"
46wire [{B}:0] bb_to_pin;
47wire [{B}:0] bb_from_pin;
48
49{bufs}
50    "##,
51        B = count,
52        bufs = bufs
53    )
54}
55
56impl<T: Synth> Logic for EdgeTristateBuffer<T> {
57    fn update(&mut self) {
58        dff_setup!(self, clock, dff_out, dff_in);
59        self.buffer.write_enable.next = self.output_enable.val();
60        self.dff_in.d.next = self.buffer.read_data.val();
61        self.dff_out.d.next = self.to_pin.val();
62        self.buffer.write_data.next = self.dff_out.q.val();
63        self.from_pin.next = self.dff_in.q.val();
64        Signal::<InOut, T>::link(&mut self.pin, &mut self.buffer.bus);
65    }
66    fn connect(&mut self) {
67        self.dff_out.clock.connect();
68        self.dff_in.clock.connect();
69        self.buffer.write_enable.connect();
70        self.dff_in.d.connect();
71        self.dff_out.d.connect();
72        self.buffer.write_data.connect();
73        self.from_pin.connect();
74    }
75    fn hdl(&self) -> Verilog {
76        Verilog::Wrapper(Wrapper {
77            code: if T::BITS == 1 {
78                wrapper_once().to_string()
79            } else {
80                wrapper_multiple(T::BITS)
81            },
82            cores: r##"
83(* blackbox *)
84module IFS1P3DX(input D, input SP, input SCLK, input CD, output Q);
85endmodule
86
87(* blackbox *)
88module OFS1P3DX(input D, input SP, input SCLK, input CD, output Q);
89endmodule
90
91(* blackbox *)
92module BB(input I, input T, output O, inout B);
93endmodule
94            "##
95            .into(),
96        })
97    }
98}
99
100#[test]
101fn test_edge_buffer_synthesizes() {
102    let mut uut = EdgeTristateBuffer::<Bits<8>>::default();
103    uut.connect_all();
104    yosys_validate("edge_tristate_buffer", &generate_verilog(&uut)).unwrap();
105}