diff --git a/BizHawk.Emulation/CPUs/ARM/ARM.Disassembly.cs b/BizHawk.Emulation/CPUs/ARM/ARM.Disassembly.cs index 3c05c84489..9b0e0e7fd4 100644 --- a/BizHawk.Emulation/CPUs/ARM/ARM.Disassembly.cs +++ b/BizHawk.Emulation/CPUs/ARM/ARM.Disassembly.cs @@ -162,6 +162,11 @@ namespace BizHawk.Emulation.CPUs.ARM else opcode = opcode.Replace(crepl, CC_strings[_CurrentCond()]); } else opcode = opcode.Replace(crepl, ""); + + if(opcode.Contains("{.size}")) + { + opcode = opcode.Replace("<{.size}>","." + args[argindex++].ToString()); + } //--------- string cpcomment = null; @@ -317,9 +322,26 @@ namespace BizHawk.Emulation.CPUs.ARM { item = ""; cpcomment = args[argindex++] as string; + break; } - break; + case "list": + { + bool single = (bool)args[argindex++]; + uint d = (uint)args[argindex++]; + uint regs = (uint)args[argindex++]; + item = "{"; + string name = single ? "s" : "d"; + bool first=true; + for (uint r = 0; r <= regs - 1; r++) + { + if (!first) item += ","; + first = false; + item += name + (r + d).ToString(); + } + item += "}"; + break; + } default: item = "<" + item + ">"; break; } diff --git a/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteArm.cs b/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteArm.cs index bd859b15d9..97c35ad739 100644 --- a/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteArm.cs +++ b/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteArm.cs @@ -377,7 +377,7 @@ namespace BizHawk.Emulation.CPUs.ARM case _.b01000: case _.b01001: if (Rn != _.b1111) return Execute_ADD_immedate_arm_A1(); - else return Execute_Unhandled("arm adr"); + else return Execute_ADR_A1(); case _.b01010: case _.b01011: return Execute_Unhandled("arm adc imm"); case _.b01100: @@ -413,13 +413,35 @@ namespace BizHawk.Emulation.CPUs.ARM uint imm12 = instruction & 0xFFF; if (n == _.b1111 && S == 0) throw new NotImplementedException("SEE ADR"); - if (n == _.b1101) throw new NotImplementedException("SEE SUB (SP minus immediate"); + if (n == _.b1101) return Execute_SUB_SP_minus_immediate_A1(); if (n == _.b1111 && S == 1) throw new NotImplementedException("SEE SUBS PC, LR and related instructions"); bool setflags = (S == 1); uint imm32 = _ARMExpandImm(imm12); return ExecuteCore_SUB_immediate_arm(Encoding.A1, setflags, n, d, imm32); } + uint Execute_SUB_SP_minus_immediate_A1() + { + //A8.6.215 + uint d = Reg16(12); + Bit S = _.BIT20(instruction); + if (d == _.b1111 && S == 1) throw new NotImplementedException("SEE SUBS PC, LR and related instructions"); + bool setflags = (S == 1); + uint imm12 = instruction & 0xFFF; + uint imm32 = _ARMExpandImm(imm12); + return ExecuteCore_SUB_SP_minus_immediate(Encoding.A1,d,setflags,imm32); + } + + uint Execute_ADR_A1() + { + //A8.6.10 + uint d = Reg16(12); + uint imm12 = instruction & 0xFFF; + uint imm32 = _ARMExpandImm(imm12); + const bool add = true; + return ExecuteCore_ADR(Encoding.A1, d, imm32, add); + } + uint Execute_ADD_immedate_arm_A1() { Bit S = _.BIT20(instruction); @@ -690,7 +712,7 @@ namespace BizHawk.Emulation.CPUs.ARM Decoder_ExecuteArm_SVCAndCP.Ensure(() => Decoder_ExecuteArm_SVCAndCP .d("op1", 6).d("op", 1).d("coproc_special", 1).d("rn_is_15", 1) - .r("op1==#0xxxxx && op1!=#000x0x && coproc_special==#1", () => Execute_Unhandled("ExecuteArm_SIMD_VFP_LoadStore")) + .r("op1==#0xxxxx && op1!=#000x0x && coproc_special==#1", () => Execute_ExtensionRegister_LoadStore()) .r("op1==#0xxxx0 && op1!=#000x0x && coproc_special==#0", () => Execute_Unhandled("STC,STC2")) .r("op1==#0xxxx1 && op1!=#000x0x && coproc_special==#0 && rn_is_15==#0", () => Execute_Unhandled("LDC,LDC2(immediate)")) .r("op1==#0xxxx1 && op1!=#000x0x && coproc_special==#0 && rn_is_15==#1", () => Execute_Unhandled("LDC,LDC2(literal)")) @@ -717,9 +739,85 @@ namespace BizHawk.Emulation.CPUs.ARM return 1; } + uint Execute_ExtensionRegister_LoadStore() + { + //A7.6 Extension register load/store instructions + uint opcode = (instruction >> 20) & 0x1F; + uint n = Reg16(16); + bool bit8 = _.BIT8(instruction)==1; + switch (opcode) + { + case _.b00100: case _.b00101: return Execute_Unhandled("64-bit transfers between ARM core and extension registers"); + case _.b01000: case _.b01100: return Execute_Unhandled("VSTM"); + case _.b01010: case _.b01110: return Execute_Unhandled("VSTM"); + case _.b10000: case _.b10100: case _.b11000: case _.b11100: return Execute_Unhandled("VSTR"); + case _.b10010: case _.b10110: + if (n != _.b1101) return Execute_Unhandled("VSTM"); + else return bit8?Execute_VPUSH_A1():Execute_VPUSH_A2(); + case _.b01001: case _.b01101: return Execute_Unhandled("VLDM"); + case _.b01011: case _.b01111: + if (n != _.b1101) return Execute_Unhandled("VLDM"); + else return Execute_Unhandled("VPOP"); + case _.b10001: case _.b10101: case _.b11001: case _.b11101: + return bit8 ? Execute_VLDR_A1() : Execute_VLDR_A2(); + case _.b10011: case _.b10111: return Execute_Unhandled("VLDM"); + default: throw new InvalidOperationException("decoder fail"); + } + } + + uint Execute_VLDR_A1() + { + //A8.6.320 + throw new NotSupportedException("Execute_VLDR_A1"); + } + + uint Execute_VLDR_A2() + { + //A8.6.320 + const bool single_reg = true; + Bit U = _.BIT23(instruction); + Bit D = _.BIT22(instruction); + bool add = (U == 1); + uint imm8 = instruction & 0xFF; + uint imm32 = _ZeroExtend_32(imm8 << 2); + uint Vd = Reg16(12); + uint n = Reg16(0); + uint d = (Vd << 1) | D; + return ExecuteCore_VLDR(Encoding.A1, single_reg, add, d, n, imm32); + } + + uint Execute_VPUSH_A1() + { + //A8.6.355 + const bool single_regs = false; + Bit D = _.BIT22(instruction); + uint d = ((uint)D << 4) | Reg16(12); + uint imm8 = instruction & 0xFF; + uint imm32 = _ZeroExtend_32(imm8 << 2); + uint regs = imm8 / 2; + Debug.Assert(!((imm8&1)==1),"see FSTMX"); + if(regs==0 || regs>16 || (d+regs)>32) _FlagUnpredictable(); + return ExecuteCore_VPUSH(Encoding.A1, single_regs, d, regs, imm32); + + } + + uint Execute_VPUSH_A2() + { + //A8.6.355 + const bool single_regs = true; + Bit D = _.BIT22(instruction); + uint d = (Reg16(12)<<1)|D; + uint imm8 = instruction & 0xFF; + uint imm32 = _ZeroExtend_32(imm8 << 2); + uint regs = imm8; + if (regs == 0 || regs > 16 || (d + regs) > 32) _FlagUnpredictable(); + return ExecuteCore_VPUSH(Encoding.A2, single_regs, d, regs, imm32); + } + uint Execute_MRC_MRC2_A1() { //ignoring admonition to see "advanced SIMD and VFP" which has been handled by decode earlier + //TODO - but i should assert anyway uint t = Reg16(12); uint cp = Reg16(8); uint opc1 = Reg8(21); diff --git a/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteCore.cs b/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteCore.cs index c921f4c8f6..b512101064 100644 --- a/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteCore.cs +++ b/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteCore.cs @@ -376,6 +376,34 @@ namespace BizHawk.Emulation.CPUs.ARM return 1; } + //A8.6.60 LDR (register) + uint ExecuteCore_LDR_register(Encoding encoding, uint t, uint n, uint m, SRType shift_t, int shift_n, bool index, bool add, bool wback) + { + if(disassemble) + return Disassemble_LDR_STR_register("LDR", t, n, m, shift_t, shift_n, index, add, wback); + + _NullCheckIfThumbEE(n); + uint offset = _Shift(r[m], shift_t, shift_n, APSR.C); + uint offset_addr = add ? (r[n] + offset) : (r[n] - offset); + uint address = index ? offset_addr : r[n]; + uint data = MemU_Read32(address); + if (wback) r[n] = offset_addr; + if (t == 15) + { + if ((address & 3) == _.b00) _LoadWritePC(data); + else _FlagUnpredictable(); + } + else if (_UnalignedSupport() || (address & 3) == _.b00) + r[t] = data; + else //can only apply before ARMv7 + if (_CurrentInstrSet() == EInstrSet.ARM) + r[t] = _ROR(data, 8 * ((int)address & 3)); + else + r[t] = (uint)_UNKNOWN(32, _ROR(data, 8 * ((int)address & 3))); + + return 1; + } + //A8.6.61 LDRB (immediate, thumb) uint ExecuteCore_LDRB_immediate_thumb(Encoding encoding, uint t, uint n, uint imm32, bool index, bool add, bool wback) { @@ -979,6 +1007,12 @@ namespace BizHawk.Emulation.CPUs.ARM 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"); + } + //A8.6.336 VMSR uint ExecuteCore_VMSR(uint t) { @@ -989,6 +1023,33 @@ namespace BizHawk.Emulation.CPUs.ARM return 1; } + //A8.6.355 VPUSH + uint ExecuteCore_VPUSH(Encoding encoding, bool single_regs, uint d, uint regs, uint imm32) + { + if (disassemble) + return DISNEW("VPUSH<{.size}>", "", single_regs ? 32 : 64, single_regs, d, regs); + + _CheckVFPEnabled(true); + _NullCheckIfThumbEE(13); + + uint address = SP - imm32; + SP = SP - imm32; + if (single_regs) + for (uint r = 0; r <= regs-1; r++) + { + MemA_WriteSingle(address, S[d+r]); + address += 4; + } + else + for (uint r = 0; r <= regs - 1; r++) + { + MemA_WriteDouble(address, D[d+r]); + address += 8; + } + + return 1; + } + } //unnecessary opcodes: BKPT, BXJ, CBNZ, CHKA, NOP, CPY, DBG, ENTERX, HB, IT, LDRBT, LDRHT, LDRSBT, LDRSHT, LEAVEX, RBIT, SBFX, SDIV, TBB diff --git a/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteThumb.cs b/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteThumb.cs index 50eb17a608..105abb37bb 100644 --- a/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteThumb.cs +++ b/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteThumb.cs @@ -127,7 +127,7 @@ namespace BizHawk.Emulation.CPUs.ARM case _.b001: return Execute_Unhandled("STRH (register) on page A8-412"); case _.b010: return Execute_STRB_register_T1(); case _.b011: return Execute_Unhandled("LDRSB (register) on page A8-164"); - case _.b100: return Execute_Unhandled("LDR (register) on page A8-124"); + case _.b100: return Execute_LDR_register_T1(); case _.b101: return Execute_Unhandled("LDRH (register)"); case _.b110: return Execute_LDRB_register_T1(); case _.b111: return Execute_Unhandled("LDRSH (register) on page A8-172"); @@ -201,6 +201,19 @@ namespace BizHawk.Emulation.CPUs.ARM return ExecuteCore_STRB_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback); } + uint Execute_LDR_register_T1() + { + //A8.6.60 + if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotSupportedException("Modified operatoin in ThumbEE"); + uint t = Reg8(0); + uint n = Reg8(3); + uint m = Reg8(6); + const bool index = true; const bool add = true; const bool wback = false; + const SRType shift_t = SRType.LSL; + const int shift_n = 0; + return ExecuteCore_LDR_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback); + } + uint Execute_LDRB_register_T1() { //A8.6.64 diff --git a/BizHawk.Emulation/CPUs/ARM/ARM.Pseudocode.cs b/BizHawk.Emulation/CPUs/ARM/ARM.Pseudocode.cs index 646ee1066f..c8ff618d15 100644 --- a/BizHawk.Emulation/CPUs/ARM/ARM.Pseudocode.cs +++ b/BizHawk.Emulation/CPUs/ARM/ARM.Pseudocode.cs @@ -101,6 +101,19 @@ namespace BizHawk.Emulation.CPUs.ARM return true; } + void MemA_WriteSingle(uint addr, float val) + { + MemA_Write32(addr,float_downcast(val)); + } + + void MemA_WriteDouble(uint addr, double val) + { + ulong uval = double_downcast(val); + //TODO endian + MemA_Write32(addr,(uint)uval); + MemA_Write32(addr+4,(uint)(uval>>32)); + } + void MemA_Write32(uint addr, uint val) { addr = _Align(addr, 4); @@ -181,6 +194,8 @@ namespace BizHawk.Emulation.CPUs.ARM _BranchTo((uint)(address & ~1)); } + bool _BigEndian() { return false; } + void _BranchTo(uint address) { _R[15] = address; diff --git a/BizHawk.Emulation/CPUs/ARM/ARM.cs b/BizHawk.Emulation/CPUs/ARM/ARM.cs index a4e5c34c0d..c5d1573629 100644 --- a/BizHawk.Emulation/CPUs/ARM/ARM.cs +++ b/BizHawk.Emulation/CPUs/ARM/ARM.cs @@ -105,12 +105,27 @@ namespace BizHawk.Emulation.CPUs.ARM } } - //todo: make R[] indexer which is defined as in manual with an assert when R[15] is written to public Registers r; uint[] _R = new uint[16]; public Status_Reg APSR; public Status_Reg SPSR; + float[] S = new float[32]; + double[] D = new double[16]; + + unsafe uint float_downcast(float f) + { + float* fp = &f; + return *(uint*)fp; + } + + unsafe ulong double_downcast(double f) + { + double* fp = &f; + return *(ulong*)fp; + } + + public uint SP { get { return r[13]; } set { r[13] = value; } } public uint LR { get { return r[14]; } set { r[14] = value; } } public uint PC { get { return r[15]; } set { r[15] = value; } }