Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

"Read Before Write" RAM

Status
Not open for further replies.

shaiko

Advanced Member level 5
Joined
Aug 20, 2011
Messages
2,644
Helped
303
Reputation
608
Reaction score
297
Trophy points
1,363
Activity points
18,302
Hello,

Do all modern FPGAs feature a "Read Before Write" RAM (RAM with un-registered output) ?
 

Xilinx and Altera both have the feature, so you only have to look at Lattice and Microsemi(Actel).
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Xilinx and Altera both have the feature
So, with Xilinx/Altera this code should always yield a "read_before_write" block RAM?
Code:
type memory_matrix is array 0 to x of std_logic_vector(y downto 0);
signal memory:memory_matrix;

process(clock) is
begin
if rising_edge(clock) then
  memory (to_integer(address))<=in_data;
end if;
end process;

out_data<=memory(address);
 

I'm not sure there is a common way to make synthesizable code for both Altera and Xilinx that does that. Have you looked at the blog post "Inferring true dual-port, dual-clock RAMs in Xilinx and Altera FPGAs" that blog seems to indicated that there isn't much commonality with Altera and Xilinx in inferring RAMs based on their coding templates beyond a pretty basic dual-port RAM.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
So, with Xilinx/Altera this code should always yield a "read_before_write" block RAM?
Code:
type memory_matrix is array 0 to x of std_logic_vector(y downto 0);
signal memory:memory_matrix;

process(clock) is
begin
if rising_edge(clock) then
  memory (to_integer(address))<=in_data;
end if;
end process;

out_data<=memory(address);

for the 7-series, UG473, Section Heading "Synchronous Dual-Port and Single-Port RAMs":
"The read and write operations are synchronous and require, a clock edge."

I looked at the stratix V guide as well. It listed M20k as not supporting async reads as well. The schematic for the address port didn't have a combinatorial path for address either.

I wouldn't expect either Xilinx or Altera to create BRAM from this.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
So, with Xilinx/Altera this code should always yield a "read_before_write" block RAM?
Code:
type memory_matrix is array 0 to x of std_logic_vector(y downto 0);
signal memory:memory_matrix;

process(clock) is
begin
if rising_edge(clock) then
  memory (to_integer(address))<=in_data;
end if;
end process;

out_data<=memory(address);

In the past, I have seen Xilinx recommned using a shared variable instead of a signal as the memory element to infer write-before-read behaviour, and signal to infer read-before-write. But altera never supported such a thing (it would always infer read-before write).

The only way to guarantee you get the behaviour you want, is to generate a core and set the behaviour paramter correctly.

IMO, if you care about such behaviour, then there is probably an issue with the design somewhere.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Statistically, inferring memory is worse than using std_logic_arith/unsigned/signed in modern code. In the last decade there have been several gotchas and even outright errors in inferring memory. The blog post shows one from Xilinx in 2010, and I've seen similar in Altera in 2011. I also had issues porting XST designs to Vivado because the two tools had slightly different support for inferred BRAM in 2013.
 

vGoodtimes,
I wouldn't expect either Xilinx or Altera to create BRAM from this

Code:
type memory_matrix is array 0 to x of std_logic_vector(y downto 0);
signal memory:memory_matrix;

process(clock) is
begin
if rising_edge(clock) then
  memory (to_integer(address))<=in_data;
end if;
end process;

out_data<=memory(address);

It successfully infers BRAM in Cyclone IV and Lattice XP devices.
And as I see it, if it passes synthesis and infers a BRAM - this BRAM must be "read before write".
As this is explicitly described in the VHDL code.
Code:
out_data<=memory(address);--show yourself NOW!

TrickyDicky,
IMO, if you care about such behaviour, then there is probably an issue with the design somewhere.
Yes, my design must use a "read before write" memory - why is that an "issue" ?
 

Interesting. perhaps it is merging a register from upstream into the structure.
 

vGoodtimes,


Code:
type memory_matrix is array 0 to x of std_logic_vector(y downto 0);
signal memory:memory_matrix;

process(clock) is
begin
if rising_edge(clock) then
  memory (to_integer(address))<=in_data;
end if;
end process;

out_data<=memory(address);

It successfully infers BRAM in Cyclone IV and Lattice XP devices.
And as I see it, if it passes synthesis and infers a BRAM - this BRAM must be "read before write".
As this is explicitly described in the VHDL code.
Code:
out_data<=memory(address);--show yourself NOW!

TrickyDicky,

Yes, my design must use a "read before write" memory - why is that an "issue" ?

No it is not read before write what it is, is a asynchronous read single port RAM, i.e. a flow-through RAM.

To my sometimes faulty recollection: Dual port RAMs use the read-before-write and write-before read settings to know how to deal with simultaneous access to the exact same location from two different ports. The "read before write" refers to accessing the same memory location during reading and writing and what is the RAM supposed to do. The choices are typically "write before read": the write happens and the data written shows up at the output of the RAM and "read before write": the old read data is presented until the write is completed then will change to the newly written data on the next cycle. Newer devices from both Altera and Xilinx have some inherent registers built into the devices that can't be bypassed regardless of how you code the RAM and in fact you won't have block RAM inferred if you don't at least register something.

Try running simulations on a BRAM testbench out of Xilinx Coregen on two designs one with the read-before-write and one with the write-before-read options set.

I typically don't care which mode it uses as I normally design things so I don't overlap read and write addresses. And I normally use the setting that has no bugs (Xilinx has had errata on the read-before-write mode on more than one occasion).

It's also one of the reasons you should probably build a library of HDL RAM wrappers that instantiate the vendor RAM IP instead of inferring them. Then you can use the vendor tool to generate a RAM add it to the if generate stuff in the file and use a generic/parameter to select the vendor you are using. Just keep adding new vendor RAM IP macros as you go.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
No it is not read before write what it is, is a asynchronous read single port RAM, i.e. a flow-through RAM.
Wrong understanding of the terminology from my side.
I thought that "read before write" is and "asynchronous read flow-through RAM" are exactly the same thing.

Anyways, from my understanding both: "read before write" and "write before read" refer to RAM with an un-registered output.
Would you agree ?
 

See PG058 for a description of the operating mode for dual port RAMs, which are WRITE_FIRST, READ_FIRST, or NO_CHANGE in Xilinx land. I know Altera has something very similar, though I don't know exactly what they are called.

Here is a screen capture of the waveforms they use to describe the modes.
Capture.JPG
Capture2.JPG

As you can see the WRITE_FIRST corresponds to a flow through mode as the data written ends up at the read port. In the case of the READ_FIRST the previous value in the memory array shows up at the output. Altera parts did something similar from what I remember.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
To my sometimes faulty recollection: Dual port RAMs use the read-before-write and write-before read settings to know how to deal with simultaneous access to the exact same location from two different ports.
This is why I don't like Xilinx's terms. It actually describes the behavior of the data output of the port being written to. Reading from port B when writing to port A actually requires port A (the write port) to be in read-first mode, and port B (the read port) can be in any mode. To get the currently written data on the output requires a mux, either with the write port in write-first mode or by just using the input data. As a developer, when I head "read-first" I think about typical use cases of dual-port BRAM and except it to mean the read port reads before the write port.

IIRC, altera has a similar restriction at the device level, but will add logic automatically during synthesis for this mode.

Anyways, from my understanding both: "read before write" and "write before read" refer to RAM with an un-registered output.
The code you show was for an async read, which means there is no x before y relationship. The data is written and immediately read, similar to treating the BRAM as a register.
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top