diff --git a/Copper68k/Copper68k.csproj b/Copper68k/Copper68k.csproj
index b29027d..b147aed 100644
--- a/Copper68k/Copper68k.csproj
+++ b/Copper68k/Copper68k.csproj
@@ -7,7 +7,7 @@
1701;1702;NU1900
Copper68k
Copper68k
- CopperMod contributors
+ Ilkka Lehtoranta
Reusable Motorola 68000-family CPU emulation core with cycle-aware interpreter backends and an opt-in MC68040 JIT.
1.1.0
Adds an opt-in internal MC68040 JIT backend through M68kCoreOptions, public JIT bus capability interfaces for host integration, and keeps the default MC68040 factory path on the interpreter for source-compatible package consumers.
diff --git a/Copper68k/M68020Interpreter.cs b/Copper68k/M68020Interpreter.cs
index bde8b63..eb40bec 100644
--- a/Copper68k/M68020Interpreter.cs
+++ b/Copper68k/M68020Interpreter.cs
@@ -4248,24 +4248,18 @@ internal void CompleteTiming(M68kInstructionTimingKey key)
_timing.CompleteInstruction(_timing.GetPlan(key));
}
+ internal void CompleteTiming(M68kTimingDescriptor descriptor)
+ {
+ _timing.CompleteInstruction(descriptor);
+ }
+
private void CompleteMovemLongTiming(
M68kInstructionTimingKey key,
string name,
int registerCount,
bool registerToMemory)
{
- const int registerListImmediateAddressCycles = 4;
- var nativeCycles = _profile.FixedInstructionNativeCycles ?? (_profile.Model == M68kAcceleratorModel.M68030
- ? registerToMemory
- ? 4 + (2 * registerCount) + registerListImmediateAddressCycles
- : 8 + (4 * registerCount) + registerListImmediateAddressCycles
- : registerToMemory
- ? 4 + (3 * registerCount) + registerListImmediateAddressCycles
- : 8 + (4 * registerCount) + registerListImmediateAddressCycles);
- var plan = _profile.Model == M68kAcceleratorModel.M68030
- ? M68kInstructionPlan.CreateHeadTail(key, name, nativeCycles, 2, 0)
- : M68kInstructionPlan.CreateFlat(key, name, nativeCycles);
- _timing.CompleteInstruction(plan);
+ CompleteTiming(M68kTimingDescriptor.MovemLong(key, name, registerCount, registerToMemory));
}
private static int CountSetBits(ushort value)
diff --git a/Copper68k/M68kTimingEngine.cs b/Copper68k/M68kTimingEngine.cs
index 0ddf92c..5f26d29 100644
--- a/Copper68k/M68kTimingEngine.cs
+++ b/Copper68k/M68kTimingEngine.cs
@@ -407,11 +407,12 @@ public void Reset()
}
public M68kInstructionPlan GetPlan(M68kInstructionTimingKey key)
+ => GetPlan(M68kTimingDescriptor.FromLegacyKey(key));
+
+ public M68kInstructionPlan GetPlan(M68kTimingDescriptor descriptor)
=> _profile.FixedInstructionNativeCycles is int fixedCycles
- ? M68kInstructionPlan.CreateFlat(key, "fixed JIT fallback", fixedCycles)
- : _profile.Model is M68kAcceleratorModel.M68030 or M68kAcceleratorModel.M68040
- ? M68030TimingModel.GetPlan(key)
- : M68020TimingModel.GetPlan(key);
+ ? M68kInstructionPlan.CreateFlat(descriptor.Key, "fixed JIT fallback", fixedCycles)
+ : M68kTimingFormula.GetPlan(descriptor, _profile.Model);
public bool ProbeInstructionCache(uint address)
=> InstructionCache.Probe(address);
@@ -530,6 +531,9 @@ public M68kExecutedInstructionTiming CompleteInstruction(M68kInstructionPlan pla
return LastInstructionTiming;
}
+ public M68kExecutedInstructionTiming CompleteInstruction(M68kTimingDescriptor descriptor)
+ => CompleteInstruction(GetPlan(descriptor));
+
private void SynchronizeMachineToNative()
{
var machineCycles = _profile.NativeToMachineCycles(_state.NativeCycles);
@@ -543,6 +547,9 @@ private void SynchronizeMachineToNative()
internal static class M68020TimingModel
{
public static M68kInstructionPlan GetPlan(M68kInstructionTimingKey key)
+ => M68kTimingFormula.GetPlan(M68kTimingDescriptor.FromLegacyKey(key), M68kAcceleratorModel.M68020);
+
+ internal static M68kInstructionPlan GetLegacyFlatPlan(M68kInstructionTimingKey key)
{
return key switch
{
@@ -758,216 +765,7 @@ private static M68kTimingBarrier ExceptionBarrier()
internal static class M68030TimingModel
{
public static M68kInstructionPlan GetPlan(M68kInstructionTimingKey key)
- {
- return key switch
- {
- M68kInstructionTimingKey.Idle => M68kInstructionPlan.CreateHeadTail(key, "IDLE", 2, 0, 0, M68kTimingBarrier.SynchronizeBus),
- M68kInstructionTimingKey.Nop => M68kInstructionPlan.CreateHeadTail(key, "NOP", 4, 0, 0, M68kTimingBarrier.SynchronizeBus),
- M68kInstructionTimingKey.LineAException => M68kInstructionPlan.CreateHeadTail(key, "LINEA", 34, 0, 0, ExceptionBarrier()),
- M68kInstructionTimingKey.LineFException => M68kInstructionPlan.CreateHeadTail(key, "LINEF", 34, 0, 0, ExceptionBarrier()),
- M68kInstructionTimingKey.IllegalInstruction => M68kInstructionPlan.CreateHeadTail(key, "ILLEGAL", 20, 0, 0, ExceptionBarrier()),
- M68kInstructionTimingKey.PrivilegeViolation => M68kInstructionPlan.CreateHeadTail(key, "PRIVILEGE", 20, 0, 0, ExceptionBarrier()),
- M68kInstructionTimingKey.FormatError => M68kInstructionPlan.CreateHeadTail(key, "FORMAT", 20, 0, 0, ExceptionBarrier()),
- M68kInstructionTimingKey.InterruptAcknowledge => M68kInstructionPlan.CreateHeadTail(key, "INTERRUPT", 44, 0, 0, ExceptionBarrier()),
- M68kInstructionTimingKey.Movec => M68kInstructionPlan.CreateHeadTail(key, "MOVEC", 12, 0, 0, M68kTimingBarrier.CacheControl | M68kTimingBarrier.SynchronizeBus),
- M68kInstructionTimingKey.ImmediateWordToConditionCodeRegister => M68kInstructionPlan.CreateHeadTail(key, "ORI/ANDI/EORI.W #,CCR", 8, 1, 1),
- M68kInstructionTimingKey.ImmediateWordToStatusRegister => M68kInstructionPlan.CreateHeadTail(key, "ORI/ANDI/EORI.W #,SR", 20, 0, 0, M68kTimingBarrier.SynchronizeBus),
- M68kInstructionTimingKey.Rte => M68kInstructionPlan.CreateHeadTail(key, "RTE", 20, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.SynchronizeBus),
- M68kInstructionTimingKey.Rtd => M68kInstructionPlan.CreateHeadTail(key, "RTD", 16, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.Rts => M68kInstructionPlan.CreateHeadTail(key, "RTS", 7, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.LinkLong => M68kInstructionPlan.CreateHeadTail(key, "LINK.L", 16, 2, 2),
- M68kInstructionTimingKey.ExtbLong => M68kInstructionPlan.CreateHeadTail(key, "EXTB.L", 4, 2, 2),
- M68kInstructionTimingKey.ExtWordData => M68kInstructionPlan.CreateHeadTail(key, "EXT.W Dn", 2, 1, 1),
- M68kInstructionTimingKey.TstWordData => M68kInstructionPlan.CreateHeadTail(key, "TST.W Dn", 2, 1, 1),
- M68kInstructionTimingKey.Moveq => M68kInstructionPlan.CreateHeadTail(key, "MOVEQ #,Dn", 2, 1, 1),
- M68kInstructionTimingKey.NegLongData => M68kInstructionPlan.CreateHeadTail(key, "NEG.L Dn", 2, 1, 1),
- M68kInstructionTimingKey.NotByteData => M68kInstructionPlan.CreateHeadTail(key, "NOT.B Dn", 2, 1, 1),
- M68kInstructionTimingKey.ClrDataLong => M68kInstructionPlan.CreateHeadTail(key, "CLR.L Dn", 2, 1, 1),
- M68kInstructionTimingKey.ClrDataWord => M68kInstructionPlan.CreateHeadTail(key, "CLR.W Dn", 2, 1, 1),
- M68kInstructionTimingKey.ClrLongAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "CLR.L (An)", 6, 1, 1),
- M68kInstructionTimingKey.ClrLongAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "CLR.L (d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.ClrLongAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "CLR.L (xxx).L", 8, 1, 1),
- M68kInstructionTimingKey.ClrByteAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "CLR.B (An)", 4, 1, 1),
- M68kInstructionTimingKey.ClrByteAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "CLR.B (d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.ClrWordAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "CLR.W (d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.ClrLongPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "CLR.L (An)+", 6, 1, 1),
- M68kInstructionTimingKey.LeaAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "LEA (xxx).L,An", 6, 1, 1),
- M68kInstructionTimingKey.LeaAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "LEA (d16,An),An", 4, 1, 1),
- M68kInstructionTimingKey.MoveByteImmediateToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B #,(xxx).L", 8, 1, 1),
- M68kInstructionTimingKey.MoveWordImmediateToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W #,(xxx).L", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongImmediateToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L #,(xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.MoveLongImmediateToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L #,(An)", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L #,(d16,An)", 10, 1, 1),
- M68kInstructionTimingKey.MoveLongImmediateToPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L #,(An)+", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongImmediateToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L #,An", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongDataToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.MoveLongDataToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L Dn,An", 2, 1, 1),
- M68kInstructionTimingKey.MoveLongDataToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L Dn,(An)", 4, 1, 1),
- M68kInstructionTimingKey.MoveLongDataToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L Dn,(d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L An,Dn", 2, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L An,An", 2, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L An,(An)", 4, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L An,(d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressToPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L An,(An)+", 4, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressIndirectToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressIndirectToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L (An),An", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongPostIncrementToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (An)+,Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongPostIncrementToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L (An)+,An", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressDisplacementToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (d16,An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressDisplacementToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L (d16,An),An", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressDisplacementToPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (d16,An),(An)+", 10, 1, 1),
- M68kInstructionTimingKey.MoveLongBriefIndexedToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (d8,An,Xn),Dn", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongBriefIndexedToAddress => M68kInstructionPlan.CreateHeadTail(key, "MOVEA.L (d8,An,Xn),An", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressIndirectToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (An),(An)", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongAbsoluteLongToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (xxx).L,Dn", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongAbsoluteWordToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (xxx).W,(d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.MoveLongAbsoluteLongToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L (xxx).L,(d16,An)", 10, 1, 1),
- M68kInstructionTimingKey.MoveLongDataToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L Dn,(xxx).L", 6, 1, 1),
- M68kInstructionTimingKey.MoveLongAddressToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.L An,(xxx).L", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.MoveByteImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.MoveByteImmediateToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B #,(An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B #,(d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteImmediateToBriefIndexed => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B #,(d8,An,Xn)", 8, 1, 1),
- M68kInstructionTimingKey.MoveByteAddressIndirectToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveBytePostIncrementToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (An)+,Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteAddressDisplacementToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (d16,An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteAbsoluteLongToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (xxx).L,Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteBriefIndexedToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (d8,An,Xn),Dn", 8, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,(xxx).L", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,(An)", 4, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,(d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToBriefIndexed => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,(d8,An,Xn)", 8, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,(An)+", 4, 1, 1),
- M68kInstructionTimingKey.MoveByteDataToPredecrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B Dn,-(An)", 4, 1, 1),
- M68kInstructionTimingKey.MoveByteBriefIndexedToPredecrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (d8,An,Xn),-(An)", 10, 1, 1),
- M68kInstructionTimingKey.MoveBytePostIncrementToPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (An)+,(An)+", 8, 1, 1),
- M68kInstructionTimingKey.MoveByteAddressIndirectToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (An),(xxx).L", 8, 1, 1),
- M68kInstructionTimingKey.MoveByteAbsoluteLongToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.B (xxx).L,(xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.MoveWordAbsoluteLongToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W (xxx).L,Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveWordAddressDisplacementToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W (d16,An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.MoveWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.MoveWordImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W #,(d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveWordDataToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W Dn,(d16,An)", 6, 1, 1),
- M68kInstructionTimingKey.MoveWordDataToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W Dn,(xxx).L", 6, 1, 1),
- M68kInstructionTimingKey.MoveWordAbsoluteLongToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W (xxx).L,(xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.MoveWordAbsoluteLongToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "MOVE.W (xxx).L,(d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.ImmediateLogicalByteToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "ORI/ANDI.B #,(xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.AddiByteImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "ADDI.B #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.AddiByteImmediateToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "ADDI.B #,(An)", 6, 1, 1),
- M68kInstructionTimingKey.AddiByteImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "ADDI.B #,(d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.AddiWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "ADDI.W #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.AddiLongImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "ADDI.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.AddiLongImmediateToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "ADDI.L #,(xxx).L", 12, 1, 1),
- M68kInstructionTimingKey.SubiByteImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "SUBI.B #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.SubiByteImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "SUBI.B #,(d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.SubiLongImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "SUBI.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.SubByteDataToData => M68kInstructionPlan.CreateHeadTail(key, "SUB.B Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.SubLongDataToData => M68kInstructionPlan.CreateHeadTail(key, "SUB.L Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.SubLongAddressToData => M68kInstructionPlan.CreateHeadTail(key, "SUB.L An,Dn", 2, 1, 1),
- M68kInstructionTimingKey.SubLongAddressDisplacementToData => M68kInstructionPlan.CreateHeadTail(key, "SUB.L (d16,An),Dn", 7, 1, 1),
- M68kInstructionTimingKey.AddWordDataToData => M68kInstructionPlan.CreateHeadTail(key, "ADD.W Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.AddLongDataToData => M68kInstructionPlan.CreateHeadTail(key, "ADD.L Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.AddxLongDataToData => M68kInstructionPlan.CreateHeadTail(key, "ADDX.L Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.AddLongPostIncrementToData => M68kInstructionPlan.CreateHeadTail(key, "ADD.L (An)+,Dn", 6, 1, 1),
- M68kInstructionTimingKey.AddWordDataToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "ADD.W Dn,(d16,An)", 9, 1, 1),
- M68kInstructionTimingKey.AddLongDataToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "ADD.L Dn,(d16,An)", 13, 1, 1),
- M68kInstructionTimingKey.AddaLongImmediateToAddress => M68kInstructionPlan.CreateHeadTail(key, "ADDA.L #,An", 6, 1, 1),
- M68kInstructionTimingKey.AddaLongDataToAddress => M68kInstructionPlan.CreateHeadTail(key, "ADDA.L Dn,An", 2, 1, 1),
- M68kInstructionTimingKey.AddaLongAddressDisplacementToAddress => M68kInstructionPlan.CreateHeadTail(key, "ADDA.L (d16,An),An", 7, 1, 1),
- M68kInstructionTimingKey.SubaLongImmediateToAddress => M68kInstructionPlan.CreateHeadTail(key, "SUBA.L #,An", 6, 1, 1),
- M68kInstructionTimingKey.DivuWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "DIVU.W #,Dn", 46, 1, 1),
- M68kInstructionTimingKey.DivsWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "DIVS.W #,Dn", 58, 1, 1),
- M68kInstructionTimingKey.MuluLong => M68kInstructionPlan.CreateHeadTail(key, "MULU.L ,Dn", 44, 1, 1),
- M68kInstructionTimingKey.MulsLong => M68kInstructionPlan.CreateHeadTail(key, "MULS.L ,Dn", 44, 1, 1),
- M68kInstructionTimingKey.DivuLong => M68kInstructionPlan.CreateHeadTail(key, "DIVU.L ,Dr:Dq", 76, 1, 1),
- M68kInstructionTimingKey.DivsLong => M68kInstructionPlan.CreateHeadTail(key, "DIVS.L ,Dr:Dq", 82, 1, 1),
- M68kInstructionTimingKey.AbcdByteDataToData => M68kInstructionPlan.CreateHeadTail(key, "ABCD.B Dn,Dn", 6, 1, 1),
- M68kInstructionTimingKey.AbcdBytePredecrementMemory => M68kInstructionPlan.CreateHeadTail(key, "ABCD.B -(An),-(An)", 18, 1, 1),
- M68kInstructionTimingKey.SbcdByteDataToData => M68kInstructionPlan.CreateHeadTail(key, "SBCD.B Dn,Dn", 6, 1, 1),
- M68kInstructionTimingKey.SbcdBytePredecrementMemory => M68kInstructionPlan.CreateHeadTail(key, "SBCD.B -(An),-(An)", 18, 1, 1),
- M68kInstructionTimingKey.NbcdByteData => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B Dn", 6, 1, 1),
- M68kInstructionTimingKey.NbcdByteAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B (An)", 8, 1, 1),
- M68kInstructionTimingKey.NbcdBytePostIncrement => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B (An)+", 8, 1, 1),
- M68kInstructionTimingKey.NbcdBytePredecrement => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B -(An)", 8, 1, 1),
- M68kInstructionTimingKey.NbcdByteAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B (d16,An)", 10, 1, 1),
- M68kInstructionTimingKey.NbcdByteBriefIndexed => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B (d8,An,Xn)", 12, 1, 1),
- M68kInstructionTimingKey.NbcdByteAbsoluteWord => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B (xxx).W", 10, 1, 1),
- M68kInstructionTimingKey.NbcdByteAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "NBCD.B (xxx).L", 12, 1, 1),
- M68kInstructionTimingKey.AndByteDataToData => M68kInstructionPlan.CreateHeadTail(key, "AND.B Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.AndWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "AND.W #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.AndLongImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "AND.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.MuluWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "MULU.W #,Dn", 46, 1, 1),
- M68kInstructionTimingKey.EoriWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "EORI.W #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.EoriLongImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "EORI.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpiLongImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "CMPI.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpiLongImmediateToPostIncrement => M68kInstructionPlan.CreateHeadTail(key, "CMPI.L #,(An)+", 10, 1, 1),
- M68kInstructionTimingKey.CmpiLongImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "CMPI.L #,(d16,An)", 9, 1, 1),
- M68kInstructionTimingKey.CmpiLongImmediateToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "CMPI.L #,(xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.CmpiByteImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "CMPI.B #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.CmpiByteImmediateToAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "CMPI.B #,(An)", 6, 1, 1),
- M68kInstructionTimingKey.CmpiByteImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "CMPI.B #,(d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.CmpiWordImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "CMPI.W #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.CmpiWordImmediateToAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "CMPI.W #,(d16,An)", 8, 1, 1),
- M68kInstructionTimingKey.CmpiWordImmediateToAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "CMPI.W #,(xxx).L", 8, 1, 1),
- M68kInstructionTimingKey.CmpaLongImmediateToAddress => M68kInstructionPlan.CreateHeadTail(key, "CMPA.L #,An", 6, 1, 1),
- M68kInstructionTimingKey.CmpaLongDataToAddress => M68kInstructionPlan.CreateHeadTail(key, "CMPA.L Dn,An", 2, 1, 1),
- M68kInstructionTimingKey.CmpaLongAddressToAddress => M68kInstructionPlan.CreateHeadTail(key, "CMPA.L An,An", 2, 1, 1),
- M68kInstructionTimingKey.CmpaLongAddressIndirectToAddress => M68kInstructionPlan.CreateHeadTail(key, "CMPA.L (An),An", 6, 1, 1),
- M68kInstructionTimingKey.CmpLongDataToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.L Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.CmpLongAddressToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.L An,Dn", 2, 1, 1),
- M68kInstructionTimingKey.CmpLongAddressIndirectToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.L (An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpLongPostIncrementToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.L (An)+,Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpByteDataToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.B Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.CmpByteAddressIndirectToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.B (An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpByteAddressDisplacementToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.B (d16,An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpByteAbsoluteLongToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.B (xxx).L,Dn", 6, 1, 1),
- M68kInstructionTimingKey.CmpWordDataToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.W Dn,Dn", 2, 1, 1),
- M68kInstructionTimingKey.CmpWordAddressDisplacementToData => M68kInstructionPlan.CreateHeadTail(key, "CMP.W (d16,An),Dn", 6, 1, 1),
- M68kInstructionTimingKey.LeaAbsoluteWord => M68kInstructionPlan.CreateHeadTail(key, "LEA (xxx).W,An", 4, 1, 1),
- M68kInstructionTimingKey.SwapData => M68kInstructionPlan.CreateHeadTail(key, "SWAP Dn", 4, 1, 1),
- M68kInstructionTimingKey.AsrLongImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ASR.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.AsrWordImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ASR.W #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.LsrLongImmediateData => M68kInstructionPlan.CreateHeadTail(key, "LSR.L #,Dn", 6, 1, 1),
- M68kInstructionTimingKey.AslLongImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ASL.L #,Dn", 8, 1, 1),
- M68kInstructionTimingKey.AslWordImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ASL.W #,Dn", 8, 1, 1),
- M68kInstructionTimingKey.RorByteImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ROR.B #,Dn", 8, 1, 1),
- M68kInstructionTimingKey.RorWordImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ROR.W #,Dn", 8, 1, 1),
- M68kInstructionTimingKey.RolWordImmediateData => M68kInstructionPlan.CreateHeadTail(key, "ROL.W #,Dn", 8, 1, 1),
- M68kInstructionTimingKey.JsrAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "JSR (xxx).L", 7, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.JmpAddressIndirect => M68kInstructionPlan.CreateHeadTail(key, "JMP (An)", 4, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.JmpAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "JMP (xxx).L", 6, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.OriByteImmediateToData => M68kInstructionPlan.CreateHeadTail(key, "ORI.B #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.BtstByteImmediateAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "BTST #,(xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.BchgByteImmediateAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "BCHG #,(xxx).L", 12, 1, 1),
- M68kInstructionTimingKey.BclrByteImmediateAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "BCLR #,(xxx).L", 12, 1, 1),
- M68kInstructionTimingKey.BsetByteImmediateAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "BSET #,(xxx).L", 12, 1, 1),
- M68kInstructionTimingKey.BsetByteImmediateAddressDisplacement => M68kInstructionPlan.CreateHeadTail(key, "BSET #,(d16,An)", 10, 1, 1),
- M68kInstructionTimingKey.BtstImmediateData => M68kInstructionPlan.CreateHeadTail(key, "BTST #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.BclrImmediateData => M68kInstructionPlan.CreateHeadTail(key, "BCLR #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.BsetImmediateData => M68kInstructionPlan.CreateHeadTail(key, "BSET #,Dn", 4, 1, 1),
- M68kInstructionTimingKey.BtstDynamicData => M68kInstructionPlan.CreateHeadTail(key, "BTST Dn,Dn", 4, 1, 1),
- M68kInstructionTimingKey.BclrDynamicData => M68kInstructionPlan.CreateHeadTail(key, "BCLR Dn,Dn", 4, 1, 1),
- M68kInstructionTimingKey.SccAbsoluteLong => M68kInstructionPlan.CreateHeadTail(key, "Scc (xxx).L", 10, 1, 1),
- M68kInstructionTimingKey.BranchByteTaken => M68kInstructionPlan.CreateHeadTail(key, "Bcc.B taken", 6, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.BranchByteNotTaken => M68kInstructionPlan.CreateHeadTail(key, "Bcc.B not taken", 4, 1, 1),
- M68kInstructionTimingKey.BsrByte => M68kInstructionPlan.CreateHeadTail(key, "BSR.B", 7, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.BranchWordTaken => M68kInstructionPlan.CreateHeadTail(key, "Bcc.W taken", 6, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.BranchWordNotTaken => M68kInstructionPlan.CreateHeadTail(key, "Bcc.W not taken", 6, 1, 1),
- M68kInstructionTimingKey.BsrWord => M68kInstructionPlan.CreateHeadTail(key, "BSR.W", 7, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.DbccConditionTrue => M68kInstructionPlan.CreateHeadTail(key, "DBcc condition true", 6, 1, 1),
- M68kInstructionTimingKey.DbccBranchTaken => M68kInstructionPlan.CreateHeadTail(key, "DBcc branch taken", 10, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.DbccExpired => M68kInstructionPlan.CreateHeadTail(key, "DBcc expired", 12, 1, 1),
- M68kInstructionTimingKey.BranchLongTaken => M68kInstructionPlan.CreateHeadTail(key, "Bcc.L taken", 10, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- M68kInstructionTimingKey.BranchLongNotTaken => M68kInstructionPlan.CreateHeadTail(key, "Bcc.L not taken", 8, 1, 1),
- M68kInstructionTimingKey.BsrLong => M68kInstructionPlan.CreateHeadTail(key, "BSR.L", 18, 0, 0, M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Branch),
- _ => throw new UnsupportedM68kTimingException(key, M68kAcceleratorModel.M68030)
- };
- }
-
- private static M68kTimingBarrier ExceptionBarrier()
- => M68kTimingBarrier.Exception | M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.SynchronizeBus;
+ => M68kTimingFormula.GetPlan(M68kTimingDescriptor.FromLegacyKey(key), M68kAcceleratorModel.M68030);
}
internal sealed class M68kAcceleratorBusBridge
diff --git a/Copper68k/M68kTimingFormula.cs b/Copper68k/M68kTimingFormula.cs
new file mode 100644
index 0000000..e671338
--- /dev/null
+++ b/Copper68k/M68kTimingFormula.cs
@@ -0,0 +1,635 @@
+using System;
+
+namespace Copper68k
+{
+ internal enum M68kTimingOperation
+ {
+ Legacy,
+ Idle,
+ Nop,
+ Exception,
+ Control,
+ StatusImmediate,
+ Return,
+ Link,
+ Extend,
+ Test,
+ Moveq,
+ Negate,
+ Not,
+ Clear,
+ LoadEffectiveAddress,
+ Move,
+ Arithmetic,
+ AddressArithmetic,
+ Multiply,
+ Divide,
+ Bcd,
+ Compare,
+ Swap,
+ ShiftRotate,
+ Jump,
+ Subroutine,
+ Movem,
+ Bit,
+ SetCondition,
+ Branch,
+ DecrementBranch
+ }
+
+ internal enum M68kTimingOperand
+ {
+ None,
+ DataRegister,
+ AddressRegister,
+ AddressIndirect,
+ PostIncrement,
+ Predecrement,
+ AddressDisplacement,
+ BriefIndexed,
+ AbsoluteWord,
+ AbsoluteLong,
+ Immediate,
+ RegisterList,
+ ConditionCodeRegister,
+ StatusRegister,
+ ControlRegister
+ }
+
+ internal enum M68kTimingOutcome
+ {
+ None,
+ Taken,
+ NotTaken,
+ ConditionTrue,
+ Expired
+ }
+
+ internal readonly record struct M68kTimingDescriptor(
+ M68kInstructionTimingKey Key,
+ M68kTimingOperation Operation,
+ M68kOperandSize Size,
+ M68kTimingOperand Source,
+ M68kTimingOperand Destination,
+ M68kTimingOutcome Outcome,
+ int RegisterCount,
+ bool RegisterToMemory,
+ string Name,
+ int NativeCycles,
+ M68kTimingBarrier Barriers)
+ {
+ public static M68kTimingDescriptor FromLegacyKey(M68kInstructionTimingKey key)
+ => M68kTimingDescriptorCatalog.FromLegacyKey(key);
+
+ public static M68kTimingDescriptor MovemLong(
+ M68kInstructionTimingKey key,
+ string name,
+ int registerCount,
+ bool registerToMemory)
+ {
+ if (registerCount < 0 || registerCount > 16)
+ {
+ throw new ArgumentOutOfRangeException(nameof(registerCount));
+ }
+
+ return new M68kTimingDescriptor(
+ key,
+ M68kTimingOperation.Movem,
+ M68kOperandSize.Long,
+ registerToMemory ? M68kTimingOperand.RegisterList : M68kTimingOperand.PostIncrement,
+ registerToMemory ? M68kTimingOperand.Predecrement : M68kTimingOperand.RegisterList,
+ M68kTimingOutcome.None,
+ registerCount,
+ registerToMemory,
+ name,
+ NativeCycles: 0,
+ M68kTimingBarrier.None);
+ }
+ }
+
+ internal static class M68kTimingFormula
+ {
+ public static M68kInstructionPlan GetPlan(M68kTimingDescriptor descriptor, M68kAcceleratorModel model)
+ {
+ var nativeCycles = GetNativeCycles(descriptor, model);
+ var barriers = GetBarriers(descriptor, model);
+ if (model == M68kAcceleratorModel.M68020 ||
+ descriptor.Operation == M68kTimingOperation.Movem && model == M68kAcceleratorModel.M68040)
+ {
+ return M68kInstructionPlan.CreateFlat(descriptor.Key, descriptor.Name, nativeCycles, barriers);
+ }
+
+ var (headCycles, tailCycles) = GetHeadTailCycles(descriptor, barriers);
+ return M68kInstructionPlan.CreateHeadTail(
+ descriptor.Key,
+ descriptor.Name,
+ nativeCycles,
+ headCycles,
+ tailCycles,
+ barriers);
+ }
+
+ private static int GetNativeCycles(M68kTimingDescriptor descriptor, M68kAcceleratorModel model)
+ {
+ if (descriptor.Operation != M68kTimingOperation.Movem)
+ {
+ return descriptor.NativeCycles;
+ }
+
+ const int registerListImmediateAddressCycles = 4;
+ if (model == M68kAcceleratorModel.M68030)
+ {
+ return descriptor.RegisterToMemory
+ ? 4 + (2 * descriptor.RegisterCount) + registerListImmediateAddressCycles
+ : 8 + (4 * descriptor.RegisterCount) + registerListImmediateAddressCycles;
+ }
+
+ return descriptor.RegisterToMemory
+ ? 4 + (3 * descriptor.RegisterCount) + registerListImmediateAddressCycles
+ : 8 + (4 * descriptor.RegisterCount) + registerListImmediateAddressCycles;
+ }
+
+ private static M68kTimingBarrier GetBarriers(M68kTimingDescriptor descriptor, M68kAcceleratorModel model)
+ {
+ var barriers = descriptor.Barriers;
+ if (descriptor.Key == M68kInstructionTimingKey.Movec &&
+ model is M68kAcceleratorModel.M68030 or M68kAcceleratorModel.M68040)
+ {
+ barriers |= M68kTimingBarrier.SynchronizeBus;
+ }
+
+ return barriers;
+ }
+
+ private static (int HeadCycles, int TailCycles) GetHeadTailCycles(
+ M68kTimingDescriptor descriptor,
+ M68kTimingBarrier barriers)
+ {
+ if ((barriers & (M68kTimingBarrier.FlushPipeline | M68kTimingBarrier.Exception | M68kTimingBarrier.Branch | M68kTimingBarrier.SynchronizeBus | M68kTimingBarrier.CacheControl)) != 0 ||
+ descriptor.Operation is M68kTimingOperation.Idle or M68kTimingOperation.Nop)
+ {
+ return (0, 0);
+ }
+
+ if (descriptor.Operation == M68kTimingOperation.Movem)
+ {
+ return (2, 0);
+ }
+
+ if (descriptor.Key is M68kInstructionTimingKey.LinkLong or M68kInstructionTimingKey.ExtbLong)
+ {
+ return (2, 2);
+ }
+
+ return (1, 1);
+ }
+ }
+
+ internal static class M68kTimingDescriptorCatalog
+ {
+ private static readonly M68kTimingDescriptor[] LegacyDescriptors = new M68kTimingDescriptor[Enum.GetValues().Length];
+ private static readonly bool[] LegacyDescriptorSupported = InitializeLegacyDescriptors();
+
+ public static M68kTimingDescriptor FromLegacyKey(M68kInstructionTimingKey key)
+ {
+ var index = (int)key;
+ if ((uint)index < (uint)LegacyDescriptors.Length && LegacyDescriptorSupported[index])
+ {
+ return LegacyDescriptors[index];
+ }
+
+ throw new UnsupportedM68kTimingException(key, M68kAcceleratorModel.M68020);
+ }
+
+ private static bool[] InitializeLegacyDescriptors()
+ {
+ var supported = new bool[LegacyDescriptors.Length];
+ foreach (var key in Enum.GetValues())
+ {
+ if (key is M68kInstructionTimingKey.MovemLongRegistersToPredecrement or
+ M68kInstructionTimingKey.MovemLongPostIncrementToRegisters)
+ {
+ continue;
+ }
+
+ var index = (int)key;
+ LegacyDescriptors[index] = CreateLegacyDescriptor(key);
+ supported[index] = true;
+ }
+
+ return supported;
+ }
+
+ private static M68kTimingDescriptor CreateLegacyDescriptor(M68kInstructionTimingKey key)
+ {
+ var baseline = M68020TimingModel.GetLegacyFlatPlan(key);
+ return new M68kTimingDescriptor(
+ key,
+ GetOperation(key),
+ GetSize(key),
+ GetSourceOperand(key),
+ GetDestinationOperand(key),
+ GetOutcome(key),
+ RegisterCount: 0,
+ RegisterToMemory: false,
+ baseline.Name,
+ baseline.NativeCycles,
+ baseline.Barriers);
+ }
+
+ private static M68kTimingOperation GetOperation(M68kInstructionTimingKey key)
+ {
+ return key switch
+ {
+ M68kInstructionTimingKey.Idle => M68kTimingOperation.Idle,
+ M68kInstructionTimingKey.Nop => M68kTimingOperation.Nop,
+ >= M68kInstructionTimingKey.LineAException and <= M68kInstructionTimingKey.InterruptAcknowledge => M68kTimingOperation.Exception,
+ M68kInstructionTimingKey.Movec => M68kTimingOperation.Control,
+ M68kInstructionTimingKey.ImmediateWordToConditionCodeRegister or
+ M68kInstructionTimingKey.ImmediateWordToStatusRegister => M68kTimingOperation.StatusImmediate,
+ M68kInstructionTimingKey.Rte or
+ M68kInstructionTimingKey.Rtd or
+ M68kInstructionTimingKey.Rts => M68kTimingOperation.Return,
+ M68kInstructionTimingKey.LinkLong => M68kTimingOperation.Link,
+ M68kInstructionTimingKey.ExtbLong or
+ M68kInstructionTimingKey.ExtWordData => M68kTimingOperation.Extend,
+ M68kInstructionTimingKey.TstWordData => M68kTimingOperation.Test,
+ M68kInstructionTimingKey.Moveq => M68kTimingOperation.Moveq,
+ M68kInstructionTimingKey.NegLongData => M68kTimingOperation.Negate,
+ M68kInstructionTimingKey.NotByteData => M68kTimingOperation.Not,
+ >= M68kInstructionTimingKey.ClrDataLong and <= M68kInstructionTimingKey.ClrLongPostIncrement => M68kTimingOperation.Clear,
+ M68kInstructionTimingKey.LeaAbsoluteLong or
+ M68kInstructionTimingKey.LeaAddressDisplacement or
+ M68kInstructionTimingKey.LeaAbsoluteWord => M68kTimingOperation.LoadEffectiveAddress,
+ >= M68kInstructionTimingKey.MoveByteImmediateToAbsoluteLong and <= M68kInstructionTimingKey.MoveWordAbsoluteLongToAddressDisplacement => M68kTimingOperation.Move,
+ >= M68kInstructionTimingKey.AddiByteImmediateToData and <= M68kInstructionTimingKey.SubaLongImmediateToAddress => GetArithmeticOperation(key),
+ >= M68kInstructionTimingKey.DivuWordImmediateToData and <= M68kInstructionTimingKey.DivsWordImmediateToData => M68kTimingOperation.Divide,
+ M68kInstructionTimingKey.MuluLong or
+ M68kInstructionTimingKey.MulsLong or
+ M68kInstructionTimingKey.MuluWordImmediateToData => M68kTimingOperation.Multiply,
+ M68kInstructionTimingKey.DivuLong or
+ M68kInstructionTimingKey.DivsLong => M68kTimingOperation.Divide,
+ >= M68kInstructionTimingKey.AbcdByteDataToData and <= M68kInstructionTimingKey.SbcdBytePredecrementMemory => M68kTimingOperation.Bcd,
+ >= M68kInstructionTimingKey.NbcdByteData and <= M68kInstructionTimingKey.NbcdByteAbsoluteLong => M68kTimingOperation.Bcd,
+ M68kInstructionTimingKey.AndByteDataToData or
+ M68kInstructionTimingKey.AndWordImmediateToData or
+ M68kInstructionTimingKey.AndLongImmediateToData or
+ M68kInstructionTimingKey.EoriWordImmediateToData or
+ M68kInstructionTimingKey.EoriLongImmediateToData or
+ M68kInstructionTimingKey.OriByteImmediateToData or
+ M68kInstructionTimingKey.ImmediateLogicalByteToAbsoluteLong => M68kTimingOperation.Arithmetic,
+ >= M68kInstructionTimingKey.CmpiLongImmediateToData and <= M68kInstructionTimingKey.CmpWordAddressDisplacementToData => M68kTimingOperation.Compare,
+ M68kInstructionTimingKey.SwapData => M68kTimingOperation.Swap,
+ >= M68kInstructionTimingKey.AsrLongImmediateData and <= M68kInstructionTimingKey.RolWordImmediateData => M68kTimingOperation.ShiftRotate,
+ M68kInstructionTimingKey.JmpAddressIndirect or
+ M68kInstructionTimingKey.JmpAbsoluteLong => M68kTimingOperation.Jump,
+ M68kInstructionTimingKey.JsrAbsoluteLong => M68kTimingOperation.Subroutine,
+ >= M68kInstructionTimingKey.BtstByteImmediateAbsoluteLong and <= M68kInstructionTimingKey.BclrDynamicData => M68kTimingOperation.Bit,
+ M68kInstructionTimingKey.SccAbsoluteLong => M68kTimingOperation.SetCondition,
+ M68kInstructionTimingKey.BranchByteTaken or
+ M68kInstructionTimingKey.BranchByteNotTaken or
+ M68kInstructionTimingKey.BranchWordTaken or
+ M68kInstructionTimingKey.BranchWordNotTaken or
+ M68kInstructionTimingKey.BranchLongTaken or
+ M68kInstructionTimingKey.BranchLongNotTaken => M68kTimingOperation.Branch,
+ M68kInstructionTimingKey.BsrByte or
+ M68kInstructionTimingKey.BsrWord or
+ M68kInstructionTimingKey.BsrLong => M68kTimingOperation.Subroutine,
+ >= M68kInstructionTimingKey.DbccConditionTrue and <= M68kInstructionTimingKey.DbccExpired => M68kTimingOperation.DecrementBranch,
+ _ => M68kTimingOperation.Legacy
+ };
+ }
+
+ private static M68kTimingOperation GetArithmeticOperation(M68kInstructionTimingKey key)
+ {
+ return key switch
+ {
+ M68kInstructionTimingKey.AddaLongImmediateToAddress or
+ M68kInstructionTimingKey.AddaLongDataToAddress or
+ M68kInstructionTimingKey.AddaLongAddressDisplacementToAddress or
+ M68kInstructionTimingKey.SubaLongImmediateToAddress => M68kTimingOperation.AddressArithmetic,
+ _ => M68kTimingOperation.Arithmetic
+ };
+ }
+
+ private static M68kOperandSize GetSize(M68kInstructionTimingKey key)
+ {
+ return key switch
+ {
+ M68kInstructionTimingKey.NotByteData or
+ M68kInstructionTimingKey.ClrByteAddressIndirect or
+ M68kInstructionTimingKey.ClrByteAddressDisplacement or
+ M68kInstructionTimingKey.MoveByteImmediateToAbsoluteLong or
+ >= M68kInstructionTimingKey.MoveByteDataToData and <= M68kInstructionTimingKey.MoveByteAbsoluteLongToAbsoluteLong or
+ M68kInstructionTimingKey.ImmediateLogicalByteToAbsoluteLong or
+ M68kInstructionTimingKey.AddiByteImmediateToData or
+ M68kInstructionTimingKey.AddiByteImmediateToAddressIndirect or
+ M68kInstructionTimingKey.AddiByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.SubiByteImmediateToData or
+ M68kInstructionTimingKey.SubiByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.SubByteDataToData or
+ >= M68kInstructionTimingKey.AbcdByteDataToData and <= M68kInstructionTimingKey.NbcdByteAbsoluteLong or
+ M68kInstructionTimingKey.AndByteDataToData or
+ >= M68kInstructionTimingKey.CmpiByteImmediateToData and <= M68kInstructionTimingKey.CmpiByteImmediateToAddressDisplacement or
+ >= M68kInstructionTimingKey.CmpByteDataToData and <= M68kInstructionTimingKey.CmpByteAbsoluteLongToData or
+ M68kInstructionTimingKey.RorByteImmediateData or
+ M68kInstructionTimingKey.OriByteImmediateToData or
+ >= M68kInstructionTimingKey.BtstByteImmediateAbsoluteLong and <= M68kInstructionTimingKey.BsetByteImmediateAddressDisplacement or
+ M68kInstructionTimingKey.BranchByteTaken or
+ M68kInstructionTimingKey.BranchByteNotTaken or
+ M68kInstructionTimingKey.BsrByte => M68kOperandSize.Byte,
+
+ M68kInstructionTimingKey.ExtWordData or
+ M68kInstructionTimingKey.TstWordData or
+ M68kInstructionTimingKey.ClrDataWord or
+ M68kInstructionTimingKey.ClrWordAddressDisplacement or
+ M68kInstructionTimingKey.MoveWordImmediateToAbsoluteLong or
+ >= M68kInstructionTimingKey.MoveWordAbsoluteLongToData and <= M68kInstructionTimingKey.MoveWordAbsoluteLongToAddressDisplacement or
+ M68kInstructionTimingKey.AddiWordImmediateToData or
+ M68kInstructionTimingKey.AddWordDataToData or
+ M68kInstructionTimingKey.AddWordDataToAddressDisplacement or
+ M68kInstructionTimingKey.DivuWordImmediateToData or
+ M68kInstructionTimingKey.DivsWordImmediateToData or
+ M68kInstructionTimingKey.AndWordImmediateToData or
+ M68kInstructionTimingKey.MuluWordImmediateToData or
+ M68kInstructionTimingKey.EoriWordImmediateToData or
+ >= M68kInstructionTimingKey.CmpiWordImmediateToData and <= M68kInstructionTimingKey.CmpiWordImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.CmpWordDataToData or
+ M68kInstructionTimingKey.CmpWordAddressDisplacementToData or
+ M68kInstructionTimingKey.LeaAbsoluteWord or
+ M68kInstructionTimingKey.SwapData or
+ M68kInstructionTimingKey.AsrWordImmediateData or
+ M68kInstructionTimingKey.AslWordImmediateData or
+ M68kInstructionTimingKey.RorWordImmediateData or
+ M68kInstructionTimingKey.RolWordImmediateData or
+ M68kInstructionTimingKey.BranchWordTaken or
+ M68kInstructionTimingKey.BranchWordNotTaken or
+ M68kInstructionTimingKey.BsrWord or
+ >= M68kInstructionTimingKey.DbccConditionTrue and <= M68kInstructionTimingKey.DbccExpired => M68kOperandSize.Word,
+
+ _ => M68kOperandSize.Long
+ };
+ }
+
+ private static M68kTimingOperand GetSourceOperand(M68kInstructionTimingKey key)
+ {
+ return key switch
+ {
+ M68kInstructionTimingKey.Movec => M68kTimingOperand.ControlRegister,
+ M68kInstructionTimingKey.ImmediateWordToConditionCodeRegister or
+ M68kInstructionTimingKey.ImmediateWordToStatusRegister or
+ M68kInstructionTimingKey.Moveq or
+ M68kInstructionTimingKey.MoveByteImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.MoveWordImmediateToAbsoluteLong or
+ >= M68kInstructionTimingKey.MoveLongImmediateToAbsoluteLong and <= M68kInstructionTimingKey.MoveLongImmediateToAddress or
+ M68kInstructionTimingKey.MoveByteImmediateToData or
+ M68kInstructionTimingKey.MoveByteImmediateToAddressIndirect or
+ M68kInstructionTimingKey.MoveByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.MoveByteImmediateToBriefIndexed or
+ M68kInstructionTimingKey.MoveWordImmediateToData or
+ M68kInstructionTimingKey.MoveWordImmediateToAddressDisplacement or
+ >= M68kInstructionTimingKey.AddiByteImmediateToData and <= M68kInstructionTimingKey.SubaLongImmediateToAddress or
+ M68kInstructionTimingKey.AndWordImmediateToData or
+ M68kInstructionTimingKey.AndLongImmediateToData or
+ M68kInstructionTimingKey.EoriWordImmediateToData or
+ M68kInstructionTimingKey.EoriLongImmediateToData or
+ M68kInstructionTimingKey.OriByteImmediateToData or
+ >= M68kInstructionTimingKey.CmpiLongImmediateToData and <= M68kInstructionTimingKey.CmpiWordImmediateToAbsoluteLong or
+ >= M68kInstructionTimingKey.BtstByteImmediateAbsoluteLong and <= M68kInstructionTimingKey.BsetByteImmediateAddressDisplacement or
+ M68kInstructionTimingKey.BtstImmediateData or
+ M68kInstructionTimingKey.BclrImmediateData or
+ M68kInstructionTimingKey.BsetImmediateData => M68kTimingOperand.Immediate,
+
+ M68kInstructionTimingKey.MoveLongDataToData or
+ M68kInstructionTimingKey.MoveLongDataToAddress or
+ M68kInstructionTimingKey.MoveLongDataToAddressIndirect or
+ M68kInstructionTimingKey.MoveLongDataToAddressDisplacement or
+ M68kInstructionTimingKey.MoveLongDataToAbsoluteLong or
+ M68kInstructionTimingKey.MoveByteDataToData or
+ M68kInstructionTimingKey.MoveByteDataToAbsoluteLong or
+ M68kInstructionTimingKey.MoveByteDataToAddressIndirect or
+ M68kInstructionTimingKey.MoveByteDataToAddressDisplacement or
+ M68kInstructionTimingKey.MoveByteDataToBriefIndexed or
+ M68kInstructionTimingKey.MoveByteDataToPostIncrement or
+ M68kInstructionTimingKey.MoveByteDataToPredecrement or
+ M68kInstructionTimingKey.MoveWordDataToAddressDisplacement or
+ M68kInstructionTimingKey.MoveWordDataToAbsoluteLong or
+ M68kInstructionTimingKey.AddaLongDataToAddress or
+ M68kInstructionTimingKey.CmpaLongDataToAddress => M68kTimingOperand.DataRegister,
+
+ M68kInstructionTimingKey.MoveLongAddressToData or
+ M68kInstructionTimingKey.MoveLongAddressToAddress or
+ M68kInstructionTimingKey.MoveLongAddressToAddressIndirect or
+ M68kInstructionTimingKey.MoveLongAddressToAddressDisplacement or
+ M68kInstructionTimingKey.MoveLongAddressToPostIncrement or
+ M68kInstructionTimingKey.MoveLongAddressToAbsoluteLong or
+ M68kInstructionTimingKey.SubLongAddressToData or
+ M68kInstructionTimingKey.CmpaLongAddressToAddress or
+ M68kInstructionTimingKey.CmpLongAddressToData => M68kTimingOperand.AddressRegister,
+
+ M68kInstructionTimingKey.MoveLongAddressIndirectToData or
+ M68kInstructionTimingKey.MoveLongAddressIndirectToAddress or
+ M68kInstructionTimingKey.MoveLongAddressIndirectToAddressIndirect or
+ M68kInstructionTimingKey.MoveByteAddressIndirectToData or
+ M68kInstructionTimingKey.MoveByteAddressIndirectToAbsoluteLong or
+ M68kInstructionTimingKey.CmpaLongAddressIndirectToAddress or
+ M68kInstructionTimingKey.CmpLongAddressIndirectToData or
+ M68kInstructionTimingKey.CmpByteAddressIndirectToData => M68kTimingOperand.AddressIndirect,
+
+ M68kInstructionTimingKey.MoveLongPostIncrementToData or
+ M68kInstructionTimingKey.MoveLongPostIncrementToAddress or
+ M68kInstructionTimingKey.MoveBytePostIncrementToData or
+ M68kInstructionTimingKey.MoveBytePostIncrementToPostIncrement or
+ M68kInstructionTimingKey.AddLongPostIncrementToData or
+ M68kInstructionTimingKey.CmpLongPostIncrementToData => M68kTimingOperand.PostIncrement,
+
+ M68kInstructionTimingKey.MoveLongAddressDisplacementToData or
+ M68kInstructionTimingKey.MoveLongAddressDisplacementToAddress or
+ M68kInstructionTimingKey.MoveLongAddressDisplacementToPostIncrement or
+ M68kInstructionTimingKey.MoveByteAddressDisplacementToData or
+ M68kInstructionTimingKey.MoveWordAddressDisplacementToData or
+ M68kInstructionTimingKey.SubLongAddressDisplacementToData or
+ M68kInstructionTimingKey.AddaLongAddressDisplacementToAddress or
+ M68kInstructionTimingKey.CmpByteAddressDisplacementToData or
+ M68kInstructionTimingKey.CmpWordAddressDisplacementToData => M68kTimingOperand.AddressDisplacement,
+
+ M68kInstructionTimingKey.MoveLongBriefIndexedToData or
+ M68kInstructionTimingKey.MoveLongBriefIndexedToAddress or
+ M68kInstructionTimingKey.MoveByteBriefIndexedToData or
+ M68kInstructionTimingKey.MoveByteBriefIndexedToPredecrement => M68kTimingOperand.BriefIndexed,
+
+ M68kInstructionTimingKey.LeaAbsoluteWord or
+ M68kInstructionTimingKey.MoveLongAbsoluteWordToAddressDisplacement => M68kTimingOperand.AbsoluteWord,
+
+ M68kInstructionTimingKey.LeaAbsoluteLong or
+ M68kInstructionTimingKey.MoveLongAbsoluteLongToData or
+ M68kInstructionTimingKey.MoveLongAbsoluteLongToAddressDisplacement or
+ M68kInstructionTimingKey.MoveByteAbsoluteLongToData or
+ M68kInstructionTimingKey.MoveByteAbsoluteLongToAbsoluteLong or
+ M68kInstructionTimingKey.MoveWordAbsoluteLongToData or
+ M68kInstructionTimingKey.MoveWordAbsoluteLongToAbsoluteLong or
+ M68kInstructionTimingKey.MoveWordAbsoluteLongToAddressDisplacement or
+ M68kInstructionTimingKey.CmpByteAbsoluteLongToData => M68kTimingOperand.AbsoluteLong,
+
+ _ => M68kTimingOperand.None
+ };
+ }
+
+ private static M68kTimingOperand GetDestinationOperand(M68kInstructionTimingKey key)
+ {
+ return key switch
+ {
+ M68kInstructionTimingKey.ImmediateWordToConditionCodeRegister => M68kTimingOperand.ConditionCodeRegister,
+ M68kInstructionTimingKey.ImmediateWordToStatusRegister => M68kTimingOperand.StatusRegister,
+ M68kInstructionTimingKey.MoveLongImmediateToAddress or
+ M68kInstructionTimingKey.MoveLongDataToAddress or
+ M68kInstructionTimingKey.MoveLongAddressToAddress or
+ M68kInstructionTimingKey.MoveLongAddressIndirectToAddress or
+ M68kInstructionTimingKey.MoveLongPostIncrementToAddress or
+ M68kInstructionTimingKey.MoveLongAddressDisplacementToAddress or
+ M68kInstructionTimingKey.MoveLongBriefIndexedToAddress or
+ M68kInstructionTimingKey.LeaAbsoluteLong or
+ M68kInstructionTimingKey.LeaAddressDisplacement or
+ M68kInstructionTimingKey.LeaAbsoluteWord or
+ >= M68kInstructionTimingKey.AddaLongImmediateToAddress and <= M68kInstructionTimingKey.SubaLongImmediateToAddress or
+ >= M68kInstructionTimingKey.CmpaLongImmediateToAddress and <= M68kInstructionTimingKey.CmpaLongAddressIndirectToAddress => M68kTimingOperand.AddressRegister,
+
+ M68kInstructionTimingKey.MoveLongImmediateToData or
+ M68kInstructionTimingKey.MoveLongDataToData or
+ M68kInstructionTimingKey.MoveLongAddressToData or
+ M68kInstructionTimingKey.MoveLongAddressIndirectToData or
+ M68kInstructionTimingKey.MoveLongPostIncrementToData or
+ M68kInstructionTimingKey.MoveLongAddressDisplacementToData or
+ M68kInstructionTimingKey.MoveLongBriefIndexedToData or
+ M68kInstructionTimingKey.MoveLongAbsoluteLongToData or
+ M68kInstructionTimingKey.MoveByteDataToData or
+ M68kInstructionTimingKey.MoveByteImmediateToData or
+ M68kInstructionTimingKey.MoveByteAddressIndirectToData or
+ M68kInstructionTimingKey.MoveBytePostIncrementToData or
+ M68kInstructionTimingKey.MoveByteAddressDisplacementToData or
+ M68kInstructionTimingKey.MoveByteAbsoluteLongToData or
+ M68kInstructionTimingKey.MoveByteBriefIndexedToData or
+ M68kInstructionTimingKey.MoveWordAbsoluteLongToData or
+ M68kInstructionTimingKey.MoveWordAddressDisplacementToData or
+ M68kInstructionTimingKey.MoveWordImmediateToData or
+ M68kInstructionTimingKey.ClrDataLong or
+ M68kInstructionTimingKey.ClrDataWord or
+ M68kInstructionTimingKey.ExtbLong or
+ M68kInstructionTimingKey.ExtWordData or
+ M68kInstructionTimingKey.TstWordData or
+ M68kInstructionTimingKey.Moveq or
+ M68kInstructionTimingKey.NegLongData or
+ M68kInstructionTimingKey.NotByteData or
+ M68kInstructionTimingKey.SwapData or
+ >= M68kInstructionTimingKey.CmpLongDataToData and <= M68kInstructionTimingKey.CmpWordAddressDisplacementToData or
+ M68kInstructionTimingKey.AndByteDataToData or
+ M68kInstructionTimingKey.AndWordImmediateToData or
+ M68kInstructionTimingKey.AndLongImmediateToData or
+ M68kInstructionTimingKey.EoriWordImmediateToData or
+ M68kInstructionTimingKey.EoriLongImmediateToData or
+ M68kInstructionTimingKey.OriByteImmediateToData or
+ >= M68kInstructionTimingKey.AsrLongImmediateData and <= M68kInstructionTimingKey.RolWordImmediateData or
+ M68kInstructionTimingKey.BtstImmediateData or
+ M68kInstructionTimingKey.BclrImmediateData or
+ M68kInstructionTimingKey.BsetImmediateData or
+ M68kInstructionTimingKey.BtstDynamicData or
+ M68kInstructionTimingKey.BclrDynamicData => M68kTimingOperand.DataRegister,
+
+ M68kInstructionTimingKey.MoveLongImmediateToAddressIndirect or
+ M68kInstructionTimingKey.MoveLongDataToAddressIndirect or
+ M68kInstructionTimingKey.MoveLongAddressToAddressIndirect or
+ M68kInstructionTimingKey.MoveLongAddressIndirectToAddressIndirect or
+ M68kInstructionTimingKey.MoveByteImmediateToAddressIndirect or
+ M68kInstructionTimingKey.MoveByteDataToAddressIndirect or
+ M68kInstructionTimingKey.ClrLongAddressIndirect or
+ M68kInstructionTimingKey.ClrByteAddressIndirect or
+ M68kInstructionTimingKey.AddiByteImmediateToAddressIndirect or
+ M68kInstructionTimingKey.CmpiByteImmediateToAddressIndirect or
+ M68kInstructionTimingKey.NbcdByteAddressIndirect => M68kTimingOperand.AddressIndirect,
+
+ M68kInstructionTimingKey.MoveLongImmediateToPostIncrement or
+ M68kInstructionTimingKey.MoveLongAddressToPostIncrement or
+ M68kInstructionTimingKey.MoveLongAddressDisplacementToPostIncrement or
+ M68kInstructionTimingKey.MoveByteDataToPostIncrement or
+ M68kInstructionTimingKey.MoveBytePostIncrementToPostIncrement or
+ M68kInstructionTimingKey.ClrLongPostIncrement or
+ M68kInstructionTimingKey.CmpiLongImmediateToPostIncrement or
+ M68kInstructionTimingKey.NbcdBytePostIncrement => M68kTimingOperand.PostIncrement,
+
+ M68kInstructionTimingKey.MoveByteDataToPredecrement or
+ M68kInstructionTimingKey.MoveByteBriefIndexedToPredecrement or
+ M68kInstructionTimingKey.NbcdBytePredecrement => M68kTimingOperand.Predecrement,
+
+ M68kInstructionTimingKey.MoveLongImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.MoveLongDataToAddressDisplacement or
+ M68kInstructionTimingKey.MoveLongAddressToAddressDisplacement or
+ M68kInstructionTimingKey.MoveLongAbsoluteWordToAddressDisplacement or
+ M68kInstructionTimingKey.MoveLongAbsoluteLongToAddressDisplacement or
+ M68kInstructionTimingKey.MoveByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.MoveWordImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.MoveWordDataToAddressDisplacement or
+ M68kInstructionTimingKey.MoveWordAbsoluteLongToAddressDisplacement or
+ M68kInstructionTimingKey.MoveByteDataToAddressDisplacement or
+ M68kInstructionTimingKey.ClrLongAddressDisplacement or
+ M68kInstructionTimingKey.ClrByteAddressDisplacement or
+ M68kInstructionTimingKey.ClrWordAddressDisplacement or
+ M68kInstructionTimingKey.AddiByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.SubiByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.AddWordDataToAddressDisplacement or
+ M68kInstructionTimingKey.AddLongDataToAddressDisplacement or
+ M68kInstructionTimingKey.CmpiLongImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.CmpiByteImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.CmpiWordImmediateToAddressDisplacement or
+ M68kInstructionTimingKey.BsetByteImmediateAddressDisplacement or
+ M68kInstructionTimingKey.NbcdByteAddressDisplacement => M68kTimingOperand.AddressDisplacement,
+
+ M68kInstructionTimingKey.MoveByteImmediateToBriefIndexed or
+ M68kInstructionTimingKey.MoveByteDataToBriefIndexed or
+ M68kInstructionTimingKey.NbcdByteBriefIndexed => M68kTimingOperand.BriefIndexed,
+
+ M68kInstructionTimingKey.NbcdByteAbsoluteWord => M68kTimingOperand.AbsoluteWord,
+
+ M68kInstructionTimingKey.MoveByteImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.MoveWordImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.MoveLongImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.MoveLongDataToAbsoluteLong or
+ M68kInstructionTimingKey.MoveLongAddressToAbsoluteLong or
+ M68kInstructionTimingKey.MoveByteDataToAbsoluteLong or
+ M68kInstructionTimingKey.MoveByteAddressIndirectToAbsoluteLong or
+ M68kInstructionTimingKey.MoveByteAbsoluteLongToAbsoluteLong or
+ M68kInstructionTimingKey.MoveWordDataToAbsoluteLong or
+ M68kInstructionTimingKey.MoveWordAbsoluteLongToAbsoluteLong or
+ M68kInstructionTimingKey.ClrLongAbsoluteLong or
+ M68kInstructionTimingKey.ImmediateLogicalByteToAbsoluteLong or
+ M68kInstructionTimingKey.AddiLongImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.CmpiLongImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.CmpiWordImmediateToAbsoluteLong or
+ M68kInstructionTimingKey.BtstByteImmediateAbsoluteLong or
+ M68kInstructionTimingKey.BchgByteImmediateAbsoluteLong or
+ M68kInstructionTimingKey.BclrByteImmediateAbsoluteLong or
+ M68kInstructionTimingKey.BsetByteImmediateAbsoluteLong or
+ M68kInstructionTimingKey.SccAbsoluteLong or
+ M68kInstructionTimingKey.NbcdByteAbsoluteLong => M68kTimingOperand.AbsoluteLong,
+
+ _ => M68kTimingOperand.None
+ };
+ }
+
+ private static M68kTimingOutcome GetOutcome(M68kInstructionTimingKey key)
+ {
+ return key switch
+ {
+ M68kInstructionTimingKey.BranchByteTaken or
+ M68kInstructionTimingKey.BranchWordTaken or
+ M68kInstructionTimingKey.BranchLongTaken or
+ M68kInstructionTimingKey.DbccBranchTaken => M68kTimingOutcome.Taken,
+ M68kInstructionTimingKey.BranchByteNotTaken or
+ M68kInstructionTimingKey.BranchWordNotTaken or
+ M68kInstructionTimingKey.BranchLongNotTaken => M68kTimingOutcome.NotTaken,
+ M68kInstructionTimingKey.DbccConditionTrue => M68kTimingOutcome.ConditionTrue,
+ M68kInstructionTimingKey.DbccExpired => M68kTimingOutcome.Expired,
+ _ => M68kTimingOutcome.None
+ };
+ }
+ }
+}
diff --git a/CopperMod.Amiga.Tests/AmigaBusTimingTests.cs b/CopperMod.Amiga.Tests/AmigaBusTimingTests.cs
index 77da2cc..ce73415 100644
--- a/CopperMod.Amiga.Tests/AmigaBusTimingTests.cs
+++ b/CopperMod.Amiga.Tests/AmigaBusTimingTests.cs
@@ -499,6 +499,19 @@ public void HardwareSchedulerSkipsLiveDisplayAdvanceWhenDisplayHasNoLiveWork()
Assert.True(bus.Agnus.CaptureSnapshot().RefreshSlotReservationCount > 0);
}
+ [Fact]
+ public void CpuBoundaryHardwareDrainDoesNotReservePureRefreshSlots()
+ {
+ var bus = new AmigaBus(enableLiveAgnusDma: true);
+ var targetCycle = OutputRowStartCycle(AmigaConstants.PalLowResOverscanBorderY);
+
+ bus.AdvanceHardwareEventsTo(targetCycle);
+ Assert.Equal(0, bus.Agnus.CaptureSnapshot().RefreshSlotReservationCount);
+
+ bus.AdvanceHardwareTo(targetCycle);
+ Assert.True(bus.Agnus.CaptureSnapshot().RefreshSlotReservationCount > 0);
+ }
+
[Fact]
public void LiveRasterlinePlanRecordsLineStateEvent()
{
@@ -559,15 +572,40 @@ public void PredictedRasterlinePlanMatchesSimpleBitplaneLine()
var snapshot = bus.Display.CaptureSnapshot();
Assert.True(
snapshot.LastPredictedRasterlinePlanLines > 0,
- $"recorded={snapshot.LastRasterlinePlanEvents}, lineState={snapshot.LastRasterlinePlanLineStateEvents}, bitplane={snapshot.LastRasterlinePlanBitplaneFetchEvents}, lines={snapshot.LastPredictedRasterlinePlanLines}, matched={snapshot.LastPredictedRasterlinePlanMatchedLines}, mismatched={snapshot.LastPredictedRasterlinePlanMismatchedLines}, unsupported={snapshot.LastPredictedRasterlinePlanUnsupportedLines}, copper={snapshot.LastPredictedRasterlinePlanUnsupportedCopperLines}, pending={snapshot.LastPredictedRasterlinePlanUnsupportedPendingWriteLines}, sprite={snapshot.LastPredictedRasterlinePlanUnsupportedSpriteLines}, invalid={snapshot.LastPredictedRasterlinePlanUnsupportedInvalidStateLines}, overflow={snapshot.LastPredictedRasterlinePlanUnsupportedOverflowLines}");
+ $"recorded={snapshot.LastRasterlinePlanEvents}, lineState={snapshot.LastRasterlinePlanLineStateEvents}, bitplane={snapshot.LastRasterlinePlanBitplaneFetchEvents}, lines={snapshot.LastPredictedRasterlinePlanLines}, matched={snapshot.LastPredictedRasterlinePlanMatchedLines}, mismatched={snapshot.LastPredictedRasterlinePlanMismatchedLines}, unsupported={snapshot.LastPredictedRasterlinePlanUnsupportedLines}, copper={snapshot.LastPredictedRasterlinePlanUnsupportedCopperLines}, pending={snapshot.LastPredictedRasterlinePlanUnsupportedPendingWriteLines}, sprite={snapshot.LastPredictedRasterlinePlanUnsupportedSpriteLines}, invalid={snapshot.LastPredictedRasterlinePlanUnsupportedInvalidStateLines}, overflow={snapshot.LastPredictedRasterlinePlanUnsupportedOverflowLines}, descriptorBuilds={snapshot.LastRasterlineDescriptorBuilds}, descriptorReplayed={snapshot.LastRasterlineDescriptorReplayedRows}, descriptorMismatches={snapshot.LastRasterlineDescriptorMismatches}");
Assert.True(
snapshot.LastPredictedRasterlinePlanMatchedLines > 0,
$"lines={snapshot.LastPredictedRasterlinePlanLines}, matched={snapshot.LastPredictedRasterlinePlanMatchedLines}, mismatched={snapshot.LastPredictedRasterlinePlanMismatchedLines}");
Assert.Equal(0, snapshot.LastPredictedRasterlinePlanMismatchedLines);
+ Assert.True(snapshot.LastRasterlineDescriptorBuilds > 0);
+ Assert.True(snapshot.LastRasterlineDescriptorBitplaneRows > 0);
+ Assert.True(snapshot.LastRasterlineDescriptorReplayAttempts > 0);
+ Assert.True(snapshot.LastRasterlineDescriptorReplayedRows > 0);
+ Assert.Equal(0, snapshot.LastRasterlineDescriptorMismatches);
+ }
+
+ [Fact]
+ public void RasterlineDescriptorReplayReadsChipRamAtFetchTime()
+ {
+ var bus = new AmigaBus(enableLiveAgnusDma: true);
+ var row = AmigaConstants.PalLowResOverscanBorderY;
+ var lineStart = OutputRowStartCycle(row);
+ var fetchCycle = LowResPlane1FetchCycle(row);
+ ConfigureLiveOneBitplaneDma(bus);
+ BigEndian.WriteUInt16(bus.ChipRam, 0x1000, 0x0000);
+
+ bus.AdvanceDmaTo(lineStart);
+ BigEndian.WriteUInt16(bus.ChipRam, 0x1000, 0xA55A);
+ bus.AdvanceDmaTo(fetchCycle);
+
+ var snapshot = bus.Display.CaptureSnapshot();
+ Assert.True(snapshot.LastRasterlineDescriptorReplayedRows > 0);
+ Assert.Equal(0, snapshot.LastRasterlineDescriptorMismatches);
+ Assert.Equal(0xA55A, ReadLiveBitplaneWord(bus, row, plane: 0, word: 0));
}
[Fact]
- public void PredictedRasterlinePlanMarksSpriteLineUnsupported()
+ public void RasterlineDescriptorReplaysSpriteRows()
{
var bus = new AmigaBus(enableLiveAgnusDma: true);
var lineStart = OutputRowStartCycle(AmigaConstants.PalLowResOverscanBorderY);
@@ -577,8 +615,12 @@ public void PredictedRasterlinePlanMarksSpriteLineUnsupported()
bus.AdvanceDmaTo(validationStop);
var snapshot = bus.Display.CaptureSnapshot();
- Assert.True(snapshot.LastPredictedRasterlinePlanUnsupportedSpriteLines > 0);
+ Assert.True(snapshot.LastRasterlineDescriptorSpriteRows > 0);
+ Assert.True(snapshot.LastRasterlineDescriptorReplayAttempts > 0);
+ Assert.True(snapshot.LastRasterlineDescriptorReplayedRows > 0);
+ Assert.Equal(0, snapshot.LastPredictedRasterlinePlanUnsupportedSpriteLines);
Assert.Equal(0, snapshot.LastPredictedRasterlinePlanMismatchedLines);
+ Assert.Equal(0, snapshot.LastRasterlineDescriptorMismatches);
}
[Fact]
@@ -966,6 +1008,24 @@ public void IntreqTimedReadObservesVblankAtExactCycle()
Assert.NotEqual(0, value & AmigaConstants.IntreqVerticalBlank);
}
+ [Fact]
+ public void IntreqReadObservesVblankAfterSameCyclePseudoFastAccess()
+ {
+ var bus = new AmigaBus(expansionRamSize: 0x10000);
+ var frameCycle = (long)AmigaConstants.A500PalCpuCyclesPerFrame;
+
+ var memoryCycle = frameCycle;
+ _ = bus.ReadWord(
+ AmigaConstants.A500BootPseudoFastRamBase,
+ ref memoryCycle,
+ AmigaBusAccessKind.CpuDataRead);
+
+ var intreqCycle = frameCycle;
+ var value = bus.ReadWord(0x00DFF01E, ref intreqCycle, AmigaBusAccessKind.CpuDataRead);
+
+ Assert.NotEqual(0, value & AmigaConstants.IntreqVerticalBlank);
+ }
+
[Fact]
public void RepeatedIntreqPollingDoesNotMissCiaTimerInterrupt()
{
@@ -1837,6 +1897,16 @@ private static long LowResPlane1FetchCycle(int row)
=> OutputRowStartCycle(row) +
((0x38 + HrmLowResPlane1FetchSlot) * AgnusChipSlotScheduler.SlotCycles);
+ private static ushort ReadLiveBitplaneWord(AmigaBus bus, int row, int plane, int word)
+ {
+ var field = typeof(OcsDisplay).GetField(
+ "_liveBitplaneWords",
+ System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
+ Assert.NotNull(field);
+ var words = Assert.IsType(field.GetValue(bus.Display));
+ return words[(row * 6 * 64) + (plane * 64) + word];
+ }
+
private static void ConfigureLiveOneBitplaneDma(AmigaBus bus)
{
bus.WriteWord(0x00DFF096, 0x8300);
diff --git a/CopperMod.Amiga.Tests/M68kTimingFormulaTests.cs b/CopperMod.Amiga.Tests/M68kTimingFormulaTests.cs
new file mode 100644
index 0000000..5797203
--- /dev/null
+++ b/CopperMod.Amiga.Tests/M68kTimingFormulaTests.cs
@@ -0,0 +1,155 @@
+using Copper68k;
+
+namespace CopperMod.Amiga.Tests;
+
+public sealed class M68kTimingFormulaTests
+{
+ public static IEnumerable