⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lancelot_vga.vhd

📁 基于FPGA的VGA控制器设计。对外支持普通VGA接口
💻 VHD
📖 第 1 页 / 共 3 页
字号:
			line_buffer_dma_empty 	<= line_buffer_wpbottom1;
			line_buffer_wprst1		<= '0';
			line_buffer_wprst2		<= line_end;
			line_buffer_rprst1		<= '0';
			line_buffer_rprst2		<= line_begin;
		END IF;
	END IF;
END PROCESS;


---------------------
-- colour Table Mux --
---------------------
PROCESS(colour_byte_sel_int, video_data)
BEGIN
	CASE colour_byte_sel_int  IS
		WHEN 0 =>
			colour_table_address <= video_data(7 DOWNTO 0);
	
		WHEN 1 =>
			colour_table_address <= video_data(15 DOWNTO 8);

		WHEN 2 =>
			colour_table_address <= video_data(23 DOWNTO 16);

		WHEN 3 =>
			colour_table_address <= video_data(31 DOWNTO 24);

		WHEN others =>
			colour_table_address <= (others => '0');

	END CASE;
END PROCESS;

-- Pipeline signal colour_byte_sel, because the video data has a latency through the line buffer of 5 video clocks. 
PROCESS(VIDEO_CLK, reset_int, colour_byte_sel)
BEGIN
	IF reset_int = '1' THEN
		colour_byte_sel_int <= 0;
		colour_byte_sel3 <= 0;
		colour_byte_sel2 <= 0;
		colour_byte_sel1 <= 0;
		colour_byte_sel0 <= 0;
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
		colour_byte_sel_int <= colour_byte_sel3;
		colour_byte_sel3 <= colour_byte_sel2;
		colour_byte_sel2 <= colour_byte_sel1;
		colour_byte_sel1 <= colour_byte_sel0;
		colour_byte_sel0 <= colour_byte_sel;
	END IF;
END PROCESS;

-------------------------
-- Line Buffer Select --
-------------------------
PROCESS(VIDEO_CLK, reset_int, line_buffer_toggle)
BEGIN
	IF reset_int = '1' THEN
		line_buffer_sel <= 0;
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
		IF line_buffer_toggle = '1' THEN
			IF line_buffer_sel = 0 THEN
				line_buffer_sel <= 1;
		   	ELSE
		   		line_buffer_sel <= 0;
		   	END IF;
		END IF;
	END IF;
END PROCESS;

-------------------
-- Pixel Counter --
-------------------
PROCESS(VIDEO_CLK, reset_int, pixel_counter_load, pixel_counter_zero)
	VARIABLE pixel_counter : INTEGER RANGE 0 TO 1024;
BEGIN
	IF reset_int = '1' THEN
		pixel_counter := 0;
		pixel_counter_zero <= '1';
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
		IF pixel_counter_load = '1' THEN
			pixel_counter := (pixel_counter_data - 1);
			pixel_counter_zero <= '0' AFTER 5 ns;
		ELSE
			IF pixel_counter_zero = '0' THEN
				pixel_counter := pixel_counter - 1;	
				
				IF pixel_counter = 0 THEN
					pixel_counter_zero <= '1' AFTER 5 ns;
				END IF;
			END IF;
		END IF;
	END IF;
END PROCESS;

-------------------
-- Vsync Counter --
-------------------
PROCESS(VIDEO_CLK, reset_int, vsync_counter_reset, vsync_counter_inc)
BEGIN
	IF reset_int = '1' THEN
		vsync_counter <= 0;
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
		IF vsync_counter_reset = '1' THEN
			vsync_counter <= 0;
		ELSE
			IF vsync_counter_inc = '1' THEN
				vsync_counter <= vsync_counter + 1 AFTER 5 ns;	
			END IF;
		END IF;
	END IF;
END PROCESS;

-----------------------
-- DMA State Machine --
-----------------------
-- This state machine has the task of requesting new video data from SDRAM.
-- If the dma line buffer is empty and the display is active, then it will request a new DMA transfer.
 
PROCESS(VIDEO_CLK, reset_int)
BEGIN
	IF reset_int = '1' THEN
		dma_current_state <= start_dma;
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
			dma_current_state <= dma_next_state AFTER 5 ns;
	END IF;
END PROCESS;

PROCESS(dma_current_state, control_reg, line_buffer_dma_empty, line_buffer_dma_full, vsync_counter, vsync_top1, vsync_top2, vsync_bottom)
BEGIN

	video_dma_request 	<= '0';
	video_dma_first 	<= '0';

	CASE dma_current_state IS

		-- Wait for start
		WHEN start_dma =>
			IF start_video = '1' THEN
				dma_next_state <= clear_dma; 
			ELSE
				dma_next_state <= start_dma;
			END IF;

		-- Clear irq
		WHEN clear_dma =>
			IF (line_buffer_dma_empty = '1' AND 
			vsync_counter > vsync_top1 AND
			vsync_counter < vsync_bottom) THEN
				dma_next_state <= set_dma;
			ELSE
				dma_next_state <= clear_dma;
			END IF;

		-- Set dma 
		WHEN set_dma =>
		
			video_dma_request <= '1';

			IF (vsync_counter = vsync_top2) THEN
				video_dma_first <= '1';
			END IF;
			
			IF (line_buffer_dma_full = '1') THEN
				dma_next_state <= clear_dma;
			ELSE
				dma_next_state <= set_dma;
			END IF;
					
		WHEN others =>
			dma_next_state <= start_dma;

	END CASE;
END PROCESS;

-- Pipeline vsync equations to increase design performance
PROCESS(VIDEO_CLK, reset_int)
BEGIN
	IF reset_int = '1' THEN
 		vsync_top1 <= 0;
 		vsync_top2 <= 0;
 		vsync_bottom <= 0;
 	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
		IF vsync_pulse_width > 0 THEN
			vsync_top1 <= vsync_pulse_width + vsync_back_porch_width - 2;
			vsync_bottom <=	vsync_pulse_width + vsync_back_porch_width + vertical_resolution;
			vsync_top2 <= vsync_pulse_width + vsync_back_porch_width - 1;
		ELSE
			vsync_top1 <= 0;
 			vsync_top2 <= 0;
 			vsync_bottom <= 0;
 		END IF;
	END IF;
END PROCESS;

-------------------------
-- Hsync State Machine --
-------------------------
-- This state machine is responsable for hsync timing and display video data
-- First it generates the hsync pulse. If new video data is available and the display is active (depends on vsync), 
-- the line buffers are swapped and it reads out the line buffer in four cycles until it is empty. 
-- Else it will generate a blank line. The state machine repeats this process forever.

PROCESS(VIDEO_CLK, reset_int)
BEGIN
	IF reset_int = '1' THEN
		hsync_current_state <= hsync_reset;
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
			hsync_current_state <= hsync_next_state AFTER 5 ns;
	END IF;
END PROCESS;

PROCESS(hsync_current_state, control_reg, line_buffer_video_empty, pixel_counter_zero, 
		horizontal_resolution, blank_vs, hsync_pulse_width, line_buffer_dma_full, hsync_back_porch_width, hsync_front_porch_width)
BEGIN
	line_buffer_rd		<= '0';
	vsync_counter_inc	<= '0';
	line_begin 			<= '0';
	line_end 			<= '0';
	line_buffer_toggle	<= '0';
	colour_byte_sel 	<= 0;
	blank_hs 			<= '0';	
	pixel_counter_load	<= '0';
	pixel_counter_data	<= 0;
	hs_int 				<= '1';
	line_missed 		<= '0';
	
	CASE hsync_current_state IS
	

	-- Wait for video starts
		WHEN hsync_reset =>
			IF start_video = '1' THEN
				hsync_next_state <= hsync_pulse;
			ELSE
				hsync_next_state <= hsync_reset;
			END IF;
	
	-- Generate hsync pulse
		WHEN hsync_pulse =>
			vsync_counter_inc <= '1';
			pixel_counter_data <= hsync_pulse_width;
			pixel_counter_load <= '1';
			hsync_next_state <= hsync_pulse1;

		WHEN hsync_pulse1 =>
			hs_int <= '0';
			IF pixel_counter_zero = '1' THEN
				hsync_next_state <= hsync_back_porch;
			ELSE
				hsync_next_state <= hsync_pulse1;
			END IF;

	-- Left border
		WHEN hsync_back_porch =>
			
			pixel_counter_data <= hsync_back_porch_width;
			pixel_counter_load <= '1';

			IF (force_blanking = '1' OR blank_vs = '0') THEN
				hsync_next_state <= hsync_back_porch1;
			
			-- Active video?
			ELSE
				IF line_buffer_dma_full = '1' THEN
					line_buffer_toggle <= '1';
					hsync_next_state <= hsync_back_porch1;
				ELSE
					hsync_next_state <= hsync_line_missed;
				END IF;
			END IF;
			
		WHEN hsync_back_porch1 =>
			IF pixel_counter_zero = '1' THEN
					IF (blank_vs = '0' OR force_blanking = '1') THEN
						hsync_next_state <= hsync_blank;
					ELSE
						line_begin <= '1';
						hsync_next_state <= hsync_active_video1;
					END IF;
			ELSE
				hsync_next_state <= hsync_back_porch1;
			END IF;

  	-- First byte from line buffer
		WHEN hsync_active_video1 =>
			line_buffer_rd <= '1';
			blank_hs <= '1';
			colour_byte_sel <= 0;
			hsync_next_state <= hsync_active_video2;

  	-- Second byte from line buffer			
		WHEN hsync_active_video2 =>
--			line_buffer_rd <= '1';
			blank_hs <= '1';
			colour_byte_sel <= 1;
			hsync_next_state <= hsync_active_video3;

  	-- Third byte from line buffer		
		WHEN hsync_active_video3 =>
			blank_hs <= '1';
			colour_byte_sel <= 2;
			hsync_next_state <= hsync_active_video4;
		
  	-- Fourth byte from line buffer	
		WHEN hsync_active_video4 =>
			blank_hs <= '1';
			colour_byte_sel <= 3;
--			line_buffer_rd <= '1';
		
			IF line_buffer_video_empty = '1' THEN
				hsync_next_state <= hsync_front_porch;
			ELSE
				hsync_next_state <= hsync_active_video1;
			END IF;

	-- Right border
		WHEN hsync_front_porch =>
			line_end <= '1';
			pixel_counter_data <= hsync_front_porch_width;
			pixel_counter_load <= '1';
			hsync_next_state <= hsync_front_porch1;

		WHEN hsync_front_porch1 =>
			IF pixel_counter_zero = '1' THEN
				hsync_next_state <= hsync_pulse;
			ELSE
				hsync_next_state <= hsync_front_porch1;
			END IF;

	-- Blank line
		WHEN hsync_blank =>
			pixel_counter_data <= horizontal_resolution - 1;
			pixel_counter_load <= '1';
			hsync_next_state <= hsync_blank1;

		WHEN hsync_blank1 =>
			IF pixel_counter_zero = '1' THEN
				hsync_next_state <= hsync_front_porch;
			ELSE
				hsync_next_state <= hsync_blank1;
			END IF;
		
	-- New video data was not provided before the end of the active video line.
	-- The state machine stays in this loop until the video was stopped. 
		WHEN hsync_line_missed =>
			line_missed <= '1';		
			IF start_video = '0' THEN
				hsync_next_state <= hsync_reset;
			ELSE
				hsync_next_state <= hsync_line_missed;
			END IF;
			
		WHEN others =>
			hsync_next_state <= hsync_reset;

	END CASE;

END PROCESS;

-------------------------
-- Vsync State Machine --
-------------------------
-- This state machine generates all the vsync timing.
-- It generates a vsync pulse. If the vertical line is in an active area of the screen, it releases the blank signal.
-- Also this process is looped forever.

PROCESS(VIDEO_CLK, reset_int)
BEGIN
	IF reset_int = '1' THEN
		vsync_current_state <= vsync_reset;
	ELSIF (VIDEO_CLK'event AND VIDEO_CLK = '1') THEN
		vsync_current_state <= vsync_next_state AFTER 5 ns;
	END IF;
END PROCESS;

PROCESS(vsync_current_state, vsync_counter, control_reg,
		vsync_pulse_width, vsync_back_porch_width, vertical_resolution, vsync_front_porch_width)
BEGIN
	
	vs_int 				<= '1';
	blank_vs 			<= '0';
	vsync_counter_reset	<= '0';
	
	CASE vsync_current_state IS
	
	-- Wait for video starts
		WHEN vsync_reset =>
			vsync_counter_reset <= '1';
			IF start_video = '1' THEN
				vsync_next_state <= vsync_pulse;
			ELSE
				vsync_next_state <= vsync_reset;
			END IF;
	
	-- Generate vsync pulse
		WHEN vsync_pulse =>
			vs_int <= '0';
			IF vsync_counter > vsync_pulse_width THEN
				vsync_next_state <= vsync_back_porch;
			ELSE
				vsync_next_state <= vsync_pulse;
			END IF;
			
 	-- Top border
		WHEN vsync_back_porch =>
			IF (vsync_counter > vsync_pulse_width + vsync_back_porch_width) THEN
				vsync_next_state <= vsync_active_video;
			ELSE
				vsync_next_state <= vsync_back_porch;
			END IF;
	
	-- Active video
		WHEN vsync_active_video =>
			blank_vs <= '1';
			IF (vsync_counter > vsync_pulse_width + vsync_back_porch_width + vertical_resolution) THEN
				vsync_next_state <= vsync_front_porch;
			ELSE
				vsync_next_state <= vsync_active_video;
			END IF;

	-- Bottom border
		WHEN vsync_front_porch =>
			IF (vsync_counter > vsync_pulse_width + vsync_back_porch_width + vertical_resolution + vsync_front_porch_width) THEN
				vsync_counter_reset <= '1';
				vsync_next_state <= vsync_pulse;
			ELSE
				vsync_next_state <= vsync_front_porch;
			END IF;

		WHEN others =>
			vsync_next_state <= vsync_reset;

	END CASE;
END PROCESS;

END behavior;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -