diff options
| author | lonkaars <loek@pipeframe.xyz> | 2023-02-20 17:13:06 +0100 | 
|---|---|---|
| committer | lonkaars <loek@pipeframe.xyz> | 2023-02-20 17:13:06 +0100 | 
| commit | 27b39499095ccb7e7e73a78776946b60fc96fb05 (patch) | |
| tree | 039075a83d876eb77d14709bca701b01520d2723 /basys3 | |
| parent | 29108f38c5f885412b0a75ae46b85720946cfdb5 (diff) | |
PPU background sprite component done (but unverified)
Diffstat (limited to 'basys3')
| -rw-r--r-- | basys3/basys3.srcs/ppu_consts.vhd | 4 | ||||
| -rw-r--r-- | basys3/basys3.srcs/ppu_sprite_bg.vhd | 150 | ||||
| -rw-r--r-- | basys3/basys3.srcs/ppu_sprite_bg_tb.vhd | 86 | ||||
| -rw-r--r-- | basys3/basys3.srcs/ppu_sprite_transform.vhd | 24 | ||||
| -rw-r--r-- | basys3/basys3.xpr | 16 | 
5 files changed, 277 insertions, 3 deletions
| diff --git a/basys3/basys3.srcs/ppu_consts.vhd b/basys3/basys3.srcs/ppu_consts.vhd index f4d428e..89b7a7a 100644 --- a/basys3/basys3.srcs/ppu_consts.vhd +++ b/basys3/basys3.srcs/ppu_consts.vhd @@ -21,12 +21,14 @@ package ppu_consts is  	constant PPU_POS_V_WIDTH : natural := 8; -- amount of bits for vertical screen offset  	constant PPU_SPRITE_WIDTH : natural := 16; -- sprite width (pixels)  	constant PPU_SPRITE_HEIGHT : natural := 16; -- sprite height (pixels) +	constant PPU_SPRITE_POS_H_WIDTH: natural := 4; -- bits needed to identify horizontal pixel within sprite +	constant PPU_SPRITE_POS_V_WIDTH: natural := 4; -- bits needed to identify vertical pixel within sprite  	constant PPU_SCREEN_WIDTH : natural := 320; -- absolute screen width (pixels)  	constant PPU_SCREEN_HEIGHT : natural := 240; -- absolute screen height (pixels)  	constant PPU_BG_CANVAS_TILES_H : natural := 40; -- amount of tiles (horizontally) on background canvas  	constant PPU_BG_CANVAS_TILES_V : natural := 30; -- amount of tiles (vertically) on background canvas  	constant PPU_TILE_INDEX_WIDTH : natural := 10; -- amount of bits needed to index a tile from TMM memory  	constant PPU_PIXELS_PER_TILE_WORD : natural := 5; -- amount of pixels defined in one word in TMM memory -	constant PPU_TILE_SIZE : natural := 48; +	constant PPU_SPRITE_PIXELS_PER_WORD : natural := 52; -- amount of words needed for a single sprite  end package ppu_consts; diff --git a/basys3/basys3.srcs/ppu_sprite_bg.vhd b/basys3/basys3.srcs/ppu_sprite_bg.vhd new file mode 100644 index 0000000..a92c401 --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_bg.vhd @@ -0,0 +1,150 @@ +library ieee; +library work; + +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.ppu_consts.all; + +entity ppu_sprite_bg is port( +	-- inputs +	CLK : in std_logic; -- pipeline clock +	RESET : in std_logic; -- reset clock counter +	OE : in std_logic; -- output enable (of CIDX) +	X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x +	Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y +	 +	-- aux inputs +	BG_SHIFT_X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +	BG_SHIFT_Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); + +	-- used memory blocks +	BAM_ADDR : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	BAM_DATA : in std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); +	TMM_ADDR : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	TMM_DATA : in std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); + +	-- outputs +	CIDX : out std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0)); -- output color +end ppu_sprite_bg; + +architecture Behavioral of ppu_sprite_bg is +	component ppu_sprite_transform port( +		XI : in std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile +		YI : in std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile +		FLIP_H, FLIP_V : in std_logic; -- flip sprite +		XO : out std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile +		YO : out std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0)); -- new pixel position relative to tile +	end component; + +	signal O_BAM_ADDR : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal I_BAM_DATA : std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); +	signal O_TMM_ADDR : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal I_TMM_DATA : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); + +	signal FLIP_H, FLIP_V : std_logic := '0'; +	signal TMM_IDX : std_logic_vector(PPU_TILE_INDEX_WIDTH-1 downto 0) := (others => '0'); + +	alias BAM_DATA_COL_IDX is I_BAM_DATA(12 downto 10); +	signal TMM_DATA_PAL_IDX : std_logic_vector(PPU_PALETTE_COLOR_WIDTH-1 downto 0); +	signal O_CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0) := (others => '0'); + +	type states is (PL_BAM_ADDR, PL_BAM_DATA, PL_TMM_ADDR, PL_TMM_DATA); +	signal state, next_state : states := PL_BAM_ADDR; + +	-- docs/architecture.md#background-attribute-memory +	alias BAM_DATA_FLIP_H is I_BAM_DATA(14); +	alias BAM_DATA_FLIP_V is I_BAM_DATA(13); +	alias BAM_DATA_TILE_IDX is I_BAM_DATA(9 downto 0); + +	signal PIXEL_ABS_X, PIXEL_ABS_Y : integer := 0; -- absolute pixel position (relative to BG canvas instead of viewport) +	signal TILE_IDX_X, TILE_IDX_Y : integer := 0; -- background canvas tile grid xy +	signal TILE_PIXEL_IDX_X, TILE_PIXEL_IDX_Y : integer := 0; -- xy position of pixel within tile +	signal TILE_PIXEL_IDX : integer := 0; -- index of pixel within tile +	signal TRANS_TILE_PIDX_X, TRANS_TILE_PIDX_Y : integer := 0; -- transformed xy position of pixel within tile +	signal TILEMAP_WORD_OFFSET : integer := 0; +	signal TRANSFORM_XI, TRANSFORM_XO : std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); +	signal TRANSFORM_YI, TRANSFORM_YO : std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0); +	signal PIXEL_BIT_OFFSET : integer := 0; +begin +	-- CIDX tri-state driver +	CIDX <= O_CIDX when OE = '1' else (others => 'Z'); + +	-- internal line separators +	FLIP_H <= BAM_DATA_FLIP_H; +	FLIP_V <= BAM_DATA_FLIP_V; +	O_CIDX <= BAM_DATA_COL_IDX & TMM_DATA_PAL_IDX; + +	-- BAM ADDR +	PIXEL_ABS_X <= to_integer(unsigned(X)) + to_integer(unsigned(BG_SHIFT_X)); +	PIXEL_ABS_Y <= to_integer(unsigned(Y)) + to_integer(unsigned(BG_SHIFT_Y)); +	TILE_IDX_X <= PIXEL_ABS_X / 16; +	TILE_IDX_Y <= PIXEL_ABS_Y / 16; +	TILE_PIXEL_IDX_X <= PIXEL_ABS_X - TILE_IDX_X * 16; +	TILE_PIXEL_IDX_Y <= PIXEL_ABS_Y - TILE_IDX_Y * 16; +	O_BAM_ADDR <= std_logic_vector(to_unsigned((TILE_IDX_Y * integer(PPU_BG_CANVAS_TILES_H)) + TILE_IDX_X, PPU_BAM_ADDR_WIDTH)); + +	-- BAM DATA + FAM ADDR +	TRANSFORM_XI <= std_logic_vector(to_unsigned(TILE_PIXEL_IDX_X, PPU_SPRITE_POS_H_WIDTH)); +	TRANSFORM_YI <= std_logic_vector(to_unsigned(TILE_PIXEL_IDX_Y, PPU_SPRITE_POS_V_WIDTH)); +	transform: component ppu_sprite_transform port map( +		XI => TRANSFORM_XI, +		YI => TRANSFORM_YI, +		FLIP_H => FLIP_H, +		FLIP_V => FLIP_V, +		XO => TRANSFORM_XO, +		YO => TRANSFORM_YO); +	TRANS_TILE_PIDX_X <= to_integer(unsigned(TRANSFORM_XO)); +	TRANS_TILE_PIDX_Y <= to_integer(unsigned(TRANSFORM_YO)); + +	TILE_PIXEL_IDX <= integer(PPU_SPRITE_WIDTH) * TRANS_TILE_PIDX_Y + TRANS_TILE_PIDX_X; +	TILEMAP_WORD_OFFSET <= TILE_PIXEL_IDX / PPU_PIXELS_PER_TILE_WORD; +	PIXEL_BIT_OFFSET <= TILE_PIXEL_IDX mod PPU_PIXELS_PER_TILE_WORD; + +	O_TMM_ADDR <= std_logic_vector(to_unsigned(PPU_SPRITE_PIXELS_PER_WORD * to_integer(unsigned(BAM_DATA_TILE_IDX)) + TILEMAP_WORD_OFFSET, PPU_TMM_ADDR_WIDTH)); + +	-- TMM DATA +	with PIXEL_BIT_OFFSET select +		TMM_DATA_PAL_IDX <= TMM_DATA(2 downto 0) when 0, +		                    TMM_DATA(5 downto 3) when 1, +		                    TMM_DATA(8 downto 6) when 2, +		                    TMM_DATA(11 downto 9) when 3, +		                    TMM_DATA(14 downto 12) when 4, +		                    (others => '0') when others; + +	-- state machine (pipeline stage counter) +	fsm: process(CLK, RESET) +	begin +		if RESET = '1' then +			state <= PL_BAM_ADDR; +		elsif rising_edge(CLK) then +			state <= next_state; +		end if; +	end process; + +	-- sync read/write +	process(state) +	begin +		next_state <= state; +		case state is +			when PL_BAM_ADDR => +				next_state <= PL_BAM_DATA; +				BAM_ADDR <= O_BAM_ADDR; + +			when PL_BAM_DATA => +				next_state <= PL_TMM_ADDR; +				I_BAM_DATA <= BAM_DATA; +				 +			when PL_TMM_ADDR => +				next_state <= PL_TMM_DATA; +				TMM_ADDR <= O_TMM_ADDR; + +			when PL_TMM_DATA => +				next_state <= PL_BAM_ADDR; +				I_TMM_DATA <= TMM_DATA; + +				 +		end case; +	end process; + +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_sprite_bg_tb.vhd b/basys3/basys3.srcs/ppu_sprite_bg_tb.vhd new file mode 100644 index 0000000..2dee2fe --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_bg_tb.vhd @@ -0,0 +1,86 @@ +library ieee; +library work; +library unisim; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; +use work.ppu_consts.all; + +entity ppu_sprite_bg_tb is +end ppu_sprite_bg_tb; + +architecture Behavioral of ppu_sprite_bg_tb is +	component ppu_sprite_bg port( +		-- inputs +		CLK : in std_logic; -- pipeline clock +		RESET : in std_logic; -- reset clock counter +		OE : in std_logic; -- output enable (of CIDX) +		X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x +		Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y +		 +		-- aux inputs +		BG_SHIFT_X : in std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +		BG_SHIFT_Y : in std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); + +		-- used memory blocks +		BAM_ADDR : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +		BAM_DATA : in std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); +		TMM_ADDR : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +		TMM_DATA : in std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); + +		-- outputs +		CIDX : out std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0)); -- output color +	end component; +	signal CLK : std_logic := '0'; -- pipeline clock +	signal RESET : std_logic := '0'; -- reset clock counter +	signal OE : std_logic := '0'; -- output enable (of CIDX) +	signal X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); -- current screen pixel x +	signal Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); -- current screen pixel y +	signal BG_SHIFT_X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); +	signal BG_SHIFT_Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); +	signal BAM_ADDR : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	signal BAM_DATA : std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0) := (others => '0'); +	signal TMM_ADDR : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	signal TMM_DATA : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0) := (others => '0'); +	signal CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); -- output color +begin +	uut : ppu_sprite_bg port map( +		CLK => CLK, +		RESET => RESET, +		OE => OE, +		X => X, +		Y => Y, +		BG_SHIFT_X => BG_SHIFT_X, +		BG_SHIFT_Y => BG_SHIFT_Y, +		BAM_ADDR => BAM_ADDR, +		BAM_DATA => BAM_DATA, +		TMM_ADDR => TMM_ADDR, +		TMM_DATA => TMM_DATA, +		CIDX => CIDX); + +	BAM_DATA <= std_logic_vector(to_unsigned(16#4814#, PPU_BAM_DATA_WIDTH));  -- hex((1 << 14) | (0 << 13) | (2 << 10) | (20 << 0)) +	TMM_DATA <= std_logic_vector(to_unsigned(16#ffff#, PPU_TMM_DATA_WIDTH)); +	X <= std_logic_vector(to_unsigned(25, PPU_POS_H_WIDTH)); +	Y <= std_logic_vector(to_unsigned(60, PPU_POS_V_WIDTH)); +	BG_SHIFT_X <= std_logic_vector(to_unsigned(3, PPU_POS_H_WIDTH)); +	BG_SHIFT_Y <= std_logic_vector(to_unsigned(3, PPU_POS_V_WIDTH)); + +	tb : process +	begin +		for i in 0 to 32 loop +			if i > 10 then +				OE <= '1'; +			end if; +			if i > 20 then +				RESET <= '1'; +			end if; +	 +			wait for 5 ns; +			CLK <= '1'; +			wait for 5 ns; +			CLK <= '0'; +		end loop; +		wait; -- stop for simulator +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_sprite_transform.vhd b/basys3/basys3.srcs/ppu_sprite_transform.vhd new file mode 100644 index 0000000..d1b1a23 --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_transform.vhd @@ -0,0 +1,24 @@ +library ieee; +library work; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.ppu_consts.all; + +entity ppu_sprite_transform is port( -- flip sprites +	XI : in std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile +	YI : in std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile +	FLIP_H, FLIP_V : in std_logic; -- flip sprite +	XO : out std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile +	YO : out std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0)); -- new pixel position relative to tile +end ppu_sprite_transform; + +architecture Behavioral of ppu_sprite_transform is +	signal FLIPPED_X : std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); +	signal FLIPPED_Y : std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0); +begin +	FLIPPED_X <= std_logic_vector(to_unsigned(PPU_SPRITE_WIDTH-1 - to_integer(unsigned(XI)), PPU_SPRITE_POS_H_WIDTH)); +	FLIPPED_Y <= std_logic_vector(to_unsigned(PPU_SPRITE_HEIGHT-1 - to_integer(unsigned(YI)), PPU_SPRITE_POS_V_WIDTH)); + +	XO <= FLIPPED_X when FLIP_H = '1' else XI; +	YO <= FLIPPED_Y when FLIP_V = '1' else YI; +end Behavioral; diff --git a/basys3/basys3.xpr b/basys3/basys3.xpr index 8dcc698..556c73e 100644 --- a/basys3/basys3.xpr +++ b/basys3/basys3.xpr @@ -61,7 +61,7 @@      <Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/>      <Option Name="EnableBDX" Val="FALSE"/>      <Option Name="DSABoardId" Val="basys3"/> -    <Option Name="WTXSimLaunchSim" Val="27"/> +    <Option Name="WTXSimLaunchSim" Val="31"/>      <Option Name="WTModelSimLaunchSim" Val="0"/>      <Option Name="WTQuestaLaunchSim" Val="0"/>      <Option Name="WTIesLaunchSim" Val="0"/> @@ -154,6 +154,12 @@            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo>        </File> +      <File Path="$PSRCDIR/ppu_sprite_transform.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File>        <Config>          <Option Name="DesignMode" Val="RTL"/>          <Option Name="TopModule" Val="ppu_sprite_bg"/> @@ -205,9 +211,15 @@            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo>        </File> +      <File Path="$PSRCDIR/ppu_sprite_bg_tb.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File>        <Config>          <Option Name="DesignMode" Val="RTL"/> -        <Option Name="TopModule" Val="ppu_addr_dec_tb"/> +        <Option Name="TopModule" Val="ppu_sprite_bg_tb"/>          <Option Name="TopLib" Val="xil_defaultlib"/>          <Option Name="TransportPathDelay" Val="0"/>          <Option Name="TransportIntDelay" Val="0"/> |