frontend: Introduce FPSCR register helper class
Encapsulates all of the FPSCR state.
This commit is contained in:
parent
b5a86889cd
commit
eba3a06d80
5 changed files with 236 additions and 59 deletions
|
@ -1226,15 +1226,15 @@ static void FPThreeOp32(BlockOfCode* code, RegAlloc& reg_alloc, IR::Block& block
|
||||||
X64Reg operand = reg_alloc.UseRegister(b, any_xmm);
|
X64Reg operand = reg_alloc.UseRegister(b, any_xmm);
|
||||||
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero32(code, result, gpr_scratch);
|
DenormalsAreZero32(code, result, gpr_scratch);
|
||||||
DenormalsAreZero32(code, operand, gpr_scratch);
|
DenormalsAreZero32(code, operand, gpr_scratch);
|
||||||
}
|
}
|
||||||
(code->*fn)(result, R(operand));
|
(code->*fn)(result, R(operand));
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
FlushToZero32(code, result, gpr_scratch);
|
FlushToZero32(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
if (block.location.FPSCR_DN()) {
|
if (block.location.FPSCR().DN()) {
|
||||||
DefaultNaN32(code, result);
|
DefaultNaN32(code, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1247,15 +1247,15 @@ static void FPThreeOp64(BlockOfCode* code, RegAlloc& reg_alloc, IR::Block& block
|
||||||
X64Reg operand = reg_alloc.UseRegister(b, any_xmm);
|
X64Reg operand = reg_alloc.UseRegister(b, any_xmm);
|
||||||
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero64(code, result, gpr_scratch);
|
DenormalsAreZero64(code, result, gpr_scratch);
|
||||||
DenormalsAreZero64(code, operand, gpr_scratch);
|
DenormalsAreZero64(code, operand, gpr_scratch);
|
||||||
}
|
}
|
||||||
(code->*fn)(result, R(operand));
|
(code->*fn)(result, R(operand));
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
FlushToZero64(code, result, gpr_scratch);
|
FlushToZero64(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
if (block.location.FPSCR_DN()) {
|
if (block.location.FPSCR().DN()) {
|
||||||
DefaultNaN64(code, result);
|
DefaultNaN64(code, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1266,14 +1266,14 @@ static void FPTwoOp32(BlockOfCode* code, RegAlloc& reg_alloc, IR::Block& block,
|
||||||
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
||||||
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero32(code, result, gpr_scratch);
|
DenormalsAreZero32(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
(code->*fn)(result, R(result));
|
(code->*fn)(result, R(result));
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
FlushToZero32(code, result, gpr_scratch);
|
FlushToZero32(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
if (block.location.FPSCR_DN()) {
|
if (block.location.FPSCR().DN()) {
|
||||||
DefaultNaN32(code, result);
|
DefaultNaN32(code, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1284,14 +1284,14 @@ static void FPTwoOp64(BlockOfCode* code, RegAlloc& reg_alloc, IR::Block& block,
|
||||||
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
||||||
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero64(code, result, gpr_scratch);
|
DenormalsAreZero64(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
(code->*fn)(result, R(result));
|
(code->*fn)(result, R(result));
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
FlushToZero64(code, result, gpr_scratch);
|
FlushToZero64(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
if (block.location.FPSCR_DN()) {
|
if (block.location.FPSCR().DN()) {
|
||||||
DefaultNaN64(code, result);
|
DefaultNaN64(code, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1402,14 +1402,14 @@ void EmitX64::EmitFPSingleToDouble(IR::Block& block, IR::Inst* inst) {
|
||||||
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
||||||
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero32(code, result, gpr_scratch);
|
DenormalsAreZero32(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
code->CVTSS2SD(result, R(result));
|
code->CVTSS2SD(result, R(result));
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
FlushToZero64(code, result, gpr_scratch);
|
FlushToZero64(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
if (block.location.FPSCR_DN()) {
|
if (block.location.FPSCR().DN()) {
|
||||||
DefaultNaN64(code, result);
|
DefaultNaN64(code, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1420,14 +1420,14 @@ void EmitX64::EmitFPDoubleToSingle(IR::Block& block, IR::Inst* inst) {
|
||||||
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
X64Reg result = reg_alloc.UseDefRegister(a, inst, any_xmm);
|
||||||
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_scratch = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero64(code, result, gpr_scratch);
|
DenormalsAreZero64(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
code->CVTSD2SS(result, R(result));
|
code->CVTSD2SS(result, R(result));
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
FlushToZero32(code, result, gpr_scratch);
|
FlushToZero32(code, result, gpr_scratch);
|
||||||
}
|
}
|
||||||
if (block.location.FPSCR_DN()) {
|
if (block.location.FPSCR().DN()) {
|
||||||
DefaultNaN32(code, result);
|
DefaultNaN32(code, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1443,7 +1443,7 @@ void EmitX64::EmitFPSingleToS32(IR::Block& block, IR::Inst* inst) {
|
||||||
// ARM saturates on conversion; this differs from x64 which returns a sentinel value.
|
// ARM saturates on conversion; this differs from x64 which returns a sentinel value.
|
||||||
// Conversion to double is lossless, and allows for clamping.
|
// Conversion to double is lossless, and allows for clamping.
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero32(code, from, gpr_scratch);
|
DenormalsAreZero32(code, from, gpr_scratch);
|
||||||
}
|
}
|
||||||
code->CVTSS2SD(from, R(from));
|
code->CVTSS2SD(from, R(from));
|
||||||
|
@ -1481,8 +1481,8 @@ void EmitX64::EmitFPSingleToU32(IR::Block& block, IR::Inst* inst) {
|
||||||
//
|
//
|
||||||
// FIXME: Inexact exception not correctly signalled with the below code
|
// FIXME: Inexact exception not correctly signalled with the below code
|
||||||
|
|
||||||
if (block.location.FPSCR_RMode() != Arm::FPRoundingMode::RoundTowardsZero && !round_towards_zero) {
|
if (block.location.FPSCR().RMode() != Arm::FPSCR::RoundingMode::TowardsZero && !round_towards_zero) {
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero32(code, from, gpr_scratch);
|
DenormalsAreZero32(code, from, gpr_scratch);
|
||||||
}
|
}
|
||||||
code->CVTSS2SD(from, R(from));
|
code->CVTSS2SD(from, R(from));
|
||||||
|
@ -1503,7 +1503,7 @@ void EmitX64::EmitFPSingleToU32(IR::Block& block, IR::Inst* inst) {
|
||||||
X64Reg xmm_mask = reg_alloc.ScratchRegister(any_xmm);
|
X64Reg xmm_mask = reg_alloc.ScratchRegister(any_xmm);
|
||||||
X64Reg gpr_mask = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_mask = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero32(code, from, gpr_scratch);
|
DenormalsAreZero32(code, from, gpr_scratch);
|
||||||
}
|
}
|
||||||
code->CVTSS2SD(from, R(from));
|
code->CVTSS2SD(from, R(from));
|
||||||
|
@ -1539,7 +1539,7 @@ void EmitX64::EmitFPDoubleToS32(IR::Block& block, IR::Inst* inst) {
|
||||||
|
|
||||||
// ARM saturates on conversion; this differs from x64 which returns a sentinel value.
|
// ARM saturates on conversion; this differs from x64 which returns a sentinel value.
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero64(code, from, gpr_scratch);
|
DenormalsAreZero64(code, from, gpr_scratch);
|
||||||
}
|
}
|
||||||
// First time is to set flags
|
// First time is to set flags
|
||||||
|
@ -1574,8 +1574,8 @@ void EmitX64::EmitFPDoubleToU32(IR::Block& block, IR::Inst* inst) {
|
||||||
// TODO: Use VCVTPD2UDQ when AVX512VL is available.
|
// TODO: Use VCVTPD2UDQ when AVX512VL is available.
|
||||||
// FIXME: Inexact exception not correctly signalled with the below code
|
// FIXME: Inexact exception not correctly signalled with the below code
|
||||||
|
|
||||||
if (block.location.FPSCR_RMode() != Arm::FPRoundingMode::RoundTowardsZero && !round_towards_zero) {
|
if (block.location.FPSCR().RMode() != Arm::FPSCR::RoundingMode::TowardsZero && !round_towards_zero) {
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero64(code, from, gpr_scratch);
|
DenormalsAreZero64(code, from, gpr_scratch);
|
||||||
}
|
}
|
||||||
ZeroIfNaN64(code, from);
|
ZeroIfNaN64(code, from);
|
||||||
|
@ -1595,7 +1595,7 @@ void EmitX64::EmitFPDoubleToU32(IR::Block& block, IR::Inst* inst) {
|
||||||
X64Reg xmm_mask = reg_alloc.ScratchRegister(any_xmm);
|
X64Reg xmm_mask = reg_alloc.ScratchRegister(any_xmm);
|
||||||
X64Reg gpr_mask = reg_alloc.ScratchRegister(any_gpr);
|
X64Reg gpr_mask = reg_alloc.ScratchRegister(any_gpr);
|
||||||
|
|
||||||
if (block.location.FPSCR_FTZ()) {
|
if (block.location.FPSCR().FTZ()) {
|
||||||
DenormalsAreZero64(code, from, gpr_scratch);
|
DenormalsAreZero64(code, from, gpr_scratch);
|
||||||
}
|
}
|
||||||
ZeroIfNaN64(code, from);
|
ZeroIfNaN64(code, from);
|
||||||
|
|
188
src/frontend/arm/FPSCR.h
Normal file
188
src/frontend/arm/FPSCR.h
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2016 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/bit_util.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace Arm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of the Floating-Point Status and Control Register.
|
||||||
|
*/
|
||||||
|
class FPSCR final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class RoundingMode {
|
||||||
|
ToNearest,
|
||||||
|
TowardsPlusInfinity,
|
||||||
|
TowardsMinusInfinity,
|
||||||
|
TowardsZero
|
||||||
|
};
|
||||||
|
|
||||||
|
FPSCR() = default;
|
||||||
|
FPSCR(const FPSCR&) = default;
|
||||||
|
FPSCR(FPSCR&&) = default;
|
||||||
|
/* implicit */ FPSCR(u32 data) : value{data} {}
|
||||||
|
|
||||||
|
FPSCR& operator=(const FPSCR&) = default;
|
||||||
|
FPSCR& operator=(FPSCR&&) = default;
|
||||||
|
FPSCR& operator=(u32 data) {
|
||||||
|
value = data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Negative condition flag.
|
||||||
|
bool N() const {
|
||||||
|
return Common::Bit<31>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Zero condition flag.
|
||||||
|
bool Z() const {
|
||||||
|
return Common::Bit<30>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Carry condition flag.
|
||||||
|
bool C() const {
|
||||||
|
return Common::Bit<29>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflow condition flag.
|
||||||
|
bool V() const {
|
||||||
|
return Common::Bit<28>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cumulative saturation flag.
|
||||||
|
bool QC() const {
|
||||||
|
return Common::Bit<27>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alternate half-precision control flag.
|
||||||
|
bool AHP() const {
|
||||||
|
return Common::Bit<26>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default NaN mode control bit.
|
||||||
|
bool DN() const {
|
||||||
|
return Common::Bit<25>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flush-to-zero mode control bit.
|
||||||
|
bool FTZ() const {
|
||||||
|
return Common::Bit<24>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounding mode control field.
|
||||||
|
RoundingMode RMode() const {
|
||||||
|
return static_cast<RoundingMode>(Common::Bits<22, 23>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates the stride of a vector.
|
||||||
|
u32 Stride() const {
|
||||||
|
return Common::Bits<20, 21>(value) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates the length of a vector.
|
||||||
|
u32 Len() const {
|
||||||
|
return Common::Bits<16, 18>(value) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Input denormal exception trap enable flag.
|
||||||
|
bool IDE() const {
|
||||||
|
return Common::Bit<15>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inexact exception trap enable flag.
|
||||||
|
bool IXE() const {
|
||||||
|
return Common::Bit<12>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Underflow exception trap enable flag.
|
||||||
|
bool UFE() const {
|
||||||
|
return Common::Bit<11>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflow exception trap enable flag.
|
||||||
|
bool OFE() const {
|
||||||
|
return Common::Bit<10>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Division by zero exception trap enable flag.
|
||||||
|
bool DZE() const {
|
||||||
|
return Common::Bit<9>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalid operation exception trap enable flag.
|
||||||
|
bool IOE() const {
|
||||||
|
return Common::Bit<8>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Input denormal cumulative exception bit.
|
||||||
|
bool IDC() const {
|
||||||
|
return Common::Bit<7>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inexact cumulative exception bit.
|
||||||
|
bool IXC() const {
|
||||||
|
return Common::Bit<4>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Underflow cumulative exception bit.
|
||||||
|
bool UFC() const {
|
||||||
|
return Common::Bit<3>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflow cumulative exception bit.
|
||||||
|
bool OFC() const {
|
||||||
|
return Common::Bit<2>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Division by zero cumulative exception bit.
|
||||||
|
bool DZC() const {
|
||||||
|
return Common::Bit<1>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalid operation cumulative exception bit.
|
||||||
|
bool IOC() const {
|
||||||
|
return Common::Bit<0>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the FPSCR indicates RunFast mode.
|
||||||
|
*
|
||||||
|
* RunFast mode is enabled when:
|
||||||
|
* - Flush-to-zero is enabled
|
||||||
|
* - Default NaNs are enabled.
|
||||||
|
* - All exception enable bits are cleared.
|
||||||
|
*/
|
||||||
|
bool InRunFastMode() const {
|
||||||
|
constexpr u32 mask = 0x03001F00;
|
||||||
|
constexpr u32 expected = 0x03000000;
|
||||||
|
|
||||||
|
return (value & mask) == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the underlying raw value within the FPSCR.
|
||||||
|
u32 Value() const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
u32 value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(FPSCR lhs, FPSCR rhs) {
|
||||||
|
return lhs.Value() == rhs.Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(FPSCR lhs, FPSCR rhs) {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Arm
|
||||||
|
} // namespace Dynarmic
|
|
@ -13,6 +13,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "frontend/arm/FPSCR.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Arm {
|
||||||
|
@ -64,13 +65,6 @@ enum class SignExtendRotation {
|
||||||
ROR_24 ///< ROR #24
|
ROR_24 ///< ROR #24
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FPRoundingMode {
|
|
||||||
RoundToNearest,
|
|
||||||
RoundTowardsPositiveInfinity,
|
|
||||||
RoundTowardsNegativeInfinity,
|
|
||||||
RoundTowardsZero,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LocationDescriptor describes the location of a basic block.
|
* LocationDescriptor describes the location of a basic block.
|
||||||
* The location is not solely based on the PC because other flags influence the way
|
* The location is not solely based on the PC because other flags influence the way
|
||||||
|
@ -80,18 +74,13 @@ enum class FPRoundingMode {
|
||||||
struct LocationDescriptor {
|
struct LocationDescriptor {
|
||||||
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
||||||
|
|
||||||
LocationDescriptor(u32 arm_pc, bool tflag, bool eflag, u32 fpscr)
|
LocationDescriptor(u32 arm_pc, bool tflag, bool eflag, FPSCR fpscr)
|
||||||
: arm_pc(arm_pc), tflag(tflag), eflag(eflag), fpscr(fpscr & FPSCR_MODE_MASK) {}
|
: arm_pc(arm_pc), tflag(tflag), eflag(eflag), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
||||||
|
|
||||||
u32 PC() const { return arm_pc; }
|
u32 PC() const { return arm_pc; }
|
||||||
bool TFlag() const { return tflag; }
|
bool TFlag() const { return tflag; }
|
||||||
bool EFlag() const { return eflag; }
|
bool EFlag() const { return eflag; }
|
||||||
u32 FPSCR() const { return fpscr; }
|
Arm::FPSCR FPSCR() const { return fpscr; }
|
||||||
bool FPSCR_FTZ() const { return Common::Bit<24>(fpscr); }
|
|
||||||
bool FPSCR_DN() const { return Common::Bit<25>(fpscr); }
|
|
||||||
u32 FPSCR_Len() const { return Common::Bits<16, 18>(fpscr) + 1; }
|
|
||||||
u32 FPSCR_Stride() const { return Common::Bits<20, 21>(fpscr) + 1; }
|
|
||||||
FPRoundingMode FPSCR_RMode() const { return static_cast<FPRoundingMode>(Common::Bits<22, 23>(fpscr)); }
|
|
||||||
|
|
||||||
bool operator == (const LocationDescriptor& o) const {
|
bool operator == (const LocationDescriptor& o) const {
|
||||||
return std::tie(arm_pc, tflag, eflag, fpscr) == std::tie(o.arm_pc, o.tflag, o.eflag, o.fpscr);
|
return std::tie(arm_pc, tflag, eflag, fpscr) == std::tie(o.arm_pc, o.tflag, o.eflag, o.fpscr);
|
||||||
|
@ -121,7 +110,7 @@ struct LocationDescriptor {
|
||||||
// This value MUST BE UNIQUE.
|
// This value MUST BE UNIQUE.
|
||||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||||
u64 pc_u64 = u64(arm_pc);
|
u64 pc_u64 = u64(arm_pc);
|
||||||
u64 fpscr_u64 = u64(fpscr) << 32;
|
u64 fpscr_u64 = u64(fpscr.Value()) << 32;
|
||||||
u64 t_u64 = tflag ? (1ull << 35) : 0;
|
u64 t_u64 = tflag ? (1ull << 35) : 0;
|
||||||
u64 e_u64 = eflag ? (1ull << 39) : 0;
|
u64 e_u64 = eflag ? (1ull << 39) : 0;
|
||||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||||
|
@ -129,9 +118,9 @@ struct LocationDescriptor {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 arm_pc;
|
u32 arm_pc;
|
||||||
bool tflag; ///< Thumb / ARM
|
bool tflag; ///< Thumb / ARM
|
||||||
bool eflag; ///< Big / Little Endian
|
bool eflag; ///< Big / Little Endian
|
||||||
u32 fpscr; ///< Floating point status control register
|
Arm::FPSCR fpscr; ///< Floating point status control register
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LocationDescriptorHash {
|
struct LocationDescriptorHash {
|
||||||
|
|
|
@ -21,7 +21,7 @@ std::string DumpBlock(const IR::Block& block) {
|
||||||
loc.PC(),
|
loc.PC(),
|
||||||
loc.TFlag() ? "T" : "!T",
|
loc.TFlag() ? "T" : "!T",
|
||||||
loc.EFlag() ? "E" : "!E",
|
loc.EFlag() ? "E" : "!E",
|
||||||
loc.FPSCR());
|
loc.FPSCR().Value());
|
||||||
};
|
};
|
||||||
|
|
||||||
ret += Common::StringFromFormat("Block: location=%s\n", loc_to_string(block.location).c_str());
|
ret += Common::StringFromFormat("Block: location=%s\n", loc_to_string(block.location).c_str());
|
||||||
|
|
|
@ -18,7 +18,7 @@ static ExtReg ToExtReg(bool sz, size_t base, bool bit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VADD(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VADD(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -37,7 +37,7 @@ bool ArmTranslatorVisitor::vfp2_VADD(Cond cond, bool D, size_t Vn, size_t Vd, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VSUB(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VSUB(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -56,7 +56,7 @@ bool ArmTranslatorVisitor::vfp2_VSUB(Cond cond, bool D, size_t Vn, size_t Vd, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -75,7 +75,7 @@ bool ArmTranslatorVisitor::vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -95,7 +95,7 @@ bool ArmTranslatorVisitor::vfp2_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -115,7 +115,7 @@ bool ArmTranslatorVisitor::vfp2_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -134,7 +134,7 @@ bool ArmTranslatorVisitor::vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, b
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -154,7 +154,7 @@ bool ArmTranslatorVisitor::vfp2_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, b
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -174,7 +174,7 @@ bool ArmTranslatorVisitor::vfp2_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, b
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VDIV(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VDIV(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -297,7 +297,7 @@ bool ArmTranslatorVisitor::vfp2_VMOV_f64_2u32(Cond cond, Reg t2, Reg t, bool M,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VMOV_reg(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VMOV_reg(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -310,7 +310,7 @@ bool ArmTranslatorVisitor::vfp2_VMOV_reg(Cond cond, bool D, size_t Vd, bool sz,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VABS(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VABS(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -327,7 +327,7 @@ bool ArmTranslatorVisitor::vfp2_VABS(Cond cond, bool D, size_t Vd, bool sz, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VNEG(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VNEG(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
@ -344,7 +344,7 @@ bool ArmTranslatorVisitor::vfp2_VNEG(Cond cond, bool D, size_t Vd, bool sz, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
||||||
if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1)
|
if (ir.current_location.FPSCR().Len() != 1 || ir.current_location.FPSCR().Stride() != 1)
|
||||||
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
return InterpretThisInstruction(); // TODO: Vectorised floating point instructions
|
||||||
|
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
|
Loading…
Reference in a new issue