2
\$\begingroup\$

I've been tasked with designing a FIFO in VHDL for the block diagram below. I understand the general mechanism of how a simple FIFO works, but I've been struggling with how to connect the address from the read/write address counter to the address of my RAM component. I tried setting the ram address to the counter address during a read/write operation but ran into issues with the address going into an undetermined state after a write during the simulation.

Some of the code was adapted from sections of FPGA prototyping by Example by Pong P. Chu. I can link to a PDF but am not sure if that's allowed here.

Any input or suggestions would be greatly appreciated! I think most of the functionality is there though I'm sure there is still something I'm missing. Mainly I'm struggling with how to set the address for the RAM. I mapped the address input from the RAM component to a signal and then tried to write to that signal to set the address during the read/write operation but the address went to an undetermined state.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity HW7 is 
       port (
        wr : in  std_logic;
        rd : in  std_logic;     
        main_clk : in std_logic;
        data_in    : in  std_logic_vector(15 downto 0);        
        
        full : out std_logic;
        empty : out std_logic;
        data_out    : out  std_logic_vector(15 downto 0);
        fifo_count   : out std_logic_vector(5 downto 0)
    );
end HW7;


architecture behavioral of HW7 is

component ram_example
    generic (
        DATA_BITS: integer := 8;
        ADDR_BITS: integer := 8
    ); 
    port (
        clk     : in  std_logic;
        address : in  std_logic_vector(ADDR_BITS-1 downto 0);
        we      : in  std_logic;
        re      : in  std_logic;        
        din     : in  std_logic_vector(DATA_BITS-1 downto 0);
        dout    : out std_logic_vector(DATA_BITS-1 downto 0)
    );
end component;

component genericCounter    
    generic(
    upDownCounterSize : integer := 16
    );
    port(
    clk_a : in std_logic := '0';
    clr : in std_logic := '0';
    upInput : in std_logic := '0';
    downInput : in std_logic := '0';
    
    count : out std_logic_vector(upDownCounterSize - 1 downto 0) := (others => '0')
    );
end component;

signal wr_addr,wr_addr_next,wr_addr_succ : std_logic_vector(4 downto 0) := (others => '0');
signal rd_addr,rd_addr_next,rd_addr_succ : std_logic_vector(4 downto 0) := (others => '0');
signal ram_address : std_logic_vector(4 downto 0) := (others => '0');    
signal cnt_signal : std_logic_vector(5 downto 0) := (others => '0'); 
signal dataIn : std_logic_vector(15 downto 0) := (others => '0');
signal dataOut : std_logic_vector(15 downto 0) := (others => '0');
signal full_flag,full_next : std_logic := '0';
signal empty_flag,empty_next : std_logic := '0';
signal mode : std_logic_vector(1 downto 0);

begin 

myRam : ram_example generic map(
    DATA_BITS => 16,
    ADDR_BITS => 5
    )
    port map(
    clk => main_clk,
    address => ram_address,
    we => wr,
    re => rd,
    din => dataIn,
    dout => dataOut
    );
    
myCounter : genericCounter generic map(
    upDownCounterSize => 6
    )
    port map(
    clk_a => main_clk,
    upInput => wr,
    downInput => rd,
    
    count => cnt_signal
    );
    
    
process(main_clk)
begin

if( rising_edge(main_clk) ) then
    wr_addr <= wr_addr_next;    --set the addresses and flags to the next state
    rd_addr <= rd_addr_next;
    full_flag <= full_next;
    empty_flag <= empty_next;     
end if;
end process;

wr_addr_succ <= std_logic_vector(unsigned(wr_addr) + 1);
rd_addr_succ <=  std_logic_vector(unsigned(rd_addr) + 1);

mode <= wr & rd;

process(wr_addr,wr_addr_succ,rd_addr,rd_addr_succ,mode,full_flag,empty_flag)
begin

wr_addr_next <= wr_addr;    --set the next address registers to the current register so we stay in the same place until a read or write signal occurs. 
rd_addr_next <= rd_addr;
full_next <= full_flag;
empty_next <= empty_flag;

case mode is
    when "00" => --do nothing
    when "01" => --read
        if(empty_flag /= '1') then  -- if FIFO isn't empty, increment the read address by 1 
            rd_addr <= rd_addr_succ;
            full_next <= '0';
            if(rd_addr_succ = wr_addr) then -- if we read and the read address + 1 equals the write address, set the empty next flag
                empty_next <= '1';
            end if;
        end if;
    when "10" => --write    -- if FIFO isn't full, increment the write address by 1
        if(full_flag /= '1') then  
            wr_addr <= wr_addr_succ;
          
            empty_next <= '0';
            if(wr_addr_succ = rd_addr) then -- if we write and the write address + 1 equals the read address, set the full next flag
                full_next <= '1';
            end if;
        end if;        
    when others => --read and write
        wr_addr_next <= wr_addr_succ;
        rd_addr_next <= rd_addr_succ;
end case;     
end process;


full <= full_flag;
empty <= empty_flag;
dataIn <= data_in;
data_out <= dataOut;
fifo_count <= cnt_signal;
end behavioral;
----------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;  -- Required for type conversions

entity ram_example is 
    generic (
        DATA_BITS: integer := 8;
        ADDR_BITS: integer := 10
    ); 
    port (
        clk     : in  std_logic;
        address : in  std_logic_vector(ADDR_BITS-1 downto 0);
        we      : in  std_logic;
        re      : in  std_logic;
        din     : in  std_logic_vector(DATA_BITS-1 downto 0);
        dout    : out std_logic_vector(DATA_BITS-1 downto 0)
    );
end ram_example;

architecture behavioral of ram_example is

   --declaration of RAM type
   type ram_type is array (0 to 2**ADDR_BITS-1) of std_logic_vector(DATA_BITS-1 downto 0);
   
   --declaration of RAM
   signal ram : ram_type;
   
   begin
   
   --process for read and write operation.
   process(clk) begin
       if(rising_edge(clk)) then
           if(we='1') then
               ram(conv_integer(address)) <= din;
           end if;
           if(re='1') then
           dout <= ram(conv_integer(address));
           end if; 
       end if; 
   end process;

end behavioral;

enter image description here

\$\endgroup\$
2
  • 3
    \$\begingroup\$ I am sorry. I don't see any specific question here. \$\endgroup\$
    – Mitu Raj
    Feb 23, 2022 at 19:23
  • \$\begingroup\$ Sorry for the lack of clarity. I edited my OP to hopefully make it more clear. I'm struggling with how to set the address for the RAM based on the operation and the count of the address counters. I tried mapping the address input to a signal and then writing to that signal to change the address, but that didn't seem valid as the address came back as undetermined. I tried: ram_address <= wr_addr_succ \$\endgroup\$
    – AyyBotto
    Feb 23, 2022 at 19:36

1 Answer 1

1
\$\begingroup\$

HDL is not matching the block diagram.

RAM of block diagram has 2 address ports (one on read side "RD_PTR", other on write side "WR_PTR"); HDL model has one address port (for read/write).

Update your RAM model to be a dual-port RAM.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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