OSDN Git Service

sprite display implemented.
authorastoria-d@fc <astoria-d@fc>
Wed, 14 Sep 2016 09:10:26 +0000 (18:10 +0900)
committerastoria-d@fc <astoria-d@fc>
Wed, 14 Sep 2016 09:10:26 +0000 (18:10 +0900)
de0_cv_nes/ppu/render.vhd

index de9b558..982757f 100644 (file)
@@ -285,8 +285,7 @@ signal wr_s_oam_data        : std_logic_vector (7 downto 0);
 \r
 signal reg_p_oam_cpy_cnt    : integer range 0 to 255;\r
 signal reg_s_oam_cpy_cnt    : integer range 0 to 32;\r
-signal spr_eval_cnt         : integer range 0 to 3;\r
-\r
+signal reg_spr_eval_cnt     : integer range 0 to 3;\r
 \r
 signal reg_p_oam_ce_n       : std_logic;\r
 signal reg_p_oam_rd_n       : std_logic;\r
@@ -304,6 +303,7 @@ signal reg_spr_x            : oam_reg_array;
 signal reg_spr_ptn_sft_start    : std_logic_vector (7 downto 0);\r
 signal reg_spr_ptn_l            : oam_reg_array;\r
 signal reg_spr_ptn_h            : oam_reg_array;\r
+signal reg_spr_hit              : integer range 0 to 1;\r
 \r
 begin\r
 \r
@@ -477,38 +477,23 @@ end;
     po_v_wr_n       <= reg_v_wr_n;\r
     po_v_addr       <= reg_v_addr;\r
 \r
-    po_plt_ce_n     <= reg_plt_ce_n;\r
-    po_plt_rd_n     <= reg_plt_rd_n;\r
-    po_plt_wr_n     <= reg_plt_wr_n;\r
-    po_plt_addr     <= reg_plt_addr;\r
-\r
     --vram r/w selector state machine...\r
-    vac_main_stat_p : process (reg_v_cur_state)\r
+    vram_ac_select_p : process (reg_v_cur_state)\r
     begin\r
         case reg_v_cur_state is\r
             when IDLE =>\r
+                reg_v_ce_n  <= 'Z';\r
                 reg_v_rd_n  <= 'Z';\r
                 reg_v_wr_n  <= 'Z';\r
             when AD_SET0 | AD_SET1 | REG_SET2 | REG_SET3 =>\r
+                reg_v_ce_n  <= '0';\r
                 reg_v_rd_n  <= '1';\r
                 reg_v_wr_n  <= '1';\r
             when AD_SET2 | AD_SET3 | REG_SET0 | REG_SET1 =>\r
+                reg_v_ce_n  <= '0';\r
                 reg_v_rd_n  <= '0';\r
                 reg_v_wr_n  <= '1';\r
         end case;\r
-\r
-        case reg_v_cur_state is\r
-            when IDLE =>\r
-                reg_v_ce_n  <= 'Z';\r
-                reg_plt_ce_n <= 'Z';\r
-                reg_plt_rd_n <= 'Z';\r
-                reg_plt_wr_n <= 'Z'; \r
-            when AD_SET0 | AD_SET1 | REG_SET2 | REG_SET3 | AD_SET2 | AD_SET3 | REG_SET0 | REG_SET1 =>\r
-                reg_v_ce_n  <= '0';\r
-                reg_plt_ce_n <= '0';\r
-                reg_plt_rd_n <= '0';\r
-                reg_plt_wr_n <= '1'; \r
-        end case;\r
     end process;\r
 \r
     --vram address state machine...\r
@@ -637,31 +622,94 @@ end;
         end if;--if (pi_rst_n = '0') then\r
     end process;\r
 \r
+    po_plt_ce_n     <= reg_plt_ce_n;\r
+    po_plt_rd_n     <= reg_plt_rd_n;\r
+    po_plt_wr_n     <= reg_plt_wr_n;\r
+    po_plt_addr     <= reg_plt_addr;\r
+\r
     --palette table state machine...\r
     plt_ac_p : process (pi_rst_n, pi_base_clk)\r
+    variable spr_i : integer range -1 to 7;\r
+\r
+function is_disp (\r
+    pm_sbg          : in std_logic;\r
+    pm_ssp          : in std_logic;\r
+    pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
+    pm_nes_y        : in integer range 0 to VGA_H_MAX - 1\r
+    ) return integer is\r
+begin\r
+    if ((pm_sbg = '1' or pm_ssp = '1') and pm_nes_x < HSCAN and pm_nes_y < VSCAN) then\r
+        return 1;\r
+    else\r
+        return 0;\r
+    end if;\r
+end;\r
+\r
+procedure get_visible_sprite (\r
+    pm_ssp          : in std_logic\r
+    ) is\r
+begin\r
+    if (pm_ssp = '1') then\r
+        for i in 0 to 7 loop\r
+            if (reg_spr_x(i) = "00000000" and\r
+                (reg_spr_ptn_h(i)(0) or reg_spr_ptn_l(i)(0)) = '1' ) then\r
+                spr_i := i;\r
+                exit;\r
+            end if;\r
+        end loop;\r
+    else\r
+        spr_i := -1;\r
+    end if;\r
+end;\r
+\r
     begin\r
         if (pi_rst_n = '0') then\r
+            reg_plt_ce_n <= 'Z';\r
+            reg_plt_rd_n <= 'Z';\r
+            reg_plt_wr_n <= 'Z'; \r
+\r
             reg_plt_addr    <= (others => 'Z');\r
             reg_plt_data    <= (others => 'Z');\r
+            reg_spr_hit     <= 0;\r
         elsif (rising_edge(pi_base_clk)) then\r
             \r
             reg_plt_data    <= pi_plt_data;\r
             --shift pattern propageted 1 cycle later.\r
-            if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                (reg_v_cur_state = AD_SET2 or reg_v_cur_state = REG_SET2)) then\r
-                if (conv_std_logic_vector(reg_nes_y, 9)(4) = '0'\r
-                    and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then\r
-                    reg_plt_addr <=\r
-                            "0" & reg_disp_attr(1 downto 0) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
-                elsif (conv_std_logic_vector(reg_nes_y, 9)(4) = '1'\r
-                    and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then\r
-                    reg_plt_addr <=\r
-                            "0" & reg_disp_attr(5 downto 4) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
-                else\r
-                    ---else: no output color >> universal bg color output.\r
-                    --0x3f00 is the universal bg palette.\r
-                    reg_plt_addr <= (others => '0');\r
+            if (is_disp(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
+                reg_plt_ce_n <= '0';\r
+                reg_plt_rd_n <= '0';\r
+                reg_plt_wr_n <= '1'; \r
+\r
+                if (reg_v_cur_state = AD_SET2 or reg_v_cur_state = REG_SET2) then\r
+                    --check sprite pattern first.\r
+                    get_visible_sprite(pi_ppu_mask(PPUSBG));\r
+                    if (spr_i >= 0) then\r
+                        --sprite display.\r
+                        reg_plt_addr <=\r
+                            "1" & reg_spr_attr(spr_i)(1 downto 0) & reg_spr_ptn_h(spr_i)(0) & reg_spr_ptn_l(spr_i)(0);\r
+                    elsif (conv_std_logic_vector(reg_nes_y, 9)(4) = '0'\r
+                        and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then\r
+                        reg_plt_addr <=\r
+                                "0" & reg_disp_attr(1 downto 0) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
+                    elsif (conv_std_logic_vector(reg_nes_y, 9)(4) = '1'\r
+                        and (reg_sft_ptn_h(0) or reg_sft_ptn_l(0)) = '1') then\r
+                        reg_plt_addr <=\r
+                                "0" & reg_disp_attr(5 downto 4) & reg_sft_ptn_h(0) & reg_sft_ptn_l(0);\r
+                    else\r
+                        ---no output color >> universal bg color output.\r
+                        --0x3f00 is the universal bg palette.\r
+                        reg_plt_addr <= (others => '0');\r
+                    end if;\r
                 end if;\r
+            else\r
+                --reset sprite hit.\r
+                reg_spr_hit     <= 0;\r
+                --release plt bus.\r
+                reg_plt_ce_n <= 'Z';\r
+                reg_plt_rd_n <= 'Z';\r
+                reg_plt_wr_n <= 'Z'; \r
+                reg_plt_addr    <= (others => 'Z');\r
+                reg_plt_data    <= (others => 'Z');\r
             end if;\r
         end if;--if (pi_rst_n = '0') then\r
     end process;\r
@@ -794,7 +842,7 @@ end;
     po_spr_wr_n     <= reg_p_oam_wr_n;\r
     po_spr_addr     <= reg_p_oam_addr;\r
 \r
-    sprite_main_p : process (pi_rst_n, pi_base_clk)\r
+    sprite_eval_p : process (pi_rst_n, pi_base_clk)\r
 function is_s_oam_clear (\r
     pm_ssp          : in std_logic;\r
     pm_nes_x        : in integer range 0 to VGA_W_MAX - 1;\r
@@ -871,7 +919,7 @@ end;
                     reg_p_oam_addr <= (others => '0');\r
                     reg_s_oam_cpy_cnt <= 0;\r
                     reg_p_oam_cpy_cnt <= 0;\r
-                    spr_eval_cnt <= 0;\r
+                    reg_spr_eval_cnt <= 0;\r
                 elsif (is_spr_eval(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
                     --copy data from primary oam ram.\r
                     reg_s_oam_addr <= conv_std_logic_vector(reg_s_oam_cpy_cnt, 5);\r
@@ -893,24 +941,24 @@ end;
                         elsif (reg_s_oam_cur_state = REG_SET1) then\r
                             reg_s_oam_ce_n <= '1';\r
                             reg_s_oam_wr_n <= '1';\r
-                            if (spr_eval_cnt = 0 and\r
+                            if (reg_spr_eval_cnt = 0 and\r
                                 (pi_spr_data <= reg_nes_y and reg_nes_y < pi_spr_data + 8)) then\r
                                 --evaluate and found sprite in the range.\r
                                 --increment s-oam.\r
                                 reg_s_oam_cpy_cnt <= reg_s_oam_cpy_cnt + 1;\r
                                 reg_p_oam_cpy_cnt <= reg_p_oam_cpy_cnt + 1;\r
-                                spr_eval_cnt <= spr_eval_cnt + 1;\r
-                            elsif (spr_eval_cnt = 0) then\r
+                                reg_spr_eval_cnt <= reg_spr_eval_cnt + 1;\r
+                            elsif (reg_spr_eval_cnt = 0) then\r
                                 --sprite not hit. next entry.\r
                                 reg_p_oam_cpy_cnt <= reg_p_oam_cpy_cnt + 4;\r
                             else\r
                                 --sprite copying.\r
                                 reg_s_oam_cpy_cnt <= reg_s_oam_cpy_cnt + 1;\r
                                 reg_p_oam_cpy_cnt <= reg_p_oam_cpy_cnt + 1;\r
-                                if (spr_eval_cnt = 3) then\r
-                                    spr_eval_cnt <= 0;\r
+                                if (reg_spr_eval_cnt = 3) then\r
+                                    reg_spr_eval_cnt <= 0;\r
                                 else\r
-                                    spr_eval_cnt <= spr_eval_cnt + 1;\r
+                                    reg_spr_eval_cnt <= reg_spr_eval_cnt + 1;\r
                                 end if;\r
                             end if;\r
                         end if;\r