Search code examples
vhdl

Small change in VHDL register file results in huge difference in total logical elements


I am new to VHDL and one of my assignments was to create an 8-bit register file. I noticed that by changing a single line of code, I could significantly increase or decrease the total number of logical elements. I am trying to understand why this causes such a significant change.

When enable is high, the register file stores the value of dataIn in the location of selectWrite. dataOut displays the value stored in the location of selectRead.

If dataOut <= entry(readIndex); is placed inside of process(clock), the total number of logical elements used is:

Total logical elements: 9/33,216 ( < 1% )
    Total combinatorial functions 9/33,216 ( < 1% )
    Dedicated logic registers 0/33,216 ( 0% )

However, if dataOut <= entry(readIndex); is placed outside of process(clock) thousands more logical elements are used:

Total logical elements: 2,672/33,216 ( 8% )
    Total combinatorial functions 1,656/33,216 ( 5% )
    Dedicated logic registers 2,048/33,216 ( 6% )

I understand that when placed inside of process(clock), dataOut will only change on the clock edge, and when placed outside of process(clock), dataOut will change unpredictably.

Why does this change cause so many more logic elements to be used?

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

entity RegisterFile is
port(
    clock  : in std_logic;
    reset  : in std_logic;
    dataIn : in std_logic_vector(7 downto 0);
    enable : in std_logic;
    selectRead  : in std_logic_vector(7 downto 0);
    selectWrite : in std_logic_vector(7 downto 0);

    dataOut : out std_logic_vector(7 downto 0)
);
end RegisterFile;

architecture RegisterFileArchitecture of RegisterFile is
    type RegisterEntry is array (0 to 255) of std_logic_vector(7 downto 0);
    signal entry : RegisterEntry;
    signal readIndex  : integer;
    signal writeIndex : integer;
begin
    -- Update read/write indices
    readIndex <= to_integer(unsigned(selectRead));
    writeIndex <= to_integer(unsigned(selectWrite));

    process(clock)
    begin
        if (rising_edge(clock)) then
            -- Update selected data
            dataOut <= entry(readIndex);    

            if (reset = '1') then
                entry(writeIndex) <= "00000000";
            elsif (enable = '1') then
                entry(writeIndex) <= dataIn;
            end if; 
        end if;
    end process;
end RegisterFileArchitecture;

Solution

  • You need to study the FPGA architecture you are using. When you have a large memory to implement, you most likely want to use the devices dedicated RAM blocks, called Block RAM in Xilinx. Block RAM has a specific structure - especially with respect to reading and writing with a clock edge vs Asynchronously (combinationaly). If your code matches it, it will use the Block RAM and very little other logic. If your code does not match a Block RAM, then you will use logic cells instead.

    Look at your report further and see what it reports in each case about block RAM usage. Look at Xilinx's documentation about the structure of Block RAM.