diff options
author | Miodrag Milanovic <mmicko@gmail.com> | 2017-02-05 12:46:44 +0100 |
---|---|---|
committer | Miodrag Milanovic <mmicko@gmail.com> | 2017-02-05 12:46:44 +0100 |
commit | 39370345d6a6f5bae5844da024af42196243f1c4 (patch) | |
tree | a552bbd8b6b63768eda95e063d93db9596055868 /src/devices/video/ppu2c0x.h | |
parent | 07d28fd8474dab2aa3896262362c9620a012fc55 (diff) |
Remove some dependency between src/devices/ and src/mame (nw)
Diffstat (limited to 'src/devices/video/ppu2c0x.h')
-rw-r--r-- | src/devices/video/ppu2c0x.h | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/src/devices/video/ppu2c0x.h b/src/devices/video/ppu2c0x.h new file mode 100644 index 00000000000..d426630eb64 --- /dev/null +++ b/src/devices/video/ppu2c0x.h @@ -0,0 +1,297 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi,Brad Oliver +/****************************************************************************** + + Nintendo 2C0x PPU emulation. + + Written by Ernesto Corvi. + This code is heavily based on Brad Oliver's MESS implementation. + +******************************************************************************/ + +#pragma once + +#ifndef __PPU_2C03B_H__ +#define __PPU_2C03B_H__ + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + +// mirroring types +#define PPU_MIRROR_NONE 0 +#define PPU_MIRROR_VERT 1 +#define PPU_MIRROR_HORZ 2 +#define PPU_MIRROR_HIGH 3 +#define PPU_MIRROR_LOW 4 +#define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror + +#define PPU_DRAW_BG 0 +#define PPU_DRAW_OAM 1 + + +// registers definition +enum +{ + PPU_CONTROL0 = 0, + PPU_CONTROL1, + PPU_STATUS, + PPU_SPRITE_ADDRESS, + PPU_SPRITE_DATA, + PPU_SCROLL, + PPU_ADDRESS, + PPU_DATA, + PPU_MAX_REG +}; + +// bit definitions for (some of) the registers +enum +{ + PPU_CONTROL0_INC = 0x04, + PPU_CONTROL0_SPR_SELECT = 0x08, + PPU_CONTROL0_CHR_SELECT = 0x10, + PPU_CONTROL0_SPRITE_SIZE = 0x20, + PPU_CONTROL0_NMI = 0x80, + + PPU_CONTROL1_DISPLAY_MONO = 0x01, + PPU_CONTROL1_BACKGROUND_L8 = 0x02, + PPU_CONTROL1_SPRITES_L8 = 0x04, + PPU_CONTROL1_BACKGROUND = 0x08, + PPU_CONTROL1_SPRITES = 0x10, + PPU_CONTROL1_COLOR_EMPHASIS = 0xe0, + + PPU_STATUS_8SPRITES = 0x20, + PPU_STATUS_SPRITE0_HIT = 0x40, + PPU_STATUS_VBLANK = 0x80 +}; + +enum +{ + PPU_NTSC_SCANLINES_PER_FRAME = 262, + PPU_PAL_SCANLINES_PER_FRAME = 312, + + PPU_BOTTOM_VISIBLE_SCANLINE = 239, + PPU_VBLANK_FIRST_SCANLINE = 241, + PPU_VBLANK_LAST_SCANLINE_NTSC = 260, + PPU_VBLANK_LAST_SCANLINE_PAL = 310 + + // Both the scanline immediately before and immediately after VBLANK + // are non-rendering and non-vblank. +}; + +/*----------- defined in video/ppu2c0x.c -----------*/ + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_PPU2C0X_ADD(_tag, _type) \ + MCFG_DEVICE_ADD(_tag, _type, 0) + +#define MCFG_PPU2C02_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C02) +#define MCFG_PPU2C03B_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C03B) +#define MCFG_PPU2C04_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C04) +#define MCFG_PPU2C07_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C07) +#define MCFG_PPU2C05_01_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C05_01) +#define MCFG_PPU2C05_02_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C05_02) +#define MCFG_PPU2C05_03_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C05_03) +#define MCFG_PPU2C05_04_ADD(_tag) \ + MCFG_PPU2C0X_ADD(_tag, PPU_2C05_04) + +#define MCFG_PPU2C0X_SET_SCREEN MCFG_VIDEO_SET_SCREEN + +#define MCFG_PPU2C0X_CPU(_tag) \ + ppu2c0x_device::set_cpu_tag(*device, "^" _tag); + +#define MCFG_PPU2C0X_COLORBASE(_color) \ + ppu2c0x_device::set_color_base(*device, _color); + +#define MCFG_PPU2C0X_SET_NMI(_class, _method) \ + ppu2c0x_device::set_nmi_delegate(*device, ppu2c0x_nmi_delegate(&_class::_method, #_class "::" #_method, nullptr, (_class *)nullptr)); + +#define MCFG_PPU2C0X_IGNORE_SPRITE_WRITE_LIMIT \ + ppu2c0x_device::use_sprite_write_limitation_disable(*device); + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* +typedef device_delegate<void (int scanline, int vblank, int blanked)> ppu2c0x_scanline_delegate; +typedef device_delegate<void (int scanline, int vblank, int blanked)> ppu2c0x_hblank_delegate; +typedef device_delegate<void (int *ppu_regs)> ppu2c0x_nmi_delegate; +typedef device_delegate<int (int address, int data)> ppu2c0x_vidaccess_delegate; +typedef device_delegate<void (offs_t offset)> ppu2c0x_latch_delegate; + + +// ======================> ppu2c0x_device + +class ppu2c0x_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + ppu2c0x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( palette_read ); + DECLARE_WRITE8_MEMBER( palette_write ); + + virtual void device_start() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + virtual void device_config_complete() override; + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override; + // address space configurations + const address_space_config m_space_config; + + static void set_cpu_tag(device_t &device, const char *tag) { downcast<ppu2c0x_device &>(device).m_cpu.set_tag(tag); } + static void set_color_base(device_t &device, int colorbase) { downcast<ppu2c0x_device &>(device).m_color_base = colorbase; } + static void set_nmi_delegate(device_t &device, ppu2c0x_nmi_delegate cb); + + /* routines */ + void init_palette( palette_device &palette, int first_entry ); + void init_palette_rgb( palette_device &palette, int first_entry ); + + void draw_background( uint8_t *line_priority ); + void draw_sprites( uint8_t *line_priority ); + void render_scanline(); + void update_scanline(); + + void spriteram_dma(address_space &space, const uint8_t page ); + void render( bitmap_ind16 &bitmap, int flipx, int flipy, int sx, int sy ); + int get_pixel( int x, int y ); + + int get_colorbase() { return m_color_base; }; + int get_current_scanline() { return m_scanline; }; + void set_scanline_callback( ppu2c0x_scanline_delegate cb ) { m_scanline_callback_proc = cb; m_scanline_callback_proc.bind_relative_to(*owner()); }; + void set_hblank_callback( ppu2c0x_hblank_delegate cb ) { m_hblank_callback_proc = cb; m_hblank_callback_proc.bind_relative_to(*owner()); }; + void set_vidaccess_callback( ppu2c0x_vidaccess_delegate cb ) { m_vidaccess_callback_proc = cb; m_vidaccess_callback_proc.bind_relative_to(*owner()); }; + void set_scanlines_per_frame( int scanlines ) { m_scanlines_per_frame = scanlines; }; + + // MMC5 has to be able to check this + int is_sprite_8x16() { return m_regs[PPU_CONTROL0] & PPU_CONTROL0_SPRITE_SIZE; }; + int get_draw_phase() { return m_draw_phase; }; + int get_tilenum() { return m_tilecount; }; + + //27/12/2002 (HACK!) + void set_latch( ppu2c0x_latch_delegate cb ) { m_latch = cb; m_latch.bind_relative_to(*owner()); }; + + // void update_screen(bitmap_t &bitmap, const rectangle &cliprect); + + required_device<cpu_device> m_cpu; + + std::unique_ptr<bitmap_ind16> m_bitmap; /* target bitmap */ + std::unique_ptr<uint8_t[]> m_spriteram; /* sprite ram */ + std::unique_ptr<pen_t[]> m_colortable; /* color table modified at run time */ + std::unique_ptr<pen_t[]> m_colortable_mono; /* monochromatic color table modified at run time */ + int m_scanline; /* scanline count */ + ppu2c0x_scanline_delegate m_scanline_callback_proc; /* optional scanline callback */ + ppu2c0x_hblank_delegate m_hblank_callback_proc; /* optional hblank callback */ + ppu2c0x_vidaccess_delegate m_vidaccess_callback_proc; /* optional video access callback */ + ppu2c0x_nmi_delegate m_nmi_callback_proc; /* nmi access callback from interface */ + int m_regs[PPU_MAX_REG]; /* registers */ + int m_refresh_data; /* refresh-related */ + int m_refresh_latch; /* refresh-related */ + int m_x_fine; /* refresh-related */ + int m_toggle; /* used to latch hi-lo scroll */ + int m_add; /* vram increment amount */ + int m_videomem_addr; /* videomem address pointer */ + int m_data_latch; /* latched videomem data */ + int m_buffered_data; + int m_tile_page; /* current tile page */ + int m_sprite_page; /* current sprite page */ + int m_back_color; /* background color */ + int m_color_base; + uint8_t m_palette_ram[0x20]; /* shouldn't be in main memory! */ + int m_scan_scale; /* scan scale */ + int m_scanlines_per_frame; /* number of scanlines per frame */ + int m_security_value; /* 2C05 protection */ + int m_tilecount; /* MMC5 can change attributes to subsets of the 34 visible tiles */ + int m_draw_phase; /* MMC5 uses different regs for BG and OAM */ + ppu2c0x_latch_delegate m_latch; + + // timers + emu_timer *m_hblank_timer; /* hblank period at end of each scanline */ + emu_timer *m_nmi_timer; /* NMI timer */ + emu_timer *m_scanline_timer; /* scanline timer */ + + // some bootleg / clone hardware appears to ignore this + static void use_sprite_write_limitation_disable(device_t &device) + { + ppu2c0x_device &dev = downcast<ppu2c0x_device &>(device); + dev.m_use_sprite_write_limitation = false; + } + + bool m_use_sprite_write_limitation; +private: + static const device_timer_id TIMER_HBLANK = 0; + static const device_timer_id TIMER_NMI = 1; + static const device_timer_id TIMER_SCANLINE = 2; + + inline uint8_t readbyte(offs_t address); + inline void writebyte(offs_t address, uint8_t data); + +}; + +class ppu2c02_device : public ppu2c0x_device { +public: + ppu2c02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c03b_device : public ppu2c0x_device { +public: + ppu2c03b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c04_device : public ppu2c0x_device { +public: + ppu2c04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c07_device : public ppu2c0x_device { +public: + ppu2c07_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c05_01_device : public ppu2c0x_device { +public: + ppu2c05_01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c05_02_device : public ppu2c0x_device { +public: + ppu2c05_02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c05_03_device : public ppu2c0x_device { +public: + ppu2c05_03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppu2c05_04_device : public ppu2c0x_device { +public: + ppu2c05_04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + + +// device type definition +//extern const device_type PPU_2C0X; +extern const device_type PPU_2C02; // NTSC NES +extern const device_type PPU_2C03B; // Playchoice 10 +extern const device_type PPU_2C04; // Vs. Unisystem +extern const device_type PPU_2C07; // PAL NES +extern const device_type PPU_2C05_01; // Vs. Unisystem (Ninja Jajamaru Kun) +extern const device_type PPU_2C05_02; // Vs. Unisystem (Mighty Bomb Jack) +extern const device_type PPU_2C05_03; // Vs. Unisystem (Gumshoe) +extern const device_type PPU_2C05_04; // Vs. Unisystem (Top Gun) + + +#endif |