GBHawk: CPU optimizations

This commit is contained in:
alyosha-tas 2020-02-28 20:46:33 -05:00
parent 2e645d0563
commit c9621eff19
8 changed files with 431 additions and 396 deletions

View File

@ -9,7 +9,8 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
// variables for executing instructions
public int instr_pntr = 0;
public ushort[] cur_instr;
public ushort[] cur_instr = new ushort [60];
public ushort[] instr_table = new ushort[256 * 2 * 60 + 60 * 8];
public int opcode;
public bool CB_prefix;
public bool halted;
@ -17,11 +18,14 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public bool jammed;
public int LY;
public void FetchInstruction(byte opcode)
// unsaved variables
public bool checker;
public void BuildInstructionTable()
{
if (!CB_prefix)
for (int i = 0; i < 256; i++)
{
switch (opcode)
switch (i)
{
case 0x00: NOP_(); break; // NOP
case 0x01: LD_IND_16(C, B, PCl, PCh); break; // LD BC, nn
@ -47,7 +51,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 0x18: JR_COND(ALWAYS_T); 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
@ -55,7 +59,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 0x20: JR_COND(FLAG_NZ); 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
@ -63,7 +67,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 0x28: JR_COND(FLAG_Z); break; // JR Z, r8
case 0x29: ADD_16(L, H, L, H); break; // ADD HL, HL
case 0x2A: LD_IND_8_INC_HL(A, L, H); break; // LD A, (HL+)
case 0x2B: DEC_16(L, H); break; // DEC HL
@ -71,7 +75,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 0x30: JR_COND(FLAG_NC); 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
@ -79,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 0x38: JR_COND(FLAG_C); break; // JR C, r8
case 0x39: ADD_16(L, H, SPl, SPh); break; // ADD HL, SP
case 0x3A: LD_IND_8_DEC_HL(A, L, H); break; // LD A, (HL-)
case 0x3B: DEC_16(SPl, SPh); break; // DEC SP
@ -215,35 +219,35 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 0xC0: RET_COND(FLAG_NZ); 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 0xC2: JP_COND(FLAG_NZ); break; // JP NZ
case 0xC3: JP_COND(ALWAYS_T); break; // JP
case 0xC4: CALL_COND(FLAG_NZ); 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 0xC8: RET_COND(FLAG_Z); break; // RET Z
case 0xC9: RET_(); break; // RET
case 0xCA: JP_COND(FlagZ); break; // JP Z
case 0xCA: JP_COND(FLAG_Z); break; // JP Z
case 0xCB: PREFIX_(); break; // PREFIX
case 0xCC: CALL_COND(FlagZ); break; // CALL Z
case 0xCD: CALL_COND(true); break; // CALL
case 0xCC: CALL_COND(FLAG_Z); break; // CALL Z
case 0xCD: CALL_COND(ALWAYS_T); 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 0xD0: RET_COND(FLAG_NC); break; // Ret NC
case 0xD1: POP_(E, D); break; // POP DE
case 0xD2: JP_COND(!FlagC); break; // JP NC
case 0xD2: JP_COND(FLAG_NC); break; // JP NC
case 0xD3: JAM_(); break; // JAM
case 0xD4: CALL_COND(!FlagC); break; // CALL NC
case 0xD4: CALL_COND(FLAG_NC); 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 0xD8: RET_COND(FLAG_C); break; // RET C
case 0xD9: RETI_(); break; // RETI
case 0xDA: JP_COND(FlagC); break; // JP C
case 0xDA: JP_COND(FLAG_C); break; // JP C
case 0xDB: JAM_(); break; // JAM
case 0xDC: CALL_COND(FlagC); break; // CALL C
case 0xDC: CALL_COND(FLAG_C); 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
@ -280,11 +284,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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)
for (int j = 0; j < cur_instr.Length; j++)
{
instr_table[i * 60 + j] = cur_instr[j];
}
switch (i)
{
case 0x00: INT_OP(RLC, B); break; // RLC B
case 0x01: INT_OP(RLC, C); break; // RLC C
@ -543,7 +549,69 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
case 0xFE: BIT_OP_IND(SET, 7, L, H); break; // SET 7, (HL)
case 0xFF: BIT_OP(SET, 7, A); break; // SET 7, A
}
for (int j = 0; j < cur_instr.Length; j++)
{
instr_table[256 * 60 + i * 60 + j] = cur_instr[j];
}
}
// other miscellaneous vectors
// reset
instr_table[256 * 60 * 2] = IDLE;
instr_table[256 * 60 * 2 + 1] = IDLE;
instr_table[256 * 60 * 2 + 2] = HALT_CHK;
instr_table[256 * 60 * 2 + 3] = OP;
// halt loop
instr_table[256 * 60 * 2 + 60] = IDLE;
instr_table[256 * 60 * 2 + 60 + 1] = IDLE;
instr_table[256 * 60 * 2 + 60 + 2] = IDLE;
instr_table[256 * 60 * 2 + 60 + 3] = OP;
// skipped loop
instr_table[256 * 60 * 2 + 60 * 2] = IDLE;
instr_table[256 * 60 * 2 + 60 * 2 + 1] = IDLE;
instr_table[256 * 60 * 2 + 60 * 2 + 2] = IDLE;
instr_table[256 * 60 * 2 + 60 * 2 + 3] = HALT;
instr_table[256 * 60 * 2 + 60 * 2 + 4] = (ushort)0;
// GBC Halt loop
instr_table[256 * 60 * 2 + 60 * 3] = IDLE;
instr_table[256 * 60 * 2 + 60 * 3 + 1] = IDLE;
instr_table[256 * 60 * 2 + 60 * 3 + 2] = HALT_CHK;
instr_table[256 * 60 * 2 + 60 * 3 + 3] = HALT;
instr_table[256 * 60 * 2 + 60 * 3 + 4] = (ushort)0;
// spec Halt loop
instr_table[256 * 60 * 2 + 60 * 4] = HALT_CHK;
instr_table[256 * 60 * 2 + 60 * 4 + 1] = IDLE;
instr_table[256 * 60 * 2 + 60 * 4 + 2] = IDLE;
instr_table[256 * 60 * 2 + 60 * 4 + 3] = HALT;
instr_table[256 * 60 * 2 + 60 * 4 + 4] = (ushort)0;
// Stop loop
instr_table[256 * 60 * 2 + 60 * 5] = IDLE;
instr_table[256 * 60 * 2 + 60 * 5 + 1] = IDLE;
instr_table[256 * 60 * 2 + 60 * 5 + 2] = IDLE;
instr_table[256 * 60 * 2 + 60 * 5 + 3] = STOP;
// interrupt vectors
INTERRUPT_();
for (int i = 0; i < cur_instr.Length; i++)
{
instr_table[256 * 60 * 2 + 60 * 6 + i] = cur_instr[i];
}
INTERRUPT_GBC_NOP();
for (int i = 0; i < cur_instr.Length; i++)
{
instr_table[256 * 60 * 2 + 60 * 7 + i] = cur_instr[i];
}
}
}
}

View File

@ -9,18 +9,18 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
DEC16, SPl, SPh,
IDLE,
WR, SPl, SPh, PCh,
IDLE,
INT_GET, 4, W,
DEC16, SPl, SPh,
IDLE,
INT_GET, 3, W,
WR, SPl, SPh, PCl,
INT_GET, 2, W,
IDLE,
INT_GET, 1, W,
IDLE,
IDLE,
IDLE,
IDLE,
INT_GET, 0, W,
ASGN, PCh, 0,
IDLE,
INT_GET, W,// NOTE: here is where we check for a cancelled IRQ
IDLE,
TR, PCl, W,
IRQ_CLEAR,
IDLE,
@ -41,13 +41,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
INT_GET, W,// NOTE: here is where we check for a cancelled IRQ
IDLE,
INT_GET, 4, W,
INT_GET, 3, W,
INT_GET, 2, W,
INT_GET, 1, W,
INT_GET, 0, W,
TR, PCl, W,
IDLE,
ASGN, PCh, 0,
@ -75,6 +75,9 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
Halt_bug_2 = false;
Halt_bug_3 = false;
interrupts_enabled = false;
int_src = 5;
int_clear = 0;
}
}
}

View File

@ -56,6 +56,16 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public const ushort INT_GET = 44;
public const ushort HALT_CHK = 45; // when in halt mode, actually check I Flag here
public const ushort IRQ_CLEAR = 46;
public const ushort COND_CHECK = 47;
public const ushort HALT_FUNC = 48;
// test conditions
public const ushort ALWAYS_T = 0;
public const ushort ALWAYS_F = 1;
public const ushort FLAG_Z = 2;
public const ushort FLAG_NZ = 3;
public const ushort FLAG_C = 4;
public const ushort FLAG_NC = 5;
public LR35902()
{
@ -66,11 +76,11 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
{
ResetRegisters();
ResetInterrupts();
BuildInstructionTable();
TotalExecutedCycles = 8;
stop_check = false;
cur_instr = new ushort[] { IDLE, IDLE, HALT_CHK, OP };
instr_pntr = 256 * 60 * 2; // point to reset
stopped = jammed = halted = FlagI = false;
instr_pntr = 0;
EI_pending = 0;
CB_prefix = false;
}
@ -126,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
// Execute instructions
public void ExecuteOne(ref byte interrupt_src, byte interrupt_enable)
{
switch (cur_instr[instr_pntr++])
switch (instr_table[instr_pntr++])
{
case IDLE:
// do nothing
@ -154,7 +164,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
// call interrupt processor
// lowest bit set is highest priority
INTERRUPT_();
instr_pntr = 256 * 60 * 2 + 60 * 6; // point to Interrupt
}
else
{
@ -163,101 +173,100 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
CDLCallback?.Invoke(RegPC, eCDLogMemFlags.FetchFirst);
FetchInstruction(ReadMemory(RegPC++));
}
instr_pntr = 0;
I_use = false;
break;
case RD:
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
Read_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case WR:
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
Write_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case TR:
TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
TR_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case ADD16:
ADD16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
ADD16_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case ADD8:
ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
ADD8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case SUB8:
SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
SUB8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case ADC8:
ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
ADC8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case SBC8:
SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
SBC8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case INC16:
INC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
INC16_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case INC8:
INC8_Func(cur_instr[instr_pntr++]);
INC8_Func(instr_table[instr_pntr++]);
break;
case DEC16:
DEC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
DEC16_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case DEC8:
DEC8_Func(cur_instr[instr_pntr++]);
DEC8_Func(instr_table[instr_pntr++]);
break;
case RLC:
RLC_Func(cur_instr[instr_pntr++]);
RLC_Func(instr_table[instr_pntr++]);
break;
case RL:
RL_Func(cur_instr[instr_pntr++]);
RL_Func(instr_table[instr_pntr++]);
break;
case RRC:
RRC_Func(cur_instr[instr_pntr++]);
RRC_Func(instr_table[instr_pntr++]);
break;
case RR:
RR_Func(cur_instr[instr_pntr++]);
RR_Func(instr_table[instr_pntr++]);
break;
case CPL:
CPL_Func(cur_instr[instr_pntr++]);
CPL_Func(instr_table[instr_pntr++]);
break;
case DA:
DA_Func(cur_instr[instr_pntr++]);
DA_Func(instr_table[instr_pntr++]);
break;
case SCF:
SCF_Func(cur_instr[instr_pntr++]);
SCF_Func(instr_table[instr_pntr++]);
break;
case CCF:
CCF_Func(cur_instr[instr_pntr++]);
CCF_Func(instr_table[instr_pntr++]);
break;
case AND8:
AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
AND8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case XOR8:
XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
XOR8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case OR8:
OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
OR8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case CP8:
CP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
CP8_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case SLA:
SLA_Func(cur_instr[instr_pntr++]);
SLA_Func(instr_table[instr_pntr++]);
break;
case SRA:
SRA_Func(cur_instr[instr_pntr++]);
SRA_Func(instr_table[instr_pntr++]);
break;
case SRL:
SRL_Func(cur_instr[instr_pntr++]);
SRL_Func(instr_table[instr_pntr++]);
break;
case SWAP:
SWAP_Func(cur_instr[instr_pntr++]);
SWAP_Func(instr_table[instr_pntr++]);
break;
case BIT:
BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
BIT_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case RES:
RES_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
RES_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case SET:
SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
SET_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case EI:
if (EI_pending == 0) { EI_pending = 2; }
@ -271,7 +280,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
bool temp = false;
if (cur_instr[instr_pntr++] == 1)
if (instr_table[instr_pntr++] == 1)
{
temp = FlagI;
}
@ -306,11 +315,11 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
// call the interrupt processor after 4 extra cycles
if (!Halt_bug_3)
{
INTERRUPT_GBC_NOP();
instr_pntr = 256 * 60 * 2 + 60 * 7; // point to Interrupt for GBC
}
else
{
INTERRUPT_();
instr_pntr = 256 * 60 * 2 + 60 * 6; // point to Interrupt
Halt_bug_3 = false;
//Console.WriteLine("Hit INT");
}
@ -318,7 +327,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
else
{
// call interrupt processor
INTERRUPT_();
instr_pntr = 256 * 60 * 2 + 60 * 6; // point to Interrupt
Halt_bug_3 = false;
}
}
@ -348,13 +357,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
}
else
{
cur_instr = new[]
{
IDLE,
IDLE,
IDLE,
OP
};
instr_pntr = 256 * 60 * 2 + 60; // point to halt loop
}
}
else
@ -380,37 +383,22 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
{
if (skip_once)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
HALT, 0 };
instr_pntr = 256 * 60 * 2 + 60 * 2; // point to skipped loop
skip_once = false;
}
else
{
if (is_GBC)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
HALT_CHK,
HALT, 0 };
instr_pntr = 256 * 60 * 2 + 60 * 3; // point to GBC Halt loop
}
else
{
cur_instr = new ushort[]
{HALT_CHK,
IDLE,
IDLE,
HALT, 0 };
instr_pntr = 256 * 60 * 2 + 60 * 4; // point to spec Halt loop
}
}
}
}
I_use = false;
instr_pntr = 0;
break;
case STOP:
stopped = true;
@ -436,18 +424,12 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
CDLCallback?.Invoke(RegPC, eCDLogMemFlags.FetchFirst);
FetchInstruction(ReadMemory(RegPC++));
instr_pntr = 0;
stop_check = false;
}
else
{
instr_pntr = 0;
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
STOP };
instr_pntr = 256 * 60 * 2 + 60 * 5; // point to stop loop
}
}
else if (interrupt_src.Bit(4)) // button pressed, not actually an interrupt though
@ -463,30 +445,22 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
CDLCallback?.Invoke(RegPC, eCDLogMemFlags.FetchFirst);
FetchInstruction(ReadMemory(RegPC++));
instr_pntr = 0;
stop_check = false;
}
else
{
instr_pntr = 0;
cur_instr = new[]
{
IDLE,
IDLE,
IDLE,
STOP
};
instr_pntr = 256 * 60 * 2 + 60 * 5; // point to stop loop
}
break;
case PREFIX:
CB_prefix = true;
break;
case ASGN:
ASGN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
ASGN_Func(instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case ADDS:
ADDS_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
ADDS_Func(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case OP_G:
OnExecFetch?.Invoke(RegPC);
@ -494,15 +468,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
CDLCallback?.Invoke(RegPC, eCDLogMemFlags.FetchFirst);
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++]);
Read_Func_F(instr_table[instr_pntr++], instr_table[instr_pntr++], instr_table[instr_pntr++]);
break;
case EI_RETI:
EI_pending = 1;
@ -510,16 +482,20 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
case INT_GET:
// check if any interrupts got cancelled along the way
// interrupt src = 5 sets the PC to zero as observed
// also the triggering interrupt seems like it is held low (i.e. annot trigger I flag) until the interrupt is serviced
// also the triggering interrupt seems like it is held low (i.e. cannot trigger I flag) until the interrupt is serviced
ushort bit_check = instr_table[instr_pntr++];
//Console.WriteLine(interrupt_src + " " + interrupt_enable + " " + TotalExecutedCycles);
if (interrupt_src.Bit(bit_check) && interrupt_enable.Bit(bit_check)) { int_src = bit_check; int_clear = (byte)(1 << bit_check); }
/*
if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; int_clear = 1; }
else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; int_clear = 2; }
else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; int_clear = 4; }
else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; int_clear = 8; }
else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; int_clear = 16; }
else { int_src = 5; int_clear = 0; }
Regs[cur_instr[instr_pntr++]] = INT_vectors[int_src];
*/
Regs[instr_table[instr_pntr++]] = INT_vectors[int_src];
break;
case HALT_CHK:
I_use = FlagI;
@ -538,6 +514,83 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
// reset back to default state
int_src = 5;
int_clear = 0;
break;
case COND_CHECK:
checker = false;
switch (instr_table[instr_pntr++])
{
case ALWAYS_T:
checker = true;
break;
case ALWAYS_F:
checker = false;
break;
case FLAG_Z:
checker = FlagZ;
break;
case FLAG_NZ:
checker = !FlagZ;
break;
case FLAG_C:
checker = FlagC;
break;
case FLAG_NC:
checker = !FlagC;
break;
}
// true condition is what is represented in the instruction vectors
// jump ahead if false
if (checker)
{
instr_pntr++;
}
else
{
// 0 = JR COND, 1 = JP COND, 2 = RET COND, 3 = CALL
switch (instr_table[instr_pntr++])
{
case 0:
instr_pntr += 10;
break;
case 1:
instr_pntr += 8;
break;
case 2:
instr_pntr += 22;
break;
case 3:
instr_pntr += 26;
break;
}
}
break;
case HALT_FUNC:
if (was_FlagI && (EI_pending == 0) && !interrupts_enabled)
{
// in GBC mode, the HALT bug is worked around by simply adding a NOP
// so it just takes 4 cycles longer to reach the next instruction
// otherwise, if interrupts are disabled,
// a glitchy decrement to the program counter happens
// either way, nothing needs to be done here
}
else
{
instr_pntr += 3;
if (!is_GBC) { skip_once = true; }
// If the interrupt flag is not currently set, but it does get set in the first check
// then a bug is triggered
// With interrupts enabled, this runs the halt command twice
// when they are disabled, it reads the next byte twice
if (!was_FlagI || (was_FlagI && !interrupts_enabled)) { Halt_bug_2 = true; }
}
break;
}
TotalExecutedCycles++;
@ -577,8 +630,23 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
interrupts_enabled ? "E" : "e"))
};
}
// State Save/Load
void FetchInstruction(int op)
{
opcode = op;
instr_pntr = 0;
if (CB_prefix) { instr_pntr += 256 * 60; }
instr_pntr += op * 60;
CB_prefix = false;
was_FlagI = FlagI;
}
// State Save/Load
public void SyncState(Serializer ser)
{
ser.BeginSection(nameof(LR35902));
@ -598,13 +666,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
ser.Sync(nameof(is_GBC), ref is_GBC);
ser.Sync(nameof(instr_pntr), ref instr_pntr);
ser.Sync(nameof(cur_instr), ref cur_instr, false);
ser.Sync(nameof(CB_prefix), ref CB_prefix);
ser.Sync(nameof(stopped), ref stopped);
ser.Sync(nameof(opcode), ref opcode);
ser.Sync(nameof(jammed), ref jammed);
ser.Sync(nameof(LY), ref LY);
ser.Sync(nameof(FlagI), ref FlagI);
ser.Sync(nameof(was_FlagI), ref was_FlagI);
ser.EndSection();
}

View File

@ -4,6 +4,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
{
public partial class LR35902
{
// local variables for operations, not stated
int Reg16_d, Reg16_s, c;
ushort ans, ans_l, ans_h, temp;
byte a_d;
bool imm;
public void Read_Func(ushort dest, ushort src_l, ushort src_h)
{
ushort addr = (ushort)(Regs[src_l] | (Regs[src_h]) << 8);
@ -35,15 +42,15 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
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 = Regs[dest_l] | (Regs[dest_h] << 8);
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);
ans_l = (ushort)(Reg16_d & 0xFF);
ans_h = (ushort)((Reg16_d & 0xFF00) >> 8);
// redo for half carry flag
Reg16_d = Regs[dest_l] | ((Regs[dest_h] & 0x0F) << 8);
@ -60,13 +67,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void ADD8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d = Regs[dest];
Reg16_d += Regs[src];
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
@ -81,13 +88,13 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void SUB8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d = Regs[dest];
Reg16_d -= Regs[src];
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
@ -123,7 +130,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void SWAP_Func(ushort src)
{
ushort temp = (ushort)((Regs[src] << 4) & 0xF0);
temp = (ushort)((Regs[src] << 4) & 0xF0);
Regs[src] = (ushort)(temp | (Regs[src] >> 4));
FlagZ = Regs[src] == 0;
@ -147,7 +154,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
{
FlagC = Regs[src].Bit(0);
ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation
temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation
Regs[src] = (ushort)((Regs[src] >> 1) | temp);
@ -221,7 +228,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void CP8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d = Regs[dest];
Reg16_d -= Regs[src];
FlagC = Reg16_d.Bit(8);
@ -238,7 +245,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void RRC_Func(ushort src)
{
bool imm = src == Aim;
imm = src == Aim;
if (imm) { src = A; }
FlagC = Regs[src].Bit(0);
@ -252,10 +259,10 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void RR_Func(ushort src)
{
bool imm = src == Aim;
imm = src == Aim;
if (imm) { src = A; }
ushort c = (ushort)(FlagC ? 0x80 : 0);
c = FlagC ? 0x80 : 0;
FlagC = Regs[src].Bit(0);
@ -268,10 +275,10 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void RLC_Func(ushort src)
{
bool imm = src == Aim;
imm = src == Aim;
if (imm) { src = A; }
ushort c = (ushort)(Regs[src].Bit(7) ? 1 : 0);
c = Regs[src].Bit(7) ? 1 : 0;
FlagC = Regs[src].Bit(7);
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
@ -283,10 +290,10 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void RL_Func(ushort src)
{
bool imm = src == Aim;
imm = src == Aim;
if (imm) { src = A; }
ushort c = (ushort)(FlagC ? 1 : 0);
c = FlagC ? 1 : 0;
FlagC = Regs[src].Bit(7);
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
@ -298,12 +305,12 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void INC8_Func(ushort src)
{
int Reg16_d = Regs[src];
Reg16_d = Regs[src];
Reg16_d += 1;
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[src] & 0xF;
@ -317,12 +324,12 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void DEC8_Func(ushort src)
{
int Reg16_d = Regs[src];
Reg16_d = Regs[src];
Reg16_d -= 1;
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[src] & 0xF;
@ -336,7 +343,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void INC16_Func(ushort src_l, ushort src_h)
{
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
Reg16_d += 1;
@ -346,7 +353,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void DEC16_Func(ushort src_l, ushort src_h)
{
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
Reg16_d -= 1;
@ -356,15 +363,15 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void ADC8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
int c = FlagC ? 1 : 0;
Reg16_d = Regs[dest];
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);
ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
@ -378,15 +385,15 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public void SBC8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
int c = FlagC ? 1 : 0;
Reg16_d = Regs[dest];
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);
ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
@ -401,36 +408,36 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
// 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];
a_d = (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; }
if (FlagC || a_d > 0x99) { a_d += 0x60; FlagC = true; }
if (FlagH || (a_d & 0x0f) > 0x09) { a_d += 0x6; }
}
else
{ // after a subtraction, only adjust if (half-)carry occurred
if (FlagC) { a -= 0x60; }
if (FlagH) { a -= 0x6; }
if (FlagC) { a_d -= 0x60; }
if (FlagH) { a_d -= 0x6; }
}
a &= 0xFF;
a_d &= 0xFF;
Regs[src] = a;
Regs[src] = a_d;
FlagZ = a == 0;
FlagZ = a_d == 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 = Regs[dest_l];
Reg16_s = Regs[src_l];
Reg16_d += Reg16_s;
ushort temp = 0;
temp = 0;
// since this is signed addition, calculate the high byte carry appropriately
if (Reg16_s.Bit(7))
@ -449,7 +456,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
temp = (ushort)(Reg16_d.Bit(8) ? 1 : 0);
}
ushort ans_l = (ushort)(Reg16_d & 0xFF);
ans_l = (ushort)(Reg16_d & 0xFF);
// JR operations do not effect flags
if (dest_l != PCl)

View File

@ -26,7 +26,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public ushort[] Regs = new ushort[14];
public bool FlagI;
public bool was_FlagI, FlagI;
public bool FlagC
{

View File

@ -8,46 +8,40 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
private void NOP_()
{
cur_instr = new[]
{
IDLE,
IDLE,
HALT_CHK,
OP
};
{IDLE,
IDLE,
HALT_CHK,
OP };
}
private void INC_16(ushort srcL, ushort srcH)
{
cur_instr = new[]
{
IDLE,
IDLE,
IDLE,
INC16,
srcL,
srcH,
IDLE,
IDLE,
HALT_CHK,
OP
};
{IDLE,
IDLE,
IDLE,
INC16,
srcL,
srcH,
IDLE,
IDLE,
HALT_CHK,
OP };
}
private void DEC_16(ushort src_l, ushort src_h)
{
cur_instr = new[]
{
IDLE,
IDLE,
IDLE,
DEC16,
src_l,
src_h,
IDLE,
IDLE,
HALT_CHK,
OP
};
{IDLE,
IDLE,
IDLE,
DEC16,
src_l,
src_h,
IDLE,
IDLE,
HALT_CHK,
OP };
}
private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
@ -83,119 +77,52 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
private void HALT_()
{
if (FlagI && (EI_pending == 0) && !interrupts_enabled)
{
if (is_GBC)
{
// in GBC mode, the HALT bug is worked around by simply adding a NOP
// so it just takes 4 cycles longer to reach the next instruction
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
OP_G};
}
else
{ // if interrupts are disabled,
// a glitchy decrement to the program counter happens
{
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
OP_G};
}
}
}
else
{
cur_instr = new ushort[]
{
cur_instr = new ushort[]
{HALT_FUNC,
IDLE,
IDLE,
OP_G,
HALT_CHK,
IDLE,
HALT, 0 };
if (!is_GBC) { skip_once = true; }
// If the interrupt flag is not currently set, but it does get set in the first check
// then a bug is triggered
// With interrupts enabled, this runs the halt command twice
// when they are disabled, it reads the next byte twice
if (!FlagI ||(FlagI && !interrupts_enabled)) { Halt_bug_2 = true; }
}
HALT, 0};
}
private void JR_COND(bool cond)
private void JR_COND(ushort 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,
HALT_CHK,
OP };
}
else
{
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
HALT_CHK,
OP };
}
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, W, PCl, PCh,
INC16, PCl, PCh,
COND_CHECK, cond, (ushort)0,
IDLE,
ASGN, Z, 0,
IDLE,
ADDS, PCl, PCh, W, Z,
HALT_CHK,
OP };
}
private void JP_COND(bool cond)
private void JP_COND(ushort cond)
{
if (cond)
{
cur_instr = new[]
{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,
HALT_CHK,
OP };
}
else
{
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
HALT_CHK,
OP };
}
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
COND_CHECK, cond, (ushort)1,
IDLE,
TR, PCl, W,
IDLE,
TR, PCh, Z,
HALT_CHK,
OP };
}
private void RET_()
@ -241,92 +168,58 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
}
private void RET_COND(bool cond)
private void RET_COND(ushort cond)
{
if (cond)
{
cur_instr = new[]
{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,
HALT_CHK,
OP };
}
else
{
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
HALT_CHK,
OP };
}
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
COND_CHECK, cond, (ushort)2,
IDLE,
RD, PCl, SPl, SPh,
IDLE,
INC16, SPl, SPh,
IDLE,
RD, PCh, SPl, SPh,
IDLE,
INC16, SPl, SPh,
IDLE,
IDLE,
IDLE,
IDLE,
HALT_CHK,
OP };
}
private void CALL_COND(bool cond)
private void CALL_COND(ushort cond)
{
if (cond)
{
cur_instr = new[]
{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,
TR, PCl, W,
TR, PCh, Z,
HALT_CHK,
OP };
}
else
{
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
HALT_CHK,
OP };
}
cur_instr = new[]
{IDLE,
IDLE,
IDLE,
RD, W, PCl, PCh,
INC16, PCl, PCh,
IDLE,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
COND_CHECK, cond, (ushort)3,
DEC16, SPl, SPh,
IDLE,
IDLE,
IDLE,
IDLE,
WR, SPl, SPh, PCh,
IDLE,
IDLE,
DEC16, SPl, SPh,
WR, SPl, SPh, PCl,
TR, PCl, W,
TR, PCh, Z,
HALT_CHK,
OP };
}
private void INT_OP(ushort operation, ushort src)

View File

@ -966,7 +966,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync(nameof(SQ1_vol_done), ref SQ1_vol_done);
ser.Sync(nameof(SQ1_calc_done), ref SQ1_calc_done);
ser.Sync(nameof(SQ1_swp_enable), ref SQ1_swp_enable);
//ser.Sync("Duplicate_SQ1_len_center", ref SQ1_len_cntr); // Deleting this breaks backwards compatibility with binary states
ser.Sync(nameof(SQ1_enable), ref SQ1_enable);
ser.Sync(nameof(SQ1_vol_state), ref SQ1_vol_state);
ser.Sync(nameof(SQ1_duty_cntr), ref SQ1_duty_cntr);
@ -989,7 +988,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync(nameof(SQ1_output), ref SQ1_output);
ser.Sync(nameof(SQ2_vol_done), ref SQ2_vol_done);
ser.Sync("Duplicate_SQ2_len_counter", ref SQ2_len_cntr); // Deleting this breaks backwards compatibility with binary states
ser.Sync(nameof(SQ2_enable), ref SQ2_enable);
ser.Sync(nameof(SQ2_vol_state), ref SQ2_vol_state);
ser.Sync(nameof(SQ2_duty_cntr), ref SQ2_duty_cntr);
@ -1007,7 +1005,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync(nameof(SQ2_output), ref SQ2_output);
ser.Sync(nameof(WAVE_can_get), ref WAVE_can_get);
ser.Sync("duplicate_WAVE_len_counter", ref WAVE_len_cntr); // Deleting this breaks backwards compatibility with binary states
ser.Sync(nameof(WAVE_enable), ref WAVE_enable);
ser.Sync(nameof(WAVE_wave_cntr), ref WAVE_wave_cntr);
ser.Sync(nameof(WAVE_intl_cntr), ref WAVE_intl_cntr);
@ -1021,7 +1018,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync(nameof(WAVE_output), ref WAVE_output);
ser.Sync(nameof(NOISE_vol_done), ref NOISE_vol_done);
ser.Sync("NOISE_len_counter", ref NOISE_len_cntr); // Deleting this breaks backwards compatibility with binary states
ser.Sync(nameof(NOISE_enable), ref NOISE_enable);
ser.Sync(nameof(NOISE_vol_state), ref NOISE_vol_state);
ser.Sync(nameof(NOISE_intl_cntr), ref NOISE_intl_cntr);

View File

@ -922,7 +922,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x
public void GetSamplesSync(out short[] samples, out int nsamp)
{
A.audio.GetSamplesSync(out var temp_samp_A, out var nsamp_A);
B.audio.GetSamplesSync(out short[] temp_samp_B, out var nsamp_B);
B.audio.GetSamplesSync(out var temp_samp_B, out var nsamp_B);
C.audio.GetSamplesSync(out var temp_samp_C, out var nsamp_C);
D.audio.GetSamplesSync(out var temp_samp_D, out var nsamp_D);