Block RAM strange behavior, address off by one

I am getting a strange error with Block RAM on a Spartan 3 FPGA. Every time I issue a read, the word at the location previous to the given address is read. For example if I'm reading from address 5, the word at address 4 is output instead. The data written to the block seems correct when I view it in ModelSim so I assume it's something with the read.

Viewing signals at the BRAM input in ModelSim shows the correct address at the input of port A and the read clock signal goes high but the wrong word appear at the output. ENA is always 1 and WEA is always

  1. The very most recent Write to this same address (from a different port) also shows the correct value being written.

The design works correctly in RTL but this problem only occurs with the post-route netlist.

Did anyone encounter a similar problem like this before and can give me a hint on what's going on.

Thank you.

Reply to
M. Hamed
Loading thread data ...

This does seem strange. Are your writes and reads always made to sequential memory locations (i.e. 1, 2, 3, ... in order)? Perhaps the error is in cycle timing and not address?

The only time I've seen something similar was with an old version of the BRAM simulation models that needed a slight positive hold time in the address. In effect it was the behavioral simulation that incorrectly gave the read data on the same clock that the address was presented. In fact BRAM's are registered in the Spartan 3 (and Virtex 2) series, so the output data should have changed on the following clock cycle. In the post-PAR timing simulation, the output changed on the following clock cycle as expected.

Reply to
Gabor

A few ideas: Are you sure about the content of the various locations? Could the error have happened when you wrote data into the BRAM?

When reading, read twicein sequence from the same address. Then you will see whether this is a read pipelining problem, or whether you really are always reading the wrong information. The error has to somewhere in your timing.

Be a sleuth! Peter Alfke

Reply to
Peter Alfke

If you generated the block RAM with coregen, there is an option to preload the RAM with a coe file. You can then simulate the block RAM both at the RTL and post P&R level, disable the writes in the code and see if you read the expected data designated by the coe file at the desired addresses.

There are some instances when the RTL does not match the post P&R simulation. i.e. (sensitivity list is incomplete in a combinatorial process, improper use of blocking assignments and variables) I don't use the later two items in synthesizable code, so I don't have much experience with them, but then again, I never get an RTL vs post P&R simulation mismatch because of them.

Hope this helps, Newman

Reply to
Newman

Thank you for all the suggestions. I am led to suspect it's a timing problem and I will investigate that. The data sheet and the handbook barely mentions anything about Setup/Hold/Cycle time requirements or otherwise I am looking in the wrong places.

Reply to
M. Hamed

Reply to
Peter Alfke

Thank you Peter for the clarification. I do understand that now. I realized that for a read, I was outputting the clock and address at the same time as if it was combinational. My problem now is to figure out a way to fit an extra cycle in my state machine to issue the clock one cycle after the address is output.

/MHS

Every

the

but

always

Reply to
M. Hamed

Every

word

the

the

but

always

different

give

Reply to
Peter Alfke

Is the state machine actually issuing the clock to the BRAM? If so, it sounds like it is a gated clock which is to be avoided.

Newman

Reply to
Newman

The state machine output changes on a clock edge ( I know some can argue this is bad style). It goes like this:

IF RISING_EDGE(clk) THEN CASE state IS

WHEN READ_BKRAM =>

bram_read

Reply to
M. Hamed

I assume that clk is the global clock. If you connect bram_read to the BLK RAM clk input, you have created another clock domain and created clock skew issues. It is better to attach the global clock to the BLK RAM clk input and use the enable signals to control the data flow and or pick off valid data via the state machine. Creating another clock domain is generally to be avoided if possible.

I hope I have understood the situation and this helps. I suspect it will.

Newman

Reply to
Newman

The clock is the global clock (for this module) but I think the method you suggested is a cleaner way to do it. I am kind of reluctant to change the design now at this stage but I'll try to follow this in the future.

Thank you.

/MHS

Reply to
M. Hamed

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.