From e3d8ad8d36cc2a11051762918c46a8651c9b34ff Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 16 Feb 2025 15:44:34 -0800 Subject: [PATCH] io: Add source-synchronous IO modules Signed-off-by: Alex Forencich --- rtl/io/taxi_ssio_ddr_in.sv | 116 ++++++++++++++++++++++++++ rtl/io/taxi_ssio_ddr_in_diff.sv | 107 ++++++++++++++++++++++++ rtl/io/taxi_ssio_ddr_out.sv | 72 +++++++++++++++++ rtl/io/taxi_ssio_ddr_out_diff.sv | 113 ++++++++++++++++++++++++++ rtl/io/taxi_ssio_sdr_in.sv | 134 +++++++++++++++++++++++++++++++ rtl/io/taxi_ssio_sdr_in_diff.sv | 105 ++++++++++++++++++++++++ rtl/io/taxi_ssio_sdr_out.sv | 62 ++++++++++++++ rtl/io/taxi_ssio_sdr_out_diff.sv | 106 ++++++++++++++++++++++++ 8 files changed, 815 insertions(+) create mode 100644 rtl/io/taxi_ssio_ddr_in.sv create mode 100644 rtl/io/taxi_ssio_ddr_in_diff.sv create mode 100644 rtl/io/taxi_ssio_ddr_out.sv create mode 100644 rtl/io/taxi_ssio_ddr_out_diff.sv create mode 100644 rtl/io/taxi_ssio_sdr_in.sv create mode 100644 rtl/io/taxi_ssio_sdr_in_diff.sv create mode 100644 rtl/io/taxi_ssio_sdr_out.sv create mode 100644 rtl/io/taxi_ssio_sdr_out_diff.sv diff --git a/rtl/io/taxi_ssio_ddr_in.sv b/rtl/io/taxi_ssio_ddr_in.sv new file mode 100644 index 0000000..b8a8b60 --- /dev/null +++ b/rtl/io/taxi_ssio_ddr_in.sv @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous DDR input + */ +module taxi_ssio_ddr_in # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic input_clk, + + input wire logic [WIDTH-1:0] input_d, + + output wire logic output_clk, + + output wire logic [WIDTH-1:0] output_q1, + output wire logic [WIDTH-1:0] output_q2 +); + +wire clk_int; +wire clk_io; + +if (!SIM && VENDOR == "XILINX") begin + // Xilinx/AMD device support + + // use Xilinx clocking primitives + + if (FAMILY == "virtex6" || FAMILY == "virtex7" || FAMILY == "kintex7" || FAMILY == "artix7") begin + // BUFIO + BUFR + // virtex6, virtex7, kintex7, artix7, zynq + + assign clk_int = input_clk; + + // pass through RX clock to input buffers + BUFIO + clk_bufio ( + .I(clk_int), + .O(clk_io) + ); + + // pass through RX clock to logic + BUFR #( + .BUFR_DIVIDE("BYPASS") + ) + clk_bufr ( + .I(clk_int), + .O(output_clk), + .CE(1'b1), + .CLR(1'b0) + ); + + end else begin + // BUFG only + // spartan6, virtexu, kintexu, virtexuplus, virtexuplusHBM, virtexuplus58g, kintexuplus, zynquplus, zynquplusRFSOC + + // buffer RX clock + BUFG + clk_bufg ( + .I(input_clk), + .O(clk_int) + ); + + // pass through RX clock to logic and input buffers + assign clk_io = clk_int; + assign output_clk = clk_int; + + end + +end else begin + // generic/simulation implementation (no vendor primitives) + + // pass through RX clock to input buffers + assign clk_io = input_clk; + + // pass through RX clock to logic + assign clk_int = input_clk; + assign output_clk = clk_int; + +end + +taxi_iddr #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(WIDTH) +) +data_iddr_inst ( + .clk(clk_io), + .d(input_d), + .q1(output_q1), + .q2(output_q2) +); + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_ddr_in_diff.sv b/rtl/io/taxi_ssio_ddr_in_diff.sv new file mode 100644 index 0000000..dcd47d5 --- /dev/null +++ b/rtl/io/taxi_ssio_ddr_in_diff.sv @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous DDR input + */ +module taxi_ssio_ddr_in_diff # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic input_clk_p, + input wire logic input_clk_n, + + input wire logic [WIDTH-1:0] input_d_p, + input wire logic [WIDTH-1:0] input_d_n, + + output wire logic output_clk, + + output wire logic [WIDTH-1:0] output_q1, + output wire logic [WIDTH-1:0] output_q2 +); + +wire input_clk; +wire [WIDTH-1:0] input_d; + +if (!SIM && VENDOR == "XILINX") begin + // Xilinx/AMD device support + + IBUFDS + clk_ibufds_inst ( + .I(input_clk_p), + .IB(input_clk_n), + .O(input_clk) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + IBUFDS + data_ibufds_inst ( + .I(input_d_p[n]), + .IB(input_d_n[n]), + .O(input_d[n]) + ); + end + +end else if (!SIM && VENDOR == "ALTERA") begin + // Altera/Intel/Altera device support + + ALT_INBUF_DIFF + clk_inbuf_diff_inst ( + .i(input_clk_p), + .ibar(input_clk_n), + .o(input_clk) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + ALT_INBUF_DIFF + data_inbuf_diff_inst ( + .i(input_d_p[n]), + .ibar(input_d_n[n]), + .o(input_d[n]) + ); + end + +end else begin + // generic/simulation implementation (no vendor primitives) + + assign input_clk = input_clk_p; + assign input_d = input_d_p; + +end + +taxi_ssio_ddr_in #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(WIDTH) +) +ssio_ddr_in_inst( + .input_clk(input_clk), + .input_d(input_d), + .output_clk(output_clk), + .output_q1(output_q1), + .output_q2(output_q2) +); + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_ddr_out.sv b/rtl/io/taxi_ssio_ddr_out.sv new file mode 100644 index 0000000..7927c78 --- /dev/null +++ b/rtl/io/taxi_ssio_ddr_out.sv @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous DDR output + */ +module taxi_ssio_ddr_out # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Use 90 degree clock for transmit + parameter logic USE_CLK90 = 1'b1, + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic clk, + input wire logic clk90, + + input wire logic [WIDTH-1:0] input_d1, + input wire logic [WIDTH-1:0] input_d2, + + output wire logic output_clk, + output wire logic [WIDTH-1:0] output_q +); + +wire ref_clk = USE_CLK90 ? clk90 : clk; + +taxi_oddr #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(1) +) +clk_oddr_inst ( + .clk(ref_clk), + .d1(1'b1), + .d2(1'b0), + .q(output_clk) +); + +taxi_oddr #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(WIDTH) +) +data_oddr_inst ( + .clk(clk), + .d1(input_d1), + .d2(input_d2), + .q(output_q) +); + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_ddr_out_diff.sv b/rtl/io/taxi_ssio_ddr_out_diff.sv new file mode 100644 index 0000000..90a1eda --- /dev/null +++ b/rtl/io/taxi_ssio_ddr_out_diff.sv @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous DDR output + */ +module taxi_ssio_ddr_out_diff # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Use 90 degree clock for transmit + parameter logic USE_CLK90 = 1'b1, + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic clk, + input wire logic clk90, + + input wire logic [WIDTH-1:0] input_d1, + input wire logic [WIDTH-1:0] input_d2, + + output wire logic output_clk_p, + output wire logic output_clk_n, + output wire logic [WIDTH-1:0] output_q_p, + output wire logic [WIDTH-1:0] output_q_n +); + +wire output_clk; +wire [WIDTH-1:0] output_q; + +taxi_ssio_ddr_out #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .USE_CLK90(USE_CLK90), + .WIDTH(WIDTH) +) +ssio_ddr_out_inst( + .clk(clk), + .clk90(clk90), + .input_d1(input_d1), + .input_d2(input_d2), + .output_clk(output_clk), + .output_q(output_q) +); + +if (!SIM && VENDOR == "XILINX") begin + // Xilinx/AMD device support + + OBUFDS + clk_obufds_inst ( + .I(output_clk), + .O(output_clk_p), + .OB(output_clk_n) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + OBUFDS + data_obufds_inst ( + .I(output_q[n]), + .O(output_q_p[n]), + .OB(output_q_n[n]) + ); + end + +end else if (!SIM && VENDOR == "ALTERA") begin + // Altera/Intel/Altera device support + + ALT_OUTBUF_DIFF + clk_outbuf_diff_inst ( + .i(output_clk), + .o(output_clk_p), + .obar(output_clk_n) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + ALT_OUTBUF_DIFF + data_outbuf_diff_inst ( + .i(output_q[n]), + .o(output_q_p[n]), + .obar(output_q_n[n]) + ); + end + +end else begin + // generic/simulation implementation (no vendor primitives) + + assign output_clk_p = output_clk; + assign output_clk_n = ~output_clk; + assign output_q_p = output_q; + assign output_q_n = ~output_q; + +end + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_sdr_in.sv b/rtl/io/taxi_ssio_sdr_in.sv new file mode 100644 index 0000000..f4942b4 --- /dev/null +++ b/rtl/io/taxi_ssio_sdr_in.sv @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous SDR input + */ +module taxi_ssio_sdr_in # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic input_clk, + + input wire logic [WIDTH-1:0] input_d, + + output wire logic output_clk, + + output wire logic [WIDTH-1:0] output_q +); + +wire clk_int; +wire clk_io; + +if (!SIM && VENDOR == "XILINX") begin + // Xilinx/AMD device support + + if (FAMILY == "virtex6" || FAMILY == "virtex7" || FAMILY == "kintex7" || FAMILY == "artix7") begin + // BUFIO + BUFR + // virtex6, virtex7, kintex7, artix7, zynq + + assign clk_int = input_clk; + + // pass through RX clock to input buffers + BUFIO + clk_bufio ( + .I(clk_int), + .O(clk_io) + ); + + // pass through RX clock to logic + BUFR #( + .BUFR_DIVIDE("BYPASS") + ) + clk_bufr ( + .I(clk_int), + .O(output_clk), + .CE(1'b1), + .CLR(1'b0) + ); + + end else if (FAMILY == "spartan6") begin + // BUFIO2 + BUFG + // spartan6 + + // pass through RX clock to input buffers + BUFIO2 #( + .DIVIDE(1), + .DIVIDE_BYPASS("TRUE"), + .I_INVERT("FALSE"), + .USE_DOUBLER("FALSE") + ) + clk_bufio ( + .I(input_clk), + .DIVCLK(clk_int), + .IOCLK(clk_io), + .SERDESSTROBE() + ); + + // pass through RX clock to MAC + BUFG + clk_bufg ( + .I(clk_int), + .O(output_clk) + ); + + end else begin + // BUFG only + // virtexu, kintexu, virtexuplus, virtexuplusHBM, virtexuplus58g, kintexuplus, zynquplus, zynquplusRFSOC + + // buffer RX clock + BUFG + clk_bufg ( + .I(input_clk), + .O(clk_int) + ); + + // pass through RX clock to logic and input buffers + assign clk_io = clk_int; + assign output_clk = clk_int; + + end + +end else begin + // generic/simulation implementation (no vendor primitives) + + // pass through RX clock to input buffers + assign clk_io = input_clk; + + // pass through RX clock to logic + assign clk_int = input_clk; + assign output_clk = clk_int; + +end + +(* IOB = "TRUE" *) +logic [WIDTH-1:0] output_q_reg = '0; + +assign output_q = output_q_reg; + +always_ff @(posedge clk_io) begin + output_q_reg <= input_d; +end + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_sdr_in_diff.sv b/rtl/io/taxi_ssio_sdr_in_diff.sv new file mode 100644 index 0000000..4c21418 --- /dev/null +++ b/rtl/io/taxi_ssio_sdr_in_diff.sv @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous SDR input + */ +module ssio_sdr_in_diff # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic input_clk_p, + input wire logic input_clk_n, + + input wire logic [WIDTH-1:0] input_d_p, + input wire logic [WIDTH-1:0] input_d_n, + + output wire logic output_clk, + + output wire logic [WIDTH-1:0] output_q +); + +wire input_clk; +wire [WIDTH-1:0] input_d; + +if (!SIM && VENDOR == "XILINX") begin + // Xilinx/AMD device support + + IBUFDS + clk_ibufds_inst ( + .I(input_clk_p), + .IB(input_clk_n), + .O(input_clk) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + IBUFDS + data_ibufds_inst ( + .I(input_d_p[n]), + .IB(input_d_n[n]), + .O(input_d[n]) + ); + end + +end else if (!SIM && VENDOR == "ALTERA") begin + // Altera/Intel/Altera device support + + ALT_INBUF_DIFF + clk_inbuf_diff_inst ( + .i(input_clk_p), + .ibar(input_clk_n), + .o(input_clk) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + ALT_INBUF_DIFF + data_inbuf_diff_inst ( + .i(input_d_p[n]), + .ibar(input_d_n[n]), + .o(input_d[n]) + ); + end + +end else begin + // generic/simulation implementation (no vendor primitives) + + assign input_clk = input_clk_p; + assign input_d = input_d_p; + +end + +taxi_ssio_sdr_in #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(WIDTH) +) +ssio_ddr_in_inst( + .input_clk(input_clk), + .input_d(input_d), + .output_clk(output_clk), + .output_q(output_q) +); + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_sdr_out.sv b/rtl/io/taxi_ssio_sdr_out.sv new file mode 100644 index 0000000..d19dc28 --- /dev/null +++ b/rtl/io/taxi_ssio_sdr_out.sv @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous SDR output + */ +module taxi_ssio_sdr_out # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic clk, + + input wire logic [WIDTH-1:0] input_d, + + output wire logic output_clk, + output wire logic [WIDTH-1:0] output_q +); + +taxi_oddr #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(1) +) +clk_oddr_inst ( + .clk(clk), + .d1(1'b0), + .d2(1'b1), + .q(output_clk) +); + +(* IOB = "TRUE" *) +logic [WIDTH-1:0] output_q_reg = '0; + +assign output_q = output_q_reg; + +always_ff @(posedge clk) begin + output_q_reg <= input_d; +end + +endmodule + +`resetall diff --git a/rtl/io/taxi_ssio_sdr_out_diff.sv b/rtl/io/taxi_ssio_sdr_out_diff.sv new file mode 100644 index 0000000..84fba78 --- /dev/null +++ b/rtl/io/taxi_ssio_sdr_out_diff.sv @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2016-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Generic source synchronous SDR output + */ +module taxi_ssio_sdr_out_diff # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter VENDOR = "XILINX", + // device family + parameter FAMILY = "virtex7", + // Width of register in bits + parameter WIDTH = 1 +) +( + input wire logic clk, + + input wire logic [WIDTH-1:0] input_d, + + output wire logic output_clk_p, + output wire logic output_clk_n, + output wire logic [WIDTH-1:0] output_q_p, + output wire logic [WIDTH-1:0] output_q_n +); + +wire output_clk; +wire [WIDTH-1:0] output_q; + +taxi_ssio_sdr_out #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .WIDTH(WIDTH) +) +ssio_ddr_out_inst( + .clk(clk), + .input_d(input_d), + .output_clk(output_clk), + .output_q(output_q) +); + +if (!SIM && VENDOR == "XILINX") begin + // Xilinx/AMD device support + + OBUFDS + clk_obufds_inst ( + .I(output_clk), + .O(output_clk_p), + .OB(output_clk_n) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + OBUFDS + data_obufds_inst ( + .I(output_q[n]), + .O(output_q_p[n]), + .OB(output_q_n[n]) + ); + end + +end else if (!SIM && VENDOR == "ALTERA") begin + // Altera/Intel/Altera device support + + ALT_OUTBUF_DIFF + clk_outbuf_diff_inst ( + .i(output_clk), + .o(output_clk_p), + .obar(output_clk_n) + ); + + for (genvar n = 0; n < WIDTH; n = n + 1) begin + ALT_OUTBUF_DIFF + data_outbuf_diff_inst ( + .i(output_q[n]), + .o(output_q_p[n]), + .obar(output_q_n[n]) + ); + end + +end else begin + // generic/simulation implementation (no vendor primitives) + + assign output_clk_p = output_clk; + assign output_clk_n = ~output_clk; + assign output_q_p = output_q; + assign output_q_n = ~output_q; + +end + +endmodule + +`resetall