BizHawk/BizHawk.Emulation/CPUs/68000/Instructions/ProgramFlow.cs

388 lines
12 KiB
C#
Raw Normal View History

2011-01-11 02:55:51 +00:00

using System;
namespace BizHawk.Emulation.CPUs.M68K
{
public partial class M68000
{
private bool TestCondition(int condition)
{
switch (condition)
{
case 0x00: return true; // True
case 0x01: return false; // False
case 0x02: return !C && !Z; // High (Unsigned)
case 0x03: return C || Z; // Less or Same (Unsigned)
case 0x04: return !C; // Carry Clear (High or Same)
case 0x05: return C; // Carry Set (Lower)
case 0x06: return !Z; // Not Equal
case 0x07: return Z; // Equal
case 0x08: return !V; // Overflow Clear
case 0x09: return V; // Overflow Set
case 0x0A: return !N; // Plus (Positive)
case 0x0B: return N; // Minus (Negative)
case 0x0C: return N && V || !N && !V; // Greater or Equal
case 0x0D: return N && !V || !N && V; // Less Than
case 0x0E: return N && V && !Z || !N && !V && !Z; // Greater Than
case 0x0F: return Z || N && !V || !N && V; // Less or Equal
default:
throw new Exception("Invalid condition "+condition);
}
}
private string DisassembleCondition(int condition)
{
switch (condition)
{
case 0x00: return "t"; // True
case 0x01: return "f"; // False
case 0x02: return "hi"; // High (Unsigned)
case 0x03: return "ls"; // Less or Same (Unsigned)
case 0x04: return "cc"; // Carry Clear (High or Same)
case 0x05: return "cs"; // Carry Set (Lower)
case 0x06: return "ne"; // Not Equal
case 0x07: return "eq"; // Equal
case 0x08: return "vc"; // Overflow Clear
case 0x09: return "vs"; // Overflow Set
case 0x0A: return "pl"; // Plus (Positive)
case 0x0B: return "mi"; // Minus (Negative)
case 0x0C: return "ge"; // Greater or Equal
case 0x0D: return "lt"; // Less Than
case 0x0E: return "gt"; // Greater Than
case 0x0F: return "le"; // Less or Equal
default: return "??"; // Invalid condition
}
}
private void Bcc() // Branch on condition
{
sbyte displacement8 = (sbyte) op;
int cond = (op >> 8) & 0x0F;
if (TestCondition(cond) == true)
{
if (displacement8 != 0)
{
// use opcode-embedded displacement
PC += displacement8;
PendingCycles -= 10;
} else {
// use extension word displacement
PC += ReadWord(PC);
PendingCycles -= 10;
}
} else { // false
if (displacement8 != 0)
PendingCycles -= 8;
else {
PC += 2;
PendingCycles -= 12;
}
}
}
private void Bcc_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
sbyte displacement8 = (sbyte)op;
int cond = (op >> 8) & 0x0F;
info.Mnemonic = "b" + DisassembleCondition(cond);
if (displacement8 != 0)
{
info.Args = string.Format("${0:X}", pc + displacement8);
} else {
info.Args = string.Format("${0:X}", pc + ReadWord(pc));
pc += 2;
}
info.Length = pc - info.PC;
}
private void BRA()
{
sbyte displacement8 = (sbyte)op;
if (displacement8 != 0)
PC += displacement8;
else
PC += ReadWord(PC);
PendingCycles -= 10;
}
private void BRA_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
info.Mnemonic = "bra";
sbyte displacement8 = (sbyte)op;
if (displacement8 != 0)
info.Args = String.Format("${0:X}", pc + displacement8);
else
{
info.Args = String.Format("${0:X}", pc + ReadWord(pc));
pc += 2;
}
info.Length = pc - info.PC;
}
private void BSR()
{
sbyte displacement8 = (sbyte)op;
A[7].s32 -= 4;
if (displacement8 != 0)
{
// use embedded displacement
WriteLong(A[7].s32, PC);
PC += displacement8;
} else {
// use extension word displacement
WriteLong(A[7].s32, PC + 2);
PC += ReadWord(PC);
}
PendingCycles -= 18;
}
private void BSR_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
info.Mnemonic = "bsr";
sbyte displacement8 = (sbyte)op;
if (displacement8 != 0)
info.Args = String.Format("${0:X}", pc + displacement8);
else {
info.Args = String.Format("${0:X}", pc + ReadWord(pc));
pc += 2;
}
info.Length = pc - info.PC;
}
private void DBcc()
{
if (TestCondition((op >> 8) & 0x0F) == true)
{
// break out of loop
PC += 2;
PendingCycles -= 12;
} else {
int reg = op & 7;
D[reg].u16--;
if (D[reg].u16 == 0xFFFF)
{
PC += 2;
PendingCycles -= 14;
} else {
PC += ReadWord(PC);
TotalExecutedCycles -= 10;
}
}
}
private void DBcc_Disasm(DisassemblyInfo info)
{
int cond = (op >> 8) & 0x0F;
if (cond == 1)
info.Mnemonic = "dbra";
else
info.Mnemonic = "db" + DisassembleCondition(cond);
int pc = info.PC + 2;
info.Args = String.Format("D{0}, ${1:X}", op & 7, pc + ReadWord(pc));
info.Length = 4;
}
private void RTS()
{
PC = ReadLong(A[7].s32);
A[7].s32 += 4;
PendingCycles -= 16;
}
private void RTS_Disasm(DisassemblyInfo info)
{
info.Mnemonic = "rts";
info.Args = "";
}
private void TST()
{
int size = (op >> 6) & 3;
int mode = (op >> 3) & 7;
int reg = (op >> 0) & 7;
int value;
switch (size)
{
case 0: value = ReadValueB(mode, reg); PendingCycles -= 4 + EACyclesBW[mode, reg]; break;
case 1: value = ReadValueW(mode, reg); PendingCycles -= 4 + EACyclesBW[mode, reg]; break;
default: value = ReadValueL(mode, reg); PendingCycles -= 4 + EACyclesL[mode, reg]; break;
}
V = false;
C = false;
N = (value < 0);
Z = (value == 0);
}
private void TST_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
int size = (op >> 6) & 3;
int mode = (op >> 3) & 7;
int reg = (op >> 0) & 7;
switch (size)
{
case 0: info.Mnemonic = "tst.b"; info.Args = DisassembleValue(mode, reg, 1, ref pc); break;
case 1: info.Mnemonic = "tst.w"; info.Args = DisassembleValue(mode, reg, 2, ref pc); break;
case 2: info.Mnemonic = "tst.l"; info.Args = DisassembleValue(mode, reg, 4, ref pc); break;
}
info.Length = pc - info.PC;
}
private void BTSTi()
{
int bit = ReadWord(PC);
PC += 2;
int mode = (op >> 3) & 7;
int reg = op & 7;
if (mode == 0)
{
bit &= 31;
int mask = 1 << bit;
Z = (D[reg].s32 & mask) == 0;
PendingCycles -= 10;
} else {
bit &= 7;
int mask = 1 << bit;
Z = (ReadValueB(mode, reg) & mask) == 0;
PendingCycles -= 8 + EACyclesBW[mode, reg];
}
}
private void BTSTi_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
int bit = ReadWord(pc); pc += 2;
int mode = (op >> 3) & 7;
int reg = op & 7;
info.Mnemonic = "btst";
info.Args = String.Format("${0:X}, {1}", bit, DisassembleValue(mode, reg, 1, ref pc));
info.Length = pc - info.PC;
}
private void BTSTr()
{
throw new NotImplementedException();
}
private void BTSTr_Disasm(DisassemblyInfo info)
{
throw new NotImplementedException();
}
private void JMP()
{
int mode = (op >> 3) & 7;
int reg = (op >> 0) & 7;
PC = ReadAddress(mode, reg);
switch (mode)
{
case 2: PendingCycles -= 8; break;
case 5: PendingCycles -= 10; break;
case 6: PendingCycles -= 14; break;
case 7:
switch (reg)
{
case 0: PendingCycles -= 10; break;
case 1: PendingCycles -= 12; break;
case 2: PendingCycles -= 10; break;
case 3: PendingCycles -= 14; break;
}
break;
}
}
private void JMP_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
int mode = (op >> 3) & 7;
int reg = (op >> 0) & 7;
info.Mnemonic = "jmp";
info.Args = DisassembleValue(mode, reg, 1, ref pc);
info.Length = pc - info.PC;
}
private void JSR()
{
int mode = (op >> 3) & 7;
int reg = (op >> 0) & 7;
int addr = ReadAddress(mode, reg);
A[7].s32 -= 4;
WriteLong(A[7].s32, PC);
PC = addr;
switch (mode)
{
case 2: PendingCycles -= 16; break;
case 5: PendingCycles -= 18; break;
case 6: PendingCycles -= 22; break;
case 7:
switch (reg)
{
case 0: PendingCycles -= 18; break;
case 1: PendingCycles -= 20; break;
case 2: PendingCycles -= 18; break;
case 3: PendingCycles -= 22; break;
}
break;
}
}
private void JSR_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
int mode = (op >> 3) & 7;
int reg = (op >> 0) & 7;
info.Mnemonic = "jsr";
info.Args = DisassembleAddress(mode, reg, ref pc);
info.Length = pc - info.PC;
}
private void LINK()
{
int reg = op & 7;
A[7].s32 -= 4;
short offset = ReadWord(PC); PC += 2;
WriteLong(A[7].s32, A[reg].s32);
A[reg].s32 = A[7].s32 + offset;
PendingCycles -= 16;
}
private void LINK_Disasm(DisassemblyInfo info)
{
int pc = info.PC + 2;
int reg = op & 7;
info.Mnemonic = "link";
info.Args = "A"+reg+", "+DisassembleImmediate(2, ref pc); // TODO need a DisassembleSigned or something
info.Length = pc - info.PC;
}
private void NOP()
{
PendingCycles -= 4;
}
private void NOP_Disasm(DisassemblyInfo info)
{
info.Mnemonic = "nop";
}
}
}