`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/03/20 14:56:39
// Design Name: 
// Module Name: axi_m_rd
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_m_rd(
    input                              ui_clk_i,
    input                              ui_rst_i,
    
    // Master Interface Read Address Ports
    output [3:0]                        m_axi_arid_o,
    output [32:0]                       m_axi_araddr_o,
    output [7:0]                        m_axi_arlen_o,
    output [2:0]                        m_axi_arsize_o,
    output [1:0]                        m_axi_arburst_o,
    output [0:0]                        m_axi_arlock_o,
    output [3:0]                        m_axi_arcache_o,
    output [2:0]                        m_axi_arprot_o,
    output                              m_axi_arvalid_o,
    input                               m_axi_arready_i,
    // Master Interface Read Data Ports
    output                              m_axi_rready_o,
    input [3:0]                         m_axi_rid_i,
    input [32:0]                        m_axi_rdata_i,
    input [1:0]                         m_axi_rresp_i,
    input                               m_axi_rlast_i,
    input                               m_axi_rvalid_i,

    input                               rd_fifo_empty_i,
    output                              rd_fifo_re_o,
    input [32:0]                        rd_fifo_addr_i,
    input [7:0]                         rd_fifo_len_i,

    input                               rd_fifo_almost_full_i,
    output                              rd_fifo_we_o,
    output [511:0]                      rd_fifo_din_o
    );

    localparam
        S_RD_IDLE       = 5'b00001,
        S_RD_ADDR_START = 5'b00010,
        S_RD_ADDR_WAIT  = 5'b00100,
        S_RD_DATA       = 5'b01000,
        S_RD_DONE       = 5'b10000;

    reg [ 4:0] c_state;
    reg [ 4:0] n_state;

    reg        rd_fifo_re;

    reg [32:0] rd_addr;
    reg        rd_addr_v;
    reg [ 7:0] rd_len;

    reg        m_axi_rready;

    assign  m_axi_arid_o    = 4'h0;
    assign  m_axi_araddr_o  = rd_addr;
    assign  m_axi_arlen_o   = rd_len - 8'b1;
    assign  m_axi_arsize_o  = 3'b110;   // 512 bit
    assign  m_axi_arburst_o = 2'b01;    // inc mode
    assign  m_axi_arlock_o  = 1'b0;
    assign  m_axi_arcache_o = 4'b0000;
    assign  m_axi_arprot_o  = 3'b000;
    assign  m_axi_arvalid_o = rd_addr_v;
    assign  m_axi_rready_o  = m_axi_rready;

    assign  rd_fifo_re_o    = rd_fifo_re;

    assign rd_fifo_we_o     = m_axi_rvalid_i;
    assign rd_fifo_din_o    = m_axi_rdata_i;

    always @(posedge ui_clk_i or posedge ui_rst_i) begin
        if(ui_rst_i) begin
            c_state <= S_RD_IDLE;
        end
        else begin
            c_state <= n_state;
        end
    end

    always @(*) begin
        n_state         = S_RD_IDLE;
        rd_fifo_re      = 1'b0;
        rd_addr         = 33'b0;
        rd_len          = 8'b0;
        rd_addr_v       = 1'b0;
        m_axi_rready    = 1'b0;

        case(c_state)
            S_RD_IDLE: begin
                if(!rd_fifo_empty_i) begin
                    rd_fifo_re  = 1'b1;
                    n_state     = S_RD_ADDR_START;
                end
                else begin
                    n_state     = S_RD_IDLE;
                end
            end
            S_RD_ADDR_START: begin
                rd_addr     = rd_fifo_addr_i;
                rd_len      = rd_fifo_len_i;
                rd_addr_v   = 1'b1;
                n_state     = S_RD_ADDR_WAIT;
            end
            S_RD_ADDR_WAIT: begin
                if(m_axi_arready_i) begin
                    n_state     = S_RD_DATA;
                end
                else begin
                    rd_addr      = rd_addr  ;
                    rd_len       = rd_len   ;
                    rd_addr_v    = rd_addr_v;
                    m_axi_rready = 1'b1;
                    n_state      = S_RD_ADDR_WAIT;
                end
            end
            S_RD_DATA: begin
                m_axi_rready = 1'b1;
                casex({m_axi_rvalid_i, m_axi_rlast_i, rd_fifo_almost_full_i})
                    3'b0xx: begin
                        n_state     = S_RD_DATA;
                    end
                    3'b11x: begin // last in full
                        n_state     = S_RD_DONE;
                    end
                    3'b100: begin
                        n_state     = S_RD_DATA;
                    end
                    3'b101: begin // overflow
                        n_state     = S_RD_DATA;
                    end
                endcase
            end
            S_RD_DONE: begin
                n_state     = S_RD_IDLE;
            end
        endcase
    end

endmodule
