--- /dev/null
+-------------------------------------------------------------------------------
+--Circular Memory to save sensor data
+-- Note that writing into a full buffer will overwrite parts of the old data
+--T. Weber, University Mainz
+-------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity CircularMemory is
+ generic(
+ g_datawidth : integer := 32; -- width of data words
+ g_addresswidth : integer := 10 -- width of address pointers, number of words is 2**g_addresswidth
+ );
+ port(
+ clk : in std_logic; -- clock input
+ rst : in std_logic; -- reset
+ wr_en : in std_logic; -- write enable
+ data_in : in std_logic_vector(g_datawidth - 1 downto 0); -- input word
+ rd_en : in std_logic; --read enable
+ data_out : out std_logic_vector(g_datawidth - 1 downto 0); -- output word
+ empty : out std_logic; --empty flag
+ full : out std_logic --full flag
+ );
+end entity CircularMemory;
+
+architecture RTL of CircularMemory is
+
+ component BlockMemory
+ generic(
+ DataWidth : integer := 10;
+ AddressWidth : integer := 10
+ );
+ port(
+ clk : in std_logic;
+ WrEn : in std_logic;
+ WrAddr : in std_logic_vector(AddressWidth - 1 downto 0);
+ Din : in std_logic_vector(DataWidth - 1 downto 0);
+ ReAddr : in std_logic_vector(AddressWidth - 1 downto 0);
+ Dout : out std_logic_vector(DataWidth - 1 downto 0)
+ );
+ end component BlockMemory;
+
+ --read and write pointers
+ constant c_high_address : integer := 2**g_addresswidth;
+ signal readpointer : integer range 0 to c_high_address - 1 := 0;
+ signal writepointer : integer range 0 to c_high_address - 1 := 0;
+ signal words_in_buffer : integer range 0 to c_high_address := 0;
+
+ --wires to block memory
+ signal WrEn_mem : std_logic;
+ signal WrAddr_mem : std_logic_vector(g_addresswidth - 1 downto 0);
+ signal Din_mem : std_logic_vector(g_datawidth - 1 downto 0);
+ signal ReAddr_mem : std_logic_vector(g_addresswidth - 1 downto 0);
+ signal Dout_mem : std_logic_vector(g_datawidth - 1 downto 0);
+
+begin
+
+ memory : entity work.BlockMemory
+ generic map(
+ DataWidth => g_datawidth,
+ AddressWidth => g_addresswidth
+ )
+ port map(
+ clk => clk,
+ WrEn => WrEn_mem,
+ WrAddr => WrAddr_mem,
+ Din => Din_mem,
+ ReAddr => ReAddr_mem,
+ Dout => Dout_mem
+ );
+
+ write_proc : process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ writepointer <= 0;
+ else
+ if wr_en = '1' then
+ WrAddr_mem <= std_logic_vector(to_unsigned(writepointer, g_addresswidth));
+ Din_mem <= data_in;
+ WrEn_mem <= '1';
+ if writepointer = c_high_address - 1 then
+ writepointer <= 0;
+ else
+ writepointer <= writepointer + 1;
+ end if;
+ else
+ writepointer <= writepointer;
+ WrAddr_mem <= (others => '0');
+ Din_mem <= (others => '0');
+ WrEn_mem <= '0';
+ end if;
+ end if;
+ end if;
+ end process write_proc;
+
+ read_proc : process (clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ readpointer <= 0;
+ else
+ if rd_en = '1' then
+ ReAddr_mem <= std_logic_vector(to_unsigned(readpointer, g_addresswidth));
+ if readpointer = c_high_address - 1 then
+ readpointer <= 0;
+ else
+ readpointer <= readpointer + 1;
+ end if;
+ else
+ readpointer <= readpointer;
+ ReAddr_mem <= (others => '0');
+ end if;
+ end if;
+ end if;
+ end process read_proc;
+
+ word_counter_proc : process (clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ words_in_buffer <= 0;
+ else
+ words_in_buffer <= words_in_buffer;
+ if wr_en = '1' and rd_en = '0' then
+ if words_in_buffer < c_high_address then
+ words_in_buffer <= words_in_buffer + 1;
+ else
+ words_in_buffer <= words_in_buffer;
+ end if;
+ elsif wr_en = '0' and rd_en = '1' then
+ if words_in_buffer > 0 then
+ words_in_buffer <= words_in_buffer - 1;
+ else
+ words_in_buffer <= 0;
+ end if;
+ end if;
+ end if;
+ end if;
+ end process word_counter_proc;
+
+
+ empty <= '1' after 1 ns when words_in_buffer = 0 else '0' after 1 ns;
+ full <= '1' after 1 ns when words_in_buffer = c_high_address else '0' after 1 ns;
+ data_out <= Dout_mem;
+
+end architecture RTL;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity CircularMemoryTest is
+end entity CircularMemoryTest;
+
+architecture sim of CircularMemoryTest is
+
+ component CircularMemory
+ generic(
+ g_datawidth : integer := 32;
+ g_addresswidth : integer := 10
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+ wr_en : in std_logic;
+ data_in : in std_logic_vector(g_datawidth - 1 downto 0);
+ rd_en : in std_logic;
+ data_out : out std_logic_vector(g_datawidth - 1 downto 0);
+ empty : out std_logic;
+ full : out std_logic
+ );
+ end component CircularMemory;
+
+ constant c_data_width : integer := 32;
+ constant c_address_width : integer := 3;
+ constant c_clk_period : time := 10 ns;
+
+ signal clk : std_logic;
+ signal rst : std_logic := '0';
+ signal wr_en : std_logic := '0';
+ signal data_in : std_logic_vector(c_data_width - 1 downto 0) := (others => '0');
+ signal rd_en : std_logic := '0';
+ signal data_out : std_logic_vector(c_data_width - 1 downto 0);
+ signal empty : std_logic;
+ signal full : std_logic;
+
+begin
+
+ dut : entity work.CircularMemory
+ generic map(
+ g_datawidth => c_data_width,
+ g_addresswidth => c_address_width
+ )
+ port map(
+ clk => clk,
+ rst => rst,
+ wr_en => wr_en,
+ data_in => data_in,
+ rd_en => rd_en,
+ data_out => data_out,
+ empty => empty,
+ full => full
+ );
+
+ clk_gen : process is
+ begin
+ clk <= '0';
+ wait for c_clk_period/2;
+ clk <= '1';
+ wait for c_clk_period/2;
+ end process clk_gen;
+
+ stimulus : process is
+ begin
+ wait for 100 ns;
+ for i in 1 to 7 loop
+ wr_en <= '1';
+ data_in <= std_logic_vector(to_unsigned(i, c_data_width));
+ wait for c_clk_period;
+ end loop;
+ wr_en <= '0';
+ wait for 50 ns;
+ for i in 1 to 7 loop
+ rd_en <= '1';
+ wait for c_clk_period;
+ end loop;
+ rd_en <= '0';
+ wait;
+ end process stimulus;
+
+
+end architecture sim;
+