Introduces sprite channel processing pipeline
Adds modules for sprite operations, including opcode decoding, register handling, and vertical pipeline calculations. Replaces legacy scheduler with a more modular and efficient design. Updates constraints for clock timing. Enhances sprite rendering pipeline with improved modularity and scalability.
This commit is contained in:
265
src/OPDecoder.vhd
Normal file
265
src/OPDecoder.vhd
Normal file
@@ -0,0 +1,265 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
use work.OPCodes.all;
|
||||
|
||||
entity OPDecoder is
|
||||
generic (
|
||||
--@ Data width of the operation data.
|
||||
G_OPCodeData_Width : integer := 10;
|
||||
--@ Width of the sprite index (Base address) register
|
||||
G_Index_Width : integer := 5;
|
||||
--@ Width of the sprite offset (Line address) register
|
||||
G_Offset_Width : integer := 8;
|
||||
--@ 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 signal; (**Rising edge** triggered)
|
||||
I_CLK : in std_logic;
|
||||
--@ Clock enable signal (**Active high**)
|
||||
I_CE : in std_logic;
|
||||
--@ Synchronous reset signal (**Active high**)
|
||||
I_RST : in std_logic;
|
||||
|
||||
--@ @virtualbus Operation-Write @dir in Operation Write Interface
|
||||
--@ Indicates if the `OPCode` and `OPData` are valid. (**Active high**)
|
||||
I_OP_Valid : in std_logic := '0';
|
||||
--@ Indicates if the decoder is ready to accept data. (**Active high**)
|
||||
O_OP_Ready : out std_logic := '0';
|
||||
--@ Operation code for the sprite channel
|
||||
I_OP_Code : in std_logic_vector(3 downto 0) := (others => '0');
|
||||
--@ Data to be used with the operation code.
|
||||
I_OP_Data : in std_logic_vector(G_OPCodeData_Width - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus Register-Write @dir out Bus to write to the register file
|
||||
--@ Write enable for the sprite index register; (**Active high**)
|
||||
O_Register_Index_WE : out std_logic := '0';
|
||||
--@ Data to write to the sprite index (Base address) register.
|
||||
O_Register_Index : out std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the sprite offset (line) register; (**Active high**)
|
||||
O_Register_Offset_WE : out std_logic := '0';
|
||||
--@ Data to write to the sprite offset (Line address) register.
|
||||
O_Register_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the X position register. (**Active high**)
|
||||
O_Register_X_We : out std_logic := '0';
|
||||
--@ Data to write to the X position register (Row) of the sprite.
|
||||
O_Register_X : out std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the Y position register. (**Active high**)
|
||||
O_Register_Y_WE : out std_logic := '0';
|
||||
--@ Data to write to the Y position register (Line) of the sprite.
|
||||
O_Register_Y : out std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the `IsVisible` flag. (**Active high**)
|
||||
O_IsVisible_WE : out std_logic := '0';
|
||||
--@ Flag to write to the `IsVisible` flag.
|
||||
O_IsVisible : out std_logic := '0';
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus Register-Read @dir In Parallel read interface to the register file
|
||||
--@ Indicates if the sprite is in the line visible.
|
||||
I_IsVisible : in std_logic := '0';
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus YHitCheck-Input-Interface @dir in YHitCheck Input Interface
|
||||
--@ Indicates if the pipeline is ready to accept data. **Active high**
|
||||
I_YHitCheck_Ready : in std_logic := '0';
|
||||
--@ Indicates if the pipeline is valid. **Active high**
|
||||
O_YHitCheck_Valid : out std_logic := '0';
|
||||
--@ The line to check if the sprite is in the line visible.
|
||||
O_YHitCheck_YToCheck : out std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus YHitCheck-Output-Interface @dir out YHitCheck Output Interface
|
||||
--@ Indicates if the pipeline is ready to deliver data. **Active high**
|
||||
O_YHitCheck_Ready : out std_logic := '0';
|
||||
--@ Indicates if `O_IsVisible` is valid. **Active high**
|
||||
I_YHitCheck_Valid : in std_logic := '0';
|
||||
--@ Indicates if the sprite is visible in the line.
|
||||
I_YHitCheck_IsVisible : in std_logic := '0';
|
||||
--@ The calculated offset address of the sprite.
|
||||
I_YHitCheck_Offset : in std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus HorizontalSpritePipeline-Interface @dir Out Interface to the horizontal sprite pipeline
|
||||
--@ AXI like valid; (**Synchronous**, **Active high**)
|
||||
O_HSpritePipeline_Valid : out std_logic := '0';
|
||||
--@ AXI like ready; (**Synchronous**, **Active high**)
|
||||
I_HSpritePipeline_Ready : in std_logic := '0';
|
||||
--@ Requested X position of the sprite in the line.
|
||||
O_HSpritePipeline_X_Request : out std_logic_vector(G_X_Width - 1 downto 0) := (others => '0')
|
||||
--@ @end
|
||||
);
|
||||
end OPDecoder;
|
||||
|
||||
architecture RTL of OPDecoder is
|
||||
signal C_OP_Ready : std_logic := '0';
|
||||
|
||||
type T_State is (
|
||||
S_Ready,
|
||||
S_Dispatch_YHitCheck,
|
||||
S_WaitResponse_YHitCheck,
|
||||
S_Dispatch_CalcPipeline
|
||||
);
|
||||
signal R_State : T_State := S_Ready;
|
||||
signal C_NextState : T_State := S_Ready;
|
||||
|
||||
signal C_OP_Data_WE : std_logic := '0';
|
||||
signal R_OP_Data : std_logic_vector(G_OPCodeData_Width - 1 downto 0) := (others => '0');
|
||||
begin
|
||||
O_OP_Ready <= C_OP_Ready;
|
||||
|
||||
P_RegisterNewLineReq : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_CE = '1' then
|
||||
if I_RST = '1' then
|
||||
R_OP_Data <= (others => '0');
|
||||
elsif C_OP_Data_WE = '1' then
|
||||
R_OP_Data <= I_OP_Data;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
P_StateForwarding : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_CE = '1' then
|
||||
if I_RST = '1' then
|
||||
R_State <= S_Ready;
|
||||
else
|
||||
R_State <= C_NextState;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
P_StateMachine : process (
|
||||
R_State, I_OP_Code, R_OP_Data, I_OP_Valid,
|
||||
I_YHitCheck_Ready, I_YHitCheck_Valid, I_YHitCheck_IsVisible, I_YHitCheck_Offset,
|
||||
I_HSpritePipeline_Ready, I_OP_Data, I_IsVisible
|
||||
)
|
||||
begin
|
||||
-- Default the next state to the current state
|
||||
C_NextState <= R_State;
|
||||
|
||||
-- Default the output signals to prevent latches
|
||||
O_Register_Index_WE <= '0';
|
||||
O_Register_Index <= (others => '0');
|
||||
O_Register_X_We <= '0';
|
||||
O_Register_X <= (others => '0');
|
||||
O_Register_Y_WE <= '0';
|
||||
O_Register_Y <= (others => '0');
|
||||
O_Register_Offset_WE <= '0';
|
||||
O_Register_Offset <= (others => '0');
|
||||
O_IsVisible_WE <= '0';
|
||||
O_IsVisible <= '0';
|
||||
O_YHitCheck_Valid <= '0';
|
||||
O_YHitCheck_Ready <= '0';
|
||||
O_YHitCheck_YToCheck <= (others => '0');
|
||||
C_OP_Ready <= '0';
|
||||
O_HSpritePipeline_Valid <= '0';
|
||||
O_HSpritePipeline_X_Request <= (others => '0');
|
||||
C_OP_Data_WE <= '0';
|
||||
|
||||
-- State Machine
|
||||
case R_State is
|
||||
when S_Ready =>
|
||||
C_OP_Ready <= '1';
|
||||
C_OP_Data_WE <= '1';
|
||||
|
||||
if I_OP_Valid = '1' then
|
||||
case I_OP_Code is
|
||||
when K_OP_NOP =>
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
when K_OP_NEWLINE =>
|
||||
O_IsVisible_WE <= '0';
|
||||
O_IsVisible <= '0';
|
||||
|
||||
C_NextState <= S_Dispatch_YHitCheck;
|
||||
|
||||
when K_OP_SET_ID =>
|
||||
O_Register_Index_WE <= '1';
|
||||
O_Register_Index <= I_OP_Data(G_Index_Width - 1 downto 0);
|
||||
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
when K_OP_SET_X =>
|
||||
O_Register_X_We <= '1';
|
||||
O_Register_X <= I_OP_Data(G_X_Width - 1 downto 0);
|
||||
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
when K_OP_SET_Y =>
|
||||
O_Register_Y_WE <= '1';
|
||||
O_Register_Y <= I_OP_Data(G_Y_Width - 1 downto 0);
|
||||
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
when K_OP_REQ_ROW_DATA =>
|
||||
if I_IsVisible = '1' then
|
||||
C_NextState <= S_Dispatch_CalcPipeline;
|
||||
end if;
|
||||
|
||||
when K_OP_CLEAR_ALL =>
|
||||
O_Register_Index_WE <= '1';
|
||||
O_Register_Index <= (others => '0');
|
||||
--
|
||||
O_Register_X_We <= '1';
|
||||
O_Register_X <= (others => '0');
|
||||
--
|
||||
O_Register_Y_WE <= '1';
|
||||
O_Register_Y <= (others => '0');
|
||||
--
|
||||
O_Register_Offset_WE <= '1';
|
||||
O_Register_Offset <= (others => '0');
|
||||
--
|
||||
O_IsVisible_WE <= '1';
|
||||
O_IsVisible <= '0';
|
||||
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
when others =>
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
|
||||
when S_Dispatch_YHitCheck =>
|
||||
O_YHitCheck_Valid <= '1';
|
||||
O_YHitCheck_YToCheck <= R_OP_Data(G_Y_Width - 1 downto 0);
|
||||
|
||||
if I_YHitCheck_Ready = '1' then
|
||||
C_NextState <= S_WaitResponse_YHitCheck;
|
||||
end if;
|
||||
|
||||
when S_WaitResponse_YHitCheck =>
|
||||
O_YHitCheck_Ready <= '1';
|
||||
|
||||
if I_YHitCheck_Valid = '1' then
|
||||
O_IsVisible_WE <= '1';
|
||||
O_IsVisible <= I_YHitCheck_IsVisible;
|
||||
|
||||
O_Register_Offset_WE <= '1';
|
||||
O_Register_Offset <= I_YHitCheck_Offset;
|
||||
|
||||
C_NextState <= S_Ready;
|
||||
|
||||
end if;
|
||||
|
||||
when S_Dispatch_CalcPipeline =>
|
||||
O_HSpritePipeline_Valid <= '1';
|
||||
O_HSpritePipeline_X_Request <= R_OP_Data(G_X_Width - 1 downto 0);
|
||||
|
||||
if I_HSpritePipeline_Ready = '1' then
|
||||
C_NextState <= S_Ready;
|
||||
end if;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
end architecture;
|
122
src/RegisterFile.vhd
Normal file
122
src/RegisterFile.vhd
Normal file
@@ -0,0 +1,122 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity RegisterFile is
|
||||
generic (
|
||||
--@ Width of the sprite index (Base address) register
|
||||
G_Index_Width : integer := 5;
|
||||
--@ Width of the sprite offset (Line address) register
|
||||
G_Offset_Width : integer := 8;
|
||||
--@ 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 signal; (**Rising edge** triggered)
|
||||
I_CLK : in std_logic;
|
||||
--@ Clock enable signal (**Active high**)
|
||||
I_CE : in std_logic := '1';
|
||||
--@ Synchronous reset signal (**Active high**)
|
||||
I_RST : in std_logic := '0';
|
||||
|
||||
--@ @virtualbus Register-Write @dir in Bus to write to the register file
|
||||
--@ Write enable for the sprite index register; (**Active high**)
|
||||
I_Index_WE : in std_logic := '0';
|
||||
--@ Data to write to the sprite index (Base address) register.
|
||||
I_Index : in std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the sprite offset (line) register; (**Active high**)
|
||||
I_Offset_WE : in std_logic := '0';
|
||||
--@ Data to write to the sprite offset (Line address) register.
|
||||
I_Offset : in std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the X position register. (**Active high**)
|
||||
I_X_We : in std_logic := '0';
|
||||
--@ Data to write to the X position register (Row) of the sprite.
|
||||
I_X : in std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the Y position register. (**Active high**)
|
||||
I_Y_WE : in std_logic := '0';
|
||||
--@ Data to write to the Y position register (Line) of the sprite.
|
||||
I_Y : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ Write enable for the `IsVisible` flag. (**Active high**)
|
||||
I_IsVisible_WE : in std_logic := '0';
|
||||
--@ Flag to write to the `IsVisible` flag.
|
||||
I_IsVisible : in std_logic := '0';
|
||||
|
||||
--@ @virtualbus Register-Read @dir out Bus to read from the register file
|
||||
--@ Sprite index (Base address) of the sprite.
|
||||
O_Index : out std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
|
||||
--@ Sprite offset (Line address) of the sprite.
|
||||
O_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
--@ X position of the sprite.
|
||||
O_X : out std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
--@ Y position of the sprite.
|
||||
O_Y : out std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ Flag to indicate if the sprite line is valid; (**Active high**)
|
||||
O_IsVisible : out std_logic := '0'
|
||||
--@ @end
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture RTL of RegisterFile is
|
||||
--@ Register for the sprite index (Base address).
|
||||
signal R_Index : std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
|
||||
--@ Register for the sprite offset (Line address).
|
||||
signal R_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
--@ Register for the X position (Row) of the sprite.
|
||||
signal R_X : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
--@ Register for the Y position (Line) of the sprite.
|
||||
signal R_Y : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ Register for the `IsVisible` flag.
|
||||
signal R_IsVisible : std_logic := '0';
|
||||
begin
|
||||
|
||||
--@ Register file process
|
||||
P_RegisterFile : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_RST = '1' then
|
||||
R_Index <= (others => '0');
|
||||
R_Offset <= (others => '0');
|
||||
R_X <= (others => '0');
|
||||
R_Y <= (others => '0');
|
||||
R_IsVisible <= '0';
|
||||
elsif I_CE = '1' then
|
||||
if I_Index_WE = '1' then
|
||||
R_Index <= I_Index;
|
||||
end if;
|
||||
|
||||
if I_Offset_WE = '1' then
|
||||
R_Offset <= I_Offset;
|
||||
end if;
|
||||
|
||||
if I_X_We = '1' then
|
||||
R_X <= I_X;
|
||||
end if;
|
||||
|
||||
if I_Y_WE = '1' then
|
||||
R_Y <= I_Y;
|
||||
end if;
|
||||
|
||||
if I_IsVisible_WE = '1' then
|
||||
R_IsVisible <= I_IsVisible;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--@ Forwarding the register values to the output
|
||||
P_Forwarding : process (
|
||||
R_Index, R_Offset, R_X, R_Y,
|
||||
R_IsVisible
|
||||
)
|
||||
begin
|
||||
O_Index <= R_Index;
|
||||
O_Offset <= R_Offset;
|
||||
O_X <= R_X;
|
||||
O_Y <= R_Y;
|
||||
O_IsVisible <= R_IsVisible;
|
||||
end process;
|
||||
|
||||
end architecture;
|
8322
src/RomPackage.vhd
Normal file
8322
src/RomPackage.vhd
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,144 +0,0 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity AXI_Handshaking_Scheduler_4 is
|
||||
generic (
|
||||
G_DataWidth : integer := 32
|
||||
);
|
||||
port (
|
||||
--@ Clock signal; (**Rising edge** triggered)
|
||||
I_CLK : in std_logic;
|
||||
--@ Clock enable signal (**Active high**)
|
||||
I_CE : in std_logic;
|
||||
--@ Synchronous reset signal (**Active high**)
|
||||
I_RST : in std_logic;
|
||||
|
||||
--@ @virtualbus P0 @dir in P0 interface
|
||||
I_P0_Valid : in std_logic := '0';
|
||||
O_P0_Ready : out std_logic := '0';
|
||||
I_P0_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
--@ @virtualbus P1 @dir in P1 interface
|
||||
I_P1_Valid : in std_logic := '0';
|
||||
O_P1_Ready : out std_logic := '0';
|
||||
I_P1_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
--@ @virtualbus P2 @dir in P2 interface
|
||||
I_P2_Valid : in std_logic := '0';
|
||||
O_P2_Ready : out std_logic := '0';
|
||||
I_P2_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
--@ @virtualbus P3 @dir in P3 interface
|
||||
I_P3_Valid : in std_logic := '0';
|
||||
O_P3_Ready : out std_logic := '0';
|
||||
I_P3_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus Out @dir out Output interface
|
||||
O_Out_Valid : out std_logic := '0';
|
||||
I_Out_Ready : in std_logic := '0';
|
||||
O_Out_Data : out std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
|
||||
O_Out_Address : out std_logic_vector(1 downto 0) := (others => '0')
|
||||
--@ @end
|
||||
|
||||
);
|
||||
end entity AXI_Handshaking_Scheduler_4;
|
||||
|
||||
architecture Rtl of AXI_Handshaking_Scheduler_4 is
|
||||
signal R_Counter : unsigned(1 downto 0) := (others => '0');
|
||||
|
||||
signal C_Select : std_logic_vector(3 downto 0) := (others => '0');
|
||||
signal C_Code : std_logic_vector(1 downto 0) := (others => '0');
|
||||
signal C_CodeReverse : std_logic_vector(1 downto 0) := (others => '0');
|
||||
begin
|
||||
|
||||
i_PriorityEncoder_4 : entity work.PriorityEncoder_4
|
||||
port map(
|
||||
I_Select => C_Select,
|
||||
O_Code => C_Code
|
||||
);
|
||||
|
||||
P_SelectMux : process (R_Counter, I_P0_Valid, I_P1_Valid, I_P2_Valid, I_P3_Valid)
|
||||
begin
|
||||
if R_Counter = "00" then
|
||||
C_Select <= I_P0_Valid & I_P1_Valid & I_P2_Valid & I_P3_Valid;
|
||||
elsif R_Counter = "01" then
|
||||
C_Select <= I_P1_Valid & I_P2_Valid & I_P3_Valid & I_P0_Valid;
|
||||
elsif R_Counter = "10" then
|
||||
C_Select <= I_P2_Valid & I_P3_Valid & I_P0_Valid & I_P1_Valid;
|
||||
elsif R_Counter = "11" then
|
||||
C_Select <= I_P3_Valid & I_P0_Valid & I_P1_Valid & I_P2_Valid;
|
||||
else
|
||||
C_Select <= (others => '-');
|
||||
end if;
|
||||
end process;
|
||||
|
||||
P_CodeReverse : process (C_Code, R_Counter)
|
||||
begin
|
||||
C_CodeReverse <= std_logic_vector(unsigned(C_Code) + R_Counter);
|
||||
end process;
|
||||
|
||||
P_OutMux : process (
|
||||
C_CodeReverse, I_P0_Data, I_P1_Data, I_P2_Data, I_P3_Data,
|
||||
I_P0_Valid, I_P1_Valid, I_P2_Valid, I_P3_Valid,
|
||||
I_Out_Ready)
|
||||
begin
|
||||
O_Out_Valid <= '0';
|
||||
O_P0_Ready <= '0';
|
||||
O_P1_Ready <= '0';
|
||||
O_P2_Ready <= '0';
|
||||
O_P3_Ready <= '0';
|
||||
O_Out_Data <= (others => '0');
|
||||
O_Out_Address <= C_CodeReverse;
|
||||
|
||||
case C_CodeReverse is
|
||||
when "00" =>
|
||||
O_Out_Valid <= I_P0_Valid;
|
||||
O_P0_Ready <= I_Out_Ready;
|
||||
O_Out_Data <= I_P0_Data;
|
||||
when "01" =>
|
||||
O_Out_Valid <= I_P1_Valid;
|
||||
O_P1_Ready <= I_Out_Ready;
|
||||
O_Out_Data <= I_P1_Data;
|
||||
when "10" =>
|
||||
O_Out_Valid <= I_P2_Valid;
|
||||
O_P2_Ready <= I_Out_Ready;
|
||||
O_Out_Data <= I_P2_Data;
|
||||
when "11" =>
|
||||
O_Out_Valid <= I_P3_Valid;
|
||||
O_P3_Ready <= I_Out_Ready;
|
||||
O_Out_Data <= I_P3_Data;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
P_Counter : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_CE = '1' then
|
||||
if I_RST = '1' then
|
||||
R_Counter <= (others => '0');
|
||||
else
|
||||
if I_Out_Ready = '1' then
|
||||
|
||||
case C_CodeReverse is
|
||||
when "00" =>
|
||||
R_Counter <= "01";
|
||||
when "01" =>
|
||||
R_Counter <= "10";
|
||||
when "10" =>
|
||||
R_Counter <= "11";
|
||||
when "11" =>
|
||||
R_Counter <= "00";
|
||||
when others =>
|
||||
R_Counter <= "00";
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process P_Counter;
|
||||
end architecture;
|
5
src/SpriteChannel.ucf
Normal file
5
src/SpriteChannel.ucf
Normal file
@@ -0,0 +1,5 @@
|
||||
# TEMPERATURE = 50 C;
|
||||
|
||||
NET I_CLK LOC = B8;
|
||||
NET I_CLK TNM_NET = CLOCK;
|
||||
TIMESPEC TS_CLOCK = PERIOD CLOCK 230 MHz HIGH 50 %;
|
232
src/SpriteChannel.vhd
Normal file
232
src/SpriteChannel.vhd
Normal file
@@ -0,0 +1,232 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity SpriteChannel is
|
||||
generic (
|
||||
--@ Data width of the operation data.
|
||||
G_OPCodeData_Width : integer := 10;
|
||||
--@ Width of the sprite index (Base address) register
|
||||
G_Index_Width : integer := 5;
|
||||
--@ Width of the sprite offset (Line address) register
|
||||
G_Offset_Width : integer := 8;
|
||||
--@ Width of the X position (Row) register
|
||||
G_X_Width : integer := 10;
|
||||
--@ Width of the Y position (Line) register
|
||||
G_Y_Width : integer := 10;
|
||||
--@ The height of the sprite in pixels
|
||||
G_Sprite_Height : integer := 16;
|
||||
--@ The width of the sprite in pixels
|
||||
G_Sprite_Width : integer := 16
|
||||
);
|
||||
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;
|
||||
|
||||
--@ @virtualbus Operation-Write @dir in Operation Write Interface
|
||||
--@ Indicates if the `OPCode` and `OPData` are valid. (**Active high**)
|
||||
I_OP_Valid : in std_logic := '0';
|
||||
--@ Indicates if the decoder is ready to accept data. (**Active high**)
|
||||
O_OP_Ready : out std_logic := '0';
|
||||
--@ Operation code for the sprite channel
|
||||
I_OP_Code : in std_logic_vector(3 downto 0) := (others => '0');
|
||||
--@ Data to be used with the operation code.
|
||||
I_OP_Data : in std_logic_vector(G_OPCodeData_Width - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus Pixel-Data @dir Out Pixel data output bus
|
||||
--@ AXI like valid; (**Synchronous**, **Active high**)
|
||||
O_Pixel_Valid : out std_logic;
|
||||
--@ AXI like ready; (**Synchronous**, **Active high**)
|
||||
I_Pixel_Ready : in std_logic;
|
||||
--@ Pixel data
|
||||
O_Pixel_Data : out std_logic_vector(7 downto 0)
|
||||
--@ @end
|
||||
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture RTL of SpriteChannel is
|
||||
signal R_Index : std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
|
||||
signal R_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
signal R_X : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
signal R_Y : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
signal R_IsVisible : std_logic := '0';
|
||||
|
||||
signal OI_P0_Address_Valid : std_logic := '0';
|
||||
signal IO_P0_Address_Ready : std_logic := '0';
|
||||
signal OI_P0_Address : std_logic_vector(G_Index_Width + G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
|
||||
signal IO_P0_Data_Valid : std_logic := '0';
|
||||
signal OI_P0_Data_Ready : std_logic := '0';
|
||||
signal IO_P0_Data : std_logic_vector(7 downto 0) := (others => '0');
|
||||
|
||||
signal OI_Register_Index_WE : std_logic := '0';
|
||||
signal OI_Register_Index : std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
|
||||
signal OI_Register_Offset_WE : std_logic := '0';
|
||||
signal OI_Register_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
signal OI_Register_X_We : std_logic := '0';
|
||||
signal OI_Register_X : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
signal OI_Register_Y_WE : std_logic := '0';
|
||||
signal OI_Register_Y : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
signal OI_IsVisible_WE : std_logic := '0';
|
||||
signal OI_IsVisible : std_logic := '0';
|
||||
|
||||
signal I_YHitCheck_Ready : std_logic := '0';
|
||||
signal I_YHitCheck_Valid : std_logic := '0';
|
||||
signal I_YHitCheck_IsVisible : std_logic := '0';
|
||||
signal I_YHitCheck_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
signal O_YHitCheck_Valid : std_logic := '0';
|
||||
signal O_YHitCheck_YToCheck : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
signal O_YHitCheck_Ready : std_logic := '0';
|
||||
|
||||
signal OI_CalcPipeline_Valid : std_logic := '0';
|
||||
signal IO_CalcPipeline_Ready : std_logic := '0';
|
||||
signal OI_CalcPipeline_X_Request : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
|
||||
begin
|
||||
i_RegisterFile : entity work.RegisterFile
|
||||
generic map(
|
||||
G_Index_Width => G_Index_Width,
|
||||
G_Offset_Width => G_Offset_Width,
|
||||
G_X_Width => G_X_Width,
|
||||
G_Y_Width => G_Y_Width
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
I_RST => I_RST,
|
||||
I_Index_WE => OI_Register_Index_WE,
|
||||
I_Index => OI_Register_Index,
|
||||
I_Offset_WE => OI_Register_Offset_WE,
|
||||
I_Offset => OI_Register_Offset,
|
||||
I_X_We => OI_Register_X_We,
|
||||
I_X => OI_Register_X,
|
||||
I_Y_WE => OI_Register_Y_WE,
|
||||
I_Y => OI_Register_Y,
|
||||
I_IsVisible_WE => OI_IsVisible_WE,
|
||||
I_IsVisible => OI_IsVisible,
|
||||
O_Index => R_Index,
|
||||
O_Offset => R_Offset,
|
||||
O_X => R_X,
|
||||
O_Y => R_Y,
|
||||
O_IsVisible => R_IsVisible
|
||||
);
|
||||
|
||||
i_OPDecoder : entity work.OPDecoder
|
||||
generic map(
|
||||
G_OPCodeData_Width => G_OPCodeData_Width,
|
||||
G_Index_Width => G_Index_Width,
|
||||
G_Offset_Width => G_Offset_Width,
|
||||
G_X_Width => G_X_Width,
|
||||
G_Y_Width => G_Y_Width
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
I_RST => I_RST,
|
||||
I_OP_Valid => I_OP_Valid,
|
||||
O_OP_Ready => O_OP_Ready,
|
||||
I_OP_Code => I_OP_Code,
|
||||
I_OP_Data => I_OP_Data,
|
||||
O_Register_Index_WE => OI_Register_Index_WE,
|
||||
O_Register_Index => OI_Register_Index,
|
||||
O_Register_Offset_WE => OI_Register_Offset_WE,
|
||||
O_Register_Offset => OI_Register_Offset,
|
||||
O_Register_X_We => OI_Register_X_We,
|
||||
O_Register_X => OI_Register_X,
|
||||
O_Register_Y_WE => OI_Register_Y_WE,
|
||||
O_Register_Y => OI_Register_Y,
|
||||
O_IsVisible_WE => OI_IsVisible_WE,
|
||||
O_IsVisible => OI_IsVisible,
|
||||
|
||||
I_IsVisible => R_IsVisible,
|
||||
|
||||
I_YHitCheck_Ready => I_YHitCheck_Ready,
|
||||
O_YHitCheck_Valid => O_YHitCheck_Valid,
|
||||
O_YHitCheck_YToCheck => O_YHitCheck_YToCheck,
|
||||
O_YHitCheck_Ready => O_YHitCheck_Ready,
|
||||
I_YHitCheck_Valid => I_YHitCheck_Valid,
|
||||
I_YHitCheck_IsVisible => I_YHitCheck_IsVisible,
|
||||
I_YHitCheck_Offset => I_YHitCheck_Offset,
|
||||
|
||||
O_HSpritePipeline_Valid => OI_CalcPipeline_Valid,
|
||||
I_HSpritePipeline_Ready => IO_CalcPipeline_Ready,
|
||||
O_HSpritePipeline_X_Request => OI_CalcPipeline_X_Request
|
||||
);
|
||||
|
||||
i_YHitCheck : entity work.VerticalSpritePipeline
|
||||
generic map(
|
||||
G_Y_Width => G_Y_Width,
|
||||
G_Sprite_Height => G_Sprite_Height,
|
||||
G_Offset_Width => G_Offset_Width,
|
||||
G_PipelineStages => 2
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
O_Ready => I_YHitCheck_Ready,
|
||||
I_Valid => O_YHitCheck_Valid,
|
||||
I_YToCheck => O_YHitCheck_YToCheck,
|
||||
I_Y => R_Y,
|
||||
I_Ready => O_YHitCheck_Ready,
|
||||
O_Valid => I_YHitCheck_Valid,
|
||||
O_IsVisible => I_YHitCheck_IsVisible,
|
||||
O_Offset => I_YHitCheck_Offset
|
||||
);
|
||||
|
||||
i_Rom : entity work.Rom
|
||||
generic map(
|
||||
G_Address_Width => 13,
|
||||
G_Data_Width => 8,
|
||||
G_P0_BufferStages => 1,
|
||||
G_P0_ID_Width => 0,
|
||||
G_P1_BufferStages => 0,
|
||||
G_P1_ID_Width => 0,
|
||||
G_RomType => "Block"
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
I_P0_Address_Valid => OI_P0_Address_Valid,
|
||||
O_P0_Address_Ready => IO_P0_Address_Ready,
|
||||
I_P0_Address => OI_P0_Address,
|
||||
O_P0_Data_Valid => IO_P0_Data_Valid,
|
||||
I_P0_Data_Ready => OI_P0_Data_Ready,
|
||||
O_P0_Data => IO_P0_Data
|
||||
);
|
||||
|
||||
i_CalcPipeline : entity work.HorizontalSpritePipeline
|
||||
generic map(
|
||||
G_Index_Width => G_Index_Width,
|
||||
G_Offset_Width => G_Offset_Width,
|
||||
G_X_Width => G_X_Width,
|
||||
G_Rom_Width => 8,
|
||||
G_Pixel_Width => 8
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
I_RST => I_RST,
|
||||
I_OP_Valid => OI_CalcPipeline_Valid,
|
||||
O_OP_Ready => IO_CalcPipeline_Ready,
|
||||
I_OP_X_Request => OI_CalcPipeline_X_Request,
|
||||
I_OP_Index => R_Index,
|
||||
I_OP_Offset => R_Offset,
|
||||
I_OP_X_Sprite => R_X,
|
||||
O_Rom_Valid => OI_P0_Address_Valid,
|
||||
I_Rom_Ready => IO_P0_Address_Ready,
|
||||
O_Rom_Address => OI_P0_Address,
|
||||
I_Rom_Valid => IO_P0_Data_Valid,
|
||||
O_Rom_Ready => OI_P0_Data_Ready,
|
||||
I_Rom_Data => IO_P0_Data,
|
||||
O_Pixel_Valid => O_Pixel_Valid,
|
||||
I_Pixel_Ready => I_Pixel_Ready,
|
||||
O_Pixel_Data => O_Pixel_Data
|
||||
);
|
||||
|
||||
end architecture RTL;
|
162
src/VerticalSpritePipeline.vhd
Normal file
162
src/VerticalSpritePipeline.vhd
Normal file
@@ -0,0 +1,162 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
use work.SpriteRom.all;
|
||||
|
||||
entity VerticalSpritePipeline is
|
||||
generic (
|
||||
--@ Width of the Y position (Line) register
|
||||
G_Y_Width : integer := 10;
|
||||
--@ The height of the sprite in pixels
|
||||
G_Sprite_Height : integer := 16;
|
||||
--@ Width of the sprite offset (Line address) register
|
||||
G_Offset_Width : integer := 8;
|
||||
--@ The pipeline stages for the calculating pipeline (multiply by 2 for the the latency of the pipeline)
|
||||
G_PipelineStages : integer := 2
|
||||
);
|
||||
port (
|
||||
--@ Clock signal; (**Rising edge** triggered)
|
||||
I_CLK : in std_logic := '0';
|
||||
--@ Clock enable signal (**Active high**)
|
||||
I_CE : in std_logic := '1';
|
||||
|
||||
--@ @virtualbus YHitCheck-Input-Interface @dir in YHitCheck Input Interface
|
||||
--@ Indicates if the pipeline is ready to accept data. (**Active high**)
|
||||
O_Ready : out std_logic := '0';
|
||||
--@ Indicates if the pipeline is valid. (**Active high**)
|
||||
I_Valid : in std_logic := '0';
|
||||
--@ The line to check if the sprite is in the line visible.
|
||||
I_YToCheck : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ The sprite Y position to check if the sprite is in the line visible.
|
||||
I_Y : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus YHitCheck-Output-Interface @dir out YHitCheck Output Interface
|
||||
--@ Indicates if the pipeline is ready to deliver data. (**Active high**)
|
||||
I_Ready : in std_logic := '0';
|
||||
--@ Indicates if `O_IsVisible` is valid. (**Active high**)
|
||||
O_Valid : out std_logic := '0';
|
||||
--@ Indicates if the sprite is visible in the line.
|
||||
O_IsVisible : out std_logic := '0';
|
||||
--@ The calculated offset address of the sprite.
|
||||
O_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0')
|
||||
--@ @end
|
||||
);
|
||||
end entity VerticalSpritePipeline;
|
||||
|
||||
architecture Rtl of VerticalSpritePipeline is
|
||||
--@ Line to check if the sprite is in the line visible
|
||||
signal R_YToCheck : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
--@ The sprite Y position to check if the sprite is in the line visible
|
||||
signal R_SpriteY : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0');
|
||||
|
||||
--@ Calculated visibility signal
|
||||
signal C_IsVisible : std_logic := '0';
|
||||
--@ The calculated offset address of the sprite
|
||||
signal C_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
|
||||
|
||||
--@ Pipeline enable signal
|
||||
signal S_CalculatingPipeline_Enable : std_logic := '0';
|
||||
begin
|
||||
|
||||
--@ Pipeline controller for the calculating pipeline
|
||||
I_CalculatingPipelineCtrl : entity work.PipelineController
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages * 2
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
O_Enable => S_CalculatingPipeline_Enable,
|
||||
I_Valid => I_Valid,
|
||||
O_Ready => O_Ready,
|
||||
O_Valid => O_Valid,
|
||||
I_Ready => I_Ready
|
||||
);
|
||||
|
||||
--@ Input register for the Y position of the sprite
|
||||
I_Y_InputRegister : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_Y_Width,
|
||||
G_RegisterBalancing => "forward"
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_CalculatingPipeline_Enable,
|
||||
I_Data => I_Y,
|
||||
O_Data => R_SpriteY
|
||||
);
|
||||
|
||||
--@ Input register for the line to check if the sprite is in the line visible
|
||||
I_YToCheck_InputRegister : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_Y_Width,
|
||||
G_RegisterBalancing => "forward"
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_CalculatingPipeline_Enable,
|
||||
I_Data => I_YToCheck,
|
||||
O_Data => R_YToCheck
|
||||
);
|
||||
|
||||
--@ Combinatory process to calculate the visibility and offset of the sprite.
|
||||
P_CalculateVisibility : process (R_SpriteY, R_YToCheck)
|
||||
variable V_SpriteY : unsigned(R_SpriteY'range);
|
||||
variable V_YToCheck : unsigned(R_YToCheck'range);
|
||||
variable V_SpriteYBottom : unsigned(R_SpriteY'range);
|
||||
variable V_OffsetLine : integer;
|
||||
variable V_Offset : unsigned(C_Offset'range);
|
||||
begin
|
||||
V_SpriteY := unsigned(R_SpriteY);
|
||||
V_YToCheck := unsigned(R_YToCheck);
|
||||
V_SpriteYBottom := V_SpriteY + to_unsigned(G_Sprite_Height - 1, R_SpriteY'length);
|
||||
|
||||
if V_YToCheck >= V_SpriteY and V_YToCheck <= V_SpriteYBottom then
|
||||
C_IsVisible <= '1';
|
||||
else
|
||||
C_IsVisible <= '0';
|
||||
end if;
|
||||
|
||||
V_OffsetLine := to_integer(V_YToCheck - V_SpriteY);
|
||||
-- pragma translate_off
|
||||
if V_OffsetLine < 0 or V_OffsetLine >= K_SPRITE_ROW_OFFSETS'length then
|
||||
V_OffsetLine := 0;
|
||||
end if;
|
||||
-- pragma translate_on
|
||||
|
||||
V_Offset := to_unsigned(K_SPRITE_ROW_OFFSETS(V_OffsetLine), C_Offset'length);
|
||||
C_Offset <= std_logic_vector(V_Offset);
|
||||
end process;
|
||||
|
||||
--@ Output register for the visibility of the sprite
|
||||
I_IsVisible_OutputRegister : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => 1,
|
||||
G_RegisterBalancing => "backward"
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_CalculatingPipeline_Enable,
|
||||
I_Data(0) => C_IsVisible,
|
||||
O_Data(0) => O_IsVisible
|
||||
);
|
||||
|
||||
--@ Output register for the offset of the sprite
|
||||
I_Offset_OutputRegister : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_Offset_Width,
|
||||
G_RegisterBalancing => "backward"
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_CalculatingPipeline_Enable,
|
||||
I_Data => C_Offset,
|
||||
O_Data => O_Offset
|
||||
);
|
||||
end architecture;
|
Reference in New Issue
Block a user