module array_ref (
    input           clk,
    input           rst_n,

    input           array_ref_start,
    output          array_ref_done,

    output          array_ref_csn,
    output reg [15:0]  array_ref_raddr,

    input   [7:0]   array_inner_tras,
    input   [7:0]   array_inner_trp
);

    reg     [1:0]   cur_state,next_state;
    localparam  [1:0]   ARR_REF_IDLE = 2'b00;
    localparam  [1:0]   ARR_REF_RCVRADDR = 2'b01;
    localparam  [1:0]   ARR_REF_RAS = 2'b10;
    localparam  [1:0]   ARR_REF_RP = 2'b11;

    reg     [7:0]   ref_ras_cnt;
    reg     [7:0]   ref_rp_cnt;

    assign  array_ref_done = (array_ref_raddr == 16'hffff) && (cur_state == ARR_REF_RP) &&
                            (ref_rp_cnt == 'd0);
    assign  array_ref_csn   = !(cur_state == ARR_REF_RAS);

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

    always @(*) begin
        case (cur_state)
            ARR_REF_IDLE        : begin
                if (array_ref_start) begin
                    next_state = ARR_REF_RCVRADDR;
                end else begin
                    next_state = ARR_REF_IDLE;
                end
            end
            ARR_REF_RCVRADDR    : begin
                next_state = ARR_REF_RAS;
            end
            ARR_REF_RAS         : begin
                if (ref_ras_cnt == 'd0) begin
                    next_state = ARR_REF_RP;
                end else begin
                    next_state = ARR_REF_RAS;
                end
            end
            ARR_REF_RP          : begin
                if (ref_rp_cnt == 'd0) begin
                    if (array_ref_raddr == 16'hffff) begin
                        next_state = ARR_REF_IDLE;
                    end else begin
                        next_state = ARR_REF_RCVRADDR;
                    end
                end else begin
                    next_state = ARR_REF_RP;
                end
            end
            default             : next_state = ARR_REF_IDLE;
        endcase
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            array_ref_raddr <= 'd0;
        end else if (cur_state == ARR_REF_IDLE) begin
            array_ref_raddr <= 'd0;
        end else if (cur_state == ARR_REF_RP && next_state == ARR_REF_RCVRADDR) begin
            array_ref_raddr <= array_ref_raddr + 1'b1;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            ref_ras_cnt <= 'd0;
        end else if (cur_state == ARR_REF_RCVRADDR) begin
            ref_ras_cnt <= array_inner_tras - 1'b1;
        end else if (cur_state == ARR_REF_RAS) begin
            if (ref_ras_cnt == 'd0) begin
                ref_ras_cnt <= ref_ras_cnt;
            end else begin
                ref_ras_cnt <= ref_ras_cnt - 1'b1;
            end
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            ref_rp_cnt <= 'd0;
        end else if (cur_state == ARR_REF_RCVRADDR) begin
            ref_rp_cnt <= array_inner_trp - 1'b1;
        end else if (cur_state == ARR_REF_RP) begin
            if (ref_rp_cnt == 'd0) begin
                ref_rp_cnt <= ref_rp_cnt;
            end else begin
                ref_rp_cnt <= ref_rp_cnt - 1'b1;
            end
        end
    end
    
endmodule