Source

License

Index

Sensor Data Receive Channel

Instantiates the LVDS ISERDES interfaces for one image sensor channel, along with its bit, word, and channel alignment training hardware.

The training of all channels will be coordinated one level up.

`default_nettype none

module sensor_data_rx_channel
#(
    // IDELAYCTRL and IDELAY
    parameter                   IODELAY_GROUP                   = "IMAGE_RX",
    parameter                   IODELAY_HIGH_PERFORMANCE_MODE   = "FALSE",      // Should match that of the clock in clocking.v

    // Input Buffers
    parameter                   IBUF_DIFF_TERM                  = "FALSE",      // Since Bank 14 has Vcco of 3V3, this must be off (see UG471, LVDS_25 I/O Standard)
    parameter                   IBUF_LOW_PWR                    = "TRUE",
    parameter                   IBUF_IOSTANDARD                 = "LVDS_25",

    // SERDES
    parameter                   WORD_WIDTH                      = 12,           // CONSTANT, DO NOT CHANGE.
 
    // For bit alignment
    parameter                   TAP_OFFSET                      = 2,            // 2 or greater. How much the initial N IDELAY lags the P IDELAY, for bit alignment.
    // For word alignment
    parameter [WORD_WIDTH-1:0]  TRAINING_WORD                   = 'b011110001101,
    parameter                   BITSLIP_INTERVAL                = 3,            // 3 or greater
    // For channel alignment
    parameter                   CHANNEL_PIPELINE_DEPTH          = 16,           // only 16 or 32 is allowed

    // For CDC FIFO of data into main clock domain
    parameter                   FIFO_DEPTH                      = 16,
    parameter                   FIFO_RAMSTYLE                   = "distributed"
)
(
    // clk_rxio domain (data and training)

    input   wire                            clk_rxio_io,
    input   wire                            clk_rxio_frame,
    input   wire                            rst_rxio_frame_n,

    input   wire                            datain_n,                       // High-speed serial I/O data in
    input   wire                            datain_p,

    // clk_main domain (control)

    input   wire                            clk_main,
    input   wire                            rst_main_n,

    input   wire                            datain_parallel_enable,         // While low, sink the data output (datain_parallel_valid stays low, data is discarded)
    output  wire                            datain_parallel_valid,          // There is a handshake, but only some FIFO slack for stalling!
    input   wire                            datain_parallel_ready,          // Do not let FIFO fill, else data is lost.
    output  wire    [WORD_WIDTH-1:0]        datain_parallel,                // Deserialized positive data, framed by datain_parallel_valid

    output  wire                            sync_train,                     // Signal sensor to output training word

    input   wire                            start_bit_word_alignment,       // Preferably a one-cycle pulse
    output  wire                            done_bit_word_alignment,        // Pulsed high means serdes data is bit and word-aligned

    input   wire                            start_channel_alignment,        // Preferably a one-cycle pulse
    output  wire                            done_channel_alignment          // Pulsed high means serdes data is channel-aligned

);

    `include "clog2_function.vh"

    localparam CHANNEL_DELAY_WIDTH = clog2(CHANNEL_PIPELINE_DEPTH);
    // Hardcoded in lower modules. Do not change.
    localparam TAP_COUNTER_WIDTH = 5;

Input SERDES.

    wire [TAP_COUNTER_WIDTH-1:0]     tap_p_current;
    wire [TAP_COUNTER_WIDTH-1:0]     tap_p_load_value;
    wire                             tap_p_load;
    wire                             datain_p_bitslip;
    wire                             datain_p_wordflip;

    wire [TAP_COUNTER_WIDTH-1:0]     tap_n_current;
    wire [TAP_COUNTER_WIDTH-1:0]     tap_n_load_value;
    wire                             tap_n_load;
    wire                             datain_n_bitslip;
    wire                             datain_n_wordflip;

    wire                             channel_delay_valid; // Load a new channel alignment tap delay
    wire                             channel_delay_ready;
    wire [CHANNEL_DELAY_WIDTH-1:0]   channel_delay;

    wire                             datain_parallel_valid_internal;
    wire                             datain_parallel_ready_internal;
    wire [WORD_WIDTH-1:0]            datain_p_parallel_internal;
    wire [WORD_WIDTH-1:0]            datain_n_parallel_internal;

    iserdes_1_to_12_data_diff
    #(
        // For the input buffer of each data line
        .IBUF_DIFF_TERM                 (IBUF_DIFF_TERM),
        .IBUF_LOW_PWR                   (IBUF_LOW_PWR),
        .IBUF_IOSTANDARD                (IBUF_IOSTANDARD),
        .IODELAY_GROUP                  (IODELAY_GROUP),                 // Must match IODELAY_GROUP applied to IDELAYCTRL module in same I/O Bank.
        .IODELAY_HIGH_PERFORMANCE_MODE  (IODELAY_HIGH_PERFORMANCE_MODE), // Should match that of the clock in clocking.v
        .CHANNEL_PIPELINE_DEPTH         (CHANNEL_PIPELINE_DEPTH)
    )
    input_data_serdes
    (
        .clk_rxio_io            (clk_rxio_io),          // High-speed I/O clock for incoming serial data (pins and SERDES)
        .clk_rxio_frame         (clk_rxio_frame),       // Framing pulse for serial-parallel conversion (SERDES)
        .rst_rxio_frame_n       (rst_rxio_frame_n),

        .datain_n               (datain_n),             // High-speed serial I/O data in
        .datain_p               (datain_p),


        .incdec_p_enable        (1'b0),                 // Enable increment/decrement of delay tap
        .incdec_p               (1'b0),                 // Increment (1) or decrement (0) delay tap
        .tap_p_current          (tap_p_current),        // Current value of delay tap
        .tap_p_load_value       (tap_p_load_value),     // New value of delay tap
        .tap_p_load             (tap_p_load),           // Load new delay tap value
        .datain_p_bitslip       (datain_p_bitslip),     // Pulse to shift output word
        .datain_p_wordflip      (datain_p_wordflip),    // Pulse to swap halfwords of the output word

        .incdec_n_enable        (1'b0),                 // Enable increment/decrement of delay tap
        .incdec_n               (1'b0),                 // Increment (1) or decrement (0) delay tap
        .tap_n_current          (tap_n_current),        // Current value of delay tap
        .tap_n_load_value       (tap_n_load_value),     // New value of delay tap
        .tap_n_load             (tap_n_load),           // Load new delay tap value
        .datain_n_bitslip       (datain_n_bitslip),     // Pulse to shift output word
        .datain_n_wordflip      (datain_n_wordflip),    // Pulse to swap halfwords of the output word

        .channel_delay_valid    (channel_delay_valid),
        .channel_delay_ready    (channel_delay_ready),
        .channel_delay          (channel_delay),

        .datain_parallel_valid  (datain_parallel_valid_internal), // There is a handshake, but no slack for stalling!
        .datain_parallel_ready  (datain_parallel_ready_internal), // Must always be ready before valid!
        .datain_p_parallel      (datain_p_parallel_internal),     // Deserialized data, framed by clk_rxio_frame
        .datain_n_parallel      (datain_n_parallel_internal)      // Deserialized data, framed by clk_rxio_frame
    );

Deserialized data fork

Feed training module and output FIFO the same deserialized serdes data. Since there is no backpressure possible, this should mostly optimize away.

    wire                            datain_parallel_valid_training;
    wire                            datain_parallel_ready_training;
    wire    [WORD_WIDTH-1:0]        datain_p_parallel_training;
    wire    [WORD_WIDTH-1:0]        datain_n_parallel_training;

    wire                            datain_parallel_valid_fifo;
    wire                            datain_parallel_ready_fifo;
    wire    [WORD_WIDTH-1:0]        datain_p_parallel_fifo;
    // verilator lint_off UNUSED
    wire    [WORD_WIDTH-1:0]        datain_n_parallel_fifo;
    // verilator lint_on  UNUSED

    Pipeline_Fork_Lazy
    #(
        .WORD_WIDTH     (WORD_WIDTH + WORD_WIDTH),
        .OUTPUT_COUNT   (2)
    )
    training_data_fork
    (
        .input_valid    (datain_parallel_valid_internal),
        .input_ready    (datain_parallel_ready_internal),
        .input_data     ({datain_n_parallel_internal, datain_p_parallel_internal}),

        .output_valid   ({datain_parallel_valid_training,                           datain_parallel_valid_fifo}),
        .output_ready   ({datain_parallel_ready_training,                           datain_parallel_ready_fifo}),
        .output_data    ({{datain_n_parallel_training, datain_p_parallel_training}, {datain_n_parallel_fifo, datain_p_parallel_fifo}})
    );

CDC transfer from I/O clock domain to main clock domain

NOTE: sink this output until the data is correct (after training) and has somewhere to go (after memory calibration is complete, or other logic is ready to receive).

    wire                            datain_parallel_valid_main;
    wire                            datain_parallel_ready_main;
    wire    [WORD_WIDTH-1:0]        datain_parallel_main;

    CDC_FIFO_Buffer
    #(
        .WORD_WIDTH         (WORD_WIDTH),
        .DEPTH              (FIFO_DEPTH),
        .RAMSTYLE           (FIFO_RAMSTYLE),
        .CIRCULAR_BUFFER    (0), // non-zero to enable
        .CDC_EXTRA_STAGES   (0)
    )
    input_data_fifo
    (
        .input_clock        (clk_rxio_frame),
        .input_clear        (~rst_rxio_frame_n),
        .input_valid        (datain_parallel_valid_fifo),
        .input_ready        (datain_parallel_ready_fifo),
        .input_data         (datain_p_parallel_fifo),

        .output_clock       (clk_main),
        .output_clear       (~rst_main_n),
        .output_valid       (datain_parallel_valid_main),
        .output_ready       (datain_parallel_ready_main),
        .output_data        (datain_parallel_main)
    );

    Pipeline_Sink
    #(
        .WORD_WIDTH     (WORD_WIDTH),
        .IMPLEMENTATION ("AND")
    )
    input_data_fifo_sink
    (
        .sink           (datain_parallel_enable == 1'b0),

        .input_valid    (datain_parallel_valid_main),
        .input_ready    (datain_parallel_ready_main),
        .input_data     (datain_parallel_main),

        .output_valid   (datain_parallel_valid),
        .output_ready   (datain_parallel_ready),
        .output_data    (datain_parallel)
    );

SERDES bit and word-alignment training module

    wire                            datain_parallel_valid_training_pipelined;
    wire                            datain_parallel_ready_training_pipelined;
    wire    [WORD_WIDTH-1:0]        datain_p_parallel_training_pipelined;
    wire    [WORD_WIDTH-1:0]        datain_n_parallel_training_pipelined;

We need a bit of pipelining to break a critical path here between the iserdes data and the training modules using the data. FIXME: this may not be needed after the move to the framing clock

    Skid_Buffer_Pipeline
    #(
        .WORD_WIDTH (WORD_WIDTH + WORD_WIDTH),
        .PIPE_DEPTH (1)
    )
    training_data_pipeline
    (
        // If PIPE_DEPTH is zero, these are unused
        // verilator lint_off UNUSED
        .clock          (clk_rxio_frame),
        .clear          (~rst_rxio_frame_n),
        // verilator lint_on  UNUSED
        .input_valid    (datain_parallel_valid_training),
        .input_ready    (datain_parallel_ready_training),
        .input_data     ({datain_n_parallel_training, datain_p_parallel_training}),

        .output_valid   (datain_parallel_valid_training_pipelined),
        .output_ready   (datain_parallel_ready_training_pipelined),
        .output_data    ({datain_n_parallel_training_pipelined, datain_p_parallel_training_pipelined})
    );

    iserdes_training
    #(
        // Bit alignment parameters
        .TAP_OFFSET             (TAP_OFFSET), // How much the initial N IDELAY lags the P IDELAY, for bit alignment.
        .WORD_WIDTH             (WORD_WIDTH),
        .TRAINING_WORD          (TRAINING_WORD),
        .BITSLIP_INTERVAL       (BITSLIP_INTERVAL),
        .CHANNEL_PIPELINE_DEPTH (CHANNEL_PIPELINE_DEPTH)
    )
    input_serdes_training
    (
        // clk_rxio_frame domain, for SERDES data and control

        .clk_rxio_frame         (clk_rxio_frame),
        .rst_rxio_frame_n       (rst_rxio_frame_n),

        .datain_parallel_valid  (datain_parallel_valid_training_pipelined),   // There is a handshake, but no slack for stalling!
        .datain_parallel_ready  (datain_parallel_ready_training_pipelined),   // Must always be ready before valid!
        .datain_p_parallel      (datain_p_parallel_training_pipelined),       // Deserialized positive data, framed by datain_parallel_valid
        .datain_n_parallel      (datain_n_parallel_training_pipelined),       // Deserialized negative data, framed by datain_parallel_valid

        .tap_p_current          (tap_p_current),                    // Current value of delay tap
        .tap_p_load_value       (tap_p_load_value),                 // New value of delay tap
        .tap_p_load             (tap_p_load),                       // Load new delay tap value
        .datain_p_bitslip       (datain_p_bitslip),                 // Pulse to shift output word
        .datain_p_wordflip      (datain_p_wordflip),                // Pulse to swap halfwords of the output word

        .tap_n_current          (tap_n_current),                    // Current value of delay tap
        .tap_n_load_value       (tap_n_load_value),                 // New value of delay tap
        .tap_n_load             (tap_n_load),                       // Load new delay tap value
        .datain_n_bitslip       (datain_n_bitslip),                 // Pulse to shift output word
        .datain_n_wordflip      (datain_n_wordflip),                // Pulse to swap halfwords of the output word

        .channel_delay_valid    (channel_delay_valid),              // Load a new channel alignment tap delay
        .channel_delay_ready    (channel_delay_ready),
        .channel_delay          (channel_delay),

        // System control signals in clk_main domain

        .clk_main               (clk_main),                         // General logic clock
        .rst_main_n             (rst_main_n),

        .sync_train             (sync_train),                       // Signal sensor to output training word

        .start_bit_word_alignment   (start_bit_word_alignment),     // Preferably a one-cycle pulse
        .done_bit_word_alignment    (done_bit_word_alignment),      // Pulsed high means serdes data is bit and word-aligned
 
        .start_channel_alignment    (start_channel_alignment),      // Preferably a one-cycle pulse
        .done_channel_alignment     (done_channel_alignment)        // Pulsed high means serdes data is channel-aligned
    );

endmodule

Back to FPGA Design Elements

fpgacpu.ca