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_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
22 vga_clk : in std_logic;
\r
23 mem_clk : in std_logic;
\r
24 rst_n : in std_logic;
\r
27 rd_n : out std_logic;
\r
28 wr_n : out std_logic;
\r
29 ale : out std_logic;
\r
30 vram_ad : inout std_logic_vector (7 downto 0);
\r
31 vram_a : out std_logic_vector (13 downto 8);
\r
34 h_sync_n : out std_logic;
\r
35 v_sync_n : out std_logic;
\r
36 r : out std_logic_vector (3 downto 0);
\r
37 g : out std_logic_vector (3 downto 0);
\r
38 b : out std_logic_vector (3 downto 0);
\r
41 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
42 ppu_mask : in std_logic_vector (7 downto 0);
\r
43 read_status : in std_logic;
\r
44 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
45 ppu_scroll_y : in std_logic_vector (7 downto 0)
\r
49 architecture rtl of vga_ctl is
\r
51 component counter_register
\r
53 dsize : integer := 8;
\r
56 port ( clk : in std_logic;
\r
57 rst_n : in std_logic;
\r
58 ce_n : in std_logic;
\r
59 we_n : in std_logic;
\r
60 d : in std_logic_vector(dsize - 1 downto 0);
\r
61 q : out std_logic_vector(dsize - 1 downto 0)
\r
65 component ppu_vga_render
\r
67 signal dbg_ppu_clk : out std_logic;
\r
68 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
69 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
70 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
73 mem_clk : in std_logic;
\r
74 rst_n : in std_logic;
\r
75 rd_n : out std_logic;
\r
76 wr_n : out std_logic;
\r
77 ale : out std_logic;
\r
78 vram_ad : inout std_logic_vector (7 downto 0);
\r
79 vram_a : out std_logic_vector (13 downto 8);
\r
80 cur_x : in std_logic_vector (8 downto 0);
\r
81 cur_y : in std_logic_vector (8 downto 0);
\r
82 r : out std_logic_vector (3 downto 0);
\r
83 g : out std_logic_vector (3 downto 0);
\r
84 b : out std_logic_vector (3 downto 0);
\r
85 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
86 ppu_mask : in std_logic_vector (7 downto 0);
\r
87 read_status : in std_logic;
\r
88 ppu_status : out std_logic_vector (7 downto 0);
\r
89 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
90 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
91 r_nw : in std_logic;
\r
92 oam_bus_ce_n : in std_logic;
\r
93 plt_bus_ce_n : in std_logic;
\r
94 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
95 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
96 v_bus_busy_n : out std_logic
\r
100 --------- screen constant -----------
\r
101 constant VGA_W : integer := 640;
\r
102 constant VGA_H : integer := 480;
\r
103 constant VGA_W_MAX : integer := 800;
\r
104 constant VGA_H_MAX : integer := 525;
\r
105 constant H_SP : integer := 95;
\r
106 constant H_BP : integer := 48;
\r
107 constant H_FP : integer := 15;
\r
108 constant V_SP : integer := 2;
\r
109 constant V_BP : integer := 33;
\r
110 constant V_FP : integer := 10;
\r
112 --------- signal declaration -----------
\r
113 signal vga_x : std_logic_vector (9 downto 0);
\r
114 signal vga_y : std_logic_vector (9 downto 0);
\r
115 signal x_res_n : std_logic;
\r
116 signal y_res_n : std_logic;
\r
117 signal y_en_n : std_logic;
\r
118 signal cnt_clk : std_logic;
\r
120 signal emu_ppu_clk : std_logic;
\r
121 signal emu_ppu_clk_n : std_logic;
\r
122 signal count5_res_n : std_logic;
\r
123 signal count5 : std_logic_vector(2 downto 0);
\r
124 signal nes_x : std_logic_vector (8 downto 0);
\r
125 signal nes_y : std_logic_vector (8 downto 0);
\r
130 signal r_nw : std_logic;
\r
131 signal oam_bus_ce_n : std_logic;
\r
132 signal plt_bus_ce_n : std_logic;
\r
133 signal oam_plt_addr : std_logic_vector (7 downto 0);
\r
134 signal oam_plt_data : std_logic_vector (7 downto 0);
\r
135 signal v_bus_busy_n : std_logic;
\r
136 signal ppu_status : std_logic_vector (7 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
146 dbg_vga_x <= vga_x;
\r
148 cnt_clk <= not vga_clk;
\r
150 --vga position counter
\r
151 x_inst : counter_register generic map (10, 1)
\r
152 port map (cnt_clk , x_res_n, '0', '1', (others => '0'), vga_x);
\r
153 y_inst : counter_register generic map (10, 1)
\r
154 port map (cnt_clk , y_res_n, y_en_n, '1', (others => '0'), vga_y);
\r
155 vga_out_p : process (rst_n, vga_clk)
\r
157 if (rst_n = '0') then
\r
163 -- r<=(others => '0');
\r
164 -- g<=(others => '0');
\r
165 -- b<=(others => '0');
\r
167 elsif (rising_edge(vga_clk)) then
\r
169 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
173 if (vga_y = conv_std_logic_vector(VGA_H_MAX, 10)) then
\r
184 --sync signal assert.
\r
185 if (vga_x >= conv_std_logic_vector((VGA_W + H_FP) , 10) and
\r
186 vga_x < conv_std_logic_vector((VGA_W + H_FP + H_SP) , 10)) then
\r
192 if (vga_y >= conv_std_logic_vector((VGA_H + V_FP) , 10) and
\r
193 vga_y < conv_std_logic_vector((VGA_H + V_FP + V_SP) , 10)) then
\r
199 -- if (vga_y <=conv_std_logic_vector((VGA_H) , 10)) then
\r
200 -- if (vga_x < conv_std_logic_vector((VGA_W) , 10)) then
\r
205 -- r<=(others => '0');
\r
206 -- g<=(others => '0');
\r
207 -- b<=(others => '0');
\r
210 -- r<=(others => '0');
\r
211 -- g<=(others => '0');
\r
212 -- b<=(others => '0');
\r
218 --emulate ppu clock that is synchronized with vga clock
\r
219 count5_inst : counter_register generic map (3, 1)
\r
220 port map (cnt_clk, count5_res_n, '0', '1', (others => '0'), count5);
\r
221 nes_x_inst : counter_register generic map (9, 1)
\r
222 port map (emu_ppu_clk , x_res_n, '0', '1', (others => '0'), nes_x);
\r
223 nes_y <= vga_y(9 downto 1);
\r
224 emu_clk_p : process (rst_n, vga_clk)
\r
226 if (rst_n = '0') then
\r
227 emu_ppu_clk <= '0';
\r
228 count5_res_n <= '0';
\r
229 elsif (rising_edge(vga_clk)) then
\r
230 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
231 count5_res_n <= '0';
\r
232 elsif (count5 = "100") then
\r
233 count5_res_n <= '0';
\r
235 count5_res_n <= '1';
\r
238 if (count5 = "001" or count5 = "011") then
\r
239 emu_ppu_clk <= '0';
\r
241 emu_ppu_clk <= '1';
\r
246 --vga emulated render instance...
\r
247 oam_plt_data <= (others => 'Z');
\r
248 emu_ppu_clk_n <= not emu_ppu_clk;
\r
249 vga_render_inst : ppu_vga_render
\r
253 dbg_disp_nt, dbg_disp_attr ,
\r
254 dbg_disp_ptn_h, dbg_disp_ptn_l ,
\r
287 ---------------------------------------------------------------
\r
288 ---------------------------------------------------------------
\r
289 ------------------------ PPU VGA Renderer ---------------------
\r
290 ---------------------------------------------------------------
\r
291 ---------------------------------------------------------------
\r
294 use ieee.std_logic_1164.all;
\r
295 use ieee.std_logic_arith.conv_std_logic_vector;
\r
296 use ieee.std_logic_unsigned.all;
\r
297 use work.motonesfpga_common.all;
\r
299 entity ppu_vga_render is
\r
301 signal dbg_ppu_clk : out std_logic;
\r
302 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
303 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
304 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
306 clk : in std_logic;
\r
307 mem_clk : in std_logic;
\r
308 rst_n : in std_logic;
\r
310 rd_n : out std_logic;
\r
311 wr_n : out std_logic;
\r
312 ale : out std_logic;
\r
313 vram_ad : inout std_logic_vector (7 downto 0);
\r
314 vram_a : out std_logic_vector (13 downto 8);
\r
316 --current drawing position 340 x 261
\r
317 cur_x : in std_logic_vector (8 downto 0);
\r
318 cur_y : in std_logic_vector (8 downto 0);
\r
319 r : out std_logic_vector (3 downto 0);
\r
320 g : out std_logic_vector (3 downto 0);
\r
321 b : out std_logic_vector (3 downto 0);
\r
323 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
324 ppu_mask : in std_logic_vector (7 downto 0);
\r
325 read_status : in std_logic;
\r
326 ppu_status : out std_logic_vector (7 downto 0);
\r
327 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
328 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
330 r_nw : in std_logic;
\r
331 oam_bus_ce_n : in std_logic;
\r
332 plt_bus_ce_n : in std_logic;
\r
333 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
334 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
335 v_bus_busy_n : out std_logic
\r
337 end ppu_vga_render;
\r
339 architecture rtl of ppu_vga_render is
\r
341 component counter_register
\r
343 dsize : integer := 8;
\r
346 port ( clk : in std_logic;
\r
347 rst_n : in std_logic;
\r
348 ce_n : in std_logic;
\r
349 we_n : in std_logic;
\r
350 d : in std_logic_vector(dsize - 1 downto 0);
\r
351 q : out std_logic_vector(dsize - 1 downto 0)
\r
355 component shift_register
\r
357 dsize : integer := 8;
\r
358 shift : integer := 1
\r
360 port ( clk : in std_logic;
\r
361 rst_n : in std_logic;
\r
362 ce_n : in std_logic;
\r
363 we_n : in std_logic;
\r
364 d : in std_logic_vector(dsize - 1 downto 0);
\r
365 q : out std_logic_vector(dsize - 1 downto 0)
\r
369 component d_flip_flop
\r
371 dsize : integer := 8
\r
374 clk : in std_logic;
\r
375 res_n : in std_logic;
\r
376 set_n : in std_logic;
\r
377 we_n : in std_logic;
\r
378 d : in std_logic_vector (dsize - 1 downto 0);
\r
379 q : out std_logic_vector (dsize - 1 downto 0)
\r
383 component tri_state_buffer
\r
385 dsize : integer := 8
\r
388 oe_n : in std_logic;
\r
389 d : in std_logic_vector (dsize - 1 downto 0);
\r
390 q : out std_logic_vector (dsize - 1 downto 0)
\r
395 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
397 clk : in std_logic;
\r
398 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
399 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
400 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
404 component palette_ram
\r
405 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
407 clk : in std_logic;
\r
408 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
409 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
410 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
416 clk : in std_logic;
\r
417 ce_n, oe_n, we_n : in std_logic;
\r
418 sync_ce_n : out std_logic
\r
422 --nes screen size is emulated to align with the vga timing...
\r
423 constant X_SIZE : integer := 9;
\r
424 constant dsize : integer := 8;
\r
425 constant asize : integer := 14;
\r
426 --constant HSCAN_MAX : integer := 341;
\r
427 constant HSCAN_MAX : integer := 321;
\r
428 constant VSCAN_MAX : integer := 262;
\r
429 constant HSCAN : integer := 256;
\r
430 constant VSCAN : integer := 240;
\r
431 --constant HSCAN_NEXT_START : integer := 320;
\r
432 --constant HSCAN_NEXT_EXTRA : integer := 336;
\r
433 constant HSCAN_NEXT_START : integer := 300;
\r
434 constant HSCAN_NEXT_EXTRA : integer := 316;
\r
437 constant PPUBNA : integer := 1; --base name address
\r
438 constant PPUVAI : integer := 2; --vram address increment
\r
439 constant PPUSPA : integer := 3; --sprite pattern table address
\r
440 constant PPUBPA : integer := 4; --background pattern table address
\r
441 constant PPUSPS : integer := 5; --sprite size
\r
442 constant PPUMS : integer := 6; --ppu master/slave
\r
443 constant PPUNEN : integer := 7; --nmi enable
\r
445 constant PPUGS : integer := 0; --grayscale
\r
446 constant PPUSBL : integer := 1; --show 8 left most bg pixel
\r
447 constant PPUSSL : integer := 2; --show 8 left most sprite pixel
\r
448 constant PPUSBG : integer := 3; --show bg
\r
449 constant PPUSSP : integer := 4; --show sprie
\r
450 constant PPUIR : integer := 5; --intensify red
\r
451 constant PPUIG : integer := 6; --intensify green
\r
452 constant PPUIB : integer := 7; --intensify blue
\r
454 constant SPRHFL : integer := 6; --flip sprigte horizontally
\r
455 constant SPRVFL : integer := 7; --flip sprigte vertically
\r
457 constant ST_SOF : integer := 5; --sprite overflow
\r
458 constant ST_SP0 : integer := 6; --sprite 0 hits
\r
459 constant ST_VBL : integer := 7; --vblank
\r
461 subtype nes_color_data is std_logic_vector (11 downto 0);
\r
462 type nes_color_array is array (0 to 63) of nes_color_data;
\r
463 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
\r
464 constant nes_color_palette : nes_color_array := (
\r
465 conv_std_logic_vector(16#777#, 12),
\r
466 conv_std_logic_vector(16#20b#, 12),
\r
467 conv_std_logic_vector(16#20b#, 12),
\r
468 conv_std_logic_vector(16#61a#, 12),
\r
469 conv_std_logic_vector(16#927#, 12),
\r
470 conv_std_logic_vector(16#b13#, 12),
\r
471 conv_std_logic_vector(16#a30#, 12),
\r
472 conv_std_logic_vector(16#740#, 12),
\r
473 conv_std_logic_vector(16#450#, 12),
\r
474 conv_std_logic_vector(16#360#, 12),
\r
475 conv_std_logic_vector(16#360#, 12),
\r
476 conv_std_logic_vector(16#364#, 12),
\r
477 conv_std_logic_vector(16#358#, 12),
\r
478 conv_std_logic_vector(16#000#, 12),
\r
479 conv_std_logic_vector(16#000#, 12),
\r
480 conv_std_logic_vector(16#000#, 12),
\r
481 conv_std_logic_vector(16#bbb#, 12),
\r
482 conv_std_logic_vector(16#46f#, 12),
\r
483 conv_std_logic_vector(16#44f#, 12),
\r
484 conv_std_logic_vector(16#94f#, 12),
\r
485 conv_std_logic_vector(16#d4c#, 12),
\r
486 conv_std_logic_vector(16#d46#, 12),
\r
487 conv_std_logic_vector(16#e50#, 12),
\r
488 conv_std_logic_vector(16#c70#, 12),
\r
489 conv_std_logic_vector(16#880#, 12),
\r
490 conv_std_logic_vector(16#5a0#, 12),
\r
491 conv_std_logic_vector(16#4a1#, 12),
\r
492 conv_std_logic_vector(16#4a6#, 12),
\r
493 conv_std_logic_vector(16#49c#, 12),
\r
494 conv_std_logic_vector(16#000#, 12),
\r
495 conv_std_logic_vector(16#000#, 12),
\r
496 conv_std_logic_vector(16#000#, 12),
\r
497 conv_std_logic_vector(16#fff#, 12),
\r
498 conv_std_logic_vector(16#6af#, 12),
\r
499 conv_std_logic_vector(16#58f#, 12),
\r
500 conv_std_logic_vector(16#a7f#, 12),
\r
501 conv_std_logic_vector(16#f6f#, 12),
\r
502 conv_std_logic_vector(16#f6b#, 12),
\r
503 conv_std_logic_vector(16#f73#, 12),
\r
504 conv_std_logic_vector(16#fa0#, 12),
\r
505 conv_std_logic_vector(16#ed2#, 12),
\r
506 conv_std_logic_vector(16#9e0#, 12),
\r
507 conv_std_logic_vector(16#7f4#, 12),
\r
508 conv_std_logic_vector(16#7e9#, 12),
\r
509 conv_std_logic_vector(16#6de#, 12),
\r
510 conv_std_logic_vector(16#777#, 12),
\r
511 conv_std_logic_vector(16#000#, 12),
\r
512 conv_std_logic_vector(16#000#, 12),
\r
513 conv_std_logic_vector(16#fff#, 12),
\r
514 conv_std_logic_vector(16#9df#, 12),
\r
515 conv_std_logic_vector(16#abf#, 12),
\r
516 conv_std_logic_vector(16#cbf#, 12),
\r
517 conv_std_logic_vector(16#ebf#, 12),
\r
518 conv_std_logic_vector(16#fbe#, 12),
\r
519 conv_std_logic_vector(16#fcb#, 12),
\r
520 conv_std_logic_vector(16#fda#, 12),
\r
521 conv_std_logic_vector(16#ff9#, 12),
\r
522 conv_std_logic_vector(16#cf8#, 12),
\r
523 conv_std_logic_vector(16#afa#, 12),
\r
524 conv_std_logic_vector(16#afc#, 12),
\r
525 conv_std_logic_vector(16#aff#, 12),
\r
526 conv_std_logic_vector(16#aaa#, 12),
\r
527 conv_std_logic_vector(16#000#, 12),
\r
528 conv_std_logic_vector(16#000#, 12)
\r
531 signal clk_n : std_logic;
\r
534 signal bg_io_cnt : std_logic_vector(0 downto 0);
\r
535 signal spr_io_cnt : std_logic_vector(0 downto 0);
\r
538 signal io_oe_n : std_logic;
\r
539 signal ah_oe_n : std_logic;
\r
541 signal cnt_x_res_n : std_logic;
\r
542 signal bg_cnt_res_n : std_logic;
\r
544 --bg prefetch position (scroll + 16 cycle ahead of current pos)
\r
545 --511 x 239 (or 255 x 479)
\r
546 signal prf_x : std_logic_vector(X_SIZE - 1 downto 0);
\r
547 signal prf_y : std_logic_vector(X_SIZE - 1 downto 0);
\r
549 signal nt_we_n : std_logic;
\r
550 signal disp_nt : std_logic_vector (dsize - 1 downto 0);
\r
552 signal attr_ce_n : std_logic;
\r
553 signal attr_we_n : std_logic;
\r
554 signal attr_val : std_logic_vector (dsize - 1 downto 0);
\r
555 signal disp_attr_we_n : std_logic;
\r
556 signal disp_attr : std_logic_vector (dsize - 1 downto 0);
\r
558 signal ptn_l_we_n : std_logic;
\r
559 signal ptn_l_in : std_logic_vector (dsize - 1 downto 0);
\r
560 signal ptn_l_val : std_logic_vector (dsize - 1 downto 0);
\r
561 signal disp_ptn_l_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
562 signal disp_ptn_l : std_logic_vector (dsize * 2 - 1 downto 0);
\r
564 signal ptn_h_we_n : std_logic;
\r
565 signal ptn_h_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
566 signal disp_ptn_h : std_logic_vector (dsize * 2 - 1 downto 0);
\r
568 --signals for palette / oam access from cpu
\r
569 signal r_n : std_logic;
\r
570 signal vram_addr : std_logic_vector (asize - 1 downto 0);
\r
573 signal plt_ram_ce_n_in : std_logic;
\r
574 signal plt_ram_ce_n : std_logic;
\r
575 signal plt_r_n : std_logic;
\r
576 signal plt_w_n : std_logic;
\r
577 signal plt_addr : std_logic_vector (4 downto 0);
\r
578 signal plt_data : std_logic_vector (dsize - 1 downto 0);
\r
580 --primari / secondary oam
\r
581 signal p_oam_ram_ce_n_in : std_logic;
\r
582 signal p_oam_ram_ce_n : std_logic;
\r
583 signal p_oam_r_n : std_logic;
\r
584 signal p_oam_w_n : std_logic;
\r
585 signal p_oam_addr : std_logic_vector (dsize - 1 downto 0);
\r
586 signal p_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
588 signal s_oam_ram_ce_n_in : std_logic;
\r
589 signal s_oam_ram_ce_n : std_logic;
\r
590 signal s_oam_r_n : std_logic;
\r
591 signal s_oam_w_n : std_logic;
\r
592 signal s_oam_addr_cpy_ce_n : std_logic;
\r
593 signal s_oam_addr_cpy_n : std_logic;
\r
594 signal s_oam_addr : std_logic_vector (4 downto 0);
\r
595 signal s_oam_addr_cpy : std_logic_vector (4 downto 0);
\r
596 signal s_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
598 signal p_oam_cnt_res_n : std_logic;
\r
599 signal p_oam_cnt_ce_n : std_logic;
\r
600 signal p_oam_cnt_wrap_n : std_logic;
\r
601 signal p_oam_cnt : std_logic_vector (dsize - 1 downto 0);
\r
602 signal p_oam_addr_in : std_logic_vector (dsize - 1 downto 0);
\r
603 signal oam_ev_status : std_logic_vector (2 downto 0);
\r
605 signal s_oam_cnt_ce_n : std_logic;
\r
606 signal s_oam_cnt : std_logic_vector (4 downto 0);
\r
608 --oam evaluation status
\r
609 constant EV_STAT_COMP : std_logic_vector (2 downto 0) := "000";
\r
610 constant EV_STAT_CP1 : std_logic_vector (2 downto 0) := "001";
\r
611 constant EV_STAT_CP2 : std_logic_vector (2 downto 0) := "010";
\r
612 constant EV_STAT_CP3 : std_logic_vector (2 downto 0) := "011";
\r
613 constant EV_STAT_PRE_COMP : std_logic_vector (2 downto 0) := "100";
\r
615 ----------sprite registers.
\r
616 type oam_pin_array is array (0 to 7) of std_logic;
\r
617 type oam_reg_array is array (0 to 7) of std_logic_vector (dsize - 1 downto 0);
\r
619 signal spr_x_we_n : oam_pin_array;
\r
620 signal spr_x_ce_n : oam_pin_array;
\r
621 signal spr_attr_we_n : oam_pin_array;
\r
622 signal spr_ptn_l_we_n : oam_pin_array;
\r
623 signal spr_ptn_h_we_n : oam_pin_array;
\r
624 signal spr_ptn_ce_n : oam_pin_array;
\r
626 signal spr_x_cnt : oam_reg_array;
\r
627 signal spr_attr : oam_reg_array;
\r
628 signal spr_ptn_l : oam_reg_array;
\r
629 signal spr_ptn_h : oam_reg_array;
\r
631 signal spr_y_we_n : std_logic;
\r
632 signal spr_tile_we_n : std_logic;
\r
633 signal spr_y_tmp : std_logic_vector (dsize - 1 downto 0);
\r
634 signal spr_tile_tmp : std_logic_vector (dsize - 1 downto 0);
\r
635 signal spr_ptn_in : std_logic_vector (dsize - 1 downto 0);
\r
639 dbg_ppu_clk <= clk;
\r
640 dbg_nes_x <= cur_x;
\r
641 dbg_disp_nt <= disp_nt;
\r
642 dbg_disp_attr <= disp_attr;
\r
643 dbg_disp_ptn_h <= disp_ptn_h;
\r
644 dbg_disp_ptn_l <= disp_ptn_l;
\r
649 ale <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
650 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
651 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
652 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
653 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
654 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
655 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
656 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
657 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
658 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
661 rd_n <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
662 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
663 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
664 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
665 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
666 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
667 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
668 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
669 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
670 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
672 wr_n <= '1' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '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)) else
\r
676 io_oe_n <= not bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
677 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
678 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
679 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
680 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
681 not spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
682 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
683 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
684 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
685 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
687 ah_oe_n <= '0' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
688 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
689 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
691 v_bus_busy_n <= ah_oe_n;
\r
693 bg_io_cnt_inst : counter_register generic map (1, 1)
\r
694 port map (clk, bg_cnt_res_n, '0', '1', (others => '0'), bg_io_cnt);
\r
695 spr_io_cnt_inst : counter_register generic map (1, 1)
\r
696 port map (clk, cnt_x_res_n, '0', '1', (others => '0'), spr_io_cnt);
\r
698 ---bg prefetch x pos is 16 + scroll cycle ahead of current pos.
\r
699 prf_x <= cur_x + ppu_scroll_x + "000010000"
\r
700 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) else
\r
701 cur_x + ppu_scroll_x + "010111011"; -- +16 -341
\r
703 prf_y <= cur_y + ppu_scroll_y
\r
704 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) and
\r
705 cur_y + ppu_scroll_y <
\r
706 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
707 cur_y + ppu_scroll_y + "000000001"
\r
708 when cur_y + ppu_scroll_y <
\r
709 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
712 nt_inst : d_flip_flop generic map(dsize)
\r
713 port map (clk_n, rst_n, '1', nt_we_n, vram_ad, disp_nt);
\r
715 at_inst : d_flip_flop generic map(dsize)
\r
716 port map (clk_n, rst_n, '1', attr_we_n, vram_ad, attr_val);
\r
718 disp_at_inst : shift_register generic map(dsize, 2)
\r
719 port map (clk_n, rst_n, attr_ce_n, disp_attr_we_n, attr_val, disp_attr);
\r
721 --chr rom data's bit is stored in opposite direction.
\r
722 --reverse bit when loading...
\r
723 ptn_l_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
724 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
725 ptn_h_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
726 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7)) &
\r
727 disp_ptn_h (dsize downto 1);
\r
729 ptn_l_inst : d_flip_flop generic map(dsize)
\r
730 port map (clk_n, rst_n, '1', ptn_l_we_n, ptn_l_in, ptn_l_val);
\r
732 disp_ptn_l_in <= ptn_l_val & disp_ptn_l (dsize downto 1);
\r
733 disp_ptn_l_inst : shift_register generic map(dsize * 2, 1)
\r
734 port map (clk_n, rst_n, '0', ptn_h_we_n, disp_ptn_l_in, disp_ptn_l);
\r
736 ptn_h_inst : shift_register generic map(dsize * 2, 1)
\r
737 port map (clk_n, rst_n, '0', ptn_h_we_n, ptn_h_in, disp_ptn_h);
\r
740 vram_io_buf : tri_state_buffer generic map (dsize)
\r
741 port map (io_oe_n, vram_addr(dsize - 1 downto 0), vram_ad);
\r
743 vram_a_buf : tri_state_buffer generic map (6)
\r
744 port map (ah_oe_n, vram_addr(asize - 1 downto dsize), vram_a);
\r
749 plt_ram_ce_n_in <= clk when plt_bus_ce_n = '0' and r_nw = '0' else
\r
750 '0' when plt_bus_ce_n = '0' and r_nw = '1' else
\r
751 '0' when ppu_mask(PPUSBG) = '1' and
\r
752 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
753 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
756 plt_addr <= oam_plt_addr(4 downto 0) when plt_bus_ce_n = '0' else
\r
757 "1" & spr_attr(0)(1 downto 0) & spr_ptn_h(0)(0) & spr_ptn_l(0)(0)
\r
758 when ppu_mask(PPUSSP) = '1' and
\r
759 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
760 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
761 spr_x_cnt(0) = "00000000" and
\r
762 (spr_ptn_h(0)(0) or spr_ptn_l(0)(0)) = '1' else
\r
763 "1" & spr_attr(1)(1 downto 0) & spr_ptn_h(1)(0) & spr_ptn_l(1)(0)
\r
764 when ppu_mask(PPUSSP) = '1' and
\r
765 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
766 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
767 spr_x_cnt(1) = "00000000" and
\r
768 (spr_ptn_h(1)(0) or spr_ptn_l(1)(0)) = '1' else
\r
769 "1" & spr_attr(2)(1 downto 0) & spr_ptn_h(2)(0) & spr_ptn_l(2)(0)
\r
770 when ppu_mask(PPUSSP) = '1' and
\r
771 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
772 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
773 spr_x_cnt(2) = "00000000" and
\r
774 (spr_ptn_h(2)(0) or spr_ptn_l(2)(0)) = '1' else
\r
775 "1" & spr_attr(3)(1 downto 0) & spr_ptn_h(3)(0) & spr_ptn_l(3)(0)
\r
776 when ppu_mask(PPUSSP) = '1' and
\r
777 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
778 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
779 spr_x_cnt(3) = "00000000" and
\r
780 (spr_ptn_h(3)(0) or spr_ptn_l(3)(0)) = '1' else
\r
781 "1" & spr_attr(4)(1 downto 0) & spr_ptn_h(4)(0) & spr_ptn_l(4)(0)
\r
782 when ppu_mask(PPUSSP) = '1' and
\r
783 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
784 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
785 spr_x_cnt(4) = "00000000" and
\r
786 (spr_ptn_h(4)(0) or spr_ptn_l(4)(0)) = '1' else
\r
787 "1" & spr_attr(5)(1 downto 0) & spr_ptn_h(5)(0) & spr_ptn_l(5)(0)
\r
788 when ppu_mask(PPUSSP) = '1' and
\r
789 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
790 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
791 spr_x_cnt(5) = "00000000" and
\r
792 (spr_ptn_h(5)(0) or spr_ptn_l(5)(0)) = '1' else
\r
793 "1" & spr_attr(6)(1 downto 0) & spr_ptn_h(6)(0) & spr_ptn_l(6)(0)
\r
794 when ppu_mask(PPUSSP) = '1' and
\r
795 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
796 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
797 spr_x_cnt(6) = "00000000" and
\r
798 (spr_ptn_h(6)(0) or spr_ptn_l(6)(0)) = '1' else
\r
799 "1" & spr_attr(7)(1 downto 0) & spr_ptn_h(7)(0) & spr_ptn_l(7)(0)
\r
800 when ppu_mask(PPUSSP) = '1' and
\r
801 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
802 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
803 spr_x_cnt(7) = "00000000" and
\r
804 (spr_ptn_h(7)(0) or spr_ptn_l(7)(0)) = '1' else
\r
805 "0" & disp_attr(1 downto 0) & disp_ptn_h(0) & disp_ptn_l(0)
\r
806 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '0' and
\r
807 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
808 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
809 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
810 "0" & disp_attr(5 downto 4) & disp_ptn_h(0) & disp_ptn_l(0)
\r
811 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '1' and
\r
812 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
813 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
814 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
815 ---else: no output color >> universal bg color output.
\r
816 --0x3f00 is the universal bg palette.
\r
819 plt_r_n <= not r_nw when plt_bus_ce_n = '0' else
\r
820 '0' when ppu_mask(PPUSBG) = '1' else
\r
822 plt_w_n <= r_nw when plt_bus_ce_n = '0' else
\r
824 plt_d_buf_w : tri_state_buffer generic map (dsize)
\r
825 port map (r_nw, oam_plt_data, plt_data);
\r
826 plt_d_buf_r : tri_state_buffer generic map (dsize)
\r
827 port map (r_n, plt_data, oam_plt_data);
\r
828 plt_ram_ctl : ram_ctrl
\r
829 port map (mem_clk, plt_ram_ce_n_in, plt_r_n, plt_w_n, plt_ram_ce_n);
\r
830 palette_inst : palette_ram generic map (5, dsize)
\r
831 port map (mem_clk, plt_ram_ce_n, plt_r_n, plt_w_n, plt_addr, plt_data);
\r
834 p_oam_ram_ce_n_in <= clk when oam_bus_ce_n = '0' and r_nw = '0' else
\r
835 '0' when oam_bus_ce_n = '0' and r_nw = '1' else
\r
836 '0' when ppu_mask(PPUSSP) = '1' and
\r
837 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
838 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
839 p_oam_cnt_wrap_n = '1' else
\r
841 p_oam_addr <= oam_plt_addr when oam_bus_ce_n = '0' else
\r
842 p_oam_addr_in when ppu_mask(PPUSSP) = '1' and
\r
843 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
844 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
845 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
846 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
848 p_oam_r_n <= not r_nw when oam_bus_ce_n = '0' else
\r
849 '0' when ppu_mask(PPUSSP) = '1' and
\r
850 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
851 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
852 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
853 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
855 p_oam_w_n <= r_nw when oam_bus_ce_n = '0' else
\r
857 oam_d_buf_w : tri_state_buffer generic map (dsize)
\r
858 port map (r_nw, oam_plt_data, p_oam_data);
\r
859 oam_d_buf_r : tri_state_buffer generic map (dsize)
\r
860 port map (r_n, p_oam_data, oam_plt_data);
\r
862 p_oam_ram_ctl : ram_ctrl
\r
863 port map (mem_clk, p_oam_ram_ce_n_in, p_oam_r_n, p_oam_w_n, p_oam_ram_ce_n);
\r
864 primary_oam_inst : ram generic map (dsize, dsize)
\r
865 port map (mem_clk, p_oam_ram_ce_n, p_oam_r_n, p_oam_w_n, p_oam_addr, p_oam_data);
\r
868 p_oam_cnt_inst : counter_register generic map (dsize, 4)
\r
869 port map (clk_n, p_oam_cnt_res_n, p_oam_cnt_ce_n, '1', (others => '0'), p_oam_cnt);
\r
870 s_oam_cnt_inst : counter_register generic map (5, 1)
\r
871 port map (clk_n, p_oam_cnt_res_n, s_oam_cnt_ce_n, '1', (others => '0'), s_oam_cnt);
\r
872 s_oam_addr_cpy_inst : counter_register generic map (5, 1)
\r
873 port map (clk_n, p_oam_cnt_res_n, s_oam_addr_cpy_ce_n,
\r
874 '1', (others => '0'), s_oam_addr_cpy);
\r
876 s_oam_ram_ce_n_in <= clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
877 cur_x > "000000001" and
\r
878 cur_x <= conv_std_logic_vector(64, X_SIZE) else
\r
879 clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
880 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
881 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
882 p_oam_cnt_wrap_n = '1' else
\r
883 '0' when ppu_mask(PPUSSP) = '1' and
\r
884 cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
885 cur_x <= conv_std_logic_vector(320, X_SIZE) and
\r
886 s_oam_addr_cpy_n = '0' else
\r
889 s_oam_ram_ctl : ram_ctrl
\r
890 port map (mem_clk, s_oam_ram_ce_n_in, s_oam_r_n, s_oam_w_n, s_oam_ram_ce_n);
\r
891 -- secondary_oam_inst : ram generic map (5, dsize)
\r
892 -- port map (mem_clk, s_oam_ram_ce_n, s_oam_r_n, s_oam_w_n, s_oam_addr, s_oam_data);
\r
894 spr_y_inst : d_flip_flop generic map(dsize)
\r
895 port map (clk_n, p_oam_cnt_res_n, '1', spr_y_we_n, s_oam_data, spr_y_tmp);
\r
896 spr_tile_inst : d_flip_flop generic map(dsize)
\r
897 port map (clk_n, p_oam_cnt_res_n, '1', spr_tile_we_n, s_oam_data, spr_tile_tmp);
\r
900 --reverse bit when NOT SPRHFL is set (.nes file format bit endian).
\r
901 spr_ptn_in <= vram_ad when spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRHFL) = '1' else
\r
902 (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
903 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
904 --array instances...
\r
905 spr_inst : for i in 0 to 7 generate
\r
906 spr_x_inst : counter_register generic map(dsize, 16#ff#)
\r
907 port map (clk_n, rst_n, spr_x_ce_n(i), spr_x_we_n(i), s_oam_data, spr_x_cnt(i));
\r
909 spr_attr_inst : d_flip_flop generic map(dsize)
\r
910 port map (clk_n, rst_n, '1', spr_attr_we_n(i), s_oam_data, spr_attr(i));
\r
912 spr_ptn_l_inst : shift_register generic map(dsize, 1)
\r
913 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
915 spr_ptn_h_inst : shift_register generic map(dsize, 1)
\r
916 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
919 pos_p : process (rst_n, clk)
\r
921 if (rst_n = '0') then
\r
922 cnt_x_res_n <= '0';
\r
923 bg_cnt_res_n <= '0';
\r
924 elsif (clk'event and clk = '0') then
\r
925 if (cur_x = conv_std_logic_vector(HSCAN_MAX - 1, X_SIZE)) then
\r
927 cnt_x_res_n <= '0';
\r
929 cnt_x_res_n <= '1';
\r
932 if (ppu_scroll_x(0) = '0' and cur_x = conv_std_logic_vector(HSCAN, X_SIZE)) then
\r
933 bg_cnt_res_n <= '0';
\r
934 elsif (ppu_scroll_x(0) = '1' and cur_x = conv_std_logic_vector(HSCAN - 1, X_SIZE)) then
\r
935 bg_cnt_res_n <= '0';
\r
937 bg_cnt_res_n <= '1';
\r
939 end if; --if (rst_n = '0') then
\r
942 clk_p : process (rst_n, clk, read_status)
\r
944 procedure output_rgb is
\r
945 variable pl_addr : integer;
\r
946 variable pl_index : integer;
\r
947 variable dot_output : boolean;
\r
949 dot_output := false;
\r
951 --first show sprite.
\r
952 if (ppu_mask(PPUSSP) = '1') then
\r
953 for i in 0 to 7 loop
\r
954 if (spr_x_cnt(i) = "00000000") then
\r
955 if ((spr_ptn_h(i)(0) or spr_ptn_l(i)(0)) = '1') then
\r
956 dot_output := true;
\r
963 if (dot_output = true and ppu_mask(PPUSBG) = '1' and
\r
964 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
965 --raise sprite 0 hit.
\r
966 ppu_status(ST_SP0) <= '1';
\r
969 --first color in the palette is transparent color.
\r
970 if (ppu_mask(PPUSBG) = '1' and dot_output = false and
\r
971 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
972 dot_output := true;
\r
973 -- d_print("output_rgb");
\r
974 -- d_print("pl_addr:" & conv_hex8(pl_addr));
\r
975 -- d_print("pl_index:" & conv_hex8(pl_index));
\r
978 --if or if not bg/sprite is shown, output color anyway
\r
979 --sinse universal bg color is included..
\r
980 pl_index := conv_integer(plt_data(5 downto 0));
\r
981 b <= nes_color_palette(pl_index) (11 downto 8);
\r
982 g <= nes_color_palette(pl_index) (7 downto 4);
\r
983 r <= nes_color_palette(pl_index) (3 downto 0);
\r
984 -- d_print("rgb:" &
\r
985 -- conv_hex8(nes_color_palette(pl_index) (11 downto 8)) &
\r
986 -- conv_hex8(nes_color_palette(pl_index) (7 downto 4)) &
\r
987 -- conv_hex8(nes_color_palette(pl_index) (3 downto 0)));
\r
991 if (rst_n = '0') then
\r
994 ppu_status <= (others => '0');
\r
996 b <= (others => '0');
\r
997 g <= (others => '0');
\r
998 r <= (others => '0');
\r
1000 if (clk'event and clk = '0') then
\r
1004 if (clk'event and clk = '1') then
\r
1006 --fetch bg pattern and display.
\r
1007 if (ppu_mask(PPUSBG) = '1' and
\r
1008 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
1009 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) and
\r
1010 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1011 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1012 --visible area bg image
\r
1015 d_print("cur_x: " & conv_hex16(conv_integer(cur_x)));
\r
1016 d_print("cur_y: " & conv_hex16(conv_integer(cur_y)));
\r
1018 ----fetch next tile byte.
\r
1019 if (prf_x (2 downto 0) = "001") then
\r
1020 --vram addr is incremented every 8 cycle.
\r
1021 --name table at 0x2000
\r
1022 vram_addr(9 downto 0)
\r
1023 <= prf_y(dsize - 1 downto 3)
\r
1024 & prf_x(dsize - 1 downto 3);
\r
1025 vram_addr(asize - 1 downto 10) <= "10" & ppu_ctrl(PPUBNA downto 0)
\r
1026 + ("000" & prf_x(dsize));
\r
1028 if (prf_x (2 downto 0) = "010") then
\r
1034 --TODO must load 8 cycle each for the first two tiles!!!
\r
1035 ----fetch attr table byte.
\r
1036 if (prf_x (4 downto 0) = "00011") then
\r
1037 --attribute table is loaded every 32 cycle.
\r
1038 --attr table at 0x23c0
\r
1039 vram_addr(dsize - 1 downto 0) <= "11000000" +
\r
1040 ("00" & prf_y(7 downto 5) & prf_x(7 downto 5));
\r
1041 vram_addr(asize - 1 downto dsize) <= "10" &
\r
1042 ppu_ctrl(PPUBNA downto 0) & "11"
\r
1043 + ("000" & prf_x(dsize) & "00");
\r
1045 if (prf_x (4 downto 0) = "00100") then
\r
1050 if (prf_x (4 downto 0) = "10000") then
\r
1051 disp_attr_we_n <= '0';
\r
1053 disp_attr_we_n <= '1';
\r
1055 ---attribute is shifted every 16 bit.
\r
1056 if (prf_x (3 downto 0) = "0000") then
\r
1062 ----fetch pattern table low byte.
\r
1063 if (prf_x (2 downto 0) = "101") then
\r
1064 --vram addr is incremented every 8 cycle.
\r
1065 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1066 disp_nt(dsize - 1 downto 0)
\r
1067 & "0" & prf_y(2 downto 0);
\r
1069 if (prf_x (2 downto 0) = "110") then
\r
1070 ptn_l_we_n <= '0';
\r
1072 ptn_l_we_n <= '1';
\r
1075 ----fetch pattern table high byte.
\r
1076 if (prf_x (2 downto 0) = "111") then
\r
1077 --vram addr is incremented every 8 cycle.
\r
1078 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1079 disp_nt(dsize - 1 downto 0)
\r
1080 & "0" & prf_y(2 downto 0) + "00000000001000";
\r
1082 if (prf_x (2 downto 0) = "000") then
\r
1083 ptn_h_we_n <= '0';
\r
1085 ptn_h_we_n <= '1';
\r
1088 end if;--if (ppu_mask(PPUSBG) = '1') and
\r
1090 --fetch sprite and display.
\r
1091 if (ppu_mask(PPUSSP) = '1' and
\r
1092 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1093 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1094 --secondary oam clear
\r
1095 if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE)) then
\r
1096 if (cur_x(0) = '0') then
\r
1097 --write secondary oam on even cycle
\r
1100 s_oam_addr <= cur_x(5 downto 1);
\r
1101 s_oam_data <= (others => '1');
\r
1103 p_oam_cnt_res_n <= '0';
\r
1104 p_oam_cnt_ce_n <= '1';
\r
1105 s_oam_cnt_ce_n <= '1';
\r
1106 p_oam_cnt_wrap_n <= '1';
\r
1107 oam_ev_status <= EV_STAT_COMP;
\r
1109 --sprite evaluation and secondary oam copy.
\r
1110 elsif (cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
1111 cur_x <= conv_std_logic_vector(256, X_SIZE)) then
\r
1112 p_oam_cnt_res_n <= '1';
\r
1114 --TODO: sprite evaluation is simplified!!
\r
1115 --not complying the original NES spec at
\r
1116 --http://wiki.nesdev.com/w/index.php/PPU_sprite_evaluation
\r
1117 --e.g., when overflow happens, it just ignore subsequent entry.
\r
1118 --old secondary sprite entry.
\r
1119 if (p_oam_cnt = "00000000" and cur_x > conv_std_logic_vector(192, X_SIZE)) then
\r
1120 p_oam_cnt_wrap_n <= '0';
\r
1123 --odd cycle copy from primary oam
\r
1124 if (cur_x(0) = '1') then
\r
1125 if (oam_ev_status = EV_STAT_COMP) then
\r
1126 p_oam_addr_in <= p_oam_cnt;
\r
1127 p_oam_cnt_ce_n <= '1';
\r
1128 s_oam_cnt_ce_n <= '1';
\r
1129 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1130 p_oam_addr_in <= p_oam_cnt + "00000001";
\r
1131 s_oam_cnt_ce_n <= '1';
\r
1133 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1134 p_oam_addr_in <= p_oam_cnt + "00000010";
\r
1135 s_oam_cnt_ce_n <= '1';
\r
1137 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1138 oam_ev_status <= EV_STAT_PRE_COMP;
\r
1139 p_oam_addr_in <= p_oam_cnt + "00000011";
\r
1140 s_oam_cnt_ce_n <= '1';
\r
1143 --even cycle copy to secondary oam (if y is in range.)
\r
1146 s_oam_addr <= s_oam_cnt;
\r
1147 s_oam_data <= p_oam_data;
\r
1149 if (oam_ev_status = EV_STAT_COMP) then
\r
1151 if (cur_y < "000000110" and p_oam_data <= cur_y + "000000001") or
\r
1152 (cur_y >= "000000110" and p_oam_data <= cur_y + "000000001" and
\r
1153 p_oam_data >= cur_y - "000000110") then
\r
1154 oam_ev_status <= EV_STAT_CP1;
\r
1155 s_oam_cnt_ce_n <= '0';
\r
1156 --copy remaining oam entry.
\r
1157 p_oam_cnt_ce_n <= '1';
\r
1160 p_oam_cnt_ce_n <= '0';
\r
1162 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1163 s_oam_cnt_ce_n <= '0';
\r
1164 oam_ev_status <= EV_STAT_CP2;
\r
1165 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1166 s_oam_cnt_ce_n <= '0';
\r
1167 oam_ev_status <= EV_STAT_CP3;
\r
1168 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1169 s_oam_cnt_ce_n <= '0';
\r
1170 elsif (oam_ev_status = EV_STAT_PRE_COMP) then
\r
1171 oam_ev_status <= EV_STAT_COMP;
\r
1172 s_oam_cnt_ce_n <= '0';
\r
1173 p_oam_cnt_ce_n <= '0';
\r
1175 end if;--if (cur_x(0) = '1') then
\r
1177 --prepare for next step
\r
1178 s_oam_addr_cpy_n <= '1';
\r
1179 spr_y_we_n <= '1';
\r
1180 spr_tile_we_n <= '1';
\r
1181 spr_x_we_n <= "11111111";
\r
1182 spr_attr_we_n <= "11111111";
\r
1183 spr_ptn_l_we_n <= "11111111";
\r
1184 spr_ptn_h_we_n <= "11111111";
\r
1186 --sprite pattern fetch
\r
1187 elsif (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
1188 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) then
\r
1190 s_oam_addr_cpy_n <= '0';
\r
1193 s_oam_addr <= s_oam_addr_cpy;
\r
1195 ----fetch y-cordinate from secondary oam
\r
1196 if (cur_x (2 downto 0) = "001" ) then
\r
1197 s_oam_addr_cpy_ce_n <= '0';
\r
1198 spr_y_we_n <= '0';
\r
1200 spr_y_we_n <= '1';
\r
1203 ----fetch tile number
\r
1204 if (cur_x (2 downto 0) = "010" ) then
\r
1205 spr_tile_we_n <= '0';
\r
1207 spr_tile_we_n <= '1';
\r
1210 ----fetch attribute
\r
1211 if (cur_x (2 downto 0) = "011" ) then
\r
1212 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1214 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1215 end if;--if (cur_x (2 downto 0) = "010" ) then
\r
1217 ----fetch x-cordinate
\r
1218 if (cur_x (2 downto 0) = "100" ) then
\r
1219 s_oam_addr_cpy_ce_n <= '1';
\r
1220 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1222 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1225 ----fetch pattern table low byte.
\r
1226 if (cur_x (2 downto 0) = "101" ) then
\r
1227 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1228 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1229 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1230 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0));
\r
1232 --flip sprite vertically.
\r
1233 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1234 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1235 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010");
\r
1239 if (cur_x (2 downto 0) = "110" ) then
\r
1240 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1242 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1245 ----fetch pattern table high byte.
\r
1246 if (cur_x (2 downto 0) = "111" ) then
\r
1247 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1248 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1249 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1250 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0))
\r
1251 + "00000000001000";
\r
1253 --flip sprite vertically.
\r
1254 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1255 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1256 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010")
\r
1257 + "00000000001000";
\r
1261 if (cur_x (2 downto 0) = "000") then
\r
1262 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1263 s_oam_addr_cpy_ce_n <= '0';
\r
1265 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2) - "001")) <= '1';
\r
1268 elsif (cur_x > conv_std_logic_vector(320, X_SIZE)) then
\r
1269 --clear last write enable.
\r
1270 spr_ptn_h_we_n <= "11111111";
\r
1271 end if;--if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE))
\r
1274 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1275 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1277 if (cur_x = "000000000") then
\r
1278 spr_x_ce_n <= "00000000";
\r
1281 for i in 0 to 7 loop
\r
1282 if (spr_x_cnt(i) = "00000000") then
\r
1283 --active sprite, start shifting..
\r
1284 spr_x_ce_n(i) <= '1';
\r
1285 spr_ptn_ce_n(i) <= '0';
\r
1289 spr_x_ce_n <= "11111111";
\r
1290 spr_ptn_ce_n <= "11111111";
\r
1291 end if; --if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE))
\r
1292 end if; --if (ppu_mask(PPUSSP) = '1') then
\r
1294 --output visible area only.
\r
1295 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1296 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1302 if ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1303 (cur_y = conv_std_logic_vector(VSCAN + 1, X_SIZE))) then
\r
1305 ppu_status(ST_VBL) <= '1';
\r
1306 elsif ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1307 (cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1308 ppu_status(ST_SP0) <= '0';
\r
1310 ppu_status(ST_VBL) <= '0';
\r
1311 --TODO: sprite overflow is not inplemented!
\r
1312 ppu_status(ST_SOF) <= '0';
\r
1314 end if; --if (clk'event and clk = '1') then
\r
1316 -- if (read_status'event and read_status = '1') then
\r
1317 -- --reading ppu status clears vblank bit.
\r
1318 -- ppu_status(ST_VBL) <= '0';
\r
1321 end if;--if (rst_n = '0') then
\r