2 use ieee.std_logic_1164.all;
3 use ieee.std_logic_arith.conv_std_logic_vector;
4 use ieee.std_logic_unsigned.all;
7 port ( clk : in std_logic;
9 vblank_n : out std_logic;
13 vram_ad : inout std_logic_vector (7 downto 0);
14 vram_a : out std_logic_vector (13 downto 8);
15 plt_bus_ce_n : in std_logic;
16 plt_r_nw : in std_logic;
17 plt_addr : in std_logic_vector (4 downto 0);
18 plt_data : inout std_logic_vector (7 downto 0);
19 pos_x : out std_logic_vector (8 downto 0);
20 pos_y : out std_logic_vector (8 downto 0);
21 r : out std_logic_vector (3 downto 0);
22 g : out std_logic_vector (3 downto 0);
23 b : out std_logic_vector (3 downto 0)
27 architecture rtl of ppu_render is
29 component counter_register
33 port ( clk : in std_logic;
37 d : in std_logic_vector(dsize - 1 downto 0);
38 q : out std_logic_vector(dsize - 1 downto 0)
42 component shift_register
47 port ( clk : in std_logic;
51 d : buffer std_logic_vector(dsize - 1 downto 0);
52 q : out std_logic_vector(dsize - 1 downto 0)
65 d : in std_logic_vector (dsize - 1 downto 0);
66 q : out std_logic_vector (dsize - 1 downto 0)
70 component tri_state_buffer
76 d : in std_logic_vector (dsize - 1 downto 0);
77 q : out std_logic_vector (dsize - 1 downto 0)
81 component test_module_init_data
82 port ( clk : in std_logic;
83 v_rd_n : out std_logic;
84 v_wr_n : out std_logic;
85 v_ale : out std_logic;
86 v_ad : out std_logic_vector (7 downto 0);
87 v_a : out std_logic_vector (13 downto 8);
88 plt_bus_ce_n : out std_logic;
89 plt_r_nw : out std_logic;
90 plt_addr : out std_logic_vector (4 downto 0);
91 plt_data : out std_logic_vector (7 downto 0)
95 procedure d_print(msg : string) is
97 use ieee.std_logic_textio.all;
98 variable out_l : line;
101 writeline(output, out_l);
104 function conv_hex8(ival : integer) return string is
105 variable tmp1, tmp2 : integer;
106 variable hex_chr: string (1 to 16) := "0123456789abcdef";
108 tmp2 := (ival mod 16 ** 2) / 16 ** 1;
109 tmp1 := ival mod 16 ** 1;
110 return hex_chr(tmp2 + 1) & hex_chr(tmp1 + 1);
113 function conv_hex8(ival : std_logic_vector) return string is
115 return conv_hex8(conv_integer(ival));
118 function conv_hex16(ival : integer) return string is
119 variable tmp1, tmp2 : integer;
120 variable hex_chr: string (1 to 16) := "0123456789abcdef";
123 tmp1 := ival mod 256;
124 return conv_hex8(tmp2) & conv_hex8(tmp1);
128 constant X_SIZE : integer := 9;
129 constant dsize : integer := 8;
130 constant asize : integer := 14;
131 constant HSCAN_MAX : integer := 341;
132 constant VSCAN_MAX : integer := 262;
133 constant HSCAN : integer := 256;
134 constant VSCAN : integer := 240;
135 constant HSCAN_NEXT_START : integer := 320;
136 constant HSCAN_NEXT_EXTRA : integer := 336;
138 subtype palette_data is std_logic_vector (dsize -1 downto 0);
139 type palette_array is array (0 to 15) of palette_data;
140 signal bg_palatte : palette_array := (others => (others => '0'));
141 signal sprite_palatte : palette_array := (others => (others => '0'));
143 subtype nes_color_data is std_logic_vector (11 downto 0);
144 type nes_color_array is array (0 to 63) of nes_color_data;
145 --ref: http://hlc6502.web.fc2.com/NesPal2.htm
146 constant nes_color_palette : nes_color_array := (
147 conv_std_logic_vector(16#787878#, 12),
148 conv_std_logic_vector(16#2000B0#, 12),
149 conv_std_logic_vector(16#2800B8#, 12),
150 conv_std_logic_vector(16#6010A0#, 12),
151 conv_std_logic_vector(16#982078#, 12),
152 conv_std_logic_vector(16#B01030#, 12),
153 conv_std_logic_vector(16#A03000#, 12),
154 conv_std_logic_vector(16#784000#, 12),
155 conv_std_logic_vector(16#485800#, 12),
156 conv_std_logic_vector(16#386800#, 12),
157 conv_std_logic_vector(16#386C00#, 12),
158 conv_std_logic_vector(16#306040#, 12),
159 conv_std_logic_vector(16#305080#, 12),
160 conv_std_logic_vector(16#000000#, 12),
161 conv_std_logic_vector(16#000000#, 12),
162 conv_std_logic_vector(16#000000#, 12),
163 conv_std_logic_vector(16#B0B0B0#, 12),
164 conv_std_logic_vector(16#4060F8#, 12),
165 conv_std_logic_vector(16#4040FF#, 12),
166 conv_std_logic_vector(16#9040F0#, 12),
167 conv_std_logic_vector(16#D840C0#, 12),
168 conv_std_logic_vector(16#D84060#, 12),
169 conv_std_logic_vector(16#E05000#, 12),
170 conv_std_logic_vector(16#C07000#, 12),
171 conv_std_logic_vector(16#888800#, 12),
172 conv_std_logic_vector(16#50A000#, 12),
173 conv_std_logic_vector(16#48A810#, 12),
174 conv_std_logic_vector(16#48A068#, 12),
175 conv_std_logic_vector(16#4090C0#, 12),
176 conv_std_logic_vector(16#000000#, 12),
177 conv_std_logic_vector(16#000000#, 12),
178 conv_std_logic_vector(16#000000#, 12),
180 conv_std_logic_vector(16#FFFFFF#, 12),
181 conv_std_logic_vector(16#60A0FF#, 12),
182 conv_std_logic_vector(16#5080FF#, 12),
183 conv_std_logic_vector(16#A070FF#, 12),
184 conv_std_logic_vector(16#F060FF#, 12),
185 conv_std_logic_vector(16#FF60B0#, 12),
186 conv_std_logic_vector(16#FF7830#, 12),
187 conv_std_logic_vector(16#FFA000#, 12),
188 conv_std_logic_vector(16#E8D020#, 12),
189 conv_std_logic_vector(16#98E800#, 12),
190 conv_std_logic_vector(16#70F040#, 12),
191 conv_std_logic_vector(16#70E090#, 12),
192 conv_std_logic_vector(16#60D0E0#, 12),
193 conv_std_logic_vector(16#787878#, 12),
194 conv_std_logic_vector(16#000000#, 12),
195 conv_std_logic_vector(16#000000#, 12),
196 conv_std_logic_vector(16#FFFFFF#, 12),
197 conv_std_logic_vector(16#90D0FF#, 12),
198 conv_std_logic_vector(16#A0B8FF#, 12),
199 conv_std_logic_vector(16#C0B0FF#, 12),
200 conv_std_logic_vector(16#E0B0FF#, 12),
201 conv_std_logic_vector(16#FFB8E8#, 12),
202 conv_std_logic_vector(16#FFC8B8#, 12),
203 conv_std_logic_vector(16#FFD8A0#, 12),
204 conv_std_logic_vector(16#FFF090#, 12),
205 conv_std_logic_vector(16#C8F080#, 12),
206 conv_std_logic_vector(16#A0F0A0#, 12),
207 conv_std_logic_vector(16#A0FFC8#, 12),
208 conv_std_logic_vector(16#A0FFF0#, 12),
209 conv_std_logic_vector(16#A0A0A0#, 12),
210 conv_std_logic_vector(16#000000#, 12),
211 conv_std_logic_vector(16#000000#, 12)
214 signal rst : std_logic;
215 signal clk_n : std_logic;
217 signal io_cnt : std_logic_vector(0 downto 0);
218 signal io_oe_n : std_logic;
220 signal render_x_en_n : std_logic;
221 signal render_x_res_n : std_logic;
222 signal render_y_en_n : std_logic;
223 signal render_y_res_n : std_logic;
225 signal cur_x : std_logic_vector(X_SIZE - 1 downto 0);
226 signal cur_y : std_logic_vector(X_SIZE - 1 downto 0);
227 signal next_x : std_logic_vector(X_SIZE - 1 downto 0);
228 signal next_y : std_logic_vector(X_SIZE - 1 downto 0);
230 signal nt_next_we_n : std_logic;
231 signal nt_val : std_logic_vector (dsize - 1 downto 0);
232 signal nt_next_val : std_logic_vector (dsize - 1 downto 0);
234 signal attr_ce_n : std_logic;
235 signal attr_we_n : std_logic;
236 signal attr_in : std_logic_vector (dsize - 1 downto 0);
237 signal attr_val : std_logic_vector (dsize - 1 downto 0);
239 signal ptn_en_n : std_logic;
241 signal ptn_l_next_we_n : std_logic;
242 signal ptn_l_next_in : std_logic_vector (dsize * 2 - 1 downto 0);
243 signal ptn_l_next_in_rev: std_logic_vector (dsize * 2 - 1 downto 0);
244 signal ptn_l_next_val : std_logic_vector (dsize * 2 - 1 downto 0);
245 signal ptn_l_in : std_logic_vector (dsize * 2 - 1 downto 0);
246 signal ptn_l_val : std_logic_vector (dsize * 2 - 1 downto 0);
248 signal ptn_h_next_we_n : std_logic;
249 signal ptn_h_next_in : std_logic_vector (dsize * 2 - 1 downto 0);
250 signal ptn_h_next_in_rev: std_logic_vector (dsize * 2 - 1 downto 0);
251 signal ptn_h_next_val : std_logic_vector (dsize * 2 - 1 downto 0);
252 signal ptn_h_val : std_logic_vector (dsize * 2 - 1 downto 0);
254 signal vram_addr : std_logic_vector (asize - 1 downto 0);
255 signal ptn_addr : std_logic_vector (asize - 1 downto 0);
258 signal init_ale : std_logic;
259 signal init_rd_n : std_logic;
260 signal init_wr_n : std_logic;
262 signal init_plt_bus_ce_n : std_logic;
263 signal init_plt_r_nw : std_logic;
264 signal init_plt_addr : std_logic_vector (4 downto 0);
265 signal init_plt_data : std_logic_vector (7 downto 0);
272 render_x_en_n <= '0';
275 -- ale <= not cur_x(0) when rst_n = '1' else '1';
276 -- rd_n <= not cur_x(0) when rst_n = '1' else '1';
278 io_cnt_inst : counter_register generic map (1)
279 port map (clk, render_x_res_n, '1', '0', (others => '0'), io_cnt);
281 ale <= io_cnt(0) when rst_n = '1' else init_ale;
282 rd_n <= io_cnt(0) when rst_n = '1' else init_rd_n;
283 wr_n <= '1' when rst_n = '1' else init_wr_n;
284 io_oe_n <= not io_cnt(0) when rst_n = '1' else '1';
286 ---x pos is 8 cycle ahead of current pos.
287 next_x <= cur_x + "000010000"
288 when cur_x < conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE) else
291 when cur_x < conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE) else
293 when cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE) else
297 cur_x_inst : counter_register generic map (X_SIZE)
298 port map (clk_n, render_x_res_n, '1',
299 render_x_en_n, (others => '0'), cur_x);
300 cur_y_inst : counter_register generic map (X_SIZE)
301 port map (clk_n, render_y_res_n, '1',
302 render_y_en_n, (others => '0'), cur_y);
304 nt_next_inst : d_flip_flop generic map(dsize)
305 port map (clk_n, rst_n, '1', nt_next_we_n, vram_ad, nt_next_val);
306 nt_inst : d_flip_flop generic map(dsize)
307 port map (clk_n, rst_n, '1', nt_next_we_n, nt_next_val, nt_val);
310 at_inst : shift_register generic map(dsize, 2)
311 port map (clk_n, rst_n, attr_ce_n, attr_we_n, attr_in, attr_val);
314 --chr rom data's bit is stored in opposite direction.
315 --reverse bit when loading...
316 ptn_l_next_in_rev <= vram_ad & ptn_l_next_val (dsize downto 1);
317 ptn_h_next_in_rev <= vram_ad & ptn_h_next_val (dsize downto 1);
318 bit_rev: for cnt in 0 to 7 generate
319 ptn_l_next_in(dsize * 2 - 1 - cnt) <= ptn_l_next_in_rev(dsize + cnt);
320 ptn_h_next_in(dsize * 2 - 1 - cnt) <= ptn_h_next_in_rev(dsize + cnt);
322 ptn_l_next_in(dsize - 1 downto 0) <= ptn_l_next_in_rev(dsize - 1 downto 0);
323 ptn_h_next_in(dsize - 1 downto 0) <= ptn_h_next_in_rev(dsize - 1 downto 0);
326 ptn_en_n <= '0' when cur_x < conv_std_logic_vector(HSCAN_NEXT_EXTRA, X_SIZE) else
329 ptn_l_next_inst : shift_register generic map(dsize * 2, 1)
330 port map (clk_n, rst_n, ptn_en_n, ptn_l_next_we_n,
331 ptn_l_next_in, ptn_l_next_val);
333 --2 bit shift restored to align with the ptn_h.
334 ptn_l_in <= ptn_l_next_val(13 downto 6) & ptn_l_val(8 downto 1);
335 ptn_l_inst : shift_register generic map(dsize * 2, 1)
336 port map (clk_n, rst_n, ptn_en_n, ptn_h_next_we_n,
337 ptn_l_in, ptn_l_val);
339 ptn_h_next_inst : shift_register generic map(dsize * 2, 1)
340 port map (clk_n, rst_n, ptn_en_n, ptn_h_next_we_n,
341 ptn_h_next_in, ptn_h_next_val);
342 ptn_h_val <= ptn_h_next_val;
344 vram_io_buf : tri_state_buffer generic map (dsize)
345 port map (io_oe_n, vram_addr(dsize - 1 downto 0), vram_ad);
347 vram_a_buf : tri_state_buffer generic map (6)
348 port map (rst, vram_addr(asize - 1 downto dsize), vram_a);
353 clk_p : process (rst_n, clk)
355 procedure output_bg_rgb is
356 variable plt_addr : integer;
357 variable palette_index : integer;
359 --firs t color in the palette is transparent color.
360 if ((ptn_l_val(0) or ptn_h_val(0)) = '1') then
361 plt_addr := conv_integer(attr_val(1 downto 0) & ptn_h_val(0) & ptn_l_val(0));
362 palette_index := conv_integer(bg_palatte(plt_addr));
363 b <= nes_color_palette(palette_index) (11 downto 8);
364 g <= nes_color_palette(palette_index) (7 downto 4);
365 r <= nes_color_palette(palette_index) (3 downto 0);
367 -- d_print("output_bg_rgb");
368 -- d_print("pht h:" & conv_hex8(ptn_h_val));
369 -- d_print("pht l:" & conv_hex8(ptn_l_val));
371 -- conv_hex8(nes_color_palette(palette_index) (3 downto 0)) & "," &
372 -- conv_hex8(nes_color_palette(palette_index) (7 downto 4)) & "," &
373 -- conv_hex8(nes_color_palette(palette_index) (11 downto 8)));
375 b <= (others => '0');
376 g <= (others => '0');
377 r <= (others => '0');
378 end if; --if ((ptn_l_val(0) or ptn_h_val(0)) = '1') then
382 if (rst_n = '0') then
383 render_x_res_n <= '0';
384 render_y_res_n <= '0';
390 cur_x = conv_std_logic_vector(HSCAN_MAX - 1, X_SIZE)) then
391 render_x_res_n <= '0';
394 if (cur_y = conv_std_logic_vector(VSCAN_MAX - 1, X_SIZE)) then
395 render_y_res_n <= '0';
397 render_y_res_n <= '1';
400 render_x_res_n <= '1';
401 render_y_res_n <= '1';
403 end if; --if (clk'event) then
405 if (clk'event and clk = '1') then
407 if (cur_x = conv_std_logic_vector(HSCAN_MAX - 1, X_SIZE)) then
408 render_y_en_n <= '0';
410 render_y_en_n <= '1';
412 end if; --if (clk'event) then
414 if (clk'event and clk = '0') then
418 if (clk'event and clk = '1') then
421 --visible area and last pixel for the next sirst pixel.
422 if (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
423 (cur_x > conv_std_logic_vector(HSCAN_NEXT_START, X_SIZE) and
424 cur_x < conv_std_logic_vector(HSCAN_NEXT_EXTRA, X_SIZE) ))
427 ----fetch next tile byte.
428 if (cur_x (2 downto 0) = "001" ) then
429 --vram addr is incremented every 8 cycle.
430 --name table at 0x2000
431 vram_addr(9 downto 0)
432 <= next_y(dsize - 1 downto 3)
433 & next_x(dsize - 1 downto 3);
434 vram_addr(asize - 1 downto 10) <= "1000";
436 if (cur_x (2 downto 0) = "010" ) then
442 ----fetch attr table byte.
443 if (cur_x (4 downto 0) = "00011" ) then
444 --attribute table is loaded every 32 cycle.
445 --attr table at 0x23c0
446 vram_addr(dsize - 1 downto 0)
447 <= "110" & cur_x(dsize - 1 downto 3);
448 vram_addr(asize - 1 downto dsize) <= "100011";
449 end if;--if (cur_x (2 downto 0) = "010" ) then
450 if (cur_x (4 downto 0) = "00100" ) then
455 ---attribute is shifted every 16 bit.
456 if (cur_x (3 downto 0) = "0100" ) then
462 ----fetch pattern table low byte.
463 if (cur_x (2 downto 0) = "101" ) then
464 --vram addr is incremented every 8 cycle.
465 vram_addr <= "01" & nt_next_val(dsize - 1 downto 0)
466 & "0" & next_y(2 downto 0);
467 end if;--if (cur_x (2 downto 0) = "100" ) then
468 if (cur_x (2 downto 0) = "110" ) then
469 ptn_l_next_we_n <= '0';
471 ptn_l_next_we_n <= '1';
474 ----fetch pattern table high byte.
475 if (cur_x (2 downto 0) = "111" ) then
476 --vram addr is incremented every 8 cycle.
477 vram_addr <= "01" & nt_next_val(dsize - 1 downto 0)
478 & "0" & next_y(2 downto 0) + 8;
479 end if; --if (cur_x (2 downto 0) = "110" ) then
480 if (cur_x (2 downto 0) = "000") then
481 ptn_h_next_we_n <= '0';
483 ptn_h_next_we_n <= '1';
484 end if;--if (cur_x (2 downto 0) = "001" ) then
486 end if; --if (cur_x <= conv_std_logic_vector(HSCAN, X_SIZE) or
488 d_print("cur_x: " & conv_hex16(conv_integer(cur_x)));
489 d_print("cur_y: " & conv_hex16(conv_integer(cur_y)));
490 d_print("next_x: " & conv_hex16(conv_integer(next_x)));
491 d_print("nt_next_val: " & conv_hex8(conv_integer(nt_next_val)));
492 d_print("vram_addr: " & conv_hex16(conv_integer(vram_addr)));
494 --output visible area only.
495 if ((cur_x < conv_std_logic_vector(HSCAN, X_SIZE)) and
496 (cur_y < conv_std_logic_vector(VSCAN, X_SIZE))) then
501 end if; --if (clk'event and clk = '1') then
502 end if;--if (rst_n = '0') then
505 -- ------------------- palette access process -------------------
506 -- plt_rw : process (plt_bus_ce_n, plt_r_nw, plt_addr, plt_data)
508 -- if (plt_bus_ce_n = '0') then
509 -- if (plt_r_nw = '0') then
510 -- if (plt_addr(4) = '0') then
511 -- bg_palatte(conv_integer(plt_addr)) <= plt_data;
513 -- sprite_palatte(conv_integer(plt_addr)) <= plt_data;
517 -- if (plt_r_nw = '1') then
518 -- if (plt_addr(4) = '0') then
519 -- plt_data <= bg_palatte(conv_integer(plt_addr));
521 -- plt_data <= sprite_palatte(conv_integer(plt_addr));
525 -- plt_data <= (others => 'Z');
529 -----fill test data during the reset.....
530 init_data : test_module_init_data
531 port map (clk, init_rd_n, init_wr_n, init_ale, vram_ad, vram_a,
532 init_plt_bus_ce_n, init_plt_r_nw, init_plt_addr, init_plt_data
535 ----- test initial value stting.
536 plt_init_w : process (init_plt_bus_ce_n, init_plt_r_nw,
537 init_plt_addr, init_plt_data)
539 if (init_plt_bus_ce_n = '0') then
540 if (init_plt_r_nw = '0') then
541 if (init_plt_addr(4) = '0') then
542 -- d_print("dummy addr:" & conv_hex8(conv_integer(init_plt_addr)));
543 -- d_print("plt val:" & conv_hex8(conv_integer(init_plt_data)));
544 bg_palatte(conv_integer(init_plt_addr)) <= init_plt_data;
554 ------------------------------------------------------
555 ------------------------------------------------------
556 ------------------------------------------------------
557 ------------------------------------------------------
558 -- initialize with dummy data
559 ------------------------------------------------------
560 ------------------------------------------------------
561 ------------------------------------------------------
562 ------------------------------------------------------
564 use IEEE.std_logic_1164.all;
565 use ieee.std_logic_arith.all;
567 entity test_module_init_data is
568 port ( clk : in std_logic;
569 v_rd_n : out std_logic;
570 v_wr_n : out std_logic;
571 v_ale : out std_logic;
572 v_ad : out std_logic_vector (7 downto 0);
573 v_a : out std_logic_vector (13 downto 8);
574 plt_bus_ce_n : out std_logic;
575 plt_r_nw : out std_logic;
576 plt_addr : out std_logic_vector (4 downto 0);
577 plt_data : out std_logic_vector (7 downto 0)
579 end test_module_init_data;
581 architecture stimulus of test_module_init_data is
583 constant ppu_clk : time := 186 ns;
584 constant size8 : integer := 8;
585 constant size16 : integer := 16;
586 constant size14 : integer := 14;
588 signal v_addr : std_logic_vector (size14 - 1 downto 0);
592 v_ad <= v_addr(size8 - 1 downto 0);
593 v_a <= v_addr(size14 - 1 downto size8);
595 -----test for vram/chr-rom
596 p_vram_init : process
597 variable i : integer := 0;
598 variable tmp : std_logic_vector (size8 - 1 downto 0);
599 constant loopcnt : integer := 15;
602 ---dummy power up wait (same amount of time as testbench)
605 --copy from chr rom to name tbl.
606 for i in 0 to loopcnt loop
611 v_addr <= conv_std_logic_vector(16#2000# + i, size14);
613 v_addr(7 downto 0) <= (others => 'Z');
618 v_addr(7 downto 0) <= conv_std_logic_vector(i + 32, size8);
625 v_addr <= conv_std_logic_vector(16#23c0# + i, size14);
627 v_addr(7 downto 0) <= (others => 'Z');
631 v_addr(7 downto 0) <= conv_std_logic_vector(16#a0# + i, size8);
635 v_addr <= (others => 'Z');
640 p_palette_init : process
641 variable i : integer := 0;
645 --fill palette teble.
648 for i in 0 to 32 loop
649 plt_addr <= conv_std_logic_vector(i, 5);
650 plt_data <= conv_std_logic_vector(i, 8);
655 plt_data <= (others => 'Z');