~ruther/jesd204b-vhdl

584e9e0aeebf25920edc7b70533604b9f2f8b285 — František Boháček 2 years ago dd7efc9
feat(link): add char alignment
2 files changed, 128 insertions(+), 0 deletions(-)

A src/data_link/char_alignment.vhd
A testbench/char_alignment_tb.vhd
A src/data_link/char_alignment.vhd => src/data_link/char_alignment.vhd +97 -0
@@ 0,0 1,97 @@
-------------------------------------------------------------------------------
-- Title      : Synchronize with character start
-- Project    : JESD204B Receiver
-------------------------------------------------------------------------------
-- File       : char_alignment.vhd
-- Description: Tries to align the beginning of the character from 8b/10b encoding.
-- Accepting 10 bits, outputting 8 bits. Will try to sync to /K/ character when
-- synced is false.
-------------------------------------------------------------------------------

-- input d_in[9:0], ci_synced
-- output co_aligned, d_out[9:0]

library ieee;
use ieee.std_logic_1164.all;

entity char_alignment is
  
  generic (
    sync_char : std_logic_vector(9 downto 0) := "0011111010"  -- The character used for synchronization (positive RD)
    );
  port (
    ci_char_clk: in std_logic;          -- The character clock
    ci_reset   : in std_logic;          -- The reset, active high.
    di_10b     : in  std_logic_vector(9 downto 0);  -- The 8b/10b encoded input data from physical layer
    ci_synced  : in  std_logic;  -- Whether the receiver is currently synchronized
    do_10b     : out std_logic_vector(9 downto 0);  -- The 8b/10b encoded data aligned with a character (if co_aligned is true, otherwise unknown)
    co_aligned : out std_logic);  -- Whether the output is currently aligned

end entity char_alignment;

architecture a1 of char_alignment is
  signal next_cache_10b : std_logic_vector(19 downto 0) := (others => '0');  -- The next value of cache_10b
  signal next_do_10b : std_logic_vector(9 downto 0) := (others => '0');  -- The next value of do_10b
  signal next_co_aligned : std_logic := '0';  

  signal reg_found_sync_char : std_logic := '0';  -- Whether sync char was found
  signal reg_cache_10b : std_logic_vector(19 downto 0) := (others => '0');  -- The cache of 10b characters.
  signal reg_do_10b : std_logic_vector(9 downto 0) := (others => '0');
  signal reg_alignment_index : integer := 0;  -- Where the character starts in the cache, if aligned.
  signal reg_last_synced : std_logic := '0';  -- The last value of ci_synced
  signal reg_co_aligned : std_logic := '0';  -- Whether aligned
begin  -- architecture a1

  -- purpose: Set next signals
  -- type   : combinational
  -- inputs : clk, reset
  -- outputs: alignment_index, cache_10b, do_10b, co_aligned
  set_next: process (ci_char_clk, ci_reset) is
  begin  -- process set_next
    if ci_reset = '0' then
      reg_last_synced <= '0';
      reg_co_aligned <= '0';
      reg_cache_10b <= (others => '0');
      reg_do_10b <= (others => '0');
    elsif rising_edge(ci_char_clk) then
      reg_last_synced <= ci_synced;
      reg_co_aligned <= next_co_aligned;
      reg_cache_10b <= next_cache_10b;
      reg_do_10b <= next_do_10b;
    end if;
  end process set_next;

  -- purpose: Tries to find the sync character if synced is false
  -- type   : sequential
  -- inputs : ci_char_clk, ci_reset, di_10b, ci_synced
  -- outputs: reg_found_sync_char, reg_alignment_index
  find_sync_char: process (ci_char_clk, ci_reset) is
  begin  -- process find_sync_char
    if ci_reset = '0' then              -- asynchronous reset (active low)
      reg_alignment_index <= 0;
      reg_found_sync_char <= '0';
    elsif rising_edge(ci_char_clk) then  -- rising clock edge
      if reg_found_sync_char = '1' then
        reg_found_sync_char <= '0';
      end if;
      -- Try to find /K/ character again and again until ci_synced is one (that
      -- will be set by 8b10b_decoder)
      if ci_synced = '0' then
        -- Try to find /K/ (sync_char) in either RD (either sync_char or not sync_char).
        for i in 0 to 9 loop
          if reg_cache_10b((9-i)+9 downto (9-i)) = sync_char or reg_cache_10b((9-i)+9 downto (9-i)) = not sync_char then
            reg_found_sync_char <= '1';
            reg_alignment_index <= 9 - i;
          end if;
        end loop;  -- i
      end if;
    end if;
  end process find_sync_char;

  co_aligned <= reg_co_aligned;
  do_10b <= reg_do_10b;

  next_co_aligned <= (reg_found_sync_char or reg_co_aligned) and not (reg_last_synced and not ci_synced);
  next_do_10b(9 downto 0) <= reg_cache_10b(reg_alignment_index+9 downto reg_alignment_index);
  next_cache_10b(19 downto 0) <= di_10b(9 downto 0) & reg_cache_10b(19 downto 10);
end architecture a1;

A testbench/char_alignment_tb.vhd => testbench/char_alignment_tb.vhd +31 -0
@@ 0,0 1,31 @@
library ieee;
use ieee.std_logic_1164.all;

entity char_alignment_tb is
end entity char_alignment_tb;

architecture a1 of char_alignment_tb is
  constant clk_period : time := 1 ns;    -- The clock period
  constant buffer_positions : integer := 2;

  signal clk : std_logic := '0';        -- The clock
  signal reset : std_logic := '0';      -- The reset

  signal synced : std_logic := '0';     -- Whether synced
  signal data_10b : std_logic_vector(9 downto 0) := (others => '0');  -- The 10b data input

  signal buffer_position : integer := 0;
  signal data_10b_buffer : std_logic_vector(10*2-1 downto 0) := "00111100110011110011";  -- The 10b data input
begin  -- architecture a1
  uut: entity work.char_alignment
    port map (
      ci_char_clk => clk,
      ci_reset    => reset,
      di_10b      => data_10b,
      ci_synced   => synced);

  data_10b <= data_10b_buffer(buffer_position*10+9 downto buffer_position*10);
  buffer_position <= (buffer_position + 1) mod buffer_positions after clk_period;
  clk <= not clk after clk_period/2;
  reset <= '1' after clk_period*2;
end architecture a1;