mirror of
https://github.com/ibm2030/IBM2030.git
synced 2026-01-11 23:52:47 +00:00
239 lines
9.2 KiB
VHDL
239 lines
9.2 KiB
VHDL
------------------------------------------------------------------------
|
|
-- vga_controller_640_60.vhd
|
|
------------------------------------------------------------------------
|
|
-- Author : Ulrich Zoltán
|
|
-- Copyright 2006 Digilent, Inc.
|
|
------------------------------------------------------------------------
|
|
-- Software version : Xilinx ISE 7.1.04i
|
|
-- WebPack
|
|
-- Device : 3s200ft256-4
|
|
------------------------------------------------------------------------
|
|
-- This file contains the logic to generate the synchronization signals,
|
|
-- horizontal and vertical pixel counter and video disable signal
|
|
-- for the 640x480@60Hz resolution.
|
|
------------------------------------------------------------------------
|
|
-- Behavioral description
|
|
------------------------------------------------------------------------
|
|
-- Please read the following article on the web regarding the
|
|
-- vga video timings:
|
|
-- http://www.epanorama.net/documents/pc/vga_timing.html
|
|
|
|
-- This module generates the video synch pulses for the monitor to
|
|
-- enter 640x480@60Hz resolution state. It also provides horizontal
|
|
-- and vertical counters for the currently displayed pixel and a blank
|
|
-- signal that is active when the pixel is not inside the visible screen
|
|
-- and the color outputs should be reset to 0.
|
|
|
|
-- timing diagram for the horizontal synch signal (HS)
|
|
-- 0 648 744 800 (pixels)
|
|
-- -------------------------|______|-----------------
|
|
-- timing diagram for the vertical synch signal (VS)
|
|
-- 0 482 484 525 (lines)
|
|
-- -----------------------------------|______|-------
|
|
|
|
-- The blank signal is delayed one pixel clock period (40ns) from where
|
|
-- the pixel leaves the visible screen, according to the counters, to
|
|
-- account for the pixel pipeline delay. This delay happens because
|
|
-- it takes time from when the counters indicate current pixel should
|
|
-- be displayed to when the color data actually arrives at the monitor
|
|
-- pins (memory read delays, synchronization delays).
|
|
------------------------------------------------------------------------
|
|
-- Port definitions
|
|
------------------------------------------------------------------------
|
|
-- rst - global reset signal
|
|
-- pixel_clk - input pin, from dcm_25MHz
|
|
-- - the clock signal generated by a DCM that has
|
|
-- - a frequency of 25MHz.
|
|
-- HS - output pin, to monitor
|
|
-- - horizontal synch pulse
|
|
-- VS - output pin, to monitor
|
|
-- - vertical synch pulse
|
|
-- hcount - output pin, 11 bits, to clients
|
|
-- - horizontal count of the currently displayed
|
|
-- - pixel (even if not in visible area)
|
|
-- vcount - output pin, 11 bits, to clients
|
|
-- - vertical count of the currently active video
|
|
-- - line (even if not in visible area)
|
|
-- blank - output pin, to clients
|
|
-- - active when pixel is not in visible area.
|
|
------------------------------------------------------------------------
|
|
-- Revision History:
|
|
-- 09/18/2006(UlrichZ): created
|
|
------------------------------------------------------------------------
|
|
|
|
library IEEE;
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
|
use IEEE.STD_LOGIC_ARITH.ALL;
|
|
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
|
|
|
-- simulation library
|
|
library UNISIM;
|
|
use UNISIM.VComponents.all;
|
|
|
|
-- the vga_controller_640_60 entity declaration
|
|
-- read above for behavioral description and port definitions.
|
|
entity vga_controller_640_60 is
|
|
port(
|
|
rst : in std_logic;
|
|
pixel_clk : in std_logic;
|
|
|
|
HS : out std_logic;
|
|
VS : out std_logic;
|
|
hcount : out std_logic_vector(10 downto 0);
|
|
vcount : out std_logic_vector(10 downto 0);
|
|
hchar : out std_logic_vector(10 downto 0);
|
|
vchar : out std_logic_vector(10 downto 0);
|
|
hpixel : out std_logic_vector(5 downto 0);
|
|
vpixel : out std_logic_vector(5 downto 0);
|
|
blank : out std_logic
|
|
);
|
|
end vga_controller_640_60;
|
|
|
|
architecture Behavioral of vga_controller_640_60 is
|
|
|
|
------------------------------------------------------------------------
|
|
-- CONSTANTS
|
|
------------------------------------------------------------------------
|
|
-- number of horizontal pixels per character
|
|
constant HPIX : std_logic_vector(5 downto 0) := "010011"; -- 19
|
|
-- number of vertical pixels per character
|
|
constant VPIX : std_logic_vector(5 downto 0) := "010011"; -- 19
|
|
-- maximum value for the horizontal pixel counter
|
|
constant HMAX : std_logic_vector(10 downto 0) := "01100100000"; -- 800
|
|
-- maximum value for the vertical pixel counter
|
|
constant VMAX : std_logic_vector(10 downto 0) := "01000001101"; -- 525
|
|
-- total number of visible columns
|
|
constant HLINES: std_logic_vector(10 downto 0) := "01010000000"; -- 640
|
|
-- value for the horizontal counter where front porch ends
|
|
constant HFP : std_logic_vector(10 downto 0) := "01010001000"; -- 648
|
|
-- value for the horizontal counter where the synch pulse ends
|
|
constant HSP : std_logic_vector(10 downto 0) := "01011101000"; -- 744
|
|
-- total number of visible lines
|
|
constant VLINES: std_logic_vector(10 downto 0) := "00111100000"; -- 480
|
|
-- value for the vertical counter where the front porch ends
|
|
constant VFP : std_logic_vector(10 downto 0) := "00111100010"; -- 482
|
|
-- value for the vertical counter where the synch pulse ends
|
|
constant VSP : std_logic_vector(10 downto 0) := "00111100100"; -- 484
|
|
-- polarity of the horizontal and vertical synch pulse
|
|
-- only one polarity used, because for this resolution they coincide.
|
|
constant SPP : std_logic := '0';
|
|
|
|
------------------------------------------------------------------------
|
|
-- SIGNALS
|
|
------------------------------------------------------------------------
|
|
|
|
-- horizontal and vertical counters
|
|
signal hcounter : std_logic_vector(10 downto 0) := (others => '0');
|
|
signal vcounter : std_logic_vector(10 downto 0) := (others => '0');
|
|
signal hch : std_logic_vector(10 downto 0) := (others => '0');
|
|
signal vch : std_logic_vector(10 downto 0) := (others => '0');
|
|
signal hpx : std_logic_vector(5 downto 0) := (others => '0');
|
|
signal vpx : std_logic_vector(5 downto 0) := (others => '0');
|
|
|
|
-- active when inside visible screen area.
|
|
signal video_enable: std_logic;
|
|
|
|
begin
|
|
|
|
-- output horizontal and vertical counters
|
|
hcount <= hcounter;
|
|
vcount <= vcounter;
|
|
hpixel <= hpx;
|
|
vpixel <= vpx;
|
|
hchar <= hch;
|
|
vchar <= vch;
|
|
|
|
-- blank is active when outside screen visible area
|
|
-- color output should be blacked (put on 0) when blank in active
|
|
-- blank is delayed one pixel clock period from the video_enable
|
|
-- signal to account for the pixel pipeline delay.
|
|
blank <= not video_enable when rising_edge(pixel_clk);
|
|
|
|
-- increment horizontal counter at pixel_clk rate
|
|
-- until HMAX is reached, then reset and keep counting
|
|
h_count: process(pixel_clk)
|
|
begin
|
|
if(rising_edge(pixel_clk)) then
|
|
if(rst = '1') then
|
|
hcounter <= (others => '0');
|
|
hch <= (others => '0');
|
|
hpx <= (others => '0');
|
|
elsif(hcounter = HMAX) then
|
|
hcounter <= (others => '0');
|
|
hch <= (others => '0');
|
|
hpx <= (others => '0');
|
|
else
|
|
hcounter <= hcounter + 1;
|
|
if(hpx=HPIX) then
|
|
hpx <= (others => '0');
|
|
hch <= hch + 1;
|
|
else
|
|
hpx <= hpx + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process h_count;
|
|
|
|
-- increment vertical counter when one line is finished
|
|
-- (horizontal counter reached HMAX)
|
|
-- until VMAX is reached, then reset and keep counting
|
|
v_count: process(pixel_clk)
|
|
begin
|
|
if(rising_edge(pixel_clk)) then
|
|
if(rst = '1') then
|
|
vcounter <= (others => '0');
|
|
vch <= (others => '0');
|
|
vpx <= (others => '0');
|
|
elsif(hcounter = HMAX) then
|
|
if(vcounter = VMAX) then
|
|
vcounter <= (others => '0');
|
|
vch <= (others => '0');
|
|
vpx <= (others => '0');
|
|
else
|
|
vcounter <= vcounter + 1;
|
|
if(vpx=VPIX) then
|
|
vpx <= (others => '0');
|
|
vch <= vch + 1;
|
|
else
|
|
vpx <= vpx + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process v_count;
|
|
|
|
-- generate horizontal synch pulse
|
|
-- when horizontal counter is between where the
|
|
-- front porch ends and the synch pulse ends.
|
|
-- The HS is active (with polarity SPP) for a total of 96 pixels.
|
|
do_hs: process(pixel_clk)
|
|
begin
|
|
if(rising_edge(pixel_clk)) then
|
|
if(hcounter >= HFP and hcounter < HSP) then
|
|
HS <= SPP;
|
|
else
|
|
HS <= not SPP;
|
|
end if;
|
|
end if;
|
|
end process do_hs;
|
|
|
|
-- generate vertical synch pulse
|
|
-- when vertical counter is between where the
|
|
-- front porch ends and the synch pulse ends.
|
|
-- The VS is active (with polarity SPP) for a total of 2 video lines
|
|
-- = 2*HMAX = 1600 pixels.
|
|
do_vs: process(pixel_clk)
|
|
begin
|
|
if(rising_edge(pixel_clk)) then
|
|
if(vcounter >= VFP and vcounter < VSP) then
|
|
VS <= SPP;
|
|
else
|
|
VS <= not SPP;
|
|
end if;
|
|
end if;
|
|
end process do_vs;
|
|
|
|
-- enable video output when pixel is in visible area
|
|
video_enable <= '1' when (hcounter < HLINES and vcounter < VLINES) else '0';
|
|
|
|
end Behavioral; |