Attention

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

complex_mul Source File

 1`timescale 1ns / 1ns
 2
 3// Complex number multiplication, as in
 4//   (a+ib)*(c+id) = (a*c-b*d)+i(a*d+b*c).
 5// All the complex numbers are IQ-serialized, such that port x
 6// carries a+ib, port y carries c+id, and port z carries the result.
 7
 8// It produces up to one answer every two clock cycles.
 9// The 18-bit inputs and output are assumed scaled to [-1,1).
10
11// This module uses two 18-bit signed hardware multipliers,
12// and can clock at over 100 MHz in Spartan-6.
13
14// It's pretty easy to ask for results that would overflow the representable
15// numbers; an extreme case is (1+i)*(1-i) = 2.  All such results get
16// saturated to the maximum representable positive or negative number.
17
18// A second copy of the result with no rounding error is also provided
19// in z_all.  Using both outputs will consume more FPGA resources than
20// using either one alone.
21
22// Output results are delayed four cycles from the input.
23// The gate_out port is nothing more or less than the gate_in
24// port, delayed four cycles.  Only the iq control is used to control
25// the data paths inside this module.
26
27module complex_mul #(
28     parameter dw = 18
29) (
30     input clk,  // Rising edge clock input; all logic is synchronous in this domain
31     input gate_in,  // Flag marking input data valid
32     input signed [dw-1:0] x,  // Multiplicand, signed, time-interleaved real and imaginary
33     input signed [dw-1:0] y,  // Multiplicand, signed, time-interleaved real and imaginary
34     input iq,  // Flag marking the real (I) part of the complex pair
35     output signed [dw-1:0] z,  // Result
36     output signed [(2*dw)-1:0] z_all,  // Result
37     output gate_out  // Delayed version of gate_in
38);
39
40// Flow-through vector multiplier
41// x, y, and z are interleaved I-Q complex numbers
42// iq set high for I, low for Q at input, a pair is I followed by Q.
43// Assumes there is some guarantee that you will never multiply two
44// full-scale negative values together.
45
46reg [3:0] iq_sr=0;
47always @(posedge clk) iq_sr <= {iq_sr[3:0],iq};
48
49// Keep one guard bit through the addition step.  That, and the
50// strange-looking "+1" below, reduces the average error offset
51// to -1/4 result bit.
52
53reg signed [dw-1:0] x1=0, x2=0, y1=0;
54reg signed [(2*dw)-1:0] prod1=0, prod2=0;
55reg signed [(2*dw)-1:0] prod1_d=0, prod2_d=0;
56reg signed [(2*dw)-1:0] sumi=0, sumq=0;
57wire signed [dw-1:0] m2mux = iq_sr[1] ? x2 : x;
58always @(posedge clk) begin
59     x1 <= x;
60     x2 <= x1;
61     y1 <= y;
62     prod1 <= x*y;
63     prod2 <= m2mux * y1;
64     prod1_d <= prod1;
65     prod2_d <= prod2;
66     sumi <= prod1_d - prod1;
67     sumq <= prod2_d + prod2 + 1;
68end
69
70`define SAT(x,old,new) ((~|x[old:new] | &x[old:new]) ? x[new:0] : {x[old],{new{~x[old]}}})
71wire iqx = iq_sr[3];
72wire signed [(2*dw)-1:0] mux = iqx ? sumq : sumi;
73reg signed [dw:0] zr=0;
74reg signed [(2*dw)-1:0] mux_r=0;
75wire signed [(dw+1):0] zsel=mux[(2*dw)-1:(dw-2)];
76always @(posedge clk) begin
77     zr <= `SAT(zsel, dw+1, dw);
78     mux_r <= mux;
79end
80assign z = zr[dw:1];
81assign z_all = mux_r;
82`undef SAT
83
84// This gate input isn't really used, but describes the length of this
85// pipeline to let users keep track of the data flow.
86
87reg [3:0] gate_sr=0;
88always @(posedge clk) gate_sr <= {gate_sr[2:0],gate_in};
89assign gate_out = gate_sr[3];
90
91endmodule