Adds VGA controller and testbench enhancements

Introduces a new VGA module for pixel rendering and sync signal generation. Implements an XY position generator for coordinate management. Updates testbench with color cycling logic and additional color constants. Adjusts timing generator logic for improved sync signal handling and accuracy. Modifies UCF constraints for compatibility with LVTTL standard.

Improves modularity and flexibility of the VGA system.
This commit is contained in:
2025-04-25 15:59:37 +00:00
parent 167901eaa6
commit 50f36afcf4
6 changed files with 380 additions and 55 deletions

View File

@@ -28,9 +28,16 @@ CONSTRAINTS = src/VGATimingGenerator_test.ucf
# @example `VSOURCE += src/main.v` (add a single Verilog file per line) # @example `VSOURCE += src/main.v` (add a single Verilog file per line)
# @example `VHDSOURCE += src/main.vhd` (add a single VHDL file per line) # @example `VHDSOURCE += src/main.vhd` (add a single VHDL file per line)
VHDSOURCE += src/VGATimingGenerator_pb.vhd # VHDSOURCE += src/VGATimingGenerator_pb.vhd
VHDSOURCE += src/VGATimingGenerator_test.vhd VHDSOURCE += src/VGATimingGenerator_test.vhd
VHDSOURCE += src/VGATimingGenerator.vhd VHDSOURCE += src/VGATimingGenerator.vhd
VHDSOURCE += src/XY_Generator.vhd
VHDSOURCE += src/VGA.vhd
VHDSOURCE += ../Asynchronous-FIFO-AXI-Handshake/libs/GrayCounter.vhd
VHDSOURCE += ../Asynchronous-FIFO-AXI-Handshake/src/AsyncFIFO.vhd
VHDSOURCE += ../Asynchronous-FIFO-AXI-Handshake/libs/Pipeline-AXI-Handshake/src/PipelineRegister.vhd
VHDSOURCE += ../Asynchronous-FIFO-AXI-Handshake/libs/Pipeline-AXI-Handshake/src/PipelineStage.vhd
VHDSOURCE += ../Asynchronous-FIFO-AXI-Handshake/libs/Pipeline-AXI-Handshake/src/PipelineController.vhd
## Test files settings.. ## ## Test files settings.. ##
# The testbench files to be compiled # The testbench files to be compiled

173
src/VGA.vhd Normal file
View File

@@ -0,0 +1,173 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity VGA is
port (
--@ Pixel Clock; (**Rising edge** triggered)
I_VGA_PixelCLK : in std_logic;
--@ Pixel Clock Enable; (**Synchronous**, **Active high**)
I_VGA_PixelCE : in std_logic;
--@ Pixel Reset; (**Synchronous**, **Active high**)
I_VGA_PixelRST : in std_logic;
--@ Clock; (**Rising edge** triggered)
I_VGA_CLK : in std_logic;
--@ Clock Enable; (**Synchronous**, **Active high**)
I_VGA_CE : in std_logic;
--@ Reset; (**Synchronous**, **Active high**)
I_VGA_RST : in std_logic;
--@ @virtualbus VGA-Signals @dir out VGA signals
--@ Horizontal Sync signal; **Active low**
O_VGA_HSync : out std_logic;
--@ Vertical Sync signal; **Active low**
O_VGA_VSync : out std_logic;
--@ VGA Red Channel
O_VGA_Red : out std_logic_vector(2 downto 0);
--@ VGA Green Channel
O_VGA_Green : out std_logic_vector(2 downto 0);
--@ VGA Blue Channel
O_VGA_Blue : out std_logic_vector(1 downto 0);
--@ @end
--@ @virtualbus XY-Request @dir Out Request for the X and Y positions
O_VGA_Req_Y_Valid : out std_logic;
I_VGA_Req_Y_Ready : in std_logic;
O_VGA_Req_Y : out std_logic_vector(9 downto 0);
O_VGA_Req_X_Valid : out std_logic;
I_VGA_Req_X_Ready : in std_logic;
O_VGA_Req_X : out std_logic_vector(9 downto 0);
--@ @end
--@ @virtualbus Pixel-Data @dir In Calculated pixel data
I_VGA_PixelData_Valid : in std_logic;
O_VGA_PixelData_Ready : out std_logic;
I_VGA_PixelData : in std_logic_vector(7 downto 0);
--@ @end
--@ @virtualbus Error-Register @dir Out Error register; (Synchronous to I_VGA_CLK)
I_VGA_Error_RST : in std_logic := '0';
O_VGA_Error : out std_logic_vector(7 downto 0) := (others => '0')
--@ @end
);
end entity VGA;
architecture RTL of VGA is
signal O_TimingGenerator_PixelReady : std_logic;
signal O_TimingGenerator_HSync : std_logic;
signal O_TimingGenerator_VSync : std_logic;
signal O_AsyncPixelDataFIFO_Valid : std_logic;
signal O_AsyncPixelDataFIFO_Data : std_logic_vector(7 downto 0);
signal C_DisablePixelOutput : std_logic := '0';
-- Error signals --
signal R_Error : std_logic_vector(7 downto 0) := (others => '0');
--@ Is set if the pixel data is requested but not available in the FIFO
signal C_Error_PixelUnderrun : std_logic := '0';
begin
INST_TimingGenerator : entity work.VGATimingGenerator
port map(
I_CLK => I_VGA_PixelCLK,
I_CE => I_VGA_PixelCE,
I_RST => I_VGA_PixelRST,
O_PixelReady => O_TimingGenerator_PixelReady,
O_HSync => O_TimingGenerator_HSync,
O_VSync => O_TimingGenerator_VSync
);
O_VGA_HSync <= O_TimingGenerator_HSync;
O_VGA_VSync <= O_TimingGenerator_VSync;
C_DisablePixelOutput <= not O_TimingGenerator_HSync and
not O_TimingGenerator_VSync;
INST_XY_Generator : entity work.XY_Generator
generic map(
G_X => 640,
G_Y => 480,
G_X_Width => 10,
G_Y_Width => 10
)
port map(
I_CLK => I_VGA_CLK,
I_CE => I_VGA_CE,
I_RST => I_VGA_RST,
O_Y_Valid => O_VGA_Req_Y_Valid,
I_Y_Ready => I_VGA_Req_Y_Ready,
O_Y => O_VGA_Req_Y,
O_X_Valid => O_VGA_Req_X_Valid,
I_X_Ready => I_VGA_Req_X_Ready,
O_X => O_VGA_Req_X
);
INST_AsyncPixelDataFIFO : entity work.AsyncFIFO
generic map(
G_Width => 8,
G_Depth => 16,
G_RamTypeFifo => "Distributed"
)
port map(
I_Write_CLK => I_VGA_CLK,
I_Write_CE => I_VGA_CE,
I_Write_Data => I_VGA_PixelData,
I_Write_Valid => I_VGA_PixelData_Valid,
O_Write_Ready => O_VGA_PixelData_Ready,
I_Read_CLK => I_VGA_PixelCLK,
I_Read_CE => I_VGA_PixelCE,
O_Read_Data => O_AsyncPixelDataFIFO_Data,
I_Read_Ready => O_TimingGenerator_PixelReady,
O_Read_Valid => O_AsyncPixelDataFIFO_Valid
);
P_O_Pixel_Register : process (I_VGA_PixelCLK)
begin
if rising_edge(I_VGA_PixelCLK) then
if I_VGA_PixelRST = '1' then
O_VGA_Red <= (others => '0');
O_VGA_Green <= (others => '0');
O_VGA_Blue <= (others => '0');
C_Error_PixelUnderrun <= '0';
elsif I_VGA_PixelCE = '1' then
-- Reset Error flags --
C_Error_PixelUnderrun <= '0';
-- -- -- -- -- -- -- --
if (O_TimingGenerator_PixelReady and O_AsyncPixelDataFIFO_Valid) = '1' then
O_VGA_Red <= O_AsyncPixelDataFIFO_Data(7 downto 5);
O_VGA_Green <= O_AsyncPixelDataFIFO_Data(4 downto 2);
O_VGA_Blue <= O_AsyncPixelDataFIFO_Data(1 downto 0);
elsif O_TimingGenerator_PixelReady = '1' then
--@ Pixel data is requested but not available in the FIFO
--@ Set error flag
C_Error_PixelUnderrun <= '1';
elsif C_DisablePixelOutput = '1' then
--@ Disable pixel output
O_VGA_Red <= (others => '0');
O_VGA_Green <= (others => '0');
O_VGA_Blue <= (others => '0');
end if;
end if;
end if;
end process;
P_Error_Register : process (I_VGA_CLK)
begin
if rising_edge(I_VGA_CLK) then
if I_VGA_RST = '1' then
R_Error <= (others => '0');
elsif I_VGA_Error_RST = '1' then
R_Error <= (others => '0');
else
R_Error(0) <= R_Error(0) or C_Error_PixelUnderrun;
end if;
end if;
end process;
O_VGA_Error <= R_Error;
end architecture;

View File

@@ -1,7 +1,7 @@
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
--@ - Name: **VGA Timing Generator** --@ - Name: **VGA Timing Generator**
--@ - Version: 0.0.1 --@ - Version: 0.0.1
--@ - Author: _Maximilian Passarello ([Blog](mpassarello.de))_ --@ - Author: _0xMax42 ([Blog](0xMax42.io))_
--@ - License: [MIT](LICENSE) --@ - License: [MIT](LICENSE)
--@ --@
--@ The VGA Timing Generator is a simple module that generates the horizontal and vertical sync signals for a VGA display. --@ The VGA Timing Generator is a simple module that generates the horizontal and vertical sync signals for a VGA display.
@@ -35,14 +35,15 @@ entity VGATimingGenerator is
G_VBack : integer := 33; G_VBack : integer := 33;
--@ Vertical Total resolution --@ Vertical Total resolution
G_VTotal : integer := 525 G_VTotal : integer := 525
); );
port ( port (
--@ Clock signal; **Rising edge** triggered --@ Clock; (**Rising edge** triggered)
I_CLK : in std_logic; I_CLK : in std_logic;
--@ Clock Enable signal --@ Clock Enable; (**Synchronous**, **Active high**)
I_CE : in std_logic; I_CE : in std_logic;
--@ Synchronous reset signal --@ Reset; (**Synchronous**, **Active high**)
I_RST : in std_logic; I_RST : in std_logic;
--@ Ready signal (AXI like) to indicate that the pixel data is ready to be displayed --@ Ready signal (AXI like) to indicate that the pixel data is ready to be displayed
O_PixelReady : out std_logic; O_PixelReady : out std_logic;
--@ @virtualbus VGA-Timing-Signals @dir out VGA timing signals --@ @virtualbus VGA-Timing-Signals @dir out VGA timing signals
@@ -50,8 +51,8 @@ entity VGATimingGenerator is
O_HSync : out std_logic; O_HSync : out std_logic;
--@ Vertical Sync signal; **Active low** --@ Vertical Sync signal; **Active low**
O_VSync : out std_logic O_VSync : out std_logic
--@ @end --@ @end
); );
end entity VGATimingGenerator; end entity VGATimingGenerator;
architecture RTL of VGATimingGenerator is architecture RTL of VGATimingGenerator is
@@ -61,19 +62,19 @@ architecture RTL of VGATimingGenerator is
signal R_VerticalCounter : unsigned(integer(ceil(log2(real(G_VTotal)))) - 1 downto 0) := (others => '0'); signal R_VerticalCounter : unsigned(integer(ceil(log2(real(G_VTotal)))) - 1 downto 0) := (others => '0');
--@ Counter Enable signal for Vertical Counter --@ Counter Enable signal for Vertical Counter
signal C_VerticalCE : std_logic := '0'; signal C_VerticalCE : std_logic := '0';
--@ Flag to indicate if the horizontal counter is in the visible area --@ Flag to indicate if the horizontal counter is in the visible area
signal C_HorizontalVisible : std_logic := '0'; signal C_HorizontalVisible : std_logic := '0';
--@ Flag to indicate if the vertical counter is in the visible area --@ Flag to indicate if the vertical counter is in the visible area
signal C_VerticalVisible : std_logic := '0'; signal C_VerticalVisible : std_logic := '0';
--@ Horizontal Sync signal shift register --@ Horizontal Sync signal shift register
signal R_HSync : std_logic_vector(1 downto 0) := (others => '0'); signal R_HSync : std_logic_vector(1 downto 0) := (others => '0');
--@ Vertical Sync signal register --@ Vertical Sync signal register
signal R_VSync : std_logic := '1'; signal R_VSync : std_logic := '1';
--@ Pixel Ready signal --@ Pixel Ready signal
signal C_PixelReady : std_logic := '0'; signal C_PixelReady : std_logic := '0';
begin begin
--@ Horizontal Pixel Counter. --@ Horizontal Pixel Counter.
--@ Overflows at G_HTotal. --@ Overflows at G_HTotal.
@@ -138,7 +139,7 @@ begin
if rising_edge(I_CLK) then if rising_edge(I_CLK) then
if I_RST = '1' then if I_RST = '1' then
R_VerticalCounter <= (others => '0'); R_VerticalCounter <= (others => '0');
elsif C_VerticalCE = '1' then elsif (I_CE and C_VerticalCE) = '1' then
if R_VerticalCounter = G_VTotal - 1 then if R_VerticalCounter = G_VTotal - 1 then
R_VerticalCounter <= (others => '0'); R_VerticalCounter <= (others => '0');
else else
@@ -154,8 +155,8 @@ begin
if rising_edge(I_CLK) then if rising_edge(I_CLK) then
if I_RST = '1' then if I_RST = '1' then
R_VSync <= '1'; R_VSync <= '1';
elsif C_VerticalCE = '1' then elsif (I_CE and C_VerticalCE) = '1' then
if R_VerticalCounter < G_VSync then if R_VerticalCounter >= G_VTotal - G_VSync then
R_VSync <= '0'; R_VSync <= '0';
else else
R_VSync <= '1'; R_VSync <= '1';
@@ -167,8 +168,8 @@ begin
--@ Flag generator for vertical visible area. --@ Flag generator for vertical visible area.
P_VerticalVisible : process (R_VerticalCounter) P_VerticalVisible : process (R_VerticalCounter)
begin begin
if R_VerticalCounter >= G_VSync + G_VBack and if R_VerticalCounter >= G_VBack and
R_VerticalCounter <= G_VTotal - G_VFront - 1 then R_VerticalCounter <= G_VTotal - G_VFront - G_VSync - 1 then
C_VerticalVisible <= '1'; C_VerticalVisible <= '1';
else else
C_VerticalVisible <= '0'; C_VerticalVisible <= '0';

View File

@@ -2,14 +2,14 @@ NET I_CLK LOC = B8;
NET I_CLK TNM_NET = CLOCK; NET I_CLK TNM_NET = CLOCK;
TIMESPEC TS_CLOCK = PERIOD CLOCK 50 MHz HIGH 50 %; TIMESPEC TS_CLOCK = PERIOD CLOCK 50 MHz HIGH 50 %;
NET O_HSync LOC = T4 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_HSync LOC = T4 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_VSync LOC = U3 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_VSync LOC = U3 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Red<0> LOC = R9 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Red<0> LOC = R9 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Red<1> LOC = T8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Red<1> LOC = T8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Red<2> LOC = R8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Red<2> LOC = R8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Green<0> LOC = N8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Green<0> LOC = N8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Green<1> LOC = P8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Green<1> LOC = P8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Green<2> LOC = P6 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Green<2> LOC = P6 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Blue<0> LOC = U5 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Blue<0> LOC = U5 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;
NET O_Blue<1> LOC = U4 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; NET O_Blue<1> LOC = U4 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2;

View File

@@ -23,11 +23,17 @@ entity VGATimingGenerator_test is
end entity VGATimingGenerator_test; end entity VGATimingGenerator_test;
architecture RTL of VGATimingGenerator_test is architecture RTL of VGATimingGenerator_test is
function rgb_to_vector(red : unsigned(2 downto 0); green : unsigned(2 downto 0); blue : unsigned(1 downto 0)) return std_logic_vector is
begin
return std_logic_vector(std_logic_vector(red) & std_logic_vector(green) & std_logic_vector(blue));
end function;
signal I_VGA_PixelCE : std_logic := '0'; signal I_VGA_PixelCE : std_logic := '0';
signal I_VGA_PixelRST : std_logic := '1'; signal I_VGA_PixelRST : std_logic := '1';
signal O_VGA_Req_Y_Valid : std_logic; signal O_VGA_Req_Y_Valid : std_logic;
signal I_VGA_Req_Y_Ready : std_logic; signal I_VGA_Req_Y_Ready : std_logic := '0';
signal O_VGA_Req_Y : std_logic_vector(9 downto 0); signal O_VGA_Req_Y : std_logic_vector(9 downto 0);
signal O_VGA_Req_X_Valid : std_logic; signal O_VGA_Req_X_Valid : std_logic;
@@ -43,24 +49,60 @@ architecture RTL of VGATimingGenerator_test is
signal I_VGA_PixelData : std_logic_vector(7 downto 0); signal I_VGA_PixelData : std_logic_vector(7 downto 0);
---- ----
constant COLOR_RED : std_logic_vector(7 downto 0) := "11100000"; -- R=7, G=0, B=0 constant K_COLOR_BLACK : std_logic_vector(7 downto 0) := rgb_to_vector("000", "000", "00");
constant COLOR_GREEN : std_logic_vector(7 downto 0) := "00011100"; -- R=0, G=7, B=0 constant K_COLOR_WHITE : std_logic_vector(7 downto 0) := rgb_to_vector("111", "111", "11");
constant COLOR_BLUE : std_logic_vector(7 downto 0) := "00000011"; -- R=0, G=0, B=3
signal R_CurrentColor : std_logic_vector(7 downto 0) := COLOR_BLUE; -- Pre-Startfarbe: Blau constant K_COLOR_RED : std_logic_vector(7 downto 0) := rgb_to_vector("111", "000", "00");
constant COLOR_CHANGE_INTERVAL : integer := 16; constant K_COLOR_GREEN : std_logic_vector(7 downto 0) := rgb_to_vector("000", "111", "00");
constant K_COLOR_BLUE : std_logic_vector(7 downto 0) := rgb_to_vector("000", "000", "11");
-- Farbwechsel-Logik (einfache zyklische Farben) constant K_COLOR_CYAN : std_logic_vector(7 downto 0) := rgb_to_vector("000", "111", "11"); -- G + B
function next_color(current : std_logic_vector(7 downto 0)) return std_logic_vector is constant K_COLOR_MAGENTA : std_logic_vector(7 downto 0) := rgb_to_vector("111", "000", "11"); -- R + B
constant K_COLOR_YELLOW : std_logic_vector(7 downto 0) := rgb_to_vector("111", "111", "00"); -- R + G
constant K_COLOR_GRAY : std_logic_vector(7 downto 0) := rgb_to_vector("100", "100", "10"); -- mittelgrau
constant K_COLOR_DARK_GRAY : std_logic_vector(7 downto 0) := rgb_to_vector("010", "010", "01");
constant K_COLOR_LIGHT_GRAY : std_logic_vector(7 downto 0) := rgb_to_vector("110", "110", "10");
constant K_COLOR_ORANGE : std_logic_vector(7 downto 0) := rgb_to_vector("111", "011", "00");
constant K_COLOR_PINK : std_logic_vector(7 downto 0) := rgb_to_vector("111", "100", "10");
constant K_COLOR_BROWN : std_logic_vector(7 downto 0) := rgb_to_vector("100", "010", "00");
constant K_COLOR_LIME : std_logic_vector(7 downto 0) := rgb_to_vector("010", "111", "00");
constant K_COLOR_NAVY : std_logic_vector(7 downto 0) := rgb_to_vector("000", "000", "01");
constant K_DEFAULT_COLOR : std_logic_vector(7 downto 0) := K_COLOR_CYAN;
signal R_CurrentColor : std_logic_vector(7 downto 0);
signal R_CurrentColorAlt : std_logic_vector(7 downto 0);
signal R_MUX_Color : std_logic := '0';
constant K_COLOR_CHANGE_INTERVAL : integer := 16;
-- Farbwechsel-Logik (einfache zyklische Farben)
function next_color(currentColor : std_logic_vector(7 downto 0)) return std_logic_vector is
begin begin
if current = COLOR_RED then -- Rot case currentColor is
return COLOR_GREEN; -- Grün when K_COLOR_BLACK => return K_COLOR_WHITE;
elsif current = COLOR_GREEN then -- Grün when K_COLOR_WHITE => return K_COLOR_RED;
return COLOR_BLUE; -- Blau when K_COLOR_RED => return K_COLOR_GREEN;
else when K_COLOR_GREEN => return K_COLOR_BLUE;
return COLOR_RED; -- Rot when K_COLOR_BLUE => return K_COLOR_CYAN;
end if; when K_COLOR_CYAN => return K_COLOR_MAGENTA;
when K_COLOR_MAGENTA => return K_COLOR_YELLOW;
when K_COLOR_YELLOW => return K_COLOR_GRAY;
when K_COLOR_GRAY => return K_COLOR_DARK_GRAY;
when K_COLOR_DARK_GRAY => return K_COLOR_LIGHT_GRAY;
when K_COLOR_LIGHT_GRAY => return K_COLOR_ORANGE;
when K_COLOR_ORANGE => return K_COLOR_PINK;
when K_COLOR_PINK => return K_COLOR_BROWN;
when K_COLOR_BROWN => return K_COLOR_LIME;
when K_COLOR_LIME => return K_COLOR_NAVY;
when K_COLOR_NAVY => return K_COLOR_BLACK; -- wieder von vorn
when others => return K_DEFAULT_COLOR;
end case;
end function; end function;
begin begin
process (I_CLK) process (I_CLK)
@@ -72,23 +114,33 @@ begin
I_VGA_PixelData_Valid <= O_VGA_Req_X_Valid; I_VGA_PixelData_Valid <= O_VGA_Req_X_Valid;
I_VGA_Req_X_Ready <= O_VGA_PixelData_Ready; I_VGA_Req_X_Ready <= O_VGA_PixelData_Ready;
I_VGA_PixelData <= R_CurrentColor when R_MUX_Color = '0' else
R_CurrentColorAlt;
process(I_CLK) process(I_CLK)
begin begin
if rising_edge(I_CLK) then if rising_edge(I_CLK) then
I_VGA_PixelRST <= '0'; I_VGA_PixelRST <= '0';
I_VGA_PixelData <= R_CurrentColor; if O_VGA_Req_X_Valid = '1' and O_VGA_PixelData_Ready = '1' then
if unsigned(O_VGA_Req_X) = to_unsigned(640-1, O_VGA_Req_X'length) then
R_MUX_Color <= '0';
elsif unsigned(O_VGA_Req_X) = to_unsigned(320-1, O_VGA_Req_X'length) then
R_MUX_Color <= '1';
end if;
end if;
-- Default
I_VGA_Req_Y_Ready <= '0';
-- Zeilenwechsel erkennen (Req_X zurück auf 0)
if O_VGA_Req_Y_Valid = '1' and I_VGA_Req_Y_Ready = '0' then if O_VGA_Req_Y_Valid = '1' and I_VGA_Req_Y_Ready = '0' then
I_VGA_Req_Y_Ready <= '1'; I_VGA_Req_Y_Ready <= '1';
if O_VGA_Req_Y = (O_VGA_Req_Y'range => '0') then
if (unsigned(O_VGA_Req_Y) mod COLOR_CHANGE_INTERVAL) = 0 then R_CurrentColor <= K_DEFAULT_COLOR;
R_CurrentColor <= next_color(R_CurrentColor); R_CurrentColorAlt <= next_color(K_DEFAULT_COLOR);
elsif (unsigned(O_VGA_Req_Y) mod K_COLOR_CHANGE_INTERVAL) = 0 then
R_CurrentColor <= next_color(R_CurrentColor);
R_CurrentColorAlt <= next_color(R_CurrentColorAlt);
end if; end if;
elsif I_VGA_Req_Y_Ready = '1' then
I_VGA_Req_Y_Ready <= '0';
end if; end if;
end if; end if;

92
src/XY_Generator.vhd Normal file
View File

@@ -0,0 +1,92 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity XY_Generator is
generic (
G_X : integer := 640;
G_Y : integer := 480;
--@ Width of the X position (Row) register
G_X_Width : integer := 10;
--@ Width of the Y position (Line) register
G_Y_Width : integer := 10
);
port (
--@ Clock; (**Rising edge** triggered)
I_CLK : in std_logic;
--@ Clock Enable; (**Synchronous**, **Active high**)
I_CE : in std_logic;
--@ Reset; (**Synchronous**, **Active high**)
I_RST : in std_logic;
--@ @virtualbus Y @dir Out Output of the Y positions, with priority over X
O_Y_Valid : out std_logic;
I_Y_Ready : in std_logic;
O_Y : out std_logic_vector(G_Y_Width - 1 downto 0);
--@ @end
--@ @virtualbus Y @dir Out Output of the X positions
O_X_Valid : out std_logic;
I_X_Ready : in std_logic;
O_X : out std_logic_vector(G_X_Width - 1 downto 0)
--@ @end
);
end entity XY_Generator;
architecture RTL of XY_Generator is
signal R_X_Counter : unsigned(G_X_Width - 1 downto 0) := (others => '0');
signal R_Y_Counter : unsigned(G_Y_Width - 1 downto 0) := (others => '0');
signal R_Y_Valid : std_logic := '1';
signal R_X_Valid : std_logic := '1';
signal C_X_Valid : std_logic := '0';
begin
C_X_Valid <= R_X_Valid and not R_Y_Valid;
process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_RST = '1' then
R_X_Counter <= (others => '0');
R_Y_Counter <= (others => '0');
R_Y_Valid <= '1';
R_X_Valid <= '1';
elsif I_CE = '1' then
if R_Y_Valid = '1' then
if I_Y_Ready = '1' then
R_Y_Valid <= '0';
end if;
elsif R_X_Valid = '1' then
if I_X_Ready = '1' then
R_X_Valid <= '0';
end if;
else
if R_X_Counter = (G_X - 1) then
R_X_Counter <= (others => '0');
R_X_Valid <= '1';
if R_Y_Counter = (G_Y - 1) then
R_Y_Counter <= (others => '0');
R_Y_Valid <= '1';
else
R_Y_Counter <= R_Y_Counter + 1;
R_Y_Valid <= '1';
end if;
else
R_X_Counter <= R_X_Counter + 1;
R_X_Valid <= '1';
end if;
end if;
end if;
end if;
end process;
O_X <= std_logic_vector(R_X_Counter);
O_Y <= std_logic_vector(R_Y_Counter);
O_Y_Valid <= R_Y_Valid;
O_X_Valid <= C_X_Valid;
end architecture;