aboutsummaryrefslogtreecommitdiff
path: root/basys3/basys3.srcs/ppu_sprite_fg.vhd
blob: 340104a5ce4a420f15d141bf71c79fa580d56a01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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
		PL_CLK : in std_logic; -- pipeline 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

		-- 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 std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- pixel position relative to tile
		YI : in std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- pixel position relative to tile
		FLIP_H, FLIP_V : in std_logic; -- flip sprite
		XO : out std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- new pixel position relative to tile
		YO : out std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0)); -- new pixel position relative to tile
	end component;
	component er_ram -- exposed register RAM
		generic(
			ADDR_W : natural := PPU_FAM_ADDR_WIDTH; -- ADDR line width
			DATA_W : natural := PPU_FAM_DATA_WIDTH; -- DATA line width
			ADDR_LOW : natural := IDX*2; -- starting address
			ADDR_RANGE : natural := 2); -- 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 temp + registers
	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_TMM_ADDR, PL_TMM_DATA);
	signal state : states := PL_TMM_ADDR;

	-- 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 PIXEL_ABS_X, PIXEL_ABS_Y : integer := 0; -- absolute pixel position (relative to FG canvas instead of viewport)
	-- signal TILE_IDX_X, TILE_IDX_Y : integer := 0; -- background canvas tile grid xy
	-- signal TILE_PIXEL_IDX_X, TILE_PIXEL_IDX_Y : integer := 0; -- xy position of pixel within tile (local tile coords)
	-- signal TRANS_TILE_PIDX_X, TRANS_TILE_PIDX_Y : integer := 0; -- transformed xy position of pixel within tile
	-- signal TRANS_TILE_PIXEL_IDX : integer := 0; -- index of pixel within tile (reading order)
	-- signal TRANSFORM_XI, TRANSFORM_XO : std_logic_vector(PPU_SPRITE_POS_H_WIDTH-1 downto 0); -- transform inputs/outputs (x axis)
	-- signal TRANSFORM_YI, TRANSFORM_YO : std_logic_vector(PPU_SPRITE_POS_V_WIDTH-1 downto 0); -- transform inputs/outputs (y axis)
	-- 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
begin
	-- output drivers
	CIDX <= T_CIDX when OE = '1' else (others => 'Z');
	TMM_ADDR <= R_TMM_ADDR;
	T_TMM_DATA <= TMM_DATA;
	-- CIDX combination
	T_CIDX <= FAM_REG_COL_IDX & TMM_DATA_PAL_IDX;

	-- FAM memory
	FAM : component er_ram port map(
		CLK => CLK,
		RST => RESET,
		WEN => FAM_WEN,
		ADDR => FAM_ADDR,
		DATA => FAM_DATA,
		REG => INT_FAM);

	-- -- -- FAM address calculations
	-- -- PIXEL_ABS_X <= to_integer(unsigned(X)) + to_integer(unsigned(FG_SHIFT_X));
	-- -- PIXEL_ABS_Y <= to_integer(unsigned(Y)) + to_integer(unsigned(FG_SHIFT_Y));
	-- -- TILE_IDX_X <= PIXEL_ABS_X / 16;
	-- -- TILE_IDX_Y <= PIXEL_ABS_Y / 16;
	-- -- TILE_PIXEL_IDX_X <= PIXEL_ABS_X - TILE_IDX_X * 16;
	-- -- TILE_PIXEL_IDX_Y <= PIXEL_ABS_Y - TILE_IDX_Y * 16;
	-- -- T_FAM_ADDR <= std_logic_vector(to_unsigned((TILE_IDX_Y * integer(PPU_FG_CANVAS_TILES_H)) + TILE_IDX_X, PPU_FAM_ADDR_WIDTH));

	-- -- -- FAM data dependant calculations
	-- -- TRANSFORM_XI <= std_logic_vector(to_unsigned(TILE_PIXEL_IDX_X, PPU_SPRITE_POS_H_WIDTH));
	-- -- TRANSFORM_YI <= std_logic_vector(to_unsigned(TILE_PIXEL_IDX_Y, PPU_SPRITE_POS_V_WIDTH));
	-- -- transform: component ppu_sprite_transform port map(
	-- -- 	XI => TRANSFORM_XI,
	-- -- 	YI => TRANSFORM_YI,
	-- -- 	FLIP_H => FAM_DATA_FLIP_H,
	-- -- 	FLIP_V => FAM_DATA_FLIP_V,
	-- -- 	XO => TRANSFORM_XO,
	-- -- 	YO => TRANSFORM_YO);
	-- -- TRANS_TILE_PIDX_X <= to_integer(unsigned(TRANSFORM_XO));
	-- -- TRANS_TILE_PIDX_Y <= to_integer(unsigned(TRANSFORM_YO));

	-- -- TRANS_TILE_PIXEL_IDX <= integer(PPU_SPRITE_WIDTH) * TRANS_TILE_PIDX_Y + TRANS_TILE_PIDX_X;
	-- -- TILEMAP_WORD_OFFSET <= TRANS_TILE_PIXEL_IDX / PPU_PIXELS_PER_TILE_WORD;
	-- -- PIXEL_BIT_OFFSET <= TRANS_TILE_PIXEL_IDX mod PPU_PIXELS_PER_TILE_WORD;

	-- -- T_TMM_ADDR <= std_logic_vector(to_unsigned(PPU_SPRITE_PIXELS_PER_WORD * to_integer(unsigned(FAM_DATA_TILE_IDX)) + TILEMAP_WORD_OFFSET, PPU_TMM_ADDR_WIDTH));

	-- -- -- 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_TMM_ADDR;
			-- reset internal pipeline registers
			R_TMM_ADDR <= (others => '0');
			R_TMM_DATA <= (others => '0');
		elsif rising_edge(CLK) then
			case state is
				when PL_TMM_ADDR =>
					state <= PL_TMM_DATA;
					R_TMM_ADDR <= T_TMM_ADDR;
				when PL_TMM_DATA =>
					state <= PL_TMM_ADDR;
					R_TMM_DATA <= T_TMM_DATA;
			end case;
		end if;
	end process;
end Behavioral;