mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
476 lines
10 KiB
C++
476 lines
10 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
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef NST_BOARD_MMC5_H
|
|
#define NST_BOARD_MMC5_H
|
|
|
|
#ifdef NST_PRAGMA_ONCE
|
|
#pragma once
|
|
#endif
|
|
|
|
namespace Nes
|
|
{
|
|
namespace Core
|
|
{
|
|
namespace Boards
|
|
{
|
|
class NST_NO_VTABLE Mmc5 : public Board
|
|
{
|
|
protected:
|
|
|
|
explicit Mmc5(const Context&);
|
|
|
|
public:
|
|
|
|
class Sound : public Apu::Channel
|
|
{
|
|
public:
|
|
|
|
explicit Sound(Apu&,bool=true);
|
|
|
|
void WriteCtrl(uint);
|
|
uint ReadCtrl() const;
|
|
|
|
void WriteSquareReg0(uint,uint);
|
|
void WriteSquareReg1(uint,uint);
|
|
void WriteSquareReg2(uint,uint);
|
|
|
|
void WritePcmReg0(uint);
|
|
void WritePcmReg1(uint);
|
|
|
|
void SaveState(State::Saver&,dword) const;
|
|
void LoadState(State::Loader&);
|
|
|
|
protected:
|
|
|
|
void Reset();
|
|
bool UpdateSettings();
|
|
Cycle Clock(Cycle,Cycle,Cycle);
|
|
Sample GetSample();
|
|
|
|
private:
|
|
|
|
enum
|
|
{
|
|
NUM_SQUARES = 2
|
|
};
|
|
|
|
class Square
|
|
{
|
|
public:
|
|
|
|
void Reset();
|
|
|
|
NST_SINGLE_CALL dword GetSample(Cycle);
|
|
|
|
NST_SINGLE_CALL void WriteReg0(uint);
|
|
NST_SINGLE_CALL void WriteReg1(uint,uint);
|
|
NST_SINGLE_CALL void WriteReg2(uint,uint);
|
|
|
|
NST_SINGLE_CALL void Disable(bool);
|
|
NST_SINGLE_CALL void ClockQuarter();
|
|
NST_SINGLE_CALL void ClockHalf();
|
|
|
|
inline uint GetLengthCounter() const;
|
|
|
|
void UpdateSettings(uint);
|
|
|
|
void SaveState(State::Saver&,dword) const;
|
|
void LoadState(State::Loader&,dword);
|
|
|
|
private:
|
|
|
|
inline bool CanOutput() const;
|
|
|
|
enum
|
|
{
|
|
MIN_FRQ = 0x4,
|
|
REG1_WAVELENGTH_LOW = 0xFF,
|
|
REG2_WAVELENGTH_HIGH = 0x07,
|
|
DUTY_SHIFT = 6
|
|
};
|
|
|
|
uint waveLength;
|
|
ibool active;
|
|
Cycle frequency;
|
|
idword timer;
|
|
uint step;
|
|
uint duty;
|
|
|
|
LengthCounter lengthCounter;
|
|
Envelope envelope;
|
|
};
|
|
|
|
class Pcm
|
|
{
|
|
public:
|
|
|
|
void Reset();
|
|
|
|
inline Sample GetSample() const;
|
|
|
|
NST_SINGLE_CALL void WriteReg0(uint);
|
|
NST_SINGLE_CALL void WriteReg1(uint);
|
|
|
|
void SaveState(State::Saver&,dword) const;
|
|
void LoadState(State::Loader&);
|
|
|
|
private:
|
|
|
|
enum
|
|
{
|
|
VOLUME = OUTPUT_MUL / 4,
|
|
PCM_DISABLE = 0x1
|
|
};
|
|
|
|
ibool enabled;
|
|
Sample sample;
|
|
Sample amp;
|
|
};
|
|
|
|
uint output;
|
|
Cycle rate;
|
|
uint fixed;
|
|
uint atHalfClock;
|
|
dword quarterClock;
|
|
Square square[NUM_SQUARES];
|
|
Pcm pcm;
|
|
DcBlocker dcBlocker;
|
|
};
|
|
|
|
// Needs to be public because of bug in GCC 3.x.x
|
|
enum FetchType
|
|
{
|
|
NT_CIRAM_0,
|
|
NT_CIRAM_1,
|
|
NT_EXRAM,
|
|
NT_FILL,
|
|
NT_ZERO
|
|
};
|
|
|
|
private:
|
|
|
|
void SubReset(bool);
|
|
void VBlank();
|
|
void HDummy();
|
|
void HActive0();
|
|
void HActiveX();
|
|
void Sync(Event,Input::Controllers*);
|
|
|
|
void SubSave(State::Saver&) const;
|
|
void SubLoad(State::Loader&,dword);
|
|
|
|
template<uint ADDRESS>
|
|
void SwapPrg8Ex(uint);
|
|
|
|
void UpdatePrg();
|
|
void UpdateChrA() const;
|
|
void UpdateChrB() const;
|
|
void UpdateRenderMethod();
|
|
|
|
bool ClockSpliter();
|
|
|
|
inline void Update();
|
|
inline ibool IsPpuSprite8x16() const;
|
|
|
|
uint GetExtPattern(uint) const;
|
|
uint GetSpliterAttribute() const;
|
|
uint GetSpliterPattern(uint) const;
|
|
|
|
template<FetchType>
|
|
NST_FORCE_INLINE uint FetchByte(uint) const;
|
|
|
|
template<FetchType NT>
|
|
NST_FORCE_INLINE uint FetchNt(uint) const;
|
|
|
|
template<FetchType NT>
|
|
NST_FORCE_INLINE uint FetchNtExt(uint);
|
|
|
|
template<FetchType NT>
|
|
NST_FORCE_INLINE uint FetchNtSplit(uint);
|
|
|
|
template<FetchType NT>
|
|
NST_FORCE_INLINE uint FetchNtExtSplit(uint);
|
|
|
|
NES_DECL_HOOK( Cpu );
|
|
NES_DECL_HOOK( HActive );
|
|
NES_DECL_HOOK( HBlank );
|
|
|
|
NES_DECL_ACCESSOR( Nt_CiRam_0 );
|
|
NES_DECL_ACCESSOR( Nt_CiRam_1 );
|
|
NES_DECL_ACCESSOR( Nt_ExRam );
|
|
NES_DECL_ACCESSOR( Nt_Fill );
|
|
NES_DECL_ACCESSOR( Nt_Zero );
|
|
NES_DECL_ACCESSOR( NtExt_CiRam_0 );
|
|
NES_DECL_ACCESSOR( NtExt_CiRam_1 );
|
|
NES_DECL_ACCESSOR( NtExt_ExRam );
|
|
NES_DECL_ACCESSOR( NtExt_Fill );
|
|
NES_DECL_ACCESSOR( NtSplit_CiRam_0 );
|
|
NES_DECL_ACCESSOR( NtSplit_CiRam_1 );
|
|
NES_DECL_ACCESSOR( NtSplit_ExRam );
|
|
NES_DECL_ACCESSOR( NtSplit_Fill );
|
|
NES_DECL_ACCESSOR( NtExtSplit_CiRam_0 );
|
|
NES_DECL_ACCESSOR( NtExtSplit_CiRam_1 );
|
|
NES_DECL_ACCESSOR( NtExtSplit_ExRam );
|
|
NES_DECL_ACCESSOR( NtExtSplit_Fill );
|
|
|
|
NES_DECL_ACCESSOR( CRom );
|
|
NES_DECL_ACCESSOR( CRomExt );
|
|
NES_DECL_ACCESSOR( CRomSplit );
|
|
NES_DECL_ACCESSOR( CRomExtSplit );
|
|
|
|
NES_DECL_POKE( 2001 );
|
|
NES_DECL_PEEK( 2001 );
|
|
|
|
NES_DECL_POKE( 5000 );
|
|
NES_DECL_POKE( 5002 );
|
|
NES_DECL_POKE( 5003 );
|
|
NES_DECL_POKE( 5004 );
|
|
NES_DECL_POKE( 5006 );
|
|
NES_DECL_POKE( 5007 );
|
|
NES_DECL_POKE( 5010 );
|
|
NES_DECL_POKE( 5011 );
|
|
NES_DECL_PEEK( 5015 );
|
|
NES_DECL_POKE( 5015 );
|
|
NES_DECL_POKE( 5100 );
|
|
NES_DECL_POKE( 5101 );
|
|
NES_DECL_POKE( 5102 );
|
|
NES_DECL_POKE( 5103 );
|
|
NES_DECL_POKE( 5104 );
|
|
NES_DECL_POKE( 5105 );
|
|
NES_DECL_POKE( 5106 );
|
|
NES_DECL_POKE( 5107 );
|
|
NES_DECL_POKE( 5113 );
|
|
NES_DECL_POKE( 5114 );
|
|
NES_DECL_POKE( 5120 );
|
|
NES_DECL_POKE( 5128 );
|
|
NES_DECL_POKE( 5130 );
|
|
NES_DECL_POKE( 5200 );
|
|
NES_DECL_POKE( 5201 );
|
|
NES_DECL_POKE( 5202 );
|
|
NES_DECL_POKE( 5203 );
|
|
NES_DECL_PEEK( 5204 );
|
|
NES_DECL_POKE( 5204 );
|
|
NES_DECL_PEEK( 5205 );
|
|
NES_DECL_POKE( 5205 );
|
|
NES_DECL_PEEK( 5206 );
|
|
NES_DECL_POKE( 5206 );
|
|
NES_DECL_PEEK( 5C00 );
|
|
NES_DECL_POKE( 5C00 );
|
|
NES_DECL_PEEK( 6000 );
|
|
NES_DECL_POKE( 6000 );
|
|
NES_DECL_PEEK( 8000 );
|
|
NES_DECL_POKE( 8000 );
|
|
NES_DECL_PEEK( A000 );
|
|
NES_DECL_POKE( A000 );
|
|
NES_DECL_PEEK( C000 );
|
|
NES_DECL_POKE( C000 );
|
|
|
|
struct Flow
|
|
{
|
|
void Reset();
|
|
|
|
typedef void (Mmc5::*Phase)();
|
|
|
|
Cycle cycles;
|
|
Phase phase;
|
|
uint scanline;
|
|
};
|
|
|
|
struct Irq
|
|
{
|
|
void Reset();
|
|
|
|
enum
|
|
{
|
|
ENABLED = 0x01,
|
|
FRAME = 0x40,
|
|
HIT = 0x80,
|
|
SIGNAL_HIT = ENABLED|HIT
|
|
};
|
|
|
|
uint state;
|
|
uint count;
|
|
uint target;
|
|
};
|
|
|
|
struct Regs
|
|
{
|
|
void Reset();
|
|
|
|
enum
|
|
{
|
|
PRG_MODE = 0x03,
|
|
PRG_MODE_32K = 0x00,
|
|
PRG_MODE_16K = 0x01,
|
|
PRG_MODE_16K_8K = 0x02,
|
|
PRG_MODE_8K = 0x03,
|
|
PRG_ROM_SELECT = 0x80,
|
|
PRG_ROM_BANK = 0x7F,
|
|
PRG_RAM_BANK = 0x07,
|
|
CHR_MODE = 0x03,
|
|
CHR_MODE_8K = 0x00,
|
|
CHR_MODE_4K = 0x01,
|
|
CHR_MODE_2K = 0x02,
|
|
CHR_MODE_1K = 0x03,
|
|
CHR_HIGH = 0x03,
|
|
WRK_WRITABLE_A = 0x02,
|
|
WRK_WRITABLE_B = 0x01,
|
|
NMT_MODE = 0x03,
|
|
NMT_CIRAM_0 = 0x00,
|
|
NMT_CIRAM_1 = 0x01,
|
|
NMT_EXRAM = 0x02,
|
|
NMT_FILL = 0x03,
|
|
EXRAM_MODE = 0x03,
|
|
EXRAM_MODE_PPU_NT = 0x00,
|
|
EXRAM_MODE_PPU_EXT = 0x01,
|
|
EXRAM_MODE_CPU_RAM = 0x02,
|
|
EXRAM_MODE_CPU_ROM = 0x03,
|
|
EXRAM_EXT_CHR_BANK = 0x3F,
|
|
PPU_CTRL0_SP8X16 = 0x20,
|
|
PPU_CTRL1_ENABLED = 0x18
|
|
};
|
|
|
|
uint prgMode;
|
|
uint chrMode;
|
|
uint exRamMode;
|
|
uint mul[2];
|
|
};
|
|
|
|
struct Banks
|
|
{
|
|
explicit Banks(uint);
|
|
|
|
void Reset();
|
|
|
|
enum
|
|
{
|
|
READABLE_6 = 0x004,
|
|
READABLE_8 = 0x008,
|
|
READABLE_A = 0x010,
|
|
READABLE_C = 0x020,
|
|
WRITABLE_6 = 0x040,
|
|
WRITABLE_8 = 0x080,
|
|
WRITABLE_A = 0x100,
|
|
WRITABLE_C = 0x200,
|
|
CAN_WRITE_6 = READABLE_6|WRITABLE_6|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B,
|
|
CAN_WRITE_8 = READABLE_8|WRITABLE_8|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B,
|
|
CAN_WRITE_A = READABLE_A|WRITABLE_A|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B,
|
|
CAN_WRITE_C = READABLE_C|WRITABLE_C|Regs::WRK_WRITABLE_A|Regs::WRK_WRITABLE_B
|
|
};
|
|
|
|
enum FetchMode
|
|
{
|
|
FETCH_MODE_NONE,
|
|
FETCH_MODE_BG,
|
|
FETCH_MODE_SP
|
|
};
|
|
|
|
enum LastChr
|
|
{
|
|
LAST_CHR_A = 0,
|
|
LAST_CHR_B = 1
|
|
};
|
|
|
|
class Wrk
|
|
{
|
|
byte banks[8];
|
|
|
|
public:
|
|
|
|
enum
|
|
{
|
|
INVALID = 8
|
|
};
|
|
|
|
explicit Wrk(dword);
|
|
|
|
inline uint operator [] (uint) const;
|
|
};
|
|
|
|
uint nmt;
|
|
word chrA[8];
|
|
word chrB[4];
|
|
dword chrHigh;
|
|
LastChr lastChr;
|
|
FetchMode fetchMode;
|
|
uint security;
|
|
byte prg[4];
|
|
const Wrk wrk;
|
|
};
|
|
|
|
struct Filler
|
|
{
|
|
void Reset();
|
|
|
|
uint tile;
|
|
uint attribute;
|
|
|
|
static const byte squared[4];
|
|
};
|
|
|
|
struct Spliter
|
|
{
|
|
void Reset();
|
|
|
|
enum
|
|
{
|
|
CTRL_START = 0x1F,
|
|
CTRL_RIGHT_SIDE = 0x40,
|
|
CTRL_ENABLED = 0x80
|
|
};
|
|
|
|
uint ctrl;
|
|
uint tile;
|
|
ibool inside;
|
|
uint yStart;
|
|
uint chrBank;
|
|
uint x;
|
|
uint y;
|
|
};
|
|
|
|
struct ExRam
|
|
{
|
|
void Reset(bool);
|
|
|
|
uint tile;
|
|
byte mem[SIZE_1K];
|
|
};
|
|
|
|
Flow flow;
|
|
Irq irq;
|
|
Regs regs;
|
|
Banks banks;
|
|
const byte* ciRam[2];
|
|
Filler filler;
|
|
Spliter spliter;
|
|
Io::Port p2001;
|
|
ExRam exRam;
|
|
Sound sound;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|