OSDN Git Service

ppu addr reset latch timing changed.
[motonesfpga/motonesfpga.git] / simulation / ppu / ppu.vhd
1 library ieee;
2 use ieee.std_logic_1164.all;
3
4 entity ppu is 
5     port (  clk         : in std_logic;
6             ce_n        : in std_logic;
7             rst_n       : in std_logic;
8             r_nw        : in std_logic;
9             cpu_addr    : in std_logic_vector (2 downto 0);
10             cpu_d       : inout std_logic_vector (7 downto 0);
11             vblank_n    : out std_logic;
12             rd_n        : out std_logic;
13             wr_n        : out std_logic;
14             ale         : out std_logic;
15             vram_ad     : inout std_logic_vector (7 downto 0);
16             vram_a      : out std_logic_vector (13 downto 8);
17             vga_clk     : in std_logic;
18             h_sync_n    : out std_logic;
19             v_sync_n    : out std_logic;
20             r           : out std_logic_vector(3 downto 0);
21             g           : out std_logic_vector(3 downto 0);
22             b           : out std_logic_vector(3 downto 0)
23     );
24 end ppu;
25
26 architecture rtl of ppu is
27
28 component ppu_render
29     port (  clk         : in std_logic;
30             rst_n       : in std_logic;
31             rd_n        : out std_logic;
32             wr_n        : out std_logic;
33             ale         : out std_logic;
34             vram_ad     : inout std_logic_vector (7 downto 0);
35             vram_a      : out std_logic_vector (13 downto 8);
36             pos_x       : out std_logic_vector (8 downto 0);
37             pos_y       : out std_logic_vector (8 downto 0);
38             r           : out std_logic_vector (3 downto 0);
39             g           : out std_logic_vector (3 downto 0);
40             b           : out std_logic_vector (3 downto 0);
41             ppu_ctrl        : in std_logic_vector (7 downto 0);
42             ppu_mask        : in std_logic_vector (7 downto 0);
43             read_status     : in std_logic;
44             ppu_status      : out std_logic_vector (7 downto 0);
45             ppu_scroll_x    : in std_logic_vector (7 downto 0);
46             ppu_scroll_y    : in std_logic_vector (7 downto 0);
47             r_nw            : in std_logic;
48             oam_bus_ce_n    : in std_logic;
49             plt_bus_ce_n    : in std_logic;
50             oam_plt_addr    : in std_logic_vector (7 downto 0);
51             oam_plt_data    : inout std_logic_vector (7 downto 0);
52             v_bus_busy_n    : out std_logic
53     );
54 end component;
55
56 component vga_ctl
57     port (  ppu_clk     : in std_logic;
58             vga_clk     : in std_logic;
59             rst_n       : in std_logic;
60             pos_x       : in std_logic_vector (8 downto 0);
61             pos_y       : in std_logic_vector (8 downto 0);
62             nes_r       : in std_logic_vector (3 downto 0);
63             nes_g       : in std_logic_vector (3 downto 0);
64             nes_b       : in std_logic_vector (3 downto 0);
65             h_sync_n    : out std_logic;
66             v_sync_n    : out std_logic;
67             r           : out std_logic_vector(3 downto 0);
68             g           : out std_logic_vector(3 downto 0);
69             b           : out std_logic_vector(3 downto 0)
70     );
71 end component;
72
73 component d_flip_flop
74     generic (
75             dsize : integer := 8
76             );
77     port (
78             clk     : in std_logic;
79             res_n   : in std_logic;
80             set_n   : in std_logic;
81             we_n    : in std_logic;
82             d       : in std_logic_vector (dsize - 1 downto 0);
83             q       : out std_logic_vector (dsize - 1 downto 0)
84         );
85 end component;
86
87 component counter_register
88     generic (
89         dsize       : integer := 8;
90         inc         : integer := 1
91     );
92     port (  clk         : in std_logic;
93             rst_n       : in std_logic;
94             ce_n        : in std_logic;
95             we_n        : in std_logic;
96             d           : in std_logic_vector(dsize - 1 downto 0);
97             q           : out std_logic_vector(dsize - 1 downto 0)
98     );
99 end component;
100
101 procedure d_print(msg : string) is
102 use std.textio.all;
103 use ieee.std_logic_textio.all;
104 variable out_l : line;
105 begin
106     write(out_l, msg);
107     writeline(output, out_l);
108 end  procedure;
109
110 signal pos_x       : std_logic_vector (8 downto 0);
111 signal pos_y       : std_logic_vector (8 downto 0);
112 signal nes_r       : std_logic_vector (3 downto 0);
113 signal nes_g       : std_logic_vector (3 downto 0);
114 signal nes_b       : std_logic_vector (3 downto 0);
115
116 constant dsize     : integer := 8;
117
118 constant PPUCTRL   : std_logic_vector(2 downto 0) := "000";
119 constant PPUMASK   : std_logic_vector(2 downto 0) := "001";
120 constant PPUSTATUS : std_logic_vector(2 downto 0) := "010";
121 constant OAMADDR   : std_logic_vector(2 downto 0) := "011";
122 constant OAMDATA   : std_logic_vector(2 downto 0) := "100";
123 constant PPUSCROLL : std_logic_vector(2 downto 0) := "101";
124 constant PPUADDR   : std_logic_vector(2 downto 0) := "110";
125 constant PPUDATA   : std_logic_vector(2 downto 0) := "111";
126
127 constant PPUVAI     : integer := 2;  --vram address increment
128 constant PPUNEN     : integer := 7;  --nmi enable
129 constant ST_VBL     : integer := 7;  --vblank
130
131 signal clk_n            : std_logic;
132
133 signal ppu_clk_cnt_res_n    : std_logic;
134 signal ppu_clk_cnt          : std_logic_vector(1 downto 0);
135
136 signal ppu_ctrl_we_n    : std_logic;
137 signal ppu_mask_we_n    : std_logic;
138 signal oam_addr_ce_n    : std_logic;
139 signal oam_addr_we_n    : std_logic;
140 signal oam_data_we_n    : std_logic;
141 signal ppu_scroll_x_we_n    : std_logic;
142 signal ppu_scroll_y_we_n    : std_logic;
143 signal ppu_scroll_cnt_ce_n  : std_logic;
144 signal ppu_addr_we_n        : std_logic;
145 signal ppu_addr_cnt_ce_n    : std_logic;
146 signal ppu_data_we_n    : std_logic;
147
148 signal ppu_ctrl         : std_logic_vector (dsize - 1 downto 0);
149 signal ppu_mask         : std_logic_vector (dsize - 1 downto 0);
150 signal read_status      : std_logic;
151 signal ppu_status       : std_logic_vector (dsize - 1 downto 0);
152 signal ppu_stat_out     : std_logic_vector (dsize - 1 downto 0);
153 signal oam_addr         : std_logic_vector (dsize - 1 downto 0);
154 signal oam_data         : std_logic_vector (dsize - 1 downto 0);
155 signal ppu_scroll_x     : std_logic_vector (dsize - 1 downto 0);
156 signal ppu_scroll_y     : std_logic_vector (dsize - 1 downto 0);
157 signal ppu_scroll_cnt   : std_logic_vector (0 downto 0);
158 signal ppu_addr         : std_logic_vector (13 downto 0);
159 signal ppu_addr_inc1    : std_logic_vector (13 downto 0);
160 signal ppu_addr_inc32   : std_logic_vector (13 downto 0);
161 signal ppu_addr_in      : std_logic_vector (13 downto 0);
162 signal ppu_addr_cnt     : std_logic_vector (0 downto 0);
163 signal ppu_data         : std_logic_vector (dsize - 1 downto 0);
164 signal ppu_data_in      : std_logic_vector (dsize - 1 downto 0);
165 signal ppu_data_out     : std_logic_vector (dsize - 1 downto 0);
166 signal read_data_n      : std_logic;
167 signal ppu_latch_rst_n  : std_logic;
168 signal v_bus_busy_n     : std_logic;
169
170 signal oam_bus_ce_n     : std_logic;
171 signal plt_bus_ce_n     : std_logic;
172
173 signal oam_plt_addr     : std_logic_vector (dsize - 1 downto 0);
174 signal oam_plt_data     : std_logic_vector (dsize - 1 downto 0);
175 signal plt_data_out     : std_logic_vector (dsize - 1 downto 0);
176
177 begin
178
179     render_inst : ppu_render port map (clk, rst_n,
180             rd_n, wr_n, ale, vram_ad, vram_a,
181             pos_x, pos_y, nes_r, nes_g, nes_b,
182             ppu_ctrl, ppu_mask, read_status, ppu_status, ppu_scroll_x, ppu_scroll_y,
183             r_nw, oam_bus_ce_n, plt_bus_ce_n, 
184             oam_plt_addr, oam_plt_data, v_bus_busy_n);
185
186     vga_inst : vga_ctl port map (clk, vga_clk, rst_n, 
187             pos_x, pos_y, nes_r, nes_g, nes_b,
188             h_sync_n, v_sync_n, r, g, b);
189
190     --PPU registers.
191     clk_n <= not clk;
192
193     ppu_clk_cnt_inst : counter_register generic map (2, 1)
194             port map (clk_n, ppu_clk_cnt_res_n, '0', '1', (others => '0'), ppu_clk_cnt); 
195
196     ppu_ctrl_inst : d_flip_flop generic map(dsize)
197             port map (clk_n, rst_n, '1', ppu_ctrl_we_n, cpu_d, ppu_ctrl);
198
199     ppu_mask_inst : d_flip_flop generic map(dsize)
200             port map (clk_n, rst_n, '1', ppu_mask_we_n, cpu_d, ppu_mask);
201
202     ppu_status_inst : d_flip_flop generic map(dsize)
203             port map (read_status, rst_n, '1', '0', ppu_status, ppu_stat_out);
204
205     oma_addr_inst : counter_register generic map(dsize, 1)
206             port map (clk_n, rst_n, oam_addr_ce_n, oam_addr_we_n, cpu_d, oam_addr);
207     oma_data_inst : d_flip_flop generic map(dsize)
208             port map (clk_n, rst_n, '1', oam_data_we_n, cpu_d, oam_data);
209
210     ppu_scroll_x_inst : d_flip_flop generic map(dsize)
211             port map (clk_n, rst_n, '1', ppu_scroll_x_we_n, cpu_d, ppu_scroll_x);
212     ppu_scroll_y_inst : d_flip_flop generic map(dsize)
213             port map (clk_n, rst_n, '1', ppu_scroll_y_we_n, cpu_d, ppu_scroll_y);
214     ppu_scroll_cnt_inst : counter_register generic map (1, 1)
215             port map (clk_n, ppu_latch_rst_n, ppu_scroll_cnt_ce_n, 
216                                             '1', (others => '0'), ppu_scroll_cnt);
217
218     ppu_addr_inst_inc1 : counter_register generic map(14, 1)
219             port map (clk_n, rst_n, ppu_data_we_n, ppu_addr_we_n, ppu_addr_in, ppu_addr_inc1);
220     ppu_addr_inst_inc32 : counter_register generic map(14, 32)
221             port map (clk_n, rst_n, ppu_data_we_n, ppu_addr_we_n, ppu_addr_in, ppu_addr_inc32);
222
223     ppu_addr <= ppu_addr_inc32 when ppu_ctrl(PPUVAI) = '1' else
224                 ppu_addr_inc1;
225
226     ppu_addr_cnt_inst : counter_register generic map (1, 1)
227             port map (clk_n, ppu_latch_rst_n, ppu_addr_cnt_ce_n, 
228                                             '1', (others => '0'), ppu_addr_cnt);
229     ppu_data_inst : d_flip_flop generic map(dsize)
230             port map (clk_n, rst_n, '1', ppu_data_we_n, cpu_d, ppu_data);
231
232     ppu_data_in_inst : d_flip_flop generic map(dsize)
233             port map (clk_n, rst_n, '1', ppu_data_we_n, vram_ad, ppu_data_in);
234
235     ppu_data_out_inst : d_flip_flop generic map(dsize)
236             port map (read_data_n, rst_n, '1', '0', ppu_data_in, ppu_data_out);
237
238     plt_data_out_inst : d_flip_flop generic map(dsize)
239             port map (clk_n, rst_n, '1', ppu_data_we_n, oam_plt_data, plt_data_out);
240
241     reg_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d, 
242                         ppu_status(ST_VBL), ppu_ctrl(PPUNEN))
243     begin
244
245         if (ppu_status(ST_VBL)'event or ppu_ctrl(PPUNEN)'event) then
246             if (ppu_status(ST_VBL) = '1' and ppu_ctrl(PPUNEN) = '1') then
247                 --start vblank.
248                 vblank_n <= '0';
249             else
250                 --clear flag.
251                 vblank_n <= '1';
252             end if;
253         end if;
254
255         if (rst_n = '0') then
256             vblank_n <= '1';
257         elsif (rst_n = '1' and ce_n = '0') then
258
259             --register set.
260             if(cpu_addr = PPUCTRL) then
261                 ppu_ctrl_we_n <= '0';
262             else
263                 ppu_ctrl_we_n <= '1';
264             end if;
265
266             if(cpu_addr = PPUMASK) then
267                 ppu_mask_we_n <= '0';
268             else
269                 ppu_mask_we_n <= '1';
270             end if;
271
272             if(cpu_addr = PPUSTATUS and r_nw = '1') then
273                 --notify reading status
274                 read_status <= '1';
275             else
276                 read_status <= '0';
277             end if;
278
279             if(cpu_addr = OAMADDR) then
280                 oam_addr_we_n <= '0';
281             else
282                 oam_addr_we_n <= '1';
283             end if;
284
285             if(cpu_addr = OAMDATA) then
286                 oam_data_we_n <= '0';
287             else
288                 oam_data_we_n <= '1';
289             end if;
290
291             if(cpu_addr = PPUSCROLL) then
292                 ppu_scroll_cnt_ce_n <= '0';
293                 if (ppu_scroll_cnt(0) = '0') then
294                     ppu_scroll_x_we_n <= '0';
295                     ppu_scroll_y_we_n <= '1';
296                 else
297                     ppu_scroll_y_we_n <= '0';
298                     ppu_scroll_x_we_n <= '1';
299                 end if;
300             else
301                 ppu_scroll_x_we_n <= '1';
302                 ppu_scroll_y_we_n <= '1';
303                 ppu_scroll_cnt_ce_n <= '1';
304             end if;
305
306             if(cpu_addr = PPUADDR) then
307                 ppu_addr_we_n <= '0';
308                 if (ppu_addr_cnt(0) = '0') then
309                     ppu_addr_in <= cpu_d(5 downto 0) & ppu_addr(7 downto 0);
310                 else
311                     ppu_addr_in <= ppu_addr(13 downto 8) & cpu_d;
312                 end if;
313             else
314                 ppu_addr_we_n <= '1';
315             end if;
316
317             if (cpu_addr = PPUDATA and r_nw = '1') then
318                 read_data_n <= '0';
319             else
320                 read_data_n <= '1';
321             end if;
322         else
323             ppu_ctrl_we_n    <= '1';
324             ppu_mask_we_n    <= '1';
325             oam_addr_we_n    <= '1';
326             oam_data_we_n    <= '1';
327             ppu_scroll_x_we_n    <= '1';
328             ppu_scroll_y_we_n    <= '1';
329             ppu_scroll_cnt_ce_n  <= '1';
330             ppu_addr_we_n        <= '1';
331             read_status <= '0';
332             read_data_n <= '1';
333         end if; --if (rst_n = '1' and ce_n = '0') 
334
335     end process;
336
337     --cpu and ppu clock timing adjustment...
338     clk_cnt_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d, clk, 
339                                 oam_plt_data, vram_ad, ppu_stat_out)
340     begin
341         if (rst_n = '0') then
342             ppu_latch_rst_n <= '0';
343         elsif (rst_n = '1' and ce_n = '0') then
344             --set counter=0 on register write.   
345             if (ce_n'event or r_nw'event or cpu_addr'event or (cpu_d'event and r_nw = '0')) then
346                 ppu_clk_cnt_res_n <= '0';
347                 --d_print("write event");
348             end if;
349
350             --start counter.
351             if (clk'event and clk = '0') then
352                 if (ppu_clk_cnt = "10") then
353                     ppu_clk_cnt_res_n <= '0';
354                 elsif (ppu_clk_cnt = "00") then
355                     ppu_clk_cnt_res_n <= '1';
356                 end if;
357
358                 if (read_status = '1') then
359                     --reading status resets ppu_addr/scroll cnt.
360                     ppu_latch_rst_n <= '0';
361                 else
362                     ppu_latch_rst_n <= '1';
363                 end if;
364                 --d_print("clk event");
365             end if;
366
367             --oam data set
368             if (cpu_addr = OAMDATA and ppu_clk_cnt = "00") then
369                 oam_bus_ce_n <= '0';
370                 oam_plt_addr <= oam_addr;
371                 if (r_nw = '1') then
372                     oam_plt_data <= (others => 'Z');
373                     cpu_d <= oam_plt_data;
374                 else
375                     oam_plt_data <= cpu_d;
376                 end if;
377                 --address increment for burst write. 
378                 oam_addr_ce_n <= '0';
379             else
380                 cpu_d <= (others => 'Z');
381                 oam_addr_ce_n <= '1';
382                 oam_bus_ce_n <= '1';
383             end if; --if (cpu_addr = OAMDATA and ppu_clk_cnt = "00") then
384
385             --vram address access.
386             if (cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
387                 ppu_addr_cnt_ce_n <= '0';
388                 if (ppu_addr_cnt(0) = '0') then
389                     --load addr high
390                     ale <= '0';
391                 else
392                     --load addr low and output vram/plt bus.
393
394                     --if address is 3fxx, set palette table.
395                     if (ppu_addr(13 downto 8) = "111111") then
396                         oam_plt_addr <= cpu_d;
397                         ale <= '0';
398                     else
399                         vram_ad <= cpu_d;
400                         vram_a <= ppu_addr(13 downto 8);
401                         ale <= '1';
402                     end if;
403                 end if;
404             elsif (cpu_addr = PPUDATA and ppu_clk_cnt = "01") then
405                 ppu_addr_cnt_ce_n <= '1';
406                 --for burst write.
407                 if (ppu_addr(13 downto 8) = "111111") then
408                     oam_plt_addr <= ppu_addr(7 downto 0);
409                     ale <= '0';
410                 else
411                     vram_a <= ppu_addr(13 downto 8);
412                     vram_ad <= ppu_addr(7 downto 0);
413                     ale <= '1';
414                 end if;
415             else
416                 ppu_addr_cnt_ce_n <= '1';
417                 ale <= '0';
418             end if; --if (cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
419
420             if (cpu_addr = PPUDATA and ppu_clk_cnt = "00") then
421                 ppu_data_we_n <= '0';
422                 vram_a <= ppu_addr(13 downto 8);
423                 if (ppu_addr(13 downto 8) = "111111") then
424                     --case palette tbl.
425                     plt_bus_ce_n <= '0';
426                     if (r_nw = '0') then
427                         oam_plt_data <= cpu_d;
428                     else
429                         oam_plt_data <= (others => 'Z');
430                         cpu_d <= oam_plt_data;
431                     end if;
432                     rd_n <= '1';
433                     wr_n <= '1';
434                 else
435                     rd_n <= not r_nw;
436                     wr_n <= r_nw;
437                     plt_bus_ce_n <= '1';
438                     if (r_nw = '0') then
439                         vram_ad <= cpu_d;
440                     else
441                         cpu_d <= ppu_data_out;
442                     end if;
443                 end if;
444             else
445                 plt_bus_ce_n <= '1';
446                 ppu_data_we_n <= '1';
447                 rd_n <= 'Z';
448                 wr_n <= 'Z';
449             end if; --if (cpu_addr = PPUDATA and ppu_clk_cnt = "00") then
450
451             --sustain cpu output data when reading.
452             if (cpu_addr = PPUDATA and r_nw = '1' and ppu_clk_cnt /= "00") then
453                 if (ppu_addr(13 downto 8) = "111111") then
454                     cpu_d <= plt_data_out;
455                 else
456                     cpu_d <= ppu_data_out;
457                 end if;
458             end if;
459             if (cpu_addr = OAMDATA and r_nw = '1' and ppu_clk_cnt /= "00") then
460                 cpu_d <= oam_data;
461             end if;
462
463             if(cpu_addr = PPUSTATUS and r_nw = '1') then
464                 cpu_d <= ppu_stat_out;
465             end if;
466
467         else
468             ppu_data_we_n    <= '1';
469             plt_bus_ce_n <= '1';
470             ppu_clk_cnt_res_n <= '0';
471             oam_bus_ce_n     <= '1';
472             oam_addr_ce_n <= '1';
473             ppu_addr_cnt_ce_n    <= '1';
474             ppu_latch_rst_n <= '1';
475
476             rd_n <= 'Z';
477             wr_n <= 'Z';
478             ale <= 'Z';
479             oam_plt_data <= (others => 'Z');
480             vram_ad <= (others => 'Z');
481             vram_a <= (others => 'Z');
482             cpu_d <= (others => 'Z');
483         end if; --if (rst_n = '0') then
484     end process;
485
486 end rtl;
487