[ARM] add handful of floating point instructions and most importantly: NOP!

This commit is contained in:
zeromus 2011-04-04 05:13:45 +00:00
parent 510e52271b
commit e78708213c
6 changed files with 385 additions and 26 deletions

View File

@ -163,10 +163,10 @@ namespace BizHawk.Emulation.CPUs.ARM
}
else opcode = opcode.Replace(crepl, "");
if(opcode.Contains("{.size}"))
{
opcode = opcode.Replace("<{.size}>","." + args[argindex++].ToString());
}
if(opcode.Contains("{.fpsize}"))
opcode = opcode.Replace("<{.fpsize}>",".F" + args[argindex++].ToString());
if (opcode.Contains(".fpsize"))
opcode = opcode.Replace("<.fpsize>", ".F" + args[argindex++].ToString());
//---------
string cpcomment = null;
@ -215,6 +215,26 @@ namespace BizHawk.Emulation.CPUs.ARM
break;
}
case "sdd":
case "sdn":
case "sdm":
if ((bool)args[argindex++])
item = "s" + args[argindex++].ToString();
else
item = "d" + args[argindex++].ToString();
break;
case "{sdd~sdn, }":
{
bool s = (bool)args[argindex++];
uint rd = (uint)args[argindex++];
uint rx = (uint)args[argindex++];
if (disopt.showExplicitAccumulateRegisters || rd != rx)
item = string.Format("{0}{1}, ", s ? "s" : "d", rd);
else item = "";
break;
}
case "fpscr": item = nstyle ? "fpscr" : "FPSCR"; break;
case "const": item = string.Format("0x{0:x}", args[argindex++]); break;
@ -228,7 +248,7 @@ namespace BizHawk.Emulation.CPUs.ARM
else item = string.Format(",#0x{0:x}", temp);
break;
}
case "{,+/-#imm}":
case "{, #+/-imm}":
{
uint temp = (uint)args[argindex + 1];
if (temp == 0 && disopt.hideZeroOffset) item = "";

View File

@ -112,7 +112,7 @@ namespace BizHawk.Emulation.CPUs.ARM
opcode += "<c>";
//we may want conditional logic here to control whether various registers are displayed (we used to have it, but i changed my mind)
if (offset)
return DISNEW(opcode, rt + ", [<Rn!><{,+/-#imm}>]", t, n, add, imm32);
return DISNEW(opcode, rt + ", [<Rn!><{, #+/-imm}>]", t, n, add, imm32);
else if (preindexed)
return DISNEW(opcode, rt + ", [<Rn!>, <+/-><imm>]!", t, n, add, imm32);
else if (postindex)

View File

@ -55,7 +55,7 @@ namespace BizHawk.Emulation.CPUs.ARM
.r("A==0 && op1 == #0x010", () => Execute_Unhandled("STRT on page A8-416"))
.r("A==1 && op1 == #0x010 && B==0", () => Execute_Unhandled("STRT on page A8-416"))
.r("A==0 && op1 == #xx0x1 && op1 != #0x011 && Rn != #1111", () => Execute_LDR_immediate_arm_A1())
.r("A==0 && op1 == #xx0x1 && op1 != #0x011 && Rn == #1111", () => ExecuteArm_LDR_literal_A1())
.r("A==0 && op1 == #xx0x1 && op1 != #0x011 && Rn == #1111", () => Execute_LDR_literal_A1())
.r("A==1 && op1 == #xx0x1 && A != #0x011 && B==0", () => Execute_Unhandled("LDR (register) on page A8-124"))
.r("A==0 && op1 == #0x011", () => Execute_Unhandled("LDRT on page A8-176"))
.r("A==1 && op1 == #0x011 && B==0", () => Execute_Unhandled("LDRT on page A8-176"))
@ -141,7 +141,7 @@ namespace BizHawk.Emulation.CPUs.ARM
return ExecuteCore_PUSH(Encoding.A2, registers, UnalignedAllowed);
}
uint ExecuteArm_LDR_literal_A1()
uint Execute_LDR_literal_A1()
{
//A8.6.59
//A8-122
@ -182,7 +182,7 @@ namespace BizHawk.Emulation.CPUs.ARM
return ExecuteArm_DataProcessing_Immediate();
if (op1 == _.b10000) return Execute_Unhandled("16-bit immediate load (MOV (immediate on page A8-193) //v6T2");
if (op1 == _.b10100) return Execute_Unhandled("high halfword 16-bit immediate load (MOVT on page A8-200) //v6T2");
if (CHK(op1, _.b11011, _.b10010)) return Execute_Unhandled("MSR (immediate), and hints on page A5-17");
if (CHK(op1, _.b11011, _.b10010)) return ExecuteArm_MSR_immediate_and_hints();
throw new InvalidOperationException("unexpected decoder fail");
default:
@ -190,6 +190,48 @@ namespace BizHawk.Emulation.CPUs.ARM
}
}
uint ExecuteArm_MSR_immediate_and_hints()
{
Bit op = _.BIT22(instruction);
uint op1 = (instruction >> 16) & 0xF;
uint op2 = instruction & 0xFF;
if (op == 0)
{
switch(op1)
{
case _.b0000:
switch (op2)
{
case 0: return Execute_NOP_A1();
case 1: return Execute_Unhandled("yield");
case 2: return Execute_Unhandled("wfe");
case 3: return Execute_Unhandled("wfi");
case 4: return Execute_Unhandled("sev");
default: return Execute_Unhandled("DBG");
}
case _.b0100:
case _.b1000: case _.b1100:
return Execute_Unhandled("MSR immediate");
case _.b0001: case _.b0101:
case _.b1001: case _.b1101:
return Execute_Unhandled("MSR immediate");
case _.b0010: case _.b0011:
case _.b0110: case _.b0111:
case _.b1010: case _.b1011:
case _.b1110: case _.b1111:
return Execute_Unhandled("MSR immediate");
default: throw new InvalidOperationException("decode fail");
}
}
else return Execute_Unhandled("MSR immediate");
}
uint Execute_NOP_A1()
{
//A8.6.110
return ExecuteCore_NOP(Encoding.A1);
}
uint ExecuteArm_SynchronizationPrimitives()
{
uint op = (instruction >> 20) & 0xF;
@ -562,7 +604,7 @@ namespace BizHawk.Emulation.CPUs.ARM
case _.b001:
switch (op)
{
case _.b01: return ExecuteArm_BX_A1();
case _.b01: return Execute_BX_A1();
case _.b11: return Execute_Unhandled("ExecuteArm_CLZ");
default:
return Execute_Undefined();
@ -588,16 +630,11 @@ namespace BizHawk.Emulation.CPUs.ARM
} //switch(op2)
}
uint ExecuteArm_BX_A1()
uint Execute_BX_A1()
{
//A8-62
//A8.6.25
uint Rm = Reg16(0);
if (disassemble)
return DIS("BX/c/", "/r0/", Rm);
uint m = r[Rm];
_BXWritePC(m);
return 1;
uint m = Reg16(0);
return ExecuteCore_BX(Encoding.A1, m);
}
uint ExecuteArm_Media() { return Execute_Unhandled("ExecuteArm_Media"); }
@ -720,7 +757,7 @@ namespace BizHawk.Emulation.CPUs.ARM
.r("op1==#00010x && coproc_special==#1", () => Execute_Unhandled("ExecuteArm_SIMD_VFP_64bit_xfer"))
.r("op1==#000100 && coproc_special==#0", () => Execute_Unhandled("MCRR,MCRR2"))
.r("op1==#000101 && coproc_special==#0", () => Execute_Unhandled("MRRC,MRRC2"))
.r("op1==#10xxxx && op==0 && coproc_special==#1", () => Execute_Unhandled("VFP data-processing on page A7-24"))
.r("op1==#10xxxx && op==0 && coproc_special==#1", () => ExecuteArm_VFP_DataProcessing())
.r("op1==#10xxxx && op==0 && coproc_special==#0", () => Execute_Unhandled("CDP,CDP2 on page A8-68"))
.r("op1==#10xxxx && op==1 && coproc_special==#1", () => ExecuteArm_ShortVFPTransfer())
.r("op1==#10xxx0 && op==1 && coproc_special==#0", () => Execute_Unhandled("MCR,MCR2 on pageA8-186"))
@ -739,6 +776,124 @@ namespace BizHawk.Emulation.CPUs.ARM
return 1;
}
uint ExecuteArm_VFP_DataProcessing()
{
//A7.5
uint opc1 = (instruction >> 20) & 0xF;
uint opc2 = (instruction >> 16) & 0xF;
uint opc3 = (instruction >> 6) & 3;
if (opc1 == _.b0000 || opc1 == _.b0100) return Execute_Unhandled("VML, VMLS (floating point)");
if (opc1 == _.b0001 || opc1 == _.b0101) return Execute_Unhandled("VNMLA, VNMLS, VNMUL");
if (opc1 == _.b0010 || opc1 == _.b0110)
if (opc3 == _.b01 || opc3 == _.b11) return Execute_Unhandled("VMUL (floating point)");
else if (opc3 == _.b00 || opc3 == _.b10) return Execute_Unhandled("VMUL (floating point)");
else throw new InvalidOperationException("decode fail");
if (opc1 == _.b0011 || opc1 == _.b0111)
if (opc3 == _.b00 || opc3 == _.b10) return Execute_VADD_floating_point_A2();
else if (opc3 == _.b01 || opc3 == _.b11) return Execute_Unhandled("VSUB (floating point)");
if (opc1 == _.b1000 || opc1 == _.b1100)
if (opc3 == _.b00 || opc3 == _.b10) return Execute_Unhandled("VDIV");
else throw new InvalidOperationException("unhandled opcode space..");
if (opc1 == _.b1011 || opc1 == _.b1111)
{
if (opc3 == _.b00 || opc3 == _.b10) return Execute_Unhandled("VMOV (immediate)");
if (opc2 == _.b0000 && opc3 == _.b01) return Execute_VMOV_register_A2();
if (opc2 == _.b0000 && opc3 == _.b11) return Execute_Unhandled("VABS");
if (opc2 == _.b0001 && opc3 == _.b01) return Execute_Unhandled("VNEG");
if (opc2 == _.b0001 && opc3 == _.b11) return Execute_Unhandled("VSQRT");
if (opc2 == _.b0010 || opc2 == _.b0011) return Execute_Unhandled("VCVTB, VCVTT (between half-precision and single precision)");
if (opc2 == _.b0100 || opc2 == _.b0101) return Execute_Unhandled("VCMP, VCMPE");
if (opc2 == _.b0111) return Execute_Unhandled("VCVT (between double precision and single precision)");
if (opc2 == _.b1000) return Execute_Unhandled("VCVT, VCVTR (between floating point and integer)");
if (opc2 == _.b1010 || opc2 == _.b1011) return Execute_Unhandled("VCVT (between floating point and fixed point)");
if (opc2 == _.b1100 || opc2 == _.b1101) return Execute_Unhandled("VCVT, VCVTR (between floating point and integer)");
if (opc2 == _.b1110 || opc2 == _.b1111) return Execute_Unhandled("VCVT (between floating point and fixed point)");
}
throw new InvalidOperationException("decoder fail");
}
uint Execute_VADD_floating_point_A2()
{
//A8.6.272
if (_FPSCR_LEN() != _.b000 || _FPSCR_STRIDE() != _.b00) throw new NotImplementedException("see VFP vectors");
const bool advsimd = false;
Bit sz = _.BIT8(instruction);
bool dp_operation = (sz == 1);
uint D = _.BIT22(instruction);
uint M = _.BIT5(instruction);
uint N = _.BIT7(instruction);
uint Vm = Reg16(0);
uint Vd = Reg16(12);
uint Vn = Reg16(16);
uint d = dp_operation ? ((D << 4) | Vd) : ((Vd << 1) | D);
uint n = dp_operation ? ((N << 4) | Vn) : ((Vn << 1) | N);
uint m = dp_operation ? ((M << 4) | Vm) : ((Vm << 1) | M);
return ExecuteCore_VADD_floating_point(Encoding.A2, dp_operation, advsimd, d, n, m);
}
uint Execute_VMOV_register_A2()
{
//A8.6.327
if (_FPSCR_LEN() != _.b000 || _FPSCR_STRIDE() != _.b00) throw new NotImplementedException("see VFP vectors");
Bit sz = _.BIT8(instruction);
bool single_register = (sz == 0);
const bool advsimd = false;
uint d,m;
uint Vd = Reg16(12);
uint Vm = Reg16(0);
uint D = _.BIT22(instruction);
uint M = _.BIT5(instruction);
uint regs = 0;
if (single_register)
{
d = (Vd << 1) | D;
m = (Vm << 1) | M;
}
else
{
d = (D << 4) | Vd;
m = (M << 4) | Vm;
regs = 1;
}
return ExecuteCore_VMOV_register(Encoding.A2, single_register, advsimd, d, m, regs);
}
uint Execute_VMOV_immediate_A2()
{
////A8.6.326
//if (_FPSCR_LEN() != _.b000 || _FPSCR_STRIDE() != _.b00) throw new NotImplementedException("see VFP vectors");
//Bit sz = _.BIT8(instruction);
//bool single_register = (sz == 0);
//const bool advsimd = false;
//uint d;
//uint Vd = Reg16(12);
//uint D = _.BIT22(instruction);
//uint imm32 = 0;
//ulong imm64 = 0;
//uint imm4H = (instruction>>16)&0xF;
//uint imm4L = (instruction&0xF);
//uint regs = 0;
//if (single_register)
//{
// d = (Vd << 1) | D;
// imm32 = _VFPExpandImm32((imm4H << 4) | imm4L);
//}
//else
//{
// d = (D << 4) | Vd;
// imm64 = _VFPExpandImm64((imm4H << 4) | imm4L);
// regs = 1;
//}
//return ExecuteCore_VMOV(Encoding.A2, single_register, advsimd, d, regs, imm32, imm64);
return 1;
}
uint Execute_ExtensionRegister_LoadStore()
{
//A7.6 Extension register load/store instructions
@ -781,7 +936,7 @@ namespace BizHawk.Emulation.CPUs.ARM
uint imm8 = instruction & 0xFF;
uint imm32 = _ZeroExtend_32(imm8 << 2);
uint Vd = Reg16(12);
uint n = Reg16(0);
uint n = Reg16(16);
uint d = (Vd << 1) | D;
return ExecuteCore_VLDR(Encoding.A1, single_reg, add, d, n, imm32);
}
@ -837,7 +992,7 @@ namespace BizHawk.Emulation.CPUs.ARM
Decoder_ExecuteArm_ShortVFPTransfer.Ensure(() => Decoder_ExecuteArm_ShortVFPTransfer
.d("A", 3).d("L", 1).d("C", 1).d("B", 2)
.r("L==0 && C==0 && A==#000", () => Execute_Unhandled("VMOV (between ARM core register and single-precision register) on page A8-648"))
.r("L==0 && C==0 && A==#111", () => ExecuteArm_VMSR_A1())
.r("L==0 && C==0 && A==#111", () => Execute_VMSR_A1())
.r("L==0 && C==1 && A==#0xx", () => Execute_Unhandled("VMOV (ARM core register to scalar) on page A8-644"))
.r("L==0 && C==1 && A==#1xx && B==#0x", () => Execute_Unhandled("VDUP (ARM core register) on page A8-594"))
.r("L==1 && C==0 && A==#000", () => Execute_Unhandled("VMOV (between ARM core register and single-precision register) on page A8-648"))
@ -854,7 +1009,7 @@ namespace BizHawk.Emulation.CPUs.ARM
return 1;
}
uint ExecuteArm_VMSR_A1()
uint Execute_VMSR_A1()
{
uint t = Reg16(12);
if (t == 15 || (t == 13 && _CurrentInstrSet() != EInstrSet.ARM)) return _UNPREDICTABLE();

View File

@ -211,6 +211,17 @@ namespace BizHawk.Emulation.CPUs.ARM
return 1;
}
//A8.6.25 BX
uint ExecuteCore_BX(Encoding encoding, uint m)
{
if (disassemble)
return DISNEW("BX<c>", "<rm>", m);
_BXWritePC(r[m]);
return 1;
}
//A8.6.35 CMP (immediate)
uint ExecuteCore_CMP_immediate(Encoding encoding, uint n, uint imm32)
{
@ -588,6 +599,14 @@ namespace BizHawk.Emulation.CPUs.ARM
return 0;
}
//A8.6.110 NOP
uint ExecuteCore_NOP(Encoding encoding)
{
if (disassemble)
return DISNEW("NOP<c>", "");
return 1;
}
//A8.6.113 ORR (immediate)
uint ExecuteCore_ORR_immediate(Encoding encoding, uint n, uint d, bool setflags, uint imm32, Bit carry)
{
@ -1007,10 +1026,73 @@ namespace BizHawk.Emulation.CPUs.ARM
return 1;
}
//A8.6.272 VADD (floating point)
uint ExecuteCore_VADD_floating_point(Encoding encoding, bool dp_operation, bool advsimd, uint d, uint n, uint m)
{
if (advsimd) throw new NotImplementedException("VMOV reg adv simd :(");
if (disassemble)
return DISNEW("VADD<c><.fpsize>", "<{SDd~SDn, }><SDn>, <SDm>", dp_operation ? 64 : 32, !dp_operation, d, n, !dp_operation, n, !dp_operation, m);
if (advsimd)
{
}
else
{
if (dp_operation)
D[d] = _FPAdd(D[n], D[m], true);
else
S[d] = _FPAdd(S[n], S[m], true);
}
return 1;
}
//A8.6.320 VLDR
uint ExecuteCore_VLDR(Encoding encoding, bool single_reg, bool add, uint d, uint n, uint imm32)
{
throw new NotImplementedException("TODO");
if (disassemble)
return DISNEW("VLDR<c>", "<SDd>, [<rn!><{, #+/-imm}>]", single_reg, d, n, add, imm32);
_CheckVFPEnabled(true);
_NullCheckIfThumbEE(n);
uint @base = (n==15)?_Align(PC,4):r[n];
uint address = add ? (@base + imm32) : (@base - imm32);
if (single_reg)
S[d] = MemA_ReadSingle(address);
else
D[d] = MemA_ReadDouble(address);
return 1;
}
//A8.6.326 VMOV (immediate)
uint ExecuteCore_VMOV_immediate(Encoding encoding, bool single_register, bool advsimd, uint d, uint regs, float imm32, double imm64)
{
if (advsimd) throw new NotImplementedException("VMOV imm adv simd :(");
throw new NotImplementedException("ExecuteCore_VMOV_immediate");
//if(disassemble)
// return DISNEW("VMOV<c><.fpsize>", "<SDd>", single_register?32:64, single_register, d
return 1;
}
//A8.6.327 VMOV (register)
uint ExecuteCore_VMOV_register(Encoding encoding, bool single_register, bool advsimd, uint d, uint m, uint regs)
{
if (advsimd) throw new NotImplementedException("VMOV reg adv simd :(");
if (disassemble)
return DISNEW("VMOV<c><.fpsize>", "<SDd>, <SDm>", single_register ? 32 : 64, single_register, d, single_register, m);
_CheckAdvSIMDOrVFPEnabled(true, advsimd);
if (single_register)
S[d] = S[m];
else for (uint r = 0; r <= regs - 1; r++)
D[d + r] = D[m + r];
return 1;
}
//A8.6.336 VMSR
@ -1027,7 +1109,7 @@ namespace BizHawk.Emulation.CPUs.ARM
uint ExecuteCore_VPUSH(Encoding encoding, bool single_regs, uint d, uint regs, uint imm32)
{
if (disassemble)
return DISNEW("VPUSH<c><{.size}>", "<list>", single_regs ? 32 : 64, single_regs, d, regs);
return DISNEW("VPUSH<c><{.fpsize}>", "<list>", single_regs ? 32 : 64, single_regs, d, regs);
_CheckVFPEnabled(true);
_NullCheckIfThumbEE(13);

View File

@ -89,6 +89,13 @@ namespace BizHawk.Emulation.CPUs.ARM
return bus.Read32(AT.READ, addr);
}
ulong MemA_Read64(uint addr)
{
ulong ret = MemA_Read32(addr);
ret |= (((ulong)MemA_Read32(addr + 4)) << 32);
return ret;
}
void _SetExclusiveMonitors(uint address, int size)
{
//TODO!!! boring!!
@ -106,6 +113,16 @@ namespace BizHawk.Emulation.CPUs.ARM
MemA_Write32(addr,float_downcast(val));
}
float MemA_ReadSingle(uint addr)
{
return float_upcast(MemA_Read32(addr));
}
double MemA_ReadDouble(uint addr)
{
return double_upcast(MemA_Read64(addr));
}
void MemA_WriteDouble(uint addr, double val)
{
ulong uval = double_downcast(val);
@ -443,6 +460,78 @@ namespace BizHawk.Emulation.CPUs.ARM
return result;
}
float _FPAdd(float op1, float op2, bool fpscr_controlled)
{
//TODO
return op1 + op2;
}
double _FPAdd(double op1, double op2, bool fpscr_controlled)
{
//TODO
return op1 + op2;
}
bool _CheckAdvSIMDOrVFPEnabled(bool x, bool y)
{
//TODO
return true;
}
static uint[] __VFPExpandImm32_table;
static uint __VFPExpandImm32_calc(uint imm8)
{
uint a = _.BIT7(imm8);
uint B = _.BIT6(imm8)^1;
uint b = _.BIT6(imm8);
b |= (b << 1); //replicated to 2 bits
b |= (b << 2); //replicated to 4 bits
b |= (b << 1); //replicated to 5 bits
uint cdefgh = imm8 & 0x3F;
return (a<<31)|(B<<30)|(b<<29)|(cdefgh<<24);
}
static ulong[] __VFPExpandImm64_table;
static ulong __VFPExpandImm64_calc(uint imm8)
{
uint a = _.BIT7(imm8);
uint B = _.BIT6(imm8) ^ 1;
uint b = _.BIT6(imm8);
b |= (b << 1); //replicated to 2 bits
b |= (b << 2); //replicated to 4 bits
b |= (b << 4); //replicated to 8 bits
uint cdefgh = imm8 & 0x3F;
uint uintret = (a << 31) | (B << 30) | (b << 29) | (cdefgh << 20);
ulong ulongret = uintret << 32;
return ulongret;
}
uint _VFPExpandImm32(uint imm8)
{
if(__VFPExpandImm32_table == null)
{
__VFPExpandImm32_table = new uint[256];
for(uint i=0;i<256;i++)
__VFPExpandImm32_table[i] = __VFPExpandImm32_calc(i);
}
return __VFPExpandImm32_table[imm8];
}
ulong _VFPExpandImm64(uint imm8)
{
if (__VFPExpandImm64_table == null)
{
__VFPExpandImm64_table = new ulong[256];
for (uint i = 0; i < 256; i++)
__VFPExpandImm64_table[i] = __VFPExpandImm64_calc(i);
}
return __VFPExpandImm64_table[imm8];
}
uint _ARMExpandImm(uint imm12)
{
//A5-10

View File

@ -113,18 +113,29 @@ namespace BizHawk.Emulation.CPUs.ARM
float[] S = new float[32];
double[] D = new double[16];
unsafe uint float_downcast(float f)
unsafe static uint float_downcast(float f)
{
float* fp = &f;
return *(uint*)fp;
}
unsafe ulong double_downcast(double f)
unsafe static float float_upcast(uint f)
{
uint* fp = &f;
return *(float*)fp;
}
unsafe static ulong double_downcast(double f)
{
double* fp = &f;
return *(ulong*)fp;
}
unsafe static double double_upcast(ulong f)
{
ulong* fp = &f;
return *(double*)fp;
}
public uint SP { get { return r[13]; } set { r[13] = value; } }
public uint LR { get { return r[14]; } set { r[14] = value; } }
@ -140,6 +151,8 @@ namespace BizHawk.Emulation.CPUs.ARM
uint FPSCR;
uint _FPSCR_LEN() { return 0; }
uint _FPSCR_STRIDE() { return 0; }
public ARM(ARM_SYS sys, ARM_BUS bus)
{