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_nes_y : out std_logic_vector (8 downto 0);
\r
20 signal dbg_vga_y : out std_logic_vector (9 downto 0);
\r
21 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
22 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
23 signal dbg_plt_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
24 signal dbg_plt_addr : out std_logic_vector (4 downto 0);
\r
25 signal dbg_plt_data : out std_logic_vector (7 downto 0);
\r
26 signal dbg_p_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
27 signal dbg_p_oam_addr : out std_logic_vector (7 downto 0);
\r
28 signal dbg_p_oam_data : out std_logic_vector (7 downto 0);
\r
29 signal dbg_s_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
30 signal dbg_s_oam_addr : out std_logic_vector (4 downto 0);
\r
31 signal dbg_s_oam_data : out std_logic_vector (7 downto 0);
\r
32 signal dbg_emu_ppu_clk : out std_logic;
\r
34 vga_clk : in std_logic;
\r
35 mem_clk : in std_logic;
\r
36 rst_n : in std_logic;
\r
39 rd_n : out std_logic;
\r
40 wr_n : out std_logic;
\r
41 ale : out std_logic;
\r
42 vram_ad : inout std_logic_vector (7 downto 0);
\r
43 vram_a : out std_logic_vector (13 downto 8);
\r
46 h_sync_n : out std_logic;
\r
47 v_sync_n : out std_logic;
\r
48 r : out std_logic_vector (3 downto 0);
\r
49 g : out std_logic_vector (3 downto 0);
\r
50 b : out std_logic_vector (3 downto 0);
\r
53 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
54 ppu_mask : in std_logic_vector (7 downto 0);
\r
55 read_status : in std_logic;
\r
56 ppu_status : out std_logic_vector (7 downto 0);
\r
57 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
58 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
60 --ppu internal ram access
\r
61 r_nw : in std_logic;
\r
62 oam_bus_ce_n : in std_logic;
\r
63 plt_bus_ce_n : in std_logic;
\r
64 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
65 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
66 v_bus_busy_n : out std_logic
\r
70 architecture rtl of vga_ppu_render is
\r
72 component counter_register
\r
74 dsize : integer := 8;
\r
77 port ( clk : in std_logic;
\r
78 rst_n : in std_logic;
\r
79 ce_n : in std_logic;
\r
80 we_n : in std_logic;
\r
81 d : in std_logic_vector(dsize - 1 downto 0);
\r
82 q : out std_logic_vector(dsize - 1 downto 0)
\r
86 component ppu_render
\r
88 signal dbg_ppu_clk : out std_logic;
\r
89 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
90 signal dbg_nes_y : out std_logic_vector (8 downto 0);
\r
91 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
92 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
93 signal dbg_plt_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
94 signal dbg_plt_addr : out std_logic_vector (4 downto 0);
\r
95 signal dbg_plt_data : out std_logic_vector (7 downto 0);
\r
96 signal dbg_p_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
97 signal dbg_p_oam_addr : out std_logic_vector (7 downto 0);
\r
98 signal dbg_p_oam_data : out std_logic_vector (7 downto 0);
\r
99 signal dbg_s_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
100 signal dbg_s_oam_addr : out std_logic_vector (4 downto 0);
\r
101 signal dbg_s_oam_data : out std_logic_vector (7 downto 0);
\r
103 ppu_clk : in std_logic;
\r
104 mem_clk : in std_logic;
\r
105 rst_n : in std_logic;
\r
106 rd_n : out std_logic;
\r
107 wr_n : out std_logic;
\r
108 ale : out std_logic;
\r
109 vram_ad : inout std_logic_vector (7 downto 0);
\r
110 vram_a : out std_logic_vector (13 downto 8);
\r
111 cur_x : in std_logic_vector (8 downto 0);
\r
112 cur_y : in std_logic_vector (8 downto 0);
\r
113 r : out std_logic_vector (3 downto 0);
\r
114 g : out std_logic_vector (3 downto 0);
\r
115 b : out std_logic_vector (3 downto 0);
\r
116 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
117 ppu_mask : in std_logic_vector (7 downto 0);
\r
118 read_status : in std_logic;
\r
119 ppu_status : out std_logic_vector (7 downto 0);
\r
120 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
121 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
123 r_nw : in std_logic;
\r
124 oam_bus_ce_n : in std_logic;
\r
125 plt_bus_ce_n : in std_logic;
\r
126 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
127 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
128 v_bus_busy_n : out std_logic
\r
132 --------- screen constant -----------
\r
133 constant VGA_W : integer := 640;
\r
134 constant VGA_H : integer := 480;
\r
135 constant VGA_W_MAX : integer := 800;
\r
136 constant VGA_H_MAX : integer := 525;
\r
137 constant H_SP : integer := 95;
\r
138 constant H_BP : integer := 48;
\r
139 constant H_FP : integer := 15;
\r
140 constant V_SP : integer := 2;
\r
141 constant V_BP : integer := 33;
\r
142 constant V_FP : integer := 10;
\r
144 --------- signal declaration -----------
\r
145 signal vga_x : std_logic_vector (9 downto 0);
\r
146 signal vga_y : std_logic_vector (9 downto 0);
\r
147 signal x_res_n : std_logic;
\r
148 signal y_res_n : std_logic;
\r
149 signal y_en_n : std_logic;
\r
150 signal cnt_clk : std_logic;
\r
152 signal emu_ppu_clk : std_logic;
\r
153 signal emu_ppu_clk_n : std_logic;
\r
154 signal count5_res_n : std_logic;
\r
155 signal count5 : std_logic_vector(2 downto 0);
\r
156 signal nes_x : std_logic_vector (8 downto 0);
\r
157 signal nes_y : std_logic_vector (8 downto 0);
\r
159 ---DE1 base clock 50 MHz
\r
160 ---motones sim project uses following clock.
\r
161 --cpu clock = base clock / 24 = 2.08 MHz (480 ns / cycle)
\r
162 --ppu clock = base clock / 8
\r
163 --vga clock = base clock / 2
\r
164 --sdram clock = 135 MHz
\r
167 dbg_vga_x <= vga_x;
\r
168 dbg_vga_y <= vga_y;
\r
169 dbg_vga_clk <= vga_clk;
\r
171 cnt_clk <= not vga_clk;
\r
173 --vga position counter
\r
174 x_inst : counter_register generic map (10, 1)
\r
175 port map (cnt_clk , x_res_n, '0', '1', (others => '0'), vga_x);
\r
176 y_inst : counter_register generic map (10, 1)
\r
177 port map (cnt_clk , y_res_n, y_en_n, '1', (others => '0'), vga_y);
\r
178 vga_out_p : process (rst_n, vga_clk)
\r
180 if (rst_n = '0') then
\r
185 elsif (rising_edge(vga_clk)) then
\r
187 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
191 if (vga_y = conv_std_logic_vector(VGA_H_MAX, 10)) then
\r
202 --sync signal assert.
\r
203 if (vga_x >= conv_std_logic_vector((VGA_W + H_FP) , 10) and
\r
204 vga_x < conv_std_logic_vector((VGA_W + H_FP + H_SP) , 10)) then
\r
210 if (vga_y >= conv_std_logic_vector((VGA_H + V_FP) , 10) and
\r
211 vga_y < conv_std_logic_vector((VGA_H + V_FP + V_SP) , 10)) then
\r
220 --emulate ppu clock that is synchronized with vga clock
\r
221 count5_inst : counter_register generic map (3, 1)
\r
222 port map (cnt_clk, count5_res_n, '0', '1', (others => '0'), count5);
\r
223 nes_x_inst : counter_register generic map (9, 1)
\r
224 port map (emu_ppu_clk , x_res_n, '0', '1', (others => '0'), nes_x);
\r
225 nes_y <= vga_y(9 downto 1);
\r
227 res_p : process (rst_n, vga_clk)
\r
229 if (rst_n = '0') then
\r
230 count5_res_n <= '0';
\r
231 elsif (rising_edge(vga_clk)) then
\r
232 if (vga_x = conv_std_logic_vector(VGA_W_MAX, 10)) then
\r
233 count5_res_n <= '0';
\r
234 elsif (count5 = "100") then
\r
235 count5_res_n <= '0';
\r
237 count5_res_n <= '1';
\r
242 emu_clk_p : process (rst_n, mem_clk)
\r
244 if (rst_n = '0') then
\r
245 emu_ppu_clk <= '0';
\r
246 elsif (rising_edge(mem_clk)) then
\r
247 if (vga_x < conv_std_logic_vector(765, 10) ) then
\r
248 if (count5 = "001" or count5 = "011") then
\r
249 emu_ppu_clk <= '0';
\r
251 emu_ppu_clk <= '1';
\r
254 emu_ppu_clk <= not emu_ppu_clk;
\r
259 ---emulated ppu clock adjustment.
\r
260 emu_ppu_clk_n <= not emu_ppu_clk;
\r
261 ppu_render_inst : ppu_render
\r
266 dbg_disp_nt, dbg_disp_attr ,
\r
267 dbg_disp_ptn_h, dbg_disp_ptn_l ,
\r
271 dbg_p_oam_ce_rn_wn ,
\r
274 dbg_s_oam_ce_rn_wn ,
\r
309 ---------------------------------------------------------------
\r
310 ---------------------------------------------------------------
\r
311 ------------------------ PPU VGA Renderer ---------------------
\r
312 ---------------------------------------------------------------
\r
313 ---------------------------------------------------------------
\r
316 use ieee.std_logic_1164.all;
\r
317 use ieee.std_logic_arith.conv_std_logic_vector;
\r
318 use ieee.std_logic_unsigned.all;
\r
319 use work.motonesfpga_common.all;
\r
321 entity ppu_render is
\r
323 signal dbg_ppu_clk : out std_logic;
\r
324 signal dbg_nes_x : out std_logic_vector (8 downto 0);
\r
325 signal dbg_nes_y : out std_logic_vector (8 downto 0);
\r
326 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
\r
327 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
\r
328 signal dbg_plt_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
329 signal dbg_plt_addr : out std_logic_vector (4 downto 0);
\r
330 signal dbg_plt_data : out std_logic_vector (7 downto 0);
\r
331 signal dbg_p_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
332 signal dbg_p_oam_addr : out std_logic_vector (7 downto 0);
\r
333 signal dbg_p_oam_data : out std_logic_vector (7 downto 0);
\r
334 signal dbg_s_oam_ce_rn_wn : out std_logic_vector (2 downto 0);
\r
335 signal dbg_s_oam_addr : out std_logic_vector (4 downto 0);
\r
336 signal dbg_s_oam_data : out std_logic_vector (7 downto 0);
\r
338 ppu_clk : in std_logic;
\r
339 mem_clk : in std_logic;
\r
340 rst_n : in std_logic;
\r
342 rd_n : out std_logic;
\r
343 wr_n : out std_logic;
\r
344 ale : out std_logic;
\r
345 vram_ad : inout std_logic_vector (7 downto 0);
\r
346 vram_a : out std_logic_vector (13 downto 8);
\r
348 --current drawing position 340 x 261
\r
349 cur_x : in std_logic_vector (8 downto 0);
\r
350 cur_y : in std_logic_vector (8 downto 0);
\r
351 r : out std_logic_vector (3 downto 0);
\r
352 g : out std_logic_vector (3 downto 0);
\r
353 b : out std_logic_vector (3 downto 0);
\r
355 ppu_ctrl : in std_logic_vector (7 downto 0);
\r
356 ppu_mask : in std_logic_vector (7 downto 0);
\r
357 read_status : in std_logic;
\r
358 ppu_status : out std_logic_vector (7 downto 0);
\r
359 ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
360 ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
362 r_nw : in std_logic;
\r
363 oam_bus_ce_n : in std_logic;
\r
364 plt_bus_ce_n : in std_logic;
\r
365 oam_plt_addr : in std_logic_vector (7 downto 0);
\r
366 oam_plt_data : inout std_logic_vector (7 downto 0);
\r
367 v_bus_busy_n : out std_logic
\r
371 architecture rtl of ppu_render is
\r
373 component counter_register
\r
375 dsize : integer := 8;
\r
378 port ( clk : in std_logic;
\r
379 rst_n : in std_logic;
\r
380 ce_n : in std_logic;
\r
381 we_n : in std_logic;
\r
382 d : in std_logic_vector(dsize - 1 downto 0);
\r
383 q : out std_logic_vector(dsize - 1 downto 0)
\r
387 component shift_register
\r
389 dsize : integer := 8;
\r
390 shift : integer := 1
\r
392 port ( clk : in std_logic;
\r
393 rst_n : in std_logic;
\r
394 ce_n : in std_logic;
\r
395 we_n : in std_logic;
\r
396 d : in std_logic_vector(dsize - 1 downto 0);
\r
397 q : out std_logic_vector(dsize - 1 downto 0)
\r
401 component d_flip_flop
\r
403 dsize : integer := 8
\r
406 clk : in std_logic;
\r
407 res_n : in std_logic;
\r
408 set_n : in std_logic;
\r
409 we_n : in std_logic;
\r
410 d : in std_logic_vector (dsize - 1 downto 0);
\r
411 q : out std_logic_vector (dsize - 1 downto 0)
\r
415 component tri_state_buffer
\r
417 dsize : integer := 8
\r
420 oe_n : in std_logic;
\r
421 d : in std_logic_vector (dsize - 1 downto 0);
\r
422 q : out std_logic_vector (dsize - 1 downto 0)
\r
427 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
429 clk : in std_logic;
\r
430 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
431 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
432 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
436 component palette_ram
\r
437 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
439 clk : in std_logic;
\r
440 ce_n, oe_n, we_n : in std_logic; --select pin active low.
\r
441 addr : in std_logic_vector (abus_size - 1 downto 0);
\r
442 d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
448 clk : in std_logic;
\r
449 ce_n, oe_n, we_n : in std_logic;
\r
450 sync_ce_n : out std_logic
\r
454 --nes screen size is emulated to align with the vga timing...
\r
455 constant X_SIZE : integer := 9;
\r
456 constant dsize : integer := 8;
\r
457 constant asize : integer := 14;
\r
458 constant HSCAN_MAX : integer := 341;
\r
459 constant VSCAN_MAX : integer := 262;
\r
460 constant HSCAN : integer := 257;
\r
461 constant VSCAN : integer := 240;
\r
462 constant HSCAN_NEXT_START : integer := 320;
\r
463 constant HSCAN_NEXT_EXTRA : integer := 336;
\r
466 constant PPUBNA : integer := 1; --base name address
\r
467 constant PPUVAI : integer := 2; --vram address increment
\r
468 constant PPUSPA : integer := 3; --sprite pattern table address
\r
469 constant PPUBPA : integer := 4; --background pattern table address
\r
470 constant PPUSPS : integer := 5; --sprite size
\r
471 constant PPUMS : integer := 6; --ppu master/slave
\r
472 constant PPUNEN : integer := 7; --nmi enable
\r
474 constant PPUGS : integer := 0; --grayscale
\r
475 constant PPUSBL : integer := 1; --show 8 left most bg pixel
\r
476 constant PPUSSL : integer := 2; --show 8 left most sprite pixel
\r
477 constant PPUSBG : integer := 3; --show bg
\r
478 constant PPUSSP : integer := 4; --show sprie
\r
479 constant PPUIR : integer := 5; --intensify red
\r
480 constant PPUIG : integer := 6; --intensify green
\r
481 constant PPUIB : integer := 7; --intensify blue
\r
483 constant SPRHFL : integer := 6; --flip sprigte horizontally
\r
484 constant SPRVFL : integer := 7; --flip sprigte vertically
\r
486 constant ST_SOF : integer := 5; --sprite overflow
\r
487 constant ST_SP0 : integer := 6; --sprite 0 hits
\r
488 constant ST_VBL : integer := 7; --vblank
\r
490 subtype nes_color_data is std_logic_vector (11 downto 0);
\r
491 type nes_color_array is array (0 to 63) of nes_color_data;
\r
492 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
\r
493 constant nes_color_palette : nes_color_array := (
\r
494 conv_std_logic_vector(16#777#, 12),
\r
495 conv_std_logic_vector(16#20b#, 12),
\r
496 conv_std_logic_vector(16#20b#, 12),
\r
497 conv_std_logic_vector(16#61a#, 12),
\r
498 conv_std_logic_vector(16#927#, 12),
\r
499 conv_std_logic_vector(16#b13#, 12),
\r
500 conv_std_logic_vector(16#a30#, 12),
\r
501 conv_std_logic_vector(16#740#, 12),
\r
502 conv_std_logic_vector(16#450#, 12),
\r
503 conv_std_logic_vector(16#360#, 12),
\r
504 conv_std_logic_vector(16#360#, 12),
\r
505 conv_std_logic_vector(16#364#, 12),
\r
506 conv_std_logic_vector(16#358#, 12),
\r
507 conv_std_logic_vector(16#000#, 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#bbb#, 12),
\r
511 conv_std_logic_vector(16#46f#, 12),
\r
512 conv_std_logic_vector(16#44f#, 12),
\r
513 conv_std_logic_vector(16#94f#, 12),
\r
514 conv_std_logic_vector(16#d4c#, 12),
\r
515 conv_std_logic_vector(16#d46#, 12),
\r
516 conv_std_logic_vector(16#e50#, 12),
\r
517 conv_std_logic_vector(16#c70#, 12),
\r
518 conv_std_logic_vector(16#880#, 12),
\r
519 conv_std_logic_vector(16#5a0#, 12),
\r
520 conv_std_logic_vector(16#4a1#, 12),
\r
521 conv_std_logic_vector(16#4a6#, 12),
\r
522 conv_std_logic_vector(16#49c#, 12),
\r
523 conv_std_logic_vector(16#000#, 12),
\r
524 conv_std_logic_vector(16#000#, 12),
\r
525 conv_std_logic_vector(16#000#, 12),
\r
526 conv_std_logic_vector(16#fff#, 12),
\r
527 conv_std_logic_vector(16#6af#, 12),
\r
528 conv_std_logic_vector(16#58f#, 12),
\r
529 conv_std_logic_vector(16#a7f#, 12),
\r
530 conv_std_logic_vector(16#f6f#, 12),
\r
531 conv_std_logic_vector(16#f6b#, 12),
\r
532 conv_std_logic_vector(16#f73#, 12),
\r
533 conv_std_logic_vector(16#fa0#, 12),
\r
534 conv_std_logic_vector(16#ed2#, 12),
\r
535 conv_std_logic_vector(16#9e0#, 12),
\r
536 conv_std_logic_vector(16#7f4#, 12),
\r
537 conv_std_logic_vector(16#7e9#, 12),
\r
538 conv_std_logic_vector(16#6de#, 12),
\r
539 conv_std_logic_vector(16#777#, 12),
\r
540 conv_std_logic_vector(16#000#, 12),
\r
541 conv_std_logic_vector(16#000#, 12),
\r
542 conv_std_logic_vector(16#fff#, 12),
\r
543 conv_std_logic_vector(16#9df#, 12),
\r
544 conv_std_logic_vector(16#abf#, 12),
\r
545 conv_std_logic_vector(16#cbf#, 12),
\r
546 conv_std_logic_vector(16#ebf#, 12),
\r
547 conv_std_logic_vector(16#fbe#, 12),
\r
548 conv_std_logic_vector(16#fcb#, 12),
\r
549 conv_std_logic_vector(16#fda#, 12),
\r
550 conv_std_logic_vector(16#ff9#, 12),
\r
551 conv_std_logic_vector(16#cf8#, 12),
\r
552 conv_std_logic_vector(16#afa#, 12),
\r
553 conv_std_logic_vector(16#afc#, 12),
\r
554 conv_std_logic_vector(16#aff#, 12),
\r
555 conv_std_logic_vector(16#aaa#, 12),
\r
556 conv_std_logic_vector(16#000#, 12),
\r
557 conv_std_logic_vector(16#000#, 12)
\r
560 signal ppu_clk_n : std_logic;
\r
563 signal bg_io_cnt : std_logic_vector(0 downto 0);
\r
564 signal spr_io_cnt : std_logic_vector(0 downto 0);
\r
567 signal io_oe_n : std_logic;
\r
568 signal ah_oe_n : std_logic;
\r
570 signal cnt_x_res_n : std_logic;
\r
571 signal bg_cnt_res_n : std_logic;
\r
573 --bg prefetch position (scroll + 16 cycle ahead of current pos)
\r
574 --511 x 239 (or 255 x 479)
\r
575 signal prf_x : std_logic_vector(X_SIZE - 1 downto 0);
\r
576 signal prf_y : std_logic_vector(X_SIZE - 1 downto 0);
\r
578 signal nt_we_n : std_logic;
\r
579 signal disp_nt : std_logic_vector (dsize - 1 downto 0);
\r
581 signal attr_ce_n : std_logic;
\r
582 signal attr_we_n : std_logic;
\r
583 signal attr_val : std_logic_vector (dsize - 1 downto 0);
\r
584 signal disp_attr_we_n : std_logic;
\r
585 signal disp_attr : std_logic_vector (dsize - 1 downto 0);
\r
587 signal ptn_l_we_n : std_logic;
\r
588 signal ptn_l_in : std_logic_vector (dsize - 1 downto 0);
\r
589 signal ptn_l_val : std_logic_vector (dsize - 1 downto 0);
\r
590 signal disp_ptn_l_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
591 signal disp_ptn_l : std_logic_vector (dsize * 2 - 1 downto 0);
\r
593 signal ptn_h_we_n : std_logic;
\r
594 signal ptn_h_in : std_logic_vector (dsize * 2 - 1 downto 0);
\r
595 signal disp_ptn_h : std_logic_vector (dsize * 2 - 1 downto 0);
\r
597 --signals for palette / oam access from cpu
\r
598 signal r_n : std_logic;
\r
599 signal vram_addr : std_logic_vector (asize - 1 downto 0);
\r
602 signal plt_ram_ce_n_in : std_logic;
\r
603 signal plt_ram_ce_n : std_logic;
\r
604 signal plt_r_n : std_logic;
\r
605 signal plt_w_n : std_logic;
\r
606 signal plt_addr : std_logic_vector (4 downto 0);
\r
607 signal plt_data : std_logic_vector (dsize - 1 downto 0);
\r
609 --primari / secondary oam
\r
610 signal p_oam_ram_ce_n_in : std_logic;
\r
611 signal p_oam_ram_ce_n : std_logic;
\r
612 signal p_oam_r_n : std_logic;
\r
613 signal p_oam_w_n : std_logic;
\r
614 signal p_oam_addr : std_logic_vector (dsize - 1 downto 0);
\r
615 signal p_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
617 signal s_oam_ram_ce_n_in : std_logic;
\r
618 signal s_oam_ram_ce_n : std_logic;
\r
619 signal s_oam_r_n : std_logic;
\r
620 signal s_oam_w_n : std_logic;
\r
621 signal s_oam_addr_cpy_ce_n : std_logic;
\r
622 signal s_oam_addr_cpy_n : std_logic;
\r
623 signal s_oam_addr : std_logic_vector (4 downto 0);
\r
624 signal s_oam_addr_cpy : std_logic_vector (4 downto 0);
\r
625 signal s_oam_data : std_logic_vector (dsize - 1 downto 0);
\r
627 signal p_oam_cnt_res_n : std_logic;
\r
628 signal p_oam_cnt_ce_n : std_logic;
\r
629 signal p_oam_cnt_wrap_n : std_logic;
\r
630 signal p_oam_cnt : std_logic_vector (dsize - 1 downto 0);
\r
631 signal p_oam_addr_in : std_logic_vector (dsize - 1 downto 0);
\r
632 signal oam_ev_status : std_logic_vector (2 downto 0);
\r
634 signal s_oam_cnt_ce_n : std_logic;
\r
635 signal s_oam_cnt : std_logic_vector (4 downto 0);
\r
637 --oam evaluation status
\r
638 constant EV_STAT_COMP : std_logic_vector (2 downto 0) := "000";
\r
639 constant EV_STAT_CP1 : std_logic_vector (2 downto 0) := "001";
\r
640 constant EV_STAT_CP2 : std_logic_vector (2 downto 0) := "010";
\r
641 constant EV_STAT_CP3 : std_logic_vector (2 downto 0) := "011";
\r
642 constant EV_STAT_PRE_COMP : std_logic_vector (2 downto 0) := "100";
\r
644 ----------sprite registers.
\r
645 type oam_pin_array is array (0 to 7) of std_logic;
\r
646 type oam_reg_array is array (0 to 7) of std_logic_vector (dsize - 1 downto 0);
\r
648 signal spr_x_we_n : oam_pin_array;
\r
649 signal spr_x_ce_n : oam_pin_array;
\r
650 signal spr_attr_we_n : oam_pin_array;
\r
651 signal spr_ptn_l_we_n : oam_pin_array;
\r
652 signal spr_ptn_h_we_n : oam_pin_array;
\r
653 signal spr_ptn_ce_n : oam_pin_array;
\r
655 signal spr_x_cnt : oam_reg_array;
\r
656 signal spr_attr : oam_reg_array;
\r
657 signal spr_ptn_l : oam_reg_array;
\r
658 signal spr_ptn_h : oam_reg_array;
\r
660 signal spr_y_we_n : std_logic;
\r
661 signal spr_tile_we_n : std_logic;
\r
662 signal spr_y_tmp : std_logic_vector (dsize - 1 downto 0);
\r
663 signal spr_tile_tmp : std_logic_vector (dsize - 1 downto 0);
\r
664 signal spr_ptn_in : std_logic_vector (dsize - 1 downto 0);
\r
668 dbg_ppu_clk <= ppu_clk;
\r
669 dbg_nes_x <= cur_x;
\r
670 dbg_nes_y <= cur_y;
\r
671 dbg_disp_nt <= disp_nt;
\r
672 dbg_disp_attr <= disp_attr;
\r
673 dbg_disp_ptn_h <= disp_ptn_h;
\r
674 dbg_disp_ptn_l <= disp_ptn_l;
\r
675 dbg_plt_addr <= plt_addr;
\r
676 dbg_plt_data <= plt_data;
\r
677 dbg_plt_ce_rn_wn <= plt_ram_ce_n & plt_r_n & plt_w_n;
\r
678 dbg_p_oam_ce_rn_wn <= p_oam_ram_ce_n & p_oam_r_n & p_oam_w_n;
\r
679 dbg_p_oam_addr <= p_oam_addr;
\r
680 dbg_p_oam_data <= p_oam_data;
\r
681 dbg_s_oam_ce_rn_wn <= s_oam_ram_ce_n & s_oam_r_n & s_oam_w_n;
\r
682 dbg_s_oam_addr <= s_oam_addr;
\r
683 dbg_s_oam_data <= p_oam_data;
\r
686 ppu_clk_n <= not ppu_clk;
\r
688 ale <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
689 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
690 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
691 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
692 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
693 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
694 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
695 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
696 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
697 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
700 rd_n <= bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
701 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
702 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
703 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
704 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
705 spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
706 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
707 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
708 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
709 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
711 wr_n <= '1' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
712 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
713 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
715 io_oe_n <= not bg_io_cnt(0) when ppu_mask(PPUSBG) = '1' and
\r
716 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
717 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
718 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
719 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
720 not spr_io_cnt(0) when ppu_mask(PPUSSP) = '1' and
\r
721 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
722 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
723 (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
724 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) else
\r
726 ah_oe_n <= '0' when (ppu_mask(PPUSBG) = '1' or ppu_mask(PPUSSP) = '1') and
\r
727 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
728 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) else
\r
730 v_bus_busy_n <= ah_oe_n;
\r
732 bg_io_cnt_inst : counter_register generic map (1, 1)
\r
733 port map (ppu_clk, bg_cnt_res_n, '0', '1', (others => '0'), bg_io_cnt);
\r
734 spr_io_cnt_inst : counter_register generic map (1, 1)
\r
735 port map (ppu_clk, cnt_x_res_n, '0', '1', (others => '0'), spr_io_cnt);
\r
737 ---bg prefetch x pos is 16 + scroll cycle ahead of current pos.
\r
738 prf_x <= cur_x + ppu_scroll_x + "000010000"
\r
739 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) else
\r
740 cur_x + ppu_scroll_x + "010111011"; -- +16 -341
\r
742 prf_y <= cur_y + ppu_scroll_y
\r
743 when cur_x < conv_std_logic_vector(HSCAN, X_SIZE) and
\r
744 cur_y + ppu_scroll_y <
\r
745 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
746 cur_y + ppu_scroll_y + "000000001"
\r
747 when cur_y + ppu_scroll_y <
\r
748 conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
\r
751 nt_inst : d_flip_flop generic map(dsize)
\r
752 port map (ppu_clk_n, rst_n, '1', nt_we_n, vram_ad, disp_nt);
\r
754 at_inst : d_flip_flop generic map(dsize)
\r
755 port map (ppu_clk_n, rst_n, '1', attr_we_n, vram_ad, attr_val);
\r
757 disp_at_inst : shift_register generic map(dsize, 2)
\r
758 port map (ppu_clk_n, rst_n, attr_ce_n, disp_attr_we_n, attr_val, disp_attr);
\r
760 --chr rom data's bit is stored in opposite direction.
\r
761 --reverse bit when loading...
\r
762 ptn_l_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
763 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
764 ptn_h_in <= (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
765 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7)) &
\r
766 disp_ptn_h (dsize downto 1);
\r
768 ptn_l_inst : d_flip_flop generic map(dsize)
\r
769 port map (ppu_clk_n, rst_n, '1', ptn_l_we_n, ptn_l_in, ptn_l_val);
\r
771 disp_ptn_l_in <= ptn_l_val & disp_ptn_l (dsize downto 1);
\r
772 disp_ptn_l_inst : shift_register generic map(dsize * 2, 1)
\r
773 port map (ppu_clk_n, rst_n, '0', ptn_h_we_n, disp_ptn_l_in, disp_ptn_l);
\r
775 ptn_h_inst : shift_register generic map(dsize * 2, 1)
\r
776 port map (ppu_clk_n, rst_n, '0', ptn_h_we_n, ptn_h_in, disp_ptn_h);
\r
779 vram_io_buf : tri_state_buffer generic map (dsize)
\r
780 port map (io_oe_n, vram_addr(dsize - 1 downto 0), vram_ad);
\r
782 vram_a_buf : tri_state_buffer generic map (6)
\r
783 port map (ah_oe_n, vram_addr(asize - 1 downto dsize), vram_a);
\r
788 plt_ram_ce_n_in <= ppu_clk when plt_bus_ce_n = '0' and r_nw = '0' else
\r
789 '0' when plt_bus_ce_n = '0' and r_nw = '1' else
\r
790 '0' when ppu_mask(PPUSBG) = '1' and
\r
791 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
792 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
795 plt_addr <= oam_plt_addr(4 downto 0) when plt_bus_ce_n = '0' else
\r
796 "1" & spr_attr(0)(1 downto 0) & spr_ptn_h(0)(0) & spr_ptn_l(0)(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(0) = "00000000" and
\r
801 (spr_ptn_h(0)(0) or spr_ptn_l(0)(0)) = '1' else
\r
802 "1" & spr_attr(1)(1 downto 0) & spr_ptn_h(1)(0) & spr_ptn_l(1)(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(1) = "00000000" and
\r
807 (spr_ptn_h(1)(0) or spr_ptn_l(1)(0)) = '1' else
\r
808 "1" & spr_attr(2)(1 downto 0) & spr_ptn_h(2)(0) & spr_ptn_l(2)(0)
\r
809 when ppu_mask(PPUSSP) = '1' and
\r
810 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
811 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
812 spr_x_cnt(2) = "00000000" and
\r
813 (spr_ptn_h(2)(0) or spr_ptn_l(2)(0)) = '1' else
\r
814 "1" & spr_attr(3)(1 downto 0) & spr_ptn_h(3)(0) & spr_ptn_l(3)(0)
\r
815 when ppu_mask(PPUSSP) = '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)) and
\r
818 spr_x_cnt(3) = "00000000" and
\r
819 (spr_ptn_h(3)(0) or spr_ptn_l(3)(0)) = '1' else
\r
820 "1" & spr_attr(4)(1 downto 0) & spr_ptn_h(4)(0) & spr_ptn_l(4)(0)
\r
821 when ppu_mask(PPUSSP) = '1' and
\r
822 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
823 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
824 spr_x_cnt(4) = "00000000" and
\r
825 (spr_ptn_h(4)(0) or spr_ptn_l(4)(0)) = '1' else
\r
826 "1" & spr_attr(5)(1 downto 0) & spr_ptn_h(5)(0) & spr_ptn_l(5)(0)
\r
827 when ppu_mask(PPUSSP) = '1' and
\r
828 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
829 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
830 spr_x_cnt(5) = "00000000" and
\r
831 (spr_ptn_h(5)(0) or spr_ptn_l(5)(0)) = '1' else
\r
832 "1" & spr_attr(6)(1 downto 0) & spr_ptn_h(6)(0) & spr_ptn_l(6)(0)
\r
833 when ppu_mask(PPUSSP) = '1' and
\r
834 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
835 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
836 spr_x_cnt(6) = "00000000" and
\r
837 (spr_ptn_h(6)(0) or spr_ptn_l(6)(0)) = '1' else
\r
838 "1" & spr_attr(7)(1 downto 0) & spr_ptn_h(7)(0) & spr_ptn_l(7)(0)
\r
839 when ppu_mask(PPUSSP) = '1' and
\r
840 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
841 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) and
\r
842 spr_x_cnt(7) = "00000000" and
\r
843 (spr_ptn_h(7)(0) or spr_ptn_l(7)(0)) = '1' else
\r
844 "0" & disp_attr(1 downto 0) & disp_ptn_h(0) & disp_ptn_l(0)
\r
845 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '0' and
\r
846 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
847 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
848 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
849 "0" & disp_attr(5 downto 4) & disp_ptn_h(0) & disp_ptn_l(0)
\r
850 when ppu_mask(PPUSBG) = '1' and cur_y(4) = '1' and
\r
851 ((disp_ptn_h(0) or disp_ptn_l(0)) = '1') and
\r
852 (cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
853 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE)) else
\r
854 ---else: no output color >> universal bg color output.
\r
855 --0x3f00 is the universal bg palette.
\r
858 plt_r_n <= not r_nw when plt_bus_ce_n = '0' else
\r
859 '0' when ppu_mask(PPUSBG) = '1' else
\r
861 plt_w_n <= r_nw when plt_bus_ce_n = '0' else
\r
863 plt_d_buf_w : tri_state_buffer generic map (dsize)
\r
864 port map (plt_w_n, oam_plt_data, plt_data);
\r
865 plt_d_buf_r : tri_state_buffer generic map (dsize)
\r
866 port map (plt_r_n, plt_data, oam_plt_data);
\r
867 plt_ram_ctl : ram_ctrl
\r
868 port map (mem_clk, plt_ram_ce_n_in, plt_r_n, plt_w_n, plt_ram_ce_n);
\r
869 palette_inst : palette_ram generic map (5, dsize)
\r
870 port map (mem_clk, plt_ram_ce_n, plt_r_n, plt_w_n, plt_addr, plt_data);
\r
873 p_oam_ram_ce_n_in <= ppu_clk when oam_bus_ce_n = '0' and r_nw = '0' else
\r
874 '0' when oam_bus_ce_n = '0' and r_nw = '1' else
\r
875 '0' when ppu_mask(PPUSSP) = '1' and
\r
876 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
877 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
878 p_oam_cnt_wrap_n = '1' else
\r
880 p_oam_addr <= oam_plt_addr when oam_bus_ce_n = '0' else
\r
881 p_oam_addr_in when ppu_mask(PPUSSP) = '1' and
\r
882 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
883 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
884 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
885 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
887 p_oam_r_n <= not r_nw when oam_bus_ce_n = '0' else
\r
888 '0' when ppu_mask(PPUSSP) = '1' and
\r
889 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
890 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) and
\r
891 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
892 cur_x <= conv_std_logic_vector(256, X_SIZE) else
\r
894 p_oam_w_n <= r_nw when oam_bus_ce_n = '0' else
\r
896 oam_d_buf_w : tri_state_buffer generic map (dsize)
\r
897 port map (p_oam_w_n, oam_plt_data, p_oam_data);
\r
898 oam_d_buf_r : tri_state_buffer generic map (dsize)
\r
899 port map (p_oam_r_n, p_oam_data, oam_plt_data);
\r
901 p_oam_ram_ctl : ram_ctrl
\r
902 port map (mem_clk, p_oam_ram_ce_n_in, p_oam_r_n, p_oam_w_n, p_oam_ram_ce_n);
\r
903 primary_oam_inst : ram generic map (dsize, dsize)
\r
904 port map (mem_clk, p_oam_ram_ce_n, p_oam_r_n, p_oam_w_n, p_oam_addr, p_oam_data);
\r
907 p_oam_cnt_inst : counter_register generic map (dsize, 4)
\r
908 port map (ppu_clk_n, p_oam_cnt_res_n, p_oam_cnt_ce_n, '1', (others => '0'), p_oam_cnt);
\r
909 s_oam_cnt_inst : counter_register generic map (5, 1)
\r
910 port map (ppu_clk_n, p_oam_cnt_res_n, s_oam_cnt_ce_n, '1', (others => '0'), s_oam_cnt);
\r
911 s_oam_addr_cpy_inst : counter_register generic map (5, 1)
\r
912 port map (ppu_clk_n, p_oam_cnt_res_n, s_oam_addr_cpy_ce_n,
\r
913 '1', (others => '0'), s_oam_addr_cpy);
\r
915 s_oam_ram_ce_n_in <= ppu_clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
916 cur_x > "000000001" and
\r
917 cur_x <= conv_std_logic_vector(64, X_SIZE) else
\r
918 ppu_clk when ppu_mask(PPUSSP) = '1' and cur_x(0) = '1' and
\r
919 cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
920 cur_x <= conv_std_logic_vector(256, X_SIZE) and
\r
921 p_oam_cnt_wrap_n = '1' else
\r
922 '0' when ppu_mask(PPUSSP) = '1' and
\r
923 cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
924 cur_x <= conv_std_logic_vector(320, X_SIZE) and
\r
925 s_oam_addr_cpy_n = '0' else
\r
928 s_oam_ram_ctl : ram_ctrl
\r
929 port map (mem_clk, s_oam_ram_ce_n_in, s_oam_r_n, s_oam_w_n, s_oam_ram_ce_n);
\r
930 secondary_oam_inst : ram generic map (5, dsize)
\r
931 port map (mem_clk, s_oam_ram_ce_n, s_oam_r_n, s_oam_w_n, s_oam_addr, s_oam_data);
\r
933 spr_y_inst : d_flip_flop generic map(dsize)
\r
934 port map (ppu_clk_n, p_oam_cnt_res_n, '1', spr_y_we_n, s_oam_data, spr_y_tmp);
\r
935 spr_tile_inst : d_flip_flop generic map(dsize)
\r
936 port map (ppu_clk_n, p_oam_cnt_res_n, '1', spr_tile_we_n, s_oam_data, spr_tile_tmp);
\r
939 --reverse bit when NOT SPRHFL is set (.nes file format bit endian).
\r
940 spr_ptn_in <= vram_ad when spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRHFL) = '1' else
\r
941 (vram_ad(0) & vram_ad(1) & vram_ad(2) & vram_ad(3) &
\r
942 vram_ad(4) & vram_ad(5) & vram_ad(6) & vram_ad(7));
\r
943 --array instances...
\r
944 spr_inst : for i in 0 to 7 generate
\r
945 spr_x_inst : counter_register generic map(dsize, 16#ff#)
\r
946 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
948 spr_attr_inst : d_flip_flop generic map(dsize)
\r
949 port map (ppu_clk_n, rst_n, '1', spr_attr_we_n(i), s_oam_data, spr_attr(i));
\r
951 spr_ptn_l_inst : shift_register generic map(dsize, 1)
\r
952 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
954 spr_ptn_h_inst : shift_register generic map(dsize, 1)
\r
955 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
958 pos_p : process (rst_n, ppu_clk)
\r
960 if (rst_n = '0') then
\r
961 cnt_x_res_n <= '0';
\r
962 bg_cnt_res_n <= '0';
\r
963 elsif (ppu_clk'event and ppu_clk = '0') then
\r
964 if (cur_x = conv_std_logic_vector(HSCAN_MAX - 1, X_SIZE)) then
\r
966 cnt_x_res_n <= '0';
\r
968 cnt_x_res_n <= '1';
\r
971 if (ppu_scroll_x(0) = '0' and cur_x = conv_std_logic_vector(HSCAN, X_SIZE)) then
\r
972 bg_cnt_res_n <= '0';
\r
973 elsif (ppu_scroll_x(0) = '1' and cur_x = conv_std_logic_vector(HSCAN - 1, X_SIZE)) then
\r
974 bg_cnt_res_n <= '0';
\r
976 bg_cnt_res_n <= '1';
\r
978 end if; --if (rst_n = '0') then
\r
981 clk_p : process (rst_n, ppu_clk, read_status)
\r
983 procedure output_rgb is
\r
984 variable pl_addr : integer;
\r
985 variable pl_index : integer;
\r
986 variable dot_output : boolean;
\r
988 dot_output := false;
\r
990 --first show sprite.
\r
991 if (ppu_mask(PPUSSP) = '1') then
\r
992 for i in 0 to 7 loop
\r
993 if (spr_x_cnt(i) = "00000000") then
\r
994 if ((spr_ptn_h(i)(0) or spr_ptn_l(i)(0)) = '1') then
\r
995 dot_output := true;
\r
1002 if (dot_output = true and ppu_mask(PPUSBG) = '1' and
\r
1003 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
1004 --raise sprite 0 hit.
\r
1005 ppu_status(ST_SP0) <= '1';
\r
1008 --first color in the palette is transparent color.
\r
1009 if (ppu_mask(PPUSBG) = '1' and dot_output = false and
\r
1010 (disp_ptn_h(0) or disp_ptn_l(0)) = '1') then
\r
1011 dot_output := true;
\r
1014 --if or if not bg/sprite is shown, output color anyway
\r
1015 --sinse universal bg color is included..
\r
1016 pl_index := conv_integer(plt_data(5 downto 0));
\r
1017 b <= nes_color_palette(pl_index) (11 downto 8);
\r
1018 g <= nes_color_palette(pl_index) (7 downto 4);
\r
1019 r <= nes_color_palette(pl_index) (3 downto 0);
\r
1021 procedure stop_rgb is
\r
1023 b <= (others => '0');
\r
1024 g <= (others => '0');
\r
1025 r <= (others => '0');
\r
1029 if (rst_n = '0') then
\r
1031 ppu_status <= (others => '0');
\r
1032 s_oam_data <= (others => 'Z');
\r
1036 if (ppu_clk'event and ppu_clk = '1') then
\r
1038 --fetch bg pattern and display.
\r
1039 if (ppu_mask(PPUSBG) = '1' and
\r
1040 (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
\r
1041 cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) and
\r
1042 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1043 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1044 --visible area bg image
\r
1047 d_print("cur_x: " & conv_hex16(conv_integer(cur_x)));
\r
1048 d_print("cur_y: " & conv_hex16(conv_integer(cur_y)));
\r
1050 ----fetch next tile byte.
\r
1051 if (prf_x (2 downto 0) = "001") then
\r
1052 --vram addr is incremented every 8 cycle.
\r
1053 --name table at 0x2000
\r
1054 vram_addr(9 downto 0)
\r
1055 <= prf_y(dsize - 1 downto 3)
\r
1056 & prf_x(dsize - 1 downto 3);
\r
1057 vram_addr(asize - 1 downto 10) <= "10" & ppu_ctrl(PPUBNA downto 0)
\r
1058 + ("000" & prf_x(dsize));
\r
1059 ----fetch attr table byte.
\r
1060 elsif (prf_x (4 downto 0) = "00011") then
\r
1061 --attribute table is loaded every 32 cycle.
\r
1062 --attr table at 0x23c0
\r
1063 vram_addr(dsize - 1 downto 0) <= "11000000" +
\r
1064 ("00" & prf_y(7 downto 5) & prf_x(7 downto 5));
\r
1065 vram_addr(asize - 1 downto dsize) <= "10" &
\r
1066 ppu_ctrl(PPUBNA downto 0) & "11"
\r
1067 + ("000" & prf_x(dsize) & "00");
\r
1068 ----fetch pattern table low byte.
\r
1069 elsif (prf_x (2 downto 0) = "101") then
\r
1070 --vram addr is incremented every 8 cycle.
\r
1071 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1072 disp_nt(dsize - 1 downto 0)
\r
1073 & "0" & prf_y(2 downto 0);
\r
1074 ----fetch pattern table high byte.
\r
1075 elsif (prf_x (2 downto 0) = "111") then
\r
1076 --vram addr is incremented every 8 cycle.
\r
1077 vram_addr <= "0" & ppu_ctrl(PPUBPA) &
\r
1078 disp_nt(dsize - 1 downto 0)
\r
1079 & "0" & prf_y(2 downto 0) + "00000000001000";
\r
1082 ----fetch next tile byte.
\r
1083 if (prf_x (2 downto 0) = "010") then
\r
1089 ----fetch attr table byte.
\r
1090 if (prf_x (4 downto 0) = "00100") then
\r
1095 if (prf_x (4 downto 0) = "10000") then
\r
1096 disp_attr_we_n <= '0';
\r
1098 disp_attr_we_n <= '1';
\r
1100 ---attribute is shifted every 16 bit.
\r
1101 if (prf_x (3 downto 0) = "0000") then
\r
1107 ----fetch pattern table low byte.
\r
1108 if (prf_x (2 downto 0) = "110") then
\r
1109 ptn_l_we_n <= '0';
\r
1111 ptn_l_we_n <= '1';
\r
1114 ----fetch pattern table high byte.
\r
1115 if (prf_x (2 downto 0) = "000") then
\r
1116 ptn_h_we_n <= '0';
\r
1118 ptn_h_we_n <= '1';
\r
1124 disp_attr_we_n <= '1';
\r
1126 ptn_l_we_n <= '1';
\r
1127 ptn_h_we_n <= '1';
\r
1128 end if;--if (ppu_mask(PPUSBG) = '1') and
\r
1130 --fetch sprite and display.
\r
1131 if (ppu_mask(PPUSSP) = '1' and
\r
1132 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE) or
\r
1133 cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1134 --secondary oam clear
\r
1135 if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE)) then
\r
1136 if (cur_x(0) = '0') then
\r
1137 --write secondary oam on even cycle
\r
1140 s_oam_addr <= cur_x(5 downto 1);
\r
1141 s_oam_data <= (others => '1');
\r
1143 p_oam_cnt_res_n <= '0';
\r
1144 p_oam_cnt_ce_n <= '1';
\r
1145 s_oam_cnt_ce_n <= '1';
\r
1146 p_oam_cnt_wrap_n <= '1';
\r
1147 oam_ev_status <= EV_STAT_COMP;
\r
1149 --sprite evaluation and secondary oam copy.
\r
1150 elsif (cur_x > conv_std_logic_vector(64, X_SIZE) and
\r
1151 cur_x <= conv_std_logic_vector(256, X_SIZE)) then
\r
1152 p_oam_cnt_res_n <= '1';
\r
1154 --TODO: sprite evaluation is simplified!!
\r
1155 --not complying the original NES spec at
\r
1156 --http://wiki.nesdev.com/w/index.php/PPU_sprite_evaluation
\r
1157 --e.g., when overflow happens, it just ignore subsequent entry.
\r
1158 --old secondary sprite entry.
\r
1159 if (p_oam_cnt = "00000000" and cur_x > conv_std_logic_vector(192, X_SIZE)) then
\r
1160 p_oam_cnt_wrap_n <= '0';
\r
1163 --odd cycle copy from primary oam
\r
1164 if (cur_x(0) = '1') then
\r
1165 if (oam_ev_status = EV_STAT_COMP) then
\r
1166 p_oam_addr_in <= p_oam_cnt;
\r
1167 p_oam_cnt_ce_n <= '1';
\r
1168 s_oam_cnt_ce_n <= '1';
\r
1169 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1170 p_oam_addr_in <= p_oam_cnt + "00000001";
\r
1171 s_oam_cnt_ce_n <= '1';
\r
1173 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1174 p_oam_addr_in <= p_oam_cnt + "00000010";
\r
1175 s_oam_cnt_ce_n <= '1';
\r
1177 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1178 oam_ev_status <= EV_STAT_PRE_COMP;
\r
1179 p_oam_addr_in <= p_oam_cnt + "00000011";
\r
1180 s_oam_cnt_ce_n <= '1';
\r
1183 --even cycle copy to secondary oam (if y is in range.)
\r
1186 s_oam_addr <= s_oam_cnt;
\r
1187 s_oam_data <= p_oam_data;
\r
1189 if (oam_ev_status = EV_STAT_COMP) then
\r
1191 if (cur_y < "000000110" and p_oam_data <= cur_y + "000000001") or
\r
1192 (cur_y >= "000000110" and p_oam_data <= cur_y + "000000001" and
\r
1193 p_oam_data >= cur_y - "000000110") then
\r
1194 oam_ev_status <= EV_STAT_CP1;
\r
1195 s_oam_cnt_ce_n <= '0';
\r
1196 --copy remaining oam entry.
\r
1197 p_oam_cnt_ce_n <= '1';
\r
1200 p_oam_cnt_ce_n <= '0';
\r
1202 elsif (oam_ev_status = EV_STAT_CP1) then
\r
1203 s_oam_cnt_ce_n <= '0';
\r
1204 oam_ev_status <= EV_STAT_CP2;
\r
1205 elsif (oam_ev_status = EV_STAT_CP2) then
\r
1206 s_oam_cnt_ce_n <= '0';
\r
1207 oam_ev_status <= EV_STAT_CP3;
\r
1208 elsif (oam_ev_status = EV_STAT_CP3) then
\r
1209 s_oam_cnt_ce_n <= '0';
\r
1210 elsif (oam_ev_status = EV_STAT_PRE_COMP) then
\r
1211 oam_ev_status <= EV_STAT_COMP;
\r
1212 s_oam_cnt_ce_n <= '0';
\r
1213 p_oam_cnt_ce_n <= '0';
\r
1215 end if;--if (cur_x(0) = '1') then
\r
1217 --prepare for next step
\r
1218 s_oam_addr_cpy_n <= '1';
\r
1219 spr_y_we_n <= '1';
\r
1220 spr_tile_we_n <= '1';
\r
1221 spr_x_we_n <= "11111111";
\r
1222 spr_attr_we_n <= "11111111";
\r
1223 spr_ptn_l_we_n <= "11111111";
\r
1224 spr_ptn_h_we_n <= "11111111";
\r
1226 --sprite pattern fetch
\r
1227 elsif (cur_x > conv_std_logic_vector(256, X_SIZE) and
\r
1228 cur_x <= conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE)) then
\r
1230 s_oam_addr_cpy_n <= '0';
\r
1233 s_oam_addr <= s_oam_addr_cpy;
\r
1235 ----fetch y-cordinate from secondary oam
\r
1236 if (cur_x (2 downto 0) = "001" ) then
\r
1237 s_oam_addr_cpy_ce_n <= '0';
\r
1238 spr_y_we_n <= '0';
\r
1240 spr_y_we_n <= '1';
\r
1243 ----fetch tile number
\r
1244 if (cur_x (2 downto 0) = "010" ) then
\r
1245 spr_tile_we_n <= '0';
\r
1247 spr_tile_we_n <= '1';
\r
1250 ----fetch attribute
\r
1251 if (cur_x (2 downto 0) = "011" ) then
\r
1252 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1254 spr_attr_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1255 end if;--if (cur_x (2 downto 0) = "010" ) then
\r
1257 ----fetch x-cordinate
\r
1258 if (cur_x (2 downto 0) = "100" ) then
\r
1259 s_oam_addr_cpy_ce_n <= '1';
\r
1260 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1262 spr_x_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1265 ----fetch pattern table low byte.
\r
1266 if (cur_x (2 downto 0) = "101" ) then
\r
1267 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1268 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1269 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1270 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0));
\r
1272 --flip sprite vertically.
\r
1273 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1274 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1275 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010");
\r
1279 if (cur_x (2 downto 0) = "110" ) then
\r
1280 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1282 spr_ptn_l_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '1';
\r
1285 ----fetch pattern table high byte.
\r
1286 if (cur_x (2 downto 0) = "111" ) then
\r
1287 if (spr_attr(conv_integer(s_oam_addr_cpy(4 downto 2)))(SPRVFL) = '0') then
\r
1288 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1289 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1290 (cur_y(2 downto 0) + "001" - spr_y_tmp(2 downto 0))
\r
1291 + "00000000001000";
\r
1293 --flip sprite vertically.
\r
1294 vram_addr <= "0" & ppu_ctrl(PPUSPA) &
\r
1295 spr_tile_tmp(dsize - 1 downto 0) & "0" &
\r
1296 (spr_y_tmp(2 downto 0) - cur_y(2 downto 0) - "010")
\r
1297 + "00000000001000";
\r
1301 if (cur_x (2 downto 0) = "000") then
\r
1302 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2))) <= '0';
\r
1303 s_oam_addr_cpy_ce_n <= '0';
\r
1305 spr_ptn_h_we_n(conv_integer(s_oam_addr_cpy(4 downto 2) - "001")) <= '1';
\r
1308 elsif (cur_x > conv_std_logic_vector(320, X_SIZE)) then
\r
1309 --clear last write enable.
\r
1310 spr_ptn_h_we_n <= "11111111";
\r
1311 end if;--if (cur_x /= "000000000" and cur_x <= conv_std_logic_vector(64, X_SIZE))
\r
1314 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1315 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1317 if (cur_x = "000000000") then
\r
1318 spr_x_ce_n <= "00000000";
\r
1321 for i in 0 to 7 loop
\r
1322 if (spr_x_cnt(i) = "00000000") then
\r
1323 --active sprite, start shifting..
\r
1324 spr_x_ce_n(i) <= '1';
\r
1325 spr_ptn_ce_n(i) <= '0';
\r
1329 spr_x_ce_n <= "11111111";
\r
1330 spr_ptn_ce_n <= "11111111";
\r
1331 end if; --if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE))
\r
1332 end if; --if (ppu_mask(PPUSSP) = '1') then
\r
1334 --output visible area only.
\r
1335 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
\r
1336 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
\r
1344 if ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1345 (cur_y = conv_std_logic_vector(VSCAN + 1, X_SIZE))) then
\r
1347 ppu_status(ST_VBL) <= '1';
\r
1348 elsif ((cur_x = conv_std_logic_vector(1, X_SIZE)) and
\r
1349 (cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE))) then
\r
1350 ppu_status(ST_SP0) <= '0';
\r
1352 ppu_status(ST_VBL) <= '0';
\r
1353 --TODO: sprite overflow is not inplemented!
\r
1354 ppu_status(ST_SOF) <= '0';
\r
1356 end if; --if (clk'event and clk = '1') then
\r
1358 -- if (read_status'event and read_status = '1') then
\r
1359 -- --reading ppu status clears vblank bit.
\r
1360 -- ppu_status(ST_VBL) <= '0';
\r
1363 end if;--if (rst_n = '0') then
\r