~ruther/jesd204b-vhdl

bbba2af74c64817166b520bac7c2622073b62ea1 — František Boháček 2 years ago 87f51b4
feat: add ring_buffer for std_logic_vector
2 files changed, 174 insertions(+), 0 deletions(-)

A src/data_link/ring_buffer.vhd
A testbench/data_link/ring_buffer_tb.vhd
A src/data_link/ring_buffer.vhd => src/data_link/ring_buffer.vhd +75 -0
@@ 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;

A testbench/data_link/ring_buffer_tb.vhd => testbench/data_link/ring_buffer_tb.vhd +99 -0
@@ 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;

Do not follow this link