397 lines
9.5 KiB
C#
397 lines
9.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|