2
\$\begingroup\$

The thing is: new data is being generated every "time step" that can be few clock cycles. So I want to store the data generated for few time steps in a "buffer". The data must be stored like in a queue. That is, the latest datum goes at the end of the queue and the first one is discarded. All the rest are moved one step ahead. That is, the second becomes the first, the third becomes the second and so on.

I want to avoid registers to save circuit area. That is why I am thinking of using on-chip memory like SRAM.

It can be understood as a FIFO based in RAM in which I could access any stored element by means of an address.

Something like:

entity special_fifo is
  generic (
    WIDTH : natural := 8;
    DEPTH : integer := 32;
    WIDTH_DEPTH : integer:=5
    );
  port (

    clock      : in std_logic;
    reset      : in std_logic;
    wren      : in std_logic;
    ren     : in std_logic;
    address    : std_logic_vector(WIDTH_DEPTH-1 downto 0);—-This is the thing that I would like to have
    data      : in std_logic_vector(WIDTH-1 downto 0);
    q       : out std_logic_vector(WIDTH-1 downto 0)

end special_fifo;

Can anyone clarify if it is doable?

Another way to ask the question could be:

Is it possible to shift the elements stored in RAM as if they formed an array. Something like this: RAM(address)<=RAM(address+1).

The number of clock cycles required does not matter in principle.

Edit: The data does need to be moved in the ram. It is data that has to be updated (thats why the latest is incorporated whereas the oldest is removed). Every single element of the current data must be accessible by means of the address. It is like updating a matrix row by row.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Besides using RAM blocks as a FIFOs with read and write circular pointers, Xilinx FPGAs can transform some logic cells into shift registers (SRL16, SRL32) which can be used to implement small synchronous FIFOs (for example 32bits * 16)

Here is a sample inferrence :

  -- FIFO
  IF push='1' THEN
    fifo<=data_in & fifo(0 TO FIFO_SIZE-2); -- Shift register
  END IF;
  IF push='1' AND pop='0' THEN
    IF not_empty='1' THEN
      level<=level+1;
    END IF;
    not_empty<='1';
  ELSIF push='0' AND pop='1' THEN
    IF level>0 THEN
      level<=level-1;
    ELSE
      not_empty<='0';
    END IF;
  END IF;

  IF flush='1' THEN
     not_empty<='0';
     level<=0;
  END IF;

  data_out<=fifo(level)

Intel/Altera Quartus handles also well that syntax and use efficient distributed RAM blocks (not hundreds of DFFs)

\$\endgroup\$
6
  • \$\begingroup\$ There are dual-port rams with 2 read ports and 2 write ports. You could use 1 read port and 1 write port for the FIFO part and the other read port for the "backdoor" access. \$\endgroup\$
    – Ben
    Apr 22, 2020 at 14:57
  • \$\begingroup\$ @Ben If there are 2 read ports and 2 write ports, then it's a quad-port RAM. If you are using a read/write port, you cannot simultaneously read and write the memory, simultaneously push and pop the FIFO. \$\endgroup\$
    – Grabul
    Apr 22, 2020 at 16:32
  • \$\begingroup\$ I meant 2 addresses but 2 read and 2 write interfaces \$\endgroup\$
    – Ben
    Apr 22, 2020 at 16:56
  • \$\begingroup\$ and yes I'm aware that you can't write at the same address at the same-time. Xilinx still calls it a dual-port RAM \$\endgroup\$
    – Ben
    Apr 22, 2020 at 17:09
  • 1
    \$\begingroup\$ @Fabio For such large memory, using a dual port RAM block with read and write pointers is better. A good article about FIFOs : zipcpu.com/blog/2017/07/29/fifo.html. \$\endgroup\$
    – Grabul
    Apr 23, 2020 at 11:57
2
\$\begingroup\$

Yes it is possible to use an SRAM as a FIFO. Have a write pointer and a read pointer. That way you won't have to shift all the SRAM data when you push or pop a new data.

signal read_pointer : unsigned(log2(WIDTH) -1 downto 0);
signal write_pointer : unsigned(log2(WIDTH) -1 downto 0);
signal full : std_logic;

Incrementer the write pointer when you write. Increment the read pointer when you read.

when read_pointer = write_pointer and full = '0', then fifo is empty. When write_pointer = read_pointer and full = '1', the fifo is full (obviously). Otherwise the size = write_pointer - read_pointer.

You could adapt this model

http://www.eng.auburn.edu/~strouce/class/elec4200/vhdlmods.pdf

Edit :

It is not a good idea to internally shift the data inside of the RAM. You don't need to do it... Like I said, a read pointer and write pointer is all you need.

Beginning:

Read ptr = Write ptr = 0. Full = 0. No data in the RAM

Operation 1,

Write 0x1234 ---> Write ptr = 1, read Ptr = 0, Full = 0; 0x1234 at address 0x00

Operation 2,

Write 0xCAFE ---> Write ptr = 2, read Ptr = 0, Full = 0. Ox1234 at address 0x00, 0xCAFE at address 0x01

Operation 3,

Read operation. Output = 0x1234 since read ptr = 0. After read is completed, read ptr = 1. Write ptr = 2. 0xCAFE at address 0x00

Operation 4,

Read operation. Output = 0xCAFE since read ptr = 1. After read is completed, read ptr = 2, Write ptr = 2. The Fifo is empty.

\$\endgroup\$
7
  • \$\begingroup\$ With the read and write pointer. How do you write and remove new and old data into and from the ram? \$\endgroup\$
    – Fabio
    Apr 21, 2020 at 17:31
  • \$\begingroup\$ Check the operation sequence I added \$\endgroup\$
    – Ben
    Apr 21, 2020 at 17:36
  • \$\begingroup\$ Your answer is clear, witty and fits with common FIFO use. However, here I wanted to achieve something a bit different. I need the data to be moved in the ram so I can access every single element in it by means of the address. Every time new data comes it has to be added at the end, therefore in order to fit the fixed sized of the buffer, the rest of the data must be moved one-step. Thus the oldest data gets removed. \$\endgroup\$
    – Fabio
    Apr 21, 2020 at 18:15
  • \$\begingroup\$ With my solution, you can still access every single element with the address. The read pointer and writer pointer are addresses but you can implement a "backdoor" address. \$\endgroup\$
    – Ben
    Apr 21, 2020 at 18:26
  • \$\begingroup\$ It is true that you can acces every single element with the addres with your solution. However, I can not see how to update the values in a fifo way (in a row by row way when comparing with a matrix). \$\endgroup\$
    – Fabio
    Apr 21, 2020 at 18:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.