From: Benjamin Herrenschmidt Date: Wed, 23 Oct 2019 01:08:55 +0000 (+1100) Subject: ram: Rework main RAM interface X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8e0389b9736c60572e13ef5eeb50d3a775c3ffc6;p=microwatt.git 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 --- 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/sim_bram_helpers.vhdl b/sim_bram_helpers.vhdl new file mode 100644 index 0000000..c511a6e --- /dev/null +++ b/sim_bram_helpers.vhdl @@ -0,0 +1,30 @@ +library ieee; +use ieee.std_logic_1164.all; + +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); + 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 sim_bram_helpers; + +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) is + begin + assert false report "VHPI" severity failure; + end behavioural_read; + + procedure behavioural_write (val: 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_write; +end sim_bram_helpers; diff --git a/sim_bram_helpers_c.c b/sim_bram_helpers_c.c new file mode 100644 index 0000000..c5678e7 --- /dev/null +++ b/sim_bram_helpers_c.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#define ALIGN_UP(VAL, SIZE) (((VAL) + ((SIZE)-1)) & ~((SIZE)-1)) + +#define vhpi0 2 /* forcing 0 */ +#define vhpi1 3 /* forcing 1 */ + +struct int_bounds +{ + int left; + int right; + char dir; + unsigned int len; +}; + +struct fat_pointer +{ + void *base; + struct int_bounds *bounds; +}; + +static char *from_string(void *__p) +{ + struct fat_pointer *p = __p; + unsigned long len = p->bounds->len; + char *m; + + m = malloc(len+1); + if (!m) { + perror("malloc"); + exit(1); + } + + memcpy(m, p->base, len); + m[len] = 0x0; + + return m; +} + +static uint64_t from_std_logic_vector(unsigned char *p, unsigned long len) +{ + unsigned long ret = 0; + + if (len > 64) { + fprintf(stderr, "%s: invalid length %lu\n", __func__, len); + exit(1); + } + + for (unsigned long i = 0; i < len; i++) { + unsigned char bit; + + if (*p == vhpi0) { + bit = 0; + } else if (*p == vhpi1) { + bit = 1; + } else { + fprintf(stderr, "%s: bad bit %d\n", __func__, *p); + bit = 0; + } + + ret = (ret << 1) | bit; + p++; + } + + return ret; +} + +static void to_std_logic_vector(unsigned long val, unsigned char *p, + unsigned long len) +{ + if (len > 64) { + fprintf(stderr, "%s: invalid length %lu\n", __func__, len); + exit(1); + } + + for (unsigned long i = 0; i < len; i++) { + if ((val >> (len-1-i) & 1)) + *p = vhpi1; + else + *p = vhpi0; + + p++; + } +} + +#define MAX_REGIONS 128 + +struct ram_behavioural { + char *filename; + unsigned long size; + void *m; +}; + +static struct ram_behavioural behavioural_regions[MAX_REGIONS]; +static unsigned long region_nr; + +unsigned long behavioural_initialize(void *__f, unsigned long size) +{ + struct ram_behavioural *r; + int fd; + struct stat buf; + unsigned long tmp_size; + void *mem; + + if (region_nr == MAX_REGIONS) { + fprintf(stderr, "%s: too many regions, bump MAX_REGIONS\n", __func__); + exit(1); + } + + r = &behavioural_regions[region_nr]; + + r->filename = from_string(__f); + r->size = ALIGN_UP(size, getpagesize()); + + fd = open(r->filename, O_RDWR); + if (fd == -1) { + fprintf(stderr, "%s: could not open %s\n", __func__, + r->filename); + exit(1); + } + + if (fstat(fd, &buf)) { + perror("fstat"); + exit(1); + } + + /* XXX Do we need to truncate the underlying file? */ + tmp_size = ALIGN_UP(buf.st_size, getpagesize()); + + if (r->size > tmp_size) { + void *m; + + /* + * We have to pad the file. Allocate the total size, then + * create a space for the file. + */ + mem = mmap(NULL, r->size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + if (tmp_size) { + munmap(mem, tmp_size); + + m = mmap(mem, tmp_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_FIXED, fd, 0); + if (m == MAP_FAILED) { + perror("mmap"); + exit(1); + } + if (m != mem) { + fprintf(stderr, "%s: mmap(MAP_FIXED) failed\n", + __func__); + exit(1); + } + } + } else { + mem = mmap(NULL, tmp_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, + fd, 0); + if (mem == MAP_FAILED) { + perror("mmap"); + exit(1); + } + } + + behavioural_regions[region_nr].m = mem; + return region_nr++; +} + +void behavioural_read(unsigned char *__val, unsigned char *__addr, + unsigned long sel, int identifier) +{ + struct ram_behavioural *r; + unsigned long val = 0; + unsigned long addr = from_std_logic_vector(__addr, 64); + unsigned char *p; + + if (identifier > region_nr) { + fprintf(stderr, "%s: bad index %d\n", __func__, identifier); + exit(1); + } + + r = &behavioural_regions[identifier]; + + for (unsigned long i = 0; i < 8; i++) { +#if 0 + /* sel only used on writes */ + if (!(sel & (1UL << i))) + continue; +#endif + + if ((addr + i) > r->size) { + fprintf(stderr, "%s: bad memory access %lx %lx\n", __func__, + addr+i, r->size); + exit(1); + } + + p = (unsigned char *)(((unsigned long)r->m) + addr + i); + val |= (((unsigned long)*p) << (i*8)); + } + +#ifdef DEBUG + printf("MEM behave %d read %016lx addr %016lx sel %02lx\n", identifier, val, + addr, sel); +#endif + + to_std_logic_vector(val, __val, 64); +} + +void behavioural_write(unsigned char *__val, unsigned char *__addr, + unsigned int sel, int identifier) +{ + struct ram_behavioural *r; + unsigned long val = from_std_logic_vector(__val, 64); + unsigned long addr = from_std_logic_vector(__addr, 64); + unsigned char *p; + + if (identifier > region_nr) { + fprintf(stderr, "%s: bad index %d\n", __func__, identifier); + exit(1); + } + + r = &behavioural_regions[identifier]; + + p = (unsigned char *)(((unsigned long)r->m) + addr); + +#ifdef DEBUG + printf("MEM behave %d write %016lx addr %016lx sel %02x\n", identifier, val, + addr, sel); +#endif + + for (unsigned long i = 0; i < 8; i++) { + if (!(sel & (1UL << i))) + continue; + + if ((addr + i) > r->size) { + fprintf(stderr, "%s: bad memory access %lx %lx\n", __func__, + addr+i, r->size); + exit(1); + } + + p = (unsigned char *)(((unsigned long)r->m) + addr + i); + *p = (val >> (i*8)) & 0xff; + } +} 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_helpers.vhdl b/simple_ram_behavioural_helpers.vhdl deleted file mode 100644 index 507594f..0000000 --- a/simple_ram_behavioural_helpers.vhdl +++ /dev/null @@ -1,30 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; - -package simple_ram_behavioural_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); - 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; - -package body simple_ram_behavioural_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 - begin - assert false report "VHPI" severity failure; - end behavioural_read; - - procedure behavioural_write (val: 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_write; -end simple_ram_behavioural_helpers; diff --git a/simple_ram_behavioural_helpers_c.c b/simple_ram_behavioural_helpers_c.c deleted file mode 100644 index c5678e7..0000000 --- a/simple_ram_behavioural_helpers_c.c +++ /dev/null @@ -1,258 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG - -#define ALIGN_UP(VAL, SIZE) (((VAL) + ((SIZE)-1)) & ~((SIZE)-1)) - -#define vhpi0 2 /* forcing 0 */ -#define vhpi1 3 /* forcing 1 */ - -struct int_bounds -{ - int left; - int right; - char dir; - unsigned int len; -}; - -struct fat_pointer -{ - void *base; - struct int_bounds *bounds; -}; - -static char *from_string(void *__p) -{ - struct fat_pointer *p = __p; - unsigned long len = p->bounds->len; - char *m; - - m = malloc(len+1); - if (!m) { - perror("malloc"); - exit(1); - } - - memcpy(m, p->base, len); - m[len] = 0x0; - - return m; -} - -static uint64_t from_std_logic_vector(unsigned char *p, unsigned long len) -{ - unsigned long ret = 0; - - if (len > 64) { - fprintf(stderr, "%s: invalid length %lu\n", __func__, len); - exit(1); - } - - for (unsigned long i = 0; i < len; i++) { - unsigned char bit; - - if (*p == vhpi0) { - bit = 0; - } else if (*p == vhpi1) { - bit = 1; - } else { - fprintf(stderr, "%s: bad bit %d\n", __func__, *p); - bit = 0; - } - - ret = (ret << 1) | bit; - p++; - } - - return ret; -} - -static void to_std_logic_vector(unsigned long val, unsigned char *p, - unsigned long len) -{ - if (len > 64) { - fprintf(stderr, "%s: invalid length %lu\n", __func__, len); - exit(1); - } - - for (unsigned long i = 0; i < len; i++) { - if ((val >> (len-1-i) & 1)) - *p = vhpi1; - else - *p = vhpi0; - - p++; - } -} - -#define MAX_REGIONS 128 - -struct ram_behavioural { - char *filename; - unsigned long size; - void *m; -}; - -static struct ram_behavioural behavioural_regions[MAX_REGIONS]; -static unsigned long region_nr; - -unsigned long behavioural_initialize(void *__f, unsigned long size) -{ - struct ram_behavioural *r; - int fd; - struct stat buf; - unsigned long tmp_size; - void *mem; - - if (region_nr == MAX_REGIONS) { - fprintf(stderr, "%s: too many regions, bump MAX_REGIONS\n", __func__); - exit(1); - } - - r = &behavioural_regions[region_nr]; - - r->filename = from_string(__f); - r->size = ALIGN_UP(size, getpagesize()); - - fd = open(r->filename, O_RDWR); - if (fd == -1) { - fprintf(stderr, "%s: could not open %s\n", __func__, - r->filename); - exit(1); - } - - if (fstat(fd, &buf)) { - perror("fstat"); - exit(1); - } - - /* XXX Do we need to truncate the underlying file? */ - tmp_size = ALIGN_UP(buf.st_size, getpagesize()); - - if (r->size > tmp_size) { - void *m; - - /* - * We have to pad the file. Allocate the total size, then - * create a space for the file. - */ - mem = mmap(NULL, r->size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - if (mem == MAP_FAILED) { - perror("mmap"); - exit(1); - } - - if (tmp_size) { - munmap(mem, tmp_size); - - m = mmap(mem, tmp_size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_FIXED, fd, 0); - if (m == MAP_FAILED) { - perror("mmap"); - exit(1); - } - if (m != mem) { - fprintf(stderr, "%s: mmap(MAP_FIXED) failed\n", - __func__); - exit(1); - } - } - } else { - mem = mmap(NULL, tmp_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, - fd, 0); - if (mem == MAP_FAILED) { - perror("mmap"); - exit(1); - } - } - - behavioural_regions[region_nr].m = mem; - return region_nr++; -} - -void behavioural_read(unsigned char *__val, unsigned char *__addr, - unsigned long sel, int identifier) -{ - struct ram_behavioural *r; - unsigned long val = 0; - unsigned long addr = from_std_logic_vector(__addr, 64); - unsigned char *p; - - if (identifier > region_nr) { - fprintf(stderr, "%s: bad index %d\n", __func__, identifier); - exit(1); - } - - r = &behavioural_regions[identifier]; - - for (unsigned long i = 0; i < 8; i++) { -#if 0 - /* sel only used on writes */ - if (!(sel & (1UL << i))) - continue; -#endif - - if ((addr + i) > r->size) { - fprintf(stderr, "%s: bad memory access %lx %lx\n", __func__, - addr+i, r->size); - exit(1); - } - - p = (unsigned char *)(((unsigned long)r->m) + addr + i); - val |= (((unsigned long)*p) << (i*8)); - } - -#ifdef DEBUG - printf("MEM behave %d read %016lx addr %016lx sel %02lx\n", identifier, val, - addr, sel); -#endif - - to_std_logic_vector(val, __val, 64); -} - -void behavioural_write(unsigned char *__val, unsigned char *__addr, - unsigned int sel, int identifier) -{ - struct ram_behavioural *r; - unsigned long val = from_std_logic_vector(__val, 64); - unsigned long addr = from_std_logic_vector(__addr, 64); - unsigned char *p; - - if (identifier > region_nr) { - fprintf(stderr, "%s: bad index %d\n", __func__, identifier); - exit(1); - } - - r = &behavioural_regions[identifier]; - - p = (unsigned char *)(((unsigned long)r->m) + addr); - -#ifdef DEBUG - printf("MEM behave %d write %016lx addr %016lx sel %02x\n", identifier, val, - addr, sel); -#endif - - for (unsigned long i = 0; i < 8; i++) { - if (!(sel & (1UL << i))) - continue; - - if ((addr + i) > r->size) { - fprintf(stderr, "%s: bad memory access %lx %lx\n", __func__, - addr+i, r->size); - exit(1); - } - - p = (unsigned char *)(((unsigned long)r->m) + addr + i); - *p = (val >> (i*8)) & 0xff; - } -} diff --git a/simple_ram_behavioural_tb.bin b/simple_ram_behavioural_tb.bin deleted file mode 100644 index b66efb8..0000000 Binary files a/simple_ram_behavioural_tb.bin and /dev/null differ 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/wishbone_bram_tb.bin b/wishbone_bram_tb.bin new file mode 100644 index 0000000..b66efb8 Binary files /dev/null and b/wishbone_bram_tb.bin differ 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;