1 -------------------------------------------------------------
\r
2 -------------------------------------------------------------
\r
3 ------------------- PPU VGA Output Control ------------------
\r
4 -------------------------------------------------------------
\r
5 -------------------------------------------------------------
\r
8 use ieee.std_logic_1164.all;
\r
9 use ieee.std_logic_unsigned.conv_integer;
\r
10 use ieee.std_logic_arith.conv_std_logic_vector;
\r
11 use ieee.std_logic_unsigned.all;
\r
12 use work.motonesfpga_common.all;
\r
14 entity vga_ppu_render is
\r
16 signal dbg_vga_clk : out std_logic;
\r
17 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
18 signal dbg_vga_x : out std_logic_vector (9 downto 0);
\r
19 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
20 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
21 signal dbg_plt_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
22 signal dbg_plt_addr : out std_logic_vector (4 downto 0);
\r
23 signal dbg_plt_data : out std_logic_vector (7 downto 0);
\r
24 signal dbg_p_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
25 signal dbg_p_oam_addr : out std_logic_vector (7 downto 0);
\r
26 signal dbg_p_oam_data : out std_logic_vector (7 downto 0);
\r
27 signal dbg_s_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
28 signal dbg_s_oam_addr : out std_logic_vector (4 downto 0);
\r
29 signal dbg_s_oam_data : out std_logic_vector (7 downto 0);
\r
31 vga_clk : in std_logic;
\r
32 mem_clk : in std_logic;
\r
33 rst_n : in std_logic;
\r
36 rd_n : out std_logic;
\r
37 wr_n : out std_logic;
\r
38 ale : out std_logic;
\r
39 vram_ad : inout std_logic_vector (7 downto 0);
\r
40 vram_a : out std_logic_vector (13 downto 8);
\r
43 h_sync_n : out std_logic;
\r
44 v_sync_n : out std_logic;
\r
45 r : out std_logic_vector (3 downto 0);
\r
46 g : out std_logic_vector (3 downto 0);
\r
47 b : out std_logic_vector (3 downto 0);
\r
50 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
51 ppu_mask : in std_logic_vector (7 downto 0);
\r
52 read_status : in std_logic;
\r
53 ppu_status : out std_logic_vector (7 downto 0);
\r
54 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
55 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
57 --ppu internal ram access
\r
58 r_nw : in std_logic;
\r
59 oam_bus_ce_n : in std_logic;
\r
60 plt_bus_ce_n : in std_logic;
\r
61 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
62 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
63 v_bus_busy_n : out std_logic
\r
67 architecture rtl of vga_ppu_render is
\r
69 component counter_register
\r
71 dsize : integer := 8;
\r
74 port ( clk : in std_logic;
\r
75 rst_n : in std_logic;
\r
76 ce_n : in std_logic;
\r
77 we_n : in std_logic;
\r
78 d : in std_logic_vector(dsize - 1 downto 0);
\r
79 q : out std_logic_vector(dsize - 1 downto 0)
\r
83 component ppu_render
\r
85 signal dbg_ppu_clk : out std_logic;
\r
86 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
87 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
88 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
89 signal dbg_plt_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
90 signal dbg_plt_addr : out std_logic_vector (4 downto 0);
\r
91 signal dbg_plt_data : out std_logic_vector (7 downto 0);
\r
92 signal dbg_p_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
93 signal dbg_p_oam_addr : out std_logic_vector (7 downto 0);
\r
94 signal dbg_p_oam_data : out std_logic_vector (7 downto 0);
\r
95 signal dbg_s_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
96 signal dbg_s_oam_addr : out std_logic_vector (4 downto 0);
\r
97 signal dbg_s_oam_data : out std_logic_vector (7 downto 0);
\r
99 ppu_clk : in std_logic;
\r
100 mem_clk : in std_logic;
\r
101 rst_n : in std_logic;
\r
102 rd_n : out std_logic;
\r
103 wr_n : out std_logic;
\r
104 ale : out std_logic;
\r
105 vram_ad : inout std_logic_vector (7 downto 0);
\r
106 vram_a : out std_logic_vector (13 downto 8);
\r
107 cur_x : in std_logic_vector (8 downto 0);
\r
108 cur_y : in std_logic_vector (8 downto 0);
\r
109 r : out std_logic_vector (3 downto 0);
\r
110 g : out std_logic_vector (3 downto 0);
\r
111 b : out std_logic_vector (3 downto 0);
\r
112 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
113 ppu_mask : in std_logic_vector (7 downto 0);
\r
114 read_status : in std_logic;
\r
115 ppu_status : out std_logic_vector (7 downto 0);
\r
116 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
117 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
119 r_nw : in std_logic;
\r
120 oam_bus_ce_n : in std_logic;
\r
121 plt_bus_ce_n : in std_logic;
\r
122 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
123 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
124 v_bus_busy_n : out std_logic
\r
128 --------- screen constant -----------
\r
129 constant VGA_W : integer := 640;
\r
130 constant VGA_H : integer := 480;
\r
131 constant VGA_W_MAX : integer := 800;
\r
132 constant VGA_H_MAX : integer := 525;
\r
133 constant H_SP : integer := 95;
\r
134 constant H_BP : integer := 48;
\r
135 constant H_FP : integer := 15;
\r
136 constant V_SP : integer := 2;
\r
137 constant V_BP : integer := 33;
\r
138 constant V_FP : integer := 10;
\r
140 --------- signal declaration -----------
\r
141 signal vga_x : std_logic_vector (9 downto 0);
\r
142 signal vga_y : std_logic_vector (9 downto 0);
\r
143 signal x_res_n : std_logic;
\r
144 signal y_res_n : std_logic;
\r
145 signal y_en_n : std_logic;
\r
146 signal cnt_clk : std_logic;
\r
148 signal emu_ppu_clk1 : std_logic;
\r
149 signal emu_ppu_clk : std_logic;
\r
150 signal emu_ppu_clk_n : std_logic;
\r
151 signal count5_res_n : std_logic;
\r
152 signal count5 : std_logic_vector(2 downto 0);
\r
153 signal nes_x : std_logic_vector (8 downto 0);
\r
154 signal nes_y : std_logic_vector (8 downto 0);
\r
156 ---DE1 base clock 50 MHz
\r
157 ---motones sim project uses following clock.
\r
158 --cpu clock = base clock / 24 = 2.08 MHz (480 ns / cycle)
\r
159 --ppu clock = base clock / 8
\r
160 --vga clock = base clock / 2
\r
161 --sdram clock = 135 MHz
\r
164 dbg_vga_x <= vga_x;
\r
166 cnt_clk <= not vga_clk;
\r
168 --vga position counter
\r
169 x_inst : counter_register generic map (10, 1)
\r
170 port map (cnt_clk , x_res_n, '0', '1', (others => '0'), vga_x);
\r
171 y_inst : counter_register generic map (10, 1)
\r
172 port map (cnt_clk , y_res_n, y_en_n, '1', (others => '0'), vga_y);
\r
173 vga_out_p : process (rst_n, vga_clk)
\r
175 if (rst_n = '0') then
\r
180 elsif (rising_edge(vga_clk)) then
\r
182 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
186 if (vga_y = conv_std_logic_vector(VGA_H_MAX, 10)) then
\r
197 --sync signal assert.
\r
198 if (vga_x >= conv_std_logic_vector((VGA_W + H_FP) , 10) and
\r
199 vga_x < conv_std_logic_vector((VGA_W + H_FP + H_SP) , 10)) then
\r
205 if (vga_y >= conv_std_logic_vector((VGA_H + V_FP) , 10) and
\r
206 vga_y < conv_std_logic_vector((VGA_H + V_FP + V_SP) , 10)) then
\r
215 --emulate ppu clock that is synchronized with vga clock
\r
216 count5_inst : counter_register generic map (3, 1)
\r
217 port map (cnt_clk, count5_res_n, '0', '1', (others => '0'), count5);
\r
218 nes_x_inst : counter_register generic map (9, 1)
\r
219 port map (emu_ppu_clk , x_res_n, '0', '1', (others => '0'), nes_x);
\r
220 nes_y <= vga_y(9 downto 1);
\r
221 emu_clk_p : process (rst_n, vga_clk)
\r
223 if (rst_n = '0') then
\r
224 emu_ppu_clk1 <= '0';
\r
225 count5_res_n <= '0';
\r
226 elsif (rising_edge(vga_clk)) then
\r
227 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
228 count5_res_n <= '0';
\r
229 elsif (count5 = "100") then
\r
230 count5_res_n <= '0';
\r
232 count5_res_n <= '1';
\r
235 if (count5 = "001" or count5 = "011") then
\r
236 emu_ppu_clk1 <= '0';
\r
238 emu_ppu_clk1 <= '1';
\r
243 ---emulated ppu clock adjustment.
\r
244 emu_ppu_clk <= emu_ppu_clk1 when vga_x < conv_std_logic_vector(765, 10) else
\r
245 emu_ppu_clk1 when vga_x > conv_std_logic_vector(798, 10) else
\r
247 emu_ppu_clk_n <= not emu_ppu_clk;
\r
248 ppu_render_inst : ppu_render
\r
252 dbg_disp_nt, dbg_disp_attr ,
\r
253 dbg_disp_ptn_h, dbg_disp_ptn_l ,
\r
257 dbg_p_oam_ce_rn_wn ,
\r
260 dbg_s_oam_ce_rn_wn ,
\r
295 ---------------------------------------------------------------
\r
296 ---------------------------------------------------------------
\r
297 ------------------------ PPU VGA Renderer ---------------------
\r
298 ---------------------------------------------------------------
\r
299 ---------------------------------------------------------------
\r
302 use ieee.std_logic_1164.all;
\r
303 use ieee.std_logic_arith.conv_std_logic_vector;
\r
304 use ieee.std_logic_unsigned.all;
\r
305 use work.motonesfpga_common.all;
\r
307 entity ppu_render is
\r
309 signal dbg_ppu_clk : out std_logic;
\r
310 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
311 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
312 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
313 signal dbg_plt_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
314 signal dbg_plt_addr : out std_logic_vector (4 downto 0);
\r
315 signal dbg_plt_data : out std_logic_vector (7 downto 0);
\r
316 signal dbg_p_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
317 signal dbg_p_oam_addr : out std_logic_vector (7 downto 0);
\r
318 signal dbg_p_oam_data : out std_logic_vector (7 downto 0);
\r
319 signal dbg_s_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
320 signal dbg_s_oam_addr : out std_logic_vector (4 downto 0);
\r
321 signal dbg_s_oam_data : out std_logic_vector (7 downto 0);
\r
323 ppu_clk : in std_logic;
\r
324 mem_clk : in std_logic;
\r
325 rst_n : in std_logic;
\r
327 rd_n : out std_logic;
\r
328 wr_n : out std_logic;
\r
329 ale : out std_logic;
\r
330 vram_ad : inout std_logic_vector (7 downto 0);
\r
331 vram_a : out std_logic_vector (13 downto 8);
\r
333 --current drawing position 340 x 261
\r
334 cur_x : in std_logic_vector (8 downto 0);
\r
335 cur_y : in std_logic_vector (8 downto 0);
\r
336 r : out std_logic_vector (3 downto 0);
\r
337 g : out std_logic_vector (3 downto 0);
\r
338 b : out std_logic_vector (3 downto 0);
\r
340 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
341 ppu_mask : in std_logic_vector (7 downto 0);
\r
342 read_status : in std_logic;
\r
343 ppu_status : out std_logic_vector (7 downto 0);
\r
344 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
345 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
347 r_nw : in std_logic;
\r
348 oam_bus_ce_n : in std_logic;
\r
349 plt_bus_ce_n : in std_logic;
\r
350 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
351 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
352 v_bus_busy_n : out std_logic
\r
356 architecture rtl of ppu_render is
\r
358 component counter_register
\r
360 dsize : integer := 8;
\r
363 port ( clk : in std_logic;
\r
364 rst_n : in std_logic;
\r
365 ce_n : in std_logic;
\r
366 we_n : in std_logic;
\r
367 d : in std_logic_vector(dsize - 1 downto 0);
\r
368 q : out std_logic_vector(dsize - 1 downto 0)
\r
372 component shift_register
\r
374 dsize : integer := 8;
\r
375 shift : integer := 1
\r
377 port ( clk : in std_logic;
\r
378 rst_n : in std_logic;
\r
379 ce_n : in std_logic;
\r
380 we_n : in std_logic;
\r
381 d : in std_logic_vector(dsize - 1 downto 0);
\r
382 q : out std_logic_vector(dsize - 1 downto 0)
\r
386 component d_flip_flop
\r
388 dsize : integer := 8
\r
391 clk : in std_logic;
\r
392 res_n : in std_logic;
\r
393 set_n : in std_logic;
\r
394 we_n : in std_logic;
\r
395 d : in std_logic_vector (dsize - 1 downto 0);
\r
396 q : out std_logic_vector (dsize - 1 downto 0)
\r
400 component tri_state_buffer
\r
402 dsize : integer := 8
\r
405 oe_n : in std_logic;
\r
406 d : in std_logic_vector (dsize - 1 downto 0);
\r
407 q : out std_logic_vector (dsize - 1 downto 0)
\r
412 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
414 clk : in std_logic;
\r
415 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
416 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
417 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
421 component palette_ram
\r
422 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
424 clk : in std_logic;
\r
425 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
426 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
427 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
433 clk : in std_logic;
\r
434 ce_n, oe_n, we_n : in std_logic;
\r
435 sync_ce_n : out std_logic
\r
439 --nes screen size is emulated to align with the vga timing...
\r
440 constant X_SIZE : integer := 9;
\r
441 constant dsize : integer := 8;
\r
442 constant asize : integer := 14;
\r
443 constant HSCAN_MAX : integer := 341;
\r
444 constant VSCAN_MAX : integer := 262;
\r
445 constant HSCAN : integer := 257;
\r
446 constant VSCAN : integer := 240;
\r
447 constant HSCAN_NEXT_START : integer := 320;
\r
448 constant HSCAN_NEXT_EXTRA : integer := 336;
\r
451 constant PPUBNA : integer := 1; --base name address
\r
452 constant PPUVAI : integer := 2; --vram address increment
\r
453 constant PPUSPA : integer := 3; --sprite pattern table address
\r
454 constant PPUBPA : integer := 4; --background pattern table address
\r
455 constant PPUSPS : integer := 5; --sprite size
\r
456 constant PPUMS : integer := 6; --ppu master/slave
\r
457 constant PPUNEN : integer := 7; --nmi enable
\r
459 constant PPUGS : integer := 0; --grayscale
\r
460 constant PPUSBL : integer := 1; --show 8 left most bg pixel
\r
461 constant PPUSSL : integer := 2; --show 8 left most sprite pixel
\r
462 constant PPUSBG : integer := 3; --show bg
\r
463 constant PPUSSP : integer := 4; --show sprie
\r
464 constant PPUIR : integer := 5; --intensify red
\r
465 constant PPUIG : integer := 6; --intensify green
\r
466 constant PPUIB : integer := 7; --intensify blue
\r
468 constant SPRHFL : integer := 6; --flip sprigte horizontally
\r
469 constant SPRVFL : integer := 7; --flip sprigte vertically
\r
471 constant ST_SOF : integer := 5; --sprite overflow
\r
472 constant ST_SP0 : integer := 6; --sprite 0 hits
\r
473 constant ST_VBL : integer := 7; --vblank
\r
475 subtype nes_color_data is std_logic_vector (11 downto 0);
\r
476 type nes_color_array is array (0 to 63) of nes_color_data;
\r
477 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
\r
478 constant nes_color_palette : nes_color_array := (
\r
479 conv_std_logic_vector(16#777#, 12),
\r
480 conv_std_logic_vector(16#20b#, 12),
\r
481 conv_std_logic_vector(16#20b#, 12),
\r
482 conv_std_logic_vector(16#61a#, 12),
\r
483 conv_std_logic_vector(16#927#, 12),
\r
484 conv_std_logic_vector(16#b13#, 12),
\r
485 conv_std_logic_vector(16#a30#, 12),
\r
486 conv_std_logic_vector(16#740#, 12),
\r
487 conv_std_logic_vector(16#450#, 12),
\r
488 conv_std_logic_vector(16#360#, 12),
\r
489 conv_std_logic_vector(16#360#, 12),
\r
490 conv_std_logic_vector(16#364#, 12),
\r
491 conv_std_logic_vector(16#358#, 12),
\r
492 conv_std_logic_vector(16#000#, 12),
\r
493 conv_std_logic_vector(16#000#, 12),
\r
494 conv_std_logic_vector(16#000#, 12),
\r
495 conv_std_logic_vector(16#bbb#, 12),
\r
496 conv_std_logic_vector(16#46f#, 12),
\r
497 conv_std_logic_vector(16#44f#, 12),
\r
498 conv_std_logic_vector(16#94f#, 12),
\r
499 conv_std_logic_vector(16#d4c#, 12),
\r
500 conv_std_logic_vector(16#d46#, 12),
\r
501 conv_std_logic_vector(16#e50#, 12),
\r
502 conv_std_logic_vector(16#c70#, 12),
\r
503 conv_std_logic_vector(16#880#, 12),
\r
504 conv_std_logic_vector(16#5a0#, 12),
\r
505 conv_std_logic_vector(16#4a1#, 12),
\r
506 conv_std_logic_vector(16#4a6#, 12),
\r
507 conv_std_logic_vector(16#49c#, 12),
\r
508 conv_std_logic_vector(16#000#, 12),
\r
509 conv_std_logic_vector(16#000#, 12),
\r
510 conv_std_logic_vector(16#000#, 12),
\r
511 conv_std_logic_vector(16#fff#, 12),
\r
512 conv_std_logic_vector(16#6af#, 12),
\r
513 conv_std_logic_vector(16#58f#, 12),
\r
514 conv_std_logic_vector(16#a7f#, 12),
\r
515 conv_std_logic_vector(16#f6f#, 12),
\r
516 conv_std_logic_vector(16#f6b#, 12),
\r
517 conv_std_logic_vector(16#f73#, 12),
\r
518 conv_std_logic_vector(16#fa0#, 12),
\r
519 conv_std_logic_vector(16#ed2#, 12),
\r
520 conv_std_logic_vector(16#9e0#, 12),
\r
521 conv_std_logic_vector(16#7f4#, 12),
\r
522 conv_std_logic_vector(16#7e9#, 12),
\r
523 conv_std_logic_vector(16#6de#, 12),
\r
524 conv_std_logic_vector(16#777#, 12),
\r
525 conv_std_logic_vector(16#000#, 12),
\r
526 conv_std_logic_vector(16#000#, 12),
\r
527 conv_std_logic_vector(16#fff#, 12),
\r
528 conv_std_logic_vector(16#9df#, 12),
\r
529 conv_std_logic_vector(16#abf#, 12),
\r
530 conv_std_logic_vector(16#cbf#, 12),
\r
531 conv_std_logic_vector(16#ebf#, 12),
\r
532 conv_std_logic_vector(16#fbe#, 12),
\r
533 conv_std_logic_vector(16#fcb#, 12),
\r
534 conv_std_logic_vector(16#fda#, 12),
\r
535 conv_std_logic_vector(16#ff9#, 12),
\r
536 conv_std_logic_vector(16#cf8#, 12),
\r
537 conv_std_logic_vector(16#afa#, 12),
\r
538 conv_std_logic_vector(16#afc#, 12),
\r
539 conv_std_logic_vector(16#aff#, 12),
\r
540 conv_std_logic_vector(16#aaa#, 12),
\r
541 conv_std_logic_vector(16#000#, 12),
\r
542 conv_std_logic_vector(16#000#, 12)
\r
545 signal ppu_clk_n : std_logic;
\r
548 signal bg_io_cnt : std_logic_vector(0 downto 0);
\r
549 signal spr_io_cnt : std_logic_vector(0 downto 0);
\r
552 signal io_oe_n : std_logic;
\r
553 signal ah_oe_n : std_logic;
\r
555 signal cnt_x_res_n : std_logic;
\r
556 signal bg_cnt_res_n : std_logic;
\r
558 --bg prefetch position (scroll + 16 cycle ahead of current pos)
\r
559 --511 x 239 (or 255 x 479)
\r
560 signal prf_x : std_logic_vector(X_SIZE - 1 downto 0);
\r
561 signal prf_y : std_logic_vector(X_SIZE - 1 downto 0);
\r
563 signal nt_we_n : std_logic;
\r
564 signal disp_nt : std_logic_vector (dsize - 1 downto 0);
\r
566 signal attr_ce_n : std_logic;
\r
567 signal attr_we_n : std_logic;
\r
568 signal attr_val : std_logic_vector (dsize - 1 downto 0);
\r
569 signal disp_attr_we_n : std_logic;
\r
570 signal disp_attr : std_logic_vector (dsize - 1 downto 0);
\r
572 signal ptn_l_we_n : std_logic;
\r
573 signal ptn_l_in : std_logic_vector (dsize - 1 downto 0);
\r
574 signal ptn_l_val : std_logic_vector (dsize - 1 downto 0);
\r
575 signal disp_ptn_l_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
576 signal disp_ptn_l : std_logic_vector (dsize * 2 - 1 downto 0);
\r
578 signal ptn_h_we_n : std_logic;
\r
579 signal ptn_h_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
580 signal disp_ptn_h : std_logic_vector (dsize * 2 - 1 downto 0);
\r
582 --signals for palette / oam access from cpu
\r
583 signal r_n : std_logic;
\r
584 signal vram_addr : std_logic_vector (asize - 1 downto 0);
\r
587 signal plt_ram_ce_n_in : std_logic;
\r
588 signal plt_ram_ce_n : std_logic;
\r
589 signal plt_r_n : std_logic;
\r
590 signal plt_w_n : std_logic;
\r
591 signal plt_addr : std_logic_vector (4 downto 0);
\r
592 signal plt_data : std_logic_vector (dsize - 1 downto 0);
\r
594 --primari / secondary oam
\r
595 signal p_oam_ram_ce_n_in : std_logic;
\r
596 signal p_oam_ram_ce_n : std_logic;
\r
597 signal p_oam_r_n : std_logic;
\r
598 signal p_oam_w_n : std_logic;
\r
599 signal p_oam_addr : std_logic_vector (dsize - 1 downto 0);
\r
600 signal p_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
602 signal s_oam_ram_ce_n_in : std_logic;
\r
603 signal s_oam_ram_ce_n : std_logic;
\r
604 signal s_oam_r_n : std_logic;
\r
605 signal s_oam_w_n : std_logic;
\r
606 signal s_oam_addr_cpy_ce_n : std_logic;
\r
607 signal s_oam_addr_cpy_n : std_logic;
\r
608 signal s_oam_addr : std_logic_vector (4 downto 0);
\r
609 signal s_oam_addr_cpy : std_logic_vector (4 downto 0);
\r
610 signal s_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
612 signal p_oam_cnt_res_n : std_logic;
\r
613 signal p_oam_cnt_ce_n : std_logic;
\r
614 signal p_oam_cnt_wrap_n : std_logic;
\r
615 signal p_oam_cnt : std_logic_vector (dsize - 1 downto 0);
\r
616 signal p_oam_addr_in : std_logic_vector (dsize - 1 downto 0);
\r
617 signal oam_ev_status : std_logic_vector (2 downto 0);
\r
619 signal s_oam_cnt_ce_n : std_logic;
\r
620 signal s_oam_cnt : std_logic_vector (4 downto 0);
\r
622 --oam evaluation status
\r
623 constant EV_STAT_COMP : std_logic_vector (2 downto 0) := "000";
\r
624 constant EV_STAT_CP1 : std_logic_vector (2 downto 0) := "001";
\r
625 constant EV_STAT_CP2 : std_logic_vector (2 downto 0) := "010";
\r
626 constant EV_STAT_CP3 : std_logic_vector (2 downto 0) := "011";
\r
627 constant EV_STAT_PRE_COMP : std_logic_vector (2 downto 0) := "100";
\r
629 ----------sprite registers.
\r
630 type oam_pin_array is array (0 to 7) of std_logic;
\r
631 type oam_reg_array is array (0 to 7) of std_logic_vector (dsize - 1 downto 0);
\r
633 signal spr_x_we_n : oam_pin_array;
\r
634 signal spr_x_ce_n : oam_pin_array;
\r
635 signal spr_attr_we_n : oam_pin_array;
\r
636 signal spr_ptn_l_we_n : oam_pin_array;
\r
637 signal spr_ptn_h_we_n : oam_pin_array;
\r
638 signal spr_ptn_ce_n : oam_pin_array;
\r
640 signal spr_x_cnt : oam_reg_array;
\r
641 signal spr_attr : oam_reg_array;
\r
642 signal spr_ptn_l : oam_reg_array;
\r
643 signal spr_ptn_h : oam_reg_array;
\r
645 signal spr_y_we_n : std_logic;
\r
646 signal spr_tile_we_n : std_logic;
\r
647 signal spr_y_tmp : std_logic_vector (dsize - 1 downto 0);
\r
648 signal spr_tile_tmp : std_logic_vector (dsize - 1 downto 0);
\r
649 signal spr_ptn_in : std_logic_vector (dsize - 1 downto 0);
\r
653 dbg_ppu_clk <= ppu_clk;
\r
654 dbg_nes_x <= cur_x;
\r
655 dbg_disp_nt <= disp_nt;
\r
656 dbg_disp_attr <= disp_attr;
\r
657 dbg_disp_ptn_h <= disp_ptn_h;
\r
658 dbg_disp_ptn_l <= disp_ptn_l;
\r
659 dbg_plt_addr <= plt_addr;
\r
660 dbg_plt_data <= plt_data;
\r
661 dbg_plt_ce_rn_wn <= plt_ram_ce_n & plt_r_n & plt_w_n;
\r
662 dbg_p_oam_ce_rn_wn <= p_oam_ram_ce_n & p_oam_r_n & p_oam_w_n;
\r
663 dbg_p_oam_addr <= p_oam_addr;
\r
664 dbg_p_oam_data <= p_oam_data;
\r
665 dbg_s_oam_ce_rn_wn <= s_oam_ram_ce_n & s_oam_r_n & s_oam_w_n;
\r
666 dbg_s_oam_addr <= s_oam_addr;
\r
667 dbg_s_oam_data <= p_oam_data;
\r
670 ppu_clk_n <= not ppu_clk;
\r
672 ale <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
673 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
674 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
675 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
676 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
677 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
678 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
679 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
680 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
681 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
684 rd_n <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
685 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
686 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
687 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
688 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
689 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
690 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
691 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
692 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
693 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
695 wr_n <= '1' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
696 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
697 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
699 io_oe_n <= not bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
700 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
701 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
702 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
703 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
704 not spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
705 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
706 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
707 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
708 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
710 ah_oe_n <= '0' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
711 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
712 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
714 v_bus_busy_n <= ah_oe_n;
\r
716 bg_io_cnt_inst : counter_register generic map (1, 1)
\r
717 port map (ppu_clk, bg_cnt_res_n, '0', '1', (others => '0'), bg_io_cnt);
\r
718 spr_io_cnt_inst : counter_register generic map (1, 1)
\r
719 port map (ppu_clk, cnt_x_res_n, '0', '1', (others => '0'), spr_io_cnt);
\r
721 ---bg prefetch x pos is 16 + scroll cycle ahead of current pos.
\r
722 prf_x <= cur_x + ppu_scroll_x + "000010000"
\r
723 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) else
\r
724 cur_x + ppu_scroll_x + "010111011"; -- +16 -341
\r
726 prf_y <= cur_y + ppu_scroll_y
\r
727 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) and
\r
728 cur_y + ppu_scroll_y <
\r
729 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
730 cur_y + ppu_scroll_y + "000000001"
\r
731 when cur_y + ppu_scroll_y <
\r
732 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
735 nt_inst : d_flip_flop generic map(dsize)
\r
736 port map (ppu_clk_n, rst_n, '1', nt_we_n, vram_ad, disp_nt);
\r
738 at_inst : d_flip_flop generic map(dsize)
\r
739 port map (ppu_clk_n, rst_n, '1', attr_we_n, vram_ad, attr_val);
\r
741 disp_at_inst : shift_register generic map(dsize, 2)
\r
742 port map (ppu_clk_n, rst_n, attr_ce_n, disp_attr_we_n, attr_val, disp_attr);
\r
744 --chr rom data's bit is stored in opposite direction.
\r
745 --reverse bit when loading...
\r
746 ptn_l_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
747 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
748 ptn_h_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
749 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7)) &
\r
750 disp_ptn_h (dsize downto 1);
\r
752 ptn_l_inst : d_flip_flop generic map(dsize)
\r
753 port map (ppu_clk_n, rst_n, '1', ptn_l_we_n, ptn_l_in, ptn_l_val);
\r
755 disp_ptn_l_in <= ptn_l_val & disp_ptn_l (dsize downto 1);
\r
756 disp_ptn_l_inst : shift_register generic map(dsize * 2, 1)
\r
757 port map (ppu_clk_n, rst_n, '0', ptn_h_we_n, disp_ptn_l_in, disp_ptn_l);
\r
759 ptn_h_inst : shift_register generic map(dsize * 2, 1)
\r
760 port map (ppu_clk_n, rst_n, '0', ptn_h_we_n, ptn_h_in, disp_ptn_h);
\r
763 vram_io_buf : tri_state_buffer generic map (dsize)
\r
764 port map (io_oe_n, vram_addr(dsize - 1 downto 0), vram_ad);
\r
766 vram_a_buf : tri_state_buffer generic map (6)
\r
767 port map (ah_oe_n, vram_addr(asize - 1 downto dsize), vram_a);
\r
772 plt_ram_ce_n_in <= ppu_clk when plt_bus_ce_n = '0' and r_nw = '0' else
\r
773 '0' when plt_bus_ce_n = '0' and r_nw = '1' else
\r
774 '0' when ppu_mask(PPUSBG) = '1' and
\r
775 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
776 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
779 plt_addr <= oam_plt_addr(4 downto 0) when plt_bus_ce_n = '0' else
\r
780 "1" & spr_attr(0)(1 downto 0) & spr_ptn_h(0)(0) & spr_ptn_l(0)(0)
\r
781 when ppu_mask(PPUSSP) = '1' and
\r
782 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
783 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
784 spr_x_cnt(0) = "00000000" and
\r
785 (spr_ptn_h(0)(0) or spr_ptn_l(0)(0)) = '1' else
\r
786 "1" & spr_attr(1)(1 downto 0) & spr_ptn_h(1)(0) & spr_ptn_l(1)(0)
\r
787 when ppu_mask(PPUSSP) = '1' and
\r
788 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
789 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
790 spr_x_cnt(1) = "00000000" and
\r
791 (spr_ptn_h(1)(0) or spr_ptn_l(1)(0)) = '1' else
\r
792 "1" & spr_attr(2)(1 downto 0) & spr_ptn_h(2)(0) & spr_ptn_l(2)(0)
\r
793 when ppu_mask(PPUSSP) = '1' and
\r
794 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
795 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
796 spr_x_cnt(2) = "00000000" and
\r
797 (spr_ptn_h(2)(0) or spr_ptn_l(2)(0)) = '1' else
\r
798 "1" & spr_attr(3)(1 downto 0) & spr_ptn_h(3)(0) & spr_ptn_l(3)(0)
\r
799 when ppu_mask(PPUSSP) = '1' and
\r
800 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
801 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
802 spr_x_cnt(3) = "00000000" and
\r
803 (spr_ptn_h(3)(0) or spr_ptn_l(3)(0)) = '1' else
\r
804 "1" & spr_attr(4)(1 downto 0) & spr_ptn_h(4)(0) & spr_ptn_l(4)(0)
\r
805 when ppu_mask(PPUSSP) = '1' and
\r
806 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
807 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
808 spr_x_cnt(4) = "00000000" and
\r
809 (spr_ptn_h(4)(0) or spr_ptn_l(4)(0)) = '1' else
\r
810 "1" & spr_attr(5)(1 downto 0) & spr_ptn_h(5)(0) & spr_ptn_l(5)(0)
\r
811 when ppu_mask(PPUSSP) = '1' and
\r
812 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
813 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
814 spr_x_cnt(5) = "00000000" and
\r
815 (spr_ptn_h(5)(0) or spr_ptn_l(5)(0)) = '1' else
\r
816 "1" & spr_attr(6)(1 downto 0) & spr_ptn_h(6)(0) & spr_ptn_l(6)(0)
\r
817 when ppu_mask(PPUSSP) = '1' and
\r
818 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
819 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
820 spr_x_cnt(6) = "00000000" and
\r
821 (spr_ptn_h(6)(0) or spr_ptn_l(6)(0)) = '1' else
\r
822 "1" & spr_attr(7)(1 downto 0) & spr_ptn_h(7)(0) & spr_ptn_l(7)(0)
\r
823 when ppu_mask(PPUSSP) = '1' and
\r
824 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
825 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
826 spr_x_cnt(7) = "00000000" and
\r
827 (spr_ptn_h(7)(0) or spr_ptn_l(7)(0)) = '1' else
\r
828 "0" & disp_attr(1 downto 0) & disp_ptn_h(0) & disp_ptn_l(0)
\r
829 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '0' and
\r
830 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
831 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
832 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
833 "0" & disp_attr(5 downto 4) & disp_ptn_h(0) & disp_ptn_l(0)
\r
834 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '1' and
\r
835 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
836 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
837 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
838 ---else: no output color >> universal bg color output.
\r
839 --0x3f00 is the universal bg palette.
\r
842 plt_r_n <= not r_nw when plt_bus_ce_n = '0' else
\r
843 '0' when ppu_mask(PPUSBG) = '1' else
\r
845 plt_w_n <= r_nw when plt_bus_ce_n = '0' else
\r
847 plt_d_buf_w : tri_state_buffer generic map (dsize)
\r
848 port map (plt_w_n, oam_plt_data, plt_data);
\r
849 plt_d_buf_r : tri_state_buffer generic map (dsize)
\r
850 port map (plt_r_n, plt_data, oam_plt_data);
\r
851 plt_ram_ctl : ram_ctrl
\r
852 port map (mem_clk, plt_ram_ce_n_in, plt_r_n, plt_w_n, plt_ram_ce_n);
\r
853 palette_inst : palette_ram generic map (5, dsize)
\r
854 port map (mem_clk, plt_ram_ce_n, plt_r_n, plt_w_n, plt_addr, plt_data);
\r
857 p_oam_ram_ce_n_in <= ppu_clk when oam_bus_ce_n = '0' and r_nw = '0' else
\r
858 '0' when oam_bus_ce_n = '0' and r_nw = '1' else
\r
859 '0' when ppu_mask(PPUSSP) = '1' and
\r
860 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
861 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
862 p_oam_cnt_wrap_n = '1' else
\r
864 p_oam_addr <= oam_plt_addr when oam_bus_ce_n = '0' else
\r
865 p_oam_addr_in when ppu_mask(PPUSSP) = '1' and
\r
866 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
867 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
868 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
869 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
871 p_oam_r_n <= not r_nw when oam_bus_ce_n = '0' else
\r
872 '0' when ppu_mask(PPUSSP) = '1' and
\r
873 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
874 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
875 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
876 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
878 p_oam_w_n <= r_nw when oam_bus_ce_n = '0' else
\r
880 oam_d_buf_w : tri_state_buffer generic map (dsize)
\r
881 port map (p_oam_w_n, oam_plt_data, p_oam_data);
\r
882 oam_d_buf_r : tri_state_buffer generic map (dsize)
\r
883 port map (p_oam_r_n, p_oam_data, oam_plt_data);
\r
885 p_oam_ram_ctl : ram_ctrl
\r
886 port map (mem_clk, p_oam_ram_ce_n_in, p_oam_r_n, p_oam_w_n, p_oam_ram_ce_n);
\r
887 primary_oam_inst : ram generic map (dsize, dsize)
\r
888 port map (mem_clk, p_oam_ram_ce_n, p_oam_r_n, p_oam_w_n, p_oam_addr, p_oam_data);
\r
891 p_oam_cnt_inst : counter_register generic map (dsize, 4)
\r
892 port map (ppu_clk_n, p_oam_cnt_res_n, p_oam_cnt_ce_n, '1', (others => '0'), p_oam_cnt);
\r
893 s_oam_cnt_inst : counter_register generic map (5, 1)
\r
894 port map (ppu_clk_n, p_oam_cnt_res_n, s_oam_cnt_ce_n, '1', (others => '0'), s_oam_cnt);
\r
895 s_oam_addr_cpy_inst : counter_register generic map (5, 1)
\r
896 port map (ppu_clk_n, p_oam_cnt_res_n, s_oam_addr_cpy_ce_n,
\r
897 '1', (others => '0'), s_oam_addr_cpy);
\r
899 s_oam_ram_ce_n_in <= ppu_clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
900 cur_x > "000000001" and
\r
901 cur_x <= conv_std_logic_vector(64, X_SIZE) else
\r
902 ppu_clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
903 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
904 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
905 p_oam_cnt_wrap_n = '1' else
\r
906 '0' when ppu_mask(PPUSSP) = '1' and
\r
907 cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
908 cur_x <= conv_std_logic_vector(320, X_SIZE) and
\r
909 s_oam_addr_cpy_n = '0' else
\r
912 s_oam_ram_ctl : ram_ctrl
\r
913 port map (mem_clk, s_oam_ram_ce_n_in, s_oam_r_n, s_oam_w_n, s_oam_ram_ce_n);
\r
914 secondary_oam_inst : ram generic map (5, dsize)
\r
915 port map (mem_clk, s_oam_ram_ce_n, s_oam_r_n, s_oam_w_n, s_oam_addr, s_oam_data);
\r
917 spr_y_inst : d_flip_flop generic map(dsize)
\r
918 port map (ppu_clk_n, p_oam_cnt_res_n, '1', spr_y_we_n, s_oam_data, spr_y_tmp);
\r
919 spr_tile_inst : d_flip_flop generic map(dsize)
\r
920 port map (ppu_clk_n, p_oam_cnt_res_n, '1', spr_tile_we_n, s_oam_data, spr_tile_tmp);
\r
923 --reverse bit when NOT SPRHFL is set (.nes file format bit endian).
\r
924 spr_ptn_in <= vram_ad when spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRHFL) = '1' else
\r
925 (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
926 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
927 --array instances...
\r
928 spr_inst : for i in 0 to 7 generate
\r
929 spr_x_inst : counter_register generic map(dsize, 16#ff#)
\r
930 port map (ppu_clk_n, rst_n, spr_x_ce_n(i), spr_x_we_n(i), s_oam_data, spr_x_cnt(i));
\r
932 spr_attr_inst : d_flip_flop generic map(dsize)
\r
933 port map (ppu_clk_n, rst_n, '1', spr_attr_we_n(i), s_oam_data, spr_attr(i));
\r
935 spr_ptn_l_inst : shift_register generic map(dsize, 1)
\r
936 port map (ppu_clk_n, rst_n, spr_ptn_ce_n(i), spr_ptn_l_we_n(i), spr_ptn_in, spr_ptn_l(i));
\r
938 spr_ptn_h_inst : shift_register generic map(dsize, 1)
\r
939 port map (ppu_clk_n, rst_n, spr_ptn_ce_n(i), spr_ptn_h_we_n(i), spr_ptn_in, spr_ptn_h(i));
\r
942 pos_p : process (rst_n, ppu_clk)
\r
944 if (rst_n = '0') then
\r
945 cnt_x_res_n <= '0';
\r
946 bg_cnt_res_n <= '0';
\r
947 elsif (ppu_clk'event and ppu_clk = '0') then
\r
948 if (cur_x = conv_std_logic_vector(HSCAN_MAX - 1, X_SIZE)) then
\r
950 cnt_x_res_n <= '0';
\r
952 cnt_x_res_n <= '1';
\r
955 if (ppu_scroll_x(0) = '0' and cur_x = conv_std_logic_vector(HSCAN, X_SIZE)) then
\r
956 bg_cnt_res_n <= '0';
\r
957 elsif (ppu_scroll_x(0) = '1' and cur_x = conv_std_logic_vector(HSCAN - 1, X_SIZE)) then
\r
958 bg_cnt_res_n <= '0';
\r
960 bg_cnt_res_n <= '1';
\r
962 end if; --if (rst_n = '0') then
\r
965 clk_p : process (rst_n, ppu_clk, read_status)
\r
967 procedure output_rgb is
\r
968 variable pl_addr : integer;
\r
969 variable pl_index : integer;
\r
970 variable dot_output : boolean;
\r
972 dot_output := false;
\r
974 --first show sprite.
\r
975 if (ppu_mask(PPUSSP) = '1') then
\r
976 for i in 0 to 7 loop
\r
977 if (spr_x_cnt(i) = "00000000") then
\r
978 if ((spr_ptn_h(i)(0) or spr_ptn_l(i)(0)) = '1') then
\r
979 dot_output := true;
\r
986 if (dot_output = true and ppu_mask(PPUSBG) = '1' and
\r
987 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
988 --raise sprite 0 hit.
\r
989 ppu_status(ST_SP0) <= '1';
\r
992 --first color in the palette is transparent color.
\r
993 if (ppu_mask(PPUSBG) = '1' and dot_output = false and
\r
994 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
995 dot_output := true;
\r
998 --if or if not bg/sprite is shown, output color anyway
\r
999 --sinse universal bg color is included..
\r
1000 pl_index := conv_integer(plt_data(5 downto 0));
\r
1001 b <= nes_color_palette(pl_index) (11 downto 8);
\r
1002 g <= nes_color_palette(pl_index) (7 downto 4);
\r
1003 r <= nes_color_palette(pl_index) (3 downto 0);
\r
1005 procedure stop_rgb is
\r
1007 b <= (others => '0');
\r
1008 g <= (others => '0');
\r
1009 r <= (others => '0');
\r
1013 if (rst_n = '0') then
\r
1015 ppu_status <= (others => '0');
\r
1016 s_oam_data <= (others => 'Z');
\r
1020 if (ppu_clk'event and ppu_clk = '1') then
\r
1022 --fetch bg pattern and display.
\r
1023 if (ppu_mask(PPUSBG) = '1' and
\r
1024 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
1025 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) and
\r
1026 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1027 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1028 --visible area bg image
\r
1031 d_print("cur_x: " & conv_hex16(conv_integer(cur_x)));
\r
1032 d_print("cur_y: " & conv_hex16(conv_integer(cur_y)));
\r
1034 ----fetch next tile byte.
\r
1035 if (prf_x (2 downto 0) = "001") then
\r
1036 --vram addr is incremented every 8 cycle.
\r
1037 --name table at 0x2000
\r
1038 vram_addr(9 downto 0)
\r
1039 <= prf_y(dsize - 1 downto 3)
\r
1040 & prf_x(dsize - 1 downto 3);
\r
1041 vram_addr(asize - 1 downto 10) <= "10" & ppu_ctrl(PPUBNA downto 0)
\r
1042 + ("000" & prf_x(dsize));
\r
1043 ----fetch attr table byte.
\r
1044 elsif (prf_x (4 downto 0) = "00011") then
\r
1045 --attribute table is loaded every 32 cycle.
\r
1046 --attr table at 0x23c0
\r
1047 vram_addr(dsize - 1 downto 0) <= "11000000" +
\r
1048 ("00" & prf_y(7 downto 5) & prf_x(7 downto 5));
\r
1049 vram_addr(asize - 1 downto dsize) <= "10" &
\r
1050 ppu_ctrl(PPUBNA downto 0) & "11"
\r
1051 + ("000" & prf_x(dsize) & "00");
\r
1052 ----fetch pattern table low byte.
\r
1053 elsif (prf_x (2 downto 0) = "101") then
\r
1054 --vram addr is incremented every 8 cycle.
\r
1055 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1056 disp_nt(dsize - 1 downto 0)
\r
1057 & "0" & prf_y(2 downto 0);
\r
1058 ----fetch pattern table high byte.
\r
1059 elsif (prf_x (2 downto 0) = "111") then
\r
1060 --vram addr is incremented every 8 cycle.
\r
1061 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1062 disp_nt(dsize - 1 downto 0)
\r
1063 & "0" & prf_y(2 downto 0) + "00000000001000";
\r
1066 ----fetch next tile byte.
\r
1067 if (prf_x (2 downto 0) = "010") then
\r
1073 ----fetch attr table byte.
\r
1074 if (prf_x (4 downto 0) = "00100") then
\r
1079 if (prf_x (4 downto 0) = "10000") then
\r
1080 disp_attr_we_n <= '0';
\r
1082 disp_attr_we_n <= '1';
\r
1084 ---attribute is shifted every 16 bit.
\r
1085 if (prf_x (3 downto 0) = "0000") then
\r
1091 ----fetch pattern table low byte.
\r
1092 if (prf_x (2 downto 0) = "110") then
\r
1093 ptn_l_we_n <= '0';
\r
1095 ptn_l_we_n <= '1';
\r
1098 ----fetch pattern table high byte.
\r
1099 if (prf_x (2 downto 0) = "000") then
\r
1100 ptn_h_we_n <= '0';
\r
1102 ptn_h_we_n <= '1';
\r
1105 end if;--if (ppu_mask(PPUSBG) = '1') and
\r
1107 --fetch sprite and display.
\r
1108 if (ppu_mask(PPUSSP) = '1' and
\r
1109 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1110 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1111 --secondary oam clear
\r
1112 if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE)) then
\r
1113 if (cur_x(0) = '0') then
\r
1114 --write secondary oam on even cycle
\r
1117 s_oam_addr <= cur_x(5 downto 1);
\r
1118 s_oam_data <= (others => '1');
\r
1120 p_oam_cnt_res_n <= '0';
\r
1121 p_oam_cnt_ce_n <= '1';
\r
1122 s_oam_cnt_ce_n <= '1';
\r
1123 p_oam_cnt_wrap_n <= '1';
\r
1124 oam_ev_status <= EV_STAT_COMP;
\r
1126 --sprite evaluation and secondary oam copy.
\r
1127 elsif (cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
1128 cur_x <= conv_std_logic_vector(256, X_SIZE)) then
\r
1129 p_oam_cnt_res_n <= '1';
\r
1131 --TODO: sprite evaluation is simplified!!
\r
1132 --not complying the original NES spec at
\r
1133 --http://wiki.nesdev.com/w/index.php/PPU_sprite_evaluation
\r
1134 --e.g., when overflow happens, it just ignore subsequent entry.
\r
1135 --old secondary sprite entry.
\r
1136 if (p_oam_cnt = "00000000" and cur_x > conv_std_logic_vector(192, X_SIZE)) then
\r
1137 p_oam_cnt_wrap_n <= '0';
\r
1140 --odd cycle copy from primary oam
\r
1141 if (cur_x(0) = '1') then
\r
1142 if (oam_ev_status = EV_STAT_COMP) then
\r
1143 p_oam_addr_in <= p_oam_cnt;
\r
1144 p_oam_cnt_ce_n <= '1';
\r
1145 s_oam_cnt_ce_n <= '1';
\r
1146 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1147 p_oam_addr_in <= p_oam_cnt + "00000001";
\r
1148 s_oam_cnt_ce_n <= '1';
\r
1150 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1151 p_oam_addr_in <= p_oam_cnt + "00000010";
\r
1152 s_oam_cnt_ce_n <= '1';
\r
1154 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1155 oam_ev_status <= EV_STAT_PRE_COMP;
\r
1156 p_oam_addr_in <= p_oam_cnt + "00000011";
\r
1157 s_oam_cnt_ce_n <= '1';
\r
1160 --even cycle copy to secondary oam (if y is in range.)
\r
1163 s_oam_addr <= s_oam_cnt;
\r
1164 s_oam_data <= p_oam_data;
\r
1166 if (oam_ev_status = EV_STAT_COMP) then
\r
1168 if (cur_y < "000000110" and p_oam_data <= cur_y + "000000001") or
\r
1169 (cur_y >= "000000110" and p_oam_data <= cur_y + "000000001" and
\r
1170 p_oam_data >= cur_y - "000000110") then
\r
1171 oam_ev_status <= EV_STAT_CP1;
\r
1172 s_oam_cnt_ce_n <= '0';
\r
1173 --copy remaining oam entry.
\r
1174 p_oam_cnt_ce_n <= '1';
\r
1177 p_oam_cnt_ce_n <= '0';
\r
1179 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1180 s_oam_cnt_ce_n <= '0';
\r
1181 oam_ev_status <= EV_STAT_CP2;
\r
1182 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1183 s_oam_cnt_ce_n <= '0';
\r
1184 oam_ev_status <= EV_STAT_CP3;
\r
1185 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1186 s_oam_cnt_ce_n <= '0';
\r
1187 elsif (oam_ev_status = EV_STAT_PRE_COMP) then
\r
1188 oam_ev_status <= EV_STAT_COMP;
\r
1189 s_oam_cnt_ce_n <= '0';
\r
1190 p_oam_cnt_ce_n <= '0';
\r
1192 end if;--if (cur_x(0) = '1') then
\r
1194 --prepare for next step
\r
1195 s_oam_addr_cpy_n <= '1';
\r
1196 spr_y_we_n <= '1';
\r
1197 spr_tile_we_n <= '1';
\r
1198 spr_x_we_n <= "11111111";
\r
1199 spr_attr_we_n <= "11111111";
\r
1200 spr_ptn_l_we_n <= "11111111";
\r
1201 spr_ptn_h_we_n <= "11111111";
\r
1203 --sprite pattern fetch
\r
1204 elsif (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
1205 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) then
\r
1207 s_oam_addr_cpy_n <= '0';
\r
1210 s_oam_addr <= s_oam_addr_cpy;
\r
1212 ----fetch y-cordinate from secondary oam
\r
1213 if (cur_x (2 downto 0) = "001" ) then
\r
1214 s_oam_addr_cpy_ce_n <= '0';
\r
1215 spr_y_we_n <= '0';
\r
1217 spr_y_we_n <= '1';
\r
1220 ----fetch tile number
\r
1221 if (cur_x (2 downto 0) = "010" ) then
\r
1222 spr_tile_we_n <= '0';
\r
1224 spr_tile_we_n <= '1';
\r
1227 ----fetch attribute
\r
1228 if (cur_x (2 downto 0) = "011" ) then
\r
1229 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1231 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1232 end if;--if (cur_x (2 downto 0) = "010" ) then
\r
1234 ----fetch x-cordinate
\r
1235 if (cur_x (2 downto 0) = "100" ) then
\r
1236 s_oam_addr_cpy_ce_n <= '1';
\r
1237 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1239 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1242 ----fetch pattern table low byte.
\r
1243 if (cur_x (2 downto 0) = "101" ) then
\r
1244 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1245 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1246 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1247 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0));
\r
1249 --flip sprite vertically.
\r
1250 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1251 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1252 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010");
\r
1256 if (cur_x (2 downto 0) = "110" ) then
\r
1257 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1259 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1262 ----fetch pattern table high byte.
\r
1263 if (cur_x (2 downto 0) = "111" ) then
\r
1264 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1265 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1266 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1267 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0))
\r
1268 + "00000000001000";
\r
1270 --flip sprite vertically.
\r
1271 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1272 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1273 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010")
\r
1274 + "00000000001000";
\r
1278 if (cur_x (2 downto 0) = "000") then
\r
1279 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1280 s_oam_addr_cpy_ce_n <= '0';
\r
1282 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2) - "001")) <= '1';
\r
1285 elsif (cur_x > conv_std_logic_vector(320, X_SIZE)) then
\r
1286 --clear last write enable.
\r
1287 spr_ptn_h_we_n <= "11111111";
\r
1288 end if;--if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE))
\r
1291 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1292 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1294 if (cur_x = "000000000") then
\r
1295 spr_x_ce_n <= "00000000";
\r
1298 for i in 0 to 7 loop
\r
1299 if (spr_x_cnt(i) = "00000000") then
\r
1300 --active sprite, start shifting..
\r
1301 spr_x_ce_n(i) <= '1';
\r
1302 spr_ptn_ce_n(i) <= '0';
\r
1306 spr_x_ce_n <= "11111111";
\r
1307 spr_ptn_ce_n <= "11111111";
\r
1308 end if; --if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE))
\r
1309 end if; --if (ppu_mask(PPUSSP) = '1') then
\r
1311 --output visible area only.
\r
1312 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1313 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1321 if ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1322 (cur_y = conv_std_logic_vector(VSCAN + 1, X_SIZE))) then
\r
1324 ppu_status(ST_VBL) <= '1';
\r
1325 elsif ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1326 (cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1327 ppu_status(ST_SP0) <= '0';
\r
1329 ppu_status(ST_VBL) <= '0';
\r
1330 --TODO: sprite overflow is not inplemented!
\r
1331 ppu_status(ST_SOF) <= '0';
\r
1333 end if; --if (clk'event and clk = '1') then
\r
1335 -- if (read_status'event and read_status = '1') then
\r
1336 -- --reading ppu status clears vblank bit.
\r
1337 -- ppu_status(ST_VBL) <= '0';
\r
1340 end if;--if (rst_n = '0') then
\r