1 -------------------------------------------------------------
\r
2 -------------------------------------------------------------
\r
3 ------------------- PPU VGA Output Control ------------------
\r
4 -------------------------------------------------------------
\r
5 -------------------------------------------------------------
\r
7 use ieee.std_logic_1164.all;
\r
8 use ieee.std_logic_unsigned.conv_integer;
\r
9 use ieee.std_logic_arith.conv_std_logic_vector;
\r
10 use ieee.std_logic_unsigned.all;
\r
14 pi_rst_n : in std_logic;
\r
15 pi_base_clk : in std_logic;
\r
16 pi_rnd_en : in std_logic_vector (3 downto 0);
\r
19 pi_ppu_ctrl : in std_logic_vector (7 downto 0);
\r
20 pi_ppu_mask : in std_logic_vector (7 downto 0);
\r
21 po_ppu_status : out std_logic_vector (7 downto 0);
\r
22 pi_ppu_scroll_x : in std_logic_vector (7 downto 0);
\r
23 pi_ppu_scroll_y : in std_logic_vector (7 downto 0);
\r
26 po_v_ce_n : out std_logic;
\r
27 po_v_rd_n : out std_logic;
\r
28 po_v_wr_n : out std_logic;
\r
29 po_v_addr : out std_logic_vector (13 downto 0);
\r
30 pi_v_data : in std_logic_vector (7 downto 0);
\r
33 po_plt_ce_n : out std_logic;
\r
34 po_plt_rd_n : out std_logic;
\r
35 po_plt_wr_n : out std_logic;
\r
36 po_plt_addr : out std_logic_vector (4 downto 0);
\r
37 pi_plt_data : in std_logic_vector (7 downto 0);
\r
40 po_spr_ce_n : out std_logic;
\r
41 po_spr_rd_n : out std_logic;
\r
42 po_spr_wr_n : out std_logic;
\r
43 po_spr_addr : out std_logic_vector (7 downto 0);
\r
44 pi_spr_data : in std_logic_vector (7 downto 0);
\r
47 po_h_sync_n : out std_logic;
\r
48 po_v_sync_n : out std_logic;
\r
49 po_r : out std_logic_vector(3 downto 0);
\r
50 po_g : out std_logic_vector(3 downto 0);
\r
51 po_b : out std_logic_vector(3 downto 0)
\r
55 architecture rtl of render is
\r
57 --secondary oam ram.
\r
59 generic (abus_size : integer := 16; dbus_size : integer := 8);
\r
61 pi_base_clk : in std_logic;
\r
62 pi_ce_n : in std_logic;
\r
63 pi_oe_n : in std_logic;
\r
64 pi_we_n : in std_logic;
\r
65 pi_addr : in std_logic_vector (abus_size - 1 downto 0);
\r
66 pio_d_io : inout std_logic_vector (dbus_size - 1 downto 0)
\r
70 --------- VGA screen constant -----------
\r
71 constant VGA_W : integer := 640;
\r
72 constant VGA_H : integer := 480;
\r
73 constant VGA_W_MAX : integer := 800;
\r
74 constant VGA_H_MAX : integer := 525;
\r
75 constant H_SYNC_S : integer := 660;
\r
76 constant H_SYNC_E : integer := 756;
\r
77 constant V_SYNC_S : integer := 494;
\r
78 constant V_SYNC_E : integer := 495;
\r
80 --nes screen size is emulated to align with the vga timing...
\r
81 constant HSCAN : integer := 256;
\r
82 constant VSCAN : integer := 240;
\r
83 constant HSCAN_NEXT_START : integer := 382;
\r
84 constant VSCAN_NEXT_START : integer := 262;
\r
85 constant HSCAN_SPR_MAX : integer := 321;
\r
86 constant HSCAN_OAM_EVA_START : integer := 64;
\r
88 constant PREFETCH_INT : integer := 16;
\r
90 constant PPUBNA : integer := 1; --base name address
\r
91 constant PPUVAI : integer := 2; --vram address increment
\r
92 constant PPUSPA : integer := 3; --sprite pattern table address
\r
93 constant PPUBPA : integer := 4; --background pattern table address
\r
94 constant PPUSPS : integer := 5; --sprite size
\r
95 constant PPUMS : integer := 6; --ppu master/slave
\r
96 constant PPUNEN : integer := 7; --nmi enable
\r
98 constant PPUGS : integer := 0; --grayscale
\r
99 constant PPUSBL : integer := 1; --show 8 left most bg pixel
\r
100 constant PPUSSL : integer := 2; --show 8 left most sprite pixel
\r
101 constant PPUSBG : integer := 3; --show bg
\r
102 constant PPUSSP : integer := 4; --show sprie
\r
103 constant PPUIR : integer := 5; --intensify red
\r
104 constant PPUIG : integer := 6; --intensify green
\r
105 constant PPUIB : integer := 7; --intensify blue
\r
107 constant SPRHFL : integer := 6; --flip sprigte horizontally
\r
108 constant SPRVFL : integer := 7; --flip sprigte vertically
\r
110 constant ST_BSY : integer := 4; --vram busy
\r
111 constant ST_SOF : integer := 5; --sprite overflow
\r
112 constant ST_SP0 : integer := 6; --sprite 0 hits
\r
113 constant ST_VBL : integer := 7; --vblank
\r
116 subtype nes_color_data is std_logic_vector (11 downto 0);
\r
117 type nes_color_array is array (0 to 63) of nes_color_data;
\r
118 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
\r
119 constant nes_color_palette : nes_color_array := (
\r
120 conv_std_logic_vector(16#777#, 12),
\r
121 conv_std_logic_vector(16#20b#, 12),
\r
122 conv_std_logic_vector(16#20b#, 12),
\r
123 conv_std_logic_vector(16#61a#, 12),
\r
124 conv_std_logic_vector(16#927#, 12),
\r
125 conv_std_logic_vector(16#b13#, 12),
\r
126 conv_std_logic_vector(16#a30#, 12),
\r
127 conv_std_logic_vector(16#740#, 12),
\r
128 conv_std_logic_vector(16#450#, 12),
\r
129 conv_std_logic_vector(16#360#, 12),
\r
130 conv_std_logic_vector(16#360#, 12),
\r
131 conv_std_logic_vector(16#364#, 12),
\r
132 conv_std_logic_vector(16#358#, 12),
\r
133 conv_std_logic_vector(16#000#, 12),
\r
134 conv_std_logic_vector(16#000#, 12),
\r
135 conv_std_logic_vector(16#000#, 12),
\r
136 conv_std_logic_vector(16#bbb#, 12),
\r
137 conv_std_logic_vector(16#46f#, 12),
\r
138 conv_std_logic_vector(16#44f#, 12),
\r
139 conv_std_logic_vector(16#94f#, 12),
\r
140 conv_std_logic_vector(16#d4c#, 12),
\r
141 conv_std_logic_vector(16#d46#, 12),
\r
142 conv_std_logic_vector(16#e50#, 12),
\r
143 conv_std_logic_vector(16#c70#, 12),
\r
144 conv_std_logic_vector(16#880#, 12),
\r
145 conv_std_logic_vector(16#5a0#, 12),
\r
146 conv_std_logic_vector(16#4a1#, 12),
\r
147 conv_std_logic_vector(16#4a6#, 12),
\r
148 conv_std_logic_vector(16#49c#, 12),
\r
149 conv_std_logic_vector(16#000#, 12),
\r
150 conv_std_logic_vector(16#000#, 12),
\r
151 conv_std_logic_vector(16#000#, 12),
\r
152 conv_std_logic_vector(16#fff#, 12),
\r
153 conv_std_logic_vector(16#6af#, 12),
\r
154 conv_std_logic_vector(16#58f#, 12),
\r
155 conv_std_logic_vector(16#a7f#, 12),
\r
156 conv_std_logic_vector(16#f6f#, 12),
\r
157 conv_std_logic_vector(16#f6b#, 12),
\r
158 conv_std_logic_vector(16#f73#, 12),
\r
159 conv_std_logic_vector(16#fa0#, 12),
\r
160 conv_std_logic_vector(16#ed2#, 12),
\r
161 conv_std_logic_vector(16#9e0#, 12),
\r
162 conv_std_logic_vector(16#7f4#, 12),
\r
163 conv_std_logic_vector(16#7e9#, 12),
\r
164 conv_std_logic_vector(16#6de#, 12),
\r
165 conv_std_logic_vector(16#777#, 12),
\r
166 conv_std_logic_vector(16#000#, 12),
\r
167 conv_std_logic_vector(16#000#, 12),
\r
168 conv_std_logic_vector(16#fff#, 12),
\r
169 conv_std_logic_vector(16#9df#, 12),
\r
170 conv_std_logic_vector(16#abf#, 12),
\r
171 conv_std_logic_vector(16#cbf#, 12),
\r
172 conv_std_logic_vector(16#ebf#, 12),
\r
173 conv_std_logic_vector(16#fbe#, 12),
\r
174 conv_std_logic_vector(16#fcb#, 12),
\r
175 conv_std_logic_vector(16#fda#, 12),
\r
176 conv_std_logic_vector(16#ff9#, 12),
\r
177 conv_std_logic_vector(16#cf8#, 12),
\r
178 conv_std_logic_vector(16#afa#, 12),
\r
179 conv_std_logic_vector(16#afc#, 12),
\r
180 conv_std_logic_vector(16#aff#, 12),
\r
181 conv_std_logic_vector(16#aaa#, 12),
\r
182 conv_std_logic_vector(16#000#, 12),
\r
183 conv_std_logic_vector(16#000#, 12)
\r
186 function is_v_access (
\r
187 pm_sbg : in std_logic;
\r
188 pm_ssp : in std_logic;
\r
189 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
190 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
193 if ((pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
194 if ((pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START)) then
\r
195 if (pm_sbg = '1') then
\r
200 elsif ((pm_nes_x > HSCAN and pm_nes_x < HSCAN_SPR_MAX)) then
\r
201 if (pm_ssp = '1') then
\r
215 pm_sbg : in std_logic;
\r
216 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
217 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
220 if (pm_sbg = '1'and
\r
221 (pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START) and
\r
222 (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
229 function is_spr_pfetch (
\r
230 pm_ssp : in std_logic;
\r
231 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
232 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
233 ) return integer is
\r
235 if (pm_ssp = '1'and
\r
236 (pm_nes_x > HSCAN and pm_nes_x < HSCAN_SPR_MAX) and
\r
237 (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
244 function is_spr_cpy (
\r
245 pm_ssp : in std_logic;
\r
246 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
247 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
248 ) return integer is
\r
250 if (pm_ssp = '1' and
\r
251 (pm_nes_x > HSCAN and pm_nes_x < HSCAN_SPR_MAX) and
\r
252 (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
259 signal reg_vga_x : integer range 0 to VGA_W_MAX - 1;
\r
260 signal reg_vga_y : integer range 0 to VGA_H_MAX - 1;
\r
262 signal reg_nes_x : integer range 0 to VGA_W_MAX / 2 - 1;
\r
263 signal reg_nes_y : integer range 0 to VGA_W_MAX / 2 - 1;
\r
264 --prefech is wider by scroll reg size.
\r
265 signal reg_prf_x : integer range 0 to VGA_W_MAX / 2 + 256 - 1;
\r
266 signal reg_prf_y : integer range 0 to VGA_W_MAX / 2 + 256 - 1;
\r
268 type reg_status is (
\r
280 -------------bg registers.
\r
281 signal reg_v_cur_state : reg_status;
\r
282 signal reg_v_next_state : reg_status;
\r
284 signal reg_v_ce_n : std_logic;
\r
285 signal reg_v_rd_n : std_logic;
\r
286 signal reg_v_wr_n : std_logic;
\r
287 signal reg_v_addr : std_logic_vector (13 downto 0);
\r
288 signal reg_v_data : std_logic_vector (7 downto 0);
\r
290 signal reg_disp_nt : std_logic_vector (7 downto 0);
\r
291 signal reg_disp_attr : std_logic_vector (7 downto 0);
\r
292 signal reg_tmp_ptn_l : std_logic_vector (7 downto 0);
\r
293 signal reg_sft_ptn_l : std_logic_vector (15 downto 0);
\r
294 signal reg_sft_ptn_h : std_logic_vector (15 downto 0);
\r
296 signal reg_plt_ce_n : std_logic;
\r
297 signal reg_plt_rd_n : std_logic;
\r
298 signal reg_plt_wr_n : std_logic;
\r
299 signal reg_plt_addr : std_logic_vector (4 downto 0);
\r
300 signal reg_plt_data : std_logic_vector (7 downto 0);
\r
302 ---------------oam registers.
\r
304 signal reg_s_oam_cur_state : reg_status;
\r
305 signal reg_s_oam_next_state : reg_status;
\r
307 signal reg_s_oam_ce_n : std_logic;
\r
308 signal reg_s_oam_rd_n : std_logic;
\r
309 signal reg_s_oam_wr_n : std_logic;
\r
310 signal reg_s_oam_addr : std_logic_vector (4 downto 0);
\r
311 signal reg_s_oam_data : std_logic_vector (7 downto 0);
\r
312 signal wr_s_oam_data : std_logic_vector (7 downto 0);
\r
314 signal reg_p_oam_cpy_cnt : integer range 0 to 255;
\r
315 signal reg_s_oam_cpy_cnt : integer range 0 to 32;
\r
316 signal reg_spr_eval_cnt : integer range 0 to 3;
\r
318 signal reg_p_oam_ce_n : std_logic;
\r
319 signal reg_p_oam_rd_n : std_logic;
\r
320 signal reg_p_oam_wr_n : std_logic;
\r
321 signal reg_p_oam_addr : std_logic_vector (7 downto 0);
\r
323 --sprite display register.
\r
324 type oam_reg_array is array (0 to 7) of std_logic_vector (7 downto 0);
\r
326 signal reg_spr_y_tmp : std_logic_vector (7 downto 0);
\r
327 signal reg_spr_tile_tmp : std_logic_vector (7 downto 0);
\r
328 signal reg_spr_attr : oam_reg_array;
\r
329 signal reg_spr_x : oam_reg_array;
\r
331 signal reg_spr_ptn_sft_start : std_logic_vector (7 downto 0);
\r
332 signal reg_spr_ptn_l : oam_reg_array;
\r
333 signal reg_spr_ptn_h : oam_reg_array;
\r
334 signal reg_spr_hit : std_logic;
\r
337 signal reg_ppu_status : std_logic_vector (7 downto 0);
\r
342 --position and sync signal generate.
\r
343 pos_p : process (pi_rst_n, pi_base_clk)
\r
345 if (pi_rst_n = '0') then
\r
352 elsif (rising_edge(pi_base_clk)) then
\r
353 if ((pi_rnd_en(0) or pi_rnd_en(2))= '1') then
\r
354 if (reg_vga_x = VGA_W_MAX - 1) then
\r
357 if (reg_vga_y = VGA_H_MAX - 1) then
\r
361 reg_vga_y <= reg_vga_y + 1;
\r
362 reg_nes_y <= (reg_vga_y + 1) / 2;
\r
365 reg_vga_x <= reg_vga_x + 1;
\r
366 reg_nes_x <= (reg_vga_x + 1) / 2;
\r
369 --sync signal assert.
\r
370 if (reg_vga_x >= H_SYNC_S and reg_vga_x < H_SYNC_E) then
\r
371 po_h_sync_n <= '0';
\r
373 po_h_sync_n <= '1';
\r
376 if (reg_vga_y >= V_SYNC_S and reg_vga_y < V_SYNC_E) then
\r
377 po_v_sync_n <= '0';
\r
379 po_v_sync_n <= '1';
\r
381 end if;--if (pi_rnd_en(1) = '1' or pi_rnd_en(3) = '1' ) then
\r
383 --pre-fetch x/y position...
\r
384 if (reg_vga_x < HSCAN_NEXT_START * 2) then
\r
385 reg_prf_x <= reg_vga_x / 2 + conv_integer(pi_ppu_scroll_x) + PREFETCH_INT;
\r
387 reg_prf_x <= reg_vga_x / 2 + conv_integer(pi_ppu_scroll_x)
\r
388 - HSCAN_NEXT_START + PREFETCH_INT;
\r
391 if (reg_vga_y < VSCAN * 2) then
\r
392 if (reg_vga_x < HSCAN_NEXT_START * 2) then
\r
393 reg_prf_y <= reg_vga_y / 2 + conv_integer(pi_ppu_scroll_y);
\r
395 reg_prf_y <= (reg_vga_y + 1) / 2 + conv_integer(pi_ppu_scroll_y);
\r
400 end if;--if (pi_rst_n = '0') then
\r
403 --state transition process...
\r
404 set_stat_p : process (pi_rst_n, pi_base_clk)
\r
406 if (pi_rst_n = '0') then
\r
407 reg_s_oam_cur_state <= IDLE;
\r
408 reg_v_cur_state <= IDLE;
\r
409 elsif (rising_edge(pi_base_clk)) then
\r
410 reg_v_cur_state <= reg_v_next_state;
\r
411 reg_s_oam_cur_state <= reg_s_oam_next_state;
\r
412 end if;--if (pi_rst_n = '0') then
\r
415 --state change to next.
\r
416 vac_next_stat_p : process (reg_v_cur_state, pi_rnd_en, pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y)
\r
418 case reg_v_cur_state is
\r
420 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1 and
\r
421 pi_rnd_en(2) = '1' and
\r
422 reg_nes_x mod 8 = 0) then
\r
423 --start vram access process.
\r
424 reg_v_next_state <= AD_SET0;
\r
426 reg_v_next_state <= reg_v_cur_state;
\r
429 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
430 reg_v_next_state <= AD_SET1;
\r
432 reg_v_next_state <= IDLE;
\r
435 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
436 reg_v_next_state <= AD_SET2;
\r
438 reg_v_next_state <= IDLE;
\r
441 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
442 reg_v_next_state <= AD_SET3;
\r
444 reg_v_next_state <= IDLE;
\r
447 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
448 reg_v_next_state <= REG_SET0;
\r
450 reg_v_next_state <= IDLE;
\r
453 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
454 reg_v_next_state <= REG_SET1;
\r
456 reg_v_next_state <= IDLE;
\r
459 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
460 reg_v_next_state <= REG_SET2;
\r
462 reg_v_next_state <= IDLE;
\r
465 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
466 reg_v_next_state <= REG_SET3;
\r
468 reg_v_next_state <= IDLE;
\r
471 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
472 reg_v_next_state <= AD_SET0;
\r
474 reg_v_next_state <= IDLE;
\r
479 po_v_ce_n <= reg_v_ce_n;
\r
480 po_v_rd_n <= reg_v_rd_n;
\r
481 po_v_wr_n <= reg_v_wr_n;
\r
482 po_v_addr <= reg_v_addr;
\r
484 --vram r/w selector state machine...
\r
485 vram_ac_select_p : process (reg_v_cur_state)
\r
487 case reg_v_cur_state is
\r
492 when AD_SET0 | AD_SET1 | REG_SET2 | REG_SET3 =>
\r
496 when AD_SET2 | AD_SET3 | REG_SET0 | REG_SET1 =>
\r
503 --vram address state machine...
\r
504 vaddr_stat_p : process (pi_rst_n, pi_base_clk)
\r
506 if (pi_rst_n = '0') then
\r
507 reg_v_addr <= (others => 'Z');
\r
508 reg_v_data <= (others => 'Z');
\r
509 reg_disp_nt <= (others => 'Z');
\r
510 reg_disp_attr <= (others => 'Z');
\r
511 elsif (rising_edge(pi_base_clk)) then
\r
512 reg_v_data <= pi_v_data;
\r
515 if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then
\r
516 ----fetch next tile byte.
\r
517 if (reg_prf_x mod 8 = 1) then
\r
518 --vram addr is incremented every 8 cycle.
\r
519 --name table at 0x2000
\r
520 reg_v_addr(9 downto 0)
\r
521 <= conv_std_logic_vector(reg_prf_y, 9)(7 downto 3)
\r
522 & conv_std_logic_vector(reg_prf_x, 9)(7 downto 3);
\r
523 reg_v_addr(13 downto 10) <= "10" & pi_ppu_ctrl(PPUBNA downto 0)
\r
524 + ("000" & conv_std_logic_vector(reg_prf_x, 9)(8));
\r
526 elsif (reg_prf_x mod 8 = 2 and reg_v_cur_state = REG_SET1) then
\r
527 reg_disp_nt <= reg_v_data;
\r
529 ----fetch attr table byte.
\r
530 elsif (reg_prf_x mod 8 = 3) then
\r
531 --attr table at 0x23c0
\r
532 reg_v_addr(7 downto 0) <= "11000000" +
\r
533 ("00" & conv_std_logic_vector(reg_prf_y, 9)(7 downto 5)
\r
534 & conv_std_logic_vector(reg_prf_x, 9)(7 downto 5));
\r
535 reg_v_addr(13 downto 8) <= "10" &
\r
536 pi_ppu_ctrl(PPUBNA downto 0) & "11"
\r
537 + ("000" & conv_std_logic_vector(reg_prf_x, 9)(8) & "00");
\r
539 elsif (reg_prf_x mod 8 = 4 and reg_v_cur_state = REG_SET1) then
\r
540 reg_disp_attr <= reg_v_data;
\r
542 ----fetch pattern table low byte.
\r
543 --pattern table at 0x0000
\r
544 elsif (reg_prf_x mod 8 = 5) then
\r
545 --vram addr is incremented every 8 cycle.
\r
546 reg_v_addr <= "0" & pi_ppu_ctrl(PPUBPA) &
\r
547 reg_disp_nt(7 downto 0)
\r
548 & "0" & conv_std_logic_vector(reg_prf_y, 9)(2 downto 0);
\r
550 ----fetch pattern table high byte.
\r
551 elsif (reg_prf_x mod 8 = 7) then
\r
552 --vram addr is incremented every 8 cycle.
\r
553 reg_v_addr <= "0" & pi_ppu_ctrl(PPUBPA) &
\r
554 reg_disp_nt(7 downto 0)
\r
555 & "1" & conv_std_logic_vector(reg_prf_y, 9)(2 downto 0);
\r
558 --sprite pattern fetch.
\r
559 --TODO: must take it into consideration, reg_nes_y = 262 case.
\r
560 elsif (is_spr_pfetch(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
561 ----fetch pattern table low byte.
\r
562 if (reg_nes_x mod 8 = 5) then
\r
563 if (reg_spr_attr((reg_nes_x - 256) / 8)(SPRVFL) = '0') then
\r
564 reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) &
\r
565 reg_spr_tile_tmp & "0" &
\r
566 (conv_std_logic_vector(reg_nes_y, 3) - reg_spr_y_tmp(2 downto 0) + "001");
\r
568 --flip sprite vertically.
\r
569 reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) &
\r
570 reg_spr_tile_tmp & "0" &
\r
571 (reg_spr_y_tmp(2 downto 0) - conv_std_logic_vector(reg_nes_y, 3) + "110");
\r
574 ----fetch pattern table high byte.
\r
575 elsif (reg_nes_x mod 8 = 7) then
\r
576 if (reg_spr_attr((reg_nes_x - 256) / 8)(SPRVFL) = '0') then
\r
577 reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) &
\r
578 reg_spr_tile_tmp & "1" &
\r
579 (conv_std_logic_vector(reg_nes_y, 3) - reg_spr_y_tmp(2 downto 0) + "001");
\r
581 --flip sprite vertically.
\r
582 reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) &
\r
583 reg_spr_tile_tmp & "1" &
\r
584 (reg_spr_y_tmp(2 downto 0) - conv_std_logic_vector(reg_nes_y, 3) + "110");
\r
588 reg_v_addr <= (others => 'Z');
\r
589 reg_v_data <= (others => 'Z');
\r
591 end if;--if (pi_rst_n = '0') then
\r
594 --pattern table state machine...
\r
595 bg_ptn_p : process (pi_rst_n, pi_base_clk)
\r
597 if (pi_rst_n = '0') then
\r
598 reg_tmp_ptn_l <= (others => '0');
\r
599 reg_sft_ptn_l <= (others => '0');
\r
600 reg_sft_ptn_h <= (others => '0');
\r
601 elsif (rising_edge(pi_base_clk)) then
\r
603 if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then
\r
605 if (reg_prf_x mod 8 = 6 and reg_v_cur_state = REG_SET1) then
\r
606 --TODO: must reverse order if attr not set.
\r
607 reg_tmp_ptn_l <= reg_v_data;
\r
610 if (reg_prf_x mod 8 = 0) then
\r
611 if (reg_v_cur_state = REG_SET1) then
\r
612 --copy low & shift.
\r
613 reg_sft_ptn_l <= reg_tmp_ptn_l & reg_sft_ptn_l(8 downto 1);
\r
614 --fetch high & shift.
\r
615 --TODO: must reverse order if attr not set.
\r
616 reg_sft_ptn_h <= reg_v_data & reg_sft_ptn_h(8 downto 1);
\r
619 if (reg_v_cur_state = AD_SET1 or reg_v_cur_state = REG_SET1) then
\r
620 reg_sft_ptn_l <= "0" & reg_sft_ptn_l(15 downto 1);
\r
621 reg_sft_ptn_h <= "0" & reg_sft_ptn_h(15 downto 1);
\r
625 end if;--if (pi_rst_n = '0') then
\r
628 po_plt_ce_n <= reg_plt_ce_n;
\r
629 po_plt_rd_n <= reg_plt_rd_n;
\r
630 po_plt_wr_n <= reg_plt_wr_n;
\r
631 po_plt_addr <= reg_plt_addr;
\r
633 --palette table state machine...
\r
634 plt_ac_p : process (pi_rst_n, pi_base_clk)
\r
635 --spr_i: 0 - 7 is the sprite display number.
\r
636 -- 8 is sprite in the back.
\r
637 -- 9 is sprite in front.
\r
638 variable spr_i : integer range 0 to 9;
\r
641 pm_sbg : in std_logic;
\r
642 pm_ssp : in std_logic;
\r
643 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
644 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
645 ) return integer is
\r
647 if ((pm_sbg = '1' or pm_ssp = '1') and pm_nes_x < HSCAN and pm_nes_y < VSCAN) then
\r
654 procedure get_visible_sprite (
\r
655 pm_ssp : in std_logic
\r
658 if (pm_ssp = '1') then
\r
659 if (reg_spr_x(0) = "00000000" and
\r
660 (reg_spr_ptn_h(0)(0) or reg_spr_ptn_l(0)(0)) = '1' ) then
\r
662 elsif (reg_spr_x(1) = "00000000" and
\r
663 (reg_spr_ptn_h(1)(0) or reg_spr_ptn_l(1)(0)) = '1' ) then
\r
665 elsif (reg_spr_x(2) = "00000000" and
\r
666 (reg_spr_ptn_h(2)(0) or reg_spr_ptn_l(2)(0)) = '1' ) then
\r
668 elsif (reg_spr_x(3) = "00000000" and
\r
669 (reg_spr_ptn_h(3)(0) or reg_spr_ptn_l(3)(0)) = '1' ) then
\r
671 elsif (reg_spr_x(4) = "00000000" and
\r
672 (reg_spr_ptn_h(4)(0) or reg_spr_ptn_l(4)(0)) = '1' ) then
\r
674 elsif (reg_spr_x(5) = "00000000" and
\r
675 (reg_spr_ptn_h(5)(0) or reg_spr_ptn_l(5)(0)) = '1' ) then
\r
677 elsif (reg_spr_x(6) = "00000000" and
\r
678 (reg_spr_ptn_h(6)(0) or reg_spr_ptn_l(6)(0)) = '1' ) then
\r
680 elsif (reg_spr_x(7) = "00000000" and
\r
681 (reg_spr_ptn_h(7)(0) or reg_spr_ptn_l(7)(0)) = '1' ) then
\r
692 if (pi_rst_n = '0') then
\r
693 reg_plt_ce_n <= 'Z';
\r
694 reg_plt_rd_n <= 'Z';
\r
695 reg_plt_wr_n <= 'Z';
\r
697 reg_plt_addr <= (others => 'Z');
\r
698 reg_plt_data <= (others => 'Z');
\r
699 reg_spr_hit <= '0';
\r
700 elsif (rising_edge(pi_base_clk)) then
\r
702 reg_plt_data <= pi_plt_data;
\r
703 --shift pattern propageted 1 cycle later.
\r
704 if (is_disp(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then
\r
705 reg_plt_ce_n <= '0';
\r
706 reg_plt_rd_n <= '0';
\r
707 reg_plt_wr_n <= '1';
\r
709 if (reg_v_cur_state = AD_SET2 or reg_v_cur_state = REG_SET2) then
\r
710 --check sprite pattern first.
\r
711 get_visible_sprite(pi_ppu_mask(PPUSSP));
\r
712 if (spr_i < 8) then
\r
715 "1" & reg_spr_attr(spr_i)(1 downto 0) & reg_spr_ptn_h(spr_i)(0) & reg_spr_ptn_l(spr_i)(0);
\r
716 --check sprite hit.
\r
717 if ((reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then
\r
718 reg_spr_hit <= '1';
\r
720 elsif (conv_std_logic_vector(reg_nes_y, 9)(4) = '0'
\r
721 and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then
\r
723 "0" & reg_disp_attr(1 downto 0) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);
\r
724 elsif (conv_std_logic_vector(reg_nes_y, 9)(4) = '1'
\r
725 and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then
\r
727 "0" & reg_disp_attr(5 downto 4) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);
\r
729 ---no output color >> universal bg color output.
\r
730 --0x3f00 is the universal bg palette.
\r
731 reg_plt_addr <= (others => '0');
\r
735 --reset sprite hit.
\r
736 reg_spr_hit <= '0';
\r
738 reg_plt_ce_n <= 'Z';
\r
739 reg_plt_rd_n <= 'Z';
\r
740 reg_plt_wr_n <= 'Z';
\r
741 reg_plt_addr <= (others => 'Z');
\r
742 reg_plt_data <= (others => 'Z');
\r
744 end if;--if (pi_rst_n = '0') then
\r
747 --vga output process...
\r
748 rgb_out_p : process (pi_rst_n, pi_base_clk)
\r
750 if (pi_rst_n = '0') then
\r
751 po_b <= (others => '0');
\r
752 po_g <= (others => '0');
\r
753 po_r <= (others => '0');
\r
755 if (rising_edge(pi_base_clk)) then
\r
756 if (reg_nes_x < HSCAN and reg_nes_y < VSCAN) then
\r
757 --if or if not bg/sprite is shown, output color anyway
\r
758 --sinse universal bg color is included..
\r
759 po_b <= nes_color_palette(conv_integer(reg_plt_data(5 downto 0))) (11 downto 8);
\r
760 po_g <= nes_color_palette(conv_integer(reg_plt_data(5 downto 0))) (7 downto 4);
\r
761 po_r <= nes_color_palette(conv_integer(reg_plt_data(5 downto 0))) (3 downto 0);
\r
763 po_b <= (others => '0');
\r
764 po_g <= (others => '0');
\r
765 po_r <= (others => '0');
\r
767 end if; --if (rising_edge(emu_ppu_clk)) then
\r
768 end if;--if (rst_n = '0') then
\r
769 end process;--output_p
\r
771 ---secondary oam ram inst.
\r
772 secondary_oam_inst : ram generic map (5, 8) port map (
\r
780 wr_s_oam_data <= reg_s_oam_data;
\r
783 --state change to next.
\r
784 s_oam_next_stat_p : process (reg_s_oam_cur_state, pi_rnd_en, pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y)
\r
785 function is_s_oam_access (
\r
786 pm_ssp : in std_logic;
\r
787 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
788 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
791 if ((pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
792 if (pm_nes_x < HSCAN_SPR_MAX) then
\r
793 if (pm_ssp = '1') then
\r
807 case reg_s_oam_cur_state is
\r
809 if (pi_ppu_mask(PPUSSP) = '1' and reg_nes_x = 0 and
\r
810 (reg_nes_y < VSCAN or reg_nes_y = VSCAN_NEXT_START) and
\r
811 pi_rnd_en(2) = '1') then
\r
812 --start sprite clear.
\r
813 reg_s_oam_next_state <= AD_SET0;
\r
815 reg_s_oam_next_state <= reg_s_oam_cur_state;
\r
818 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
819 reg_s_oam_next_state <= AD_SET1;
\r
821 reg_s_oam_next_state <= IDLE;
\r
824 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
825 reg_s_oam_next_state <= AD_SET2;
\r
827 reg_s_oam_next_state <= IDLE;
\r
830 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
831 reg_s_oam_next_state <= AD_SET3;
\r
833 reg_s_oam_next_state <= IDLE;
\r
836 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
837 reg_s_oam_next_state <= REG_SET0;
\r
839 reg_s_oam_next_state <= IDLE;
\r
842 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
843 reg_s_oam_next_state <= REG_SET1;
\r
845 reg_s_oam_next_state <= IDLE;
\r
848 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
849 reg_s_oam_next_state <= REG_SET2;
\r
851 reg_s_oam_next_state <= IDLE;
\r
854 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
855 reg_s_oam_next_state <= REG_SET3;
\r
857 reg_s_oam_next_state <= IDLE;
\r
860 if (is_s_oam_access(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
861 reg_s_oam_next_state <= AD_SET0;
\r
863 reg_s_oam_next_state <= IDLE;
\r
868 --sprite main process...
\r
870 po_spr_ce_n <= reg_p_oam_ce_n;
\r
871 po_spr_rd_n <= reg_p_oam_rd_n;
\r
872 po_spr_wr_n <= reg_p_oam_wr_n;
\r
873 po_spr_addr <= reg_p_oam_addr;
\r
875 sprite_eval_p : process (pi_rst_n, pi_base_clk)
\r
876 function is_s_oam_clear (
\r
877 pm_ssp : in std_logic;
\r
878 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
879 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
880 ) return integer is
\r
882 if (pm_ssp = '0' or
\r
883 (pm_nes_x > HSCAN_OAM_EVA_START) or
\r
884 (pm_nes_y >= VSCAN and pm_nes_y < VSCAN_NEXT_START)) then
\r
891 function is_spr_eval (
\r
892 pm_ssp : in std_logic;
\r
893 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
894 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
895 ) return integer is
\r
897 if (pm_ssp = '1' and
\r
898 (pm_nes_x >= HSCAN_OAM_EVA_START and pm_nes_x <= HSCAN) and
\r
899 (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then
\r
907 if (pi_rst_n = '0') then
\r
908 ---secondary oam ram
\r
909 reg_s_oam_ce_n <= '1';
\r
910 reg_s_oam_rd_n <= '1';
\r
911 reg_s_oam_wr_n <= '1';
\r
912 reg_s_oam_data <= (others => 'Z');
\r
913 reg_s_oam_addr <= (others => '0');
\r
914 reg_s_oam_cpy_cnt <= 0;
\r
915 reg_p_oam_cpy_cnt <= 0;
\r
918 reg_p_oam_ce_n <= 'Z';
\r
919 reg_p_oam_rd_n <= 'Z';
\r
920 reg_p_oam_wr_n <= 'Z';
\r
921 reg_p_oam_addr <= (others => 'Z');
\r
923 reg_spr_y_tmp <= (others => '0');
\r
924 reg_spr_tile_tmp <= (others => '0');
\r
925 for i in 0 to 7 loop
\r
926 reg_spr_attr(i) <= (others => '0');
\r
929 if (rising_edge(pi_base_clk)) then
\r
930 if (is_s_oam_clear(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
931 --fill s_oam with FF.
\r
932 reg_s_oam_data <= (others => '1');
\r
933 reg_s_oam_rd_n <= '1';
\r
934 if (reg_s_oam_cur_state = AD_SET0) then
\r
935 reg_s_oam_ce_n <= '0';
\r
936 reg_s_oam_wr_n <= '1';
\r
937 elsif (reg_s_oam_cur_state = REG_SET0) then
\r
938 reg_s_oam_wr_n <= '0';
\r
939 elsif (reg_s_oam_cur_state = REG_SET1) then
\r
940 reg_s_oam_wr_n <= '1';
\r
941 elsif (reg_s_oam_cur_state = REG_SET3) then
\r
942 reg_s_oam_addr <= reg_s_oam_addr + 1;
\r
945 --init primary oam.
\r
946 reg_p_oam_ce_n <= '1';
\r
947 reg_p_oam_rd_n <= '1';
\r
948 reg_p_oam_wr_n <= '1';
\r
949 reg_p_oam_addr <= (others => '0');
\r
950 reg_s_oam_cpy_cnt <= 0;
\r
951 reg_p_oam_cpy_cnt <= 0;
\r
952 reg_spr_eval_cnt <= 0;
\r
953 elsif (is_spr_eval(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
954 --copy data from primary oam ram.
\r
955 reg_s_oam_addr <= conv_std_logic_vector(reg_s_oam_cpy_cnt, 5);
\r
956 reg_s_oam_data <= pi_spr_data;
\r
957 reg_s_oam_rd_n <= '1';
\r
959 reg_p_oam_ce_n <= '0';
\r
960 reg_p_oam_rd_n <= '0';
\r
961 reg_p_oam_wr_n <= '1';
\r
962 reg_p_oam_addr <= conv_std_logic_vector(reg_p_oam_cpy_cnt, 8);
\r
964 if (reg_s_oam_cpy_cnt < 32) then
\r
965 if (reg_s_oam_cur_state = AD_SET0) then
\r
966 reg_s_oam_ce_n <= '0';
\r
967 reg_s_oam_wr_n <= '1';
\r
968 elsif (reg_s_oam_cur_state = REG_SET0) then
\r
969 reg_s_oam_ce_n <= '0';
\r
970 reg_s_oam_wr_n <= '0';
\r
971 elsif (reg_s_oam_cur_state = REG_SET1) then
\r
972 reg_s_oam_ce_n <= '1';
\r
973 reg_s_oam_wr_n <= '1';
\r
974 if (reg_spr_eval_cnt = 0 and
\r
975 (pi_spr_data - 1 <= reg_nes_y and reg_nes_y < pi_spr_data + 7)) then
\r
976 --evaluate and found sprite in the range.
\r
978 reg_s_oam_cpy_cnt <= reg_s_oam_cpy_cnt + 1;
\r
979 reg_p_oam_cpy_cnt <= reg_p_oam_cpy_cnt + 1;
\r
980 reg_spr_eval_cnt <= reg_spr_eval_cnt + 1;
\r
981 elsif (reg_spr_eval_cnt = 0) then
\r
982 --sprite not hit. next entry.
\r
983 reg_p_oam_cpy_cnt <= reg_p_oam_cpy_cnt + 4;
\r
986 reg_s_oam_cpy_cnt <= reg_s_oam_cpy_cnt + 1;
\r
987 reg_p_oam_cpy_cnt <= reg_p_oam_cpy_cnt + 1;
\r
988 if (reg_spr_eval_cnt = 3) then
\r
989 reg_spr_eval_cnt <= 0;
\r
991 reg_spr_eval_cnt <= reg_spr_eval_cnt + 1;
\r
996 elsif (is_spr_cpy(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
997 --release p-oam access.
\r
998 reg_p_oam_ce_n <= '1';
\r
999 reg_p_oam_rd_n <= '1';
\r
1000 reg_p_oam_wr_n <= '1';
\r
1001 reg_p_oam_addr <= (others => '0');
\r
1003 --copy s-oam to sprite register.
\r
1004 --257 to 320 = (1 to 64) & 256
\r
1005 -->(1 to 64) / 2 & 256.
\r
1006 reg_s_oam_ce_n <= '0';
\r
1007 reg_s_oam_addr <= conv_std_logic_vector((reg_nes_x - 256) / 2, 5);
\r
1008 reg_s_oam_data <= (others => 'Z');
\r
1009 reg_s_oam_wr_n <= '1';
\r
1010 reg_s_oam_rd_n <= '0';
\r
1011 if (reg_s_oam_cur_state = REG_SET1) then
\r
1012 if (reg_nes_x mod 8 = 2) then
\r
1013 reg_spr_y_tmp <= wr_s_oam_data;
\r
1014 elsif (reg_nes_x mod 8 = 4) then
\r
1015 reg_spr_tile_tmp <= wr_s_oam_data;
\r
1016 elsif (reg_nes_x mod 8 = 6) then
\r
1017 reg_spr_attr((reg_nes_x - 256) / 8) <= wr_s_oam_data;
\r
1021 elsif (is_spr_pfetch(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
1022 --release s-oam access.
\r
1023 reg_s_oam_ce_n <= '1';
\r
1024 reg_s_oam_addr <= (others => 'Z');
\r
1025 reg_s_oam_data <= (others => 'Z');
\r
1026 reg_s_oam_wr_n <= '1';
\r
1027 reg_s_oam_rd_n <= '1';
\r
1029 reg_s_oam_ce_n <= '1';
\r
1030 reg_s_oam_rd_n <= '1';
\r
1031 reg_s_oam_wr_n <= '1';
\r
1032 reg_s_oam_data <= (others => 'Z');
\r
1033 reg_s_oam_addr <= (others => '0');
\r
1034 reg_s_oam_cpy_cnt <= 0;
\r
1036 reg_p_oam_ce_n <= 'Z';
\r
1037 reg_p_oam_rd_n <= 'Z';
\r
1038 reg_p_oam_wr_n <= 'Z';
\r
1039 reg_p_oam_addr <= (others => 'Z');
\r
1041 end if; --if (rising_edge(emu_ppu_clk)) then
\r
1042 end if;--if (rst_n = '0') then
\r
1045 --sprite pattern data process.
\r
1046 sprite_ptn_p : process (pi_rst_n, pi_base_clk)
\r
1048 function is_spr_disp (
\r
1049 pm_ssp : in std_logic;
\r
1050 pm_nes_x : in integer range 0 to VGA_W_MAX - 1;
\r
1051 pm_nes_y : in integer range 0 to VGA_H_MAX - 1
\r
1052 ) return integer is
\r
1054 if (pm_ssp = '1' and pm_nes_x < HSCAN and pm_nes_y < VSCAN) then
\r
1062 if (pi_rst_n = '0') then
\r
1063 reg_spr_ptn_sft_start <= (others => '0');
\r
1064 for i in 0 to 7 loop
\r
1065 reg_spr_x(i) <= (others => '0');
\r
1066 reg_spr_ptn_l(i) <= (others => '0');
\r
1067 reg_spr_ptn_h(i) <= (others => '0');
\r
1070 if (rising_edge(pi_base_clk)) then
\r
1071 if (is_spr_cpy(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
1072 if (reg_s_oam_cur_state = REG_SET1) then
\r
1073 if (reg_nes_x mod 8 = 0) then
\r
1074 reg_spr_x((reg_nes_x - 256) / 8 - 1) <= wr_s_oam_data;
\r
1078 --sprite pattern is read from vram.
\r
1079 if (reg_s_oam_cur_state = REG_SET1) then
\r
1080 if (reg_nes_x mod 8 = 6) then
\r
1081 reg_spr_ptn_l((reg_nes_x - 256) / 8) <= pi_v_data;
\r
1082 elsif (reg_nes_x mod 8 = 0) then
\r
1083 reg_spr_ptn_h((reg_nes_x - 256) / 8 - 1) <= pi_v_data;
\r
1087 elsif (is_spr_disp(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
1088 --sprite pattern shift.
\r
1089 if (reg_s_oam_cur_state = AD_SET0 or reg_s_oam_cur_state = REG_SET0) then
\r
1090 for i in 0 to 7 loop
\r
1091 if (reg_spr_ptn_sft_start(i) = '1') then
\r
1093 reg_spr_ptn_l(i) <= "0" & reg_spr_ptn_l(i)(7 downto 1);
\r
1094 reg_spr_ptn_h(i) <= "0" & reg_spr_ptn_h(i)(7 downto 1);
\r
1096 if (reg_spr_x(i) = "00000000") then
\r
1097 reg_spr_ptn_sft_start(i) <= '1';
\r
1099 reg_spr_x(i) <= reg_spr_x(i) - 1;
\r
1105 reg_spr_ptn_sft_start <= (others => '0');
\r
1107 end if; --if (rising_edge(emu_ppu_clk)) then
\r
1108 end if;--if (rst_n = '0') then
\r
1111 po_ppu_status <= reg_ppu_status;
\r
1113 --status register set.
\r
1114 status_p : process (pi_rst_n, pi_base_clk)
\r
1116 if (pi_rst_n = '0') then
\r
1117 reg_ppu_status <= (others => '0');
\r
1119 if (rising_edge(pi_base_clk)) then
\r
1120 --avoid latches...
\r
1121 reg_ppu_status(3 downto 0) <= (others => '0');
\r
1122 --TODO: sprite overflow is not inplemented!
\r
1123 reg_ppu_status(ST_SOF) <= '0';
\r
1125 --ppu busy flag set. not sure this complies the nes spec...
\r
1126 if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then
\r
1127 reg_ppu_status(ST_BSY) <= '1';
\r
1129 reg_ppu_status(ST_BSY) <= '0';
\r
1132 --sprite 0 hit set.
\r
1133 if (reg_nes_y = VSCAN_NEXT_START - 1) then
\r
1134 reg_ppu_status(ST_SP0) <= '0';
\r
1136 reg_ppu_status(ST_SP0) <= reg_spr_hit;
\r
1139 if (reg_nes_y > VSCAN and reg_nes_y < VSCAN_NEXT_START) then
\r
1141 reg_ppu_status(ST_VBL) <= '1';
\r
1144 reg_ppu_status(ST_VBL) <= '0';
\r
1146 end if; --if (rising_edge(emu_ppu_clk)) then
\r
1147 end if;--if (rst_n = '0') then
\r