156 lines
3.5 KiB
C++
156 lines
3.5 KiB
C++
|
|
// NES MMC5 mapper, currently only tailored for Castlevania 3 (U)
|
|
|
|
// Nes_Emu 0.7.0. http://www.slack.net/~ant/
|
|
|
|
#include "Nes_Mapper.h"
|
|
|
|
#include "Nes_Core.h"
|
|
#include <string.h>
|
|
|
|
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
|
|
can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
General Public License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version. This
|
|
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
more details. You should have received a copy of the GNU Lesser General
|
|
Public License along with this module; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
#include "blargg_source.h"
|
|
|
|
struct mmc5_state_t
|
|
{
|
|
enum { reg_count = 0x30 };
|
|
byte regs [0x30];
|
|
byte irq_enabled;
|
|
};
|
|
// to do: finalize state format
|
|
BOOST_STATIC_ASSERT( sizeof (mmc5_state_t) == 0x31 );
|
|
|
|
class Mapper_Mmc5 : public Nes_Mapper, mmc5_state_t {
|
|
nes_time_t irq_time;
|
|
public:
|
|
Mapper_Mmc5()
|
|
{
|
|
mmc5_state_t* state = this;
|
|
register_state( state, sizeof *state );
|
|
}
|
|
|
|
virtual void reset_state()
|
|
{
|
|
irq_time = no_irq;
|
|
regs [0x00] = 2;
|
|
regs [0x01] = 3;
|
|
regs [0x14] = 0x7f;
|
|
regs [0x15] = 0x7f;
|
|
regs [0x16] = 0x7f;
|
|
regs [0x17] = 0x7f;
|
|
}
|
|
|
|
virtual void read_state( mapper_state_t const& in )
|
|
{
|
|
Nes_Mapper::read_state( in );
|
|
irq_time = no_irq;
|
|
}
|
|
|
|
enum { regs_addr = 0x5100 };
|
|
|
|
virtual void apply_mapping();
|
|
|
|
virtual nes_time_t next_irq( nes_time_t )
|
|
{
|
|
if ( irq_enabled & 0x80 )
|
|
return irq_time;
|
|
|
|
return no_irq;
|
|
}
|
|
|
|
virtual bool write_intercepted( nes_time_t time, nes_addr_t addr, int data )
|
|
{
|
|
int reg = addr - regs_addr;
|
|
if ( (unsigned) reg < reg_count )
|
|
{
|
|
regs [reg] = data;
|
|
switch ( reg )
|
|
{
|
|
case 0x05:
|
|
mirror_manual( data & 3, data >> 2 & 3,
|
|
data >> 4 & 3, data >> 6 & 3 );
|
|
break;
|
|
|
|
case 0x15:
|
|
set_prg_bank( 0x8000, bank_16k, data >> 1 & 0x3f );
|
|
break;
|
|
|
|
case 0x16:
|
|
set_prg_bank( 0xC000, bank_8k, data & 0x7f );
|
|
break;
|
|
|
|
case 0x17:
|
|
set_prg_bank( 0xE000, bank_8k, data & 0x7f );
|
|
break;
|
|
|
|
case 0x20:
|
|
case 0x21:
|
|
case 0x22:
|
|
case 0x23:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2a:
|
|
case 0x2b:
|
|
set_chr_bank( ((reg >> 1 & 4) + (reg & 3)) * 0x400, bank_1k, data );
|
|
break;
|
|
}
|
|
check( (regs [0x00] & 3) == 2 );
|
|
check( (regs [0x01] & 3) == 3 );
|
|
}
|
|
else if ( addr == 0x5203 )
|
|
{
|
|
irq_time = no_irq;
|
|
if ( data && data < 240 )
|
|
{
|
|
irq_time = (341 * 21 + 128 + (data * 341)) / 3;
|
|
if ( irq_time < time )
|
|
irq_time = no_irq;
|
|
}
|
|
irq_changed();
|
|
}
|
|
else if ( addr == 0x5204 )
|
|
{
|
|
irq_enabled = data;
|
|
irq_changed();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual void write( nes_time_t, nes_addr_t, int ) { }
|
|
};
|
|
|
|
void Mapper_Mmc5::apply_mapping()
|
|
{
|
|
static unsigned char list [] = {
|
|
0x05, 0x15, 0x16, 0x17,
|
|
0x20, 0x21, 0x22, 0x23,
|
|
0x28, 0x29, 0x2a, 0x2b
|
|
};
|
|
|
|
for ( int i = 0; i < (int) sizeof list; i++ )
|
|
write_intercepted( 0, regs_addr + list [i], regs [list [i]] );
|
|
intercept_writes( 0x5100, 0x200 );
|
|
}
|
|
|
|
void register_mmc5_mapper();
|
|
void register_mmc5_mapper()
|
|
{
|
|
register_mapper<Mapper_Mmc5>( 5 );
|
|
}
|
|
|