Search code examples
vhdlhdlvivado

Array aggregation on self-defined types?


I'm trying to implement an FSM with a RAM behavior. There are multiple addresses of this ram that should be initialized while describing this FSM. So, I'm using the array aggregation technique to initialize the first 20 addresses of the ram_block. However, I'm getting a bad syntax error on each line the aggregation has occurred or the partial section of the ram_block(i) has initialized. Any helps would be appreciated.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;

entity RegisterController is
    port(
        r1_p: inout std_logic_vector(31 downto 0);
        r2_p: inout std_logic_vector(31 downto 0);
        write_p: in std_logic;
        enable_p: in std_logic;
        clk_p: in std_logic;
        ram_rw: in std_logic;                       -- 0 => Read from ram | 1 => Write to the ram
        reset_p: in std_logic
    );
end RegisterController;

architecture RTL of RegisterController is
    -- Create the ram word
    subtype ram_word is std_logic_vector(66 downto 0);

    -- Create the ram block of 32 ram_words
    type ram_block is array (31 downto 0) of ram_word;

    -- Address to read from the ram
    signal R_ADDR_S: std_logic_vector(4 downto 0) := "00000";

begin
    RAM_LOAD: process(clk)
    begin 
        -- We're gonna load the 32 words of this ram with clock first
        -- Outputs are being updated in the runtime :D
        if(rising_edge(clk)) then
            if(ram_rw = '1') then
                -- STATE 0 DESCRIPTION
                ram_block(0) <= ("000", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsgined(0, 32)));
                ram_block(1) <= ("000", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32)));
                ram_block(2) <= ("001", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32)));
                ram_block(3) <= ("001", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32)));

                -- STATE 1 DESCRIPTION
                ram_block(4) <= (66 downto 64) => "001";
                ram_block(5) <= (66 downto 64) => "001";
                ram_block(6) <= ("001", r2_p, r1_p);
                ram_block(7) <= (66 downto 64) => "010";

                -- STATE 2 DESCRIPTION
                ram_block(8) <= (66 downto 64) => "010";
                ram_block(9) <= (66 downto 64) => "010";
                ram_block(10) <= (66 downto 64) => "011";
                ram_block(11) <= (66 downto 64) => "011";

                -- STATE 3 DESCRIPTION
                ram_block(12) <= (66 downto 64) => "011";
                ram_block(13) <= (66 downto 64) => "011";
                ram_block(14) <= (66 downto 64) => "100";
                ram_block(15) <= (66 downto 64) => "100";

                -- STATE 4 DESCRIPTION
                ram_block(16) <= (66 downto 64) => "100";
                ram_block(17) <= (66 downto 64) => "100";
                ram_block(18) <= (66 downto 64) => "001";
                ram_block(19) <= (66 downto 64) => "001";
                ram_block(31 downto 20) <= std_logic_vector(to_unsigned(0, 67));
            end if;
        end if;
    end process;

    START_FSM: process(clk)
        -- TEMPORARY VARIABLE TO STORE THE READ VALUE FROM THE RAM BLOCK
        variable temp_read_ram: std_logic_vector(66 downto 0);
        variable temp_read_ram2: std_logic_vector(66 downto 0);
        -- R3 Declaration as a variable 
        variable R3_V: std_logic_vector(31 downto 0);
    begin 
        if(rising_edge(clk)) then
            if(ram_rw = '0') then
                -- START READING THE RAM FROM ADDRESS 0
                temp_read_ram := ram_block(to_integer(unsigned(R_ADDR_S)));
                R_ADDR_S(4 downto 2) <= temp_read_ram(66 downto 64);
                R_ADDR_S(1 downto 0) <= (enable_p, write_p);

                -- UPDATE THE OUTPUTS
                if(R_ADDR_S = "00110") then
                    -- READ THE PREVIOUS VALUE IN THAT ADDRESS
                    temp_read_ram2 <= ram_block(R_ADDR_S);
                    -- UPDATE THE OUTPUT VALUES INSIDE RAM
                    ram_block(R_ADDR_S) <= (temp_read_ram2(66 downto 64), r2_p, r1_p);
                    -- NO NEED TO UPDATE r2_p and r1_p
                elsif(R_ADDR_S = "00111") then
                    -- PUT THE CURRENT VALUE OF R1 TO THE R3
                    temp_read_ram2 <= ram_block(R_ADDR_S);
                    -- SAVE R1 TO THE R3_V
                    R3_V := temp_read_ram2(31 downto 0);

                elsif(R_ADDR_S = "01110" or R_ADDR_S = "01111") then
                    -- READ THE PREVIOUS VALIE IN THOSE ADDRESSES
                    temp_read_ram2 <= ram_block(R_ADDR_S);
                    -- UPDATE THE OUTPUT VALUE OF R2 INSIDE RAM
                    ram_block(R_ADDR_S) <= (temp_read_ram2(66 downto 64), R3_V, temp_read_ram2(31 downto 0)); 
                    -- UPDATE THE OUTPUT VALUE OF r2_p
                    r2_p <= R3_V;
               else
               else
                    -- NO CHANGE
                    ram_block(R_ADDR_S) <= ram_block(R_ADDR_S);
               end if;
           end if;
       end if;
   end process;       
end RTL;

Solution

  • There's not one, but many syntax errors in your code.

    First off, ram_block is a type, not a signal. So why are you assigning values to it? You need to declare a signal first. I.e.

    -- Create the ram block of 32 ram_words
    type ram_block_type is array (31 downto 0) of ram_word;
    signal ram_block : ram_block_type := (others => (others => '0'));
    

    ^ what I also include here, is initialization of the signal. Same can be done for:

    signal R_ADDR_S: std_logic_vector(4 downto 0) := (others => '0');
    

    In the process, you are assigning values to many locations in the RAM at the same time! That is not RAM-like. A random access memory usually only has 1 or 2 ports, accessing 1 resp. 2 elements at a time. You are designing generic distributed memory, so imho should not call it RAM.

    Assigning to part of the array has a specific syntax. You can either assign the whole matrix in one go (this is VHDL-2008 by the way):

    ram_block <= (4 => (66 downto 64 => "001", others => '0'), others => '0');
    

    Note: you need to assign all values here, hence the others statement. Second option, assign one sub-array

    ram_block(4) <= (66 downto 64 => "001", others => '0');
    

    Finally, and probably what you want, assign a specific sub-set of a sub-array:

    ram_block(4)(66 downto 64) <= "001";
    

    But in this case, you want to initialize the array, as else unassigned std_logic's will have the default value 'U'.

    Then:

    ram_block(31 downto 20) <= std_logic_vector(to_unsigned(0, 67));
    

    This will not work. You're assigning an array structure to an array-of-arrays.

    Variable R3_V is assigned in one situation, but not used directly: It is used a different clock cycle. In that case do not use a variable: that is bad coding style. It should be a signal.

    And you must remember that signals assigned in a clocked process will not have access to their new value until the next delta cycle. Thus the assignment of signal R_ADDR_S(4 downto 2) <= temp_read_ram(66 downto 64); will not be available for the following if-statements!

    Other things:

    • clk should probably be clk_p
    • to_unsgined -> to_unsigned
    • in line 79 you use the correct ram_block(to_integer(unsigned(R_ADDR_S))), but later (line 86) you do it wrong ram_block(R_ADDR_S)
    • in line 79 you also correctly assign a variable using :=, but later (line 86 again) you use the incorrect <=.
    • there's a double else at the end of the code.