`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/03/20 16:05:32
// Design Name: 
// Module Name: axi_m_wr
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_m_wr(
    input                              ui_clk_i,
    input                              ui_rst_i,

    // Master Interface Write Address Ports
    output [3:0]                       m_axi_awid_o,
    output [32:0]                      m_axi_awaddr_o,
    output [7:0]                       m_axi_awlen_o,
    output [2:0]                       m_axi_awsize_o,
    output [1:0]                       m_axi_awburst_o,
    output [0:0]                       m_axi_awlock_o,
    output [3:0]                       m_axi_awcache_o,
    output [2:0]                       m_axi_awprot_o,
    output                             m_axi_awvalid_o,
    input                              m_axi_awready_i,
    // Master Interface Write Data Ports
    output [512:0]                     m_axi_wdata_o,
    output [63:0]                      m_axi_wstrb_o,
    output                             m_axi_wlast_o,
    output                             m_axi_wvalid_o,
    input                              m_axi_wready_i,
    // Master Interface Write Response Ports
    output                             m_axi_bready_o,
    input [3:0]                        m_axi_bid_i,
    input [1:0]                        m_axi_bresp_i,
    input                              m_axi_bvalid_i,
 
    input                              wr_fifo_empty_i,
    output                             wr_fifo_re_o,
    input [32:0]                       wr_fifo_addr_i,
    input [7:0]                        wr_fifo_len_i,
    input [511:0]                      wr_fifo_data_i,
    input [63:0]                       wr_fifo_mask_i
    );

    localparam
        S_WR_IDLE       = 5'b00001,
        S_WR_ADDR_START = 5'b00010,
        S_WR_ADDR_WAIT  = 5'b00100,
        S_WR_DATA       = 5'b01000,
        S_WR_DONE       = 5'b10000;

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

    reg         wr_fifo_re;
    reg [32:0]  wr_addr;
    reg [7:0]   wr_len;
    reg         wr_addr_v;
    reg [511:0] wr_data;
    reg [63:0]  wr_mask;
    reg         wr_data_v;
    reg         wr_last;

    reg         m_axi_bready;

    assign wr_fifo_re_o    = wr_fifo_re;
    assign m_axi_awid_o    = 4'h0;
    assign m_axi_awaddr_o  = wr_addr;
    assign m_axi_awlen_o   = 8'b0;
    assign m_axi_awsize_o  = 3'b110; // 512 bit
    assign m_axi_awburst_o = 2'b01; // inc mode
    assign m_axi_awlock_o  = 1'b0;
    assign m_axi_awcache_o = 4'b0000;
    assign m_axi_awprot_o  = 3'b000;
    assign m_axi_awvalid_o = wr_addr_v;
    assign m_axi_wdata_o   = wr_data;
    assign m_axi_wstrb_o   = wr_mask;
    assign m_axi_wlast_o   = wr_last;
    assign m_axi_wvalid_o  = wr_data_v;
    assign m_axi_bready_o  = m_axi_bready;

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

    always @(*) begin
        n_state     = S_WR_IDLE;
        wr_fifo_re  = 1'b0;
        wr_addr     = 33'b0;
        wr_len      = 8'b0;
        wr_addr_v   = 1'b0;
        wr_data     = 512'b0;
        wr_mask     = 64'b0;
        wr_data_v   = 1'b0;
        wr_last     = 1'b0;
        m_axi_bready = 1'b0;

        case(c_state)
            S_WR_IDLE: begin
                if(!wr_fifo_empty_i) begin
                    wr_fifo_re  = 1'b1;
                    n_state     = S_WR_ADDR_START;
                end
                else begin
                    n_state = S_WR_IDLE;
                end
            end
            S_WR_ADDR_START: begin
                wr_addr     = wr_fifo_addr_i;
                wr_len      = wr_fifo_len_i;
                wr_addr_v   = 1'b1;
                wr_data     = wr_fifo_data_i;
                wr_mask     = wr_fifo_mask_i;
                n_state     = S_WR_ADDR_WAIT;
            end
            S_WR_ADDR_WAIT: begin
                if(m_axi_awready_i) begin
                    wr_data_v   = 1'b1;
                    n_state     = S_WR_DATA;
                end
                else begin
                    wr_addr     = wr_addr;
                    wr_len      = wr_len;
                    wr_addr_v   = wr_addr_v;
                    wr_data     = wr_data;
                    wr_mask     = wr_mask;
                    n_state     = S_WR_ADDR_WAIT;
                end
            end
            S_WR_DATA: begin
                if(m_axi_wready_i) begin
                    wr_last     = 1'b1;
                    n_state     = S_WR_DONE;
                end
                else begin
                    wr_data     = wr_data;
                    wr_mask     = wr_mask;
                    wr_data_v   = wr_data_v;
                    n_state     = S_WR_DATA;
                end
            end
            S_WR_DONE: begin
                if(m_axi_bvalid_i && m_axi_bresp_i == 2'b00) begin
                    n_state = S_WR_IDLE;
                end
                else begin
                    n_state = S_WR_DONE;
                end
            end
        endcase
    end


endmodule
