diff options
| author | lonkaars <loek@pipeframe.xyz> | 2023-02-24 13:20:02 +0100 | 
|---|---|---|
| committer | lonkaars <loek@pipeframe.xyz> | 2023-02-24 13:20:02 +0100 | 
| commit | f3a47bde9bfaaa716de835c0c1499a685b4ac4f7 (patch) | |
| tree | 90abe28726ea7484184179129256022472eb2e24 /basys3 | |
| parent | 7da7908989686daa2ac9fd2f3f79cad2f03c0828 (diff) | |
| parent | 14a1c464c27206bff847fd46d3d5594b30f53af9 (diff) | |
Merge branch 'dev' into ppu-interface
Diffstat (limited to 'basys3')
34 files changed, 2076 insertions, 410 deletions
| diff --git a/basys3/basys3.srcs/apu.vhd b/basys3/basys3.srcs/apu.vhd index 4a594ab..1fff1e8 100644 --- a/basys3/basys3.srcs/apu.vhd +++ b/basys3/basys3.srcs/apu.vhd @@ -3,29 +3,29 @@ use ieee.std_logic_1164.all;  --use ieee.numeric_std.all;  entity apu is port( -	CLK100: in std_logic; -- system clock -	RESET: in std_logic; -- global (async) system reset -	DATA: in std_logic_vector(15 downto 0); -	SOUND: out std_logic); +	CLK100 : in std_logic; -- system clock +	RESET : in std_logic; -- global (async) system reset +	DATA : in std_logic_vector(15 downto 0); +	SOUND : out std_logic); -	-- EN: in std_logic; -- PPU VRAM enable (enable ADDR and DATA tri-state drivers) -	-- WEN: in std_logic; -- PPU VRAM write enable -	-- ADDR: in std_logic_vector(15 downto 0); -- PPU VRAM ADDR -	-- R,G,B: out std_logic_vector(3 downto 0); -	-- NVSYNC, NHSYNC: out std_logic; -- native VGA out -	-- TVSYNC, TVBLANK, THSYNC, THBLANK: out std_logic); -- tiny VGA out +	-- EN : in std_logic; -- PPU VRAM enable (enable ADDR and DATA tri-state drivers) +	-- WEN : in std_logic; -- PPU VRAM write enable +	-- ADDR : in std_logic_vector(15 downto 0); -- PPU VRAM ADDR +	-- R,G,B : out std_logic_vector(3 downto 0); +	-- NVSYNC, NHSYNC : out std_logic; -- native VGA out +	-- TVSYNC, TVBLANK, THSYNC, THBLANK : out std_logic); -- tiny VGA out  end apu;  architecture Behavioral of apu is  	component apu_note_to_frequency port( -		data: in std_logic_vector(7 downto 0); -		freq: out std_logic_vector(7 downto 0)); --frequency +		data : in std_logic_vector(7 downto 0); +		freq : out std_logic_vector(7 downto 0)); --frequency  	end component;  	component apu_LUT_reader port( -		clk: in std_logic; -		rst: in std_logic; -		wave: in std_logic_vector(1 downto 0); -		level: out std_logic_vector(7 downto 0)); +		clk : in std_logic; +		rst : in std_logic; +		wave : in std_logic_vector(1 downto 0); +		level : out std_logic_vector(7 downto 0));  	end component;  begin diff --git a/basys3/basys3.srcs/apu_LUT_reader.vhd b/basys3/basys3.srcs/apu_lut_reader.vhd index 6039798..2f92eca 100644 --- a/basys3/basys3.srcs/apu_LUT_reader.vhd +++ b/basys3/basys3.srcs/apu_lut_reader.vhd @@ -2,7 +2,7 @@ library ieee;  use ieee.std_logic_1164.all;  use ieee.numeric_std.all; -entity apu_LUT_reader is +entity apu_lut_reader is      port (          clk : in std_logic;          rst : in std_logic; @@ -12,7 +12,7 @@ entity apu_LUT_reader is      );  end entity; -architecture Behavioral of apu_LUT_reader is +architecture behavioral of apu_lut_reader is      constant AMPLITUDE : natural := 0;      constant SAMPLE_SIZE : natural := 256; diff --git a/basys3/basys3.srcs/apu_tb_LUT_reader.vhd b/basys3/basys3.srcs/apu_lut_reader_tb.vhd index 5a38d39..1b425bf 100644 --- a/basys3/basys3.srcs/apu_tb_LUT_reader.vhd +++ b/basys3/basys3.srcs/apu_lut_reader_tb.vhd @@ -2,14 +2,14 @@ library ieee;  use ieee.std_logic_1164.all;  use ieee.numeric_std.all; -library UNISIM; -use UNISIM.VComponents.all; +library unisim; +use unisim.vcomponents.all; -entity apu_tb_LUT_reader is +entity apu_lut_reader_tb is  end entity; -architecture Behavioral of apu_tb_LUT_reader is -    component apu_LUT_reader is +architecture Behavioral of apu_lut_reader_tb is +    component apu_lut_reader is          port (              clk   : in std_logic;              rst : in std_logic; diff --git a/basys3/basys3.srcs/apu_note_to_frequency.vhd b/basys3/basys3.srcs/apu_note_to_frequency.vhd index 8a7b3d6..810cef9 100644 --- a/basys3/basys3.srcs/apu_note_to_frequency.vhd +++ b/basys3/basys3.srcs/apu_note_to_frequency.vhd @@ -10,9 +10,9 @@ entity apu_note_to_frequency is port (  end entity;  architecture Behavioral of apu_note_to_frequency is -	signal buff_small: std_logic_vector(7 downto 0) := (others => '0'); -	signal buff: std_logic_vector(11 downto 0) := (others => '0'); -	signal shift: integer; +	signal buff_small : std_logic_vector(7 downto 0) := (others => '0'); +	signal buff : std_logic_vector(15 downto 0) := (others => '0'); +	signal shift : integer;  begin      shift <= to_integer(unsigned( data(2 downto 0) )); diff --git a/basys3/basys3.srcs/apu_note_to_frequency_tb.vhd b/basys3/basys3.srcs/apu_note_to_frequency_tb.vhd index 6814c1f..f48a40c 100644 --- a/basys3/basys3.srcs/apu_note_to_frequency_tb.vhd +++ b/basys3/basys3.srcs/apu_note_to_frequency_tb.vhd @@ -10,20 +10,20 @@ end entity;  architecture Behavioral of apu_note_to_frequency_tb is  	component apu_note_to_frequency is port( -		data: in std_logic_vector(7 downto 0); -		freq: out std_logic_vector(11 downto 0)); -- frequency +		data : in std_logic_vector(7 downto 0); +		freq : out std_logic_vector(11 downto 0)); -- frequency  	end component; -	signal data: std_logic_vector(7 downto 0) := (others => '0'); -	signal freq: std_logic_vector(11 downto 0) := (others => '0'); +	signal data : std_logic_vector(7 downto 0) := (others => '0'); +	signal freq : std_logic_vector(11 downto 0) := (others => '0'); -	signal ok: boolean := false; +	signal ok : boolean := false;  begin -	uut: apu_note_to_frequency port map( +	uut : apu_note_to_frequency port map(  		data => data,  		freq => freq); -	tb: process +	tb : process  	begin  		for i in 0 to 255 loop  			data <= std_logic_vector(to_unsigned(i, 8)); diff --git a/basys3/basys3.srcs/er_ram.vhd b/basys3/basys3.srcs/er_ram.vhd new file mode 100644 index 0000000..66f905b --- /dev/null +++ b/basys3/basys3.srcs/er_ram.vhd @@ -0,0 +1,53 @@ +library ieee; +library work; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity er_ram is -- exposed register RAM +	generic( +		ADDR_W : natural := 2; -- ADDR line width +		DATA_W : natural := 2; -- DATA line width +		ADDR_LOW : natural := 16#0000#; -- starting address +		ADDR_RANGE : natural := 16#0002#); -- amount of valid addresses after ADDR_LOW +	port( +		CLK : in std_logic; -- clock +		RST : in std_logic; -- async memory clear +		WEN : in std_logic; -- write enable +		ADDR : in std_logic_vector(ADDR_W-1 downto 0); -- address line +		DATA : in std_logic_vector(DATA_W-1 downto 0); -- data input +		REG : out std_logic_vector((ADDR_RANGE*DATA_W)-1 downto 0)); -- exposed register output +end er_ram; + +architecture Behavioral of er_ram is +	component er_ram_mod +		generic( +			W : natural := DATA_W; -- module data width +			ADDR_W : natural := ADDR_W; -- address width +			ADDR_M : std_logic_vector(ADDR_W-1 downto 0) := (others => '0')); -- address match +		port( +			CLK : in std_logic; -- clock +			RST : in std_logic; -- async memory clear +			WEN : in std_logic; -- write enable +			ADDR : in std_logic_vector(ADDR_W-1 downto 0); +			DATA : in std_logic_vector(W-1 downto 0); -- data +			REG : out std_logic_vector(W-1 downto 0)); -- direct register out +	end component; +	signal INT_REG : std_logic_vector((ADDR_RANGE*DATA_W)-1 downto 0); +begin +	REG <= INT_REG; + +	registers : for idx in 0 to ADDR_RANGE - 1 generate +		reg : component er_ram_mod +			generic map( +				W => DATA_W, +				ADDR_W => ADDR_W, +				ADDR_M => std_logic_vector(to_unsigned(ADDR_LOW + idx, ADDR_W))) +			port map( +				CLK => CLK, +				RST => RST, +				WEN => WEN, +				ADDR => ADDR, +				DATA => DATA, +				REG => INT_REG(idx*DATA_W+DATA_W-1 downto idx*DATA_W)); +	end generate; +end Behavioral; diff --git a/basys3/basys3.srcs/er_ram_mod.vhd b/basys3/basys3.srcs/er_ram_mod.vhd new file mode 100644 index 0000000..ae680b1 --- /dev/null +++ b/basys3/basys3.srcs/er_ram_mod.vhd @@ -0,0 +1,34 @@ +library ieee; +library work; +use ieee.std_logic_1164.all; + +entity er_ram_mod is -- exposed register RAM module (single register) +	generic( +		W : natural := 1; -- module data width +		ADDR_W : natural := 1; -- address width +		ADDR_M : std_logic_vector(ADDR_W-1 downto 0) := (others => '0')); -- address match +	port( +		CLK : in std_logic; -- clock +		RST : in std_logic; -- async memory clear +		WEN : in std_logic; -- write enable +		ADDR : in std_logic_vector(ADDR_W-1 downto 0); -- RAM address line +		DATA : in std_logic_vector(W-1 downto 0); -- RAM input data line +		REG : out std_logic_vector(W-1 downto 0)); -- direct register output lines +end er_ram_mod; + +architecture Behavioral of er_ram_mod is +	signal DATA_REG : std_logic_vector(W-1 downto 0); +begin +	REG <= DATA_REG; + +	process(CLK, RST) +	begin +		if RST = '1' then +			DATA_REG <= (others => '0'); +		elsif rising_edge(CLK) then +			if WEN = '1' and ADDR = ADDR_M then +				DATA_REG <= DATA; +			end if; +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/er_ram_mod_tb.vhd b/basys3/basys3.srcs/er_ram_mod_tb.vhd new file mode 100644 index 0000000..aa77a56 --- /dev/null +++ b/basys3/basys3.srcs/er_ram_mod_tb.vhd @@ -0,0 +1,81 @@ +library ieee; +library unisim; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; + +entity er_ram_mod_tb is +end er_ram_mod_tb; + +architecture behavioral of er_ram_mod_tb is +	component er_ram_mod +		generic( +			W : natural := 1; -- module data width +			ADDR_W : natural := 1; -- address width +			ADDR_M : std_logic_vector(ADDR_W-1 downto 0) := (others => '0')); -- address match +		port( +			CLK : in std_logic; -- clock +			RST : in std_logic; -- async memory clear +			WEN : in std_logic; -- write enable +			ADDR : in std_logic_vector(ADDR_W-1 downto 0); +			DATA : in std_logic_vector(W-1 downto 0); -- data +			REG : out std_logic_vector(W-1 downto 0)); -- direct register out +	end component; + +	signal CLK, RST, WEN : std_logic := '0'; +	signal ADDR : std_logic_vector(3 downto 0); +	signal DATA : std_logic_vector(7 downto 0); +	signal REG : std_logic_vector(7 downto 0); +begin +	uut : component er_ram_mod +		generic map( +			W => 8, +			ADDR_W => 4, +			ADDR_M => x"5") +		port map( +			CLK => CLK, +			RST => RST, +			WEN => WEN, +			ADDR => ADDR, +			DATA => DATA, +			REG => REG); + +	tb : process +	begin +		wait for 5 ns; + +		-- async reset (safety) +		RST <= '1'; +		wait for 5 ns; +		RST <= '0'; +		wait for 5 ns; + +		-- set 0xef at address 0x5 (exists) +		DATA <= x"ef"; +		ADDR <= x"5"; +		WEN <= '1'; + +		CLK <= '1'; +		wait for 5 ns; +		CLK <= '0'; +		wait for 5 ns; + +		-- set 0x34 at address 0x4 (doesn't exist) +		ADDR <= x"4"; +		DATA <= x"34"; + +		CLK <= '1'; +		wait for 5 ns; +		CLK <= '0'; +		wait for 5 ns; + +		-- reset +		RST <= '1'; +		wait for 5 ns; +		RST <= '0'; +		wait for 5 ns; + +		wait; -- stop for simulator +	end process; +end; diff --git a/basys3/basys3.srcs/er_ram_tb.vhd b/basys3/basys3.srcs/er_ram_tb.vhd new file mode 100644 index 0000000..d360442 --- /dev/null +++ b/basys3/basys3.srcs/er_ram_tb.vhd @@ -0,0 +1,116 @@ +library ieee; +library unisim; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; + +entity er_ram_tb is +end er_ram_tb; + +architecture behavioral of er_ram_tb is +	component er_ram +		generic( +			ADDR_W : natural := 2; -- ADDR line width +			DATA_W : natural := 2; -- DATA line width +			ADDR_LOW : natural := 16#0000#; -- starting address +			ADDR_RANGE : natural := 16#0002#); -- amount of valid addresses after ADDR_LOW +		port( +			CLK : in std_logic; -- clock +			RST : in std_logic; -- async memory clear +			WEN : in std_logic; -- write enable +			ADDR : in std_logic_vector(ADDR_W-1 downto 0); +			DATA : in std_logic_vector(DATA_W-1 downto 0); +			REG : out std_logic_vector((ADDR_W*DATA_W)-1 downto 0)); +	end component; + +	signal CLK, RST, WEN : std_logic := '0'; +	signal ADDR : std_logic_vector(3 downto 0); +	signal DATA : std_logic_vector(7 downto 0); +	signal REG : std_logic_vector(31 downto 0); +begin +	uut : component er_ram +		generic map( +			ADDR_W => 4, +			DATA_W => 8, +			ADDR_LOW => 0, +			ADDR_RANGE => 4) +		port map( +			CLK => CLK, +			RST => RST, +			WEN => WEN, +			ADDR => ADDR, +			DATA => DATA, +			REG => REG); + +	tb : process +	begin +		wait for 5 ns; + +		-- async reset (safety) +		RST <= '1'; +		wait for 5 ns; +		RST <= '0'; +		wait for 5 ns; + +		-- set 0xef at address 0x1 (exists) +		DATA <= x"ef"; +		ADDR <= x"1"; +		WEN <= '1'; + +		CLK <= '1'; +		wait for 5 ns; +		CLK <= '0'; +		wait for 5 ns; + +		-- set 0x34 at address 0x4 (doesn't exist) +		ADDR <= x"4"; +		DATA <= x"34"; + +		CLK <= '1'; +		wait for 5 ns; +		CLK <= '0'; +		wait for 5 ns; + +		-- reset +		RST <= '1'; +		wait for 5 ns; +		RST <= '0'; +		wait for 5 ns; + +		-- set REG to 0x12345678 +		ADDR <= x"0"; +		DATA <= x"12"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		ADDR <= x"1"; +		DATA <= x"34"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		ADDR <= x"2"; +		DATA <= x"56"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		ADDR <= x"3"; +		DATA <= x"78"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		wait; -- stop for simulator +	end process; +end; diff --git a/basys3/basys3.srcs/ppu.vhd b/basys3/basys3.srcs/ppu.vhd index 663f3ab..9cf1bc0 100644 --- a/basys3/basys3.srcs/ppu.vhd +++ b/basys3/basys3.srcs/ppu.vhd @@ -6,184 +6,191 @@ use ieee.std_logic_1164.all;  use work.ppu_consts.all;  entity ppu is port( -	CLK100: in std_logic; -- system clock -	RESET: in std_logic; -- global (async) system reset -	EN: in std_logic; -- PPU VRAM enable (enable ADDR and DATA tri-state drivers) -	WEN: in std_logic; -- PPU VRAM write enable -	ADDR: in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- PPU VRAM ADDR -	DATA: in std_logic_vector(PPU_RAM_BUS_DATA_WIDTH-1 downto 0); -	R,G,B: out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -	NVSYNC, NHSYNC: out std_logic; -- native VGA out -	TVSYNC, TVBLANK, THSYNC, THBLANK: out std_logic); -- tiny VGA out +	CLK100 : in std_logic; -- system clock +	RESET : in std_logic; -- global (async) system reset +	EN : in std_logic; -- PPU VRAM enable (enable ADDR and DATA tri-state drivers) +	WEN : in std_logic; -- PPU VRAM write enable +	ADDR : in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- PPU VRAM ADDR +	DATA : in std_logic_vector(PPU_RAM_BUS_DATA_WIDTH-1 downto 0); +	R,G,B : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); +	NVSYNC, NHSYNC : out std_logic; -- native VGA out +	TVSYNC, TVBLANK, THSYNC, THBLANK : out std_logic); -- tiny VGA out  end ppu;  architecture Behavioral of ppu is +	-- TODO: separate SPRITE_BG and SPRITE_FG lines (foreground_sprite only needs 2 clock cycles)  	component ppu_pceg port( -- pipeline clock edge generator -		CLK: in std_logic; -- system clock -		RESET: in std_logic; -- async reset -		SPRITE: out std_logic; -- sprite info fetch + sprite pixel fetch -		COMP_PAL: out std_logic; -- compositor + palette lookup -		DONE: out std_logic); -- last pipeline stage done +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -- async reset +		SPRITE : out std_logic; -- sprite info fetch + sprite pixel fetch +		COMP_PAL : out std_logic; -- compositor + palette lookup +		DONE : out std_logic); -- last pipeline stage done  	end component;  	component ppu_addr_dec port( -- pipeline clock edge generator -		WEN: in std_logic; -- EXT write enable +		WEN : in std_logic; -- EXT write enable  		TMM_WEN,  		BAM_WEN,  		FAM_WEN,  		PAL_WEN, -		AUX_WEN: out std_logic; -- write enable MUX -		EN: in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI) -		ADDR: in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in -		TMM_AI: in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -		BAM_AI: in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -		FAM_AI: in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -		PAL_AI: in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -		AUX_AI: in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -		TMM_AO: out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -		BAM_AO: out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -		FAM_AO: out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -		PAL_AO: out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -		AUX_AO: out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0)); +		AUX_WEN : out std_logic; -- write enable MUX +		EN : in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI) +		ADDR : in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in +		TMM_AI : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +		BAM_AI : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +		FAM_AI : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +		PAL_AI : in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +		AUX_AI : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); +		TMM_AO : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +		BAM_AO : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +		FAM_AO : out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +		PAL_AO : out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +		AUX_AO : out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0));  	end component;  	component ppu_bam port( -- BAM block memory -		clka: in std_logic; -		rsta: in std_logic; -		wea: in std_logic_vector(0 downto 0); -		addra: in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -		dina: in std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); -		douta: out std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); -		rsta_busy: out std_logic); +		clka : in std_logic; +		rsta : in std_logic; +		wea : in std_logic_vector(0 downto 0); +		addra : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +		dina : in std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); +		douta : out std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); +		rsta_busy : out std_logic);  	end component;  	component ppu_tmm port( -- TMM block memory -		clka: in std_logic; -		rsta: in std_logic; -		wea: in std_logic_vector(0 downto 0); -		addra: in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -		dina: in std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); -		douta: out std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); -		rsta_busy: out std_logic); +		clka : in std_logic; +		rsta : in std_logic; +		wea : in std_logic_vector(0 downto 0); +		addra : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +		dina : in std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); +		douta : out std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); +		rsta_busy : out std_logic);  	end component;  	component ppu_aux port( -		CLK: in std_logic; -- system clock -		RESET: in std_logic; -- reset memory +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -- reset memory  		-- internal memory block (AUX) -		AUX_WEN: in std_logic; -- VRAM AUX write enable -		AUX_ADDR: in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -- VRAM AUX address -		AUX_DATA: in std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0); -- VRAM AUX data +		AUX_WEN : in std_logic; -- VRAM AUX write enable +		AUX_ADDR : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -- VRAM AUX address +		AUX_DATA : in std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0); -- VRAM AUX data  		-- aux outputs -		BG_SHIFT_X: out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -		BG_SHIFT_Y: out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -		FG_FETCH: out std_logic); +		BG_SHIFT_X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +		BG_SHIFT_Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); +		FG_FETCH : out std_logic);  	end component;  	component ppu_sprite_bg port( -- background sprite  		-- inputs -		CLK: in std_logic; -- system 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 +		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); +		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); +		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 +		CIDX : out std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0)); -- output color  	end component; -	component ppu_sprite_fg port( -- foreground sprite -		-- inputs -		CLK: in std_logic; -- system clock -		RESET: in std_logic; -- reset internal memory and clock counters -		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 -		FETCH: in std_logic; -- fetch sprite data from TMM (TODO: generic map, set foreground sprite component index) +	component ppu_sprite_fg -- foreground sprite +		generic ( +			IDX : natural := 0); +		port( +			-- inputs +			CLK : in std_logic; -- system clock +			RESET : in std_logic; -- reset internal memory and clock counters +			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 +			FETCH : in std_logic; -- fetch sprite data from TMM +			VBLANK : in std_logic; -- fetch during vblank -		-- internal memory block (FAM) -		FAM_WEN: in std_logic; -- VRAM FAM write enable -		FAM_ADDR: in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -- VRAM fam address -		FAM_DATA: in std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0); -- VRAM fam data +			-- internal memory block (FAM) +			FAM_WEN : in std_logic; -- VRAM FAM write enable +			FAM_ADDR : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -- VRAM fam address +			FAM_DATA : in std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0); -- VRAM fam data -		-- used memory blocks -		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); +			-- used memory blocks +			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 -		HIT: out std_logic); -- current pixel is not transparent +			-- outputs +			CIDX : out std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); -- output color +			HIT : out std_logic); -- current pixel is not transparent  	end component;  	component ppu_comp port( -- compositor -		FG_HIT: in std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0); -		BG_EN: out std_logic; -		FG_EN: out std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0)); +		FG_HIT : in std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0); +		BG_EN : out std_logic; +		FG_EN : out std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0));  	end component;  	component ppu_plut port( -- palette lookup table -		CLK: in std_logic; -- system clock -		CIDX: in std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); -- color in -		RESET: in std_logic; +		CLK : in std_logic; -- system clock +		CIDX : in std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); -- color in +		RESET : in std_logic;  		-- internal memory block (AUX) -		PAL_WEN: in std_logic; -- VRAM PAL write enable -		PAL_ADDR: in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -- VRAM PAL address -		PAL_DATA: in std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0); -- VRAM PAL data +		PAL_WEN : in std_logic; -- VRAM PAL write enable +		PAL_ADDR : in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -- VRAM PAL address +		PAL_DATA : in std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0); -- VRAM PAL data -		R,G,B: out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0)); -- VGA color out +		R,G,B : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0)); -- VGA color out  	end component;  	component ppu_vga_tiny port( -- tiny vga signal generator -		CLK: in std_logic; -- system clock -		RESET: in std_logic; +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -		X: out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x -		Y: out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y +		X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x +		Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y  		VSYNC, VBLANK, -		HSYNC, HBLANK: out std_logic); -- VGA sync outputs +		HSYNC, HBLANK : out std_logic); -- VGA sync outputs  	end component;  	component ppu_vga_native port( -- native vga signal generator (upscaler) -		CLK: in std_logic; -- system clock -		RESET: in std_logic; +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -		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 -		PREADY: in std_logic; -- current pixel ready (pixel color is stable) -		RI,GI,BI: in std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color in +		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 +		PREADY : in std_logic; -- current pixel ready (pixel color is stable) +		RI,GI,BI : in std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color in -		RO,GO,BO: out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color out -		VSYNC, HSYNC: out std_logic); -- VGA sync outputs +		RO,GO,BO : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color out +		VSYNC, HSYNC : out std_logic); -- VGA sync outputs  	end component;  	-- signals -	signal SYSCLK, SYSRST: std_logic; -- system clock and reset -	signal PL_SPRITE, PL_COMP_PAL, PL_DONE: std_logic; -- pipeline stages -	signal TMM_WEN, BAM_WEN, FAM_WEN, PAL_WEN, AUX_WEN: std_logic; -	signal TMM_AI, TMM_AO: std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -	signal BAM_AI, BAM_AO: std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -	signal FAM_AI, FAM_AO: std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -	signal PAL_AI, PAL_AO: std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -	signal AUX_AI, AUX_AO: std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -	signal TMM_DO: std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); -	signal BAM_DO: std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); -	signal FAM_DO: std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0); -	signal PAL_DO: std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0); -	signal AUX_DO: std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0); -	signal CIDX: std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); -	signal BG_EN: std_logic; -	signal FG_EN, FG_HIT: std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0); -	signal X: std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x -	signal Y: std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y -	signal UR,UG,UB: std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- unstable RGB (to be buffered) -	signal SR,SG,SB: std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- stable RGB (buffered until PL_COMP_PAL) -	signal BG_SHIFT_X: std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -	signal BG_SHIFT_Y: std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -	signal FG_FETCH: std_logic; +	signal SYSCLK, SYSRST : std_logic; -- system clock and reset +	signal PL_SPRITE, PL_COMP_PAL, PL_DONE : std_logic; -- pipeline stages +	signal TMM_WEN, BAM_WEN, FAM_WEN, PAL_WEN, AUX_WEN : std_logic; +	signal TMM_AI, TMM_AO : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	signal BAM_AI, BAM_AO : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	signal FAM_AI, FAM_AO : std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +	signal PAL_AI, PAL_AO : std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +	signal AUX_AI, AUX_AO : std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); +	signal TMM_DO : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0); +	signal BAM_DO : std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0); +	signal FAM_DO : std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0); +	signal PAL_DO : std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0); +	signal AUX_DO : std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0); +	signal CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); +	signal BG_EN : std_logic; +	signal FG_EN, FG_HIT : std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0); +	signal X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x +	signal Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y +	signal UR,UG,UB : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- unstable RGB (to be buffered) +	signal SR,SG,SB : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- stable RGB (buffered until PL_COMP_PAL) +	signal BG_SHIFT_X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +	signal BG_SHIFT_Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); +	signal FG_FETCH : std_logic; +	signal TINY_VBLANK, TINY_VSYNC, TINY_HBLANK, TINY_HSYNC, +	       NATIVE_VSYNC, NATIVE_HSYNC : std_logic;  begin  	SYSCLK <= CLK100;  	SYSRST <= RESET; @@ -197,14 +204,21 @@ begin  	FAM_AI <= (others => '0');  	PAL_AI <= (others => '0'); -	pipeline_clock_edge_generator: component ppu_pceg port map( +	TVBLANK <= TINY_VBLANK; +	TVSYNC <= TINY_VSYNC; +	THBLANK <= TINY_HBLANK; +	THSYNC <= TINY_HSYNC; +	NVSYNC <= NATIVE_VSYNC; +	NHSYNC <= NATIVE_HSYNC; + +	pipeline_clock_edge_generator : component ppu_pceg port map(  		CLK => SYSCLK,  		RESET => SYSRST,  		SPRITE => PL_SPRITE,  		COMP_PAL => PL_COMP_PAL,  		DONE => PL_DONE); -	address_decoder: component ppu_addr_dec port map( +	address_decoder : component ppu_addr_dec port map(  		EN => EN,  		WEN => WEN,  		ADDR => ADDR, @@ -224,7 +238,7 @@ begin  		PAL_WEN => PAL_WEN,  		AUX_WEN => AUX_WEN); -	background_attribute_memory: component ppu_bam port map( +	background_attribute_memory : component ppu_bam port map(  		clka => SYSCLK,  		rsta => SYSRST,  		wea => (others => BAM_WEN), @@ -232,7 +246,7 @@ begin  		dina => DATA(PPU_BAM_DATA_WIDTH-1 downto 0),  		douta => BAM_DO,  		rsta_busy => open); -	tilemap_memory: component ppu_tmm port map( +	tilemap_memory : component ppu_tmm port map(  		clka => SYSCLK,  		rsta => SYSRST,  		wea => (others => TMM_WEN), @@ -241,7 +255,7 @@ begin  		douta => TMM_DO,  		rsta_busy => open); -	aux: component ppu_aux port map( +	aux : component ppu_aux port map(  		CLK => SYSCLK,  		RESET => SYSRST,  		AUX_WEN => AUX_WEN, @@ -251,7 +265,7 @@ begin  		BG_SHIFT_Y => BG_SHIFT_Y,  		FG_FETCH => FG_FETCH); -	background_sprite: component ppu_sprite_bg port map( +	background_sprite : component ppu_sprite_bg port map(  		CLK => PL_SPRITE,  		RESET => SYSRST,  		OE => BG_EN, @@ -265,29 +279,32 @@ begin  		TMM_DATA => TMM_DO,  		CIDX => CIDX); -	foreground_sprites: for FG_IDX in 0 to PPU_FG_SPRITE_COUNT-1 generate -		foreground_sprite: component ppu_sprite_fg port map( -			CLK => PL_SPRITE, -			RESET => SYSRST, -			OE => FG_EN(FG_IDX), -			X => X, -			Y => Y, -			FETCH => FG_FETCH, -			FAM_WEN => FAM_WEN, -			FAM_ADDR => FAM_AO, -			FAM_DATA => DATA(PPU_FAM_DATA_WIDTH-1 downto 0), -			TMM_ADDR => TMM_AI, -			TMM_DATA => TMM_DO, -			CIDX => CIDX, -			HIT => FG_HIT(FG_IDX)); +	foreground_sprites : for FG_IDX in 0 to PPU_FG_SPRITE_COUNT-1 generate +		foreground_sprite : component ppu_sprite_fg +			generic map( IDX => FG_IDX ) +			port map( +				CLK => SYSCLK, +				RESET => SYSRST, +				OE => FG_EN(FG_IDX), +				X => X, +				Y => Y, +				FETCH => FG_FETCH, +				VBLANK => TINY_VBLANK, +				FAM_WEN => FAM_WEN, +				FAM_ADDR => FAM_AO, +				FAM_DATA => DATA(PPU_FAM_DATA_WIDTH-1 downto 0), +				TMM_ADDR => TMM_AI, +				TMM_DATA => TMM_DO, +				CIDX => CIDX, +				HIT => FG_HIT(FG_IDX));  	end generate; -	compositor: component ppu_comp port map( -- compositor +	compositor : component ppu_comp port map( -- compositor  		FG_HIT => FG_HIT,  		BG_EN => BG_EN,  		FG_EN => FG_EN); -	palette_lookup: component ppu_plut port map( -- palette lookup table +	palette_lookup : component ppu_plut port map( -- palette lookup table  		CLK => SYSCLK,  		CIDX => CIDX,  		RESET => SYSRST, @@ -312,17 +329,17 @@ begin  		end if;  	end process; -	tiny_vga_signal_generator: component ppu_vga_tiny port map( -- tiny vga signal generator +	tiny_vga_signal_generator : component ppu_vga_tiny port map( -- tiny vga signal generator  		CLK => SYSCLK,  		RESET => SYSRST,  		X => X,  		Y => Y, -		VSYNC => TVSYNC, -		VBLANK => TVBLANK, -		HSYNC => THSYNC, -		HBLANK => THBLANK); +		VSYNC => TINY_VSYNC, +		VBLANK => TINY_VBLANK, +		HSYNC => TINY_HSYNC, +		HBLANK => TINY_HBLANK); -	native_vga_signal_generator: component ppu_vga_native port map( -- native vga signal generator (upscaler) +	native_vga_signal_generator : component ppu_vga_native port map( -- native vga signal generator (upscaler)  		CLK => SYSCLK,  		RESET => SYSRST,  		X => X, @@ -334,6 +351,6 @@ begin  		RO => R,  		GO => G,  		BO => B, -		VSYNC => NVSYNC, -		HSYNC => NHSYNC); +		VSYNC => NATIVE_VSYNC, +		HSYNC => NATIVE_HSYNC);  end Behavioral; diff --git a/basys3/basys3.srcs/ppu_addr_dec.vhd b/basys3/basys3.srcs/ppu_addr_dec.vhd new file mode 100644 index 0000000..e0c374f --- /dev/null +++ b/basys3/basys3.srcs/ppu_addr_dec.vhd @@ -0,0 +1,51 @@ +library ieee; +library work; +use ieee.std_logic_1164.all; +--use ieee.numeric_std.all; +use work.ppu_consts.all; + +entity ppu_addr_dec is port( +	EN : in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI) +	WEN : in std_logic; -- EXT write enable +	TMM_WEN, +	BAM_WEN, +	FAM_WEN, +	PAL_WEN, +	AUX_WEN : out std_logic; -- write enable MUX +	ADDR : in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in +	TMM_AI : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	BAM_AI : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	FAM_AI : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +	PAL_AI : in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +	AUX_AI : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); +	TMM_AO : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	BAM_AO : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	FAM_AO : out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +	PAL_AO : out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +	AUX_AO : out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0)); +end ppu_addr_dec; + +architecture Behavioral of ppu_addr_dec is +	signal TMM_RANGE, BAM_RANGE, FAM_RANGE, PAL_RANGE, AUX_RANGE : std_logic := '0'; -- ADDR in range of memory area +begin +	-- address MUX +	TMM_AO <= ADDR(PPU_TMM_ADDR_WIDTH-1 downto 0) when EN = '1' else TMM_AI; +	BAM_AO <= ADDR(PPU_BAM_ADDR_WIDTH-1 downto 0) when EN = '1' else BAM_AI; +	FAM_AO <= ADDR(PPU_FAM_ADDR_WIDTH-1 downto 0) when EN = '1' else FAM_AI; +	PAL_AO <= ADDR(PPU_PAL_ADDR_WIDTH-1 downto 0) when EN = '1' else PAL_AI; +	AUX_AO <= ADDR(PPU_AUX_ADDR_WIDTH-1 downto 0) when EN = '1' else AUX_AI; + +	-- WEN MUX +	TMM_WEN <= TMM_RANGE and WEN; +	BAM_WEN <= BAM_RANGE and WEN; +	FAM_WEN <= FAM_RANGE and WEN; +	PAL_WEN <= PAL_RANGE and WEN; +	AUX_WEN <= AUX_RANGE and WEN; + +	-- address ranges +	TMM_RANGE <= '1' when not ((ADDR(15) and ADDR(14) and ADDR(13)) or (ADDR(15) and ADDR(14) and ADDR(12))) else '0'; +	BAM_RANGE <= '1' when TMM_RANGE = '0' and (ADDR(11) = '0') else '0'; +	FAM_RANGE <= '1' when TMM_RANGE = '0' and (ADDR(11) = '1' and ADDR(10) = '0') else '0'; +	PAL_RANGE <= '1' when TMM_RANGE = '0' and (ADDR(11) = '1' and ADDR(10) = '1' and ADDR(9) = '0') else '0'; +	AUX_RANGE <= '1' when TMM_RANGE = '0' and (ADDR(11) = '1' and ADDR(10) = '1' and ADDR(9) = '1') else '0'; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_addr_dec.vhdl b/basys3/basys3.srcs/ppu_addr_dec.vhdl deleted file mode 100644 index 28c22fc..0000000 --- a/basys3/basys3.srcs/ppu_addr_dec.vhdl +++ /dev/null @@ -1,51 +0,0 @@ -library ieee; -library work; -use ieee.std_logic_1164.all; ---use ieee.numeric_std.all; -use work.ppu_consts.all; - -entity ppu_addr_dec is port( -	EN: in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI) -	WEN: in std_logic; -- EXT write enable -	TMM_WEN, -	BAM_WEN, -	FAM_WEN, -	PAL_WEN, -	AUX_WEN: out std_logic; -- write enable MUX -	ADDR: in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in -	TMM_AI: in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -	BAM_AI: in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -	FAM_AI: in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -	PAL_AI: in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -	AUX_AI: in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -	TMM_AO: out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -	BAM_AO: out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -	FAM_AO: out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -	PAL_AO: out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -	AUX_AO: out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0)); -end ppu_addr_dec; - -architecture Behavioral of ppu_addr_dec is -	signal TMM_RANGE, BAM_RANGE, FAM_RANGE, PAL_RANGE, AUX_RANGE: std_logic := '0'; -- ADDR in range of memory area -begin -	-- address MUX -	TMM_AO <= ADDR(PPU_TMM_ADDR_WIDTH-1 downto 0) when EN = '1' else TMM_AI; -	BAM_AO <= ADDR(PPU_BAM_ADDR_WIDTH-1 downto 0) when EN = '1' else BAM_AI; -	FAM_AO <= ADDR(PPU_FAM_ADDR_WIDTH-1 downto 0) when EN = '1' else FAM_AI; -	PAL_AO <= ADDR(PPU_PAL_ADDR_WIDTH-1 downto 0) when EN = '1' else PAL_AI; -	AUX_AO <= ADDR(PPU_AUX_ADDR_WIDTH-1 downto 0) when EN = '1' else AUX_AI; - -	-- WEN MUX -	TMM_WEN <= TMM_RANGE and WEN; -	BAM_WEN <= BAM_RANGE and WEN; -	FAM_WEN <= FAM_RANGE and WEN; -	PAL_WEN <= PAL_RANGE and WEN; -	AUX_WEN <= AUX_RANGE and WEN; - -	-- address ranges -	TMM_RANGE <= '1' when not (ADDR(15) = '1' and ADDR(14) = '1') else '0'; -	BAM_RANGE <= '1' when (ADDR(15) = '1' and ADDR(14) = '1') and (ADDR(11) = '0') else '0'; -	FAM_RANGE <= '1' when (ADDR(15) = '1' and ADDR(14) = '1') and (ADDR(11) = '1' and ADDR(10) = '0') else '0'; -	PAL_RANGE <= '1' when (ADDR(15) = '1' and ADDR(14) = '1') and (ADDR(11) = '1' and ADDR(10) = '1' and ADDR(9) = '0') else '0'; -	AUX_RANGE <= '1' when (ADDR(15) = '1' and ADDR(14) = '1') and (ADDR(11) = '1' and ADDR(10) = '1' and ADDR(9) = '1') else '0'; -end Behavioral; diff --git a/basys3/basys3.srcs/ppu_addr_dec_tb.vhd b/basys3/basys3.srcs/ppu_addr_dec_tb.vhd new file mode 100644 index 0000000..f31ee67 --- /dev/null +++ b/basys3/basys3.srcs/ppu_addr_dec_tb.vhd @@ -0,0 +1,86 @@ +library ieee; +library unisim; +library work; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; +use work.ppu_consts.all; + +entity ppu_addr_dec_tb is +end ppu_addr_dec_tb; + +architecture behavioral of ppu_addr_dec_tb is +	component ppu_addr_dec port( +		EN : in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI) +		WEN : in std_logic; -- EXT write enable +		TMM_WEN, +		BAM_WEN, +		FAM_WEN, +		PAL_WEN, +		AUX_WEN : out std_logic; -- write enable MUX +		ADDR : in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in +		TMM_AI : in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +		BAM_AI : in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +		FAM_AI : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +		PAL_AI : in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +		AUX_AI : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); +		TMM_AO : out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +		BAM_AO : out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +		FAM_AO : out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +		PAL_AO : out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +		AUX_AO : out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0)); +	end component; +	signal EN : std_logic; +	signal WEN : std_logic; +	signal TMM_WEN, BAM_WEN, FAM_WEN, PAL_WEN, AUX_WEN : std_logic; +	signal ADDR : std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); +	signal TMM_AI : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	signal BAM_AI : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	signal FAM_AI : std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +	signal PAL_AI : std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +	signal AUX_AI : std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); +	signal TMM_AO : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); +	signal BAM_AO : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); +	signal FAM_AO : std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); +	signal PAL_AO : std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); +	signal AUX_AO : std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); +begin +	uut : ppu_addr_dec port map( +    EN => EN, +    WEN => WEN, +    TMM_WEN => TMM_WEN, +    BAM_WEN => BAM_WEN, +    FAM_WEN => FAM_WEN, +    PAL_WEN => PAL_WEN, +    AUX_WEN => AUX_WEN, +    ADDR => ADDR, +    TMM_AI => TMM_AI, +    BAM_AI => BAM_AI, +    FAM_AI => FAM_AI, +    PAL_AI => PAL_AI, +    AUX_AI => AUX_AI, +    TMM_AO => TMM_AO, +    BAM_AO => BAM_AO, +    FAM_AO => FAM_AO, +    PAL_AO => PAL_AO, +    AUX_AO => AUX_AO); + +  EN <= '1'; +  WEN <= '1'; + +  TMM_AI <= (others => '1'); +  BAM_AI <= (others => '0'); +  FAM_AI <= (others => '1'); +  PAL_AI <= (others => '0'); +  AUX_AI <= (others => '0'); + +	tb : process +	begin +		for i in 0 to 65535 loop +      ADDR <= std_logic_vector(to_unsigned(i,16)); +      wait for 10 ps; +		end loop; +		wait; -- stop for simulator +	end process; +end; diff --git a/basys3/basys3.srcs/ppu_addr_dec_tb.vhdl b/basys3/basys3.srcs/ppu_addr_dec_tb.vhdl deleted file mode 100644 index 5c7119d..0000000 --- a/basys3/basys3.srcs/ppu_addr_dec_tb.vhdl +++ /dev/null @@ -1,86 +0,0 @@ -library ieee; -library unisim; -library work; - -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; -use unisim.vcomponents.all; -use work.ppu_consts.all; - -entity ppu_addr_dec_tb is -end ppu_addr_dec_tb; - -architecture behavioral of ppu_addr_dec_tb is -	component ppu_addr_dec port( -		EN: in std_logic; -- EXT *ADDR enable (switch *AO to ADDR instead of *AI) -		WEN: in std_logic; -- EXT write enable -		TMM_WEN, -		BAM_WEN, -		FAM_WEN, -		PAL_WEN, -		AUX_WEN: out std_logic; -- write enable MUX -		ADDR: in std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -- address in -		TMM_AI: in std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -		BAM_AI: in std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -		FAM_AI: in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -		PAL_AI: in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -		AUX_AI: in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -		TMM_AO: out std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -		BAM_AO: out std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -		FAM_AO: out std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -		PAL_AO: out std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -		AUX_AO: out std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0)); -	end component; -	signal EN: std_logic; -	signal WEN: std_logic; -	signal TMM_WEN, BAM_WEN, FAM_WEN, PAL_WEN, AUX_WEN: std_logic; -	signal ADDR: std_logic_vector(PPU_RAM_BUS_ADDR_WIDTH-1 downto 0); -	signal TMM_AI: std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -	signal BAM_AI: std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -	signal FAM_AI: std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -	signal PAL_AI: std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -	signal AUX_AI: std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -	signal TMM_AO: std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0); -	signal BAM_AO: std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0); -	signal FAM_AO: std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -	signal PAL_AO: std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -	signal AUX_AO: std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -begin -	uut: ppu_addr_dec port map( -    EN => EN, -    WEN => WEN, -    TMM_WEN => TMM_WEN, -    BAM_WEN => BAM_WEN, -    FAM_WEN => FAM_WEN, -    PAL_WEN => PAL_WEN, -    AUX_WEN => AUX_WEN, -    ADDR => ADDR, -    TMM_AI => TMM_AI, -    BAM_AI => BAM_AI, -    FAM_AI => FAM_AI, -    PAL_AI => PAL_AI, -    AUX_AI => AUX_AI, -    TMM_AO => TMM_AO, -    BAM_AO => BAM_AO, -    FAM_AO => FAM_AO, -    PAL_AO => PAL_AO, -    AUX_AO => AUX_AO); - -  EN <= '1'; -  WEN <= '1'; - -  TMM_AI <= (others => '1'); -  BAM_AI <= (others => '0'); -  FAM_AI <= (others => '1'); -  PAL_AI <= (others => '0'); -  AUX_AI <= (others => '0'); - -	tb: process -	begin -		for i in 0 to 65535 loop -      ADDR <= std_logic_vector(to_unsigned(i,16)); -      wait for 10 ps; -		end loop; -		wait; -- stop for simulator -	end process; -end; diff --git a/basys3/basys3.srcs/ppu_aux.vhd b/basys3/basys3.srcs/ppu_aux.vhd new file mode 100644 index 0000000..9062bc4 --- /dev/null +++ b/basys3/basys3.srcs/ppu_aux.vhd @@ -0,0 +1,52 @@ +library ieee; +library work; +use ieee.std_logic_1164.all; +--use ieee.numeric_std.all; +use work.ppu_consts.all; + +entity ppu_aux is port( +	CLK : in std_logic; -- system clock +	RESET : in std_logic; -- reset memory + +	-- internal memory block (AUX) +	AUX_WEN : in std_logic; -- VRAM AUX write enable +	AUX_ADDR : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -- VRAM AUX address +	AUX_DATA : in std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0); -- VRAM AUX data +	 +	-- aux outputs +	BG_SHIFT_X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +	BG_SHIFT_Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); +	FG_FETCH : out std_logic); +end ppu_aux; + +architecture Behavioral of ppu_aux is +	component er_ram +		generic( +			ADDR_W : natural := PPU_AUX_ADDR_WIDTH; -- ADDR line width +			DATA_W : natural := PPU_AUX_DATA_WIDTH; -- DATA line width +			ADDR_LOW : natural := 16#0000#; -- starting address +			ADDR_RANGE : natural := 16#0002#); -- amount of valid addresses after ADDR_LOW +		port( +			CLK : in std_logic; -- clock +			RST : in std_logic; -- async memory clear +			WEN : in std_logic; -- write enable +			ADDR : in std_logic_vector(ADDR_W-1 downto 0); +			DATA : in std_logic_vector(DATA_W-1 downto 0); +			REG : out std_logic_vector((ADDR_RANGE*DATA_W)-1 downto 0)); -- exposed register output +	end component; + +	signal INT_REG : std_logic_vector(2 * PPU_AUX_DATA_WIDTH - 1 downto 0); +begin +	-- docs/architecture.md#auxiliary-memory +	FG_FETCH <= INT_REG(17); +	BG_SHIFT_X <= INT_REG(16 downto 8); +	BG_SHIFT_Y <= INT_REG(7 downto 0); + +	RAM : component er_ram port map( +		CLK => CLK, +		RST => RESET, +		WEN => AUX_WEN, +		ADDR => AUX_ADDR, +		DATA => AUX_DATA, +		REG => INT_REG); +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_aux_tb.vhd b/basys3/basys3.srcs/ppu_aux_tb.vhd new file mode 100644 index 0000000..ab3db62 --- /dev/null +++ b/basys3/basys3.srcs/ppu_aux_tb.vhd @@ -0,0 +1,100 @@ +library ieee; +library unisim; +library work; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; +use work.ppu_consts.all; + +entity ppu_aux_tb is +end ppu_aux_tb; + +architecture behavioral of ppu_aux_tb is +	component ppu_aux port( +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -- reset memory + +		-- internal memory block (AUX) +		AUX_WEN : in std_logic; -- VRAM AUX write enable +		AUX_ADDR : in std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0); -- VRAM AUX address +		AUX_DATA : in std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0); -- VRAM AUX data +		 +		-- aux outputs +		BG_SHIFT_X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +		BG_SHIFT_Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); +		FG_FETCH : out std_logic); +	end component; + +	signal CLK, RST, WEN : std_logic := '0'; +	signal ADDR : std_logic_vector(PPU_AUX_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal DATA : std_logic_vector(PPU_AUX_DATA_WIDTH-1 downto 0) := (others => '0'); + +	signal BG_SHIFT_X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); +	signal BG_SHIFT_Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); +	signal FG_FETCH : std_logic; +begin +	uut : component ppu_aux +		port map( +			CLK => CLK, +			RESET => RST, +			AUX_WEN => WEN, +			AUX_ADDR => ADDR, +			AUX_DATA => DATA, +			BG_SHIFT_X => BG_SHIFT_X, +			BG_SHIFT_Y => BG_SHIFT_Y, +			FG_FETCH => FG_FETCH); + +	tb : process +	begin +		-- reset +		RST <= '1'; +		wait for 5 ns; +		RST <= '0'; +		wait for 5 ns; + +		WEN <= '1'; +		-- set BG_SHIFT_X to 178 +		-- set BG_SHIFT_Y to 39 +		-- set FG_FETCH to 1 +		ADDR(0) <= '0'; +		DATA <= x"b327"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		ADDR(0) <= '1'; +		DATA <= x"0002"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		wait for 5 ns; + +		-- set BG_SHIFT_X to 30 +		-- set BG_SHIFT_Y to 69 +		-- set FG_FETCH to 0 +		ADDR(0) <= '0'; +		DATA <= x"1e45"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + +		ADDR(0) <= '1'; +		DATA <= x"0000"; + +		CLK <= '1'; +		wait for 1 ns; +		CLK <= '0'; +		wait for 1 ns; + + +		wait; -- stop for simulator +	end process; +end; diff --git a/basys3/basys3.srcs/ppu_comp.vhd b/basys3/basys3.srcs/ppu_comp.vhd new file mode 100644 index 0000000..e79738f --- /dev/null +++ b/basys3/basys3.srcs/ppu_comp.vhd @@ -0,0 +1,36 @@ +library ieee; +use ieee.std_logic_1164.all; +use work.ppu_consts.all; + +entity ppu_comp is port (  +	FG_HIT : in std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0); +	BG_EN : out std_logic; +	FG_EN : out std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0)); +end ppu_comp; + +architecture Behavioral of ppu_comp is +	signal FG_HIT_EMPTY : std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0) := (others => '0'); +begin +	process (FG_HIT) +		variable HIT : boolean := false; +	begin +		-- check if FG_HIT is not empty +		if FG_HIT /= FG_HIT_EMPTY then +			BG_EN <= '0'; +			for i in 0 to PPU_FG_SPRITE_COUNT-1 loop +				-- if FG_HIT is the first one then enable it +				if(FG_HIT(i) = '1' and HIT = false) then +					FG_EN(i) <= '1'; +					HIT := true; +				else +					-- make rest low +					FG_EN(i) <= '0'; +				end if; +			end loop; +			HIT := false; +		else +			BG_EN <= '1'; +			FG_EN <= (others => '0'); +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_comp_tb.vhd b/basys3/basys3.srcs/ppu_comp_tb.vhd new file mode 100644 index 0000000..be4c2e3 --- /dev/null +++ b/basys3/basys3.srcs/ppu_comp_tb.vhd @@ -0,0 +1,40 @@ +library ieee; +library unisim; +use ieee.std_logic_1164.all; +use work.ppu_consts.all; +use unisim.vcomponents.all; + +entity ppu_comp_tb is +end ppu_comp_tb; + +architecture behavioral of ppu_comp_tb is +	component ppu_comp port ( +		FG_HIT : in std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0); +		BG_EN : out std_logic; +		FG_EN : out std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0)); +	end component; +	signal FG_HIT : std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0) := (others => '0'); +	signal BG_EN : std_logic := '0'; +	signal FG_EN : std_logic_vector(PPU_FG_SPRITE_COUNT-1 downto 0) := (others => '0'); +begin +	uut : ppu_comp port map ( +		FG_HIT => FG_HIT, +		BG_EN => BG_EN, +		FG_EN => FG_EN +	); +	tb : process +	begin +		FG_HIT <= (others => '0'); +		wait for 1 ps; +		FG_HIT(6) <= '1'; +		FG_HIT(5) <= '1'; +		FG_HIT(100) <= '1'; +		wait for 1 ps; + +		FG_HIT(0) <= '1'; +		wait for 1 ps; +		FG_HIT <= (others => '0'); +		wait for 1 ps; +		wait; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_consts.vhd b/basys3/basys3.srcs/ppu_consts.vhd index c063586..75b6168 100644 --- a/basys3/basys3.srcs/ppu_consts.vhd +++ b/basys3/basys3.srcs/ppu_consts.vhd @@ -1,22 +1,55 @@ +library ieee; +use ieee.math_real.all; + +-- https://docs.google.com/spreadsheets/d/1MU6K4c4PtMR_JXIpc3I0ZJdLZNnoFO7G2P3olCz6LSc  package ppu_consts is -	constant PPU_RAM_BUS_ADDR_WIDTH: natural := 16; -- RAM bus address width -	constant PPU_RAM_BUS_DATA_WIDTH: natural := 16; -- RAM bus data width -	constant PPU_FG_SPRITE_COUNT: natural := 128; -- amount of foreground sprites -	constant PPU_COLOR_OUTPUT_DEPTH: natural := 4; -- VGA output channel depth -	constant PPU_PALETTE_IDX_WIDTH: natural := 3; -- palette index width (within sprite) -	constant PPU_PALETTE_WIDTH: natural := 3; -- palette index width (palette table) -	constant PPU_PALETTE_CIDX_WIDTH: natural := PPU_PALETTE_IDX_WIDTH + PPU_PALETTE_WIDTH; -- global palette index width -	constant PPU_TMM_ADDR_WIDTH: natural := 16; -	constant PPU_TMM_DATA_WIDTH: natural := 16; -	constant PPU_BAM_ADDR_WIDTH: natural := 11; -	constant PPU_BAM_DATA_WIDTH: natural := 15; -	constant PPU_FAM_ADDR_WIDTH: natural := 8; -	constant PPU_FAM_DATA_WIDTH: natural := 16; -	constant PPU_PAL_ADDR_WIDTH: natural := 6; -	constant PPU_PAL_DATA_WIDTH: natural := 12; -	constant PPU_AUX_ADDR_WIDTH: natural := 2; -	constant PPU_AUX_DATA_WIDTH: natural := 16; -	constant PPU_POS_H_WIDTH: natural := 9; -- amount of bits for horizontal screen offset -	constant PPU_POS_V_WIDTH: natural := 8; -- amount of bits for vertical screen offset -end package ppu_consts; +	-- utility functions +	function ceil_log2(n : natural) return natural; +	constant PPU_RAM_BUS_ADDR_WIDTH : natural := 16; -- RAM bus address width +	constant PPU_RAM_BUS_DATA_WIDTH : natural := 16; -- RAM bus data width +	constant PPU_FG_SPRITE_COUNT : natural := 128; -- foreground sprites +	constant PPU_COLOR_OUTPUT_DEPTH : natural := 4; -- VGA output channel depth +	constant PPU_PALETTE_COLOR_WIDTH : natural := 3; -- palette index width (within sprite) +	constant PPU_PALETTE_INDEX_WIDTH : natural := 3; -- palette index width (palette table) +	constant PPU_PALETTE_CIDX_WIDTH : natural := (PPU_PALETTE_COLOR_WIDTH + PPU_PALETTE_INDEX_WIDTH); -- global palette index width +	constant PPU_TMM_ADDR_WIDTH : natural := 16; -- tilemap memory ram bus address width +	constant PPU_TMM_DATA_WIDTH : natural := 15; -- tilemap memory ram bus data width +	constant PPU_BAM_ADDR_WIDTH : natural := 11; -- background attribute memory ram bus address width +	constant PPU_BAM_DATA_WIDTH : natural := 15; -- background attribute memory ram bus data width +	constant PPU_FAM_ADDR_WIDTH : natural := 8; -- foreground attribute memory ram bus address width +	constant PPU_FAM_DATA_WIDTH : natural := 16; -- foreground attribute memory ram bus data width +	constant PPU_PAL_ADDR_WIDTH : natural := 6; -- palette memory ram bus address width +	constant PPU_PAL_DATA_WIDTH : natural := 12; -- palette memory ram bus data width +	constant PPU_AUX_ADDR_WIDTH : natural := 1; -- auxiliary memory ram bus address width +	constant PPU_AUX_DATA_WIDTH : natural := 16; -- auxiliary memory ram bus data width +	constant PPU_POS_H_WIDTH : natural := 9; -- bits for horizontal screen offset +	constant PPU_POS_V_WIDTH : natural := 8; -- 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_PIDX_WIDTH : natural := 8; -- bits needed to identify horizontal and vertical pixel within sprite +	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; -- tiles (horizontally) on background canvas +	constant PPU_BG_CANVAS_TILES_V : natural := 30; -- tiles (vertically) on background canvas +	constant PPU_BG_CANVAS_TILE_H_WIDTH : natural := 6; -- bits needed to describe horizontal bg tile index (grid coordinates) +	constant PPU_BG_CANVAS_TILE_V_WIDTH : natural := 5; -- bits needed to describe vertical bg tile index (grid coordinates) +	constant PPU_TILE_INDEX_WIDTH : natural := 10; -- bits needed to index a tile from TMM memory +	constant PPU_PIXELS_PER_TILE_WORD : natural := 5; -- pixels defined in one word in TMM memory +	constant PPU_SPRITE_WORD_COUNT : natural := 52; -- words needed for a single sprite +	constant PPU_PIXEL_BIT_WIDTH : natural := 3; -- bits needed to identify pixel in TMM word +	constant PPU_TILE_BIT_WIDTH : natural := (PPU_SPRITE_WIDTH * PPU_SPRITE_HEIGHT * PPU_PALETTE_COLOR_WIDTH); -- bits in single tile +	constant PPU_TMM_CACHE_FETCH_C_COUNT : natural := PPU_SPRITE_WORD_COUNT + 1; +	constant PPU_TMM_CACHE_FETCH_A_COUNT : natural := PPU_TMM_CACHE_FETCH_C_COUNT * PPU_FG_SPRITE_COUNT; -- amount of clocks to fetch new TMM cache +	constant PPU_TMM_CACHE_FETCH_A_WIDTH : natural := ceil_log2(PPU_TMM_CACHE_FETCH_A_COUNT); +end package ppu_consts; +package body ppu_consts is +	-- https://stackoverflow.com/questions/21783280/number-of-bits-to-represent-an-integer-in-vhdl +	-- Returns number of bits required to represent val in binary vector +	function ceil_log2(n : natural) return natural is +	begin +		return natural(integer(ceil(log2(real(n - 1))))); +	end function; +end package body ppu_consts; diff --git a/basys3/basys3.srcs/ppu_pceg.vhdl b/basys3/basys3.srcs/ppu_pceg.vhd index 9675e5b..1aaeee4 100644 --- a/basys3/basys3.srcs/ppu_pceg.vhdl +++ b/basys3/basys3.srcs/ppu_pceg.vhd @@ -3,18 +3,18 @@ use ieee.std_logic_1164.all;  --use ieee.numeric_std.all;  entity ppu_pceg is port( -	CLK: in std_logic; -- system clock -	RESET: in std_logic; -- async reset -	SPRITE: out std_logic; -- sprite info fetch + sprite pixel fetch -	COMP_PAL: out std_logic; -- compositor + palette lookup -	DONE: out std_logic); -- last pipeline stage done +	CLK : in std_logic; -- system clock +	RESET : in std_logic; -- async reset +	SPRITE : out std_logic; -- sprite info fetch + sprite pixel fetch +	COMP_PAL : out std_logic; -- compositor + palette lookup +	DONE : out std_logic); -- last pipeline stage done  end ppu_pceg;  architecture Behavioral of ppu_pceg is -	constant PPU_PL_TOTAL_STAGES: natural := 14; +	constant PPU_PL_TOTAL_STAGES : natural := 14;  	type states is (PL_SPRITE, PL_COMP_PAL, PL_DONE); -	signal state: states := PL_SPRITE; +	signal state : states := PL_SPRITE;  begin  	-- output drivers  	SPRITE <= CLK when RESET = '0' and state = PL_SPRITE else '0'; @@ -22,7 +22,7 @@ begin  	DONE <= '1' when RESET = '0' and state = PL_DONE else '0';  	process(CLK, RESET) -		variable CLK_IDX: natural range 0 to PPU_PL_TOTAL_STAGES+1 := 0; +		variable CLK_IDX : natural range 0 to PPU_PL_TOTAL_STAGES+1 := 0;  	begin  		if RESET = '1' then  			state <= PL_SPRITE; diff --git a/basys3/basys3.srcs/ppu_pceg_tb.vhdl b/basys3/basys3.srcs/ppu_pceg_tb.vhd index 137d4b4..719ec06 100644 --- a/basys3/basys3.srcs/ppu_pceg_tb.vhdl +++ b/basys3/basys3.srcs/ppu_pceg_tb.vhd @@ -10,27 +10,27 @@ end ppu_pceg_tb;  architecture behavioral of ppu_pceg_tb is  	component ppu_pceg port( -		CLK: in std_logic; -- system clock -		RESET: in std_logic; -- async reset -		SPRITE: out std_logic; -- sprite info fetch + sprite pixel fetch -		COMP_PAL: out std_logic; -- compositor + palette lookup -		DONE: out std_logic); -- last pipeline stage done +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -- async reset +		SPRITE : out std_logic; -- sprite info fetch + sprite pixel fetch +		COMP_PAL : out std_logic; -- compositor + palette lookup +		DONE : out std_logic); -- last pipeline stage done  	end component; -	signal CLK: std_logic := '0'; -	signal RESET: std_logic := '0'; -	signal SPRITE: std_logic; -	signal COMP_PAL: std_logic; -	signal DONE: std_logic; +	signal CLK : std_logic := '0'; +	signal RESET : std_logic := '0'; +	signal SPRITE : std_logic; +	signal COMP_PAL : std_logic; +	signal DONE : std_logic;  begin -	uut: ppu_pceg port map( +	uut : ppu_pceg port map(  		CLK => CLK,  		RESET => RESET,  		SPRITE => SPRITE,  		COMP_PAL => COMP_PAL,  		DONE => DONE); -	tb: process +	tb : process  	begin  		for i in 0 to 32 loop  			if i > 20 then diff --git a/basys3/basys3.srcs/ppu_plut.vhd b/basys3/basys3.srcs/ppu_plut.vhd new file mode 100644 index 0000000..d2e132e --- /dev/null +++ b/basys3/basys3.srcs/ppu_plut.vhd @@ -0,0 +1,69 @@ +library ieee; +use ieee.std_logic_1164.all; +use work.ppu_consts.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; + +entity ppu_plut is port (  +	CLK : in std_logic; -- system clock +	CIDX : in std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0); -- color in +	RESET : in std_logic; + +	-- internal memory block (AUX) +	PAL_WEN : in std_logic; -- VRAM PAL write enable +	PAL_ADDR : in std_logic_vector(PPU_PAL_ADDR_WIDTH-1 downto 0); -- VRAM PAL address +	PAL_DATA : in std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0); -- VRAM PAL data + +	R,G,B : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0)); -- VGA color out +end ppu_plut; + +architecture Behavioral of ppu_plut is +	component er_ram +		generic( +			ADDR_W : natural := PPU_PAL_ADDR_WIDTH; -- ADDR line width +			DATA_W : natural := PPU_PAL_DATA_WIDTH; -- DATA line width +			ADDR_LOW : natural := 16#0000#; -- starting address +			ADDR_RANGE : natural := 16#0040#); -- amount of valid addresses after ADDR_LOW +		port( +			CLK : in std_logic; -- clock +			RST : in std_logic; -- async memory clear +			WEN : in std_logic; -- write enable +			ADDR : in std_logic_vector(ADDR_W-1 downto 0); +			DATA : in std_logic_vector(DATA_W-1 downto 0); +			REG : out std_logic_vector((ADDR_RANGE*DATA_W)-1 downto 0)); -- exposed register output +	end component; +	 +	signal PLUT : std_logic_vector((64 * PPU_PAL_DATA_WIDTH)-1 downto 0) := (others => '0'); +	signal CHECK_ZERO_CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0) := (others => '0'); -- color in +begin +	RAM : component er_ram port map( +		CLK => CLK, +		RST => RESET, +		WEN => PAL_WEN, +		ADDR => PAL_ADDR, +		DATA => PAL_DATA, +		REG => PLUT); + +	process(CLK, RESET) +		variable COLOR : std_logic_vector(PPU_PAL_DATA_WIDTH-1 downto 0) := (others => '0'); -- COLORS RGB IN +		variable CIDX_INT : integer := 0; +	begin +		if RESET = '1' then +			PLUT <= (others => '0'); +		else +			if rising_edge (CLK) then +				if (CIDX /= CHECK_ZERO_CIDX) then +					CIDX_INT := to_integer(unsigned(CIDX)); +					COLOR := PLUT((12 * CIDX_INT) + 11 downto (12*CIDX_INT)); +					R <= COLOR(11 downto  8); +					G <= COLOR(7 downto 4); +					B <= COLOR(3 downto 0); +				else +					R <= x"0"; +					G <= x"0"; +					B <= x"0"; +				end if; +			end if; +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_sprite_bg.vhd b/basys3/basys3.srcs/ppu_sprite_bg.vhd new file mode 100644 index 0000000..dba5b8e --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_bg.vhd @@ -0,0 +1,138 @@ +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; + +-- TODO: add input stable / output stable pipeline stages if this doesn't work with propagation delays +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 unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile +		YI : in unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile +		FLIP_H, FLIP_V : in std_logic; -- flip sprite +		XO : out unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile +		YO : out unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0)); -- new pixel position relative to tile +	end component; + +	-- BAM and TMM in/out temp + registers +	signal T_BAM_ADDR, R_BAM_ADDR : std_logic_vector(PPU_BAM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal T_BAM_DATA, R_BAM_DATA : std_logic_vector(PPU_BAM_DATA_WIDTH-1 downto 0) := (others => '0'); +	signal T_TMM_ADDR, R_TMM_ADDR : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal T_TMM_DATA, R_TMM_DATA : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0) := (others => '0'); + +	-- state machine for synchronizing pipeline stages +	type states is (PL_BAM_ADDR, PL_BAM_DATA, PL_TMM_ADDR, PL_TMM_DATA); +	signal state : states := PL_BAM_ADDR; + +	-- docs/architecture.md#background-attribute-memory +	alias BAM_DATA_FLIP_H is R_BAM_DATA(14); -- flip horizontally +	alias BAM_DATA_FLIP_V is R_BAM_DATA(13); -- flip vertically +	alias BAM_DATA_TILE_IDX is R_BAM_DATA(9 downto 0); -- tilemap tile index +	alias BAM_DATA_COL_IDX is R_BAM_DATA(12 downto 10); -- palette for sprite + +	-- auxiliary signals (temp variables) +	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_PIDX_X, TRANS_TILE_PIDX_X : unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0) := (others => '0'); -- x position of pixel within tile (local tile coords) +	signal TILE_PIDX_Y, TRANS_TILE_PIDX_Y : unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0) := (others => '0'); -- y position of pixel within tile (local tile coords) +	signal TRANS_TILE_PIDX : integer := 0; -- index of pixel within tile (reading order) +	signal TILEMAP_WORD_OFFSET : integer := 0; -- word offset from tile start address in TMM +	signal PIXEL_BIT_OFFSET : integer := 0; -- pixel index within word of TMM +	signal TMM_DATA_PAL_IDX : std_logic_vector(PPU_PALETTE_COLOR_WIDTH-1 downto 0); -- color of palette +	signal T_CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0) := (others => '0'); -- output color buffer/register +begin +	-- output drivers +	CIDX <= T_CIDX when OE = '1' else (others => 'Z'); +	BAM_ADDR <= R_BAM_ADDR; +	TMM_ADDR <= R_TMM_ADDR; +	T_BAM_DATA <= BAM_DATA; +	T_TMM_DATA <= TMM_DATA; +	-- CIDX combination +	T_CIDX <= BAM_DATA_COL_IDX & TMM_DATA_PAL_IDX; + +	-- BAM address calculations +	PIXEL_ABS_X <= to_integer(unsigned(X)) + to_integer(unsigned(BG_SHIFT_X)); -- pixel position relative to background canvas +	PIXEL_ABS_Y <= to_integer(unsigned(Y)) + to_integer(unsigned(BG_SHIFT_Y)); -- pixel position relative to background canvas +	TILE_IDX_X <= PIXEL_ABS_X / 16; -- tile grid index +	TILE_IDX_Y <= PIXEL_ABS_Y / 16; -- tile grid index +	TILE_PIDX_X <= to_unsigned(PIXEL_ABS_X - TILE_IDX_X * 16, TILE_PIDX_X'length); -- (sprite local) pixel coords +	TILE_PIDX_Y <= to_unsigned(PIXEL_ABS_Y - TILE_IDX_Y * 16, TILE_PIDX_Y'length); -- (sprite local) pixel coords +	T_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 dependant calculations +	transform: component ppu_sprite_transform port map( +		XI => TILE_PIDX_X, +		YI => TILE_PIDX_Y, +		FLIP_H => BAM_DATA_FLIP_H, +		FLIP_V => BAM_DATA_FLIP_V, +		XO => TRANS_TILE_PIDX_X, +		YO => TRANS_TILE_PIDX_Y); + +	-- TMM address calculations +	TRANS_TILE_PIDX <= integer(PPU_SPRITE_WIDTH) * to_integer(TRANS_TILE_PIDX_Y) + to_integer(TRANS_TILE_PIDX_X); -- pixel index of sprite +	TILEMAP_WORD_OFFSET <= TRANS_TILE_PIDX / PPU_PIXELS_PER_TILE_WORD; -- word offset from starting word of sprite +	PIXEL_BIT_OFFSET <= TRANS_TILE_PIDX mod PPU_PIXELS_PER_TILE_WORD; -- pixel bit offset +	T_TMM_ADDR <= std_logic_vector(to_unsigned(PPU_SPRITE_WORD_COUNT * to_integer(unsigned(BAM_DATA_TILE_IDX)) + TILEMAP_WORD_OFFSET, PPU_TMM_ADDR_WIDTH)); -- TMM address + +	-- TMM DATA +	with PIXEL_BIT_OFFSET select +		TMM_DATA_PAL_IDX <= R_TMM_DATA(2 downto 0) when 0, +		                    R_TMM_DATA(5 downto 3) when 1, +		                    R_TMM_DATA(8 downto 6) when 2, +		                    R_TMM_DATA(11 downto 9) when 3, +		                    R_TMM_DATA(14 downto 12) when 4, +		                    (others => '0') when others; + +	-- state machine (pipeline stage counter) + sync r/w +	process(CLK, RESET) +	begin +		if RESET = '1' then +			-- reset state +			state <= PL_BAM_ADDR; +			-- reset internal pipeline registers +			R_BAM_ADDR <= (others => '0'); +			R_BAM_DATA <= (others => '0'); +			R_TMM_ADDR <= (others => '0'); +			R_TMM_DATA <= (others => '0'); +		elsif rising_edge(CLK) then +			case state is +				when PL_BAM_ADDR => +					state <= PL_BAM_DATA; +					R_BAM_ADDR <= T_BAM_ADDR; +				when PL_BAM_DATA => +					state <= PL_TMM_ADDR; +					R_BAM_DATA <= T_BAM_DATA; +				when PL_TMM_ADDR => +					state <= PL_TMM_DATA; +					R_TMM_ADDR <= T_TMM_ADDR; +				when PL_TMM_DATA => +					state <= PL_BAM_ADDR; +					R_TMM_DATA <= T_TMM_DATA; +			end case; +		end if; +	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..65da15c --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_bg_tb.vhd @@ -0,0 +1,107 @@ +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); + +	-- inputs +	-- BAM_DATA -> FLIP_H + palette index 2 + tilemap index 10 +	-- TMM_DATA -> all pixels color 7 +	-- X -> 25 +	-- Y -> 60 +	-- BG_SHIFT_X -> 3 +	-- BG_SHIFT_Y -> 3 +	BAM_DATA <= 15x"4814"; -- hex((1 << 14) | (0 << 13) | (2 << 10) | (20 << 0)) +	TMM_DATA <= 15x"7e3f"; -- hex(0x7fff & ~(0b111 << 6)) +	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)); + +	-- expected outputs: +	-- absolute pixel coordinates -> (28, 63) +	-- absolute background canvas tile index coordinates -> (1, 3) +	-- tile index -> 3 * 40 + 1 = 121 +	-- BAM_ADDR => 121 (OK) +	-- sprite local coordinates -> (12, 15) +	-- transformed local coordinates -> (12, 0) (apply FLIP_H) +	-- pixel index -> 0 * 16 + 12 = 12 +	-- pixel word address -> 52 * 20 + 12//5 -> 1042 +	-- TMM_ADDR => 1042 (OK) +	-- pixel bits -> [pixel n+] = 12 % 5 = 2 -> 8 downto 6 +	-- cidx should be -- (2 << 3) | (0 << 0) = 16 +	-- CIDX => 16 (OK) + +	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_fg.vhd b/basys3/basys3.srcs/ppu_sprite_fg.vhd new file mode 100644 index 0000000..af7cfa3 --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_fg.vhd @@ -0,0 +1,192 @@ +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; + +-- TODO: add input stable / output stable pipeline stages if this doesn't work with propagation delays +entity ppu_sprite_fg is -- foreground sprite +	generic ( +		IDX : natural := 0); -- sprite index number +	port( +		-- inputs +		CLK : in std_logic; -- system clock +		RESET : in std_logic; -- reset internal memory and clock counters +		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 +		FETCH : in std_logic; -- fetch sprite data from TMM +		VBLANK : in std_logic; -- fetch during vblank + +		-- internal memory block (FAM) +		FAM_WEN : in std_logic; -- VRAM FAM write enable +		FAM_ADDR : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -- VRAM fam address +		FAM_DATA : in std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0); -- VRAM fam data + +		-- used memory blocks +		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 +		HIT : out std_logic); -- current pixel is not transparent +end ppu_sprite_fg; + +architecture Behavioral of ppu_sprite_fg is +	component ppu_sprite_transform port( +		XI : in unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile +		YI : in unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile +		FLIP_H, FLIP_V : in std_logic; -- flip sprite +		XO : out unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile +		YO : out unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0)); -- new pixel position relative to tile +	end component; +	component er_ram -- exposed register RAM +		generic( +			ADDR_W : natural := 2; -- ADDR line width +			DATA_W : natural := 2; -- DATA line width +			ADDR_LOW : natural := 16#0000#; -- starting address +			ADDR_RANGE : natural := 16#0002#); -- amount of valid addresses after ADDR_LOW +		port( +			CLK : in std_logic; -- clock +			RST : in std_logic; -- async memory clear +			WEN : in std_logic; -- write enable +			ADDR : in std_logic_vector(ADDR_W-1 downto 0); -- address line +			DATA : in std_logic_vector(DATA_W-1 downto 0); -- data input +			REG : out std_logic_vector((ADDR_RANGE*DATA_W)-1 downto 0)); -- exposed register output +	end component; + +	-- FAM and TMM in/out lines +	signal T_TMM_ADDR : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal T_TMM_DATA : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0) := (others => '0'); + +	-- auxiliary signals (temp variables) +	signal T_CIDX : std_logic_vector(PPU_PALETTE_CIDX_WIDTH-1 downto 0) := (others => '0'); -- output color buffer/register +	signal INT_FAM : std_logic_vector(31 downto 0); + +	-- FAM aliases (docs/architecture.md#foreground-attribute-memory) +	alias FAM_REG_FLIP_H is INT_FAM(31); -- Flip horizontally +	alias FAM_REG_FLIP_V is INT_FAM(30); -- Flip vertically +	alias FAM_REG_POS_H is INT_FAM(29 downto 21); -- horizontal position (offset by -16) +	alias FAM_REG_POS_V is INT_FAM(20 downto 13); -- vertical position (offset by -16) +	alias FAM_REG_COL_IDX is INT_FAM(12 downto 10); -- Palette index for tile +	alias FAM_REG_TILE_IDX is INT_FAM(9 downto 0); -- Tilemap index + +	signal SPRITE_ACTIVE : std_logic := '0'; -- is pixel in bounding box of sprite +	signal PIXEL_ABS_X, PIXEL_ABS_Y : integer := 0; -- absolute pixel position (relative to FG canvas instead of viewport) +	signal TILE_PIDX_X, TRANS_TILE_PIDX_X : unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0) := (others => '0'); -- xy position of pixel within tile (local tile coords) +	signal TILE_PIDX_Y, TRANS_TILE_PIDX_Y : unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0) := (others => '0'); -- xy position of pixel within tile (local tile coords) +	signal TRANS_TILE_PIXEL_IDX : integer := 0; -- index of pixel within tile (reading order) +	signal TILEMAP_WORD_OFFSET : integer := 0; -- word offset from tile start address in TMM +	signal TMM_DATA_PAL_IDX : std_logic_vector(PPU_PALETTE_COLOR_WIDTH-1 downto 0); -- color of palette + +	-- TMM cache lines +	signal TMM_CACHE_WEN, TMM_CACHE_UPDATE_TURN : std_logic := '0'; +	signal TMM_CACHE_DATA : std_logic_vector(PPU_TMM_DATA_WIDTH-1 downto 0) := (others => '0'); +	signal TMM_CACHE_ADDR : std_logic_vector(PPU_TMM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal TMM_CACHE : std_logic_vector((PPU_SPRITE_WORD_COUNT * PPU_TMM_DATA_WIDTH)-1 downto 0); +begin +	-- output drivers +	CIDX <= T_CIDX when OE = '1' else (others => 'Z'); +	-- CIDX combination +	T_CIDX <= FAM_REG_COL_IDX & TMM_DATA_PAL_IDX; + +	-- FAM memory +	FAM : component er_ram +		generic map( +			ADDR_W => PPU_FAM_ADDR_WIDTH, +			DATA_W => PPU_FAM_DATA_WIDTH, +			ADDR_LOW => IDX*2, +			ADDR_RANGE => 2) +		port map( +			CLK => CLK, +			RST => RESET, +			WEN => FAM_WEN, +			ADDR => FAM_ADDR, +			DATA => FAM_DATA, +			REG => INT_FAM); + +	-- pixel position within bounding box of sprite +	SPRITE_ACTIVE <= '1' when ((unsigned(X) + 16) >= unsigned(FAM_REG_POS_H)) and +	                          ((unsigned(X) + 16) < (unsigned(FAM_REG_POS_H) + to_unsigned(PPU_SPRITE_WIDTH, PPU_POS_H_WIDTH))) and +	                          ((unsigned(Y) + 16) >= unsigned(FAM_REG_POS_V)) and +	                          ((unsigned(Y) + 16) < (unsigned(FAM_REG_POS_V) + to_unsigned(PPU_SPRITE_HEIGHT, PPU_POS_V_WIDTH))) else '0'; + +	-- (sprite local) pixel coords +	TILE_PIDX_X <= resize(unsigned(X) + 16 - resize(unsigned(FAM_REG_POS_H), TILE_PIDX_X'length), TILE_PIDX_X'length); +	TILE_PIDX_Y <= resize(unsigned(Y) + 16 - resize(unsigned(FAM_REG_POS_V), TILE_PIDX_Y'length), TILE_PIDX_Y'length); + +	-- transform local coords +	transform: component ppu_sprite_transform port map( +		XI => TILE_PIDX_X, +		YI => TILE_PIDX_Y, +		FLIP_H => FAM_REG_FLIP_H, +		FLIP_V => FAM_REG_FLIP_V, +		XO => TRANS_TILE_PIDX_X, +		YO => TRANS_TILE_PIDX_Y); + +	-- pixel index +	TRANS_TILE_PIXEL_IDX <= integer(PPU_SPRITE_WIDTH) * to_integer(TRANS_TILE_PIDX_Y) + to_integer(TRANS_TILE_PIDX_X); +	-- palette color at pixel +	TMM_DATA_PAL_IDX <= TMM_CACHE(TRANS_TILE_PIXEL_IDX * integer(PPU_PALETTE_COLOR_WIDTH) + integer(PPU_PALETTE_COLOR_WIDTH)-1 downto TRANS_TILE_PIXEL_IDX * integer(PPU_PALETTE_COLOR_WIDTH)); +	-- if pixel in sprite hitbox and TMM_DATA_PAL_IDX > 0 +	HIT <= SPRITE_ACTIVE and (nor TMM_DATA_PAL_IDX); + +	-- FETCH LOGIC BELOW +	TMM_ADDR <= T_TMM_ADDR when TMM_CACHE_UPDATE_TURN else (others => 'Z'); +	T_TMM_DATA <= TMM_DATA; + +	-- TTM cache +	ttm_cache : component er_ram +		generic map( +			ADDR_W => PPU_TMM_ADDR_WIDTH, +			DATA_W => PPU_TMM_DATA_WIDTH, +			ADDR_LOW => 0, +			ADDR_RANGE => PPU_SPRITE_WORD_COUNT) +		port map( +			CLK => CLK, +			RST => RESET, +			WEN => TMM_CACHE_WEN, +			ADDR => TMM_CACHE_ADDR, +			DATA => TMM_CACHE_DATA, +			REG => TMM_CACHE); + +	-- fetch machine, should do the following (offset data read by one clock -> propagation/lookup delay): +	-- CLK[53 * IDX + 0] (addr = 0) +	-- CLK[53 * IDX + 1] (addr = 1, read data[0]) +	-- CLK[53 * IDX + 2] (addr = 2, read data[1]), etc +	-- a full tile is 52 words, but since the offset is 1 clock, a total copy takes 53 clock cycles +	process(CLK, RESET, FETCH) +		constant TMM_FETCH_CLK_RANGE_BEGIN : natural := PPU_TMM_CACHE_FETCH_C_COUNT * IDX; -- fetch CLK count for copying this module's sprite from TMM +		variable TMM_FETCH_CTR : unsigned(PPU_TMM_CACHE_FETCH_A_WIDTH-1 downto 0) := (others => '0'); -- CLK counter while FETCH=1 +		variable TMM_FETCH_CTR_REL : unsigned(PPU_TMM_CACHE_FETCH_A_WIDTH-1 downto 0) := (others => '0'); -- CLK counter relative for sprite[IDX] +	begin +		if RESET = '1' or FETCH = '0' then +			TMM_FETCH_CTR := (others => '0'); +			TMM_FETCH_CTR_REL := (others => '0'); +			TMM_CACHE_WEN <= '0'; +			TMM_CACHE_UPDATE_TURN <= '0'; +		elsif rising_edge(CLK) then +			TMM_FETCH_CTR := TMM_FETCH_CTR + 1; +			TMM_FETCH_CTR_REL := TMM_FETCH_CTR - TMM_FETCH_CLK_RANGE_BEGIN; + +			if TMM_FETCH_CTR >= TMM_FETCH_CLK_RANGE_BEGIN and +			   TMM_FETCH_CTR < (TMM_FETCH_CLK_RANGE_BEGIN + PPU_TMM_CACHE_FETCH_C_COUNT) then +				TMM_CACHE_UPDATE_TURN <= '1'; +				if TMM_FETCH_CTR_REL < PPU_TMM_CACHE_FETCH_C_COUNT - 1 then -- calculate address until second to last clock +					T_TMM_ADDR <= std_logic_vector(resize(TMM_FETCH_CTR - IDX, T_TMM_ADDR'length)); +					TMM_CACHE_ADDR <= std_logic_vector(resize(TMM_FETCH_CTR_REL - 1, TMM_CACHE_ADDR'length)); +				end if; + +				if TMM_FETCH_CTR_REL > 0 then -- read offset +					TMM_CACHE_DATA <= T_TMM_DATA; +					TMM_CACHE_WEN <= '1'; +				end if; +			else +				TMM_CACHE_WEN <= '0'; +				TMM_CACHE_UPDATE_TURN <= '0'; +			end if; +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_sprite_fg_tb.vhd b/basys3/basys3.srcs/ppu_sprite_fg_tb.vhd new file mode 100644 index 0000000..19b9f35 --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_fg_tb.vhd @@ -0,0 +1,140 @@ +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_fg_tb is +end ppu_sprite_fg_tb; + +architecture Behavioral of ppu_sprite_fg_tb is +	component ppu_sprite_fg -- foreground sprite +		generic ( +			IDX : natural := 0); -- sprite index number +		port( +			-- inputs +			CLK : in std_logic; -- system clock +			RESET : in std_logic; -- reset internal memory and clock counters +			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 +			FETCH : in std_logic; -- fetch sprite data from TMM +			VBLANK : in std_logic; -- fetch during vblank + +			-- internal memory block (FAM) +			FAM_WEN : in std_logic; -- VRAM FAM write enable +			FAM_ADDR : in std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0); -- VRAM fam address +			FAM_DATA : in std_logic_vector(PPU_FAM_DATA_WIDTH-1 downto 0); -- VRAM fam data + +			-- used memory blocks +			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 +			HIT : out std_logic); -- current pixel is not transparent +	end component; +	signal CLK : std_logic := '0'; +	signal RESET : std_logic := '0'; +	signal OE : std_logic := '0'; +	signal X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); +	signal Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); +	signal FETCH : std_logic := '0'; +	signal VBLANK : std_logic := '0'; +	signal FAM_WEN : std_logic := '0'; +	signal FAM_ADDR : std_logic_vector(PPU_FAM_ADDR_WIDTH-1 downto 0) := (others => '0'); +	signal FAM_DATA : std_logic_vector(PPU_FAM_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) := (others => '0'); +	signal HIT : std_logic; + +	signal CLK_I : unsigned(31 downto 0) := (others => '0'); +begin +	uut: component ppu_sprite_fg +		generic map( IDX => 2 ) +		port map( +			CLK => CLK, +			RESET => RESET, +			OE => OE, +			X => X, +			Y => Y, +			FETCH => FETCH, +			VBLANK => VBLANK, +			FAM_WEN => FAM_WEN, +			FAM_ADDR => FAM_ADDR, +			FAM_DATA => FAM_DATA, +			TMM_ADDR => TMM_ADDR, +			TMM_DATA => TMM_DATA, +			CIDX => CIDX, +			HIT => HIT); + +	tb : process +	begin +		-- initialize TMM cache +		RESET <= '1'; wait for 1 ns; RESET <= '0'; wait for 1 ns; + +		OE <= '1'; +		VBLANK <= '0'; +		FETCH <= '0'; + +		-- FAM contents: +		-- flip horizontally +		-- xy -> (42-16, 8-16) = (26, -8) +		-- palette index 2 +		-- tilemap index 460 (0x1cc) +		-- = hex((1 << 31) | (0 << 30) | (42 << 21) | (8 << 13) | (2 << 10) | (460 << 0)) +		FAM_WEN <= '1'; +		FAM_ADDR <= std_logic_vector(to_unsigned(16#0005#, FAM_ADDR'length)); +		FAM_DATA <= std_logic_vector(to_unsigned(16#8541#, FAM_DATA'length)); +		CLK <= '1'; wait for 1 ns; CLK <= '0'; wait for 1 ns; +		FAM_ADDR <= std_logic_vector(to_unsigned(16#0004#, FAM_ADDR'length)); +		FAM_DATA <= std_logic_vector(to_unsigned(16#09cc#, FAM_DATA'length)); +		CLK <= '1'; wait for 1 ns; CLK <= '0'; wait for 1 ns; +		FAM_WEN <= '0'; + +		for i in 0 to 32 loop +			if i = 0 then +				X <= std_logic_vector(to_unsigned(25, X'length)); +				Y <= std_logic_vector(to_unsigned(60, Y'length)); +			end if; + +			if i = 3 then +				X <= std_logic_vector(to_unsigned(29, X'length)); +				Y <= std_logic_vector(to_unsigned(4, Y'length)); +			end if; +	 +			wait for 5 ns; CLK <= '1'; wait for 5 ns; CLK <= '0'; +		end loop; + +		wait for 1 ns; +		RESET <= '1'; +		wait for 10 ns; +		RESET <= '0'; +		VBLANK <= '1'; +		FETCH <= '1'; +		wait for 1 ns; + +		-- FETCH check +		for i in 0 to 500 loop +			CLK_I <= to_unsigned(i, 32); +			-- if i > 10 then +			-- 	OE <= '1'; +			-- end if; +			-- if i > 20 then +			-- 	RESET <= '1'; +			-- end if; + +			TMM_DATA <= std_logic_vector(to_unsigned(i - 106, TMM_DATA'length)); +	 +			CLK <= '1'; +			wait for 1 ns; +			CLK <= '0'; +			wait for 1 ns; +		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..f94616c --- /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 unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile +	YI : in unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile +	FLIP_H, FLIP_V : in std_logic; -- flip sprite +	XO : out unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile +	YO : out unsigned(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 : unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); +	signal FLIPPED_Y : unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); +begin +	FLIPPED_X <= to_unsigned(PPU_SPRITE_WIDTH-1, PPU_SPRITE_POS_H_WIDTH) - XI; +	FLIPPED_Y <= to_unsigned(PPU_SPRITE_HEIGHT-1, PPU_SPRITE_POS_V_WIDTH) - YI; + +	XO <= FLIPPED_X when FLIP_V = '1' else XI; +	YO <= FLIPPED_Y when FLIP_H = '1' else YI; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_sprite_transform_tb.vhd b/basys3/basys3.srcs/ppu_sprite_transform_tb.vhd new file mode 100644 index 0000000..516a653 --- /dev/null +++ b/basys3/basys3.srcs/ppu_sprite_transform_tb.vhd @@ -0,0 +1,66 @@ +library ieee; +library unisim; +library work; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use unisim.vcomponents.all; +use work.ppu_consts.all; + +entity ppu_sprite_transform_tb is +end ppu_sprite_transform_tb; + +architecture behavioral of ppu_sprite_transform_tb is +	component ppu_sprite_transform port( -- flip sprites +		XI : in unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile +		YI : in unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile +		FLIP_H, FLIP_V : in std_logic; -- flip sprite +		XO : out unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile +		YO : out unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0)); -- new pixel position relative to tile +	end component; + +	signal XI : unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); +	signal YI : unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); +	signal FLIP_H, FLIP_V : std_logic := '0'; +	signal XO : unsigned(PPU_SPRITE_POS_H_WIDTH-1 downto 0); +	signal YO : unsigned(PPU_SPRITE_POS_V_WIDTH-1 downto 0); +begin +	uut : component ppu_sprite_transform +		port map( +			XI => XI, +			YI => YI, +			FLIP_H => FLIP_H, +			FLIP_V => FLIP_V, +			XO => XO, +			YO => YO); + +	tb : process +	begin +		XI <= to_unsigned(4, PPU_SPRITE_POS_H_WIDTH); +		YI <= to_unsigned(6, PPU_SPRITE_POS_V_WIDTH); +		wait for 5 ns; + +		XI <= to_unsigned(2, PPU_SPRITE_POS_H_WIDTH); +		YI <= to_unsigned(14, PPU_SPRITE_POS_V_WIDTH); +		wait for 5 ns; + +		FLIP_H <= '1'; +		wait for 5 ns; + +		FLIP_V <= '1'; +		wait for 5 ns; + +		XI <= to_unsigned(6, PPU_SPRITE_POS_H_WIDTH); +		YI <= to_unsigned(8, PPU_SPRITE_POS_V_WIDTH); +		wait for 5 ns; + +		FLIP_H <= '0'; +		wait for 5 ns; + +		XI <= to_unsigned(2, PPU_SPRITE_POS_H_WIDTH); +		YI <= to_unsigned(14, PPU_SPRITE_POS_V_WIDTH); +		wait for 5 ns; + +		wait; -- stop for simulator +	end process; +end; diff --git a/basys3/basys3.srcs/ppu_vga_native.vhd b/basys3/basys3.srcs/ppu_vga_native.vhd new file mode 100644 index 0000000..47288e9 --- /dev/null +++ b/basys3/basys3.srcs/ppu_vga_native.vhd @@ -0,0 +1,95 @@ +library ieee; +use ieee.std_logic_1164.all; +use work.ppu_consts.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; + +entity ppu_vga_native is port ( +	CLK: in std_logic; -- system clock +	RESET: in std_logic; + +	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 +	PREADY: in std_logic; -- current pixel ready (pixel color is stable) +	RI,GI,BI: in std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color in + +	RO,GO,BO: out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color out +	VSYNC, HSYNC: out std_logic); -- VGA sync outputs +end ppu_vga_native; + +architecture Behavioral of ppu_vga_native is +	type line_buffer is array(319 downto 0) of std_logic_vector(11 downto 0); +	signal ram_x0 : line_buffer; -- buffer 0 +	signal ram_x1: line_buffer; -- buffer 1 +	signal hcount: std_logic_vector(9 downto 0):= (others => '0'); +	signal vcount: std_logic_vector(9 downto 0):= (others => '0'); +	signal clk_counter: std_logic_vector(1 downto 0):= (others => '0'); +	signal rgb_out : std_logic_vector(11 downto 0):= (others => '0'); -- output colors +	signal px : integer; -- conversion for hcount +	signal py :integer; -- conversion for vcount +	signal buffer_filled_on_buffer0 : integer; +	signal buffer_filled_on_buffer1 : integer; +begin +	process (clk, x, y) +		variable v_x : integer; -- integer to hold vector X +	begin +		if rising_edge(clk) then +			clk_counter <= clk_counter + 1; +			if clk_counter = "11" then +				v_x := to_integer(unsigned(x) - 72); +				if v_x >= 0 and v_x < 320 and PREADY = '1' then +					if y(0) = '0' then +						ram_x0(v_x) <= RI & GI & BI; +						if v_x = 319 then +							buffer_filled_on_buffer0 <= to_integer(unsigned(y) - 14); +						end if; +					else +						ram_x1(v_x) <= RI & GI & BI; +						if v_x = 319 then +							buffer_filled_on_buffer1 <= to_integer(unsigned(y) - 14); +						end if; +					end if; +				end if; +				-- T display(display data) +				if (hcount >= 144) and (hcount < 784) and (vcount >= 31) and (vcount < 511) then +					px <= to_integer(unsigned(hcount) - 144); +					py <= to_integer(unsigned(vcount) - 31); +					if buffer_filled_on_buffer0 = (py/2) then +						rgb_out <= ram_x0(px/2); +					elsif buffer_filled_on_buffer1 = (py/2) then +						rgb_out <= ram_x1(px/2); +					else +						rgb_out <= (others => '0'); +					end if; +				end if; +				-- pulse width +				hsync <= '1'; +				if hcount < 97 then +					hsync <= '0'; +				end if; + +				vsync <= '1'; +				if vcount < 3 then +					vsync <= '0'; +				end if; + +				-- sync pulse time +				hcount <= hcount + 1; + +				if hcount = 800 then +					vcount <= vcount + 1; +					hcount <= (others => '0'); +				end if; + +				if vcount = 521 then +					vcount <= (others => '0'); +				end if; +			end if; + +			-- output colors +		RO <= rgb_out(11 downto 8); +		GO <= rgb_out(7 downto 4); +		BO <= rgb_out(3 downto 0); +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_vga_native_tb.vhd b/basys3/basys3.srcs/ppu_vga_native_tb.vhd new file mode 100644 index 0000000..06061a0 --- /dev/null +++ b/basys3/basys3.srcs/ppu_vga_native_tb.vhd @@ -0,0 +1,89 @@ +library ieee; +library unisim; +use ieee.std_logic_1164.all; +use work.ppu_consts.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; +use unisim.vcomponents.all; + +entity ppu_vga_native_tb is +end ppu_vga_native_tb; + +architecture Behavioral of ppu_vga_native_tb is +	component ppu_vga_native port ( +		CLK : in std_logic; -- system clock +		RESET : in std_logic; + +		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 +		PREADY : in std_logic; -- current pixel ready (pixel color is stable) +		RI,GI,BI : in std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color in + +		RO,GO,BO : out std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0); -- VGA color out +		VSYNC, HSYNC : out std_logic); -- VGA sync outputs +	end component; +	signal CLK : std_logic := '0'; +	signal RST : std_logic := '0'; +	signal PREADY : std_logic := '0'; + +	signal X : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); +	signal Y : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); + +	signal RI,GI,BI : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0) := (others => '0'); -- VGA color in +	signal RO,GO,BO : std_logic_vector(PPU_COLOR_OUTPUT_DEPTH-1 downto 0) := (others => '0'); -- VGA color out +	signal VSYNC, HSYNC :  std_logic := '0'; + +	signal Xas : integer := 72; +	signal Yas : integer := 14; +	signal counter : std_logic_vector(1 downto 0) := (others => '0'); +begin +	uut : ppu_vga_native port map( +		CLK => CLK, +		RESET => RST, +		X => X, +		Y => Y, +		PREADY => PREADY, +		RI => RI, +		GI => GI, +		BI => BI, +		RO => RO, +		GO => GO, +		BO => BO, +		VSYNC => VSYNC, +		HSYNC => HSYNC +	); + +	tb : process +	begin +		CLK <= '1'; +		wait for 1 ps; +		CLK <= '0'; +		wait for 1 ps; +	end process; + +	process(CLK) +	begin +		if rising_edge(CLK) then +			counter <= counter + 1; +		end if; + +		if(counter = "11") then +			pready <= '1'; +			ri <= x"d"; +			gi <= x"a"; +			bi <= x"d"; +			x <= std_logic_vector(to_unsigned(Xas, x'length)); +			if (Xas = 391) then +				Xas <= 72; +				y <= std_logic_vector(to_unsigned(Yas, y'length)); +				if (Yas = 255) then +					Yas <= 14; +				else +					Yas <= Yas + 1; +				end if; +			else +				Xas <= Xas + 1; +			end if; +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/ppu_vga_tiny.vhd b/basys3/basys3.srcs/ppu_vga_tiny.vhd new file mode 100644 index 0000000..0e496f6 --- /dev/null +++ b/basys3/basys3.srcs/ppu_vga_tiny.vhd @@ -0,0 +1,73 @@ +library ieee; +use ieee.std_logic_1164.all; +use work.ppu_consts.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; + +entity ppu_vga_tiny is port ( +	CLK : in std_logic; -- system clock +	RESET : in std_logic; + +	X : out std_logic_vector(PPU_POS_H_WIDTH-1 downto 0); -- current screen pixel x +	Y : out std_logic_vector(PPU_POS_V_WIDTH-1 downto 0); -- current screen pixel y + +	VSYNC, VBLANK, +	HSYNC, HBLANK : out std_logic); -- VGA sync outputs +end ppu_vga_tiny; + +architecture Behavioral of ppu_vga_tiny is +	signal hcount : std_logic_vector(PPU_POS_H_WIDTH-1 downto 0) := (others => '0'); +	signal vcount : std_logic_vector(PPU_POS_V_WIDTH-1 downto 0) := (others => '0'); +	signal clk_counter : std_logic_vector(4 downto 0) := (others => '0'); +begin +	process (CLK) +	begin +		if rising_edge(CLK) then +			clk_counter <= clk_counter + 1; +			if(clk_counter > 15) then +				clk_counter <= (others => '0'); +				-- x,y data out +				X <= hcount; +				Y <= vcount; + +				--pulse width +				if hcount < 32 or hcount >= 320-80 then +					hsync <= '0'; +				else +					hsync <= '1'; +				end if; + +				if vcount < 8 or vcount >= 240-15 then +					vsync <= '0'; +				else +					vsync <= '1'; +				end if; + +				-- Hblank and Vblank outputs +				if hcount >= 320-80 then +					hblank <= '1'; +				else +					hblank <= '0'; +				end if; + +				if vcount >= 240-15 then +					vblank <= '1'; +				else +					vblank <= '0'; +				end if; + +				-- sync pulse time +				hcount <= hcount + 1; + +				if hcount = 400 then +					vcount <= vcount + 1; +					hcount <= (others => '0'); +				end if; + +				if vcount = 255 then +					vcount <= (others => '0'); +				end if; +			end if; +		end if; +	end process; +end Behavioral; diff --git a/basys3/basys3.srcs/sources_1/ip/ppu_bam/ppu_bam.xci b/basys3/basys3.srcs/sources_1/ip/ppu_bam/ppu_bam.xci index f5e1696..e299ea1 100644 --- a/basys3/basys3.srcs/sources_1/ip/ppu_bam/ppu_bam.xci +++ b/basys3/basys3.srcs/sources_1/ip/ppu_bam/ppu_bam.xci @@ -163,7 +163,7 @@          "BOARD_CONNECTIONS": [ { "value": "" } ],          "DEVICE": [ { "value": "xc7a35t" } ],          "PACKAGE": [ { "value": "cpg236" } ], -        "PREFHDL": [ { "value": "VERILOG" } ], +        "PREFHDL": [ { "value": "VHDL" } ],          "SILICON_REVISION": [ { "value": "" } ],          "SIMULATOR_LANGUAGE": [ { "value": "MIXED" } ],          "SPEEDGRADE": [ { "value": "-1" } ], diff --git a/basys3/basys3.srcs/sources_1/ip/ppu_tmm/ppu_tmm.xci b/basys3/basys3.srcs/sources_1/ip/ppu_tmm/ppu_tmm.xci index 51914b1..9663635 100644 --- a/basys3/basys3.srcs/sources_1/ip/ppu_tmm/ppu_tmm.xci +++ b/basys3/basys3.srcs/sources_1/ip/ppu_tmm/ppu_tmm.xci @@ -14,7 +14,7 @@          "Use_AXI_ID": [ { "value": "false", "resolve_type": "user", "format": "bool", "enabled": false, "usage": "all" } ],          "AXI_ID_Width": [ { "value": "4", "resolve_type": "user", "format": "long", "enabled": false, "usage": "all" } ],          "Memory_Type": [ { "value": "Single_Port_RAM", "resolve_type": "user", "usage": "all" } ], -        "PRIM_type_to_Implement": [ { "value": "BRAM", "resolve_type": "user", "usage": "all" } ], +        "PRIM_type_to_Implement": [ { "value": "BRAM", "resolve_type": "user", "enabled": false, "usage": "all" } ],          "Enable_32bit_Address": [ { "value": "false", "resolve_type": "user", "format": "bool", "usage": "all" } ],          "ecctype": [ { "value": "No_ECC", "resolve_type": "user", "enabled": false, "usage": "all" } ],          "ECC": [ { "value": "false", "resolve_type": "user", "format": "bool", "enabled": false, "usage": "all" } ], @@ -32,13 +32,13 @@          "Algorithm": [ { "value": "Minimum_Area", "resolve_type": "user", "usage": "all" } ],          "Primitive": [ { "value": "8kx2", "resolve_type": "user", "enabled": false, "usage": "all" } ],          "Assume_Synchronous_Clk": [ { "value": "false", "resolve_type": "user", "format": "bool", "enabled": false, "usage": "all" } ], -        "Write_Width_A": [ { "value": "16", "resolve_type": "user", "format": "long", "usage": "all" } ], -        "Write_Depth_A": [ { "value": "49152", "value_src": "user", "resolve_type": "user", "format": "long", "usage": "all" } ], -        "Read_Width_A": [ { "value": "16", "resolve_type": "user", "usage": "all" } ], +        "Write_Width_A": [ { "value": "15", "value_src": "user", "resolve_type": "user", "format": "long", "usage": "all" } ], +        "Write_Depth_A": [ { "value": "53248", "value_src": "user", "resolve_type": "user", "format": "long", "usage": "all" } ], +        "Read_Width_A": [ { "value": "15", "resolve_type": "user", "usage": "all" } ],          "Operating_Mode_A": [ { "value": "WRITE_FIRST", "resolve_type": "user", "usage": "all" } ],          "Enable_A": [ { "value": "Always_Enabled", "value_src": "user", "resolve_type": "user", "usage": "all" } ], -        "Write_Width_B": [ { "value": "16", "resolve_type": "user", "enabled": false, "usage": "all" } ], -        "Read_Width_B": [ { "value": "16", "resolve_type": "user", "enabled": false, "usage": "all" } ], +        "Write_Width_B": [ { "value": "15", "resolve_type": "user", "enabled": false, "usage": "all" } ], +        "Read_Width_B": [ { "value": "15", "resolve_type": "user", "enabled": false, "usage": "all" } ],          "Operating_Mode_B": [ { "value": "WRITE_FIRST", "resolve_type": "user", "enabled": false, "usage": "all" } ],          "Enable_B": [ { "value": "Always_Enabled", "resolve_type": "user", "enabled": false, "usage": "all" } ],          "Register_PortA_Output_of_Memory_Primitives": [ { "value": "true", "resolve_type": "user", "format": "bool", "usage": "all" } ], @@ -110,10 +110,10 @@          "C_USE_BYTE_WEA": [ { "value": "0", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_WEA_WIDTH": [ { "value": "1", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_WRITE_MODE_A": [ { "value": "WRITE_FIRST", "resolve_type": "generated", "usage": "all" } ], -        "C_WRITE_WIDTH_A": [ { "value": "16", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_READ_WIDTH_A": [ { "value": "16", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_WRITE_DEPTH_A": [ { "value": "49152", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_READ_DEPTH_A": [ { "value": "49152", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_WRITE_WIDTH_A": [ { "value": "15", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_READ_WIDTH_A": [ { "value": "15", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_WRITE_DEPTH_A": [ { "value": "53248", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_READ_DEPTH_A": [ { "value": "53248", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_ADDRA_WIDTH": [ { "value": "16", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_HAS_RSTB": [ { "value": "0", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_RST_PRIORITY_B": [ { "value": "CE", "resolve_type": "generated", "usage": "all" } ], @@ -124,10 +124,10 @@          "C_USE_BYTE_WEB": [ { "value": "0", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_WEB_WIDTH": [ { "value": "1", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_WRITE_MODE_B": [ { "value": "WRITE_FIRST", "resolve_type": "generated", "usage": "all" } ], -        "C_WRITE_WIDTH_B": [ { "value": "16", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_READ_WIDTH_B": [ { "value": "16", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_WRITE_DEPTH_B": [ { "value": "49152", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_READ_DEPTH_B": [ { "value": "49152", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_WRITE_WIDTH_B": [ { "value": "15", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_READ_WIDTH_B": [ { "value": "15", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_WRITE_DEPTH_B": [ { "value": "53248", "resolve_type": "generated", "format": "long", "usage": "all" } ], +        "C_READ_DEPTH_B": [ { "value": "53248", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_ADDRB_WIDTH": [ { "value": "16", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_HAS_MEM_OUTPUT_REGS_A": [ { "value": "1", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_HAS_MEM_OUTPUT_REGS_B": [ { "value": "0", "resolve_type": "generated", "format": "long", "usage": "all" } ], @@ -153,9 +153,9 @@          "C_EN_SHUTDOWN_PIN": [ { "value": "0", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_EN_SAFETY_CKT": [ { "value": "1", "resolve_type": "generated", "format": "long", "usage": "all" } ],          "C_DISABLE_WARN_BHV_RANGE": [ { "value": "0", "resolve_type": "generated", "format": "long", "usage": "all" } ], -        "C_COUNT_36K_BRAM": [ { "value": "22", "resolve_type": "generated", "usage": "all" } ], -        "C_COUNT_18K_BRAM": [ { "value": "1", "resolve_type": "generated", "usage": "all" } ], -        "C_EST_POWER_SUMMARY": [ { "value": "Estimated Power for IP     :     16.534446 mW", "resolve_type": "generated", "usage": "all" } ] +        "C_COUNT_36K_BRAM": [ { "value": "19", "resolve_type": "generated", "usage": "all" } ], +        "C_COUNT_18K_BRAM": [ { "value": "8", "resolve_type": "generated", "usage": "all" } ], +        "C_EST_POWER_SUMMARY": [ { "value": "Estimated Power for IP     :     13.861152 mW", "resolve_type": "generated", "usage": "all" } ]        },        "project_parameters": {          "ARCHITECTURE": [ { "value": "artix7" } ], @@ -163,7 +163,7 @@          "BOARD_CONNECTIONS": [ { "value": "" } ],          "DEVICE": [ { "value": "xc7a35t" } ],          "PACKAGE": [ { "value": "cpg236" } ], -        "PREFHDL": [ { "value": "VERILOG" } ], +        "PREFHDL": [ { "value": "VHDL" } ],          "SILICON_REVISION": [ { "value": "" } ],          "SIMULATOR_LANGUAGE": [ { "value": "MIXED" } ],          "SPEEDGRADE": [ { "value": "-1" } ], @@ -189,8 +189,8 @@          "rsta": [ { "direction": "in", "driver_value": "0" } ],          "wea": [ { "direction": "in", "size_left": "0", "size_right": "0", "driver_value": "0" } ],          "addra": [ { "direction": "in", "size_left": "15", "size_right": "0", "driver_value": "0" } ], -        "dina": [ { "direction": "in", "size_left": "15", "size_right": "0", "driver_value": "0" } ], -        "douta": [ { "direction": "out", "size_left": "15", "size_right": "0" } ], +        "dina": [ { "direction": "in", "size_left": "14", "size_right": "0", "driver_value": "0" } ], +        "douta": [ { "direction": "out", "size_left": "14", "size_right": "0" } ],          "rsta_busy": [ { "direction": "out" } ]        },        "interfaces": { diff --git a/basys3/basys3.xpr b/basys3/basys3.xpr index 466cc1f..4060a21 100644 --- a/basys3/basys3.xpr +++ b/basys3/basys3.xpr @@ -42,8 +42,10 @@      <Option Name="SimulatorGccVersionVCS" Val="9.2.0"/>      <Option Name="SimulatorGccVersionRiviera" Val="9.3.0"/>      <Option Name="SimulatorGccVersionActiveHdl" Val="9.3.0"/> +    <Option Name="TargetLanguage" Val="VHDL"/>      <Option Name="BoardPart" Val="digilentinc.com:basys3:part0:1.2"/>      <Option Name="BoardPartRepoPaths" Val="$PPRDIR/../../../../.Xilinx/Vivado/2022.2/xhub/board_store/xilinx_board_store"/> +    <Option Name="SourceMgmtMode" Val="DisplayOnly"/>      <Option Name="ActiveSimSet" Val="sim_1"/>      <Option Name="DefaultLib" Val="xil_defaultlib"/>      <Option Name="ProjectType" Val="Default"/> @@ -59,20 +61,20 @@      <Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/>      <Option Name="EnableBDX" Val="FALSE"/>      <Option Name="DSABoardId" Val="basys3"/> -    <Option Name="WTXSimLaunchSim" Val="12"/> +    <Option Name="WTXSimLaunchSim" Val="113"/>      <Option Name="WTModelSimLaunchSim" Val="0"/>      <Option Name="WTQuestaLaunchSim" Val="0"/>      <Option Name="WTIesLaunchSim" Val="0"/>      <Option Name="WTVcsLaunchSim" Val="0"/>      <Option Name="WTRivieraLaunchSim" Val="0"/>      <Option Name="WTActivehdlLaunchSim" Val="0"/> -    <Option Name="WTXSimExportSim" Val="3"/> -    <Option Name="WTModelSimExportSim" Val="3"/> -    <Option Name="WTQuestaExportSim" Val="3"/> +    <Option Name="WTXSimExportSim" Val="4"/> +    <Option Name="WTModelSimExportSim" Val="4"/> +    <Option Name="WTQuestaExportSim" Val="4"/>      <Option Name="WTIesExportSim" Val="0"/> -    <Option Name="WTVcsExportSim" Val="3"/> -    <Option Name="WTRivieraExportSim" Val="3"/> -    <Option Name="WTActivehdlExportSim" Val="3"/> +    <Option Name="WTVcsExportSim" Val="4"/> +    <Option Name="WTRivieraExportSim" Val="4"/> +    <Option Name="WTActivehdlExportSim" Val="4"/>      <Option Name="GenerateIPUpgradeLog" Val="TRUE"/>      <Option Name="XSimRadix" Val="hex"/>      <Option Name="XSimTimeUnit" Val="ns"/> @@ -96,20 +98,20 @@            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo>        </File> -      <File Path="$PSRCDIR/ppu_addr_dec.vhdl"> -        <FileInfo> +      <File Path="$PSRCDIR/ppu_pceg.vhd"> +        <FileInfo SFType="VHDL2008">            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo>        </File> -      <File Path="$PSRCDIR/ppu_pceg.vhdl"> -        <FileInfo> +      <File Path="$PSRCDIR/ppu.vhd"> +        <FileInfo SFType="VHDL2008">            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo>        </File> -      <File Path="$PSRCDIR/ppu.vhd"> -        <FileInfo> +      <File Path="$PSRCDIR/ppu_addr_dec.vhd"> +        <FileInfo SFType="VHDL2008">            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo> @@ -117,7 +119,6 @@        <File Path="$PSRCDIR/apu.vhd">          <FileInfo>            <Attr Name="UserDisabled" Val="1"/> -          <Attr Name="AutoDisabled" Val="1"/>            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo> @@ -125,7 +126,73 @@        <File Path="$PSRCDIR/apu_note_to_frequency.vhd">          <FileInfo>            <Attr Name="UserDisabled" Val="1"/> -          <Attr Name="AutoDisabled" Val="1"/> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/er_ram.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/er_ram_mod.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_aux.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_sprite_bg.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <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> +      <File Path="$PSRCDIR/ppu_sprite_fg.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_vga_tiny.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_comp.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_plut.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_vga_native.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/apu_lut_reader.vhd"> +        <FileInfo> +          <Attr Name="UserDisabled" Val="1"/>            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo> @@ -144,15 +211,14 @@      </FileSet>      <FileSet Name="sim_1" Type="SimulationSrcs" RelSrcDir="$PSRCDIR/sim_1" RelGenDir="$PGENDIR/sim_1">        <Filter Type="Srcs"/> -      <File Path="$PSRCDIR/ppu_addr_dec_tb.vhdl"> +      <File Path="$PSRCDIR/ppu_addr_dec_tb.vhd">          <FileInfo>            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo>        </File> -      <File Path="$PSRCDIR/ppu_pceg_tb.vhdl"> -        <FileInfo> -          <Attr Name="AutoDisabled" Val="1"/> +      <File Path="$PSRCDIR/ppu_pceg_tb.vhd"> +        <FileInfo SFType="VHDL2008">            <Attr Name="UsedIn" Val="synthesis"/>            <Attr Name="UsedIn" Val="simulation"/>          </FileInfo> @@ -160,14 +226,49 @@        <File Path="$PSRCDIR/apu_note_to_frequency_tb.vhd">          <FileInfo>            <Attr Name="UserDisabled" Val="1"/> -          <Attr Name="AutoDisabled" Val="1"/> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/er_ram_mod_tb.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/er_ram_tb.vhd"> +        <FileInfo SFType="VHDL2008"> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_aux_tb.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <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> +      <File Path="$PSRCDIR/ppu_sprite_transform_tb.vhd"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="simulation"/> +        </FileInfo> +      </File> +      <File Path="$PSRCDIR/ppu_sprite_fg_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_fg_tb"/>          <Option Name="TopLib" Val="xil_defaultlib"/>          <Option Name="TransportPathDelay" Val="0"/>          <Option Name="TransportIntDelay" Val="0"/> @@ -177,10 +278,19 @@          <Option Name="PamSignalDriverFile" Val="xil_bypass_driver"/>          <Option Name="PamPseudoTop" Val="pseudo_tb"/>          <Option Name="SrcSet" Val="sources_1"/> +        <Option Name="NLNetlistMode" Val="funcsim"/>        </Config>      </FileSet>      <FileSet Name="utils_1" Type="Utils" RelSrcDir="$PSRCDIR/utils_1" RelGenDir="$PGENDIR/utils_1">        <Filter Type="Utils"/> +      <File Path="$PSRCDIR/utils_1/imports/synth_1/ppu.dcp"> +        <FileInfo> +          <Attr Name="UsedIn" Val="synthesis"/> +          <Attr Name="UsedIn" Val="implementation"/> +          <Attr Name="UsedInSteps" Val="synth_1"/> +          <Attr Name="AutoDcp" Val="1"/> +        </FileInfo> +      </File>        <Config>          <Option Name="TopAutoSet" Val="TRUE"/>        </Config> @@ -234,11 +344,12 @@      </Simulator>    </Simulators>    <Runs Version="1" Minor="19"> -    <Run Id="synth_1" Type="Ft3:Synth" SrcSet="sources_1" Part="xc7a35tcpg236-1" ConstrsSet="constrs_1" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="true" WriteIncrSynthDcp="false" State="current" IncludeInArchive="true" IsChild="false" AutoIncrementalDir="$PSRCDIR/utils_1/imports/synth_1" AutoRQSDir="$PSRCDIR/utils_1/imports/synth_1"> +    <Run Id="synth_1" Type="Ft3:Synth" SrcSet="sources_1" Part="xc7a35tcpg236-1" ConstrsSet="constrs_1" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="true" IncrementalCheckpoint="$PSRCDIR/utils_1/imports/synth_1/ppu.dcp" WriteIncrSynthDcp="false" State="current" Dir="$PRUNDIR/synth_1" IncludeInArchive="true" IsChild="false" AutoIncrementalDir="$PSRCDIR/utils_1/imports/synth_1" AutoRQSDir="$PSRCDIR/utils_1/imports/synth_1">        <Strategy Version="1" Minor="2">          <StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2022"/>          <Step Id="synth_design"/>        </Strategy> +      <GeneratedRun Dir="$PRUNDIR" File="gen_run.xml"/>        <ReportStrategy Name="Vivado Synthesis Default Reports" Flow="Vivado Synthesis 2022"/>        <Report Name="ROUTE_DESIGN.REPORT_METHODOLOGY" Enabled="1"/>        <RQSFiles/> |