----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 09/30/2025 05:47:45 PM
-- Design Name: 
-- Module Name: eth_frame_unpacker - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity eth_frame_unpacker is
  port (
    clk           : in  std_logic;
    resetn        : in  std_logic;  -- active-low synchronous reset

    s_axis_tdata  : in  std_logic_vector(511 downto 0);
    s_axis_tvalid : in  std_logic;
    s_axis_tlast  : in  std_logic;
    s_axis_tkeep  : in  std_logic_vector(63 downto 0);
    s_axis_tuser  : in  std_logic; -- frame error indicator (qualified by s_axis_tvalid and s_axis_tlast)

    m_axis_tdata  : out std_logic_vector(511 downto 0);
    m_axis_tvalid : out std_logic;
    m_axis_tlast  : out std_logic;
    m_axis_tuser  : out std_logic;  -- frame error indicator (qualified by m_axis_tvalid and m_axis_tlast)

    rx_frame_err_cnt : out std_logic_vector(31 downto 0);
    rx_frame_cnt     : out std_logic_vector(31 downto 0)
  );
end entity;

architecture rtl of eth_frame_unpacker is

  type state_type is (IDLE, RUN);

  signal state_r          : state_type := IDLE;
  signal state            : state_type;
  signal carry            : std_logic_vector(399 downto 0);
  signal carry_r          : std_logic_vector(399 downto 0) := (others => '0');
  signal frame_err_cnt_i  : std_logic_vector(31 downto 0);
  signal frame_err_cnt_r  : std_logic_vector(31 downto 0) := (others => '0');
  signal frame_cnt_i      : std_logic_vector(31 downto 0);
  signal frame_cnt_r      : std_logic_vector(31 downto 0) := (others => '0');
  signal m_tvalid         : std_logic;
  signal m_tvalid_r       : std_logic := '0';
  signal m_tdata          : std_logic_vector(511 downto 0);
  signal m_tdata_r        : std_logic_vector(511 downto 0) := (others => '0');
  signal m_tuser          : std_logic;
  signal m_tuser_r        : std_logic := '0';
  signal m_tlast          : std_logic;
  signal m_tlast_r        : std_logic := '0';

begin

  -- Drive outputs
  m_axis_tuser      <= m_tuser_r;
  m_axis_tdata      <= m_tdata_r;
  m_axis_tlast      <= m_tlast_r;
  m_axis_tvalid     <= m_tvalid_r;
  rx_frame_err_cnt  <= frame_err_cnt_r;
  rx_frame_cnt      <= frame_cnt_r;

  -----------------------------------------------------------------------------
  -- Combinational next-state / next-data
  -----------------------------------------------------------------------------
  process(state_r, carry_r, m_tdata_r, m_tuser_r, m_tlast_r, frame_err_cnt_r,
          s_axis_tdata, s_axis_tvalid, s_axis_tlast, s_axis_tuser, frame_cnt_r)
  begin
    -- Defaults
    state           <= state_r;
    carry           <= carry_r;
    frame_err_cnt_i <= frame_err_cnt_r;
    frame_cnt_i     <= frame_cnt_r; 
    m_tvalid        <= '0';
    m_tdata         <= m_tdata_r;
    m_tuser         <= m_tuser_r; 
    m_tlast         <= m_tlast_r;

    case state_r is
      -------------------------------------------------------------------------
      when IDLE =>     
        if s_axis_tvalid = '1' then
          -- cache high 50B; no output yet (need second beat to form first 64B payload)
          carry(399 downto 0) <= s_axis_tdata(511 downto 112);
          state               <= RUN;
        end if;
      -------------------------------------------------------------------------
      when RUN =>
        if s_axis_tvalid = '1' then
          carry(399 downto 0) <= s_axis_tdata(511 downto 112);
          m_tdata             <= s_axis_tdata(111 downto 0) & carry_r;
          m_tvalid            <= '1';
          m_tuser             <= s_axis_tuser;
          m_tlast             <= s_axis_tlast;          
          if(s_axis_tlast = '1')then
            state <= IDLE;
            frame_cnt_i <= std_logic_vector(unsigned(frame_cnt_r) +1);
          end if;         
          if(s_axis_tlast = '1' and s_axis_tuser = '1')then
            frame_err_cnt_i <= std_logic_vector(unsigned(frame_err_cnt_r) +1);
          end if;
        end if;
      -------------------------------------------------------------------------
    end case;
  end process;

  -----------------------------------------------------------------------------
  -- Regs
  -----------------------------------------------------------------------------
  seq_proc : process(clk)
  begin
    if rising_edge(clk) then   
      if resetn = '0' then
        state_r         <= IDLE;       
        frame_err_cnt_r <= (others => '0');
        frame_cnt_r     <= (others => '0');
        m_tvalid_r      <= '0';       
      else
        state_r         <= state;
        frame_err_cnt_r <= frame_err_cnt_i;
        frame_cnt_r     <= frame_cnt_i;
        m_tvalid_r      <= m_tvalid;
      end if;      
      carry_r           <= carry;
      m_tdata_r         <= m_tdata;        
      m_tuser_r         <= m_tuser;        
      m_tlast_r         <= m_tlast;     
    end if;
  end process;
end architecture;

