2 use ieee.std_logic_1164.all;
5 port ( clk : 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;
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)
26 architecture rtl of ppu is
29 port ( clk : in std_logic;
31 vblank_n : 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);
48 oam_bus_ce_n : in std_logic;
49 plt_bus_ce_n : in std_logic;
50 oma_plt_addr : in std_logic_vector (7 downto 0);
51 oma_plt_data : inout std_logic_vector (7 downto 0)
56 port ( ppu_clk : in std_logic;
57 vga_clk : 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)
81 d : in std_logic_vector (dsize - 1 downto 0);
82 q : out std_logic_vector (dsize - 1 downto 0)
86 component counter_register
91 port ( clk : in std_logic;
95 d : in std_logic_vector(dsize - 1 downto 0);
96 q : out std_logic_vector(dsize - 1 downto 0)
100 procedure d_print(msg : string) is
102 use ieee.std_logic_textio.all;
103 variable out_l : line;
106 writeline(output, out_l);
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);
115 constant dsize : integer := 8;
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";
126 signal clk_n : std_logic;
128 signal ppu_clk_cnt_res_n : std_logic;
129 signal ppu_clk_cnt : std_logic_vector(1 downto 0);
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;
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);
157 signal oam_bus_ce_n : std_logic;
158 signal plt_bus_ce_n : std_logic;
160 signal oma_plt_addr : std_logic_vector (7 downto 0);
161 signal oma_plt_data : std_logic_vector (7 downto 0);
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 oma_plt_addr, oma_plt_data);
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);
179 ppu_clk_cnt_inst : counter_register generic map (2, 1)
180 port map (clk_n, ppu_clk_cnt_res_n, '1', '0', (others => '0'), ppu_clk_cnt);
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);
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);
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);
191 oma_addr_inst : counter_register generic map(dsize, 1)
192 port map (clk_n, rst_n, oam_addr_we_n, oam_addr_ce_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);
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, '1', ppu_scroll_cnt_ce_n, (others => '0'), ppu_scroll_cnt);
203 ppu_addr_inst : counter_register generic map(14, 1)
204 port map (clk_n, rst_n, ppu_addr_we_n, ppu_data_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, '1', ppu_addr_cnt_ce_n, (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);
211 reg_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d)
214 if (rst_n = '1' and ce_n = '0') then
217 if(cpu_addr = PPUCTRL) then
218 ppu_ctrl_we_n <= '0';
220 ppu_ctrl_we_n <= '1';
223 if(cpu_addr = PPUMASK) then
224 ppu_mask_we_n <= '0';
226 ppu_mask_we_n <= '1';
229 if(cpu_addr = PPUSTATUS) then
230 ppu_status_we_n <= '0';
232 ppu_status_we_n <= '1';
235 if(cpu_addr = OAMADDR) then
236 oam_addr_we_n <= '0';
238 oam_addr_we_n <= '1';
241 if(cpu_addr = OAMDATA) then
242 oam_data_we_n <= '0';
244 oam_data_we_n <= '1';
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';
253 ppu_scroll_y_we_n <= '0';
254 ppu_scroll_x_we_n <= '1';
257 ppu_scroll_x_we_n <= '1';
258 ppu_scroll_y_we_n <= '1';
259 ppu_scroll_cnt_ce_n <= '1';
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);
268 ppu_addr_in <= ppu_addr(13 downto 8) & cpu_d;
271 ppu_addr_cnt_ce_n <= '1';
272 ppu_addr_we_n <= '1';
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')
289 --cpu and ppu clock timing adjustment...
290 clk_cnt_set_p : process (rst_n, ce_n, r_nw, cpu_addr, cpu_d, clk)
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) then
295 ppu_clk_cnt_res_n <= '0';
296 --d_print("write event");
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';
306 --d_print("clk event");
310 if (cpu_addr = OAMDATA and ppu_clk_cnt = "00") then
312 oma_plt_addr <= oam_addr;
313 oma_plt_data <= cpu_d;
314 --address increment for burst write.
315 oam_addr_ce_n <= '0';
317 oam_addr_ce_n <= '1';
321 --vram address access.
322 if (cpu_addr = PPUADDR and ppu_clk_cnt = "00") then
323 if (ppu_addr_cnt(0) = '0') then
327 --load addr low and output vram/plt bus.
329 --if address is 3fxx, set palette table.
330 if (ppu_addr(13 downto 8) = "111111") then
331 oma_plt_addr <= cpu_d;
335 vram_a <= ppu_addr(13 downto 8);
339 elsif (cpu_addr = PPUDATA and ppu_clk_cnt = "01") then
341 if (ppu_addr(13 downto 8) = "111111") then
342 oma_plt_addr <= ppu_addr(7 downto 0);
345 vram_a <= ppu_addr(13 downto 8);
346 vram_ad <= ppu_addr(7 downto 0);
353 if (cpu_addr = PPUDATA and ppu_clk_cnt = "00") then
354 ppu_data_we_n <= '0';
355 if (ppu_addr(13 downto 8) = "111111") then
358 oma_plt_data <= cpu_d;
371 ppu_data_we_n <= '1';
377 ppu_data_we_n <= '1';
379 ppu_clk_cnt_res_n <= '0';
381 oam_addr_ce_n <= '1';
386 vram_ad <= (others => 'Z');
387 vram_a <= (others => 'Z');