module array_status_ctrl(
    
    input               clk,
    input               rst_n,

    input               axi2array_frame_valid,
    input [152:0]       axi2array_frame_data,
    output              axi2array_frame_ready,

    output              array_wr_frame_valid,
    output [151:0]      array_wr_frame_data,
    input               array_wr_frame_ready,
    input               array_wr_done,

    output              array_rd_frame_valid,
    output [151:0]      array_rd_frame_data,
    input               array_rd_frame_ready,
    input               array_rd_done,

    output              array_ref_start,
    input               array_ref_done,

    output [1:0]        array_mux_sel,

    input               mc_work_en,
    input               array_ref_en,
    input [24:0]        array_inner_tref0,
    input [24:0]        array_inner_tref1,
    input               array_inner_ref_sel
);

    reg         [1:0]   cur_state,next_state;
    localparam  [1:0]   ARRAY_STA_IDLE = 2'b00;
    localparam  [1:0]   ARRAY_STA_WR   = 2'b10;
    localparam  [1:0]   ARRAY_STA_RD   = 2'b11;
    localparam  [1:0]   ARRAY_STA_REF  = 2'b01;

    reg                 mc_work_en_r    ,mc_work_en_sync;
    reg                 array_ref_en_r  ,array_ref_en_sync;
    reg                 array_inner_ref_sel_r,array_inner_ref_sel_sync;
    reg                 array_ref_req;
    reg     [24:0]      array_ref_cnt;
    wire    [24:0]      array_inner_tref;
    wire                array_wr_req    ,array_rd_req;

    assign axi2array_frame_ready = ((cur_state == ARRAY_STA_WR) && array_wr_frame_ready) ||                                           ((cur_state == ARRAY_STA_RD) && array_rd_frame_ready);
    assign array_wr_frame_valid  = ((cur_state == ARRAY_STA_WR) && axi2array_frame_valid);
    assign array_rd_frame_valid  = ((cur_state == ARRAY_STA_RD) && axi2array_frame_valid);
    assign array_wr_frame_data   = axi2array_frame_data[151:0];
    assign array_rd_frame_data   = axi2array_frame_data[151:0];
    assign array_ref_start       = ((cur_state == ARRAY_STA_IDLE && array_ref_req));
    assign array_mux_sel         = cur_state;
    
    assign array_inner_tref      = array_inner_ref_sel_sync ?array_inner_tref1:array_inner_tref0;
    assign array_wr_req          = axi2array_frame_valid && axi2array_frame_data[152];
    assign array_rd_req          = axi2array_frame_valid && !axi2array_frame_data[152];


    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cur_state <= ARRAY_STA_IDLE;
        end else begin
            cur_state <= next_state;
        end
    end

    always@(*) begin
        case(cur_state)
        ARRAY_STA_IDLE : begin
            if(array_ref_req) begin
                next_state = ARRAY_STA_REF;
            end else if(array_wr_req) begin
                next_state = ARRAY_STA_WR;
            end else if(array_rd_req) begin
                next_state = ARRAY_STA_RD;
            end else begin
                next_state = ARRAY_STA_IDLE;
            end
        end
        ARRAY_STA_WR   : begin
            if(array_wr_done) begin
                next_state = ARRAY_STA_IDLE;
            end else begin
                next_state = ARRAY_STA_WR;
            end
        end
        ARRAY_STA_RD   : begin
            if(array_rd_done) begin
                next_state = ARRAY_STA_IDLE;     
            end else begin
                next_state = ARRAY_STA_RD;
            end
        end
        ARRAY_STA_REF  : begin
            if(array_ref_done) begin
                next_state = ARRAY_STA_IDLE;
            end else begin
                next_state = ARRAY_STA_REF;
            end
        end
        default : next_state = ARRAY_STA_IDLE;
        endcase
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            mc_work_en_r    <= 'd0;
            mc_work_en_sync <= 'd0;
        end else begin
            mc_work_en_r    <= mc_work_en;
            mc_work_en_sync <= mc_work_en_r;
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            array_ref_en_r  <= 'd0;
            array_ref_en_sync <= 'd0;
        end else begin
            array_ref_en_r  <= array_ref_en;
            array_ref_en_sync <= array_ref_en_r;
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            array_inner_ref_sel_r    <= 'd0;
            array_inner_ref_sel_sync <= 'd0;
        end else begin
            array_inner_ref_sel_r    <= array_inner_ref_sel;
            array_inner_ref_sel_sync <= array_inner_ref_sel_r;
        end
    end


    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            array_ref_req <= 'd0;
        end else if(mc_work_en) begin
            array_ref_req <= (array_ref_cnt >= array_inner_tref && mc_work_en_sync &&
                            array_ref_en_sync) ? 1:0;            
        end else if(cur_state == ARRAY_STA_IDLE) begin
            array_ref_req <= 'd0;
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            array_ref_cnt <= 'd0;
        end else if(mc_work_en && array_ref_en) begin
            if(array_ref_cnt >= array_inner_tref) begin
                array_ref_cnt <= 'd0;
            end else begin
                array_ref_cnt <= array_ref_cnt + 1'b1;
            end
        end else begin
            array_ref_cnt <= 'd0;
        end
    end


endmodule
