1 -------------------------------------------------------------
\r
2 -------------------------------------------------------------
\r
3 ------------------- PPU VGA Output Control ------------------
\r
4 -------------------------------------------------------------
\r
5 -------------------------------------------------------------
\r
7 use ieee.std_logic_1164.all;
\r
8 use ieee.std_logic_unsigned.conv_integer;
\r
9 use ieee.std_logic_arith.conv_std_logic_vector;
\r
10 use ieee.std_logic_unsigned.all;
\r
14 pi_rst_n : in std_logic;
\r
15 pi_base_clk : in std_logic;
\r
16 pi_rnd_en : in std_logic_vector (3 downto 0);
\r
19 pi_ppu_ctrl : in std_logic_vector (7 downto 0);
\r
20 pi_ppu_mask : in std_logic_vector (7 downto 0);
\r
21 po_ppu_status : out std_logic_vector (7 downto 0);
\r
22 pi_ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
23 pi_ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
26 po_rd_n : out std_logic;
\r
27 po_wr_n : out std_logic;
\r
28 po_v_addr : out std_logic_vector (13 downto 0);
\r
29 pi_v_data : in std_logic_vector (7 downto 0);
\r
32 po_spr_ce_n : out std_logic;
\r
33 po_spr_rd_n : out std_logic;
\r
34 po_spr_wr_n : out std_logic;
\r
35 po_spr_addr : out std_logic_vector (7 downto 0);
\r
36 pi_spr_data : in std_logic_vector (7 downto 0);
\r
39 po_h_sync_n : out std_logic;
\r
40 po_v_sync_n : out std_logic;
\r
41 po_r : out std_logic_vector(3 downto 0);
\r
42 po_g : out std_logic_vector(3 downto 0);
\r
43 po_b : out std_logic_vector(3 downto 0)
\r
47 architecture rtl of render is
\r
50 --------- VGA screen constant -----------
\r
51 constant VGA_W : integer := 640;
\r
52 constant VGA_H : integer := 480;
\r
53 constant VGA_W_MAX : integer := 800;
\r
54 constant VGA_H_MAX : integer := 525;
\r
55 constant H_SP : integer := 95;
\r
56 constant H_BP : integer := 48;
\r
57 constant H_FP : integer := 15;
\r
58 constant V_SP : integer := 2;
\r
59 constant V_BP : integer := 33;
\r
60 constant V_FP : integer := 10;
\r
62 --nes screen size is emulated to align with the vga timing...
\r
63 constant HSCAN : integer := 256;
\r
64 constant VSCAN : integer := 240;
\r
65 constant HSCAN_NEXT_START : integer := 382;
\r
66 constant VSCAN_NEXT_START : integer := 262;
\r
67 constant HSCAN_SPR_MAX : integer := 321;
\r
68 constant HSCAN_OAM_EVA_START : integer := 64;
\r
70 constant PPUBNA : integer := 1; --base name address
\r
71 constant PPUVAI : integer := 2; --vram address increment
\r
72 constant PPUSPA : integer := 3; --sprite pattern table address
\r
73 constant PPUBPA : integer := 4; --background pattern table address
\r
74 constant PPUSPS : integer := 5; --sprite size
\r
75 constant PPUMS : integer := 6; --ppu master/slave
\r
76 constant PPUNEN : integer := 7; --nmi enable
\r
78 constant PPUGS : integer := 0; --grayscale
\r
79 constant PPUSBL : integer := 1; --show 8 left most bg pixel
\r
80 constant PPUSSL : integer := 2; --show 8 left most sprite pixel
\r
81 constant PPUSBG : integer := 3; --show bg
\r
82 constant PPUSSP : integer := 4; --show sprie
\r
83 constant PPUIR : integer := 5; --intensify red
\r
84 constant PPUIG : integer := 6; --intensify green
\r
85 constant PPUIB : integer := 7; --intensify blue
\r
87 constant SPRHFL : integer := 6; --flip sprigte horizontally
\r
88 constant SPRVFL : integer := 7; --flip sprigte vertically
\r
90 constant ST_BSY : integer := 4; --vram busy
\r
91 constant ST_SOF : integer := 5; --sprite overflow
\r
92 constant ST_SP0 : integer := 6; --sprite 0 hits
\r
93 constant ST_VBL : integer := 7; --vblank
\r
96 subtype nes_color_data is std_logic_vector (11 downto 0);
\r
97 type nes_color_array is array (0 to 63) of nes_color_data;
\r
98 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
\r
99 constant nes_color_palette : nes_color_array := (
\r
100 conv_std_logic_vector(16#777#, 12),
\r
101 conv_std_logic_vector(16#20b#, 12),
\r
102 conv_std_logic_vector(16#20b#, 12),
\r
103 conv_std_logic_vector(16#61a#, 12),
\r
104 conv_std_logic_vector(16#927#, 12),
\r
105 conv_std_logic_vector(16#b13#, 12),
\r
106 conv_std_logic_vector(16#a30#, 12),
\r
107 conv_std_logic_vector(16#740#, 12),
\r
108 conv_std_logic_vector(16#450#, 12),
\r
109 conv_std_logic_vector(16#360#, 12),
\r
110 conv_std_logic_vector(16#360#, 12),
\r
111 conv_std_logic_vector(16#364#, 12),
\r
112 conv_std_logic_vector(16#358#, 12),
\r
113 conv_std_logic_vector(16#000#, 12),
\r
114 conv_std_logic_vector(16#000#, 12),
\r
115 conv_std_logic_vector(16#000#, 12),
\r
116 conv_std_logic_vector(16#bbb#, 12),
\r
117 conv_std_logic_vector(16#46f#, 12),
\r
118 conv_std_logic_vector(16#44f#, 12),
\r
119 conv_std_logic_vector(16#94f#, 12),
\r
120 conv_std_logic_vector(16#d4c#, 12),
\r
121 conv_std_logic_vector(16#d46#, 12),
\r
122 conv_std_logic_vector(16#e50#, 12),
\r
123 conv_std_logic_vector(16#c70#, 12),
\r
124 conv_std_logic_vector(16#880#, 12),
\r
125 conv_std_logic_vector(16#5a0#, 12),
\r
126 conv_std_logic_vector(16#4a1#, 12),
\r
127 conv_std_logic_vector(16#4a6#, 12),
\r
128 conv_std_logic_vector(16#49c#, 12),
\r
129 conv_std_logic_vector(16#000#, 12),
\r
130 conv_std_logic_vector(16#000#, 12),
\r
131 conv_std_logic_vector(16#000#, 12),
\r
132 conv_std_logic_vector(16#fff#, 12),
\r
133 conv_std_logic_vector(16#6af#, 12),
\r
134 conv_std_logic_vector(16#58f#, 12),
\r
135 conv_std_logic_vector(16#a7f#, 12),
\r
136 conv_std_logic_vector(16#f6f#, 12),
\r
137 conv_std_logic_vector(16#f6b#, 12),
\r
138 conv_std_logic_vector(16#f73#, 12),
\r
139 conv_std_logic_vector(16#fa0#, 12),
\r
140 conv_std_logic_vector(16#ed2#, 12),
\r
141 conv_std_logic_vector(16#9e0#, 12),
\r
142 conv_std_logic_vector(16#7f4#, 12),
\r
143 conv_std_logic_vector(16#7e9#, 12),
\r
144 conv_std_logic_vector(16#6de#, 12),
\r
145 conv_std_logic_vector(16#777#, 12),
\r
146 conv_std_logic_vector(16#000#, 12),
\r
147 conv_std_logic_vector(16#000#, 12),
\r
148 conv_std_logic_vector(16#fff#, 12),
\r
149 conv_std_logic_vector(16#9df#, 12),
\r
150 conv_std_logic_vector(16#abf#, 12),
\r
151 conv_std_logic_vector(16#cbf#, 12),
\r
152 conv_std_logic_vector(16#ebf#, 12),
\r
153 conv_std_logic_vector(16#fbe#, 12),
\r
154 conv_std_logic_vector(16#fcb#, 12),
\r
155 conv_std_logic_vector(16#fda#, 12),
\r
156 conv_std_logic_vector(16#ff9#, 12),
\r
157 conv_std_logic_vector(16#cf8#, 12),
\r
158 conv_std_logic_vector(16#afa#, 12),
\r
159 conv_std_logic_vector(16#afc#, 12),
\r
160 conv_std_logic_vector(16#aff#, 12),
\r
161 conv_std_logic_vector(16#aaa#, 12),
\r
162 conv_std_logic_vector(16#000#, 12),
\r
163 conv_std_logic_vector(16#000#, 12)
\r
166 signal reg_vga_x : integer range 0 to VGA_W_MAX - 1;
\r
167 signal reg_vga_y : integer range 0 to VGA_H_MAX - 1;
\r
169 signal reg_nes_x : integer range 0 to VGA_W_MAX / 2 - 1;
\r
170 signal reg_nes_y : integer range 0 to VGA_W_MAX / 2 - 1;
\r
172 type vac_state is (
\r
184 signal reg_v_cur_state : vac_state;
\r
185 signal reg_v_next_state : vac_state;
\r
187 signal reg_v_rd_n : std_logic;
\r
188 signal reg_v_wr_n : std_logic;
\r
189 signal reg_v_addr : std_logic_vector (13 downto 0);
\r
190 signal reg_v_data : std_logic_vector (7 downto 0);
\r
194 --position and sync signal generate.
\r
195 pos_p : process (pi_rst_n, pi_base_clk)
\r
197 if (pi_rst_n = '0') then
\r
202 elsif (rising_edge(pi_base_clk)) then
\r
204 reg_nes_x <= reg_vga_x / 2;
\r
205 reg_nes_y <= reg_vga_y / 2;
\r
207 if ((pi_rnd_en(0) or pi_rnd_en(2))= '1') then
\r
208 if (reg_vga_x = VGA_W_MAX - 1) then
\r
210 if (reg_vga_x = VGA_H_MAX - 1) then
\r
213 reg_vga_y <= reg_vga_y + 1;
\r
216 reg_vga_x <= reg_vga_x + 1;
\r
219 --sync signal assert.
\r
220 if (reg_vga_x >= VGA_W + H_FP and reg_vga_x < VGA_W + H_FP + H_SP) then
\r
221 po_h_sync_n <= '0';
\r
223 po_h_sync_n <= '1';
\r
226 if (reg_vga_y >= VGA_H + V_FP and reg_vga_y < VGA_H + V_FP + V_SP) then
\r
227 po_v_sync_n <= '0';
\r
229 po_v_sync_n <= '1';
\r
232 end if;--if (pi_rnd_en(1) = '1' or pi_rnd_en(3) = '1' ) then
\r
233 end if;--if (pi_rst_n = '0') then
\r
236 --vram access state machine (state transition)...
\r
237 vac_set_stat_p : process (pi_rst_n, pi_base_clk)
\r
239 if (pi_rst_n = '0') then
\r
240 reg_v_cur_state <= IDLE;
\r
241 reg_v_data <= (others => 'Z');
\r
242 elsif (rising_edge(pi_base_clk)) then
\r
243 reg_v_data <= pi_v_data;
\r
244 reg_v_cur_state <= reg_v_next_state;
\r
245 end if;--if (pi_rst_n = '0') then
\r
248 --state change to next.
\r
249 vac_next_stat_p : process (reg_v_cur_state, pi_rnd_en, pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y)
\r
250 function bg_process (
\r
251 pm_sbg : in std_logic;
\r
252 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
253 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
256 if (pm_sbg = '1'and
\r
257 (pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START) and
\r
258 (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
266 pm_sbg : in std_logic;
\r
267 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
268 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
271 if (pm_sbg = '0' or
\r
272 (pm_nes_x > HSCAN and pm_nes_x < HSCAN_NEXT_START) or
\r
273 (pm_nes_y >= VSCAN and pm_nes_y < VSCAN_NEXT_START)) then
\r
280 case reg_v_cur_state is
\r
282 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
283 pi_rnd_en(3) = '1' and
\r
284 reg_nes_x mod 8 = 0) then
\r
285 --start vram access process.
\r
286 reg_v_next_state <= AD_SET0;
\r
288 reg_v_next_state <= reg_v_cur_state;
\r
291 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
294 reg_v_next_state <= AD_SET1;
\r
295 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then
\r
296 ---when nes_x=257, fall to idle
\r
297 reg_v_next_state <= IDLE;
\r
299 reg_v_next_state <= reg_v_cur_state;
\r
302 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
305 reg_v_next_state <= AD_SET2;
\r
307 reg_v_next_state <= reg_v_cur_state;
\r
310 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
313 reg_v_next_state <= AD_SET3;
\r
315 reg_v_next_state <= reg_v_cur_state;
\r
318 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
321 reg_v_next_state <= REG_SET0;
\r
323 reg_v_next_state <= reg_v_cur_state;
\r
326 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
329 reg_v_next_state <= REG_SET1;
\r
331 reg_v_next_state <= reg_v_cur_state;
\r
334 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
337 reg_v_next_state <= REG_SET2;
\r
339 reg_v_next_state <= reg_v_cur_state;
\r
342 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
345 reg_v_next_state <= REG_SET3;
\r
347 reg_v_next_state <= reg_v_cur_state;
\r
350 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and
\r
353 reg_v_next_state <= AD_SET0;
\r
355 reg_v_next_state <= reg_v_cur_state;
\r
360 po_rd_n <= reg_v_rd_n;
\r
361 po_wr_n <= reg_v_wr_n;
\r
362 po_v_addr <= reg_v_addr;
\r
364 --main vram access state machine...
\r
365 vac_main_stat_p : process (reg_v_cur_state)
\r
367 case reg_v_cur_state is
\r
371 reg_v_addr <= (others => 'Z');
\r
375 reg_v_addr <= (others => 'Z');
\r
379 reg_v_addr <= (others => 'Z');
\r
383 reg_v_addr <= (others => 'Z');
\r
387 reg_v_addr <= (others => 'Z');
\r
391 reg_v_addr <= (others => 'Z');
\r
395 reg_v_addr <= (others => 'Z');
\r
399 reg_v_addr <= (others => 'Z');
\r
403 reg_v_addr <= (others => 'Z');
\r
407 po_ppu_status <= (others => '0');
\r
409 po_spr_ce_n <= 'Z';
\r
410 po_spr_rd_n <= 'Z';
\r
411 po_spr_wr_n <= 'Z';
\r
412 po_spr_addr <= (others => 'Z');
\r
414 po_r <= (others => 'Z');
\r
415 po_g <= (others => 'Z');
\r
416 po_b <= (others => 'Z');
\r