Search code examples
memoryvhdl

VHDL efficient and correct memory assignment


I'm trying to generate a memory for on FPGA, but I'm having some questions related to how I should approach the stored data. When I'd like to update data, do I need to use a new_q1 signal or not? (like I tried to apply in my code (version 1 and 3)). I was told that I need a new q1 signal (I don't exactly know why) and that I always should have an 'else' statement to prevent 'don't cares'.

Version 1 is the version with a new q1 signal, however, there is no initial value for new_q1. Version 2 is the version I actually started with but I received a comment that this is not the correct approach for some reason I don't quite understand.

Version 3 is the version that is fully working like it was explained to me, however, in my opinion, it is way too much and the synthesizer is rejecting my new_q1 constructions.

What version should I go with and can somembody clarify that what I'm being told is correct or not and why?

Version 1:

entity memory is
   port(
    clk : in std_logic;
    reset : in std_logic;
    selector : in std_logic_vector(5 downto 0);
    write : in std_logic;
    value : out std_logic
    );
end memory;


architecture behaviour of memory is
    signal q1, new_q1 : std_logic_vector(63 downto 0);
begin
    process(clk, reset) is
        begin
        if( clk'event AND clk = '1') then
            if(reset = '1') then
                q1 <= (others => '0');
            else
                q1 <= new_q1;
            end if;
        end if;
    end process;
    process(q1) is
        if(write = '1') then
            new_q1(to_integer(unsigned(selector)) <= '1';
        else
            new_q1 <= q1;
        end if;
    end process;
    value <= q1(to_integer(unsigned(selector));
end behaviour;

Version 2:

entity memory is
   port(
    clk : in std_logic;
    reset : in std_logic;
    selector : in std_logic_vector(5 downto 0);
    write : in std_logic;
    value : out std_logic
    );
end memory;

architecture behaviour of memory is
    signal q1 : std_logic_vector(63 downto 0);
begin
    process(clk, reset) is
        begin
        if( clk'event AND clk = '1') then
            if(reset = '1') then
                q1 <= (others => '0');
            else
                if(write = '1') then
                    q1(to_integer(unsigned(selector)) <= '1';
                else
                    ....
                end if;
            end if;
        end if;
    end process;

    value <= q1(to_integer(unsigned(selector));
end behaviour;

Version 3:

entity memory is
   port(
    clk : in std_logic;
    reset : in std_logic;
    selector : in std_logic_vector(5 downto 0);
    write : in std_logic;
    value : out std_logic
    );
end memory;

architecture behaviour of memory is
    signal q1 : std_logic_vector(63 downto 0);
begin
    process(clk, reset) is
        begin
        if( clk'event AND clk = '1') then
            if(reset = '1') then
                q1 <= (others => '0');
            else
                q1 <= new_q1;   

            end if;
        end if;
    end process;

    process(q1, write) is
        if(write = '1') then
            if(unsigned(selector) < 63) then
                new_q1 <= q1(63 downto to_integer(unsigned(selector))) & '1' & q1(to_integer(unsigned(selector)) downto 0);
            else
                new_q1 <= '1' & q1(to_integer(unsigned(selector)) downto 0);
            end if;
        else
            new_q1 <= q1;
        end if;
    end process;

    value <= q1(to_integer(unsigned(selector));
end behaviour;

Solution

  • Based on some assumptions about operation, as noted in the port list, a design may look like below. Implementation in a FPGA is likely to be made using flip-flops, and not internal memories, due to size and the special function, so the name memory may be misleading through.

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity memory is
      port(
        clk      : in std_logic;
        reset    : in std_logic;  -- Synchronous, assumed to be applied initially
        selector : in std_logic_vector(5 downto 0);
        write    : in std_logic;  -- Write set bit only, synchronous
        value    : out std_logic  -- Read value, asynchronous
        );
    end memory;
    
    architecture behaviour of memory is
      signal q1 : std_logic_vector(63 downto 0);
    begin
    
      -- Reset and write set, synchronous
      process (clk) is
      begin
        if (clk'event and clk = '1') then  -- Rising clock
          if (reset = '1') then  -- Reset, synchronous
            q1 <= (others => '0');  -- Clear all bits
          elsif (write = '1') then  -- Write to set for selector bit
            q1(to_integer(unsigned(selector))) <= '1';  -- Set single bit
          end if;
        end if;
      end process;
    
      -- Read, asynchronous
      value <= q1(to_integer(unsigned(selector)));  -- Read single bit
    
    end behaviour;