library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use std.textio.all; library work; use work.utils.all; use work.wishbone_types.all; --- verilator access TODO --! @brief Simple memory module for use in Wishbone-based systems. entity wishbone_bram_wrapper is generic( MEMORY_SIZE : natural := 4096; --! Memory size in bytes. RAM_INIT_FILE : string; SIM_MAIN_BRAM : boolean := false ); port( clk : in std_logic; rst : in std_logic; -- Wishbone interface: wishbone_in : in wishbone_master_out; wishbone_out : out wishbone_slave_out; -- BRAM verilator access bram_we : out std_ulogic; bram_re : out std_ulogic; bram_addr : out std_logic_vector(log2ceil(MEMORY_SIZE) - 3- 1 downto 0); bram_di : out std_logic_vector(63 downto 0); bram_do : in std_logic_vector(63 downto 0); bram_sel : out std_logic_vector(7 downto 0) ); end entity wishbone_bram_wrapper; architecture behaviour of wishbone_bram_wrapper is constant ram_addr_bits : integer := log2ceil(MEMORY_SIZE) - 3; -- RAM interface signal ram_addr : std_logic_vector(ram_addr_bits - 1 downto 0); signal ram_we : std_ulogic; signal ram_re : std_ulogic; -- Others signal ack, ack_buf : std_ulogic; begin -- Actual RAM template sim_ram: if SIM_MAIN_BRAM = true generate ram_0: entity work.main_bram generic map( WIDTH => 64, HEIGHT_BITS => ram_addr_bits, MEMORY_SIZE => MEMORY_SIZE, RAM_INIT_FILE => RAM_INIT_FILE ) port map( clk => clk, addr => ram_addr, din => wishbone_in.dat, dout => wishbone_out.dat, sel => wishbone_in.sel, re => ram_re, we => ram_we ); end generate; -- Verilator access to bram signals bram_sel <= wishbone_in.sel; wishbone_out.dat <= bram_do; bram_di <= wishbone_in.dat; bram_addr <= ram_addr; bram_we <= ram_we; bram_re <= ram_re; -- Wishbone interface ram_addr <= wishbone_in.adr(ram_addr_bits - 1 downto 0); -- not that a wishbone compliant version of libre-soc is needed ram_we <= wishbone_in.stb and wishbone_in.cyc and wishbone_in.we; ram_re <= wishbone_in.stb and wishbone_in.cyc and not wishbone_in.we; wishbone_out.stall <= '0'; wishbone_out.ack <= ack_buf; wb_0: process(clk) begin if rising_edge(clk) then if rst = '1' or wishbone_in.cyc = '0' then ack_buf <= '0'; ack <= '0'; else -- On loads, we have a delay cycle due to BRAM bufferring -- but not on stores. So try to send an early ack on a -- store if we aren't behind an existing load ack. -- if ram_we = '1' and ack = '0' then ack_buf <= '1'; else ack <= wishbone_in.stb; ack_buf <= ack; end if; end if; end if; end process; end architecture behaviour;