OSDN Git Service

46fdbe9a1ac52e69c1fafee54ee7407e522646d5
[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 \r
58 --------- VGA screen constant -----------\r
59 constant VGA_W          : integer := 640;\r
60 constant VGA_H          : integer := 480;\r
61 constant VGA_W_MAX      : integer := 800;\r
62 constant VGA_H_MAX      : integer := 525;\r
63 constant H_SYNC_S       : integer := 660;\r
64 constant H_SYNC_E       : integer := 756;\r
65 constant V_SYNC_S       : integer := 494;\r
66 constant V_SYNC_E       : integer := 495;\r
67 \r
68 --nes screen size is emulated to align with the vga timing...\r
69 constant HSCAN                  : integer := 256;\r
70 constant VSCAN                  : integer := 240;\r
71 constant HSCAN_NEXT_START       : integer := 382;\r
72 constant VSCAN_NEXT_START       : integer := 262;\r
73 constant HSCAN_SPR_MAX          : integer := 321;\r
74 constant HSCAN_OAM_EVA_START    : integer := 64;\r
75 \r
76 constant PREFETCH_INT           : integer := 16;\r
77 \r
78 constant PPUBNA    : integer := 1;  --base name address\r
79 constant PPUVAI    : integer := 2;  --vram address increment\r
80 constant PPUSPA    : integer := 3;  --sprite pattern table address\r
81 constant PPUBPA    : integer := 4;  --background pattern table address\r
82 constant PPUSPS    : integer := 5;  --sprite size\r
83 constant PPUMS     : integer := 6;  --ppu master/slave\r
84 constant PPUNEN    : integer := 7;  --nmi enable\r
85 \r
86 constant PPUGS     : integer := 0;  --grayscale\r
87 constant PPUSBL    : integer := 1;  --show 8 left most bg pixel\r
88 constant PPUSSL    : integer := 2;  --show 8 left most sprite pixel\r
89 constant PPUSBG    : integer := 3;  --show bg\r
90 constant PPUSSP    : integer := 4;  --show sprie\r
91 constant PPUIR     : integer := 5;  --intensify red\r
92 constant PPUIG     : integer := 6;  --intensify green\r
93 constant PPUIB     : integer := 7;  --intensify blue\r
94 \r
95 constant SPRHFL     : integer := 6;  --flip sprigte horizontally\r
96 constant SPRVFL     : integer := 7;  --flip sprigte vertically\r
97 \r
98 constant ST_BSY     : integer := 4;  --vram busy\r
99 constant ST_SOF     : integer := 5;  --sprite overflow\r
100 constant ST_SP0     : integer := 6;  --sprite 0 hits\r
101 constant ST_VBL     : integer := 7;  --vblank\r
102 \r
103 \r
104 subtype nes_color_data  is std_logic_vector (11 downto 0);\r
105 type nes_color_array    is array (0 to 63) of nes_color_data;\r
106 --ref: http://hlc6502.web.fc2.com/NesPal2.htm\r
107 constant nes_color_palette : nes_color_array := (\r
108         conv_std_logic_vector(16#777#, 12), \r
109         conv_std_logic_vector(16#20b#, 12), \r
110         conv_std_logic_vector(16#20b#, 12), \r
111         conv_std_logic_vector(16#61a#, 12), \r
112         conv_std_logic_vector(16#927#, 12), \r
113         conv_std_logic_vector(16#b13#, 12), \r
114         conv_std_logic_vector(16#a30#, 12), \r
115         conv_std_logic_vector(16#740#, 12), \r
116         conv_std_logic_vector(16#450#, 12), \r
117         conv_std_logic_vector(16#360#, 12), \r
118         conv_std_logic_vector(16#360#, 12), \r
119         conv_std_logic_vector(16#364#, 12), \r
120         conv_std_logic_vector(16#358#, 12), \r
121         conv_std_logic_vector(16#000#, 12), \r
122         conv_std_logic_vector(16#000#, 12), \r
123         conv_std_logic_vector(16#000#, 12),\r
124         conv_std_logic_vector(16#bbb#, 12), \r
125         conv_std_logic_vector(16#46f#, 12), \r
126         conv_std_logic_vector(16#44f#, 12), \r
127         conv_std_logic_vector(16#94f#, 12), \r
128         conv_std_logic_vector(16#d4c#, 12), \r
129         conv_std_logic_vector(16#d46#, 12), \r
130         conv_std_logic_vector(16#e50#, 12), \r
131         conv_std_logic_vector(16#c70#, 12), \r
132         conv_std_logic_vector(16#880#, 12), \r
133         conv_std_logic_vector(16#5a0#, 12), \r
134         conv_std_logic_vector(16#4a1#, 12), \r
135         conv_std_logic_vector(16#4a6#, 12), \r
136         conv_std_logic_vector(16#49c#, 12), \r
137         conv_std_logic_vector(16#000#, 12), \r
138         conv_std_logic_vector(16#000#, 12), \r
139         conv_std_logic_vector(16#000#, 12),\r
140         conv_std_logic_vector(16#fff#, 12), \r
141         conv_std_logic_vector(16#6af#, 12), \r
142         conv_std_logic_vector(16#58f#, 12), \r
143         conv_std_logic_vector(16#a7f#, 12), \r
144         conv_std_logic_vector(16#f6f#, 12), \r
145         conv_std_logic_vector(16#f6b#, 12), \r
146         conv_std_logic_vector(16#f73#, 12), \r
147         conv_std_logic_vector(16#fa0#, 12), \r
148         conv_std_logic_vector(16#ed2#, 12), \r
149         conv_std_logic_vector(16#9e0#, 12), \r
150         conv_std_logic_vector(16#7f4#, 12), \r
151         conv_std_logic_vector(16#7e9#, 12), \r
152         conv_std_logic_vector(16#6de#, 12), \r
153         conv_std_logic_vector(16#777#, 12), \r
154         conv_std_logic_vector(16#000#, 12), \r
155         conv_std_logic_vector(16#000#, 12),\r
156         conv_std_logic_vector(16#fff#, 12), \r
157         conv_std_logic_vector(16#9df#, 12), \r
158         conv_std_logic_vector(16#abf#, 12), \r
159         conv_std_logic_vector(16#cbf#, 12), \r
160         conv_std_logic_vector(16#ebf#, 12), \r
161         conv_std_logic_vector(16#fbe#, 12), \r
162         conv_std_logic_vector(16#fcb#, 12), \r
163         conv_std_logic_vector(16#fda#, 12), \r
164         conv_std_logic_vector(16#ff9#, 12), \r
165         conv_std_logic_vector(16#cf8#, 12), \r
166         conv_std_logic_vector(16#afa#, 12), \r
167         conv_std_logic_vector(16#afc#, 12), \r
168         conv_std_logic_vector(16#aff#, 12), \r
169         conv_std_logic_vector(16#aaa#, 12), \r
170         conv_std_logic_vector(16#000#, 12), \r
171         conv_std_logic_vector(16#000#, 12)\r
172         );\r
173 \r
174 function is_bg (\r
175     pm_sbg          : in std_logic;\r
176     pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
177     pm_nes_y        : in integer range 0 to VGA_H_MAX - 1\r
178     )return integer is\r
179 begin\r
180     if (pm_sbg = '1'and\r
181         (pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START) and\r
182         (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then\r
183         return 1;\r
184     else\r
185         return 0;\r
186     end if;\r
187 end;\r
188 \r
189 signal reg_vga_x        : integer range 0 to VGA_W_MAX - 1;\r
190 signal reg_vga_y        : integer range 0 to VGA_H_MAX - 1;\r
191 \r
192 signal reg_nes_x        : integer range 0 to VGA_W_MAX / 2 - 1;\r
193 signal reg_nes_y        : integer range 0 to VGA_W_MAX / 2 - 1;\r
194 --prefech is wider by scroll reg size.\r
195 signal reg_prf_x        : integer range 0 to VGA_W_MAX / 2 + 256 - 1;\r
196 signal reg_prf_y        : integer range 0 to VGA_W_MAX / 2 + 256 - 1;\r
197 \r
198 type vac_state is (\r
199     IDLE,\r
200     AD_SET0,\r
201     AD_SET1,\r
202     AD_SET2,\r
203     AD_SET3,\r
204     REG_SET0,\r
205     REG_SET1,\r
206     REG_SET2,\r
207     REG_SET3\r
208     );\r
209 \r
210 signal reg_v_cur_state      : vac_state;\r
211 signal reg_v_next_state     : vac_state;\r
212 \r
213 signal reg_v_ce_n       : std_logic;\r
214 signal reg_v_rd_n       : std_logic;\r
215 signal reg_v_wr_n       : std_logic;\r
216 signal reg_v_addr       : std_logic_vector (13 downto 0);\r
217 signal reg_v_data       : std_logic_vector (7 downto 0);\r
218 \r
219 signal reg_disp_nt          : std_logic_vector (7 downto 0);\r
220 signal reg_disp_attr        : std_logic_vector (7 downto 0);\r
221 signal reg_tmp_ptn_l        : std_logic_vector (7 downto 0);\r
222 signal reg_sft_ptn_l        : std_logic_vector (15 downto 0);\r
223 signal reg_sft_ptn_h        : std_logic_vector (15 downto 0);\r
224 \r
225 signal reg_plt_ce_n       : std_logic;\r
226 signal reg_plt_rd_n       : std_logic;\r
227 signal reg_plt_wr_n       : std_logic;\r
228 signal reg_plt_addr       : std_logic_vector (4 downto 0);\r
229 signal reg_plt_data       : std_logic_vector (7 downto 0);\r
230 \r
231 begin\r
232 \r
233     --position and sync signal generate.\r
234     pos_p : process (pi_rst_n, pi_base_clk)\r
235     begin\r
236         if (pi_rst_n = '0') then\r
237             reg_vga_x <= 0;\r
238             reg_vga_y <= 0;\r
239             reg_nes_x <= 0;\r
240             reg_nes_y <= 0;\r
241             reg_prf_x <= 0;\r
242             reg_prf_y <= 0;\r
243         elsif (rising_edge(pi_base_clk)) then\r
244             if ((pi_rnd_en(0) or pi_rnd_en(2))= '1') then\r
245                 if (reg_vga_x = VGA_W_MAX - 1) then\r
246                     reg_vga_x <= 0;\r
247                     reg_nes_x <= 0;\r
248                     if (reg_vga_y = VGA_H_MAX - 1) then\r
249                         reg_vga_y <= 0;\r
250                         reg_nes_y <= 0;\r
251                     else\r
252                         reg_vga_y <= reg_vga_y + 1;\r
253                         reg_nes_y <= (reg_vga_y + 1) / 2;\r
254                     end if;\r
255                 else\r
256                     reg_vga_x <= reg_vga_x + 1;\r
257                     reg_nes_x <= (reg_vga_x + 1) / 2;\r
258                 end if;\r
259 \r
260                 --sync signal assert.\r
261                 if (reg_vga_x >= H_SYNC_S and reg_vga_x < H_SYNC_E) then\r
262                     po_h_sync_n <= '0';\r
263                 else\r
264                     po_h_sync_n <= '1';\r
265                 end if;\r
266 \r
267                 if (reg_vga_y >= V_SYNC_S and reg_vga_y < V_SYNC_E) then\r
268                     po_v_sync_n <= '0';\r
269                 else\r
270                     po_v_sync_n <= '1';\r
271                 end if;\r
272             end if;--if (pi_rnd_en(1) = '1' or pi_rnd_en(3) = '1' ) then\r
273 \r
274             --pre-fetch x/y position...\r
275             if (reg_vga_x < HSCAN_NEXT_START * 2) then\r
276                 reg_prf_x <= reg_vga_x / 2 + conv_integer(pi_ppu_scroll_x) + PREFETCH_INT;\r
277             else\r
278                 reg_prf_x <= reg_vga_x / 2 + conv_integer(pi_ppu_scroll_x)\r
279                                 - HSCAN_NEXT_START + PREFETCH_INT;\r
280             end if;\r
281 \r
282             if (reg_vga_y < VSCAN * 2) then\r
283                 if (reg_vga_x < HSCAN_NEXT_START * 2) then\r
284                     reg_prf_y <= reg_vga_y / 2 + conv_integer(pi_ppu_scroll_y);\r
285                 else\r
286                     reg_prf_y <= (reg_vga_y + 1) / 2 + conv_integer(pi_ppu_scroll_y);\r
287                 end if;\r
288             else\r
289                 reg_prf_y <= 0;\r
290             end if;\r
291         end if;--if (pi_rst_n = '0') then\r
292     end process;\r
293 \r
294     --vram access state machine (state transition)...\r
295     vac_set_stat_p : process (pi_rst_n, pi_base_clk)\r
296     begin\r
297         if (pi_rst_n = '0') then\r
298             reg_v_cur_state <= IDLE;\r
299         elsif (rising_edge(pi_base_clk)) then\r
300             reg_v_cur_state <= reg_v_next_state;\r
301         end if;--if (pi_rst_n = '0') then\r
302     end process;\r
303 \r
304     --state change to next.\r
305     vac_next_stat_p : process (reg_v_cur_state, pi_rnd_en, pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y)\r
306 function bg_process (\r
307     pm_sbg          : in std_logic;\r
308     pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
309     pm_nes_y        : in integer range 0 to VGA_H_MAX - 1\r
310     )return integer is\r
311 begin\r
312     if (pm_sbg = '1'and\r
313         (pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START) and\r
314         (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then\r
315         return 1;\r
316     else\r
317         return 0;\r
318     end if;\r
319 end;\r
320 \r
321 function is_idle (\r
322     pm_sbg          : in std_logic;\r
323     pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
324     pm_nes_y        : in integer range 0 to VGA_H_MAX - 1\r
325     )return integer is\r
326 begin\r
327     if (pm_sbg = '0' or\r
328         (pm_nes_x > HSCAN and pm_nes_x < HSCAN_NEXT_START) or\r
329         (pm_nes_y >= VSCAN and pm_nes_y < VSCAN_NEXT_START)) then\r
330         return 1;\r
331     else\r
332         return 0;\r
333     end if;\r
334 end;\r
335     begin\r
336         case reg_v_cur_state is\r
337             when IDLE =>\r
338                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
339                     pi_rnd_en(2) = '1' and\r
340                     reg_nes_x mod 8 = 0) then\r
341                     --start vram access process.\r
342                     reg_v_next_state <= AD_SET0;\r
343                 else\r
344                     reg_v_next_state <= reg_v_cur_state;\r
345                 end if;\r
346             when AD_SET0 =>\r
347                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
348                     pi_rnd_en(3) = '1'\r
349                 ) then\r
350                     reg_v_next_state <= AD_SET1;\r
351                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
352                     ---when nes_x=257, fall to idle\r
353                     reg_v_next_state <= IDLE;\r
354                 else\r
355                     reg_v_next_state <= reg_v_cur_state;\r
356                 end if;\r
357             when AD_SET1 =>\r
358                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
359                     pi_rnd_en(0) = '1'\r
360                 ) then\r
361                     reg_v_next_state <= AD_SET2;\r
362                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
363                     ---when nes_x=257, fall to idle\r
364                     reg_v_next_state <= IDLE;\r
365                 else\r
366                     reg_v_next_state <= reg_v_cur_state;\r
367                 end if;\r
368             when AD_SET2 =>\r
369                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
370                     pi_rnd_en(1) = '1'\r
371                 ) then\r
372                     reg_v_next_state <= AD_SET3;\r
373                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
374                     ---when nes_x=257, fall to idle\r
375                     reg_v_next_state <= IDLE;\r
376                 else\r
377                     reg_v_next_state <= reg_v_cur_state;\r
378                 end if;\r
379             when AD_SET3 =>\r
380                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
381                     pi_rnd_en(2) = '1'\r
382                 ) then\r
383                     reg_v_next_state <= REG_SET0;\r
384                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
385                     ---when nes_x=257, fall to idle\r
386                     reg_v_next_state <= IDLE;\r
387                 else\r
388                     reg_v_next_state <= reg_v_cur_state;\r
389                 end if;\r
390             when REG_SET0 =>\r
391                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
392                     pi_rnd_en(3) = '1'\r
393                 ) then\r
394                     reg_v_next_state <= REG_SET1;\r
395                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
396                     ---when nes_x=257, fall to idle\r
397                     reg_v_next_state <= IDLE;\r
398                 else\r
399                     reg_v_next_state <= reg_v_cur_state;\r
400                 end if;\r
401             when REG_SET1 =>\r
402                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
403                     pi_rnd_en(0) = '1'\r
404                 ) then\r
405                     reg_v_next_state <= REG_SET2;\r
406                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
407                     ---when nes_x=257, fall to idle\r
408                     reg_v_next_state <= IDLE;\r
409                 else\r
410                     reg_v_next_state <= reg_v_cur_state;\r
411                 end if;\r
412             when REG_SET2 =>\r
413                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
414                     pi_rnd_en(1) = '1'\r
415                 ) then\r
416                     reg_v_next_state <= REG_SET3;\r
417                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
418                     ---when nes_x=257, fall to idle\r
419                     reg_v_next_state <= IDLE;\r
420                 else\r
421                     reg_v_next_state <= reg_v_cur_state;\r
422                 end if;\r
423             when REG_SET3 =>\r
424                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
425                     pi_rnd_en(2) = '1'\r
426                 ) then\r
427                     reg_v_next_state <= AD_SET0;\r
428                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
429                     ---when nes_x=257, fall to idle\r
430                     reg_v_next_state <= IDLE;\r
431                 else\r
432                     reg_v_next_state <= reg_v_cur_state;\r
433                 end if;\r
434         end case;\r
435     end process;\r
436 \r
437     po_v_ce_n       <= reg_v_ce_n;\r
438     po_v_rd_n       <= reg_v_rd_n;\r
439     po_v_wr_n       <= reg_v_wr_n;\r
440     po_v_addr       <= reg_v_addr;\r
441 \r
442     po_plt_ce_n     <= reg_plt_ce_n;\r
443     po_plt_rd_n     <= reg_plt_rd_n;\r
444     po_plt_wr_n     <= reg_plt_wr_n;\r
445     po_plt_addr     <= reg_plt_addr;\r
446 \r
447     --vram r/w selector state machine...\r
448     vac_main_stat_p : process (reg_v_cur_state)\r
449     begin\r
450         case reg_v_cur_state is\r
451             when IDLE =>\r
452                 reg_v_rd_n  <= 'Z';\r
453                 reg_v_wr_n  <= 'Z';\r
454             when AD_SET0 | AD_SET1 | REG_SET2 | REG_SET3 =>\r
455                 reg_v_rd_n  <= '1';\r
456                 reg_v_wr_n  <= '1';\r
457             when AD_SET2 | AD_SET3 | REG_SET0 | REG_SET1 =>\r
458                 reg_v_rd_n  <= '0';\r
459                 reg_v_wr_n  <= '1';\r
460         end case;\r
461 \r
462         case reg_v_cur_state is\r
463             when IDLE =>\r
464                 reg_v_ce_n  <= 'Z';\r
465                 reg_plt_ce_n <= 'Z';\r
466                 reg_plt_rd_n <= 'Z';\r
467                 reg_plt_wr_n <= 'Z'; \r
468             when AD_SET0 | AD_SET1 | REG_SET2 | REG_SET3 | AD_SET2 | AD_SET3 | REG_SET0 | REG_SET1 =>\r
469                 reg_v_ce_n  <= '0';\r
470                 reg_plt_ce_n <= '0';\r
471                 reg_plt_rd_n <= '0';\r
472                 reg_plt_wr_n <= '1'; \r
473         end case;\r
474     end process;\r
475 \r
476     --vram address state machine...\r
477     vaddr_stat_p : process (pi_rst_n, pi_base_clk)\r
478     begin\r
479         if (pi_rst_n = '0') then\r
480             reg_v_addr  <= (others => 'Z');\r
481             reg_v_data    <= (others => 'Z');\r
482             reg_disp_nt     <= (others => 'Z');\r
483             reg_disp_attr   <= (others => 'Z');\r
484         elsif (rising_edge(pi_base_clk)) then\r
485             reg_v_data      <= pi_v_data;\r
486 \r
487             if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
488                 ----fetch next tile byte.\r
489                 if (reg_prf_x mod 8 = 1) then\r
490                     --vram addr is incremented every 8 cycle.\r
491                     --name table at 0x2000\r
492                     reg_v_addr(9 downto 0)\r
493                         <= conv_std_logic_vector(reg_prf_y, 9)(7 downto 3)\r
494                             & conv_std_logic_vector(reg_prf_x, 9)(7 downto 3);\r
495                     reg_v_addr(13 downto 10) <= "10" & pi_ppu_ctrl(PPUBNA downto 0)\r
496                                                     + ("000" & conv_std_logic_vector(reg_prf_x, 9)(8));\r
497                 \r
498                 elsif (reg_prf_x mod 8 = 2 and reg_v_cur_state = REG_SET1) then\r
499                     reg_disp_nt     <= reg_v_data;\r
500                 \r
501                 ----fetch attr table byte.\r
502                 elsif (reg_prf_x mod 8 = 3) then\r
503                     --attr table at 0x23c0\r
504                     reg_v_addr(7 downto 0) <= "11000000" +\r
505                             ("00" & conv_std_logic_vector(reg_prf_y, 9)(7 downto 5)\r
506                                   & conv_std_logic_vector(reg_prf_x, 9)(7 downto 5));\r
507                     reg_v_addr(13 downto 8) <= "10" &\r
508                             pi_ppu_ctrl(PPUBNA downto 0) & "11"\r
509                                 + ("000" & conv_std_logic_vector(reg_prf_x, 9)(8) & "00");\r
510                 \r
511                 elsif (reg_prf_x mod 8 = 4 and reg_v_cur_state = REG_SET1) then\r
512                     reg_disp_attr   <= reg_v_data;\r
513 \r
514                 ----fetch pattern table low byte.\r
515                 elsif (reg_prf_x mod 8 = 5) then\r
516                      --vram addr is incremented every 8 cycle.\r
517                      reg_v_addr <= "0" & pi_ppu_ctrl(PPUBPA) &\r
518                                           reg_disp_nt(7 downto 0)\r
519                                         & "0" & conv_std_logic_vector(reg_prf_y, 9)(2 downto 0);\r
520 \r
521                 ----fetch pattern table high byte.\r
522                 elsif (reg_prf_x mod 8 = 7) then\r
523                      --vram addr is incremented every 8 cycle.\r
524                      reg_v_addr <= "0" & pi_ppu_ctrl(PPUBPA) &\r
525                                           reg_disp_nt(7 downto 0)\r
526                                         & "0" & conv_std_logic_vector(reg_prf_y, 9)(2 downto 0)\r
527                                         + "00000000001000";\r
528                 end if;\r
529             end if;\r
530         end if;--if (pi_rst_n = '0') then\r
531     end process;\r
532 \r
533     --pattern table state machine...\r
534     bg_ptn_p : process (pi_rst_n, pi_base_clk)\r
535     begin\r
536         if (pi_rst_n = '0') then\r
537             reg_tmp_ptn_l <= (others => '0');\r
538             reg_sft_ptn_l <= (others => '0');\r
539             reg_sft_ptn_h <= (others => '0');\r
540         elsif (rising_edge(pi_base_clk)) then\r
541 \r
542             if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
543                 --fetch low first.\r
544                 if (reg_prf_x mod 8 = 6 and reg_v_cur_state = REG_SET1) then\r
545                     reg_tmp_ptn_l <= reg_v_data;\r
546                 end if;\r
547 \r
548                 if (reg_prf_x mod 8 = 0) then\r
549                     if (reg_v_cur_state = REG_SET1) then\r
550                         --copy low & shift.\r
551                         reg_sft_ptn_l <= reg_tmp_ptn_l & reg_sft_ptn_l(8 downto 1);\r
552                         --fetch high & shift.\r
553                         reg_sft_ptn_h <= reg_v_data & reg_sft_ptn_h(8 downto 1);\r
554                     end if;\r
555                 else\r
556                     if (reg_v_cur_state = AD_SET1 or reg_v_cur_state = REG_SET1) then\r
557                         reg_sft_ptn_l <= "0" & reg_sft_ptn_l(15 downto 1);\r
558                         reg_sft_ptn_h <= "0" & reg_sft_ptn_h(15 downto 1);\r
559                     end if;\r
560                 end if;\r
561             end if;\r
562         end if;--if (pi_rst_n = '0') then\r
563     end process;\r
564 \r
565     --palette table state machine...\r
566     plt_ac_p : process (pi_rst_n, pi_base_clk)\r
567     begin\r
568         if (pi_rst_n = '0') then\r
569             reg_plt_addr    <= (others => 'Z');\r
570             reg_plt_data    <= (others => 'Z');\r
571         elsif (rising_edge(pi_base_clk)) then\r
572             \r
573             reg_plt_data    <= pi_plt_data;\r
574             --shift pattern propageted 1 cycle later.\r
575             if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
576                 (reg_v_cur_state = AD_SET2 or reg_v_cur_state = REG_SET2)) then\r
577                 if (conv_std_logic_vector(reg_nes_y, 9)(4) = '0'\r
578                     and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then\r
579                     reg_plt_addr <=\r
580                             "0" & reg_disp_attr(1 downto 0) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
581                 elsif (conv_std_logic_vector(reg_nes_y, 9)(4) = '1'\r
582                     and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then\r
583                     reg_plt_addr <=\r
584                             "0" & reg_disp_attr(5 downto 4) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
585                 else\r
586                     ---else: no output color >> universal bg color output.\r
587                     --0x3f00 is the universal bg palette.\r
588                     reg_plt_addr <= (others => '0');\r
589                 end if;\r
590             end if;\r
591         end if;--if (pi_rst_n = '0') then\r
592     end process;\r
593 \r
594     rgb_out_p : process (pi_rst_n, pi_base_clk)\r
595     begin\r
596         if (pi_rst_n = '0') then\r
597             po_b <= (others => '0');\r
598             po_g <= (others => '0');\r
599             po_r <= (others => '0');\r
600         else\r
601             if (rising_edge(pi_base_clk)) then\r
602                 if (reg_nes_x < HSCAN and reg_nes_y < VSCAN) then\r
603                     --if or if not bg/sprite is shown, output color anyway \r
604                     --sinse universal bg color is included..\r
605                     po_b <= nes_color_palette(conv_integer(reg_plt_data(5 downto 0))) (11 downto 8);\r
606                     po_g <= nes_color_palette(conv_integer(reg_plt_data(5 downto 0))) (7 downto 4);\r
607                     po_r <= nes_color_palette(conv_integer(reg_plt_data(5 downto 0))) (3 downto 0);\r
608                 else\r
609                     po_b <= (others => '0');\r
610                     po_g <= (others => '0');\r
611                     po_r <= (others => '0');\r
612                 end if;\r
613             end if; --if (rising_edge(emu_ppu_clk)) then\r
614         end if;--if (rst_n = '0') then\r
615     end process;--output_p\r
616 \r
617     po_ppu_status   <= (others => '0');\r
618 \r
619     po_spr_ce_n     <= 'Z';\r
620     po_spr_rd_n     <= 'Z';\r
621     po_spr_wr_n     <= 'Z';\r
622     po_spr_addr     <= (others => 'Z');\r
623 \r
624 end rtl;\r