Attention

This documentation is a work in progress. Expect to see errors and unfinished things.

iq_deinterleaver Source File

 1`timescale 1ns / 1ns
 2
 3/** IQ_DEINTERLEAVER **
 4     Deinterleave an IQ stream into separate I and Q components.
 5     scale input allows IQ data to be scaled down by a non-binary factor, which
 6     can be used to match the scaling of downconverted channels
 7
 8     I_OUT = (I_IN*scale) >> (scale_wi-davr-1)
 9*/
10
11module iq_deinterleaver #(
12   parameter scale_wi  = 18, // Width of scale input and downscale factor
13   parameter dwi       = 16, // Width of iq stream
14   parameter davr      = 4   // Guard bits to keep at output of scale multiplication
15) (
16   input                        clk,
17   input  signed [scale_wi-1:0] scale_in,   // Scaling factor; scale is typically positive;
18                                            // full-scale negative is not allowed
19   input  signed [dwi-1:0]      iq_data_in, // IQ interleaved data
20   input                        iq_sel,     // 1 (I), 0 (Q)
21   output                       valid_out,
22   output        [dwi+davr-1:0] i_data_out,
23   output        [dwi+davr-1:0] q_data_out
24);
25   localparam SEL_I = 1, SEL_Q = 0;
26
27   reg signed  [scale_wi+dwi-1:0] scaled_iq = 0, scaled_iq_r = 0;
28   wire signed [dwi+davr-1:0]     scaled_iq_out;
29   reg         [dwi+davr-1:0]     i_data_l = 0, i_data = 0, q_data = 0;
30   reg                            iq_sel_r = 0, iq_sel_r2 = 0;
31   reg                            valid_r = 0, valid_r2 = 0;
32
33   // Use a multiplier so we can get full-scale to match between
34   // input and output when using a non-binary CIC interval
35   always @(posedge clk) begin
36      scaled_iq   <= iq_data_in * scale_in;
37      iq_sel_r    <= iq_sel;
38      scaled_iq_r <= scaled_iq;
39      iq_sel_r2   <= iq_sel_r;
40   end
41
42   // Drop sign bit and shift down TODO: Explain this operation, especially -1
43   assign scaled_iq_out = scaled_iq_r[scale_wi+dwi-2:scale_wi-davr-1];
44
45   always @(posedge clk) begin
46      case (iq_sel_r2)
47         SEL_I : i_data_l <= scaled_iq_out;
48         SEL_Q : q_data   <= scaled_iq_out;
49      endcase
50
51      valid_r <= iq_sel_r2==SEL_I ? 1'b1 : 1'b0;
52
53      i_data   <= i_data_l; // Time-align the common case where I and Q are paired
54      valid_r2 <= valid_r;
55   end
56
57   assign valid_out  = valid_r2;
58   assign i_data_out = i_data;
59   assign q_data_out = q_data;
60
61endmodule