From bbba2af74c64817166b520bac7c2622073b62ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 19 Feb 2023 20:30:08 +0100 Subject: [PATCH] feat: add ring_buffer for std_logic_vector --- src/data_link/ring_buffer.vhd | 75 +++++++++++++++++++ testbench/data_link/ring_buffer_tb.vhd | 99 ++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/data_link/ring_buffer.vhd create mode 100644 testbench/data_link/ring_buffer_tb.vhd diff --git a/src/data_link/ring_buffer.vhd b/src/data_link/ring_buffer.vhd new file mode 100644 index 0000000..ecdadb2 --- /dev/null +++ b/src/data_link/ring_buffer.vhd @@ -0,0 +1,75 @@ +library ieee; +use work.data_link_pkg.all; +use ieee.std_logic_1164.all; + +entity ring_buffer is + + generic ( + CHARACTER_SIZE : integer := 8; + BUFFER_SIZE : integer; + READ_SIZE : integer); -- The size of the buffer + + port ( + ci_clk : in std_logic; -- The clock + ci_reset : in std_logic; -- The reset (active low) + ci_adjust_position : in integer range -READ_SIZE/2-1 to READ_SIZE/2+1; + ci_read : in std_logic; -- One to read in current cycle, Zero + -- to stay on current reading position + di_character : in std_logic_vector(CHARACTER_SIZE-1 downto 0); -- The character to save on next clock + co_read : out std_logic_vector(CHARACTER_SIZE*READ_SIZE - 1 downto 0); -- The output characters read from the buffer + co_size : out integer; -- The current count of filled data + co_read_position : out integer; -- The current read position inside of + -- the buffer + co_write_position : out integer; -- The current write position + -- next character will be written to + co_filled : out std_logic); -- Whether the buffer is full + +end entity ring_buffer; + +architecture a1 of ring_buffer is + signal buff : std_logic_vector(CHARACTER_SIZE*BUFFER_SIZE-1 downto 0); + signal buff_twice : std_logic_vector(2*CHARACTER_SIZE*BUFFER_SIZE-1 downto 0); + signal next_read : std_logic_vector(CHARACTER_SIZE*BUFFER_SIZE-1 downto 0); + signal read_position : integer := 0; + signal adjusted_read_position : integer := 0; + signal write_position : integer := 0; + signal reg_size : integer := 0; + signal size : integer := 0; +begin -- architecture a1 + -- purpose: Adjust read position and read next character + -- type : sequential + -- inputs : ci_clk, ci_reset + -- outputs: read_position, write_position, buff + read: process (ci_clk, ci_reset) is + begin -- process read + if ci_reset = '0' then -- asynchronous reset (active low) + buff <= (others => '0'); + read_position <= 0; + reg_size <= 0; + elsif ci_clk'event and ci_clk = '1' then -- rising clock edge + if ci_read = '1' then + read_position <= (read_position + ci_adjust_position + READ_SIZE) mod BUFFER_SIZE; + co_read_position <= read_position + ci_adjust_position; + reg_size <= size - READ_SIZE - ci_adjust_position + 1; + co_read <= buff_twice(2*CHARACTER_SIZE*BUFFER_SIZE - 1 - (read_position + ci_adjust_position)*CHARACTER_SIZE downto 2*CHARACTER_SIZE*BUFFER_SIZE - (read_position + ci_adjust_position + READ_SIZE)*CHARACTER_SIZE); + else + reg_size <= reg_size + 1; + end if; + + adjusted_read_position <= read_position + ci_adjust_position; + buff(CHARACTER_SIZE*BUFFER_SIZE-1 - CHARACTER_SIZE*write_position downto CHARACTER_SIZE*BUFFER_SIZE - CHARACTER_SIZE*(write_position + 1)) <= di_character; + write_position <= (write_position + 1) mod BUFFER_SIZE; + end if; + end process read; + + co_write_position <= write_position; + co_size <= size; + size <= BUFFER_SIZE when reg_size > BUFFER_SIZE else + reg_size; + buff_twice(2*CHARACTER_SIZE*BUFFER_SIZE - 1 downto CHARACTER_SIZE*BUFFER_SIZE) <= buff; + buff_twice(CHARACTER_SIZE*BUFFER_SIZE - 1 downto 0) <= buff; + + co_filled <= '1' when reg_size > BUFFER_SIZE else + '0'; + +end architecture a1; diff --git a/testbench/data_link/ring_buffer_tb.vhd b/testbench/data_link/ring_buffer_tb.vhd new file mode 100644 index 0000000..5de11ca --- /dev/null +++ b/testbench/data_link/ring_buffer_tb.vhd @@ -0,0 +1,99 @@ +library ieee; +use ieee.std_logic_1164.all; +use work.testing_functions.all; +use work.data_link_pkg.all; + +entity ring_buffer_tb is + +end entity ring_buffer_tb; + +architecture a1 of ring_buffer_tb is + type test_vector is record + di_character : std_logic_vector(7 downto 0); + ci_read : std_logic; + ci_adjust_position : integer; + end record test_vector; + + type test_vector_array is array (natural range <>) of test_vector; + + constant test_vectors : test_vector_array := + ( + ("00000000", '0', 0), + ("00000001", '0', 0), + ("00000010", '0', 0), + ("00000011", '0', 0), + ("00000100", '0', 0), + ("11111111", '0', 0), + ("00000110", '0', 0), + ("00000111", '1', 2), + ("00001000", '0', 0), + ("00001001", '0', 0), + ("11111111", '0', 0), + ("00000001", '0', 0), + ("00000010", '1', 0), + ("00000011", '0', 0), + ("00000100", '0', 0), + ("11111111", '0', 0), + ("00000000", '0', 0), + ("00000000", '1', 0), + ("01000000", '0', 0), + ("01000000", '0', 0), + ("11111111", '0', 0), + ("01000000", '0', 0), + ("01000000", '0', 0), + ("01000000", '0', 0), + ("01000000", '0', 0), + ("11111111", '1', 0), + ("01000000", '0', 0), + ("01000000", '1', 0), + ("01000000", '0', 0) + ); + signal F : integer := 5; + + constant clk_period : time := 1 ns; + signal clk : std_logic := '0'; + signal reset : std_logic := '0'; + signal ci_read : std_logic; + signal ci_adjust_position : integer; + signal di_character : std_logic_vector(7 downto 0); + signal co_read : std_logic_vector(F*8-1 downto 0); + signal co_size : integer; + signal co_filled : std_logic; + + signal test_data_index : integer := 0; +begin -- architecture a1 + uut : entity work.ring_buffer + generic map ( + READ_SIZE => F, + BUFFER_SIZE => 2*F + ) + port map ( + ci_clk => clk, + ci_reset => reset, + di_character => di_character, + ci_adjust_position => ci_adjust_position, + ci_read => ci_read, + co_read => co_read, + co_size => co_size, + co_filled => co_filled); + + clk <= not clk after clk_period/2; + reset <= '1' after clk_period*2; + + test: process is + begin -- process test + wait for clk_period*2; + + for i in test_vectors'range loop + test_data_index <= i; + di_character <= test_vectors(i).di_character; + ci_read <= test_vectors(i).ci_read; + ci_adjust_position <= test_vectors(i).ci_adjust_position; + + wait for clk_period; + end loop; -- i + + wait for 100 ms; + end process test; + +end architecture a1; -- 2.48.1