Z80A: Add a WAIT state that can puase the CPU on reads / writes

NOTE: a wait state is added automatically to IN/OUT reads / writes, but I don't know if this is already accounted for in the cycle timings, TODO.
This commit is contained in:
alyosha-tas 2018-05-15 09:44:39 -04:00
parent 258fef46d7
commit a185f33487
3 changed files with 139 additions and 20 deletions

View File

@ -18,6 +18,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
// variables for executing instructions
public int instr_pntr = 0;
public ushort instr_swap;
public ushort[] cur_instr;
public int opcode;
public bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix;

View File

@ -45,6 +45,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
public bool FlagI;
public bool FlagW; // wait flag, when set to true reads / writes will be delayed
public bool FlagC
{
get { return (Regs[5] & 0x01) != 0; }
@ -109,6 +111,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
{
Regs[i] = 0;
}
FlagI = false;
FlagW = false;
}
private bool[] TableParity;
@ -125,8 +130,5 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
TableParity[i] = (Bits & 1) == 0;
}
}
}
}

View File

@ -75,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
public const ushort I_BIT = 60;
public const ushort HL_BIT = 61;
public const ushort FTCH_DB = 62;
public const ushort WAIT = 63; // enterred when readin or writing and FlagW is true
public byte temp_R;
@ -146,7 +147,6 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
// Execute instructions
public void ExecuteOne()
{
if (Regs[A] > 255) { Console.WriteLine(RegPC); }
switch (cur_instr[instr_pntr++])
{
case IDLE:
@ -174,6 +174,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
iff1 = false;
NMI_();
NMICallback();
instr_pntr = 0;
}
else if (iff1 && FlagI)
{
@ -200,14 +201,24 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
break;
}
IRQCallback();
instr_pntr = 0;
}
else
{
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null) TraceCallback(State());
FetchInstruction(FetchMemory(RegPC++));
if(!FlagW)
{
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null) TraceCallback(State());
FetchInstruction(FetchMemory(RegPC++));
instr_pntr = 0;
}
else
{
instr_pntr--;
instr_swap = OP;
cur_instr[instr_pntr] = WAIT;
}
}
instr_pntr = 0;
temp_R = (byte)(Regs[R] & 0x7F);
temp_R++;
@ -250,6 +261,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
DEC16, PCl, PCh,
OP };
instr_pntr = 0;
// adjust WZ register accordingly
switch (temp1)
{
@ -297,6 +309,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
iff1 = false;
NMI_();
NMICallback();
instr_pntr = 0;
}
else if (iff1 && FlagI)
{
@ -323,12 +336,23 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
break;
}
IRQCallback();
instr_pntr = 0;
}
else
{
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null) TraceCallback(State());
FetchInstruction(FetchMemory(RegPC++));
if (!FlagW)
{
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null) TraceCallback(State());
FetchInstruction(FetchMemory(RegPC++));
instr_pntr = 0;
}
else
{
instr_pntr--;
instr_swap = OP;
cur_instr[instr_pntr] = WAIT;
}
}
temp_R = (byte)(Regs[R] & 0x7F);
@ -336,7 +360,6 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
temp_R &= 0x7F;
Regs[R] = (byte)((Regs[R] & 0x80) | temp_R);
}
instr_pntr = 0;
break;
case HALT:
@ -409,16 +432,53 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
instr_pntr = 0;
break;
case RD:
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
if (!FlagW)
{
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
}
else
{
instr_pntr--;
instr_swap = RD;
cur_instr[instr_pntr] = WAIT;
}
break;
case WR:
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
if (!FlagW)
{
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
}
else
{
instr_pntr--;
instr_swap = WR;
cur_instr[instr_pntr] = WAIT;
}
break;
case I_RD:
I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
if (!FlagW)
{
I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
}
else
{
instr_pntr--;
instr_swap = I_RD;
cur_instr[instr_pntr] = WAIT;
}
break;
case I_WR:
I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
if (!FlagW)
{
I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
}
else
{
instr_pntr--;
instr_swap =I_WR;
cur_instr[instr_pntr] = WAIT;
}
break;
case TR:
TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
@ -572,10 +632,28 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
iff1 = iff2;
break;
case OUT:
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
if (!FlagW)
{
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
}
else
{
instr_pntr--;
instr_swap = OUT;
cur_instr[instr_pntr] = WAIT;
}
break;
case IN:
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
if (!FlagW)
{
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
}
else
{
instr_pntr--;
instr_swap = IN;
cur_instr[instr_pntr] = WAIT;
}
break;
case NEG:
NEG_8_Func(cur_instr[instr_pntr++]);
@ -601,6 +679,42 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
case FTCH_DB:
FTCH_DB_Func();
break;
case WAIT:
if (FlagW)
{
instr_pntr--;
}
else
{
switch (instr_swap)
{
case OP:
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null) TraceCallback(State());
FetchInstruction(FetchMemory(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 I_RD:
I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case I_WR:
I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case IN:
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case OUT:
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
}
}
break;
}
TotalExecutedCycles++;
}
@ -672,10 +786,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
ser.Sync("ExecutedCycles", ref TotalExecutedCycles);
ser.Sync("EI_pending", ref EI_pending);
ser.Sync("instruction_pointer", ref instr_pntr);
ser.Sync("current instruction", ref cur_instr, false);
ser.Sync("instr_pntr", ref instr_pntr);
ser.Sync("cur_instr", ref cur_instr, false);
ser.Sync("instr_swap", ref instr_swap);
ser.Sync("opcode", ref opcode);
ser.Sync("FlagI", ref FlagI);
ser.Sync("FlagW", ref FlagW);
ser.Sync("NO Preifx", ref NO_prefix);
ser.Sync("CB Preifx", ref CB_prefix);