summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/ppu2c0x.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/ppu2c0x.cpp')
-rw-r--r--src/devices/video/ppu2c0x.cpp787
1 files changed, 417 insertions, 370 deletions
diff --git a/src/devices/video/ppu2c0x.cpp b/src/devices/video/ppu2c0x.cpp
index fe220ed1e6e..dd895b469f1 100644
--- a/src/devices/video/ppu2c0x.cpp
+++ b/src/devices/video/ppu2c0x.cpp
@@ -32,18 +32,9 @@
/***************************************************************************
- CONSTANTS
+ CONSTANTS
***************************************************************************/
-/* constant definitions */
-#define VISIBLE_SCREEN_WIDTH (32*8) /* Visible screen width */
-#define VISIBLE_SCREEN_HEIGHT (30*8) /* Visible screen height */
-#define VIDEOMEM_SIZE 0x1000 /* videomem size */
-#define VIDEOMEM_PAGE_SIZE 0x400 /* videomem page size */
-#define SPRITERAM_SIZE 0x100 /* spriteram size */
-#define SPRITERAM_MASK (0x100-1) /* spriteram size */
-#define CHARGEN_NUM_CHARS 512 /* max number of characters handled by the chargen */
-
/* default monochromatic colortable */
static const pen_t default_colortable_mono[] =
{
@@ -87,13 +78,13 @@ DEFINE_DEVICE_TYPE(PPU_2C05_04, ppu2c05_04_device, "ppu2c05_04", "2C05_04 PPU")
// default address map
-void ppu2c0x_device::ppu2c0x(address_map &map)
+void ppu2c0x_device::ppu2c0x(address_map& map)
{
if (!has_configured_map(0))
{
map(0x0000, 0x3eff).ram();
map(0x3f00, 0x3fff).rw(FUNC(ppu2c0x_device::palette_read), FUNC(ppu2c0x_device::palette_write));
-// map(0x0000, 0x3fff).ram();
+ //map(0x0000, 0x3fff).ram();
}
}
@@ -104,7 +95,8 @@ void ppu2c0x_device::ppu2c0x(address_map &map)
device_memory_interface::space_config_vector ppu2c0x_device::memory_space_config() const
{
- return space_config_vector {
+ return space_config_vector
+ {
std::make_pair(0, &m_space_config)
};
}
@@ -123,40 +115,40 @@ void ppu2c0x_device::device_config_complete()
m_latch.set(nullptr);
}
-ppu2c0x_device::ppu2c0x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock)
- , device_memory_interface(mconfig, *this)
- , device_video_interface(mconfig, *this)
- , device_palette_interface(mconfig, *this)
- , m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, address_map_constructor(FUNC(ppu2c0x_device::ppu2c0x), this))
- , m_cpu(*this, finder_base::DUMMY_TAG)
- , m_scanline(0) // reset the scanline count
- , m_scanline_callback_proc(*this)
- , m_hblank_callback_proc(*this)
- , m_vidaccess_callback_proc(*this)
- , m_int_callback(*this)
- , m_refresh_data(0)
- , m_refresh_latch(0)
- , m_x_fine(0)
- , m_toggle(0)
- , m_add(1)
- , m_videomem_addr(0)
- , m_data_latch(0)
- , m_buffered_data(0)
- , m_tile_page(0)
- , m_sprite_page(0)
- , m_back_color(0)
- , m_scan_scale(1) // set the scan scale (this is for dual monitor vertical setups)
- , m_tilecount(0)
- , m_draw_phase(0)
- , m_latch(*this)
- , m_use_sprite_write_limitation(true)
+ppu2c0x_device::ppu2c0x_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal_map) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ device_video_interface(mconfig, *this),
+ device_palette_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, internal_map),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_scanline(0), // reset the scanline count
+ m_line_write_increment_large(32),
+ m_paletteram_in_ppuspace(false),
+ m_tile_page(0),
+ m_back_color(0),
+ m_refresh_data(0),
+ m_x_fine(0),
+ m_tilecount(0),
+ m_latch(*this),
+ m_scanline_callback_proc(*this),
+ m_hblank_callback_proc(*this),
+ m_vidaccess_callback_proc(*this),
+ m_int_callback(*this),
+ m_refresh_latch(0),
+ m_toggle(0),
+ m_add(1),
+ m_videomem_addr(0),
+ m_data_latch(0),
+ m_buffered_data(0),
+ m_sprite_page(0),
+ m_scan_scale(1), // set the scan scale (this is for dual monitor vertical setups)
+ m_draw_phase(0),
+ m_use_sprite_write_limitation(true)
{
- for (auto & elem : m_regs)
+ for (auto& elem : m_regs)
elem = 0;
- memset(m_palette_ram, 0, ARRAY_LENGTH(m_palette_ram));
-
m_scanlines_per_frame = NTSC_SCANLINES_PER_FRAME;
m_vblank_first_scanline = VBLANK_FIRST_SCANLINE;
@@ -164,34 +156,46 @@ ppu2c0x_device::ppu2c0x_device(const machine_config &mconfig, device_type type,
m_security_value = 0;
}
-ppu2c0x_rgb_device::ppu2c0x_rgb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_device(mconfig, type, tag, owner, clock)
- , m_palette_data(*this, "palette", 0xc0)
+ppu2c0x_device::ppu2c0x_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(ppu2c0x_device::ppu2c0x), this))
+{
+ m_paletteram_in_ppuspace = true;
+}
+
+ppu2c0x_rgb_device::ppu2c0x_rgb_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_device(mconfig, type, tag, owner, clock),
+ m_palette_data(*this, "palette", 0xc0)
{
}
// NTSC NES
-ppu2c02_device::ppu2c02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_device(mconfig, PPU_2C02, tag, owner, clock)
+ppu2c02_device::ppu2c02_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_device(mconfig, PPU_2C02, tag, owner, clock)
{
}
// Playchoice 10
-ppu2c03b_device::ppu2c03b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_rgb_device(mconfig, PPU_2C03B, tag, owner, clock)
+ppu2c03b_device::ppu2c03b_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_rgb_device(mconfig, PPU_2C03B, tag, owner, clock)
{
}
// Vs. Unisystem
-ppu2c04_device::ppu2c04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_rgb_device(mconfig, PPU_2C04, tag, owner, clock)
+ppu2c04_device::ppu2c04_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_rgb_device(mconfig, PPU_2C04, tag, owner, clock)
{
}
// PAL NES
-ppu2c07_device::ppu2c07_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_device(mconfig, PPU_2C07, tag, owner, clock)
+ppu2c07_device::ppu2c07_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_device(mconfig, PPU_2C07, tag, owner, clock)
{
m_scanlines_per_frame = PAL_SCANLINES_PER_FRAME;
}
// PAL clones
-ppupalc_device::ppupalc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_device(mconfig, PPU_PALC, tag, owner, clock)
+ppupalc_device::ppupalc_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_device(mconfig, PPU_PALC, tag, owner, clock)
{
m_scanlines_per_frame = PAL_SCANLINES_PER_FRAME;
m_vblank_first_scanline = VBLANK_FIRST_SCANLINE_PALC;
@@ -199,22 +203,26 @@ ppupalc_device::ppupalc_device(const machine_config &mconfig, const char *tag, d
// The PPU_2C05 variants have different protection value, set at device start, but otherwise are all the same...
// Vs. Unisystem (Ninja Jajamaru Kun)
-ppu2c05_01_device::ppu2c05_01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_rgb_device(mconfig, PPU_2C05_01, tag, owner, clock)
+ppu2c05_01_device::ppu2c05_01_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_rgb_device(mconfig, PPU_2C05_01, tag, owner, clock)
{
m_security_value = 0x1b; // game (jajamaru) doesn't seem to ever actually check it
}
// Vs. Unisystem (Mighty Bomb Jack)
-ppu2c05_02_device::ppu2c05_02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_rgb_device(mconfig, PPU_2C05_02, tag, owner, clock)
+ppu2c05_02_device::ppu2c05_02_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_rgb_device(mconfig, PPU_2C05_02, tag, owner, clock)
{
m_security_value = 0x3d;
}
// Vs. Unisystem (Gumshoe)
-ppu2c05_03_device::ppu2c05_03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_rgb_device(mconfig, PPU_2C05_03, tag, owner, clock)
+ppu2c05_03_device::ppu2c05_03_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_rgb_device(mconfig, PPU_2C05_03, tag, owner, clock)
{
m_security_value = 0x1c;
}
// Vs. Unisystem (Top Gun)
-ppu2c05_04_device::ppu2c05_04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_rgb_device(mconfig, PPU_2C05_04, tag, owner, clock)
+ppu2c05_04_device::ppu2c05_04_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ ppu2c0x_rgb_device(mconfig, PPU_2C05_04, tag, owner, clock)
{
m_security_value = 0x1b;
}
@@ -245,6 +253,11 @@ void ppu2c0x_device::device_start()
m_colortable = std::make_unique<pen_t[]>(ARRAY_LENGTH(default_colortable));
m_colortable_mono = std::make_unique<pen_t[]>(ARRAY_LENGTH(default_colortable_mono));
+ m_palette_ram.resize(0x20);
+
+ for (int i = 0; i < 0x20; i++)
+ m_palette_ram[i] = 0x00;
+
/* initialize the color tables */
for (int i = 0; i < ARRAY_LENGTH(default_colortable_mono); i++)
{
@@ -291,7 +304,7 @@ void ppu2c0x_device::device_start()
// readbyte - read a byte at the given address
//-------------------------------------------------
-inline uint8_t ppu2c0x_device::readbyte(offs_t address)
+uint8_t ppu2c0x_device::readbyte(offs_t address)
{
return space().read_byte(address);
}
@@ -413,14 +426,14 @@ void ppu2c0x_device::init_palette(bool indirect)
switch (color_emphasis)
{
- case 0: r_mod = 1.0; g_mod = 1.0; b_mod = 1.0; break;
- case 1: r_mod = 1.24; g_mod = .915; b_mod = .743; break;
- case 2: r_mod = .794; g_mod = 1.09; b_mod = .882; break;
- case 3: r_mod = .905; g_mod = 1.03; b_mod = 1.28; break;
- case 4: r_mod = .741; g_mod = .987; b_mod = 1.0; break;
- case 5: r_mod = 1.02; g_mod = .908; b_mod = .979; break;
- case 6: r_mod = 1.02; g_mod = .98; b_mod = .653; break;
- case 7: r_mod = .75; g_mod = .75; b_mod = .75; break;
+ case 0: r_mod = 1.0; g_mod = 1.0; b_mod = 1.0; break;
+ case 1: r_mod = 1.24; g_mod = .915; b_mod = .743; break;
+ case 2: r_mod = .794; g_mod = 1.09; b_mod = .882; break;
+ case 3: r_mod = .905; g_mod = 1.03; b_mod = 1.28; break;
+ case 4: r_mod = .741; g_mod = .987; b_mod = 1.0; break;
+ case 5: r_mod = 1.02; g_mod = .908; b_mod = .979; break;
+ case 6: r_mod = 1.02; g_mod = .98; b_mod = .653; break;
+ case 7: r_mod = .75; g_mod = .75; b_mod = .75; break;
}
*/
@@ -451,13 +464,13 @@ void ppu2c0x_rgb_device::init_palette()
for (int color_emphasis = 0; color_emphasis < 8; color_emphasis++)
{
for (int color_num = 0; color_num < 64; color_num++)
- {
- int R = ((color_emphasis & 1) ? 7 : m_palette_data[color_num * 3]);
- int G = ((color_emphasis & 2) ? 7 : m_palette_data[color_num * 3 + 1]);
- int B = ((color_emphasis & 4) ? 7 : m_palette_data[color_num * 3 + 2]);
+ {
+ int R = ((color_emphasis & 1) ? 7 : m_palette_data[color_num * 3]);
+ int G = ((color_emphasis & 2) ? 7 : m_palette_data[color_num * 3 + 1]);
+ int B = ((color_emphasis & 4) ? 7 : m_palette_data[color_num * 3 + 2]);
- set_pen_color(entry++, pal3bit(R), pal3bit(G), pal3bit(B));
- }
+ set_pen_color(entry++, pal3bit(R), pal3bit(G), pal3bit(B));
+ }
}
/* color tables are modified at run-time, and are initialized on 'ppu2c0x_reset' */
@@ -487,96 +500,96 @@ static const gfx_layout ppu_charlayout =
// device_timer - handle timer events
//-------------------------------------------------
-void ppu2c0x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void ppu2c0x_device::device_timer(emu_timer& timer, device_timer_id id, int param, void* ptr)
{
int blanked, vblank;
switch (id)
{
- case TIMER_HBLANK:
- blanked = (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES)) == 0;
- vblank = ((m_scanline >= m_vblank_first_scanline - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
+ case TIMER_HBLANK:
+ blanked = (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES)) == 0;
+ vblank = ((m_scanline >= m_vblank_first_scanline - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
- //update_scanline();
+ //update_scanline();
- if (!m_hblank_callback_proc.isnull())
- m_hblank_callback_proc(m_scanline, vblank, blanked);
+ if (!m_hblank_callback_proc.isnull())
+ m_hblank_callback_proc(m_scanline, vblank, blanked);
- m_hblank_timer->adjust(attotime::never);
- break;
+ m_hblank_timer->adjust(attotime::never);
+ break;
- case TIMER_NMI:
- // Actually fire the VMI
- m_int_callback(ASSERT_LINE);
- m_int_callback(CLEAR_LINE);
+ case TIMER_NMI:
+ // Actually fire the VMI
+ m_int_callback(ASSERT_LINE);
+ m_int_callback(CLEAR_LINE);
- m_nmi_timer->adjust(attotime::never);
- break;
+ m_nmi_timer->adjust(attotime::never);
+ break;
- case TIMER_SCANLINE:
- blanked = (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES)) == 0;
- vblank = ((m_scanline >= m_vblank_first_scanline - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
- int next_scanline;
+ case TIMER_SCANLINE:
+ blanked = (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES)) == 0;
+ vblank = ((m_scanline >= m_vblank_first_scanline - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
+ int next_scanline;
- /* if a callback is available, call it */
- if (!m_scanline_callback_proc.isnull())
- m_scanline_callback_proc(m_scanline, vblank, blanked);
+ /* if a callback is available, call it */
+ if (!m_scanline_callback_proc.isnull())
+ m_scanline_callback_proc(m_scanline, vblank, blanked);
- /* update the scanline that just went by */
- update_scanline();
+ /* update the scanline that just went by */
+ update_scanline();
- /* increment our scanline count */
- m_scanline++;
+ /* increment our scanline count */
+ m_scanline++;
- // logerror("starting scanline %d (MAME %d, beam %d)\n", m_scanline, device->screen().vpos(), device->screen().hpos());
+ //logerror("starting scanline %d (MAME %d, beam %d)\n", m_scanline, device->screen().vpos(), device->screen().hpos());
- /* Note: this is called at the _end_ of each scanline */
- if (m_scanline == m_vblank_first_scanline)
- {
- // logerror("vblank starting\n");
- /* We just entered VBLANK */
- m_regs[PPU_STATUS] |= PPU_STATUS_VBLANK;
-
- /* If NMI's are set to be triggered, go for it */
- if (m_regs[PPU_CONTROL0] & PPU_CONTROL0_NMI)
- {
- // We need an ever-so-slight delay between entering vblank and firing an NMI - enough so that
- // a game can read the high bit of $2002 before the NMI is called (potentially resetting the bit
- // via a read from $2002 in the NMI handler).
- // B-Wings is an example game that needs this.
- m_nmi_timer->adjust(m_cpu->cycles_to_attotime(4));
- }
- }
+ /* Note: this is called at the _end_ of each scanline */
+ if (m_scanline == m_vblank_first_scanline)
+ {
+ // logerror("vblank starting\n");
+ /* We just entered VBLANK */
+ m_regs[PPU_STATUS] |= PPU_STATUS_VBLANK;
- if (m_scanline == m_scanlines_per_frame - 1)
+ /* If NMI's are set to be triggered, go for it */
+ if (m_regs[PPU_CONTROL0] & PPU_CONTROL0_NMI)
{
- // logerror("vblank ending\n");
- /* clear the vblank & sprite hit flag */
- m_regs[PPU_STATUS] &= ~(PPU_STATUS_VBLANK | PPU_STATUS_SPRITE0_HIT | PPU_STATUS_8SPRITES);
+ // We need an ever-so-slight delay between entering vblank and firing an NMI - enough so that
+ // a game can read the high bit of $2002 before the NMI is called (potentially resetting the bit
+ // via a read from $2002 in the NMI handler).
+ // B-Wings is an example game that needs this.
+ m_nmi_timer->adjust(m_cpu->cycles_to_attotime(4));
}
+ }
- /* see if we rolled */
- else if (m_scanline == m_scanlines_per_frame)
- {
- /* if background or sprites are enabled, copy the ppu address latch */
- if (!blanked)
- m_refresh_data = m_refresh_latch;
+ if (m_scanline == m_scanlines_per_frame - 1)
+ {
+ //logerror("vblank ending\n");
+ /* clear the vblank & sprite hit flag */
+ m_regs[PPU_STATUS] &= ~(PPU_STATUS_VBLANK | PPU_STATUS_SPRITE0_HIT | PPU_STATUS_8SPRITES);
+ }
- /* reset the scanline count */
- m_scanline = 0;
- //logerror("sprite 0 x: %d y: %d num: %d\n", m_spriteram[3], m_spriteram[0] + 1, m_spriteram[1]);
- }
+ /* see if we rolled */
+ else if (m_scanline == m_scanlines_per_frame)
+ {
+ /* if background or sprites are enabled, copy the ppu address latch */
+ if (!blanked)
+ m_refresh_data = m_refresh_latch;
- next_scanline = m_scanline + 1;
- if (next_scanline == m_scanlines_per_frame)
- next_scanline = 0;
+ /* reset the scanline count */
+ m_scanline = 0;
+ //logerror("sprite 0 x: %d y: %d num: %d\n", m_spriteram[3], m_spriteram[0] + 1, m_spriteram[1]);
+ }
- // Call us back when the hblank starts for this scanline
- m_hblank_timer->adjust(m_cpu->cycles_to_attotime(260) / 3); // ??? FIXME - hardcoding NTSC, need better calculation
+ next_scanline = m_scanline + 1;
+ if (next_scanline == m_scanlines_per_frame)
+ next_scanline = 0;
- // trigger again at the start of the next scanline
- m_scanline_timer->adjust(screen().time_until_pos(next_scanline * m_scan_scale));
- break;
+ // Call us back when the hblank starts for this scanline
+ m_hblank_timer->adjust(m_cpu->cycles_to_attotime(260) / 3); // ??? FIXME - hardcoding NTSC, need better calculation
+
+ // trigger again at the start of the next scanline
+ m_scanline_timer->adjust(screen().time_until_pos(next_scanline * m_scan_scale));
+ break;
}
}
@@ -587,20 +600,20 @@ void ppu2c0x_device::read_tile_plane_data(int address, int color)
m_planebuf[1] = readbyte((address + 8) & 0x1fff);
}
-void ppu2c0x_device::shift_tile_plane_data(uint8_t &pix)
+void ppu2c0x_device::shift_tile_plane_data(uint8_t& pix)
{
pix = ((m_planebuf[0] >> 7) & 1) | (((m_planebuf[1] >> 7) & 1) << 1);
m_planebuf[0] = m_planebuf[0] << 1;
m_planebuf[1] = m_planebuf[1] << 1;
}
-void ppu2c0x_device::draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uint32_t *&dest, const pen_t *color_table)
+void ppu2c0x_device::draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uint32_t*& dest, const pen_t* color_table)
{
pen_t pen;
if (pix)
{
- const pen_t *paldata = &color_table[4 * color];
+ const pen_t* paldata = &color_table[4 * color];
pen = this->pen(paldata[pix]);
}
else
@@ -611,7 +624,7 @@ void ppu2c0x_device::draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uin
*dest = pen;
}
-void ppu2c0x_device::draw_tile(uint8_t *line_priority, int color_byte, int color_bits, int address, int start_x, pen_t back_pen, uint32_t *&dest, const pen_t *color_table)
+void ppu2c0x_device::draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, pen_t back_pen, uint32_t*& dest, const pen_t* color_table)
{
int color = (((color_byte >> color_bits) & 0x03));
@@ -635,17 +648,17 @@ void ppu2c0x_device::draw_tile(uint8_t *line_priority, int color_byte, int color
}
}
-void ppu2c0x_device::draw_background(uint8_t *line_priority)
-{
- bitmap_rgb32 &bitmap = *m_bitmap;
- int start_x = (m_x_fine ^ 0x07) - 7;
- uint8_t scroll_x_coarse, scroll_y_coarse, scroll_y_fine, color_mask;
- int x, tile_index, i;
+// m_refresh_data is important as it is updated during rendering, and overwritten when you write new scroll values
+// making raster effects more complex than on other systems
+// https://retrocomputing.stackexchange.com/questions/1898/how-can-i-create-a-split-scroll-effect-in-an-nes-game
- const pen_t *color_table;
+void ppu2c0x_device::draw_background(uint8_t* line_priority)
+{
+ bitmap_rgb32& bitmap = *m_bitmap;
- m_tilecount = 0;
+ uint8_t color_mask;
+ const pen_t* color_table;
/* setup the color mask and colortable to use */
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
@@ -664,17 +677,21 @@ void ppu2c0x_device::draw_background(uint8_t *line_priority)
/* determine where in the nametable to start drawing from */
/* based on the current scanline and scroll regs */
- scroll_x_coarse = m_refresh_data & 0x1f;
- scroll_y_coarse = (m_refresh_data & 0x3e0) >> 5;
- scroll_y_fine = (m_refresh_data & 0x7000) >> 12;
+ uint8_t scroll_x_coarse = m_refresh_data & 0x001f;
+ uint8_t scroll_y_coarse = (m_refresh_data & 0x03e0) >> 5;
+ uint16_t nametable = (m_refresh_data & 0x0c00);
+ uint8_t scroll_y_fine = (m_refresh_data & 0x7000) >> 12;
- x = scroll_x_coarse;
+ int x = scroll_x_coarse;
/* get the tile index */
- tile_index = ((m_refresh_data & 0xc00) | 0x2000) + scroll_y_coarse * 32;
+ int tile_index = (nametable | 0x2000) + scroll_y_coarse * 32;
/* set up dest */
- uint32_t *dest = &bitmap.pix32(m_scanline, start_x);
+ int start_x = (m_x_fine ^ 0x07) - 7;
+ uint32_t* dest = &bitmap.pix32(m_scanline, start_x);
+
+ m_tilecount = 0;
/* draw the 32 or 33 tiles that make up a line */
while (m_tilecount < 34)
@@ -730,7 +747,7 @@ void ppu2c0x_device::draw_background(uint8_t *line_priority)
if (!(m_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND_L8))
{
dest = &bitmap.pix32(m_scanline);
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
*(dest++) = back_pen;
line_priority[i] ^= 0x02;
@@ -738,13 +755,28 @@ void ppu2c0x_device::draw_background(uint8_t *line_priority)
}
}
+void ppu2c0x_device::draw_background_pen()
+{
+ bitmap_rgb32& bitmap = *m_bitmap;
+
+ /* setup the color mask and colortable to use */
+ uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0xf0 : 0xff;
+
+ /* cache the background pen */
+ pen_t back_pen = pen(m_back_color & color_mask);
+
+ // Fill this scanline with the background pen.
+ for (int i = 0; i < bitmap.width(); i++)
+ bitmap.pix32(m_scanline, i) = back_pen;
+}
+
void ppu2c0x_device::read_sprite_plane_data(int address)
{
m_planebuf[0] = readbyte((address + 0) & 0x1fff);
m_planebuf[1] = readbyte((address + 8) & 0x1fff);
}
-void ppu2c0x_device::make_sprite_pixel_data(uint8_t &pixel_data, int flipx)
+void ppu2c0x_device::make_sprite_pixel_data(uint8_t& pixel_data, int flipx)
{
if (flipx)
{
@@ -760,9 +792,9 @@ void ppu2c0x_device::make_sprite_pixel_data(uint8_t &pixel_data, int flipx)
}
}
-void ppu2c0x_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32 &bitmap)
+void ppu2c0x_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32& bitmap)
{
- const pen_t *paldata = &m_colortable[4 * color];
+ const pen_t* paldata = &m_colortable[4 * color];
bitmap.pix32(m_scanline, sprite_xpos + pixel) = pen(paldata[pixel_data]);
}
@@ -771,9 +803,9 @@ void ppu2c0x_device::read_extra_sprite_bits(int sprite_index)
// needed for some clones
}
-void ppu2c0x_device::draw_sprites(uint8_t *line_priority)
+void ppu2c0x_device::draw_sprites(uint8_t* line_priority)
{
- bitmap_rgb32 &bitmap = *m_bitmap;
+ bitmap_rgb32& bitmap = *m_bitmap;
int sprite_xpos, sprite_ypos, sprite_index;
int tile, index1;
@@ -790,7 +822,7 @@ void ppu2c0x_device::draw_sprites(uint8_t *line_priority)
/* determine if the sprites are 8x8 or 8x16 */
size = (m_regs[PPU_CONTROL0] & PPU_CONTROL0_SPRITE_SIZE) ? 16 : 8;
- first_pixel = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_SPRITES_L8)? 0: 8;
+ first_pixel = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_SPRITES_L8) ? 0 : 8;
for (sprite_index = 0; sprite_index < SPRITERAM_SIZE; sprite_index += 4)
{
@@ -816,11 +848,11 @@ void ppu2c0x_device::draw_sprites(uint8_t *line_priority)
if ((sprite_ypos + size <= m_scanline) || (sprite_ypos > m_scanline))
continue;
- tile = m_spriteram[sprite_index + 1];
+ tile = m_spriteram[sprite_index + 1];
color = (m_spriteram[sprite_index + 2] & 0x03) + 4;
- pri = m_spriteram[sprite_index + 2] & 0x20;
- flipx = m_spriteram[sprite_index + 2] & 0x40;
- flipy = m_spriteram[sprite_index + 2] & 0x80;
+ pri = m_spriteram[sprite_index + 2] & 0x20;
+ flipx = m_spriteram[sprite_index + 2] & 0x40;
+ flipy = m_spriteram[sprite_index + 2] & 0x80;
read_extra_sprite_bits(sprite_index);
if (size == 16)
@@ -852,13 +884,13 @@ void ppu2c0x_device::draw_sprites(uint8_t *line_priority)
if (size == 8)
index1 += ((m_sprite_page == 0) ? 0 : 0x1000);
- read_sprite_plane_data(index1+sprite_line);
+ read_sprite_plane_data(index1 + sprite_line);
/* if there are more than 8 sprites on this line, set the flag */
if (sprite_count == 8)
{
m_regs[PPU_STATUS] |= PPU_STATUS_8SPRITES;
-// logerror ("> 8 sprites, scanline: %d\n", m_scanline);
+ //logerror ("> 8 sprites, scanline: %d\n", m_scanline);
/* the real NES only draws up to 8 sprites - the rest should be invisible */
break;
@@ -956,20 +988,12 @@ void ppu2c0x_device::render_scanline()
/* see if we need to render the background */
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND)
+ {
draw_background(line_priority);
+ }
else
{
- bitmap_rgb32 &bitmap = *m_bitmap;
-
- /* setup the color mask and colortable to use */
- uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0xf0 : 0xff;
-
- /* cache the background pen */
- pen_t back_pen = pen(m_back_color & color_mask);
-
- // Fill this scanline with the background pen.
- for (int i = 0; i < bitmap.width(); i++)
- bitmap.pix32(m_scanline, i) = back_pen;
+ draw_background_pen();
}
m_draw_phase = PPU_DRAW_OAM;
@@ -983,74 +1007,96 @@ void ppu2c0x_device::render_scanline()
g_profiler.stop();
}
-void ppu2c0x_device::update_scanline()
+void ppu2c0x_device::scanline_increment_fine_ycounter()
{
- if (m_scanline <= BOTTOM_VISIBLE_SCANLINE)
+ /* increment the fine y-scroll */
+ m_refresh_data += 0x1000;
+
+ /* if it's rolled, increment the coarse y-scroll */
+ if (m_refresh_data & 0x8000)
{
- /* Render this scanline if appropriate */
- if (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES))
- {
- if (m_scanline_timer->remaining() == attotime::zero)
- {
- /* If background or sprites are enabled, copy the ppu address latch */
- /* Copy only the scroll x-coarse and the x-overflow bit */
- m_refresh_data &= ~0x041f;
- m_refresh_data |= (m_refresh_latch & 0x041f);
- }
+ uint16_t tmp;
+ tmp = (m_refresh_data & 0x03e0) + 0x20;
+ m_refresh_data &= 0x7c1f;
-// logerror("updating refresh_data: %04x (scanline: %d)\n", m_refresh_data, m_scanline);
- render_scanline();
- }
+ /* handle bizarro scrolling rollover at the 30th (not 32nd) vertical tile */
+ if (tmp == 0x03c0)
+ m_refresh_data ^= 0x0800;
else
- {
- bitmap_rgb32 &bitmap = *m_bitmap;
- pen_t back_pen;
+ m_refresh_data |= (tmp & 0x03e0);
- /* setup the color mask and colortable to use */
- uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0xf0 : 0xff;
+ //logerror("updating refresh_data: %04x\n", m_refresh_data);
+ }
+}
- /* cache the background pen */
- if (m_videomem_addr >= 0x3f00)
- {
- // If the PPU's VRAM address happens to point into palette ram space while
- // both the sprites and background are disabled, the PPU paints the scanline
- // with the palette entry at the VRAM address instead of the usual background
- // pen. Micro Machines makes use of this feature.
- int pen_num = m_palette_ram[(m_videomem_addr & 0x03) ? (m_videomem_addr & 0x1f) : 0];
+void ppu2c0x_device::update_visible_enabled_scanline()
+{
+ if (m_scanline_timer->remaining() == attotime::zero)
+ {
+ /* If background or sprites are enabled, copy the ppu address latch */
+ /* Copy only the scroll x-coarse and the x-overflow bit */
+ m_refresh_data &= ~0x041f;
+ m_refresh_data |= (m_refresh_latch & 0x041f);
+ }
- back_pen = pen(pen_num);
- }
- else
- back_pen = pen(m_back_color & color_mask);
+ //logerror("updating refresh_data: %04x (scanline: %d)\n", m_refresh_data, m_scanline);
+ render_scanline();
+}
- // Fill this scanline with the background pen.
- for (int i = 0; i < bitmap.width(); i++)
- bitmap.pix32(m_scanline, i) = back_pen;
- }
+void ppu2c0x_device::update_visible_disabled_scanline()
+{
+ bitmap_rgb32& bitmap = *m_bitmap;
+ pen_t back_pen;
- if (m_scanline_timer->remaining() == attotime::zero)
- {
- /* increment the fine y-scroll */
- m_refresh_data += 0x1000;
+ /* setup the color mask and colortable to use */
+ uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0xf0 : 0xff;
- /* if it's rolled, increment the coarse y-scroll */
- if (m_refresh_data & 0x8000)
- {
- uint16_t tmp;
- tmp = (m_refresh_data & 0x03e0) + 0x20;
- m_refresh_data &= 0x7c1f;
+ back_pen = pen(m_back_color & color_mask);
- /* handle bizarro scrolling rollover at the 30th (not 32nd) vertical tile */
- if (tmp == 0x03c0)
- m_refresh_data ^= 0x0800;
- else
- m_refresh_data |= (tmp & 0x03e0);
+ if (m_paletteram_in_ppuspace)
+ {
+ /* cache the background pen */
+ if (m_videomem_addr >= 0x3f00)
+ {
+ // If the PPU's VRAM address happens to point into palette ram space while
+ // both the sprites and background are disabled, the PPU paints the scanline
+ // with the palette entry at the VRAM address instead of the usual background
+ // pen. Micro Machines makes use of this feature.
+ int pen_num = m_palette_ram[(m_videomem_addr & 0x03) ? (m_videomem_addr & 0x1f) : 0];
- //logerror("updating refresh_data: %04x\n", m_refresh_data);
- }
+ back_pen = pen(pen_num);
}
}
+ // Fill this scanline with the background pen.
+ for (int i = 0; i < bitmap.width(); i++)
+ bitmap.pix32(m_scanline, i) = back_pen;
+}
+
+void ppu2c0x_device::update_visible_scanline()
+{
+ /* Render this scanline if appropriate */
+ if (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES))
+ {
+ update_visible_enabled_scanline();
+ }
+ else
+ {
+ update_visible_disabled_scanline();
+ }
+
+ if (m_scanline_timer->remaining() == attotime::zero)
+ {
+ scanline_increment_fine_ycounter();
+ }
+}
+
+void ppu2c0x_device::update_scanline()
+{
+ if (m_scanline <= BOTTOM_VISIBLE_SCANLINE)
+ {
+ update_visible_scanline();
+ }
}
/*************************************
@@ -1115,47 +1161,47 @@ uint8_t ppu2c0x_device::read(offs_t offset)
// see which register to read
switch (offset & 7)
{
- case PPU_STATUS: /* 2 */
- // The top 3 bits of the status register are the only ones that report data. The
- // remainder contain whatever was last in the PPU data latch, except on the RC2C05 (protection)
- if (m_security_value)
- m_data_latch = (m_regs[PPU_STATUS] & 0xc0) | m_security_value;
- else
- m_data_latch = m_regs[PPU_STATUS] | (m_data_latch & 0x1f);
-
- // Reset hi/lo scroll toggle
- m_toggle = 0;
-
- // If the vblank bit is set, clear all status bits but the 2 sprite flags
- if (m_data_latch & PPU_STATUS_VBLANK)
- m_regs[PPU_STATUS] &= 0x60;
- break;
+ case PPU_STATUS: /* 2 */
+ // The top 3 bits of the status register are the only ones that report data. The
+ // remainder contain whatever was last in the PPU data latch, except on the RC2C05 (protection)
+ if (m_security_value)
+ m_data_latch = (m_regs[PPU_STATUS] & 0xc0) | m_security_value;
+ else
+ m_data_latch = m_regs[PPU_STATUS] | (m_data_latch & 0x1f);
- case PPU_SPRITE_DATA: /* 4 */
- m_data_latch = m_spriteram[m_regs[PPU_SPRITE_ADDRESS]];
- break;
+ // Reset hi/lo scroll toggle
+ m_toggle = 0;
- case PPU_DATA: /* 7 */
- if (!m_latch.isnull())
- m_latch( m_videomem_addr & 0x3fff);
+ // If the vblank bit is set, clear all status bits but the 2 sprite flags
+ if (m_data_latch & PPU_STATUS_VBLANK)
+ m_regs[PPU_STATUS] &= 0x60;
+ break;
- if (m_videomem_addr >= 0x3f00)
- {
- m_data_latch = readbyte(m_videomem_addr);
- // buffer the mirrored NT data
- m_buffered_data = readbyte(m_videomem_addr & 0x2fff);
- }
- else
- {
- m_data_latch = m_buffered_data;
- m_buffered_data = readbyte(m_videomem_addr);
- }
+ case PPU_SPRITE_DATA: /* 4 */
+ m_data_latch = m_spriteram[m_regs[PPU_SPRITE_ADDRESS]];
+ break;
- m_videomem_addr += m_add;
- break;
+ case PPU_DATA: /* 7 */
+ if (!m_latch.isnull())
+ m_latch(m_videomem_addr & 0x3fff);
- default:
- break;
+ if ((m_videomem_addr >= 0x3f00) && m_paletteram_in_ppuspace)
+ {
+ m_data_latch = readbyte(m_videomem_addr);
+ // buffer the mirrored NT data
+ m_buffered_data = readbyte(m_videomem_addr & 0x2fff);
+ }
+ else
+ {
+ m_data_latch = m_buffered_data;
+ m_buffered_data = readbyte(m_videomem_addr);
+ }
+
+ m_videomem_addr += m_add;
+ break;
+
+ default:
+ break;
}
return m_data_latch;
@@ -1189,135 +1235,136 @@ void ppu2c0x_device::write(offs_t offset, uint8_t data)
switch (offset & 7)
{
- case PPU_CONTROL0: /* 0 */
- m_regs[PPU_CONTROL0] = data;
+ case PPU_CONTROL0: /* 0 */
+ m_regs[PPU_CONTROL0] = data;
- /* update the name table number on our refresh latches */
- m_refresh_latch &= 0x73ff;
- m_refresh_latch |= (data & 3) << 10;
+ /* update the name table number on our refresh latches */
+ m_refresh_latch &= 0x73ff;
+ m_refresh_latch |= (data & 3) << 10;
- /* the char ram bank points either 0x0000 or 0x1000 (page 0 or page 4) */
- m_tile_page = (data & PPU_CONTROL0_CHR_SELECT) >> 2;
- m_sprite_page = (data & PPU_CONTROL0_SPR_SELECT) >> 1;
+ /* the char ram bank points either 0x0000 or 0x1000 (page 0 or page 4) */
+ m_tile_page = (data & PPU_CONTROL0_CHR_SELECT) >> 2;
+ m_sprite_page = (data & PPU_CONTROL0_SPR_SELECT) >> 1;
- m_add = (data & PPU_CONTROL0_INC) ? 32 : 1;
-// logerror("control0 write: %02x (scanline: %d)\n", data, m_scanline);
- break;
+ m_add = (data & PPU_CONTROL0_INC) ? m_line_write_increment_large : 1;
+ //logerror("control0 write: %02x (scanline: %d)\n", data, m_scanline);
+ break;
- case PPU_CONTROL1: /* 1 */
- /* if color intensity has changed, change all the color tables to reflect them */
- if ((data & PPU_CONTROL1_COLOR_EMPHASIS) != (m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS))
+ case PPU_CONTROL1: /* 1 */
+ /* if color intensity has changed, change all the color tables to reflect them */
+ if ((data & PPU_CONTROL1_COLOR_EMPHASIS) != (m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS))
+ {
+ int i;
+ for (i = 0; i <= 0x1f; i++)
{
- int i;
- for (i = 0; i <= 0x1f; i++)
- {
- uint8_t oldColor = m_palette_ram[i];
+ uint8_t oldColor = m_palette_ram[i];
- m_colortable[i] = oldColor + (data & PPU_CONTROL1_COLOR_EMPHASIS) * 2;
- }
+ m_colortable[i] = oldColor + (data & PPU_CONTROL1_COLOR_EMPHASIS) * 2;
}
+ }
-// logerror("control1 write: %02x (scanline: %d)\n", data, m_scanline);
- m_regs[PPU_CONTROL1] = data;
- break;
-
- case PPU_SPRITE_ADDRESS: /* 3 */
- m_regs[PPU_SPRITE_ADDRESS] = data;
- break;
+ //logerror("control1 write: %02x (scanline: %d)\n", data, m_scanline);
+ m_regs[PPU_CONTROL1] = data;
+ break;
- case PPU_SPRITE_DATA: /* 4 */
- // If the PPU is currently rendering the screen, 0xff is written instead of the desired data.
- if (m_use_sprite_write_limitation)
- if (m_scanline <= BOTTOM_VISIBLE_SCANLINE)
- data = 0xff;
- m_spriteram[m_regs[PPU_SPRITE_ADDRESS]] = data;
- m_regs[PPU_SPRITE_ADDRESS] = (m_regs[PPU_SPRITE_ADDRESS] + 1) & 0xff;
- break;
+ case PPU_SPRITE_ADDRESS: /* 3 */
+ m_regs[PPU_SPRITE_ADDRESS] = data;
+ break;
- case PPU_SCROLL: /* 5 */
- if (m_toggle)
- {
- /* second write */
- m_refresh_latch &= 0x0c1f;
- m_refresh_latch |= (data & 0xf8) << 2;
- m_refresh_latch |= (data & 0x07) << 12;
-// logerror("scroll write 2: %d, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
- }
- else
- {
- /* first write */
- m_refresh_latch &= 0x7fe0;
- m_refresh_latch |= (data & 0xf8) >> 3;
+ case PPU_SPRITE_DATA: /* 4 */
+ // If the PPU is currently rendering the screen, 0xff is written instead of the desired data.
+ if (m_use_sprite_write_limitation)
+ if (m_scanline <= BOTTOM_VISIBLE_SCANLINE)
+ data = 0xff;
+ m_spriteram[m_regs[PPU_SPRITE_ADDRESS]] = data;
+ m_regs[PPU_SPRITE_ADDRESS] = (m_regs[PPU_SPRITE_ADDRESS] + 1) & 0xff;
+ break;
- m_x_fine = data & 7;
-// logerror("scroll write 1: %d, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
- }
+ case PPU_SCROLL: /* 5 */
+ if (m_toggle)
+ {
+ /* second write */
+ m_refresh_latch &= 0x0c1f;
+ m_refresh_latch |= (data & 0xf8) << 2;
+ m_refresh_latch |= (data & 0x07) << 12;
+ //logerror("scroll write 2: %d, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
+ }
+ else
+ {
+ /* first write */
+ m_refresh_latch &= 0x7fe0;
+ m_refresh_latch |= (data & 0xf8) >> 3;
- m_toggle ^= 1;
- break;
+ m_x_fine = data & 7;
+ //logerror("scroll write 1: %d, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
+ }
- case PPU_ADDRESS: /* 6 */
- if (m_toggle)
- {
- /* second write */
- m_refresh_latch &= 0x7f00;
- m_refresh_latch |= data;
- m_refresh_data = m_refresh_latch;
+ m_toggle ^= 1;
+ break;
- m_videomem_addr = m_refresh_latch;
-// logerror("vram addr write 2: %02x, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
- }
- else
- {
- /* first write */
- m_refresh_latch &= 0x00ff;
- m_refresh_latch |= (data & 0x3f) << 8;
-// logerror("vram addr write 1: %02x, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
- }
+ case PPU_ADDRESS: /* 6 */
+ if (m_toggle)
+ {
+ /* second write */
+ m_refresh_latch &= 0x7f00;
+ m_refresh_latch |= data;
+ m_refresh_data = m_refresh_latch;
- m_toggle ^= 1;
- break;
+ m_videomem_addr = m_refresh_latch;
+ //logerror("vram addr write 2: %02x, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
+ }
+ else
+ {
+ /* first write */
+ m_refresh_latch &= 0x00ff;
+ m_refresh_latch |= (data & 0x3f) << 8;
+ //logerror("vram addr write 1: %02x, %04x (scanline: %d)\n", data, m_refresh_latch, m_scanline);
+ }
- case PPU_DATA: /* 7 */
- {
- int tempAddr = m_videomem_addr & 0x3fff;
+ m_toggle ^= 1;
+ break;
- if (!m_latch.isnull())
- m_latch(tempAddr);
+ case PPU_DATA: /* 7 */
+ {
+ int tempAddr = m_videomem_addr & 0x3fff;
- /* if there's a callback, call it now */
- if (!m_vidaccess_callback_proc.isnull())
- data = m_vidaccess_callback_proc(tempAddr, data);
+ if (!m_latch.isnull())
+ m_latch(tempAddr);
- /* see if it's on the chargen portion */
- if (tempAddr < 0x2000)
- {
- /* store the data */
- writebyte(tempAddr, data);
- }
+ /* if there's a callback, call it now */
+ if (!m_vidaccess_callback_proc.isnull())
+ data = m_vidaccess_callback_proc(tempAddr, data);
- else
- {
- writebyte(tempAddr, data);
- }
- /* increment the address */
- m_videomem_addr += m_add;
- }
- break;
+ /* see if it's on the chargen portion */
+ if (tempAddr < 0x2000)
+ {
+ /* store the data */
+ writebyte(tempAddr, data);
+ }
+ else // this codepath is identical?
+ {
+ writebyte(tempAddr, data);
+ }
+ /* increment the address */
+ m_videomem_addr += m_add;
+ }
+ break;
- default:
- /* ignore other registers writes */
- break;
+ default:
+ /* ignore other registers writes */
+ break;
}
m_data_latch = data;
}
-uint16_t ppu2c0x_device::get_vram_dest() {
+uint16_t ppu2c0x_device::get_vram_dest()
+{
return m_videomem_addr;
}
-void ppu2c0x_device::set_vram_dest(uint16_t dest) {
+void ppu2c0x_device::set_vram_dest(uint16_t dest)
+{
m_videomem_addr = dest;
}
@@ -1327,7 +1374,7 @@ void ppu2c0x_device::set_vram_dest(uint16_t dest) {
*
*************************************/
-void ppu2c0x_device::spriteram_dma( address_space &space, const uint8_t page )
+void ppu2c0x_device::spriteram_dma(address_space& space, const uint8_t page)
{
int i;
int address = page << 8;
@@ -1348,7 +1395,7 @@ void ppu2c0x_device::spriteram_dma( address_space &space, const uint8_t page )
*
*************************************/
-void ppu2c0x_device::render(bitmap_rgb32 &bitmap, int flipx, int flipy, int sx, int sy, const rectangle &cliprect)
+void ppu2c0x_device::render(bitmap_rgb32& bitmap, int flipx, int flipy, int sx, int sy, const rectangle& cliprect)
{
if (m_scanline_timer->remaining() != attotime::zero)
{
@@ -1358,7 +1405,7 @@ void ppu2c0x_device::render(bitmap_rgb32 &bitmap, int flipx, int flipy, int sx,
copybitmap(bitmap, *m_bitmap, flipx, flipy, sx, sy, cliprect);
}
-uint32_t ppu2c0x_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+uint32_t ppu2c0x_device::screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect)
{
render(bitmap, 0, 0, 0, 0, cliprect);
return 0;