OSDN Git Service

code clean up.
[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             vblank_n    : out std_logic;
32             rd_n        : out std_logic;
33             wr_n        : out std_logic;
34             ale         : out std_logic;
35             vram_ad     : inout std_logic_vector (7 downto 0);
36             vram_a      : out std_logic_vector (13 downto 8);
37             pos_x       : out std_logic_vector (8 downto 0);
38             pos_y       : out std_logic_vector (8 downto 0);
39             r           : out std_logic_vector (3 downto 0);
40             g           : out std_logic_vector (3 downto 0);
41             b           : out std_logic_vector (3 downto 0);
42             ppu_ctrl        : in std_logic_vector (7 downto 0);
43             ppu_mask        : in std_logic_vector (7 downto 0);
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     );
53 end component;
54
55 component vga_ctl
56     port (  ppu_clk     : in std_logic;
57             vga_clk     : in std_logic;
58             rst_n       : in std_logic;
59             pos_x       : in std_logic_vector (8 downto 0);
60             pos_y       : in std_logic_vector (8 downto 0);
61             nes_r       : in std_logic_vector (3 downto 0);
62             nes_g       : in std_logic_vector (3 downto 0);
63             nes_b       : in std_logic_vector (3 downto 0);
64             h_sync_n    : out std_logic;
65             v_sync_n    : out std_logic;
66             r           : out std_logic_vector(3 downto 0);
67             g           : out std_logic_vector(3 downto 0);
68             b           : out std_logic_vector(3 downto 0)
69     );
70 end component;
71
72 component d_flip_flop
73     generic (
74             dsize : integer := 8
75             );
76     port (
77             clk     : in std_logic;
78             res_n   : in std_logic;
79             set_n   : in std_logic;
80             we_n    : in std_logic;
81             d       : in std_logic_vector (dsize - 1 downto 0);
82             q       : out std_logic_vector (dsize - 1 downto 0)
83         );
84 end component;
85
86 component counter_register
87     generic (
88         dsize       : integer := 8;
89         inc         : integer := 1
90     );
91     port (  clk         : in std_logic;
92             rst_n       : in std_logic;
93             ce_n        : in std_logic;
94             we_n        : in std_logic;
95             d           : in std_logic_vector(dsize - 1 downto 0);
96             q           : out std_logic_vector(dsize - 1 downto 0)
97     );
98 end component;
99
100 procedure d_print(msg : string) is
101 use std.textio.all;
102 use ieee.std_logic_textio.all;
103 variable out_l : line;
104 begin
105     write(out_l, msg);
106     writeline(output, out_l);
107 end  procedure;
108
109 signal pos_x       : std_logic_vector (8 downto 0);
110 signal pos_y       : std_logic_vector (8 downto 0);
111 signal nes_r       : std_logic_vector (3 downto 0);
112 signal nes_g       : std_logic_vector (3 downto 0);
113 signal nes_b       : std_logic_vector (3 downto 0);
114
115 constant dsize     : integer := 8;
116
117 constant PPUCTRL   : std_logic_vector(2 downto 0) := "000";
118 constant PPUMASK   : std_logic_vector(2 downto 0) := "001";
119 constant PPUSTATUS : std_logic_vector(2 downto 0) := "010";
120 constant OAMADDR   : std_logic_vector(2 downto 0) := "011";
121 constant OAMDATA   : std_logic_vector(2 downto 0) := "100";
122 constant PPUSCROLL : std_logic_vector(2 downto 0) := "101";
123 constant PPUADDR   : std_logic_vector(2 downto 0) := "110";
124 constant PPUDATA   : std_logic_vector(2 downto 0) := "111";
125
126 signal clk_n            : std_logic;
127
128 signal ppu_clk_cnt_res_n    : std_logic;
129 signal ppu_clk_cnt          : std_logic_vector(1 downto 0);
130
131 signal ppu_ctrl_we_n    : std_logic;
132 signal ppu_mask_we_n    : std_logic;
133 signal ppu_status_we_n  : std_logic;
134 signal oam_addr_ce_n    : std_logic;
135 signal oam_addr_we_n    : std_logic;
136 signal oam_data_we_n    : std_logic;
137 signal ppu_scroll_x_we_n    : std_logic;
138 signal ppu_scroll_y_we_n    : std_logic;
139 signal ppu_scroll_cnt_ce_n  : std_logic;
140 signal ppu_addr_we_n        : std_logic;
141 signal ppu_addr_cnt_ce_n    : std_logic;
142 signal ppu_data_we_n    : std_logic;
143
144 signal ppu_ctrl         : std_logic_vector (dsize - 1 downto 0);
145 signal ppu_mask         : std_logic_vector (dsize - 1 downto 0);
146 signal ppu_status       : std_logic_vector (dsize - 1 downto 0);
147 signal oam_addr         : std_logic_vector (dsize - 1 downto 0);
148 signal oam_data         : std_logic_vector (dsize - 1 downto 0);
149 signal ppu_scroll_x     : std_logic_vector (dsize - 1 downto 0);
150 signal ppu_scroll_y     : std_logic_vector (dsize - 1 downto 0);
151 signal ppu_scroll_cnt   : std_logic_vector (0 downto 0);
152 signal ppu_addr         : std_logic_vector (13 downto 0);
153 signal ppu_addr_in      : std_logic_vector (13 downto 0);
154 signal ppu_addr_cnt     : std_logic_vector (0 downto 0);
155 signal ppu_data         : std_logic_vector (dsize - 1 downto 0);
156
157 signal oam_bus_ce_n     : std_logic;
158 signal plt_bus_ce_n     : std_logic;
159
160 signal oam_plt_addr     : std_logic_vector (7 downto 0);
161 signal oam_plt_data     : std_logic_vector (7 downto 0);
162
163 begin
164
165     render_inst : ppu_render port map (clk, rst_n, vblank_n, 
166             rd_n, wr_n, ale, vram_ad, vram_a,
167             pos_x, pos_y, nes_r, nes_g, nes_b,
168             ppu_ctrl, ppu_mask, ppu_status, ppu_scroll_x, ppu_scroll_y,
169             r_nw, oam_bus_ce_n, plt_bus_ce_n, 
170             oam_plt_addr, oam_plt_data);
171
172     vga_inst : vga_ctl port map (clk, vga_clk, rst_n, 
173             pos_x, pos_y, nes_r, nes_g, nes_b,
174             h_sync_n, v_sync_n, r, g, b);
175
176     --PPU registers.
177     clk_n <= not clk;
178
179     ppu_clk_cnt_inst : counter_register generic map (2, 1)
180             port map (clk_n, ppu_clk_cnt_res_n, '0', '1', (others => '0'), ppu_clk_cnt); 
181
182     ppu_ctrl_inst : d_flip_flop generic map(dsize)
183             port map (clk_n, rst_n, '1', ppu_ctrl_we_n, cpu_d, ppu_ctrl);
184
185     ppu_mask_inst : d_flip_flop generic map(dsize)
186             port map (clk_n, rst_n, '1', ppu_mask_we_n, cpu_d, ppu_mask);
187
188     ppu_status_inst : d_flip_flop generic map(dsize)
189             port map (clk_n, rst_n, '1', ppu_status_we_n, cpu_d, ppu_status);
190
191     oma_addr_inst : counter_register generic map(dsize, 1)
192             port map (clk_n, rst_n, oam_addr_ce_n, oam_addr_we_n, cpu_d, oam_addr);
193     oma_data_inst : d_flip_flop generic map(dsize)
194             port map (clk_n, rst_n, '1', oam_data_we_n, cpu_d, oam_data);
195
196     ppu_scroll_x_inst : d_flip_flop generic map(dsize)
197             port map (clk_n, rst_n, '1', ppu_scroll_x_we_n, cpu_d, ppu_scroll_x);
198     ppu_scroll_y_inst : d_flip_flop generic map(dsize)
199             port map (clk_n, rst_n, '1', ppu_scroll_y_we_n, cpu_d, ppu_scroll_y);
200     ppu_scroll_cnt_inst : counter_register generic map (1, 1)
201             port map (clk_n, rst_n, ppu_scroll_cnt_ce_n, '1', (others => '0'), ppu_scroll_cnt);
202
203     ppu_addr_inst : counter_register generic map(14, 1)
204             port map (clk_n, rst_n, ppu_data_we_n, ppu_addr_we_n, ppu_addr_in, ppu_addr);
205     ppu_addr_cnt_inst : counter_register generic map (1, 1)
206             port map (clk_n, rst_n, ppu_addr_cnt_ce_n, '1', (others => '0'), ppu_addr_cnt);
207     ppu_data_inst : d_flip_flop generic map(dsize)
208             port map (clk_n, rst_n, '1', ppu_data_we_n, cpu_d, ppu_data);
209
210
211     reg_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d)
212     begin
213
214         if (rst_n = '1' and ce_n = '0') then
215
216             --register set.
217             if(cpu_addr = PPUCTRL) then
218                 ppu_ctrl_we_n <= '0';
219             else
220                 ppu_ctrl_we_n <= '1';
221             end if;
222
223             if(cpu_addr = PPUMASK) then
224                 ppu_mask_we_n <= '0';
225             else
226                 ppu_mask_we_n <= '1';
227             end if;
228
229             if(cpu_addr = PPUSTATUS) then
230                 ppu_status_we_n <= '0';
231             else
232                 ppu_status_we_n <= '1';
233             end if;
234
235             if(cpu_addr = OAMADDR) then
236                 oam_addr_we_n <= '0';
237             else
238                 oam_addr_we_n <= '1';
239             end if;
240
241             if(cpu_addr = OAMDATA) then
242                 oam_data_we_n <= '0';
243             else
244                 oam_data_we_n <= '1';
245             end if;
246
247             if(cpu_addr = PPUSCROLL) then
248                 ppu_scroll_cnt_ce_n <= '0';
249                 if (ppu_scroll_cnt(0) = '0') then
250                     ppu_scroll_x_we_n <= '0';
251                     ppu_scroll_y_we_n <= '1';
252                 else
253                     ppu_scroll_y_we_n <= '0';
254                     ppu_scroll_x_we_n <= '1';
255                 end if;
256             else
257                 ppu_scroll_x_we_n <= '1';
258                 ppu_scroll_y_we_n <= '1';
259                 ppu_scroll_cnt_ce_n <= '1';
260             end if;
261
262             if(cpu_addr = PPUADDR) then
263                 ppu_addr_cnt_ce_n <= '0';
264                 ppu_addr_we_n <= '0';
265                 if (ppu_addr_cnt(0) = '0') then
266                     ppu_addr_in <= cpu_d(5 downto 0) & ppu_addr(7 downto 0);
267                 else
268                     ppu_addr_in <= ppu_addr(13 downto 8) & cpu_d;
269                 end if;
270             else
271                 ppu_addr_cnt_ce_n <= '1';
272                 ppu_addr_we_n <= '1';
273             end if;
274         else
275             ppu_ctrl_we_n    <= '1';
276             ppu_mask_we_n    <= '1';
277             ppu_status_we_n  <= '1';
278             oam_addr_we_n    <= '1';
279             oam_data_we_n    <= '1';
280             ppu_scroll_x_we_n    <= '1';
281             ppu_scroll_y_we_n    <= '1';
282             ppu_scroll_cnt_ce_n  <= '1';
283             ppu_addr_we_n        <= '1';
284             ppu_addr_cnt_ce_n    <= '1';
285         end if; --if (rst_n = '1' and ce_n = '0') 
286
287     end process;
288
289     --cpu and ppu clock timing adjustment...
290     clk_cnt_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d, clk, oam_plt_data, vram_ad)
291     begin
292         if (rst_n = '1' and ce_n = '0') then
293             --set counter=0 on register write.   
294             if (ce_n'event or r_nw'event or cpu_addr'event or (cpu_d'event and r_nw = '0')) then
295                 ppu_clk_cnt_res_n <= '0';
296                 --d_print("write event");
297             end if;
298
299             --start counter.
300             if (clk'event and clk = '0') then
301                 if (ppu_clk_cnt = "10") then
302                     ppu_clk_cnt_res_n <= '0';
303                 elsif (ppu_clk_cnt = "00") then
304                     ppu_clk_cnt_res_n <= '1';
305                 end if;
306                 --d_print("clk event");
307             end if;
308
309             --oam data set
310             if (cpu_addr = OAMDATA and ppu_clk_cnt = "00") then
311                 oam_bus_ce_n <= '0';
312                 oam_plt_addr <= oam_addr;
313                 if (r_nw = '1') then
314                     oam_plt_data <= (others => 'Z');
315                     cpu_d <= oam_plt_data;
316                 else
317                     oam_plt_data <= cpu_d;
318                 end if;
319                 --address increment for burst write. 
320                 oam_addr_ce_n <= '0';
321             else
322                 cpu_d <= (others => 'Z');
323                 oam_addr_ce_n <= '1';
324                 oam_bus_ce_n <= '1';
325             end if;
326
327             --vram address access.
328             if (cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
329                 if (ppu_addr_cnt(0) = '0') then
330                     --load addr high
331                     ale <= '0';
332                 else
333                     --load addr low and output vram/plt bus.
334
335                     --if address is 3fxx, set palette table.
336                     if (ppu_addr(13 downto 8) = "111111") then
337                         oam_plt_addr <= cpu_d;
338                         ale <= '0';
339                     else
340                         vram_ad <= cpu_d;
341                         vram_a <= ppu_addr(13 downto 8);
342                         ale <= '1';
343                     end if;
344                 end if;
345             elsif (cpu_addr = PPUDATA and ppu_clk_cnt = "01") then
346                 --for burst write.
347                 if (ppu_addr(13 downto 8) = "111111") then
348                     oam_plt_addr <= ppu_addr(7 downto 0);
349                     ale <= '0';
350                 else
351                     vram_a <= ppu_addr(13 downto 8);
352                     vram_ad <= ppu_addr(7 downto 0);
353                     ale <= '1';
354                 end if;
355             else
356                 ale <= '0';
357             end if;
358
359             if (cpu_addr = PPUDATA and ppu_clk_cnt = "00") then
360                 ppu_data_we_n <= '0';
361                 if (ppu_addr(13 downto 8) = "111111") then
362                     --case palette tbl.
363                     plt_bus_ce_n <= '0';
364                     if (r_nw = '0') then
365                         oam_plt_data <= cpu_d;
366                     else
367                         oam_plt_data <= (others => 'Z');
368                         cpu_d <= oam_plt_data;
369                     end if;
370                     rd_n <= '1';
371                     wr_n <= '1';
372                 else
373                     rd_n <= not r_nw;
374                     wr_n <= r_nw;
375                     plt_bus_ce_n <= '1';
376                     if (r_nw = '0') then
377                         vram_ad <= cpu_d;
378                     else
379                         vram_ad <= (others => 'Z');
380                         cpu_d <= vram_ad;
381                     end if;
382                 end if;
383             else
384                 plt_bus_ce_n <= '1';
385                 ppu_data_we_n <= '1';
386                 rd_n <= '1';
387                 wr_n <= '1';
388             end if;
389
390             --sustain cpu output data when reading.
391             if (cpu_addr = PPUDATA and r_nw = '1' and ppu_clk_cnt /= "00") then
392                 cpu_d <= ppu_data;
393             end if;
394             if (cpu_addr = OAMDATA and r_nw = '1' and ppu_clk_cnt /= "00") then
395                 cpu_d <= oam_data;
396             end if;
397
398         else
399             ppu_data_we_n    <= '1';
400             plt_bus_ce_n <= '1';
401             ppu_clk_cnt_res_n <= '0';
402             oam_bus_ce_n     <= '1';
403             oam_addr_ce_n <= '1';
404
405             rd_n <= 'Z';
406             wr_n <= 'Z';
407             ale <= 'Z';
408             oam_plt_data <= (others => 'Z');
409             vram_ad <= (others => 'Z');
410             vram_a <= (others => 'Z');
411             cpu_d <= (others => 'Z');
412         end if;
413     end process;
414
415 end rtl;
416