mirror of
https://github.com/holub/mame
synced 2025-06-27 22:54:42 +03:00
(MESS) nes_mmc5: * hacked around the limitations of our PPU code, so to support the
different CHR registers * improved PRG-RAM handling * first attempt to add split screen mode, still broken no whatsnew the hack only deals with the way MMC-5 monitors PPU activity, not with the actual effect. when I get to the point of completing my not-yet-abandoned PPU rewrite, the new calls in ppu2c0x.h will go away...
This commit is contained in:
parent
c747802a77
commit
7cecc33fe7
@ -142,7 +142,9 @@ ppu2c0x_device::ppu2c0x_device(const machine_config &mconfig, device_type type,
|
|||||||
m_tile_page(0),
|
m_tile_page(0),
|
||||||
m_sprite_page(0),
|
m_sprite_page(0),
|
||||||
m_back_color(0),
|
m_back_color(0),
|
||||||
m_scan_scale(1) // set the scan scale (this is for dual monitor vertical setups)
|
m_scan_scale(1), // set the scan scale (this is for dual monitor vertical setups)
|
||||||
|
m_tilecount(0),
|
||||||
|
m_draw_phase(0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < PPU_MAX_REG; i++)
|
for (int i = 0; i < PPU_MAX_REG; i++)
|
||||||
m_regs[i] = 0;
|
m_regs[i] = 0;
|
||||||
@ -258,6 +260,8 @@ void ppu2c0x_device::device_start()
|
|||||||
save_item(NAME(m_scanlines_per_frame));
|
save_item(NAME(m_scanlines_per_frame));
|
||||||
save_item(NAME(m_regs));
|
save_item(NAME(m_regs));
|
||||||
save_item(NAME(m_palette_ram));
|
save_item(NAME(m_palette_ram));
|
||||||
|
save_item(NAME(m_draw_phase));
|
||||||
|
save_item(NAME(m_tilecount));
|
||||||
save_pointer(NAME(m_spriteram), SPRITERAM_SIZE);
|
save_pointer(NAME(m_spriteram), SPRITERAM_SIZE);
|
||||||
save_pointer(NAME(m_colortable), ARRAY_LENGTH(default_colortable));
|
save_pointer(NAME(m_colortable), ARRAY_LENGTH(default_colortable));
|
||||||
save_pointer(NAME(m_colortable_mono), ARRAY_LENGTH(default_colortable_mono));
|
save_pointer(NAME(m_colortable_mono), ARRAY_LENGTH(default_colortable_mono));
|
||||||
@ -565,7 +569,7 @@ void ppu2c0x_device::draw_background( UINT8 *line_priority )
|
|||||||
const pen_t *color_table;
|
const pen_t *color_table;
|
||||||
const pen_t *paldata;
|
const pen_t *paldata;
|
||||||
|
|
||||||
int tilecount = 0;
|
m_tilecount = 0;
|
||||||
|
|
||||||
/* setup the color mask and colortable to use */
|
/* setup the color mask and colortable to use */
|
||||||
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
|
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
|
||||||
@ -597,7 +601,7 @@ void ppu2c0x_device::draw_background( UINT8 *line_priority )
|
|||||||
dest = &bitmap.pix16(m_scanline, start_x);
|
dest = &bitmap.pix16(m_scanline, start_x);
|
||||||
|
|
||||||
/* draw the 32 or 33 tiles that make up a line */
|
/* draw the 32 or 33 tiles that make up a line */
|
||||||
while (tilecount < 34)
|
while (m_tilecount < 34)
|
||||||
{
|
{
|
||||||
int color_byte;
|
int color_byte;
|
||||||
int color_bits;
|
int color_bits;
|
||||||
@ -672,7 +676,7 @@ void ppu2c0x_device::draw_background( UINT8 *line_priority )
|
|||||||
tile_index ^= 0x400;
|
tile_index ^= 0x400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tilecount++;
|
m_tilecount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the left 8 pixels for the background are off, blank 'em */
|
/* if the left 8 pixels for the background are off, blank 'em */
|
||||||
@ -897,6 +901,8 @@ void ppu2c0x_device::render_scanline( void )
|
|||||||
/* clear the line priority for this scanline */
|
/* clear the line priority for this scanline */
|
||||||
memset(line_priority, 0, VISIBLE_SCREEN_WIDTH);
|
memset(line_priority, 0, VISIBLE_SCREEN_WIDTH);
|
||||||
|
|
||||||
|
m_draw_phase = PPU_DRAW_BG;
|
||||||
|
|
||||||
/* see if we need to render the background */
|
/* see if we need to render the background */
|
||||||
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND)
|
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND)
|
||||||
draw_background(line_priority);
|
draw_background(line_priority);
|
||||||
@ -921,9 +927,13 @@ void ppu2c0x_device::render_scanline( void )
|
|||||||
bitmap.pix16(m_scanline, i) = back_pen;
|
bitmap.pix16(m_scanline, i) = back_pen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_draw_phase = PPU_DRAW_OAM;
|
||||||
|
|
||||||
/* if sprites are on, draw them, but we call always to process them */
|
/* if sprites are on, draw them, but we call always to process them */
|
||||||
draw_sprites(line_priority);
|
draw_sprites(line_priority);
|
||||||
|
|
||||||
|
m_draw_phase = PPU_DRAW_BG;
|
||||||
|
|
||||||
/* done updating, whew */
|
/* done updating, whew */
|
||||||
g_profiler.stop();
|
g_profiler.stop();
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
#define PPU_MIRROR_LOW 4
|
#define PPU_MIRROR_LOW 4
|
||||||
#define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror
|
#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
|
// registers definition
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -166,13 +170,17 @@ public:
|
|||||||
|
|
||||||
int get_colorbase() { return m_color_base; };
|
int get_colorbase() { return m_color_base; };
|
||||||
int get_current_scanline() { return m_scanline; };
|
int get_current_scanline() { return m_scanline; };
|
||||||
int is_sprite_8x16() { return BIT(m_regs[0], 5); }; // MMC5 has to be able to check this
|
|
||||||
void set_scanline_callback( ppu2c0x_scanline_delegate cb ) { m_scanline_callback_proc = cb; m_scanline_callback_proc.bind_relative_to(*owner()); };
|
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_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_vidaccess_callback( ppu2c0x_vidaccess_delegate cb ) { m_vidaccess_callback_proc = cb; m_vidaccess_callback_proc.bind_relative_to(*owner()); };
|
||||||
static void set_nmi_delegate(device_t &device,ppu2c0x_nmi_delegate cb);
|
static void set_nmi_delegate(device_t &device,ppu2c0x_nmi_delegate cb);
|
||||||
void set_scanlines_per_frame( int scanlines ) { m_scanlines_per_frame = scanlines; };
|
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!)
|
//27/12/2002 (HACK!)
|
||||||
void set_latch( ppu2c0x_latch_delegate cb ) { m_latch = cb; m_latch.bind_relative_to(*owner()); };
|
void set_latch( ppu2c0x_latch_delegate cb ) { m_latch = cb; m_latch.bind_relative_to(*owner()); };
|
||||||
|
|
||||||
@ -205,6 +213,8 @@ public:
|
|||||||
int m_scan_scale; /* scan scale */
|
int m_scan_scale; /* scan scale */
|
||||||
int m_scanlines_per_frame; /* number of scanlines per frame */
|
int m_scanlines_per_frame; /* number of scanlines per frame */
|
||||||
int m_security_value; /* 2C05 protection */
|
int m_security_value; /* 2C05 protection */
|
||||||
|
int m_tilecount; /* MMC5 can change attributes to subsets of the 34 visibile tiles */
|
||||||
|
int m_draw_phase; /* MMC5 uses different regs for BG and OAM */
|
||||||
ppu2c0x_latch_delegate m_latch;
|
ppu2c0x_latch_delegate m_latch;
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
|
@ -68,15 +68,20 @@ void nes_exrom_device::device_start()
|
|||||||
save_item(NAME(m_wram_base));
|
save_item(NAME(m_wram_base));
|
||||||
save_item(NAME(m_wram_protect_1));
|
save_item(NAME(m_wram_protect_1));
|
||||||
save_item(NAME(m_wram_protect_2));
|
save_item(NAME(m_wram_protect_2));
|
||||||
save_item(NAME(m_mmc5_last_chr_a)); // basically unused in current code
|
save_item(NAME(m_vrom_bank));
|
||||||
|
save_item(NAME(m_last_chr));
|
||||||
|
save_item(NAME(m_ex1_chr));
|
||||||
|
save_item(NAME(m_split_chr));
|
||||||
|
save_item(NAME(m_prg_regs));
|
||||||
|
save_item(NAME(m_prg_ram_mapped));
|
||||||
|
save_item(NAME(m_ex1_bank));
|
||||||
save_item(NAME(m_high_chr));
|
save_item(NAME(m_high_chr));
|
||||||
save_item(NAME(m_split_scr));
|
save_item(NAME(m_split_scr));
|
||||||
|
save_item(NAME(m_split_rev));
|
||||||
save_item(NAME(m_split_ctrl));
|
save_item(NAME(m_split_ctrl));
|
||||||
save_item(NAME(m_split_yst));
|
save_item(NAME(m_split_yst));
|
||||||
save_item(NAME(m_split_bank));
|
save_item(NAME(m_split_bank));
|
||||||
save_item(NAME(m_prg_regs));
|
save_item(NAME(m_vcount));
|
||||||
save_item(NAME(m_vrom_bank));
|
|
||||||
save_item(NAME(m_last_chr));
|
|
||||||
|
|
||||||
m_exram = auto_alloc_array_clear(machine(), UINT8, 0x400);
|
m_exram = auto_alloc_array_clear(machine(), UINT8, 0x400);
|
||||||
save_pointer(NAME(m_exram), 0x400);
|
save_pointer(NAME(m_exram), 0x400);
|
||||||
@ -103,19 +108,27 @@ void nes_exrom_device::pcb_reset()
|
|||||||
m_wram_base = 0;
|
m_wram_base = 0;
|
||||||
m_wram_protect_1 = 0;
|
m_wram_protect_1 = 0;
|
||||||
m_wram_protect_2 = 0;
|
m_wram_protect_2 = 0;
|
||||||
m_mmc5_last_chr_a = 1;
|
|
||||||
m_high_chr = 0;
|
m_high_chr = 0;
|
||||||
m_split_scr = 0;
|
m_split_scr = 0;
|
||||||
|
m_split_rev = 0;
|
||||||
m_split_ctrl = 0;
|
m_split_ctrl = 0;
|
||||||
m_split_yst = 0;
|
m_split_yst = 0;
|
||||||
m_split_bank = 0;
|
m_split_bank = 0;
|
||||||
m_last_chr = LAST_CHR_REG_A;
|
m_last_chr = LAST_CHR_REG_A;
|
||||||
|
m_ex1_chr = 0;
|
||||||
|
m_split_chr = 0;
|
||||||
|
m_ex1_bank = 0;
|
||||||
|
m_vcount = 0;
|
||||||
|
|
||||||
memset(m_vrom_bank, 0x3ff, ARRAY_LENGTH(m_vrom_bank));
|
memset(m_vrom_bank, 0x3ff, ARRAY_LENGTH(m_vrom_bank));
|
||||||
m_prg_regs[0] = 0xfc;
|
m_prg_regs[0] = 0xfc;
|
||||||
m_prg_regs[1] = 0xfd;
|
m_prg_regs[1] = 0xfd;
|
||||||
m_prg_regs[2] = 0xfe;
|
m_prg_regs[2] = 0xfe;
|
||||||
m_prg_regs[3] = 0xff;
|
m_prg_regs[3] = 0xff;
|
||||||
|
m_prg_ram_mapped[0] = 0;
|
||||||
|
m_prg_ram_mapped[1] = 0;
|
||||||
|
m_prg_ram_mapped[2] = 0;
|
||||||
|
m_prg_ram_mapped[3] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,8 +153,13 @@ void nes_exrom_device::prgram_bank8_x(int start, int bank)
|
|||||||
{
|
{
|
||||||
assert(start < 4);
|
assert(start < 4);
|
||||||
assert(bank >= 0);
|
assert(bank >= 0);
|
||||||
|
assert(m_prgram_size + m_battery_size);
|
||||||
|
|
||||||
bank &= (m_prgram_size / 0x2000) - 1;
|
// currently we use 4x8k BWRAM + 4x8k WRAM banks, independently from the actual PRG-RAM size
|
||||||
|
// mirroring of the actual size is taken care of at bank setup (even if no known commercial game relies on it!)
|
||||||
|
//bank &= (m_prgram_size / 0x2000) - 1;
|
||||||
|
if (!m_prgram_size || !m_battery_size)
|
||||||
|
bank &= 3;
|
||||||
|
|
||||||
// PRG RAM is mapped after PRG ROM
|
// PRG RAM is mapped after PRG ROM
|
||||||
m_prg_bank[start] = m_prg_chunks + bank;
|
m_prg_bank[start] = m_prg_chunks + bank;
|
||||||
@ -156,15 +174,15 @@ void nes_exrom_device::update_prg()
|
|||||||
switch (m_prg_mode)
|
switch (m_prg_mode)
|
||||||
{
|
{
|
||||||
case 0: // 32k banks
|
case 0: // 32k banks
|
||||||
bank3 = (m_prg_regs[3] & 0x7f) >> 2;
|
bank3 = m_prg_regs[3] >> 2;
|
||||||
prg32(bank3);
|
prg32(bank3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // 16k banks
|
case 1: // 16k banks
|
||||||
bank1 = (m_prg_regs[1] & 0x7f) >> 1;
|
bank1 = m_prg_regs[1] >> 1;
|
||||||
bank3 = (m_prg_regs[3] & 0x7f) >> 1;
|
bank3 = m_prg_regs[3] >> 1;
|
||||||
|
|
||||||
if (!BIT(m_prg_regs[1], 7)) // PRG RAM
|
if (m_prg_ram_mapped[1])
|
||||||
{
|
{
|
||||||
prgram_bank8_x(0, ((bank1 << 1) & 0x07));
|
prgram_bank8_x(0, ((bank1 << 1) & 0x07));
|
||||||
prgram_bank8_x(1, ((bank1 << 1) & 0x07) | 1);
|
prgram_bank8_x(1, ((bank1 << 1) & 0x07) | 1);
|
||||||
@ -176,11 +194,11 @@ void nes_exrom_device::update_prg()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // 16k-8k banks
|
case 2: // 16k-8k banks
|
||||||
bank1 = (m_prg_regs[1] & 0x7f) >> 1;
|
bank1 = m_prg_regs[1] >> 1;
|
||||||
bank2 = (m_prg_regs[2] & 0x7f);
|
bank2 = m_prg_regs[2];
|
||||||
bank3 = (m_prg_regs[3] & 0x7f);
|
bank3 = m_prg_regs[3];
|
||||||
|
|
||||||
if (!BIT(m_prg_regs[1], 7))
|
if (m_prg_ram_mapped[1])
|
||||||
{
|
{
|
||||||
prgram_bank8_x(0, ((bank1 << 1) & 0x07));
|
prgram_bank8_x(0, ((bank1 << 1) & 0x07));
|
||||||
prgram_bank8_x(1, ((bank1 << 1) & 0x07) | 1);
|
prgram_bank8_x(1, ((bank1 << 1) & 0x07) | 1);
|
||||||
@ -188,7 +206,7 @@ void nes_exrom_device::update_prg()
|
|||||||
else
|
else
|
||||||
prg16_89ab(bank1);
|
prg16_89ab(bank1);
|
||||||
|
|
||||||
if (!BIT(m_prg_regs[2], 7))
|
if (m_prg_ram_mapped[2])
|
||||||
prgram_bank8_x(2, bank2 & 0x07);
|
prgram_bank8_x(2, bank2 & 0x07);
|
||||||
else
|
else
|
||||||
prg8_cd(bank2);
|
prg8_cd(bank2);
|
||||||
@ -197,22 +215,22 @@ void nes_exrom_device::update_prg()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // 8k banks
|
case 3: // 8k banks
|
||||||
bank0 = (m_prg_regs[0] & 0x7f);
|
bank0 = m_prg_regs[0];
|
||||||
bank1 = (m_prg_regs[1] & 0x7f);
|
bank1 = m_prg_regs[1];
|
||||||
bank2 = (m_prg_regs[2] & 0x7f);
|
bank2 = m_prg_regs[2];
|
||||||
bank3 = (m_prg_regs[3] & 0x7f);
|
bank3 = m_prg_regs[3];
|
||||||
|
|
||||||
if (!BIT(m_prg_regs[0], 7))
|
if (m_prg_ram_mapped[0])
|
||||||
prgram_bank8_x(0, bank0 & 0x07);
|
prgram_bank8_x(0, bank0 & 0x07);
|
||||||
else
|
else
|
||||||
prg8_89(bank0);
|
prg8_89(bank0);
|
||||||
|
|
||||||
if (!BIT(m_prg_regs[1], 7))
|
if (m_prg_ram_mapped[1])
|
||||||
prgram_bank8_x(1, bank1 & 0x07);
|
prgram_bank8_x(1, bank1 & 0x07);
|
||||||
else
|
else
|
||||||
prg8_ab(bank1);
|
prg8_ab(bank1);
|
||||||
|
|
||||||
if (!BIT(m_prg_regs[2], 7))
|
if (m_prg_ram_mapped[2])
|
||||||
prgram_bank8_x(2, bank2 & 0x07);
|
prgram_bank8_x(2, bank2 & 0x07);
|
||||||
else
|
else
|
||||||
prg8_cd(bank2);
|
prg8_cd(bank2);
|
||||||
@ -222,81 +240,10 @@ void nes_exrom_device::update_prg()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nes_exrom_device::update_chr()
|
|
||||||
{
|
|
||||||
// for the moment ignore the case of sprite_8x16 [need to be hooked up to PPU properly!]
|
|
||||||
switch (m_chr_mode)
|
|
||||||
{
|
|
||||||
case 0: // 8k pages
|
|
||||||
if (m_last_chr == LAST_CHR_REG_A)
|
|
||||||
{
|
|
||||||
chr8(m_vrom_bank[7] & 0xff, CHRROM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chr8((m_vrom_bank[11] & 0xff) << 1, CHRROM);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: // 4k pages
|
|
||||||
if (m_last_chr == LAST_CHR_REG_A)
|
|
||||||
{
|
|
||||||
chr4_0(m_vrom_bank[3] & 0xff, CHRROM);
|
|
||||||
chr4_4(m_vrom_bank[7] & 0xff, CHRROM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chr4_0(m_vrom_bank[11] & 0xff, CHRROM);
|
|
||||||
chr4_4(m_vrom_bank[11] & 0xff, CHRROM);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // 2k pages
|
|
||||||
if (m_last_chr == LAST_CHR_REG_A)
|
|
||||||
{
|
|
||||||
chr2_0(m_vrom_bank[1], CHRROM);
|
|
||||||
chr2_2(m_vrom_bank[3], CHRROM);
|
|
||||||
chr2_4(m_vrom_bank[5], CHRROM);
|
|
||||||
chr2_6(m_vrom_bank[7], CHRROM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chr2_0(m_vrom_bank[ 9], CHRROM);
|
|
||||||
chr2_2(m_vrom_bank[11], CHRROM);
|
|
||||||
chr2_4(m_vrom_bank[ 9], CHRROM);
|
|
||||||
chr2_6(m_vrom_bank[11], CHRROM);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: // 1k pages
|
|
||||||
if (m_last_chr == LAST_CHR_REG_A)
|
|
||||||
{
|
|
||||||
chr1_0(m_vrom_bank[0], CHRROM);
|
|
||||||
chr1_1(m_vrom_bank[1], CHRROM);
|
|
||||||
chr1_2(m_vrom_bank[2], CHRROM);
|
|
||||||
chr1_3(m_vrom_bank[3], CHRROM);
|
|
||||||
chr1_4(m_vrom_bank[4], CHRROM);
|
|
||||||
chr1_5(m_vrom_bank[5], CHRROM);
|
|
||||||
chr1_6(m_vrom_bank[6], CHRROM);
|
|
||||||
chr1_7(m_vrom_bank[7], CHRROM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// chr1_0(m_vrom_bank[ 8], CHRROM);
|
|
||||||
// chr1_1(m_vrom_bank[ 9], CHRROM);
|
|
||||||
// chr1_2(m_vrom_bank[10], CHRROM);
|
|
||||||
// chr1_3(m_vrom_bank[11], CHRROM);
|
|
||||||
chr1_4(m_vrom_bank[ 8], CHRROM);
|
|
||||||
chr1_5(m_vrom_bank[ 9], CHRROM);
|
|
||||||
chr1_6(m_vrom_bank[10], CHRROM);
|
|
||||||
chr1_7(m_vrom_bank[11], CHRROM);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked )
|
void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked )
|
||||||
{
|
{
|
||||||
|
m_vcount = scanline;
|
||||||
|
|
||||||
if (scanline == m_irq_count)
|
if (scanline == m_irq_count)
|
||||||
{
|
{
|
||||||
if (m_irq_enable)
|
if (m_irq_enable)
|
||||||
@ -310,14 +257,6 @@ void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked )
|
|||||||
m_irq_status |= 0x40;
|
m_irq_status |= 0x40;
|
||||||
else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE)
|
else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE)
|
||||||
m_irq_status &= ~0x40;
|
m_irq_status &= ~0x40;
|
||||||
|
|
||||||
/* FIXME: this is ok, but then we would need to update them again when we have the BG Hblank
|
|
||||||
I leave it commented out until the PPU is updated for this */
|
|
||||||
// ppu2c0x_device *m_ppu = machine().device<ppu2c0x_device>("ppu");
|
|
||||||
// if (m_ppu->is_sprite_8x16() || m_mmc5_last_chr_a)
|
|
||||||
// update_chr_a();
|
|
||||||
// else
|
|
||||||
// update_chr_b();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -343,6 +282,20 @@ void nes_exrom_device::set_mirror(int page, int src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool nes_exrom_device::in_split()
|
||||||
|
{
|
||||||
|
ppu2c0x_device *ppu = machine().device<ppu2c0x_device>("ppu");
|
||||||
|
int tile = ppu->get_tilenum();
|
||||||
|
|
||||||
|
if (tile < 34)
|
||||||
|
{
|
||||||
|
if (!m_split_rev && tile < m_split_ctrl)
|
||||||
|
return TRUE;
|
||||||
|
if (m_split_rev && tile >= m_split_ctrl)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
READ8_MEMBER(nes_exrom_device::nt_r)
|
READ8_MEMBER(nes_exrom_device::nt_r)
|
||||||
{
|
{
|
||||||
@ -356,6 +309,7 @@ READ8_MEMBER(nes_exrom_device::nt_r)
|
|||||||
return m_floodtile;
|
return m_floodtile;
|
||||||
|
|
||||||
case EXRAM:
|
case EXRAM:
|
||||||
|
// to investigate: can split screen affect this too?
|
||||||
if (!BIT(m_exram_control, 1))
|
if (!BIT(m_exram_control, 1))
|
||||||
return m_exram[offset & 0x3ff];
|
return m_exram[offset & 0x3ff];
|
||||||
else
|
else
|
||||||
@ -363,16 +317,33 @@ READ8_MEMBER(nes_exrom_device::nt_r)
|
|||||||
|
|
||||||
case CIRAM:
|
case CIRAM:
|
||||||
default:
|
default:
|
||||||
|
// Uchuu Keibitai SDF uses extensively split screen for its intro,
|
||||||
|
// but it does not work yet
|
||||||
|
if (m_split_scr && !(m_exram_control & 0x02) && in_split())
|
||||||
|
{
|
||||||
|
ppu2c0x_device *ppu = machine().device<ppu2c0x_device>("ppu");
|
||||||
|
int tile = ppu->get_tilenum();
|
||||||
|
|
||||||
|
if ((offset & 0x3ff) >= 0x3c0)
|
||||||
|
{
|
||||||
|
int pos = (((m_split_yst + m_vcount) & ~0x1f) | (tile & 0x1f)) >> 2;
|
||||||
|
return m_exram[0x3c0 | pos];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pos = (((m_split_yst + m_vcount) & 0xf8) << 2) | (tile & 0x1f);
|
||||||
|
return m_exram[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_exram_control == 1)
|
if (m_exram_control == 1)
|
||||||
{
|
{
|
||||||
if ((offset & 0x3ff) >= 0x3c0)
|
if ((offset & 0x3ff) >= 0x3c0)
|
||||||
return m_mmc5_attrib[(m_exram[offset & 0x3ff] >> 6) & 0x03];
|
return m_mmc5_attrib[(m_exram[offset & 0x3ff] >> 6) & 0x03];
|
||||||
else
|
else // in this case, we write Ex1 CHR bank, but then access NT normally!
|
||||||
{
|
{
|
||||||
// in this case, we swap CHR bank, but then access NT normally!
|
m_ex1_chr = 1;
|
||||||
int bank = (m_exram[offset & 0x3ff] & 0x3f) | (m_high_chr << 6);
|
m_ex1_bank = (m_exram[offset & 0x3ff] & 0x3f) | (m_high_chr << 6);
|
||||||
chr4_0(bank, CHRROM);
|
|
||||||
chr4_4(bank, CHRROM);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_nt_access[page][offset & 0x3ff];
|
return m_nt_access[page][offset & 0x3ff];
|
||||||
@ -399,6 +370,72 @@ WRITE8_MEMBER(nes_exrom_device::nt_w)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline UINT8 nes_exrom_device::base_chr_r(int bank, UINT32 offset)
|
||||||
|
{
|
||||||
|
UINT32 helper = 0;
|
||||||
|
|
||||||
|
switch (m_chr_mode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (bank < 8)
|
||||||
|
helper = ((m_vrom_bank[bank | 7] & 0xff) * 0x2000) + (offset & 0x1fff);
|
||||||
|
else
|
||||||
|
helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x2000) + (offset & 0xfff);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x1000) + (offset & 0xfff);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
helper = (m_vrom_bank[bank | 1] * 0x800) + (offset & 0x7ff);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
helper = (m_vrom_bank[bank] * 0x400) + (offset & 0x3ff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_vrom[helper];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UINT8 nes_exrom_device::split_chr_r(UINT32 offset)
|
||||||
|
{
|
||||||
|
UINT32 helper = (m_split_bank * 0x1000) + (offset & 0x3f8) + (m_split_yst & 7);
|
||||||
|
return m_vrom[helper];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UINT8 nes_exrom_device::bg_ex1_chr_r(UINT32 offset)
|
||||||
|
{
|
||||||
|
UINT32 helper = (m_ex1_bank * 0x1000) + (offset & 0xfff);
|
||||||
|
return m_vrom[helper];
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8_MEMBER(nes_exrom_device::chr_r)
|
||||||
|
{
|
||||||
|
int bank = offset >> 10;
|
||||||
|
ppu2c0x_device *ppu = machine().device<ppu2c0x_device>("ppu");
|
||||||
|
|
||||||
|
// Extended Attribute Mode (Ex1) does affect BG drawing even for 8x16 sprites (JustBreed uses it extensively!)
|
||||||
|
// However, if a game enables Ex1 but does not write a new m_ex1_bank, I'm not sure here we get the correct behavior
|
||||||
|
if (m_exram_control == 1 && ppu->get_draw_phase() == PPU_DRAW_BG && m_ex1_chr)
|
||||||
|
return bg_ex1_chr_r(offset & 0xfff);
|
||||||
|
|
||||||
|
if (m_split_scr && !(m_exram_control & 0x02) && in_split() && ppu->get_draw_phase() == PPU_DRAW_BG && m_split_chr)
|
||||||
|
return split_chr_r(offset & 0xfff);
|
||||||
|
|
||||||
|
if (ppu->is_sprite_8x16())
|
||||||
|
{
|
||||||
|
if (ppu->get_draw_phase() == PPU_DRAW_OAM)
|
||||||
|
return base_chr_r(bank & 7, offset & 0x1fff);
|
||||||
|
|
||||||
|
if (ppu->get_draw_phase() == PPU_DRAW_BG)
|
||||||
|
return base_chr_r((bank & 3) + 8, offset & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_last_chr == LAST_CHR_REG_A)
|
||||||
|
return base_chr_r(bank & 7, offset & 0x1fff);
|
||||||
|
else
|
||||||
|
return base_chr_r((bank & 3) + 8, offset & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
READ8_MEMBER(nes_exrom_device::read_l)
|
READ8_MEMBER(nes_exrom_device::read_l)
|
||||||
{
|
{
|
||||||
@ -430,7 +467,7 @@ READ8_MEMBER(nes_exrom_device::read_l)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
logerror("MMC5 uncaught read, offset: %04x\n", offset + 0x4100);
|
logerror("MMC5 uncaught read, offset: %04x\n", offset + 0x4100);
|
||||||
return 0x00;
|
return m_open_bus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,7 +511,8 @@ WRITE8_MEMBER(nes_exrom_device::write_l)
|
|||||||
|
|
||||||
case 0x1101:
|
case 0x1101:
|
||||||
m_chr_mode = data & 0x03;
|
m_chr_mode = data & 0x03;
|
||||||
update_chr();
|
m_ex1_chr = 0;
|
||||||
|
m_split_chr = 0;
|
||||||
//LOG_MMC(("MMC5 vrom bank mode: %02x\n", data));
|
//LOG_MMC(("MMC5 vrom bank mode: %02x\n", data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -517,7 +555,8 @@ WRITE8_MEMBER(nes_exrom_device::write_l)
|
|||||||
case 0x1115:
|
case 0x1115:
|
||||||
case 0x1116:
|
case 0x1116:
|
||||||
case 0x1117:
|
case 0x1117:
|
||||||
m_prg_regs[offset & 3] = data;
|
m_prg_regs[offset & 3] = data & 0x7f;
|
||||||
|
m_prg_ram_mapped[offset & 3] = !BIT(data, 7); // m_prg_ram_mapped[3] is not used, in fact!
|
||||||
update_prg();
|
update_prg();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -531,7 +570,8 @@ WRITE8_MEMBER(nes_exrom_device::write_l)
|
|||||||
case 0x1127:
|
case 0x1127:
|
||||||
m_vrom_bank[offset & 0x07] = data | (m_high_chr << 8);
|
m_vrom_bank[offset & 0x07] = data | (m_high_chr << 8);
|
||||||
m_last_chr = LAST_CHR_REG_A;
|
m_last_chr = LAST_CHR_REG_A;
|
||||||
update_chr();
|
m_ex1_chr = 0;
|
||||||
|
m_split_chr = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1128:
|
case 0x1128:
|
||||||
@ -540,20 +580,22 @@ WRITE8_MEMBER(nes_exrom_device::write_l)
|
|||||||
case 0x112b:
|
case 0x112b:
|
||||||
m_vrom_bank[offset & 0x0f] = data | (m_high_chr << 8);
|
m_vrom_bank[offset & 0x0f] = data | (m_high_chr << 8);
|
||||||
m_last_chr = LAST_CHR_REG_B;
|
m_last_chr = LAST_CHR_REG_B;
|
||||||
update_chr();
|
m_ex1_chr = 0;
|
||||||
|
m_split_chr = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1130:
|
case 0x1130:
|
||||||
m_high_chr = data & 0x03;
|
m_high_chr = data & 0x03;
|
||||||
|
m_ex1_chr = 0;
|
||||||
|
m_split_chr = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 0x1200:
|
case 0x1200:
|
||||||
m_split_scr = data;
|
|
||||||
// in EX2 and EX3 modes, no split screen
|
// in EX2 and EX3 modes, no split screen
|
||||||
if (m_exram_control & 0x02)
|
m_split_scr = BIT(data, 7);
|
||||||
m_split_scr &= 0x7f;
|
m_split_rev = BIT(data, 6);
|
||||||
m_split_ctrl = data;
|
m_split_ctrl = data & 0x1f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1201:
|
case 0x1201:
|
||||||
@ -562,6 +604,7 @@ WRITE8_MEMBER(nes_exrom_device::write_l)
|
|||||||
|
|
||||||
case 0x1202:
|
case 0x1202:
|
||||||
m_split_bank = data;
|
m_split_bank = data;
|
||||||
|
m_split_chr = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1203:
|
case 0x1203:
|
||||||
@ -580,7 +623,7 @@ WRITE8_MEMBER(nes_exrom_device::write_l)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logerror("** MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data);
|
logerror("MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -604,7 +647,7 @@ READ8_MEMBER(nes_exrom_device::read_m)
|
|||||||
else if (m_battery) // 1 chip, BWRAM
|
else if (m_battery) // 1 chip, BWRAM
|
||||||
return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery_size - 1)];
|
return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery_size - 1)];
|
||||||
else
|
else
|
||||||
return ((offset + 0x6000) & 0xff00) >> 8;
|
return m_open_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE8_MEMBER(nes_exrom_device::write_m)
|
WRITE8_MEMBER(nes_exrom_device::write_m)
|
||||||
@ -612,8 +655,23 @@ WRITE8_MEMBER(nes_exrom_device::write_m)
|
|||||||
if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01)
|
if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_battery)
|
if (m_battery && m_wram_base < 4)
|
||||||
m_battery[offset & (m_battery_size - 1)] = data;
|
m_battery[(offset + m_wram_base * 0x2000) & (m_battery_size - 1)] = data;
|
||||||
if (m_prgram)
|
else if (m_prgram)
|
||||||
m_prgram[offset & (m_prgram_size - 1)] = data;
|
m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram_size - 1)] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some games (e.g. Bandit Kings of Ancient China) write to PRG-RAM through 0x8000-0xdfff
|
||||||
|
// it does not work well yet!
|
||||||
|
WRITE8_MEMBER(nes_exrom_device::write_h)
|
||||||
|
{
|
||||||
|
int bank = offset / 0x2000;
|
||||||
|
if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01 || bank == 3 || !m_prg_ram_mapped[bank])
|
||||||
|
return;
|
||||||
|
|
||||||
|
bank = m_prg_bank[bank] - m_prg_chunks;
|
||||||
|
if (m_battery && m_prg_bank[bank] < m_prg_chunks + 4)
|
||||||
|
m_battery[((bank * 0x2000) + (offset & 0x1fff)) & (m_battery_size - 1)] = data;
|
||||||
|
else if (m_prgram)
|
||||||
|
m_prgram[(((bank & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram_size - 1)] = data;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@ public:
|
|||||||
virtual DECLARE_READ8_MEMBER(read_m);
|
virtual DECLARE_READ8_MEMBER(read_m);
|
||||||
virtual DECLARE_WRITE8_MEMBER(write_l);
|
virtual DECLARE_WRITE8_MEMBER(write_l);
|
||||||
virtual DECLARE_WRITE8_MEMBER(write_m);
|
virtual DECLARE_WRITE8_MEMBER(write_m);
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(write_h);
|
||||||
|
|
||||||
|
virtual DECLARE_READ8_MEMBER(chr_r);
|
||||||
virtual DECLARE_READ8_MEMBER(nt_r);
|
virtual DECLARE_READ8_MEMBER(nt_r);
|
||||||
virtual DECLARE_WRITE8_MEMBER(nt_w);
|
virtual DECLARE_WRITE8_MEMBER(nt_w);
|
||||||
|
|
||||||
@ -29,7 +32,11 @@ protected:
|
|||||||
void prgram_bank8_x(int start, int bank);
|
void prgram_bank8_x(int start, int bank);
|
||||||
void update_render_mode();
|
void update_render_mode();
|
||||||
void update_prg();
|
void update_prg();
|
||||||
void update_chr();
|
|
||||||
|
inline UINT8 base_chr_r(int bank, UINT32 offset);
|
||||||
|
inline UINT8 split_chr_r(UINT32 offset);
|
||||||
|
inline UINT8 bg_ex1_chr_r(UINT32 offset);
|
||||||
|
inline bool in_split();
|
||||||
|
|
||||||
UINT16 m_irq_count;
|
UINT16 m_irq_count;
|
||||||
UINT8 m_irq_status;
|
UINT8 m_irq_status;
|
||||||
@ -52,16 +59,22 @@ protected:
|
|||||||
int m_exram_control; // $5104
|
int m_exram_control; // $5104
|
||||||
int m_wram_base; // $5113
|
int m_wram_base; // $5113
|
||||||
|
|
||||||
UINT8 m_mmc5_last_chr_a;
|
|
||||||
UINT8 m_last_chr;
|
UINT8 m_last_chr;
|
||||||
|
UINT8 m_ex1_chr;
|
||||||
|
UINT8 m_split_chr;
|
||||||
UINT8 m_prg_regs[4];
|
UINT8 m_prg_regs[4];
|
||||||
|
UINT8 m_prg_ram_mapped[4];
|
||||||
|
|
||||||
|
UINT8 m_ex1_bank;
|
||||||
|
|
||||||
UINT8 m_high_chr; // $5130
|
UINT8 m_high_chr; // $5130
|
||||||
|
|
||||||
UINT8 m_split_scr; // $5200
|
UINT8 m_split_scr; // $5200
|
||||||
|
UINT8 m_split_rev; // $5200
|
||||||
UINT8 m_split_ctrl; // $5200
|
UINT8 m_split_ctrl; // $5200
|
||||||
UINT8 m_split_yst; // $5201
|
UINT8 m_split_yst; // $5201
|
||||||
UINT8 m_split_bank; // $5202
|
UINT8 m_split_bank; // $5202
|
||||||
|
int m_vcount;
|
||||||
|
|
||||||
// MMC-5 contains 1K of internal ram
|
// MMC-5 contains 1K of internal ram
|
||||||
UINT8 *m_exram;
|
UINT8 *m_exram;
|
||||||
|
@ -697,6 +697,7 @@ void device_nes_cart_interface::pcb_start(running_machine &machine, UINT8 *ciram
|
|||||||
int next_bank = m_prg_size / 0x2000;
|
int next_bank = m_prg_size / 0x2000;
|
||||||
m_prg_bank_mem[i]->configure_entries(0, m_prg_size / 0x2000, m_prg, 0x2000);
|
m_prg_bank_mem[i]->configure_entries(0, m_prg_size / 0x2000, m_prg, 0x2000);
|
||||||
// MMC5 (and a few other PCBs) can also map WRAM/BWRAM in these banks, so we add here 4x8K banks for each RAM chip
|
// MMC5 (and a few other PCBs) can also map WRAM/BWRAM in these banks, so we add here 4x8K banks for each RAM chip
|
||||||
|
// No boards with 64Kb of WRAM/BWRAM has been found so far, otherwise the code has to be updated!
|
||||||
if (m_battery)
|
if (m_battery)
|
||||||
{
|
{
|
||||||
if (m_battery_size / 0x2000 == 4)
|
if (m_battery_size / 0x2000 == 4)
|
||||||
|
Loading…
Reference in New Issue
Block a user