Merge pull request #1058 from TASVideos/GBHawk

Gb hawk
This commit is contained in:
alyosha-tas 2017-11-19 10:39:55 -05:00 committed by GitHub
commit bc425ba44c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 7417 additions and 2864 deletions

View File

@ -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;

View File

@ -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
{

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -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
}
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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 =
{

View File

@ -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;
}
}
}

View File

@ -0,0 +1 @@
TODO: STOP for second byte nonzero

View File

@ -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;
}
}
}
}

View File

@ -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 };
}
}
}

View File

@ -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

View File

@ -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; }
}
}
}

View File

@ -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; }
}
}

View File

@ -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

View File

@ -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; }
}
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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
}
}
}

View File

@ -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;
}
}
}

View File

@ -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()
{
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,3 @@
TODO:
Official Mappers
Unofficial Mappers

View File

@ -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

View File

@ -0,0 +1 @@
TODO:

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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(

View File

@ -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)
{

1
ReadMe.txt Normal file
View File

@ -0,0 +1 @@
TODO: