Attention

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

fdownconvert Source File

 1`timescale 1ns / 1ns
 2// Synthesizes to 80 4-LUTs and 2 MULT18X18s at 150 MHz in XC3Sxxx-4 using XST-10.1i
 3
 4// Name: Near-IQ Downconverter
 5//% Provide LO at cosd and sind ports
 6//% Output is stream of IQ samples
 7// Input cosd and sind are ordinary LO signals, and this module reorders them.
 8// N.B.: full-scale negative is an invalid LO value.
 9//
10// Compute IQ by performing the matrix multiplication described in the paper below
11// http://recycle.lbl.gov/~ldoolitt/llrf/down/reconstruct.pdf
12// Where n and n+1 are consecutive samples in time
13// | I | =  |  sin[n + 1]\theta   -sin n\theta |  X  | a_data[n]   |
14// | Q |    | -cos[n + 1]\theta    cos n\theta |     | a_data[n+1] |
15// Larry Doolittle, LBNL, 2014
16module fdownconvert #(
17     parameter a_dw=16,  // XXX don't change this
18     parameter o_dw=16   // XXX don't change this
19) (
20     input clk,  // timespec 6.66 ns
21     input mod2,
22     input signed [17:0] cosd,  // LO input
23     input signed [17:0] sind,  // LO input
24
25     input signed [a_dw-1:0] a_data,   // ADC readings
26     input a_gate,
27     input a_trig,
28
29     output signed [o_dw-1:0] o_data,  // Interleaved I&Q
30     output o_gate,
31     output o_trig,
32     output time_err   // TODO: Explain this
33);
34
35// reordering logic, generate the delayed signals for the above matrix multiplication
36reg signed [17:0] cosd_d1=0, cosd_d2=0, cosd_r=0;
37reg signed [17:0] sind_d1=0, sind_d2=0, sind_r=0;
38always @(posedge clk) begin
39     cosd_d1 <= cosd;
40     cosd_d2 <= cosd_d1;
41     cosd_r <= ~mod2 ? cosd_d2 : cosd;
42     sind_d1 <= sind;
43     sind_d2 <= sind_d1;
44     sind_r <= ~mod2 ? sind_d2 : sind;
45end
46
47// downconvert input signal to I and Q
48// an extra pipeline stage has been added to help routing near multiplier
49reg signed [32:0] mul_i=0, mul_q=0, mul_i1=0, mul_q1=0, mul_i2=0, mul_q2=0;
50always @(posedge clk) begin
51     mul_i  <= a_data * cosd_r;
52     mul_i1 <= mul_i;
53     mul_i2 <= mul_i1;
54     mul_q  <= a_data * sind_r;
55     mul_q1 <= mul_q;
56     mul_q2 <= mul_q1;
57end
58
59`define SAT(x,old,new) ((~|x[old:new] | &x[old:new]) ? x[new:0] : {x[old],{new{~x[old]}}})
60reg signed [15:0] iq_out0=0;
61reg signed [16:0] sum_i1x=0, sum_q1x=0, sum_q2x=0;
62always @(posedge clk) begin
63     sum_i1x <= $signed(mul_i1[32:17]) - $signed(mul_i2[32:17]);
64     sum_q1x <= $signed(mul_q2[32:17]) - $signed(mul_q1[32:17]);
65     sum_q2x <= sum_q1x;
66end
67wire signed [16:0] iq_mux = mod2 ? sum_q2x : sum_i1x;
68always @(posedge clk) iq_out0 <= `SAT(iq_mux,16,15);
69
70reg last_mod2=0, time_err_r=0;
71always @(posedge clk) begin
72     last_mod2 <= mod2;
73     time_err_r <= (mod2 ^ ~last_mod2) | ~a_gate;
74end
75
76`undef SAT
77
78assign o_data = iq_out0;
79assign o_gate = 1'b1;
80assign o_trig = mod2;
81assign time_err = time_err_r;
82
83endmodule