module rchannel (
    input           clk,
    input           rst_n,
    input           axi_s_arvalid,
    input   [7:0]   axi_s_arlen,
    input   [25:0]  axi_s_araddr,
    output          axi_s_arready,
    output          axi_s_rvalid,
    output          axi_s_rlast,
    output  [63:0]  axi_s_rdata,
    output          rframe_valid,
    output  [159:0] rframe_data,
    input           rframe_ready,
    input           array2axi_rdata_valid,
    input   [127:0] array2axi_rdata
);
    
    wire        rsof,reof;
    reg [15:0]  rraddr;
    reg [5:0]   rcaddr;
    wire [127:0] wdata;
    wire [7:0]  arlen;

    wire [15:0] arraddr;
    wire [5:0]  arcaddr;
    
    reg [6:0]  rframe_cnt;
    reg [7:0]  rdata_cnt;

        
    reg [1:0] cur_state,next_state;
    localparam [1:0] RCH_IDLE      = 2'b00;
    localparam [1:0] RCH_GET_RADDR = 2'b01;
    localparam [1:0] RCH_SD_RADDR  = 2'b10;




    wire        sync_fifo_ar_wr_en;
    wire        sync_fifo_ar_rd_en;
    wire        sync_fifo_ar_full;
    wire        sync_fifo_ar_empty;
    wire [29:0] sync_fifo_ar_wr_data;
    wire [29:0] sync_fifo_ar_rd_data;


    sync_fifo #(.DATA_WIDTH(30),
                .FIFO_DEPTH(4)
    ) sync_fifo_ar (
                .clk        (clk),
                .rst_n      (rst_n),
                .wr_en      (sync_fifo_ar_wr_en),
                .wr_data    (sync_fifo_ar_wr_data),
                .full       (sync_fifo_ar_full),
                .rd_en      (sync_fifo_ar_rd_en),
                .rd_data    (sync_fifo_ar_rd_data),
                .empty      (sync_fifo_ar_empty)
    );

    wire        sync_fifo_arlen_wr_en;
    wire        sync_fifo_arlen_rd_en;
    wire        sync_fifo_arlen_full;
    wire        sync_fifo_arlen_empty;
    wire [7:0] sync_fifo_arlen_wr_data;
    wire [7:0] sync_fifo_arlen_rd_data;


    sync_fifo #(.DATA_WIDTH(8),
                .FIFO_DEPTH(4)
    ) sync_fifo_arlen (
                .clk        (clk),
                .rst_n      (rst_n),
                .wr_en      (sync_fifo_arlen_wr_en),
                .wr_data    (sync_fifo_arlen_wr_data),
                .full       (sync_fifo_arlen_full),
                .rd_en      (sync_fifo_arlen_rd_en),
                .rd_data    (sync_fifo_arlen_rd_data),
                .empty      (sync_fifo_arlen_empty)
    );

    wire        sync_fifo_r_wr_en;
    wire        sync_fifo_r_rd_en;
    wire        sync_fifo_r_full;
    wire        sync_fifo_r_empty;
    wire [127:0]sync_fifo_r_wr_data;
    wire [63:0] sync_fifo_r_rd_data;


    sync_fifo_128_to_64 #(.DATA_IN_WIDTH(128),
                          .FIFO_DEPTH(8),
                          .DATA_OUT_WIDTH(64)
    ) sync_fifo_r (
                .clk        (clk),
                .rst_n      (rst_n),
                .wr_en      (sync_fifo_r_wr_en),
                .wr_data    (sync_fifo_r_wr_data),
                .full       (sync_fifo_r_full),
                .rd_en      (sync_fifo_r_rd_en),
                .rd_data    (sync_fifo_r_rd_data),
                .empty      (sync_fifo_r_empty)
    );
    

    assign  axi_s_arready = !sync_fifo_ar_full;
    assign  rframe_valid  = (cur_state == RCH_SD_RADDR);
    assign  rframe_data   = {rsof,reof,rraddr,rcaddr,128'b0,arlen};
    assign  axi_s_rvalid  = !sync_fifo_r_empty;
    assign  axi_s_rdata   = sync_fifo_r_rd_data;
    assign  axi_s_rlast   = axi_s_rvalid && (rdata_cnt == sync_fifo_arlen_rd_data);

    assign sync_fifo_ar_wr_en = axi_s_arvalid && axi_s_arready;
    assign sync_fifo_ar_wr_data = {axi_s_araddr[25:4],axi_s_arlen};
    assign sync_fifo_ar_rd_en = rframe_ready && rframe_valid && 
                                rframe_cnt == arlen>>1'b1 && !sync_fifo_ar_empty;
    
    assign {arraddr , arcaddr, arlen} = sync_fifo_ar_rd_data;
    assign sync_fifo_arlen_wr_en = rframe_valid && rframe_ready && 
                                rframe_cnt == arlen >> 1'b1;
    assign sync_fifo_arlen_wr_data = arlen;
    assign sync_fifo_arlen_rd_en   = axi_s_rlast && axi_s_rvalid;
    assign rsof = rframe_valid && (rframe_cnt == 7'b0 || rcaddr == 6'd0);
    assign reof = rframe_valid && (rframe_cnt == arlen >>1'b1 || rcaddr == 6'h3f);


    assign sync_fifo_r_wr_en = array2axi_rdata_valid && !sync_fifo_r_full;
    assign sync_fifo_r_wr_data = array2axi_rdata;
    assign sync_fifo_r_rd_en = !sync_fifo_r_empty;


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

    always@(*) begin
        case(cur_state)
            RCH_IDLE: begin
                if(sync_fifo_ar_wr_en) begin
                    next_state <= RCH_GET_RADDR;
                end else begin
                    next_state <=  RCH_IDLE;
                end
            end
            RCH_GET_RADDR: begin
                    next_state <= RCH_SD_RADDR;
            end
            RCH_SD_RADDR:  begin
                    if(rframe_ready && rframe_valid && rframe_cnt == arlen >>1) begin
                        next_state <= RCH_IDLE;
                    end else begin
                        next_state <= RCH_SD_RADDR;
                    end
            end
        endcase
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rraddr <= 'd0;
        end else if(cur_state == RCH_GET_RADDR) begin
            rraddr <= arraddr;
            if(rframe_valid && rframe_ready) begin
                if(rcaddr == 6'b111111) begin
                    rraddr <= rraddr + 1'b1;
                end else begin
                    rraddr <= rraddr;
                end
            end
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rcaddr <= 'd0;
        end else if (cur_state == RCH_GET_RADDR) begin
            rcaddr <= arcaddr;
            if(rframe_valid && rframe_ready) begin
                if(rcaddr == 6'b111111) begin
                    rcaddr <= 'd0;
                end else begin
                    rcaddr <= rcaddr + 1;
                end
            end
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rframe_cnt <= 'd0;
        end else if (rframe_valid && rframe_ready) begin
            if(rframe_cnt == arlen>>1'b1) begin
                rframe_cnt <= 'd0;
            end else begin
                rframe_cnt <= rframe_cnt + 1'b1;
            end
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rdata_cnt <= 'd0;
        end else if(axi_s_rvalid) begin
            if(rdata_cnt == sync_fifo_arlen_rd_data) begin
                rdata_cnt <= 'd0;
            end else begin
                rdata_cnt <= rdata_cnt + 1'b1;
            end
        end
    end

endmodule
