//////////////////////////////////////////////////////////////////////////////////
// Company:         TAIR
// Engineer:        
// 
// Create Date:     10/30/2023 11:24:31 AM
// Design Name:
// Module Name:     FifoCtrl
// Project Name:    S5443_V3_FPGA3
// Target Devices:  BOARD: BY5443v3. FPGA: xc7s25csga225-2
// Tool Versions:
// Description:     This module generate controll signals for FIFO's 
// 
// Dependencies: 
// 
// Revision:
// Revision 1.0 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module FifoCtrl #(
	parameter FIFO_0_READ_MSB_ADDR = 12'h0+12'd28,
	parameter FIFO_1_READ_MSB_ADDR = 12'h50+12'd28,
	parameter FIFO_2_READ_MSB_ADDR = 12'hf0+12'd28,
	parameter FIFO_3_READ_MSB_ADDR = 12'h140+12'd28,
	parameter FIFO_4_READ_MSB_ADDR = 12'h190+12'd28,
	parameter FIFO_5_READ_MSB_ADDR = 12'h1e0+12'd28,
	parameter FIFO_6_READ_MSB_ADDR = 12'h230+12'd28,
	parameter STAGES = 3
)
(
	input ToFifoTxWriteVal_i,
	input ToFifoTxReadVal_i,
	input ToFifoRxWriteVal_i,
	input ToFifoRxReadVal_i,

	input FifoTxFull_i,
	input FifoTxEmpty_i,
	input FifoRxFull_i,
	input FifoRxEmpty_i,
	input [11:0] SmcAddr_i,

	input FifoTxWrClock_i,
	input FifoTxRdClock_i,
	input FifoRxWrClock_i,
	input FifoRxRdClock_i,

	input FifoTxRst_i,
	input FifoRxRst_i,

	input FifoTxRstWrPtr_i,
	input FifoRxRstRdPtr_i,

	output [7:0] RxFifoUpDnCnt_o,
	output [7:0] TxFifoUpDnCnt_o,

	output EmptyFlagTxForDsp_o,

	output FifoTxWriteEn_o,
	output FifoTxReadEn_o,
	output FifoRxWriteEn_o,
	output FifoRxReadEn_o
);

//================================================================================
//  REG/WIRE
//================================================================================
	reg fifoTxWriteEn;
	reg fifoTxReadEn;
	reg fifoRxWriteEn;
	reg fifoRxReadEn;
	
	(* dont_touch = "true" *)reg [7:0] txFifoWrPtr;
	(* dont_touch = "true" *)reg [7:0] txFifoRdPtr;
	(* dont_touch = "true" *)reg [7:0] rxFifoWrPtr;
	(* dont_touch = "true" *)reg [7:0] rxFifoRdPtr;
	
	(* dont_touch = "true" *)reg [7:0] rxFifoUpDnCnt;
	(* dont_touch = "true" *)reg [7:0] txFifoUpDnCnt;
	
	reg [1:0] readEnCnt;
	reg emptyFlagTxForDsp;    
		
	wire requestToFifo0	= (SmcAddr_i == FIFO_0_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	wire requestToFifo1	= (SmcAddr_i == FIFO_1_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	wire requestToFifo2	= (SmcAddr_i == FIFO_2_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	wire requestToFifo3	= (SmcAddr_i == FIFO_3_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	wire requestToFifo4	= (SmcAddr_i == FIFO_4_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	wire requestToFifo5	= (SmcAddr_i == FIFO_5_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	wire requestToFifo6	= (SmcAddr_i == FIFO_6_READ_MSB_ADDR) ? 1'b1 : 1'b0;
	
	wire requestToFifo	= (requestToFifo0|requestToFifo1|requestToFifo2|requestToFifo3|requestToFifo4|requestToFifo5|requestToFifo6) ? 1'b1 : 1'b0;

	wire [7:0] rxFifoWrPtrSync;
	wire [7:0] txFifoWrPtrSync;
	wire [7:0] txFifoRdPtrSync;

	wire rxFifoRstSync;

//================================================================================
//	ASSIGNMENTS
//================================================================================	
	assign FifoTxWriteEn_o = fifoTxWriteEn;
	assign FifoTxReadEn_o = fifoTxReadEn;
	assign FifoRxWriteEn_o = fifoRxWriteEn;
	assign FifoRxReadEn_o = fifoRxReadEn;
	
	assign RxFifoUpDnCnt_o = rxFifoUpDnCnt;
	assign TxFifoUpDnCnt_o = txFifoUpDnCnt;
	
	assign EmptyFlagTxForDsp_o = emptyFlagTxForDsp;
	
//================================================================================
//	LOCALPARAMS
//================================================================================

//================================================================================
//	CODING
//================================================================================
	RxFifoPtrSync #(
		.WIDTH	(8),
		.STAGES	(STAGES)
	)
	rxFifoPtrSync (
		.ClkFast_i		(FifoRxWrClock_i),
		.ClkSlow_i		(FifoRxRdClock_i),
		.RxFifoWrPtr_i	(rxFifoWrPtr),
		.RxFifoWrPtr_o	(rxFifoWrPtrSync)
	);

	TxFifoPtrSync #(
		.WIDTH	(8),
		.STAGES	(STAGES)
	)
	txFifoPtrSync (
		.ClkFast_i(FifoTxRdClock_i),
		.ClkSlow_i(FifoTxWrClock_i),
		.TxFifoWrPtr_i(txFifoRdPtr),
		.TxFifoWrPtr_o(txFifoRdPtrSync)
	);
	
	always @(posedge FifoRxRdClock_i) begin 
		if (FifoRxRstRdPtr_i) begin 
			readEnCnt <= 1'b0;
		end
		else begin 
			if (ToFifoRxReadVal_i) begin 
				readEnCnt <= readEnCnt + 1'b1;
			end
			else begin 
				readEnCnt <= 1'b0;
			end
		end
	end
	
	always @(posedge FifoTxWrClock_i) begin 
		if (ToFifoTxWriteVal_i && !FifoTxFull_i) begin 
			fifoTxWriteEn <= 1'b1;
		end
		else begin 
			fifoTxWriteEn <= 1'b0;
		end
	end
	
	always @(posedge FifoTxRdClock_i) begin 
		if (ToFifoTxReadVal_i && !FifoTxEmpty_i) begin 
			fifoTxReadEn <= 1'b1;
		end
		else begin 
			fifoTxReadEn <= 1'b0;
		end
	end
	
	always @(posedge FifoRxWrClock_i) begin 
		if (ToFifoRxWriteVal_i && !FifoRxFull_i) begin 
			fifoRxWriteEn <= 1'b1;
		end
		else begin 
			fifoRxWriteEn <= 1'b0;
		end
	end
	
	always @(posedge FifoRxRdClock_i) begin 
		if (ToFifoRxReadVal_i && !FifoRxEmpty_i && requestToFifo && readEnCnt < 1 ) begin 
			fifoRxReadEn <= 1'b1;
		end
		else begin 
			fifoRxReadEn <= 1'b0;
		end
	end
	
	always @(posedge FifoTxWrClock_i) begin 
		if (FifoTxRstWrPtr_i) begin 
			txFifoWrPtr <= 8'h0;
		end
		else begin 
			if (fifoTxWriteEn  ) begin 
				txFifoWrPtr <= txFifoWrPtr + 1'b1;
			end
		end
	end
	
	always @(posedge FifoTxRdClock_i) begin 
		if (FifoTxRst_i) begin 
			txFifoRdPtr <= 8'h0;
		end
		else begin 
			if (fifoTxReadEn) begin 
				txFifoRdPtr <= txFifoRdPtr + 1'b1;
			end
		end
	end
	
	always @(posedge FifoRxWrClock_i) begin 
		if (FifoRxRst_i) begin 
			rxFifoWrPtr <= 8'h0;
		end
		else begin
			if (fifoRxWriteEn) begin 
				rxFifoWrPtr <= rxFifoWrPtr + 1'b1;
			end
		end
	end
	
	always @(posedge FifoRxRdClock_i) begin 
		if (FifoRxRstRdPtr_i) begin 
			rxFifoRdPtr <= 8'h0;
		end
		else begin 
			if (fifoRxReadEn) begin 
				rxFifoRdPtr <= rxFifoRdPtr + 1'b1;
			end
		end
	end
	
	always @(posedge FifoRxRdClock_i) begin 
		if (FifoRxRstRdPtr_i) begin 
			rxFifoUpDnCnt <= 8'h0;
		end
		else begin 
			rxFifoUpDnCnt <= rxFifoWrPtrSync - rxFifoRdPtr;
		end
	end
	
	always @(posedge FifoTxWrClock_i) begin 
		if (FifoTxRst_i) begin 
			txFifoUpDnCnt <= 8'h0;
		end
		else begin 
			txFifoUpDnCnt <= txFifoWrPtr - txFifoRdPtrSync;
		end
	end

	always @(*) begin
		if (txFifoUpDnCnt == 8'h0) begin
			emptyFlagTxForDsp <= 1'b1;
		end
		else begin
			emptyFlagTxForDsp <= 1'b0;
		end
	end
	
endmodule