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