nestopia/source/core/board/NstBoardAction53.cpp
2019-05-28 11:22:24 -04:00

209 lines
5.4 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include "NstBoard.hpp"
#include "NstBoardAction53.hpp"
namespace Nes
{
namespace Core
{
namespace Boards
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Action53::SubReset(const bool hard)
{
Map( 0x5000U, 0x5FFFU, &Action53::Poke_5000 );
Map( 0x8000U, 0xFFFFU, &Action53::Poke_8000 );
if (hard)
{
preg[1] = 0xf;
preg[3] = 0x3f;
}
}
void Action53::SubLoad(State::Loader& state,const dword baseChunk)
{
NST_VERIFY( baseChunk == (AsciiId<'A','5','3'>::V) );
if (baseChunk == AsciiId<'A','5','3'>::V)
{
while (const dword chunk = state.Begin())
{
if (chunk == AsciiId<'R','E','G'>::V)
{
State::Loader::Data<6> data( state );
preg[0] = data[0];
preg[1] = data[1];
preg[2] = data[2];
preg[3] = data[3];
mirroring = data[4];
index = data[5];
}
state.End();
}
}
}
void Action53::SubSave(State::Saver& state) const
{
const byte data[] =
{
preg[0], preg[1], preg[2], preg[3],
mirroring, index
};
state.Begin( AsciiId<'A','5','3'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NES_POKE_D(Action53, 5000)
{
index = ((data >> 6) & 0x2) | (data & 0x1);
}
NES_POKE_D(Action53, 8000)
{
switch (index) {
case 0:
if (!(mirroring & 2)) {
mirroring = (mirroring & 0x2) | (data >> 4) & 0x1;
set_nmt_mirroring();
}
chr.SwapBank<SIZE_8K, 0x0000>( data & 0x3 );
break;
case 1:
if (!(mirroring & 2)) {
mirroring = (mirroring & 0x2) | (data >> 4) & 0x1;
set_nmt_mirroring();
}
preg[1] = data & 0xf;
set_prg();
break;
case 2:
preg[2] = data & 0x3c;
mirroring = (data & 3);
set_prg();
set_nmt_mirroring();
break;
case 3:
preg[3] = data & 0x3f;
set_prg();
break;
}
}
void Action53::set_prg(void)
{
byte prglo, prghi;
byte prg_inner_b = preg[1];
byte prg_outer_b = (preg[3] << 1);
/* this can probably be rolled up, but i have no motivation to do so
* until it's been tested */
switch (preg[2] & 0x3c)
{
/* 32K modes */
case 0x00:
case 0x04:
prglo = prg_outer_b;
prghi = prg_outer_b | 0x1;
break;
case 0x10:
case 0x14:
prglo = (prg_outer_b & ~0x2) | ((prg_inner_b << 1) & 0x2);
prghi = (prg_outer_b & ~0x2) | ((prg_inner_b << 1) & 0x2) | 0x1;
break;
case 0x20:
case 0x24:
prglo = (prg_outer_b & ~0x6) | ((prg_inner_b << 1) & 0x6);
prghi = (prg_outer_b & ~0x6) | ((prg_inner_b << 1) & 0x6) | 0x1;
break;
case 0x30:
case 0x34:
prglo = (prg_outer_b & ~0xe) | ((prg_inner_b << 1) & 0xe);
prghi = (prg_outer_b & ~0xe) | ((prg_inner_b << 1) & 0xe) | 0x1;
break;
/* bottom fixed modes */
case 0x08:
prglo = prg_outer_b;
prghi = prg_outer_b | (prg_inner_b & 0x1);
break;
case 0x18:
prglo = prg_outer_b;
prghi = (prg_outer_b & ~0x2) | (prg_inner_b & 0x3);
break;
case 0x28:
prglo = prg_outer_b;
prghi = (prg_outer_b & ~0x6) | (prg_inner_b & 0x7);
break;
case 0x38:
prglo = prg_outer_b;
prghi = (prg_outer_b & ~0xe) | (prg_inner_b & 0xf);
break;
/* top fixed modes */
case 0x0c:
prglo = prg_outer_b | (prg_inner_b & 0x1);
prghi = prg_outer_b | 0x1;
break;
case 0x1c:
prglo = (prg_outer_b & ~0x2) | (prg_inner_b & 0x3);
prghi = prg_outer_b | 0x1;
break;
case 0x2c:
prglo = (prg_outer_b & ~0x6) | (prg_inner_b & 0x7);
prghi = prg_outer_b | 0x1;
break;
case 0x3c:
prglo = (prg_outer_b & ~0xe) | (prg_inner_b & 0xf);
prghi = prg_outer_b | 0x1;
break;
}
prg.SwapBank<SIZE_16K, 0x0000>( prglo );
prg.SwapBank<SIZE_16K, 0x4000>( prghi );
}
void Action53::set_nmt_mirroring(void)
{
switch (mirroring)
{
case 0: ppu.SetMirroring( Ppu::NMT_0 ); break;
case 1: ppu.SetMirroring( Ppu::NMT_1 ); break;
case 2: ppu.SetMirroring( Ppu::NMT_V ); break;
case 3: ppu.SetMirroring( Ppu::NMT_H ); break;
}
}
}
}
}