Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17054 Discussions

LPM DIVIDE behaves differently between simulation and implementation

marcorig
Beginner
1,742 Views

I have implemented a divider in a custom VHDL module in order to replace the instances of the LPM_DIVIDE IPs in my project. I've then checked the functionality of my module against the LPM_DIVIDE and verified through a simulation that, with the exception of a different initial latency, my divider behaves exactly the same way of the LPM_DIVIDE IP, covering all the dynamic of the input operands. The problem is that when I test it on the hardware, I have some slightly different results. Debugging the problem with SignalTap, I verified that the problem was due to a different behavior of the LPM_DIVIDE IP on the hardware with respect to the simulation. I verified that the different behavior occurs when the result of the division has a negative sign. I have attached the results of the simulation and of the acquisition on SignalTap in case of a division between a negative numerator and a positive denominator. The correct result should be the one of the simulation (0xFF..FFF4FF), but for a reason that I still don't understand, in the hardware implementation the result is 0xFF..FFF4FE. Do you have any suggestion? Is there some kind of rounding in the implementation that is not present in the simulation model?

0 Kudos
21 Replies
ShengN_Intel
Employee
1,621 Views

Hi,


If you check the simulation, the 0xFF..FFF4FF is under 010139F1A9h.

However in signal tap, you're checking under 010131CEB9h.

May be use other trigger condition to trigger the 0xFF..FFF4FF under 010139F1A9h, may be use transitional.


Thanks,

Regards,

Sheng


0 Kudos
marcorig
Beginner
1,601 Views

Hi Sheng, thank you for the answer. The 0xFF..FFF4FF (quotient) output is under 010139F1A9h (denominator) and 7FFFFA7872h (numerator) in the simulation because I've simulated the divider standalone in order to check its behavior feeding the IP only with those operands. In HW the divider is part of a more complex design and it is fed in pipeline with a stream of operands. That's the reason why in SignalTap you also see the subsequent operands, but the 0xFF..FFF4FE is the result of the first two operands of the stream, that are the same of the simulation:  LPM_DIVIDE_Simulation_vs_SignalTap.PNG

0 Kudos
ShengN_Intel
Employee
1,547 Views

Hi,


Pipeline will add latency. Could you simulate the whole complex design with pipeline instead of just divider standalone? What will be seen?


Thanks,

Regards,

Sheng


0 Kudos
marcorig
Beginner
1,472 Views

Hi Sheng.

The number of pipeline stages is a parameter of the divider and I use the same value both in the simulation and in the implementation. There are no differences. The entire complex design is impossibile to simulate due to its size. What can I do is to simulate and implement a simple one only with the divider and an operands generator inside, monitoring the outputs both in simulation and in signaltap. I think that I'll see the same behavior. Il post the results here in the next days.

0 Kudos
ShengN_Intel
Employee
1,461 Views

Hi,


Understood that. Please let me know whether simple one only with the divider and an operands generator inside got same simulation and signal tap?


Thanks,

Regards,

Sheng


0 Kudos
marcorig
Beginner
1,241 Views

Hi Sheng,

I've implemented this simple selfchecking module, which instantiates only the LPM_DIVIDE, stimulated with 1000 couple of operands. I've simulated the module, synthesized and checked its behavior with SignalTap. As I though, the strange behaviour previously observed is present also in this version:

marcorig_0-1741009948767.png

Considering the first operation:

Operands:

Numerator = FFFFFFEC82000000h = -83718307840d 

Denominator = 000000000Bh = 11d.

The result is -83718307840/11 = -7610755258.181818 or  -7610755258 with a remainder of -2, that are the outputs provided by the module during the simulation: Quotient: FFFFFFFE3A5D1746h and Remainder: 7FFFFFFFFEh

On the other side, the implemented divider publishes these results:

Quotient: FFFFFFFE3A5D1745h and remainder of 0000000009h, which are different from the one seen during simulation.

I've tested the module using Quartus Prime Version 20.1.1 Build 720 11/11/2020 Patches 1.02std SJ Standard Edition implementing it on a Arria 10 10AX066K4F35I3SG.

0 Kudos
marcorig
Beginner
1,355 Views

Hi Sheng, I've implemented a simple module which instantiates the LPM_DIVIDER only and a process that feeds the divider with 1000 couples of operands. As I expected, I've seen the same strange behavior of the implemented module which is different from the simulation when the quotient is negative. The following figure show this difference:

LPM_DIVIDE_Simulation_vs_SignalTap_2.PNG

I've taken into consideration only the first division of the sequence, since the problem is the same also in the subsequent divisions. Operands: 

Numerator = FFFFFFEC82000000h = -83718307840d; Denominator = 000000000Bh = 11d.

Quotient (SignalTap) = FFFFFFFE3A5D1745h = -7610755259d; Remainder (SignalTap) = 0000000009h = 9d.

Quotient (Simulation) = FFFFFFFE3A5D1746h = -7610755258d; Remainder (Simulation) = 7FFFFFFFFEh = -2d.

If can be of some help, I've implemented the module on a ARRIA10 FPGA (10AX066K4F35I3SG) using the following version of Quartus Prime: Quartus Prime Version 20.1.1 Build 720 11/11/2020 Patches 1.02std SJ Standard Edition.

Thank you,

Marco

0 Kudos
ShengN_Intel
Employee
1,328 Views

Hi,


Could you provide the project file for taking a look?


Thanks,

Regards,

Sheng



0 Kudos
marcorig
Beginner
1,311 Views

Hi Sheng,

since the ARRIA10 board is a custom board, I've done another project using the Intel MAX10 FPGA Development kit and simply instantiated the lpm_divide_self_operands_gen.vhd in the top module. I've checked again the outputs of the divider with signal tap, confirming that also with that device I see the same behavior. I attached the whole project (I deleted the ./db subfolder otherwise the compressed file would have been more than 23MB allowed for the attachments). There is also the signal tap inside the project, which shows the following, triggering with operands_counter = 1:

 

LPM_DIVIDE_SignalTap_on_MAX10.PNG

Considering this, I don't think it's an issue of the device.

 

0 Kudos
ShengN_Intel
Employee
1,299 Views

Hi,


Possible provide the testbench as well for simulation?


Thanks,

Regards,

Sheng


0 Kudos
marcorig
Beginner
1,286 Views

Yes, of course. Here it is.

0 Kudos
ShengN_Intel
Employee
1,258 Views

Hi,

 

For signal tap, i can get the same result as you.

However for simulation, i use your testbench and modelsim but i can't get the same result as you check attached pic. It keeps the same at FFFFFFEC78000000. Is there anything i miss?

 

Thanks,

Regards,

Sheng

 

0 Kudos
marcorig
Beginner
1,250 Views

Reduce the following constant:

constant INITIAL_WAIT : natural := 200000000; -- 2 seconds

to

constant INITIAL_WAIT : natural := 200000; -- 2 seconds

otherwise the simulation will wait 2 seconds before starting to generate the operands. Attached the updated code, with the initial_wait reduced.

0 Kudos
ShengN_Intel
Employee
1,191 Views

Hi,


I observe that if change pipeline number, the signal tap results will be different.

I suspect is the timing issue. Could you add .sdc file to check is that the timing pass? Make sure the timing is pass.


Thanks,

Regards,

Sheng


0 Kudos
ShengN_Intel
Employee
1,181 Views

Hi,

 

Please ignore the previous post. I had found the root cause.

Please use the LPM_DIVIDE megafunction from IP Catalog instead of direct using the component because there're some parameters you set not properly. For example.

Denominator width can't be set to 39 if check the dropdown screenshot:

Screenshot 2025-03-05 125053.png

Pipeline can't be set more than numerator width screenshot:

Screenshot 2025-03-05 125021.png

After using the LPM_DIVIDE megafunction from IP Catalog, I get the correct simulation result screenshot:

Screenshot 2025-03-05 125537.png

 

Thanks,

Regards,

Sheng

 

 

0 Kudos
marcorig
Beginner
1,140 Views

Hi Sheng,

I think that the problem is not the number of pipeline stages nor the size of the denominator (even if both the limitations are not clear for me), but following your suggestion I've tried the IP catalog, instead of instantiating directly the IP in the code. I've noticed that at a certain point of the personalization GUI of the IP, there are two radio boxes which allows the user to select the sign of the remainder:

Remainder sign IP personalization.PNG

Depending on the selection, this changes the value of the generic parameter "LPM_HINT" of the LPM_DIVIDE:

lpm_hint => "LPM_REMAINDERPOSITIVE=FALSE", when No has been selected

lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE", when Yes has been selected

Setting the generic LPM_HINT => "LPM_REMAINDERPOSITIVE=TRUE" in the code, even the lpm_divide_self_operands_gen.vhd returns the same result of signal_tap.

In the lpm_divide_self_operands_gen.vhd i posted previously, the parameter was set to "UNUSED". Checking here: https://www.intel.com/content/www/us/en/docs/programmable/683490/24-1/parameters-72926.html , the parameter was not required, and in any case I get the parameter value from the component declaration in LPM_PACK.vhd in the < Quartus® Prime installation directory>\libraries\vhdl\lpm directory, by default is set to "UNUSED".

I see 2 issues here:

  1. Leaving the parameter LPM_HINT => "UNUSED" causes a mismatch between the simulation and the implementation, because the behaviour of the IP in simulation is like the parameter is set to FALSE, while in implementation the remainder sign is always positive, therefore like the parameter is set to TRUE. Therefore the parameter shall be set to a value and not leaved "UNUSED", or somehow Quartus should alert the user for this mismatch!
  2. Even setting LPM_REMAINDERPOSITIVE = TRUE, the quotient is not correct, since, for example, if you try a simple division like -5/3, the result should be -1 with a remainder of -2, while the IP returns -2 with a remainder of 1. That's obviously not correct, and I didn't expect that changing that parameter changes also the values of quotient and remainder, but only the sign of the remainder, as the name of the parameter and the explanation provided in the guide states.

For confirmation, I attached a more simple version of the lpm_divide_self_operands_gen.vhd, where I instantiate 3 version of the LPM_DIVIDE function with only 1 stage of pipeline, as you suggested and with the parameter LPM_HINT set to "LPM_REMAINDERPOSITIVE=TRUE", "LPM_REMAINDERPOSITIVE=FALSE" and "UNUSED". I also update the lpm_divide_self_operands_gen_tb.vhd setting the denominator width to 32 (it is an allowed value). The operators are now simply -5 and 3. If you simulate the module you'll get that the outputs are the following:

LPM_HINT.PNG

So we get 2 different quotient and remainder values, not only the sign of the remainder changes setting the LPM_HINT parameter. The s_quotient_hint_rem_pos_true value is not correct and is the value that we have in HW leaving the parameter "UNUSED", that's different from the value that we have in simulation. On signaltap (I also attached the updated Quartus Project), we see: 

LPM_HINT_SIGTAP.PNG

0 Kudos
ShengN_Intel
Employee
1,114 Views

Hi,


Yes, when tick Yes the LPM_HINT will use "LPM_REMAINDERPOSITIVE=TRUE" while tick No the LPM_HINT will use "LPM_REMAINDERPOSITIVE=FALSE". If LPM_HINT uses either "LPM_REMAINDERPOSITIVE=TRUE" or "LPM_REMAINDERPOSITIVE=FALSE", the results between simulation and signal tap are same.

If LPM_HINT use "UNUSED", the results between simulation and signal tap are not same. Please don't use "UNUSED" because correct usage are "LPM_REMAINDERPOSITIVE=TRUE" or "LPM_REMAINDERPOSITIVE=FALSE" for LPM_HINT.

So we can conclude the LPM DIVIDE behaves same between simulation and signal tap right? which answer the title of this thread.


So there's another new question regarding functionality right?


Thanks,

Regards,

Sheng


0 Kudos
ShengN_Intel
Employee
880 Views

Hi,


For functionality in this post community.intel.com/t5/Intel-Quartus-Prime-Software/LPM-DIVIDE-behaves-differently-between-simulation-and/m-p/1672473#M85726, i think should be no problem check below:

For a numerator of −5 and a denominator of 3, using the LPM (Library of Parameterized Modules) IP division method where the remainder is always positive, we follow these rules:

Quotient Calculation: Perform integer division (truncate towards zero):

−5÷3=−1(integer division)

Remainder Calculation:

remainder=numerator−(quotient×denominator)

remainder=−5−(−1×3)=−5+3=−2

However, since LPM IP requires a positive remainder, we adjust by adding 3 to remainder and reducing quotient by 1:

new quotient=−1−1=−2

new remainder=−2+3=1

Final Result:

LPM_HINT => "LPM_REMAINDERPOSITIVE=TRUE":

quotient=-2

remander=1

LPM_HINT => "LPM_REMAINDERPOSITIVE=FALSE":

quotient=-1

remander=-2



The simulation and signal tap result for LPM_HINT => "LPM_REMAINDERPOSITIVE=TRUE" and LPM_HINT => "LPM_REMAINDERPOSITIVE=FALSE" are correct.

Only the result for LPM_HINT => "UNUSED" is incorrect, please don't use LPM_HINT => "UNUSED" (Incorrect Usage)



And for the numerator and denominator width you can use from 1 to 64 if check this document https://www.intel.com/content/www/us/en/docs/programmable/683490/20-3/parameters-72926.html. Sorry I was mislead by the dropnow menu.


Thanks,

Regards,

Sheng


0 Kudos
marcorig
Beginner
829 Views

Hi Sheng,

thank you very much for the detailed information about the IP’s functionality. However, in my opinion, the issue of the mismatch between simulation and implementation cannot be considered resolved, as I would like to understand:

  1. Where is it stated in Altera's documentation that using the parameter LPM_HINT => "UNUSED" is incorrect, as you mentioned?
  2. If LPM_HINT => "UNUSED" is incorrect, why is it assigned as the default value in the module declaration inside lpm_pack.vhd?

To truly resolve the issue and prevent it from occurring in the future for other users, I believe that the simulation model of LPM_DIVIDE should be updated so that the behavior in simulation matches the implemented behavior, regardless of the value of the LPM_HINT parameter.

 

Regards,

Marco.

0 Kudos
ShengN_Intel
Employee
788 Views

Hi Marco,


Please check this link http://www.pldworld.com/_altera/html/_sw/q2help/source/mega/mega_file_lpm_divide.htm

Altera also recommends instantiating this function as described in Using the MegaWizard® Plug-In Manager.


It's better to instantiate that function through MegaWizard Plug-In Manager.


Thanks,

Regards,

Sheng



0 Kudos
Reply