////////////////////////////////////////////////////////////////////////////////////////////
// Company:         TAIR
// Engineer:        Chigrinskiy A.  
// 
// Create Date:     18/04/2024 
// Design Name: 
// Module Name:     FifoCtrl
// Project Name:    SB_TMSG44V1_FPGA
// Target Devices:  Board: SB_TMSG44v1. FPGA: GW1N-LV9PG256C6/I5
// Tool versions:
// Description:     This module is a controller for the FIFOs. It controls the read and write pointers of the FIFOs.
//
// Dependencies:  
// Revision: 
// Revision 1.0 - File Created
// Additional Comments: 
//
////////////////////////////////////////////////////////////////////////////////////////////
module FifoCtrl #(
    parameter IN_WIDTH = 24,
    parameter WR_NUM = 1,
    parameter OUT_WIDTH = 24
)(
    input WrClk_i,
    input RdClk_i,
    input Rst_i,
    input [IN_WIDTH-1:0] Data_i,
    input Val_i,
    input BusySpiM_i,
    input FifoFull_i,
    input FifoEmpty_i,

    output [OUT_WIDTH-1:0] Data_o,
    output reg ReadEn_o,
    output reg  WriteEn_o,
    output reg ValRdData_o

);
//================================================================================
//	LOCAL PARAMETERS
//================================================================================
localparam DATA_WIDTH = WR_NUM*IN_WIDTH;

//================================================================================
//	REG/WIRE
//================================================================================
reg [DATA_WIDTH-1:0] dataReg;
reg [1:0]  wrCnt;

//================================================================================
//  ASSIGNMENTS
//================================================================================
assign Data_o = dataReg[OUT_WIDTH-1:0];

//================================================================================
//	CODING
//================================================================================
always @(posedge WrClk_i) begin 
    if (Rst_i) begin 
        wrCnt <= 0;
    end
    else begin 
        if (Val_i) begin 
            wrCnt <= wrCnt + 1;
        end
        else if (wrCnt == WR_NUM) begin 
            wrCnt <= 0;
        end
    end
end

always @(posedge WrClk_i) begin 
    if (Rst_i) begin 
        dataReg <= 0;
    end
    else begin
        if (WR_NUM>1) begin
            case (WR_NUM)  
            3: begin
                case (wrCnt)
                0 : begin 
                    if (Val_i) begin 
                        dataReg[(3*IN_WIDTH)-1:(2*IN_WIDTH)] <= Data_i;
                    end
                end
                1 : begin 
                    if (Val_i) begin 
                        dataReg[(2*IN_WIDTH)-1:IN_WIDTH] <= Data_i;
                    end
                end
                2 : begin 
                    if (Val_i) begin 
                        dataReg[IN_WIDTH-1:0] <= Data_i;
                    end
                end
                endcase
            end
            2 : begin 
                case (wrCnt)
                0: begin 
                    if (Val_i) begin 
                        dataReg[(2*IN_WIDTH)-1:IN_WIDTH] <= Data_i;
                    end
                end
                1: begin 
                    if (Val_i) begin 
                        dataReg[IN_WIDTH-1:0] <= Data_i;
                    end
                end
                endcase
            end
            endcase
        end
        else begin
            if (Val_i) begin 
                dataReg[IN_WIDTH-1:0] <= Data_i;
            end
        end
    end
end

always @(posedge WrClk_i) begin
    if (Rst_i) begin 
        WriteEn_o <= 1'b0;
    end
    else begin  
        if (Val_i && wrCnt == WR_NUM-1) begin
            WriteEn_o <= 1'b1;
        end
        else begin 
            WriteEn_o <= 1'b0;
        end
    end
end

always @(*) begin
    if (Rst_i) begin 
        ReadEn_o = 1'b0;
    end
    else begin  
        if (!FifoEmpty_i && !BusySpiM_i) begin 
            ReadEn_o = 1'b1;
        end
        else begin 
            ReadEn_o = 1'b0;
        end
    end
end

always @(posedge RdClk_i) begin 
    if (Rst_i) begin 
        ValRdData_o <= 1'b0;
    end
    else begin 
        if (ReadEn_o) begin 
            ValRdData_o <= 1'b1;
        end
        else begin 
            ValRdData_o <= 1'b0;
        end
    end
end

endmodule