//////////////////////////////////////////////////////////////////////////////////
// Company:         TAIR
// Engineer:        
// 
// Create Date:     10/30/2023 11:24:31 AM
// Design Name:
// Module Name:     ClkManager
// Project Name:    S5443_V3_FPGA3
// Target Devices:  BOARD: BY5443v3. FPGA: xc7s25csga225-2
// Tool Versions:
// Description: 	This module is a clock distributor. Based on a setting it 
//					multiplexing cloks that generated either from MMCM or from 
//					a custom divider.     
// 
// Dependencies: 
// 
// Revision:
// Revision 1.0 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module ClkManager 
#(
	parameter	SPI_NUM	=	7,
	parameter	STAGES	=	3
)
(
	input Clk_i,
	input Rst_i,
	input Rst80_i,
	input [7:0] BaudRate0_i,
	input [7:0] BaudRate1_i,
	input [7:0] BaudRate2_i,
	input [7:0] BaudRate3_i,
	input [7:0] BaudRate4_i,
	input [7:0] BaudRate5_i,
	input [7:0] BaudRate6_i,

	output	Clk80_o,
	output	[SPI_NUM-1:0]	SpiClk_o
);

//================================================================================
//	REG/WIRE
//================================================================================
	wire clk0out;
	wire clk1out;
	wire clk2out;
	wire clk3out;
	wire clk4out;
	wire clk5out;
	wire clk6out;
	
	wire locked;
	
	wire [SPI_NUM-1:0] clkOutMMCM;
	
	wire [SPI_NUM-1:0] clkMan;
	
	wire [0:2] clkNum [SPI_NUM-1:0];
	wire [0:3] clkDiv [SPI_NUM-1:0];
	wire [0:3] clkDivSync [SPI_NUM-1:0];
	wire [SPI_NUM-1:0] clkCh; 
	wire [SPI_NUM-1:0] spiClk;

//================================================================================
//	ASSIGNMENTS
//===============================================================================
	assign clkNum[0] = BaudRate0_i[7:5];
	assign clkNum[1] = BaudRate1_i[7:5];
	assign clkNum[2] = BaudRate2_i[7:5];
	assign clkNum[3] = BaudRate3_i[7:5];
	assign clkNum[4] = BaudRate4_i[7:5];
	assign clkNum[5] = BaudRate5_i[7:5];
	assign clkNum[6] = BaudRate6_i[7:5];

	assign clkDiv[0] = BaudRate0_i[3:0];
	assign clkDiv[1] = BaudRate1_i[3:0];
	assign clkDiv[2] = BaudRate2_i[3:0];
	assign clkDiv[3] = BaudRate3_i[3:0];
	assign clkDiv[4] = BaudRate4_i[3:0];
	assign clkDiv[5] = BaudRate5_i[3:0];
	assign clkDiv[6] = BaudRate6_i[3:0];

	assign clkCh[0] = BaudRate0_i[4];
	assign clkCh[1] = BaudRate1_i[4];
	assign clkCh[2] = BaudRate2_i[4];
	assign clkCh[3] = BaudRate3_i[4];
	assign clkCh[4] = BaudRate4_i[4];
	assign clkCh[5] = BaudRate5_i[4];
	assign clkCh[6] = BaudRate6_i[4];

	assign SpiClk_o = spiClk; 
	assign Clk100_o = clk0out;
	assign Clk80_o = clk1out;

//================================================================================
//	LOCALPARAMS
//================================================================================


//================================================================================
//	CODING
//================================================================================   
	genvar i;

	generate
		for (i = 0; i < SPI_NUM; i = i + 1) begin : ClkGen
			ClkDivider ClkDivider (
				.Clk_i		(clk1out),
				.ClkDiv_i	(clkDivSync[i]),
				.Rst_i		(Rst80_i),
				.Clk_o		(clkMan[i])
			);

			CmdSync #(
				.WIDTH		(4),
				.STAGES		(STAGES)
			) CmdSync (
				.ClkFast_i	(Clk_i),
				.ClkSlow_i	(clk1out),
				.ClkDiv_i	(clkDiv[i]),
				.ClkDiv_o	(clkDivSync[i])
			);

			MmcmClkMux MmcmClkMux (
				.Rst_i			(Rst_i),
				.clkNum			(clkNum[i]),
				.Clk0_i			(clk0out),
				.Clk1_i			(clk1out),
				.Clk2_i			(clk2out),
				.Clk3_i			(clk3out),
				.Clk4_i			(clk4out),
				.Clk5_i			(clk5out),
				.Clk6_i			(clk6out),
				.ClkOutMMCM_o	(clkOutMMCM[i])
			);
	
			SpiClkMux SpiClkMux (
				.Rst_i		(Rst_i),
				.clkCh		(clkCh[i]),
				.clkOutMMCM	(clkOutMMCM[i]),
				.clkMan		(clkMan[i]),
				.SpiClk_o	(spiClk[i])
			);
		end
	endgenerate
	
	MMCM MMCM
	(
		// Clock out ports
		.clk_out1(clk0out),	//100 MHz
		.clk_out2(clk1out),	// 80 MHz
		.clk_out3(clk2out),	// 70 MHz
		.clk_out4(clk3out),	// 60MHz
		.clk_out5(clk4out),	// 50MHz
		.clk_out6(clk5out),	// 40MHz
		.clk_out7(clk6out),	// 30MHz 
		// Status and control signals
		.reset(Rst_i),		// input reset
		.locked(locked),	// output locked
		// Clock in ports
		.clk_in1(Clk_i)		// input clk_in1
	);
	
endmodule