-- ***************************************************** -- GAMEPAL DEVELOPMENT TEAM -- -- VIDEO MODULE -- -- APRIL 04, 1998 -- ***************************************************** -- Portions From: Jim Hamblen, Georgia Tech School of ECE -- Use the standard IEEE libraries for all binary signals library IEEE; use IEEE.std_logic_1164.all; use IEEE.STD_LOGIC_ARITH.all; use IEEE.STD_LOGIC_UNSIGNED.all; -- Use the LPM modules to get the RAM. LIBRARY lpm; USE lpm.lpm_components.ALL; entity video is port( -- Signals for the push buttons and clock signal Clock : in std_logic; -- Signals signal LSB_a, LSB_b, LSB_c, LSB_d, LSB_e, LSB_f, LSB_g, LSB_dp, MSB_a, MSB_b, MSB_c, MSB_d, MSB_e, MSB_f, MSB_g, MSB_dp : out std_logic; signal Red,Green,Blue : out std_logic; signal Horiz_sync,Vert_sync : out std_logic; signal Flex_Switch_1, Flex_Switch_2, Flex_Switch_3, Flex_Switch_4: in std_logic; signal Flex_Switch_5, Flex_Switch_6, Flex_Switch_7, Flex_Switch_8: in std_logic; signal Current_Function: in std_logic_vector(1 downto 0); signal Dice_VectorA : in std_logic_vector(17 downto 0); signal Dice_VectorB : in std_logic_vector(17 downto 0); signal Timer_Vector : in std_logic_vector(17 downto 0) ); end video; architecture behavior of video is -- Video Display Signals signal H_count,V_count: std_logic_vector(9 Downto 0); signal F_count: std_logic_vector(4 Downto 0); signal Color_count: std_logic_vector(3 Downto 0); signal Red_Data, Green_Data, Blue_Data, Power_On, Rev_video : std_logic; signal Change_Color : std_logic; -- Signals for Video ROM Memory for Pixel Data signal rom_address: std_logic_vector(8 Downto 0); signal sum_address: std_logic_vector(6 Downto 0); signal rom_data: std_logic_vector(7 Downto 0); signal col_address, row_address: std_logic_vector(5 Downto 0); signal current_pos : std_logic_vector(5 Downto 0); signal pixel_col_count, pixel_row_count: std_logic_vector(5 Downto 0); signal rom_mux_output: std_logic; -- ROM ADDRESSES -- MAIN MENU ADRESSESS signal main_address: std_logic_vector(7 downto 0); signal main_data: std_logic_vector(5 downto 0); -- DICE MENU ADRESSESS signal dice_address: std_logic_vector(7 downto 0); signal dice_data: std_logic_vector(5 downto 0); -- MAIN MENU ADRESSESS signal timer_address: std_logic_vector(7 downto 0); signal timer_data: std_logic_vector(5 downto 0); -- Signals for LED Display signal LSB,MSB: std_logic_vector(3 Downto 0); signal LSB_7SEG,MSB_7SEG: std_logic_vector(6 Downto 0); -- Signals for Push buttons --signal PB1_sync, PB2_sync, PB2_Single_Pulse, PB1_Single_Pulse: std_logic; --signal PB2_debounced, PB1_debounced, PB2_debounced_Sync, PB1_debounced_Sync: std_logic; --signal PB1_debounced_delay, PB2_debounced_delay, --signal Debounce_clock: std_logic; --signal SHIFT_PB1, SHIFT_PB2: std_logic_vector(3 Downto 0); signal switch, switch_sync: std_logic_vector(7 Downto 0); constant H_max : std_logic_vector(9 Downto 0) := CONV_STD_LOGIC_VECTOR(799,10); -- 799 is max horiz count constant V_max : std_logic_vector(9 Downto 0) := CONV_STD_LOGIC_VECTOR(524,10); -- 524 is max vert count signal video_on, video_on_H, video_on_V: std_logic; begin -- Small 8 by 8 Character Genrator ROM for Video Display tiny_char_gen_rom: lpm_rom GENERIC MAP ( lpm_widthad => 9, lpm_numwords => "512", lpm_outdata => "UNREGISTERED", lpm_address_control => "UNREGISTERED", -- Reads in mif file for character generator data lpm_file => "charbank.mif", lpm_width => 8) PORT MAP ( address => rom_address, q => rom_data); -- ROM FOR THE MAIN MENU MAINMENU_ROM: lpm_rom GENERIC MAP ( lpm_widthad => 8, lpm_numwords => "256", lpm_outdata => "UNREGISTERED", lpm_address_control => "UNREGISTERED", -- Reads in mif file for data display format lpm_file => "mainmenu.mif", lpm_width => 6) PORT MAP ( address => main_address, q => main_data); -- ROM FOR THE DICE DICE_ROM: lpm_rom GENERIC MAP ( lpm_widthad => 8, lpm_numwords => "256", lpm_outdata => "UNREGISTERED", lpm_address_control => "UNREGISTERED", -- Reads in mif file for data display format lpm_file => "dice.mif", lpm_width => 6) PORT MAP ( address => dice_address, q => dice_data); -- ROM FOR THE TIMER TIMER_rom: lpm_rom GENERIC MAP ( lpm_widthad => 8, lpm_numwords => "256", lpm_outdata => "UNREGISTERED", lpm_address_control => "UNREGISTERED", -- Reads in mif file for data display format lpm_file => "timer.mif", lpm_width => 6) PORT MAP ( address => timer_address, q => timer_data); --------------------------------------------------------------------------------------- -- Colors for pixel data on video signal -- address video_rom for pixel color data -- Switch 2 or Rev_Video will reverse video COLOR_CHOOSE : PROCESS BEGIN IF Change_Color = '0' then Red_Data <= not ((rom_mux_output xor Switch_Sync(2)) xor Rev_video); Green_Data <= not ((rom_mux_output xor Switch_Sync(2)) xor Rev_video); Blue_Data <= '1'; ELSE Red_Data <= '1'; Green_Data <= not ((rom_mux_output xor Switch_Sync(2)) xor Rev_video); Blue_Data <= not ((rom_mux_output xor Switch_Sync(2)) xor Rev_video); END IF; END PROCESS COLOR_CHOOSE; -- Display 8 by 8 font with 16 by 16 pixel array -- Step through rows for each character pattern rom_address(2 Downto 0) <= pixel_row_count(3 Downto 1); -- Mux to pick off correct rom data bit from 8-bit word -- for on screen character generation rom_mux_output <= rom_data ( (CONV_INTEGER(NOT pixel_col_count(3 downto 1)))); -- The RGB signal pins to the VGA monitor Red <= Red_Data and video_on; Green <= Green_Data and video_on; Blue <= Blue_Data and video_on; -- video_on turns off pixel data when not in the view area video_on <= video_on_H and video_on_V; -- Combine Flex Dip Switch Inputs into Switch vector Switch <= Flex_Switch_8 & Flex_Switch_7 & Flex_Switch_6 & Flex_Switch_5 & Flex_Switch_4 & Flex_Switch_3 & Flex_Switch_2 & Flex_Switch_1; -- This process generates the signals needed for a Video Display --It Generates Horizontal and Vertical Timing Signals for Video the Signal --It also counts pixel rows and columns to provide addresses for the --process that generates the data for the Video Signal VIDEO_DISPLAY: Process Begin Wait until(Clock'Event) and (Clock='1'); If Power_on = '0' Then H_count <= CONV_STD_LOGIC_VECTOR(654,10); V_count <= CONV_STD_LOGIC_VECTOR(493,10); Video_on_H <= '0'; Video_on_V <= '0'; Power_On <= '1'; Else -- H_count counts pixels (640 + extra time for sync signals) -- -- <-Clock out RGB Pixel Row Data -> <-H Sync-> -- ------------------------------------__________-------- -- 0 640 659 755 799 -- If (H_count >= H_max) then -- H_count <= To_StdLogicVector(B"0000000000"); H_count <= "0000000000"; Else -- H_count <= H_count + To_StdLogicVector(B"0000000001"); H_count <= H_count + "0000000001"; End if; --Generate Horizontal Sync Signal If (H_count <= CONV_STD_LOGIC_VECTOR(755,10)) and (H_count >= CONV_STD_LOGIC_VECTOR(659,10)) Then Horiz_Sync <= '0'; ELSE Horiz_Sync <= '1'; End if; --V_count counts rows of pixels (480 + extra time for sync signals) -- -- <---- 480 Horizontal Syncs (pixel rows) --> ->V Sync<- -- -----------------------------------------------_______------------ -- 0 480 493-494 524 -- If (V_count >= V_max) and (H_count >= CONV_STD_LOGIC_VECTOR(699,10)) then -- V_count <= To_StdLogicVector(B"0000000000"); V_count <= "0000000000"; Else If (H_count = CONV_STD_LOGIC_VECTOR(699,10)) Then -- V_count <= V_count + To_StdLogicVector(B"0000000001"); V_count <= V_count + "0000000001"; End if; End if; -- Generate Vertical Sync Signal If (V_count <= CONV_STD_LOGIC_VECTOR(494,10)) and (V_count >= CONV_STD_LOGIC_VECTOR(493,10)) Then Vert_Sync <= '0'; ELSE Vert_Sync <= '1'; End if; -- Generate Video on Screen Signals for Pixel Data -- Generate row and col address for 16 by 16 font -- If (H_count <= CONV_STD_LOGIC_VECTOR(639,10)) Then video_on_H <= '1'; If pixel_col_count < CONV_STD_LOGIC_VECTOR(15,6) Then pixel_col_count <= pixel_col_count + '1'; Else pixel_col_count <= "000000"; col_address <= col_address + '1'; End if; ELSE video_on_H <= '0'; pixel_col_count <= "000000"; col_address <= "000000"; End if; IF(H_COUNT = CONV_STD_LOGIC_VECTOR(641,10)) Then pixel_row_count <= pixel_row_count + '1'; If (pixel_row_count = CONV_STD_LOGIC_VECTOR(15,6)) THEN pixel_row_count <= "000000"; row_address <= row_address + '1'; End if; END IF; If (V_count <= CONV_STD_LOGIC_VECTOR(479,10)) Then video_on_V <= '1'; ELSE video_on_V <= '0'; pixel_row_count <= "000000"; row_address <= "000000"; End if; If (V_count = CONV_STD_LOGIC_VECTOR(0,10)) and (H_count = CONV_STD_LOGIC_VECTOR(0,10)) then If (F_count = CONV_STD_LOGIC_VECTOR(30,5)) then -- F_count <= To_StdLogicVector(B"00000"); F_count <= "00000"; Else -- F_count <= F_count + To_StdLogicVector(B"00001"); F_count <= F_count + "00001"; End if; End if; End if; end process VIDEO_DISPLAY; -- Address for Constant Character Data ROM main_address(4 Downto 0) <= Col_address(4 Downto 0); main_address(7 Downto 5 ) <= Row_address(2 Downto 0); dice_address(4 Downto 0) <= Col_address(4 Downto 0); dice_address(7 Downto 5 ) <= Row_address(2 Downto 0); timer_address(4 Downto 0) <= Col_address(4 Downto 0); timer_address(7 Downto 5 ) <= Row_address(2 Downto 0); -- This Process Provides Character Data for Video Display -- by generating addresses for the Character Generator ROM -- using row address and col address provided by the Video -- Display process VIDEO_DISPLAY_DATA: process begin wait until (clock'event) and (clock='1'); -- Reverse Video for Title at top of screen Switch_Sync <= Switch; If (row_address <= "000011") Then rev_video <= '1'; ELSE rev_video <= '0'; End if; If (row_address > "000011") then Change_Color <= '1'; ELSE Change_Color <= '0'; END IF; -- Blank characters on Edges If (col_address < "000001") or (col_address >"100000") Then rom_address(8 Downto 3) <= "100000"; Else --CASE Current_Function(1 downto 0) IS CASE Current_Function IS WHEN "00" => If (((col_address >= "000001") and (col_address <= "100000")) and ((row_address >= "000001") and (row_address <= "000111"))) Then rom_address(8 downto 3) <= main_data; Else If (row_address < "000001") or (row_address > "000111") Then rom_address(8 Downto 3) <= "100000"; end if; end if; WHEN "01" => If (((col_address >= "000001") and (col_address <= "100000")) and ((row_address >= "000001") and (row_address <= "000111"))) Then CASE dice_data IS WHEN "111010" => rom_address(8 downto 3) <= Dice_VectorA(5 downto 0); WHEN "111011" => rom_address(8 downto 3) <= Dice_VectorA(11 downto 6); WHEN "111100" => rom_address(8 downto 3) <= Dice_VectorA(17 downto 12); WHEN "111101" => rom_address(8 downto 3) <= Dice_VectorB(5 downto 0); WHEN "111110" => rom_address(8 downto 3) <= Dice_VectorB(11 downto 6); WHEN "111111" => rom_address(8 downto 3) <= Dice_VectorB(17 downto 12); WHEN others => rom_address(8 downto 3) <= Dice_data; END CASE; Else If (row_address < "000001") or (row_address > "000111") Then rom_address(8 Downto 3) <= "100000"; end if; end if; WHEN "10" => If (((col_address >= "000001") and (col_address <= "100000")) and ((row_address >= "000001") and (row_address <= "000111"))) Then CASE Timer_data IS WHEN "111010" => rom_address(8 downto 3) <= Timer_Vector(5 downto 0); WHEN "111011" => rom_address(8 downto 3) <= Timer_Vector(11 downto 6); WHEN "111100" => rom_address(8 downto 3) <= Timer_Vector(17 downto 12); WHEN others => rom_address(8 downto 3) <= Timer_data; END CASE; Else If (row_address < "000001") or (row_address > "000111") Then rom_address(8 Downto 3) <= "100000"; end if; end if; WHEN others => If (((col_address >= "000001") and (col_address <= "100000")) and ((row_address >= "000001") and (row_address <= "000111"))) Then rom_address(8 downto 3) <= main_data; Else If (row_address < "000001") or (row_address > "000111") Then rom_address(8 Downto 3) <= "100000"; end if; end if; END CASE; end if; end process VIDEO_DISPLAY_DATA; -- Values to Display in 7Seg LEDs --MSB_dp <= NOT board_CLOCK; --LSB_dp <= NOT RESET; MSB_dp <= NOT Rev_Video; LSB_dp <= NOT Rev_Video; MSB <= rom_data(7 Downto 4); LSB <= rom_data(3 Downto 0); MSB_a <= NOT MSB_7SEG(6); MSB_b <= NOT MSB_7SEG(5); MSB_c <= NOT MSB_7SEG(4); MSB_d <= NOT MSB_7SEG(3); MSB_e <= NOT MSB_7SEG(2); MSB_f <= NOT MSB_7SEG(1); MSB_g <= NOT MSB_7SEG(0); LSB_a <= NOT LSB_7SEG(6); LSB_b <= NOT LSB_7SEG(5); LSB_c <= NOT LSB_7SEG(4); LSB_d <= NOT LSB_7SEG(3); LSB_e <= NOT LSB_7SEG(2); LSB_f <= NOT LSB_7SEG(1); LSB_g <= NOT LSB_7SEG(0); LED_DISPLAY: process (MSB,LSB) -- BCD to 7 Segment Decoders for LED Displays begin CASE MSB IS WHEN "0000" => MSB_7SEG <= "1111110"; WHEN "0001" => MSB_7SEG <= "0110000"; WHEN "0010" => MSB_7SEG <= "1101101"; WHEN "0011" => MSB_7SEG <= "1111001"; WHEN "0100" => MSB_7SEG <= "0110011"; WHEN "0101" => MSB_7SEG <= "1011011"; WHEN "0110" => MSB_7SEG <= "1011111"; WHEN "0111" => MSB_7SEG <= "1110000"; WHEN "1000" => MSB_7SEG <= "1111111"; WHEN "1001" => MSB_7SEG <= "1111011"; WHEN "1010" => MSB_7SEG <= "1110111"; WHEN "1011" => MSB_7SEG <= "0011111"; WHEN "1100" => MSB_7SEG <= "1001110"; WHEN "1101" => MSB_7SEG <= "0111101"; WHEN "1110" => MSB_7SEG <= "1001111"; WHEN "1111" => MSB_7SEG <= "1000111"; WHEN OTHERS => MSB_7SEG <= "0000001"; END CASE; CASE LSB IS WHEN "0000" => LSB_7SEG <= "1111110"; WHEN "0001" => LSB_7SEG <= "0110000"; WHEN "0010" => LSB_7SEG <= "1101101"; WHEN "0011" => LSB_7SEG <= "1111001"; WHEN "0100" => LSB_7SEG <= "0110011"; WHEN "0101" => LSB_7SEG <= "1011011"; WHEN "0110" => LSB_7SEG <= "1011111"; WHEN "0111" => LSB_7SEG <= "1110000"; WHEN "1000" => LSB_7SEG <= "1111111"; WHEN "1001" => LSB_7SEG <= "1111011"; WHEN "1010" => LSB_7SEG <= "1110111"; WHEN "1011" => LSB_7SEG <= "0011111"; WHEN "1100" => LSB_7SEG <= "1001110"; WHEN "1101" => LSB_7SEG <= "0111101"; WHEN "1110" => LSB_7SEG <= "1001111"; WHEN "1111" => LSB_7SEG <= "1000111"; WHEN OTHERS => LSB_7SEG <= "0000001"; END CASE; end process LED_DISPLAY; -- Sync extenal pushbutton inputs to chip clock --PUSH_BUTTON: process (clock) --begin -- wait until (clock'event) and (clock='1'); --PB1_Sync <= NOT PB1; --PB2_Sync <= NOT PB2; --PB1_DEBOUNCED_SYNC <= PB1_DEBOUNCED; --PB2_DEBOUNCED_SYNC <= PB2_DEBOUNCED; --end process PUSH_BUTTON; -- Debounce Button: Filters out mechanical bounce for around 80Ms. -- Debounce clock uses Vert_Sync timing signal (16Ms) to save hardware -- for clock prescaler --DEBOUNCE_BUTTON1: process (debounce_clock) --begin -- wait until (debounce_clock'event) and (debounce_clock='1'); -- SHIFT_PB1(2 Downto 0) <= SHIFT_PB1(3 Downto 1); -- SHIFT_PB1(3) <= PB1_Sync; -- If SHIFT_PB1(3 Downto 0)="1111" THEN -- PB1_DEBOUNCED <= '1'; -- ELSE -- PB1_DEBOUNCED <= '0'; -- End if; --end process DEBOUNCE_BUTTON1; --DEBOUNCE_BUTTON2: process (debounce_clock) --begin -- wait until (debounce_clock'event) and (debounce_clock='1'); --SHIFT_PB2(2 Downto 0) <= SHIFT_PB2(3 Downto 1); --SHIFT_PB2(3) <= PB2_Sync; --If SHIFT_PB2(3 Downto 0)="1111" THEN --PB2_DEBOUNCED <= '1'; --ELSE -- PB2_DEBOUNCED <= '0'; --End if; --end process DEBOUNCE_BUTTON2; --SINGLE_PULSE_PB1: process (Clock) --begin -- wait until (CLOCK'event) and (CLOCK='1'); -- If POWER_ON='0' Then -- PB1_SINGLE_PULSE <='0'; -- PB1_DEBOUNCED_DELAY <= '1'; -- ELSE -- Generates Single Clock Cycle Pulse When Switch Hit -- No matter how long switch is held down -- IF PB1_DEBOUNCED_SYNC = '1' AND PB1_DEBOUNCED_DELAY = '0' THEN -- PB1_SINGLE_PULSE <= '1'; -- ELSE -- PB1_SINGLE_PULSE <= '0'; -- END IF; -- PB1_DEBOUNCED_DELAY <= PB1_DEBOUNCED_SYNC; -- End if; --end process SINGLE_PULSE_PB1; --SINGLE_PULSE_PB2: process (Clock) --begin -- wait until (CLOCK'event) and (CLOCK='1'); -- If POWER_ON='0' Then -- PB2_SINGLE_PULSE <='0'; -- PB2_DEBOUNCED_DELAY <= '1'; -- ELSE -- PB2_DEBOUNCED_DELAY <= PB2_DEBOUNCED_SYNC; -- Generates Single Clock Cycle Pulse When Switch Hit -- No matter how long switch is held down -- IF PB2_DEBOUNCED_SYNC = '1' AND PB2_DEBOUNCED_DELAY = '0' THEN -- PB2_SINGLE_PULSE <= '1'; -- ELSE -- PB2_SINGLE_PULSE <= '0'; -- END IF; -- End if; --end process SINGLE_PULSE_PB2; end behavior;