From 8e0389b9736c60572e13ef5eeb50d3a775c3ffc6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 23 Oct 2019 12:08:55 +1100 Subject: [PATCH] ram: Rework main RAM interface This replaces the simple_ram_behavioural and mw_soc_memory modules with a common wishbone_bram_wrapper.vhdl that interfaces the pipelined WB with a lower-level RAM module, along with an FPGA and a sim variants of the latter. Signed-off-by: Benjamin Herrenschmidt --- Makefile | 32 +-- README.md | 2 +- core_tb.vhdl | 2 +- dcache_tb.vhdl | 10 +- dmi_dtm_tb.vhdl | 4 +- fpga/main_bram.vhdl | 83 ++++++ fpga/mw_soc_memory.vhdl | 112 -------- icache_tb.vhdl | 34 ++- microwatt.core | 6 +- scripts/run_test.sh | 2 +- scripts/test_micropython.py | 2 +- scripts/test_micropython_long.py | 2 +- sim_bram.vhdl | 67 +++++ ...ural_helpers.vhdl => sim_bram_helpers.vhdl | 12 +- ...ioural_helpers_c.c => sim_bram_helpers_c.c | 0 simple_ram_behavioural.vhdl | 133 ---------- simple_ram_behavioural_tb.vhdl | 246 ------------------ soc.vhdl | 2 +- ...behavioural_tb.bin => wishbone_bram_tb.bin | Bin wishbone_bram_tb.vhdl | 175 +++++++++++++ wishbone_bram_wrapper.vhdl | 76 ++++++ 21 files changed, 462 insertions(+), 540 deletions(-) create mode 100644 fpga/main_bram.vhdl delete mode 100644 fpga/mw_soc_memory.vhdl create mode 100644 sim_bram.vhdl rename simple_ram_behavioural_helpers.vhdl => sim_bram_helpers.vhdl (84%) rename simple_ram_behavioural_helpers_c.c => sim_bram_helpers_c.c (100%) delete mode 100644 simple_ram_behavioural.vhdl delete mode 100644 simple_ram_behavioural_tb.vhdl rename simple_ram_behavioural_tb.bin => wishbone_bram_tb.bin (100%) create mode 100644 wishbone_bram_tb.vhdl create mode 100644 wishbone_bram_wrapper.vhdl diff --git a/Makefile b/Makefile index 1c68ff4..85a0262 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ GHDL=ghdl GHDLFLAGS=--std=08 -Psim-unisim CFLAGS=-O2 -Wall -all = core_tb simple_ram_behavioural_tb soc_reset_tb icache_tb dcache_tb multiply_tb dmi_dtm_tb divider_tb \ - rotator_tb countzero_tb +all = core_tb soc_reset_tb icache_tb dcache_tb multiply_tb dmi_dtm_tb divider_tb \ + rotator_tb countzero_tb wishbone_bram_tb # XXX # loadstore_tb fetch_tb @@ -35,11 +35,14 @@ helpers.o: cache_ram.o: plru.o: plru_tb.o: plru.o -icache_tb.o: common.o wishbone_types.o icache.o simple_ram_behavioural.o -dcache_tb.o: common.o wishbone_types.o dcache.o simple_ram_behavioural.o utils.o: +sim_bram.o: sim_bram_helpers.o utils.o +wishbone_bram_wrapper.o: wishbone_types.o sim_bram.o utils.o +wishbone_bram_tb.o: wishbone_bram_wrapper.o icache.o: utils.o common.o wishbone_types.o plru.o cache_ram.o utils.o +icache_tb.o: common.o wishbone_types.o icache.o wishbone_bram_wrapper.o dcache.o: utils.o common.o wishbone_types.o plru.o cache_ram.o utils.o +dcache_tb.o: common.o wishbone_types.o dcache.o wishbone_bram_wrapper.o insn_helpers.o: loadstore1.o: common.o helpers.o logical.o: decode_types.o @@ -52,11 +55,8 @@ register_file.o: common.o rotator.o: common.o rotator_tb.o: common.o glibc_random.o ppc_fx_insns.o insn_helpers.o rotator.o sim_console.o: -simple_ram_behavioural_helpers.o: -simple_ram_behavioural_tb.o: wishbone_types.o simple_ram_behavioural.o -simple_ram_behavioural.o: wishbone_types.o simple_ram_behavioural_helpers.o sim_uart.o: wishbone_types.o sim_console.o -soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o simple_ram_behavioural.o dmi_dtm_xilinx.o wishbone_debug_master.o +soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o wishbone_bram_wrapper.o dmi_dtm_xilinx.o wishbone_debug_master.o wishbone_arbiter.o: wishbone_types.o wishbone_types.o: writeback.o: common.o crhelpers.o @@ -74,17 +74,17 @@ fpga/soc_reset_tb.o: fpga/soc_reset.o soc_reset_tb: fpga/soc_reset_tb.o fpga/soc_reset.o $(GHDL) -e $(GHDLFLAGS) soc_reset_tb -core_tb: core_tb.o simple_ram_behavioural_helpers_c.o sim_console_c.o sim_jtag_socket_c.o - $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o -Wl,sim_console_c.o -Wl,sim_jtag_socket_c.o $@ +core_tb: core_tb.o sim_bram_helpers_c.o sim_console_c.o sim_jtag_socket_c.o + $(GHDL) -e $(GHDLFLAGS) -Wl,sim_bram_helpers_c.o -Wl,sim_console_c.o -Wl,sim_jtag_socket_c.o $@ fetch_tb: fetch_tb.o $(GHDL) -e $(GHDLFLAGS) $@ icache_tb: icache_tb.o - $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@ + $(GHDL) -e $(GHDLFLAGS) -Wl,sim_bram_helpers_c.o $@ dcache_tb: dcache_tb.o - $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@ + $(GHDL) -e $(GHDLFLAGS) -Wl,sim_bram_helpers_c.o $@ plru_tb: plru_tb.o $(GHDL) -e $(GHDLFLAGS) $@ @@ -107,11 +107,11 @@ countzero_tb: countzero_tb.o simple_ram_tb: simple_ram_tb.o $(GHDL) -e $(GHDLFLAGS) $@ -simple_ram_behavioural_tb: simple_ram_behavioural_helpers_c.o simple_ram_behavioural_tb.o - $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@ +wishbone_bram_tb: sim_bram_helpers_c.o wishbone_bram_tb.o + $(GHDL) -e $(GHDLFLAGS) -Wl,sim_bram_helpers_c.o $@ -dmi_dtm_tb: dmi_dtm_tb.o simple_ram_behavioural_helpers_c.o - $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@ +dmi_dtm_tb: dmi_dtm_tb.o sim_bram_helpers_c.o + $(GHDL) -e $(GHDLFLAGS) -Wl,sim_bram_helpers_c.o $@ tests = $(sort $(patsubst tests/%.out,%,$(wildcard tests/*.out))) diff --git a/README.md b/README.md index 86e9e22..7c6bc11 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ make - Link in the micropython image: ``` -ln -s ../micropython/ports/powerpc/build/firmware.bin simple_ram_behavioural.bin +ln -s ../micropython/ports/powerpc/build/firmware.bin main_ram.bin ``` - Now run microwatt, sending debug output to /dev/null: diff --git a/core_tb.vhdl b/core_tb.vhdl index 672b424..90fc30c 100644 --- a/core_tb.vhdl +++ b/core_tb.vhdl @@ -20,7 +20,7 @@ begin generic map( SIM => true, MEMORY_SIZE => 524288, - RAM_INIT_FILE => "simple_ram_behavioural.bin", + RAM_INIT_FILE => "main_ram.bin", RESET_LOW => false ) port map( diff --git a/dcache_tb.vhdl b/dcache_tb.vhdl index 0edbdb7..437fd7d 100644 --- a/dcache_tb.vhdl +++ b/dcache_tb.vhdl @@ -35,9 +35,9 @@ begin ); -- BRAM Memory slave - bram0: entity work.mw_soc_memory + bram0: entity work.wishbone_bram_wrapper generic map( - MEMORY_SIZE => 128, + MEMORY_SIZE => 1024, RAM_INIT_FILE => "icache_test.bin" ) port map( @@ -121,7 +121,6 @@ begin d_in.valid <= '1'; wait until rising_edge(clk); d_in.valid <= '0'; - wait until rising_edge(clk) and d_out.write_enable = '1'; assert d_out.valid = '1'; assert d_out.write_data = x"0000004100000040" @@ -130,7 +129,10 @@ begin " expected 0000004100000040" severity failure; - wait for clk_period*4; + wait until rising_edge(clk); + wait until rising_edge(clk); + wait until rising_edge(clk); + wait until rising_edge(clk); assert false report "end of test" severity failure; wait; diff --git a/dmi_dtm_tb.vhdl b/dmi_dtm_tb.vhdl index fe60c12..0694266 100644 --- a/dmi_dtm_tb.vhdl +++ b/dmi_dtm_tb.vhdl @@ -50,8 +50,8 @@ begin dmi_ack => dmi_ack ); - simple_ram_0: entity work.mw_soc_memory - generic map(RAM_INIT_FILE => "simple_ram_behavioural.bin", + simple_ram_0: entity work.wishbone_bram_wrapper + generic map(RAM_INIT_FILE => "main_ram.bin", MEMORY_SIZE => 524288) port map(clk => clk, rst => rst, wishbone_in => wishbone_ram_out, diff --git a/fpga/main_bram.vhdl b/fpga/main_bram.vhdl new file mode 100644 index 0000000..810d60c --- /dev/null +++ b/fpga/main_bram.vhdl @@ -0,0 +1,83 @@ +-- Single port Block RAM with one cycle output buffer + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use std.textio.all; + +library work; + +entity main_bram is + generic( + WIDTH : natural := 64; + HEIGHT_BITS : natural := 1024; + MEMORY_SIZE : natural := 65536; + RAM_INIT_FILE : string + ); + port( + clk : in std_logic; + addr : in std_logic_vector(HEIGHT_BITS - 1 downto 0) ; + di : in std_logic_vector(WIDTH-1 downto 0); + do : out std_logic_vector(WIDTH-1 downto 0); + sel : in std_logic_vector((WIDTH/8)-1 downto 0); + re : in std_ulogic; + we : in std_ulogic + ); +end entity main_bram; + +architecture behaviour of main_bram is + + constant WIDTH_BYTES : natural := WIDTH / 8; + + -- RAM type definition + type ram_t is array(0 to (MEMORY_SIZE / WIDTH_BYTES) - 1) of std_logic_vector(WIDTH-1 downto 0); + + -- RAM loading + impure function init_ram(name : STRING) return ram_t is + file ram_file : text open read_mode is name; + variable ram_line : line; + variable temp_word : std_logic_vector(WIDTH-1 downto 0); + variable temp_ram : ram_t := (others => (others => '0')); + begin + for i in 0 to (MEMORY_SIZE / WIDTH_BYTES) - 1 loop + exit when endfile(ram_file); + readline(ram_file, ram_line); + hread(ram_line, temp_word); + temp_ram(i) := temp_word; + end loop; + + return temp_ram; + end function; + + -- RAM instance + signal memory : ram_t := init_ram(RAM_INIT_FILE); + attribute ram_style : string; + attribute ram_style of memory : signal is "block"; + attribute ram_decomp : string; + attribute ram_decomp of memory : signal is "power"; + + -- Others + signal obuf : std_logic_vector(WIDTH-1 downto 0); +begin + + -- Actual RAM template + memory_0: process(clk) + begin + if rising_edge(clk) then + if we = '1' then + for i in 0 to 7 loop + if sel(i) = '1' then + memory(conv_integer(addr))((i + 1) * 8 - 1 downto i * 8) <= + di((i + 1) * 8 - 1 downto i * 8); + end if; + end loop; + end if; + if re = '1' then + obuf <= memory(conv_integer(addr)); + end if; + do <= obuf; + end if; + end process; + +end architecture behaviour; diff --git a/fpga/mw_soc_memory.vhdl b/fpga/mw_soc_memory.vhdl deleted file mode 100644 index 7e998b2..0000000 --- a/fpga/mw_soc_memory.vhdl +++ /dev/null @@ -1,112 +0,0 @@ --- Based on: --- The Potato Processor - A simple processor for FPGAs --- (c) Kristian Klomsten Skordal 2014 - 2015 - -library ieee; -use ieee.std_logic_1164.all; -use ieee.std_logic_unsigned.all; -use ieee.numeric_std.all; -use std.textio.all; - -library work; -use work.wishbone_types.all; - -use work.pp_utilities.all; - ---! @brief Simple memory module for use in Wishbone-based systems. -entity mw_soc_memory is - generic( - MEMORY_SIZE : natural := 4096; --! Memory size in bytes. - RAM_INIT_FILE : string - ); - port( - clk : in std_logic; - rst : in std_logic; - - -- Wishbone interface: - wishbone_in : in wishbone_master_out; - wishbone_out : out wishbone_slave_out - ); -end entity mw_soc_memory; - -architecture behaviour of mw_soc_memory is - -- RAM type definition - type ram_t is array(0 to (MEMORY_SIZE / 8) - 1) of std_logic_vector(63 downto 0); - - -- RAM loading - impure function init_ram(name : STRING) return ram_t is - file ram_file : text open read_mode is name; - variable ram_line : line; - variable temp_word : std_logic_vector(63 downto 0); - variable temp_ram : ram_t := (others => (others => '0')); - begin - for i in 0 to (MEMORY_SIZE/8)-1 loop - exit when endfile(ram_file); - readline(ram_file, ram_line); - hread(ram_line, temp_word); - temp_ram(i) := temp_word; - end loop; - - return temp_ram; - end function; - - -- RAM instance - signal memory : ram_t := init_ram(RAM_INIT_FILE); - attribute ram_style : string; - attribute ram_style of memory : signal is "block"; - attribute ram_decomp : string; - attribute ram_decomp of memory : signal is "power"; - - -- RAM interface - constant ram_addr_bits : integer := log2(MEMORY_SIZE) - 3; - signal ram_addr : std_logic_vector(ram_addr_bits - 1 downto 0); - signal ram_di : std_logic_vector(63 downto 0); - signal ram_do : std_logic_vector(63 downto 0); - signal ram_sel : std_logic_vector(7 downto 0); - signal ram_we : std_ulogic; - - -- Others - signal ram_obuf : std_logic_vector(63 downto 0); - signal ack, ack_obuf : std_ulogic; -begin - - -- Actual RAM template - memory_0: process(clk) - begin - if rising_edge(clk) then - if ram_we = '1' then - for i in 0 to 7 loop - if ram_sel(i) = '1' then - memory(conv_integer(ram_addr))((i + 1) * 8 - 1 downto i * 8) <= - ram_di((i + 1) * 8 - 1 downto i * 8); - end if; - end loop; - end if; - ram_do <= memory(conv_integer(ram_addr)); - ram_obuf <= ram_do; - end if; - end process; - - -- Wishbone interface - ram_addr <= wishbone_in.adr(ram_addr_bits + 2 downto 3); - ram_di <= wishbone_in.dat; - ram_sel <= wishbone_in.sel; - ram_we <= wishbone_in.we and wishbone_in.stb and wishbone_in.cyc; - wishbone_out.stall <= '0'; - wishbone_out.ack <= ack_obuf; - wishbone_out.dat <= ram_obuf; - - wb_0: process(clk) - begin - if rising_edge(clk) then - if rst = '1' or wishbone_in.cyc = '0' then - ack_obuf <= '0'; - ack <= '0'; - else - ack <= wishbone_in.stb; - ack_obuf <= ack; - end if; - end if; - end process; - -end architecture behaviour; diff --git a/icache_tb.vhdl b/icache_tb.vhdl index a50cabe..ea5cf3a 100644 --- a/icache_tb.vhdl +++ b/icache_tb.vhdl @@ -36,9 +36,9 @@ begin ); -- BRAM Memory slave - bram0: entity work.mw_soc_memory + bram0: entity work.wishbone_bram_wrapper generic map( - MEMORY_SIZE => 128, + MEMORY_SIZE => 1024, RAM_INIT_FILE => "icache_test.bin" ) port map( @@ -70,14 +70,18 @@ begin i_out.nia <= (others => '0'); i_out.stop_mark <= '0'; - wait for 4*clk_period; + wait until rising_edge(clk); + wait until rising_edge(clk); + wait until rising_edge(clk); + wait until rising_edge(clk); i_out.req <= '1'; i_out.nia <= x"0000000000000004"; wait for 30*clk_period; + wait until rising_edge(clk); - assert i_in.valid = '1'; + assert i_in.valid = '1' severity failure; assert i_in.insn = x"00000001" report "insn @" & to_hstring(i_out.nia) & "=" & to_hstring(i_in.insn) & @@ -86,27 +90,29 @@ begin i_out.req <= '0'; - wait for clk_period; + wait until rising_edge(clk); -- hit i_out.req <= '1'; i_out.nia <= x"0000000000000008"; - wait for clk_period; - assert i_in.valid = '1'; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert i_in.valid = '1' severity failure; assert i_in.insn = x"00000002" report "insn @" & to_hstring(i_out.nia) & "=" & to_hstring(i_in.insn) & " expected 00000002" severity failure; - wait for clk_period; + wait until rising_edge(clk); -- another miss i_out.req <= '1'; i_out.nia <= x"0000000000000040"; wait for 30*clk_period; + wait until rising_edge(clk); - assert i_in.valid = '1'; + assert i_in.valid = '1' severity failure; assert i_in.insn = x"00000010" report "insn @" & to_hstring(i_out.nia) & "=" & to_hstring(i_in.insn) & @@ -116,13 +122,15 @@ begin -- test something that aliases i_out.req <= '1'; i_out.nia <= x"0000000000000100"; - wait for clk_period; - assert i_in.valid = '0'; - wait for clk_period; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert i_in.valid = '0' severity failure; + wait until rising_edge(clk); wait for 30*clk_period; + wait until rising_edge(clk); - assert i_in.valid = '1'; + assert i_in.valid = '1' severity failure; assert i_in.insn = x"00000040" report "insn @" & to_hstring(i_out.nia) & "=" & to_hstring(i_in.insn) & diff --git a/microwatt.core b/microwatt.core index 35ada86..ee48376 100644 --- a/microwatt.core +++ b/microwatt.core @@ -36,20 +36,22 @@ filesets: - plru.vhdl - cache_ram.vhdl - core_debug.vhdl + - utils.vhdl file_type : vhdlSource-2008 soc: files: - wishbone_arbiter.vhdl - wishbone_debug_master.vhdl + - wishbone_bram_wrapper.vhdl - soc.vhdl file_type : vhdlSource-2008 fpga: files: - - fpga/pp_fifo.vhd - - fpga/mw_soc_memory.vhdl + - fpga/main_bram.vhdl - fpga/soc_reset.vhdl + - fpga/pp_fifo.vhd - fpga/pp_soc_uart.vhd - fpga/pp_utilities.vhd - fpga/toplevel.vhdl diff --git a/scripts/run_test.sh b/scripts/run_test.sh index b6f2ee6..ef737fe 100755 --- a/scripts/run_test.sh +++ b/scripts/run_test.sh @@ -21,7 +21,7 @@ Y=$(${MICROWATT_DIR}/scripts/hash.py tests/${TEST}.out) cd $TMPDIR -cp ${MICROWATT_DIR}/tests/${TEST}.bin simple_ram_behavioural.bin +cp ${MICROWATT_DIR}/tests/${TEST}.bin main_ram.bin X=$( ${MICROWATT_DIR}/core_tb | ${MICROWATT_DIR}/scripts/hash.py ) diff --git a/scripts/test_micropython.py b/scripts/test_micropython.py index d7ffb2d..edc076f 100755 --- a/scripts/test_micropython.py +++ b/scripts/test_micropython.py @@ -13,7 +13,7 @@ cwd = os.getcwd() os.chdir(tempdir.name) copyfile(os.path.join(cwd, 'tests/micropython.bin'), - os.path.join(tempdir.name, 'simple_ram_behavioural.bin')) + os.path.join(tempdir.name, 'main_ram.bin')) cmd = [ os.path.join(cwd, './core_tb') ] diff --git a/scripts/test_micropython_long.py b/scripts/test_micropython_long.py index 805c6b2..6dea3a4 100755 --- a/scripts/test_micropython_long.py +++ b/scripts/test_micropython_long.py @@ -13,7 +13,7 @@ cwd = os.getcwd() os.chdir(tempdir.name) copyfile(os.path.join(cwd, 'tests/micropython.bin'), - os.path.join(tempdir.name, 'simple_ram_behavioural.bin')) + os.path.join(tempdir.name, 'main_ram.bin')) cmd = [ os.path.join(cwd, './core_tb') ] diff --git a/sim_bram.vhdl b/sim_bram.vhdl new file mode 100644 index 0000000..d2d4f1b --- /dev/null +++ b/sim_bram.vhdl @@ -0,0 +1,67 @@ +-- Single port Block RAM with one cycle output buffer +-- +-- Simulated via C helpers + +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.sim_bram_helpers.all; + +entity main_bram is + generic( + WIDTH : natural := 64; + HEIGHT_BITS : natural := 1024; + MEMORY_SIZE : natural := 65536; + RAM_INIT_FILE : string + ); + port( + clk : in std_logic; + addr : in std_logic_vector(HEIGHT_BITS - 1 downto 0) ; + di : in std_logic_vector(WIDTH-1 downto 0); + do : out std_logic_vector(WIDTH-1 downto 0); + sel : in std_logic_vector((WIDTH/8)-1 downto 0); + re : in std_ulogic; + we : in std_ulogic + ); +end entity main_bram; + +architecture sim of main_bram is + + constant WIDTH_BYTES : natural := WIDTH / 8; + constant pad_zeros : std_ulogic_vector(log2(WIDTH_BYTES)-1 downto 0) + := (others => '0'); + + signal identifier : integer := behavioural_initialize(filename => RAM_INIT_FILE, + size => MEMORY_SIZE); + -- Others + signal obuf : std_logic_vector(WIDTH-1 downto 0); +begin + + -- Actual RAM template + memory_0: process(clk) + variable ret_dat_v : std_ulogic_vector(63 downto 0); + variable addr64 : std_ulogic_vector(63 downto 0); + begin + if rising_edge(clk) then + addr64 := (others => '0'); + addr64(HEIGHT_BITS + 2 downto 3) := addr; + if we = '1' then + report "RAM writing " & to_hstring(di) & " to " & + to_hstring(addr & pad_zeros) & " sel:" & to_hstring(sel); + behavioural_write(di, addr64, to_integer(unsigned(sel)), identifier); + end if; + if re = '1' then + behavioural_read(ret_dat_v, addr64, to_integer(unsigned(sel)), identifier); + report "RAM reading from " & to_hstring(addr & pad_zeros) & + " returns " & to_hstring(ret_dat_v); + obuf <= ret_dat_v(obuf'left downto 0); + end if; + do <= obuf; + end if; + end process; + +end architecture sim; diff --git a/simple_ram_behavioural_helpers.vhdl b/sim_bram_helpers.vhdl similarity index 84% rename from simple_ram_behavioural_helpers.vhdl rename to sim_bram_helpers.vhdl index 507594f..c511a6e 100644 --- a/simple_ram_behavioural_helpers.vhdl +++ b/sim_bram_helpers.vhdl @@ -1,24 +1,24 @@ library ieee; use ieee.std_logic_1164.all; -package simple_ram_behavioural_helpers is +package sim_bram_helpers is function behavioural_initialize (filename: String; size: integer) return integer; attribute foreign of behavioural_initialize : function is "VHPIDIRECT behavioural_initialize"; - procedure behavioural_read (val: out std_ulogic_vector(63 downto 0); addr: std_ulogic_vector(63 downto 0); length: integer; identifier: integer; reload: integer); + procedure behavioural_read (val: out std_ulogic_vector(63 downto 0); addr: std_ulogic_vector(63 downto 0); length: integer; identifier:integer); attribute foreign of behavioural_read : procedure is "VHPIDIRECT behavioural_read"; procedure behavioural_write (val: std_ulogic_vector(63 downto 0); addr: std_ulogic_vector(63 downto 0); length: integer; identifier: integer); attribute foreign of behavioural_write : procedure is "VHPIDIRECT behavioural_write"; -end simple_ram_behavioural_helpers; +end sim_bram_helpers; -package body simple_ram_behavioural_helpers is +package body sim_bram_helpers is function behavioural_initialize (filename: String; size: integer) return integer is begin assert false report "VHPI" severity failure; end behavioural_initialize; - procedure behavioural_read (val: out std_ulogic_vector(63 downto 0); addr: std_ulogic_vector(63 downto 0); length: integer; identifier: integer; reload: integer) is + procedure behavioural_read (val: out std_ulogic_vector(63 downto 0); addr: std_ulogic_vector(63 downto 0); length: integer; identifier: integer) is begin assert false report "VHPI" severity failure; end behavioural_read; @@ -27,4 +27,4 @@ package body simple_ram_behavioural_helpers is begin assert false report "VHPI" severity failure; end behavioural_write; -end simple_ram_behavioural_helpers; +end sim_bram_helpers; diff --git a/simple_ram_behavioural_helpers_c.c b/sim_bram_helpers_c.c similarity index 100% rename from simple_ram_behavioural_helpers_c.c rename to sim_bram_helpers_c.c diff --git a/simple_ram_behavioural.vhdl b/simple_ram_behavioural.vhdl deleted file mode 100644 index d6255b8..0000000 --- a/simple_ram_behavioural.vhdl +++ /dev/null @@ -1,133 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; -use std.textio.all; - -library work; -use work.wishbone_types.all; -use work.simple_ram_behavioural_helpers.all; - -entity mw_soc_memory is - generic ( - RAM_INIT_FILE : string; - MEMORY_SIZE : integer; - PIPELINE_DEPTH : integer := 1 - ); - - port ( - clk : in std_ulogic; - rst : in std_ulogic; - - wishbone_in : in wishbone_master_out; - wishbone_out : out wishbone_slave_out - ); -end mw_soc_memory; - -architecture behave of mw_soc_memory is - type wishbone_state_t is (IDLE, ACK); - - signal state : wishbone_state_t := IDLE; - signal ret_ack : std_ulogic := '0'; - signal identifier : integer := behavioural_initialize(filename => RAM_INIT_FILE, size => MEMORY_SIZE); - signal reload : integer := 0; - signal ret_dat : wishbone_data_type; - - subtype pipe_idx_t is integer range 0 to PIPELINE_DEPTH-1; - type pipe_ack_t is array(pipe_idx_t) of std_ulogic; - type pipe_dat_t is array(pipe_idx_t) of wishbone_data_type; -begin - - pipe_big: if PIPELINE_DEPTH > 1 generate - signal pipe_ack : pipe_ack_t; - signal pipe_dat : pipe_dat_t; - begin - wishbone_out.stall <= '0'; - wishbone_out.ack <= pipe_ack(0); - wishbone_out.dat <= pipe_dat(0); - - pipe_big_sync: process(clk) - begin - if rising_edge(clk) then - pipe_stages: for i in 0 to PIPELINE_DEPTH-2 loop - pipe_ack(i) <= pipe_ack(i+1); - pipe_dat(i) <= pipe_dat(i+1); - end loop; - pipe_ack(PIPELINE_DEPTH-1) <= ret_ack; - pipe_dat(PIPELINE_DEPTH-1) <= ret_dat; - end if; - end process; - end generate; - - pipe_one: if PIPELINE_DEPTH = 1 generate - signal pipe_ack : std_ulogic; - signal pipe_dat : wishbone_data_type; - begin - wishbone_out.stall <= '0'; - wishbone_out.ack <= pipe_ack; - wishbone_out.dat <= pipe_dat; - - pipe_one_sync: process(clk) - begin - if rising_edge(clk) then - pipe_ack <= ret_ack; - pipe_dat <= ret_dat; - end if; - end process; - end generate; - - pipe_none: if PIPELINE_DEPTH = 0 generate - begin - wishbone_out.ack <= ret_ack; - wishbone_out.dat <= ret_dat; - wishbone_out.stall <= wishbone_in.cyc and not ret_ack; - end generate; - - wishbone_process: process(clk) - variable ret_dat_v : wishbone_data_type; - variable adr : std_ulogic_vector(63 downto 0); - begin - if rising_edge(clk) then - if rst = '1' then - state <= IDLE; - ret_ack <= '0'; - else - ret_dat <= x"FFFFFFFFFFFFFFFF"; - ret_ack <= '0'; - - -- Active - if wishbone_in.cyc = '1' then - case state is - when IDLE => - if wishbone_in.stb = '1' then - adr := (wishbone_in.adr'left downto 0 => wishbone_in.adr, - others => '0'); - -- write - if wishbone_in.we = '1' then - assert not(is_x(wishbone_in.dat)) and not(is_x(wishbone_in.adr)) severity failure; - report "RAM writing " & to_hstring(wishbone_in.dat) & " to " & to_hstring(wishbone_in.adr); - behavioural_write(wishbone_in.dat, adr, to_integer(unsigned(wishbone_in.sel)), identifier); - reload <= reload + 1; - ret_ack <= '1'; - if PIPELINE_DEPTH = 0 then - state <= ACK; - end if; - else - behavioural_read(ret_dat_v, adr, to_integer(unsigned(wishbone_in.sel)), identifier, reload); - report "RAM reading from " & to_hstring(wishbone_in.adr) & " returns " & to_hstring(ret_dat_v); - ret_dat <= ret_dat_v; - ret_ack <= '1'; - if PIPELINE_DEPTH = 0 then - state <= ACK; - end if; - end if; - end if; - when ACK => - state <= IDLE; - end case; - else - state <= IDLE; - end if; - end if; - end if; - end process; -end behave; diff --git a/simple_ram_behavioural_tb.vhdl b/simple_ram_behavioural_tb.vhdl deleted file mode 100644 index bee7d2e..0000000 --- a/simple_ram_behavioural_tb.vhdl +++ /dev/null @@ -1,246 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library work; -use work.wishbone_types.all; - -entity simple_ram_behavioural_tb is -end simple_ram_behavioural_tb; - -architecture behave of simple_ram_behavioural_tb is - signal clk : std_ulogic; - signal rst : std_ulogic := '1'; - - constant clk_period : time := 10 ns; - - signal w_in : wishbone_slave_out; - signal w_out : wishbone_master_out; - - impure function to_adr(a: integer) return std_ulogic_vector is - begin - return std_ulogic_vector(to_unsigned(a, w_out.adr'length)); - end; -begin - simple_ram_0: entity work.mw_soc_memory - generic map ( - RAM_INIT_FILE => "simple_ram_behavioural_tb.bin", - MEMORY_SIZE => 16 - ) - port map ( - clk => clk, - rst => rst, - wishbone_out => w_in, - wishbone_in => w_out - ); - - clock: process - begin - clk <= '1'; - wait for clk_period / 2; - clk <= '0'; - wait for clk_period / 2; - end process clock; - - stim: process - begin - w_out.adr <= (others => '0'); - w_out.dat <= (others => '0'); - w_out.cyc <= '0'; - w_out.stb <= '0'; - w_out.sel <= (others => '0'); - w_out.we <= '0'; - - wait for clk_period; - rst <= '0'; - - wait for clk_period; - - w_out.cyc <= '1'; - - -- test various read lengths and alignments - w_out.stb <= '1'; - w_out.sel <= "00000001"; - w_out.adr <= to_adr(0); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(7 downto 0) = x"00" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00000001"; - w_out.adr <= to_adr(1); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(7 downto 0) = x"01" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00000001"; - w_out.adr <= to_adr(7); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(7 downto 0) = x"07" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00000011"; - w_out.adr <= to_adr(0); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(15 downto 0) = x"0100" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00000011"; - w_out.adr <= to_adr(1); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(15 downto 0) = x"0201" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00000011"; - w_out.adr <= to_adr(7); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(15 downto 0) = x"0807" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00001111"; - w_out.adr <= to_adr(0); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(31 downto 0) = x"03020100" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00001111"; - w_out.adr <= to_adr(1); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(31 downto 0) = x"04030201" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00001111"; - w_out.adr <= to_adr(7); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(31 downto 0) = x"0A090807" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "11111111"; - w_out.adr <= to_adr(0); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(63 downto 0) = x"0706050403020100" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "11111111"; - w_out.adr <= to_adr(1); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(63 downto 0) = x"0807060504030201" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "11111111"; - w_out.adr <= to_adr(7); - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(63 downto 0) = x"0E0D0C0B0A090807" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - -- test various write lengths and alignments - w_out.stb <= '1'; - w_out.sel <= "00000001"; - w_out.adr <= to_adr(0); - w_out.we <= '1'; - w_out.dat(7 downto 0) <= x"0F"; - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "00000001"; - w_out.adr <= to_adr(0); - w_out.we <= '0'; - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat(7 downto 0) = x"0F" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "11111111"; - w_out.adr <= to_adr(7); - w_out.we <= '1'; - w_out.dat <= x"BADC0FFEBADC0FFE"; - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - w_out.stb <= '1'; - w_out.sel <= "11111111"; - w_out.adr <= to_adr(7); - w_out.we <= '0'; - assert w_in.ack = '0'; - wait for clk_period; - assert w_in.ack = '1'; - assert w_in.dat = x"BADC0FFEBADC0FFE" report to_hstring(w_in.dat); - w_out.stb <= '0'; - wait for clk_period; - assert w_in.ack = '0'; - - assert false report "end of test" severity failure; - wait; - end process; -end behave; diff --git a/soc.vhdl b/soc.vhdl index b9a8215..6ed6bf7 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -170,7 +170,7 @@ begin wb_uart0_out.stall <= '0' when wb_uart0_in.cyc = '0' else not wb_uart0_out.ack; -- BRAM Memory slave - bram0: entity work.mw_soc_memory + bram0: entity work.wishbone_bram_wrapper generic map( MEMORY_SIZE => MEMORY_SIZE, RAM_INIT_FILE => RAM_INIT_FILE diff --git a/simple_ram_behavioural_tb.bin b/wishbone_bram_tb.bin similarity index 100% rename from simple_ram_behavioural_tb.bin rename to wishbone_bram_tb.bin diff --git a/wishbone_bram_tb.vhdl b/wishbone_bram_tb.vhdl new file mode 100644 index 0000000..be64db6 --- /dev/null +++ b/wishbone_bram_tb.vhdl @@ -0,0 +1,175 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.wishbone_types.all; + +entity wishbone_bram_tb is +end wishbone_bram_tb; + +architecture behave of wishbone_bram_tb is + signal clk : std_ulogic; + signal rst : std_ulogic := '1'; + + constant clk_period : time := 10 ns; + + signal w_in : wishbone_slave_out; + signal w_out : wishbone_master_out; + + impure function to_adr(a: integer) return std_ulogic_vector is + begin + return std_ulogic_vector(to_unsigned(a, w_out.adr'length)); + end; +begin + simple_ram_0: entity work.wishbone_bram_wrapper + generic map ( + RAM_INIT_FILE => "wishbone_bram_tb.bin", + MEMORY_SIZE => 16 + ) + port map ( + clk => clk, + rst => rst, + wishbone_out => w_in, + wishbone_in => w_out + ); + + clock: process + begin + clk <= '1'; + wait for clk_period / 2; + clk <= '0'; + wait for clk_period / 2; + end process clock; + + stim: process + begin + w_out.adr <= (others => '0'); + w_out.dat <= (others => '0'); + w_out.cyc <= '0'; + w_out.stb <= '0'; + w_out.sel <= (others => '0'); + w_out.we <= '0'; + + wait until rising_edge(clk); + rst <= '0'; + wait until rising_edge(clk); + + w_out.cyc <= '1'; + + -- Test read 0 + w_out.stb <= '1'; + w_out.sel <= "11111111"; + w_out.adr <= to_adr(0); + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert w_in.ack = '1'; + assert w_in.dat(63 downto 0) = x"0706050403020100" report to_hstring(w_in.dat); + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test read 8 + w_out.stb <= '1'; + w_out.sel <= "11111111"; + w_out.adr <= to_adr(8); + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert w_in.ack = '1'; + assert w_in.dat(63 downto 0) = x"0F0E0D0C0B0A0908" report to_hstring(w_in.dat); + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test write byte at 0 + w_out.stb <= '1'; + w_out.sel <= "00000001"; + w_out.adr <= to_adr(0); + w_out.we <= '1'; + w_out.dat(7 downto 0) <= x"0F"; + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk) and w_in.ack = '1'; + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test read back + w_out.stb <= '1'; + w_out.sel <= "11111111"; + w_out.adr <= to_adr(0); + w_out.we <= '0'; + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert w_in.ack = '1'; + assert w_in.dat(63 downto 0) = x"070605040302010F" report to_hstring(w_in.dat); + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test write dword at 4 + w_out.stb <= '1'; + w_out.sel <= "11110000"; + w_out.adr <= to_adr(0); + w_out.we <= '1'; + w_out.dat(63 downto 32) <= x"BAADFEED"; + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk) and w_in.ack = '1'; + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test read back + w_out.stb <= '1'; + w_out.sel <= "11111111"; + w_out.adr <= to_adr(0); + w_out.we <= '0'; + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert w_in.ack = '1'; + assert w_in.dat(63 downto 0) = x"BAADFEED0302010F" report to_hstring(w_in.dat); + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test write qword at 8 + w_out.stb <= '1'; + w_out.sel <= "11111111"; + w_out.adr <= to_adr(8); + w_out.we <= '1'; + w_out.dat(63 downto 0) <= x"0001020304050607"; + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk) and w_in.ack = '1'; + wait until rising_edge(clk); + assert w_in.ack = '0'; + + -- Test read back + w_out.stb <= '1'; + w_out.sel <= "11111111"; + w_out.adr <= to_adr(8); + w_out.we <= '0'; + assert w_in.ack = '0'; + wait until rising_edge(clk); + w_out.stb <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + assert w_in.ack = '1'; + assert w_in.dat(63 downto 0) = x"0001020304050607" report to_hstring(w_in.dat); + wait until rising_edge(clk); + assert w_in.ack = '0'; + + assert false report "end of test" severity failure; + wait; + end process; +end behave; diff --git a/wishbone_bram_wrapper.vhdl b/wishbone_bram_wrapper.vhdl new file mode 100644 index 0000000..a711c3d --- /dev/null +++ b/wishbone_bram_wrapper.vhdl @@ -0,0 +1,76 @@ +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; + +--! @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 + ); + port( + clk : in std_logic; + rst : in std_logic; + + -- Wishbone interface: + wishbone_in : in wishbone_master_out; + wishbone_out : out wishbone_slave_out + ); +end entity wishbone_bram_wrapper; + +architecture behaviour of wishbone_bram_wrapper is + constant ram_addr_bits : integer := log2(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 + 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, + di => wishbone_in.dat, + do => wishbone_out.dat, + sel => wishbone_in.sel, + re => ram_re, + we => ram_we + ); + + -- Wishbone interface + ram_addr <= wishbone_in.adr(ram_addr_bits + 2 downto 3); + 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 + ack <= wishbone_in.stb; + ack_buf <= ack; + end if; + end if; + end process; + +end architecture behaviour;