
// --------------------------------------------------------------------
// Copyright (c) 2007 by Terasic Technologies Inc. 
// --------------------------------------------------------------------
//
// Permission:
//
//   Terasic grants permission to use and modify this code for use
//   in synthesis for all Terasic Development Boards and Altera Development 
//   Kits made by Terasic.  Other use of this code, including the selling 
//   ,duplication, or modification of any portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL/Verilog or C/C++ source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Terasic provides no warranty regarding the use 
//   or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Terasic Technologies Inc
//                     356 Fu-Shin E. Rd Sec. 1. JhuBei City,
//                     HsinChu County, Taiwan
//                     302
//
//                     web: http://www.terasic.com/
//                     email: support@terasic.com
//
// --------------------------------------------------------------------

/*

Horizonal Timing
A (us) Scanline 
B (us) Sync pulse
C (us) Back porchch
D (us) Active video
E (us) Front porcch
E+B+C = blanking

         ______________________          _________
________|        VIDEO         |________| VIDEO (next line)
    |-C-|----------D-----------|-E-|
__   _______________________________   ___________
  |_|                               |_|
  |B|
  |---------------A-----------------|


Vertical Timing
O (ms) Total frame
P (ms) Sync length
Q (ms) Back porch
R (ms) Active video
S (ms) Front porch
         ______________________          ________
________|        VIDEO         |________| VIDEO (next fram
    |-Q-|----------R-----------|-S-|
__   ______________________________   ___________
  |_|                              |_|
  |P|
  |---------------O----------------|


VGA 640x480@60Hz

Reference:
http://www.epanorama.net/documents/pc/vga_timing.html

"VGA industry standard" 640x480 pixel mode

example: 640x480@60
General characteristics
Clock frequency 25.175 MHz
Line  frequency 31469 Hz
Field frequency 59.94 Hz

One line
  8 pixels front porch
 96 pixels horizontal sync
 40 pixels back porch
  8 pixels left border
640 pixels video
  8 pixels right border
---
800 pixels total per line

One field
  2 lines front porch
  2 lines vertical sync
 25 lines back porch
  8 lines top border
480 lines video
  8 lines bottom border
---
525 lines total per field 

Other details
Sync polarity: H negative, V negative
Scan type: non interlaced.



*/

module vga_time_generator(

           clk,
           reset_n,
 
           h_disp,
           h_fporch,
           h_sync,   
           h_bporch,
 
           v_disp,
           v_fporch,
           v_sync,   
           v_bporch,
           
           hs_polarity,
           vs_polarity,
           frame_interlaced,
 
           vga_hs,
           vga_vs,
           vga_de,
           
           pixel_i_odd_frame,
           pixel_x,
           pixel_y
           
 
);

////////////////////////////////////////////////
/////// Port Declare
////////////////////////////////////////////////
input       	clk;
input       	reset_n;

input [11:0]	h_disp;
input [11:0]	h_fporch;
input [11:0]	h_sync;   
input [11:0]	h_bporch;

input [11:0]	v_disp;
input [11:0]	v_fporch;
input [11:0]	v_sync;   
input [11:0]	v_bporch;

input			hs_polarity;
input			vs_polarity;
input			frame_interlaced;

output  reg		vga_hs;
output  reg    	vga_vs;
output      	vga_de;

output	reg		pixel_i_odd_frame;
output  reg	[11:0]	pixel_x;
output  reg	[11:0]	pixel_y;




////////////////////////////////////////////////
///////h sync////////
////////////////////////////////////////////////
//h total sum//
reg [11:0]	h_total;
reg [11:0]	h_total_half;
reg [11:0]	h_pixel_start;
reg [11:0]	h_pixel_end;
reg		  	h_sync_polarity;
reg  	  	vga_h_de;

wire h_de;
wire [11:0] h_valid_pixel_count;
wire h_last_pixel;
assign h_de = (h_counter >= h_pixel_start && h_counter < h_pixel_end)?1'b1:1'b0;
assign h_valid_pixel_count = h_counter - h_pixel_start;
assign h_last_pixel = (h_counter+1 == h_total)?1'b1:1'b0;


//h counter gen //
reg [11:0]h_counter;
reg	[11:0] h_cur_disp;


//	H_Sync, H_Blank Generator, 
always @(posedge clk or negedge reset_n)
begin
	if (!reset_n)
	begin
		h_counter <= 12'h000;
		vga_hs <= hs_polarity?1'b1:1'b0;
		vga_h_de <= 1'b0;
		pixel_x <= 12'hfff;
		h_cur_disp <= 0;
    end
    else if (h_cur_disp != h_disp)
    begin
		h_cur_disp <= h_disp;
		//
		h_total <= h_disp+h_fporch+h_sync+h_bporch;	
		h_total_half <= (h_disp+h_fporch+h_sync+h_bporch ) >> 1;	
		h_pixel_start <= h_sync+h_bporch;
		h_pixel_end <= h_sync+h_bporch+h_disp;
		h_sync_polarity <= hs_polarity;
		//
		h_counter <= 12'h000;
		vga_hs <= hs_polarity?1'b1:1'b0;
		vga_h_de <= 1'b0;
		pixel_x <= 12'hfff;
	end
	else
	begin
		// h_counter
		if (!h_last_pixel) 
			h_counter <= h_counter+1'b1;
		else 
			h_counter <= 0;
			
	    // h sync generator
		if (h_counter < h_sync)
			vga_hs <= h_sync_polarity?1'b1:1'b0;
        else					
			vga_hs <= h_sync_polarity?1'b0:1'b1;
			
	    // de
		pixel_x <= (h_de)?h_valid_pixel_count:12'hfff; 
		vga_h_de <= h_de;
		
    end						
end


////////////////////////////////////////////////
/////v sync///// 
////////////////////////////////////////////////
//v total sum//
reg vga_v_de;
reg [11:0]v_total;
reg [11:0]v_pixel_start;
reg [11:0]v_pixel_end;
reg		  v_sync_polarity;
reg		  v_interlaced;
reg	  	  gen_field1_sync;
reg		  f0_to_f1;

wire [11:0] v_field_total;
wire [11:0] v_field_disp;
wire [11:0] v_valid_line_count;
wire v_de;
assign v_de = (v_counter >= v_pixel_start && v_counter < v_pixel_end)?1'b1:1'b0;
assign v_valid_line_count = v_counter - v_pixel_start;
assign v_field_disp = (frame_interlaced)?(v_disp >> 1):v_disp;
assign v_field_total = v_sync+v_bporch+v_field_disp+v_fporch;

//v counter gen
reg [11:0] v_counter;
reg	[11:0] v_cur_disp;

//	H_Sync, H_Blank Generator, 
always @(posedge clk or negedge reset_n)
begin
	if (!reset_n)
	begin
		v_counter <= 12'h000;
		vga_vs <= vs_polarity?1'b1:1'b0;
		vga_v_de <= 1'b0;
		pixel_y <= 12'hfff;
		pixel_i_odd_frame <= 1'b0;
		v_cur_disp <= 0;
	end
    else if (v_cur_disp != v_disp)
	begin
		v_cur_disp <= v_disp;
		//
		v_pixel_start <= v_sync+v_bporch;
		v_pixel_end <= v_sync+v_bporch+v_field_disp;
		v_total <= v_field_total;// + frame_interlaced; 
		v_sync_polarity <= vs_polarity;
		v_interlaced <= frame_interlaced;
		f0_to_f1 <= 1'b0;
		//
		v_counter <= 12'h000;
		vga_vs <= vs_polarity?1'b1:1'b0;
		vga_v_de <= 1'b0;
		pixel_y <= 12'hfff;
		pixel_i_odd_frame <= 1'b0;
	end
	else if (h_counter == 0 && f0_to_f1)
		f0_to_f1 <= 1'b0;  // line between field0 and filed1
	else if (h_counter == h_total_half && (f0_to_f1 || pixel_i_odd_frame))
	begin   // generate sync for filed1
		// v sync generator
		if (f0_to_f1)
			pixel_i_odd_frame <= 1'b1;
		else	
		begin
			if (v_counter < v_sync)  // v_counter, 0,1,2,3.... 
				vga_vs <= v_sync_polarity?1'b1:1'b0;
			else					
				vga_vs <= v_sync_polarity?1'b0:1'b1;		
		end		
	end	
	else if (h_counter == 0)
	begin
		// v_counter
		if (v_counter+1  < v_total) 
			v_counter <= v_counter+1'b1;
		else 
		begin
			v_counter <= 0;
			//
			if (v_interlaced)
			begin
				if (pixel_i_odd_frame)
					pixel_i_odd_frame <= 1'b0; 
				else	
					f0_to_f1 <= 1'b1;
			end
		end	
		
	    // v sync generator
	    if (!pixel_i_odd_frame)
	    begin
			if (v_counter < v_sync)
				vga_vs <= v_sync_polarity?1'b1:1'b0;
			else					
				vga_vs <= v_sync_polarity?1'b0:1'b1;
        end					
			
	    // blank	
	    vga_v_de <= v_de;
		if (!v_de)
			pixel_y <= 12'hfff;
		else if (!v_interlaced)
			pixel_y <= v_valid_line_count;
		else if (pixel_i_odd_frame)
			pixel_y <= (v_valid_line_count << 1) + 1;  // odd frame, 1, 3, 5, ...
		else
			pixel_y <= v_valid_line_count << 1;  // even frame, 0, 2, 4, ...
			
	end
end

//sync timing output//


assign vga_de = vga_h_de & vga_v_de;


endmodule


module VGA_SINK(
        // global Signals
        clk,
        reset_n,
   
		
		// avalong s1 ST-SINK(streaming) interface
		ready_out,
		valid_in,
		data_in,  // pass RGB data
		sop_in,  // start of papacket
		eop_in,  // end of packet // Required by Avaon-ST spec.  Unused in this core.
		empty_in,  // Required by Avaon-ST spec.  Unused in this core.
		
		// VGA export interface
		vga_clk,
		vga_hs,
		vga_vs,
		vga_de,
		vga_r,
		vga_g,
		vga_b
);


/*****************************************************************************
 *                           Parameter Declarations                          *
 *****************************************************************************/
parameter SYMBOLS_PER_BEAT   = 1; 
parameter BITS_PER_SYMBOL    = 24;
parameter READY_LATENCY      = 0; 
parameter MAX_CHANNEL        = 0;

parameter H_DISP	         = 640;
parameter H_FPORCH	         = 16;
parameter H_SYNC	         = 96;
parameter H_BPORCH	         = 48;
parameter V_DISP	         = 480;
parameter V_FPORCH	         = 10;
parameter V_SYNC	         = 2;
parameter V_BPORCH	         = 33;



/*****************************************************************************
 *                           Constant Declarations                           *
 *****************************************************************************/


`define STATE_IDLE    		0
`define STATE_WAIT_SOP		1   // start of packet
`define STATE_WAIT_EOF		2   // end of frame
`define STATE_STREAMING 	3

/*****************************************************************************
 *                             Port Declarations                             *
 *****************************************************************************/
        // global signal
input							clk;
input							reset_n;
	
		
		// avalong s1 ST-SINK(streaming) interface
output	reg						ready_out;
input							valid_in;
input	[23:0]					data_in;
input							sop_in;
input							eop_in;
input							empty_in;
//input	 [1:0]					empty_in;

		
		// VGA export interface
output				vga_clk;
output	reg			vga_hs;
output	reg			vga_vs;
output	reg			vga_de;
output	reg	[7:0]	vga_r;
output	reg	[7:0]	vga_g;
output	reg	[7:0]	vga_b;


/*****************************************************************************
 *                 Internal wires and registers Declarations                 *
 *****************************************************************************/
reg		[1:0]                   streaming_state;



/*****************************************************************************
 *                         Finite State Machine(s)                           *
 *****************************************************************************/


/*****************************************************************************
 *                             Sequential logic                              *
 *****************************************************************************/
 



/*****************************************************************************
 *                            Combinational logic                            *
 *****************************************************************************/


/*****************************************************************************
 *                              Internal Modules                             *
 *****************************************************************************/
wire			pix_hs;
wire			pix_vs;
wire			pix_de;
wire	[11:0]	pix_x;
wire	[11:0]	pix_y;



vga_time_generator vga_time_generator_instance(
		.clk      (vga_clk),
		.reset_n  (reset_n),
	//	.timing_change(timing_chang),
		.h_disp   (H_DISP),
		.h_fporch (H_FPORCH),
		.h_sync   (H_SYNC), 
		.h_bporch (H_BPORCH),
		
		.v_disp   (V_DISP),
		.v_fporch (V_FPORCH),
		.v_sync   (V_SYNC),
		.v_bporch (V_BPORCH),
		.hs_polarity(1'b0),
		.vs_polarity(1'b0),
		.frame_interlaced(1'b0),
		
		.vga_hs   (pix_hs),
		.vga_vs   (pix_vs),
		.vga_de   (pix_de),
		.pixel_x  (pix_x),
		.pixel_y ( pix_y),
		.pixel_i_odd_frame() 
);


// state mechine
always @ (posedge clk or negedge reset_n)
begin
	if (!reset_n)
	begin
		streaming_state <= `STATE_IDLE;
	end
	else if (streaming_state == `STATE_IDLE)
	begin
		streaming_state <= `STATE_WAIT_SOP;
		// reset
	end
	else if (streaming_state == `STATE_WAIT_SOP)
	begin
		if (valid_in && sop_in)
			streaming_state <= `STATE_WAIT_EOF;
	end
	else if (streaming_state == `STATE_WAIT_EOF)
	begin
		if (pix_y >= V_DISP)
		begin
			streaming_state <= `STATE_STREAMING;
		end
	end
	else if (streaming_state == `STATE_STREAMING)
	begin
		if (valid_in && eop_in)
			streaming_state <= `STATE_WAIT_SOP;
	end
end


//============ stage 1 =======
assign vga_clk = clk;


reg 		vga_hs_1;
reg 		vga_vs_1;
reg 		vga_de_1;
reg [23:0]	vga_data_1;

wire		query_pixel;
assign query_pixel = pix_de & valid_in;

always @ (posedge clk)
begin
	if (streaming_state != `STATE_STREAMING)
	begin
		ready_out <= 1'b0;
		vga_data_1 <= (pix_de)?24'hFFFFFF: 24'h000000;
	end	
	else
	begin
		ready_out <= query_pixel;
		vga_data_1 <= (query_pixel)?data_in:24'h000000;
	end

	vga_hs_1 <= pix_hs;
	vga_vs_1 <= pix_vs;
	vga_de_1 <= pix_de;
end


//============ stage 2 =======
always @ (posedge clk)
begin
	{vga_b,vga_g,vga_r} <= vga_data_1;
	vga_hs <= vga_hs_1;
	vga_vs <= vga_vs_1;
	vga_de <= vga_de_1;
end



endmodule





