OSDN Git Service

vram access cs set 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_rd_n         : out std_logic;\r
27         po_wr_n         : out std_logic;\r
28         po_v_addr       : out std_logic_vector (13 downto 0);\r
29         pi_v_data       : in std_logic_vector (7 downto 0);\r
30 \r
31         --sprite i/f\r
32         po_spr_ce_n     : out std_logic;\r
33         po_spr_rd_n     : out std_logic;\r
34         po_spr_wr_n     : out std_logic;\r
35         po_spr_addr     : out std_logic_vector (7 downto 0);\r
36         pi_spr_data     : in std_logic_vector (7 downto 0);\r
37 \r
38         --vga output\r
39         po_h_sync_n    : out std_logic;\r
40         po_v_sync_n    : out std_logic;\r
41         po_r           : out std_logic_vector(3 downto 0);\r
42         po_g           : out std_logic_vector(3 downto 0);\r
43         po_b           : out std_logic_vector(3 downto 0)\r
44         );\r
45 end render;\r
46 \r
47 architecture rtl of render is\r
48 \r
49 \r
50 --------- VGA screen constant -----------\r
51 constant VGA_W          : integer := 640;\r
52 constant VGA_H          : integer := 480;\r
53 constant VGA_W_MAX      : integer := 800;\r
54 constant VGA_H_MAX      : integer := 525;\r
55 constant H_SP           : integer := 95;\r
56 constant H_BP           : integer := 48;\r
57 constant H_FP           : integer := 15;\r
58 constant V_SP           : integer := 2;\r
59 constant V_BP           : integer := 33;\r
60 constant V_FP           : integer := 10;\r
61 \r
62 --nes screen size is emulated to align with the vga timing...\r
63 constant HSCAN                  : integer := 256;\r
64 constant VSCAN                  : integer := 240;\r
65 constant HSCAN_NEXT_START       : integer := 382;\r
66 constant VSCAN_NEXT_START       : integer := 262;\r
67 constant HSCAN_SPR_MAX          : integer := 321;\r
68 constant HSCAN_OAM_EVA_START    : integer := 64;\r
69 \r
70 constant PPUBNA    : integer := 1;  --base name address\r
71 constant PPUVAI    : integer := 2;  --vram address increment\r
72 constant PPUSPA    : integer := 3;  --sprite pattern table address\r
73 constant PPUBPA    : integer := 4;  --background pattern table address\r
74 constant PPUSPS    : integer := 5;  --sprite size\r
75 constant PPUMS     : integer := 6;  --ppu master/slave\r
76 constant PPUNEN    : integer := 7;  --nmi enable\r
77 \r
78 constant PPUGS     : integer := 0;  --grayscale\r
79 constant PPUSBL    : integer := 1;  --show 8 left most bg pixel\r
80 constant PPUSSL    : integer := 2;  --show 8 left most sprite pixel\r
81 constant PPUSBG    : integer := 3;  --show bg\r
82 constant PPUSSP    : integer := 4;  --show sprie\r
83 constant PPUIR     : integer := 5;  --intensify red\r
84 constant PPUIG     : integer := 6;  --intensify green\r
85 constant PPUIB     : integer := 7;  --intensify blue\r
86 \r
87 constant SPRHFL     : integer := 6;  --flip sprigte horizontally\r
88 constant SPRVFL     : integer := 7;  --flip sprigte vertically\r
89 \r
90 constant ST_BSY     : integer := 4;  --vram busy\r
91 constant ST_SOF     : integer := 5;  --sprite overflow\r
92 constant ST_SP0     : integer := 6;  --sprite 0 hits\r
93 constant ST_VBL     : integer := 7;  --vblank\r
94 \r
95 \r
96 subtype nes_color_data  is std_logic_vector (11 downto 0);\r
97 type nes_color_array    is array (0 to 63) of nes_color_data;\r
98 --ref: http://hlc6502.web.fc2.com/NesPal2.htm\r
99 constant nes_color_palette : nes_color_array := (\r
100         conv_std_logic_vector(16#777#, 12), \r
101         conv_std_logic_vector(16#20b#, 12), \r
102         conv_std_logic_vector(16#20b#, 12), \r
103         conv_std_logic_vector(16#61a#, 12), \r
104         conv_std_logic_vector(16#927#, 12), \r
105         conv_std_logic_vector(16#b13#, 12), \r
106         conv_std_logic_vector(16#a30#, 12), \r
107         conv_std_logic_vector(16#740#, 12), \r
108         conv_std_logic_vector(16#450#, 12), \r
109         conv_std_logic_vector(16#360#, 12), \r
110         conv_std_logic_vector(16#360#, 12), \r
111         conv_std_logic_vector(16#364#, 12), \r
112         conv_std_logic_vector(16#358#, 12), \r
113         conv_std_logic_vector(16#000#, 12), \r
114         conv_std_logic_vector(16#000#, 12), \r
115         conv_std_logic_vector(16#000#, 12),\r
116         conv_std_logic_vector(16#bbb#, 12), \r
117         conv_std_logic_vector(16#46f#, 12), \r
118         conv_std_logic_vector(16#44f#, 12), \r
119         conv_std_logic_vector(16#94f#, 12), \r
120         conv_std_logic_vector(16#d4c#, 12), \r
121         conv_std_logic_vector(16#d46#, 12), \r
122         conv_std_logic_vector(16#e50#, 12), \r
123         conv_std_logic_vector(16#c70#, 12), \r
124         conv_std_logic_vector(16#880#, 12), \r
125         conv_std_logic_vector(16#5a0#, 12), \r
126         conv_std_logic_vector(16#4a1#, 12), \r
127         conv_std_logic_vector(16#4a6#, 12), \r
128         conv_std_logic_vector(16#49c#, 12), \r
129         conv_std_logic_vector(16#000#, 12), \r
130         conv_std_logic_vector(16#000#, 12), \r
131         conv_std_logic_vector(16#000#, 12),\r
132         conv_std_logic_vector(16#fff#, 12), \r
133         conv_std_logic_vector(16#6af#, 12), \r
134         conv_std_logic_vector(16#58f#, 12), \r
135         conv_std_logic_vector(16#a7f#, 12), \r
136         conv_std_logic_vector(16#f6f#, 12), \r
137         conv_std_logic_vector(16#f6b#, 12), \r
138         conv_std_logic_vector(16#f73#, 12), \r
139         conv_std_logic_vector(16#fa0#, 12), \r
140         conv_std_logic_vector(16#ed2#, 12), \r
141         conv_std_logic_vector(16#9e0#, 12), \r
142         conv_std_logic_vector(16#7f4#, 12), \r
143         conv_std_logic_vector(16#7e9#, 12), \r
144         conv_std_logic_vector(16#6de#, 12), \r
145         conv_std_logic_vector(16#777#, 12), \r
146         conv_std_logic_vector(16#000#, 12), \r
147         conv_std_logic_vector(16#000#, 12),\r
148         conv_std_logic_vector(16#fff#, 12), \r
149         conv_std_logic_vector(16#9df#, 12), \r
150         conv_std_logic_vector(16#abf#, 12), \r
151         conv_std_logic_vector(16#cbf#, 12), \r
152         conv_std_logic_vector(16#ebf#, 12), \r
153         conv_std_logic_vector(16#fbe#, 12), \r
154         conv_std_logic_vector(16#fcb#, 12), \r
155         conv_std_logic_vector(16#fda#, 12), \r
156         conv_std_logic_vector(16#ff9#, 12), \r
157         conv_std_logic_vector(16#cf8#, 12), \r
158         conv_std_logic_vector(16#afa#, 12), \r
159         conv_std_logic_vector(16#afc#, 12), \r
160         conv_std_logic_vector(16#aff#, 12), \r
161         conv_std_logic_vector(16#aaa#, 12), \r
162         conv_std_logic_vector(16#000#, 12), \r
163         conv_std_logic_vector(16#000#, 12)\r
164         );\r
165 \r
166 signal reg_vga_x        : integer range 0 to VGA_W_MAX - 1;\r
167 signal reg_vga_y        : integer range 0 to VGA_H_MAX - 1;\r
168 \r
169 signal reg_nes_x        : integer range 0 to VGA_W_MAX / 2 - 1;\r
170 signal reg_nes_y        : integer range 0 to VGA_W_MAX / 2 - 1;\r
171 \r
172 type vac_state is (\r
173     IDLE,\r
174     AD_SET0,\r
175     AD_SET1,\r
176     AD_SET2,\r
177     AD_SET3,\r
178     REG_SET0,\r
179     REG_SET1,\r
180     REG_SET2,\r
181     REG_SET3\r
182     );\r
183 \r
184 signal reg_v_cur_state      : vac_state;\r
185 signal reg_v_next_state     : vac_state;\r
186 \r
187 signal reg_v_rd_n       : std_logic;\r
188 signal reg_v_wr_n       : std_logic;\r
189 signal reg_v_addr       : std_logic_vector (13 downto 0);\r
190 signal reg_v_data       : std_logic_vector (7 downto 0);\r
191 \r
192 begin\r
193 \r
194     --position and sync signal generate.\r
195     pos_p : process (pi_rst_n, pi_base_clk)\r
196     begin\r
197         if (pi_rst_n = '0') then\r
198             reg_vga_x <= 0;\r
199             reg_vga_y <= 0;\r
200             reg_nes_x <= 0;\r
201             reg_nes_y <= 0;\r
202         elsif (rising_edge(pi_base_clk)) then\r
203 \r
204             reg_nes_x <= reg_vga_x / 2;\r
205             reg_nes_y <= reg_vga_y / 2;\r
206 \r
207             if ((pi_rnd_en(0) or pi_rnd_en(2))= '1') then\r
208                 if (reg_vga_x = VGA_W_MAX - 1) then\r
209                     reg_vga_x <= 0;\r
210                     if (reg_vga_x = VGA_H_MAX - 1) then\r
211                         reg_vga_y <= 0;\r
212                     else\r
213                         reg_vga_y <= reg_vga_y + 1;\r
214                     end if;\r
215                 else\r
216                     reg_vga_x <= reg_vga_x + 1;\r
217                 end if;\r
218 \r
219                 --sync signal assert.\r
220                 if (reg_vga_x >= VGA_W + H_FP and reg_vga_x < VGA_W + H_FP + H_SP) then\r
221                     po_h_sync_n <= '0';\r
222                 else\r
223                     po_h_sync_n <= '1';\r
224                 end if;\r
225 \r
226                 if (reg_vga_y >= VGA_H + V_FP and reg_vga_y < VGA_H + V_FP + V_SP) then\r
227                     po_v_sync_n <= '0';\r
228                 else\r
229                     po_v_sync_n <= '1';\r
230                 end if;\r
231 \r
232             end if;--if (pi_rnd_en(1) = '1' or pi_rnd_en(3) = '1' ) then\r
233         end if;--if (pi_rst_n = '0') then\r
234     end process;\r
235 \r
236     --vram access state machine (state transition)...\r
237     vac_set_stat_p : process (pi_rst_n, pi_base_clk)\r
238     begin\r
239         if (pi_rst_n = '0') then\r
240             reg_v_cur_state <= IDLE;\r
241             reg_v_data    <= (others => 'Z');\r
242         elsif (rising_edge(pi_base_clk)) then\r
243             reg_v_data    <= pi_v_data;\r
244             reg_v_cur_state <= reg_v_next_state;\r
245         end if;--if (pi_rst_n = '0') then\r
246     end process;\r
247 \r
248     --state change to next.\r
249     vac_next_stat_p : process (reg_v_cur_state, pi_rnd_en, pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y)\r
250 function bg_process (\r
251     pm_sbg          : in std_logic;\r
252     pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
253     pm_nes_y        : in integer range 0 to VGA_H_MAX - 1\r
254     )return integer is\r
255 begin\r
256     if (pm_sbg = '1'and\r
257         (pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START) and\r
258         (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then\r
259         return 1;\r
260     else\r
261         return 0;\r
262     end if;\r
263 end;\r
264 \r
265 function is_idle (\r
266     pm_sbg          : in std_logic;\r
267     pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
268     pm_nes_y        : in integer range 0 to VGA_H_MAX - 1\r
269     )return integer is\r
270 begin\r
271     if (pm_sbg = '0' or\r
272         (pm_nes_x > HSCAN and pm_nes_x < HSCAN_NEXT_START) or\r
273         (pm_nes_y >= VSCAN and pm_nes_y < VSCAN_NEXT_START)) then\r
274         return 1;\r
275     else\r
276         return 0;\r
277     end if;\r
278 end;\r
279     begin\r
280         case reg_v_cur_state is\r
281             when IDLE =>\r
282                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
283                     pi_rnd_en(3) = '1' and\r
284                     reg_nes_x mod 8 = 0) then\r
285                     --start vram access process.\r
286                     reg_v_next_state <= AD_SET0;\r
287                 else\r
288                     reg_v_next_state <= reg_v_cur_state;\r
289                 end if;\r
290             when AD_SET0 =>\r
291                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
292                     pi_rnd_en(0) = '1'\r
293                 ) then\r
294                     reg_v_next_state <= AD_SET1;\r
295                 elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
296                     ---when nes_x=257, fall to idle\r
297                     reg_v_next_state <= IDLE;\r
298                 else\r
299                     reg_v_next_state <= reg_v_cur_state;\r
300                 end if;\r
301             when AD_SET1 =>\r
302                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
303                     pi_rnd_en(1) = '1'\r
304                 ) then\r
305                     reg_v_next_state <= AD_SET2;\r
306                 else\r
307                     reg_v_next_state <= reg_v_cur_state;\r
308                 end if;\r
309             when AD_SET2 =>\r
310                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
311                     pi_rnd_en(2) = '1'\r
312                 ) then\r
313                     reg_v_next_state <= AD_SET3;\r
314                 else\r
315                     reg_v_next_state <= reg_v_cur_state;\r
316                 end if;\r
317             when AD_SET3 =>\r
318                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
319                     pi_rnd_en(3) = '1'\r
320                 ) then\r
321                     reg_v_next_state <= REG_SET0;\r
322                 else\r
323                     reg_v_next_state <= reg_v_cur_state;\r
324                 end if;\r
325             when REG_SET0 =>\r
326                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
327                     pi_rnd_en(0) = '1'\r
328                 ) then\r
329                     reg_v_next_state <= REG_SET1;\r
330                 else\r
331                     reg_v_next_state <= reg_v_cur_state;\r
332                 end if;\r
333             when REG_SET1 =>\r
334                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
335                     pi_rnd_en(1) = '1'\r
336                 ) then\r
337                     reg_v_next_state <= REG_SET2;\r
338                 else\r
339                     reg_v_next_state <= reg_v_cur_state;\r
340                 end if;\r
341             when REG_SET2 =>\r
342                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
343                     pi_rnd_en(2) = '1'\r
344                 ) then\r
345                     reg_v_next_state <= REG_SET3;\r
346                 else\r
347                     reg_v_next_state <= reg_v_cur_state;\r
348                 end if;\r
349             when REG_SET3 =>\r
350                 if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
351                     pi_rnd_en(3) = '1'\r
352                 ) then\r
353                     reg_v_next_state <= AD_SET0;\r
354                 else\r
355                     reg_v_next_state <= reg_v_cur_state;\r
356                 end if;\r
357         end case;\r
358     end process;\r
359 \r
360     po_rd_n         <= reg_v_rd_n;\r
361     po_wr_n         <= reg_v_wr_n;\r
362     po_v_addr       <= reg_v_addr;\r
363 \r
364     --main vram access state machine...\r
365     vac_main_stat_p : process (reg_v_cur_state)\r
366     begin\r
367         case reg_v_cur_state is\r
368             when IDLE =>\r
369                 reg_v_rd_n  <= 'Z';\r
370                 reg_v_wr_n  <= 'Z';\r
371                 reg_v_addr  <= (others => 'Z');\r
372             when AD_SET0 =>\r
373                 reg_v_rd_n  <= '1';\r
374                 reg_v_wr_n  <= '1';\r
375                 reg_v_addr  <= (others => 'Z');\r
376             when AD_SET1 =>\r
377                 reg_v_rd_n  <= '1';\r
378                 reg_v_wr_n  <= '1';\r
379                 reg_v_addr  <= (others => 'Z');\r
380             when AD_SET2 =>\r
381                 reg_v_rd_n  <= '0';\r
382                 reg_v_wr_n  <= '1';\r
383                 reg_v_addr  <= (others => 'Z');\r
384             when AD_SET3 =>\r
385                 reg_v_rd_n  <= '0';\r
386                 reg_v_wr_n  <= '1';\r
387                 reg_v_addr  <= (others => 'Z');\r
388             when REG_SET0 =>\r
389                 reg_v_rd_n  <= '0';\r
390                 reg_v_wr_n  <= '1';\r
391                 reg_v_addr  <= (others => 'Z');\r
392             when REG_SET1 =>\r
393                 reg_v_rd_n  <= '0';\r
394                 reg_v_wr_n  <= '1';\r
395                 reg_v_addr  <= (others => 'Z');\r
396             when REG_SET2 =>\r
397                 reg_v_rd_n  <= '1';\r
398                 reg_v_wr_n  <= '1';\r
399                 reg_v_addr  <= (others => 'Z');\r
400             when REG_SET3 =>\r
401                 reg_v_rd_n  <= '1';\r
402                 reg_v_wr_n  <= '1';\r
403                 reg_v_addr  <= (others => 'Z');\r
404         end case;\r
405     end process;\r
406 \r
407     po_ppu_status   <= (others => '0');\r
408 \r
409     po_spr_ce_n     <= 'Z';\r
410     po_spr_rd_n     <= 'Z';\r
411     po_spr_wr_n     <= 'Z';\r
412     po_spr_addr     <= (others => 'Z');\r
413 \r
414     po_r           <= (others => 'Z');\r
415     po_g           <= (others => 'Z');\r
416     po_b           <= (others => 'Z');\r
417 end rtl;\r
418 \r