blob: cd0352e5cc65476cba9d316ef14f17f02e29a5bd [file] [log] [blame]
`default_nettype none
// ============================================================================
module oserdes_test #
(
parameter DATA_WIDTH = 8,
parameter DATA_RATE = "SDR",
parameter ERROR_HOLD = 2500000
)
(
// "Hi speed" clock and reset
input wire CLK,
input wire RST,
// OSERDES clocks
input wire CLK1,
input wire CLK2,
// Data pin
inout wire IO_DAT,
// Error indicator
output wire O_ERROR
);
// ============================================================================
// Generate CLK2 and CLKDIV for OSERDES using BUFRs
localparam CLKDIV_DIVIDE =
(DATA_RATE == "SDR" && DATA_WIDTH == 2) ? "2" :
(DATA_RATE == "SDR" && DATA_WIDTH == 3) ? "3" :
(DATA_RATE == "SDR" && DATA_WIDTH == 4) ? "4" :
(DATA_RATE == "SDR" && DATA_WIDTH == 5) ? "5" :
(DATA_RATE == "SDR" && DATA_WIDTH == 6) ? "6" :
(DATA_RATE == "SDR" && DATA_WIDTH == 7) ? "7" :
(DATA_RATE == "SDR" && DATA_WIDTH == 8) ? "8" :
(DATA_RATE == "DDR" && DATA_WIDTH == 4) ? "4" :
(DATA_RATE == "DDR" && DATA_WIDTH == 6) ? "6" :
(DATA_RATE == "DDR" && DATA_WIDTH == 8) ? "8" : "BYPASS";
wire CLKX;
wire CLKDIV;
BUFIO io_buf (.I((DATA_RATE == "DDR") ? CLK2 : CLK1), .O(CLKX));
BUFR #
(
.BUFR_DIVIDE (CLKDIV_DIVIDE)
)
bufr_clkdiv
(
.I (CLK1),
.O (CLKDIV),
.CLR (RST),
.CE (1'd1)
);
// The clock enable signal for the "hi speed" clock domain.
reg clkdiv_r;
wire ce;
always @(posedge CLK)
clkdiv_r <= CLKDIV;
assign ce = clkdiv_r && !CLKDIV;
// ============================================================================
// Data source
reg lfsr_stb;
wire [7:0] lfsr_dat;
lfsr lfsr
(
.CLK (CLK),
.RST (RST),
.CE (ce),
.O (lfsr_dat)
);
always @(posedge CLK)
if (RST)
lfsr_stb <= 1'b0;
else
lfsr_stb <= ce;
// Synchronize generated data wordst to the CLKDIV
reg [7:0] ser_dat;
always @(posedge CLKDIV)
ser_dat <= lfsr_dat;
// ============================================================================
// OSERDES
// OSERDES reset generator (required for it to work properly!)
reg [3:0] ser_rst_sr;
initial ser_rst_sr <= 4'hF;
always @(posedge CLKDIV or posedge RST)
if (RST) ser_rst_sr <= 4'hF;
else ser_rst_sr <= ser_rst_sr >> 1;
wire ser_rst = ser_rst_sr[0];
// OSERDES
wire ser_oq;
wire ser_tq;
OSERDESE2 #
(
.DATA_RATE_OQ (DATA_RATE),
.DATA_WIDTH (DATA_WIDTH),
.DATA_RATE_TQ ((DATA_RATE == "DDR" && DATA_WIDTH == 4) ? "DDR" : "SDR"),
.TRISTATE_WIDTH ((DATA_RATE == "DDR" && DATA_WIDTH == 4) ? 4 : 1)
)
oserdes
(
.CLK (CLKX),
.CLKDIV (CLKDIV),
.RST (ser_rst),
.OCE (1'b1),
.D1 (ser_dat[0]),
.D2 (ser_dat[1]),
.D3 (ser_dat[2]),
.D4 (ser_dat[3]),
.D5 (ser_dat[4]),
.D6 (ser_dat[5]),
.D7 (ser_dat[6]),
.D8 (ser_dat[7]),
.OQ (ser_oq),
.TCE (1'b1),
.T1 (1'b0), // All 0 to keep OBUFT always on.
.T2 (1'b0),
.T3 (1'b0),
.T4 (1'b0),
.TQ (ser_tq)
);
// ============================================================================
// IOB
wire iob_i;
OBUFT obuf
(
.I (ser_oq),
.T (ser_tq),
.O (IO_DAT)
);
IBUF ibuf
(
.I (IO_DAT),
.O (iob_i)
);
// ============================================================================
// Reference data serializer
reg [7:0] ref_sr;
wire ref_o;
always @(posedge CLK)
if (RST)
ref_sr <= 0;
else if (ce)
ref_sr <= lfsr_dat;
else
ref_sr <= ref_sr >> 1;
assign ref_o = ref_sr[0];
// ============================================================================
// Data comparator
comparator #
(
.ERROR_COUNT (16),
.ERROR_HOLD (ERROR_HOLD)
)
comparator
(
.CLK (CLK),
.RST (RST),
.I_DAT_REF (ref_o),
.I_DAT_IOB (iob_i),
.O_ERROR (O_ERROR)
);
endmodule