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

incrementing an element in an array produces lots of (false) paths

Altera_Forum
Honored Contributor II
1,033 Views

Dear All 

 

In my VHDL I wish to count the number of "leading edges" on certain channels. There are 128 channels and I wish to be able to count up to 2^24. I define type matrix is array (0 to 127) of integer range 0 to 16777216 ; variable channel_lead_cnt : matrix; variable element : integer range 0 to 127 := 0 ;  

where "element" will hold the channel number. When I receive a leading edge on a given channel, I increment the counter: 

channel_lead_cnt(element) := channel_lead_cnt(element)+1;  

 

Having synthesised the code* and P&R it onto my device**, I use the TimeQuest Timing Analyser to look at the paths related to 'channel_lead_cnt', and I see a vast number of paths, for example: 

data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt data_counter:PPDATACNT|channel_trail_cnt  

There seem to be paths between element i of the array, and element j of the array. In the full output, i and j take all values from 0 to 127. Given the code I posted above, I don't see a reason why a path is needed if i != j ( I hope that makes sense! In the above examples, i=107 and j=0...5). I am always doing  

channel_lead_cnt(i) := channel_lead_cnt(i) + 1;  

and never  

channel_lead_cnt(i) := channel_lead_cnt(j) + 1;  

 

Is this the expected behaviour? I have tried rewriting the command using a for loop, and using a case statement, but the issue remains. When looking at the data_counter module in the chip planner, I see the routing utilisation is almost 70% in the area of the data_counter module, far higher than any other area. Moreover, many of the paths (real and false) fail timing. 

 

Can anyone suggest a way to: 

1. Correct my understanding, if I do not understand something. 

2. Rewrite the code so that the false paths are not generated. 

3. Write SDC false-path commands that remove the false paths but keep the true *** . 

 

Unfortunately, I have at least four similar "counter arrays" in the code, some even larger, each of which present the same behaviour!  

 

Any help or advice is greatly appreciated 

 

Thanks 

 

Chris Parkinson 

 

*  

I am using Quartus II 32-bit version 13.1.0 Build 162 

 

** 

The device is a Stratix III EP3SL200F1152C4  

 

*** I can easily set ALL of the paths to be false paths. Of course, this is not satisfactory, since many true paths fail timing. I have also tried using for loops within the .sdc file, however TimeQuest did not accept my attempts. Naturally, due to the scale of the problem, its impractical to explicitly set_false_path for each false path, since there are a few hundred thousand of them.
0 Kudos
2 Replies
Altera_Forum
Honored Contributor II
395 Views

You have created an array of objects which you selectively increment. It looks like you only increment one of the 128 counters on any given moment. So you created a big mux to supply one argument to the adder, the other argument being fixed to 1, and write the result back. So there is a path from j deasserting to í asserting. 

You don't mention the required clock speed so I'm guessing a bit but a 24 bit adder/counter is relatively slow, and the large mux makes that a lot worse. 

 

IMO you better instantiate 128 counters which are directly tied to their channel edge detector. The resource usage may/will be larger but it will run a lot faster. If that's not fast enough you'll have to create a faster counter by splitting the counter into smaller parts and generating registered lookahead carries to cascade the split counters. 

 

Another option, and closest to the code you have written so far, and if the edges for a each channel are spread wide apart enough you could pipeline your code, putting a register between the 'read' of variable i, incrementing it and writing it back. 

 

Yet another option is to use a dual port RAM (M4k or M9k) to hold the variables and write sequential code to read, increment and write back the result into ram. Clearing the results may be an issue though, as you have to cycle through the RAM to do so. This will have the lowest LE usage. 

 

Regards, 

 

Josy
0 Kudos
Altera_Forum
Honored Contributor II
395 Views

There two issues here. One is the large number of counters each of width 24 bits, this requires resource and the dual port ram suggested by JosyB is best. 

The other issue is that you are saying your counters are not independent when they should be but it must be your code. You need a loop to unroll into independent counters. There should be no counting dependency between them. 

 

for i in 0 to 127 loop counter(i) := counter(i) + 1; end loop;  

this shoud unroll to independant 128 counters
0 Kudos
Reply