-- Video module -- -- DLX Implementation -- Uses VGA to Display Data -- PB1 is clock for Altera Board -- PB2 is synchronous reset for Altera Board -- i.e. must clock (hit PB1) while holding down PB2 for reset -- PC is also displayed on 7 Segment Display -- -- Dr. James Hamblen, Professor at Georgia Institute of Technology -- Doug McAlister Michael Sugg -- library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_ARITH.all; use IEEE.STD_LOGIC_UNSIGNED.all; LIBRARY lpm; USE lpm.lpm_components.ALL; entity video is Generic(ADDR_WIDTH: integer := 12; DATA_WIDTH: integer := 1); port(signal PB1, PB2, BrdClock, Clock : in std_logic; 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 switch : in std_logic_vector(0 to 7); signal DLX_Clock,Reset : out std_logic; signal MSB_Dot,LSB_Dot : in std_logic; signal MSB_Data,LSB_Data : in std_logic_vector(3 downto 0); signal video_data : in std_logic_vector(5 downto 0); signal video_row, video_col : in std_logic_vector(5 downto 0); signal video_write : in std_logic); 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: std_logic; signal Red_pipe,Green_pipe,Blue_pipe : std_logic; signal Horiz_sync_pipe,Vert_sync_pipe : std_logic; -- signal Rev_video : 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 pixel_col_count, pixel_row_count: std_logic_vector(5 Downto 0); signal rom_mux_output: std_logic; signal format_address: std_logic_vector(9 downto 0); signal format_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, Debounce_clock: std_logic; signal SHIFT_PB1, SHIFT_PB2: std_logic_vector(3 Downto 0); signal switch_sync: std_logic_vector(7 Downto 0); signal PCon : std_logic; signal notclock : std_logic; 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; signal we : std_logic; -- PROGRAM BEGIN begin -- Small 8 by 8 Character Genrator ROM for Video Display notclock <= not clock; process(clock) -- variable we_tmp : std_logic :='0'; begin case clock is when '0' => we <= video_write; when others => we <= '0'; end case; end process; 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 => "tcgrom.mif", lpm_width => 8) PORT MAP ( address => rom_address, q => rom_data); -- Character Format ROM for Video Display -- Displays constant format character data -- on left side of Display area format_ram: lpm_ram_dq GENERIC MAP (lpm_widthad => 10, --lpm_numwords => "60", lpm_outdata => "UNREGISTERED", lpm_indata => "REGISTERED", lpm_address_control => "UNREGISTERED", -- Reads in mif file for data display format\ lpm_file => "vidram.mif", lpm_width => 6) PORT MAP (data => video_data, address => format_address, we => we, inclock => notclock, --outclock => outclock, q => format_data); --------------------------------------------------------------------------------------- -- Reset and Clock Signal for MIPS processor Reset <= PB2_Debounced_Sync; -- When all switches are on, use the internal clock DLX_Clock <= BrdClock when Switch(0 to 7) = "11111111" else PB1_Debounced_Sync; -- Colors for pixel data on video signal -- address video_rom for pixel color data -- Switch 2 or Rev_Video will reverse video 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 <= '0'; --Rev_video <= '0'; -- 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_pipe <= Red_Data and video_on; Green_pipe <= Green_Data and video_on; Blue_pipe <= Blue_Data and video_on; Process Begin Wait Until brdclock'EVENT and brdclock = '1'; Red <= Red_pipe; Green <= Green_pipe; Blue <= Blue_pipe; Horiz_sync <= horiz_sync_pipe; Vert_sync <= vert_sync_pipe; End process; -- video_on turns off pixel data when not in the view area video_on <= video_on_H and video_on_V; -- 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(BrdClock'Event) and (BrdClock='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 <= "0000000000"; Else 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_pipe <= '0'; ELSE Horiz_Sync_pipe <= '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 <= "0000000000"; Else If (H_count = CONV_STD_LOGIC_VECTOR(699,10)) Then 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_pipe <= '0'; Debounce_CLock <= '0'; ELSE Vert_Sync_pipe <= '1'; Debounce_Clock <= '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 <= "00000"; Else F_count <= F_count + "00001"; End if; End if; End if; -- POWER ON (no juice) end process VIDEO_DISPLAY; -- Address for Constant Character Data ROM --format_address(1 Downto 0) <= Col_address(1 Downto 0); --format_address(5 Downto 2) <= Row_address(4 Downto 1); format_address <= (video_row(3 downto 0) & video_col(5 downto 0)) when Video_Write='1' else (row_address(3 downto 0) & col_address(5 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 (BrdClock'event) and (BrdClock='1'); if row_address < conv_std_logic_vector(16,6) then rom_address(8 downto 3) <= format_data; else rom_address(8 downto 3) <= "100000"; end if; end process VIDEO_DISPLAY_DATA; -- Values to Display in 7Seg LEDs MSB_dp <= MSB_DOT; LSB_dp <= LSB_DOT; MSB <= MSB_DATA(3 downto 0); LSB <= LSB_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 (BrdClock) begin wait until (BrdClock'event) and (BrdClock='1'); PB1_Sync <= NOT PB1; PB2_Sync <= NOT PB2; Switch_Sync <= Switch; 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 (BrdClock) begin wait until (BrdClock'event) and (BrdClock='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 (BrdClock) begin wait until (BrdClock'event) and (BrdClock='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;