commit
bc425ba44c
|
@ -112,11 +112,12 @@ namespace BizHawk.Client.Common
|
|||
case "SNES":
|
||||
return SystemInfo.SNES;
|
||||
case "GB":
|
||||
/*
|
||||
if ((Emulator as IGameboyCommon).IsCGBMode())
|
||||
{
|
||||
return SystemInfo.GBC;
|
||||
}
|
||||
|
||||
*/
|
||||
return SystemInfo.GB;
|
||||
case "A26":
|
||||
return SystemInfo.Atari2600;
|
||||
|
|
|
@ -13,6 +13,7 @@ using BizHawk.Emulation.Cores.Computers.AppleII;
|
|||
using BizHawk.Emulation.Cores.Computers.Commodore64;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using BizHawk.Emulation.Cores.PCEngine;
|
||||
using BizHawk.Emulation.Cores.Sega.Saturn;
|
||||
|
@ -935,10 +936,36 @@ namespace BizHawk.Client.Common
|
|||
break;
|
||||
|
||||
case "GB":
|
||||
case "GBC":
|
||||
if (!Global.Config.GB_AsSGB)
|
||||
{
|
||||
core = CoreInventory.Instance["GB", "Gambatte"];
|
||||
if (Global.Config.GB_UseGBHawk)
|
||||
{
|
||||
core = CoreInventory.Instance["GB", "GBHawk"];
|
||||
}
|
||||
else
|
||||
{
|
||||
core = CoreInventory.Instance["GB", "Gambatte"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Global.Config.SGB_UseBsnes)
|
||||
{
|
||||
game.System = "SNES";
|
||||
game.AddOption("SGB");
|
||||
var snes = new LibsnesCore(game, rom.FileData, null, nextComm, GetCoreSettings<LibsnesCore>(), GetCoreSyncSettings<LibsnesCore>());
|
||||
nextEmulator = snes;
|
||||
}
|
||||
else
|
||||
{
|
||||
core = CoreInventory.Instance["SGB", "SameBoy"];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "GBC":
|
||||
if (!Global.Config.GB_AsSGB)
|
||||
{
|
||||
core = CoreInventory.Instance["GBC", "Gambatte"];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -557,6 +557,7 @@ namespace BizHawk.Client.Common
|
|||
public bool SNES_InSnes9x = true;
|
||||
public bool GBA_UsemGBA = true;
|
||||
public bool SGB_UseBsnes = false;
|
||||
public bool GB_UseGBHawk = false;
|
||||
public bool CoreForcingViaGameDB = true;
|
||||
public string LibretroCore;
|
||||
}
|
||||
|
|
|
@ -194,9 +194,12 @@
|
|||
this.MgbaCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SGBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SgbBsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SgbBsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SgbSameBoyMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGambatteMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGBHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem16 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.allowGameDBCoreOverridesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
|
||||
|
@ -1810,7 +1813,8 @@
|
|||
this.CoreSNESSubMenu,
|
||||
this.GbaCoreSubMenu,
|
||||
this.SGBCoreSubmenu,
|
||||
this.GBInSGBMenuItem,
|
||||
this.GBCoreSubmenu,
|
||||
this.GBInSGBMenuItem,
|
||||
this.toolStripMenuItem16,
|
||||
this.allowGameDBCoreOverridesToolStripMenuItem,
|
||||
this.toolStripSeparator8,
|
||||
|
@ -1908,10 +1912,20 @@
|
|||
this.SGBCoreSubmenu.Size = new System.Drawing.Size(239, 22);
|
||||
this.SGBCoreSubmenu.Text = "SGB";
|
||||
this.SGBCoreSubmenu.DropDownOpened += new System.EventHandler(this.SGBCoreSubmenu_DropDownOpened);
|
||||
//
|
||||
// SgbBsnesMenuItem
|
||||
//
|
||||
this.SgbBsnesMenuItem.Name = "SgbBsnesMenuItem";
|
||||
//
|
||||
// GBCoreSubmenu
|
||||
//
|
||||
this.GBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.GBGambatteMenuItem,
|
||||
this.GBGBHawkMenuItem});
|
||||
this.GBCoreSubmenu.Name = "GBCoreSubmenu";
|
||||
this.GBCoreSubmenu.Size = new System.Drawing.Size(239, 22);
|
||||
this.GBCoreSubmenu.Text = "GB";
|
||||
this.GBCoreSubmenu.DropDownOpened += new System.EventHandler(this.GBCoreSubmenu_DropDownOpened);
|
||||
//
|
||||
// SgbBsnesMenuItem
|
||||
//
|
||||
this.SgbBsnesMenuItem.Name = "SgbBsnesMenuItem";
|
||||
this.SgbBsnesMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.SgbBsnesMenuItem.Text = "BSNES";
|
||||
this.SgbBsnesMenuItem.Click += new System.EventHandler(this.SgbCorePick_Click);
|
||||
|
@ -1922,10 +1936,24 @@
|
|||
this.SgbSameBoyMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.SgbSameBoyMenuItem.Text = "SameBoy";
|
||||
this.SgbSameBoyMenuItem.Click += new System.EventHandler(this.SgbCorePick_Click);
|
||||
//
|
||||
// GBInSGBMenuItem
|
||||
//
|
||||
this.GBInSGBMenuItem.Name = "GBInSGBMenuItem";
|
||||
//
|
||||
// GBGambatteMenuItem
|
||||
//
|
||||
this.GBGambatteMenuItem.Name = "GBGambatteMenuItem";
|
||||
this.GBGambatteMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.GBGambatteMenuItem.Text = "Gambatte";
|
||||
this.GBGambatteMenuItem.Click += new System.EventHandler(this.GBCorePick_Click);
|
||||
//
|
||||
// GBGBHawkMenuItem
|
||||
//
|
||||
this.GBGBHawkMenuItem.Name = "GBGBHawkMenuItem";
|
||||
this.GBGBHawkMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.GBGBHawkMenuItem.Text = "GBHawk";
|
||||
this.GBGBHawkMenuItem.Click += new System.EventHandler(this.GBCorePick_Click);
|
||||
//
|
||||
// GBInSGBMenuItem
|
||||
//
|
||||
this.GBInSGBMenuItem.Name = "GBInSGBMenuItem";
|
||||
this.GBInSGBMenuItem.Size = new System.Drawing.Size(239, 22);
|
||||
this.GBInSGBMenuItem.Text = "GB in SGB";
|
||||
this.GBInSGBMenuItem.Click += new System.EventHandler(this.GbInSgbMenuItem_Click);
|
||||
|
@ -4407,6 +4435,9 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem SGBCoreSubmenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem SgbBsnesMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SgbSameBoyMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBCoreSubmenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBGambatteMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBGBHawkMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem pCFXToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem preferencesToolStripMenuItem3;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerToolStripMenuItem;
|
||||
|
|
|
@ -1244,6 +1244,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
SgbSameBoyMenuItem.Checked = !Global.Config.SGB_UseBsnes;
|
||||
}
|
||||
|
||||
private void GBCoreSubmenu_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
GBGambatteMenuItem.Checked = !Global.Config.GB_UseGBHawk;
|
||||
GBGBHawkMenuItem.Checked = Global.Config.GB_UseGBHawk;
|
||||
}
|
||||
|
||||
private void SgbCorePick_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Config.SGB_UseBsnes ^= true;
|
||||
|
@ -1254,6 +1260,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
private void GBCorePick_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Config.GB_UseGBHawk ^= true;
|
||||
// TODO: only flag if one of these cores
|
||||
if (!Emulator.IsNull())
|
||||
{
|
||||
FlagNeedsReboot();
|
||||
}
|
||||
}
|
||||
|
||||
private void GbInSgbMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Config.GB_AsSGB ^= true;
|
||||
|
|
|
@ -581,6 +581,35 @@
|
|||
<DependentUpon>VBANext.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\VBARegisterHelper.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Audio.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IDebuggable.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IEmulator.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IInputPollable.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IMemoryDomains.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.ISaveRam.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.ISettable.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IStatable.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawkControllerDeck.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawkControllers.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\HW_Registers.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\MapperBase.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_Camera.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_Default.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_HuC1.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_HuC3.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC1_Multi.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC1.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC2.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC3.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC5.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC6.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MBC7.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_MMM01.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_TAMA5.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\MemoryMap.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\PPU.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Timer.cs" />
|
||||
<Compile Include="Consoles\Nintendo\N64\N64SyncSettings.GLideN64.cs" />
|
||||
<Compile Include="Consoles\Nintendo\N64\N64.IDebuggable.cs">
|
||||
<DependentUpon>N64.cs</DependentUpon>
|
||||
|
@ -752,7 +781,7 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper049.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper052.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper074.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper114.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper114.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper115.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper121.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper123.cs" />
|
||||
|
@ -1161,6 +1190,14 @@
|
|||
<Compile Include="CPUs\CP1610\CP1610.Disassembler.cs" />
|
||||
<Compile Include="CPUs\CP1610\CP1610.Execute.cs" />
|
||||
<Compile Include="CPUs\HuC6280\HuC6280_CDL.cs" />
|
||||
<Compile Include="CPUs\LR35902\Execute.cs" />
|
||||
<Compile Include="CPUs\LR35902\Interrupts.cs" />
|
||||
<Compile Include="CPUs\LR35902\LR35902.cs" />
|
||||
<Compile Include="CPUs\LR35902\NewDisassembler.cs" />
|
||||
<Compile Include="CPUs\LR35902\Operations.cs" />
|
||||
<Compile Include="CPUs\LR35902\Registers.cs" />
|
||||
<Compile Include="CPUs\LR35902\Tables_Direct.cs" />
|
||||
<Compile Include="CPUs\LR35902\Tables_Indirect.cs" />
|
||||
<Compile Include="CPUs\W65816\Disassembler.cs" />
|
||||
<Compile Include="CPUs\68000\Diassembler.cs" />
|
||||
<Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" />
|
||||
|
@ -1186,12 +1223,6 @@
|
|||
<Compile Include="CPUs\x86\Execute.cs" />
|
||||
<Compile Include="CPUs\x86\Timing.cs" />
|
||||
<Compile Include="CPUs\x86\x86.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Execute.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Interrupts.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\NewDisassembler.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Registers.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Tables.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Z80.cs" />
|
||||
<Compile Include="CPUs\Z80A\NewDisassembler.cs" />
|
||||
<Compile Include="CPUs\Z80A\Execute.cs" />
|
||||
<Compile Include="CPUs\Z80A\Interrupts.cs" />
|
||||
|
@ -1322,4 +1353,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,552 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public partial class LR35902
|
||||
{
|
||||
private int totalExecutedCycles;
|
||||
public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } }
|
||||
|
||||
private int EI_pending;
|
||||
private bool interrupts_enabled;
|
||||
|
||||
// variables for executing instructions
|
||||
public int instr_pntr = 0;
|
||||
public ushort[] cur_instr;
|
||||
public int opcode;
|
||||
public bool CB_prefix;
|
||||
public bool halted;
|
||||
public bool stopped;
|
||||
public bool jammed;
|
||||
public int LY;
|
||||
|
||||
public void FetchInstruction(byte opcode)
|
||||
{
|
||||
if (!CB_prefix)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00: NOP_(); break; // NOP
|
||||
case 0x01: LD_IND_16(C, B, PCl, PCh); break; // LD BC, nn
|
||||
case 0x02: LD_8_IND(C, B, A); break; // LD (BC), A
|
||||
case 0x03: INC_16(C, B); break; // INC BC
|
||||
case 0x04: INT_OP(INC8, B); break; // INC B
|
||||
case 0x05: INT_OP(DEC8, B); break; // DEC B
|
||||
case 0x06: LD_IND_8_INC(B, PCl, PCh); break; // LD B, n
|
||||
case 0x07: INT_OP(RLC, Aim); break; // RLCA
|
||||
case 0x08: LD_R_IM(SPl, SPh, PCl, PCh); break; // LD (imm), SP
|
||||
case 0x09: ADD_16(L, H, C, B); break; // ADD HL, BC
|
||||
case 0x0A: REG_OP_IND(TR, A, C, B); break; // LD A, (BC)
|
||||
case 0x0B: DEC_16(C, B); break; // DEC BC
|
||||
case 0x0C: INT_OP(INC8, C); break; // INC C
|
||||
case 0x0D: INT_OP(DEC8, C); break; // DEC C
|
||||
case 0x0E: LD_IND_8_INC(C, PCl, PCh); break; // LD C, n
|
||||
case 0x0F: INT_OP(RRC, Aim); break; // RRCA
|
||||
case 0x10: STOP_(); break; // STOP
|
||||
case 0x11: LD_IND_16(E, D, PCl, PCh); break; // LD DE, nn
|
||||
case 0x12: LD_8_IND(E, D, A); break; // LD (DE), A
|
||||
case 0x13: INC_16(E, D); break; // INC DE
|
||||
case 0x14: INT_OP(INC8, D); break; // INC D
|
||||
case 0x15: INT_OP(DEC8, D); break; // DEC D
|
||||
case 0x16: LD_IND_8_INC(D, PCl, PCh); break; // LD D, n
|
||||
case 0x17: INT_OP(RL, Aim); break; // RLA
|
||||
case 0x18: JR_COND(true); break; // JR, r8
|
||||
case 0x19: ADD_16(L, H, E, D); break; // ADD HL, DE
|
||||
case 0x1A: REG_OP_IND(TR, A, E, D); break; // LD A, (DE)
|
||||
case 0x1B: DEC_16(E, D); break; // DEC DE
|
||||
case 0x1C: INT_OP(INC8, E); break; // INC E
|
||||
case 0x1D: INT_OP(DEC8, E); break; // DEC E
|
||||
case 0x1E: LD_IND_8_INC(E, PCl, PCh); break; // LD E, n
|
||||
case 0x1F: INT_OP(RR, Aim); break; // RRA
|
||||
case 0x20: JR_COND(!FlagZ); break; // JR NZ, r8
|
||||
case 0x21: LD_IND_16(L, H, PCl, PCh); break; // LD HL, nn
|
||||
case 0x22: LD_8_IND_INC(L, H, A); break; // LD (HL+), A
|
||||
case 0x23: INC_16(L, H); break; // INC HL
|
||||
case 0x24: INT_OP(INC8, H); break; // INC H
|
||||
case 0x25: INT_OP(DEC8, H); break; // DEC H
|
||||
case 0x26: LD_IND_8_INC(H, PCl, PCh); break; // LD H, n
|
||||
case 0x27: INT_OP(DA, A); break; // DAA
|
||||
case 0x28: JR_COND(FlagZ); break; // JR Z, r8
|
||||
case 0x29: ADD_16(L, H, L, H); break; // ADD HL, HL
|
||||
case 0x2A: LD_IND_8_INC(A, L, H); break; // LD A, (HL+)
|
||||
case 0x2B: DEC_16(L, H); break; // DEC HL
|
||||
case 0x2C: INT_OP(INC8, L); break; // INC L
|
||||
case 0x2D: INT_OP(DEC8, L); break; // DEC L
|
||||
case 0x2E: LD_IND_8_INC(L, PCl, PCh); break; // LD L, n
|
||||
case 0x2F: INT_OP(CPL, A); break; // CPL
|
||||
case 0x30: JR_COND(!FlagC); break; // JR NC, r8
|
||||
case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn
|
||||
case 0x32: LD_8_IND_DEC(L, H, A); break; // LD (HL-), A
|
||||
case 0x33: INC_16(SPl, SPh); break; // INC SP
|
||||
case 0x34: INC_8_IND(L, H); break; // INC (HL)
|
||||
case 0x35: DEC_8_IND(L, H); break; // DEC (HL)
|
||||
case 0x36: LD_8_IND_IND(L, H, PCl, PCh); break; // LD (HL), n
|
||||
case 0x37: INT_OP(SCF, A); break; // SCF
|
||||
case 0x38: JR_COND(FlagC); break; // JR C, r8
|
||||
case 0x39: ADD_16(L, H, SPl, SPh); break; // ADD HL, SP
|
||||
case 0x3A: LD_IND_8_DEC(A, L, H); break; // LD A, (HL-)
|
||||
case 0x3B: DEC_16(SPl, SPh); break; // DEC SP
|
||||
case 0x3C: INT_OP(INC8, A); break; // INC A
|
||||
case 0x3D: INT_OP(DEC8, A); break; // DEC A
|
||||
case 0x3E: LD_IND_8_INC(A, PCl, PCh); break; // LD A, n
|
||||
case 0x3F: INT_OP(CCF, A); break; // CCF
|
||||
case 0x40: REG_OP(TR, B, B); break; // LD B, B
|
||||
case 0x41: REG_OP(TR, B, C); break; // LD B, C
|
||||
case 0x42: REG_OP(TR, B, D); break; // LD B, D
|
||||
case 0x43: REG_OP(TR, B, E); break; // LD B, E
|
||||
case 0x44: REG_OP(TR, B, H); break; // LD B, H
|
||||
case 0x45: REG_OP(TR, B, L); break; // LD B, L
|
||||
case 0x46: REG_OP_IND(TR, B, L, H); break; // LD B, (HL)
|
||||
case 0x47: REG_OP(TR, B, A); break; // LD B, A
|
||||
case 0x48: REG_OP(TR, C, B); break; // LD C, B
|
||||
case 0x49: REG_OP(TR, C, C); break; // LD C, C
|
||||
case 0x4A: REG_OP(TR, C, D); break; // LD C, D
|
||||
case 0x4B: REG_OP(TR, C, E); break; // LD C, E
|
||||
case 0x4C: REG_OP(TR, C, H); break; // LD C, H
|
||||
case 0x4D: REG_OP(TR, C, L); break; // LD C, L
|
||||
case 0x4E: REG_OP_IND(TR, C, L, H); break; // LD C, (HL)
|
||||
case 0x4F: REG_OP(TR, C, A); break; // LD C, A
|
||||
case 0x50: REG_OP(TR, D, B); break; // LD D, B
|
||||
case 0x51: REG_OP(TR, D, C); break; // LD D, C
|
||||
case 0x52: REG_OP(TR, D, D); break; // LD D, D
|
||||
case 0x53: REG_OP(TR, D, E); break; // LD D, E
|
||||
case 0x54: REG_OP(TR, D, H); break; // LD D, H
|
||||
case 0x55: REG_OP(TR, D, L); break; // LD D, L
|
||||
case 0x56: REG_OP_IND(TR, D, L, H); break; // LD D, (HL)
|
||||
case 0x57: REG_OP(TR, D, A); break; // LD D, A
|
||||
case 0x58: REG_OP(TR, E, B); break; // LD E, B
|
||||
case 0x59: REG_OP(TR, E, C); break; // LD E, C
|
||||
case 0x5A: REG_OP(TR, E, D); break; // LD E, D
|
||||
case 0x5B: REG_OP(TR, E, E); break; // LD E, E
|
||||
case 0x5C: REG_OP(TR, E, H); break; // LD E, H
|
||||
case 0x5D: REG_OP(TR, E, L); break; // LD E, L
|
||||
case 0x5E: REG_OP_IND(TR, E, L, H); break; // LD E, (HL)
|
||||
case 0x5F: REG_OP(TR, E, A); break; // LD E, A
|
||||
case 0x60: REG_OP(TR, H, B); break; // LD H, B
|
||||
case 0x61: REG_OP(TR, H, C); break; // LD H, C
|
||||
case 0x62: REG_OP(TR, H, D); break; // LD H, D
|
||||
case 0x63: REG_OP(TR, H, E); break; // LD H, E
|
||||
case 0x64: REG_OP(TR, H, H); break; // LD H, H
|
||||
case 0x65: REG_OP(TR, H, L); break; // LD H, L
|
||||
case 0x66: REG_OP_IND(TR, H, L, H); break; // LD H, (HL)
|
||||
case 0x67: REG_OP(TR, H, A); break; // LD H, A
|
||||
case 0x68: REG_OP(TR, L, B); break; // LD L, B
|
||||
case 0x69: REG_OP(TR, L, C); break; // LD L, C
|
||||
case 0x6A: REG_OP(TR, L, D); break; // LD L, D
|
||||
case 0x6B: REG_OP(TR, L, E); break; // LD L, E
|
||||
case 0x6C: REG_OP(TR, L, H); break; // LD L, H
|
||||
case 0x6D: REG_OP(TR, L, L); break; // LD L, L
|
||||
case 0x6E: REG_OP_IND(TR, L, L, H); break; // LD L, (HL)
|
||||
case 0x6F: REG_OP(TR, L, A); break; // LD L, A
|
||||
case 0x70: LD_8_IND(L, H, B); break; // LD (HL), B
|
||||
case 0x71: LD_8_IND(L, H, C); break; // LD (HL), C
|
||||
case 0x72: LD_8_IND(L, H, D); break; // LD (HL), D
|
||||
case 0x73: LD_8_IND(L, H, E); break; // LD (HL), E
|
||||
case 0x74: LD_8_IND(L, H, H); break; // LD (HL), H
|
||||
case 0x75: LD_8_IND(L, H, L); break; // LD (HL), L
|
||||
case 0x76: HALT_(); break; // HALT
|
||||
case 0x77: LD_8_IND(L, H, A); break; // LD (HL), A
|
||||
case 0x78: REG_OP(TR, A, B); break; // LD A, B
|
||||
case 0x79: REG_OP(TR, A, C); break; // LD A, C
|
||||
case 0x7A: REG_OP(TR, A, D); break; // LD A, D
|
||||
case 0x7B: REG_OP(TR, A, E); break; // LD A, E
|
||||
case 0x7C: REG_OP(TR, A, H); break; // LD A, H
|
||||
case 0x7D: REG_OP(TR, A, L); break; // LD A, L
|
||||
case 0x7E: REG_OP_IND(TR, A, L, H); break; // LD A, (HL)
|
||||
case 0x7F: REG_OP(TR, A, A); break; // LD A, A
|
||||
case 0x80: REG_OP(ADD8, A, B); break; // ADD A, B
|
||||
case 0x81: REG_OP(ADD8, A, C); break; // ADD A, C
|
||||
case 0x82: REG_OP(ADD8, A, D); break; // ADD A, D
|
||||
case 0x83: REG_OP(ADD8, A, E); break; // ADD A, E
|
||||
case 0x84: REG_OP(ADD8, A, H); break; // ADD A, H
|
||||
case 0x85: REG_OP(ADD8, A, L); break; // ADD A, L
|
||||
case 0x86: REG_OP_IND(ADD8, A, L, H); break; // ADD A, (HL)
|
||||
case 0x87: REG_OP(ADD8, A, A); break; // ADD A, A
|
||||
case 0x88: REG_OP(ADC8, A, B); break; // ADC A, B
|
||||
case 0x89: REG_OP(ADC8, A, C); break; // ADC A, C
|
||||
case 0x8A: REG_OP(ADC8, A, D); break; // ADC A, D
|
||||
case 0x8B: REG_OP(ADC8, A, E); break; // ADC A, E
|
||||
case 0x8C: REG_OP(ADC8, A, H); break; // ADC A, H
|
||||
case 0x8D: REG_OP(ADC8, A, L); break; // ADC A, L
|
||||
case 0x8E: REG_OP_IND(ADC8, A, L, H); break; // ADC A, (HL)
|
||||
case 0x8F: REG_OP(ADC8, A, A); break; // ADC A, A
|
||||
case 0x90: REG_OP(SUB8, A, B); break; // SUB A, B
|
||||
case 0x91: REG_OP(SUB8, A, C); break; // SUB A, C
|
||||
case 0x92: REG_OP(SUB8, A, D); break; // SUB A, D
|
||||
case 0x93: REG_OP(SUB8, A, E); break; // SUB A, E
|
||||
case 0x94: REG_OP(SUB8, A, H); break; // SUB A, H
|
||||
case 0x95: REG_OP(SUB8, A, L); break; // SUB A, L
|
||||
case 0x96: REG_OP_IND(SUB8, A, L, H); break; // SUB A, (HL)
|
||||
case 0x97: REG_OP(SUB8, A, A); break; // SUB A, A
|
||||
case 0x98: REG_OP(SBC8, A, B); break; // SBC A, B
|
||||
case 0x99: REG_OP(SBC8, A, C); break; // SBC A, C
|
||||
case 0x9A: REG_OP(SBC8, A, D); break; // SBC A, D
|
||||
case 0x9B: REG_OP(SBC8, A, E); break; // SBC A, E
|
||||
case 0x9C: REG_OP(SBC8, A, H); break; // SBC A, H
|
||||
case 0x9D: REG_OP(SBC8, A, L); break; // SBC A, L
|
||||
case 0x9E: REG_OP_IND(SBC8, A, L, H); break; // SBC A, (HL)
|
||||
case 0x9F: REG_OP(SBC8, A, A); break; // SBC A, A
|
||||
case 0xA0: REG_OP(AND8, A, B); break; // AND A, B
|
||||
case 0xA1: REG_OP(AND8, A, C); break; // AND A, C
|
||||
case 0xA2: REG_OP(AND8, A, D); break; // AND A, D
|
||||
case 0xA3: REG_OP(AND8, A, E); break; // AND A, E
|
||||
case 0xA4: REG_OP(AND8, A, H); break; // AND A, H
|
||||
case 0xA5: REG_OP(AND8, A, L); break; // AND A, L
|
||||
case 0xA6: REG_OP_IND(AND8, A, L, H); break; // AND A, (HL)
|
||||
case 0xA7: REG_OP(AND8, A, A); break; // AND A, A
|
||||
case 0xA8: REG_OP(XOR8, A, B); break; // XOR A, B
|
||||
case 0xA9: REG_OP(XOR8, A, C); break; // XOR A, C
|
||||
case 0xAA: REG_OP(XOR8, A, D); break; // XOR A, D
|
||||
case 0xAB: REG_OP(XOR8, A, E); break; // XOR A, E
|
||||
case 0xAC: REG_OP(XOR8, A, H); break; // XOR A, H
|
||||
case 0xAD: REG_OP(XOR8, A, L); break; // XOR A, L
|
||||
case 0xAE: REG_OP_IND(XOR8, A, L, H); break; // XOR A, (HL)
|
||||
case 0xAF: REG_OP(XOR8, A, A); break; // XOR A, A
|
||||
case 0xB0: REG_OP(OR8, A, B); break; // OR A, B
|
||||
case 0xB1: REG_OP(OR8, A, C); break; // OR A, C
|
||||
case 0xB2: REG_OP(OR8, A, D); break; // OR A, D
|
||||
case 0xB3: REG_OP(OR8, A, E); break; // OR A, E
|
||||
case 0xB4: REG_OP(OR8, A, H); break; // OR A, H
|
||||
case 0xB5: REG_OP(OR8, A, L); break; // OR A, L
|
||||
case 0xB6: REG_OP_IND(OR8, A, L, H); break; // OR A, (HL)
|
||||
case 0xB7: REG_OP(OR8, A, A); break; // OR A, A
|
||||
case 0xB8: REG_OP(CP8, A, B); break; // CP A, B
|
||||
case 0xB9: REG_OP(CP8, A, C); break; // CP A, C
|
||||
case 0xBA: REG_OP(CP8, A, D); break; // CP A, D
|
||||
case 0xBB: REG_OP(CP8, A, E); break; // CP A, E
|
||||
case 0xBC: REG_OP(CP8, A, H); break; // CP A, H
|
||||
case 0xBD: REG_OP(CP8, A, L); break; // CP A, L
|
||||
case 0xBE: REG_OP_IND(CP8, A, L, H); break; // CP A, (HL)
|
||||
case 0xBF: REG_OP(CP8, A, A); break; // CP A, A
|
||||
case 0xC0: RET_COND(!FlagZ); break; // Ret NZ
|
||||
case 0xC1: POP_(C, B); break; // POP BC
|
||||
case 0xC2: JP_COND(!FlagZ); break; // JP NZ
|
||||
case 0xC3: JP_COND(true); break; // JP
|
||||
case 0xC4: CALL_COND(!FlagZ); break; // CALL NZ
|
||||
case 0xC5: PUSH_(C, B); break; // PUSH BC
|
||||
case 0xC6: REG_OP_IND_INC(ADD8, A, PCl, PCh); break; // ADD A, n
|
||||
case 0xC7: RST_(0); break; // RST 0
|
||||
case 0xC8: RET_COND(FlagZ); break; // RET Z
|
||||
case 0xC9: RET_(); break; // RET
|
||||
case 0xCA: JP_COND(FlagZ); break; // JP Z
|
||||
case 0xCB: PREFIX_(); break; // PREFIX
|
||||
case 0xCC: CALL_COND(FlagZ); break; // CALL Z
|
||||
case 0xCD: CALL_COND(true); break; // CALL
|
||||
case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n
|
||||
case 0xCF: RST_(0x08); break; // RST 0x08
|
||||
case 0xD0: RET_COND(!FlagC); break; // Ret NC
|
||||
case 0xD1: POP_(E, D); break; // POP DE
|
||||
case 0xD2: JP_COND(!FlagC); break; // JP NC
|
||||
case 0xD3: JAM_(); break; // JAM
|
||||
case 0xD4: CALL_COND(!FlagC); break; // CALL NC
|
||||
case 0xD5: PUSH_(E, D); break; // PUSH DE
|
||||
case 0xD6: REG_OP_IND_INC(SUB8, A, PCl, PCh); break; // SUB A, n
|
||||
case 0xD7: RST_(0x10); break; // RST 0x10
|
||||
case 0xD8: RET_COND(FlagC); break; // RET C
|
||||
case 0xD9: RETI_(); break; // RETI
|
||||
case 0xDA: JP_COND(FlagC); break; // JP C
|
||||
case 0xDB: JAM_(); break; // JAM
|
||||
case 0xDC: CALL_COND(FlagC); break; // CALL C
|
||||
case 0xDD: JAM_(); break; // JAM
|
||||
case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n
|
||||
case 0xDF: RST_(0x18); break; // RST 0x18
|
||||
case 0xE0: LD_FF_IND_8(PCl, PCh, A); break; // LD(n), A
|
||||
case 0xE1: POP_(L, H); break; // POP HL
|
||||
case 0xE2: LD_FFC_IND_8(PCl, PCh, A); break; // LD(C), A
|
||||
case 0xE3: JAM_(); break; // JAM
|
||||
case 0xE4: JAM_(); break; // JAM
|
||||
case 0xE5: PUSH_(L, H); break; // PUSH HL
|
||||
case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n
|
||||
case 0xE7: RST_(0x20); break; // RST 0x20
|
||||
case 0xE8: ADD_SP(); break; // ADD SP,n
|
||||
case 0xE9: JP_HL(); break; // JP (HL)
|
||||
case 0xEA: LD_FF_IND_16(PCl, PCh, A); break; // LD(nn), A
|
||||
case 0xEB: JAM_(); break; // JAM
|
||||
case 0xEC: JAM_(); break; // JAM
|
||||
case 0xED: JAM_(); break; // JAM
|
||||
case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n
|
||||
case 0xEF: RST_(0x28); break; // RST 0x28
|
||||
case 0xF0: LD_8_IND_FF(A, PCl, PCh); break; // A, LD(n)
|
||||
case 0xF1: POP_(F, A); break; // POP AF
|
||||
case 0xF2: LD_8_IND_FFC(A, PCl, PCh); break; // A, LD(C)
|
||||
case 0xF3: DI_(); break; // DI
|
||||
case 0xF4: JAM_(); break; // JAM
|
||||
case 0xF5: PUSH_(F, A); break; // PUSH AF
|
||||
case 0xF6: REG_OP_IND_INC(OR8, A, PCl, PCh); break; // OR A, n
|
||||
case 0xF7: RST_(0x30); break; // RST 0x30
|
||||
case 0xF8: LD_HL_SPn(); break; // LD HL, SP+n
|
||||
case 0xF9: LD_SP_HL(); break; // LD, SP, HL
|
||||
case 0xFA: LD_16_IND_FF(A, PCl, PCh); break; // A, LD(nn)
|
||||
case 0xFB: EI_(); break; // EI
|
||||
case 0xFC: JAM_(); break; // JAM
|
||||
case 0xFD: JAM_(); break; // JAM
|
||||
case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // XOR A, n
|
||||
case 0xFF: RST_(0x38); break; // RST 0x38
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CB_prefix = false;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00: INT_OP(RLC, B); break; // RLC B
|
||||
case 0x01: INT_OP(RLC, C); break; // RLC C
|
||||
case 0x02: INT_OP(RLC, D); break; // RLC D
|
||||
case 0x03: INT_OP(RLC, E); break; // RLC E
|
||||
case 0x04: INT_OP(RLC, H); break; // RLC H
|
||||
case 0x05: INT_OP(RLC, L); break; // RLC L
|
||||
case 0x06: INT_OP_IND(RLC, L, H); break; // RLC (HL)
|
||||
case 0x07: INT_OP(RLC, A); break; // RLC A
|
||||
case 0x08: INT_OP(RRC, B); break; // RRC B
|
||||
case 0x09: INT_OP(RRC, C); break; // RRC C
|
||||
case 0x0A: INT_OP(RRC, D); break; // RRC D
|
||||
case 0x0B: INT_OP(RRC, E); break; // RRC E
|
||||
case 0x0C: INT_OP(RRC, H); break; // RRC H
|
||||
case 0x0D: INT_OP(RRC, L); break; // RRC L
|
||||
case 0x0E: INT_OP_IND(RRC, L, H); break; // RRC (HL)
|
||||
case 0x0F: INT_OP(RRC, A); break; // RRC A
|
||||
case 0x10: INT_OP(RL, B); break; // RL B
|
||||
case 0x11: INT_OP(RL, C); break; // RL C
|
||||
case 0x12: INT_OP(RL, D); break; // RL D
|
||||
case 0x13: INT_OP(RL, E); break; // RL E
|
||||
case 0x14: INT_OP(RL, H); break; // RL H
|
||||
case 0x15: INT_OP(RL, L); break; // RL L
|
||||
case 0x16: INT_OP_IND(RL, L, H); break; // RL (HL)
|
||||
case 0x17: INT_OP(RL, A); break; // RL A
|
||||
case 0x18: INT_OP(RR, B); break; // RR B
|
||||
case 0x19: INT_OP(RR, C); break; // RR C
|
||||
case 0x1A: INT_OP(RR, D); break; // RR D
|
||||
case 0x1B: INT_OP(RR, E); break; // RR E
|
||||
case 0x1C: INT_OP(RR, H); break; // RR H
|
||||
case 0x1D: INT_OP(RR, L); break; // RR L
|
||||
case 0x1E: INT_OP_IND(RR, L, H); break; // RR (HL)
|
||||
case 0x1F: INT_OP(RR, A); break; // RR A
|
||||
case 0x20: INT_OP(SLA, B); break; // SLA B
|
||||
case 0x21: INT_OP(SLA, C); break; // SLA C
|
||||
case 0x22: INT_OP(SLA, D); break; // SLA D
|
||||
case 0x23: INT_OP(SLA, E); break; // SLA E
|
||||
case 0x24: INT_OP(SLA, H); break; // SLA H
|
||||
case 0x25: INT_OP(SLA, L); break; // SLA L
|
||||
case 0x26: INT_OP_IND(SLA, L, H); break; // SLA (HL)
|
||||
case 0x27: INT_OP(SLA, A); break; // SLA A
|
||||
case 0x28: INT_OP(SRA, B); break; // SRA B
|
||||
case 0x29: INT_OP(SRA, C); break; // SRA C
|
||||
case 0x2A: INT_OP(SRA, D); break; // SRA D
|
||||
case 0x2B: INT_OP(SRA, E); break; // SRA E
|
||||
case 0x2C: INT_OP(SRA, H); break; // SRA H
|
||||
case 0x2D: INT_OP(SRA, L); break; // SRA L
|
||||
case 0x2E: INT_OP_IND(SRA, L, H); break; // SRA (HL)
|
||||
case 0x2F: INT_OP(SRA, A); break; // SRA A
|
||||
case 0x30: INT_OP(SWAP, B); break; // SWAP B
|
||||
case 0x31: INT_OP(SWAP, C); break; // SWAP C
|
||||
case 0x32: INT_OP(SWAP, D); break; // SWAP D
|
||||
case 0x33: INT_OP(SWAP, E); break; // SWAP E
|
||||
case 0x34: INT_OP(SWAP, H); break; // SWAP H
|
||||
case 0x35: INT_OP(SWAP, L); break; // SWAP L
|
||||
case 0x36: INT_OP_IND(SWAP, L, H); break; // SWAP (HL)
|
||||
case 0x37: INT_OP(SWAP, A); break; // SWAP A
|
||||
case 0x38: INT_OP(SRL, B); break; // SRL B
|
||||
case 0x39: INT_OP(SRL, C); break; // SRL C
|
||||
case 0x3A: INT_OP(SRL, D); break; // SRL D
|
||||
case 0x3B: INT_OP(SRL, E); break; // SRL E
|
||||
case 0x3C: INT_OP(SRL, H); break; // SRL H
|
||||
case 0x3D: INT_OP(SRL, L); break; // SRL L
|
||||
case 0x3E: INT_OP_IND(SRL, L, H); break; // SRL (HL)
|
||||
case 0x3F: INT_OP(SRL, A); break; // SRL A
|
||||
case 0x40: BIT_OP(BIT, 0, B); break; // BIT 0, B
|
||||
case 0x41: BIT_OP(BIT, 0, C); break; // BIT 0, C
|
||||
case 0x42: BIT_OP(BIT, 0, D); break; // BIT 0, D
|
||||
case 0x43: BIT_OP(BIT, 0, E); break; // BIT 0, E
|
||||
case 0x44: BIT_OP(BIT, 0, H); break; // BIT 0, H
|
||||
case 0x45: BIT_OP(BIT, 0, L); break; // BIT 0, L
|
||||
case 0x46: BIT_TE_IND(BIT, 0, L, H); break; // BIT 0, (HL)
|
||||
case 0x47: BIT_OP(BIT, 0, A); break; // BIT 0, A
|
||||
case 0x48: BIT_OP(BIT, 1, B); break; // BIT 1, B
|
||||
case 0x49: BIT_OP(BIT, 1, C); break; // BIT 1, C
|
||||
case 0x4A: BIT_OP(BIT, 1, D); break; // BIT 1, D
|
||||
case 0x4B: BIT_OP(BIT, 1, E); break; // BIT 1, E
|
||||
case 0x4C: BIT_OP(BIT, 1, H); break; // BIT 1, H
|
||||
case 0x4D: BIT_OP(BIT, 1, L); break; // BIT 1, L
|
||||
case 0x4E: BIT_TE_IND(BIT, 1, L, H); break; // BIT 1, (HL)
|
||||
case 0x4F: BIT_OP(BIT, 1, A); break; // BIT 1, A
|
||||
case 0x50: BIT_OP(BIT, 2, B); break; // BIT 2, B
|
||||
case 0x51: BIT_OP(BIT, 2, C); break; // BIT 2, C
|
||||
case 0x52: BIT_OP(BIT, 2, D); break; // BIT 2, D
|
||||
case 0x53: BIT_OP(BIT, 2, E); break; // BIT 2, E
|
||||
case 0x54: BIT_OP(BIT, 2, H); break; // BIT 2, H
|
||||
case 0x55: BIT_OP(BIT, 2, L); break; // BIT 2, L
|
||||
case 0x56: BIT_TE_IND(BIT, 2, L, H); break; // BIT 2, (HL)
|
||||
case 0x57: BIT_OP(BIT, 2, A); break; // BIT 2, A
|
||||
case 0x58: BIT_OP(BIT, 3, B); break; // BIT 3, B
|
||||
case 0x59: BIT_OP(BIT, 3, C); break; // BIT 3, C
|
||||
case 0x5A: BIT_OP(BIT, 3, D); break; // BIT 3, D
|
||||
case 0x5B: BIT_OP(BIT, 3, E); break; // BIT 3, E
|
||||
case 0x5C: BIT_OP(BIT, 3, H); break; // BIT 3, H
|
||||
case 0x5D: BIT_OP(BIT, 3, L); break; // BIT 3, L
|
||||
case 0x5E: BIT_TE_IND(BIT, 3, L, H); break; // BIT 3, (HL)
|
||||
case 0x5F: BIT_OP(BIT, 3, A); break; // BIT 3, A
|
||||
case 0x60: BIT_OP(BIT, 4, B); break; // BIT 4, B
|
||||
case 0x61: BIT_OP(BIT, 4, C); break; // BIT 4, C
|
||||
case 0x62: BIT_OP(BIT, 4, D); break; // BIT 4, D
|
||||
case 0x63: BIT_OP(BIT, 4, E); break; // BIT 4, E
|
||||
case 0x64: BIT_OP(BIT, 4, H); break; // BIT 4, H
|
||||
case 0x65: BIT_OP(BIT, 4, L); break; // BIT 4, L
|
||||
case 0x66: BIT_TE_IND(BIT, 4, L, H); break; // BIT 4, (HL)
|
||||
case 0x67: BIT_OP(BIT, 4, A); break; // BIT 4, A
|
||||
case 0x68: BIT_OP(BIT, 5, B); break; // BIT 5, B
|
||||
case 0x69: BIT_OP(BIT, 5, C); break; // BIT 5, C
|
||||
case 0x6A: BIT_OP(BIT, 5, D); break; // BIT 5, D
|
||||
case 0x6B: BIT_OP(BIT, 5, E); break; // BIT 5, E
|
||||
case 0x6C: BIT_OP(BIT, 5, H); break; // BIT 5, H
|
||||
case 0x6D: BIT_OP(BIT, 5, L); break; // BIT 5, L
|
||||
case 0x6E: BIT_TE_IND(BIT, 5, L, H); break; // BIT 5, (HL)
|
||||
case 0x6F: BIT_OP(BIT, 5, A); break; // BIT 5, A
|
||||
case 0x70: BIT_OP(BIT, 6, B); break; // BIT 6, B
|
||||
case 0x71: BIT_OP(BIT, 6, C); break; // BIT 6, C
|
||||
case 0x72: BIT_OP(BIT, 6, D); break; // BIT 6, D
|
||||
case 0x73: BIT_OP(BIT, 6, E); break; // BIT 6, E
|
||||
case 0x74: BIT_OP(BIT, 6, H); break; // BIT 6, H
|
||||
case 0x75: BIT_OP(BIT, 6, L); break; // BIT 6, L
|
||||
case 0x76: BIT_TE_IND(BIT, 6, L, H); break; // BIT 6, (HL)
|
||||
case 0x77: BIT_OP(BIT, 6, A); break; // BIT 6, A
|
||||
case 0x78: BIT_OP(BIT, 7, B); break; // BIT 7, B
|
||||
case 0x79: BIT_OP(BIT, 7, C); break; // BIT 7, C
|
||||
case 0x7A: BIT_OP(BIT, 7, D); break; // BIT 7, D
|
||||
case 0x7B: BIT_OP(BIT, 7, E); break; // BIT 7, E
|
||||
case 0x7C: BIT_OP(BIT, 7, H); break; // BIT 7, H
|
||||
case 0x7D: BIT_OP(BIT, 7, L); break; // BIT 7, L
|
||||
case 0x7E: BIT_TE_IND(BIT, 7, L, H); break; // BIT 7, (HL)
|
||||
case 0x7F: BIT_OP(BIT, 7, A); break; // BIT 7, A
|
||||
case 0x80: BIT_OP(RES, 0, B); break; // RES 0, B
|
||||
case 0x81: BIT_OP(RES, 0, C); break; // RES 0, C
|
||||
case 0x82: BIT_OP(RES, 0, D); break; // RES 0, D
|
||||
case 0x83: BIT_OP(RES, 0, E); break; // RES 0, E
|
||||
case 0x84: BIT_OP(RES, 0, H); break; // RES 0, H
|
||||
case 0x85: BIT_OP(RES, 0, L); break; // RES 0, L
|
||||
case 0x86: BIT_OP_IND(RES, 0, L, H); break; // RES 0, (HL)
|
||||
case 0x87: BIT_OP(RES, 0, A); break; // RES 0, A
|
||||
case 0x88: BIT_OP(RES, 1, B); break; // RES 1, B
|
||||
case 0x89: BIT_OP(RES, 1, C); break; // RES 1, C
|
||||
case 0x8A: BIT_OP(RES, 1, D); break; // RES 1, D
|
||||
case 0x8B: BIT_OP(RES, 1, E); break; // RES 1, E
|
||||
case 0x8C: BIT_OP(RES, 1, H); break; // RES 1, H
|
||||
case 0x8D: BIT_OP(RES, 1, L); break; // RES 1, L
|
||||
case 0x8E: BIT_OP_IND(RES, 1, L, H); break; // RES 1, (HL)
|
||||
case 0x8F: BIT_OP(RES, 1, A); break; // RES 1, A
|
||||
case 0x90: BIT_OP(RES, 2, B); break; // RES 2, B
|
||||
case 0x91: BIT_OP(RES, 2, C); break; // RES 2, C
|
||||
case 0x92: BIT_OP(RES, 2, D); break; // RES 2, D
|
||||
case 0x93: BIT_OP(RES, 2, E); break; // RES 2, E
|
||||
case 0x94: BIT_OP(RES, 2, H); break; // RES 2, H
|
||||
case 0x95: BIT_OP(RES, 2, L); break; // RES 2, L
|
||||
case 0x96: BIT_OP_IND(RES, 2, L, H); break; // RES 2, (HL)
|
||||
case 0x97: BIT_OP(RES, 2, A); break; // RES 2, A
|
||||
case 0x98: BIT_OP(RES, 3, B); break; // RES 3, B
|
||||
case 0x99: BIT_OP(RES, 3, C); break; // RES 3, C
|
||||
case 0x9A: BIT_OP(RES, 3, D); break; // RES 3, D
|
||||
case 0x9B: BIT_OP(RES, 3, E); break; // RES 3, E
|
||||
case 0x9C: BIT_OP(RES, 3, H); break; // RES 3, H
|
||||
case 0x9D: BIT_OP(RES, 3, L); break; // RES 3, L
|
||||
case 0x9E: BIT_OP_IND(RES, 3, L, H); break; // RES 3, (HL)
|
||||
case 0x9F: BIT_OP(RES, 3, A); break; // RES 3, A
|
||||
case 0xA0: BIT_OP(RES, 4, B); break; // RES 4, B
|
||||
case 0xA1: BIT_OP(RES, 4, C); break; // RES 4, C
|
||||
case 0xA2: BIT_OP(RES, 4, D); break; // RES 4, D
|
||||
case 0xA3: BIT_OP(RES, 4, E); break; // RES 4, E
|
||||
case 0xA4: BIT_OP(RES, 4, H); break; // RES 4, H
|
||||
case 0xA5: BIT_OP(RES, 4, L); break; // RES 4, L
|
||||
case 0xA6: BIT_OP_IND(RES, 4, L, H); break; // RES 4, (HL)
|
||||
case 0xA7: BIT_OP(RES, 4, A); break; // RES 4, A
|
||||
case 0xA8: BIT_OP(RES, 5, B); break; // RES 5, B
|
||||
case 0xA9: BIT_OP(RES, 5, C); break; // RES 5, C
|
||||
case 0xAA: BIT_OP(RES, 5, D); break; // RES 5, D
|
||||
case 0xAB: BIT_OP(RES, 5, E); break; // RES 5, E
|
||||
case 0xAC: BIT_OP(RES, 5, H); break; // RES 5, H
|
||||
case 0xAD: BIT_OP(RES, 5, L); break; // RES 5, L
|
||||
case 0xAE: BIT_OP_IND(RES, 5, L, H); break; // RES 5, (HL)
|
||||
case 0xAF: BIT_OP(RES, 5, A); break; // RES 5, A
|
||||
case 0xB0: BIT_OP(RES, 6, B); break; // RES 6, B
|
||||
case 0xB1: BIT_OP(RES, 6, C); break; // RES 6, C
|
||||
case 0xB2: BIT_OP(RES, 6, D); break; // RES 6, D
|
||||
case 0xB3: BIT_OP(RES, 6, E); break; // RES 6, E
|
||||
case 0xB4: BIT_OP(RES, 6, H); break; // RES 6, H
|
||||
case 0xB5: BIT_OP(RES, 6, L); break; // RES 6, L
|
||||
case 0xB6: BIT_OP_IND(RES, 6, L, H); break; // RES 6, (HL)
|
||||
case 0xB7: BIT_OP(RES, 6, A); break; // RES 6, A
|
||||
case 0xB8: BIT_OP(RES, 7, B); break; // RES 7, B
|
||||
case 0xB9: BIT_OP(RES, 7, C); break; // RES 7, C
|
||||
case 0xBA: BIT_OP(RES, 7, D); break; // RES 7, D
|
||||
case 0xBB: BIT_OP(RES, 7, E); break; // RES 7, E
|
||||
case 0xBC: BIT_OP(RES, 7, H); break; // RES 7, H
|
||||
case 0xBD: BIT_OP(RES, 7, L); break; // RES 7, L
|
||||
case 0xBE: BIT_OP_IND(RES, 7, L, H); break; // RES 7, (HL)
|
||||
case 0xBF: BIT_OP(RES, 7, A); break; // RES 7, A
|
||||
case 0xC0: BIT_OP(SET, 0, B); break; // SET 0, B
|
||||
case 0xC1: BIT_OP(SET, 0, C); break; // SET 0, C
|
||||
case 0xC2: BIT_OP(SET, 0, D); break; // SET 0, D
|
||||
case 0xC3: BIT_OP(SET, 0, E); break; // SET 0, E
|
||||
case 0xC4: BIT_OP(SET, 0, H); break; // SET 0, H
|
||||
case 0xC5: BIT_OP(SET, 0, L); break; // SET 0, L
|
||||
case 0xC6: BIT_OP_IND(SET, 0, L, H); break; // SET 0, (HL)
|
||||
case 0xC7: BIT_OP(SET, 0, A); break; // SET 0, A
|
||||
case 0xC8: BIT_OP(SET, 1, B); break; // SET 1, B
|
||||
case 0xC9: BIT_OP(SET, 1, C); break; // SET 1, C
|
||||
case 0xCA: BIT_OP(SET, 1, D); break; // SET 1, D
|
||||
case 0xCB: BIT_OP(SET, 1, E); break; // SET 1, E
|
||||
case 0xCC: BIT_OP(SET, 1, H); break; // SET 1, H
|
||||
case 0xCD: BIT_OP(SET, 1, L); break; // SET 1, L
|
||||
case 0xCE: BIT_OP_IND(SET, 1, L, H); break; // SET 1, (HL)
|
||||
case 0xCF: BIT_OP(SET, 1, A); break; // SET 1, A
|
||||
case 0xD0: BIT_OP(SET, 2, B); break; // SET 2, B
|
||||
case 0xD1: BIT_OP(SET, 2, C); break; // SET 2, C
|
||||
case 0xD2: BIT_OP(SET, 2, D); break; // SET 2, D
|
||||
case 0xD3: BIT_OP(SET, 2, E); break; // SET 2, E
|
||||
case 0xD4: BIT_OP(SET, 2, H); break; // SET 2, H
|
||||
case 0xD5: BIT_OP(SET, 2, L); break; // SET 2, L
|
||||
case 0xD6: BIT_OP_IND(SET, 2, L, H); break; // SET 2, (HL)
|
||||
case 0xD7: BIT_OP(SET, 2, A); break; // SET 2, A
|
||||
case 0xD8: BIT_OP(SET, 3, B); break; // SET 3, B
|
||||
case 0xD9: BIT_OP(SET, 3, C); break; // SET 3, C
|
||||
case 0xDA: BIT_OP(SET, 3, D); break; // SET 3, D
|
||||
case 0xDB: BIT_OP(SET, 3, E); break; // SET 3, E
|
||||
case 0xDC: BIT_OP(SET, 3, H); break; // SET 3, H
|
||||
case 0xDD: BIT_OP(SET, 3, L); break; // SET 3, L
|
||||
case 0xDE: BIT_OP_IND(SET, 3, L, H); break; // SET 3, (HL)
|
||||
case 0xDF: BIT_OP(SET, 3, A); break; // SET 3, A
|
||||
case 0xE0: BIT_OP(SET, 4, B); break; // SET 4, B
|
||||
case 0xE1: BIT_OP(SET, 4, C); break; // SET 4, C
|
||||
case 0xE2: BIT_OP(SET, 4, D); break; // SET 4, D
|
||||
case 0xE3: BIT_OP(SET, 4, E); break; // SET 4, E
|
||||
case 0xE4: BIT_OP(SET, 4, H); break; // SET 4, H
|
||||
case 0xE5: BIT_OP(SET, 4, L); break; // SET 4, L
|
||||
case 0xE6: BIT_OP_IND(SET, 4, L, H); break; // SET 4, (HL)
|
||||
case 0xE7: BIT_OP(SET, 4, A); break; // SET 4, A
|
||||
case 0xE8: BIT_OP(SET, 5, B); break; // SET 5, B
|
||||
case 0xE9: BIT_OP(SET, 5, C); break; // SET 5, C
|
||||
case 0xEA: BIT_OP(SET, 5, D); break; // SET 5, D
|
||||
case 0xEB: BIT_OP(SET, 5, E); break; // SET 5, E
|
||||
case 0xEC: BIT_OP(SET, 5, H); break; // SET 5, H
|
||||
case 0xED: BIT_OP(SET, 5, L); break; // SET 5, L
|
||||
case 0xEE: BIT_OP_IND(SET, 5, L, H); break; // SET 5, (HL)
|
||||
case 0xEF: BIT_OP(SET, 5, A); break; // SET 5, A
|
||||
case 0xF0: BIT_OP(SET, 6, B); break; // SET 6, B
|
||||
case 0xF1: BIT_OP(SET, 6, C); break; // SET 6, C
|
||||
case 0xF2: BIT_OP(SET, 6, D); break; // SET 6, D
|
||||
case 0xF3: BIT_OP(SET, 6, E); break; // SET 6, E
|
||||
case 0xF4: BIT_OP(SET, 6, H); break; // SET 6, H
|
||||
case 0xF5: BIT_OP(SET, 6, L); break; // SET 6, L
|
||||
case 0xF6: BIT_OP_IND(SET, 6, L, H); break; // SET 6, (HL)
|
||||
case 0xF7: BIT_OP(SET, 6, A); break; // SET 6, A
|
||||
case 0xF8: BIT_OP(SET, 7, B); break; // SET 7, B
|
||||
case 0xF9: BIT_OP(SET, 7, C); break; // SET 7, C
|
||||
case 0xFA: BIT_OP(SET, 7, D); break; // SET 7, D
|
||||
case 0xFB: BIT_OP(SET, 7, E); break; // SET 7, E
|
||||
case 0xFC: BIT_OP(SET, 7, H); break; // SET 7, H
|
||||
case 0xFD: BIT_OP(SET, 7, L); break; // SET 7, L
|
||||
case 0xFE: BIT_OP_IND(SET, 7, L, H); break; // SET 7, (HL)
|
||||
case 0xFF: BIT_OP(SET, 7, A); break; // SET 7, A
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.Z80GB
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public partial class Z80
|
||||
public partial class LR35902
|
||||
{
|
||||
private bool iff1;
|
||||
public bool IFF1 { get { return iff1; } set { iff1 = value; } }
|
||||
|
@ -10,9 +10,6 @@ namespace BizHawk.Emulation.Common.Components.Z80GB
|
|||
private bool iff2;
|
||||
public bool IFF2 { get { return iff2; } set { iff2 = value; } }
|
||||
|
||||
private bool interrupt;
|
||||
public bool Interrupt { get { return interrupt; } set { interrupt = value; } }
|
||||
|
||||
private bool nonMaskableInterrupt;
|
||||
public bool NonMaskableInterrupt
|
||||
{
|
||||
|
@ -30,23 +27,42 @@ namespace BizHawk.Emulation.Common.Components.Z80GB
|
|||
set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; }
|
||||
}
|
||||
|
||||
private bool halted;
|
||||
public bool Halted { get { return halted; } set { halted = value; } }
|
||||
private void INTERRUPT_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
INT_GET, W,// NOTE: here is where we check for a cancelled IRQ
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR, PCl, W,
|
||||
ASGN, PCh, 0,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60, 0x00};
|
||||
|
||||
public ushort int_src;
|
||||
|
||||
private void ResetInterrupts()
|
||||
{
|
||||
IFF1 = false;
|
||||
IFF2 = false;
|
||||
Interrupt = false;
|
||||
NonMaskableInterrupt = false;
|
||||
NonMaskableInterruptPending = false;
|
||||
InterruptMode = 1;
|
||||
Halted = false;
|
||||
}
|
||||
|
||||
private void Halt()
|
||||
{
|
||||
Halted = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,503 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
// GameBoy CPU (Sharp LR35902)
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public sealed partial class LR35902
|
||||
{
|
||||
// operations that can take place in an instruction
|
||||
public const ushort IDLE = 0;
|
||||
public const ushort OP = 1;
|
||||
public const ushort RD = 2;
|
||||
public const ushort WR = 3;
|
||||
public const ushort TR = 4;
|
||||
public const ushort ADD16 = 5;
|
||||
public const ushort ADD8 = 6;
|
||||
public const ushort SUB8 = 7;
|
||||
public const ushort ADC8 = 8;
|
||||
public const ushort SBC8 = 9;
|
||||
public const ushort INC16 = 10;
|
||||
public const ushort INC8 = 11;
|
||||
public const ushort DEC16 = 12;
|
||||
public const ushort DEC8 = 13;
|
||||
public const ushort RLC = 14;
|
||||
public const ushort RL = 15;
|
||||
public const ushort RRC = 16;
|
||||
public const ushort RR = 17;
|
||||
public const ushort CPL = 18;
|
||||
public const ushort DA = 19;
|
||||
public const ushort SCF = 20;
|
||||
public const ushort CCF = 21;
|
||||
public const ushort AND8 = 22;
|
||||
public const ushort XOR8 = 23;
|
||||
public const ushort OR8 = 24;
|
||||
public const ushort CP8 = 25;
|
||||
public const ushort SLA = 26;
|
||||
public const ushort SRA = 27;
|
||||
public const ushort SRL = 28;
|
||||
public const ushort SWAP = 29;
|
||||
public const ushort BIT = 30;
|
||||
public const ushort RES = 31;
|
||||
public const ushort SET = 32;
|
||||
public const ushort EI = 33;
|
||||
public const ushort DI = 34;
|
||||
public const ushort HALT = 35;
|
||||
public const ushort STOP = 36;
|
||||
public const ushort PREFIX = 37;
|
||||
public const ushort ASGN = 38;
|
||||
public const ushort ADDS = 39; // signed 16 bit operation used in 2 instructions
|
||||
public const ushort OP_G = 40; // glitchy opcode read performed by halt when interrupts disabled
|
||||
public const ushort JAM = 41; // all undocumented opcodes jam the machine
|
||||
public const ushort RD_F = 42; // special read case to pop value into F
|
||||
public const ushort EI_RETI = 43; // reti has no delay in interrupt enable
|
||||
public const ushort INT_GET = 44;
|
||||
|
||||
public LR35902()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
TotalExecutedCycles = 0;
|
||||
cur_instr = new ushort[] { OP };
|
||||
}
|
||||
|
||||
// Memory Access
|
||||
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
public Action<ushort, byte> WriteMemory;
|
||||
public Func<ushort, byte> PeekMemory;
|
||||
public Func<ushort, byte> DummyReadMemory;
|
||||
|
||||
//this only calls when the first byte of an instruction is fetched.
|
||||
public Action<ushort> OnExecFetch;
|
||||
|
||||
public void UnregisterMemoryMapper()
|
||||
{
|
||||
ReadMemory = null;
|
||||
ReadMemory = null;
|
||||
PeekMemory = null;
|
||||
DummyReadMemory = null;
|
||||
}
|
||||
|
||||
public void SetCallbacks
|
||||
(
|
||||
Func<ushort, byte> ReadMemory,
|
||||
Func<ushort, byte> DummyReadMemory,
|
||||
Func<ushort, byte> PeekMemory,
|
||||
Action<ushort, byte> WriteMemory
|
||||
)
|
||||
{
|
||||
this.ReadMemory = ReadMemory;
|
||||
this.DummyReadMemory = DummyReadMemory;
|
||||
this.PeekMemory = PeekMemory;
|
||||
this.WriteMemory = WriteMemory;
|
||||
}
|
||||
|
||||
// Execute instructions
|
||||
public void ExecuteOne(ref byte interrupt_src, byte interrupt_enable)
|
||||
{
|
||||
switch (cur_instr[instr_pntr++])
|
||||
{
|
||||
case IDLE:
|
||||
// do nothing
|
||||
break;
|
||||
case OP:
|
||||
// Read the opcode of the next instruction
|
||||
if (EI_pending > 0 && !CB_prefix)
|
||||
{
|
||||
EI_pending--;
|
||||
if (EI_pending == 0)
|
||||
{
|
||||
interrupts_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (FlagI && interrupts_enabled && !CB_prefix && !jammed)
|
||||
{
|
||||
interrupts_enabled = false;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo
|
||||
{
|
||||
Disassembly = "====IRQ====",
|
||||
RegisterInfo = ""
|
||||
});
|
||||
}
|
||||
|
||||
// call interrupt processor
|
||||
// lowest bit set is highest priority
|
||||
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; }
|
||||
else { /*Console.WriteLine("No source"); }*/ throw new Exception("Interrupt without Source"); }
|
||||
|
||||
|
||||
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
|
||||
|
||||
INTERRUPT_();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
}
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case RD:
|
||||
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case WR:
|
||||
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case TR:
|
||||
TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADD16:
|
||||
ADD16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADD8:
|
||||
ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SUB8:
|
||||
SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADC8:
|
||||
ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SBC8:
|
||||
SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INC16:
|
||||
INC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INC8:
|
||||
INC8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DEC16:
|
||||
DEC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DEC8:
|
||||
DEC8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RLC:
|
||||
RLC_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RL:
|
||||
RL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RRC:
|
||||
RRC_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RR:
|
||||
RR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CPL:
|
||||
CPL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DA:
|
||||
DA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SCF:
|
||||
SCF_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CCF:
|
||||
CCF_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case AND8:
|
||||
AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case XOR8:
|
||||
XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case OR8:
|
||||
OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CP8:
|
||||
CP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SLA:
|
||||
SLA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SRA:
|
||||
SRA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SRL:
|
||||
SRL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SWAP:
|
||||
SWAP_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case BIT:
|
||||
BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RES:
|
||||
RES_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SET:
|
||||
SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case EI:
|
||||
EI_pending = 2;
|
||||
break;
|
||||
case DI:
|
||||
interrupts_enabled = false;
|
||||
EI_pending = 0;
|
||||
break;
|
||||
case HALT:
|
||||
halted = true;
|
||||
|
||||
if (EI_pending > 0 && !CB_prefix)
|
||||
{
|
||||
EI_pending--;
|
||||
if (EI_pending == 0)
|
||||
{
|
||||
interrupts_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if the I flag is asserted at the time of halt, don't halt
|
||||
|
||||
if (FlagI && interrupts_enabled && !CB_prefix && !jammed)
|
||||
{
|
||||
interrupts_enabled = false;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo
|
||||
{
|
||||
Disassembly = "====IRQ====",
|
||||
RegisterInfo = ""
|
||||
});
|
||||
}
|
||||
halted = false;
|
||||
// call interrupt processor
|
||||
instr_pntr = 0;
|
||||
// lowest bit set is highest priority
|
||||
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; }
|
||||
else { /*Console.WriteLine("No source"); } */throw new Exception("Interrupt without Source"); }
|
||||
|
||||
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
|
||||
|
||||
INTERRUPT_();
|
||||
}
|
||||
else if (FlagI)
|
||||
{
|
||||
// even if interrupt servicing is disabled, any interrupt flag raised still resumes execution
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo
|
||||
{
|
||||
Disassembly = "====un-halted====",
|
||||
RegisterInfo = ""
|
||||
});
|
||||
}
|
||||
halted = false;
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
instr_pntr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
instr_pntr = 0;
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
}
|
||||
break;
|
||||
case STOP:
|
||||
stopped = true;
|
||||
|
||||
if (interrupt_src.Bit(4)) // button pressed, not actually an interrupt though
|
||||
{
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo
|
||||
{
|
||||
Disassembly = "====un-stop====",
|
||||
RegisterInfo = ""
|
||||
});
|
||||
}
|
||||
|
||||
stopped = false;
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
instr_pntr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
instr_pntr = 0;
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
STOP };
|
||||
}
|
||||
break;
|
||||
case PREFIX:
|
||||
CB_prefix = true;
|
||||
break;
|
||||
case ASGN:
|
||||
ASGN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADDS:
|
||||
ADDS_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case OP_G:
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null) TraceCallback(State());
|
||||
|
||||
FetchInstruction(ReadMemory(RegPC)); // note no increment
|
||||
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case JAM:
|
||||
jammed = true;
|
||||
instr_pntr--;
|
||||
break;
|
||||
case RD_F:
|
||||
Read_Func_F(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case EI_RETI:
|
||||
EI_pending = 1;
|
||||
break;
|
||||
case INT_GET:
|
||||
// check if any interrupts got cancelled along the way
|
||||
// interrupt src = 5 sets the PC to zero as observed
|
||||
if (int_src == 0)
|
||||
{
|
||||
if (interrupt_enable.Bit(0)) { interrupt_src -= 1; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 1)
|
||||
{
|
||||
if (interrupt_enable.Bit(1)) { interrupt_src -= 2; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 2)
|
||||
{
|
||||
if (interrupt_enable.Bit(2)) { interrupt_src -= 4; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 3)
|
||||
{
|
||||
if (interrupt_enable.Bit(3)) { interrupt_src -= 8; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
if (int_src == 4)
|
||||
{
|
||||
if (interrupt_enable.Bit(4)) { interrupt_src -= 16; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
|
||||
// if we lost the interrupt, find the next highest interrupt, if any
|
||||
if (int_src == 5)
|
||||
{
|
||||
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; interrupt_src -= 1; }
|
||||
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; interrupt_src -= 2; }
|
||||
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; interrupt_src -= 4; }
|
||||
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; interrupt_src -= 8; }
|
||||
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; interrupt_src -= 16; }
|
||||
else { int_src = 5; }
|
||||
}
|
||||
|
||||
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
|
||||
|
||||
Regs[cur_instr[instr_pntr++]] = INT_vectors[int_src];
|
||||
break;
|
||||
}
|
||||
totalExecutedCycles++;
|
||||
}
|
||||
|
||||
// tracer stuff
|
||||
|
||||
public Action<TraceInfo> TraceCallback;
|
||||
|
||||
public string TraceHeader
|
||||
{
|
||||
get { return "LR35902: PC, machine code, mnemonic, operands, registers (A, F, B, C, D, E, H, L, SP), Cy, flags (ZNHCI)"; }
|
||||
}
|
||||
|
||||
public TraceInfo State(bool disassemble = true)
|
||||
{
|
||||
ushort notused;
|
||||
|
||||
return new TraceInfo
|
||||
{
|
||||
Disassembly = string.Format(
|
||||
"{0} ",
|
||||
disassemble ? Disassemble(RegPC, ReadMemory, out notused) : "---").PadRight(40),
|
||||
RegisterInfo = string.Format(
|
||||
"A:{0:X2} F:{1:X2} B:{2:X2} C:{3:X2} D:{4:X2} E:{5:X2} H:{6:X2} L:{7:X2} SP:{8:X2} Cy:{9} LY:{10} {11}{12}{13}{14}{15}{16}",
|
||||
Regs[A],
|
||||
Regs[F],
|
||||
Regs[B],
|
||||
Regs[C],
|
||||
Regs[D],
|
||||
Regs[E],
|
||||
Regs[H],
|
||||
Regs[L],
|
||||
Regs[SPl] | (Regs[SPh] << 8),
|
||||
TotalExecutedCycles,
|
||||
LY,
|
||||
FlagZ ? "Z" : "z",
|
||||
FlagN ? "N" : "n",
|
||||
FlagH ? "H" : "h",
|
||||
FlagC ? "C" : "c",
|
||||
FlagI ? "I" : "i",
|
||||
interrupts_enabled ? "E" : "e")
|
||||
};
|
||||
}
|
||||
// State Save/Load
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("LR35902");
|
||||
ser.Sync("Regs", ref Regs, false);
|
||||
ser.Sync("IRQ", ref interrupts_enabled);
|
||||
ser.Sync("NMI", ref nonMaskableInterrupt);
|
||||
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
|
||||
ser.Sync("IM", ref interruptMode);
|
||||
ser.Sync("IFF1", ref iff1);
|
||||
ser.Sync("IFF2", ref iff2);
|
||||
ser.Sync("Halted", ref halted);
|
||||
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
|
||||
ser.Sync("EI_pending", ref EI_pending);
|
||||
ser.Sync("int_src", ref int_src);
|
||||
|
||||
ser.Sync("instruction_pointer", ref instr_pntr);
|
||||
ser.Sync("current instruction", ref cur_instr, false);
|
||||
ser.Sync("CB Preifx", ref CB_prefix);
|
||||
ser.Sync("Stopped", ref stopped);
|
||||
ser.Sync("opcode", ref opcode);
|
||||
ser.Sync("jammped", ref jammed);
|
||||
ser.Sync("LY", ref LY);
|
||||
ser.Sync("FlagI", ref FlagI);
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.Z80GB
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
// adapted from the information at http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
|
||||
public class NewDisassembler
|
||||
public sealed partial class LR35902
|
||||
{
|
||||
static string[] table =
|
||||
{
|
|
@ -0,0 +1,467 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public partial class LR35902
|
||||
{
|
||||
public void Read_Func(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
|
||||
}
|
||||
|
||||
// speical read for POP AF that always clears the lower 4 bits of F
|
||||
public void Read_Func_F(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
Regs[dest] = (ushort)(ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0);
|
||||
}
|
||||
|
||||
public void Write_Func(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h]) << 8), (byte)Regs[src]);
|
||||
}
|
||||
|
||||
public void TR_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = Regs[src];
|
||||
}
|
||||
|
||||
public void ADD16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
|
||||
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
|
||||
|
||||
Reg16_d += Reg16_s;
|
||||
|
||||
FlagC = Reg16_d.Bit(16);
|
||||
|
||||
ushort ans_l = (ushort)(Reg16_d & 0xFF);
|
||||
ushort ans_h = (ushort)((Reg16_d & 0xFF00) >> 8);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest_l] | ((Regs[dest_h] & 0x0F) << 8);
|
||||
Reg16_s = Regs[src_l] | ((Regs[src_h] & 0x0F) << 8);
|
||||
|
||||
Reg16_d += Reg16_s;
|
||||
|
||||
FlagH = Reg16_d.Bit(12);
|
||||
FlagN = false;
|
||||
|
||||
Regs[dest_l] = ans_l;
|
||||
Regs[dest_h] = ans_h;
|
||||
}
|
||||
|
||||
public void ADD8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d += Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d += (Regs[src] & 0xF);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
|
||||
FlagN = false;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void SUB8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void BIT_Func(ushort bit, ushort src)
|
||||
{
|
||||
FlagZ = !Regs[src].Bit(bit);
|
||||
FlagH = true;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SET_Func(ushort bit, ushort src)
|
||||
{
|
||||
Regs[src] |= (ushort)(1 << bit);
|
||||
}
|
||||
|
||||
public void RES_Func(ushort bit, ushort src)
|
||||
{
|
||||
Regs[src] &= (ushort)(0xFF - (1 << bit));
|
||||
}
|
||||
|
||||
public void ASGN_Func(ushort src, ushort val)
|
||||
{
|
||||
Regs[src] = val;
|
||||
}
|
||||
|
||||
public void SWAP_Func(ushort src)
|
||||
{
|
||||
ushort temp = (ushort)((Regs[src] << 4) & 0xF0);
|
||||
Regs[src] = (ushort)(temp | (Regs[src] >> 4));
|
||||
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
FlagC = false;
|
||||
}
|
||||
|
||||
public void SLA_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)((Regs[src] << 1) & 0xFF);
|
||||
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SRA_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation
|
||||
|
||||
Regs[src] = (ushort)((Regs[src] >> 1) | temp);
|
||||
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SRL_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(0) ? true : false;
|
||||
|
||||
Regs[src] = (ushort)(Regs[src] >> 1);
|
||||
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void CPL_Func(ushort src)
|
||||
{
|
||||
Regs[src] = (ushort)((~Regs[src]) & 0xFF);
|
||||
|
||||
FlagH = true;
|
||||
FlagN = true;
|
||||
}
|
||||
|
||||
public void CCF_Func(ushort src)
|
||||
{
|
||||
FlagC = !FlagC;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SCF_Func(ushort src)
|
||||
{
|
||||
FlagC = true;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void AND8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] & Regs[src]);
|
||||
|
||||
FlagZ = Regs[dest] == 0;
|
||||
FlagC = false;
|
||||
FlagH = true;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void OR8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] | Regs[src]);
|
||||
|
||||
FlagZ = Regs[dest] == 0;
|
||||
FlagC = false;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void XOR8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] ^ Regs[src]);
|
||||
|
||||
FlagZ = Regs[dest] == 0;
|
||||
FlagC = false;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void CP8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
|
||||
FlagN = true;
|
||||
}
|
||||
|
||||
public void RRC_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)((FlagC ? 0x80 : 0) | (Regs[src] >> 1));
|
||||
|
||||
FlagZ = imm ? false : (Regs[src] == 0);
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void RR_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
ushort c = (ushort)(FlagC ? 0x80 : 0);
|
||||
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)(c | (Regs[src] >> 1));
|
||||
|
||||
FlagZ = imm ? false : (Regs[src] == 0);
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void RLC_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
ushort c = (ushort)(Regs[src].Bit(7) ? 1 : 0);
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
|
||||
|
||||
FlagZ = imm ? false : (Regs[src] == 0);
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void RL_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
ushort c = (ushort)(FlagC ? 1 : 0);
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
|
||||
|
||||
FlagZ = imm ? false : (Regs[src] == 0);
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void INC8_Func(ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[src];
|
||||
Reg16_d += 1;
|
||||
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[src] & 0xF;
|
||||
Reg16_d += 1;
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = false;
|
||||
|
||||
Regs[src] = ans;
|
||||
}
|
||||
|
||||
public void DEC8_Func(ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[src];
|
||||
Reg16_d -= 1;
|
||||
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[src] & 0xF;
|
||||
Reg16_d -= 1;
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
|
||||
Regs[src] = ans;
|
||||
}
|
||||
|
||||
public void INC16_Func(ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
|
||||
|
||||
Reg16_d += 1;
|
||||
|
||||
Regs[src_l] = (ushort)(Reg16_d & 0xFF);
|
||||
Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
public void DEC16_Func(ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
|
||||
|
||||
Reg16_d -= 1;
|
||||
|
||||
Regs[src_l] = (ushort)(Reg16_d & 0xFF);
|
||||
Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
public void ADC8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
int c = FlagC ? 1 : 0;
|
||||
|
||||
Reg16_d += (Regs[src] + c);
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d += ((Regs[src] & 0xF) + c);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = false;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void SBC8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
int c = FlagC ? 1 : 0;
|
||||
|
||||
Reg16_d -= (Regs[src] + c);
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= ((Regs[src] & 0xF) + c);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
// DA code courtesy of AWJ: http://forums.nesdev.com/viewtopic.php?f=20&t=15944
|
||||
public void DA_Func(ushort src)
|
||||
{
|
||||
byte a = (byte)Regs[src];
|
||||
|
||||
if (!FlagN)
|
||||
{ // after an addition, adjust if (half-)carry occurred or if result is out of bounds
|
||||
if (FlagC || a > 0x99) { a += 0x60; FlagC = true; }
|
||||
if (FlagH || (a & 0x0f) > 0x09) { a += 0x6; }
|
||||
}
|
||||
else
|
||||
{ // after a subtraction, only adjust if (half-)carry occurred
|
||||
if (FlagC) { a -= 0x60; }
|
||||
if (FlagH) { a -= 0x6; }
|
||||
}
|
||||
|
||||
a &= 0xFF;
|
||||
|
||||
Regs[src] = a;
|
||||
|
||||
FlagZ = a == 0;
|
||||
FlagH = false;
|
||||
}
|
||||
|
||||
// used for signed operations
|
||||
public void ADDS_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[dest_l];
|
||||
int Reg16_s = Regs[src_l];
|
||||
|
||||
Reg16_d += Reg16_s;
|
||||
|
||||
ushort temp = 0;
|
||||
|
||||
// since this is signed addition, calculate the high byte carry appropriately
|
||||
if (Reg16_s.Bit(7))
|
||||
{
|
||||
if (((Reg16_d & 0xFF) >= Regs[dest_l]))
|
||||
{
|
||||
temp = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = (ushort)(Reg16_d.Bit(8) ? 1 : 0);
|
||||
}
|
||||
|
||||
ushort ans_l = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// JR operations do not effect flags
|
||||
if (dest_l != PCl)
|
||||
{
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest_l] & 0xF;
|
||||
Reg16_d += Regs[src_l] & 0xF;
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = false;
|
||||
FlagZ = false;
|
||||
}
|
||||
|
||||
Regs[dest_l] = ans_l;
|
||||
Regs[dest_h] += temp;
|
||||
Regs[dest_h] &= 0xFF;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TODO: STOP for second byte nonzero
|
|
@ -0,0 +1,73 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public partial class LR35902
|
||||
{
|
||||
// registers
|
||||
|
||||
public static ushort PCl = 0;
|
||||
public static ushort PCh = 1;
|
||||
public static ushort SPl = 2;
|
||||
public static ushort SPh = 3;
|
||||
public static ushort A = 4;
|
||||
public static ushort F = 5;
|
||||
public static ushort B = 6;
|
||||
public static ushort C = 7;
|
||||
public static ushort D = 8;
|
||||
public static ushort E = 9;
|
||||
public static ushort H = 10;
|
||||
public static ushort L = 11;
|
||||
public static ushort W = 12;
|
||||
public static ushort Z = 13;
|
||||
public static ushort Aim = 14; // use this indicator for RLCA etc., since the Z flag is reset on those
|
||||
|
||||
public ushort[] Regs = new ushort[14];
|
||||
|
||||
public bool FlagI;
|
||||
|
||||
public bool FlagC
|
||||
{
|
||||
get { return (Regs[5] & 0x10) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagH
|
||||
{
|
||||
get { return (Regs[5] & 0x20) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagN
|
||||
{
|
||||
get { return (Regs[5] & 0x40) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagZ
|
||||
{
|
||||
get { return (Regs[5] & 0x80) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); }
|
||||
}
|
||||
|
||||
public ushort RegPC
|
||||
{
|
||||
get { return (ushort)(Regs[0] | (Regs[1] << 8)); }
|
||||
set
|
||||
{
|
||||
Regs[0] = (ushort)(value & 0xFF);
|
||||
Regs[1] = (ushort)((value >> 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetRegisters()
|
||||
{
|
||||
for (int i=0; i < 14; i++)
|
||||
{
|
||||
Regs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,498 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public partial class LR35902
|
||||
{
|
||||
// this contains the vectors of instrcution operations
|
||||
// NOTE: This list is NOT confirmed accurate for each individual cycle
|
||||
|
||||
private void NOP_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void INC_16(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{INC16, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
||||
private void DEC_16(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{DEC16, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{ADD16, dest_l, dest_h, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void REG_OP(ushort operation, ushort dest, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, dest, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void STOP_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
STOP };
|
||||
}
|
||||
|
||||
private void HALT_()
|
||||
{
|
||||
if (!FlagI)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
}
|
||||
else
|
||||
{
|
||||
// if interrupts are disabled,
|
||||
// a glitchy decrement to the program counter happens
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP_G};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void JR_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
ASGN, Z, 0,
|
||||
IDLE,
|
||||
ADDS, PCl, PCh, W, Z,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void JP_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
TR, PCl, W,
|
||||
IDLE,
|
||||
TR, PCh, Z,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void RET_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, PCl, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, PCh, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void RETI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, PCl, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, PCh, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
EI_RETI,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
||||
private void RET_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, PCl, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, PCh, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void CALL_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
TR, PCl, W,
|
||||
TR, PCh, Z,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void INT_OP(ushort operation, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void BIT_OP(ushort operation, ushort bit, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, bit, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void PUSH_(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, src_h,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, src_l,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// NOTE: this is the only instruction that can write to F
|
||||
// but the bottom 4 bits of F are always 0, so instead of putting a special check for every read op
|
||||
// let's just put a special operation here specifically for F
|
||||
private void POP_(ushort src_l, ushort src_h)
|
||||
{
|
||||
if (src_l != F)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, src_l, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, src_h, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD_F, src_l, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, src_h, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void RST_(ushort n)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCh,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
ASGN, PCh, 0,
|
||||
ASGN, PCl, n,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void PREFIX_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{PREFIX,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void DI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{DI,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void EI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{EI,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void JP_HL()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{TR, PCl, L,
|
||||
IDLE,
|
||||
TR, PCh, H,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void ADD_SP()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
ASGN, Z, 0,
|
||||
IDLE,
|
||||
ADDS, SPl, SPh, W, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_SP_HL()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR, SPl, L,
|
||||
IDLE,
|
||||
TR, SPh, H,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_HL_SPn()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
TR, H, SPh,
|
||||
TR, L, SPl,
|
||||
ASGN, Z, 0,
|
||||
ADDS, L, H, W, Z,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void JAM_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{JAM,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
namespace BizHawk.Emulation.Common.Components.LR35902
|
||||
{
|
||||
public partial class LR35902
|
||||
{
|
||||
private void INT_OP_IND(ushort operation, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
operation, Z,
|
||||
IDLE,
|
||||
WR, src_l, src_h, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
operation, bit, Z,
|
||||
IDLE,
|
||||
WR, src_l, src_h, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void BIT_TE_IND(ushort operation, ushort bit, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
operation, bit, Z,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
operation, dest, Z,
|
||||
INC16, src_l, src_h,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
operation, dest, Z,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_R_IM(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
WR, W, Z, dest_l,
|
||||
IDLE,
|
||||
INC16, W, Z,
|
||||
IDLE,
|
||||
WR, W, Z, dest_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND_INC(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, dest_l, dest_h, src,
|
||||
IDLE,
|
||||
INC16, dest_l, dest_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND_DEC(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, dest_l, dest_h, src,
|
||||
IDLE,
|
||||
DEC16, dest_l, dest_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, dest_l, dest_h, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
WR, dest_l, dest_h, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, dest, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, dest, src_l, src_h,
|
||||
IDLE,
|
||||
DEC16, src_l, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, dest_l, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
RD, dest_h, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void INC_8_IND(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
INC8, Z,
|
||||
IDLE,
|
||||
WR, src_l, src_h, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void DEC_8_IND(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
DEC8, Z,
|
||||
IDLE,
|
||||
WR, src_l, src_h, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
||||
private void LD_8_IND_FF(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, src_l, src_h,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
ASGN, Z , 0xFF,
|
||||
RD, dest, W, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_FF_IND_8(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, dest_l, dest_h,
|
||||
INC16, dest_l, dest_h,
|
||||
IDLE,
|
||||
ASGN, Z , 0xFF,
|
||||
WR, W, Z, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND_FFC(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
ASGN, Z , 0xFF,
|
||||
RD, dest, C, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_FFC_IND_8(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
ASGN, Z , 0xFF,
|
||||
WR, C, Z, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_16_IND_FF(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
RD, Z, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
RD, dest, W, Z,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_FF_IND_16(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, dest_l, dest_h,
|
||||
IDLE,
|
||||
INC16, dest_l, dest_h,
|
||||
IDLE,
|
||||
RD, Z, dest_l, dest_h,
|
||||
IDLE,
|
||||
INC16, dest_l, dest_h,
|
||||
IDLE,
|
||||
WR, W, Z, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,166 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.Z80GB
|
||||
{
|
||||
public partial class Z80
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
[Serializable]
|
||||
public struct RegisterPair
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public ushort Word;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public byte Low;
|
||||
|
||||
[FieldOffset(1)]
|
||||
public byte High;
|
||||
|
||||
public RegisterPair(ushort value)
|
||||
{
|
||||
Word = value;
|
||||
Low = (byte)(Word);
|
||||
High = (byte)(Word >> 8);
|
||||
}
|
||||
|
||||
public static implicit operator ushort(RegisterPair rp)
|
||||
{
|
||||
return rp.Word;
|
||||
}
|
||||
|
||||
public static implicit operator RegisterPair(ushort value)
|
||||
{
|
||||
return new RegisterPair(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FlagC
|
||||
{
|
||||
get { return (RegAF.Low & 0x10) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x10) | (value ? 0x10 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagH
|
||||
{
|
||||
get { return (RegAF.Low & 0x20) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x20) | (value ? 0x20 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagN
|
||||
{
|
||||
get { return (RegAF.Low & 0x40) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x40) | (value ? 0x40 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagZ
|
||||
{
|
||||
get { return (RegAF.Low & 0x80) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x80) | (value ? 0x80 : 0x00)); }
|
||||
}
|
||||
|
||||
private RegisterPair RegAF;
|
||||
private RegisterPair RegBC;
|
||||
private RegisterPair RegDE;
|
||||
private RegisterPair RegHL;
|
||||
|
||||
private byte RegI; // I (interrupt vector)
|
||||
|
||||
private RegisterPair RegSP; // SP (stack pointer)
|
||||
private RegisterPair RegPC; // PC (program counter)
|
||||
|
||||
private void ResetRegisters()
|
||||
{
|
||||
RegAF = 0; RegBC = 0; RegDE = 0; RegHL = 0;
|
||||
RegI = 0;
|
||||
RegSP.Word = 0; RegPC.Word = 0;
|
||||
}
|
||||
|
||||
public byte RegisterA
|
||||
{
|
||||
get { return RegAF.High; }
|
||||
set { RegAF.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterF
|
||||
{
|
||||
get { return RegAF.Low; }
|
||||
set { RegAF.Low = (byte)(value & 0xF0); }
|
||||
}
|
||||
|
||||
public ushort RegisterAF
|
||||
{
|
||||
get { return RegAF.Word; }
|
||||
set { RegAF.Word = (byte)(value & 0xFFF0); }
|
||||
}
|
||||
|
||||
public byte RegisterB
|
||||
{
|
||||
get { return RegBC.High; }
|
||||
set { RegBC.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterC
|
||||
{
|
||||
get { return RegBC.Low; }
|
||||
set { RegBC.Low = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterBC
|
||||
{
|
||||
get { return RegBC.Word; }
|
||||
set { RegBC.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterD
|
||||
{
|
||||
get { return RegDE.High; }
|
||||
set { RegDE.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterE
|
||||
{
|
||||
get { return RegDE.Low; }
|
||||
set { RegDE.Low = value; }
|
||||
}
|
||||
public ushort RegisterDE
|
||||
{
|
||||
get { return RegDE.Word; }
|
||||
set { RegDE.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterH
|
||||
{
|
||||
get { return RegHL.High; }
|
||||
set { RegHL.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterL
|
||||
{
|
||||
get { return RegHL.Low; }
|
||||
set { RegHL.Low = value; }
|
||||
}
|
||||
public ushort RegisterHL
|
||||
{
|
||||
get { return RegHL.Word; }
|
||||
set { RegHL.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterPC
|
||||
{
|
||||
get { return RegPC.Word; }
|
||||
set { RegPC.Word = value; }
|
||||
}
|
||||
public ushort RegisterSP
|
||||
{
|
||||
get { return RegSP.Word; }
|
||||
set { RegSP.Word = value; }
|
||||
}
|
||||
public byte RegisterI
|
||||
{
|
||||
get { return RegI; }
|
||||
set { RegI = value; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
namespace BizHawk.Emulation.Common.Components.Z80GB
|
||||
{
|
||||
public partial class Z80
|
||||
{
|
||||
private void InitializeTables()
|
||||
{
|
||||
InitTableDaa();
|
||||
}
|
||||
|
||||
private static readonly byte[] IncTable =
|
||||
{
|
||||
160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
private static readonly byte[] DecTable =
|
||||
{
|
||||
192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96,
|
||||
064, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96
|
||||
};
|
||||
|
||||
private static readonly byte[] SwapTable =
|
||||
{
|
||||
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
|
||||
0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
|
||||
0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
|
||||
0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
|
||||
0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
|
||||
0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
|
||||
0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
|
||||
0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
|
||||
0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
|
||||
0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
|
||||
0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
|
||||
0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
|
||||
0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
|
||||
0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
|
||||
0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
|
||||
0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
|
||||
};
|
||||
|
||||
private static readonly byte[] mCycleTable = new byte[]
|
||||
{
|
||||
1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1,
|
||||
1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1,
|
||||
3, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1,
|
||||
3, 3, 2, 2, 1, 3, 3, 3, 3, 2, 2, 2, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
5, 3, 4, 4, 6, 4, 2, 4, 5, 4, 4, 1, 6, 6, 2, 4,
|
||||
5, 3, 4, 0, 6, 4, 2, 4, 5, 4, 4, 0, 6, 0, 2, 4,
|
||||
3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4,
|
||||
3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4,
|
||||
};
|
||||
|
||||
private static readonly byte[] cbMCycleTable = new byte[]
|
||||
{
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
};
|
||||
|
||||
private ushort[] TableDaa;
|
||||
private void InitTableDaa()
|
||||
{
|
||||
TableDaa = new ushort[65536];
|
||||
for (int af = 0; af < 65536; ++af)
|
||||
{
|
||||
byte a = (byte)(af >> 8);
|
||||
byte tmp = a;
|
||||
|
||||
if (IsN(af))
|
||||
{
|
||||
if (IsH(af) || ((a & 0x0F) > 0x09)) tmp -= 0x06;
|
||||
if (IsC(af) || a > 0x99) tmp -= 0x60;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsH(af) || ((a & 0x0F) > 0x09)) tmp += 0x06;
|
||||
if (IsC(af) || a > 0x99) tmp += 0x60;
|
||||
}
|
||||
|
||||
TableDaa[af] = (ushort)((tmp * 256) + FlagByte(IsC(af) || a > 0x99, ((a ^ tmp) & 0x10) != 0, IsN(af), tmp == 0));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte FlagByte(bool C, bool H, bool N, bool Z)
|
||||
{
|
||||
return (byte)(
|
||||
(C ? 0x10 : 0) +
|
||||
(H ? 0x20 : 0) +
|
||||
(N ? 0x40 : 0) +
|
||||
(Z ? 0x80 : 0)
|
||||
);
|
||||
}
|
||||
|
||||
private static bool IsC(int value) { return (value & 0x10) != 0; }
|
||||
private static bool IsH(int value) { return (value & 0x20) != 0; }
|
||||
private static bool IsN(int value) { return (value & 0x40) != 0; }
|
||||
private static bool IsZ(int value) { return (value & 0x80) != 0; }
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
// This Z80-Gameboy emulator is a modified version of Ben Ryves 'Brazil' emulator.
|
||||
// It is MIT licensed (not public domain). (See Licenses)
|
||||
|
||||
namespace BizHawk.Emulation.Common.Components.Z80GB
|
||||
{
|
||||
public sealed partial class Z80
|
||||
{
|
||||
private static bool logging = false;
|
||||
private static StreamWriter log;
|
||||
|
||||
static Z80()
|
||||
{
|
||||
if (logging)
|
||||
log = new StreamWriter("log_Z80.txt");
|
||||
}
|
||||
|
||||
public Z80()
|
||||
{
|
||||
InitializeTables();
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
PendingCycles = 0;
|
||||
TotalExecutedCycles = 0;
|
||||
}
|
||||
|
||||
// Memory Access
|
||||
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
public Action<ushort, byte> WriteMemory;
|
||||
|
||||
public void UnregisterMemoryMapper()
|
||||
{
|
||||
ReadMemory = null;
|
||||
WriteMemory = null;
|
||||
}
|
||||
|
||||
// State Save/Load
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
writer.WriteLine("[Z80]");
|
||||
writer.WriteLine("AF {0:X4}", RegAF.Word);
|
||||
writer.WriteLine("BC {0:X4}", RegBC.Word);
|
||||
writer.WriteLine("DE {0:X4}", RegDE.Word);
|
||||
writer.WriteLine("HL {0:X4}", RegHL.Word);
|
||||
writer.WriteLine("I {0:X2}", RegI);
|
||||
writer.WriteLine("SP {0:X4}", RegSP.Word);
|
||||
writer.WriteLine("PC {0:X4}", RegPC.Word);
|
||||
writer.WriteLine("IRQ {0}", interrupt);
|
||||
writer.WriteLine("NMI {0}", nonMaskableInterrupt);
|
||||
writer.WriteLine("NMIPending {0}", nonMaskableInterruptPending);
|
||||
writer.WriteLine("IM {0}", InterruptMode);
|
||||
writer.WriteLine("IFF1 {0}", IFF1);
|
||||
writer.WriteLine("IFF2 {0}", IFF2);
|
||||
writer.WriteLine("Halted {0}", Halted);
|
||||
writer.WriteLine("ExecutedCycles {0}", TotalExecutedCycles);
|
||||
writer.WriteLine("PendingCycles {0}", PendingCycles);
|
||||
writer.WriteLine("[/Z80]");
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
string[] args = reader.ReadLine().Split(' ');
|
||||
if (args[0].Trim() == "") continue;
|
||||
if (args[0] == "[/Z80]") break;
|
||||
if (args[0] == "AF")
|
||||
RegAF.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "BC")
|
||||
RegBC.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "DE")
|
||||
RegDE.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "HL")
|
||||
RegHL.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "I")
|
||||
RegI = byte.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "SP")
|
||||
RegSP.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "PC")
|
||||
RegPC.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "IRQ")
|
||||
interrupt = bool.Parse(args[1]);
|
||||
else if (args[0] == "NMI")
|
||||
nonMaskableInterrupt = bool.Parse(args[1]);
|
||||
else if (args[0] == "NMIPending")
|
||||
nonMaskableInterruptPending = bool.Parse(args[1]);
|
||||
else if (args[0] == "IM")
|
||||
InterruptMode = int.Parse(args[1]);
|
||||
else if (args[0] == "IFF1")
|
||||
IFF1 = bool.Parse(args[1]);
|
||||
else if (args[0] == "IFF2")
|
||||
IFF2 = bool.Parse(args[1]);
|
||||
else if (args[0] == "Halted")
|
||||
Halted = bool.Parse(args[1]);
|
||||
else if (args[0] == "ExecutedCycles")
|
||||
TotalExecutedCycles = int.Parse(args[1]);
|
||||
else if (args[0] == "PendingCycles")
|
||||
PendingCycles = int.Parse(args[1]);
|
||||
|
||||
else
|
||||
Console.WriteLine("Skipping unrecognized identifier " + args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(RegAF.Word);
|
||||
writer.Write(RegBC.Word);
|
||||
writer.Write(RegDE.Word);
|
||||
writer.Write(RegHL.Word);
|
||||
writer.Write(RegI);
|
||||
writer.Write(RegSP.Word);
|
||||
writer.Write(RegPC.Word);
|
||||
writer.Write(interrupt);
|
||||
writer.Write(nonMaskableInterrupt);
|
||||
writer.Write(nonMaskableInterruptPending);
|
||||
writer.Write(InterruptMode);
|
||||
writer.Write(IFF1);
|
||||
writer.Write(IFF2);
|
||||
writer.Write(Halted);
|
||||
writer.Write(TotalExecutedCycles);
|
||||
writer.Write(PendingCycles);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
RegAF.Word = reader.ReadUInt16();
|
||||
RegBC.Word = reader.ReadUInt16();
|
||||
RegDE.Word = reader.ReadUInt16();
|
||||
RegHL.Word = reader.ReadUInt16();
|
||||
RegI = reader.ReadByte();
|
||||
RegSP.Word = reader.ReadUInt16();
|
||||
RegPC.Word = reader.ReadUInt16();
|
||||
interrupt = reader.ReadBoolean();
|
||||
nonMaskableInterrupt = reader.ReadBoolean();
|
||||
nonMaskableInterruptPending = reader.ReadBoolean();
|
||||
InterruptMode = reader.ReadInt32();
|
||||
IFF1 = reader.ReadBoolean();
|
||||
IFF2 = reader.ReadBoolean();
|
||||
Halted = reader.ReadBoolean();
|
||||
TotalExecutedCycles = reader.ReadInt32();
|
||||
PendingCycles = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void LogData()
|
||||
{
|
||||
if (!logging)
|
||||
return;
|
||||
log.WriteLine("AF {0:X4}", RegAF.Word);
|
||||
log.WriteLine("BC {0:X4}", RegBC.Word);
|
||||
log.WriteLine("DE {0:X4}", RegDE.Word);
|
||||
log.WriteLine("HL {0:X4}", RegHL.Word);
|
||||
log.WriteLine("SP {0:X4}", RegSP.Word);
|
||||
log.WriteLine("PC {0:X4}", RegPC.Word);
|
||||
log.WriteLine("------");
|
||||
log.WriteLine();
|
||||
log.Flush();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
/*
|
||||
["A"] = cpu.A,
|
||||
["X"] = cpu.X,
|
||||
["Y"] = cpu.Y,
|
||||
["S"] = cpu.S,
|
||||
["PC"] = cpu.PC,
|
||||
["Flag C"] = cpu.FlagC,
|
||||
["Flag Z"] = cpu.FlagZ,
|
||||
["Flag I"] = cpu.FlagI,
|
||||
["Flag D"] = cpu.FlagD,
|
||||
["Flag B"] = cpu.FlagB,
|
||||
["Flag V"] = cpu.FlagV,
|
||||
["Flag N"] = cpu.FlagN,
|
||||
["Flag T"] = cpu.FlagT
|
||||
*/
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
//cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
//cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
//cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
//cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
//cpu.PC = (ushort)value;
|
||||
break;
|
||||
case "Flag I":
|
||||
//cpu.FlagI = value > 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles
|
||||
{
|
||||
get { return cpu.TotalExecutedCycles; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk : IEmulator, IVideoProvider
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
|
||||
|
||||
public byte controller_state;
|
||||
public byte controller_state_old;
|
||||
public bool in_vblank_old;
|
||||
public bool in_vblank;
|
||||
public bool vblank_rise;
|
||||
|
||||
public void FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
//Console.WriteLine("-----------------------FRAME-----------------------");
|
||||
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
cpu.TraceCallback = s => _tracer.Put(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu.TraceCallback = null;
|
||||
}
|
||||
|
||||
_frame++;
|
||||
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
// it seems that theMachine.Reset() doesn't clear ram, etc
|
||||
// this should leave hsram intact but clear most other things
|
||||
HardReset();
|
||||
}
|
||||
|
||||
_islag = true;
|
||||
|
||||
GetControllerState(controller);
|
||||
|
||||
do_frame();
|
||||
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
}
|
||||
|
||||
public void do_frame()
|
||||
{
|
||||
// gameboy frames can be variable lengths
|
||||
// we want to end a frame when VBlank turns from false to true
|
||||
int ticker = 0;
|
||||
while (!vblank_rise && (ticker < 100000))
|
||||
{
|
||||
audio.tick();
|
||||
timer.tick_1();
|
||||
ppu.tick();
|
||||
|
||||
cpu.ExecuteOne(ref REG_FF0F, REG_FFFF);
|
||||
|
||||
timer.tick_2();
|
||||
|
||||
|
||||
if (in_vblank && !in_vblank_old)
|
||||
{
|
||||
vblank_rise = true;
|
||||
}
|
||||
ticker++;
|
||||
in_vblank_old = in_vblank;
|
||||
}
|
||||
|
||||
vblank_rise = false;
|
||||
}
|
||||
|
||||
public void RunCPUCycle()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void GetControllerState(IController controller)
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
controller_state = _controllerDeck.ReadPort1(controller);
|
||||
|
||||
// set interrupt flag if a pin went from high to low
|
||||
if (controller_state < controller_state_old)
|
||||
{
|
||||
if (REG_FFFF.Bit(4)) { cpu.FlagI = true; }
|
||||
REG_FF0F |= 0x10;
|
||||
}
|
||||
|
||||
controller_state_old = controller_state;
|
||||
}
|
||||
|
||||
public void serial_transfer()
|
||||
{
|
||||
if (serial_control.Bit(7) && !serial_start_old)
|
||||
{
|
||||
serial_start_old = true;
|
||||
|
||||
// transfer out on byte of data
|
||||
// needs to be modelled
|
||||
}
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "GB";
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_frame = 0;
|
||||
_lagcount = 0;
|
||||
_islag = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region Video provider
|
||||
|
||||
public int _frameHz = 60;
|
||||
|
||||
public int[] _vidbuffer;
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 160;
|
||||
public int VirtualHeight => 144;
|
||||
public int BufferWidth => 160;
|
||||
public int BufferHeight => 144;
|
||||
public int BackgroundColor => unchecked((int)0xFF000000);
|
||||
public int VsyncNumerator => _frameHz;
|
||||
public int VsyncDenominator => 1;
|
||||
|
||||
public static readonly uint[] color_palette = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 };
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk : IInputPollable
|
||||
{
|
||||
public int LagCount
|
||||
{
|
||||
get { return _lagcount; }
|
||||
set { _lagcount = value; }
|
||||
}
|
||||
|
||||
public bool IsLagFrame
|
||||
{
|
||||
get { return _islag; }
|
||||
set { _islag = value; }
|
||||
}
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
public bool _islag = true;
|
||||
private int _lagcount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk
|
||||
{
|
||||
private IMemoryDomains MemoryDomains;
|
||||
|
||||
public void SetupMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
new MemoryDomainDelegate(
|
||||
"Main RAM",
|
||||
RAM.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr],
|
||||
(addr, value) => RAM[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"Zero Page RAM",
|
||||
ZP_RAM.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => ZP_RAM[addr],
|
||||
(addr, value) => ZP_RAM[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"System Bus",
|
||||
0X10000,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => PeekSystemBus(addr),
|
||||
(addr, value) => PokeSystemBus(addr, value),
|
||||
1)
|
||||
};
|
||||
|
||||
MemoryDomains = new MemoryDomainList(domains);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
|
||||
}
|
||||
|
||||
private byte PeekSystemBus(long addr)
|
||||
{
|
||||
ushort addr2 = (ushort)(addr & 0xFFFF);
|
||||
return ReadMemory(addr2);
|
||||
}
|
||||
|
||||
private void PokeSystemBus(long addr, byte value)
|
||||
{
|
||||
ushort addr2 = (ushort)(addr & 0xFFFF);
|
||||
WriteMemory(addr2, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk : ISaveRam
|
||||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
return (byte[])_sram.Clone();
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
Buffer.BlockCopy(data, 0, _sram, 0, data.Length);
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk : IEmulator, IStatable, ISettable<GBHawk.GBSettings, GBHawk.GBSyncSettings>
|
||||
{
|
||||
public GBSettings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
|
||||
public GBSyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSettings(GBSettings o)
|
||||
{
|
||||
_settings = o;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool PutSyncSettings(GBSyncSettings o)
|
||||
{
|
||||
bool ret = GBSyncSettings.NeedsReboot(_syncSettings, o);
|
||||
_syncSettings = o;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private GBSettings _settings = new GBSettings();
|
||||
public GBSyncSettings _syncSettings = new GBSyncSettings();
|
||||
|
||||
public class GBSettings
|
||||
{
|
||||
public GBSettings Clone()
|
||||
{
|
||||
return (GBSettings)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
public class GBSyncSettings
|
||||
{
|
||||
private string _port1 = GBHawkControllerDeck.DefaultControllerName;
|
||||
|
||||
[JsonIgnore]
|
||||
public string Port1
|
||||
{
|
||||
get { return _port1; }
|
||||
set
|
||||
{
|
||||
if (!GBHawkControllerDeck.ValidControllerTypes.ContainsKey(value))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid controller type: " + value);
|
||||
}
|
||||
|
||||
_port1 = value;
|
||||
}
|
||||
}
|
||||
|
||||
public GBSyncSettings Clone()
|
||||
{
|
||||
return (GBSyncSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(GBSyncSettings x, GBSyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => true;
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
SyncState(new Serializer(writer));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
SyncState(new Serializer(reader));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
cpu.SyncState(ser);
|
||||
mapper.SyncState(ser);
|
||||
timer.SyncState(ser);
|
||||
ppu.SyncState(ser);
|
||||
audio.SyncState(ser);
|
||||
|
||||
ser.BeginSection("Gameboy");
|
||||
ser.Sync("core", ref core, false);
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("IsLag", ref _islag);
|
||||
_controllerDeck.SyncState(ser);
|
||||
|
||||
ser.Sync("controller_state", ref controller_state);
|
||||
ser.Sync("controller_state_old", ref controller_state_old);
|
||||
ser.Sync("in_vblank", ref in_vblank);
|
||||
ser.Sync("in_vblank_old", ref in_vblank_old);
|
||||
ser.Sync("vblank_rise", ref vblank_rise);
|
||||
ser.Sync("GB_bios_register", ref GB_bios_register);
|
||||
ser.Sync("input_register", ref input_register);
|
||||
|
||||
ser.Sync("serial_control", ref serial_control);
|
||||
ser.Sync("serial_data_out", ref serial_data_out);
|
||||
ser.Sync("serial_data_in", ref serial_data_in);
|
||||
ser.Sync("serial_start_old", ref serial_start_old);
|
||||
|
||||
ser.Sync("REG_FFFF", ref REG_FFFF);
|
||||
ser.Sync("REG_FF0F", ref REG_FF0F);
|
||||
ser.Sync("enable_VBL", ref enable_VBL);
|
||||
ser.Sync("enable_LCDC", ref enable_PRS);
|
||||
ser.Sync("enable_TIMO", ref enable_TIMO);
|
||||
ser.Sync("enable_SER", ref enable_SER);
|
||||
ser.Sync("enable_STAT", ref enable_STAT);
|
||||
|
||||
// memory domains
|
||||
ser.Sync("RAM", ref RAM, false);
|
||||
ser.Sync("ZP_RAM", ref ZP_RAM, false);
|
||||
ser.Sync("CHR_RAM", ref CHR_RAM, false);
|
||||
ser.Sync("BG_map_1", ref BG_map_1, false);
|
||||
ser.Sync("BG_map_2", ref BG_map_2, false);
|
||||
ser.Sync("OAM", ref OAM, false);
|
||||
// probably a better way to do this
|
||||
if (cart_RAM != null)
|
||||
{
|
||||
ser.Sync("cart_RAM", ref cart_RAM, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.Components.LR35902;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
[Core(
|
||||
"GBHawk",
|
||||
"",
|
||||
isPorted: false,
|
||||
isReleased: true)]
|
||||
[ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))]
|
||||
public partial class GBHawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable,
|
||||
ISettable<GBHawk.GBSettings, GBHawk.GBSyncSettings>
|
||||
{
|
||||
// this register controls whether or not the GB BIOS is mapped into memory
|
||||
public byte GB_bios_register;
|
||||
|
||||
public byte input_register;
|
||||
|
||||
public byte serial_control;
|
||||
public byte serial_data_out;
|
||||
public byte serial_data_in;
|
||||
public bool serial_start_old;
|
||||
|
||||
// The unused bits in this register are still read/writable
|
||||
public byte REG_FFFF;
|
||||
// The unused bits in this register (interrupt flags) are always set
|
||||
public byte REG_FF0F = 0xE0;
|
||||
public bool enable_VBL;
|
||||
public bool enable_STAT;
|
||||
public bool enable_TIMO;
|
||||
public bool enable_SER;
|
||||
public bool enable_PRS;
|
||||
|
||||
|
||||
// memory domains
|
||||
public byte[] RAM = new byte[0x2000];
|
||||
public byte[] ZP_RAM = new byte[0x80];
|
||||
public byte[] CHR_RAM = new byte[0x1800];
|
||||
public byte[] BG_map_1 = new byte[0x400];
|
||||
public byte[] BG_map_2 = new byte[0x400];
|
||||
public byte[] OAM = new byte[0xA0];
|
||||
|
||||
public readonly byte[] _rom;
|
||||
public readonly byte[] _bios;
|
||||
public readonly byte[] _sram = new byte[2048];
|
||||
public readonly byte[] header = new byte[0x50];
|
||||
|
||||
public byte[] cart_RAM;
|
||||
|
||||
private int _frame = 0;
|
||||
|
||||
public MapperBase mapper;
|
||||
|
||||
private readonly ITraceable _tracer;
|
||||
|
||||
public LR35902 cpu;
|
||||
public PPU ppu;
|
||||
public Timer timer;
|
||||
public Audio audio;
|
||||
|
||||
[CoreConstructor("GB")]
|
||||
public GBHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
|
||||
cpu = new LR35902
|
||||
{
|
||||
ReadMemory = ReadMemory,
|
||||
WriteMemory = WriteMemory,
|
||||
PeekMemory = ReadMemory,
|
||||
DummyReadMemory = ReadMemory,
|
||||
OnExecFetch = ExecFetch
|
||||
};
|
||||
ppu = new PPU();
|
||||
timer = new Timer();
|
||||
audio = new Audio();
|
||||
|
||||
CoreComm = comm;
|
||||
|
||||
_settings = (GBSettings)settings ?? new GBSettings();
|
||||
_syncSettings = (GBSyncSettings)syncSettings ?? new GBSyncSettings();
|
||||
_controllerDeck = new GBHawkControllerDeck(_syncSettings.Port1);
|
||||
|
||||
byte[] Bios = comm.CoreFileProvider.GetFirmware("GB", "World", false, "BIOS Not Found, Cannot Load");
|
||||
_bios = Bios;
|
||||
|
||||
Buffer.BlockCopy(rom, 0x100, header, 0, 0x50);
|
||||
|
||||
string hash_md5 = null;
|
||||
hash_md5 = "md5:" + rom.HashMD5(0, rom.Length);
|
||||
Console.WriteLine(hash_md5);
|
||||
|
||||
_rom = rom;
|
||||
Setup_Mapper();
|
||||
|
||||
_frameHz = 60;
|
||||
|
||||
timer.Core = this;
|
||||
audio.Core = this;
|
||||
ppu.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ISoundProvider>(audio);
|
||||
ServiceProvider = ser;
|
||||
|
||||
_tracer = new TraceBuffer { Header = cpu.TraceHeader };
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
|
||||
SetupMemoryDomains();
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public DisplayType Region => DisplayType.NTSC;
|
||||
|
||||
private readonly GBHawkControllerDeck _controllerDeck;
|
||||
|
||||
private void HardReset()
|
||||
{
|
||||
GB_bios_register = 0; // bios enable
|
||||
in_vblank = true; // we start off in vblank since the LCD is off
|
||||
in_vblank_old = true;
|
||||
|
||||
Register_Reset();
|
||||
timer.Reset();
|
||||
ppu.Reset();
|
||||
audio.Reset();
|
||||
|
||||
cpu.SetCallbacks(ReadMemory, ReadMemory, ReadMemory, WriteMemory);
|
||||
|
||||
_vidbuffer = new int[VirtualWidth * VirtualHeight];
|
||||
}
|
||||
|
||||
private void ExecFetch(ushort addr)
|
||||
{
|
||||
MemoryCallbacks.CallExecutes(addr, "System Bus");
|
||||
}
|
||||
|
||||
private void Setup_Mapper()
|
||||
{
|
||||
// setup up mapper based on header entry
|
||||
string mppr;
|
||||
|
||||
switch (header[0x47])
|
||||
{
|
||||
case 0x0: mapper = new MapperDefault(); mppr = "NROM"; break;
|
||||
case 0x1: mapper = new MapperMBC1(); mppr = "MBC1"; break;
|
||||
case 0x2: mapper = new MapperMBC1(); mppr = "MBC1"; break;
|
||||
case 0x3: mapper = new MapperMBC1(); mppr = "MBC1"; break;
|
||||
case 0x5: mapper = new MapperMBC2(); mppr = "MBC2"; break;
|
||||
case 0x6: mapper = new MapperMBC2(); mppr = "MBC2"; break;
|
||||
case 0x8: mapper = new MapperDefault(); mppr = "NROM"; break;
|
||||
case 0x9: mapper = new MapperDefault(); mppr = "NROM"; break;
|
||||
case 0xB: mapper = new MapperMMM01(); mppr = "MMM01"; break;
|
||||
case 0xC: mapper = new MapperMMM01(); mppr = "MMM01"; break;
|
||||
case 0xD: mapper = new MapperMMM01(); mppr = "MMM01"; break;
|
||||
case 0xF: mapper = new MapperMBC3(); mppr = "MBC3"; break;
|
||||
case 0x10: mapper = new MapperMBC3(); mppr = "MBC3"; break;
|
||||
case 0x11: mapper = new MapperMBC3(); mppr = "MBC3"; break;
|
||||
case 0x12: mapper = new MapperMBC3(); mppr = "MBC3"; break;
|
||||
case 0x13: mapper = new MapperMBC3(); mppr = "MBC3"; break;
|
||||
case 0x19: mapper = new MapperMBC5(); mppr = "MBC5"; break;
|
||||
case 0x1A: mapper = new MapperMBC5(); mppr = "MBC5"; break;
|
||||
case 0x1B: mapper = new MapperMBC5(); mppr = "MBC5"; break;
|
||||
case 0x1C: mapper = new MapperMBC5(); mppr = "MBC5"; break;
|
||||
case 0x1D: mapper = new MapperMBC5(); mppr = "MBC5"; break;
|
||||
case 0x1E: mapper = new MapperMBC5(); mppr = "MBC5"; break;
|
||||
case 0x20: mapper = new MapperMBC6(); mppr = "MBC6"; break;
|
||||
case 0x22: mapper = new MapperMBC7(); mppr = "MBC7"; break;
|
||||
case 0xFC: mapper = new MapperCamera(); mppr = "CAM"; break;
|
||||
case 0xFD: mapper = new MapperTAMA5(); mppr = "TAMA5"; break;
|
||||
case 0xFE: mapper = new MapperHuC3(); mppr = "HuC3"; break;
|
||||
case 0xFF: mapper = new MapperHuC1(); mppr = "HuC1"; break;
|
||||
|
||||
case 0x4:
|
||||
case 0x7:
|
||||
case 0xA:
|
||||
case 0xE:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case 0x1F:
|
||||
case 0x21:
|
||||
default:
|
||||
// mapper not implemented
|
||||
throw new Exception("Mapper not implemented");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// special case for multi cart mappers
|
||||
if ((_rom.HashMD5(0,_rom.Length) == "97122B9B183AAB4079C8D36A4CE6E9C1") ||
|
||||
(_rom.HashMD5(0, _rom.Length) == "9FB9C42CF52DCFDCFBAD5E61AE1B5777") ||
|
||||
(_rom.HashMD5(0, _rom.Length) == "CF1F58AB72112716D3C615A553B2F481")
|
||||
)
|
||||
{
|
||||
Console.WriteLine("Using Multi-Cart Mapper");
|
||||
mapper = new MapperMBC1Multi();
|
||||
}
|
||||
|
||||
Console.Write("Mapper: ");
|
||||
Console.WriteLine(mppr);
|
||||
|
||||
cart_RAM = null;
|
||||
|
||||
switch (header[0x49])
|
||||
{
|
||||
case 1:
|
||||
cart_RAM = new byte[0x800];
|
||||
break;
|
||||
case 2:
|
||||
cart_RAM = new byte[0x2000];
|
||||
break;
|
||||
case 3:
|
||||
cart_RAM = new byte[0x8000];
|
||||
break;
|
||||
case 4:
|
||||
cart_RAM = new byte[0x20000];
|
||||
break;
|
||||
case 5:
|
||||
cart_RAM = new byte[0x10000];
|
||||
break;
|
||||
}
|
||||
|
||||
// mbc2 carts have built in RAM
|
||||
if (mppr == "MBC2")
|
||||
{
|
||||
cart_RAM = new byte[0x200];
|
||||
}
|
||||
|
||||
mapper.Core = this;
|
||||
mapper.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public class GBHawkControllerDeck
|
||||
{
|
||||
public GBHawkControllerDeck(string controller1Name)
|
||||
{
|
||||
if (!ValidControllerTypes.ContainsKey(controller1Name))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid controller type: " + controller1Name);
|
||||
}
|
||||
|
||||
Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1);
|
||||
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = Port1.Definition.Name,
|
||||
BoolButtons = Port1.Definition.BoolButtons
|
||||
.Concat(new[]
|
||||
{
|
||||
"Power",
|
||||
"Reset",
|
||||
})
|
||||
.ToList()
|
||||
};
|
||||
|
||||
Definition.FloatControls.AddRange(Port1.Definition.FloatControls);
|
||||
|
||||
Definition.FloatRanges.AddRange(Port1.Definition.FloatRanges);
|
||||
}
|
||||
|
||||
public byte ReadPort1(IController c)
|
||||
{
|
||||
return Port1.Read(c);
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Port1");
|
||||
Port1.SyncState(ser);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
private readonly IPort Port1;
|
||||
|
||||
private static Dictionary<string, Type> _controllerTypes;
|
||||
|
||||
public static Dictionary<string, Type> ValidControllerTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_controllerTypes == null)
|
||||
{
|
||||
_controllerTypes = typeof(GBHawkControllerDeck).Assembly
|
||||
.GetTypes()
|
||||
.Where(t => typeof(IPort).IsAssignableFrom(t))
|
||||
.Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.ToDictionary(tkey => tkey.DisplayName());
|
||||
}
|
||||
|
||||
return _controllerTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public static string DefaultControllerName => typeof(StandardControls).DisplayName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a GB add on
|
||||
/// </summary>
|
||||
public interface IPort
|
||||
{
|
||||
byte Read(IController c);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
|
||||
int PortNum { get; }
|
||||
}
|
||||
|
||||
[DisplayName("Standard controls")]
|
||||
public class StandardControls : IPort
|
||||
{
|
||||
public StandardControls(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "Game Boy",
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (c.IsPressed(Definition.BoolButtons[i]))
|
||||
{
|
||||
result -= (byte)(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Right", "Left", "Up", "Down", "A", "B", "Select", "Start"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk
|
||||
{
|
||||
public byte Read_Registers(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
// Read Input
|
||||
case 0xFF00:
|
||||
_islag = false;
|
||||
|
||||
input_register &= 0xF0;
|
||||
if ((input_register & 0x30) == 0x20)
|
||||
{
|
||||
input_register |= (byte)(controller_state & 0xF);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x10)
|
||||
{
|
||||
input_register |= (byte)((controller_state & 0xF0) >> 4);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x30)
|
||||
{
|
||||
// if both polls are set, then a bit is zero if either or both pins are zero
|
||||
byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
|
||||
input_register |= temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_register |= 0xF;
|
||||
}
|
||||
ret = input_register;
|
||||
break;
|
||||
|
||||
// Serial data port
|
||||
case 0xFF01:
|
||||
ret = serial_data_in;
|
||||
break;
|
||||
|
||||
// Serial port control
|
||||
case 0xFF02:
|
||||
ret = serial_control;
|
||||
break;
|
||||
|
||||
// Timer Registers
|
||||
case 0xFF04:
|
||||
case 0xFF05:
|
||||
case 0xFF06:
|
||||
case 0xFF07:
|
||||
ret = timer.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Interrupt flags
|
||||
case 0xFF0F:
|
||||
ret = REG_FF0F;
|
||||
break;
|
||||
|
||||
// audio regs
|
||||
case 0xFF10:
|
||||
case 0xFF11:
|
||||
case 0xFF12:
|
||||
case 0xFF13:
|
||||
case 0xFF14:
|
||||
case 0xFF16:
|
||||
case 0xFF17:
|
||||
case 0xFF18:
|
||||
case 0xFF19:
|
||||
case 0xFF1A:
|
||||
case 0xFF1B:
|
||||
case 0xFF1C:
|
||||
case 0xFF1D:
|
||||
case 0xFF1E:
|
||||
case 0xFF20:
|
||||
case 0xFF21:
|
||||
case 0xFF22:
|
||||
case 0xFF23:
|
||||
case 0xFF24:
|
||||
case 0xFF25:
|
||||
case 0xFF26:
|
||||
case 0xFF30:
|
||||
case 0xFF31:
|
||||
case 0xFF32:
|
||||
case 0xFF33:
|
||||
case 0xFF34:
|
||||
case 0xFF35:
|
||||
case 0xFF36:
|
||||
case 0xFF37:
|
||||
case 0xFF38:
|
||||
case 0xFF39:
|
||||
case 0xFF3A:
|
||||
case 0xFF3B:
|
||||
case 0xFF3C:
|
||||
case 0xFF3D:
|
||||
case 0xFF3E:
|
||||
case 0xFF3F:
|
||||
ret = audio.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// PPU Regs
|
||||
case 0xFF40:
|
||||
case 0xFF41:
|
||||
case 0xFF42:
|
||||
case 0xFF43:
|
||||
case 0xFF44:
|
||||
case 0xFF45:
|
||||
case 0xFF46:
|
||||
case 0xFF47:
|
||||
case 0xFF48:
|
||||
case 0xFF49:
|
||||
case 0xFF4A:
|
||||
case 0xFF4B:
|
||||
ret = ppu.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Bios control register. Not sure if it is readable
|
||||
case 0xFF50:
|
||||
ret = 0xFF;
|
||||
break;
|
||||
|
||||
// interrupt control register
|
||||
case 0xFFFF:
|
||||
ret = REG_FFFF;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = 0xFF;
|
||||
break;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Write_Registers(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
// select input
|
||||
case 0xFF00:
|
||||
input_register = (byte)(0xC0 | (value & 0x3F)); // top 2 bits always 1
|
||||
break;
|
||||
|
||||
// Serial data port
|
||||
case 0xFF01:
|
||||
serial_data_out = value;
|
||||
serial_data_in = serial_data_out;
|
||||
break;
|
||||
|
||||
// Serial port control
|
||||
case 0xFF02:
|
||||
serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1
|
||||
break;
|
||||
|
||||
// Timer Registers
|
||||
case 0xFF04:
|
||||
case 0xFF05:
|
||||
case 0xFF06:
|
||||
case 0xFF07:
|
||||
timer.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// Interrupt flags
|
||||
case 0xFF0F:
|
||||
REG_FF0F = (byte)(0xE0 | value);
|
||||
|
||||
// check if enabling any of the bits triggered an IRQ
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (REG_FFFF.Bit(i) && REG_FF0F.Bit(i))
|
||||
{
|
||||
cpu.FlagI = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if no bits are in common between flags and enables, de-assert the IRQ
|
||||
if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu.FlagI = false; }
|
||||
|
||||
break;
|
||||
|
||||
// audio regs
|
||||
case 0xFF10:
|
||||
case 0xFF11:
|
||||
case 0xFF12:
|
||||
case 0xFF13:
|
||||
case 0xFF14:
|
||||
case 0xFF16:
|
||||
case 0xFF17:
|
||||
case 0xFF18:
|
||||
case 0xFF19:
|
||||
case 0xFF1A:
|
||||
case 0xFF1B:
|
||||
case 0xFF1C:
|
||||
case 0xFF1D:
|
||||
case 0xFF1E:
|
||||
case 0xFF20:
|
||||
case 0xFF21:
|
||||
case 0xFF22:
|
||||
case 0xFF23:
|
||||
case 0xFF24:
|
||||
case 0xFF25:
|
||||
case 0xFF26:
|
||||
case 0xFF30:
|
||||
case 0xFF31:
|
||||
case 0xFF32:
|
||||
case 0xFF33:
|
||||
case 0xFF34:
|
||||
case 0xFF35:
|
||||
case 0xFF36:
|
||||
case 0xFF37:
|
||||
case 0xFF38:
|
||||
case 0xFF39:
|
||||
case 0xFF3A:
|
||||
case 0xFF3B:
|
||||
case 0xFF3C:
|
||||
case 0xFF3D:
|
||||
case 0xFF3E:
|
||||
case 0xFF3F:
|
||||
audio.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// PPU Regs
|
||||
case 0xFF40:
|
||||
case 0xFF41:
|
||||
case 0xFF42:
|
||||
case 0xFF43:
|
||||
case 0xFF44:
|
||||
case 0xFF45:
|
||||
case 0xFF46:
|
||||
case 0xFF47:
|
||||
case 0xFF48:
|
||||
case 0xFF49:
|
||||
case 0xFF4A:
|
||||
case 0xFF4B:
|
||||
ppu.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs
|
||||
case 0xFF50:
|
||||
//Console.WriteLine(value);
|
||||
if (GB_bios_register != 1)
|
||||
{
|
||||
GB_bios_register = value;
|
||||
}
|
||||
break;
|
||||
|
||||
// interrupt control register
|
||||
case 0xFFFF:
|
||||
REG_FFFF = value;
|
||||
enable_VBL = REG_FFFF.Bit(0);
|
||||
enable_STAT = REG_FFFF.Bit(1);
|
||||
enable_TIMO = REG_FFFF.Bit(2);
|
||||
enable_SER = REG_FFFF.Bit(3);
|
||||
enable_PRS = REG_FFFF.Bit(4);
|
||||
|
||||
// check if enabling any of the bits triggered an IRQ
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (REG_FFFF.Bit(i) && REG_FF0F.Bit(i))
|
||||
{
|
||||
cpu.FlagI = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if no bits are in common between flags and enables, de-assert the IRQ
|
||||
if (((REG_FF0F & 0x1F) & REG_FFFF) == 0) { cpu.FlagI = false; }
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Register_Reset()
|
||||
{
|
||||
input_register = 0xCF; // not reading any input
|
||||
serial_control = 0x7E;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public class MapperBase
|
||||
{
|
||||
public GBHawk Core { get; set; }
|
||||
|
||||
public virtual byte ReadMemory(ushort addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual byte PeekMemory(ushort addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperCamera : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperDefault : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperHuC1 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperHuC3 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// MBC1 with bank switching and RAM
|
||||
public class MapperMBC1 : MapperBase
|
||||
{
|
||||
public int ROM_bank;
|
||||
public int RAM_bank;
|
||||
public bool RAM_enable;
|
||||
public bool sel_mode;
|
||||
public int ROM_mask;
|
||||
public int RAM_mask;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
ROM_bank = 1;
|
||||
RAM_bank = 0;
|
||||
RAM_enable = false;
|
||||
sel_mode = false;
|
||||
ROM_mask = Core._rom.Length / 0x4000 - 1;
|
||||
RAM_mask = 0;
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
RAM_mask = Core.cart_RAM.Length / 0x2000 - 1;
|
||||
if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x4000)
|
||||
{
|
||||
// lowest bank is fixed, but is still effected by mode
|
||||
if (sel_mode)
|
||||
{
|
||||
return Core._rom[(ROM_bank & 0x60) * 0x4000 + addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
|
||||
{
|
||||
return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
RAM_enable = ((value & 0xA) == 0xA) ? true : false;
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
value &= 0x1F;
|
||||
|
||||
// writing zero gets translated to 1
|
||||
if (value == 0) { value = 1; }
|
||||
|
||||
ROM_bank &= 0xE0;
|
||||
ROM_bank |= value;
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
else if (addr < 0x6000)
|
||||
{
|
||||
if (sel_mode && Core.cart_RAM != null)
|
||||
{
|
||||
RAM_bank = value & 3;
|
||||
RAM_bank &= RAM_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
ROM_bank &= 0x1F;
|
||||
ROM_bank |= ((value & 3) << 5);
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sel_mode = (value & 1) > 0;
|
||||
|
||||
if (sel_mode && Core.cart_RAM != null)
|
||||
{
|
||||
ROM_bank &= 0x1F;
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
RAM_bank = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
|
||||
{
|
||||
Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("ROM_Bank", ref ROM_bank);
|
||||
ser.Sync("ROM_Mask", ref ROM_mask);
|
||||
ser.Sync("RAM_Bank", ref RAM_bank);
|
||||
ser.Sync("RAM_Mask", ref RAM_mask);
|
||||
ser.Sync("RAM_enable", ref RAM_enable);
|
||||
ser.Sync("sel_mode", ref sel_mode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// MBC1 with bank switching and RAM
|
||||
public class MapperMBC1Multi : MapperBase
|
||||
{
|
||||
public int ROM_bank;
|
||||
public int RAM_bank;
|
||||
public bool RAM_enable;
|
||||
public bool sel_mode;
|
||||
public int ROM_mask;
|
||||
public int RAM_mask;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
ROM_bank = 1;
|
||||
RAM_bank = 0;
|
||||
RAM_enable = false;
|
||||
sel_mode = false;
|
||||
ROM_mask = (Core._rom.Length / 0x4000 * 2) - 1; // due to how mapping workd, we want a 1 bit higher mask
|
||||
RAM_mask = 0;
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
RAM_mask = Core.cart_RAM.Length / 0x2000 - 1;
|
||||
if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x4000)
|
||||
{
|
||||
// lowest bank is fixed, but is still effected by mode
|
||||
if (sel_mode)
|
||||
{
|
||||
return Core._rom[((ROM_bank & 0x60) >> 1) * 0x4000 + addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[(addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
|
||||
{
|
||||
return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
RAM_enable = ((value & 0xA) == 0xA) ? true : false;
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
value &= 0x1F;
|
||||
|
||||
// writing zero gets translated to 1
|
||||
if (value == 0) { value = 1; }
|
||||
|
||||
ROM_bank &= 0xE0;
|
||||
ROM_bank |= value;
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
else if (addr < 0x6000)
|
||||
{
|
||||
if (sel_mode && Core.cart_RAM != null)
|
||||
{
|
||||
RAM_bank = value & 3;
|
||||
RAM_bank &= RAM_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
ROM_bank &= 0x1F;
|
||||
ROM_bank |= ((value & 3) << 5);
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sel_mode = (value & 1) > 0;
|
||||
|
||||
if (sel_mode && Core.cart_RAM != null)
|
||||
{
|
||||
ROM_bank &= 0x1F;
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
RAM_bank = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
|
||||
{
|
||||
Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("ROM_Bank", ref ROM_bank);
|
||||
ser.Sync("ROM_Mask", ref ROM_mask);
|
||||
ser.Sync("RAM_Bank", ref RAM_bank);
|
||||
ser.Sync("RAM_Mask", ref RAM_mask);
|
||||
ser.Sync("RAM_enable", ref RAM_enable);
|
||||
ser.Sync("sel_mode", ref sel_mode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// MBC1 with bank switching and RAM
|
||||
public class MapperMBC2 : MapperBase
|
||||
{
|
||||
public int ROM_bank;
|
||||
public int RAM_bank;
|
||||
public bool RAM_enable;
|
||||
public int ROM_mask;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
ROM_bank = 1;
|
||||
RAM_bank = 0;
|
||||
RAM_enable = false;
|
||||
ROM_mask = Core._rom.Length / 0x4000 - 1;
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x4000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000];
|
||||
}
|
||||
else if ((addr >= 0xA000) && (addr < 0xA200))
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
RAM_enable = (addr & 0x100) > 0;
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
if ((addr & 0x100) > 0)
|
||||
{
|
||||
ROM_bank = value & 0xF;
|
||||
}
|
||||
}
|
||||
else if ((addr >= 0xA000) && (addr < 0xA200))
|
||||
{
|
||||
if (RAM_enable)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = (byte)(value & 0xF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("ROM_Bank", ref ROM_bank);
|
||||
ser.Sync("ROM_Mask", ref ROM_mask);
|
||||
ser.Sync("RAM_Bank", ref RAM_bank);
|
||||
ser.Sync("RAM_enable", ref RAM_enable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperMBC3 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperMBC5 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperMBC6 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperMBC7 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperMMM01 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
public class MapperTAMA5 : MapperBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
{
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PokeMemory(ushort addr, byte value)
|
||||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
TODO:
|
||||
Official Mappers
|
||||
Unofficial Mappers
|
|
@ -0,0 +1,168 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
||||
/*
|
||||
$FFFF Interrupt Enable Flag
|
||||
$FF80-$FFFE Zero Page - 127 bytes
|
||||
$FF00-$FF7F Hardware I/O Registers
|
||||
$FEA0-$FEFF Unusable Memory
|
||||
$FE00-$FE9F OAM - Object Attribute Memory
|
||||
$E000-$FDFF Echo RAM - Reserved, Do Not Use
|
||||
$D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only)
|
||||
$C000-$CFFF Internal RAM - Bank 0 (fixed)
|
||||
$A000-$BFFF Cartridge RAM (If Available)
|
||||
$9C00-$9FFF BG Map Data 2
|
||||
$9800-$9BFF BG Map Data 1
|
||||
$8000-$97FF Character RAM
|
||||
$4000-$7FFF Cartridge ROM - Switchable Banks 1-xx
|
||||
$0150-$3FFF Cartridge ROM - Bank 0 (fixed)
|
||||
$0100-$014F Cartridge Header Area
|
||||
$0000-$00FF Restart and Interrupt Vectors
|
||||
*/
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public partial class GBHawk
|
||||
{
|
||||
public byte ReadMemory(ushort addr)
|
||||
{
|
||||
MemoryCallbacks.CallReads(addr, "System Bus");
|
||||
|
||||
if (addr < 0x100)
|
||||
{
|
||||
// return Either BIOS ROM or Game ROM
|
||||
if ((GB_bios_register & 0x1) == 0)
|
||||
{
|
||||
return _bios[addr]; // Return BIOS
|
||||
}
|
||||
else
|
||||
{
|
||||
return mapper.ReadMemory(addr);
|
||||
}
|
||||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
return mapper.ReadMemory(addr);
|
||||
}
|
||||
else if (addr < 0x9800)
|
||||
{
|
||||
if (ppu.VRAM_access_read) { return CHR_RAM[addr - 0x8000]; }
|
||||
else { return 0xFF; }
|
||||
}
|
||||
else if (addr < 0x9C00)
|
||||
{
|
||||
if (ppu.VRAM_access_read) { return BG_map_1[addr - 0x9800]; }
|
||||
else { return 0xFF; }
|
||||
}
|
||||
else if (addr < 0xA000)
|
||||
{
|
||||
if (ppu.VRAM_access_read) { return BG_map_2[addr - 0x9C00]; }
|
||||
else { return 0xFF; }
|
||||
}
|
||||
else if (addr < 0xC000)
|
||||
{
|
||||
return mapper.ReadMemory(addr);
|
||||
}
|
||||
else if (addr < 0xE000)
|
||||
{
|
||||
return RAM[addr - 0xC000];
|
||||
}
|
||||
else if (addr < 0xFE00)
|
||||
{
|
||||
return RAM[addr - 0xE000];
|
||||
}
|
||||
else if (addr < 0xFEA0)
|
||||
{
|
||||
if (ppu.OAM_access_read) { return OAM[addr - 0xFE00]; }
|
||||
else { return 0xFF; }
|
||||
}
|
||||
else if (addr < 0xFF00)
|
||||
{
|
||||
// unmapped memory, returns 0xFF
|
||||
return 0xFF;
|
||||
}
|
||||
else if (addr < 0xFF80)
|
||||
{
|
||||
return Read_Registers(addr);
|
||||
}
|
||||
else if (addr < 0xFFFF)
|
||||
{
|
||||
return ZP_RAM[addr - 0xFF80];
|
||||
}
|
||||
else
|
||||
{
|
||||
return Read_Registers(addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
MemoryCallbacks.CallWrites(addr, "System Bus");
|
||||
|
||||
if (addr < 0x100)
|
||||
{
|
||||
// return Either BIOS ROM or Game ROM
|
||||
if ((GB_bios_register & 0x1) == 0)
|
||||
{
|
||||
// Can't write to BIOS region
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper.WriteMemory(addr, value);
|
||||
}
|
||||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
mapper.WriteMemory(addr, value);
|
||||
}
|
||||
else if (addr < 0x9800)
|
||||
{
|
||||
if (ppu.VRAM_access_write) { CHR_RAM[addr - 0x8000] = value; }
|
||||
}
|
||||
else if (addr < 0x9C00)
|
||||
{
|
||||
if (ppu.VRAM_access_write) { BG_map_1[addr - 0x9800] = value; }
|
||||
}
|
||||
else if (addr < 0xA000)
|
||||
{
|
||||
if (ppu.VRAM_access_write) { BG_map_2[addr - 0x9C00] = value; }
|
||||
}
|
||||
else if (addr < 0xC000)
|
||||
{
|
||||
mapper.WriteMemory(addr, value);
|
||||
}
|
||||
else if (addr < 0xE000)
|
||||
{
|
||||
RAM[addr - 0xC000] = value;
|
||||
}
|
||||
else if (addr < 0xFE00)
|
||||
{
|
||||
RAM[addr - 0xE000] = value;
|
||||
}
|
||||
else if (addr < 0xFEA0)
|
||||
{
|
||||
if (ppu.OAM_access_write) { OAM[addr - 0xFE00] = value; }
|
||||
}
|
||||
else if (addr < 0xFF00)
|
||||
{
|
||||
// unmapped, writing has no effect
|
||||
}
|
||||
else if (addr < 0xFF80)
|
||||
{
|
||||
Write_Registers(addr, value);
|
||||
}
|
||||
else if (addr < 0xFFFF)
|
||||
{
|
||||
ZP_RAM[addr - 0xFF80] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Write_Registers(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
TODO:
|
|
@ -0,0 +1,175 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Timer Emulation
|
||||
public class Timer
|
||||
{
|
||||
public GBHawk Core { get; set; }
|
||||
|
||||
public ushort divider_reg;
|
||||
public byte timer_reload;
|
||||
public byte timer;
|
||||
public byte timer_old;
|
||||
public byte timer_control;
|
||||
public byte pending_reload;
|
||||
public byte write_ignore;
|
||||
public bool old_state;
|
||||
public bool state;
|
||||
public bool reload_block;
|
||||
public bool TMA_coincidence;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF04: ret = (byte)(divider_reg >> 8); break; // DIV register
|
||||
case 0xFF05: ret = timer; break; // TIMA (Timer Counter)
|
||||
case 0xFF06: ret = timer_reload; break; // TMA (Timer Modulo)
|
||||
case 0xFF07: ret = timer_control; break; // TAC (Timer Control)
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
// DIV register
|
||||
case 0xFF04:
|
||||
divider_reg = 0;
|
||||
break;
|
||||
|
||||
// TIMA (Timer Counter)
|
||||
case 0xFF05:
|
||||
if (write_ignore == 0)
|
||||
{
|
||||
timer_old = timer;
|
||||
timer = value;
|
||||
reload_block = true;
|
||||
}
|
||||
break;
|
||||
|
||||
// TMA (Timer Modulo)
|
||||
case 0xFF06:
|
||||
timer_reload = value;
|
||||
if (TMA_coincidence)
|
||||
{
|
||||
timer = timer_reload;
|
||||
timer_old = timer;
|
||||
}
|
||||
break;
|
||||
|
||||
// TAC (Timer Control)
|
||||
case 0xFF07:
|
||||
timer_control = (byte)((timer_control & 0xf8) | (value & 0x7)); // only bottom 3 bits function
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void tick_1()
|
||||
{
|
||||
if (write_ignore > 0)
|
||||
{
|
||||
write_ignore--;
|
||||
if (write_ignore==0)
|
||||
{
|
||||
TMA_coincidence = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pending_reload > 0)
|
||||
{
|
||||
pending_reload--;
|
||||
if (pending_reload == 0 && !reload_block)
|
||||
{
|
||||
timer = timer_reload;
|
||||
timer_old = timer;
|
||||
write_ignore = 4;
|
||||
TMA_coincidence = true;
|
||||
|
||||
// set interrupts
|
||||
if (Core.REG_FFFF.Bit(2)) { Core.cpu.FlagI = true; }
|
||||
Core.REG_FF0F |= 0x04;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void tick_2()
|
||||
{
|
||||
divider_reg++;
|
||||
|
||||
// pick a bit to test based on the current value of timer control
|
||||
switch (timer_control & 3)
|
||||
{
|
||||
case 0:
|
||||
state = divider_reg.Bit(9);
|
||||
break;
|
||||
case 1:
|
||||
state = divider_reg.Bit(3);
|
||||
break;
|
||||
case 2:
|
||||
state = divider_reg.Bit(5);
|
||||
break;
|
||||
case 3:
|
||||
state = divider_reg.Bit(7);
|
||||
break;
|
||||
}
|
||||
|
||||
// And it with the state of the timer on/off bit
|
||||
state &= timer_control.Bit(2);
|
||||
|
||||
// this procedure allows several glitchy timer ticks, since it only measures falling edge of the state
|
||||
// so things like turning the timer off and resetting the divider will tick the timer
|
||||
if (old_state && !state)
|
||||
{
|
||||
timer_old = timer;
|
||||
timer++;
|
||||
|
||||
// if overflow, set the interrupt flag and reload the timer (4 clocks later)
|
||||
if (timer < timer_old)
|
||||
{
|
||||
pending_reload = 4;
|
||||
reload_block = false;
|
||||
}
|
||||
}
|
||||
|
||||
old_state = state;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
divider_reg = 0;
|
||||
timer_reload = 0;
|
||||
timer = 0;
|
||||
timer_old = 0;
|
||||
timer_control = 0xF8;
|
||||
pending_reload = 0;
|
||||
write_ignore = 0;
|
||||
old_state = false;
|
||||
state = false;
|
||||
reload_block = false;
|
||||
TMA_coincidence = false;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("divider_reg", ref divider_reg);
|
||||
ser.Sync("timer_reload", ref timer_reload);
|
||||
ser.Sync("timer", ref timer);
|
||||
ser.Sync("timer_old", ref timer_old);
|
||||
ser.Sync("timer_control", ref timer_control);
|
||||
ser.Sync("pending_reload", ref pending_reload);
|
||||
ser.Sync("write_ignore", ref write_ignore);
|
||||
ser.Sync("old_state", ref old_state);
|
||||
ser.Sync("state", ref state);
|
||||
ser.Sync("reload_block", ref reload_block);
|
||||
ser.Sync("TMA_coincidence", ref TMA_coincidence);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.Components.Z80GB;
|
||||
using BizHawk.Emulation.Common.Components.LR35902;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
public override string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
ushort tmp;
|
||||
string ret = NewDisassembler.Disassemble((ushort)addr, a => m.PeekByte(a), out tmp);
|
||||
string ret = LR35902.Disassemble((ushort)addr, a => m.PeekByte(a), out tmp);
|
||||
length = tmp;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -80,11 +80,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
|
||||
public class GambatteSyncSettings
|
||||
{
|
||||
[DisplayName("Enable BIOS: WARNING: File must exist!")]
|
||||
[Description("Boots game using system BIOS. Should be used for TASing")]
|
||||
[DefaultValue(false)]
|
||||
public bool EnableBIOS { get; set; }
|
||||
|
||||
public enum ConsoleModeType
|
||||
{
|
||||
Auto,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.Components.Z80GB;
|
||||
using BizHawk.Emulation.Common.Components.LR35902;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||
{
|
||||
|
@ -19,8 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
Tracer.Put(new TraceInfo
|
||||
{
|
||||
Disassembly =
|
||||
NewDisassembler
|
||||
.Disassemble((ushort)s[1], addr => LibGambatte.gambatte_cpuread(GambatteState, addr), out unused)
|
||||
LR35902.Disassemble((ushort)s[1], addr => LibGambatte.gambatte_cpuread(GambatteState, addr), out unused)
|
||||
.PadRight(36),
|
||||
RegisterInfo =
|
||||
string.Format(
|
||||
|
|
|
@ -99,16 +99,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
break;
|
||||
}
|
||||
|
||||
if (_syncSettings.EnableBIOS && BiosRom == null)
|
||||
{
|
||||
throw new MissingFirmwareException("Boot Rom not found");
|
||||
}
|
||||
|
||||
// to disable BIOS loading into gambatte, just set bios_length to 0
|
||||
if (!_syncSettings.EnableBIOS)
|
||||
{
|
||||
bios_length = 0;
|
||||
}
|
||||
bios_length = 0;
|
||||
|
||||
if (_syncSettings.GBACGB)
|
||||
{
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
TODO:
|
Loading…
Reference in New Issue