------------------------------------------------------------------------------- -- Title : vga_driver architecture -- Project : LU Digital Design ------------------------------------------------------------------------------- -- File : vga_driver.vhd -- Author : Thomas Handl -- Company : TU Wien -- Created : 2004-12-15 -- Last update: 2007-09-13 ------------------------------------------------------------------------------- -- Description: generate hsync and vsync ------------------------------------------------------------------------------- -- Copyright (c) 2004 TU Wien ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2004-12-15 1.0 handl Created -- 2006-01-24 2.0 ST revised ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- LIBRARIES ------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use IEEE.std_logic_arith.all; use work.vga_pak.all; ------------------------------------------------------------------------------- -- ARCHITECTURE ------------------------------------------------------------------------------- architecture behav of vga_driver is attribute syn_preserve : boolean; attribute syn_preserve of behav : architecture is true; constant TIME_A : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0) := "1100011111"; constant TIME_B : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0) := "0001011010"; constant TIME_BC : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0) := "0010000111"; constant TIME_BCD : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0) := "1100000111"; constant TIME_O : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0) := "1000001000"; constant TIME_P : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0) := "0000000001"; constant TIME_PQ : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0) := "0000100001"; constant TIME_PQR : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0) := "1000000001"; signal h_sync : std_logic; signal h_sync_next : std_logic; signal hsync_state : hsync_state_type; signal hsync_state_next : hsync_state_type; signal h_enable_sig : std_logic; signal h_enable_next : std_logic; signal set_hsync_counter : std_logic; signal hsync_counter : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0); signal hsync_counter_next : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0); constant HSYN_CNT_MAX : std_logic_vector(HSYN_CNT_WIDTH-1 downto 0) := "1111111111"; signal column_counter_sig : std_logic_vector(COL_CNT_WIDTH-1 downto 0); signal column_counter_next : std_logic_vector(COL_CNT_WIDTH-1 downto 0); signal set_column_counter : std_logic; signal v_sync : std_logic; signal v_sync_next : std_logic; signal vsync_state : vsync_state_type; signal vsync_state_next : vsync_state_type; signal v_enable_sig : std_logic; signal v_enable_next : std_logic; signal set_vsync_counter : std_logic; signal vsync_counter : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0); signal vsync_counter_next : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0); constant VSYN_CNT_MAX : std_logic_vector(VSYN_CNT_WIDTH-1 downto 0) := "1111111111"; signal line_counter_sig : std_logic_vector(LINE_CNT_WIDTH-1 downto 0); signal line_counter_next : std_logic_vector(LINE_CNT_WIDTH-1 downto 0); signal set_line_counter : std_logic; begin ---------------------------------------------------------------------------- -- Column_Counter [0..639]: calculates column number for next pixel to be displayed ---------------------------------------------------------------------------- COLUMN_COUNT_syn: process(clk, reset, column_counter_next) begin if clk'event and clk = '1' then if reset = RES_ACT then -- synchronous reset column_counter_sig <= (others => '0'); else column_counter_sig <= column_counter_next; -- synchronous capture end if; end if; end process; COLUMN_COUNT_next: process(set_column_counter, column_counter_sig) begin if set_column_counter = ENABLE then -- reset counter column_counter_next <= (others => '0'); else if column_counter_sig < RIGHT_BORDER then column_counter_next <= column_counter_sig + '1'; -- increment column else column_counter_next <= RIGHT_BORDER; -- ... but do not count beyond right border end if; end if; end process; ---------------------------------------------------------------------------- -- Line_counter [0..479]: calculates line number for next pixel to be displayed ---------------------------------------------------------------------------- LINE_COUNT_syn: process(clk, reset, line_counter_next) begin if clk'event and clk = '1' then if reset = RES_ACT then -- synchronous reset line_counter_sig <= (others => '0'); else line_counter_sig <= line_counter_next; -- synchronous capture end if; end if; end process; LINE_COUNT_next: process(set_line_counter, line_counter_sig, set_hsync_counter) begin if set_line_counter = ENABLE then -- reset counter line_counter_next <= (others => '0'); else if line_counter_sig < BOTTOM_BORDER then if set_hsync_counter = '1' then -- when enabled line_counter_next <= line_counter_sig + '1'; -- ... increment line else line_counter_next <= line_counter_sig; end if; else line_counter_next <= BOTTOM_BORDER; -- ... but do not count below bottom end if; end if; end process; ---------------------------------------------------------------------------- -- Hsync_Counter: generates time base for HSYNC State Machine ---------------------------------------------------------------------------- HSYNC_COUNT_syn: process(clk, reset, hsync_counter_next) begin if clk'event and clk = '1' then if reset = RES_ACT then -- synchronous reset hsync_counter <= (others => '0'); else hsync_counter <= hsync_counter_next; -- synchronous capture end if; end if; end process; HSYNC_COUNT_next: process(set_hsync_counter, hsync_counter) begin if set_hsync_counter = ENABLE then -- reset counter hsync_counter_next <= (others => '0'); else if hsync_counter < HSYN_CNT_MAX then hsync_counter_next <= hsync_counter + '1'; -- increment time else hsync_counter_next <= HSYN_CNT_MAX; -- ... but do not count beyond max period end if; end if; end process; ---------------------------------------------------------------------------- -- HSYNC STATE MACHINE: generates hsync signal and controls hsync counter & column counter ---------------------------------------------------------------------------- HSYNC_FSM_syn: process (clk, reset) -- synchronous capture begin if clk'event and clk = '1' then if reset = RES_ACT then hsync_state <= RESET_STATE; h_sync <= '1'; v_enable_sig <= not(ENABLE); else hsync_state <= hsync_state_next; h_sync <= h_sync_next; v_enable_sig <= v_enable_next; end if; end if; end process; HSYNC_FSM_next : process(hsync_state, hsync_counter, h_sync, v_enable_sig) -- next-state logic begin -- default assignments hsync_state_next <= hsync_state; -- ... hold current state h_sync_next <= h_sync; -- ... and values v_enable_next <= v_enable_sig; case hsync_state is when RESET_STATE => h_sync_next <= '0'; -- next signal values are defined here v_enable_next <= not(ENABLE); hsync_state_next <= B_STATE; -- ... as well as state transitions when B_STATE => h_sync_next <= '0'; if hsync_counter = TIME_B then hsync_state_next <= C_STATE; end if; when D_STATE => h_sync_next <= '1'; if hsync_counter = TIME_BC then hsync_state_next <= pre_D_STATE; end if; when pre_D_STATE => v_enable_next <= ENABLE; hsync_state_next <= D_STATE; when C_STATE => v_enable_next <= ENABLE; if hsync_counter = TIME_BCD then hsync_state_next <= E_STATE; end if; when E_STATE => v_enable_next <= not(ENABLE); if hsync_counter = TIME_A then hsync_state_next <= pre_B_STATE; end if; when pre_B_STATE => h_sync_next <= '0'; v_enable_next <= not(ENABLE); hsync_state_next <= B_STATE; when others => null; end case; end process; HSYNC_FSM_out : process(hsync_state) -- output logic begin set_hsync_counter <= not(ENABLE); -- default assignments set_column_counter <= not(ENABLE); case hsync_state is when RESET_STATE => -- outputs for each state are defined here set_hsync_counter <= ENABLE; when pre_D_STATE => set_column_counter <= ENABLE; when pre_B_STATE => set_hsync_counter <= ENABLE; when others => null; end case; end process; ---------------------------------------------------------------------------- -- Vsync_Counter: generates time base for VSYNC State Machine ---------------------------------------------------------------------------- VSYNC_COUNT_syn: process(clk, reset, vsync_counter_next) begin if clk'event and clk = '1' then if reset = RES_ACT then -- synchronous reset vsync_counter <= (others => '0'); else vsync_counter <= vsync_counter_next; -- synchronous capture end if; end if; end process; VSYNC_COUNT_next: process(set_vsync_counter, vsync_counter, set_hsync_counter) begin if set_vsync_counter = ENABLE then -- reset counter vsync_counter_next <= (others => '0'); else if vsync_counter < VSYN_CNT_MAX then if set_hsync_counter = '1' then -- if enabled vsync_counter_next <= vsync_counter + '1'; -- ... increment time else vsync_counter_next <= vsync_counter; end if; else vsync_counter_next <= VSYN_CNT_MAX; -- ... but do not count beyond max period end if; end if; end process; ---------------------------------------------------------------------------- -- VSYNC STATE MACHINE: generates vsync signal and controls vsync counter & line counter ---------------------------------------------------------------------------- VSYNC_FSM_syn : process (clk, reset) -- synchronous capture begin if clk'event and clk = '1' then if reset = RES_ACT then vsync_state <= RESET_STATE; v_sync <= '1'; h_enable_sig <= not(ENABLE); else vsync_state <= vsync_state_next; v_sync <= v_sync_next; h_enable_sig <= h_enable_next; end if; end if; end process; VSYNC_FSM_next : process(vsync_state, vsync_counter, v_sync, h_enable_sig) begin -- next state logic vsync_state_next <= vsync_state; -- default assignments v_sync_next <= v_sync; h_enable_next <= h_enable_sig; case vsync_state is -- state transitions and next signals are defined here when RESET_STATE => v_sync_next <= '0'; h_enable_next <= not(ENABLE); vsync_state_next <= P_STATE; when P_STATE => v_sync_next <= '0'; if vsync_counter = time_p then vsync_state_next <= Q_STATE; end if; when Q_STATE => v_sync_next <= '1'; if vsync_counter = time_pq then vsync_state_next <= pre_R_STATE; end if; when pre_R_STATE => h_enable_next <= ENABLE; vsync_state_next <= R_STATE; when R_STATE => h_enable_next <= ENABLE; if vsync_counter = time_pqr then vsync_state_next <= S_STATE; end if; when S_STATE => h_enable_next <= not(ENABLE); if vsync_counter = time_o then vsync_state_next <= pre_P_STATE; end if; when pre_P_STATE => v_sync_next <= '0'; h_enable_next <= not(ENABLE); vsync_state_next <= P_STATE; when others => null; end case; end process; VSYNC_FSM_out : process(vsync_state) begin -- output logic set_vsync_counter <= not(ENABLE); -- output values for each state defined here set_line_counter <= not(ENABLE); case vsync_state is when RESET_STATE => set_vsync_counter <= ENABLE; when pre_R_STATE => set_line_counter <= ENABLE; when pre_P_STATE => set_vsync_counter <= ENABLE; when others => null; end case; end process; -- signal wiring for entity (introduced _sig to allow readback of output signals) column_counter <= column_counter_sig; v_enable <= v_enable_sig; line_counter <= line_counter_sig; h_enable <= h_enable_sig; hsync <= h_sync; vsync <= v_sync; ----------------------------------------------------------------------------- -- debug signals ----------------------------------------------------------------------------- d_hsync_state <= hsync_state; d_vsync_state <= vsync_state; d_hsync_counter <= hsync_counter; d_vsync_counter <= vsync_counter; d_set_hsync_counter <= set_hsync_counter; d_set_vsync_counter <= set_vsync_counter; d_set_column_counter <= set_column_counter; d_set_line_counter <= set_line_counter; end behav; ------------------------------------------------------------------------------- -- END ARCHITECTURE -------------------------------------------------------------------------------