2 use ieee.std_logic_1164.all;
3 use work.motonesfpga_common.all;
7 signal dbg_ppu_ce_n : out std_logic;
8 signal dbg_ppu_ctrl, dbg_ppu_mask, dbg_ppu_status : out std_logic_vector (7 downto 0);
9 signal dbg_ppu_addr : out std_logic_vector (13 downto 0);
10 signal dbg_ppu_data, dbg_ppu_scrl_x, dbg_ppu_scrl_y : out std_logic_vector (7 downto 0);
12 signal dbg_ppu_clk : out std_logic;
13 signal dbg_nes_x : out std_logic_vector (8 downto 0);
14 signal dbg_vga_x : out std_logic_vector (9 downto 0);
15 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
16 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
17 signal dbg_ppu_addr_we_n : out std_logic;
18 signal dbg_ppu_clk_cnt : out std_logic_vector(1 downto 0);
22 mem_clk : in std_logic;
26 cpu_addr : in std_logic_vector (2 downto 0);
27 cpu_d : inout std_logic_vector (7 downto 0);
29 vblank_n : out std_logic;
33 vram_ad : inout std_logic_vector (7 downto 0);
34 vram_a : out std_logic_vector (13 downto 8);
36 vga_clk : in std_logic;
37 h_sync_n : out std_logic;
38 v_sync_n : out std_logic;
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)
46 architecture rtl of ppu is
50 signal dbg_ppu_clk : out std_logic;
51 signal dbg_nes_x : out std_logic_vector (8 downto 0);
52 signal dbg_vga_x : out std_logic_vector (9 downto 0);
53 signal dbg_disp_nt, dbg_disp_attr : out std_logic_vector (7 downto 0);
54 signal dbg_disp_ptn_h, dbg_disp_ptn_l : out std_logic_vector (15 downto 0);
58 vga_clk : in std_logic;
59 mem_clk : in std_logic;
64 vram_ad : inout std_logic_vector (7 downto 0);
65 vram_a : out std_logic_vector (13 downto 8);
67 h_sync_n : out std_logic;
68 v_sync_n : out std_logic;
69 r : out std_logic_vector (3 downto 0);
70 g : out std_logic_vector (3 downto 0);
71 b : out std_logic_vector (3 downto 0);
73 ppu_ctrl : in std_logic_vector (7 downto 0);
74 ppu_mask : in std_logic_vector (7 downto 0);
75 read_status : in std_logic;
76 ppu_scroll_x : in std_logic_vector (7 downto 0);
77 ppu_scroll_y : in std_logic_vector (7 downto 0);
78 ppu_status : out std_logic_vector (7 downto 0);
79 v_bus_busy_n : out std_logic;
82 oam_bus_ce_n : in std_logic;
83 plt_bus_ce_n : in std_logic;
84 oam_plt_addr : in std_logic_vector (7 downto 0);
85 oam_plt_data : inout std_logic_vector (7 downto 0)
98 d : in std_logic_vector (dsize - 1 downto 0);
99 q : out std_logic_vector (dsize - 1 downto 0)
103 component counter_register
105 dsize : integer := 8;
108 port ( clk : in std_logic;
109 rst_n : in std_logic;
112 d : in std_logic_vector(dsize - 1 downto 0);
113 q : out std_logic_vector(dsize - 1 downto 0)
117 constant dsize : integer := 8;
119 constant PPUCTRL : std_logic_vector(2 downto 0) := "000";
120 constant PPUMASK : std_logic_vector(2 downto 0) := "001";
121 constant PPUSTATUS : std_logic_vector(2 downto 0) := "010";
122 constant OAMADDR : std_logic_vector(2 downto 0) := "011";
123 constant OAMDATA : std_logic_vector(2 downto 0) := "100";
124 constant PPUSCROLL : std_logic_vector(2 downto 0) := "101";
125 constant PPUADDR : std_logic_vector(2 downto 0) := "110";
126 constant PPUDATA : std_logic_vector(2 downto 0) := "111";
128 constant PPUVAI : integer := 2; --vram address increment
129 constant PPUNEN : integer := 7; --nmi enable
130 constant ST_VBL : integer := 7; --vblank
132 signal clk_n : std_logic;
134 signal ppu_clk_cnt_res_n : std_logic;
135 signal ppu_clk_cnt : std_logic_vector(1 downto 0);
137 signal ppu_ctrl_we_n : std_logic;
138 signal ppu_mask_we_n : std_logic;
139 signal oam_addr_ce_n : std_logic;
140 signal oam_addr_we_n : std_logic;
141 signal oam_data_we_n : std_logic;
142 signal ppu_scroll_x_we_n : std_logic;
143 signal ppu_scroll_y_we_n : std_logic;
144 signal ppu_scroll_cnt_ce_n : std_logic;
145 signal ppu_addr_we_n : std_logic;
146 signal ppu_addr_cnt_ce_n : std_logic;
147 signal ppu_data_we_n : std_logic;
149 signal ppu_ctrl : std_logic_vector (dsize - 1 downto 0);
150 signal ppu_mask : std_logic_vector (dsize - 1 downto 0);
151 signal read_status : std_logic;
152 signal ppu_status : std_logic_vector (dsize - 1 downto 0);
153 signal ppu_stat_out : std_logic_vector (dsize - 1 downto 0);
154 signal oam_addr : std_logic_vector (dsize - 1 downto 0);
155 signal oam_data : std_logic_vector (dsize - 1 downto 0);
156 signal ppu_scroll_x : std_logic_vector (dsize - 1 downto 0);
157 signal ppu_scroll_y : std_logic_vector (dsize - 1 downto 0);
158 signal ppu_scroll_cnt : std_logic_vector (0 downto 0);
159 signal ppu_addr : std_logic_vector (13 downto 0);
160 signal ppu_addr_inc1 : std_logic_vector (13 downto 0);
161 signal ppu_addr_inc32 : std_logic_vector (13 downto 0);
162 signal ppu_addr_in : std_logic_vector (13 downto 0);
163 signal ppu_addr_cnt : std_logic_vector (0 downto 0);
164 signal ppu_data : std_logic_vector (dsize - 1 downto 0);
165 signal ppu_data_in : std_logic_vector (dsize - 1 downto 0);
166 signal ppu_data_out : std_logic_vector (dsize - 1 downto 0);
167 signal read_data_n : std_logic;
168 signal ppu_latch_rst_n : std_logic;
169 signal v_bus_busy_n : std_logic;
171 signal oam_bus_ce_n : std_logic;
172 signal plt_bus_ce_n : std_logic;
174 signal oam_plt_addr : std_logic_vector (dsize - 1 downto 0);
175 signal oam_plt_data : std_logic_vector (dsize - 1 downto 0);
176 signal plt_data_out : std_logic_vector (dsize - 1 downto 0);
181 dbg_ppu_ce_n <= ce_n;
182 dbg_ppu_ctrl <= ppu_ctrl;
183 dbg_ppu_mask <= ppu_mask;
184 dbg_ppu_status <= ppu_status;
185 dbg_ppu_addr <= ppu_addr;
186 dbg_ppu_data <= ppu_data;
187 dbg_ppu_scrl_x <= ppu_scroll_x;
188 dbg_ppu_scrl_y <= ppu_scroll_y;
189 dbg_ppu_addr_we_n <= ppu_addr_we_n;
190 dbg_ppu_clk_cnt <= ppu_clk_cnt;
194 render_inst : ppu_render port map (
198 dbg_disp_nt, dbg_disp_attr, dbg_disp_ptn_h, dbg_disp_ptn_l,
200 clk, vga_clk, mem_clk, rst_n,
201 rd_n, wr_n, ale, vram_ad, vram_a,
202 h_sync_n, v_sync_n, r, g, b,
203 ppu_ctrl, ppu_mask, read_status, ppu_scroll_x, ppu_scroll_y,
204 ppu_status, v_bus_busy_n,
205 r_nw, oam_bus_ce_n, plt_bus_ce_n,
206 oam_plt_addr, oam_plt_data);
211 ppu_clk_cnt_inst : counter_register generic map (2, 1)
212 port map (clk_n, ppu_clk_cnt_res_n, '0', '1', (others => '0'), ppu_clk_cnt);
214 ppu_ctrl_inst : d_flip_flop generic map(dsize)
215 port map (clk_n, rst_n, '1', ppu_ctrl_we_n, cpu_d, ppu_ctrl);
217 ppu_mask_inst : d_flip_flop generic map(dsize)
218 port map (clk_n, rst_n, '1', ppu_mask_we_n, cpu_d, ppu_mask);
220 ppu_status_inst : d_flip_flop generic map(dsize)
221 port map (read_status, rst_n, '1', '0', ppu_status, ppu_stat_out);
223 oma_addr_inst : counter_register generic map(dsize, 1)
224 port map (clk_n, rst_n, oam_addr_ce_n, oam_addr_we_n, cpu_d, oam_addr);
225 oma_data_inst : d_flip_flop generic map(dsize)
226 port map (clk_n, rst_n, '1', oam_data_we_n, cpu_d, oam_data);
228 ppu_scroll_x_inst : d_flip_flop generic map(dsize)
229 port map (clk_n, rst_n, '1', ppu_scroll_x_we_n, cpu_d, ppu_scroll_x);
230 ppu_scroll_y_inst : d_flip_flop generic map(dsize)
231 port map (clk_n, rst_n, '1', ppu_scroll_y_we_n, cpu_d, ppu_scroll_y);
232 ppu_scroll_cnt_inst : counter_register generic map (1, 1)
233 port map (clk_n, ppu_latch_rst_n, ppu_scroll_cnt_ce_n,
234 '1', (others => '0'), ppu_scroll_cnt);
236 ppu_addr_inst_inc1 : counter_register generic map(14, 1)
237 port map (clk_n, rst_n, ppu_data_we_n, ppu_addr_we_n, ppu_addr_in, ppu_addr_inc1);
238 ppu_addr_inst_inc32 : counter_register generic map(14, 32)
239 port map (clk_n, rst_n, ppu_data_we_n, ppu_addr_we_n, ppu_addr_in, ppu_addr_inc32);
241 ppu_addr <= ppu_addr_inc32 when ppu_ctrl(PPUVAI) = '1' else
244 ppu_addr_cnt_inst : counter_register generic map (1, 1)
245 port map (clk_n, ppu_latch_rst_n, ppu_addr_cnt_ce_n,
246 '1', (others => '0'), ppu_addr_cnt);
247 ppu_data_inst : d_flip_flop generic map(dsize)
248 port map (clk_n, rst_n, '1', ppu_data_we_n, cpu_d, ppu_data);
250 ppu_data_in_inst : d_flip_flop generic map(dsize)
251 port map (clk_n, rst_n, '1', ppu_data_we_n, vram_ad, ppu_data_in);
253 ppu_data_out_inst : d_flip_flop generic map(dsize)
254 port map (read_data_n, rst_n, '1', '0', ppu_data_in, ppu_data_out);
256 plt_data_out_inst : d_flip_flop generic map(dsize)
257 port map (clk_n, rst_n, '1', ppu_data_we_n, oam_plt_data, plt_data_out);
259 reg_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d,
260 ppu_status(ST_VBL), ppu_ctrl(PPUNEN))
263 -- if (ppu_status(ST_VBL)'event or ppu_ctrl(PPUNEN)'event) then
264 -- if (ppu_status(ST_VBL) = '1' and ppu_ctrl(PPUNEN) = '1') then
273 if (rst_n = '0') then
275 elsif (rst_n = '1' and ce_n = '0') then
278 if(cpu_addr = PPUCTRL) then
279 ppu_ctrl_we_n <= '0';
281 ppu_ctrl_we_n <= '1';
284 if(cpu_addr = PPUMASK) then
285 ppu_mask_we_n <= '0';
287 ppu_mask_we_n <= '1';
290 if(cpu_addr = PPUSTATUS and r_nw = '1') then
291 --notify reading status
297 if(cpu_addr = OAMADDR) then
298 oam_addr_we_n <= '0';
300 oam_addr_we_n <= '1';
303 if(cpu_addr = OAMDATA) then
304 oam_data_we_n <= '0';
306 oam_data_we_n <= '1';
309 if(cpu_addr = PPUSCROLL) then
310 ppu_scroll_cnt_ce_n <= '0';
311 if (ppu_scroll_cnt(0) = '0') then
312 ppu_scroll_x_we_n <= '0';
313 ppu_scroll_y_we_n <= '1';
315 ppu_scroll_y_we_n <= '0';
316 ppu_scroll_x_we_n <= '1';
319 ppu_scroll_x_we_n <= '1';
320 ppu_scroll_y_we_n <= '1';
321 ppu_scroll_cnt_ce_n <= '1';
324 if(cpu_addr = PPUADDR) then
325 if (ppu_addr_cnt(0) = '0') then
326 ppu_addr_in <= cpu_d(5 downto 0) & ppu_addr(7 downto 0);
328 ppu_addr_in <= ppu_addr(13 downto 8) & cpu_d;
332 if (cpu_addr = PPUDATA and r_nw = '1') then
338 ppu_ctrl_we_n <= '1';
339 ppu_mask_we_n <= '1';
340 oam_addr_we_n <= '1';
341 oam_data_we_n <= '1';
342 ppu_scroll_x_we_n <= '1';
343 ppu_scroll_y_we_n <= '1';
344 ppu_scroll_cnt_ce_n <= '1';
347 end if; --if (rst_n = '1' and ce_n = '0')
351 ppu_clk_cnt_res_n <= not ce_n;
353 --cpu and ppu clock timing adjustment...
354 clk_cnt_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d, clk,
355 oam_plt_data, vram_ad, ppu_stat_out)
357 if (rst_n = '0') then
358 ppu_latch_rst_n <= '0';
359 ppu_addr_we_n <= '1';
363 oam_plt_data <= (others => 'Z');
364 vram_ad <= (others => 'Z');
365 vram_a <= (others => 'Z');
366 cpu_d <= (others => 'Z');
367 elsif (rst_n = '1' and ce_n = '0') then
368 --set counter=0 on register write.
369 -- if (ce_n'event or r_nw'event or cpu_addr'event or (cpu_d'event and r_nw = '0')) then
370 -- ppu_clk_cnt_res_n <= '0';
371 -- --d_print("write event");
375 if (clk'event and clk = '0') then
376 if (read_status = '1') then
377 --reading status resets ppu_addr/scroll cnt.
378 ppu_latch_rst_n <= '0';
380 ppu_latch_rst_n <= '1';
382 --d_print("clk event");
386 if (cpu_addr = OAMDATA and ppu_clk_cnt = "00") then
388 oam_plt_addr <= oam_addr;
390 oam_plt_data <= (others => 'Z');
391 cpu_d <= oam_plt_data;
393 oam_plt_data <= cpu_d;
395 --address increment for burst write.
396 oam_addr_ce_n <= '0';
398 cpu_d <= (others => 'Z');
399 oam_addr_ce_n <= '1';
401 end if; --if (cpu_addr = OAMDATA and ppu_clk_cnt = "00") then
403 --vram address access.
404 if(cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
405 ppu_addr_we_n <= '0';
407 ppu_addr_we_n <= '1';
410 if (cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
411 ppu_addr_cnt_ce_n <= '0';
412 if (ppu_addr_cnt(0) = '0') then
416 --load addr low and output vram/plt bus.
418 --if address is 3fxx, set palette table.
419 if (ppu_addr(13 downto 8) = "111111") then
420 oam_plt_addr <= cpu_d;
424 vram_a <= ppu_addr(13 downto 8);
428 elsif (cpu_addr = PPUDATA and ppu_clk_cnt = "01") then
429 ppu_addr_cnt_ce_n <= '1';
431 if (ppu_addr(13 downto 8) = "111111") then
432 oam_plt_addr <= ppu_addr(7 downto 0);
435 vram_a <= ppu_addr(13 downto 8);
436 vram_ad <= ppu_addr(7 downto 0);
440 ppu_addr_cnt_ce_n <= '1';
442 end if; --if (cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
444 if (cpu_addr = PPUDATA and ppu_clk_cnt = "00") then
445 ppu_data_we_n <= '0';
446 vram_a <= ppu_addr(13 downto 8);
447 if (ppu_addr(13 downto 8) = "111111") then
451 oam_plt_data <= cpu_d;
453 oam_plt_data <= (others => 'Z');
454 cpu_d <= oam_plt_data;
465 cpu_d <= ppu_data_out;
470 ppu_data_we_n <= '1';
473 end if; --if (cpu_addr = PPUDATA and ppu_clk_cnt = "00") then
475 --sustain cpu output data when reading.
476 if (cpu_addr = PPUDATA and r_nw = '1' and ppu_clk_cnt /= "00") then
477 if (ppu_addr(13 downto 8) = "111111") then
478 cpu_d <= plt_data_out;
480 cpu_d <= ppu_data_out;
483 if (cpu_addr = OAMDATA and r_nw = '1' and ppu_clk_cnt /= "00") then
487 if(cpu_addr = PPUSTATUS and r_nw = '1') then
488 cpu_d <= ppu_stat_out;
492 ppu_addr_we_n <= '1';
493 ppu_data_we_n <= '1';
496 oam_addr_ce_n <= '1';
497 ppu_addr_cnt_ce_n <= '1';
498 ppu_latch_rst_n <= '1';
503 oam_plt_data <= (others => 'Z');
504 vram_ad <= (others => 'Z');
505 vram_a <= (others => 'Z');
506 cpu_d <= (others => 'Z');
507 end if; --if (rst_n = '0') then