quicknes: fire emblem

This commit is contained in:
goyuken 2014-05-07 18:19:36 +00:00
parent 80695269f5
commit 5415f51de0
15 changed files with 204 additions and 10 deletions

Binary file not shown.

View File

@ -284,5 +284,7 @@ EXPORT const char *qn_get_mapper(Nes_Emu *e, int *number)
case 66: return "gnrom";
case 87: return "mapper_87";
case 232: return "quattro";
case 9: return "mmc2";
case 10: return "mmc4";
}
}

View File

@ -24,6 +24,7 @@
<ClCompile Include="..\nes_emu\Mapper_Namco106.cpp" />
<ClCompile Include="..\nes_emu\Mapper_Vrc6.cpp" />
<ClCompile Include="..\nes_emu\misc_mappers.cpp" />
<ClCompile Include="..\nes_emu\Mmc24.cpp" />
<ClCompile Include="..\nes_emu\Multi_Buffer.cpp" />
<ClCompile Include="..\nes_emu\Nes_Apu.cpp" />
<ClCompile Include="..\nes_emu\Nes_Buffer.cpp" />
@ -64,6 +65,7 @@
<ClInclude Include="..\nes_emu\Blip_Buffer.h" />
<ClInclude Include="..\nes_emu\Blip_Synth.h" />
<ClInclude Include="..\nes_emu\Effects_Buffer.h" />
<ClInclude Include="..\nes_emu\Mmc24.h" />
<ClInclude Include="..\nes_emu\Multi_Buffer.h" />
<ClInclude Include="..\nes_emu\Nes_Apu.h" />
<ClInclude Include="..\nes_emu\Nes_Buffer.h" />

View File

@ -135,6 +135,9 @@
<ClCompile Include="..\bizinterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\nes_emu\Mmc24.cpp">
<Filter>Source Files\nes_emu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\nes_emu\abstract_file.h">
@ -257,5 +260,8 @@
<ClInclude Include="..\fex\Data_Reader.h">
<Filter>Header Files\fex</Filter>
</ClInclude>
<ClInclude Include="..\nes_emu\Mmc24.h">
<Filter>Header Files\nes_emu</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -38,6 +38,7 @@ SRCS = \
../nes_emu/Nes_State.cpp \
../nes_emu/nes_util.cpp \
../nes_emu/Nes_Vrc6_Apu.cpp \
../nes_emu/Mmc24.cpp \
../bizinterface.cpp \
../fex/Data_Reader.cpp \
../fex/blargg_errors.cpp \

View File

@ -209,5 +209,8 @@ void register_optional_mappers()
extern void register_namco106_mapper();
register_namco106_mapper();
extern void register_mmc24();
register_mmc24();
}

117
quicknes/nes_emu/Mmc24.cpp Normal file
View File

@ -0,0 +1,117 @@
#include <cstring>
#include "Nes_Mapper.h"
#include "blargg_source.h"
#include "Mmc24.h"
class MMC2: public Nes_Mapper
{
byte regs[6]; // A,B,C,D,E,F
void mirror(byte val)
{
if (val & 1)
mirror_horiz();
else
mirror_vert();
}
public:
MMC2()
{
register_state(regs, sizeof(regs));
}
virtual void reset_state()
{
std::memset(regs, 0, sizeof(regs));
}
virtual void apply_mapping()
{
mirror(regs[5]);
set_prg_bank(0x8000, bank_8k, regs[0]);
set_prg_bank(0xa000, bank_8k, 13);
set_prg_bank(0xc000, bank_8k, 14);
set_prg_bank(0xe000, bank_8k, 15);
set_chr_bank(0x0000, bank_4k, regs[1]);
set_chr_bank(0x1000, bank_4k, regs[3]);
set_chr_bank_ex(0x0000, bank_4k, regs[2]);
set_chr_bank_ex(0x1000, bank_4k, regs[4]);
}
virtual void write(nes_time_t, nes_addr_t addr, int data)
{
switch (addr >> 12)
{
case 0xa: regs[0] = data; set_prg_bank(0x8000, bank_8k, data); break;
case 0xb: regs[1] = data; set_chr_bank(0x0000, bank_4k, data); break;
case 0xc: regs[2] = data; set_chr_bank_ex(0x0000, bank_4k, data); break;
case 0xd: regs[3] = data; set_chr_bank(0x1000, bank_4k, data); break;
case 0xe: regs[4] = data; set_chr_bank_ex(0x1000, bank_4k, data); break;
case 0xf: regs[5] = data; mirror(data); break;
}
}
};
class MMC4: public Nes_Mapper
{
byte regs[6]; // A,B,C,D,E,F
void mirror(byte val)
{
if (val & 1)
mirror_horiz();
else
mirror_vert();
}
public:
MMC4()
{
register_state(regs, sizeof(regs));
}
virtual void reset_state()
{
std::memset(regs, 0, sizeof(regs));
}
virtual void apply_mapping()
{
enable_sram();
mirror(regs[5]);
set_prg_bank(0x8000, bank_16k, regs[0]);
set_chr_bank(0x0000, bank_4k, regs[1]);
set_chr_bank(0x1000, bank_4k, regs[3]);
set_chr_bank_ex(0x0000, bank_4k, regs[2]);
set_chr_bank_ex(0x1000, bank_4k, regs[4]);
}
virtual void write(nes_time_t, nes_addr_t addr, int data)
{
switch (addr >> 12)
{
case 0xa: regs[0] = data; set_prg_bank(0x8000, bank_16k, data); break;
case 0xb: regs[1] = data; set_chr_bank(0x0000, bank_4k, data); break;
case 0xc: regs[2] = data; set_chr_bank_ex(0x0000, bank_4k, data); break;
case 0xd: regs[3] = data; set_chr_bank(0x1000, bank_4k, data); break;
case 0xe: regs[4] = data; set_chr_bank_ex(0x1000, bank_4k, data); break;
case 0xf: regs[5] = data; mirror(data); break;
}
}
};
void register_mmc24()
{
register_mapper<MMC2>(9);
register_mapper<MMC4>(10);
}

7
quicknes/nes_emu/Mmc24.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef MMC24_H
#define MMC24_H
void register_mmc24();
#endif

View File

@ -148,6 +148,12 @@ void Nes_Mapper::set_chr_bank( nes_addr_t addr, bank_size_t bs, int bank )
emu().ppu.set_chr_bank( addr, 1 << bs, bank << bs );
}
void Nes_Mapper::set_chr_bank_ex( nes_addr_t addr, bank_size_t bs, int bank )
{
emu().ppu.render_until( emu().clock() );
emu().ppu.set_chr_bank_ex( addr, 1 << bs, bank << bs );
}
void Nes_Mapper::mirror_manual( int page0, int page1, int page2, int page3 )
{
emu().ppu.render_bg_until( emu().clock() );

View File

@ -121,6 +121,7 @@ protected:
// Map 'size' bytes from 'CHR + bank * size' to PPU address space starting at 'addr'
void set_chr_bank( nes_addr_t addr, bank_size_t size, int bank );
void set_chr_bank_ex( nes_addr_t addr, bank_size_t size, int bank );
// Set PPU mirroring. All mappings implemented using mirror_manual().
void mirror_manual( int page0, int page1, int page2, int page3 );

View File

@ -226,7 +226,7 @@ inline void Nes_Ppu::invalidate_sprite_max( nes_time_t t )
// Sprite 0 hit
inline int Nes_Ppu_Impl::first_opaque_sprite_line() const
inline int Nes_Ppu_Impl::first_opaque_sprite_line() /*const*/
{
// advance earliest time if sprite has blank lines at beginning
byte const* p = map_chr( sprite_tile_index( spr_ram ) * 16 );

View File

@ -66,4 +66,3 @@ while ( true )
if ( !count )
break;
}

View File

@ -33,6 +33,10 @@ Nes_Ppu_Impl::Nes_Ppu_Impl()
max_palette_size = 0;
tile_cache_mem = NULL;
ppu_state_t::unused = 0;
mmc24_enabled = false;
mmc24_latched[0] = 0;
mmc24_latched[1] = 0;
#ifndef NDEBUG
// verify that unaligned accesses work
@ -126,6 +130,29 @@ void Nes_Ppu_Impl::set_chr_bank( int addr, int size, long data )
}
}
void Nes_Ppu_Impl::set_chr_bank_ex( int addr, int size, long data )
{
mmc24_enabled = true;
check( !chr_is_writable || addr == data ); // to do: is CHR RAM ever bank-switched?
//dprintf( "Tried to set CHR RAM bank at %04X to CHR+%04X\n", addr, data );
if ( data + size > chr_size )
data %= chr_size;
int count = (unsigned) size / chr_page_size;
assert( chr_page_size * count == size );
assert( addr + size <= chr_addr_size );
int page = (unsigned) addr / chr_page_size;
while ( count-- )
{
chr_pages_ex [page] = data - page * chr_page_size;
page++;
data += chr_page_size;
}
}
void Nes_Ppu_Impl::save_state( Nes_State_* out ) const
{
*out->ppu = *this;

View File

@ -1,4 +1,3 @@
// NES PPU misc functions and setup
// Nes_Emu 0.7.0
@ -45,6 +44,7 @@ public:
enum { vaddr_clock_mask = 0x1000 };
void set_nt_banks( int bank0, int bank1, int bank2, int bank3 );
void set_chr_bank( int addr, int size, long data );
void set_chr_bank_ex( int addr, int size, long data );
// Nametable and CHR RAM
enum { nt_ram_size = 0x1000 };
@ -77,7 +77,7 @@ protected: //friend class Nes_Ppu; private:
enum { last_sprite_max_scanline = 240 };
long recalc_sprite_max( int scanline );
int first_opaque_sprite_line() const;
int first_opaque_sprite_line() /*const*/;
protected: //friend class Nes_Ppu_Rendering; private:
@ -91,8 +91,8 @@ protected: //friend class Nes_Ppu_Rendering; private:
typedef uint32_t cache_t;
typedef cache_t cached_tile_t [4];
cached_tile_t const& get_bg_tile( int index ) const;
cached_tile_t const& get_sprite_tile( byte const* sprite ) const;
cached_tile_t const& get_bg_tile( int index ) /*const*/;
cached_tile_t const& get_sprite_tile( byte const* sprite ) /*const*/;
byte* get_nametable( int addr ) { return nt_banks [addr >> 10 & 3]; };
private:
@ -103,14 +103,37 @@ private:
// Mapping
enum { chr_page_size = 0x400 };
long chr_pages [chr_addr_size / chr_page_size];
long map_chr_addr( unsigned a ) const { return chr_pages [a / chr_page_size] + a; }
long chr_pages_ex [chr_addr_size / chr_page_size];
long map_chr_addr( unsigned a ) /*const*/
{
if (!mmc24_enabled)
return chr_pages [a / chr_page_size] + a;
int page = a >> 12 & 1;
int newval0 = (a & 0xff0) != 0xfd0;
int newval1 = (a & 0xff0) == 0xfe0;
long ret;
if (mmc24_latched[page])
ret = chr_pages_ex [a / chr_page_size] + a;
else
ret = chr_pages [a / chr_page_size] + a;
mmc24_latched[page] &= newval0;
mmc24_latched[page] |= newval1;
return ret;
}
byte* nt_banks [4];
bool mmc24_enabled;
byte mmc24_latched [2];
// CHR data
byte const* chr_data; // points to chr ram when there is no read-only data
byte* chr_ram; // always points to impl->chr_ram; makes write_2007() faster
long chr_size;
byte const* map_chr( int addr ) const { return &chr_data [map_chr_addr( addr )]; }
byte const* map_chr( int addr ) /*const*/ { return &chr_data [map_chr_addr( addr )]; }
// CHR cache
cached_tile_t* tile_cache;

View File

@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
// Nes_Ppu_Impl
inline Nes_Ppu_Impl::cached_tile_t const&
Nes_Ppu_Impl::get_sprite_tile( byte const* sprite ) const
Nes_Ppu_Impl::get_sprite_tile( byte const* sprite ) /*const*/
{
cached_tile_t* tiles = tile_cache;
if ( sprite [2] & 0x40 )
@ -45,7 +45,7 @@ inline Nes_Ppu_Impl::cached_tile_t const&
((byte*) tiles + map_chr_addr( index * bytes_per_tile ));
}
inline Nes_Ppu_Impl::cached_tile_t const& Nes_Ppu_Impl::get_bg_tile( int index ) const
inline Nes_Ppu_Impl::cached_tile_t const& Nes_Ppu_Impl::get_bg_tile( int index ) /*const*/
{
// use index directly, since cached tile is same size as native tile
BOOST_STATIC_ASSERT( sizeof (cached_tile_t) == bytes_per_tile );