ghdl / ghdl-yosys-plugin

VHDL synthesis (based on ghdl)
GNU General Public License v3.0
304 stars 31 forks source link

Fix to block RAM handling as per https://github.com/YosysHQ/yosys/issues/3364#issuecomment-1148066807 #171

Closed robinsonb5 closed 2 years ago

robinsonb5 commented 2 years ago

I can't claim credit for this fix, but it solves a problem I bumped into when inferring RAM blocks. Details of the problem, and fix, in this Yosys issue: https://github.com/YosysHQ/yosys/issues/3364

Testcase below:

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

package interface is
    constant maxAddrBitBRAMLimit : integer := 32;
    constant minAddrBit : integer := 2;
    constant wordSize : integer := 32;
    type ToROM is record
        memAWriteEnable : std_logic;
        memAAddr : std_logic_vector(maxAddrBitBRAMLimit downto minAddrBit);
        memAWrite : std_logic_vector(wordSize-1 downto 0);
        memBWriteEnable : std_logic;
        memBAddr : std_logic_vector(maxAddrBitBRAMLimit downto minAddrBit);
        memBWrite : std_logic_vector(wordSize-1 downto 0);
    end record;
    type FromROM is record
        memARead : std_logic_vector(wordSize-1 downto 0);
        memBRead : std_logic_vector(wordSize-1 downto 0);
    end record;

end package;

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

library work;
use work.interface.all;

entity BootROM is
generic
    (
        maxAddrBitBRAM : integer := 7
    );
port (
    clk : in std_logic;
    areset : in std_logic := '0';
    from_sys : in ToROM;
    to_sys : out FromROM
);
end entity;

architecture arch of BootROM is

type ram_type is array(natural range 0 to ((2**(maxAddrBitBRAM+1))/4)-1) of std_logic_vector(wordSize-1 downto 0);

shared variable ram : ram_type :=
(
     0 => x"84808080",
     1 => x"8c0b8480",
     2 => x"8081e004",
     3 => x"00848080",
     4 => x"808c04ff",
     5 => x"0d800404",
     6 => x"40000017",
     7 => x"00000000",
     8 => x"0b83ffe0",
     9 => x"80080b83",
    10 => x"ffe08408",
    11 => x"0b83ffe0",
    12 => x"88088480",
    13 => x"80809808",
    14 => x"2d0b83ff",
    15 => x"e0880c0b",
    16 => x"83ffe084",
    17 => x"0c0b83ff",
    18 => x"e0800c04",
    19 => x"00000000",
    20 => x"00000000",
    21 => x"00000000",
    22 => x"00000000",
    23 => x"00000000",
    24 => x"71fd0608",
    25 => x"72830609",
    26 => x"81058205",
    27 => x"832b2a83",
    28 => x"ffff0652",
    29 => x"0471fc06",
    30 => x"08728306",
    31 => x"09810583",
    others => x"00000000"
);

attribute no_rw_check: boolean;
attribute no_rw_check of ram : variable is true;

begin

process (clk)
begin
    if (clk'event and clk = '1') then
        if (from_sys.memAWriteEnable = '1') and (from_sys.memBWriteEnable = '1') and (from_sys.memAAddr=from_sys.memBAddr) and (from_sys.memAWrite/=from_sys.memBWrite) then
            report "write collision" severity failure;
        end if;

        if (from_sys.memAWriteEnable = '1') then
            ram(to_integer(unsigned(from_sys.memAAddr(maxAddrBitBRAM downto 2)))) := from_sys.memAWrite;
            to_sys.memARead <= from_sys.memAWrite;
        else
            to_sys.memARead <= ram(to_integer(unsigned(from_sys.memAAddr(maxAddrBitBRAM downto 2))));
        end if;
    end if;
end process;

process (clk)
begin
    if (clk'event and clk = '1') then
        if (from_sys.memBWriteEnable = '1') then
            ram(to_integer(unsigned(from_sys.memBAddr(maxAddrBitBRAM downto 2)))) := from_sys.memBWrite;
            to_sys.memBRead <= from_sys.memBWrite;
        else
            to_sys.memBRead <= ram(to_integer(unsigned(from_sys.memBAddr(maxAddrBitBRAM downto 2))));
        end if;
    end if;
end process;

end arch;
tgingold commented 2 years ago

Thanks.

tgingold commented 2 years ago

I added a test from your testcase.