diff --git a/project.cfg b/project.cfg index dda78c5..1afe342 100644 --- a/project.cfg +++ b/project.cfg @@ -28,9 +28,16 @@ CONSTRAINTS = src/VGATimingGenerator_test.ucf # @example `VSOURCE += src/main.v` (add a single Verilog 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.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.. ## # The testbench files to be compiled diff --git a/src/VGA.vhd b/src/VGA.vhd new file mode 100644 index 0000000..8b1f290 --- /dev/null +++ b/src/VGA.vhd @@ -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; diff --git a/src/VGATimingGenerator.vhd b/src/VGATimingGenerator.vhd index 205062d..1be7a26 100644 --- a/src/VGATimingGenerator.vhd +++ b/src/VGATimingGenerator.vhd @@ -1,7 +1,7 @@ ---------------------------------------------------------------------------------- --@ - Name: **VGA Timing Generator** --@ - Version: 0.0.1 ---@ - Author: _Maximilian Passarello ([Blog](mpassarello.de))_ +--@ - Author: _0xMax42 ([Blog](0xMax42.io))_ --@ - License: [MIT](LICENSE) --@ --@ 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; --@ Vertical Total resolution G_VTotal : integer := 525 - ); + ); port ( - --@ Clock signal; **Rising edge** triggered - I_CLK : in std_logic; - --@ Clock Enable signal - I_CE : in std_logic; - --@ Synchronous reset signal - I_RST : in std_logic; + --@ 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; + --@ Ready signal (AXI like) to indicate that the pixel data is ready to be displayed O_PixelReady : out std_logic; --@ @virtualbus VGA-Timing-Signals @dir out VGA timing signals @@ -50,8 +51,8 @@ entity VGATimingGenerator is O_HSync : out std_logic; --@ Vertical Sync signal; **Active low** O_VSync : out std_logic - --@ @end - ); + --@ @end + ); end entity VGATimingGenerator; 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'); --@ 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 - signal C_HorizontalVisible : std_logic := '0'; + signal C_HorizontalVisible : std_logic := '0'; --@ 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 - 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 - signal R_VSync : std_logic := '1'; + signal R_VSync : std_logic := '1'; --@ Pixel Ready signal - signal C_PixelReady : std_logic := '0'; + signal C_PixelReady : std_logic := '0'; begin --@ Horizontal Pixel Counter. --@ Overflows at G_HTotal. @@ -138,7 +139,7 @@ begin if rising_edge(I_CLK) then if I_RST = '1' then R_VerticalCounter <= (others => '0'); - elsif C_VerticalCE = '1' then + elsif (I_CE and C_VerticalCE) = '1' then if R_VerticalCounter = G_VTotal - 1 then R_VerticalCounter <= (others => '0'); else @@ -154,8 +155,8 @@ begin if rising_edge(I_CLK) then if I_RST = '1' then R_VSync <= '1'; - elsif C_VerticalCE = '1' then - if R_VerticalCounter < G_VSync then + elsif (I_CE and C_VerticalCE) = '1' then + if R_VerticalCounter >= G_VTotal - G_VSync then R_VSync <= '0'; else R_VSync <= '1'; @@ -167,8 +168,8 @@ begin --@ Flag generator for vertical visible area. P_VerticalVisible : process (R_VerticalCounter) begin - if R_VerticalCounter >= G_VSync + G_VBack and - R_VerticalCounter <= G_VTotal - G_VFront - 1 then + if R_VerticalCounter >= G_VBack and + R_VerticalCounter <= G_VTotal - G_VFront - G_VSync - 1 then C_VerticalVisible <= '1'; else C_VerticalVisible <= '0'; diff --git a/src/VGATimingGenerator_test.ucf b/src/VGATimingGenerator_test.ucf index 19419ae..d41d69d 100644 --- a/src/VGATimingGenerator_test.ucf +++ b/src/VGATimingGenerator_test.ucf @@ -2,14 +2,14 @@ NET I_CLK LOC = B8; NET I_CLK TNM_NET = CLOCK; TIMESPEC TS_CLOCK = PERIOD CLOCK 50 MHz HIGH 50 %; -NET O_HSync LOC = T4 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_VSync LOC = U3 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_HSync LOC = T4 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +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<1> LOC = T8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_Red<2> LOC = R8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_Green<0> LOC = N8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_Green<1> LOC = P8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_Green<2> LOC = P6 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_Blue<0> LOC = U5 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; -NET O_Blue<1> LOC = U4 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; \ No newline at end of file +NET O_Red<0> LOC = R9 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Red<1> LOC = T8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Red<2> LOC = R8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Green<0> LOC = N8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Green<1> LOC = P8 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Green<2> LOC = P6 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Blue<0> LOC = U5 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; +NET O_Blue<1> LOC = U4 | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 2; \ No newline at end of file diff --git a/src/VGATimingGenerator_test.vhd b/src/VGATimingGenerator_test.vhd index 4fbdfae..30cc9e1 100644 --- a/src/VGATimingGenerator_test.vhd +++ b/src/VGATimingGenerator_test.vhd @@ -23,11 +23,17 @@ entity VGATimingGenerator_test is end entity VGATimingGenerator_test; 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_PixelRST : std_logic := '1'; 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_X_Valid : std_logic; @@ -43,24 +49,60 @@ architecture RTL of VGATimingGenerator_test is 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 COLOR_GREEN : std_logic_vector(7 downto 0) := "00011100"; -- R=0, G=7, B=0 - constant COLOR_BLUE : std_logic_vector(7 downto 0) := "00000011"; -- R=0, G=0, B=3 + constant K_COLOR_BLACK : std_logic_vector(7 downto 0) := rgb_to_vector("000", "000", "00"); + constant K_COLOR_WHITE : std_logic_vector(7 downto 0) := rgb_to_vector("111", "111", "11"); - signal R_CurrentColor : std_logic_vector(7 downto 0) := COLOR_BLUE; -- Pre-Startfarbe: Blau - constant COLOR_CHANGE_INTERVAL : integer := 16; + constant K_COLOR_RED : std_logic_vector(7 downto 0) := rgb_to_vector("111", "000", "00"); + 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) - function next_color(current : std_logic_vector(7 downto 0)) return std_logic_vector is + constant K_COLOR_CYAN : std_logic_vector(7 downto 0) := rgb_to_vector("000", "111", "11"); -- G + B + 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 - if current = COLOR_RED then -- Rot - return COLOR_GREEN; -- Grün - elsif current = COLOR_GREEN then -- Grün - return COLOR_BLUE; -- Blau - else - return COLOR_RED; -- Rot - end if; + case currentColor is + when K_COLOR_BLACK => return K_COLOR_WHITE; + when K_COLOR_WHITE => return K_COLOR_RED; + when K_COLOR_RED => return K_COLOR_GREEN; + when K_COLOR_GREEN => return K_COLOR_BLUE; + when K_COLOR_BLUE => return K_COLOR_CYAN; + 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; + + begin process (I_CLK) @@ -72,23 +114,33 @@ begin I_VGA_PixelData_Valid <= O_VGA_Req_X_Valid; 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) begin if rising_edge(I_CLK) then 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 I_VGA_Req_Y_Ready <= '1'; - - if (unsigned(O_VGA_Req_Y) mod COLOR_CHANGE_INTERVAL) = 0 then - R_CurrentColor <= next_color(R_CurrentColor); + if O_VGA_Req_Y = (O_VGA_Req_Y'range => '0') then + R_CurrentColor <= K_DEFAULT_COLOR; + 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; + elsif I_VGA_Req_Y_Ready = '1' then + I_VGA_Req_Y_Ready <= '0'; end if; end if; diff --git a/src/XY_Generator.vhd b/src/XY_Generator.vhd new file mode 100644 index 0000000..46b8e2a --- /dev/null +++ b/src/XY_Generator.vhd @@ -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;