rust_hdl_fpga_support/lattice/ecp5/
edge_tristate_buffer.rs1use 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}