From 584e9e0aeebf25920edc7b70533604b9f2f8b285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 30 Oct 2022 21:36:22 +0100 Subject: [PATCH] feat(link): add char alignment --- src/data_link/char_alignment.vhd | 97 ++++++++++++++++++++++++++++++++ testbench/char_alignment_tb.vhd | 31 ++++++++++ 2 files changed, 128 insertions(+) create mode 100644 src/data_link/char_alignment.vhd create mode 100644 testbench/char_alignment_tb.vhd diff --git a/src/data_link/char_alignment.vhd b/src/data_link/char_alignment.vhd new file mode 100644 index 0000000000000000000000000000000000000000..98f4464ae26a9c46a1677979946904010d2452d1 --- /dev/null +++ b/src/data_link/char_alignment.vhd @@ -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; diff --git a/testbench/char_alignment_tb.vhd b/testbench/char_alignment_tb.vhd new file mode 100644 index 0000000000000000000000000000000000000000..03253e1ff0fad68db8ec782a8d26228281aeb78e --- /dev/null +++ b/testbench/char_alignment_tb.vhd @@ -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;