mac_ctrl_rx_code

/*

  

Copyright (c) 2023 Alex Forencich

  

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files (the "Software"), to deal

in the Software without restriction, including without limitation the rights

to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

copies of the Software, and to permit persons to whom the Software is

furnished to do so, subject to the following conditions:

  

The above copyright notice and this permission notice shall be included in

all copies or substantial portions of the Software.

  

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY

FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

THE SOFTWARE.

  

*/

  

// Language: Verilog 2001

  

`resetall

`timescale 1ns / 1ps

`default_nettype none

  

/*

 * MAC control receive

*/

//! Bloque que se encarga de configurar el receptor MAC

module mac_ctrl_rx #

(

    parameter DATA_WIDTH = 8,                      //! Ancho de datos en bits

    parameter KEEP_ENABLE = DATA_WIDTH > 8,        //! Flag para habilitar señal de keep

    parameter KEEP_WIDTH = DATA_WIDTH / 8,         //! Ancho de la señal keep

    parameter ID_ENABLE = 0,                       //! Flag para habilitar ID

    parameter ID_WIDTH = 8,                        //! Ancho de la señal ID

    parameter DEST_ENABLE = 0,                     //! Flag para habilitar el destino

    parameter DEST_WIDTH = 8,                      //! Ancho de la señal de destino

    parameter USER_ENABLE = 1,                     //! Flag para habilitar el usuario

    parameter USER_WIDTH = 1,                      //! Ancho de la señal de usuario

    parameter USE_READY = 0,                       //! Uso de señal de ready

    parameter MCF_PARAMS_SIZE = 18                 //! Tamaño de los parámetros del marco de control MAC

)

(

    input  wire                          clk,            //! Señal de clock

    input  wire                          rst,            //! Señal de reset

    /*

    * Entrada de flujo AXI

    */

    input  wire [DATA_WIDTH-1:0]         s_axis_tdata,   //! Datos de entrada

    input  wire [KEEP_WIDTH-1:0]         s_axis_tkeep,   //! Señal keep de entrada

    input  wire                          s_axis_tvalid,  //! Señal de datos de entrada validos

    output wire                          s_axis_tready,  //! Señal de ready para datos de entrada

    input  wire                          s_axis_tlast,   //! Señal last para datos de entrada

    input  wire [ID_WIDTH-1:0]           s_axis_tid,     //! ID de entrada

    input  wire [DEST_WIDTH-1:0]         s_axis_tdest,   //! Destino de entrada

    input  wire [USER_WIDTH-1:0]         s_axis_tuser,   //! Usuario de entrada

    /*

    * Salida de flujo AXI

    */

    output wire [DATA_WIDTH-1:0]         m_axis_tdata,   //! Datos de salida

    output wire [KEEP_WIDTH-1:0]         m_axis_tkeep,   //! Señal keep de salida

    output wire                          m_axis_tvalid,  //! Señal de válida para datos de salida

    input  wire                          m_axis_tready,  //! Señal de ready para datos de salida

    output wire                          m_axis_tlast,   //! Señal last para datos de salida

    output wire [ID_WIDTH-1:0]           m_axis_tid,     //! ID de salida

    output wire [DEST_WIDTH-1:0]         m_axis_tdest,   //! Destino de salida

    output wire [USER_WIDTH-1:0]         m_axis_tuser,   //! Usuario de salida

    /*

    * Interfaz del marco de control MAC

    */

    output wire                          mcf_valid,      //! Señal de marco de control MAC valido

    output wire [47:0]                   mcf_eth_dst,    //! Dirección MAC de destino para el marco de control MAC

    output wire [47:0]                   mcf_eth_src,    //! Dirección MAC de origen para el marco de control MAC

    output wire [15:0]                   mcf_eth_type,   //! Tipo Ethernet para el marco de control MAC

    output wire [15:0]                   mcf_opcode,     //! Opcode para el marco de control MAC

    output wire [MCF_PARAMS_SIZE*8-1:0]  mcf_params,     //! Parámetros para el marco de control MAC

    output wire [ID_WIDTH-1:0]           mcf_id,         //! ID para el marco de control MAC

    output wire [DEST_WIDTH-1:0]         mcf_dest,       //! Destino para el marco de control MAC

    output wire [USER_WIDTH-1:0]         mcf_user,       //! Campo de usuario para el marco de control MAC

    /*

    * Configuración

    */

    input  wire [47:0]                   cfg_mcf_rx_eth_dst_mcast,       //! Configuración de dirección MAC de destino multicast

    input  wire                          cfg_mcf_rx_check_eth_dst_mcast, //! Verificación de dirección MAC de destino multicast

    input  wire [47:0]                   cfg_mcf_rx_eth_dst_ucast,       //! Configuración de dirección MAC de destino unicast

    input  wire                          cfg_mcf_rx_check_eth_dst_ucast, //! Verificación de dirección MAC de destino unicast

    input  wire [47:0]                   cfg_mcf_rx_eth_src,             //! Configuración de dirección MAC de origen

    input  wire                          cfg_mcf_rx_check_eth_src,       //! Verificación de dirección MAC de origen

    input  wire [15:0]                   cfg_mcf_rx_eth_type,            //! Configuración de tipo Ethernet

    input  wire [15:0]                   cfg_mcf_rx_opcode_lfc,          //! Opcode para Control de Flujo de Enlace (LFC)

    input  wire                          cfg_mcf_rx_check_opcode_lfc,    //! Verificación de opcode de Control de Flujo de Enlace (LFC)

    input  wire [15:0]                   cfg_mcf_rx_opcode_pfc,          //! Opcode para Control de Flujo de Prioridad (PFC)

    input  wire                          cfg_mcf_rx_check_opcode_pfc,    //! Verificación de opcode de Control de Flujo de Prioridad (PFC)

    input  wire                          cfg_mcf_rx_forward,             //! Configuración de habilitación de reenvío

    input  wire                          cfg_mcf_rx_enable,              //! Configuración de habilitación de recepción de marco de control MAC

    /*

     * Estado

     */

    output wire                          stat_rx_mcf     //! Salida de estado para el marco de control MAC

);

parameter BYTE_LANES = KEEP_ENABLE ? KEEP_WIDTH : 1;    //! Ancho de carriles de bytes

  

parameter HDR_SIZE = 60;                                //! Tamaño del encabezado en bytes

parameter CYCLE_COUNT = (HDR_SIZE + BYTE_LANES - 1) / BYTE_LANES; //! Cantidad de ciclos necesarios para el encabezado

parameter PTR_WIDTH = $clog2(CYCLE_COUNT);              //! Ancho del puntero para el número de ciclos

parameter OFFSET = HDR_SIZE % BYTE_LANES;               //! Desplazamiento del tamaño del encabezado en bytes

  

// check configuration

initial begin

    if (BYTE_LANES * 8 != DATA_WIDTH) begin

        $error("Error: AXI stream interface requires byte (8-bit) granularity (instance %m)");

        $finish;

    end

  

    if (MCF_PARAMS_SIZE > 44) begin

        $error("Error: Maximum MCF_PARAMS_SIZE is 44 bytes (instance %m)");

        $finish;

    end

end

  

/*

  

MAC control frame

  

 Field                       Length

 Destination MAC address     6 octets [01:80:C2:00:00:01]

 Source MAC address          6 octets

 Ethertype                   2 octets [0x8808]

 Opcode                      2 octets

 Parameters                  0-44 octets

  

This module manages the reception of MAC control frames.  Incoming frames are

checked based on the ethertype and (optionally) MAC addresses.  Matching control

frames are marked by setting tuser[0] on the data output and forwarded through

a separate interface for processing.

  

*/

  

reg read_mcf_reg = 1'b1, read_mcf_next;         //! Registro de lectura de MCF

reg mcf_frame_reg = 1'b0, mcf_frame_next;       //! Registro de marco de MCF

reg [PTR_WIDTH-1:0] ptr_reg = 0, ptr_next;      //! Registro de puntero

  

reg s_axis_tready_reg = 1'b0, s_axis_tready_next; //! Registro de listo para la salida

  

// internal datapath

reg  [DATA_WIDTH-1:0]   m_axis_tdata_int;         //! Registro para almacenar datos en el camino de datos interno

reg  [KEEP_WIDTH-1:0]   m_axis_tkeep_int;         //! Registro para almacenar señales de keep en el camino de datos interno

reg                     m_axis_tvalid_int;        //! Registro para almacenar la señal de validez en el camino de datos interno

reg                     m_axis_tready_int_reg = 1'b0; //! Registro para almacenar la señal de preparado en el camino de datos interno

reg                     m_axis_tlast_int;         //! Registro para almacenar la señal de último en el camino de datos interno

reg  [ID_WIDTH-1:0]     m_axis_tid_int;           //! Registro para almacenar el ID en el camino de datos interno

reg  [DEST_WIDTH-1:0]   m_axis_tdest_int;         //! Registro para almacenar el destino en el camino de datos interno

reg  [USER_WIDTH-1:0]   m_axis_tuser_int;         //! Registro para almacenar la información de usuario en el camino de datos interno

wire                    m_axis_tready_int_early;  //! Wire para la señal temprana de preparado en el camino de datos interno

  
  

reg                          mcf_valid_reg = 0, mcf_valid_next;         //! Válido de MCF

reg [47:0]                   mcf_eth_dst_reg = 0, mcf_eth_dst_next;     //! Destino Ethernet de MCF

reg [47:0]                   mcf_eth_src_reg = 0, mcf_eth_src_next;     //! Origen Ethernet de MCF

reg [15:0]                   mcf_eth_type_reg = 0, mcf_eth_type_next;   //! Tipo Ethernet de MCF

reg [15:0]                   mcf_opcode_reg = 0, mcf_opcode_next;       //! Opcode de MCF

reg [MCF_PARAMS_SIZE*8-1:0]  mcf_params_reg = 0, mcf_params_next;       //! Parámetros de MCF

reg [ID_WIDTH-1:0]           mcf_id_reg = 0, mcf_id_next;               //! ID de MCF

reg [DEST_WIDTH-1:0]         mcf_dest_reg = 0, mcf_dest_next;           //! Destino de MCF

reg [USER_WIDTH-1:0]         mcf_user_reg = 0, mcf_user_next;           //! Usuario de MCF

  
  

reg stat_rx_mcf_reg = 1'b0, stat_rx_mcf_next;

  

assign s_axis_tready = s_axis_tready_reg;

  

assign mcf_valid = mcf_valid_reg;

assign mcf_eth_dst = mcf_eth_dst_reg;

assign mcf_eth_src = mcf_eth_src_reg;

assign mcf_eth_type = mcf_eth_type_reg;

assign mcf_opcode = mcf_opcode_reg;

assign mcf_params = mcf_params_reg;

assign mcf_id = mcf_id_reg;

assign mcf_dest = mcf_dest_reg;

assign mcf_user = mcf_user_reg;

  

assign stat_rx_mcf = stat_rx_mcf_reg;

  

wire mcf_eth_dst_mcast_match = mcf_eth_dst_next == cfg_mcf_rx_eth_dst_mcast;

wire mcf_eth_dst_ucast_match = mcf_eth_dst_next == cfg_mcf_rx_eth_dst_ucast;

wire mcf_eth_src_match = mcf_eth_src_next == cfg_mcf_rx_eth_src;

wire mcf_eth_type_match = mcf_eth_type_next == cfg_mcf_rx_eth_type;

wire mcf_opcode_lfc_match = mcf_opcode_next == cfg_mcf_rx_opcode_lfc;

wire mcf_opcode_pfc_match = mcf_opcode_next == cfg_mcf_rx_opcode_pfc;

  

wire mcf_eth_dst_match = ((mcf_eth_dst_mcast_match && cfg_mcf_rx_check_eth_dst_mcast) ||

    (mcf_eth_dst_ucast_match && cfg_mcf_rx_check_eth_dst_ucast) ||

    (!cfg_mcf_rx_check_eth_dst_mcast && !cfg_mcf_rx_check_eth_dst_ucast));

  

wire mcf_opcode_match = ((mcf_opcode_lfc_match && cfg_mcf_rx_check_opcode_lfc) ||

    (mcf_opcode_pfc_match && cfg_mcf_rx_check_opcode_pfc) ||

    (!cfg_mcf_rx_check_opcode_lfc && !cfg_mcf_rx_check_opcode_pfc));

  

wire mcf_match = (mcf_eth_dst_match &&

    (mcf_eth_src_match || !cfg_mcf_rx_check_eth_src) &&

    mcf_eth_type_match && mcf_opcode_match);

  

integer k;

  

//! Implementa la lógica para capturar y procesar un encabezado MAC desde un flujo de datos AXI, almacenando sus campos en registros internos y tomando decisiones basadas en configuraciones y señales de control

always @* begin

    read_mcf_next = read_mcf_reg;

    mcf_frame_next = mcf_frame_reg;

    ptr_next = ptr_reg;

  

    // pass through data

    m_axis_tdata_int = s_axis_tdata;

    m_axis_tkeep_int = s_axis_tkeep;

    m_axis_tvalid_int = s_axis_tvalid;

    m_axis_tlast_int = s_axis_tlast;

    m_axis_tid_int = s_axis_tid;

    m_axis_tdest_int = s_axis_tdest;

    m_axis_tuser_int = s_axis_tuser;

  

    s_axis_tready_next = m_axis_tready_int_early || !USE_READY;

  

    mcf_valid_next = 1'b0;

    mcf_eth_dst_next = mcf_eth_dst_reg;

    mcf_eth_src_next = mcf_eth_src_reg;

    mcf_eth_type_next = mcf_eth_type_reg;

    mcf_opcode_next = mcf_opcode_reg;

    mcf_params_next = mcf_params_reg;

    mcf_id_next = mcf_id_reg;

    mcf_dest_next = mcf_dest_reg;

    mcf_user_next = mcf_user_reg;

  

    stat_rx_mcf_next = 1'b0;

  

    // si el canal de salida está listo (o no se utiliza el ready) y el canal de entrada es válido

    if ((s_axis_tready || !USE_READY) && s_axis_tvalid) begin

        // si se está leyendo el registro de control MAC

        if (read_mcf_reg) begin

            ptr_next = ptr_reg + 1; // incrementa el puntero para el siguiente byte

  

            // captura los campos del encabezado MAC

            mcf_id_next = s_axis_tid; // captura el ID del encabezado

            mcf_dest_next = s_axis_tdest; // captura el destino del encabezado

            mcf_user_next = s_axis_tuser; // captura el usuario del encabezado

  

            // macro para leer campos del encabezado según el offset

            `define _HEADER_FIELD_(offset, field) \

                if (ptr_reg == offset/BYTE_LANES) begin \

                    field = s_axis_tdata[(offset%BYTE_LANES)*8 +: 8]; \

                end

  

            `_HEADER_FIELD_(0,  mcf_eth_dst_next[5*8 +: 8])   // captura la parte alta de la dirección de destino

            `_HEADER_FIELD_(1,  mcf_eth_dst_next[4*8 +: 8])   // captura la siguiente parte de la dirección de destino

            `_HEADER_FIELD_(2,  mcf_eth_dst_next[3*8 +: 8])   // captura la siguiente parte de la dirección de destino

            `_HEADER_FIELD_(3,  mcf_eth_dst_next[2*8 +: 8])   // captura la siguiente parte de la dirección de destino

            `_HEADER_FIELD_(4,  mcf_eth_dst_next[1*8 +: 8])   // captura la siguiente parte de la dirección de destino

            `_HEADER_FIELD_(5,  mcf_eth_dst_next[0*8 +: 8])   // captura la parte baja de la dirección de destino

            `_HEADER_FIELD_(6,  mcf_eth_src_next[5*8 +: 8])   // captura la parte alta de la dirección de origen

            `_HEADER_FIELD_(7,  mcf_eth_src_next[4*8 +: 8])   // captura la siguiente parte de la dirección de origen

            `_HEADER_FIELD_(8,  mcf_eth_src_next[3*8 +: 8])   // captura la siguiente parte de la dirección de origen

            `_HEADER_FIELD_(9,  mcf_eth_src_next[2*8 +: 8])   // captura la siguiente parte de la dirección de origen

            `_HEADER_FIELD_(10, mcf_eth_src_next[1*8 +: 8])   // captura la siguiente parte de la dirección de origen

            `_HEADER_FIELD_(11, mcf_eth_src_next[0*8 +: 8])   // captura la parte baja de la dirección de origen

            `_HEADER_FIELD_(12, mcf_eth_type_next[1*8 +: 8])  // captura el byte alto del tipo de Ethernet

            `_HEADER_FIELD_(13, mcf_eth_type_next[0*8 +: 8])  // captura el byte bajo del tipo de Ethernet

            `_HEADER_FIELD_(14, mcf_opcode_next[1*8 +: 8])    // captura el byte alto del código de operación

            `_HEADER_FIELD_(15, mcf_opcode_next[0*8 +: 8])    // captura el byte bajo del código de operación

  

            // si está en el primer byte de los parámetros, se limpia el campo

            if (ptr_reg == 0/BYTE_LANES) begin

                mcf_params_next = 0;

            end

  

            // captura de parámetros adicionales del encabezado MAC

            for (k = 0; k < MCF_PARAMS_SIZE; k = k + 1) begin

                if (ptr_reg == (16+k)/BYTE_LANES) begin

                    mcf_params_next[k*8 +: 8] = s_axis_tdata[((16+k)%BYTE_LANES)*8 +: 8];

                end

            end

  

            // si está en el último byte del encabezado MAC y se cumple la condición de 'keep'

            if (ptr_reg == 15/BYTE_LANES && (!KEEP_ENABLE || s_axis_tkeep[13%BYTE_LANES])) begin

                // se registra la coincidencia al final del campo de opcode

                mcf_frame_next = mcf_match && cfg_mcf_rx_enable;

            end

  

            // si se llega al último byte del encabezado MAC

            if (ptr_reg == (HDR_SIZE-1)/BYTE_LANES) begin

                read_mcf_next = 1'b0; // termina la lectura del encabezado

            end

  

            `undef _HEADER_FIELD_ // se deshace la macro

        end

  

        // si se recibe el último byte del paquete

        if (s_axis_tlast) begin

            // si el paquete está marcado como inválido

            if (s_axis_tuser[0]) begin

                // el marco está marcado como inválido

            end else if (mcf_frame_next) begin

                // si no se debe reenviar el paquete, se marca como inválido

                if (!cfg_mcf_rx_forward) begin

                    m_axis_tuser_int[0] = 1'b1;

                end

                // se transfiere el encabezado MAC saliente

                mcf_valid_next = 1'b1;

                stat_rx_mcf_next = 1'b1;

            end

  

            // se prepara para leer el siguiente encabezado

            read_mcf_next = 1'b1;

            mcf_frame_next = 1'b0;

            ptr_next = 0;

        end

    end

  

end

  

//! Actualiza datos con la señal del clock

always @(posedge clk) begin

    read_mcf_reg <= read_mcf_next;

    mcf_frame_reg <= mcf_frame_next;

    ptr_reg <= ptr_next;

  

    s_axis_tready_reg <= s_axis_tready_next;

  

    mcf_valid_reg <= mcf_valid_next;

    mcf_eth_dst_reg <= mcf_eth_dst_next;

    mcf_eth_src_reg <= mcf_eth_src_next;

    mcf_eth_type_reg <= mcf_eth_type_next;

    mcf_opcode_reg <= mcf_opcode_next;

    mcf_params_reg <= mcf_params_next;

    mcf_id_reg <= mcf_id_next;

    mcf_dest_reg <= mcf_dest_next;

    mcf_user_reg <= mcf_user_next;

  

    stat_rx_mcf_reg <= stat_rx_mcf_next;

  

    if (rst) begin

        read_mcf_reg <= 1'b1;

        mcf_frame_reg <= 1'b0;

        ptr_reg <= 0;

        s_axis_tready_reg <= 1'b0;

        mcf_valid_reg <= 1'b0;

        stat_rx_mcf_reg <= 1'b0;

    end

end

  

// output datapath logic

reg [DATA_WIDTH-1:0] m_axis_tdata_reg  = {DATA_WIDTH{1'b0}};        //! Registro para datos de salida

reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg  = {KEEP_WIDTH{1'b0}};        //! Registro para mantener bits de datos de salida válidos

reg                  m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;  //! Registro de señal de validez actual y siguiente

reg                  m_axis_tlast_reg  = 1'b0;                      //! Registro de señal de último dato de salida

reg [ID_WIDTH-1:0]   m_axis_tid_reg    = {ID_WIDTH{1'b0}};          //! Registro de identificador de transacción de salida

reg [DEST_WIDTH-1:0] m_axis_tdest_reg  = {DEST_WIDTH{1'b0}};        //! Registro de destino de transacción de salida

reg [USER_WIDTH-1:0] m_axis_tuser_reg  = {USER_WIDTH{1'b0}};        //! Registro de datos de usuario de salida

  

reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg  = {DATA_WIDTH{1'b0}};   //! Registro temporal para datos de salida

reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg  = {KEEP_WIDTH{1'b0}};   //! Registro temporal para mantener bits de datos de salida válidos

reg                  temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next; //! Registro temporal de señal de validez actual y siguiente

reg                  temp_m_axis_tlast_reg  = 1'b0;                 //! Registro temporal de señal de último dato de salida

reg [ID_WIDTH-1:0]   temp_m_axis_tid_reg    = {ID_WIDTH{1'b0}};     //! Registro temporal de identificador de transacción de salida

reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg  = {DEST_WIDTH{1'b0}};   //! Registro temporal de destino de transacción de salida

reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg  = {USER_WIDTH{1'b0}};   //! Registro temporal de datos de usuario de salida

  

// datapath control

reg store_axis_int_to_output;                                       //! Señal para almacenar datos internos en la salida

reg store_axis_int_to_temp;                                         //! Señal para almacenar datos internos en el registro temporal

reg store_axis_temp_to_output;                                      //! Señal para almacenar datos temporales en la salida

  

assign m_axis_tdata  = m_axis_tdata_reg;

assign m_axis_tkeep  = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};

assign m_axis_tvalid = m_axis_tvalid_reg;

assign m_axis_tlast  = m_axis_tlast_reg;

assign m_axis_tid    = ID_ENABLE   ? m_axis_tid_reg   : {ID_WIDTH{1'b0}};

assign m_axis_tdest  = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};

assign m_axis_tuser  = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};

  

// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)

assign m_axis_tready_int_early = m_axis_tready || !USE_READY || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid_reg || !m_axis_tvalid_int));

  

//! Gestiona la transferencia del estado listo del destino hacia la fuente de datos

always @* begin

    // transfer sink ready state to source

    m_axis_tvalid_next = m_axis_tvalid_reg;

    temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;

  

    store_axis_int_to_output = 1'b0;

    store_axis_int_to_temp = 1'b0;

    store_axis_temp_to_output = 1'b0;

  

    if (m_axis_tready_int_reg) begin

        // input is ready

        if (m_axis_tready || !USE_READY || !m_axis_tvalid_reg) begin

            // output is ready or currently not valid, transfer data to output

            m_axis_tvalid_next = m_axis_tvalid_int;

            store_axis_int_to_output = 1'b1;

        end else begin

            // output is not ready, store input in temp

            temp_m_axis_tvalid_next = m_axis_tvalid_int;

            store_axis_int_to_temp = 1'b1;

        end

    end else if (m_axis_tready || !USE_READY) begin

        // input is not ready, but output is ready

        m_axis_tvalid_next = temp_m_axis_tvalid_reg;

        temp_m_axis_tvalid_next = 1'b0;

        store_axis_temp_to_output = 1'b1;

    end

end

  

//! Maneja la lógica de transferencia de datos entre diferentes etapas, asegurando que los datos sean correctamente almacenados y transferidos conforme a las condiciones de listo y a las señales de control disponibles

always @(posedge clk) begin

    m_axis_tvalid_reg <= m_axis_tvalid_next;

    m_axis_tready_int_reg <= m_axis_tready_int_early;

    temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;

  

    // datapath

    if (store_axis_int_to_output) begin

        m_axis_tdata_reg <= m_axis_tdata_int;

        m_axis_tkeep_reg <= m_axis_tkeep_int;

        m_axis_tlast_reg <= m_axis_tlast_int;

        m_axis_tid_reg   <= m_axis_tid_int;

        m_axis_tdest_reg <= m_axis_tdest_int;

        m_axis_tuser_reg <= m_axis_tuser_int;

    end else if (store_axis_temp_to_output) begin

        m_axis_tdata_reg <= temp_m_axis_tdata_reg;

        m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;

        m_axis_tlast_reg <= temp_m_axis_tlast_reg;

        m_axis_tid_reg   <= temp_m_axis_tid_reg;

        m_axis_tdest_reg <= temp_m_axis_tdest_reg;

        m_axis_tuser_reg <= temp_m_axis_tuser_reg;

    end

  

    if (store_axis_int_to_temp) begin

        temp_m_axis_tdata_reg <= m_axis_tdata_int;

        temp_m_axis_tkeep_reg <= m_axis_tkeep_int;

        temp_m_axis_tlast_reg <= m_axis_tlast_int;

        temp_m_axis_tid_reg   <= m_axis_tid_int;

        temp_m_axis_tdest_reg <= m_axis_tdest_int;

        temp_m_axis_tuser_reg <= m_axis_tuser_int;

    end

  

    if (rst) begin

        m_axis_tvalid_reg <= 1'b0;

        m_axis_tready_int_reg <= 1'b0;

        temp_m_axis_tvalid_reg <= 1'b0;

    end

end

  

endmodule

  

`resetall