delete extra/external 68k core
This commit is contained in:
parent
58738c1af3
commit
f3dc6068ce
|
@ -191,19 +191,6 @@
|
||||||
<Compile Include="CPUs\HuC6280\Disassembler.cs" />
|
<Compile Include="CPUs\HuC6280\Disassembler.cs" />
|
||||||
<Compile Include="CPUs\HuC6280\Execute.cs" />
|
<Compile Include="CPUs\HuC6280\Execute.cs" />
|
||||||
<Compile Include="CPUs\HuC6280\HuC6280.cs" />
|
<Compile Include="CPUs\HuC6280\HuC6280.cs" />
|
||||||
<Compile Include="CPUs\MC68000\Helpers.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\IMemoryController.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\MC68K.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\MemoryAccess.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\BitManipulation.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\DataMovement.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\IntegerArithmetic.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\Logical.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\Multiprocessor.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\ProgramControl.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\ShiftRotate.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\Operations\SystemControl.cs" />
|
|
||||||
<Compile Include="CPUs\MC68000\OpTable.cs" />
|
|
||||||
<Compile Include="CPUs\MOS 6502\Disassembler.cs" />
|
<Compile Include="CPUs\MOS 6502\Disassembler.cs" />
|
||||||
<Compile Include="CPUs\MOS 6502\Execute.cs" />
|
<Compile Include="CPUs\MOS 6502\Execute.cs" />
|
||||||
<Compile Include="CPUs\MOS 6502\MOS6502.cs" />
|
<Compile Include="CPUs\MOS 6502\MOS6502.cs" />
|
||||||
|
|
|
@ -1,130 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public enum ShiftDirection
|
|
||||||
{
|
|
||||||
Right = 0,
|
|
||||||
Left = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Helpers
|
|
||||||
{
|
|
||||||
public static int[,] MOVECyclesBW;
|
|
||||||
public static int[,] MOVECyclesL;
|
|
||||||
|
|
||||||
static Helpers()
|
|
||||||
{
|
|
||||||
MOVECyclesBW = new int[12,9] {
|
|
||||||
{ 4, 4, 8, 8, 8, 12, 14, 12, 16 },
|
|
||||||
{ 4, 4, 8, 8, 8, 12, 14, 12, 16 },
|
|
||||||
{ 8, 8, 12, 12, 12, 16, 18, 16, 20 },
|
|
||||||
{ 8, 8, 12, 12, 12, 16, 18, 16, 20 },
|
|
||||||
{ 10, 10, 14, 14, 14, 18, 20, 18, 22 },
|
|
||||||
{ 12, 12, 16, 16, 16, 20, 22, 20, 24 },
|
|
||||||
{ 14, 14, 18, 18, 18, 22, 24, 22, 26 },
|
|
||||||
{ 12, 12, 16, 16, 16, 20, 22, 20, 24 },
|
|
||||||
{ 16, 16, 20, 20, 20, 24, 26, 24, 28 },
|
|
||||||
{ 12, 12, 16, 16, 16, 20, 22, 20, 24 },
|
|
||||||
{ 14, 14, 18, 18, 18, 22, 24, 22, 26 },
|
|
||||||
{ 8, 8, 12, 12, 12, 16, 18, 16, 20 }
|
|
||||||
};
|
|
||||||
|
|
||||||
MOVECyclesL = new int[12,9] {
|
|
||||||
{ 4, 4, 12, 12, 12, 16, 18, 16, 20 },
|
|
||||||
{ 4, 4, 12, 12, 12, 16, 18, 16, 20 },
|
|
||||||
{ 12, 12, 20, 20, 20, 24, 26, 24, 28 },
|
|
||||||
{ 12, 12, 20, 20, 20, 24, 26, 24, 28 },
|
|
||||||
{ 14, 14, 22, 22, 22, 26, 28, 26, 30 },
|
|
||||||
{ 16, 16, 24, 24, 24, 28, 30, 28, 32 },
|
|
||||||
{ 18, 18, 26, 26, 26, 30, 32, 30, 34 },
|
|
||||||
{ 16, 16, 24, 24, 24, 28, 30, 28, 32 },
|
|
||||||
{ 20, 20, 28, 28, 28, 32, 34, 32, 36 },
|
|
||||||
{ 16, 16, 24, 24, 24, 28, 30, 28, 32 },
|
|
||||||
{ 18, 18, 26, 26, 26, 30, 32, 30, 34 },
|
|
||||||
{ 12, 12, 20, 20, 20, 24, 26, 24, 28 }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Inject
|
|
||||||
public static void Inject(ref int register, byte value)
|
|
||||||
{
|
|
||||||
register = (register & -0x100) | value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Inject(ref int register, sbyte value)
|
|
||||||
{
|
|
||||||
register = (register & -0x100) | (byte)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Inject(ref int register, ushort value)
|
|
||||||
{
|
|
||||||
register = (register & -0x10000) | value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Inject(ref int register, short value)
|
|
||||||
{
|
|
||||||
register = (register & -0x10000) | (ushort)value;
|
|
||||||
}
|
|
||||||
#endregion Inject
|
|
||||||
|
|
||||||
public static void Swap(ref int a, ref int b)
|
|
||||||
{
|
|
||||||
int c = a;
|
|
||||||
a = b;
|
|
||||||
b = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int EACalcTimeBW(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: return 0;
|
|
||||||
case 1: return 0;
|
|
||||||
case 2: return 4;
|
|
||||||
case 3: return 4;
|
|
||||||
case 4: return 6;
|
|
||||||
case 5: return 8;
|
|
||||||
case 6: return 10;
|
|
||||||
case 7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0: return 8;
|
|
||||||
case 1: return 12;
|
|
||||||
case 2: return 8;
|
|
||||||
case 3: return 10;
|
|
||||||
case 4: return 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int EACalcTimeL(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: return 0;
|
|
||||||
case 1: return 0;
|
|
||||||
case 2: return 8;
|
|
||||||
case 3: return 8;
|
|
||||||
case 4: return 10;
|
|
||||||
case 5: return 12;
|
|
||||||
case 6: return 14;
|
|
||||||
case 7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0: return 12;
|
|
||||||
case 1: return 16;
|
|
||||||
case 2: return 12;
|
|
||||||
case 3: return 14;
|
|
||||||
case 4: return 8;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public interface IMemoryController
|
|
||||||
{
|
|
||||||
sbyte ReadB(int address);
|
|
||||||
short ReadW(int address);
|
|
||||||
int ReadL(int address);
|
|
||||||
|
|
||||||
void WriteB(int address, sbyte value);
|
|
||||||
void WriteW(int address, short value);
|
|
||||||
void WriteL(int address, int value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,238 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
// BIG NOTICE!!!!!!
|
|
||||||
|
|
||||||
// This is the 68000 core from Sega360.
|
|
||||||
// IT IS GPL! It is a starter core so I can work on Genesis hardware emulation first.
|
|
||||||
// This core MUST BE, and WILL BE replaced with new code at a later date.
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public sealed partial class MC68K
|
|
||||||
{
|
|
||||||
public int m_PC;
|
|
||||||
private int m_SR;
|
|
||||||
private ushort m_IR;
|
|
||||||
|
|
||||||
public int[] m_D = new int[8];
|
|
||||||
public int[] m_A = new int[8];
|
|
||||||
|
|
||||||
private int m_Usp;
|
|
||||||
private int m_Ssp;
|
|
||||||
|
|
||||||
private IMemoryController m_Controller;
|
|
||||||
|
|
||||||
public long m_Cycles;
|
|
||||||
|
|
||||||
private int m_InterruptFlag;
|
|
||||||
|
|
||||||
public MC68K(IMemoryController controller)
|
|
||||||
{
|
|
||||||
this.m_Controller = controller;
|
|
||||||
this.BuildOpTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Interrupt(int vector)
|
|
||||||
{
|
|
||||||
this.m_InterruptFlag = vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleInterrupt()
|
|
||||||
{
|
|
||||||
int vector = 24 + this.m_InterruptFlag;
|
|
||||||
this.m_InterruptFlag = 0;
|
|
||||||
Trap(vector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
this.m_SR = 0x2000;
|
|
||||||
this.SP = ReadL(0x0);
|
|
||||||
this.m_PC = ReadL(0x4);
|
|
||||||
this.m_Cycles = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OpHistory
|
|
||||||
{
|
|
||||||
public int PC;
|
|
||||||
public Operation Operation;
|
|
||||||
public OpHistory(int pc, Operation op)
|
|
||||||
{
|
|
||||||
this.PC = pc;
|
|
||||||
this.Operation = op;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<OpHistory> m_OpList = new List<OpHistory>(200);
|
|
||||||
public void Execute(long cycles)
|
|
||||||
{
|
|
||||||
this.m_Cycles = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// if (m_PC == 0x02DD8)
|
|
||||||
//m_PC = 0x02DD8;
|
|
||||||
if (this.m_Cycles >= cycles)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.m_InterruptFlag > 0)
|
|
||||||
{
|
|
||||||
HandleInterrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (this.m_PC == 0x4752)
|
|
||||||
//{ }
|
|
||||||
|
|
||||||
// Fetch
|
|
||||||
this.m_IR = (ushort)FetchW();
|
|
||||||
|
|
||||||
// Decode
|
|
||||||
Operation op = this.m_OpTable[this.m_IR];
|
|
||||||
|
|
||||||
//if (op == null)
|
|
||||||
//{
|
|
||||||
// ShowOpList();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if (m_OpList.Count == m_OpList.Capacity)
|
|
||||||
//{
|
|
||||||
// m_OpList.RemoveAt(0);
|
|
||||||
//}
|
|
||||||
//m_OpList.Add(new OpHistory(this.m_PC - 2, op));
|
|
||||||
|
|
||||||
// Execute
|
|
||||||
op();
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Step()
|
|
||||||
{
|
|
||||||
if (this.m_InterruptFlag > 0)
|
|
||||||
{
|
|
||||||
HandleInterrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_IR = (ushort)FetchW();
|
|
||||||
Operation op = this.m_OpTable[this.m_IR];
|
|
||||||
op();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowOpList()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_OpList.Count; i++)
|
|
||||||
{
|
|
||||||
Console.WriteLine(Convert.ToString(m_OpList[i].PC, 16) + "\t" + m_OpList[i].Operation.Method.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool C // Carry
|
|
||||||
{
|
|
||||||
get { return (this.m_SR & 1) > 0; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value) { this.m_SR |= 1; }
|
|
||||||
else { this.m_SR &= -2; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool V // Overflow
|
|
||||||
{
|
|
||||||
get { return (this.m_SR & 2) > 0; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value) { this.m_SR |= 2; }
|
|
||||||
else { this.m_SR &= -3; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Z // Zero
|
|
||||||
{
|
|
||||||
get { return (this.m_SR & 4) > 0; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value) { this.m_SR |= 4; }
|
|
||||||
else { this.m_SR &= -5; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool N // Negative
|
|
||||||
{
|
|
||||||
get { return (this.m_SR & 8) > 0; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value) { this.m_SR |= 8; }
|
|
||||||
else { this.m_SR &= -9; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool X // Extend
|
|
||||||
{
|
|
||||||
get { return (this.m_SR & 16) > 0; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value) { this.m_SR |= 16; }
|
|
||||||
else { this.m_SR &= -17; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool S // Supervisor Mode
|
|
||||||
{
|
|
||||||
get { return (this.m_SR & 8192) > 0; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value) { this.m_SR |= 8192; }
|
|
||||||
else { this.m_SR &= -8193; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int SP
|
|
||||||
{
|
|
||||||
get { return this.m_A[7]; }
|
|
||||||
set { this.m_A[7] = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TestCondition(int cCode)
|
|
||||||
{
|
|
||||||
switch (cCode)
|
|
||||||
{
|
|
||||||
case 0x0: // T
|
|
||||||
return true;
|
|
||||||
case 0x1: // F
|
|
||||||
return false;
|
|
||||||
case 0x2: // HI
|
|
||||||
return !C && !Z;
|
|
||||||
case 0x3: // LS
|
|
||||||
return C || Z;
|
|
||||||
case 0x4: // CC(HI)
|
|
||||||
return !C;
|
|
||||||
case 0x5: // CS(LO)
|
|
||||||
return C;
|
|
||||||
case 0x6: // NE
|
|
||||||
return !Z;
|
|
||||||
case 0x7: // EQ
|
|
||||||
return Z;
|
|
||||||
case 0x8: // VC
|
|
||||||
return !V;
|
|
||||||
case 0x9: // VS
|
|
||||||
return V;
|
|
||||||
case 0xA: // PL
|
|
||||||
return !N;
|
|
||||||
case 0xB: // MI
|
|
||||||
return N;
|
|
||||||
case 0xC: // GE
|
|
||||||
return N && V || !N && !V;
|
|
||||||
case 0xD: // LT
|
|
||||||
return N && !V || !N && V;
|
|
||||||
case 0xE: // GT
|
|
||||||
return N && V && !Z || !N && !V && !Z;
|
|
||||||
case 0xF: // LE
|
|
||||||
return Z || N && !V || !N && V;
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Bad condition code");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,819 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
#region Read
|
|
||||||
private sbyte ReadB(int address)
|
|
||||||
{
|
|
||||||
return this.m_Controller.ReadB(address &= 0x00FFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private short ReadW(int address)
|
|
||||||
{
|
|
||||||
return this.m_Controller.ReadW(address &= 0x00FFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int ReadL(int address)
|
|
||||||
{
|
|
||||||
return this.m_Controller.ReadL(address &= 0x00FFFFFF);
|
|
||||||
}
|
|
||||||
#endregion Read
|
|
||||||
|
|
||||||
#region Write
|
|
||||||
private void WriteB(int address, sbyte value)
|
|
||||||
{
|
|
||||||
this.m_Controller.WriteB(address &= 0x00FFFFFF, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteW(int address, short value)
|
|
||||||
{
|
|
||||||
this.m_Controller.WriteW(address &= 0x00FFFFFF, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteL(int address, int value)
|
|
||||||
{
|
|
||||||
this.m_Controller.WriteL(address &= 0x00FFFFFF, value);
|
|
||||||
}
|
|
||||||
#endregion Write
|
|
||||||
|
|
||||||
#region Fetch
|
|
||||||
private sbyte FetchB()
|
|
||||||
{
|
|
||||||
return ReadB(this.m_PC++);
|
|
||||||
}
|
|
||||||
|
|
||||||
private short FetchW()
|
|
||||||
{
|
|
||||||
short data = ReadW(this.m_PC);
|
|
||||||
this.m_PC += 2;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int FetchL()
|
|
||||||
{
|
|
||||||
int data = ReadL(this.m_PC);
|
|
||||||
this.m_PC += 4;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
#endregion Fetch
|
|
||||||
|
|
||||||
#region Peek
|
|
||||||
private sbyte PeekB()
|
|
||||||
{
|
|
||||||
return ReadB(this.m_PC);
|
|
||||||
}
|
|
||||||
|
|
||||||
private short PeekW()
|
|
||||||
{
|
|
||||||
return ReadW(this.m_PC);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int PeekL()
|
|
||||||
{
|
|
||||||
return ReadL(this.m_PC);
|
|
||||||
}
|
|
||||||
#endregion Peek
|
|
||||||
|
|
||||||
private int FetchIndex()
|
|
||||||
{
|
|
||||||
short extension = FetchW();
|
|
||||||
int da = (extension >> 15) & 0x1;
|
|
||||||
int reg = (extension >> 12) & 0x7;
|
|
||||||
int wl = (extension >> 11) & 0x1;
|
|
||||||
int scale = (extension >> 9) & 0x3;
|
|
||||||
sbyte displacement = (sbyte)extension;
|
|
||||||
|
|
||||||
int indexReg = (scale == 0) ? 1 : ((scale == 1) ? 2 : ((scale == 2) ? 4 : 8));
|
|
||||||
if (da == 0)
|
|
||||||
{
|
|
||||||
indexReg *= (wl == 0) ? (short)this.m_D[reg] : this.m_D[reg];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
indexReg *= (wl == 0) ? (short)this.m_A[reg] : this.m_A[reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
return displacement + indexReg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int PeekIndex()
|
|
||||||
{
|
|
||||||
short extension = PeekW();
|
|
||||||
int da = extension >> 15 & 0x1;
|
|
||||||
int reg = extension >> 12 & 0x7;
|
|
||||||
int wl = extension >> 11 & 0x1;
|
|
||||||
int scale = extension >> 9 & 0x3;
|
|
||||||
sbyte displacement = (sbyte)extension;
|
|
||||||
|
|
||||||
int indexReg = (scale == 0) ? 1 : ((scale == 1) ? 2 : ((scale == 2) ? 4 : 8));
|
|
||||||
if (da == 0)
|
|
||||||
{
|
|
||||||
indexReg *= (wl == 0) ? (short)this.m_D[reg] : this.m_D[reg];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
indexReg *= (wl == 0) ? (short)this.m_A[reg] : this.m_A[reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
return displacement + indexReg;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region FetchOperand
|
|
||||||
private sbyte FetchOperandB(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
return (sbyte)this.m_D[register];
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
return (sbyte)this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
sbyte operand = ReadB(this.m_A[register]);
|
|
||||||
this.m_A[register] += (register == 7) ? 2 : 1;
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
this.m_A[register] -= (register == 7) ? 2 : 1;
|
|
||||||
return ReadB(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_A[register] + FetchW());
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return this.ReadB(this.m_A[register] + FetchIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return ReadB(FetchW());
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return ReadB(FetchL());
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_PC + FetchW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
sbyte operand = ReadB(this.m_PC + PeekIndex());
|
|
||||||
this.m_PC += 2;
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
return (sbyte)FetchW();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private short FetchOperandW(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
return (short)this.m_D[register];
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
return (short)this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
short operand = ReadW(this.m_A[register]);
|
|
||||||
this.m_A[register] += 2;
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
this.m_A[register] -= 2;
|
|
||||||
return ReadW(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register] + FetchW());
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register] + FetchIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return ReadW(FetchW());
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return ReadW(FetchL());
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
return FetchW();
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_PC + FetchW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
short operand = ReadW(this.m_PC + PeekIndex());
|
|
||||||
this.m_PC += 2;
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int FetchOperandL(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
return this.m_D[register];
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
return this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
int operand = ReadL(this.m_A[register]);
|
|
||||||
this.m_A[register] += 4;
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
this.m_A[register] -= 4;
|
|
||||||
return ReadL(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register] + FetchW());
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register] + FetchIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return ReadL(FetchW());
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return ReadL(FetchL());
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
return FetchL();
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_PC + FetchW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
int operand = ReadL(this.m_PC + PeekIndex());
|
|
||||||
this.m_PC += 2;
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion FetchOperand
|
|
||||||
|
|
||||||
#region FetchAddress
|
|
||||||
private int FetchAddress(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid mode!");
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid mode!");
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
return this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
return this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return (this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return (this.m_A[register] + FetchIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return FetchW();
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return FetchL();
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid mode!");
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return (this.m_PC + FetchW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
int address = (this.m_PC + PeekIndex());
|
|
||||||
this.m_PC += 2;
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion FetchAddress
|
|
||||||
|
|
||||||
#region SetOperand
|
|
||||||
private void SetOperandB(int mode, int register, sbyte value)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
this.m_A[register] = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
WriteB(this.m_A[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
WriteB(this.m_A[register]++, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
WriteB(--this.m_A[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
WriteB(this.m_A[register] + FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
WriteB(this.m_A[register] + FetchIndex(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
WriteB(FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
WriteB(FetchL(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid mode!");
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
WriteB(this.m_PC + FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
WriteB(this.m_PC + PeekIndex(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetOperandW(int mode, int register, short value)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
this.m_A[register] = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
WriteW(m_A[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
WriteW(m_A[register], value);
|
|
||||||
m_A[register] += 2;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
m_A[register] -= 2;
|
|
||||||
WriteW(m_A[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
WriteW(this.m_A[register] + FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
WriteW(this.m_A[register] + FetchIndex(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
WriteW(FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
WriteW(FetchL(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid mode!");
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
WriteW(this.m_PC + FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
WriteW(this.m_PC + PeekIndex(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetOperandL(int mode, int register, int value)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
this.m_D[register] = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x1:
|
|
||||||
{
|
|
||||||
// When setting address registers, need to fill whole byte
|
|
||||||
this.m_A[register] = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[register], value);
|
|
||||||
this.m_A[register] += 4;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
this.m_A[register] -= 4;
|
|
||||||
WriteL(this.m_A[register], value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[register] + FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[register] + FetchIndex(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
WriteL(FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
WriteL(FetchL(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid mode!");
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
WriteL(this.m_PC + FetchW(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[register] + PeekIndex(), value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion SetOperand
|
|
||||||
|
|
||||||
#region PeekOperand
|
|
||||||
private sbyte PeekOperandB(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
return (sbyte)this.m_D[register];
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
return (sbyte)this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
return ReadB(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_A[register] + PeekW());
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return this.ReadB(this.m_A[register] + PeekIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return ReadB(PeekW());
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return ReadB(PeekL());
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
return (sbyte)PeekW();
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return ReadB(this.m_PC + PeekW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
return this.ReadB(this.m_PC + FetchIndex());
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private short PeekOperandW(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
return (short)this.m_D[register];
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
return (short)this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register] + PeekW());
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_A[register] + PeekIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return ReadW(PeekW());
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return ReadW(PeekL());
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
return PeekW();
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_PC + PeekW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
return ReadW(this.m_PC + PeekIndex());
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int PeekOperandL(int mode, int register)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0x0: // Dn
|
|
||||||
{
|
|
||||||
return this.m_D[register];
|
|
||||||
}
|
|
||||||
case 0x1: // An
|
|
||||||
{
|
|
||||||
return this.m_A[register];
|
|
||||||
}
|
|
||||||
case 0x2: // (An)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x3: // (An)+
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x4: // -(An)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register]);
|
|
||||||
}
|
|
||||||
case 0x5: //(d16,An)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_A[register] + PeekW());
|
|
||||||
}
|
|
||||||
case 0x6: // (d8,An,Xn)
|
|
||||||
{
|
|
||||||
return this.ReadL(this.m_A[register] + FetchIndex());
|
|
||||||
}
|
|
||||||
case 0x7:
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case 0x0: // (xxx).W
|
|
||||||
{
|
|
||||||
return ReadL(PeekW());
|
|
||||||
}
|
|
||||||
case 0x1: // (xxx).L
|
|
||||||
{
|
|
||||||
return ReadL(PeekL());
|
|
||||||
}
|
|
||||||
case 0x4: // #<data>
|
|
||||||
{
|
|
||||||
return PeekL();
|
|
||||||
}
|
|
||||||
case 0x2: // (d16,PC)
|
|
||||||
{
|
|
||||||
return ReadL(this.m_PC + PeekW());
|
|
||||||
}
|
|
||||||
case 0x3: // (d8,PC,Xn)
|
|
||||||
{
|
|
||||||
return this.ReadB(this.m_PC + FetchIndex());
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Addressing mode doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion PeekOperand
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
internal delegate void Operation();
|
|
||||||
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
private Operation[] m_OpTable = new Operation[0x10000];
|
|
||||||
|
|
||||||
private void BuildOpTable()
|
|
||||||
{
|
|
||||||
// First, define regular expressions for each operation
|
|
||||||
Dictionary<Operation, Regex> opIndex = new Dictionary<Operation, Regex>();
|
|
||||||
|
|
||||||
// Data Movement
|
|
||||||
opIndex.Add(new Operation(EXG), new Regex("1100" + "[0-1]{3}" + "1" + "(01000|01001|10001)" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(LEA), new Regex("0100" + "[0-1]{3}" + "111" + "(((010|101|110)[0-1]{3})|(111(000|001|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(LINK), new Regex("0100111001010" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(MOVE), new Regex("00" + "(01|11|10)" + "(([0-1]{3}(000|010|011|100|101|110))|((000|001)111))" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(MOVEA), new Regex("00" + "(11|10)" + "[0-1]{3}" + "001" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(MOVEM_Mem2Reg), new Regex("01001" + "1" + "001" + "[0-1]" + "((010|011|101|110)[0-1]{3}|(111(000|001|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(MOVEM_Reg2Mem), new Regex("01001" + "0" + "001" + "[0-1]" + "((010|100|101|110)[0-1]{3}|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(MOVEP), new Regex("0000" + "[0-1]{3}" + "(100|101|110|111)" + "001" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(MOVEQ), new Regex("0111" + "[0-1]{3}" + "0" + "[0-1]{8}"));
|
|
||||||
opIndex.Add(new Operation(PEA), new Regex("0100100001" + "(((010|101|110)[0-1]{3})|(111(000|001|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(UNLK), new Regex("0100111001011" + "[0-1]{3}"));
|
|
||||||
|
|
||||||
// Integer Arithmetic
|
|
||||||
opIndex.Add(new Operation(ADD_Dest), new Regex("1101" + "[0-1]{3}" + "1" + "(00|01|10)" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(ADD_Source), new Regex("1101" + "[0-1]{3}" + "0" + "(00|01|10)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(ADDA), new Regex("1101" + "[0-1]{3}" + "(011|111)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(ADDI), new Regex("00000110" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(ADDQ), new Regex("0101" + "[0-1]{3}" + "0" + "(00|01|10)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(ADDX), new Regex("1101" + "[0-1]{3}" + "1" + "(00|01|10)" + "00" + "[0-1]" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(CLR), new Regex("01000010" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(CMP), new Regex("1011" + "[0-1]{3}" + "(000|001|010)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(CMPA), new Regex("1011" + "[0-1]{3}" + "(011|111)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(CMPI), new Regex("00001100" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(CMPM), new Regex("1011" + "[0-1]{3}" + "1" + "(00|01|10)" + "001" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(DIVS), new Regex("1000" + "[0-1]{3}" + "111" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(DIVU), new Regex("1000" + "[0-1]{3}" + "011" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(EXT), new Regex("0100100" + "(010|011|111)" + "000" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(MULS), new Regex("1100" + "[0-1]{3}" + "111" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(MULU), new Regex("1100" + "[0-1]{3}" + "011" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(NEG), new Regex("01000100" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(NEGX), new Regex("01000000" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(SUB_Dest), new Regex("1001" + "[0-1]{3}" + "1" + "(00|01|10)" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(SUB_Source), new Regex("1001" + "[0-1]{3}" + "0" + "(00|01|10)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(SUBA), new Regex("1001" + "[0-1]{3}" + "(011|111)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(SUBI), new Regex("00000100" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(SUBQ), new Regex("0101" + "[0-1]{3}" + "1" + "(00|01|10)" + "(((000|001|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(SUBX), new Regex("1001" + "[0-1]{3}" + "1" + "(00|01|10)" + "00" + "[0-1]" + "[0-1]{3}"));
|
|
||||||
|
|
||||||
// Logical
|
|
||||||
opIndex.Add(new Operation(AND_Dest), new Regex("1100" + "[0-1]{3}" + "1" + "(00|01|10)" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(AND_Source), new Regex("1100" + "[0-1]{3}" + "0" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(ANDI), new Regex("00000010" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(EOR), new Regex("1011" + "[0-1]{3}" + "(100|101|110)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(EORI), new Regex("00001010" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(OR_Dest), new Regex("1000" + "[0-1]{3}" + "1" + "(00|01|10)" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(OR_Source), new Regex("1000" + "[0-1]{3}" + "0" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(ORI), new Regex("00000000" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(NOT), new Regex("01000110" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
|
|
||||||
// Shift and Rotate
|
|
||||||
opIndex.Add(new Operation(ASL), new Regex("1110" + "[0-1]{3}" + "1" + "(00|01|10)" + "[0-1]" + "00" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ASR), new Regex("1110" + "[0-1]{3}" + "0" + "(00|01|10)" + "[0-1]" + "00" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ASL_ASR_Memory), new Regex("1110000" + "[0-1]" + "11" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(LSL), new Regex("1110" + "[0-1]{3}" + "1" + "(00|01|10)" + "[0-1]" + "01" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(LSR), new Regex("1110" + "[0-1]{3}" + "0" + "(00|01|10)" + "[0-1]" + "01" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(LSL_LSR_Memory), new Regex("1110001" + "[0-1]" + "11" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(ROL), new Regex("1110" + "[0-1]{3}" + "1" + "(00|01|10)" + "[0-1]" + "11" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ROR), new Regex("1110" + "[0-1]{3}" + "0" + "(00|01|10)" + "[0-1]" + "11" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ROL_ROR_Memory), new Regex("1110011" + "[0-1]" + "11" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(ROXL), new Regex("1110" + "[0-1]{3}" + "1" + "(00|01|10)" + "[0-1]" + "10" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ROXR), new Regex("1110" + "[0-1]{3}" + "0" + "(00|01|10)" + "[0-1]" + "10" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ROXL_ROXR_Memory), new Regex("1110010" + "[0-1]" + "11" + "(((010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(SWAP), new Regex("0100100001000" + "[0-1]{3}"));
|
|
||||||
|
|
||||||
// Bit Manipulation
|
|
||||||
opIndex.Add(new Operation(BTST_Dynamic), new Regex("0000" + "[0-1]{3}" + "100" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(BTST_Static), new Regex("0000100000" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|010|011)))"));
|
|
||||||
|
|
||||||
opIndex.Add(new Operation(BSET_Dynamic), new Regex("0000" + "[0-1]{3}" + "111" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(BSET_Static), new Regex("0000100011" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
|
|
||||||
opIndex.Add(new Operation(BCLR_Dynamic), new Regex("0000" + "[0-1]{3}" + "110" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(BCLR_Static), new Regex("0000100010" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
|
|
||||||
opIndex.Add(new Operation(BCHG_Dynamic), new Regex("0000" + "[0-1]{3}" + "101" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(BCHG_Static), new Regex("0000100001" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
|
|
||||||
// Program Control
|
|
||||||
opIndex.Add(new Operation(Bcc), new Regex("0110" + "(001|010|011|100|101|110|111)[0-1]" + "[0-1]{8}"));
|
|
||||||
opIndex.Add(new Operation(DBcc), new Regex("0101" + "[0-1]{4}" + "11001" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(Scc), new Regex("0101" + "[0-1]{4}" + "11" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
|
|
||||||
opIndex.Add(new Operation(BRA), new Regex("01100000" + "[0-1]{8}"));
|
|
||||||
opIndex.Add(new Operation(BSR), new Regex("01100001" + "[0-1]{8}"));
|
|
||||||
opIndex.Add(new Operation(JMP), new Regex("0100111011" + "(((010|101|110)[0-1]{3})|(111(000|001|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(JSR), new Regex("0100111010" + "(((010|101|110)[0-1]{3})|(111(000|001|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(NOP), new Regex("0100111001110001"));
|
|
||||||
|
|
||||||
opIndex.Add(new Operation(RTS), new Regex("0100111001110101"));
|
|
||||||
|
|
||||||
opIndex.Add(new Operation(TST), new Regex("01001010" + "(00|01|10)" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
|
|
||||||
// System Control
|
|
||||||
opIndex.Add(new Operation(ANDI_to_CCR), new Regex("0000001000111100"));
|
|
||||||
opIndex.Add(new Operation(ANDI_to_SR), new Regex("0000001001111100"));
|
|
||||||
opIndex.Add(new Operation(CHK), new Regex("0100" + "[0-1]{3}" + "(11|10)" + "0" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(EORI_to_CCR), new Regex("0000101000111100"));
|
|
||||||
opIndex.Add(new Operation(EORI_to_SR), new Regex("0000101001111100"));
|
|
||||||
opIndex.Add(new Operation(ILLEGAL), new Regex("0100101011111100"));
|
|
||||||
opIndex.Add(new Operation(MOVE_from_SR), new Regex("0100000011" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001)))"));
|
|
||||||
opIndex.Add(new Operation(MOVE_to_CCR), new Regex("0100010011" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(MOVE_to_SR), new Regex("0100011011" + "(((000|010|011|100|101|110)[0-1]{3})|(111(000|001|100|010|011)))"));
|
|
||||||
opIndex.Add(new Operation(MOVE_USP), new Regex("010011100110" + "[0-1]" + "[0-1]{3}"));
|
|
||||||
opIndex.Add(new Operation(ORI_to_CCR), new Regex("0000000000111100"));
|
|
||||||
opIndex.Add(new Operation(ORI_to_SR), new Regex("0000000001111100"));
|
|
||||||
opIndex.Add(new Operation(RESET), new Regex("0100111001110000"));
|
|
||||||
opIndex.Add(new Operation(RTE), new Regex("0100111001110011"));
|
|
||||||
opIndex.Add(new Operation(RTR), new Regex("0100111001110111"));
|
|
||||||
opIndex.Add(new Operation(STOP), new Regex("0100111001110010"));
|
|
||||||
opIndex.Add(new Operation(TRAP), new Regex("010011100100" + "[0-1]{4}"));
|
|
||||||
opIndex.Add(new Operation(TRAPV), new Regex("0100111001110110"));
|
|
||||||
|
|
||||||
// Now, run through every possible 16-bit binary number,
|
|
||||||
// find the matching expression, and add that code to the table
|
|
||||||
for (int i = 0; i < 0x10000; i++)
|
|
||||||
{
|
|
||||||
string binaryString = Convert.ToString(i, 2);
|
|
||||||
binaryString = binaryString.PadLeft(16, '0');
|
|
||||||
Dictionary<Operation, Regex>.Enumerator enumerator = opIndex.GetEnumerator();
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
if (enumerator.Current.Value.IsMatch(binaryString))
|
|
||||||
{
|
|
||||||
if (this.m_OpTable[i] != null)
|
|
||||||
{
|
|
||||||
throw new Exception("Two operations with clashing codes!");
|
|
||||||
}
|
|
||||||
this.m_OpTable[i] = enumerator.Current.Key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,207 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
private void Btst(int mode, int register, int mask)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: // Destination is data register
|
|
||||||
{
|
|
||||||
int operand = FetchOperandL(mode, register);
|
|
||||||
this.Z = ((operand & mask) == 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
byte operand = (byte)FetchOperandB(mode, register);
|
|
||||||
this.Z = ((operand & mask) == 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BTST_Dynamic()
|
|
||||||
{
|
|
||||||
int bitNumberRegister = (this.m_IR >> 9) & 0x7;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = this.m_D[bitNumberRegister];
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Btst(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 4 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BTST_Static()
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = (byte)(FetchW() & 0x00FF);
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Btst(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 10 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bset(int mode, int register, int mask)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: // Destination is data register
|
|
||||||
{
|
|
||||||
int operand = PeekOperandL(mode, register);
|
|
||||||
this.Z = ((operand & mask) == 0);
|
|
||||||
SetOperandL(mode, register, (operand | mask));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
byte operand = (byte)PeekOperandB(mode, register);
|
|
||||||
this.Z = ((operand & mask) == 0);
|
|
||||||
SetOperandB(mode, register, (sbyte)(operand | mask));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BSET_Dynamic()
|
|
||||||
{
|
|
||||||
int bitNumberRegister = (this.m_IR >> 9) & 0x7;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = this.m_D[bitNumberRegister];
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Bset(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BSET_Static()
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = (byte)(FetchW() & 0x00FF);
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Bset(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 12 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bclr(int mode, int register, int mask)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: // Destination is data register
|
|
||||||
{
|
|
||||||
int operand = PeekOperandL(mode, register);
|
|
||||||
this.Z = ((operand & mask) > 0);
|
|
||||||
SetOperandL(mode, register, (operand & ~mask));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
byte operand = (byte)PeekOperandB(mode, register);
|
|
||||||
this.Z = ((operand & mask) > 0);
|
|
||||||
SetOperandB(mode, register, (sbyte)(operand & ~mask));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BCLR_Dynamic()
|
|
||||||
{
|
|
||||||
int bitNumberRegister = (this.m_IR >> 9) & 0x7;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = this.m_D[bitNumberRegister];
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Bclr(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 10 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BCLR_Static()
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = (byte)(FetchW() & 0x00FF);
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Bclr(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 14 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bchg(int mode, int register, int mask)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: // Destination is data register
|
|
||||||
{
|
|
||||||
int operand = PeekOperandL(mode, register);
|
|
||||||
this.Z = ((operand & mask) > 0);
|
|
||||||
SetOperandL(mode, register, (operand ^ mask));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
byte operand = (byte)PeekOperandB(mode, register);
|
|
||||||
this.Z = ((operand & mask) > 0);
|
|
||||||
SetOperandB(mode, register, (sbyte)(operand ^ mask));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BCHG_Dynamic()
|
|
||||||
{
|
|
||||||
int bitNumberRegister = (this.m_IR >> 9) & 0x7;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = this.m_D[bitNumberRegister];
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Bchg(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BCHG_Static()
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Need to convert bit number into a mask
|
|
||||||
int bitNumber = (byte)(FetchW() & 0x00FF);
|
|
||||||
bitNumber %= (mode == 0) ? 32 : 8;
|
|
||||||
int mask = 1 << bitNumber;
|
|
||||||
|
|
||||||
Bchg(mode, register, mask);
|
|
||||||
this.m_Cycles += (mode == 0) ? 12 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,396 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
private void EXG() // Exchange registers
|
|
||||||
{
|
|
||||||
this.m_Cycles += 6;
|
|
||||||
|
|
||||||
switch ((this.m_IR >> 3) & 0x31)
|
|
||||||
{
|
|
||||||
case 8:
|
|
||||||
Helpers.Swap(ref this.m_D[(this.m_IR >> 9) & 0x7], ref this.m_D[this.m_IR & 0x7]);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 9:
|
|
||||||
Helpers.Swap(ref this.m_A[(this.m_IR >> 9) & 0x7], ref this.m_A[this.m_IR & 0x7]);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 17:
|
|
||||||
Helpers.Swap(ref this.m_D[(this.m_IR >> 9) & 0x7], ref this.m_A[this.m_IR & 0x7]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LEA() // Load effective address
|
|
||||||
{
|
|
||||||
this.m_A[(this.m_IR >> 9) & 0x7] =
|
|
||||||
FetchAddress((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
|
|
||||||
switch ((this.m_IR >> 3) & 0x7)
|
|
||||||
{
|
|
||||||
case 0x2: this.m_Cycles += 4; break;
|
|
||||||
case 0x5: this.m_Cycles += 8; break;
|
|
||||||
case 0x6: this.m_Cycles += 12; break;
|
|
||||||
case 0x7:
|
|
||||||
switch (this.m_IR & 0x7)
|
|
||||||
{
|
|
||||||
case 0x0: this.m_Cycles += 8; break;
|
|
||||||
case 0x1: this.m_Cycles += 12; break;
|
|
||||||
case 0x2: this.m_Cycles += 8; break;
|
|
||||||
case 0x3: this.m_Cycles += 12; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LINK()
|
|
||||||
{
|
|
||||||
this.SP -= 4;
|
|
||||||
WriteL(this.SP, this.m_A[this.m_IR & 0x7]);
|
|
||||||
this.m_A[this.m_IR & 0x7] = this.SP;
|
|
||||||
this.SP += FetchW();
|
|
||||||
|
|
||||||
this.m_Cycles += 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVE() // Move data from source to destination
|
|
||||||
{
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_reg = this.m_IR & 0x7;
|
|
||||||
int dest_mode = (this.m_IR >> 6) & 0x7;
|
|
||||||
int dest_reg = (this.m_IR >> 9) & 0x7;
|
|
||||||
|
|
||||||
int operand = 0;
|
|
||||||
switch ((this.m_IR >> 12) & 0x3)
|
|
||||||
{
|
|
||||||
case 1: // B
|
|
||||||
operand = FetchOperandB(src_mode, src_reg);
|
|
||||||
SetOperandB(dest_mode, dest_reg, (sbyte)operand);
|
|
||||||
this.m_Cycles += Helpers.MOVECyclesBW[src_mode + ((src_mode == 7) ? src_reg : 0),
|
|
||||||
dest_mode + ((dest_mode == 7) ? dest_reg : 0)];
|
|
||||||
break;
|
|
||||||
case 3: // W
|
|
||||||
operand = FetchOperandW(src_mode, src_reg);
|
|
||||||
SetOperandW(dest_mode, dest_reg, (short)operand);
|
|
||||||
this.m_Cycles += Helpers.MOVECyclesBW[src_mode + ((src_mode == 7) ? src_reg : 0),
|
|
||||||
dest_mode + ((dest_mode == 7) ? dest_reg : 0)];
|
|
||||||
break;
|
|
||||||
case 2: // L
|
|
||||||
operand = FetchOperandL(src_mode, src_reg);
|
|
||||||
SetOperandL(dest_mode, dest_reg, operand);
|
|
||||||
this.m_Cycles += Helpers.MOVECyclesL[src_mode + ((src_mode == 7) ? src_reg : 0),
|
|
||||||
dest_mode + ((dest_mode == 7) ? dest_reg : 0)];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = (operand < 0);
|
|
||||||
this.Z = (operand == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVEA() // Move Address
|
|
||||||
{
|
|
||||||
// W
|
|
||||||
if ((this.m_IR >> 12 & 0x3) == 3)
|
|
||||||
{
|
|
||||||
this.m_A[this.m_IR >> 9 & 0x7] =
|
|
||||||
FetchOperandW(this.m_IR >> 3 & 0x7, this.m_IR & 0x7);
|
|
||||||
// TODO Need to check these clock cycles
|
|
||||||
this.m_Cycles += Helpers.MOVECyclesBW[(this.m_IR >> 3 & 0x7) + (((this.m_IR >> 3 & 0x7) == 7) ? (this.m_IR & 0x7) : 0), 1];
|
|
||||||
}
|
|
||||||
// L
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_A[this.m_IR >> 9 & 0x7] =
|
|
||||||
FetchOperandL(this.m_IR >> 3 & 0x7, this.m_IR & 0x7);
|
|
||||||
// TODO Need to check these clock cycles
|
|
||||||
this.m_Cycles += Helpers.MOVECyclesL[(this.m_IR >> 3 & 0x7) + (((this.m_IR >> 3 & 0x7) == 7) ? (this.m_IR & 0x7) : 0), 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVEM_Mem2Reg()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x1;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
ushort regMap = (ushort)FetchW();
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
int address = FetchAddress(src_mode, src_register);
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // W
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
this.m_D[i] = ReadW(address);
|
|
||||||
address += 2;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
this.m_A[i] = ReadW(address);
|
|
||||||
address += 2;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
if (src_mode == 3) // Postincrement mode
|
|
||||||
{
|
|
||||||
this.m_A[src_register] = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += count * 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: // L
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
this.m_D[i] = (int)ReadL(address);
|
|
||||||
address += 4;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
this.m_A[i] = (int)ReadL(address);
|
|
||||||
address += 4;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
if (src_mode == 3) // Postincrement mode
|
|
||||||
{
|
|
||||||
this.m_A[src_register] = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += count * 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (src_mode)
|
|
||||||
{
|
|
||||||
case 0x2: this.m_Cycles += 12; break;
|
|
||||||
case 0x3: this.m_Cycles += 12; break;
|
|
||||||
case 0x5: this.m_Cycles += 16; break;
|
|
||||||
case 0x6: this.m_Cycles += 18; break;
|
|
||||||
case 0x7:
|
|
||||||
switch (src_register)
|
|
||||||
{
|
|
||||||
case 0x0: this.m_Cycles += 16; break;
|
|
||||||
case 0x1: this.m_Cycles += 20; break;
|
|
||||||
case 0x2: this.m_Cycles += 16; break;
|
|
||||||
case 0x3: this.m_Cycles += 18; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVEM_Reg2Mem()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x1;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
ushort regMap = (ushort)FetchW();
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
int address = FetchAddress(src_mode, src_register);
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // W
|
|
||||||
{
|
|
||||||
if (src_mode == 4) // Pre-decrement mode
|
|
||||||
{
|
|
||||||
for (int i = 7; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
address -= 2;
|
|
||||||
WriteW(address, (sbyte)this.m_A[i]);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
for (int i = 7; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
address -= 2;
|
|
||||||
WriteW(address, (sbyte)this.m_D[i]);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
this.m_A[src_register] = address;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
WriteW(address, (sbyte)this.m_D[i]);
|
|
||||||
address += 2;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
WriteW(address, (sbyte)this.m_A[i]);
|
|
||||||
address += 2;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.m_Cycles += 4 * count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: // L
|
|
||||||
{
|
|
||||||
if (src_mode == 4) // Pre-decrement mode
|
|
||||||
{
|
|
||||||
for (int i = 7; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
address -= 4;
|
|
||||||
WriteL(address, this.m_A[i]);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
for (int i = 7; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
address -= 4;
|
|
||||||
WriteL(address, this.m_D[i]);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
this.m_A[src_register] = address;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
WriteL(address, this.m_D[i]);
|
|
||||||
address += 4;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((regMap & 0x1) > 0)
|
|
||||||
{
|
|
||||||
WriteL(address, this.m_A[i]);
|
|
||||||
address += 4;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
regMap = (ushort)(regMap >> 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.m_Cycles += 8 * count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (src_mode)
|
|
||||||
{
|
|
||||||
case 0x2: this.m_Cycles += 8; break;
|
|
||||||
case 0x4: this.m_Cycles += 8; break;
|
|
||||||
case 0x5: this.m_Cycles += 12; break;
|
|
||||||
case 0x6: this.m_Cycles += 14; break;
|
|
||||||
case 0x7:
|
|
||||||
switch (src_register)
|
|
||||||
{
|
|
||||||
case 0x0: this.m_Cycles += 12; break;
|
|
||||||
case 0x1: this.m_Cycles += 16; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVEP()
|
|
||||||
{
|
|
||||||
int dataregister = (this.m_IR >> 9) & 0x7;
|
|
||||||
int opmode = (this.m_IR >> 6) & 0x7;
|
|
||||||
int addressregister = this.m_IR & 0x7;
|
|
||||||
short displacement = FetchW();
|
|
||||||
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVEQ() // Move quick
|
|
||||||
{
|
|
||||||
// Data byte is sign-extended to 32 bits
|
|
||||||
int data = (sbyte)this.m_IR;
|
|
||||||
|
|
||||||
this.N = (data < 0);
|
|
||||||
this.Z = (data == 0);
|
|
||||||
this.V = this.C = false;
|
|
||||||
|
|
||||||
this.m_D[(this.m_IR >> 9) & 0x7] = data;
|
|
||||||
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PEA() // Push effective address
|
|
||||||
{
|
|
||||||
this.SP -= 4;
|
|
||||||
WriteL(this.SP, FetchAddress((this.m_IR >> 3) & 0x7, this.m_IR & 0x7));
|
|
||||||
|
|
||||||
switch ((this.m_IR >> 3) & 0x7)
|
|
||||||
{
|
|
||||||
case 0x2: this.m_Cycles += 12; break;
|
|
||||||
case 0x5: this.m_Cycles += 16; break;
|
|
||||||
case 0x6: this.m_Cycles += 20; break;
|
|
||||||
case 0x7:
|
|
||||||
switch (this.m_IR & 0x7)
|
|
||||||
{
|
|
||||||
case 0x0: this.m_Cycles += 16; break;
|
|
||||||
case 0x1: this.m_Cycles += 20; break;
|
|
||||||
case 0x2: this.m_Cycles += 16; break;
|
|
||||||
case 0x3: this.m_Cycles += 20; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UNLK()
|
|
||||||
{
|
|
||||||
this.SP = this.m_A[this.m_IR & 0x7];
|
|
||||||
this.m_A[this.m_IR & 0x7] = ReadL(this.SP);
|
|
||||||
this.SP += 4;
|
|
||||||
|
|
||||||
this.m_Cycles += 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,869 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
#region Add Helper Functions
|
|
||||||
private sbyte Add(sbyte a, sbyte b, bool updateConditions, bool useX)
|
|
||||||
{
|
|
||||||
int result = useX ? (int)a + (int)b + (this.X ? 1 : 0) : (int)a + (int)b;
|
|
||||||
|
|
||||||
if (updateConditions)
|
|
||||||
{
|
|
||||||
this.C = this.X = (result & 0x100) > 0;
|
|
||||||
this.V = result > sbyte.MaxValue || result < sbyte.MinValue;
|
|
||||||
this.N = result < 0;
|
|
||||||
if (!useX) { this.Z = result == 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (sbyte)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private short Add(short a, short b, bool updateConditions, bool useX)
|
|
||||||
{
|
|
||||||
int result = useX ? (int)a + (int)b + (this.X ? 1 : 0) : (int)a + (int)b;
|
|
||||||
|
|
||||||
if (updateConditions)
|
|
||||||
{
|
|
||||||
this.C = this.X = (result & 0x10000) > 0;
|
|
||||||
this.V = result > short.MaxValue || result < short.MinValue;
|
|
||||||
this.N = result < 0;
|
|
||||||
if (!useX) { this.Z = result == 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (short)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int Add(int a, int b, bool updateConditions, bool useX)
|
|
||||||
{
|
|
||||||
long result = useX ? (long)a + (long)b + (this.X ? 1 : 0) : (long)a + (long)b;
|
|
||||||
|
|
||||||
if (updateConditions)
|
|
||||||
{
|
|
||||||
this.C = this.X = (result & 0x100000000) > 0;
|
|
||||||
this.V = result > int.MaxValue || result < int.MinValue;
|
|
||||||
this.N = result < 0;
|
|
||||||
if (!useX) { this.Z = result == 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)result;
|
|
||||||
}
|
|
||||||
#endregion Add Helper Functions
|
|
||||||
|
|
||||||
#region Sub Helper Functions
|
|
||||||
private sbyte Sub(sbyte a, sbyte b, bool updateConditions, bool setX, bool useX)
|
|
||||||
{
|
|
||||||
int result = useX ? (int)b - (int)a - (this.X ? 1 : 0) : (int)b - (int)a;
|
|
||||||
|
|
||||||
if (updateConditions)
|
|
||||||
{
|
|
||||||
this.C = (result & 0x100) > 0;
|
|
||||||
this.V = result > sbyte.MaxValue || result < sbyte.MinValue;
|
|
||||||
this.N = result < 0;
|
|
||||||
if (!useX) { this.Z = result == 0; }
|
|
||||||
if (setX) { this.X = this.C; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (sbyte)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private short Sub(short a, short b, bool updateConditions, bool setX, bool useX)
|
|
||||||
{
|
|
||||||
int result = useX ? (int)b - (int)a - (this.X ? 1 : 0) : (int)b - (int)a;
|
|
||||||
|
|
||||||
if (updateConditions)
|
|
||||||
{
|
|
||||||
this.C = (result & 0x10000) > 0;
|
|
||||||
this.V = result > short.MaxValue || result < short.MinValue;
|
|
||||||
this.N = result < 0;
|
|
||||||
if (!useX) { this.Z = result == 0; }
|
|
||||||
if (setX) { this.X = this.C; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (short)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int Sub(int a, int b, bool updateConditions, bool setX, bool useX)
|
|
||||||
{
|
|
||||||
long result = useX ? (long)b - (long)a - (this.X ? 1 : 0) : (long)b - (long)a;
|
|
||||||
|
|
||||||
if (updateConditions)
|
|
||||||
{
|
|
||||||
this.C = (result & 0x100000000) > 0;
|
|
||||||
this.V = result > int.MaxValue || result < int.MinValue;
|
|
||||||
this.N = result < 0;
|
|
||||||
if (!useX) { this.Z = result == 0; }
|
|
||||||
if (setX) { this.X = this.C; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)result;
|
|
||||||
}
|
|
||||||
#endregion Sub Helper Functions
|
|
||||||
|
|
||||||
private void ADD_Dest()
|
|
||||||
{
|
|
||||||
int src_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sbyte result = Add((sbyte)this.m_D[src_register], PeekOperandB(mode, register), true, false);
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
short result = Add((short)this.m_D[src_register], PeekOperandW(mode, register), true, false);
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int result = Add(this.m_D[src_register], PeekOperandL(mode, register), true, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += 12 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ADD_Source()
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sbyte result = Add((sbyte)this.m_D[dest_register], FetchOperandB(src_mode, src_register), true, false);
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
short result = Add((short)this.m_D[dest_register], FetchOperandW(src_mode, src_register), true, false);
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int result = Add(this.m_D[dest_register], FetchOperandL(src_mode, src_register), true, false);
|
|
||||||
this.m_D[dest_register] = result;
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ADDA()
|
|
||||||
{
|
|
||||||
int register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int opmode = (this.m_IR >> 6) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (opmode)
|
|
||||||
{
|
|
||||||
case 3: // W
|
|
||||||
this.m_A[register] += FetchOperandW(src_mode, src_register);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
case 7: // L
|
|
||||||
this.m_A[register] += FetchOperandL(src_mode, src_register);
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ADDI()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Add((sbyte)FetchW(), PeekOperandB(mode, register), true, false);
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Add(FetchW(), PeekOperandW(mode, register), true, false);
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Add(FetchL(), PeekOperandL(mode, register), true, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 16 : 20 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ADDQ() // Add Quick
|
|
||||||
{
|
|
||||||
int data = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// With data, 0 means 8
|
|
||||||
data = (data == 0) ? 8 : data;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
if (mode == 1)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Byte operation not allowed on address registers");
|
|
||||||
}
|
|
||||||
sbyte result = Add(PeekOperandB(mode, register), (sbyte)data, (mode != 1), false);
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
switch (mode) {
|
|
||||||
case 0: this.m_Cycles += 4; break;
|
|
||||||
case 1: this.m_Cycles += 4; break;
|
|
||||||
default: this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register); break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
if (mode == 1)
|
|
||||||
{
|
|
||||||
int result = Add(PeekOperandL(mode, register), data, false, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
short result = Add(PeekOperandW(mode, register), (short)data, true, false);
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
}
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: this.m_Cycles += 4; break;
|
|
||||||
case 1: this.m_Cycles += 4; break;
|
|
||||||
default: this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register); break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Add(PeekOperandL(mode, register), data, (mode != 1), false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: this.m_Cycles += 8; break;
|
|
||||||
case 1: this.m_Cycles += 8; break;
|
|
||||||
default: this.m_Cycles += 12 + Helpers.EACalcTimeL(mode, register); break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ADDX()
|
|
||||||
{
|
|
||||||
int regRx = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int rm = (this.m_IR >> 3) & 0x1;
|
|
||||||
int regRy = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
if (rm == 0)
|
|
||||||
{
|
|
||||||
this.m_D[regRy] = Add((sbyte)this.m_D[regRx], (sbyte)this.m_D[regRy], true, true);
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteB(this.m_A[regRy], Add(ReadB(this.m_A[regRx]), ReadB(this.m_A[regRy]), true, true));
|
|
||||||
this.m_Cycles += 18;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
if (rm == 0)
|
|
||||||
{
|
|
||||||
this.m_D[regRy] = Add((short)this.m_D[regRx], (short)this.m_D[regRy], true, true);
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteW(this.m_A[regRy], Add(ReadW(this.m_A[regRx]), ReadW(this.m_A[regRy]), true, true));
|
|
||||||
this.m_Cycles += 18;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
if (rm == 0)
|
|
||||||
{
|
|
||||||
this.m_D[regRy] = Add(this.m_D[regRx], this.m_D[regRy], true, true);
|
|
||||||
this.m_Cycles += 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[regRy], Add(ReadB(this.m_A[regRx]), ReadB(this.m_A[regRy]), true, true));
|
|
||||||
this.m_Cycles += 30;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CLR() // Clear an operand
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
this.C = this.N = this.V = false;
|
|
||||||
this.Z = true;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
SetOperandB(mode, register, 0);
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 1: // W
|
|
||||||
SetOperandW(mode, register, 0);
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 2: // L
|
|
||||||
SetOperandL(mode, register, 0);
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 12 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CMP() // Compare
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int opmode = (this.m_IR >> 6) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (opmode)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
Sub(FetchOperandB(src_mode, src_register), (sbyte)this.m_D[dest_register], true, false, false);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
case 1: // W
|
|
||||||
Sub(FetchOperandW(src_mode, src_register), (short)this.m_D[dest_register], true, false, false);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
case 2: // L
|
|
||||||
Sub(FetchOperandL(src_mode, src_register), this.m_D[dest_register], true, false, false);
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CMPA()
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int opmode = (this.m_IR >> 6) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (opmode)
|
|
||||||
{
|
|
||||||
case 3: // W
|
|
||||||
Sub((int)FetchOperandW(src_mode, src_register), this.m_A[dest_register], true, false, false);
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
case 7: // L
|
|
||||||
Sub(FetchOperandL(src_mode, src_register), this.m_A[dest_register], true, false, false);
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CMPI()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
Sub((sbyte)FetchW(), FetchOperandB(mode, register), true, false, false);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 1: // W
|
|
||||||
Sub((short)FetchW(), FetchOperandW(mode, register), true, false, false);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 2: // L
|
|
||||||
Sub(FetchL(), FetchOperandL(mode, register), true, false, false);
|
|
||||||
this.m_Cycles += (mode == 0) ? 14 : 12 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CMPM()
|
|
||||||
{
|
|
||||||
int registerAx = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int registerAy = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
Sub((sbyte)this.m_A[registerAy], (sbyte)this.m_A[registerAy], true, false, false);
|
|
||||||
this.m_Cycles += 12;
|
|
||||||
return;
|
|
||||||
case 1: // W
|
|
||||||
Sub((short)this.m_A[registerAy], (short)this.m_A[registerAy], true, false, false);
|
|
||||||
this.m_Cycles += 12;
|
|
||||||
return;
|
|
||||||
case 2: // L
|
|
||||||
Sub(this.m_A[registerAy], this.m_A[registerAy], true, false, false);
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DIVS() // Unsigned multiply
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// On 68000, only allowable size is Word
|
|
||||||
int source = (short)FetchOperandW(src_mode, src_register);
|
|
||||||
int dest = this.m_D[dest_register];
|
|
||||||
|
|
||||||
this.C = false;
|
|
||||||
if (source == 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Divide by zero...");
|
|
||||||
}
|
|
||||||
|
|
||||||
int quotient = dest / source;
|
|
||||||
int remainder = dest % source;
|
|
||||||
|
|
||||||
// Detect overflow
|
|
||||||
if (quotient < short.MinValue || quotient > short.MaxValue)
|
|
||||||
{
|
|
||||||
this.V = true;
|
|
||||||
throw new ArgumentException("Division overflow");
|
|
||||||
}
|
|
||||||
this.m_D[dest_register] = (remainder << 16) | quotient;
|
|
||||||
|
|
||||||
this.m_Cycles += 158 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
|
|
||||||
this.N = quotient < 0;
|
|
||||||
this.Z = quotient == 0;
|
|
||||||
this.V = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DIVU() // Unsigned multiply
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// On 68000, only allowable size is Word
|
|
||||||
uint source = (uint)FetchOperandW(src_mode, src_register);
|
|
||||||
uint dest = (uint)this.m_D[dest_register];
|
|
||||||
|
|
||||||
this.C = false;
|
|
||||||
if (source == 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Divide by zero...");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint quotient = dest / source;
|
|
||||||
uint remainder = dest % source;
|
|
||||||
|
|
||||||
// Detect overflow
|
|
||||||
if (quotient < ushort.MinValue || quotient > ushort.MaxValue ||
|
|
||||||
remainder < ushort.MinValue || remainder > ushort.MaxValue)
|
|
||||||
{
|
|
||||||
this.V = true;
|
|
||||||
throw new ArgumentException("Division overflow");
|
|
||||||
}
|
|
||||||
this.m_D[dest_register] = (int)((remainder << 16) | quotient);
|
|
||||||
|
|
||||||
this.m_Cycles += 140 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
|
|
||||||
this.N = quotient < 0;
|
|
||||||
this.Z = quotient == 0;
|
|
||||||
this.V = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EXT() // Sign extend
|
|
||||||
{
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
|
|
||||||
switch ((this.m_IR >> 6) & 0x7)
|
|
||||||
{
|
|
||||||
case 2: // Byte to word
|
|
||||||
Helpers.Inject(ref this.m_D[this.m_IR & 0x7], (short)((sbyte)this.m_D[this.m_IR & 0x7]));
|
|
||||||
break;
|
|
||||||
case 3: // Word to long
|
|
||||||
this.m_D[this.m_IR & 0x7] = (short)this.m_D[this.m_IR & 0x7];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MULS() // Unsigned multiply
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// On 68000, only allowable size is Word
|
|
||||||
short operand = FetchOperandW(src_mode, src_register);
|
|
||||||
short currentValue = (short)this.m_D[dest_register];
|
|
||||||
|
|
||||||
int newValue = operand * currentValue;
|
|
||||||
this.m_D[dest_register] = newValue;
|
|
||||||
|
|
||||||
this.m_Cycles += 70 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
|
|
||||||
this.N = newValue < 0;
|
|
||||||
this.Z = newValue == 0;
|
|
||||||
this.V = false; // Can't get an overflow
|
|
||||||
this.C = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MULU() // Unsigned multiply
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// On 68000, only allowable size is Word
|
|
||||||
ushort operand = (ushort)FetchOperandW(src_mode, src_register);
|
|
||||||
ushort currentValue = (ushort)this.m_D[dest_register];
|
|
||||||
|
|
||||||
uint newValue = (uint)(operand * currentValue);
|
|
||||||
this.m_D[dest_register] = (int)newValue;
|
|
||||||
|
|
||||||
this.m_Cycles += 70 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
|
|
||||||
this.N = (int)newValue < 0;
|
|
||||||
this.Z = (newValue == 0);
|
|
||||||
this.V = false; // Can't get an overflow
|
|
||||||
this.C = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NEG()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
SetOperandB(mode, register, Sub(PeekOperandB(mode, register), (sbyte)0, true, true, false));
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
SetOperandW(mode, register, Sub(PeekOperandW(mode, register), (short)0, true, true, false));
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
SetOperandL(mode, register, Sub(PeekOperandL(mode, register), (int)0, true, true, false));
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 12 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NEGX()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
SetOperandB(mode, register, Sub(PeekOperandB(mode, register), (sbyte)0, true, true, false));
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
SetOperandW(mode, register, Sub(PeekOperandW(mode, register), (short)0, true, true, false));
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
SetOperandL(mode, register, Sub(PeekOperandL(mode, register), (int)0, true, true, false));
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 12 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SUB_Dest()
|
|
||||||
{
|
|
||||||
int src_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sbyte result = Sub((sbyte)this.m_D[src_register], PeekOperandB(mode, register), true, true, false);
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
short result = Sub((short)this.m_D[src_register], PeekOperandW(mode, register), true, true, false);
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int result = Sub(this.m_D[src_register], PeekOperandL(mode, register), true, true, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += 12 + Helpers.EACalcTimeL(mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SUB_Source()
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sbyte result = Sub(FetchOperandB(src_mode, src_register), (sbyte)this.m_D[dest_register], true, true, false);
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
short result = Sub(FetchOperandW(src_mode, src_register), (short)this.m_D[dest_register], true, true, false);
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int result = Sub(FetchOperandL(src_mode, src_register), this.m_D[dest_register], true, true, false);
|
|
||||||
this.m_D[dest_register] = (int)result;
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SUBA()
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int opmode = (this.m_IR >> 6) & 0x7;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (opmode)
|
|
||||||
{
|
|
||||||
case 3: // W
|
|
||||||
{
|
|
||||||
int operand = FetchOperandW(src_mode, src_register); // Sign-extended
|
|
||||||
this.m_A[dest_register] -= operand;
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 7: // L
|
|
||||||
{
|
|
||||||
int operand = FetchOperandL(src_mode, src_register);
|
|
||||||
this.m_A[dest_register] -= operand;
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SUBI()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Sub((sbyte)FetchW(), PeekOperandB(mode, register), true, true, false);
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Sub(FetchW(), PeekOperandW(mode, register), true, true, false);
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Sub(FetchL(), PeekOperandL(mode, register), true, true, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 16 : 20 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SUBQ() // Add Quick
|
|
||||||
{
|
|
||||||
int data = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// With data, 0 means 8
|
|
||||||
data = (data == 0) ? 8 : data;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
if (mode == 1)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Byte operation not allowed on address registers");
|
|
||||||
}
|
|
||||||
sbyte result = Sub((sbyte)data, PeekOperandB(mode, register), (mode != 1), true, false);
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: this.m_Cycles += 4; break;
|
|
||||||
case 1: this.m_Cycles += 8; break;
|
|
||||||
default: this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register); break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
if (mode == 1)
|
|
||||||
{
|
|
||||||
int result = Sub(data, PeekOperandL(mode, register), false, true, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
short result = Sub((short)data, PeekOperandW(mode, register), true, true, false);
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
}
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: this.m_Cycles += 4; break;
|
|
||||||
case 1: this.m_Cycles += 8; break;
|
|
||||||
default: this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register); break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Sub(data, PeekOperandL(mode, register), (mode != 1), true, false);
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case 0: this.m_Cycles += 8; break;
|
|
||||||
case 1: this.m_Cycles += 8; break;
|
|
||||||
default: this.m_Cycles += 12 + Helpers.EACalcTimeL(mode, register); break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SUBX()
|
|
||||||
{
|
|
||||||
int regRx = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int rm = (this.m_IR >> 3) & 0x1;
|
|
||||||
int regRy = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
if (rm == 0)
|
|
||||||
{
|
|
||||||
this.m_D[regRy] = Sub((sbyte)this.m_D[regRx], (sbyte)this.m_D[regRy], true, true, true);
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteB(this.m_A[regRy], Sub(ReadB(this.m_A[regRx]), ReadB(this.m_A[regRy]), true, true, true));
|
|
||||||
this.m_Cycles += 18;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
if (rm == 0)
|
|
||||||
{
|
|
||||||
this.m_D[regRy] = Sub((short)this.m_D[regRx], (short)this.m_D[regRy], true, true, true);
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteW(this.m_A[regRy], Sub(ReadW(this.m_A[regRx]), ReadW(this.m_A[regRy]), true, true, true));
|
|
||||||
this.m_Cycles += 18;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
if (rm == 0)
|
|
||||||
{
|
|
||||||
this.m_D[regRy] = Sub(this.m_D[regRx], this.m_D[regRy], true, true, true);
|
|
||||||
this.m_Cycles += 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteL(this.m_A[regRy], Sub(ReadB(this.m_A[regRx]), ReadB(this.m_A[regRy]), true, true, true));
|
|
||||||
this.m_Cycles += 30;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,405 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
#region AND Helpers
|
|
||||||
private sbyte And(sbyte a, sbyte b)
|
|
||||||
{
|
|
||||||
sbyte result = (sbyte)(a & b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private short And(short a, short b)
|
|
||||||
{
|
|
||||||
short result = (short)(a & b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int And(int a, int b)
|
|
||||||
{
|
|
||||||
int result = (int)(a & b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endregion AND Helpers
|
|
||||||
|
|
||||||
private void AND_Dest()
|
|
||||||
{
|
|
||||||
int src_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int dest_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int dest_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = And((sbyte)this.m_D[src_register], PeekOperandB(dest_mode, dest_register));
|
|
||||||
SetOperandB(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = And((short)this.m_D[src_register], PeekOperandW(dest_mode, dest_register));
|
|
||||||
SetOperandW(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = And(this.m_D[src_register], PeekOperandL(dest_mode, dest_register));
|
|
||||||
SetOperandL(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AND_Source()
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = And((sbyte)this.m_D[dest_register], FetchOperandB(src_mode, src_register));
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = And((short)this.m_D[dest_register], FetchOperandW(src_mode, src_register));
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = And(this.m_D[dest_register], FetchOperandL(src_mode, src_register));
|
|
||||||
this.m_D[dest_register] = result;
|
|
||||||
this.m_Cycles += 12 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ANDI()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = And((sbyte)FetchW(), PeekOperandB(mode, register));
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = And(FetchW(), PeekOperandW(mode, register));
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = And(FetchL(), PeekOperandL(mode, register));
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 14 : 20 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region EOR Helpers
|
|
||||||
private sbyte Eor(sbyte a, sbyte b)
|
|
||||||
{
|
|
||||||
sbyte result = (sbyte)(a ^ b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private short Eor(short a, short b)
|
|
||||||
{
|
|
||||||
short result = (short)(a ^ b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int Eor(int a, int b)
|
|
||||||
{
|
|
||||||
int result = (int)(a ^ b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endregion EOR Helpers
|
|
||||||
|
|
||||||
private void EOR()
|
|
||||||
{
|
|
||||||
int src_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int dest_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int dest_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Eor((sbyte)this.m_D[src_register], PeekOperandB(dest_mode, dest_register));
|
|
||||||
SetOperandB(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += (dest_mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Eor((short)this.m_D[src_register], PeekOperandW(dest_mode, dest_register));
|
|
||||||
SetOperandW(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += (dest_mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Eor(this.m_D[src_register], PeekOperandL(dest_mode, dest_register));
|
|
||||||
SetOperandL(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += (dest_mode == 0) ? 8 : 12 + Helpers.EACalcTimeL(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EORI()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Eor((sbyte)FetchW(), PeekOperandB(mode, register));
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Eor(FetchW(), PeekOperandW(mode, register));
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Eor(FetchL(), PeekOperandL(mode, register));
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 16 : 20 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region OR Helpers
|
|
||||||
private sbyte Or(sbyte a, sbyte b)
|
|
||||||
{
|
|
||||||
sbyte result = (sbyte)(a | b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private short Or(short a, short b)
|
|
||||||
{
|
|
||||||
short result = (short)(a | b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int Or(int a, int b)
|
|
||||||
{
|
|
||||||
int result = (int)(a | b);
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endregion OR Helpers
|
|
||||||
|
|
||||||
private void OR_Dest()
|
|
||||||
{
|
|
||||||
int src_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int dest_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int dest_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Or((sbyte)this.m_D[src_register], PeekOperandB(dest_mode, dest_register));
|
|
||||||
SetOperandB(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Or((short)this.m_D[src_register], PeekOperandW(dest_mode, dest_register));
|
|
||||||
SetOperandW(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Or(this.m_D[src_register], PeekOperandL(dest_mode, dest_register));
|
|
||||||
SetOperandL(dest_mode, dest_register, result);
|
|
||||||
this.m_Cycles += 12 + Helpers.EACalcTimeL(dest_mode, dest_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OR_Source()
|
|
||||||
{
|
|
||||||
int dest_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int src_mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int src_register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Or((sbyte)this.m_D[dest_register], FetchOperandB(src_mode, src_register));
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Or((short)this.m_D[dest_register], FetchOperandW(src_mode, src_register));
|
|
||||||
Helpers.Inject(ref this.m_D[dest_register], result);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Or(this.m_D[dest_register], FetchOperandL(src_mode, src_register));
|
|
||||||
this.m_D[dest_register] = result;
|
|
||||||
this.m_Cycles += 6 + Helpers.EACalcTimeL(src_mode, src_register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ORI()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
sbyte result = Or((sbyte)FetchW(), PeekOperandB(mode, register));
|
|
||||||
SetOperandB(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
short result = Or(FetchW(), PeekOperandW(mode, register));
|
|
||||||
SetOperandW(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 8 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
int result = Or(FetchL(), PeekOperandL(mode, register));
|
|
||||||
SetOperandL(mode, register, result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 16 : 20 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NOT()
|
|
||||||
{
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
long result = 0;
|
|
||||||
this.V = this.C = false;
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
result = ~PeekOperandB(mode, register);
|
|
||||||
SetOperandB(mode, register, (sbyte)result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
result = ~PeekOperandW(mode, register);
|
|
||||||
SetOperandW(mode, register, (short)result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
result = ~PeekOperandL(mode, register);
|
|
||||||
SetOperandL(mode, register, (int)result);
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 12 + Helpers.EACalcTimeL(mode, register);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.N = result < 0;
|
|
||||||
this.Z = result == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
private void TAS() // Test and set
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
sbyte operand = PeekOperandB(mode, register);
|
|
||||||
|
|
||||||
this.N = (operand < 0);
|
|
||||||
this.Z = (operand == 0);
|
|
||||||
this.V = false;
|
|
||||||
this.C = false;
|
|
||||||
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 14 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
|
|
||||||
// Set the 7th bit
|
|
||||||
byte uOperand = (byte)operand;
|
|
||||||
uOperand |= 0x80;
|
|
||||||
SetOperandB(mode, register, (sbyte)uOperand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,208 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
private void Bcc() // Branch conditionally
|
|
||||||
{
|
|
||||||
if ((sbyte)this.m_IR == 0)
|
|
||||||
{
|
|
||||||
if (TestCondition((this.m_IR >> 8) & 0xF))
|
|
||||||
{
|
|
||||||
this.m_PC += FetchW();
|
|
||||||
this.m_Cycles += 10;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_PC += 2;
|
|
||||||
this.m_Cycles += 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (TestCondition((this.m_IR >> 8) & 0xF))
|
|
||||||
{
|
|
||||||
this.m_PC += (sbyte)this.m_IR;
|
|
||||||
this.m_Cycles += 10;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_Cycles += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DBcc() // Test condition, decrement, branch
|
|
||||||
{
|
|
||||||
if (TestCondition((this.m_IR >> 8) & 0xF))
|
|
||||||
{
|
|
||||||
// Need to move PC on...
|
|
||||||
this.m_PC += 2;
|
|
||||||
this.m_Cycles += 12;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
short counter = (short)this.m_D[this.m_IR & 0x7];
|
|
||||||
Helpers.Inject(ref this.m_D[this.m_IR & 0x7], --counter);
|
|
||||||
|
|
||||||
if (counter == -1)
|
|
||||||
{
|
|
||||||
this.m_PC += 2;
|
|
||||||
this.m_Cycles += 14;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_PC += FetchW();
|
|
||||||
this.m_Cycles += 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Scc() // Set according to condition
|
|
||||||
{
|
|
||||||
int cCode = (this.m_IR >> 8) & 0xF;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
if (TestCondition(cCode))
|
|
||||||
{
|
|
||||||
// Set all the bits
|
|
||||||
SetOperandB(mode, register, -1);
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Clear all the bits
|
|
||||||
SetOperandB(mode, register, 0);
|
|
||||||
this.m_Cycles += (mode == 0) ? 4 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BRA() // Branch Always
|
|
||||||
{
|
|
||||||
this.m_Cycles += 10;
|
|
||||||
|
|
||||||
if ((sbyte)this.m_IR == 0)
|
|
||||||
{
|
|
||||||
this.m_PC += PeekW();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_PC += (sbyte)this.m_IR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BSR() // Branch to subroutine
|
|
||||||
{
|
|
||||||
this.SP -= 4;
|
|
||||||
|
|
||||||
// 16-bit displacement
|
|
||||||
if ((sbyte)this.m_IR == 0)
|
|
||||||
{
|
|
||||||
WriteL(this.SP, this.m_PC + 2);
|
|
||||||
this.m_PC += PeekW();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8-bit displacement
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteL(this.SP, this.m_PC);
|
|
||||||
this.m_PC += (sbyte)this.m_IR;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += 18;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void JMP() // Jump
|
|
||||||
{
|
|
||||||
this.m_PC = FetchAddress((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
|
|
||||||
switch ((this.m_IR >> 3) & 0x7)
|
|
||||||
{
|
|
||||||
case 0x2: this.m_Cycles += 8; break;
|
|
||||||
case 0x5: this.m_Cycles += 10; break;
|
|
||||||
case 0x6: this.m_Cycles += 14; break;
|
|
||||||
case 0x7:
|
|
||||||
switch (this.m_IR & 0x7)
|
|
||||||
{
|
|
||||||
case 0x0: this.m_Cycles += 10; break;
|
|
||||||
case 0x1: this.m_Cycles += 12; break;
|
|
||||||
case 0x2: this.m_Cycles += 10; break;
|
|
||||||
case 0x3: this.m_Cycles += 14; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void JSR() // Jump to subroutine
|
|
||||||
{
|
|
||||||
int address = FetchAddress((this.m_IR >> 3) & 0x7, this.m_IR & 0x7) & 0x00FFFFFF;
|
|
||||||
this.SP -= 4;
|
|
||||||
WriteL(this.SP, this.m_PC);
|
|
||||||
this.m_PC = address;
|
|
||||||
|
|
||||||
switch ((this.m_IR >> 3) & 0x7)
|
|
||||||
{
|
|
||||||
case 0x2: this.m_Cycles += 16; break;
|
|
||||||
case 0x5: this.m_Cycles += 18; break;
|
|
||||||
case 0x6: this.m_Cycles += 22; break;
|
|
||||||
case 0x7:
|
|
||||||
switch (this.m_IR & 0x7)
|
|
||||||
{
|
|
||||||
case 0x0: this.m_Cycles += 18; break;
|
|
||||||
case 0x1: this.m_Cycles += 20; break;
|
|
||||||
case 0x2: this.m_Cycles += 18; break;
|
|
||||||
case 0x3: this.m_Cycles += 22; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NOP() // No operation
|
|
||||||
{
|
|
||||||
// Doesn't do anything, it's there to help flush the integer pipeline
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RTS() // Return from Subroutine
|
|
||||||
{
|
|
||||||
this.m_PC = ReadL(this.SP);
|
|
||||||
this.SP += 4;
|
|
||||||
this.m_Cycles += 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TST() // Test an operand
|
|
||||||
{
|
|
||||||
// Use an integer operand, it gets sign-extended and we can check it afterwards
|
|
||||||
int operand = 0;
|
|
||||||
switch ((this.m_IR >> 6) & 0x3)
|
|
||||||
{
|
|
||||||
case 0: // B
|
|
||||||
{
|
|
||||||
operand = FetchOperandB((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: // W
|
|
||||||
{
|
|
||||||
operand = FetchOperandW((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeBW((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: // L
|
|
||||||
{
|
|
||||||
operand = FetchOperandL((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
this.m_Cycles += 4 + Helpers.EACalcTimeL((this.m_IR >> 3) & 0x7, this.m_IR & 0x7);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.V = this.C = false;
|
|
||||||
this.N = (operand < 0);
|
|
||||||
this.Z = (operand == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,622 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
#region Arithmetic Shift
|
|
||||||
private void ASL()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.C = this.V = false;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sbyte value = (sbyte)this.m_D[register];
|
|
||||||
bool msbit = value < 0;
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = value < 0;
|
|
||||||
value <<= 1;
|
|
||||||
this.V |= ((value < 0) != msbit);
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
short value = (short)this.m_D[register];
|
|
||||||
bool msbit = value < 0;
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = value < 0;
|
|
||||||
value <<= 1;
|
|
||||||
this.V |= ((value < 0) != msbit);
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int value = this.m_D[register];
|
|
||||||
bool msbit = value < 0;
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = value < 0;
|
|
||||||
value <<= 1;
|
|
||||||
this.V |= ((value < 0) != msbit);
|
|
||||||
}
|
|
||||||
this.m_D[register] = value;
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ASR()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.C = this.V = false;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sbyte value = (sbyte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
short value = (short)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int value = this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
this.m_D[register] = value;
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ASL_ASR_Memory()
|
|
||||||
{
|
|
||||||
int direction = (this.m_IR >> 8) & 0x1; // 0 = Right, 1 = Left
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
short value = PeekOperandW(mode, register);
|
|
||||||
if (direction == 0)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
this.V = false; // For right shift, MSB can't change
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool msbit = (value < 0);
|
|
||||||
this.C = this.X = value < 0;
|
|
||||||
value <<= 1;
|
|
||||||
this.V |= ((value < 0) != msbit);
|
|
||||||
}
|
|
||||||
this.N = value < 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
SetOperandW(mode, register, value);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
#endregion Arithmetic Shift
|
|
||||||
|
|
||||||
#region Logical Shift
|
|
||||||
private void LSL()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.C = this.V = false;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
byte value = (byte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 0x80) > 0;
|
|
||||||
value <<= 1;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x80) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ushort value = (ushort)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 0x8000) > 0;
|
|
||||||
value <<= 1;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
uint value = (uint)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 0x80000000) > 0;
|
|
||||||
value <<= 1;
|
|
||||||
}
|
|
||||||
this.m_D[register] = (int)value;
|
|
||||||
this.N = (value & 0x80000000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LSR()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.C = this.V = false;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
byte value = (byte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x80) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ushort value = (ushort)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
uint value = (uint)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
this.m_D[register] = (int)value;
|
|
||||||
this.N = (value & 0x80000000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LSL_LSR_Memory()
|
|
||||||
{
|
|
||||||
int direction = (this.m_IR >> 8) & 0x1; // 0 = Right, 1 = Left
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
ushort value = (ushort)PeekOperandW(mode, register);
|
|
||||||
if (direction == 0)
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 1) > 0;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.C = this.X = (value & 0x8000) > 0;
|
|
||||||
value <<= 1;
|
|
||||||
}
|
|
||||||
this.V = false;
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
SetOperandW(mode, register, (short)value);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
#endregion Logical Shift
|
|
||||||
|
|
||||||
#region Rotate (without extend)
|
|
||||||
private void ROL()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.C = this.V = false;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
byte value = (byte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 0x80) > 0;
|
|
||||||
value = (byte)((value >> 7) | (value << 1));
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x80) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ushort value = (ushort)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 0x8000) > 0;
|
|
||||||
value = (ushort)((value >> 15) | (value << 1));
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
uint value = (uint)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 0x80000000) > 0;
|
|
||||||
value = (uint)((value >> 31) | (value << 1));
|
|
||||||
}
|
|
||||||
this.m_D[register] = (int)value;
|
|
||||||
this.N = (value & 0x80000000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ROR()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.C = this.V = false;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
byte value = (byte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (byte)((value << 7) | (value >> 1));
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x80) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ushort value = (ushort)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (ushort)((value << 15) | (value >> 1));
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
uint value = (uint)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (uint)((value << 31) | (value >> 1));
|
|
||||||
}
|
|
||||||
this.m_D[register] = (int)value;
|
|
||||||
this.N = (value & 0x80000000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ROL_ROR_Memory()
|
|
||||||
{
|
|
||||||
int direction = (this.m_IR >> 8) & 0x1; // 0 = Right, 1 = Left
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
ushort value = (ushort)PeekOperandW(mode, register);
|
|
||||||
if (direction == 0)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (ushort)((value >> 1) | (value << 15));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.C = (value & 0x8000) > 0;
|
|
||||||
value = (ushort)((value >> 15) | (value << 1));
|
|
||||||
}
|
|
||||||
this.V = false;
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
SetOperandW(mode, register, (short)value);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
#endregion Rotate (without extend)
|
|
||||||
|
|
||||||
#region Rotate (with extend)
|
|
||||||
private void ROXL()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.V = false;
|
|
||||||
this.C = this.X;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
byte value = (byte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 0x80) > 0;
|
|
||||||
value = (byte)((value << 1) | ((this.X) ? 1: 0));
|
|
||||||
this.X = this.C;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x80) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ushort value = (ushort)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 0x8000) > 0;
|
|
||||||
value = (ushort)((value << 1) | ((this.X) ? 1 : 0));
|
|
||||||
this.X = this.C;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
uint value = (uint)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 0x80000000) > 0;
|
|
||||||
value = (uint)((value << 1) | ((this.X) ? (uint)1 : (uint)0));
|
|
||||||
this.X = this.C;
|
|
||||||
}
|
|
||||||
this.m_D[register] = (int)value;
|
|
||||||
this.N = (value & 0x80000000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ROXR()
|
|
||||||
{
|
|
||||||
int count_register = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 6) & 0x3;
|
|
||||||
int ir = (this.m_IR >> 5) & 0x1;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
int shift_count = (ir == 0) ?
|
|
||||||
((count_register == 0) ? 8 : count_register) :
|
|
||||||
(this.m_D[count_register] % 64);
|
|
||||||
|
|
||||||
this.V = false;
|
|
||||||
this.C = this.X;
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
byte value = (byte)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (byte)(((this.X) ? 0x80 : 0) | (value >> 1));
|
|
||||||
this.X = this.C;
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x80) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ushort value = (ushort)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (ushort)(((this.X) ? 0x8000 : 0) | (value >> 1));
|
|
||||||
}
|
|
||||||
Helpers.Inject(ref this.m_D[register], value);
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 6 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
uint value = (uint)this.m_D[register];
|
|
||||||
for (int i = 0; i < shift_count; i++)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (uint)(((this.X) ? 0x80000000 : 0) | (value >> 1));
|
|
||||||
}
|
|
||||||
this.m_D[register] = (int)value;
|
|
||||||
this.N = (value & 0x80000000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
this.m_Cycles += 8 + 2 * shift_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ROXL_ROXR_Memory()
|
|
||||||
{
|
|
||||||
int direction = (this.m_IR >> 8) & 0x1; // 0 = Right, 1 = Left
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
ushort value = (ushort)PeekOperandW(mode, register);
|
|
||||||
if (direction == 0)
|
|
||||||
{
|
|
||||||
this.C = (value & 1) > 0;
|
|
||||||
value = (ushort)(((this.X) ? 0x8000 : 0) | (value >> 1));
|
|
||||||
this.X = this.C;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.C = (value & 0x8000) > 0;
|
|
||||||
value = (ushort)((value << 1) | ((this.X) ? 1 : 0));
|
|
||||||
this.X = this.C;
|
|
||||||
}
|
|
||||||
this.V = false;
|
|
||||||
this.N = (value & 0x8000) > 0;
|
|
||||||
this.Z = value == 0;
|
|
||||||
SetOperandW(mode, register, (short)value);
|
|
||||||
this.m_Cycles += 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
#endregion Rotate (with extend)
|
|
||||||
|
|
||||||
private void SWAP() // Swap halves of a register
|
|
||||||
{
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
this.m_D[register] = (int)(((uint)this.m_D[register] << 16) |
|
|
||||||
((uint)this.m_D[register] >> 16));
|
|
||||||
|
|
||||||
this.N = (this.m_D[register] < 0);
|
|
||||||
this.Z = (this.m_D[register] == 0);
|
|
||||||
this.V = this.C = false;
|
|
||||||
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,271 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MC68000
|
|
||||||
{
|
|
||||||
public partial class MC68K
|
|
||||||
{
|
|
||||||
private void ANDI_to_CCR()
|
|
||||||
{
|
|
||||||
Helpers.Inject(ref this.m_SR, (byte)(this.m_SR & FetchW()));
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ANDI_to_SR()
|
|
||||||
{
|
|
||||||
if (this.S)
|
|
||||||
{
|
|
||||||
this.m_SR &= FetchW();
|
|
||||||
|
|
||||||
// Might not be in supervisor mode any more...
|
|
||||||
if (!this.S)
|
|
||||||
{
|
|
||||||
this.m_Ssp = this.SP;
|
|
||||||
this.SP = this.m_Usp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO - cycle counter
|
|
||||||
Trap(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CHK()
|
|
||||||
{
|
|
||||||
int registerToCheck = (this.m_IR >> 9) & 0x7;
|
|
||||||
int size = (this.m_IR >> 7) & 0x3;
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
// Only word size is legal on the 68000
|
|
||||||
|
|
||||||
if ((short)this.m_D[registerToCheck] < 0)
|
|
||||||
{
|
|
||||||
this.N = true;
|
|
||||||
Trap(6);
|
|
||||||
}
|
|
||||||
else if ((short)this.m_D[registerToCheck] > FetchOperandW(mode, size))
|
|
||||||
{
|
|
||||||
this.N = false;
|
|
||||||
Trap(6);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_Cycles += 10 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EORI_to_CCR()
|
|
||||||
{
|
|
||||||
Helpers.Inject(ref this.m_SR, (byte)(this.m_SR ^ FetchW()));
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EORI_to_SR()
|
|
||||||
{
|
|
||||||
if (this.S)
|
|
||||||
{
|
|
||||||
this.m_SR ^= FetchW();
|
|
||||||
|
|
||||||
// Might not be in supervisor mode any more...
|
|
||||||
if (!this.S)
|
|
||||||
{
|
|
||||||
this.m_Ssp = this.SP;
|
|
||||||
this.SP = this.m_Usp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO - cycle counter
|
|
||||||
Trap(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ILLEGAL()
|
|
||||||
{
|
|
||||||
Trap(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVE_from_SR()
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
SetOperandW(mode, register, (short)this.m_SR);
|
|
||||||
this.m_Cycles += (mode == 0) ? 6 : 8 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVE_to_CCR()
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
this.m_SR &= 0xFF00;
|
|
||||||
this.m_SR |= (ushort)(FetchOperandW(mode, register) & 0x00FF);
|
|
||||||
this.m_Cycles += (mode == 0) ? 12 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVE_to_SR() // Move to the Status Register
|
|
||||||
{
|
|
||||||
int mode = (this.m_IR >> 3) & 0x7;
|
|
||||||
int register = this.m_IR & 0x7;
|
|
||||||
|
|
||||||
if (this.S)
|
|
||||||
{
|
|
||||||
this.m_SR = (ushort)FetchOperandW(mode, register);
|
|
||||||
this.m_Cycles += (mode == 0) ? 12 : 12 + Helpers.EACalcTimeBW(mode, register);
|
|
||||||
|
|
||||||
// Might not be in supervisor mode now...
|
|
||||||
if (!this.S)
|
|
||||||
{
|
|
||||||
this.m_Ssp = this.SP;
|
|
||||||
this.SP = this.m_Usp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Trap(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MOVE_USP() // Move User Stack Pointer
|
|
||||||
{
|
|
||||||
if (this.S)
|
|
||||||
{
|
|
||||||
if (((this.m_IR >> 3) & 0x1) == 0)
|
|
||||||
{
|
|
||||||
this.m_Usp = this.m_A[this.m_IR & 0x7];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.m_A[this.m_IR & 0x7] = this.m_Usp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO Cycles
|
|
||||||
Trap(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ORI_to_CCR()
|
|
||||||
{
|
|
||||||
Helpers.Inject(ref this.m_SR, (byte)(this.m_SR | (ushort)FetchW()));
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ORI_to_SR()
|
|
||||||
{
|
|
||||||
if (this.S)
|
|
||||||
{
|
|
||||||
this.m_SR |= (ushort)FetchW();
|
|
||||||
|
|
||||||
// Might not be in supervisor mode any more...
|
|
||||||
if (!this.S)
|
|
||||||
{
|
|
||||||
this.m_Ssp = this.SP;
|
|
||||||
this.SP = this.m_Usp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO - TRAP, cycle counter
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RESET()
|
|
||||||
{
|
|
||||||
this.m_Cycles += 132;
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RTE()
|
|
||||||
{
|
|
||||||
if (this.S)
|
|
||||||
{
|
|
||||||
this.m_SR = (ushort)ReadW(this.SP);
|
|
||||||
this.SP += 2;
|
|
||||||
this.m_PC = ReadL(this.SP);
|
|
||||||
this.SP += 4;
|
|
||||||
|
|
||||||
// Might not be in supervisor mode any more...
|
|
||||||
if (!this.S)
|
|
||||||
{
|
|
||||||
this.m_Ssp = this.SP;
|
|
||||||
this.SP = this.m_Usp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Privilege exception
|
|
||||||
Trap(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RTR()
|
|
||||||
{
|
|
||||||
// Seems a bit like RTE, but only affects condition codes
|
|
||||||
this.m_SR = (ushort)((0x00FF & ReadW(this.m_Ssp)) | (0xFF00 & this.m_SR));
|
|
||||||
this.SP += 2;
|
|
||||||
this.m_PC = ReadL(this.SP);
|
|
||||||
this.SP += 4;
|
|
||||||
this.m_Cycles += 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void STOP()
|
|
||||||
{
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Trap(int trapVector)
|
|
||||||
{
|
|
||||||
// Make sure we're in supervisor mode
|
|
||||||
if (!this.S)
|
|
||||||
{
|
|
||||||
this.m_Usp = this.SP;
|
|
||||||
this.SP = this.m_Ssp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add stack frame
|
|
||||||
this.SP -= 4;
|
|
||||||
WriteL(this.SP, this.m_PC);
|
|
||||||
this.SP -= 2;
|
|
||||||
WriteW(this.SP, (short)this.m_SR);
|
|
||||||
|
|
||||||
// Enter supervisor mode
|
|
||||||
this.S = true;
|
|
||||||
|
|
||||||
// Get vector address from ROM header
|
|
||||||
this.m_PC = ReadL(trapVector * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TRAP()
|
|
||||||
{
|
|
||||||
int trapVector = (this.m_IR & 0x000F);
|
|
||||||
Trap(trapVector + 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TRAPV()
|
|
||||||
{
|
|
||||||
this.m_Cycles += 4;
|
|
||||||
if (this.V)
|
|
||||||
{
|
|
||||||
Trap(7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,7 @@
|
||||||
- Ys IV
|
- Ys IV
|
||||||
|
|
||||||
- Graphics corruption:
|
- Graphics corruption:
|
||||||
- Buster Bros, check seagull during opening
|
- Camp California, check seagull during opening
|
||||||
- In part of Dungeon Explorer II intro
|
- In part of Dungeon Explorer II intro
|
||||||
- Popful Mail... some corruption on Turbo Engine too.... and pcejin?
|
- Popful Mail... some corruption on Turbo Engine too.... and pcejin?
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ Arcade Card games:
|
||||||
|
|
||||||
- Record of Lodoss War wont start game from title screen
|
- Record of Lodoss War wont start game from title screen
|
||||||
- Valis: Screen is black during entire intro section
|
- Valis: Screen is black during entire intro section
|
||||||
- Valis III: playable,gfx issue on title screen... possible due to not updating VDC regs on LSB? really should just fix that once at for all...
|
|
||||||
|
|
||||||
======= TurboGrafx compatibility issues =======
|
======= TurboGrafx compatibility issues =======
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,16 @@ using System.IO;
|
||||||
using BizHawk.Emulation.CPUs.M68K;
|
using BizHawk.Emulation.CPUs.M68K;
|
||||||
using BizHawk.Emulation.CPUs.Z80;
|
using BizHawk.Emulation.CPUs.Z80;
|
||||||
using BizHawk.Emulation.Sound;
|
using BizHawk.Emulation.Sound;
|
||||||
using MC68000;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Sega
|
namespace BizHawk.Emulation.Consoles.Sega
|
||||||
{
|
{
|
||||||
public sealed partial class Genesis : IEmulator, IMemoryController
|
public sealed partial class Genesis : IEmulator
|
||||||
{
|
{
|
||||||
// ROM
|
// ROM
|
||||||
public byte[] RomData;
|
public byte[] RomData;
|
||||||
|
|
||||||
// Machine stuff
|
// Machine stuff
|
||||||
public MC68K MainCPU; // TODO un-static
|
public M68000 MainCPU;
|
||||||
public M68000 _MainCPU;
|
|
||||||
public Z80A SoundCPU;
|
public Z80A SoundCPU;
|
||||||
public GenVDP VDP;
|
public GenVDP VDP;
|
||||||
public SN76489 PSG;
|
public SN76489 PSG;
|
||||||
|
@ -55,12 +53,10 @@ namespace BizHawk.Emulation.Consoles.Sega
|
||||||
// 320 are active display, the remaining 160 are horizontal blanking.
|
// 320 are active display, the remaining 160 are horizontal blanking.
|
||||||
// A total of 3420 mclks per line, but 2560 mclks are active display and 860 mclks are blanking.
|
// A total of 3420 mclks per line, but 2560 mclks are active display and 860 mclks are blanking.
|
||||||
|
|
||||||
public Genesis(bool sega360)
|
public Genesis()
|
||||||
{
|
{
|
||||||
CoreOutputComm = new CoreOutputComm();
|
CoreOutputComm = new CoreOutputComm();
|
||||||
|
MainCPU = new M68000();
|
||||||
if (sega360) MainCPU = new MC68K(this);
|
|
||||||
_MainCPU = new M68000();
|
|
||||||
SoundCPU = new Z80A();
|
SoundCPU = new Z80A();
|
||||||
YM2612 = new YM2612();
|
YM2612 = new YM2612();
|
||||||
PSG = new SN76489();
|
PSG = new SN76489();
|
||||||
|
@ -68,12 +64,12 @@ namespace BizHawk.Emulation.Consoles.Sega
|
||||||
VDP.DmaReadFrom68000 = ReadW;
|
VDP.DmaReadFrom68000 = ReadW;
|
||||||
SoundMixer = new SoundMixer(YM2612, PSG);
|
SoundMixer = new SoundMixer(YM2612, PSG);
|
||||||
|
|
||||||
_MainCPU.ReadByte = ReadB;
|
MainCPU.ReadByte = ReadB;
|
||||||
_MainCPU.ReadWord = ReadW;
|
MainCPU.ReadWord = ReadW;
|
||||||
_MainCPU.ReadLong = ReadL;
|
MainCPU.ReadLong = ReadL;
|
||||||
_MainCPU.WriteByte = WriteB;
|
MainCPU.WriteByte = WriteB;
|
||||||
_MainCPU.WriteWord = WriteW;
|
MainCPU.WriteWord = WriteW;
|
||||||
_MainCPU.WriteLong = WriteL;
|
MainCPU.WriteLong = WriteL;
|
||||||
|
|
||||||
SoundCPU.ReadMemory = ReadMemoryZ80;
|
SoundCPU.ReadMemory = ReadMemoryZ80;
|
||||||
SoundCPU.WriteMemory = WriteMemoryZ80;
|
SoundCPU.WriteMemory = WriteMemoryZ80;
|
||||||
|
@ -95,16 +91,6 @@ namespace BizHawk.Emulation.Consoles.Sega
|
||||||
_MainCPU.Reset();
|
_MainCPU.Reset();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
public void StepMine()
|
|
||||||
{
|
|
||||||
_MainCPU.Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StepHis()
|
|
||||||
{
|
|
||||||
MainCPU.Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FrameAdvance(bool render)
|
public void FrameAdvance(bool render)
|
||||||
{
|
{
|
||||||
Frame++;
|
Frame++;
|
||||||
|
@ -116,7 +102,7 @@ namespace BizHawk.Emulation.Consoles.Sega
|
||||||
if (VDP.ScanLine < 224)
|
if (VDP.ScanLine < 224)
|
||||||
VDP.RenderLine();
|
VDP.RenderLine();
|
||||||
|
|
||||||
_MainCPU.ExecuteCycles(488);
|
MainCPU.ExecuteCycles(488);
|
||||||
if (Z80Runnable)
|
if (Z80Runnable)
|
||||||
{
|
{
|
||||||
//Console.WriteLine("running z80");
|
//Console.WriteLine("running z80");
|
||||||
|
@ -127,8 +113,8 @@ namespace BizHawk.Emulation.Consoles.Sega
|
||||||
if (VDP.ScanLine == 224)
|
if (VDP.ScanLine == 224)
|
||||||
{
|
{
|
||||||
// End-frame stuff
|
// End-frame stuff
|
||||||
if (VDP.VInterruptEnabled)
|
/*if (VDP.VInterruptEnabled)
|
||||||
MainCPU.Interrupt(6);
|
MainCPU.Interrupt(6);*/
|
||||||
|
|
||||||
if (Z80Runnable)
|
if (Z80Runnable)
|
||||||
SoundCPU.Interrupt = true;
|
SoundCPU.Interrupt = true;
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ namespace BizHawk.MultiClient
|
||||||
nextEmulator = new PCEngine(game, rom.RomData);
|
nextEmulator = new PCEngine(game, rom.RomData);
|
||||||
break;
|
break;
|
||||||
case "GEN":
|
case "GEN":
|
||||||
nextEmulator = new Genesis(true); //TODO
|
nextEmulator = new Genesis(); //TODO
|
||||||
break;
|
break;
|
||||||
case "TI83":
|
case "TI83":
|
||||||
nextEmulator = new TI83(game, rom.RomData);
|
nextEmulator = new TI83(game, rom.RomData);
|
||||||
|
|
Loading…
Reference in New Issue