OSDN Git Service

sprite pix processing ok!!!
[motonesfpga/motonesfpga.git] / de0_cv_nes / ppu / render.vhd
1 -------------------------------------------------------------\r
2 -------------------------------------------------------------\r
3 ------------------- PPU VGA Output Control ------------------\r
4 -------------------------------------------------------------\r
5 -------------------------------------------------------------\r
6 library ieee;\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
11 \r
12 entity render is \r
13     port (\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
17 \r
18         --ppu i/f\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
24 \r
25         --vram i/f\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
31 \r
32         --plt i/f\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
38 \r
39         --sprite i/f\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
45 \r
46         --vga output\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
52         );\r
53 end render;\r
54 \r
55 architecture rtl of render is\r
56 \r
57 --secondary oam ram.\r
58 component ram\r
59     generic (abus_size : integer := 16; dbus_size : integer := 8);\r
60     port (\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
67         );\r
68 end component;\r
69 \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
79 \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
87 \r
88 constant PREFETCH_INT           : integer := 16;\r
89 \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
97 \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
106 \r
107 constant SPRHFL     : integer := 6;  --flip sprigte horizontally\r
108 constant SPRVFL     : integer := 7;  --flip sprigte vertically\r
109 \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
114 \r
115 \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
184         );\r
185 \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
191     )return integer is\r
192 begin\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
196                 return 1;\r
197             else\r
198                 return 0;\r
199             end if;\r
200         elsif ((pm_nes_x > HSCAN and pm_nes_x < HSCAN_SPR_MAX)) then\r
201             if (pm_ssp = '1') then\r
202                 return 1;\r
203             else\r
204                 return 0;\r
205             end if;\r
206         else\r
207             return 0;\r
208         end if;\r
209     else\r
210         return 0;\r
211     end if;\r
212 end;\r
213 \r
214 function is_bg (\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
218     )return integer is\r
219 begin\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
223         return 1;\r
224     else\r
225         return 0;\r
226     end if;\r
227 end;\r
228 \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
234 begin\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
238         return 1;\r
239     else\r
240         return 0;\r
241     end if;\r
242 end;\r
243 \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
249 begin\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
253         return 1;\r
254     else\r
255         return 0;\r
256     end if;\r
257 end;\r
258 \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
261 \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
267 \r
268 type reg_status is (\r
269     IDLE,\r
270     AD_SET0,\r
271     AD_SET1,\r
272     AD_SET2,\r
273     AD_SET3,\r
274     REG_SET0,\r
275     REG_SET1,\r
276     REG_SET2,\r
277     REG_SET3\r
278     );\r
279 \r
280 -------------bg registers.\r
281 signal reg_v_cur_state      : reg_status;\r
282 signal reg_v_next_state     : reg_status;\r
283 \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
289 \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
295 \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
301 \r
302 ---------------oam registers.\r
303 \r
304 signal reg_s_oam_cur_state      : reg_status;\r
305 signal reg_s_oam_next_state     : reg_status;\r
306 \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
313 \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
317 \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
322 \r
323 --sprite display register.\r
324 type oam_reg_array    is array (0 to 7) of std_logic_vector (7 downto 0);\r
325 \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
330 \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
335 \r
336 --status register.\r
337 signal reg_ppu_status       : std_logic_vector (7 downto 0);\r
338 \r
339 \r
340 begin\r
341 \r
342     --position and sync signal generate.\r
343     pos_p : process (pi_rst_n, pi_base_clk)\r
344     begin\r
345         if (pi_rst_n = '0') then\r
346             reg_vga_x <= 0;\r
347             reg_vga_y <= 0;\r
348             reg_nes_x <= 0;\r
349             reg_nes_y <= 0;\r
350             reg_prf_x <= 0;\r
351             reg_prf_y <= 0;\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
355                     reg_vga_x <= 0;\r
356                     reg_nes_x <= 0;\r
357                     if (reg_vga_y = VGA_H_MAX - 1) then\r
358                         reg_vga_y <= 0;\r
359                         reg_nes_y <= 0;\r
360                     else\r
361                         reg_vga_y <= reg_vga_y + 1;\r
362                         reg_nes_y <= (reg_vga_y + 1) / 2;\r
363                     end if;\r
364                 else\r
365                     reg_vga_x <= reg_vga_x + 1;\r
366                     reg_nes_x <= (reg_vga_x + 1) / 2;\r
367                 end if;\r
368 \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
372                 else\r
373                     po_h_sync_n <= '1';\r
374                 end if;\r
375 \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
378                 else\r
379                     po_v_sync_n <= '1';\r
380                 end if;\r
381             end if;--if (pi_rnd_en(1) = '1' or pi_rnd_en(3) = '1' ) then\r
382 \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
386             else\r
387                 reg_prf_x <= reg_vga_x / 2 + conv_integer(pi_ppu_scroll_x)\r
388                                 - HSCAN_NEXT_START + PREFETCH_INT;\r
389             end if;\r
390 \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
394                 else\r
395                     reg_prf_y <= (reg_vga_y + 1) / 2 + conv_integer(pi_ppu_scroll_y);\r
396                 end if;\r
397             else\r
398                 reg_prf_y <= 0;\r
399             end if;\r
400         end if;--if (pi_rst_n = '0') then\r
401     end process;\r
402 \r
403     --state transition process...\r
404     set_stat_p : process (pi_rst_n, pi_base_clk)\r
405     begin\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
413     end process;\r
414 \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
417     begin\r
418         case reg_v_cur_state is\r
419             when IDLE =>\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
425                 else\r
426                     reg_v_next_state <= reg_v_cur_state;\r
427                 end if;\r
428             when AD_SET0 =>\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
431                 else\r
432                     reg_v_next_state <= IDLE;\r
433                 end if;\r
434             when AD_SET1 =>\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
437                 else\r
438                     reg_v_next_state <= IDLE;\r
439                 end if;\r
440             when AD_SET2 =>\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
443                 else\r
444                     reg_v_next_state <= IDLE;\r
445                 end if;\r
446             when AD_SET3 =>\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
449                 else\r
450                     reg_v_next_state <= IDLE;\r
451                 end if;\r
452             when REG_SET0 =>\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
455                 else\r
456                     reg_v_next_state <= IDLE;\r
457                 end if;\r
458             when REG_SET1 =>\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
461                 else\r
462                     reg_v_next_state <= IDLE;\r
463                 end if;\r
464             when REG_SET2 =>\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
467                 else\r
468                     reg_v_next_state <= IDLE;\r
469                 end if;\r
470             when REG_SET3 =>\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
473                 else\r
474                     reg_v_next_state <= IDLE;\r
475                 end if;\r
476         end case;\r
477     end process;\r
478 \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
483 \r
484     --vram r/w selector state machine...\r
485     vram_ac_select_p : process (reg_v_cur_state)\r
486     begin\r
487         case reg_v_cur_state is\r
488             when IDLE =>\r
489                 reg_v_ce_n  <= 'Z';\r
490                 reg_v_rd_n  <= 'Z';\r
491                 reg_v_wr_n  <= 'Z';\r
492             when AD_SET0 | AD_SET1 | REG_SET2 | REG_SET3 =>\r
493                 reg_v_ce_n  <= '0';\r
494                 reg_v_rd_n  <= '1';\r
495                 reg_v_wr_n  <= '1';\r
496             when AD_SET2 | AD_SET3 | REG_SET0 | REG_SET1 =>\r
497                 reg_v_ce_n  <= '0';\r
498                 reg_v_rd_n  <= '0';\r
499                 reg_v_wr_n  <= '1';\r
500         end case;\r
501     end process;\r
502 \r
503     --vram address state machine...\r
504     vaddr_stat_p : process (pi_rst_n, pi_base_clk)\r
505     begin\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
513 \r
514             --bg vram fetch.\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
525                 \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
528                 \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
538                 \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
541 \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
549 \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
556                 end if;\r
557 \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
567                     else\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
572                     end if;\r
573 \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
580                     else\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
585                     end if;\r
586                 end if;\r
587             else\r
588                 reg_v_addr  <= (others => 'Z');\r
589                 reg_v_data    <= (others => 'Z');\r
590             end if;\r
591         end if;--if (pi_rst_n = '0') then\r
592     end process;\r
593 \r
594     --pattern table state machine...\r
595     bg_ptn_p : process (pi_rst_n, pi_base_clk)\r
596     begin\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
602 \r
603             if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
604                 --fetch low first.\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
608                 end if;\r
609 \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
617                     end if;\r
618                 else\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
622                     end if;\r
623                 end if;\r
624             end if;\r
625         end if;--if (pi_rst_n = '0') then\r
626     end process;\r
627 \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
632 \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
639 \r
640 function is_disp (\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
646 begin\r
647     if ((pm_sbg = '1' or pm_ssp = '1') and pm_nes_x < HSCAN and pm_nes_y < VSCAN) then\r
648         return 1;\r
649     else\r
650         return 0;\r
651     end if;\r
652 end;\r
653 \r
654 procedure get_visible_sprite (\r
655     pm_ssp          : in std_logic\r
656     ) is\r
657 begin\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
661             spr_i := 0;\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
664             spr_i := 1;\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
667             spr_i := 2;\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
670             spr_i := 3;\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
673             spr_i := 4;\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
676             spr_i := 5;\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
679             spr_i := 6;\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
682             spr_i := 7;\r
683         else\r
684             spr_i := 8;\r
685         end if;\r
686     else\r
687         spr_i := 8;\r
688     end if;\r
689 end;\r
690 \r
691     begin\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
696 \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
701             \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
708 \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
713                         --sprite display.\r
714                         reg_plt_addr <=\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
719                         end if;\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
722                         reg_plt_addr <=\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
726                         reg_plt_addr <=\r
727                                 "0" & reg_disp_attr(5 downto 4) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
728                     else\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
732                     end if;\r
733                 end if;\r
734             else\r
735                 --reset sprite hit.\r
736                 reg_spr_hit     <= '0';\r
737                 --release plt bus.\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
743             end if;\r
744         end if;--if (pi_rst_n = '0') then\r
745     end process;\r
746 \r
747     --vga output process...\r
748     rgb_out_p : process (pi_rst_n, pi_base_clk)\r
749     begin\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
754         else\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
762                 else\r
763                     po_b <= (others => '0');\r
764                     po_g <= (others => '0');\r
765                     po_r <= (others => '0');\r
766                 end if;\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
770 \r
771     ---secondary oam ram inst.\r
772     secondary_oam_inst : ram generic map (5, 8) port map (\r
773                             pi_base_clk,\r
774                             reg_s_oam_ce_n,\r
775                             reg_s_oam_rd_n,\r
776                             reg_s_oam_wr_n,\r
777                             reg_s_oam_addr,\r
778                             wr_s_oam_data\r
779                             );\r
780     wr_s_oam_data <= reg_s_oam_data;\r
781 \r
782 \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
789     )return integer is\r
790 begin\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
794                 return 1;\r
795             else\r
796                 return 0;\r
797             end if;\r
798         else\r
799             return 0;\r
800         end if;\r
801     else\r
802         return 0;\r
803     end if;\r
804 end;\r
805 \r
806     begin\r
807         case reg_s_oam_cur_state is\r
808             when IDLE =>\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
814                 else\r
815                     reg_s_oam_next_state <= reg_s_oam_cur_state;\r
816                 end if;\r
817             when AD_SET0 =>\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
820                 else\r
821                     reg_s_oam_next_state <= IDLE;\r
822                 end if;\r
823             when AD_SET1 =>\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
826                 else\r
827                     reg_s_oam_next_state <= IDLE;\r
828                 end if;\r
829             when AD_SET2 =>\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
832                 else\r
833                     reg_s_oam_next_state <= IDLE;\r
834                 end if;\r
835             when AD_SET3 =>\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
838                 else\r
839                     reg_s_oam_next_state <= IDLE;\r
840                 end if;\r
841             when REG_SET0 =>\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
844                 else\r
845                     reg_s_oam_next_state <= IDLE;\r
846                 end if;\r
847             when REG_SET1 =>\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
850                 else\r
851                     reg_s_oam_next_state <= IDLE;\r
852                 end if;\r
853             when REG_SET2 =>\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
856                 else\r
857                     reg_s_oam_next_state <= IDLE;\r
858                 end if;\r
859             when REG_SET3 =>\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
862                 else\r
863                     reg_s_oam_next_state <= IDLE;\r
864                 end if;\r
865         end case;\r
866     end process;\r
867 \r
868     --sprite main process...\r
869 \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
874 \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
881 begin\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
885         return 0;\r
886     else\r
887         return 1;\r
888     end if;\r
889 end;\r
890 \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
896 begin\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
900         return 1;\r
901     else\r
902         return 0;\r
903     end if;\r
904 end;\r
905 \r
906     begin\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
916 \r
917             --primary oam ram.\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
922 \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
927             end loop;\r
928         else\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
943                     end if;\r
944                     \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
958 \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
963 \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
977                                 --increment s-oam.\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
984                             else\r
985                                 --sprite copying.\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
990                                 else\r
991                                     reg_spr_eval_cnt <= reg_spr_eval_cnt + 1;\r
992                                 end if;\r
993                             end if;\r
994                         end if;\r
995                     end if;\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
1002 \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
1018                         end if;\r
1019                     end if;\r
1020 \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
1028                 else\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
1035 \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
1040                 end if;\r
1041             end if; --if (rising_edge(emu_ppu_clk)) then\r
1042         end if;--if (rst_n = '0') then\r
1043     end process;\r
1044 \r
1045     --sprite pattern data process.\r
1046     sprite_ptn_p : process (pi_rst_n, pi_base_clk)\r
1047 \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
1053 begin\r
1054     if (pm_ssp = '1' and pm_nes_x < HSCAN and pm_nes_y < VSCAN) then\r
1055         return 1;\r
1056     else\r
1057         return 0;\r
1058     end if;\r
1059 end;\r
1060 \r
1061     begin\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
1068             end loop;\r
1069         else\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
1075                         end if;\r
1076                     end if;\r
1077 \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
1084                         end if;\r
1085                     end if;\r
1086 \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
1092                                 --shift pattern.\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
1095                             else\r
1096                                 if (reg_spr_x(i) = "00000000") then\r
1097                                     reg_spr_ptn_sft_start(i) <= '1';\r
1098                                 else\r
1099                                     reg_spr_x(i) <= reg_spr_x(i) - 1;\r
1100                                 end if;\r
1101                             end if;\r
1102                         end loop;\r
1103                     end if;\r
1104                 else\r
1105                     reg_spr_ptn_sft_start <= (others => '0');\r
1106                 end if;\r
1107             end if; --if (rising_edge(emu_ppu_clk)) then\r
1108         end if;--if (rst_n = '0') then\r
1109     end process;\r
1110 \r
1111     po_ppu_status   <= reg_ppu_status;\r
1112 \r
1113     --status register set.\r
1114     status_p : process (pi_rst_n, pi_base_clk)\r
1115     begin\r
1116         if (pi_rst_n = '0') then\r
1117             reg_ppu_status <= (others => '0');\r
1118         else\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
1124 \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
1128                 else\r
1129                     reg_ppu_status(ST_BSY) <= '0';\r
1130                 end if;\r
1131 \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
1135                 else\r
1136                     reg_ppu_status(ST_SP0) <= reg_spr_hit;\r
1137                 end if;\r
1138 \r
1139                 if (reg_nes_y > VSCAN and reg_nes_y < VSCAN_NEXT_START) then\r
1140                     --vblank start\r
1141                     reg_ppu_status(ST_VBL) <= '1';\r
1142                 else\r
1143                     --vblank end\r
1144                     reg_ppu_status(ST_VBL) <= '0';\r
1145                 end if;\r
1146             end if; --if (rising_edge(emu_ppu_clk)) then\r
1147         end if;--if (rst_n = '0') then\r
1148     end process;\r
1149 \r
1150 end rtl;\r