1 // license:BSD-3-Clause 2 // copyright-holders:Ernesto Corvi,Brad Oliver 3 /****************************************************************************** 4 5 Nintendo 2C0x PPU emulation. 6 7 Written by Ernesto Corvi. 8 This code is heavily based on Brad Oliver's MESS implementation. 9 10 ******************************************************************************/ 11 12 #ifndef MAME_VIDEO_PPU2C0X_H 13 #define MAME_VIDEO_PPU2C0X_H 14 15 #pragma once 16 17 ///************************************************************************* 18 // MACROS / CONSTANTS 19 ///************************************************************************* 20 21 // mirroring types 22 #define PPU_MIRROR_NONE 0 23 #define PPU_MIRROR_VERT 1 24 #define PPU_MIRROR_HORZ 2 25 #define PPU_MIRROR_HIGH 3 26 #define PPU_MIRROR_LOW 4 27 #define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror 28 29 #define PPU_DRAW_BG 0 30 #define PPU_DRAW_OAM 1 31 32 /* constant definitions */ 33 #define VISIBLE_SCREEN_WIDTH (32*8) /* Visible screen width */ 34 #define VISIBLE_SCREEN_HEIGHT (30*8) /* Visible screen height */ 35 #define SPRITERAM_SIZE 0x100 /* spriteram size */ 36 37 ///************************************************************************* 38 // TYPE DEFINITIONS 39 ///************************************************************************* 40 41 // ======================> ppu2c0x_device 42 43 class ppu2c0x_device : public device_t, 44 public device_memory_interface, 45 public device_video_interface 46 { 47 public: 48 typedef device_delegate<void (int scanline, int vblank, int blanked)> scanline_delegate; 49 typedef device_delegate<void (int scanline, int vblank, int blanked)> hblank_delegate; 50 typedef device_delegate<void (int *ppu_regs)> nmi_delegate; 51 typedef device_delegate<int (int address, int data)> vidaccess_delegate; 52 typedef device_delegate<void (offs_t offset)> latch_delegate; 53 54 enum 55 { 56 NTSC_SCANLINES_PER_FRAME = 262, 57 PAL_SCANLINES_PER_FRAME = 312, 58 VS_CLONE_SCANLINES_PER_FRAME = 280, 59 60 BOTTOM_VISIBLE_SCANLINE = 239, 61 VBLANK_FIRST_SCANLINE = 241, 62 VBLANK_FIRST_SCANLINE_PALC = 291, 63 VBLANK_FIRST_SCANLINE_VS_CLONE = 240, 64 VBLANK_LAST_SCANLINE_NTSC = 260, 65 VBLANK_LAST_SCANLINE_PAL = 310, 66 VBLANK_LAST_SCANLINE_VS_CLONE = 279 67 68 // Both the scanline immediately before and immediately after VBLANK 69 // are non-rendering and non-vblank. 70 }; 71 72 virtual uint8_t read(offs_t offset); 73 virtual void write(offs_t offset, uint8_t data); 74 virtual uint8_t palette_read(offs_t offset); 75 virtual void palette_write(offs_t offset, uint8_t data); 76 set_cpu_tag(T && tag)77 template <typename T> void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); } int_callback()78 auto int_callback() { return m_int_callback.bind(); } 79 80 /* routines */ 81 void apply_color_emphasis_and_clamp(bool is_pal_or_dendy, int color_emphasis, double& R, double& G, double& B); 82 rgb_t nespal_to_RGB(int color_intensity, int color_num, int color_emphasis, bool is_pal_or_dendy); 83 virtual void init_palette_tables(); 84 85 virtual void read_tile_plane_data(int address, int color); 86 virtual void shift_tile_plane_data(uint8_t &pix); 87 virtual void draw_tile_pixel(uint8_t pix, int color, uint32_t back_pen, uint32_t *&dest); 88 virtual void draw_tile(uint8_t *line_priority, int color_byte, int color_bits, int address, int start_x, uint32_t back_pen, uint32_t *&dest); 89 virtual void draw_background( uint8_t *line_priority ); 90 virtual void draw_back_pen(uint32_t* dst, int back_pen); 91 void draw_background_pen(); 92 93 virtual void read_sprite_plane_data(int address); 94 virtual void make_sprite_pixel_data(uint8_t &pixel_data, int flipx); 95 virtual void draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32 &bitmap); 96 virtual bool is_spritepixel_opaque(int pixel_data, int color); 97 virtual void draw_sprite_pixel_low(bitmap_rgb32& bitmap, int pixel_data, int pixel, int sprite_xpos, int color, int sprite_index, uint8_t* line_priority); 98 virtual void draw_sprite_pixel_high(bitmap_rgb32& bitmap, int pixel_data, int pixel, int sprite_xpos, int color, int sprite_index, uint8_t* line_priority); 99 virtual void read_extra_sprite_bits(int sprite_index); 100 101 virtual int apply_sprite_pattern_page(int index1, int size); 102 virtual void draw_sprites(uint8_t *line_priority); 103 void render_scanline(); 104 virtual void scanline_increment_fine_ycounter(); 105 void update_visible_enabled_scanline(); 106 void update_visible_disabled_scanline(); 107 void update_visible_scanline(); 108 void update_scanline(); 109 110 void spriteram_dma(address_space &space, const uint8_t page); 111 void render(bitmap_rgb32 &bitmap, int flipx, int flipy, int sx, int sy, const rectangle &cliprect); 112 uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); 113 get_current_scanline()114 int get_current_scanline() { return m_scanline; } set_scanline_callback(T &&...args)115 template <typename... T> void set_scanline_callback(T &&... args) { m_scanline_callback_proc.set(std::forward<T>(args)...); m_scanline_callback_proc.resolve(); /* FIXME: if this is supposed to be set at config time, it should be resolved on start */ } set_hblank_callback(T &&...args)116 template <typename... T> void set_hblank_callback(T &&... args) { m_hblank_callback_proc.set(std::forward<T>(args)...); m_hblank_callback_proc.resolve(); /* FIXME: if this is supposed to be set at config time, it should be resolved on start */ } set_vidaccess_callback(T &&...args)117 template <typename... T> void set_vidaccess_callback(T &&... args) { m_vidaccess_callback_proc.set(std::forward<T>(args)...); m_vidaccess_callback_proc.resolve(); /* FIXME: if this is supposed to be set at config time, it should be resolved on start */ } set_scanlines_per_frame(int scanlines)118 void set_scanlines_per_frame(int scanlines) { m_scanlines_per_frame = scanlines; } 119 120 // MMC5 has to be able to check this is_sprite_8x16()121 int is_sprite_8x16() { return m_regs[PPU_CONTROL0] & PPU_CONTROL0_SPRITE_SIZE; } get_draw_phase()122 int get_draw_phase() { return m_draw_phase; } get_tilenum()123 int get_tilenum() { return m_tilecount; } 124 125 //27/12/2002 (HACK!) set_latch(T &&...args)126 template <typename... T> void set_latch(T &&... args) { m_latch.set(std::forward<T>(args)...); m_latch.resolve(); /* FIXME: if this is supposed to be set at config time, it should be resolved on start */ } 127 128 // void update_screen(bitmap_t &bitmap, const rectangle &cliprect); 129 130 // some bootleg / clone hardware appears to ignore this use_sprite_write_limitation_disable()131 void use_sprite_write_limitation_disable() { m_use_sprite_write_limitation = false; } 132 uint16_t get_vram_dest(); 133 void set_vram_dest(uint16_t dest); 134 135 void ppu2c0x(address_map &map); 136 in_vblanking()137 bool in_vblanking() { return (m_scanline >= m_vblank_first_scanline - 1); } 138 protected: 139 ppu2c0x_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal_map); 140 141 // registers definition 142 enum 143 { 144 PPU_CONTROL0 = 0, 145 PPU_CONTROL1, 146 PPU_STATUS, 147 PPU_SPRITE_ADDRESS, 148 PPU_SPRITE_DATA, 149 PPU_SCROLL, 150 PPU_ADDRESS, 151 PPU_DATA, 152 PPU_MAX_REG 153 }; 154 155 // bit definitions for (some of) the registers 156 enum 157 { 158 PPU_CONTROL0_INC = 0x04, 159 PPU_CONTROL0_SPR_SELECT = 0x08, 160 PPU_CONTROL0_CHR_SELECT = 0x10, 161 PPU_CONTROL0_SPRITE_SIZE = 0x20, 162 PPU_CONTROL0_NMI = 0x80, 163 164 PPU_CONTROL1_DISPLAY_MONO = 0x01, 165 PPU_CONTROL1_BACKGROUND_L8 = 0x02, 166 PPU_CONTROL1_SPRITES_L8 = 0x04, 167 PPU_CONTROL1_BACKGROUND = 0x08, 168 PPU_CONTROL1_SPRITES = 0x10, 169 PPU_CONTROL1_COLOR_EMPHASIS = 0xe0, 170 171 PPU_STATUS_8SPRITES = 0x20, 172 PPU_STATUS_SPRITE0_HIT = 0x40, 173 PPU_STATUS_VBLANK = 0x80 174 }; 175 176 // construction/destruction 177 ppu2c0x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0); 178 179 virtual void device_start() override; 180 virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; 181 virtual void device_config_complete() override; 182 183 // device_config_memory_interface overrides 184 virtual space_config_vector memory_space_config() const override; 185 186 // address space configurations 187 const address_space_config m_space_config; 188 189 required_device<cpu_device> m_cpu; 190 191 void start_nopalram(); 192 193 int m_scanlines_per_frame; /* number of scanlines per frame */ 194 int m_security_value; /* 2C05 protection */ 195 int m_vblank_first_scanline; /* the very first scanline where VBLANK occurs */ 196 197 // used in rendering 198 uint8_t m_planebuf[2]; 199 int m_scanline; /* scanline count */ 200 std::unique_ptr<uint8_t[]> m_spriteram; /* sprite ram */ 201 202 int m_videoram_addr_mask; 203 int m_global_refresh_mask; 204 int m_line_write_increment_large; 205 bool m_paletteram_in_ppuspace; // sh6578 doesn't have the palette in PPU space, so various side-effects don't apply 206 std::vector<uint8_t> m_palette_ram; /* shouldn't be in main memory! */ 207 std::unique_ptr<bitmap_rgb32> m_bitmap; /* target bitmap */ 208 int m_regs[PPU_MAX_REG]; /* registers */ 209 int m_tile_page; /* current tile page */ 210 int m_back_color; /* background color */ 211 int m_refresh_data; /* refresh-related */ 212 int m_x_fine; /* refresh-related */ 213 int m_toggle; /* used to latch hi-lo scroll */ 214 int m_tilecount; /* MMC5 can change attributes to subsets of the 34 visible tiles */ 215 latch_delegate m_latch; 216 217 218 uint8_t readbyte(offs_t address); 219 220 uint32_t m_nespens[0x40*8]; 221 private: 222 static constexpr device_timer_id TIMER_HBLANK = 0; 223 static constexpr device_timer_id TIMER_NMI = 1; 224 static constexpr device_timer_id TIMER_SCANLINE = 2; 225 226 inline void writebyte(offs_t address, uint8_t data); 227 228 229 scanline_delegate m_scanline_callback_proc; /* optional scanline callback */ 230 hblank_delegate m_hblank_callback_proc; /* optional hblank callback */ 231 vidaccess_delegate m_vidaccess_callback_proc; /* optional video access callback */ 232 devcb_write_line m_int_callback; /* nmi access callback from interface */ 233 234 int m_refresh_latch; /* refresh-related */ 235 int m_add; /* vram increment amount */ 236 int m_videomem_addr; /* videomem address pointer */ 237 int m_data_latch; /* latched videomem data */ 238 int m_buffered_data; 239 int m_sprite_page; /* current sprite page */ 240 int m_scan_scale; /* scan scale */ 241 int m_draw_phase; /* MMC5 uses different regs for BG and OAM */ 242 243 // timers 244 emu_timer *m_hblank_timer; /* hblank period at end of each scanline */ 245 emu_timer *m_nmi_timer; /* NMI timer */ 246 emu_timer *m_scanline_timer; /* scanline timer */ 247 248 bool m_use_sprite_write_limitation; 249 }; 250 251 class ppu2c0x_rgb_device : public ppu2c0x_device { 252 protected: 253 ppu2c0x_rgb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0); 254 255 virtual void init_palette_tables() override; 256 257 private: 258 required_region_ptr<uint8_t> m_palette_data; 259 }; 260 261 class ppu2c02_device : public ppu2c0x_device { 262 public: 263 ppu2c02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 264 }; 265 266 class ppu2c03b_device : public ppu2c0x_rgb_device { 267 public: 268 ppu2c03b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 269 }; 270 271 class ppu2c04_device : public ppu2c0x_rgb_device { 272 public: 273 ppu2c04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 274 }; 275 276 class ppu2c07_device : public ppu2c0x_device { 277 public: 278 ppu2c07_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 279 }; 280 281 class ppupalc_device : public ppu2c0x_device { 282 public: 283 ppupalc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 284 }; 285 286 class ppu2c05_01_device : public ppu2c0x_rgb_device { 287 public: 288 ppu2c05_01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 289 }; 290 291 class ppu2c05_02_device : public ppu2c0x_rgb_device { 292 public: 293 ppu2c05_02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 294 }; 295 296 class ppu2c05_03_device : public ppu2c0x_rgb_device { 297 public: 298 ppu2c05_03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 299 }; 300 301 class ppu2c05_04_device : public ppu2c0x_rgb_device { 302 public: 303 ppu2c05_04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 304 }; 305 306 class ppu2c04_clone_device : public ppu2c0x_device { 307 public: 308 ppu2c04_clone_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); 309 310 virtual uint8_t read(offs_t offset) override; 311 virtual void write(offs_t offset, uint8_t data) override; 312 313 virtual void draw_background(uint8_t *line_priority) override; 314 virtual void draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32 &bitmap) override; 315 virtual void draw_sprites(uint8_t *line_priority) override; 316 317 virtual void init_palette_tables() override; 318 319 protected: 320 virtual void device_start() override; 321 322 private: 323 required_region_ptr<uint8_t> m_palette_data; 324 325 std::unique_ptr<uint8_t[]> m_spritebuf; /* buffered sprite ram for next frame */ 326 }; 327 328 // device type definition 329 //extern const device_type PPU_2C0X; 330 DECLARE_DEVICE_TYPE(PPU_2C02, ppu2c02_device) // NTSC NES 331 DECLARE_DEVICE_TYPE(PPU_2C03B, ppu2c03b_device) // Playchoice 10 332 DECLARE_DEVICE_TYPE(PPU_2C04, ppu2c04_device) // Vs. Unisystem 333 DECLARE_DEVICE_TYPE(PPU_2C07, ppu2c07_device) // PAL NES 334 DECLARE_DEVICE_TYPE(PPU_PALC, ppupalc_device) // PAL Clones 335 DECLARE_DEVICE_TYPE(PPU_2C05_01, ppu2c05_01_device) // Vs. Unisystem (Ninja Jajamaru Kun) 336 DECLARE_DEVICE_TYPE(PPU_2C05_02, ppu2c05_02_device) // Vs. Unisystem (Mighty Bomb Jack) 337 DECLARE_DEVICE_TYPE(PPU_2C05_03, ppu2c05_03_device) // Vs. Unisystem (Gumshoe) 338 DECLARE_DEVICE_TYPE(PPU_2C05_04, ppu2c05_04_device) // Vs. Unisystem (Top Gun) 339 DECLARE_DEVICE_TYPE(PPU_2C04C, ppu2c04_clone_device) // Vs. Unisystem (Super Mario Bros. bootlegs) 340 341 #endif // MAME_VIDEO_PPU2C0X_H 342