File: complex_multiply.sv

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (86 lines) | stat: -rw-r--r-- 2,903 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//
// Copyright 2025 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: complex_multiply
//
// Description:
//
//  This module performs a complex multiplication of two complex numbers. The
//  module has a fixed latency of 4 clock cycles in which the enable signal
//  needs to be asserted. The input widths are configurable but are limited by
//  the DSP48 block of the Xilinx FPGA, which is the target for synthesis. The
//  multiplication result is returned with full precision of WIDTH_A + WIDTH_B +
//  1 bits, which is the worst case for the output width.
//
// Parameters:
//
//   WIDTH_A : Width of the real and imaginary parts of the first complex
//             number. The maximum width is 25 bits.
//   WIDTH_B : Width of the real and imaginary parts of the second complex
//             number. The maximum width is 18 bits.
//

module complex_multiply #(
  int WIDTH_A = 25,
  int WIDTH_B = 18,
  localparam WIDTH_OUT = WIDTH_A + WIDTH_B + 1
)(
  input  logic clk,
  input  logic enable,

  input  logic signed [WIDTH_A-1 : 0] a_real,
  input  logic signed [WIDTH_A-1 : 0] a_imag,
  input  logic signed [WIDTH_B-1 : 0] b_real,
  input  logic signed [WIDTH_B-1 : 0] b_imag,

  output logic signed [WIDTH_OUT-1 : 0] out_real,
  output logic signed [WIDTH_OUT-1 : 0] out_imag
);

  // try to reuse the registers from DSP48 block of the Xilinx FPGA
  logic signed [WIDTH_A-1:0] a_real_reg, a_imag_reg, a2_imag_reg;
  logic signed [WIDTH_B-1:0] b_real_reg, b_imag_reg, b2_real_reg, b2_imag_reg;
  logic signed [WIDTH_OUT-1:0] mult_real_1, mult_real_2,
    mult_imag_1, mult_imag_2, mult_real_1_d, mult_imag_1_d;

  // check widths to comply with the Xilinx DSP48 block
  if (WIDTH_A > 25)
    $error("Input width A exceeds 25 bits, which is the maximum for DSP48.");
  if (WIDTH_B > 18)
    $error("Input width B exceeds 18 bits, which is the maximum for DSP48.");

  // calculate (a+bi) * (c+di) = (ac-bd) + (ad+bc)i
  always_ff @(posedge clk) begin
    if (enable) begin
      // cycle 1 - register the inputs
      a_real_reg <= a_real;
      a_imag_reg <= a_imag;
      b_real_reg <= b_real;
      b_imag_reg <= b_imag;

      // cycle 2 - calculate the first summands and delay inputs for the second
      // summands
      mult_real_1 <= a_real_reg * b_real_reg;
      mult_imag_1 <= a_real_reg * b_imag_reg;

      a2_imag_reg <= a_imag_reg;
      b2_real_reg <= b_real_reg;
      b2_imag_reg <= b_imag_reg;

      // cycle 3 - calculate the second multiplications and delay the existing
      // products
      mult_real_2 <= a2_imag_reg * b2_imag_reg;
      mult_imag_2 <= a2_imag_reg * b2_real_reg;

      mult_real_1_d <= mult_real_1;
      mult_imag_1_d <= mult_imag_1;

      // cycle 4 - sum the results
      out_real <= mult_real_1_d - mult_real_2;
      out_imag <= mult_imag_1_d + mult_imag_2;
    end
  end

endmodule