From a185f334876a52c463427d14f2b6f56b3d4c8105 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 15 May 2018 09:44:39 -0400 Subject: [PATCH] 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. --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 1 + .../CPUs/Z80A/Registers.cs | 8 +- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 150 ++++++++++++++++-- 3 files changed, 139 insertions(+), 20 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index eddf74d0a4..5f4ccb2437 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -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; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index 14e447bc65..0e8dde3435 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -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; } } - - - } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index f26582dd41..c3786015a3 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -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);