// ----------------------------------------------------------------------------

// HDMI64 - C64 Video HDMI Converter (with Scanline Effect)

// www.commodore.gen.tr - delimawi'2016

// ----------------------------------------------------------------------------

// Project based on HDMI Sample Code from fpga4fun.com

// ----------------------------------------------------------------------------



module HDMI_Encoder

(

	input pixelClock,						// 27MHz Incomming Video Pixel Clock

	input pixelClockX10,					// 270MHz HDMI Bit Clock (pixelClockx10)

	input extHSync,

	input extVSync,

	

	output [2:0] TMDSp, TMDSn,			// HDMI Output Pins 

	output TMDSp_clock, TMDSn_clock,

	

	// FIFO Output

	output [9:0] PixelAddress,

	input  [7:0] PixelLuma,

	input  [7:0] PixelChroma

	

	// OSD RAM

//	output [9:0]	osdAddress,

//	output  			osdClock,

//	input  [7:0]	osdData

);



// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------



// http://tinyvga.com/vga-timing



//	Format 	V active 	Int/Prog 	Total Lines 	V blanking1 	V Freq 	H Freq 	Pixel Freq 		H total 	H active 	H blanking 	Aspect2 		Display3 	Reference

//	17,18 	576 			Prog 			625 				49 				50.000 	31.250 	27.000 			864 		720 			144 			4x3,16x9 	CRT/Dig 		BT1358[31]



// ----------------------------------------------

// Timing 720x576 @50 Hz

// pixelClock 30MHz

// ---------------------------------------------- 

`define DISPLAY_WIDTH			720

`define DISPLAY_HEIGHT			576

`define FULL_WIDTH				864

`define FULL_HEIGHT				624



`define H_FRONT_PORCH			12

`define H_SYNC						64

 

`define V_FRONT_PORCH			5

`define V_SYNC 					5





/*

// ----------------------------------------------

// Timing 720x576 @50 Hz

// pixelClock 30MHz

// ---------------------------------------------- 

`define DISPLAY_WIDTH			720

`define DISPLAY_HEIGHT			576

`define FULL_WIDTH				864  // 968

`define FULL_HEIGHT				624 // 625

`define H_FRONT_PORCH			40

`define H_SYNC						72 

`define V_FRONT_PORCH			3

`define V_SYNC 					28

*/



/*

// ----------------------------------------------

// Timing 640x480 @60 Hz

// pixelClock 25MHz

// ---------------------------------------------- 

`define DISPLAY_WIDTH			640

`define DISPLAY_HEIGHT			480

`define FULL_WIDTH				800

`define FULL_HEIGHT				525

`define H_FRONT_PORCH			16

`define H_SYNC						96 

`define V_FRONT_PORCH			10

`define V_SYNC 					2

*/



/*

// ----------------------------------------------

// Timing 720x480 @55 Hz

// pixelClock 25MHz

// ---------------------------------------------- 

`define DISPLAY_WIDTH			720

`define DISPLAY_HEIGHT			480

`define FULL_WIDTH				858

`define FULL_HEIGHT				525

`define H_FRONT_PORCH			16

`define H_SYNC						62 

`define V_FRONT_PORCH			9

`define V_SYNC 					6

*/





`define H_SYNC_BEGIN				`DISPLAY_WIDTH+`H_FRONT_PORCH			

`define H_SYNC_END				`H_SYNC_BEGIN+`H_SYNC					

`define V_SYNC_BEGIN				`DISPLAY_HEIGHT+`V_FRONT_PORCH		

`define V_SYNC_END				`V_SYNC_BEGIN+`V_SYNC					



reg [9:0] regXPos, regYPos;			// 10 Bit X,Y Counters (0-1023)

reg regHSync,regVSync,regDrawing;					// HDMI Synch Pulses



wire [7:0]	regInpRed, regInpBlue, regInpGreen;

reg [7:0]	regRed, regBlue, regGreen;



assign PixelAddress=regXPos;



always @(posedge pixelClock)

begin

	regDrawing<=(regXPos<`DISPLAY_WIDTH)&&(regYPos<`DISPLAY_HEIGHT);

	regHSync <= (regXPos>=`H_SYNC_BEGIN)&&(regXPos<`H_SYNC_END);

	regVSync <= (regYPos>=`V_SYNC_BEGIN) && (regYPos<`V_SYNC_END);

end

	

//always @(posedge extVSync)

//begin

//	regYPos=0;

//end



reg regExtHSync, regExtVSync;





always @(posedge pixelClock)

begin

	



	if ( (regXPos==(`FULL_WIDTH-1))  /*|| ((extHSync==1) && (regExtHSync==0))*/  )

	begin

		if (regYPos==(`FULL_HEIGHT-1) || ((extVSync==1) && (regExtVSync==0))  ) 

		begin

			regYPos<=0;

		end else 

		begin

			regYPos<=regYPos+1'b1;

		end

		regXPos<=0;

	end else 

	begin

		regXPos<=regXPos+1'b1;

	end

	

	regExtHSync<=extHSync;

	regExtVSync<=extVSync;

	

end



// ----------------------------------------------------------------------------

// Scanline Effect

// ----------------------------------------------------------------------------



reg [7:0] regCr;

reg [7:0] regCb;



reg [7:0] regLumaHist2;

reg [7:0] regLumaHist1;

reg [7:0] regLumaHist0;



wire [9:0] curLuma;



assign curLuma=regLumaHist0+regLumaHist0+PixelLuma+PixelLuma;



YCbCr2RGB Convert( .oRed(regInpRed), .oGreen(regInpGreen), .oBlue(regInpBlue), .iY(curLuma[9:2]), .iCb(regCb), .iCr(regCr), .iCLK(pixelClock));



always @(posedge pixelClock)

begin

	if (regXPos[0]==1)

	begin

		regCr<=PixelChroma;

	end else

	begin

	  regCb<=PixelChroma;

	end



	regLumaHist2<=regLumaHist1;

	regLumaHist1<=regLumaHist0;

	regLumaHist0<=PixelLuma;

	

	

//	regInpRed<=regCr;

//	regInpGreen<=100;

//	regInpBlue<=regCb;

	

	

	if (regYPos[0]==1)

	begin



	  regRed <= (regInpRed>>2)*3;

  regGreen <= (regInpGreen>>2)*3;

	  regBlue <= (regInpBlue>>2)*3;



//	  regRed <= (regInpRed>>1);

 // regGreen <= (regInpGreen>>1);

	//  regBlue <= (regInpBlue>>1);



//		regRed<=regInpRed;

//		regGreen<=regInpGreen;

//		regBlue<=regInpBlue;

	end

	else

	begin

		regRed 	<= regInpRed;

		regGreen	<= regInpGreen;

		regBlue 	<= regInpBlue;

	end

	

end





// ----------------------------------------------------------------------------

// Generate TDMS Encoded 10 Bit Signals

// ----------------------------------------------------------------------------



wire [9:0] TMDS_red;

wire [9:0] TMDS_green;

wire [9:0] TMDS_blue;



TMDS_encoder encode_R( .clk(pixelClock), .VD(regRed  ), .CD(2'b00)        , .VDE(regDrawing), .TMDS(TMDS_red)    );

TMDS_encoder encode_G( .clk(pixelClock), .VD(regGreen), .CD(2'b00)        , .VDE(regDrawing), .TMDS(TMDS_green)  );

TMDS_encoder encode_B( .clk(pixelClock), .VD(regBlue ), .CD({regVSync,regHSync}), .VDE(regDrawing), .TMDS(TMDS_blue)   );



// ----------------------------------------------------------------------------

// Generate TDMS Clock

// ----------------------------------------------------------------------------



wire clk_TMDS=pixelClockX10;



// ----------------------------------------------------------------------------

// Generate TDMS Signals (Serialise)

// ----------------------------------------------------------------------------



reg [3:0] TMDS_mod10=0;  			// modulus 10 counter

reg [9:0] TMDS_shift_red=0;		// 10 Bit Shift Registers

reg [9:0] TMDS_shift_green=0;		// 10 Bit Shift Registers

reg [9:0] TMDS_shift_blue=0;		// 10 Bit Shift Registers



reg TMDS_shift_load=0;



always @(posedge clk_TMDS) 	TMDS_shift_load <= (TMDS_mod10==4'd9);



always @(posedge clk_TMDS)

begin

	TMDS_shift_red  	<= TMDS_shift_load ? TMDS_red   : TMDS_shift_red  [9:1];

	TMDS_shift_green	<= TMDS_shift_load ? TMDS_green : TMDS_shift_green[9:1];

	TMDS_shift_blue 	<= TMDS_shift_load ? TMDS_blue  : TMDS_shift_blue [9:1];	

	

	TMDS_mod10			<= (TMDS_mod10==4'd9) ? 4'd0 : TMDS_mod10+4'd1;

end



assign TMDSp[2]    = TMDS_shift_red[0]  ;

assign TMDSp[1]    = TMDS_shift_green[0];

assign TMDSp[0]    = TMDS_shift_blue[0] ;

assign TMDSp_clock = pixelClock;



assign TMDSn[2] 		= !TMDSp[2];

assign TMDSn[1] 		= !TMDSp[1];

assign TMDSn[0] 		= !TMDSp[0];

assign TMDSn_clock	= !TMDSp_clock;



endmodule







































// ----------------------------------------------------------------------------

// TDMS Encoder

// ----------------------------------------------------------------------------



module TMDS_encoder

(

	input clk,

	input [7:0] VD,  			// video data (red, green or blue)

	input [1:0] CD,  			// control data

	input VDE,				  	// video data enable, to choose between CD (when VDE=0) and VD (when VDE=1)

	output reg [9:0] TMDS = 0

);



wire [3:0] Nb1s = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7];

wire XNOR = (Nb1s>4'd4) || (Nb1s==4'd4 && VD[0]==1'b0);

wire [8:0] q_m = {~XNOR, q_m[6:0] ^ VD[7:1] ^ {7{XNOR}}, VD[0]};



reg [3:0] balance_acc = 0;



wire [3:0] balance = q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7] - 4'd4;



wire balance_sign_eq = (balance[3] == balance_acc[3]);



wire invert_q_m = (balance==0 || balance_acc==0) ? ~q_m[8] : balance_sign_eq;



wire [3:0] balance_acc_inc = balance - ({q_m[8] ^ ~balance_sign_eq} & ~(balance==0 || balance_acc==0));



wire [3:0] balance_acc_new = invert_q_m ? balance_acc-balance_acc_inc : balance_acc+balance_acc_inc;



wire [9:0] TMDS_data = {invert_q_m, q_m[8], q_m[7:0] ^ {8{invert_q_m}}};



wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100) : (CD[0] ? 10'b0010101011 : 10'b1101010100);



always @(posedge clk) TMDS <= VDE ? TMDS_data : TMDS_code;

always @(posedge clk) balance_acc <= VDE ? balance_acc_new : 4'h0;

endmodule





































module YCbCr2RGB (	

	oRed,

	oGreen,

	oBlue,

    

	iY,

	iCb,

	iCr,

	iCLK					

);



//===========================================================================

// PORT declarations

//===========================================================================

					

input [7:0] iY  ;

input [7:0] iCb ;

input [7:0] iCr ;

input 		iCLK;

output [7:0]oRed;

output [7:0]oGreen;

output [7:0]oBlue;



//=============================================================================

// REG/WIRE declarations

//=============================================================================



// OUTPUT RGB 10bit x 3 //

reg 	[7:0]  oRed;

reg 	[7:0]  oGreen;

reg 	[7:0]  oBlue;



// TEMP RGB 21bit x 3 //

wire 	[20:0] mR;

wire 	[20:0] mG;

wire 	[20:0] mB;



/*******************************************/

/* IMPLEMENT: ( Fractional:12BITs )        */

/* R = Y+   1.402(Cr-128) 				   */

/* G = Y- 0.34414(Cb-128) -0.71212(Cr-128) */

/* B = Y+   1.772(Cb-128)				   */

/*										   */

/*******************************************/

assign mR =  iY*3500 + 4096*(iCr-128) + 1647*(iCr-128); //0.402x4096

assign mG =  iY*3500 - 1410*(iCb-128) - 2917*(iCr-128); //0.34414x4096 , 0.71212x4096

assign mB =  iY*3500 + 4096*(iCb-128) + 3162*(iCb-128); //0.772x4096 





// 0 ~ 3FF CLAMP //

always @(posedge iCLK) begin

	oRed  [7:0] =(mR[20])? 0 :( (mR >= 20'hfffff)? 10'hFF: mR[19:12] ) ;

	oGreen[7:0] =(mG[20])? 0 :( (mG >= 20'hfffff)? 10'hFF: mG[19:12] ) ;

	oBlue [7:0] =(mB[20])? 0 :( (mB >= 20'hfffff)? 10'hFF: mB[19:12] ) ;

end



endmodule







