Attention

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

complex_mul_flat Source File

 1`timescale 1ns / 1ns
 2// TODO:
 3// Could potentially save a cycle in the flip-flop, by combining Add and Saturate into 1 cycle
 4module complex_mul_flat(
 5     input clk,  // Rising edge clock input; all logic is synchronous in this domain
 6     input gate_in,  // Flag marking input data valid
 7     input signed [17:0] x_I,  // Multiplicand 1, real
 8     input signed [17:0] x_Q,  // Multiplicand 1, imag
 9     input signed [17:0] y_I,  // Multiplicand 2, real
10     input signed [17:0] y_Q,  // Multiplicand 2, imag
11     output signed [17:0] z_I,  // Result, real
12     output signed [17:0] z_Q,  // Result, imag
13     output signed [35:0] z_I_all,  // Result, real, large
14     output signed [35:0] z_Q_all,  // Result, imag, large
15     output gate_out  // Delayed version of gate_in
16);
17
18// Flow-through vector multiplier
19// Assumes there is some guarantee that you will never multiply two
20// full-scale negative values together.
21// (A + j B) * (C + j D)
22reg signed [35:0] AC=0, BD=0, AD=0, BC=0, z_I_all_i=0, z_Q_all_i=0;
23reg signed [18:0] I_small=0, Q_small=0;
24
25`define SAT(x,old,new) ((~|x[old:new] | &x[old:new]) ? x[new:0] : {x[old],{new{~x[old]}}})
26
27// Keep one guard bit through the addition step.  That, and the
28// strange-looking "+1" below, reduces the average error offset
29// to -1/4 result bit.
30wire signed [19:0] z_I_sel=z_I_all_i[35:16], z_Q_sel=z_Q_all_i[35:16];
31
32always @(posedge clk) begin
33     AC <= x_I * y_I;
34     BD <= x_Q * y_Q;
35     AD <= x_I * y_Q;
36     BC <= x_Q * y_I;
37     // Fit 2 36bit signed number additions into a 35 bit number, as signed multiply
38     // produces a bogus bit
39     z_I_all_i <= AC - BD;
40     z_Q_all_i <= AD + BC + 1;
41     I_small <= `SAT(z_I_sel, 19, 18);
42     Q_small <= `SAT(z_Q_sel, 19, 18);
43end
44`undef SAT
45
46assign z_I_all = z_I_all_i;
47assign z_Q_all = z_Q_all_i;
48assign z_I = I_small[18:1];
49assign z_Q = Q_small[18:1];
50
51
52// This gate input isn't really used, but describes the length of this
53// pipeline to let users keep track of the data flow.
54
55reg [2:0] gate_sr=0;
56always @(posedge clk) gate_sr <= {gate_sr[1:0],gate_in};
57assign gate_out = gate_sr[2];
58
59endmodule