aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/io_cap_gen/cat_input_lvds.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/io_cap_gen/cat_input_lvds.v')
-rw-r--r--fpga/usrp3/lib/io_cap_gen/cat_input_lvds.v609
1 files changed, 609 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/io_cap_gen/cat_input_lvds.v b/fpga/usrp3/lib/io_cap_gen/cat_input_lvds.v
new file mode 100644
index 000000000..9b24ca6ca
--- /dev/null
+++ b/fpga/usrp3/lib/io_cap_gen/cat_input_lvds.v
@@ -0,0 +1,609 @@
+//
+// Copyright 2016 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: cat_input_lvds
+//
+// Description:
+//
+// Receive interface to AD9361 (Catalina) in LVDS mode.
+//
+// Use Xilinx SERDES to deserialize interleaved sample data off
+// half-word-width LVDS differential data bus from the Catalina.
+//
+// Use FRAME signal to initially synchronize to incoming data after reset
+// de-asserts.
+//
+// In all modes (SISO or MIMO) we output a clock of 1/4 the frequency
+// of the Catalina source-synchronous bus clock to be used as the radio_clk.
+//
+// In SISO mode, every cycle of the radio_clk supplies a new RX sample which
+// is routed to both radios, even if only one is actively receiving.
+//
+// In MIMO mode, every cycle of the radio clock supplies a pair of
+// time aligned MIMO samples which are routed to different radios.
+//
+// The frame_sample signal controls the expected frame signal timing. When
+// frame_sample is 0, the period of the ddr_frame signal is expected to equal
+// two samples (e.g., one from each channel). When frame_sample is 1, the frame
+// period is expected to equal the length of one sample. This allows the module
+// to be used for 2R2T (frame_sample = 1) or 1R1T mode (frame_sample = 0).
+//
+
+
+module cat_input_lvds #(
+ parameter INVERT_FRAME_RX = 0,
+ parameter INVERT_DATA_RX = 6'b00_0000,
+ parameter USE_CLOCK_DELAY = 1,
+ parameter USE_DATA_DELAY = 1,
+ parameter CLOCK_DELAY_MODE = "VAR_LOAD",
+ parameter DATA_DELAY_MODE = "VAR_LOAD",
+ parameter CLOCK_DELAY = 0,
+ parameter DATA_DELAY = 0,
+ parameter WIDTH = 6,
+ parameter GROUP = "DEFAULT",
+ parameter USE_BUFG = 1
+) (
+ input clk200,
+ input rst,
+
+ // Data and frame timing (synchronous to radio_clk)
+ input mimo, // Output one channel (MIMO=0) or two (MIMO=1)
+ input frame_sample, // Two samples per frame period (frame_sample=0) or one sample per frame (frame_sample=1)
+
+ // Region local Clocks for I/O cells.
+ output ddr_clk,
+ output sdr_clk,
+
+ // Source Synchronous external input clock
+ input ddr_clk_p,
+ input ddr_clk_n,
+
+ // Source Synchronous data lines
+ input [WIDTH-1:0] ddr_data_p,
+ input [WIDTH-1:0] ddr_data_n,
+ input ddr_frame_p,
+ input ddr_frame_n,
+
+ // Delay control interface
+ input ctrl_clk,
+ input [4:0] ctrl_data_delay,
+ input [4:0] ctrl_clk_delay,
+ input ctrl_ld_data_delay,
+ input ctrl_ld_clk_delay,
+
+ // Global output clocks, ddr_clk/4 & ddr_clk/2
+ output radio_clk,
+ output radio_clk_2x,
+
+ // SDR Data buses
+ output reg [(WIDTH*2)-1:0] i0,
+ output reg [(WIDTH*2)-1:0] q0,
+ output reg [(WIDTH*2)-1:0] i1,
+ output reg [(WIDTH*2)-1:0] q1,
+ output reg rx_aligned
+
+);
+
+ //------------------------------------------------------------------
+ // UG471 says take reset high asynchronously, and de-assert
+ // synchronized to CLKDIV (sdr_clk) for SERDES.
+ //------------------------------------------------------------------
+ (* ASYNC_REG = "TRUE" *) reg rst_sdr_sync, rst_sdr_sync_ms;
+
+ always @(posedge sdr_clk or posedge rst)
+ if (rst) begin
+ rst_sdr_sync_ms <= 1'b1;
+ rst_sdr_sync <= 1'b1;
+ end else begin
+ rst_sdr_sync_ms <= 1'b0;
+ rst_sdr_sync <= rst_sdr_sync_ms;
+ end
+
+
+ //------------------------------------------------------------------
+ // IDELAY is calibrated using (mandatory) IDELAYCTRL cell.
+ // Must be feed stable free running clock specified by: FIDELAYCTRL_REF.(200MHz)
+ // Mandatory async reset required, min pulse of: TIDELAYCTRL_RPW (~60nS)
+ //------------------------------------------------------------------
+ (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
+ IDELAYCTRL IDELAYCTRL_i0 (
+ .REFCLK (clk200),
+ .RST (rst_sdr_sync),
+ .RDY ()
+ );
+
+
+ //------------------------------------------------------------------
+ // Clock input
+ //------------------------------------------------------------------
+ wire ddr_clk_dly, ddr_clk_unbuf;
+
+ IBUFDS #(
+ .DIFF_TERM("TRUE")
+ ) clk_ibufds (
+ .O(ddr_clk_unbuf),
+ .I(ddr_clk_p),
+ .IB(ddr_clk_n)
+ );
+
+ generate
+ if (USE_CLOCK_DELAY) begin : gen_clock_delay
+ (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
+ IDELAYE2 #(
+ .CINVCTRL_SEL ("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
+ .DELAY_SRC ("IDATAIN"), // Delay input (IDATAIN, DATAIN)
+ .HIGH_PERFORMANCE_MODE ("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
+ .IDELAY_TYPE (CLOCK_DELAY_MODE),
+ .IDELAY_VALUE (CLOCK_DELAY),
+ .PIPE_SEL ("FALSE"),
+ .REFCLK_FREQUENCY (200.0),
+ .SIGNAL_PATTERN ("CLOCK")
+ ) ddr_clk_idelaye2 (
+ .CNTVALUEOUT (), // 5-bit output: Counter value output
+ .DATAOUT (ddr_clk_dly), // 1-bit output: Delayed data output
+ .C (ctrl_clk), // 1-bit input: Clock input
+ .CE (1'b0), // 1-bit input: Active high enable increment/decrement input
+ .CINVCTRL (1'b0), // 1-bit input: Dynamic clock inversion input
+ .CNTVALUEIN (ctrl_clk_delay), // 5-bit input: Counter value input
+ .DATAIN (1'b0), // 1-bit input: Internal delay data input
+ .IDATAIN (ddr_clk_unbuf), // 1-bit input: Data input from the I/O
+ .INC (1'b0), // 1-bit input: Increment / Decrement tap delay input
+ .LD (ctrl_ld_clk_delay), // 1-bit input: Load IDELAY_VALUE input
+ .LDPIPEEN (1'b0), // 1-bit input: Enable PIPELINE register to load data input
+ .REGRST (1'b0) // 1-bit input: Active-high reset tap-delay input
+ );
+ end
+ else begin
+ assign ddr_clk_dly = ddr_clk_unbuf;
+ end
+
+ endgenerate
+
+ // IO CLock is DDR freq. This drives SERDES and other I/O elements with minimal clock skew.
+ BUFIO ddr_clk_bufio (.O(ddr_clk),.I(ddr_clk_dly));
+
+ // SDR clock is one quarter DDR freq and local to regio using BUFR
+ // BUFR is a constraint of the SERDES since we need frequency agnostic clock division.
+ // UG471 states can use BUFIO and BUFR divided to directly drive a SERDES legally.
+ // (Other option is pair of BUFG's plus an MMCM - But MMCM has fixed frequency)
+ wire sdr_clk_2x;
+
+ BUFR #(
+ .BUFR_DIVIDE ("2"),
+ .SIM_DEVICE ("7SERIES")
+ ) sdr_clk_2x_bufr (
+ .O (sdr_clk_2x),
+ .CE (1'b1),
+ .CLR (1'b0),
+ .I (ddr_clk_dly)
+ );
+
+ BUFR #(
+ .BUFR_DIVIDE("4"),
+ .SIM_DEVICE("7SERIES")
+ ) sdr_clk_bufr (
+ .O(sdr_clk),
+ .CE(1'b1),
+ .CLR(1'b0),
+ .I(ddr_clk_dly)
+ );
+
+ generate
+ if (USE_BUFG) begin : gen_BUFG
+ // radio_clock is sdr_clk re-buffered with BUFG, and radio_clk_2x is
+ // sdr_clk_2x re-buffered, so both can be used globally. This introduces skew
+ // between sdr_clk -> radio_clock so we must hand data between them carefully
+ // even though they have a fixed phase relationship.
+ BUFG radio_clk_1x_bufg (.O(radio_clk), .I(sdr_clk));
+ BUFG radio_clk_2x_bufg (.O(radio_clk_2x), .I(sdr_clk_2x));
+ end else begin
+ assign radio_clk = sdr_clk;
+ assign radio_clk_2x = sdr_clk_2x;
+ end
+ endgenerate
+
+
+
+ //------------------------------------------------------------------
+ // Frame Signal
+ //------------------------------------------------------------------
+ wire ddr_frame, ddr_frame_dly;
+ wire [7:0] des_frame; // deserialized frame signal
+ reg bitslip;
+ reg aligned;
+
+
+ //
+ // Use FRAME signal to get bitstream word aligned.
+ //
+ // In MIMO mode, FRAME is asserted during the entirety of channel 0, and
+ // deasserts during the entirety of channel 1.
+ //
+ localparam IDLE = 0;
+ localparam SEARCH = 1;
+ localparam SLIP1 = 3;
+ localparam SLIP2 = 2;
+ localparam SLIP3 = 4;
+ localparam SLIP4 = 5;
+ localparam SYNC = 6;
+
+
+ reg [2:0] frame_state;
+
+ //
+ // Delay start of framesync operation for 64 clocks after reset de-asserts to
+ // SERDES to be sure they are in a steady state.
+ //
+ // Each time we assert bitslip we then have to wait 2 cycles before we can
+ // examine the results.
+ //
+ // Checking for 0xF0 and 0xCC allows us to support 1R1T and 2R2T timing,
+ // which have different frame periods.
+ wire frame_is_aligned =
+ (!frame_sample && (des_frame[7:0] == (INVERT_FRAME_RX ? 8'h0F : 8'hF0))) ||
+ ( frame_sample && (des_frame[7:0] == (INVERT_FRAME_RX ? 8'h33 : 8'hCC)));
+
+ reg [5:0] sync_delay;
+ reg run_sync;
+
+
+ always @(posedge sdr_clk)
+ if (rst_sdr_sync) begin
+ sync_delay <= 6'h0;
+ run_sync <= 1'b0;
+ end else if (sync_delay == 6'h3F)
+ run_sync <= 1'b1;
+ else
+ sync_delay <= sync_delay + 1'b1;
+
+ always @(posedge sdr_clk)
+ begin
+ if (!run_sync) begin
+ frame_state <= IDLE;
+ bitslip <= 1'b0;
+ aligned <= 1'b0;
+ end else begin
+ case (frame_state)
+ IDLE: begin
+ bitslip <= 1'b0;
+ aligned <= 1'b0;
+ frame_state <= SEARCH;
+ end
+
+ SEARCH: begin
+ if (frame_is_aligned) begin
+ frame_state <= SYNC;
+ bitslip <= 1'b0;
+ aligned <= 1'b1;
+ end else begin
+ // Bitslip until captured frame is aligned
+ bitslip <= 1'b1;
+ frame_state <= SLIP1;
+ aligned <= 1'b0;
+ end
+ end
+
+ SLIP1: begin
+ frame_state <= SLIP2;
+ bitslip <= 1'b0;
+ aligned <= 1'b0;
+ end
+
+ SLIP2: begin
+ frame_state <= SLIP3;
+ bitslip <= 1'b0;
+ aligned <= 1'b0;
+ end
+
+ SLIP3: begin
+ frame_state <= SLIP4;
+ bitslip <= 1'b0;
+ aligned <= 1'b0;
+ end
+
+ SLIP4: begin
+ frame_state <= SEARCH;
+ bitslip <= 1'b0;
+ aligned <= 1'b0;
+ end
+
+ SYNC: begin
+ if (frame_is_aligned) begin
+ frame_state <= SYNC;
+ aligned <= 1'b1;
+ end else begin
+ frame_state <= SEARCH;
+ aligned <= 1'b0;
+ end
+ end
+
+ endcase // case(frame_state)
+
+ end
+ end
+
+
+ IBUFDS #(
+ .DIFF_TERM ("TRUE")
+ ) ddr_frame_ibufds (
+ .O (ddr_frame),
+ .I (ddr_frame_p),
+ .IB (ddr_frame_n)
+ );
+
+ generate
+ if (USE_DATA_DELAY) begin : gen_frame_delay
+ (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
+ IDELAYE2 #(
+ .CINVCTRL_SEL ("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
+ .DELAY_SRC ("IDATAIN"), // Delay input (IDATAIN, DATAIN)
+ .HIGH_PERFORMANCE_MODE ("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
+ .IDELAY_TYPE (DATA_DELAY_MODE),
+ .IDELAY_VALUE (DATA_DELAY),
+ .PIPE_SEL ("FALSE"),
+ .REFCLK_FREQUENCY (200.0),
+ .SIGNAL_PATTERN ("DATA")
+ ) ddr_frame_idelaye2 (
+ .CNTVALUEOUT (), // 5-bit output: Counter value output
+ .DATAOUT (ddr_frame_dly), // 1-bit output: Delayed data output
+ .C (ctrl_clk), // 1-bit input: Clock input
+ .CE (1'b0), // 1-bit input: Active high enable increment/decrement input
+ .CINVCTRL (1'b0), // 1-bit input: Dynamic clock inversion input
+ .CNTVALUEIN (ctrl_data_delay), // 5-bit input: Counter value input
+ .DATAIN (1'b0), // 1-bit input: Internal delay data input
+ .IDATAIN (ddr_frame), // 1-bit input: Data input from the I/O
+ .INC (1'b0), // 1-bit input: Increment / Decrement tap delay input
+ .LD (ctrl_ld_data_delay), // 1-bit input: Load IDELAY_VALUE input
+ .LDPIPEEN (1'b0), // 1-bit input: Enable PIPELINE register to load data input
+ .REGRST (1'b0) // 1-bit input: Active-high reset tap-delay input
+ );
+ end
+ else begin
+ assign ddr_frame_dly = ddr_frame;
+ end
+ endgenerate
+
+ ISERDESE2 #(
+ .DATA_RATE ("DDR"), // DDR, SDR
+ .DATA_WIDTH (8), // Parallel data width (2-8,10,14)
+ .DYN_CLKDIV_INV_EN ("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
+ .DYN_CLK_INV_EN ("FALSE"), // Enable DYNCLKINVSEL inversion (FALSE, TRUE)
+ // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
+ .INIT_Q1 (1'b0),
+ .INIT_Q2 (1'b0),
+ .INIT_Q3 (1'b0),
+ .INIT_Q4 (1'b0),
+ .INTERFACE_TYPE ("NETWORKING"),
+ .IOBDELAY ("BOTH"),
+ .NUM_CE (1),
+ .OFB_USED ("FALSE"),
+ .SERDES_MODE ("MASTER"),
+ // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
+ .SRVAL_Q1 (1'b0),
+ .SRVAL_Q2 (1'b0),
+ .SRVAL_Q3 (1'b0),
+ .SRVAL_Q4 (1'b0)
+ ) ddr_frame_serdese2 (
+ .O (), // 1-bit output: Combinatorial output
+ // Q1 - Q8: 1-bit (each) output: Registered data outputs
+ .Q1 (des_frame[0]),
+ .Q2 (des_frame[1]),
+ .Q3 (des_frame[2]),
+ .Q4 (des_frame[3]),
+ .Q5 (des_frame[4]),
+ .Q6 (des_frame[5]),
+ .Q7 (des_frame[6]),
+ .Q8 (des_frame[7]),
+ // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
+ .SHIFTOUT1 (),
+ .SHIFTOUT2 (),
+ // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
+ // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
+ // to Q8 output ports will shift, as in a barrel-shifter operation, one
+ // position every time Bitslip is invoked (DDR operation is different from SDR)
+ .BITSLIP (bitslip),
+ // CE1, CE2: 1-bit (each) input: Data register clock enable inputs
+ .CE1 (1'b1),
+ .CE2 (1'b1),
+ .CLKDIVP (1'b0), // 1-bit input: TBD
+ // Clocks: 1-bit (each) input: ISERDESE2 clock input ports
+ .CLK (ddr_clk), // 1-bit input: High-speed clock
+ .CLKB (~ddr_clk), // 1-bit input: High-speed secondary clock
+ .CLKDIV (sdr_clk), // 1-bit input: Divided clock
+ .OCLK (1'b0), // 1-bit input: High-speed output clock used when INTERFACE_TYPE="MEMORY"
+ // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
+ .DYNCLKDIVSEL (1'b0), // 1-bit input: Dynamic CLKDIV inversion
+ .DYNCLKSEL (1'b0), // 1-bit input: Dynamic CLK/CLKB inversion
+ // Input Data: 1-bit (each) input: ISERDESE2 data input ports
+ .D (1'b0), // 1-bit input: Data input
+ .DDLY (ddr_frame_dly), // 1-bit input: Serial data from IDELAYE2
+ .OFB (1'b0), // 1-bit input: Data feedback from OSERDESE2
+ .OCLKB (1'b0), // 1-bit input: High-speed negative edge output clock
+ .RST (rst_sdr_sync), // 1-bit input: Active high asynchronous reset
+ // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
+ .SHIFTIN1 (1'b0),
+ .SHIFTIN2 (1'b0)
+ );
+
+
+ //------------------------------------------------------------------
+ // Data Bus
+ //------------------------------------------------------------------
+ wire [WIDTH-1:0] ddr_data;
+ wire [WIDTH-1:0] ddr_data_dly;
+ wire [(WIDTH*2)-1:0] data_i0, data_i1;
+ wire [(WIDTH*2)-1:0] data_q0, data_q1;
+
+
+ genvar i;
+ generate
+ for (i=0 ; i<WIDTH ; i=i+1) begin : generate_data_bus
+
+ IBUFDS #(
+ .DIFF_TERM ("TRUE")
+ ) ddr_data_ibufds (
+ .O (ddr_data[i]),
+ .I (ddr_data_p[i]),
+ .IB (ddr_data_n[i])
+ );
+
+ if (USE_DATA_DELAY) begin : gen_data_delay
+ (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
+ IDELAYE2 #(
+ .CINVCTRL_SEL ("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
+ .DELAY_SRC ("IDATAIN"), // Delay input (IDATAIN, DATAIN)
+ .HIGH_PERFORMANCE_MODE ("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
+ .IDELAY_TYPE (DATA_DELAY_MODE),
+ .IDELAY_VALUE (DATA_DELAY),
+ .PIPE_SEL ("FALSE"),
+ .REFCLK_FREQUENCY (200.0),
+ .SIGNAL_PATTERN ("DATA")
+ ) ddr_data_idelaye2 (
+ .CNTVALUEOUT (), // 5-bit output: Counter value output
+ .DATAOUT (ddr_data_dly[i]), // 1-bit output: Delayed data output
+ .C (ctrl_clk), // 1-bit input: Clock input
+ .CE (1'b0), // 1-bit input: Active high enable increment/decrement input
+ .CINVCTRL (1'b0), // 1-bit input: Dynamic clock inversion input
+ .CNTVALUEIN (ctrl_data_delay), // 5-bit input: Counter value input
+ .DATAIN (1'b0), // 1-bit input: Internal delay data input
+ .IDATAIN (ddr_data[i]), // 1-bit input: Data input from the I/O
+ .INC (1'b0), // 1-bit input: Increment / Decrement tap delay input
+ .LD (ctrl_ld_data_delay), // 1-bit input: Load IDELAY_VALUE input
+ .LDPIPEEN (1'b0), // 1-bit input: Enable PIPELINE register to load data input
+ .REGRST (1'b0) // 1-bit input: Active-high reset tap-delay input
+ );
+ end
+ else begin
+ assign ddr_data_dly[i] = ddr_data[i];
+ end
+
+ ISERDESE2 #(
+ .DATA_RATE ("DDR"), // DDR, SDR
+ .DATA_WIDTH (8), // Parallel data width (2-8,10,14)
+ .DYN_CLKDIV_INV_EN ("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
+ .DYN_CLK_INV_EN ("FALSE"), // Enable DYNCLKINVSEL inversion (FALSE, TRUE)
+ // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
+ .INIT_Q1 (1'b0),
+ .INIT_Q2 (1'b0),
+ .INIT_Q3 (1'b0),
+ .INIT_Q4 (1'b0),
+ .INTERFACE_TYPE ("NETWORKING"),
+ .IOBDELAY ("BOTH"),
+ .NUM_CE (1),
+ .OFB_USED ("FALSE"),
+ .SERDES_MODE ("MASTER"),
+ // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
+ .SRVAL_Q1 (1'b0),
+ .SRVAL_Q2 (1'b0),
+ .SRVAL_Q3 (1'b0),
+ .SRVAL_Q4 (1'b0)
+ ) ddr_data_serdese2 (
+ .O (), // 1-bit output: Combinatorial output
+ // Q1 - Q8: 1-bit (each) output: Registered data outputs
+ .Q1 (data_q1[i]),
+ .Q2 (data_i1[i]),
+ .Q3 (data_q1[WIDTH+i]),
+ .Q4 (data_i1[WIDTH+i]),
+ .Q5 (data_q0[i]),
+ .Q6 (data_i0[i]),
+ .Q7 (data_q0[WIDTH+i]),
+ .Q8 (data_i0[WIDTH+i]),
+ // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
+ .SHIFTOUT1 (),
+ .SHIFTOUT2 (),
+ // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
+ // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
+ // to Q8 output ports will shift, as in a barrel-shifter operation, one
+ // position every time Bitslip is invoked (DDR operation is different from SDR)
+ .BITSLIP (bitslip),
+ // CE1, CE2: 1-bit (each) input: Data register clock enable inputs
+ .CE1 (1'b1),
+ .CE2 (1'b1),
+ .CLKDIVP (1'b0), // 1-bit input: TBD
+ // Clocks: 1-bit (each) input: ISERDESE2 clock input ports
+ .CLK (ddr_clk), // 1-bit input: High-speed clock
+ .CLKB (~ddr_clk), // 1-bit input: High-speed secondary clock
+ .CLKDIV (sdr_clk), // 1-bit input: Divided clock
+ .OCLK (1'b0), // 1-bit input: High-speed output clock used when INTERFACE_TYPE="MEMORY"
+ // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
+ .DYNCLKDIVSEL (1'b0), // 1-bit input: Dynamic CLKDIV inversion
+ .DYNCLKSEL (1'b0), // 1-bit input: Dynamic CLK/CLKB inversion
+ // Input Data: 1-bit (each) input: ISERDESE2 data input ports
+ .D (1'b0), // 1-bit input: Data input
+ .DDLY (ddr_data_dly[i]), // 1-bit input: Serial data from IDELAYE2
+ .OFB (1'b0), // 1-bit input: Data feedback from OSERDESE2
+ .OCLKB (1'b0), // 1-bit input: High-speed negative edge output clock
+ .RST (rst_sdr_sync), // 1-bit input: Active high asynchronous reset
+ // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
+ .SHIFTIN1 (1'b0),
+ .SHIFTIN2 (1'b0)
+ );
+
+ end // block: generate_data_bus
+ endgenerate
+
+ //
+ // Cross these cycles to radio_clk using negative edge. This give 1/2 a radio
+ // clock period + BUFG insertion delay for signals to propagate. Thats > 6nS.
+ //
+ reg [(WIDTH*2)-1:0] radio_data_i0, radio_data_i1, radio_data_q0, radio_data_q1;
+ reg radio_aligned;
+
+ always @(negedge radio_clk)
+ begin
+ radio_data_i0[(WIDTH*2)-1:0] <= data_i0[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
+ radio_data_q0[(WIDTH*2)-1:0] <= data_q0[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
+ radio_data_i1[(WIDTH*2)-1:0] <= data_i1[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
+ radio_data_q1[(WIDTH*2)-1:0] <= data_q1[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
+ radio_aligned <= aligned;
+ end
+
+ always @(posedge radio_clk)
+ begin
+ i0 <= radio_data_i0;
+ q0 <= radio_data_q0;
+ if (mimo) { i1, q1 } <= { radio_data_i1, radio_data_q1 };
+ else { i1, q1 } <= { radio_data_i0, radio_data_q0 }; // dup single valid channel to both radios
+ rx_aligned <= radio_aligned;
+ end
+
+ /*******************************************************************
+ * Debug only logic below here.
+ ******************************************************************/
+/*-----\/----- EXCLUDED -----\/-----
+ (* keep = "true", max_fanout = 10 *) reg [7:0] des_frame_reg;
+ (* keep = "true", max_fanout = 10 *) reg rst_sdr_sync_reg;
+ (* keep = "true", max_fanout = 10 *) reg run_sync_reg;
+ (* keep = "true", max_fanout = 10 *) reg bitslip_reg;
+ (* keep = "true", max_fanout = 10 *) reg aligned_reg;
+ (* keep = "true", max_fanout = 10 *) reg [2:0] frame_state_reg;
+
+ always @(posedge sdr_clk)
+ begin
+ des_frame_reg <= des_frame;
+ rst_sdr_sync_reg <= rst_sdr_sync;
+ run_sync_reg <= run_sync;
+ bitslip_reg <= bitslip;
+ aligned_reg <= aligned;
+ frame_state_reg <= frame_state;
+ end
+
+ ila64 ila64_i (
+ .clk(sdr_clk), // input clk
+ .probe0(
+ {
+ des_frame_reg,
+ rst_sdr_sync_reg,
+ run_sync_reg,
+ bitslip_reg,
+ aligned_reg,
+ frame_state_reg
+ }
+ )
+ );
+ -----/\----- EXCLUDED -----/\----- */
+
+endmodule
+