//Copyright 2008 Altera Corporation. All rights reserved.  Altera products  
//are protected under numerous U.S. and foreign patents, maskwork rights,     
//copyrights and other intellectual property laws.                            
//                                                                            
//This reference design file, and your use thereof, is subject to and         
//governed by the terms and conditions of the applicable Altera Reference     
//Design License Agreement.  By using this reference design file, you         
//indicate your acceptance of such terms and conditions between you and       
//Altera Corporation.  In the event that you do not agree with such terms and 
//conditions, you may not use the reference design file. Please promptly      
//destroy any copies you have made.                                           
//                                                                            
//This reference design file being provided on an "as-is" basis and as an     
//accommodation and therefore all warranties, representations or guarantees   
//of any kind (whether express, implied or statutory) including, without      
//limitation, warranties of merchantability, non-infringement, or fitness for 
//a particular purpose, are specifically disclaimed.  By making this          
//reference design file available, Altera expressly does not recommend,       
//suggest or require that this reference design file be used in combination   
//with any other product not provided by Altera.                              

module TR4_SDI_TOP(
                     
                     gp_clk,
							BUTTON,
							SW,
							LED,
							
  		          		AES_CLK,
		          		AES_CLK_PDTSn,
		          		AES_CLK_S,
 		         		AES_IN,
		         		AES_OUT,
		          		AES_VCXO_DN,
		          		AES_VCXO_UP,
 		          		HSYNC,
 		          		ODDEVEN,
		         		SDI_BYPASS,
		         		SDI_CLK_BP,
		          		SDI_CLK_MLTF,
		         		SDI_CLK_N,
		          		SDI_CLK_OE,
		          		SDI_CLK_RST,
		          		SDI_CLK_SEL,
		            	SDI_CLK_V,
 		         		SDI_EQOUT_P,
		          		SDI_HSMC_CLK,
 		          		SDI_HSMC_CLK_P,
		         		SDI_LED_RX_G,
		         		SDI_LED_RX_R,
		         		SDI_LED_TX_G,
		            	SDI_LED_TX_R,
		          		SDI_RATE_SEL,
		         		SDI_TX_P,
		          		SDI_XTAL_SEL,
 		          		VFORMAT,
 		          		VSYNC
);
input                      gp_clk;    //50M
output		     [3:0]		LED;
input 		     [3:0]		BUTTON;
input 		     [3:0]		SW;

input 		          		AES_CLK;
output		          		AES_CLK_PDTSn;
output		     [2:0]		AES_CLK_S;
input 		     [1:0]		AES_IN;
output		     [1:0]		AES_OUT;
output		          		AES_VCXO_DN;
output		          		AES_VCXO_UP;
input 		          		HSYNC;
input 		          		ODDEVEN;
output		     [1:0]		SDI_BYPASS;
output		     [1:0]		SDI_CLK_BP;
output		          		SDI_CLK_MLTF;
output		     [1:0]		SDI_CLK_N;
output		          		SDI_CLK_OE;
output		          		SDI_CLK_RST;
output		          		SDI_CLK_SEL;
output		     [3:0]		SDI_CLK_V;
input 		     [1:0]		SDI_EQOUT_P;
output		          		SDI_HSMC_CLK;
input 		          		SDI_HSMC_CLK_P;
output		     [1:0]		SDI_LED_RX_G;
output		     [1:0]		SDI_LED_RX_R;
output		     [1:0]		SDI_LED_TX_G;
output		     [1:0]		SDI_LED_TX_R;
output		     [1:0]		SDI_RATE_SEL;
output		     [1:0]		SDI_TX_P;
output		          		SDI_XTAL_SEL;
input 		          		VFORMAT;
input 		          		VSYNC;

reg [1:0] SDI_LED_TX_R,SDI_LED_TX_G,SDI_LED_RX_R,SDI_LED_RX_G;

reg				u_reset_r1, u_reset_r2, reset ;
reg	[2:0]		u_pb_r1, u_pb_r2, pushbutton ;
reg	[3:0]		u_dipsw_r1, u_dipsw_r2, dipsw ;
wire	[3:0]		aes_in ;
wire 				aes_clk;


reg	[19:0]	db_count ;	//debounce counter
wire [2:0] user_pb	=	BUTTON[2:0];
wire 		cpu_resetn	=	BUTTON[3];
wire [3:0] user_dipsw=	SW;
always @ ( posedge gp_clk ) begin

	// this should create a pulse that is one clock long every
	//524288 clocks (1/2 Meg)
	if ( db_count[19] )
		db_count <= #1 0 ;
	else
		db_count <= #1 db_count + 1 ;
	
	// debounce and double register.
	if ( db_count[19] ) begin	// use db_count[19] as an enable
		u_reset_r1	<= #1 ~cpu_resetn ;
		u_reset_r2	<= #1 u_reset_r1 ;
		///////////////////////////////
		u_pb_r1		<= #1 ~user_pb ;	// invert the userpb
		u_pb_r2		<= #1 u_pb_r1 ;		
		///////////////////////////////
		u_dipsw_r1	<= #1 user_dipsw ;
		u_dipsw_r2	<= #1 u_dipsw_r1 ;

		////////////////////////////////
		if ( u_reset_r2 == u_reset_r1 ) 
			reset	<= #1 u_reset_r2 ;	
		else
			reset	<= #1 1'b1 ; //keep in reset
	
		////////////////////////////////////////////////
		// if pushbuttons stable then allow pb to change
		// pushbutton is active (1'b1) when the BP is pressed
		if ( u_pb_r2 == u_pb_r1 ) 
			pushbutton	<= #1 u_pb_r2 ; 
		
		//////////////////////////////////////////////
		// if u_dipsw stable then allow dipsw to change
		begin : for_i_loop
		integer i ;
		for( i=0; i<4; i=i+1 ) begin 
		  if ( u_dipsw_r2[i] == u_dipsw_r1[i] ) 
			dipsw[i]	<= #1 u_dipsw_r2[i] ;
		  end
		end
	end
end



/////////////////////////////////////////////////////////////////////////////////
// set up the AES PLL to the correct settings for the over sampleing frequency
// outputs
//
// S2 S1 S0  CLK1    CLK2   
// 0  0  0   98.304   98.304 
// 0  0  1   90.3168  90.3168 
// 0  1  0  122.88   122.88 
// 0  1  1  112.896  112.896
// 1  0  0   98.304  122.88 
// 1  0  1   90.3168 112.896 
// 1  1  0   98.304   90.3168 
// 1  1  1  122.88   112.896
//

assign	 AES_CLK_S[0]	= 0	;
assign	 AES_CLK_S[1]	= 0	;
assign	 AES_CLK_S[2] 	= 0	;
assign	 AES_CLK_PDTSn = 1	;	// powerdown tristate = 0, active = 1
//assign	 aes_out[1] 	= 0 ;	//assign	 aes_out[2] 	= 1 ;

//////////////////////////////////////////////////////////////////////////////
// these two signals are connected to a tristate enable on the HSMC SDI board
// an active signal on VCXO up will pull the control voltage high
// an active signal on VCXO dn will pull the control voltage low
assign	 AES_VCXO_UP 	= 1	;	//oe enable to FET to PLL V-control pull up
assign	 AES_VCXO_DN 	= 1	;     	//oe enable to FET to PLL V-control pull down



// use DDR IO registers for the AES signals
altddr_i u1_altddr_i (
	.aclr		( reset ),
	.datain		(  AES_IN[0] ),
	.inclock	( aes_clk ),
	.dataout_h	( aes_in[0] ),
	.dataout_l	( aes_in[1] )
);

altddr_i u2_altddr_i (
	.aclr		( reset ),
	.datain		(  AES_IN[1] ),
	.inclock	( aes_clk ),
	.dataout_h	( aes_in[2] ),
	.dataout_l	( aes_in[3] )
);


///////////////////////////////////////////////////////////////////////////
// Set ICS810001-22 for 148.5 MHz., input clock is 67.5 MHz from AGX board
// Use  27 MHz oscillator on daughtercard	
assign		SDI_CLK_SEL	= dipsw[1] ;		//0 = sdi_hsmc_clk, 1 = extclk_in
assign		SDI_XTAL_SEL	= dipsw[0] ;	// 0 = 27MHz, 1 = 26.973MHz
assign		SDI_CLK_BP[0]	= 1 ;		// PLL Active / Bypass
assign		SDI_CLK_BP[1]	= 1 ;
assign		sdi_clk_oe_out	= 1 ;
assign		SDI_CLK_N[0]	= 0 ;
assign		SDI_CLK_N[1]	= 0 ;


assign 		SDI_CLK_V	= 4'b1101 ;	//4'b1101 to lock pll to the 15.625KHz hsync generated
assign 		SDI_HSMC_CLK	= hsync_ref ;		

assign		SDI_CLK_MLTF	= 0 ;
assign		SDI_CLK_RST	= 0 ;

///////////////////////////////////////////////////////////////////////////////
// counter for hsync signal generation. 
// pll will lock to: 45,000 Hz;	33,750 Hz ; 15,625 Hz; 15,734 Hz; 28,125Hz 
// depending on set up of the pll using 100MHz, 125MHz or 62.5MHz Arria GX PCIe
// clocks the frequency of 15,625 can be generated with an even divisor number
//		hsync freq
// clock 	15,625 KHz
// 100.0 MHz	6400.00
// 125.0 MHz	8000.00
//  62.5 Mhz	4000.00


//////////////////////////////////////////////////////////////////////
// this counter is only to sync the SDI PLL to a known frequency if 
// there is no input to the SDI channels. 
// the IDT / ICS pll will lock to various hsync frequencies
////////////////////////////////////////////////////////
//divide counter,  
//divide osc (100MHz) by 6400 to get 15,625 Hz ref freq.
//8192 - 1793(0x701; 11'b111_0000_0001) + 1 = 6400
// or:
//divide osc (100MHz) by 3200 to get 31,250 Hz then.
//divide 31,250 by 2 using a toggle FF for square wave for 
//clock of 15,625 Hz
//4096 - 897(0x381; 10'b11_1000_0001) + 1 = 3200
//2^12 = 4096
//////////////////////////////////////////////////////
//--example
// 4bits 3 bits for counting bit 4 is for TC
//
// 0000
// 0001
// 0010
// 0011 <<<<<<+
// 0100       |
// 0101       |
// 0110       |
// 0111       |
// 1000 >>>>>>+
//
// 2^3 = 8
// Therefore
// 8 - 3 + 1 = 6
// 8 is the roll over value
// 3 is the reset value
// 6 is the number of states or count value.
///////////////////////////////////////////////////
reg [13:0]	hsync_count ;	// hsync counter.
reg		hsync_ref ;
wire		hsync_tc ; 	//terminal count for hsync

assign	hsync_tc	= hsync_count[12] ;

always @ ( posedge gp_clk ) begin	//gp clk is ? 50MHz or 100MHz ?
	if ( hsync_tc ) begin
		hsync_count	<= #1 14'h0381 ;
		hsync_ref	<= #1 ~hsync_ref ;
	end
	else
		hsync_count	<= #1 hsync_count + 1 ;
end


wire [1:0]	force_sdi_err ;
wire [1:0]	sdi_load ;

assign	force_sdi_err	= { pushbutton[1], pushbutton[1]} ;
assign	sdi_load	= { pushbutton[0], pushbutton[0]} ;



wire [1:0]	compare, rx_sdi_freqlock,rx_sdi_phcomperr, 
		sdi_pll_locked, tx_sdi_phcomperr, xcvrrx_clkout ;
		
xcvr_lpbk u1_xcvr_lpbk(
	.reset			( reset ),
	.xcvr_refclk		( SDI_HSMC_CLK_P ),	//transciever ref clock
	.gp_clk			( gp_clk ), 	//50MHz clock
	
	//highspeed io
	.rx_p			( SDI_EQOUT_P[0] ),
	.tx_p			( SDI_TX_P[0] ),
	
	//status - control
	//inputs
	.load			( sdi_load[0] ) , //loads prbs and clears err count
	.prbs_seed		(20'hbeef),	//prbs seed 20 bit value
	.txerror_vec		( {force_sdi_err[0],19'b0} ) ,	// 20 bit vector normally zeros
	
	//outputs
	.err_count		( err_count1 ) , // 20 bit count value. 
	.compare 		( compare[0] ),
	.rx_freqlock		( rx_sdi_freqlock[0] ) ,
	.rx_phcomperr 		( rx_sdi_phcomperr[0] ),		
	.pll_locked 		( sdi_pll_locked[0] ),
	.tx_phcomperr		( tx_sdi_phcomperr[0] ),
	.rx_clkout		( xcvrrx_clkout[0] )  
	) ;


xcvr_lpbk u2_xcvr_lpbk(
	.reset			( reset ),
	.xcvr_refclk		( SDI_HSMC_CLK_P ),	//transciever ref clock
	.gp_clk			( gp_clk ), 	//50MHz clock
	
	//highspeed io
	.rx_p			( SDI_EQOUT_P[1] ),
	.tx_p			( SDI_TX_P[1] ),
	
	//status - control
	//inputs
	.load			( sdi_load[1] ) , //loads prbs and clears err count
	.prbs_seed		(20'hdead),	//prbs seed 20 bit value
	.txerror_vec		( {19'b0, force_sdi_err[1]} ) , // 20 bit vector normally zeros
	
	//outputs
	.err_count		( err_count2 ) , //20 bit count value
	.compare 		( compare[1] ),
	.rx_freqlock		( rx_sdi_freqlock[1] ) ,
	.rx_phcomperr 		( rx_sdi_phcomperr[1] ),		
	.pll_locked 		( sdi_pll_locked[1] ),
	.tx_phcomperr		( tx_sdi_phcomperr[1] ),
	.rx_clkout		( xcvrrx_clkout[1] )  
	) ;

	
	
wire	[2:1]	aes_err ;


///////////////////////////////////////////////////////////////////////////
//generate AES output clock. 
reg [3:0]	aes_clk_div4 ;

// start to read from fifo when half full  
always @ (posedge AES_CLK or posedge reset) begin
     if (reset)
		aes_clk_div4 <= #1 4'b1100 ; 
     else 
     		aes_clk_div4 <= #1 { aes_clk_div4[2:0], aes_clk_div4[3] };
end

assign aes_clk	= 	aes_clk_div4[0] ;


wire [2:1]	force_aes_err ;
assign	force_aes_err	= { pushbutton[2], pushbutton[2]} ;	
	
	
////////////////////////////////////////////////////////////////////
// aes loopback test
aes_lpbk aeslpbk_u2(
	.reset 		( reset ),
	.aes_clk 	( aes_clk ),		//aes clock
	.aes_data_i 	( aes_in ),		//4 bits
	.load_i 	( { pushbutton[0], pushbutton[0] } ) ,	//2 bits
	.force_err_i	( { force_aes_err[2], force_aes_err[1] } ) ,

	//outputs
	.aes_data_o 	( AES_OUT ),		//2 bits
	.aes_err_o 	( aes_err )		//2 bits
	) ;	
	
///////////////////////////////////////////////////////////////////////////////
//-- PLL used to generate parallel domain clocks from incoming 148.5MHz clock.
//-- Alternatively, logic could be used to generate these /2 and /11 clocks.
//-----------------------------------------------------------------------------
//wire   pclk_27;
//wire   pclk_74;
wire clk_5khz;

pll_tx_pclks pll_pclks_inst (
	.areset 	(1'b0),
	.inclk0 	( SDI_HSMC_CLK_P ),
	.c0		( pclk_27 ),
	.c1		( pclk_74 ),
	.c2		( clk_5khz )		// c2 = 5KHz
);

reg [12:0] 	slowcnt ;
wire		slowcnt_tc ;  

assign slowcnt_tc = slowcnt[12] ;  //assign the terminal count 

always @( posedge clk_5khz ) begin
	
	if ( slowcnt_tc )
		slowcnt	<= #1 0 ;
	else
		slowcnt <= slowcnt + 1 ;
	end

reg	[3:0]	led_r ;
reg	[1:0]	tx_rx_ledstate ;
//reg	[1:0]	compare_r ;
//reg	[2:1]	aes_err_r ;
// this should change the bit rate of the transmitter once every 1 - 2 secs. 




always @(posedge clk_5khz or posedge reset ) begin
	if ( reset ) begin
		tx_rx_ledstate	<= #1 2'b00 ; 	
		SDI_LED_TX_R	<= #1 2'b00 ;
		SDI_LED_TX_G 	<= #1 2'b00 ;
		led_r		<= #1 4'h0 ;
		//compare_r	<= #1 2'b00 ;
		//aes_err_r	<= #1 2'b00 ;
	end
		
	else if ( slowcnt_tc ) begin
		tx_rx_ledstate	<= #1	tx_rx_ledstate + 1 ; 
		led_r		<= #1   {aes_err[2:1],~compare[1:0] } ;	


		//this needs to change since it is only checking on the enable signal!!!!
		/*
		if ( ~compare[0] )
			compare_r[0]	<= #1 1'b1 ;
		else
			compare_r[0]	<= #1 compare_r[0] ;
					
		if ( ~compare[1] )
			compare_r[1]	<= #1 1'b1 ;
		else
			compare_r[1]	<= #1 compare_r[1] ;
		
		//aes error latch
		if ( aes_err[1] )
			aes_err_r[1]	<= #1 1'b1 ;
		else
			aes_err_r[1]	<= #1 aes_err_r[1] ;
		//aes error latch
		if ( aes_err[2] )
			aes_err_r[2]	<= #1 1'b1 ;
		else
			aes_err_r[2]	<= #1 aes_err_r[2] ;
		*/
		
		
		case ( tx_rx_ledstate ) 
			2'b00 : begin
				SDI_LED_TX_R	<= #1 2'b00 ;
				SDI_LED_TX_G 	<= #1 2'b00 ;
				SDI_LED_RX_R	<= #1 2'b11 ;
				SDI_LED_RX_G 	<= #1 2'b11 ;
				end
				
			2'b01 : begin
				SDI_LED_TX_R	<= #1 2'b11 ;
				SDI_LED_TX_G 	<= #1 2'b00 ;
				SDI_LED_RX_R	<= #1 2'b00 ;
				SDI_LED_RX_G 	<= #1 2'b11 ;
				end

			2'b10 : begin
				SDI_LED_TX_R	<= #1 2'b00 ;
				SDI_LED_TX_G 	<= #1 2'b11 ;
				SDI_LED_RX_R	<= #1 2'b11 ;
				SDI_LED_RX_G 	<= #1 2'b00 ;
				end
			2'b11 : begin
				SDI_LED_TX_R	<= #1 2'b11 ;
				SDI_LED_TX_G 	<= #1 2'b11 ;
				SDI_LED_RX_R	<= #1 2'b00 ;
				SDI_LED_RX_G 	<= #1 2'b00 ;
				end
		endcase 
	end
end	

assign LED = led_r ;



endmodule 












	
	
	
	

