~ruther/jesd204b-vhdl

6a95f377770b6b4d9adc432a05a86318705321db — František Boháček 2 years ago 7d1e3cd
feat(link): add frame alignment
2 files changed, 147 insertions(+), 0 deletions(-)

A src/data_link/data_link_pkg.vhd
A src/data_link/frame_alignment.vhd
A src/data_link/data_link_pkg.vhd => src/data_link/data_link_pkg.vhd +13 -0
@@ 0,0 1,13 @@
library ieee;
use ieee.std_logic_1164.all;

package data_link is

  type character_vector is record
    kout            : std_logic;  -- Whether the character is a control character
    disparity_error : std_logic;  -- Whether there was a disparity error (if this is true, the character will still be correct)
    missing_error   : std_logic;  -- Whether the character was not found in the table
    d8b             : std_logic_vector(7 downto 0);  -- The decoded data
  end record character_vector;

end package data_link;

A src/data_link/frame_alignment.vhd => src/data_link/frame_alignment.vhd +134 -0
@@ 0,0 1,134 @@
library ieee;
use ieee.std_logic_1164.all;
use work.data_link_pkg.all;

entity frame_alignment is
  generic (
    sync_char      : std_logic_vector(7 downto 0) := "10111100";
    A_char         : std_logic_vector(7 downto 0) := "01111100";
    F_char         : std_logic_vector(7 downto 0) := "11111100";
    F_replace_data : std_logic_vector(7 downto 0) := "11111100";  -- The character to replace with upon receiving /F/ with scrambled data
    A_replace_data : std_logic_vector(7 downto 0) := "01111100");  -- The character to replace with upon receiving /A/ with scrambled data
  port (
    ci_char_clk       : in  std_logic;
    ci_reset          : in  std_logic;
    ci_F              : in  integer range 0 to 256;  -- The number of octets in a frame
    ci_K              : in  integer range 0 to 32;  -- The number of frames in a multiframe
    ci_request_sync   : in std_logic;   -- Whether sync is requested
    ci_scrambled      : in  std_logic;  -- Whether the data is scrambled
    ci_enable_realign : in  std_logic;  -- Whether to enable automatic realignment
    di_char           : in  character_vector;       -- The received character
    co_aligned        : out std_logic;
    co_misaligned     : out std_logic;
    co_octet_index    : out integer range 0 to 256;  -- The index of the octet in current frame
    co_frame_index    : out integer range 0 to 32;  -- The index of the frame in current multiframe
    do_char           : out character_vector);      -- The output character
end entity frame_alignment;

architecture a1 of frame_alignment is
  type alignment_state is (RESET, INIT, ALIGNED, MISALIGNED, WRONG_ALIGNMENT);
  -- The states of alignment. MISALIGNED means first alignment error.
  -- WRONG_ALIGNMENT is for second alignment error. won't be set if
  -- ci_enable_realigned is set. Thnen realignment will be processed.
  signal reg_state : alignment_state := RESET;

  signal reg_last_frame_data : std_logic_vector(7 downto 0) := "00000000";

  signal next_is_last_octet : std_logic := '0';
  signal next_is_last_frame : std_logic := '0';

  signal is_f : std_logic := '0';
  signal is_a : std_logic := '0';

  signal is_wrong_char : std_logic := '0';

  signal reg_octet_index : integer range 0 to 256 := 0;
  signal reg_frame_index : integer range 0 to 32 := 0;

  signal next_octet_index : integer range 0 to 256 := 0;
  signal next_frame_index : integer range 0 to 32 := 0;
  signal next_char : character_vector := ('0', '0', '0', "00000000");
begin  -- architecture a1
  set_next: process (ci_char_clk, ci_reset) is
  begin  -- process set_next
    if ci_reset = '0' then              -- asynchronous reset (active low)
      reg_frame_index <= 0;
      reg_octet_index <= 0;
      do_char <= ('0', '0', '0', "00000000");
      reg_state <= RESET;
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge
      do_char <= next_char;

      -- set last_frame_data if this is the last frame and not /F/ or /A/
      if next_is_last_octet = '1' and not (is_f = '1' or is_a = '1') then
        reg_last_frame_data <= di_char.d8b;
      end if;

      if ci_request_sync = '1' or (di_char.kout = '1' and di_char.d8b = sync_char) then
        reg_state <= INIT;
        reg_frame_index <= 0;
        reg_octet_index <= 0;
      elsif reg_state = RESET then
        reg_frame_index <= 0;
        reg_octet_index <= 0;
      elsif reg_state = INIT then
        reg_frame_index <= 0;
        reg_octet_index <= 0;

        if di_char.d8b /= sync_char or di_char.kout = '0' then
          reg_state <= ALIGNED;
        end if; -- switch to aligned
      else
        reg_frame_index <= next_frame_index;
        reg_octet_index <= next_octet_index;
        if reg_state = ALIGNED then
          if is_wrong_char = '1' then
            reg_state <= MISALIGNED;
          end if;
        elsif reg_state = MISALIGNED then
          if is_wrong_char = '1' then

            if ci_enable_realign = '1' then
              reg_octet_index <= ci_F - 1;
            else
              reg_state <= WRONG_ALIGNMENT;
            end if;
          elsif is_wrong_char = '0' and (is_f = '1' or is_a = '1') then
            reg_state <= ALIGNED;
          end if;
        elsif reg_state = WRONG_ALIGNMENT then
          if is_wrong_char = '0' and (is_f = '1' or is_a = '1') then
            reg_state <= MISALIGNED;
          elsif ci_enable_realign = '1' and (is_f = '1' or is_a = '1') then
            reg_frame_index <= ci_F - 1;
          end if;
        end if;
      end if; -- in INIT
    end if; -- clk, reset
  end process set_next;

  is_wrong_char <= (is_f and not next_is_last_octet) or (is_a and not (next_is_last_octet and next_is_last_frame));
  next_char.kout <= di_char.kout when is_f = '0' and is_a = '0' else '0';
  next_char.d8b <= di_char.d8b when is_f = '0' and is_a = '0' else
                 reg_last_frame_data when ci_scrambled = '0' else
                 F_replace_data when is_f = '1' else
                 A_replace_data;
  next_char.disparity_error <= di_char.disparity_error;
  next_char.missing_error <= di_char.missing_error;

  next_is_last_octet <= '1' when next_octet_index = ci_F - 1 else '0';
  next_is_last_frame <= '1' when next_frame_index = ci_K - 1 else '0';

  is_f <= '1' when di_char.d8b = F_char and di_char.kout = '1' else '0';
  is_a <= '1' when di_char.d8b = A_char and di_char.kout = '1' else '0';

  next_frame_index <= reg_frame_index when reg_octet_index < (ci_F - 1) else
                      reg_frame_index + 1 when reg_frame_index < (ci_K - 1) else
                      0;
  next_octet_index <= reg_octet_index + 1 when reg_octet_index < (ci_F - 1) else 0;

  co_misaligned <= '1' when reg_state = WRONG_ALIGNMENT else '0';
  co_aligned <= '1' when reg_state = ALIGNED or reg_state = MISALIGNED else '0';
  co_octet_index <= reg_octet_index;
  co_frame_index <= reg_frame_index;
end architecture a1;

Do not follow this link