Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20755 Discussions

Verilog Synthesis Q

Altera_Forum
Honored Contributor II
2,383 Views

Am bumping into a synthesis problem inside of an always construct. Simplified code is 

 

reg true_or_false[0:9999]; 

reg a; 

 

always (negedge clk) 

begin 

if (a <5000) 

true_or_false[a] <= 1 

else if (a < 10000) 

true_or_false[a+5000] <= 1 

end 

 

The error I get is "Cannot convert all sets of registers into RAM megafunctions when creating nodes. The resulting number of registers remaining in design exceeds the number of registers in device....." 

 

If I remove the if else construct, no allocations (register/memory/etc) are > 30%. 

 

I'm quite sure I'm violating an HDL paradigm. Could use a little guidance on why and thoughts on how I might implement it correctly. 

 

THNX, 

ME
0 Kudos
17 Replies
Altera_Forum
Honored Contributor II
611 Views

Your simplified code isn't very clear. 

But from the looks of the message, you're designing something that requires a huge number of register (more than the FPGA has) and can't be converted to use SRAM. 

 

What you need to do is to try and re-write your code in such a way that it uses SRAM and meets Quartus HDL SRAM templates. 

See the HDL coding guidelines handbook for details.
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

Besides observing the conditions for RAM inference, you should think about the data type of reg a. It's a bit variable, how can it address a memory array?

0 Kudos
Altera_Forum
Honored Contributor II
611 Views

Sorry for the confusion. Was trying to simplify the problem for brevity's sake. 

 

Basically, I am capture the address bus on an old 80196 MPU using Cyclone 4 on a TerASIC DE2-115. Am using a NIOS II processor which preprocesses the 80196 list files to determine if a given address is a branch or not. If so, the branch offset is loaded into the TerASIC SRAM at an offset equal to the MPU address (so if MPU address 0x1234 represents a branch 0f 12, I store 12 at SRAM offset 0x1234). 

 

When a new address is available, I calculate the two addresses: one the represents the jump that occurs if the branch evaluates true, the other if false (I have to deal with a 5 byte prefetch on the false side). 

 

All of this synthesizes and fits quite well. My total logic element usage is 13% and my totoal memory bit usage is 53%. This 53% includes a 128k bit array that defines a true and false branch indication for each of the 64k addresses. So I don't think I'm running out of FPGA RAM due to the bit array. 

 

Once I determine that a given address represents a branch, I continue to collect addresses until either the true or false case is resolved. This is where I run into the RAM megafunction error. The code is in an always loop and looks like this (note branch_address is calculated earlier and is used as an index into the decision array): 

 

reg decision[0:128k-1] - Sorry too early in the morning to calculate 128 * 1024 - 1 

 

if ((new_address > branch_false_address) && (new_address < branch_true_address)) 

decision[branch_address] <= 1; 

else if (new_address == branch_true_address) 

decision[branch_address+65536] <= 1 

 

Adding this seeming innocuous code is where the problem lies. Am working to understand if it is the conditional logic statements or trying to set the decision array element that is causing me the problem. It seems that it is the conditionals that are causing the problem. BUt will confirm... 

 

Hope this clears it up some. Any more thoughts are greatly appreciated.
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

The post mainly shows that's it's useless to show small code snippets. It's even unclear, if you have synchronous (in an edge sensitive always block) or asynchronous writes to reg decision. 

 

I suggest to try it the other way around. Understand about the hardware features of FPGA internal RAM and the requirements of RAM inference from behavioral code. Then write your code considering these informations.
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

SO I tried something a little different. Rather than creating the if else construct, I did something like this (inside a state machine): 

 

 

branch_found: 

begin 

greater_than_false_address[0] <= (current_tdr_address >= branch_false_address[0]) ? 1 :0; 

less_than_true_address[0] <= (current_tdr_address < branch_true_address[0]) ? 1 : 0; 

equal_to_true_address[0] <= (current_tdr_address == branch_true_address[0]) ? 1 : 0; 

branch_processor_state[0] <= processing_branch; 

end 

processing_branch: 

begin 

decision[current_tdr_address] <= greater_than_false_address[0] & less_than_true_address[0]; 

end 

 

All synthesizes well with the same logic and memory usage statistics until I add the single assignment in the processing_branch case. 

 

I checked my settings and the max_number_of_uninferred_ram_logic is set to -1 (no max). Have attempted to read up on inferred/uninferred ram. It seems that the documentation would be quite helpful for someone that already understood the paradigm. However, I am having trouble converting that written academics to the practical problem that I have (I'm not the sharpest tool in the shed). 

 

Any help is greatly appreciated.... 

 

ME
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

one more thing after re-reading all the posts: 

 

branch_address and current_tdr_address are defined as: 

 

reg [15:0] branch_address; 

reg [15:0] current_tdr_address;
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

FvM, 

 

Thanks for the continued guidance. Am new to the FPGA world, so I'm sure my Q's are rather sophomoric. Not sure I understand you post about behavioral logic (I understand there is a difference between this and combinatorial logic). Could I ask for a VERY brief example of how you implement this as behavioral. 

 

ME
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

btw, it's in a synchronous always which contains a state machine... 

 

thanks agagin
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

What FvM means is that you need to write your code while meeting Quartus templates for inferring RAM for your FPGA. 

They are documented in the HDL coding guidelines handbook, but it's something like this 

 

// 1x128k memory reg memory; always @ (posedge clk) begin if (write) memory <= data_in; data_out <= memory; end 

 

If your Verilog code describes something Quartus doesn't know or cannot map to RAM (M9K) blocks, Quartus will try to map it to registers. 

Since the FPGA in question only has ~115k registers, they're not enough to implement your 128 kbit table, plus all the remaining logic.
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

Thank to both of you. I'm starting to get there. Please bear with a couple more dumb questions. 

 

Have been reading the HDL coding guidelines and I'm sure they will make sense once I solve the problem. One question. In your example, you specify a write signal. My understanding is that I don't need the write signal to access the array. Rather, since the always loop conforms to the standards you discuss, the synthesizer defines the array as ram rather than registers. 

 

A second question. In my example, if I remove the statement that actully attempts to write to the array, it synthesizes and appears to place the array in RAM. 

 

Thank you both for your continued patience as I learn.... 

 

ME
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

Another thought as I work my way through this.... 

 

The array in question is also accessed from the NIOS CPU via an Avalon MM Slave interface. This works quite well. My NIOS application successfully reads and writes to the same array I am trying to access. I do have a single bit entity that defines whether the NIOS or my custom FPGA code has access to the array. Does the use of the Avalon MM slave "force" quartus to define the array as memory (thus why it shows up as memory bits in the compilation report)? 

 

Thanks again, 

ME
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

First question: 

Indeed, the write condition is not required for the code to be inferred into RAM. 

You'll just get a RAM block which is constantly writing into the position indicated by address. 

 

Second question: 

I assume you refer to the code in your post# 6. Two questions there. 

1. If you don't have a statement which writes the RAM, the reads always return 0 and thus Quartus should optimize it away entirely. 

2. How do you read it?
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

Ok, that answers my questions. 

 

No, the Avalon-MM slave doesn't force anything. It's the reverse, actually. 

 

The way you've coded the read/write access from the Avalon-MM interface allows Quartus to infer RAM blocks. Which is happily does. 

 

When you add the extra code to write the array, you're adding something that is preventing Quartus from inferring a RAM. 

 

There are two reasons for Quartus not being able to infer a RAM. 

1. It's not possible. Your code describes a behaviour that the M9K blocks can't implement: asynchronous access or clearing the contents for example. Quartus tends to provide messages in those cases. 

2. Software limitation. Synthesis is somewhat pattern orientated and Quartus doesn't always recognize the code. That's why we have to follow the templates.
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

First question: Yeah! I got one right.....8>) 

 

 

Second question: Yes, I am referencing the code which writes to the array in# 6. I am reading it via a NIOS CPU application via an Avaon MM slave interface. I'm guessing that even though I remove the write statement in# 6, because the array is accessed from the NIOS, it is being instantiated as RAM. The NIOS interface works perfectly (Can read and write to the array). As soon as I add something as simple as: 

 

decision[0] <= 1; 

 

to the code from# 6, i get the ram inference issue. 

 

At this point I'm working through the I don't know what I don't know issue. I appreciate your continued guidance... 

 

ME
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

If decision[current_tdr_address] <= any_expression is inside an edge sensitive always block, and the only write access to the the register array, it should cause no difficulties to implement it in internal RAM. The problem can be caused on the read side as well. The problem can't be determined from these code snippets.

0 Kudos
Altera_Forum
Honored Contributor II
611 Views

DING..I think the light just went on. I have a different module that does a similar thing. However, it doesn't have to go through an complex logic. It simply sets a bit in a similar array based on the address that comes in. It works fine. It is also accessed via the NIOS application as well as from my custom code. However, all of the accesses (from both the NIOs and my FPGA code) are in the same synchronous always construct. The synthesizer displays a message that it is inferring RAM and now I think I understand why. Since both types of accesses are in the same always construct the synthesizer configures that array as RAM. However, in my decision array instance I was attempting to access the array via two different always constructs. In one instance as a Avalon MM slave and in the second as a direct write. In the second case, since i don't conform to the memory interface stndards, the synthesizer can't resolve it as memory and thus tries to make it registers. 

 

Am I close? 

 

Anyway, as soon as I moved the write access into the same always construct, everything started to compile. 

 

I'll see how this progresses today. Hopefully, you won't hear from me any mre. 

 

THANKS AGAIN TO BOTH OF YOU FOR YOUR HELP. I TRULY APPRECIATE YOU MENTORSHIP.
0 Kudos
Altera_Forum
Honored Contributor II
611 Views

FvM, 

 

Just saw your last post. My apologies for the code snippets. I wasn't trying to be evasive. I didn't want to post a plethora of code and ask you to fix it. I wanted to work through the issue so I understood why? Both your and rbug's guidance has been very helpful. 

 

I was planning on asking about inferred RAM upon completion of my project as I din't quite understand the implications. Based on today's thread and your guidance, I understand now..... 

 

You help is truly appreciated.... 

 

Have a great day. 

 

Mark
0 Kudos
Reply