Forum Discussion
Fmax Improvment
I'm trying to improve Fmax in our design. See the archived quartus II proejct file in the attachment. The source files are also attached.
In my currrent design, after compilation, Fmax can reach only 141Mhz. But my target is to reach 300mhz. Do you know how to optimize it to achieve 300mhz? The device I'm using is Arria V 5AGXBA3D4F31C4.22 Replies
- Altera_Forum
Honored Contributor
The usual way to improve timing is reduce the amount of logic between registers. Use tier quest to find the worst paths and reduce the logic. Then improve this paths and keep on working on the next worry paths.
With afmax if 140 I suspect you have probably got large accounts of logic between the regs. For 300mhz you'll need a max of 1-2 puts between regs and extra registers around rams and dsps as these can often be bottlenecks. Summary.. Add more pipelining - Altera_Forum
Honored Contributor
Thank you! Tricky.
--- Quote Start --- The usual way to improve timing is reduce the amount of logic between registers. Use tier quest to find the worst paths and reduce the logic. Then improve this paths and keep on working on the next worry paths. --- Quote End --- I'm new to time quest. Could you help to be more specific? Or some documents you can recommend? - Altera_Forum
Honored Contributor
Altera have a time quest tutorial
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0cciqfjaa&url=https%3a%2f%2fwww.altera.com%2fen_us%2fpdfs%2fliterature%2fug%2fug_tq_tutorial.pdf&ei=lpvivf_nkcfcaoq5gygh&usg=afqjcnh-52x-lt7rit91yaorkawzgdt93w&sig2=bgivq3tfcghbrwevb2vhwq&bvm=bv.92291466,d.d2s - Altera_Forum
Honored Contributor
--- Quote Start --- For 300mhz you'll need a max of 1-2 puts between regs and extra registers around rams and dsps as these can often be bottlenecks. Summary.. Add more pipelining --- Quote End --- Hello Tricky, not that clear about this statement. Could you help to explain more? In my case, do you have some ideas to optimize my code? - Altera_Forum
Honored Contributor
This is only a start:
1) You have to add an SDC file with create_clock like this create_clock -name Clk -period 3.333 [get_ports {Clk}] so that you inform Quartus that you want 300 MHz. You will get fmax 144 MHz with Cyclone IV (I have not Quartus subscription so changed target device) 2) In Analysis & Synthesis Settings: - set Speed into Optimization Technique - enable Perform WYSIWYG primitive resynthesis 3) In Physical Synthesis Optimizations set effort to Extra and Check all options under Optimize for performance With also 2) and 3) you will get fmax 180 MHz 4) Add a PLL to compensate clock (so in Normal Mode) Wrap all with a file like this (or simply add PLL in your TOP)
Note: You should use PLL compatible with your device, maybe ALTPLL is not compatible with Arria V5. You should also add PLL with Megawizard Plugin Manger to your project. I recommend you to use 50 MHz oscillator onboard and multiply it with PLL to 300 MHz. So SDC became:LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY work; ENTITY IPG1_FIP_worker IS PORT ( Reset : IN STD_LOGIC; In_Start_In : IN STD_LOGIC; In_DE_In : IN STD_LOGIC; inclk0 : IN STD_LOGIC; In_Data_In : IN STD_LOGIC_VECTOR(35 DOWNTO 0); Setting_B_In : IN STD_LOGIC_VECTOR(11 DOWNTO 0); Setting_Disables_In : IN STD_LOGIC_VECTOR(2 DOWNTO 0); Setting_Field_In : IN STD_LOGIC_VECTOR(3 DOWNTO 0); Setting_G_In : IN STD_LOGIC_VECTOR(11 DOWNTO 0); Setting_Line_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Setting_Pattern_In : IN STD_LOGIC_VECTOR(3 DOWNTO 0); Setting_Pixel_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Setting_R_In : IN STD_LOGIC_VECTOR(11 DOWNTO 0); Setting_TotLine_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Setting_TotPixel_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Out_Start_Out : OUT STD_LOGIC; Out_DE_Out : OUT STD_LOGIC; Out_Data_Out : OUT STD_LOGIC_VECTOR(35 DOWNTO 0) ); END IPG1_FIP_worker; ARCHITECTURE bdf_type OF IPG1_FIP_worker IS COMPONENT top GENERIC (BurstLength : INTEGER; Intended_compiler : STRING; Intended_device_family : STRING; IPG1_Max_combine_nr : INTEGER ); PORT(Clk : IN STD_LOGIC; Reset : IN STD_LOGIC; In_Start_In : IN STD_LOGIC; In_DE_In : IN STD_LOGIC; In_Data_In : IN STD_LOGIC_VECTOR(35 DOWNTO 0); Setting_B_In : IN STD_LOGIC_VECTOR(11 DOWNTO 0); Setting_Disables_In : IN STD_LOGIC_VECTOR(2 DOWNTO 0); Setting_Field_In : IN STD_LOGIC_VECTOR(3 DOWNTO 0); Setting_G_In : IN STD_LOGIC_VECTOR(11 DOWNTO 0); Setting_Line_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Setting_Pattern_In : IN STD_LOGIC_VECTOR(3 DOWNTO 0); Setting_Pixel_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Setting_R_In : IN STD_LOGIC_VECTOR(11 DOWNTO 0); Setting_TotLine_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Setting_TotPixel_In : IN STD_LOGIC_VECTOR(15 DOWNTO 0); Out_Start_Out : OUT STD_LOGIC; Out_DE_Out : OUT STD_LOGIC; Out_Data_Out : OUT STD_LOGIC_VECTOR(35 DOWNTO 0) ); END COMPONENT; COMPONENT pll PORT(inclk0 : IN STD_LOGIC; c0 : OUT STD_LOGIC ); END COMPONENT; SIGNAL SYNTHESIZED_WIRE_0 : STD_LOGIC; BEGIN b2v_inst : top GENERIC MAP(BurstLength => 64, Intended_compiler => "Default", Intended_device_family => "Default", IPG1_Max_combine_nr => 8 ) PORT MAP(Clk => SYNTHESIZED_WIRE_0, Reset => Reset, In_Start_In => In_Start_In, In_DE_In => In_DE_In, In_Data_In => In_Data_In, Setting_B_In => Setting_B_In, Setting_Disables_In => Setting_Disables_In, Setting_Field_In => Setting_Field_In, Setting_G_In => Setting_G_In, Setting_Line_In => Setting_Line_In, Setting_Pattern_In => Setting_Pattern_In, Setting_Pixel_In => Setting_Pixel_In, Setting_R_In => Setting_R_In, Setting_TotLine_In => Setting_TotLine_In, Setting_TotPixel_In => Setting_TotPixel_In, Out_Start_Out => Out_Start_Out, Out_DE_Out => Out_DE_Out, Out_Data_Out => Out_Data_Out); b2v_inst1 : pll PORT MAP(inclk0 => inclk0, c0 => SYNTHESIZED_WIRE_0); END bdf_type;
Now fmax (always on Cyclone IV but on Arria V will be better) will be 183 MHz. Slightly better but helps with timings of a lot of paths. 5) Run Timequest and start Report Timing Closure Recommendations, you will see that to improve you have to add pipeline (= Flip-Flop) between some paths.. Hottest path is from top:b2v_inst|testpattern_Setting_TotPixel[5] to top:b2v_inst|IPG1_FIP_worker_testpattern:i_testpattern|HelperGrayBar[1]_OTERM23, you have Adder and LessThan operator in same clock cycle, check in your code what is wrong and try to split it into 2 clock cycles and repeat 5)derive_clock_uncertainty derive_pll_clocks create_clock -name inclk0 -period 20.0 - Altera_Forum
Honored Contributor
flz47655. Thank you for your detailed explanation.
Is it possible you can give me an example how to add pipeline for the hottest path in my design? - Altera_Forum
Honored Contributor
You can find a lot of examples of pipelines in books and on web. Have you found where to insert pipeline in VHDL?
- Altera_Forum
Honored Contributor
--- Quote Start --- You can find a lot of examples of pipelines in books and on web. Have you found where to insert pipeline in VHDL? --- Quote End --- I think I should insert pipeline in the code below. Am I right?
If there are some limitation of the resources that i'm not allowed to add more pipeline, do you have some ideas to simplify the logic in my design?-- Gray bar(16 gray bars) HelperGrayBar <= "1111"; -- gray level 15 if unsigned(Setting_Pixel) < shift_right(unsigned(Setting_TotPixel),4) then HelperGrayBar <= "0000"; -- black elsif unsigned(Setting_Pixel) < shift_right(unsigned(Setting_TotPixel),3) then HelperGrayBar <= "0001"; -- gray level 1 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),3)) + (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "0010"; -- gray level 2 elsif unsigned(Setting_Pixel) < shift_right(unsigned(Setting_TotPixel),2) then HelperGrayBar <= "0011"; -- gray level 3 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),2)) + (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "0100"; -- gray level 4 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),2)) + (shift_right(unsigned(Setting_TotPixel),3))) then HelperGrayBar <= "0101"; -- gray level 5 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) - (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "0110"; -- gray level 6 elsif unsigned(Setting_Pixel) < (shift_right(unsigned(Setting_TotPixel),1)) then HelperGrayBar <= "0111"; -- gray level 7 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) + (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "1000"; -- gray level 8 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) + (shift_right(unsigned(Setting_TotPixel),3))) then HelperGrayBar <= "1001"; -- gray level 9 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) + (shift_right(unsigned(Setting_TotPixel),3)) + (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "1010"; -- gray level 10 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) + (shift_right(unsigned(Setting_TotPixel),2))) then HelperGrayBar <= "1011"; -- gray level 11 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) + (shift_right(unsigned(Setting_TotPixel),2)) + (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "1100"; -- gray level 12 elsif unsigned(Setting_Pixel) < ((shift_right(unsigned(Setting_TotPixel),1)) + (shift_right(unsigned(Setting_TotPixel),2)) + (shift_right(unsigned(Setting_TotPixel),3))) then HelperGrayBar <= "1101"; -- gray level 13 elsif unsigned(Setting_Pixel) < (unsigned(Setting_TotPixel) - (shift_right(unsigned(Setting_TotPixel),4))) then HelperGrayBar <= "1110"; -- gray level 14 end if; - Altera_Forum
Honored Contributor
Yeah, just do shift_right in one clock cycle, add in another and lesser in another.
Pipeline is just a FFs that are unused in combinatiorial-logic-only LEs. If you are run out of resource you can't scale up frequency.. - Altera_Forum
Honored Contributor
What this code shows is how verbose it can become when you start using innapropriate types.
Why is setting_pixel not an unsigned already? instead of shift_right function, why not do /2^n? so a 1 bit shift is /2, 2 = /2 etc. so instead of the massive long lines you already have, you could just use:elsif Setting_Pixel < ( Setting_TotPixel/2 + Setting_TotPixel/8 ) then