cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
phytebunk
Observer
Observer
332 Views
Registered: ‎03-26-2019

Verilog: How to implement a pipeline multiplier?

Hey,

I'd like to implement a 31 * 32-bit signed multiplier using Verilog. My platform is a Zynq 7010-based Red Pitaya. The multiplier should run at 125 MHz while samples that need to be multiplied arrive at 1 MHz. So there is a valid signal based detection to figure out when the next multiplication should start. Currently there are timing issues with the multiplication although I reduced the clock frequency to 100 MHz. (Worst path has 2.2 ns slack) The delay results mostly from the logic (>70%) where 4 ns are related to the DSP48E. There are three DSP48E in series within this path.

To solve this timing issue I want Vivado to use a pipelined multiplication. But it seems like Vivado doesn't understand the option of pipelining. AR#8657.html  explains how to implement a pipelined multiplier in Verilog. Unfortunately my try to use this technique didn't lead to pipelining. (Made the timing even worse.)

I would be really glad about a hint how to get my pipelining work.

Thanks!

module phase_controller(
    input i_clk,
    input i_reset,
    input i_enable,
    input signed[64-1:0] i_phase,
    input i_phase_valid,
    input signed[32-1:0] i_gain_i,
    output reg o_is_armed,
    output [32-1:0] o_frequency,
    output reg o_frequency_valid
    );
    
    reg signed[32-1:0] gain_i_buffer;
    reg signed [63-1:0] error_gain_product[16];
    reg signed [33-1:0] frequency_sign_extended;
    //parameter signed [64-1:0] UPPER_PHASE_SATURATION = 64'sd1073741823;
    parameter signed [31-1:0] UPPER_PHASE_SATURATION = 31'sd1073741823;
    reg signed [33-1:0] freq_offset = 33'sd42949673;
    reg [3:0] prog_cntr;
    integer i;
    reg [4-1:0] counter = 4'd1;
    always @(posedge i_clk) begin
        if (i_reset) begin
        end
        else begin
            case(prog_cntr)
                4'd0: begin
                    if(i_enable) prog_cntr <= prog_cntr + 4'd1;
                end
                4'd1: begin
                    frequency_sign_extended <= freq_offset;
                    o_is_armed <= 1'b1;
                    gain_i_buffer <= i_gain_i;
                    prog_cntr <= prog_cntr + 4'd1;
                end
                4'd2: begin
                    if(i_phase_valid) begin
                        if(i_phase > UPPER_PHASE_SATURATION) begin
                            error_gain_product[0] <= (-UPPER_PHASE_SATURATION * gain_i_buffer);
                        end
                        else if(i_phase < -UPPER_PHASE_SATURATION) begin
                            error_gain_product[0] <= (UPPER_PHASE_SATURATION * gain_i_buffer);
                        end
                        else begin
                            error_gain_product[0] <= (-{i_phase[64-1], i_phase[30-1:0]} * gain_i_buffer);
                        end
                        prog_cntr <= prog_cntr + 4'd1;
                    end
                end
                4'd3: begin
                    if (counter == 4'd15) begin
                        prog_cntr <= prog_cntr + 4'd1;
                        counter <= 4'd1;
                    end
                    else begin
                        counter <= counter + 4'd1;
                    end
                    for(i =1;i <16;i =i +1) <<<<<<============= PIPELINING ??
                    error_gain_product [i] <= error_gain_product [i-1];
                end
                4'd4: begin
                    frequency_sign_extended <= freq_offset + (error_gain_product[15]>>> 40);
                    o_frequency_valid <= 1'b1;
                    prog_cntr <= prog_cntr + 4'd1;
                end
                4'd5: begin
                     o_frequency_valid <= 1'b0;
                     gain_i_buffer <= i_gain_i;
                     prog_cntr <= 4'd2;
                end
            endcase
        end
    end
    assign o_frequency = frequency_sign_extended[32-1:0];
endmodule
0 Kudos
2 Replies
gopal_1921ee16
Participant
Participant
314 Views
Registered: ‎01-14-2020

I think you can use multiplier IP available in Vivado, instantiate in your design to make 32 bit multiplier. 

Gopal_krishna
dgisselq
Scholar
Scholar
271 Views
Registered: ‎05-21-2015

@phytebunk ,

It can be a challenge to get Vivado to recognize the multiplier in your logic and do the right thing with it.  I recommend, therefore, that multiplies be isolated from the logic around them so that multiplication blocks are no more complicated than:

 

always @(posedge clk)
if (condition)
   mpy_result <= a * b;

 

Were I to try pipelining this, I'd recommend something instead like:

 

always @(posedge clk)
if (condition)
  mpy_pipe <= a * b;

always @(posedge clk)
  mpy_result <= mpy_pipe;

I'm not sure how complex Vivado's optimizer is in order to recognize things, but these should at least be recognizable.

Dan