`include "vpg_source/vpg.h"

`define COLOR_RGB444	0

module Tr4_DVI_TOP(
  CLK_50,
  BUTTON,
  HSMC_DVI_RX_CLK,
  HSMC_DVI_RX_D,
  HSMC_DVI_RX_DE,
  HSMC_DVI_RX_HS,
  HSMC_DVI_RX_VS,
  
  HSMC_DVI_TX_CLK,
  HSMC_DVI_TX_ISEL,
  HSMC_DVI_TX_SCL,
  HSMC_DVI_TX_HTPLG,
  HSMC_DVI_TX_SDA,
  HSMC_TX_PD_N,
  HSMC_DVI_TX_DE,
  HSMC_DVI_TX_VS, 
  HSMC_DVI_TX_HS, 
  HSMC_DVI_TX_D,
  HSMC_DVI_RX_DDCSCL,
  HSMC_DVI_RX_DDCSDA,
  HSMC_EDID_WP,
  
  LED);
 
input            CLK_50;
input  [3:0]     BUTTON;
input            HSMC_DVI_RX_CLK;
input [23:0]     HSMC_DVI_RX_D;
input            HSMC_DVI_RX_DE;
input            HSMC_DVI_RX_HS;
input            HSMC_DVI_RX_VS;
  
output           HSMC_DVI_TX_CLK;
output           HSMC_DVI_TX_ISEL;
output           HSMC_DVI_TX_SCL;
output           HSMC_DVI_TX_HTPLG;
inout            HSMC_DVI_TX_SDA;
output           HSMC_EDID_WP;
output           HSMC_TX_PD_N;
output           HSMC_DVI_TX_DE;
output           HSMC_DVI_TX_VS; 
output           HSMC_DVI_TX_HS; 
output   [23:0]  HSMC_DVI_TX_D;
output           HSMC_DVI_RX_DDCSCL;
inout            HSMC_DVI_RX_DDCSDA;
output   [3:0]   LED;

wire reset_n;
wire pll_100M;
wire pll_100K;

wire gen_sck;
wire gen_i2s;
wire gen_ws;



sys_pll sys_pll_inst(
	.areset(1'b0),
	.inclk0(CLK_50),
	.c0(pll_100M),
	.c1(pll_100K),
	.locked(reset_n)
	);
	


//---------------------------------------------------//
//				Mode Change Button Monitor 			 //
//---------------------------------------------------//
wire			mode_button;
reg				pre_mode_button;
reg		[15:0]	debounce_cnt;
reg		[3:0]	vpg_mode;	
reg				vpg_mode_change;

	assign mode_button = ~BUTTON[3];
	always@(posedge pll_100M or negedge reset_n)
		begin
			if (!reset_n)
				begin
					vpg_mode <= `VGA_640x480p60;
					debounce_cnt <= 1;
					vpg_mode_change <= 1'b1;
				end
			else if (vpg_mode_change)
				vpg_mode_change <= 1'b0;
			else if (debounce_cnt)
				debounce_cnt <= debounce_cnt + 1'b1;
			else if (mode_button && !pre_mode_button)
				begin
					debounce_cnt <= 1;
					vpg_mode_change <= 1'b1;
					if (vpg_mode == `VESA_1600x1200p60)
						vpg_mode <= `VGA_640x480p60;
					else
						vpg_mode <= vpg_mode + 1'b1;
				end
		end

	always@(posedge pll_100M)
		begin
			pre_mode_button <= mode_button;
		end


//----------------------------------------------//
// 			 Video Pattern Generator	  	   	//
//----------------------------------------------//
wire [3:0]	vpg_disp_mode;
wire [1:0]	vpg_disp_color;

wire vpg_pclk;
wire vpg_de;
wire vpg_hs;
wire vpg_vs;
wire [23:0]	vpg_data;


vpg	vpg_inst(
	.clk_100(pll_100M),
	.reset_n(reset_n),
	.mode(vpg_mode),
	.mode_change(vpg_mode_change),
	.disp_color(`COLOR_RGB444),       
	.vpg_pclk(vpg_pclk),
	.vpg_de(vpg_de),
	.vpg_hs(vpg_hs),
	.vpg_vs(vpg_vs),
	.vpg_r(vpg_data[23:16]),
	.vpg_g(vpg_data[15:8]),
	.vpg_b(vpg_data[7:0])
);
//----------------------------------------------//
// 				DVI receiver					//
//----------------------------------------------//
// In schematic OCK_INV=GND, latches output data on falling edge
wire rx_clk;
reg	[23:0]	rx_data;
reg			rx_de;
reg			rx_hs;
reg			rx_vs;
assign rx_clk = ~HSMC_DVI_RX_CLK;
always@(posedge rx_clk) // OCK_INV=GND, latches output data on falling edge
begin
	rx_data <= {HSMC_DVI_RX_D[23:16], HSMC_DVI_RX_D[15:8], HSMC_DVI_RX_D[7:0]};
	rx_de <= HSMC_DVI_RX_DE;
	rx_hs <= HSMC_DVI_RX_HS;
	rx_vs <= HSMC_DVI_RX_VS;
	
end
		


//----------------------------------------------//
// 			 DVI TX                 	  	   	//
//----------------------------------------------//
//=============== DVI TX CONFIG ==================
assign HSMC_DVI_TX_ISEL 	= 1'b0; 	// disable i2c
assign HSMC_DVI_TX_SCL 	= 1'b1; 	// BSEL=0, 12-bit, dual-edge input
assign HSMC_DVI_TX_HTPLG 	= 1'b1; 	// Note. *** EDGE=1, primary latch to occur on the rising edge of the input clock IDCK+
assign HSMC_DVI_TX_SDA 	= 1'b1;  	// DSEL=X (VREF=3.3V)
assign HSMC_TX_PD_N 		= 1;

//
reg			loopback_mode;
reg	[15:0]	disable_cnt;
reg			pre_loopback_btn;
wire        loopback_btn;
assign loopback_btn = ~BUTTON[2];

always @ (posedge pll_100K)
begin
	if (disable_cnt)
	begin
		disable_cnt <= disable_cnt + 1'b1;
	end
	else if (loopback_btn && !pre_loopback_btn && disable_cnt == 0)
	begin
		loopback_mode <= loopback_mode + 1'b1;
		disable_cnt <= 16'hFFFF;
	end
	//
	pre_loopback_btn <= loopback_btn;
end

clk_selector clk_selector_inst(
	.data0(vpg_pclk),
	.data1(rx_clk),
	.sel(loopback_mode),
	.result(HSMC_DVI_TX_CLK)
	);

video_selector video_selector_inst(
	.clock(HSMC_DVI_TX_CLK),
	.data0x({vpg_de, vpg_vs, vpg_hs, vpg_data}),
	.data1x({rx_de, rx_vs, rx_hs, rx_data}),
	.sel(loopback_mode),
	.result({HSMC_DVI_TX_DE, HSMC_DVI_TX_VS, HSMC_DVI_TX_HS, HSMC_DVI_TX_D})
	);

//----------------------------------------------//
// 			 DVI RX EDID (EEPROM Writing)  	   	//
//----------------------------------------------//
wire edid_writing;
WRITE_EDID WRITE_EDID_inst(
		.CLK_I2C_100K(pll_100K),
		.EDID_WRITE_TRIGGER(~BUTTON[1]),
		.EDID_WRITING(edid_writing),
		.EDID_WP(HSMC_EDID_WP),
		.EDID_DDCSCL(HSMC_DVI_RX_DDCSCL),
		.EDID_DDCSDA(HSMC_DVI_RX_DDCSDA)
		);

	
		
// edid-writing: led indication
reg [3:0] 	edid_writing_led;		
reg [12:0] 	edid_led_cnt;		
always @(posedge pll_100K)
begin
	if (edid_writing)
	begin
		if (edid_led_cnt == 0)
			edid_writing_led <= edid_writing_led ^ 4'hF;
		edid_led_cnt <= edid_led_cnt + 1'b1;
	end
	else
	begin
		edid_writing_led <= 4'hF;
		edid_led_cnt <= 0;
	end
end		

//==================== LED indication
assign LED[3:0] = edid_writing?edid_writing_led:(loopback_mode?4'h0:~vpg_mode); // 4 leds are turn on for loopback mode		


endmodule
