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
16 signal dbg_ppu_clk : out std_logic;
\r
17 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
18 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
19 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
21 vga_clk : in std_logic;
\r
22 mem_clk : in std_logic;
\r
23 rst_n : in std_logic;
\r
26 rd_n : out std_logic;
\r
27 wr_n : out std_logic;
\r
28 ale : out std_logic;
\r
29 vram_ad : inout std_logic_vector (7 downto 0);
\r
30 vram_a : out std_logic_vector (13 downto 8);
\r
33 h_sync_n : out std_logic;
\r
34 v_sync_n : out std_logic;
\r
35 r : out std_logic_vector (3 downto 0);
\r
36 g : out std_logic_vector (3 downto 0);
\r
37 b : out std_logic_vector (3 downto 0);
\r
40 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
41 ppu_mask : in std_logic_vector (7 downto 0);
\r
42 read_status : in std_logic;
\r
43 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
44 ppu_scroll_y : in std_logic_vector (7 downto 0)
\r
48 architecture rtl of vga_ctl is
\r
50 component counter_register
\r
52 dsize : integer := 8;
\r
55 port ( clk : in std_logic;
\r
56 rst_n : in std_logic;
\r
57 ce_n : in std_logic;
\r
58 we_n : in std_logic;
\r
59 d : in std_logic_vector(dsize - 1 downto 0);
\r
60 q : out std_logic_vector(dsize - 1 downto 0)
\r
64 component ppu_vga_render
\r
66 signal dbg_ppu_clk : out std_logic;
\r
67 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
68 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
69 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
72 mem_clk : in std_logic;
\r
73 rst_n : in std_logic;
\r
74 rd_n : out std_logic;
\r
75 wr_n : out std_logic;
\r
76 ale : out std_logic;
\r
77 vram_ad : inout std_logic_vector (7 downto 0);
\r
78 vram_a : out std_logic_vector (13 downto 8);
\r
79 cur_x : in std_logic_vector (8 downto 0);
\r
80 cur_y : in std_logic_vector (8 downto 0);
\r
81 r : out std_logic_vector (3 downto 0);
\r
82 g : out std_logic_vector (3 downto 0);
\r
83 b : out std_logic_vector (3 downto 0);
\r
84 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
85 ppu_mask : in std_logic_vector (7 downto 0);
\r
86 read_status : in std_logic;
\r
87 ppu_status : out std_logic_vector (7 downto 0);
\r
88 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
89 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
90 r_nw : in std_logic;
\r
91 oam_bus_ce_n : in std_logic;
\r
92 plt_bus_ce_n : in std_logic;
\r
93 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
94 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
95 v_bus_busy_n : out std_logic
\r
99 --------- screen constant -----------
\r
100 constant VGA_W : integer := 640;
\r
101 constant VGA_H : integer := 480;
\r
102 constant VGA_W_MAX : integer := 800;
\r
103 constant VGA_H_MAX : integer := 525;
\r
104 constant H_SP : integer := 95;
\r
105 constant H_BP : integer := 48;
\r
106 constant H_FP : integer := 15;
\r
107 constant V_SP : integer := 2;
\r
108 constant V_BP : integer := 33;
\r
109 constant V_FP : integer := 10;
\r
111 --------- signal declaration -----------
\r
112 signal vga_x : std_logic_vector (9 downto 0);
\r
113 signal vga_y : std_logic_vector (9 downto 0);
\r
114 signal x_res_n : std_logic;
\r
115 signal y_res_n : std_logic;
\r
116 signal y_en_n : std_logic;
\r
117 signal cnt_clk : std_logic;
\r
119 signal emu_ppu_clk : std_logic;
\r
120 signal emu_ppu_clk_n : std_logic;
\r
121 signal count5_res_n : std_logic;
\r
122 signal count5 : std_logic_vector(2 downto 0);
\r
123 signal nes_x : std_logic_vector (8 downto 0);
\r
124 signal nes_y : std_logic_vector (8 downto 0);
\r
129 signal r_nw : std_logic;
\r
130 signal oam_bus_ce_n : std_logic;
\r
131 signal plt_bus_ce_n : std_logic;
\r
132 signal oam_plt_addr : std_logic_vector (7 downto 0);
\r
133 signal oam_plt_data : std_logic_vector (7 downto 0);
\r
134 signal v_bus_busy_n : std_logic;
\r
135 signal ppu_status : std_logic_vector (7 downto 0);
\r
136 signal dbg_disp_ptn_h2, dbg_disp_ptn_l2 : std_logic_vector (15 downto 0);
\r
138 ---DE1 base clock 50 MHz
\r
139 ---motones sim project uses following clock.
\r
140 --cpu clock = base clock / 24 = 2.08 MHz (480 ns / cycle)
\r
141 --ppu clock = base clock / 8
\r
142 --vga clock = base clock / 2
\r
143 --sdram clock = 135 MHz
\r
147 dbg_disp_ptn_h <= "000000" & vga_x;
\r
148 dbg_disp_ptn_l <= "0000000" & nes_x;
\r
151 cnt_clk <= not vga_clk;
\r
153 --vga position counter
\r
154 x_inst : counter_register generic map (10, 1)
\r
155 port map (cnt_clk , x_res_n, '0', '1', (others => '0'), vga_x);
\r
156 y_inst : counter_register generic map (10, 1)
\r
157 port map (cnt_clk , y_res_n, y_en_n, '1', (others => '0'), vga_y);
\r
158 vga_out_p : process (rst_n, vga_clk)
\r
160 if (rst_n = '0') then
\r
166 -- r<=(others => '0');
\r
167 -- g<=(others => '0');
\r
168 -- b<=(others => '0');
\r
170 elsif (rising_edge(vga_clk)) then
\r
172 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
176 if (vga_y = conv_std_logic_vector(VGA_H_MAX, 10)) then
\r
187 --sync signal assert.
\r
188 if (vga_x >= conv_std_logic_vector((VGA_W + H_FP) , 10) and
\r
189 vga_x < conv_std_logic_vector((VGA_W + H_FP + H_SP) , 10)) then
\r
195 if (vga_y >= conv_std_logic_vector((VGA_H + V_FP) , 10) and
\r
196 vga_y < conv_std_logic_vector((VGA_H + V_FP + V_SP) , 10)) then
\r
202 -- if (vga_y <=conv_std_logic_vector((VGA_H) , 10)) then
\r
203 -- if (vga_x < conv_std_logic_vector((VGA_W) , 10)) then
\r
208 -- r<=(others => '0');
\r
209 -- g<=(others => '0');
\r
210 -- b<=(others => '0');
\r
213 -- r<=(others => '0');
\r
214 -- g<=(others => '0');
\r
215 -- b<=(others => '0');
\r
221 --emulate ppu clock that is synchronized with vga clock
\r
222 count5_inst : counter_register generic map (3, 1)
\r
223 port map (cnt_clk, count5_res_n, '0', '1', (others => '0'), count5);
\r
224 nes_x_inst : counter_register generic map (9, 1)
\r
225 port map (emu_ppu_clk , x_res_n, '0', '1', (others => '0'), nes_x);
\r
226 nes_y <= vga_y(9 downto 1);
\r
227 emu_clk_p : process (rst_n, vga_clk)
\r
229 if (rst_n = '0') then
\r
230 emu_ppu_clk <= '0';
\r
231 count5_res_n <= '0';
\r
232 elsif (rising_edge(vga_clk)) then
\r
233 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
234 count5_res_n <= '0';
\r
235 elsif (count5 = "100") then
\r
236 count5_res_n <= '0';
\r
238 count5_res_n <= '1';
\r
241 if (count5 = "001" or count5 = "011") then
\r
242 emu_ppu_clk <= '0';
\r
244 emu_ppu_clk <= '1';
\r
249 --vga emulated render instance...
\r
250 oam_plt_data <= (others => 'Z');
\r
251 emu_ppu_clk_n <= not emu_ppu_clk;
\r
252 vga_render_inst : ppu_vga_render
\r
256 dbg_disp_nt, dbg_disp_attr ,
\r
257 dbg_disp_ptn_h2, dbg_disp_ptn_l2 ,
\r
290 ---------------------------------------------------------------
\r
291 ---------------------------------------------------------------
\r
292 ------------------------ PPU VGA Renderer ---------------------
\r
293 ---------------------------------------------------------------
\r
294 ---------------------------------------------------------------
\r
297 use ieee.std_logic_1164.all;
\r
298 use ieee.std_logic_arith.conv_std_logic_vector;
\r
299 use ieee.std_logic_unsigned.all;
\r
300 use work.motonesfpga_common.all;
\r
302 entity ppu_vga_render is
\r
304 signal dbg_ppu_clk : out std_logic;
\r
305 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
306 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
307 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
309 clk : in std_logic;
\r
310 mem_clk : in std_logic;
\r
311 rst_n : in std_logic;
\r
313 rd_n : out std_logic;
\r
314 wr_n : out std_logic;
\r
315 ale : out std_logic;
\r
316 vram_ad : inout std_logic_vector (7 downto 0);
\r
317 vram_a : out std_logic_vector (13 downto 8);
\r
319 --current drawing position 340 x 261
\r
320 cur_x : in std_logic_vector (8 downto 0);
\r
321 cur_y : in std_logic_vector (8 downto 0);
\r
322 r : out std_logic_vector (3 downto 0);
\r
323 g : out std_logic_vector (3 downto 0);
\r
324 b : out std_logic_vector (3 downto 0);
\r
326 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
327 ppu_mask : in std_logic_vector (7 downto 0);
\r
328 read_status : in std_logic;
\r
329 ppu_status : out std_logic_vector (7 downto 0);
\r
330 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
331 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
333 r_nw : in std_logic;
\r
334 oam_bus_ce_n : in std_logic;
\r
335 plt_bus_ce_n : in std_logic;
\r
336 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
337 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
338 v_bus_busy_n : out std_logic
\r
340 end ppu_vga_render;
\r
342 architecture rtl of ppu_vga_render is
\r
344 component counter_register
\r
346 dsize : integer := 8;
\r
349 port ( clk : in std_logic;
\r
350 rst_n : in std_logic;
\r
351 ce_n : in std_logic;
\r
352 we_n : in std_logic;
\r
353 d : in std_logic_vector(dsize - 1 downto 0);
\r
354 q : out std_logic_vector(dsize - 1 downto 0)
\r
358 component shift_register
\r
360 dsize : integer := 8;
\r
361 shift : integer := 1
\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 d_flip_flop
\r
374 dsize : integer := 8
\r
377 clk : in std_logic;
\r
378 res_n : in std_logic;
\r
379 set_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 tri_state_buffer
\r
388 dsize : integer := 8
\r
391 oe_n : in std_logic;
\r
392 d : in std_logic_vector (dsize - 1 downto 0);
\r
393 q : out std_logic_vector (dsize - 1 downto 0)
\r
398 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
400 clk : in std_logic;
\r
401 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
402 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
403 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
407 component palette_ram
\r
408 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
410 clk : in std_logic;
\r
411 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
412 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
413 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
419 clk : in std_logic;
\r
420 ce_n, oe_n, we_n : in std_logic;
\r
421 sync_ce_n : out std_logic
\r
425 --nes screen size is emulated to align with the vga timing...
\r
426 constant X_SIZE : integer := 9;
\r
427 constant dsize : integer := 8;
\r
428 constant asize : integer := 14;
\r
429 --constant HSCAN_MAX : integer := 341;
\r
430 constant HSCAN_MAX : integer := 321;
\r
431 constant VSCAN_MAX : integer := 262;
\r
432 constant HSCAN : integer := 256;
\r
433 constant VSCAN : integer := 240;
\r
434 --constant HSCAN_NEXT_START : integer := 320;
\r
435 --constant HSCAN_NEXT_EXTRA : integer := 336;
\r
436 constant HSCAN_NEXT_START : integer := 300;
\r
437 constant HSCAN_NEXT_EXTRA : integer := 316;
\r
440 constant PPUBNA : integer := 1; --base name address
\r
441 constant PPUVAI : integer := 2; --vram address increment
\r
442 constant PPUSPA : integer := 3; --sprite pattern table address
\r
443 constant PPUBPA : integer := 4; --background pattern table address
\r
444 constant PPUSPS : integer := 5; --sprite size
\r
445 constant PPUMS : integer := 6; --ppu master/slave
\r
446 constant PPUNEN : integer := 7; --nmi enable
\r
448 constant PPUGS : integer := 0; --grayscale
\r
449 constant PPUSBL : integer := 1; --show 8 left most bg pixel
\r
450 constant PPUSSL : integer := 2; --show 8 left most sprite pixel
\r
451 constant PPUSBG : integer := 3; --show bg
\r
452 constant PPUSSP : integer := 4; --show sprie
\r
453 constant PPUIR : integer := 5; --intensify red
\r
454 constant PPUIG : integer := 6; --intensify green
\r
455 constant PPUIB : integer := 7; --intensify blue
\r
457 constant SPRHFL : integer := 6; --flip sprigte horizontally
\r
458 constant SPRVFL : integer := 7; --flip sprigte vertically
\r
460 constant ST_SOF : integer := 5; --sprite overflow
\r
461 constant ST_SP0 : integer := 6; --sprite 0 hits
\r
462 constant ST_VBL : integer := 7; --vblank
\r
464 subtype nes_color_data is std_logic_vector (11 downto 0);
\r
465 type nes_color_array is array (0 to 63) of nes_color_data;
\r
466 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
\r
467 constant nes_color_palette : nes_color_array := (
\r
468 conv_std_logic_vector(16#777#, 12),
\r
469 conv_std_logic_vector(16#20b#, 12),
\r
470 conv_std_logic_vector(16#20b#, 12),
\r
471 conv_std_logic_vector(16#61a#, 12),
\r
472 conv_std_logic_vector(16#927#, 12),
\r
473 conv_std_logic_vector(16#b13#, 12),
\r
474 conv_std_logic_vector(16#a30#, 12),
\r
475 conv_std_logic_vector(16#740#, 12),
\r
476 conv_std_logic_vector(16#450#, 12),
\r
477 conv_std_logic_vector(16#360#, 12),
\r
478 conv_std_logic_vector(16#360#, 12),
\r
479 conv_std_logic_vector(16#364#, 12),
\r
480 conv_std_logic_vector(16#358#, 12),
\r
481 conv_std_logic_vector(16#000#, 12),
\r
482 conv_std_logic_vector(16#000#, 12),
\r
483 conv_std_logic_vector(16#000#, 12),
\r
484 conv_std_logic_vector(16#bbb#, 12),
\r
485 conv_std_logic_vector(16#46f#, 12),
\r
486 conv_std_logic_vector(16#44f#, 12),
\r
487 conv_std_logic_vector(16#94f#, 12),
\r
488 conv_std_logic_vector(16#d4c#, 12),
\r
489 conv_std_logic_vector(16#d46#, 12),
\r
490 conv_std_logic_vector(16#e50#, 12),
\r
491 conv_std_logic_vector(16#c70#, 12),
\r
492 conv_std_logic_vector(16#880#, 12),
\r
493 conv_std_logic_vector(16#5a0#, 12),
\r
494 conv_std_logic_vector(16#4a1#, 12),
\r
495 conv_std_logic_vector(16#4a6#, 12),
\r
496 conv_std_logic_vector(16#49c#, 12),
\r
497 conv_std_logic_vector(16#000#, 12),
\r
498 conv_std_logic_vector(16#000#, 12),
\r
499 conv_std_logic_vector(16#000#, 12),
\r
500 conv_std_logic_vector(16#fff#, 12),
\r
501 conv_std_logic_vector(16#6af#, 12),
\r
502 conv_std_logic_vector(16#58f#, 12),
\r
503 conv_std_logic_vector(16#a7f#, 12),
\r
504 conv_std_logic_vector(16#f6f#, 12),
\r
505 conv_std_logic_vector(16#f6b#, 12),
\r
506 conv_std_logic_vector(16#f73#, 12),
\r
507 conv_std_logic_vector(16#fa0#, 12),
\r
508 conv_std_logic_vector(16#ed2#, 12),
\r
509 conv_std_logic_vector(16#9e0#, 12),
\r
510 conv_std_logic_vector(16#7f4#, 12),
\r
511 conv_std_logic_vector(16#7e9#, 12),
\r
512 conv_std_logic_vector(16#6de#, 12),
\r
513 conv_std_logic_vector(16#777#, 12),
\r
514 conv_std_logic_vector(16#000#, 12),
\r
515 conv_std_logic_vector(16#000#, 12),
\r
516 conv_std_logic_vector(16#fff#, 12),
\r
517 conv_std_logic_vector(16#9df#, 12),
\r
518 conv_std_logic_vector(16#abf#, 12),
\r
519 conv_std_logic_vector(16#cbf#, 12),
\r
520 conv_std_logic_vector(16#ebf#, 12),
\r
521 conv_std_logic_vector(16#fbe#, 12),
\r
522 conv_std_logic_vector(16#fcb#, 12),
\r
523 conv_std_logic_vector(16#fda#, 12),
\r
524 conv_std_logic_vector(16#ff9#, 12),
\r
525 conv_std_logic_vector(16#cf8#, 12),
\r
526 conv_std_logic_vector(16#afa#, 12),
\r
527 conv_std_logic_vector(16#afc#, 12),
\r
528 conv_std_logic_vector(16#aff#, 12),
\r
529 conv_std_logic_vector(16#aaa#, 12),
\r
530 conv_std_logic_vector(16#000#, 12),
\r
531 conv_std_logic_vector(16#000#, 12)
\r
534 signal clk_n : std_logic;
\r
537 signal bg_io_cnt : std_logic_vector(0 downto 0);
\r
538 signal spr_io_cnt : std_logic_vector(0 downto 0);
\r
541 signal io_oe_n : std_logic;
\r
542 signal ah_oe_n : std_logic;
\r
544 signal cnt_x_res_n : std_logic;
\r
545 signal bg_cnt_res_n : std_logic;
\r
547 --bg prefetch position (scroll + 16 cycle ahead of current pos)
\r
548 --511 x 239 (or 255 x 479)
\r
549 signal prf_x : std_logic_vector(X_SIZE - 1 downto 0);
\r
550 signal prf_y : std_logic_vector(X_SIZE - 1 downto 0);
\r
552 signal nt_we_n : std_logic;
\r
553 signal disp_nt : std_logic_vector (dsize - 1 downto 0);
\r
555 signal attr_ce_n : std_logic;
\r
556 signal attr_we_n : std_logic;
\r
557 signal attr_val : std_logic_vector (dsize - 1 downto 0);
\r
558 signal disp_attr_we_n : std_logic;
\r
559 signal disp_attr : std_logic_vector (dsize - 1 downto 0);
\r
561 signal ptn_l_we_n : std_logic;
\r
562 signal ptn_l_in : std_logic_vector (dsize - 1 downto 0);
\r
563 signal ptn_l_val : std_logic_vector (dsize - 1 downto 0);
\r
564 signal disp_ptn_l_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
565 signal disp_ptn_l : std_logic_vector (dsize * 2 - 1 downto 0);
\r
567 signal ptn_h_we_n : std_logic;
\r
568 signal ptn_h_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
569 signal disp_ptn_h : std_logic_vector (dsize * 2 - 1 downto 0);
\r
571 --signals for palette / oam access from cpu
\r
572 signal r_n : std_logic;
\r
573 signal vram_addr : std_logic_vector (asize - 1 downto 0);
\r
576 signal plt_ram_ce_n_in : std_logic;
\r
577 signal plt_ram_ce_n : std_logic;
\r
578 signal plt_r_n : std_logic;
\r
579 signal plt_w_n : std_logic;
\r
580 signal plt_addr : std_logic_vector (4 downto 0);
\r
581 signal plt_data : std_logic_vector (dsize - 1 downto 0);
\r
583 --primari / secondary oam
\r
584 signal p_oam_ram_ce_n_in : std_logic;
\r
585 signal p_oam_ram_ce_n : std_logic;
\r
586 signal p_oam_r_n : std_logic;
\r
587 signal p_oam_w_n : std_logic;
\r
588 signal p_oam_addr : std_logic_vector (dsize - 1 downto 0);
\r
589 signal p_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
591 signal s_oam_ram_ce_n_in : std_logic;
\r
592 signal s_oam_ram_ce_n : std_logic;
\r
593 signal s_oam_r_n : std_logic;
\r
594 signal s_oam_w_n : std_logic;
\r
595 signal s_oam_addr_cpy_ce_n : std_logic;
\r
596 signal s_oam_addr_cpy_n : std_logic;
\r
597 signal s_oam_addr : std_logic_vector (4 downto 0);
\r
598 signal s_oam_addr_cpy : std_logic_vector (4 downto 0);
\r
599 signal s_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
601 signal p_oam_cnt_res_n : std_logic;
\r
602 signal p_oam_cnt_ce_n : std_logic;
\r
603 signal p_oam_cnt_wrap_n : std_logic;
\r
604 signal p_oam_cnt : std_logic_vector (dsize - 1 downto 0);
\r
605 signal p_oam_addr_in : std_logic_vector (dsize - 1 downto 0);
\r
606 signal oam_ev_status : std_logic_vector (2 downto 0);
\r
608 signal s_oam_cnt_ce_n : std_logic;
\r
609 signal s_oam_cnt : std_logic_vector (4 downto 0);
\r
611 --oam evaluation status
\r
612 constant EV_STAT_COMP : std_logic_vector (2 downto 0) := "000";
\r
613 constant EV_STAT_CP1 : std_logic_vector (2 downto 0) := "001";
\r
614 constant EV_STAT_CP2 : std_logic_vector (2 downto 0) := "010";
\r
615 constant EV_STAT_CP3 : std_logic_vector (2 downto 0) := "011";
\r
616 constant EV_STAT_PRE_COMP : std_logic_vector (2 downto 0) := "100";
\r
618 ----------sprite registers.
\r
619 type oam_pin_array is array (0 to 7) of std_logic;
\r
620 type oam_reg_array is array (0 to 7) of std_logic_vector (dsize - 1 downto 0);
\r
622 signal spr_x_we_n : oam_pin_array;
\r
623 signal spr_x_ce_n : oam_pin_array;
\r
624 signal spr_attr_we_n : oam_pin_array;
\r
625 signal spr_ptn_l_we_n : oam_pin_array;
\r
626 signal spr_ptn_h_we_n : oam_pin_array;
\r
627 signal spr_ptn_ce_n : oam_pin_array;
\r
629 signal spr_x_cnt : oam_reg_array;
\r
630 signal spr_attr : oam_reg_array;
\r
631 signal spr_ptn_l : oam_reg_array;
\r
632 signal spr_ptn_h : oam_reg_array;
\r
634 signal spr_y_we_n : std_logic;
\r
635 signal spr_tile_we_n : std_logic;
\r
636 signal spr_y_tmp : std_logic_vector (dsize - 1 downto 0);
\r
637 signal spr_tile_tmp : std_logic_vector (dsize - 1 downto 0);
\r
638 signal spr_ptn_in : std_logic_vector (dsize - 1 downto 0);
\r
642 dbg_ppu_clk <= clk;
\r
643 dbg_nes_x <= cur_x;
\r
644 dbg_disp_nt <= disp_nt;
\r
645 dbg_disp_attr <= disp_attr;
\r
646 dbg_disp_ptn_h <= disp_ptn_h;
\r
647 dbg_disp_ptn_l <= disp_ptn_l;
\r
652 ale <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
653 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
654 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
655 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
656 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
657 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
658 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
659 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
660 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
661 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
664 rd_n <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
665 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
666 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
667 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
668 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
669 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
670 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
671 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
672 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
673 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
675 wr_n <= '1' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
676 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
677 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
679 io_oe_n <= not bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
680 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
681 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
682 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
683 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
684 not spr_io_cnt(0) when ppu_mask(PPUSSP) = '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(256, X_SIZE) and
\r
688 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
690 ah_oe_n <= '0' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
691 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
692 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
694 v_bus_busy_n <= ah_oe_n;
\r
696 bg_io_cnt_inst : counter_register generic map (1, 1)
\r
697 port map (clk, bg_cnt_res_n, '0', '1', (others => '0'), bg_io_cnt);
\r
698 spr_io_cnt_inst : counter_register generic map (1, 1)
\r
699 port map (clk, cnt_x_res_n, '0', '1', (others => '0'), spr_io_cnt);
\r
701 ---bg prefetch x pos is 16 + scroll cycle ahead of current pos.
\r
702 prf_x <= cur_x + ppu_scroll_x + "000010000"
\r
703 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) else
\r
704 cur_x + ppu_scroll_x + "010111011"; -- +16 -341
\r
706 prf_y <= cur_y + ppu_scroll_y
\r
707 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) and
\r
708 cur_y + ppu_scroll_y <
\r
709 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
710 cur_y + ppu_scroll_y + "000000001"
\r
711 when cur_y + ppu_scroll_y <
\r
712 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
715 nt_inst : d_flip_flop generic map(dsize)
\r
716 port map (clk_n, rst_n, '1', nt_we_n, vram_ad, disp_nt);
\r
718 at_inst : d_flip_flop generic map(dsize)
\r
719 port map (clk_n, rst_n, '1', attr_we_n, vram_ad, attr_val);
\r
721 disp_at_inst : shift_register generic map(dsize, 2)
\r
722 port map (clk_n, rst_n, attr_ce_n, disp_attr_we_n, attr_val, disp_attr);
\r
724 --chr rom data's bit is stored in opposite direction.
\r
725 --reverse bit when loading...
\r
726 ptn_l_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
727 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
728 ptn_h_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
729 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7)) &
\r
730 disp_ptn_h (dsize downto 1);
\r
732 ptn_l_inst : d_flip_flop generic map(dsize)
\r
733 port map (clk_n, rst_n, '1', ptn_l_we_n, ptn_l_in, ptn_l_val);
\r
735 disp_ptn_l_in <= ptn_l_val & disp_ptn_l (dsize downto 1);
\r
736 disp_ptn_l_inst : shift_register generic map(dsize * 2, 1)
\r
737 port map (clk_n, rst_n, '0', ptn_h_we_n, disp_ptn_l_in, disp_ptn_l);
\r
739 ptn_h_inst : shift_register generic map(dsize * 2, 1)
\r
740 port map (clk_n, rst_n, '0', ptn_h_we_n, ptn_h_in, disp_ptn_h);
\r
743 vram_io_buf : tri_state_buffer generic map (dsize)
\r
744 port map (io_oe_n, vram_addr(dsize - 1 downto 0), vram_ad);
\r
746 vram_a_buf : tri_state_buffer generic map (6)
\r
747 port map (ah_oe_n, vram_addr(asize - 1 downto dsize), vram_a);
\r
752 plt_ram_ce_n_in <= clk when plt_bus_ce_n = '0' and r_nw = '0' else
\r
753 '0' when plt_bus_ce_n = '0' and r_nw = '1' else
\r
754 '0' when ppu_mask(PPUSBG) = '1' and
\r
755 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
756 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
759 plt_addr <= oam_plt_addr(4 downto 0) when plt_bus_ce_n = '0' else
\r
760 "1" & spr_attr(0)(1 downto 0) & spr_ptn_h(0)(0) & spr_ptn_l(0)(0)
\r
761 when ppu_mask(PPUSSP) = '1' and
\r
762 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
763 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
764 spr_x_cnt(0) = "00000000" and
\r
765 (spr_ptn_h(0)(0) or spr_ptn_l(0)(0)) = '1' else
\r
766 "1" & spr_attr(1)(1 downto 0) & spr_ptn_h(1)(0) & spr_ptn_l(1)(0)
\r
767 when ppu_mask(PPUSSP) = '1' and
\r
768 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
769 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
770 spr_x_cnt(1) = "00000000" and
\r
771 (spr_ptn_h(1)(0) or spr_ptn_l(1)(0)) = '1' else
\r
772 "1" & spr_attr(2)(1 downto 0) & spr_ptn_h(2)(0) & spr_ptn_l(2)(0)
\r
773 when ppu_mask(PPUSSP) = '1' and
\r
774 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
775 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
776 spr_x_cnt(2) = "00000000" and
\r
777 (spr_ptn_h(2)(0) or spr_ptn_l(2)(0)) = '1' else
\r
778 "1" & spr_attr(3)(1 downto 0) & spr_ptn_h(3)(0) & spr_ptn_l(3)(0)
\r
779 when ppu_mask(PPUSSP) = '1' and
\r
780 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
781 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
782 spr_x_cnt(3) = "00000000" and
\r
783 (spr_ptn_h(3)(0) or spr_ptn_l(3)(0)) = '1' else
\r
784 "1" & spr_attr(4)(1 downto 0) & spr_ptn_h(4)(0) & spr_ptn_l(4)(0)
\r
785 when ppu_mask(PPUSSP) = '1' and
\r
786 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
787 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
788 spr_x_cnt(4) = "00000000" and
\r
789 (spr_ptn_h(4)(0) or spr_ptn_l(4)(0)) = '1' else
\r
790 "1" & spr_attr(5)(1 downto 0) & spr_ptn_h(5)(0) & spr_ptn_l(5)(0)
\r
791 when ppu_mask(PPUSSP) = '1' and
\r
792 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
793 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
794 spr_x_cnt(5) = "00000000" and
\r
795 (spr_ptn_h(5)(0) or spr_ptn_l(5)(0)) = '1' else
\r
796 "1" & spr_attr(6)(1 downto 0) & spr_ptn_h(6)(0) & spr_ptn_l(6)(0)
\r
797 when ppu_mask(PPUSSP) = '1' and
\r
798 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
799 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
800 spr_x_cnt(6) = "00000000" and
\r
801 (spr_ptn_h(6)(0) or spr_ptn_l(6)(0)) = '1' else
\r
802 "1" & spr_attr(7)(1 downto 0) & spr_ptn_h(7)(0) & spr_ptn_l(7)(0)
\r
803 when ppu_mask(PPUSSP) = '1' and
\r
804 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
805 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
806 spr_x_cnt(7) = "00000000" and
\r
807 (spr_ptn_h(7)(0) or spr_ptn_l(7)(0)) = '1' else
\r
808 "0" & disp_attr(1 downto 0) & disp_ptn_h(0) & disp_ptn_l(0)
\r
809 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '0' and
\r
810 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
811 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
812 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
813 "0" & disp_attr(5 downto 4) & disp_ptn_h(0) & disp_ptn_l(0)
\r
814 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '1' and
\r
815 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
816 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
817 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
818 ---else: no output color >> universal bg color output.
\r
819 --0x3f00 is the universal bg palette.
\r
822 plt_r_n <= not r_nw when plt_bus_ce_n = '0' else
\r
823 '0' when ppu_mask(PPUSBG) = '1' else
\r
825 plt_w_n <= r_nw when plt_bus_ce_n = '0' else
\r
827 plt_d_buf_w : tri_state_buffer generic map (dsize)
\r
828 port map (r_nw, oam_plt_data, plt_data);
\r
829 plt_d_buf_r : tri_state_buffer generic map (dsize)
\r
830 port map (r_n, plt_data, oam_plt_data);
\r
831 plt_ram_ctl : ram_ctrl
\r
832 port map (mem_clk, plt_ram_ce_n_in, plt_r_n, plt_w_n, plt_ram_ce_n);
\r
833 palette_inst : palette_ram generic map (5, dsize)
\r
834 port map (mem_clk, plt_ram_ce_n, plt_r_n, plt_w_n, plt_addr, plt_data);
\r
837 p_oam_ram_ce_n_in <= clk when oam_bus_ce_n = '0' and r_nw = '0' else
\r
838 '0' when oam_bus_ce_n = '0' and r_nw = '1' else
\r
839 '0' when ppu_mask(PPUSSP) = '1' and
\r
840 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
841 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
842 p_oam_cnt_wrap_n = '1' else
\r
844 p_oam_addr <= oam_plt_addr when oam_bus_ce_n = '0' else
\r
845 p_oam_addr_in when ppu_mask(PPUSSP) = '1' and
\r
846 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
847 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
848 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
849 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
851 p_oam_r_n <= not r_nw when oam_bus_ce_n = '0' else
\r
852 '0' when ppu_mask(PPUSSP) = '1' and
\r
853 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
854 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
855 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
856 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
858 p_oam_w_n <= r_nw when oam_bus_ce_n = '0' else
\r
860 oam_d_buf_w : tri_state_buffer generic map (dsize)
\r
861 port map (r_nw, oam_plt_data, p_oam_data);
\r
862 oam_d_buf_r : tri_state_buffer generic map (dsize)
\r
863 port map (r_n, p_oam_data, oam_plt_data);
\r
865 p_oam_ram_ctl : ram_ctrl
\r
866 port map (mem_clk, p_oam_ram_ce_n_in, p_oam_r_n, p_oam_w_n, p_oam_ram_ce_n);
\r
867 primary_oam_inst : ram generic map (dsize, dsize)
\r
868 port map (mem_clk, p_oam_ram_ce_n, p_oam_r_n, p_oam_w_n, p_oam_addr, p_oam_data);
\r
871 p_oam_cnt_inst : counter_register generic map (dsize, 4)
\r
872 port map (clk_n, p_oam_cnt_res_n, p_oam_cnt_ce_n, '1', (others => '0'), p_oam_cnt);
\r
873 s_oam_cnt_inst : counter_register generic map (5, 1)
\r
874 port map (clk_n, p_oam_cnt_res_n, s_oam_cnt_ce_n, '1', (others => '0'), s_oam_cnt);
\r
875 s_oam_addr_cpy_inst : counter_register generic map (5, 1)
\r
876 port map (clk_n, p_oam_cnt_res_n, s_oam_addr_cpy_ce_n,
\r
877 '1', (others => '0'), s_oam_addr_cpy);
\r
879 s_oam_ram_ce_n_in <= clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
880 cur_x > "000000001" and
\r
881 cur_x <= conv_std_logic_vector(64, X_SIZE) else
\r
882 clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
883 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
884 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
885 p_oam_cnt_wrap_n = '1' else
\r
886 '0' when ppu_mask(PPUSSP) = '1' and
\r
887 cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
888 cur_x <= conv_std_logic_vector(320, X_SIZE) and
\r
889 s_oam_addr_cpy_n = '0' else
\r
892 s_oam_ram_ctl : ram_ctrl
\r
893 port map (mem_clk, s_oam_ram_ce_n_in, s_oam_r_n, s_oam_w_n, s_oam_ram_ce_n);
\r
894 -- secondary_oam_inst : ram generic map (5, dsize)
\r
895 -- port map (mem_clk, s_oam_ram_ce_n, s_oam_r_n, s_oam_w_n, s_oam_addr, s_oam_data);
\r
897 spr_y_inst : d_flip_flop generic map(dsize)
\r
898 port map (clk_n, p_oam_cnt_res_n, '1', spr_y_we_n, s_oam_data, spr_y_tmp);
\r
899 spr_tile_inst : d_flip_flop generic map(dsize)
\r
900 port map (clk_n, p_oam_cnt_res_n, '1', spr_tile_we_n, s_oam_data, spr_tile_tmp);
\r
903 --reverse bit when NOT SPRHFL is set (.nes file format bit endian).
\r
904 spr_ptn_in <= vram_ad when spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRHFL) = '1' else
\r
905 (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
906 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
907 --array instances...
\r
908 spr_inst : for i in 0 to 7 generate
\r
909 spr_x_inst : counter_register generic map(dsize, 16#ff#)
\r
910 port map (clk_n, rst_n, spr_x_ce_n(i), spr_x_we_n(i), s_oam_data, spr_x_cnt(i));
\r
912 spr_attr_inst : d_flip_flop generic map(dsize)
\r
913 port map (clk_n, rst_n, '1', spr_attr_we_n(i), s_oam_data, spr_attr(i));
\r
915 spr_ptn_l_inst : shift_register generic map(dsize, 1)
\r
916 port map (clk_n, rst_n, spr_ptn_ce_n(i), spr_ptn_l_we_n(i), spr_ptn_in, spr_ptn_l(i));
\r
918 spr_ptn_h_inst : shift_register generic map(dsize, 1)
\r
919 port map (clk_n, rst_n, spr_ptn_ce_n(i), spr_ptn_h_we_n(i), spr_ptn_in, spr_ptn_h(i));
\r
922 pos_p : process (rst_n, clk)
\r
924 if (rst_n = '0') then
\r
925 cnt_x_res_n <= '0';
\r
926 bg_cnt_res_n <= '0';
\r
927 elsif (clk'event and clk = '0') then
\r
928 if (cur_x = conv_std_logic_vector(HSCAN_MAX - 1, X_SIZE)) then
\r
930 cnt_x_res_n <= '0';
\r
932 cnt_x_res_n <= '1';
\r
935 if (ppu_scroll_x(0) = '0' and cur_x = conv_std_logic_vector(HSCAN, X_SIZE)) then
\r
936 bg_cnt_res_n <= '0';
\r
937 elsif (ppu_scroll_x(0) = '1' and cur_x = conv_std_logic_vector(HSCAN - 1, X_SIZE)) then
\r
938 bg_cnt_res_n <= '0';
\r
940 bg_cnt_res_n <= '1';
\r
942 end if; --if (rst_n = '0') then
\r
945 clk_p : process (rst_n, clk, read_status)
\r
947 procedure output_rgb is
\r
948 variable pl_addr : integer;
\r
949 variable pl_index : integer;
\r
950 variable dot_output : boolean;
\r
952 dot_output := false;
\r
954 --first show sprite.
\r
955 if (ppu_mask(PPUSSP) = '1') then
\r
956 for i in 0 to 7 loop
\r
957 if (spr_x_cnt(i) = "00000000") then
\r
958 if ((spr_ptn_h(i)(0) or spr_ptn_l(i)(0)) = '1') then
\r
959 dot_output := true;
\r
966 if (dot_output = true and ppu_mask(PPUSBG) = '1' and
\r
967 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
968 --raise sprite 0 hit.
\r
969 ppu_status(ST_SP0) <= '1';
\r
972 --first color in the palette is transparent color.
\r
973 if (ppu_mask(PPUSBG) = '1' and dot_output = false and
\r
974 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
975 dot_output := true;
\r
976 -- d_print("output_rgb");
\r
977 -- d_print("pl_addr:" & conv_hex8(pl_addr));
\r
978 -- d_print("pl_index:" & conv_hex8(pl_index));
\r
981 --if or if not bg/sprite is shown, output color anyway
\r
982 --sinse universal bg color is included..
\r
983 pl_index := conv_integer(plt_data(5 downto 0));
\r
984 b <= nes_color_palette(pl_index) (11 downto 8);
\r
985 g <= nes_color_palette(pl_index) (7 downto 4);
\r
986 r <= nes_color_palette(pl_index) (3 downto 0);
\r
987 -- d_print("rgb:" &
\r
988 -- conv_hex8(nes_color_palette(pl_index) (11 downto 8)) &
\r
989 -- conv_hex8(nes_color_palette(pl_index) (7 downto 4)) &
\r
990 -- conv_hex8(nes_color_palette(pl_index) (3 downto 0)));
\r
994 if (rst_n = '0') then
\r
997 ppu_status <= (others => '0');
\r
999 b <= (others => '0');
\r
1000 g <= (others => '0');
\r
1001 r <= (others => '0');
\r
1003 if (clk'event and clk = '0') then
\r
1007 if (clk'event and clk = '1') then
\r
1009 --fetch bg pattern and display.
\r
1010 if (ppu_mask(PPUSBG) = '1' and
\r
1011 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
1012 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) and
\r
1013 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1014 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1015 --visible area bg image
\r
1018 d_print("cur_x: " & conv_hex16(conv_integer(cur_x)));
\r
1019 d_print("cur_y: " & conv_hex16(conv_integer(cur_y)));
\r
1021 ----fetch next tile byte.
\r
1022 if (prf_x (2 downto 0) = "001") then
\r
1023 --vram addr is incremented every 8 cycle.
\r
1024 --name table at 0x2000
\r
1025 vram_addr(9 downto 0)
\r
1026 <= prf_y(dsize - 1 downto 3)
\r
1027 & prf_x(dsize - 1 downto 3);
\r
1028 vram_addr(asize - 1 downto 10) <= "10" & ppu_ctrl(PPUBNA downto 0)
\r
1029 + ("000" & prf_x(dsize));
\r
1031 if (prf_x (2 downto 0) = "010") then
\r
1037 --TODO must load 8 cycle each for the first two tiles!!!
\r
1038 ----fetch attr table byte.
\r
1039 if (prf_x (4 downto 0) = "00011") then
\r
1040 --attribute table is loaded every 32 cycle.
\r
1041 --attr table at 0x23c0
\r
1042 vram_addr(dsize - 1 downto 0) <= "11000000" +
\r
1043 ("00" & prf_y(7 downto 5) & prf_x(7 downto 5));
\r
1044 vram_addr(asize - 1 downto dsize) <= "10" &
\r
1045 ppu_ctrl(PPUBNA downto 0) & "11"
\r
1046 + ("000" & prf_x(dsize) & "00");
\r
1048 if (prf_x (4 downto 0) = "00100") then
\r
1053 if (prf_x (4 downto 0) = "10000") then
\r
1054 disp_attr_we_n <= '0';
\r
1056 disp_attr_we_n <= '1';
\r
1058 ---attribute is shifted every 16 bit.
\r
1059 if (prf_x (3 downto 0) = "0000") then
\r
1065 ----fetch pattern table low byte.
\r
1066 if (prf_x (2 downto 0) = "101") then
\r
1067 --vram addr is incremented every 8 cycle.
\r
1068 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1069 disp_nt(dsize - 1 downto 0)
\r
1070 & "0" & prf_y(2 downto 0);
\r
1072 if (prf_x (2 downto 0) = "110") then
\r
1073 ptn_l_we_n <= '0';
\r
1075 ptn_l_we_n <= '1';
\r
1078 ----fetch pattern table high byte.
\r
1079 if (prf_x (2 downto 0) = "111") then
\r
1080 --vram addr is incremented every 8 cycle.
\r
1081 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1082 disp_nt(dsize - 1 downto 0)
\r
1083 & "0" & prf_y(2 downto 0) + "00000000001000";
\r
1085 if (prf_x (2 downto 0) = "000") then
\r
1086 ptn_h_we_n <= '0';
\r
1088 ptn_h_we_n <= '1';
\r
1091 end if;--if (ppu_mask(PPUSBG) = '1') and
\r
1093 --fetch sprite and display.
\r
1094 if (ppu_mask(PPUSSP) = '1' and
\r
1095 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1096 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1097 --secondary oam clear
\r
1098 if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE)) then
\r
1099 if (cur_x(0) = '0') then
\r
1100 --write secondary oam on even cycle
\r
1103 s_oam_addr <= cur_x(5 downto 1);
\r
1104 s_oam_data <= (others => '1');
\r
1106 p_oam_cnt_res_n <= '0';
\r
1107 p_oam_cnt_ce_n <= '1';
\r
1108 s_oam_cnt_ce_n <= '1';
\r
1109 p_oam_cnt_wrap_n <= '1';
\r
1110 oam_ev_status <= EV_STAT_COMP;
\r
1112 --sprite evaluation and secondary oam copy.
\r
1113 elsif (cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
1114 cur_x <= conv_std_logic_vector(256, X_SIZE)) then
\r
1115 p_oam_cnt_res_n <= '1';
\r
1117 --TODO: sprite evaluation is simplified!!
\r
1118 --not complying the original NES spec at
\r
1119 --http://wiki.nesdev.com/w/index.php/PPU_sprite_evaluation
\r
1120 --e.g., when overflow happens, it just ignore subsequent entry.
\r
1121 --old secondary sprite entry.
\r
1122 if (p_oam_cnt = "00000000" and cur_x > conv_std_logic_vector(192, X_SIZE)) then
\r
1123 p_oam_cnt_wrap_n <= '0';
\r
1126 --odd cycle copy from primary oam
\r
1127 if (cur_x(0) = '1') then
\r
1128 if (oam_ev_status = EV_STAT_COMP) then
\r
1129 p_oam_addr_in <= p_oam_cnt;
\r
1130 p_oam_cnt_ce_n <= '1';
\r
1131 s_oam_cnt_ce_n <= '1';
\r
1132 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1133 p_oam_addr_in <= p_oam_cnt + "00000001";
\r
1134 s_oam_cnt_ce_n <= '1';
\r
1136 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1137 p_oam_addr_in <= p_oam_cnt + "00000010";
\r
1138 s_oam_cnt_ce_n <= '1';
\r
1140 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1141 oam_ev_status <= EV_STAT_PRE_COMP;
\r
1142 p_oam_addr_in <= p_oam_cnt + "00000011";
\r
1143 s_oam_cnt_ce_n <= '1';
\r
1146 --even cycle copy to secondary oam (if y is in range.)
\r
1149 s_oam_addr <= s_oam_cnt;
\r
1150 s_oam_data <= p_oam_data;
\r
1152 if (oam_ev_status = EV_STAT_COMP) then
\r
1154 if (cur_y < "000000110" and p_oam_data <= cur_y + "000000001") or
\r
1155 (cur_y >= "000000110" and p_oam_data <= cur_y + "000000001" and
\r
1156 p_oam_data >= cur_y - "000000110") then
\r
1157 oam_ev_status <= EV_STAT_CP1;
\r
1158 s_oam_cnt_ce_n <= '0';
\r
1159 --copy remaining oam entry.
\r
1160 p_oam_cnt_ce_n <= '1';
\r
1163 p_oam_cnt_ce_n <= '0';
\r
1165 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1166 s_oam_cnt_ce_n <= '0';
\r
1167 oam_ev_status <= EV_STAT_CP2;
\r
1168 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1169 s_oam_cnt_ce_n <= '0';
\r
1170 oam_ev_status <= EV_STAT_CP3;
\r
1171 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1172 s_oam_cnt_ce_n <= '0';
\r
1173 elsif (oam_ev_status = EV_STAT_PRE_COMP) then
\r
1174 oam_ev_status <= EV_STAT_COMP;
\r
1175 s_oam_cnt_ce_n <= '0';
\r
1176 p_oam_cnt_ce_n <= '0';
\r
1178 end if;--if (cur_x(0) = '1') then
\r
1180 --prepare for next step
\r
1181 s_oam_addr_cpy_n <= '1';
\r
1182 spr_y_we_n <= '1';
\r
1183 spr_tile_we_n <= '1';
\r
1184 spr_x_we_n <= "11111111";
\r
1185 spr_attr_we_n <= "11111111";
\r
1186 spr_ptn_l_we_n <= "11111111";
\r
1187 spr_ptn_h_we_n <= "11111111";
\r
1189 --sprite pattern fetch
\r
1190 elsif (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
1191 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) then
\r
1193 s_oam_addr_cpy_n <= '0';
\r
1196 s_oam_addr <= s_oam_addr_cpy;
\r
1198 ----fetch y-cordinate from secondary oam
\r
1199 if (cur_x (2 downto 0) = "001" ) then
\r
1200 s_oam_addr_cpy_ce_n <= '0';
\r
1201 spr_y_we_n <= '0';
\r
1203 spr_y_we_n <= '1';
\r
1206 ----fetch tile number
\r
1207 if (cur_x (2 downto 0) = "010" ) then
\r
1208 spr_tile_we_n <= '0';
\r
1210 spr_tile_we_n <= '1';
\r
1213 ----fetch attribute
\r
1214 if (cur_x (2 downto 0) = "011" ) then
\r
1215 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1217 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1218 end if;--if (cur_x (2 downto 0) = "010" ) then
\r
1220 ----fetch x-cordinate
\r
1221 if (cur_x (2 downto 0) = "100" ) then
\r
1222 s_oam_addr_cpy_ce_n <= '1';
\r
1223 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1225 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1228 ----fetch pattern table low byte.
\r
1229 if (cur_x (2 downto 0) = "101" ) then
\r
1230 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1231 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1232 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1233 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0));
\r
1235 --flip sprite vertically.
\r
1236 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1237 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1238 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010");
\r
1242 if (cur_x (2 downto 0) = "110" ) then
\r
1243 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1245 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1248 ----fetch pattern table high byte.
\r
1249 if (cur_x (2 downto 0) = "111" ) then
\r
1250 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1251 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1252 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1253 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0))
\r
1254 + "00000000001000";
\r
1256 --flip sprite vertically.
\r
1257 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1258 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1259 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010")
\r
1260 + "00000000001000";
\r
1264 if (cur_x (2 downto 0) = "000") then
\r
1265 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1266 s_oam_addr_cpy_ce_n <= '0';
\r
1268 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2) - "001")) <= '1';
\r
1271 elsif (cur_x > conv_std_logic_vector(320, X_SIZE)) then
\r
1272 --clear last write enable.
\r
1273 spr_ptn_h_we_n <= "11111111";
\r
1274 end if;--if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE))
\r
1277 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1278 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1280 if (cur_x = "000000000") then
\r
1281 spr_x_ce_n <= "00000000";
\r
1284 for i in 0 to 7 loop
\r
1285 if (spr_x_cnt(i) = "00000000") then
\r
1286 --active sprite, start shifting..
\r
1287 spr_x_ce_n(i) <= '1';
\r
1288 spr_ptn_ce_n(i) <= '0';
\r
1292 spr_x_ce_n <= "11111111";
\r
1293 spr_ptn_ce_n <= "11111111";
\r
1294 end if; --if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE))
\r
1295 end if; --if (ppu_mask(PPUSSP) = '1') then
\r
1297 --output visible area only.
\r
1298 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1299 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1305 if ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1306 (cur_y = conv_std_logic_vector(VSCAN + 1, X_SIZE))) then
\r
1308 ppu_status(ST_VBL) <= '1';
\r
1309 elsif ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1310 (cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1311 ppu_status(ST_SP0) <= '0';
\r
1313 ppu_status(ST_VBL) <= '0';
\r
1314 --TODO: sprite overflow is not inplemented!
\r
1315 ppu_status(ST_SOF) <= '0';
\r
1317 end if; --if (clk'event and clk = '1') then
\r
1319 -- if (read_status'event and read_status = '1') then
\r
1320 -- --reading ppu status clears vblank bit.
\r
1321 -- ppu_status(ST_VBL) <= '0';
\r
1324 end if;--if (rst_n = '0') then
\r