--------------------------------------------------------------------------------
--
--                             CV_bars.VHD
--        Color Bars (754 X 480) to NTSC composite video monitor
--                          Author: Jim Burnet
--                         Avnet Design Services
--
--
--
--
-- CV_bars.vhd will output a digital representation of RGB color bars 
-- to an external video DAC (ADV7120) with timing and synchronization 
-- appropriate for a 754 X 480 (910 X 525) display on a NTSC television 
-- monitor. Color bars and syncs are generated on the fly; a frame buffer
-- is not used.  Testing was done with an Analog Devices ADV723 NTSC
-- Composite Video Encoder driven by the RGB analog output of the ADV7120.
--
-- Timing is based on the standard 4fsc NTDS frequency of 14.31818MHz.
-- This provides an interlaced scan rate (field rate) of 29.97Hz and
-- 525 vertical lines.  At this rate the theoretical  horizontal resolution
-- is 910 pixels (14.31818e6/29.97)/525 = 910.  Of these 910 pixels, 754 are
-- active (theoretically "viewable") and 156 are blanked (e.g., retrace
-- timing, etc.).  This "blanked" region encompasses the Front Porch,
-- Horizontal Sync, and Back Porch portions of the composite video waveform.
--
-- While the "viewable" region is 754 pixels, a number of factors determine 
-- the actual "viewed" horizontal resolution which is approximately 330 pixels.
-- Of the 525 vertical lines of resolution, approximately 480 are "viewable"
-- while 45 are "blanked" (vertical retrace, etc.). 
-- 
--
--      Clock Frequency:     14.31818MHz  (69.841ns)
--      Line Frequency:      15.734KHz    (63.556us)
--      Field Frequency:     29.97Hz      (33.367ms)
--      Frame Frequency:     59.94Hz      (16.683ms)
--
--      # of Frame lines:            525 (two interlaced fields)
--      # of Field lines:            262.5
--      # of pixels/line:            910
--      # of active pixels/line:     754
--      # of blanked pixels/line:    156
--
--
-- 	Horizontal Line:
--     Front Porch:          22 pixels     (1.54us)
--     Horizontal Sync:      67 pixels     (4.74us)
--     *Back Porch:          67 pixels     (4.61us)
--     Video:               754 pixels    (52.66us)
--                         -----         ------------
--                          910 pixels    (63.55us)
--
--          * Back porch contains approximately 9 cycles of 3.5795MHz
--            chroma burst (~2.514us).
--
--   Vertical Field:
--     Pre-Equalizing Pulses:      3   Horizontal line times (190.667us)
--     Serration Pulses:           3   Horizontal line times (190.667us)
--     Post-Equalizing Pulses:     3   Horizontal line times (190.667us)
--     Vertical Blanking:         11   Horizontal line times (699.112us)
--     Video:                    242.5 Horizontal line times (15.412ms)
--                               -----                      -------------
--                               262.5 Horizontal line times (16.683ms)
--
--
-- The color bars to be displayed are 94 pixels in width (754/8) with
-- colors as shown in the figure below.  The color bars are switch-selectable
-- for 75% amplitude or 100% amplitude, and 100% saturation.
--  
-- 		+--------+------+------+------+------+-------+------+------+------+
-- 		|        |      |      |      |      |       |      |      |      |
-- 		|H  B  I |      |      |      |      |       |      |      |      |
-- 		|O  L  N |      |      |      |      |       |      |      |      |
-- 		|R  A  T |WHITE |YELLOW| CYAN |GREEN |MAGENTA| RED  | BLUE |WHITE |
-- 		|I  N  E |      |      |      |      |       |      |      |      |
-- 		|Z  K  R |R=191 |R=191 |R=000 |R=000 |R=191  |R=191 |R=000 |R=191 |
-- 		|O  I  V |G=191 |G=191 |G=191 |G=191 |G=000  |G=000 |G=000 |G=191 |
-- 		|N  N  A |B=191 |B=000 |B=191 |B=000 |B=191  |B=000 |B=191 |B=191 |
-- 		|T  G  L |      |      |      |      |       |      |      |      |
-- 		|A       |      |      |      |      |       |      |      |      |
-- 		|L       |      |      |      |      |       |      |      |      |
-- 		|        |      |      |      |      |       |      |      |      |
-- 		+--------+------+------+------+------+-------+------+------+------+
--      ^       ^^      ^      ^      ^      ^       ^      ^      ^      ^
--      |       ||      |      |      |      |       |      |      |      |
--     754      |0      95    189    283    377     471    565    659    753
--              |
--             909
--
--
-- The 754 X 480 display is, essentially, a 480 row by 754 column matrix that
-- is drawn one row at a time left to right, top to bottom in an interlaced
-- manner. Upon reaching the right extremity (n, 753) the beam is blanked 
-- (turned off), returned to the left hand edge (horizontal retrace), and 
-- positioned to draw the next line.  Upon reaching the bottom right extremity
-- (479, 753) the beam is blanked and returned to the top left (0, 0) of the 
-- screen (vertical retrace).  Additional (undisplayed) overhead associated 
-- with display timing increases the 754 X 480 display to 910 X 525 pixels. 
-- See the tables above for actual timings. 

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity vsync is
	port( video_clk            : in std_logic;
	     switch                : in std_logic;
         reset                 : in std_logic;
		 TV_det                : in std_logic;
		 DAC_clk               : out std_logic;
         Horiz_sync, Vert_sync : out std_logic;
         Comp_sync, Blank      : out std_logic;
         H_count, V_count      : out std_logic_vector (9 downto 0);
	     video_out             : out std_logic_vector(23 downto 0);
	     STND                  : out std_logic;
	     SA                    : out std_logic;
		 CE                    : out std_logic;
		 Term                  : out std_logic;
		 LED_0                 : out std_logic
	    );
end vsync;

architecture behavior of vsync is
	constant H_max              : std_logic_vector(9 downto 0) :=
		CONV_STD_LOGIC_VECTOR(909,10);  -- 909 is max horiz count
	constant V_max              : std_logic_vector(9 downto 0) := 
	     CONV_STD_LOGIC_VECTOR(525,10);  -- 525 is max vert count
	signal  Video_out_75        : std_logic_vector(23 downto 0);
	signal  Video_out_100       : std_logic_vector(23 downto 0);
	signal  Hcnt, Vcnt          : std_logic_vector(9 downto 0);
	signal  Sync_pulse          : std_logic_vector(1 downto 0);
	signal  sync_H, sync_V      : std_logic;
--	signal  sync_Vcomp          : std_logic;
	signal  H_blank, V_blank    : std_logic;
	signal  active_video        : std_logic;
	signal  amp_switch          : std_logic;

begin

-- Blank = 0 during the 10.7usec Horizontal blanking interval
-- and the 20 horizontal line (each field) Vertical blanking
-- interval.  Blank = 1 during the active (viewable) video regions.

    DAC_clk <= video_clk; -- supply 14.31818MHz to video DAC
    Blank         <= not(H_blank or V_blank);
    active_video  <= not(H_blank or V_blank);
    H_count       <= Hcnt;
    V_count       <= Vcnt;
    amp_switch    <= switch;

    STND  <= '1';  -- 1 = NTSC; 0 = PAL
    SA    <= '0';  -- 1 = NA NTSC; 0 = SA NTSC and PAL(M)
    CE    <= '1';  -- 1 = AD723 enabled; 0 = AD723 power down
    Term  <= '1';  -- 1 = RGB terminated; 0 = terminations floating
	
    LED_0 <= TV_det; -- turn on LED if AD723 detects a TV set

-- Hcnt counts horizontal pixels from 0 to 909, with pixel 0 beginning
-- the active video region.  Hcnt regions are as follows:
--
--     Active Video:         0 through 753
--     Front Porch:        754 through 775
--     Horizontal Sync:    776 through 842
--     Back porch:         842 through 909
--
	
COUNTERS: process (reset, video_clk)
begin

if (reset = '0') then
    Hcnt <= H_max;
    Vcnt <= "0000000000";
	
elsif rising_edge(video_clk) 	
then
    if (Hcnt >= H_max) then
        Hcnt <= "0000000000";
    else
        Hcnt <= Hcnt + "0000000001";
    end if;
	
-- Vcnt counts vertical lines to provide properly positioned vertical
-- synchronizing pulses (Equalization, Serration, Blanking) snd field
-- delineation (262.5 lines X 2).  Vcnt uses both line # and Hcnt
-- Pixel # in order to determine the end of the last field line and
-- the beginning of the vertical synchronization period.

-- Vcnt will count line numbers from 1 through 525, incrementing at the
-- end of each horizontal line (pixel #909) and resetting to line #1
-- at line #525, pixel #909. Note that Hcnt counts from 0 through 909.

    if ((Vcnt >= V_max) and (Hcnt >= 909)) then
         Vcnt <= "0000000001"; -- bottom of the display, reset to the top
    elsif (Hcnt = 909) then
           Vcnt <= Vcnt + "0000000001"; -- end of a line, increment to next
    end if;

end if;
end process;


-- Generate the horizontal blanking region 
-- Horizontal blanking occurs for the 10.7usec period
-- from pixel #0 through pixel #152.
    H_blank <= '1' when ((Hcnt <= 152) and (Hcnt >= 0))
                   else '0';	
	   
-- Generate the vertical blanking region
    V_blank <= '1' when (Sync_pulse /= "00")
                   else '0';					   
					   
-- Generation of the Composite Video synchronization signals 
-- and the placement of the vertical synchronization pulses 
-- in order to delineate the two interlaced fields is a somewhat
-- cumbersome task.  The placement and ordering of the vertical 
-- synchronization pulses change by 1/2 scan line from field one
-- to field two, with field two being more complex because the
-- first visible scan line (283) is blanked until the middle of
-- display.
--
-- The vector Sync_pulse is set to trigger a specific vertical
-- synchronization pulse sequence (pre-equalizing, serration,
-- or post-equalizing) or the horizontal synchronization pulse.
-- The Vertical Blanking Interval is defined by Sync_pulse = non-zero.
--
-- Refer to the SMPTE 170M-1999 specification for further
-- timing details.


-- Sync_pulse = "01" drives the 2.3usec pre and post equalizing pulses
-- Sync_pulse = "10" drives the 27.1usec serration pulses
-- Sync_pulse = "00" drives the 4.8usec horizontal sync pulses
--
-- The Vertical Sync Pulse encompasses lines 4 through 6 
--   and 262.5 through 269.5 (~190usec).
--
-- The Vertical Blanking Interval encompasses lines 1 through 20 in field 1
--   and lines 263.5 through line 283.5 in field 2.
--
-- The Horizontal Sync Pulse encompasses 4.8usec in all horizontal lines
--   from 10 through 263 and 273 through 525.
--
-- The Horizontal Blanking Interval begins coincident with the Horizontal
--   Sync Pulse and lasts for 10.7usec.

    Sync_pulse <= "01" when 
          (((Vcnt <    4)  and (Vcnt >=   1))  -- lines 1-3
       or  ((Vcnt <   10)  and (Vcnt >=   7))  -- lines 7-9
	  or  ((Vcnt =  263)  and (Hcnt >= 455))  -- line 263 above pixel 454
       or  ((Vcnt <  266)  and (Vcnt >= 264))  -- lines 264-265
       or  ((Vcnt =  266)  and (Hcnt <  455))  -- line 266 below pixel 455
       or  ((Vcnt =  269)  and (Hcnt >= 455))  -- line 269 above pixel 454
       or  ((Vcnt <  272)  and (Vcnt >= 270))  -- lines 270-271
       or  ((Vcnt =  272)  and (Hcnt <  455))) -- line 272 below pixel 455
	   
       else "10" when
		(((Vcnt <    7)  and (Vcnt >=   4))  -- lines 4-6
       or  ((Vcnt =  266)  and (Hcnt >= 455))  -- line 266 above pixel 454
       or  ((Vcnt <  269)  and (Vcnt >= 267))  -- lines 267-268
       or  ((Vcnt =  269)  and (Hcnt <  455))) -- line 269 below pixel 455
	   
       else "11" when
		(((Vcnt <   21)  and (Vcnt >=  10))  -- lines 10-20
       or  ((Vcnt =  283)  and (Hcnt >= 455))  -- line 283 above pixel 454
       or  ((Vcnt <  283)  and (Vcnt >= 264))  -- lines 264-282
       or  ((Vcnt =  283)  and (Hcnt <  455))) -- line 283 below pixel 455
	   
	  else "00";

		   		   
	sync_H <= '1' when (Sync_pulse = "00" and ((Hcnt < 68)   and (Hcnt >= 0)))
                     or (Sync_pulse = "01" and ((Hcnt < 33)   and (Hcnt >= 0)))
				 or (Sync_pulse = "10" and ((Hcnt < 333)  and (Hcnt >= 0)))
				 or (Sync_pulse = "11" and ((Hcnt < 68)   and (Hcnt >= 0)))
		   		else '0';

     sync_V <= '1'  when (Sync_pulse = "10")
                    else '0';					  
					  
--     sync_Vcomp <= '1' when (Sync_pulse = "01" and ((Hcnt < 33)   and (Hcnt >= 0)))
--                     or (Sync_pulse = "01" and ((Hcnt < 488)  and (Hcnt >= 455)))
--                     or (Sync_pulse = "10" and ((Hcnt < 333)  and (Hcnt >= 0)))
--                     or (Sync_pulse = "10" and ((Hcnt < 843)  and (Hcnt >= 455)))
--                     else '0';

-- Generate the Horizontal and Vertical sync outputs	
	Horiz_sync <= sync_H;
	Vert_sync  <= sync_V;
	
-- Generate the Composite Video Sync output
--	Comp_sync <= (sync_H xnor sync_Vcomp);
	Comp_sync <= '1';
-- ***** Turn off Comp_sync to the ADV7120 DAC so we don't get sync-on Green
-- *****  when we are trying to drive the AD723 NTSC encoder.

-- When active_video = 1, generate color bars on the fly (no buffering).
-- amp_switch = 0 outputs 75% amplitude color bars
-- amp_switch = 1 outputs 100% amplitude color bars
	
     Video_out <= Video_out_75  when ((active_video = '1') and (amp_switch = '0')) else
	             Video_out_100 when ((active_video = '1') and (amp_switch = '1')) else
                  X"000000";
		  
--	 color bars: W/C/Y/G/M/B/R/W @75%
      video_out_75 <= X"bfbfbf" when ((Hcnt < 254) and (Hcnt >= 172)) else
	                  X"00bfbf" when ((Hcnt < 336) and (Hcnt >= 254)) else
	                  X"bfbf00" when ((Hcnt < 420) and (Hcnt >= 336)) else
	                  X"00bf00" when ((Hcnt < 504) and (Hcnt >= 420)) else
	                  X"bf00bf" when ((Hcnt < 586) and (Hcnt >= 504)) else
	                  X"0000bf" when ((Hcnt < 668) and (Hcnt >= 586)) else
	 			      X"bf0000" when ((Hcnt < 750) and (Hcnt >= 668)) else
				      X"bfbfbf" when ((Hcnt < 832) and (Hcnt >= 750)) else
                      X"000000";
					  
--	color bars: W/C/Y/G/M/B/R/W @100%
     video_out_100 <= X"ffffff" when ((Hcnt < 254) and (Hcnt >= 172)) else
                      X"00ffff" when ((Hcnt < 336) and (Hcnt >= 254)) else
	                  X"ffff00" when ((Hcnt < 420) and (Hcnt >= 336)) else
	                  X"00ff00" when ((Hcnt < 504) and (Hcnt >= 420)) else
	                  X"ff00ff" when ((Hcnt < 586) and (Hcnt >= 504)) else
	                  X"0000ff" when ((Hcnt < 668) and (Hcnt >= 586)) else
	 			      X"ff0000" when ((Hcnt < 750) and (Hcnt >= 668)) else
				      X"ffffff" when ((Hcnt < 832) and (Hcnt >= 750)) else
				      X"000000";
  
end behavior;
