VHDL VGA sync circuit

3.6k Views Asked by At

Can some one please tell me how this circuit increments h_count_reg and v_count_reg?? I don't really see it. Also what do they mean by the output is buffered exactly? It's just delayed by one pixel? don't really see that either. thanks!

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity vgaController is Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; hsync : out STD_LOGIC; vsync : out STD_LOGIC; video_on : out STD_LOGIC; p_tick : out STD_LOGIC; pixel_x : out STD_LOGIC_VECTOR (9 downto 0); pixel_y : out STD_LOGIC_VECTOR (9 downto 0)); end vgaController; architecture Behavioral of vgaController is -- VGA 640 -by - 480 sync p a r a m e t e r s constant HD: integer:=640; --horizontal display area constant HF: integer:=16 ; --h. front porch constant HB: integer:=48 ; --h. back porch constant HR: integer:=96 ; --h. retrace "Sync Pulse" constant VD: integer:=480; -- vertical display area constant VF: integer:=10 ; -- v. front porch constant VB: integer:=33 ; -- v. back porch constant VR: integer:=2 ; -- v. retrace "sync pulse" -- mod-2 counter signal mod2_reg, mod2_next : std_logic;--mod-2 counter to generate the 25-MHz enable tick -- sync counters, two counters for the horizontal and vertical scans signal v_count_reg, v_count_next : unsigned(9 downto 0); signal h_count_reg, h_count_next : unsigned(9 downto 0); --To remove --potential glitches, output buffers are inserted for the hsync and vsync signals. This leads --to a one-clock-cycle delay. add a similar buffer for the rgb signal in the pixel --generation circuit to compensate for the delay. -- output buffer signal v_sync_reg, h_sync_reg: std_logic; signal v_sync_next ,h_sync_next : std_logic; --status signal signal h_end , v_end , pixel_tick: std_logic; begin --register process(clk,reset) begin if (reset='1') then mod2_reg <='0'; v_count_reg <=(others=>'0'); h_count_reg <=(others=>'0'); v_sync_reg <='0'; h_sync_reg <='0'; elsif(clk'event and clk='1')then mod2_reg <=mod2_next; v_count_reg <=v_count_next; h_count_reg <=h_count_next; v_sync_reg <=v_sync_next; h_sync_reg <=h_sync_next; end if; end process; --mod-2 circuit to generate 25 MHz enable tick mod2_next <= not mod2_reg; -- 25 MHz pixel tick pixel_tick <= '1' when mod2_reg = '1' else '0'; --status h_end <= --end of horizonal counter '1' when h_count_reg = (HD+HF+HB+HR-1) else --799 '0'; v_end <= --end of vertial counter '1' when v_count_reg = (VD+VF+VB+VR-1) else --524 '0'; -- mod-800 horizontal sync counter process(h_count_reg,h_end,pixel_tick) begin if (pixel_tick='1') then --25 MHz tick if h_end='1' then h_count_next <= (others=>'0'); else h_count_next <= h_count_reg+1; end if; else h_count_next <= h_count_reg; end if; end process; -- mode-525 vertical sync counter process(v_count_reg,h_end,v_end,pixel_tick) begin if (pixel_tick='1' and h_end='1') then if (v_end='1') then v_count_next <= (others=>'0'); else v_count_next <= v_count_reg+1; end if; else v_count_next <= v_count_reg; end if; end process; -- horizontal and vertial sync, buffered to avoid glitch h_sync_next <= '1' when (h_count_reg >= (HD+HF)) --656 and (h_count_reg <= (HD+HF+HR-1)) else --751 '0'; v_sync_next <= '1' when (v_count_reg >= (VD+VF)) --490 and (v_count_reg <= (VD+VF+VR-1)) else --491 '0'; --video on/off video_on <= '1' when (h_count_reg < HD) and (v_count_reg < VD) else '0'; --output signals hsync <= h_sync_reg; vsync <= v_sync_reg; pixel_x <= std_logic_vector(h_count_reg); pixel_y <= std_logic_vector(v_count_reg); p_tick <= pixel_tick; end Behavioral;

3

There are 3 best solutions below

4
On BEST ANSWER

The vertical and horizontal counters are spread across two processes:

--register
process(clk,reset)
    begin
        if (reset='1') then
            mod2_reg     <='0';
            v_count_reg  <=(others=>'0');
            h_count_reg  <=(others=>'0');
            v_sync_reg   <='0';
            h_sync_reg   <='0';
        elsif(clk'event and clk='1')then
            mod2_reg     <=mod2_next;
            v_count_reg  <=v_count_next;
            h_count_reg  <=h_count_next;
            v_sync_reg   <=v_sync_next;
            h_sync_reg   <=h_sync_next;
        end if;
end process;

Where in the elsif condition the counters are loaded from v_count_next and h_count_next, which are produced in two different processes:

-- mod-800 horizontal sync counter
process(h_count_reg,h_end,pixel_tick)
    begin
        if (pixel_tick='1') then --25 MHz tick
            if h_end='1' then 
                h_count_next <= (others=>'0');
            else
                h_count_next <= h_count_reg+1;
            end if;
        else
            h_count_next <= h_count_reg;
        end if;
end process;

-- mode-525 vertical sync counter
process(v_count_reg,h_end,v_end,pixel_tick)
    begin
        if (pixel_tick='1' and h_end='1') then
            if (v_end='1') then
                v_count_next <= (others=>'0');
            else
                v_count_next <= v_count_reg+1;
            end if;
        else
            v_count_next <= v_count_reg;
        end if;
end process;

(And about now you could imagine it's a good idea to actually label process statements).

As far as the "buffered":

--To remove
--potential glitches, output buffers are inserted for the hsync and vsync signals. This leads
--to a one-clock-cycle delay. add a similar buffer for the rgb signal in the pixel
--generation circuit to compensate for the delay.
-- output buffer
signal v_sync_reg, h_sync_reg: std_logic;
signal v_sync_next ,h_sync_next : std_logic;
--status signal
signal h_end , v_end , pixel_tick: std_logic;

Those are the last two assignments in the --register process above. And from the comments the one clock delay through flip flops is to remove combinatoric glitches caused by relational operators:

h_sync_next <=
    '1' when (h_count_reg >= (HD+HF))  --656
          and (h_count_reg <= (HD+HF+HR-1)) else --751
    '0';

v_sync_next <=
    '1' when (v_count_reg >= (VD+VF))  --490
         and (v_count_reg <= (VD+VF+VR-1)) else --491
    '0';
7
On

Just for interest, here's a single-process refactoring of the above.

It's considerably shorter and, to my eyes at least, much easier to understand, modify and get right. Multiple trivial processes with unnecessary signals simply to communicate between them obscure the design (as you noted!) - and provide a fertile breeding ground for bugs.

One warning : I have not verified that this is an exact implementation of your design; if you choose to use it, that would be your responsibility.

Opinions welcome.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity vgaController is
    Port ( clk : in  STD_LOGIC;
           reset : in STD_LOGIC;
           hsync : out  STD_LOGIC;
           vsync : out  STD_LOGIC;
           video_on : out  STD_LOGIC;
           p_tick : out  STD_LOGIC;
           pixel_x : out  STD_LOGIC_VECTOR (9 downto 0);
           pixel_y : out  STD_LOGIC_VECTOR (9 downto 0));
end vgaController;

architecture Behavioral of vgaController is
-- VGA 640 -by - 480 sync  p a r a m e t e r s
constant HD: integer:=640; --horizontal display area
constant HF: integer:=16 ; --h. front porch
constant HB: integer:=48 ; --h. back porch
constant HR: integer:=96 ; --h. retrace "Sync Pulse" 
constant VD: integer:=480; -- vertical display area
constant VF: integer:=10 ; -- v. front porch
constant VB: integer:=33 ; -- v. back porch
constant VR: integer:=2  ; -- v. retrace "sync pulse"
-- derived constants to make code clearer
constant H_Last       : integer := HD+HF+HB+HR-1;
constant H_Sync_First : integer := HD+HF;
constant H_Sync_Last  : integer := HD+HF+HR-1;
constant V_Last       : integer := VD+VF+VB+VR-1;
constant V_Sync_First : integer := VD+VF;
constant V_Sync_Last  : integer := VD+VF+VR-1;

-- sync counters,  two counters for the horizontal and vertical scans
signal v_count : unsigned(9 downto 0);
signal h_count : unsigned(9 downto 0);

--status signal
signal pixel_tick: std_logic;

begin
    --register
    process(clk,reset)
        begin
            if (reset='1') then
                pixel_tick   <= '0';
                v_count      <= (others=>'0');
                h_count      <= (others=>'0');
                vsync       <= '0';
                hsync       <= '0';
            elsif(clk'event and clk='1')then
                pixel_tick     <= not pixel_tick;

                -- H and V pixel counters
                if pixel_tick = '1' then
                   if h_count = h_last then
                      h_count <= (others=>'0');
                      -- and start the next line
                      if v_count = v_last then
                         v_count <= (others=>'0');
                      else
                         v_count <= v_count + 1;
                      end if;
                   else
                      h_count <= h_count + 1;
                   end if;
                end if;

                -- default assignments for sync
                hsync <= '0';
                vsync <= '0';
                -- H and V sync pulses
                if h_count >= H_Sync_First and h_count <= H_Sync_Last then
                   hsync <= '1';
                end if;
                if v_count >= V_Sync_First and v_count <= V_Sync_Last then
                   vsync <= '1';
                end if;
            end if;
    end process;

    --video on/off ... was unregistered so I'll leave it that way
    video_on <= '1' when (h_count < HD) and (v_count < VD) else '0';

    --output signals 
    pixel_x <= std_logic_vector(h_count);
    pixel_y <= std_logic_vector(v_count);
    p_tick <= pixel_tick;

end Behavioral;
1
On

The buffers (register is a better name, because it's not an output buffer) are needed -- not only to suppress glitches --, but rather then to ensure equal output delay timings for every pin (v_sync, h_sync and color). If you do not use the registers before your downstream output buffer, you will get bad color effects on the screen.

Please be aware, that your x,y coordinate counter circuit addresses the next pixel not the current. So there must be a delays between the counter values and h/v_sync depending on the delay between counter -> get-pixel-information -> pixel color output.