OSDN Git Service

sprite vram integration
authorastoria-d@fc <astoria-d@fc>
Tue, 13 Sep 2016 11:07:31 +0000 (20:07 +0900)
committerastoria-d@fc <astoria-d@fc>
Tue, 13 Sep 2016 11:07:31 +0000 (20:07 +0900)
de0_cv_nes/ppu/render.vhd

index 8816b99..dddfc8f 100644 (file)
@@ -198,6 +198,19 @@ begin
     end if;\r
 end;\r
 \r
+function is_spr_pfetch (\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_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
 signal reg_vga_x        : integer range 0 to VGA_W_MAX - 1;\r
 signal reg_vga_y        : integer range 0 to VGA_H_MAX - 1;\r
 \r
@@ -350,39 +363,38 @@ begin
 \r
     --state change to next.\r
     vac_next_stat_p : process (reg_v_cur_state, pi_rnd_en, pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y)\r
-function bg_process (\r
+function is_v_access (\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'and\r
-        (pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START) and\r
-        (pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then\r
-        return 1;\r
+    if ((pm_nes_y < VSCAN or pm_nes_y = VSCAN_NEXT_START)) then\r
+        if ((pm_nes_x <= HSCAN or pm_nes_x >= HSCAN_NEXT_START)) then\r
+            if (pm_sbg = '1') then\r
+                return 1;\r
+            else\r
+                return 0;\r
+            end if;\r
+        elsif ((pm_nes_x > HSCAN and pm_nes_x < HSCAN_SPR_MAX)) then\r
+            if (pm_ssp = '1') then\r
+                return 1;\r
+            else\r
+                return 0;\r
+            end if;\r
+        else\r
+            return 0;\r
+        end if;\r
     else\r
         return 0;\r
     end if;\r
 end;\r
 \r
-function is_idle (\r
-    pm_sbg          : 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 = '0' or\r
-        (pm_nes_x > HSCAN and pm_nes_x < HSCAN_NEXT_START) or\r
-        (pm_nes_y >= VSCAN and pm_nes_y < VSCAN_NEXT_START)) then\r
-        return 1;\r
-    else\r
-        return 0;\r
-    end if;\r
-end;\r
     begin\r
         case reg_v_cur_state is\r
             when IDLE =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1 and\r
                     pi_rnd_en(2) = '1' and\r
                     reg_nes_x mod 8 = 0) then\r
                     --start vram access process.\r
@@ -391,92 +403,84 @@ end;
                     reg_v_next_state <= reg_v_cur_state;\r
                 end if;\r
             when AD_SET0 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(3) = '1'\r
-                ) then\r
-                    reg_v_next_state <= AD_SET1;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(3) = '1') then\r
+                        reg_v_next_state <= AD_SET1;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when AD_SET1 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(0) = '1'\r
-                ) then\r
-                    reg_v_next_state <= AD_SET2;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(0) = '1') then\r
+                        reg_v_next_state <= AD_SET2;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when AD_SET2 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(1) = '1'\r
-                ) then\r
-                    reg_v_next_state <= AD_SET3;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(1) = '1') then\r
+                        reg_v_next_state <= AD_SET3;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when AD_SET3 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(2) = '1'\r
-                ) then\r
-                    reg_v_next_state <= REG_SET0;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(2) = '1') then\r
+                        reg_v_next_state <= REG_SET0;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when REG_SET0 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(3) = '1'\r
-                ) then\r
-                    reg_v_next_state <= REG_SET1;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(3) = '1') then\r
+                        reg_v_next_state <= REG_SET1;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when REG_SET1 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(0) = '1'\r
-                ) then\r
-                    reg_v_next_state <= REG_SET2;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(0) = '1') then\r
+                        reg_v_next_state <= REG_SET2;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when REG_SET2 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(1) = '1'\r
-                ) then\r
-                    reg_v_next_state <= REG_SET3;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(1) = '1') then\r
+                        reg_v_next_state <= REG_SET3;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
             when REG_SET3 =>\r
-                if (bg_process(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1 and\r
-                    pi_rnd_en(2) = '1'\r
-                ) then\r
-                    reg_v_next_state <= AD_SET0;\r
-                elsif (is_idle(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
-                    ---when nes_x=257, fall to idle\r
-                    reg_v_next_state <= IDLE;\r
+                if (is_v_access(pi_ppu_mask(PPUSBG), pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    if (pi_rnd_en(2) = '1') then\r
+                        reg_v_next_state <= AD_SET0;\r
+                    else\r
+                        reg_v_next_state <= reg_v_cur_state;\r
+                    end if;\r
                 else\r
-                    reg_v_next_state <= reg_v_cur_state;\r
+                    reg_v_next_state <= IDLE;\r
                 end if;\r
         end case;\r
     end process;\r
@@ -531,6 +535,7 @@ end;
         elsif (rising_edge(pi_base_clk)) then\r
             reg_v_data      <= pi_v_data;\r
 \r
+            --bg vram fetch.\r
             if (is_bg(pi_ppu_mask(PPUSBG), reg_nes_x, reg_nes_y) = 1) then\r
                 ----fetch next tile byte.\r
                 if (reg_prf_x mod 8 = 1) then\r
@@ -573,6 +578,40 @@ end;
                                         & "0" & conv_std_logic_vector(reg_prf_y, 9)(2 downto 0)\r
                                         + "00000000001000";\r
                 end if;\r
+\r
+            --sprite pattern fetch.\r
+            elsif (is_spr_pfetch(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                ----fetch pattern table low byte.\r
+                if (reg_nes_x mod 8 = 5) then\r
+                    if (reg_spr_attr((reg_nes_x - 256) / 8)(SPRVFL) = '0') then\r
+                        reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) & \r
+                                    reg_spr_tile_tmp & "0" & \r
+                                    (conv_std_logic_vector(reg_nes_y, 3) + "001" - reg_spr_y_tmp(2 downto 0));\r
+                    else\r
+                        --flip sprite vertically.\r
+                        reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) & \r
+                                    reg_spr_tile_tmp & "0" & \r
+                                    (reg_spr_y_tmp(2 downto 0) - conv_std_logic_vector(reg_nes_y, 3) - "010");\r
+                    end if;\r
+\r
+                ----fetch pattern table high byte.\r
+                elsif (reg_nes_x mod 8 = 7) then\r
+                    if (reg_spr_attr((reg_nes_x - 256) / 8)(SPRVFL) = '0') then\r
+                        reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) & \r
+                                    reg_spr_tile_tmp & "0" & \r
+                                    (conv_std_logic_vector(reg_nes_y, 3) + "001" - reg_spr_y_tmp(2 downto 0))\r
+                                        + "00000000001000";\r
+                    else\r
+                        --flip sprite vertically.\r
+                        reg_v_addr <= "0" & pi_ppu_ctrl(PPUSPA) & \r
+                                    reg_spr_tile_tmp & "0"  & \r
+                                    (reg_spr_y_tmp(2 downto 0) - conv_std_logic_vector(reg_nes_y, 3) - "010")\r
+                                        + "00000000001000";\r
+                    end if;\r
+                end if;\r
+            else\r
+                reg_v_addr  <= (others => 'Z');\r
+                reg_v_data    <= (others => 'Z');\r
             end if;\r
         end if;--if (pi_rst_n = '0') then\r
     end process;\r
@@ -917,7 +956,13 @@ end;
                         end if;\r
                     end if;\r
                 elsif (is_spr_cpy(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
-                    --copy to sprite register.\r
+                    --release p-oam access.\r
+                    reg_p_oam_ce_n <= '1';\r
+                    reg_p_oam_rd_n <= '1';\r
+                    reg_p_oam_wr_n <= '1';\r
+                    reg_p_oam_addr <= (others => '0');\r
+\r
+                    --copy s-oam to sprite register.\r
                     --257 to 320 = (1 to 64) & 256\r
                     -->(1 to 64) / 2 & 256.\r
                     reg_s_oam_ce_n <= '0';\r
@@ -936,6 +981,23 @@ end;
                             reg_spr_x((reg_nes_x - 256) / 8 - 1) <= wr_s_oam_data;\r
                         end if;\r
                     end if;\r
+\r
+                    --sprite pattern is read from vram.\r
+                    if (reg_s_oam_cur_state = REG_SET1) then\r
+                        if (reg_nes_x mod 8 = 6) then\r
+                            reg_spr_ptn_l((reg_nes_x - 256) / 8) <= pi_v_data;\r
+                        elsif (reg_nes_x mod 8 = 0) then\r
+                            reg_spr_ptn_h((reg_nes_x - 256) / 8 - 1) <= pi_v_data;\r
+                        end if;\r
+                    end if;\r
+\r
+                elsif (is_spr_pfetch(pi_ppu_mask(PPUSSP), reg_nes_x, reg_nes_y) = 1) then\r
+                    --release s-oam access.\r
+                    reg_s_oam_ce_n <= '1';\r
+                    reg_s_oam_addr <= (others => 'Z');\r
+                    reg_s_oam_data <= (others => 'Z');\r
+                    reg_s_oam_wr_n <= '1';\r
+                    reg_s_oam_rd_n <= '1';\r
                 else\r
                     reg_s_oam_ce_n <= '1';\r
                     reg_s_oam_rd_n <= '1';\r
@@ -951,7 +1013,8 @@ end;
                 end if;\r
             end if; --if (rising_edge(emu_ppu_clk)) then\r
         end if;--if (rst_n = '0') then\r
-   end process;\r
+\r
+    end process;\r
 \r
     po_ppu_status   <= (others => '0');\r
 \r