module	VGA_Ctrl	(	//	Host Side
						iRed,
						iGreen,
						iBlue,
						oCurrent_X,
						oCurrent_Y,
						oAddress,
						oRequest,
						//	VGA Side
						oVGA_R,
						oVGA_G,
						oVGA_B,
						oVGA_HS,
						oVGA_VS,
						oVGA_SYNC,
						oVGA_BLANK,
						oVGA_CLOCK,
						//	Control Signal
						iCLK,
						iRST_N,
						iSW);
//	Host Side
input		[9:0]	iRed;
input		[9:0]	iGreen;
input		[9:0]	iBlue;
output		[21:0]	oAddress;
output		[10:0]	oCurrent_X;
output		[10:0]	oCurrent_Y;
output				oRequest;
//	VGA Side
output		[9:0]	oVGA_R;
output		[9:0]	oVGA_G;
output		[9:0]	oVGA_B;
output	reg			oVGA_HS;
output	reg			oVGA_VS;
output				oVGA_SYNC;
output				oVGA_BLANK;
output				oVGA_CLOCK;
reg			[10:0]	oColorX, oColorY;
//	Control Signal
input				iCLK;
input				iRST_N;
input           [9:0]           iSW;
//	Internal Registers
reg			[10:0]	H_Cont;
reg			[10:0]	V_Cont;
reg             [8:0]          pixel;
reg             [9:0]           tempR, tempG, tempB;
////////////////////////////////////////////////////////////
//	Horizontal	Parameter
parameter	H_FRONT	=	16;
parameter	H_SYNC	=	96;
parameter	H_BACK	=	48;
parameter	H_ACT	=	640;
parameter	H_BLANK	=	H_FRONT+H_SYNC+H_BACK;
parameter	H_TOTAL	=	H_FRONT+H_SYNC+H_BACK+H_ACT;
////////////////////////////////////////////////////////////
//	Vertical Parameter
parameter	V_FRONT	=	11;
parameter	V_SYNC	=	2;
parameter	V_BACK	=	31;
parameter	V_ACT	=	480;
parameter	V_BLANK	=	V_FRONT+V_SYNC+V_BACK;
parameter	V_TOTAL	=	V_FRONT+V_SYNC+V_BACK+V_ACT;
////////////////////////////////////////////////////////////
assign	oVGA_SYNC	=	1'b1;			//	This pin is unused.
assign	oVGA_BLANK	=	~((H_Cont<H_BLANK)||(V_Cont<V_BLANK));
assign	oVGA_CLOCK	=	~iCLK;
assign	oVGA_R		=	tempR;
assign	oVGA_G		=	tempG;
assign	oVGA_B		=	tempB;
assign	oAddress	=	oCurrent_Y*H_ACT+oCurrent_X;
assign	oRequest	=	((H_Cont>=H_BLANK && H_Cont<H_TOTAL)	&&
						 (V_Cont>=V_BLANK && V_Cont<V_TOTAL));
assign	oCurrent_X	=	(H_Cont>=H_BLANK)	?	H_Cont-H_BLANK	:	11'h0	;
assign	oCurrent_Y	=	(V_Cont>=V_BLANK)	?	V_Cont-V_BLANK	:	11'h0	;

reg [2:0] R [640*480];
reg [2:0] G [640*480];
reg [2:0] B [640*480];
reg [$clog2(640*480*2):0] counter;

wire done;

assign done = !iRST_N ? 0 : counter == 640*480*2;

always @(posedge iCLK) begin
  if (!oCurrent_Y && !done) begin
    counter <= 0;
  end else if(counter < 640*480*2) begin
    R[oCurrent_Y*640+oCurrent_X] <= iRed[9:7];
    G[oCurrent_Y*640+oCurrent_X] <= iGreen[9:7];
    B[oCurrent_Y*640+oCurrent_X] <= iBlue[9:7];
  end

  if ((counter < 640*480*2) && !done) begin
      counter <= counter + 1;
  end

  pixel <= {
             R[oCurrent_Y*640+oCurrent_X],
	     G[oCurrent_Y*640+oCurrent_X],
	     B[oCurrent_Y*640+oCurrent_X]
           };
end

always @ (*)  begin
  if (iSW[0] && iRed >= 600 && iRed <= 1023 && iBlue <= 360 && iBlue >= 0 && iGreen <= 640) begin // Cloak Mask
    tempR = {pixel[8:6], 7'b1111100};
    tempG = {pixel[5:3], 7'b1111100};
    tempB = {pixel[2:0], 7'b1111100};
  end else if(iSW[1]) begin // Video OFF
    tempR = 10'b0;
    tempG = 10'b0;
    tempB = 10'b0;
  end else if(iSW[2]) begin // Captured Foreground Image
    tempR = {pixel[8:6], 7'b1111100};
    tempG = {pixel[5:3], 7'b1111100};
    tempB = {pixel[2:0], 7'b1111100};
  end else if(iSW[3]) begin // Red Filter
    tempR = iRed;
    tempG = 10'b0;
    tempB = 10'b0;
  end else if(iSW[4]) begin // Green Filter
    tempR = 10'b0;
    tempG = iGreen;
    tempB = 10'b0;
  end else if(iSW[5]) begin // Blue Filter
    tempR = 10'b0;
    tempG = 10'b0;
    tempB = iBlue;
 end else if(iSW[6]) begin // Grayscale Filter
    tempR = (iRed != 0) ? (299 * iRed / 1000) + (587 * iGreen / 1000) + (114 * iBlue / 1000) : 0;
    tempG = (iGreen != 0) ? (299 * iRed / 1000) + (587 * iGreen / 1000) + (114 * iBlue / 1000) : 0;
    tempB = (iBlue != 0) ? (299 * iRed / 1000) + (587 * iGreen / 1000) + (114 * iBlue / 1000) : 0;
 end else if(iSW[7]) begin // Invert Video
    tempR = 1023 - ((iRed + iGreen + iBlue) / 3);
    tempG = 1023 - ((iRed + iGreen + iBlue) / 3);
    tempB = 1023 - ((iRed + iGreen + iBlue) / 3);
 end else if(iSW[8]) begin // Dark Video
    tempR = (iRed > 200) ? iRed - 200 : 0;
    tempG = (iGreen > 200) ? iGreen - 200 : 0;
    tempB = (iBlue > 200) ? iBlue - 200 : 0;
 end else if(iSW[9]) begin // Bright Video
    tempR = (iRed + 200 > 1023) ? 1023 : iRed + 200;
    tempG = (iGreen + 200 > 1023) ? 1023 : iGreen + 200;
    tempB = (iBlue + 200 > 1023) ? 1023 : iBlue + 200;
 end else begin // Real-time Video
    tempR = iRed;
    tempG = iGreen;
    tempB = iBlue;
  end
end

always@(posedge iCLK or negedge iRST_N)
begin
	if(!iRST_N)
	begin
		H_Cont		<=	0;
		oVGA_HS	<=	1;
	end
	else
	begin
		if(H_Cont<H_TOTAL)
		H_Cont	<=	H_Cont+1'b1;
		else
		H_Cont	<=	0;
		//	Horizontal Sync
		if(H_Cont==H_FRONT-1)			//	Front porch end
		oVGA_HS	<=	1'b0;
		if(H_Cont==H_FRONT+H_SYNC-1)	//	Sync pulse end
		oVGA_HS	<=	1'b1;
	end
end

//	Vertical Generator: Refer to the horizontal sync
always@(posedge oVGA_HS or negedge iRST_N)
begin
	if(!iRST_N)
	begin
		V_Cont		<=	0;
		oVGA_VS	<=	1;
	end
	else
	begin
		if(V_Cont<V_TOTAL)
		V_Cont	<=	V_Cont+1'b1;
		else
		V_Cont	<=	0;
		//	Vertical Sync
		if(V_Cont==V_FRONT-1)		//	Front porch end
		oVGA_VS	<=	1'b0;
		if(V_Cont==V_FRONT+V_SYNC-1)	//	Sync pulse end
		oVGA_VS	<=	1'b1;
	end
end

endmodule
