Forum Discussion
LPM_Divide Megafunction Timing Issues
Hey,
I'm working with an Arria II GX. I've been having timing issues with the lpm_divide megafunction. I have created a divider using the MegaWizard Plug-In Manager that has a Numerator of 64-bits (signed, FixedPoint) and a Denominator of 32-bits (signed, FixedPoint). I've been fighting the core's failing timing for so long that I decided to create a new project with the divider as the top-level. The only other file in the new project is my SDC file with my clock settings (150 MHz). After running Synthesis and Fitter over and over changing the core's internal latency, I've found that the core all by itself needs a latency of at least 40-45 cycles to pass timing in the TimeQuest Timing Analyzer (and this is with greatly increased Synthesis and Fitter settings optimized for Speed). I realize that having the numerator at 64-bits is the maximum the core allows, but in our application I don't see any way around it. Does anyone have any ideas/hints that can help with this timing issue? The core is part of a much larger processor project, and it has become a real burden to close timing with these Div Cores crying all the time. I'm using Quartus II ver. 11.0. Any help is greatly appreciated.11 Replies
- Altera_Forum
Honored Contributor
Avoid division, it is always slow :-)
If you are dividing by constants, do a 'multiply by reciprocal' instead. I also think it is possible to use an approximate reciprocal, a multiply, and then a few Newton-Raphson type iterations. - Altera_Forum
Honored Contributor
Thanks for the reply. The denominators are not constants, but are the results of previous stages of arithmetic. I kicked around multiplying by the reciprocal but I don't see how I can implement this without using another Div core to find the inverse (reciprocal). All my denominators are in a 16.16 fixed point format.
- Altera_Forum
Honored Contributor
Didn't take me long to find http://www.acsel-lab.com/arithmetic/papers/arith09/arith09_fowler.pdf
- Altera_Forum
Honored Contributor
I'm hesitant to implement this type of method for a couple reasons. The first being that I'm relatively new to VHDL design and would feel more comfortable using Altera's generated core rather than trying to create my own using this complex method. I'm also real scarce on resources in the FPGA as it is.
The processor design is for the most part complete. My only remaining hurdle is trying to figure out how to manipulate this divider core. I've ran a few tests where I modified the MAXIMIZE_SPEED parameter in an attempt to increase my slack. After a few iterations of running synthesis and PAR, it appears that changing this parameter does absolutely nothing. The fitter report and TimeQuest numbers all remained the same. Can anybody offer some information/help on how to get this core working efficiently and to pass timing? - Altera_Forum
Honored Contributor
divide involves many levels of logics. besides, you are using quite a high frequency clock. the most effective way is to increase latency of your divide to meet timing closure. Increasing latency means it reduces the logics that a datapath needs to go through from one register to another register. If your system is processing data in parallel, increasing latency shouldn't affect performance much as it only adds some overheads before you get the outputs.
- Altera_Forum
Honored Contributor
You can use clock enable at your chosen rate. Assuming the core has clock enable port then you can apply multicycle of clock speed/enable speed.
You can also use logic generated clock and connect it to global lines. - Altera_Forum
Honored Contributor
Thanks for the replies. After doing a lot of research about possible alternatives, it looks like I'm gonna have to live with the Divider core. I have its latency set at 48 cycles right now and it's passing timing. The only problem is that whenever I make the slightest change to the overall project, the div cores are the first thing to start crying in Timing Analysis.
Guess it's something that I'm just gonna have to deal with (over and over). - Altera_Forum
Honored Contributor
--- Quote Start --- Hey, I'm working with an Arria II GX. I've been having timing issues with the lpm_divide megafunction. I have created a divider using the MegaWizard Plug-In Manager that has a Numerator of 64-bits (signed, FixedPoint) and a Denominator of 32-bits (signed, FixedPoint). I've been fighting the core's failing timing for so long that I decided to create a new project with the divider as the top-level. The only other file in the new project is my SDC file with my clock settings (150 MHz). After running Synthesis and Fitter over and over changing the core's internal latency, I've found that the core all by itself needs a latency of at least 40-45 cycles to pass timing in the TimeQuest Timing Analyzer (and this is with greatly increased Synthesis and Fitter settings optimized for Speed). I realize that having the numerator at 64-bits is the maximum the core allows, but in our application I don't see any way around it. Does anyone have any ideas/hints that can help with this timing issue? The core is part of a much larger processor project, and it has become a real burden to close timing with these Div Cores crying all the time. I'm using Quartus II ver. 11.0. Any help is greatly appreciated. --- Quote End --- connect the divider to a slow clock domain(like 50Mhz).sync the input to the slow clock and sync the result to the 150Mhz. ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // Target Devices: // Tool versions: // // Create Date: // Project Name: // Project Top Name: // Design Name: // Module Top Name: // Module Name: // Description: // // Dependencies: numer / denom // SYNC_LEN > 2 // delay equal to (DEL_LEN)*SYNC_LEN + 2 + (SYNC_LEN - DEL_LEN) // Revision: 1.0 // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// `timescale 1ns / 10ps module DIV_TOP# ( parameter CLK_SYS = 160_000_000, parameter CLK_DIV = 40_000_000, parameter SYNC_LEN = 3 ) ( input clk_div, // 40M input clk_sys, //160MHz input rst_n, input div_start, input [23:0] numer, input [13:0] denom, output reg div_done, output [23:0] quotient, output [13:0] remain ); /******************************************************** Parameter \********************************************************/ localparam U_DLY = 1; localparam DEL_LEN = CLK_SYS / CLK_DIV; /******************************************************** Signals \********************************************************/ reg [SYNC_LEN-1:0] sync_shift; reg [SYNC_LEN-1:0] sync_shift2; reg div_start_flag; reg div_valid; wire div_en; reg div_en_dly; reg [23:0] div_num; reg [13:0] div_dem; reg [23:0] div_quo; reg [13:0] div_rem; wire [23:0] div_quo_w; wire [13:0] div_rem_w; /******************************************************** Main code \********************************************************/ assign div_en = sync_shift[SYNC_LEN-1] ^ sync_shift[SYNC_LEN-2]; assign quotient = div_quo; assign remain = div_rem; always@(posedge clk_sys,negedge rst_n) begin if(rst_n==1'b0) begin div_start_flag <= 1'b0; end else if(div_start) begin div_start_flag <=# U_DLY ~div_start_flag; end end always@(posedge clk_sys,negedge rst_n) begin if(rst_n==1'b0) begin div_num <= 'h0; div_dem <= 'h0; end else if(div_start) begin div_num <=# U_DLY numer; div_dem <=# U_DLY denom; end end always@(posedge clk_sys,negedge rst_n) begin if(rst_n==1'b0) begin div_quo <= 'h0; div_rem <= 'h0; end else if(div_valid) begin div_quo <=# U_DLY div_quo_w; div_rem <=# U_DLY div_rem_w; end end always@(posedge clk_sys,negedge rst_n) begin if(rst_n==1'b0) begin div_done <= 'b0; end else begin div_done <=# U_DLY div_valid; end end always@(posedge clk_div,negedge rst_n) begin if(rst_n==1'b0) begin sync_shift <= 'h0; end else begin sync_shift <=# U_DLY {sync_shift[SYNC_LEN-2:0],div_start_flag}; end end always@(posedge clk_sys,negedge rst_n) begin if(rst_n==1'b0) begin sync_shift2 <= 'h0; end else begin sync_shift2 <=# U_DLY {sync_shift2[SYNC_LEN-2:0],div_en_dly}; end end always@(posedge clk_div,negedge rst_n) begin if(rst_n==1'b0) begin div_en_dly <= 1'b0; end else begin div_en_dly <=# U_DLY div_en; end end always@(posedge clk_sys,negedge rst_n) begin if(rst_n==1'b0) begin div_valid <= 1'b0; end else begin div_valid <=# U_DLY ~sync_shift2[SYNC_LEN-1]&sync_shift2[SYNC_LEN-2]; end end /******************************************************** instance \********************************************************/ DIV_24_14 DIV_U0( .clken (div_en), .clock (clk_div), .denom (div_dem), .numer (div_num), .quotient (div_quo_w), .remain (div_rem_w) ); endmodule - Altera_Forum
Honored Contributor
--- Quote Start --- connect the divider to a slow clock domain(like 50Mhz).sync the input to the slow clock and sync the result to the 150Mhz. --- Quote End --- Thats no good if your data rate is 150MHz!!!! - Altera_Forum
Honored Contributor
Was able to pass timing for now. It seems the only way to achieve positive slack is to keep adding latency cycles. I finally went for broke and set the core to its max latency (64 cycles for a 64-bit numerator) and was able to get the slack up to +0.200. Going to start scaling back a little to see the minimum I can use.
Also, I found it interesting that when I created a project with 2 input convert to float cores, a floating point divide core, and an output convert float to fixed core, all those cores together were about 20-25% of the registers used in a single fixed point 64-bit divide. Thanks all for your replies.