diff options
Diffstat (limited to '')
128 files changed, 2013 insertions, 12458 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 50ed468d7..f5b4069c7 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -57,7 +57,6 @@ void Config::ReadValues() { Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT); // Core - Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter); Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 30); Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 005f3de23..be4b289bd 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -27,7 +27,6 @@ pad_sleft = pad_sright = [Core] -cpu_core = ## 0: Interpreter (default), 1: OldInterpreter (may work better, soon to be deprecated) gpu_refresh_rate = ## 30 (default) frame_skip = ## 0: No frameskip (default), 1 : 2x frameskip, 2 : 4x frameskip, etc. diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index b0ff5a37e..76aeaedd0 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -43,7 +43,6 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt(); Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt(); Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); qt_config->endGroup(); @@ -83,7 +82,6 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - qt_config->setValue("cpu_core", Settings::values.cpu_core); qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); qt_config->setValue("frame_skip", Settings::values.frame_skip); qt_config->endGroup(); diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index c61ace925..54d21dc90 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -17,16 +17,9 @@ #include "core/arm/skyeye_common/armdefs.h" #include "core/arm/disassembler/arm_disasm.h" -DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { -} - -QModelIndex DisassemblerModel::index(int row, int column, const QModelIndex& parent) const { - return createIndex(row, column); -} +DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { -QModelIndex DisassemblerModel::parent(const QModelIndex& child) const { - return QModelIndex(); } int DisassemblerModel::columnCount(const QModelIndex& parent) const { diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h index 0deccc240..5e19d7c51 100644 --- a/src/citra_qt/debugger/disassembler.h +++ b/src/citra_qt/debugger/disassembler.h @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <QAbstractItemModel> +#pragma once + +#include <QAbstractListModel> #include <QDockWidget> + #include "ui_disassembler.h" #include "common/common.h" @@ -12,15 +15,13 @@ class QAction; class EmuThread; -class DisassemblerModel : public QAbstractItemModel +class DisassemblerModel : public QAbstractListModel { Q_OBJECT public: DisassemblerModel(QObject* parent); - QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex& child) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; diff --git a/src/citra_qt/debugger/disassembler.ui b/src/citra_qt/debugger/disassembler.ui index bd0752aa4..5ca6dc5d2 100644 --- a/src/citra_qt/debugger/disassembler.ui +++ b/src/citra_qt/debugger/disassembler.ui @@ -13,63 +13,66 @@ <property name="windowTitle"> <string>Disassembly</string> </property> - <widget class="QWidget" name="dockWidgetContents"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="button_step"> - <property name="text"> - <string>Step</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_pause"> - <property name="text"> - <string>Pause</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_continue"> - <property name="text"> - <string>Continue</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton"> - <property name="text"> - <string>Step Into</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_breakpoint"> - <property name="text"> - <string>Set Breakpoint</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QTreeView" name="treeView"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="indentation"> - <number>20</number> - </property> - <property name="rootIsDecorated"> - <bool>false</bool> - </property> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - </widget> - </item> + <widget class="QWidget" name="dockWidgetContents"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="button_step"> + <property name="text"> + <string>Step</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_pause"> + <property name="text"> + <string>Pause</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_continue"> + <property name="text"> + <string>Continue</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>Step Into</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_breakpoint"> + <property name="text"> + <string>Set Breakpoint</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QTreeView" name="treeView"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="indentation"> + <number>20</number> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> </layout> </widget> </widget> diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index a9423d6c7..43c59738f 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -170,8 +170,8 @@ void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value) void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value) { - if (framebuffer_height != new_value) { - framebuffer_height = new_value; + if (framebuffer_height != static_cast<unsigned>(new_value)) { + framebuffer_height = static_cast<unsigned>(new_value); framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom)); emit Update(); diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp index 54f628e4c..1e3767c18 100644 --- a/src/citra_qt/util/spinbox.cpp +++ b/src/citra_qt/util/spinbox.cpp @@ -36,7 +36,7 @@ #include "spinbox.h" -CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), base(10), min_value(-100), max_value(100), value(0), num_digits(0) +CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), min_value(-100), max_value(100), value(0), base(10), num_digits(0) { // TODO: Might be nice to not immediately call the slot. // Think of an address that is being replaced by a different one, in which case a lot diff --git a/src/common/logging/log.h b/src/common/logging/log.h index af931a7e8..6c5ca3968 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -32,7 +32,7 @@ typedef u8 ClassType; /** * Specifies the sub-system that generated the log message. * - * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in log.cpp. + * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in backend.cpp. */ enum class Class : ClassType { Log, ///< Messages about the log system itself diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2168d9959..0ab0e440c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -6,13 +6,9 @@ set(SRCS arm/dyncom/arm_dyncom_interpreter.cpp arm/dyncom/arm_dyncom_run.cpp arm/dyncom/arm_dyncom_thumb.cpp - arm/interpreter/arm_interpreter.cpp arm/interpreter/armcopro.cpp - arm/interpreter/armemu.cpp arm/interpreter/arminit.cpp arm/interpreter/armsupp.cpp - arm/interpreter/armvirt.cpp - arm/interpreter/thumbemu.cpp arm/skyeye_common/vfp/vfp.cpp arm/skyeye_common/vfp/vfpdouble.cpp arm/skyeye_common/vfp/vfpinstr.cpp @@ -30,6 +26,7 @@ set(SRCS hle/kernel/kernel.cpp hle/kernel/mutex.cpp hle/kernel/semaphore.cpp + hle/kernel/session.cpp hle/kernel/shared_memory.cpp hle/kernel/timer.cpp hle/kernel/thread.cpp @@ -108,7 +105,6 @@ set(HEADERS arm/dyncom/arm_dyncom_interpreter.h arm/dyncom/arm_dyncom_run.h arm/dyncom/arm_dyncom_thumb.h - arm/interpreter/arm_interpreter.h arm/skyeye_common/arm_regformat.h arm/skyeye_common/armdefs.h arm/skyeye_common/armemu.h diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index e612f7439..ef37ee055 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -86,6 +86,15 @@ public: virtual void AddTicks(u64 ticks) = 0; /** + * Initializes a CPU context for use on this CPU + * @param context Thread context to reset + * @param stack_top Pointer to the top of the stack + * @param entry_point Entry point for execution + * @param arg User argument for thread + */ + virtual void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) = 0; + + /** * Saves the current CPU context * @param ctx Thread context to save */ diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 01ffbcc87..68fddc94f 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -36,9 +36,8 @@ ARM_DynCom::ARM_DynCom() { state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext state->Emulate = 3; - state->pc = state->Reg[15] = 0x00000000; + state->Reg[15] = 0x00000000; state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack - state->servaddr = 0xFFFF0000; state->NirqSig = HIGH; VFPInit(state.get()); // Initialize the VFP @@ -50,7 +49,7 @@ ARM_DynCom::~ARM_DynCom() { } void ARM_DynCom::SetPC(u32 pc) { - state->pc = state->Reg[15] = pc; + state->Reg[15] = pc; } u32 ARM_DynCom::GetPC() const { @@ -94,6 +93,16 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) { AddTicks(ticks_executed); } +void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { + memset(&context, 0, sizeof(Core::ThreadContext)); + + context.cpu_registers[0] = arg; + context.pc = entry_point; + context.sp = stack_top; + context.cpsr = 0x1F; // Usermode + context.mode = 8; // Instructs dyncom CPU core to start execution as if it's "resuming" a thread. +} + void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); @@ -106,7 +115,6 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { ctx.fpscr = state->VFP[1]; ctx.fpexc = state->VFP[2]; - ctx.reg_15 = state->Reg[15]; ctx.mode = state->NextInstr; } @@ -116,13 +124,12 @@ void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { state->Reg[13] = ctx.sp; state->Reg[14] = ctx.lr; - state->pc = ctx.pc; + state->Reg[15] = ctx.pc; state->Cpsr = ctx.cpsr; state->VFP[1] = ctx.fpscr; state->VFP[2] = ctx.fpexc; - state->Reg[15] = ctx.reg_15; state->NextInstr = ctx.mode; } diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index f16fb070c..9e2dda843 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -13,79 +13,24 @@ class ARM_DynCom final : virtual public ARM_Interface { public: - ARM_DynCom(); ~ARM_DynCom(); - /** - * Set the Program Counter to an address - * @param pc Address to set PC to - */ void SetPC(u32 pc) override; - - /* - * Get the current Program Counter - * @return Returns current PC - */ u32 GetPC() const override; - - /** - * Get an ARM register - * @param index Register index (0-15) - * @return Returns the value in the register - */ u32 GetReg(int index) const override; - - /** - * Set an ARM register - * @param index Register index (0-15) - * @param value Value to set register to - */ void SetReg(int index, u32 value) override; - - /** - * Get the current CPSR register - * @return Returns the value of the CPSR register - */ u32 GetCPSR() const override; - - /** - * Set the current CPSR register - * @param cpsr Value to set CPSR to - */ void SetCPSR(u32 cpsr) override; - /** - * Returns the number of clock ticks since the last reset - * @return Returns number of clock ticks - */ u64 GetTicks() const override; - - /** - * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time) - * @param ticks Number of ticks to advance the CPU core - */ void AddTicks(u64 ticks) override; - /** - * Saves the current CPU context - * @param ctx Thread context to save - */ + void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg); void SaveContext(Core::ThreadContext& ctx) override; - - /** - * Loads a CPU context - * @param ctx Thread context to load - */ void LoadContext(const Core::ThreadContext& ctx) override; - /// Prepare core for thread reschedule (if needed to correctly handle state) void PrepareReschedule() override; - - /** - * Executes the given number of instructions - * @param num_instructions Number of instructions to executes - */ void ExecuteInstructions(int num_instructions) override; private: diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 4e569fd9a..c91943f24 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -34,10 +34,6 @@ enum { THUMB = (1 << 7) }; -#undef BITS -#undef BIT -#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) -#define BIT(s, n) ((s >> (n)) & 1) #define RM BITS(sht_oper, 0, 3) #define RS BITS(sht_oper, 8, 11) @@ -48,10 +44,6 @@ enum { #define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) #define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32) -#define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) ) - -extern void switch_mode(arm_core_t *core, uint32_t mode); - typedef arm_core_t arm_processor; typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper); @@ -231,45 +223,6 @@ unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_ope return shifter_operand; } -typedef struct _MiscImmeData { - unsigned int U; - unsigned int Rn; - unsigned int offset_8; -} MiscLSData; - -typedef struct _MiscRegData { - unsigned int U; - unsigned int Rn; - unsigned int Rm; -} MiscRegData; - -typedef struct _MiscImmePreIdx { - unsigned int offset_8; - unsigned int U; - unsigned int Rn; -} MiscImmePreIdx; - -typedef struct _MiscRegPreIdx { - unsigned int U; - unsigned int Rn; - unsigned int Rm; -} MiscRegPreIdx; - -typedef struct _MiscImmePstIdx { - unsigned int offset_8; - unsigned int U; - unsigned int Rn; -} MIscImmePstIdx; - -typedef struct _MiscRegPstIdx { - unsigned int Rn; - unsigned int Rm; - unsigned int U; -} MiscRegPstIdx; - -typedef struct _LSWordorUnsignedByte { -} LDnST; - typedef void (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int rw); typedef struct _ldst_inst { @@ -279,8 +232,9 @@ typedef struct _ldst_inst { #define DEBUG_MSG LOG_DEBUG(Core_ARM11, "inst is %x", inst); CITRA_IGNORE_EXIT(0) int CondPassed(arm_processor *cpu, unsigned int cond); -#define LnSWoUB(s) glue(LnSWoUB, s) -#define MLnS(s) glue(MLnS, s) + +#define LnSWoUB(s) glue(LnSWoUB, s) +#define MLnS(s) glue(MLnS, s) #define LdnStM(s) glue(LdnStM, s) #define W_BIT BIT(inst, 21) @@ -3557,7 +3511,6 @@ static tdstate decode_thumb_instr(arm_processor *cpu, uint32_t inst, addr_t addr case 26: case 27: if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ - u32 cond = (tinstr & 0x0F00) >> 8; inst_index = table_length - 4; *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); } else { @@ -3697,6 +3650,9 @@ static bool InAPrivilegedMode(arm_core_t *core) { } unsigned InterpreterMainLoop(ARMul_State* state) { + #undef RM + #undef RS + #define CRn inst_cream->crn #define OPCODE_2 inst_cream->opcode_2 #define CRm inst_cream->crm @@ -4769,20 +4725,20 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (inst_cream->cp_num == 15) { if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { CP15_REG(CP15_MAIN_ID) = RD; + } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) { + CP15_REG(CP15_CONTROL) = RD; } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { CP15_REG(CP15_AUXILIARY_CONTROL) = RD; } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD; - } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) { - CP15_REG(CP15_CONTROL) = RD; - } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { - CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD; } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD; } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD; } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD; + } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { + CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD; } else if(CRn == MMU_CACHE_OPS){ //LOG_WARNING(Core_ARM11, "cache operations have not implemented."); } else if(CRn == MMU_TLB_OPS){ @@ -4837,12 +4793,18 @@ unsigned InterpreterMainLoop(ARMul_State* state) { break; } } else if(CRn == MMU_PID) { - if(OPCODE_2 == 0) + if(OPCODE_2 == 0) { CP15_REG(CP15_PID) = RD; - else if(OPCODE_2 == 1) + } else if(OPCODE_2 == 1) { CP15_REG(CP15_CONTEXT_ID) = RD; - else if(OPCODE_2 == 3) { - CP15_REG(CP15_THREAD_URO) = RD; + } else if (OPCODE_2 == 2) { + CP15_REG(CP15_THREAD_UPRW) = RD; + } else if(OPCODE_2 == 3) { + if (InAPrivilegedMode(cpu)) + CP15_REG(CP15_THREAD_URO) = RD; + } else if (OPCODE_2 == 4) { + if (InAPrivilegedMode(cpu)) + CP15_REG(CP15_THREAD_PRW) = RD; } else { LOG_ERROR(Core_ARM11, "mmu_mcr wrote UNKNOWN - reg %d", CRn); } @@ -4930,31 +4892,40 @@ unsigned InterpreterMainLoop(ARMul_State* state) { if (inst_cream->cp_num == 15) { if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { RD = cpu->CP15[CP15(CP15_MAIN_ID)]; + } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) { + RD = cpu->CP15[CP15(CP15_CACHE_TYPE)]; } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) { RD = cpu->CP15[CP15(CP15_CONTROL)]; } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)]; } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)]; - } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)]; + } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { + RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)]; + } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { + RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)]; + } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { + RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) { RD = cpu->CP15[CP15(CP15_FAULT_STATUS)]; - } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) { - RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; - } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) { - RD = cpu->CP15[CP15(CP15_CACHE_TYPE)]; } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) { RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)]; + } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) { + RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; } else if (CRn == 13) { - if(OPCODE_2 == 0) + if(OPCODE_2 == 0) { RD = CP15_REG(CP15_PID); - else if(OPCODE_2 == 1) + } else if(OPCODE_2 == 1) { RD = CP15_REG(CP15_CONTEXT_ID); - else if(OPCODE_2 == 3) { + } else if (OPCODE_2 == 2) { + RD = CP15_REG(CP15_THREAD_UPRW); + } else if(OPCODE_2 == 3) { RD = Memory::KERNEL_MEMORY_VADDR; + } else if (OPCODE_2 == 4) { + if (InAPrivilegedMode(cpu)) + RD = CP15_REG(CP15_THREAD_PRW); } else { LOG_ERROR(Core_ARM11, "mmu_mrr wrote UNKNOWN - reg %d", CRn); } @@ -5003,7 +4974,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) { } uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0) | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); - uint32_t mask; + uint32_t mask = 0; if (!inst_cream->R) { if (InAPrivilegedMode(cpu)) { if ((operand & StateMask) != 0) { diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp index de70ca8ae..d5a698365 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp @@ -48,7 +48,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t case 3: // ADD/SUB { - ARMword subset[4] = { + static const ARMword subset[4] = { 0xE0900000, // ADDS Rd,Rs,Rn 0xE0500000, // SUBS Rd,Rs,Rn 0xE2900000, // ADDS Rd,Rs,#imm3 @@ -67,7 +67,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t case 6: // ADD case 7: // SUB { - ARMword subset[4] = { + static const ARMword subset[4] = { 0xE3B00000, // MOVS Rd,#imm8 0xE3500000, // CMP Rd,#imm8 0xE2900000, // ADDS Rd,Rd,#imm8 @@ -95,7 +95,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t t_mul }; - struct { + static const struct { ARMword opcode; otype type; } subset[16] = { @@ -205,7 +205,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t // merged into a single subset, saving on the following boolean: if ((tinstr & (1 << 9)) == 0) { - ARMword subset[4] = { + static const ARMword subset[4] = { 0xE7800000, // STR Rd,[Rb,Ro] 0xE7C00000, // STRB Rd,[Rb,Ro] 0xE7900000, // LDR Rd,[Rb,Ro] @@ -218,7 +218,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t |((tinstr & 0x01C0) >> 6); // Ro } else { - ARMword subset[4] = { + static const ARMword subset[4] = { 0xE18000B0, // STRH Rd,[Rb,Ro] 0xE19000D0, // LDRSB Rd,[Rb,Ro] 0xE19000B0, // LDRH Rd,[Rb,Ro] @@ -236,7 +236,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t case 14: // STRB Rd,[Rb,#imm5] case 15: // LDRB Rd,[Rb,#imm5] { - ARMword subset[4] = { + static const ARMword subset[4] = { 0xE5800000, // STR Rd,[Rb,#imm5] 0xE5900000, // LDR Rd,[Rb,#imm5] 0xE5C00000, // STRB Rd,[Rb,#imm5] @@ -300,7 +300,7 @@ tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t } else if ((tinstr & 0x0F00) == 0x0e00) *ainstr = 0xEF000000 | SWI_Breakpoint; else { - ARMword subset[4] = { + static const ARMword subset[4] = { 0xE92D0000, // STMDB sp!,{rlist} 0xE92D4000, // STMDB sp!,{rlist,lr} 0xE8BD0000, // LDMIA sp!,{rlist} diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp deleted file mode 100644 index c76d371a2..000000000 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/arm/interpreter/arm_interpreter.h" - -#include "core/core.h" - -const static cpu_config_t arm11_cpu_info = { - "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE -}; - -ARM_Interpreter::ARM_Interpreter() { - state = new ARMul_State; - - ARMul_EmulateInit(); - memset(state, 0, sizeof(ARMul_State)); - - ARMul_NewState(state); - - state->abort_model = 0; - state->cpu = (cpu_config_t*)&arm11_cpu_info; - state->bigendSig = LOW; - - ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); - state->lateabtSig = LOW; - - // Reset the core to initial state - ARMul_CoProInit(state); - ARMul_Reset(state); - state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext - state->Emulate = 3; - - state->pc = state->Reg[15] = 0x00000000; - state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack - state->servaddr = 0xFFFF0000; -} - -ARM_Interpreter::~ARM_Interpreter() { - delete state; -} - -void ARM_Interpreter::SetPC(u32 pc) { - state->pc = state->Reg[15] = pc; -} - -u32 ARM_Interpreter::GetPC() const { - return state->pc; -} - -u32 ARM_Interpreter::GetReg(int index) const { - return state->Reg[index]; -} - -void ARM_Interpreter::SetReg(int index, u32 value) { - state->Reg[index] = value; -} - -u32 ARM_Interpreter::GetCPSR() const { - return state->Cpsr; -} - -void ARM_Interpreter::SetCPSR(u32 cpsr) { - state->Cpsr = cpsr; -} - -u64 ARM_Interpreter::GetTicks() const { - return state->NumInstrs; -} - -void ARM_Interpreter::AddTicks(u64 ticks) { - state->NumInstrs += ticks; -} - -void ARM_Interpreter::ExecuteInstructions(int num_instructions) { - state->NumInstrsToExecute = num_instructions - 1; - ARMul_Emulate32(state); -} - -void ARM_Interpreter::SaveContext(Core::ThreadContext& ctx) { - memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); - memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); - - ctx.sp = state->Reg[13]; - ctx.lr = state->Reg[14]; - ctx.pc = state->pc; - ctx.cpsr = state->Cpsr; - - ctx.fpscr = state->VFP[1]; - ctx.fpexc = state->VFP[2]; - - ctx.reg_15 = state->Reg[15]; - ctx.mode = state->NextInstr; -} - -void ARM_Interpreter::LoadContext(const Core::ThreadContext& ctx) { - memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); - memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); - - state->Reg[13] = ctx.sp; - state->Reg[14] = ctx.lr; - state->pc = ctx.pc; - state->Cpsr = ctx.cpsr; - - state->VFP[1] = ctx.fpscr; - state->VFP[2] = ctx.fpexc; - - state->Reg[15] = ctx.reg_15; - state->NextInstr = ctx.mode; -} - -void ARM_Interpreter::PrepareReschedule() { - state->NumInstrsToExecute = 0; -} diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h deleted file mode 100644 index e5ecc69c2..000000000 --- a/src/core/arm/interpreter/arm_interpreter.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common.h" - -#include "core/arm/arm_interface.h" -#include "core/arm/skyeye_common/armdefs.h" -#include "core/arm/skyeye_common/armemu.h" - -class ARM_Interpreter final : virtual public ARM_Interface { -public: - - ARM_Interpreter(); - ~ARM_Interpreter(); - - /** - * Set the Program Counter to an address - * @param pc Address to set PC to - */ - void SetPC(u32 pc) override; - - /* - * Get the current Program Counter - * @return Returns current PC - */ - u32 GetPC() const override; - - /** - * Get an ARM register - * @param index Register index (0-15) - * @return Returns the value in the register - */ - u32 GetReg(int index) const override; - - /** - * Set an ARM register - * @param index Register index (0-15) - * @param value Value to set register to - */ - void SetReg(int index, u32 value) override; - - /** - * Get the current CPSR register - * @return Returns the value of the CPSR register - */ - u32 GetCPSR() const override; - - /** - * Set the current CPSR register - * @param cpsr Value to set CPSR to - */ - void SetCPSR(u32 cpsr) override; - - /** - * Returns the number of clock ticks since the last reset - * @return Returns number of clock ticks - */ - u64 GetTicks() const override; - - /** - * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time) - * @param ticks Number of ticks to advance the CPU core - */ - void AddTicks(u64 ticks) override; - - /** - * Saves the current CPU context - * @param ctx Thread context to save - */ - void SaveContext(Core::ThreadContext& ctx) override; - - /** - * Loads a CPU context - * @param ctx Thread context to load - */ - void LoadContext(const Core::ThreadContext& ctx) override; - - /// Prepare core for thread reschedule (if needed to correctly handle state) - void PrepareReschedule() override; - -protected: - - /** - * Executes the given number of instructions - * @param num_instructions Number of instructions to executes - */ - void ExecuteInstructions(int num_instructions) override; - -private: - - ARMul_State* state; - -}; diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp index b4ddc3d96..4ae0c52e4 100644 --- a/src/core/arm/interpreter/armcopro.cpp +++ b/src/core/arm/interpreter/armcopro.cpp @@ -19,213 +19,45 @@ #include "core/arm/skyeye_common/armemu.h" #include "core/arm/skyeye_common/vfp/vfp.h" -//chy 2005-07-08 -//#include "ansidecl.h" -//chy ------- -//#include "iwmmxt.h" +// Dummy Co-processors. -/* Dummy Co-processors. */ - -static unsigned -NoCoPro3R(ARMul_State * state, -unsigned a, ARMword b) +static unsigned int NoCoPro3R(ARMul_State* state, unsigned int a, ARMword b) { return ARMul_CANT; } -static unsigned -NoCoPro4R(ARMul_State * state, -unsigned a, -ARMword b, ARMword c) +static unsigned int NoCoPro4R(ARMul_State* state, unsigned int a, ARMword b, ARMword c) { return ARMul_CANT; } -static unsigned -NoCoPro4W(ARMul_State * state, -unsigned a, -ARMword b, ARMword * c) +static unsigned int NoCoPro4W(ARMul_State* state, unsigned int a, ARMword b, ARMword* c) { return ARMul_CANT; } -static unsigned -NoCoPro5R(ARMul_State * state, -unsigned a, -ARMword b, -ARMword c, ARMword d) +static unsigned int NoCoPro5R(ARMul_State* state, unsigned int a, ARMword b, ARMword c, ARMword d) { return ARMul_CANT; } -static unsigned -NoCoPro5W(ARMul_State * state, -unsigned a, -ARMword b, -ARMword * c, ARMword * d) +static unsigned int NoCoPro5W(ARMul_State* state, unsigned int a, ARMword b, ARMword* c, ARMword* d) { return ARMul_CANT; } -/* The XScale Co-processors. */ - -/* Coprocessor 15: System Control. */ -static void write_cp14_reg(unsigned, ARMword); -static ARMword read_cp14_reg(unsigned); - -/* Check an access to a register. */ - -static unsigned -check_cp15_access(ARMul_State * state, -unsigned reg, -unsigned CRm, unsigned opcode_1, unsigned opcode_2) -{ - /* Do not allow access to these register in USER mode. */ - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode == USER26MODE || state->Mode == USER32MODE) - return ARMul_CANT; - - /* Opcode_1should be zero. */ - if (opcode_1 != 0) - return ARMul_CANT; - - /* Different register have different access requirements. */ - switch (reg) { - case 0: - case 1: - /* CRm must be 0. Opcode_2 can be anything. */ - if (CRm != 0) - return ARMul_CANT; - break; - case 2: - case 3: - /* CRm must be 0. Opcode_2 must be zero. */ - if ((CRm != 0) || (opcode_2 != 0)) - return ARMul_CANT; - break; - case 4: - /* Access not allowed. */ - return ARMul_CANT; - case 5: - case 6: - /* Opcode_2 must be zero. CRm must be 0. */ - if ((CRm != 0) || (opcode_2 != 0)) - return ARMul_CANT; - break; - case 7: - /* Permissable combinations: - Opcode_2 CRm - 0 5 - 0 6 - 0 7 - 1 5 - 1 6 - 1 10 - 4 10 - 5 2 - 6 5 */ - switch (opcode_2) { - default: - return ARMul_CANT; - case 6: - if (CRm != 5) - return ARMul_CANT; - break; - case 5: - if (CRm != 2) - return ARMul_CANT; - break; - case 4: - if (CRm != 10) - return ARMul_CANT; - break; - case 1: - if ((CRm != 5) && (CRm != 6) && (CRm != 10)) - return ARMul_CANT; - break; - case 0: - if ((CRm < 5) || (CRm > 7)) - return ARMul_CANT; - break; - } - break; - - case 8: - /* Permissable combinations: - Opcode_2 CRm - 0 5 - 0 6 - 0 7 - 1 5 - 1 6 */ - if (opcode_2 > 1) - return ARMul_CANT; - if ((CRm < 5) || (CRm > 7)) - return ARMul_CANT; - if (opcode_2 == 1 && CRm == 7) - return ARMul_CANT; - break; - case 9: - /* Opcode_2 must be zero or one. CRm must be 1 or 2. */ - if (((CRm != 0) && (CRm != 1)) - || ((opcode_2 != 1) && (opcode_2 != 2))) - return ARMul_CANT; - break; - case 10: - /* Opcode_2 must be zero or one. CRm must be 4 or 8. */ - if (((CRm != 0) && (CRm != 1)) - || ((opcode_2 != 4) && (opcode_2 != 8))) - return ARMul_CANT; - break; - case 11: - /* Access not allowed. */ - return ARMul_CANT; - case 12: - /* Access not allowed. */ - return ARMul_CANT; - case 13: - /* Opcode_2 must be zero. CRm must be 0. */ - if ((CRm != 0) || (opcode_2 != 0)) - return ARMul_CANT; - break; - case 14: - /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */ - if (opcode_2 != 0) - return ARMul_CANT; - - if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8) - && (CRm != 9)) - return ARMul_CANT; - break; - case 15: - /* Opcode_2 must be zero. CRm must be 1. */ - if ((CRm != 1) || (opcode_2 != 0)) - return ARMul_CANT; - break; - default: - /* Should never happen. */ - return ARMul_CANT; - } - - return ARMul_DONE; -} - -/* Install co-processor instruction handlers in this routine. */ - -unsigned -ARMul_CoProInit(ARMul_State * state) +// Install co-processor instruction handlers in this routine. +void ARMul_CoProInit(ARMul_State* state) { - unsigned int i; - - /* Initialise tham all first. */ - for (i = 0; i < 16; i++) + // Initialise tham all first. + for (unsigned int i = 0; i < 16; i++) ARMul_CoProDetach(state, i); - /* Install CoPro Instruction handlers here. - The format is: - ARMul_CoProAttach (state, CP Number, Init routine, Exit routine - LDC routine, STC routine, MRC routine, MCR routine, - CDP routine, Read Reg routine, Write Reg routine). */ + // Install CoPro Instruction handlers here. + // The format is: + // ARMul_CoProAttach (state, CP Number, Init routine, Exit routine + // LDC routine, STC routine, MRC routine, MCR routine, + // CDP routine, Read Reg routine, Write Reg routine). if (state->is_v6) { ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC, VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); @@ -235,57 +67,43 @@ ARMul_CoProInit(ARMul_State * state) /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/ } - //chy 2003-09-03 do it in future!!!!???? -#if 0 - if (state->is_iWMMXt) { - ARMul_CoProAttach(state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, - NULL, NULL, IwmmxtCDP, NULL, NULL); - ARMul_CoProAttach(state, 1, NULL, NULL, NULL, NULL, - IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, - NULL); - } -#endif - /* No handlers below here. */ + // No handlers below here. - /* Call all the initialisation routines. */ - for (i = 0; i < 16; i++) + // Call all the initialisation routines. + for (unsigned int i = 0; i < 16; i++) { if (state->CPInit[i]) (state->CPInit[i]) (state); - - return TRUE; + } } -/* Install co-processor finalisation routines in this routine. */ - -void -ARMul_CoProExit(ARMul_State * state) +// Install co-processor finalisation routines in this routine. +void ARMul_CoProExit(ARMul_State * state) { - register unsigned i; - - for (i = 0; i < 16; i++) + for (unsigned int i = 0; i < 16; i++) if (state->CPExit[i]) (state->CPExit[i]) (state); - for (i = 0; i < 16; i++) /* Detach all handlers. */ + // Detach all handlers. + for (unsigned int i = 0; i < 16; i++) ARMul_CoProDetach(state, i); } -/* Routines to hook Co-processors into ARMulator. */ +// Routines to hook Co-processors into ARMulator. void -ARMul_CoProAttach(ARMul_State * state, +ARMul_CoProAttach(ARMul_State* state, unsigned number, -ARMul_CPInits * init, -ARMul_CPExits * exit, -ARMul_LDCs * ldc, -ARMul_STCs * stc, -ARMul_MRCs * mrc, -ARMul_MCRs * mcr, -ARMul_MRRCs * mrrc, -ARMul_MCRRs * mcrr, -ARMul_CDPs * cdp, -ARMul_CPReads * read, ARMul_CPWrites * write) +ARMul_CPInits* init, +ARMul_CPExits* exit, +ARMul_LDCs* ldc, +ARMul_STCs* stc, +ARMul_MRCs* mrc, +ARMul_MCRs* mcr, +ARMul_MRRCs* mrrc, +ARMul_MCRRs* mcrr, +ARMul_CDPs* cdp, +ARMul_CPReads* read, ARMul_CPWrites* write) { if (init != NULL) state->CPInit[number] = init; @@ -311,8 +129,7 @@ ARMul_CPReads * read, ARMul_CPWrites * write) state->CPWrite[number] = write; } -void -ARMul_CoProDetach(ARMul_State * state, unsigned number) +void ARMul_CoProDetach(ARMul_State* state, unsigned number) { ARMul_CoProAttach(state, number, NULL, NULL, NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp deleted file mode 100644 index 7114313d6..000000000 --- a/src/core/arm/interpreter/armemu.cpp +++ /dev/null @@ -1,5648 +0,0 @@ -/* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - Modifications to add arch. v4 support by <jsmith@cygnus.com>. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "core/arm/skyeye_common/arm_regformat.h" -#include "core/arm/skyeye_common/armdefs.h" -#include "core/arm/skyeye_common/armemu.h" -#include "core/hle/hle.h" - -static ARMword GetDPRegRHS (ARMul_State *, ARMword); -static ARMword GetDPSRegRHS (ARMul_State *, ARMword); -static void WriteR15 (ARMul_State *, ARMword); -static void WriteSR15 (ARMul_State *, ARMword); -static void WriteR15Branch (ARMul_State *, ARMword); -static ARMword GetLSRegRHS (ARMul_State *, ARMword); -static ARMword GetLS7RHS (ARMul_State *, ARMword); -static unsigned LoadWord (ARMul_State *, ARMword, ARMword); -static unsigned LoadHalfWord (ARMul_State *, ARMword, ARMword, int); -static unsigned LoadByte (ARMul_State *, ARMword, ARMword, int); -static unsigned StoreWord (ARMul_State *, ARMword, ARMword); -static unsigned StoreHalfWord (ARMul_State *, ARMword, ARMword); -static unsigned StoreByte (ARMul_State *, ARMword, ARMword); -static void LoadMult (ARMul_State *, ARMword, ARMword, ARMword); -static void StoreMult (ARMul_State *, ARMword, ARMword, ARMword); -static void LoadSMult (ARMul_State *, ARMword, ARMword, ARMword); -static void StoreSMult (ARMul_State *, ARMword, ARMword, ARMword); -static unsigned Multiply64 (ARMul_State *, ARMword, int, int); -static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int); -static void Handle_Load_Double (ARMul_State *, ARMword); -static void Handle_Store_Double (ARMul_State *, ARMword); - -static int handle_v6_insn (ARMul_State * state, ARMword instr); - -#define LUNSIGNED (0) /* unsigned operation */ -#define LSIGNED (1) /* signed operation */ -#define LDEFAULT (0) /* default : do nothing */ -#define LSCC (1) /* set condition codes on result */ - -/* Short-hand macros for LDR/STR. */ - -/* Store post decrement writeback. */ -#define SHDOWNWB() \ - lhs = LHS ; \ - if (StoreHalfWord (state, instr, lhs)) \ - LSBase = lhs - GetLS7RHS (state, instr); - -/* Store post increment writeback. */ -#define SHUPWB() \ - lhs = LHS ; \ - if (StoreHalfWord (state, instr, lhs)) \ - LSBase = lhs + GetLS7RHS (state, instr); - -/* Store pre decrement. */ -#define SHPREDOWN() \ - (void)StoreHalfWord (state, instr, LHS - GetLS7RHS (state, instr)); - -/* Store pre decrement writeback. */ -#define SHPREDOWNWB() \ - temp = LHS - GetLS7RHS (state, instr); \ - if (StoreHalfWord (state, instr, temp)) \ - LSBase = temp; - -/* Store pre increment. */ -#define SHPREUP() \ - (void)StoreHalfWord (state, instr, LHS + GetLS7RHS (state, instr)); - -/* Store pre increment writeback. */ -#define SHPREUPWB() \ - temp = LHS + GetLS7RHS (state, instr); \ - if (StoreHalfWord (state, instr, temp)) \ - LSBase = temp; - -/* Load post decrement writeback. */ -#define LHPOSTDOWN() \ -{ \ - int done = 1; \ - lhs = LHS; \ - temp = lhs - GetLS7RHS (state, instr); \ - \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load post increment writeback. */ -#define LHPOSTUP() \ -{ \ - int done = 1; \ - lhs = LHS; \ - temp = lhs + GetLS7RHS (state, instr); \ - \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, lhs, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre decrement. */ -#define LHPREDOWN() \ -{ \ - int done = 1; \ - \ - temp = LHS - GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \ - break; \ - case 2: /* SB */ \ - (void) LoadByte (state, instr, temp, LSIGNED); \ - break; \ - case 3: /* SH */ \ - (void) LoadHalfWord (state, instr, temp, LSIGNED); \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre decrement writeback. */ -#define LHPREDOWNWB() \ -{ \ - int done = 1; \ - \ - temp = LHS - GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre increment. */ -#define LHPREUP() \ -{ \ - int done = 1; \ - \ - temp = LHS + GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \ - break; \ - case 2: /* SB */ \ - (void) LoadByte (state, instr, temp, LSIGNED); \ - break; \ - case 3: /* SH */ \ - (void) LoadHalfWord (state, instr, temp, LSIGNED); \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* Load pre increment writeback. */ -#define LHPREUPWB() \ -{ \ - int done = 1; \ - \ - temp = LHS + GetLS7RHS (state, instr); \ - switch (BITS (5, 6)) \ - { \ - case 1: /* H */ \ - if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \ - LSBase = temp; \ - break; \ - case 2: /* SB */ \ - if (LoadByte (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 3: /* SH */ \ - if (LoadHalfWord (state, instr, temp, LSIGNED)) \ - LSBase = temp; \ - break; \ - case 0: \ - /* SWP handled elsewhere. */ \ - default: \ - done = 0; \ - break; \ - } \ - if (done) \ - break; \ -} - -/* EMULATION of ARM6. */ - -int ARMul_ICE_debug(ARMul_State *state,ARMword instr,ARMword addr); -#ifdef MODE32 -//chy 2006-04-12, for ICE debug -int ARMul_ICE_debug(ARMul_State *state,ARMword instr,ARMword addr) -{ - return 0; -} - -ARMword ARMul_Debug(ARMul_State * state, ARMword pc, ARMword instr) -{ - return 0; -} - -ARMword ARMul_Emulate32(ARMul_State* state) -#else -ARMword ARMul_Emulate26(ARMul_State* state) -#endif -{ - /* The PC pipeline value depends on whether ARM - or Thumb instructions are being - d. */ - ARMword isize; - ARMword instr; /* The current instruction. */ - ARMword dest = 0; /* Almost the DestBus. */ - ARMword temp; /* Ubiquitous third hand. */ - ARMword pc = 0; /* The address of the current instruction. */ - ARMword lhs; /* Almost the ABus and BBus. */ - ARMword rhs; - ARMword decoded = 0; /* Instruction pipeline. */ - ARMword loaded = 0; - ARMword decoded_addr=0; - ARMword loaded_addr=0; - ARMword have_bp=0; - - /* Execute the next instruction. */ - if (state->NextInstr < PRIMEPIPE) { - decoded = state->decoded; - loaded = state->loaded; - pc = state->pc; - //chy 2006-04-12, for ICE debug - decoded_addr=state->decoded_addr; - loaded_addr=state->loaded_addr; - } - - do { - //print_func_name(state->pc); - /* Just keep going. */ - isize = INSN_SIZE; - - switch (state->NextInstr) { - case SEQ: - /* Advance the pipeline, and an S cycle. */ - state->Reg[15] += isize; - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp = ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrS (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - if (have_bp) goto TEST_EMULATE; - break; - - case NONSEQ: - /* Advance the pipeline, and an N cycle. */ - state->Reg[15] += isize; - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrN (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - case PCINCEDSEQ: - /* Program counter advanced, and an S cycle. */ - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrS (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - case PCINCEDNONSEQ: - /* Program counter advanced, and an N cycle. */ - pc += isize; - instr = decoded; - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,decoded_addr); - decoded = loaded; - decoded_addr=loaded_addr; - //loaded = ARMul_LoadInstrN (state, pc + (isize * 2), - // isize); - loaded_addr=pc + (isize * 2); - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - case RESUME: - /* The program counter has been changed. */ - pc = state->Reg[15]; -#ifndef MODE32 - pc = pc & R15PCBITS; -#endif - state->Reg[15] = pc + (isize * 2); - state->Aborted = 0; - //chy 2004-05-25, fix bug provided by Carl van Schaik<cvansch@cse.unsw.EDU.AU> - state->AbortAddr = 1; - - instr = ARMul_LoadInstrN (state, pc, isize); - //instr = ARMul_ReLoadInstr (state, pc, isize); - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,pc); - //decoded = - // ARMul_ReLoadInstr (state, pc + isize, isize); - decoded_addr=pc+isize; - //loaded = ARMul_ReLoadInstr (state, pc + isize * 2, - // isize); - loaded_addr=pc + isize * 2; - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - - default: - /* The program counter has been changed. */ - pc = state->Reg[15]; -#ifndef MODE32 - pc = pc & R15PCBITS; -#endif - state->Reg[15] = pc + (isize * 2); - state->Aborted = 0; - //chy 2004-05-25, fix bug provided by Carl van Schaik<cvansch@cse.unsw.EDU.AU> - state->AbortAddr = 1; - - instr = ARMul_LoadInstrN (state, pc, isize); - - //chy 2006-04-12, for ICE debug - have_bp=ARMul_ICE_debug(state,instr,pc); - - decoded_addr=pc+isize; - - loaded_addr=pc + isize * 2; - NORMALCYCLE; - if (have_bp) goto TEST_EMULATE; - break; - } - - instr = ARMul_LoadInstrN (state, pc, isize); - state->last_instr = state->CurrInstr; - state->CurrInstr = instr; - ARMul_Debug(state, pc, instr); - - /* Any exceptions ? */ - if (state->NresetSig == LOW) { - ARMul_Abort (state, ARMul_ResetV); - break; - } else if (!state->NfiqSig && !FFLAG) { - ARMul_Abort (state, ARMul_FIQV); - break; - } else if (!state->NirqSig && !IFLAG) { - ARMul_Abort (state, ARMul_IRQV); - break; - } - - if (state->Emulate < ONCE) { - state->NextInstr = RESUME; - break; - } - - state->NumInstrs++; - -#ifdef MODET - /* Provide Thumb instruction decoding. If the processor is in Thumb - mode, then we can simply decode the Thumb instruction, and map it - to the corresponding ARM instruction (by directly loading the - instr variable, and letting the normal ARM simulator - execute). There are some caveats to ensure that the correct - pipelined PC value is used when executing Thumb code, and also for - dealing with the BL instruction. */ - if (TFLAG) { - ARMword armOp = 0; - /* Check if in Thumb mode. */ - switch (ARMul_ThumbDecode(state, pc, instr, &armOp)) { - case t_undefined: - /* This is a Thumb instruction. */ - ARMul_UndefInstr (state, instr); - goto donext; - - case t_branch: - /* Already processed. */ - //pc = state->Reg[15] - 2; - //state->pc = state->Reg[15] - 2; //ichfly why do I need that - goto donext; - - case t_decoded: - /* ARM instruction available. */ - //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); - - if (armOp == 0xDEADC0DE) { - LOG_ERROR(Core_ARM11, "Failed to decode thumb opcode %04X at %08X", instr, pc); - } - - instr = armOp; - - /* So continue instruction decoding. */ - break; - default: - break; - } - } -#endif - /* Check the condition codes. */ - if ((temp = TOPBITS (28)) == AL) { - /* Vile deed in the need for speed. */ - goto mainswitch; - } - - /* Check the condition code. */ - switch ((int) TOPBITS (28)) { - case AL: - temp = TRUE; - break; - case NV: - - /* shenoubang add for armv7 instr dmb 2012-3-11 */ - if (state->is_v7) { - if ((instr & 0x0fffff00) == 0x057ff000) { - switch((instr >> 4) & 0xf) { - case 4: /* dsb */ - case 5: /* dmb */ - case 6: /* isb */ - // TODO: do no implemented thes instr - goto donext; - } - } - } - /* dyf add for armv6 instruct CPS 2010.9.17 */ - if (state->is_v6) { - /* clrex do nothing here temporary */ - if (instr == 0xf57ff01f) { - //printf("clrex \n"); - /* shenoubang 2012-3-14 refer the dyncom_interpreter */ - state->exclusive_tag_array[0] = 0xFFFFFFFF; - state->exclusive_access_state = 0; - goto donext; - } - - if (BITS(20, 27) == 0x10) { - if (BIT(19)) { - if (BIT(8)) { - if (BIT(18)) - state->Cpsr |= 1<<8; - else - state->Cpsr &= ~(1<<8); - } - if (BIT(7)) { - if (BIT(18)) - state->Cpsr |= 1<<7; - else - state->Cpsr &= ~(1<<7); - ASSIGNINT (state->Cpsr & INTBITS); - } - if (BIT(6)) { - if (BIT(18)) - state->Cpsr |= 1<<6; - else - state->Cpsr &= ~(1<<6); - ASSIGNINT (state->Cpsr & INTBITS); - } - } - if (BIT(17)) { - state->Cpsr |= BITS(0, 4); - printf("skyeye test state->Mode\n"); - if (state->Mode != (state->Cpsr & MODEBITS)) { - state->Mode = ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS); - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - } - } - goto donext; - } - } - if (state->is_v5) { - if (BITS (25, 27) == 5) { /* BLX(1) */ - ARMword dest; - - state->Reg[14] = pc + 4; - - /* Force entry into Thumb mode. */ - dest = pc + 8 + 1; - if (BIT (23)) - dest += (NEGBRANCH + - (BIT (24) << 1)); - else - dest += POSBRANCH + - (BIT (24) << 1); - - WriteR15Branch (state, dest); - goto donext; - } else if ((instr & 0xFC70F000) == 0xF450F000) { - /* The PLD instruction. Ignored. */ - goto donext; - } else if (((instr & 0xfe500f00) == 0xfc100100) - || ((instr & 0xfe500f00) == - 0xfc000100)) { - /* wldrw and wstrw are unconditional. */ - goto mainswitch; - } else { - /* UNDEFINED in v5, UNPREDICTABLE in v3, v4, non executed in v1, v2. */ - ARMul_UndefInstr (state, instr); - } - } - temp = FALSE; - break; - case EQ: - temp = ZFLAG; - break; - case NE: - temp = !ZFLAG; - break; - case VS: - temp = VFLAG; - break; - case VC: - temp = !VFLAG; - break; - case MI: - temp = NFLAG; - break; - case PL: - temp = !NFLAG; - break; - case CS: - temp = CFLAG; - break; - case CC: - temp = !CFLAG; - break; - case HI: - temp = (CFLAG && !ZFLAG); - break; - case LS: - temp = (!CFLAG || ZFLAG); - break; - case GE: - temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); - break; - case LT: - temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); - break; - case GT: - temp = ((!NFLAG && !VFLAG && !ZFLAG) - || (NFLAG && VFLAG && !ZFLAG)); - break; - case LE: - temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) - || ZFLAG; - break; - } /* cc check */ - -//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... - - /* Actual execution of instructions begins here. */ - /* If the condition codes don't match, stop here. */ - if (temp) { -mainswitch: - - /* shenoubang sbfx and ubfx instr 2012-3-16 */ - if (state->is_v6) { - unsigned int m, lsb, width, Rd, Rn, data; - Rd = Rn = lsb = width = data = m = 0; - - //printf("helloworld\n"); - if ((((int) BITS (21, 27)) == 0x3f) && (((int) BITS (4, 6)) == 0x5)) { - m = (unsigned)BITS(7, 11); - width = (unsigned)BITS(16, 20); - Rd = (unsigned)BITS(12, 15); - Rn = (unsigned)BITS(0, 3); - if ((Rd == 15) || (Rn == 15)) { - ARMul_UndefInstr (state, instr); - } else if ((m + width) < 32) { - data = state->Reg[Rn]; - state->Reg[Rd] ^= state->Reg[Rd]; - state->Reg[Rd] = ((ARMword)(data << (31 -(m + width))) >> ((31 - (m + width)) + (m))); - //SKYEYE_LOG_IN_CLR(RED, "UBFX: In %s, line = %d, Reg_src[%d] = 0x%x, Reg_d[%d] = 0x%x, m = %d, width = %d, Rd = %d, Rn = %d\n", - // __FUNCTION__, __LINE__, Rn, data, Rd, state->Reg[Rd], m, width + 1, Rd, Rn); - goto donext; - } - } // ubfx instr - else if ((((int) BITS (21, 27)) == 0x3d) && (((int) BITS (4, 6)) == 0x5)) { - int tmp = 0; - Rd = BITS(12, 15); - Rn = BITS(0, 3); - lsb = BITS(7, 11); - width = BITS(16, 20); - if ((Rd == 15) || (Rn == 15)) { - ARMul_UndefInstr (state, instr); - } else if ((lsb + width) < 32) { - state->Reg[Rd] ^= state->Reg[Rd]; - data = state->Reg[Rn]; - tmp = (data << (32 - (lsb + width + 1))); - state->Reg[Rd] = (tmp >> (32 - (lsb + width + 1))); - //SKYEYE_LOG_IN_CLR(RED, "sbfx: In %s, line = %d, pc = 0x%x, instr = 0x%x,Rd = 0x%x, Rn = 0x%x, lsb = %d, width = %d, Rs[%d] = 0x%x, Rd[%d] = 0x%x\n", - // __func__, __LINE__, pc, instr, Rd, Rn, lsb, width + 1, Rn, state->Reg[Rn], Rd, state->Reg[Rd]); - goto donext; - } - } // sbfx instr - else if ((((int)BITS(21, 27)) == 0x3e) && ((int)BITS(4, 6) == 0x1)) { - //(ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) - unsigned msb ,tmp_rn, tmp_rd, dst; - tmp_rd = tmp_rn = dst = 0; - Rd = BITS(12, 15); - Rn = BITS(0, 3); - lsb = BITS(7, 11); - msb = BITS(16, 20); //-V519 - if (Rd == 15) { - ARMul_UndefInstr (state, instr); - } else if (Rn == 15) { - data = state->Reg[Rd]; - tmp_rd = ((ARMword)(data << (31 - lsb)) >> (31 - lsb)); - dst = ((data >> msb) << (msb - lsb)); - dst = (dst << lsb) | tmp_rd; - goto donext; - } // bfc instr - else if (((msb >= lsb) && (msb < 32))) { - data = state->Reg[Rn]; - tmp_rn = ((ARMword)(data << (31 - (msb - lsb))) >> (31 - (msb - lsb))); - data = state->Reg[Rd]; - tmp_rd = ((ARMword)(data << (31 - lsb)) >> (31 - lsb)); - dst = ((data >> msb) << (msb - lsb)) | tmp_rn; - dst = (dst << lsb) | tmp_rd; - goto donext; - } // bfi instr - } - } - - switch ((int) BITS (20, 27)) { - /* Data Processing Register RHS Instructions. */ - - case 0x00: /* AND reg and MUL */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, down, post indexed. */ - SHDOWNWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (BITS (4, 7) == 9) { - /* MUL */ - rhs = state->Reg[MULRHSReg]; - //if (MULLHSReg == MULDESTReg) { - if(0) { /* For armv6, the restriction is removed */ - UNDEF_MULDestEQOp1; - state->Reg[MULDESTReg] = 0; - } else if (MULDESTReg != 15) - state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs; - else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, ARMul_MultTable[temp], 0L); - } else { - /* AND reg. */ - rhs = DPRegRHS; - dest = LHS & rhs; - WRITEDEST (dest); - } - break; - - case 0x01: /* ANDS reg and MULS */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, down, post indexed. */ - LHPOSTDOWN (); - /* Fall through to rest of decoding. */ -#endif - if (BITS (4, 7) == 9) { - /* MULS */ - rhs = state->Reg[MULRHSReg]; - - //if (MULLHSReg == MULDESTReg) { - if(0) { - printf("Something in %d line\n", __LINE__); - UNDEF_WARNING; - UNDEF_MULDestEQOp1; - state->Reg[MULDESTReg] = 0; - CLEARN; - SETZ; - } else if (MULDESTReg != 15) { - dest = state->Reg[MULLHSReg] * rhs; - ARMul_NegZero (state, dest); - state->Reg[MULDESTReg] = dest; - } else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, ARMul_MultTable[temp], 0L); - } else { - /* ANDS reg. */ - rhs = DPSRegRHS; - dest = LHS & rhs; - WRITESDEST (dest); - } - break; - - case 0x02: /* EOR reg and MLA */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, down, post indexed. */ - SHDOWNWB (); - break; - } -#endif - if (BITS (4, 7) == 9) { /* MLA */ - rhs = state->Reg[MULRHSReg]; -#if 0 - if (MULLHSReg == MULDESTReg) { - UNDEF_MULDestEQOp1; - state->Reg[MULDESTReg] = state->Reg[MULACCReg]; - } else if (MULDESTReg != 15) { -#endif - if (MULDESTReg != 15) { - state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg]; - } else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, ARMul_MultTable[temp], 0L); - } else { - rhs = DPRegRHS; - dest = LHS ^ rhs; - WRITEDEST (dest); - } - break; - - case 0x03: /* EORS reg and MLAS */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, down, post-indexed. */ - LHPOSTDOWN (); - /* Fall through to rest of the decoding. */ -#endif - if (BITS (4, 7) == 9) { - /* MLAS */ - rhs = state->Reg[MULRHSReg]; - //if (MULLHSReg == MULDESTReg) { - if (0) { - UNDEF_MULDestEQOp1; - dest = state->Reg[MULACCReg]; - ARMul_NegZero (state, dest); - state->Reg[MULDESTReg] = dest; - } else if (MULDESTReg != 15) { - dest = state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg]; - ARMul_NegZero (state, dest); - state->Reg[MULDESTReg] = dest; - } else - UNDEF_MULPCDest; - - for (dest = 0, temp = 0; dest < 32; - dest++) - if (rhs & (1L << dest)) - temp = dest; - - /* Mult takes this many/2 I cycles. */ - ARMul_Icycles (state, ARMul_MultTable[temp], 0L); - } else { - /* EORS Reg. */ - rhs = DPSRegRHS; - dest = LHS ^ rhs; - WRITESDEST (dest); - } - break; - - case 0x04: /* SUB reg */ - // Signifies UMAAL - if (state->is_v6 && BITS(4, 7) == 0x09) { - if (handle_v6_insn(state, instr)) - break; - } - -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, down, post indexed. */ - SHDOWNWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS - rhs; - WRITEDEST (dest); - break; - - case 0x05: /* SUBS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, no write-back, down, post indexed. */ - LHPOSTDOWN (); - /* Fall through to the rest of the instruction decoding. */ -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs - rhs; - - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, dest); - ARMul_SubOverflow (state, lhs, rhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x06: /* RSB reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, down, post indexed. */ - SHDOWNWB (); - break; - } -#endif - rhs = DPRegRHS; - dest = rhs - LHS; - WRITEDEST (dest); - break; - - case 0x07: /* RSBS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, down, post indexed. */ - LHPOSTDOWN (); - /* Fall through to remainder of instruction decoding. */ -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = rhs - lhs; - - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, dest); - ARMul_SubOverflow (state, rhs, lhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x08: /* ADD reg */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, up, post indexed. */ - SHUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif -#ifdef MODET - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32 = 64 */ - ARMul_Icycles (state, Multiply64 (state, instr, LUNSIGNED, LDEFAULT), 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS + rhs; - WRITEDEST (dest); - break; - - case 0x09: /* ADDS reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, up, post indexed. */ - LHPOSTUP (); - /* Fall through to remaining instruction decoding. */ -#endif -#ifdef MODET - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, Multiply64 (state, instr, LUNSIGNED, LSCC), 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, dest); - ARMul_AddOverflow (state, lhs, rhs, dest); - } else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x0a: /* ADC reg */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, up, post-indexed. */ - SHUPWB (); - break; - } - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, MultiplyAdd64 (state, instr, LUNSIGNED, LDEFAULT), 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS + rhs + CFLAG; - WRITEDEST (dest); - break; - - case 0x0b: /* ADCS reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, up, post indexed. */ - LHPOSTUP (); - /* Fall through to remaining instruction decoding. */ - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, MultiplyAdd64 (state, instr, LUNSIGNED, LSCC), 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs + rhs + CFLAG; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, dest); - ARMul_AddOverflow (state, lhs, rhs, dest); - } else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x0c: /* SBC reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, up post indexed. */ - SHUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, Multiply64 (state, instr, LSIGNED, LDEFAULT), 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS - rhs - !CFLAG; - WRITEDEST (dest); - break; - - case 0x0d: /* SBCS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, no write-back, up, post indexed. */ - LHPOSTUP (); - - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, Multiply64 (state, instr, LSIGNED, LSCC), 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = lhs - rhs - !CFLAG; - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, dest); - ARMul_SubOverflow (state, lhs, rhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x0e: /* RSC reg */ -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, up, post indexed. */ - SHUPWB (); - break; - } - - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, MultiplyAdd64 (state, instr, LSIGNED, LDEFAULT), 0L); - break; - } -#endif - rhs = DPRegRHS; - dest = rhs - LHS - !CFLAG; - WRITEDEST (dest); - break; - - case 0x0f: /* RSCS reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, up, post indexed. */ - LHPOSTUP (); - /* Fall through to remaining instruction decoding. */ - - if (BITS (4, 7) == 0x9) { - /* MULL */ - /* 32x32=64 */ - ARMul_Icycles (state, MultiplyAdd64 (state, instr, LSIGNED, LSCC), 0L); - break; - } -#endif - lhs = LHS; - rhs = DPRegRHS; - dest = rhs - lhs - !CFLAG; - - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, dest); - ARMul_SubOverflow (state, rhs, lhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x10: /* TST reg and MRS CPSR and SWP word. */ - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1) { - /* ElSegundo SMLAxy insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - ARMword op2 = state->Reg[BITS (8, 11)]; - ARMword Rn = state->Reg[BITS (12, 15)]; - - if (BIT (5)) - op1 >>= 16; - if (BIT (6)) - op2 >>= 16; - op1 &= 0xFFFF; - op2 &= 0xFFFF; - if (op1 & 0x8000) - op1 -= 65536; - if (op2 & 0x8000) - op2 -= 65536; - op1 *= op2; - //printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn); - if (AddOverflow(op1, Rn, op1 + Rn)) - SETQ; - state->Reg[BITS (16, 19)] = op1 + Rn; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QADD insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - ARMword op2 = state->Reg[BITS (16, 19)]; - ARMword result = op1 + op2; - if (AddOverflow(op1, op2, result)) { - result = POS (result) ? 0x80000000 : 0x7fffffff; - SETQ; - } - state->Reg[BITS (12, 15)] = result; - break; - } - } -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, down, pre indexed. */ - SHPREDOWN (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (BITS (4, 11) == 9) { - /* SWP */ - UNDEF_SWPPC; - temp = LHS; - BUSUSEDINCPCS; -#ifndef MODE32 - if (VECTORACCESS (temp) || ADDREXCEPT (temp)) { - INTERNALABORT (temp); - (void) ARMul_LoadWordN (state, temp); - (void) ARMul_LoadWordN (state, temp); - } else -#endif - dest = ARMul_SwapWord (state, temp, state->Reg[RHSReg]); - if (temp & 3) - DEST = ARMul_Align (state, temp, dest); - else - DEST = dest; - if (state->abortSig || state->Aborted) - TAKEABORT; - } else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */ - UNDEF_MRSPC; - DEST = ARMul_GetCPSR(state); - } else { - UNDEF_Test; - } - break; - - case 0x11: /* TSTP reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, down, pre indexed. */ - LHPREDOWN (); - /* Continue with remaining instruction decode. */ -#endif - if (DESTReg == 15) { - /* TSTP reg */ -#ifdef MODE32 - //chy 2006-02-15 if in user mode, can not set cpsr 0:23 - //from p165 of ARMARM book - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS & rhs; - SETR15PSR (temp); -#endif - } else { - /* TST reg */ - rhs = DPSRegRHS; - dest = LHS & rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x12: /* TEQ reg and MSR reg to CPSR (ARM6). */ - - if (state->is_v5) { - if (BITS (4, 7) == 3) { - /* BLX(2) */ - ARMword temp; - - if (TFLAG) - temp = (pc + 2) | 1; - else - temp = pc + 4; - - WriteR15Branch (state, state->Reg[RHSReg]); - state->Reg[14] = temp; - break; - } - } - - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1 && (BIT (5) == 0 || BITS (12, 15) == 0)) { - /* ElSegundo SMLAWy/SMULWy insn. */ - unsigned long long op1 = state->Reg[BITS (0, 3)]; - unsigned long long op2 = state->Reg[BITS (8, 11)]; - unsigned long long result; - - if (BIT (6)) - op2 >>= 16; - if (op1 & 0x80000000) - op1 -= 1ULL << 32; - op2 &= 0xFFFF; - if (op2 & 0x8000) - op2 -= 65536; - result = (op1 * op2) >> 16; - - if (BIT (5) == 0) { - ARMword Rn = state->Reg[BITS(12, 15)]; - - if (AddOverflow((ARMword)result, Rn, (ARMword)(result + Rn))) - SETQ; - result += Rn; - } - state->Reg[BITS (16, 19)] = (ARMword)result; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QSUB insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - ARMword op2 = state->Reg[BITS (16, 19)]; - ARMword result = op1 - op2; - - if (SubOverflow - (op1, op2, result)) { - result = POS (result) ? 0x80000000 : 0x7fffffff; - SETQ; - } - - state->Reg[BITS (12, 15)] = result; - break; - } - } -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, down, pre indexed. */ - SHPREDOWNWB (); - break; - } - if (BITS (4, 27) == 0x12FFF1) { - /* BX */ - WriteR15Branch (state, state->Reg[RHSReg]); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (state->is_v5) { - if (BITS (4, 7) == 0x7) { - //ARMword value; - //extern int SWI_vector_installed; - - /* Hardware is allowed to optionally override this - instruction and treat it as a breakpoint. Since - this is a simulator not hardware, we take the position - that if a SWI vector was not installed, then an Abort - vector was probably not installed either, and so - normally this instruction would be ignored, even if an - Abort is generated. This is a bad thing, since GDB - uses this instruction for its breakpoints (at least in - Thumb mode it does). So intercept the instruction here - and generate a breakpoint SWI instead. */ - /* Force the next instruction to be refetched. */ - state->NextInstr = RESUME; - break; - } - } - if (DESTReg == 15) { - /* MSR reg to CPSR. */ - UNDEF_MSRPC; - temp = DPRegRHS; -#ifdef MODET - /* Don't allow TBIT to be set by MSR. */ - temp &= ~TBIT; -#endif - ARMul_FixCPSR (state, instr, temp); - } else - UNDEF_Test; - - break; - - case 0x13: /* TEQP reg */ -#ifdef MODET - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, down, pre indexed. */ - LHPREDOWNWB (); - /* Continue with remaining instruction decode. */ -#endif - if (DESTReg == 15) { - /* TEQP reg */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS ^ rhs; - SETR15PSR (temp); -#endif - } else { - /* TEQ Reg. */ - rhs = DPSRegRHS; - dest = LHS ^ rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x14: /* CMP reg and MRS SPSR and SWP byte. */ - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1) { - /* ElSegundo SMLALxy insn. */ - unsigned long long op1 = state->Reg[BITS (0, 3)]; - unsigned long long op2 = state->Reg[BITS (8, 11)]; - unsigned long long dest; - //unsigned long long result; - - if (BIT (5)) - op1 >>= 16; - if (BIT (6)) - op2 >>= 16; - op1 &= 0xFFFF; - if (op1 & 0x8000) - op1 -= 65536; - op2 &= 0xFFFF; - if (op2 & 0x8000) - op2 -= 65536; - - dest = (unsigned long long) state->Reg[BITS (16, 19)] << 32; - dest |= state->Reg[BITS (12, 15)]; - dest += op1 * op2; - state->Reg[BITS(12, 15)] = (ARMword)dest; - state->Reg[BITS(16, 19)] = (ARMword)(dest >> 32); - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QDADD insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - ARMword op2 = state->Reg[BITS (16, 19)]; - ARMword op2d = op2 + op2; - ARMword result; - - if (AddOverflow - (op2, op2, op2d)) { - SETQ; - op2d = POS (op2d) ? 0x80000000 : 0x7fffffff; - } - - result = op1 + op2d; - if (AddOverflow(op1, op2d, result)) { - SETQ; - result = POS (result) ? 0x80000000 : 0x7fffffff; - } - - state->Reg[BITS (12, 15)] = result; - break; - } - } -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, down, pre indexed. */ - SHPREDOWN (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (BITS (4, 11) == 9) { - /* SWP */ - UNDEF_SWPPC; - temp = LHS; - BUSUSEDINCPCS; -#ifndef MODE32 - if (VECTORACCESS (temp) || ADDREXCEPT (temp)) { - INTERNALABORT (temp); - (void) ARMul_LoadByte (state, temp); - (void) ARMul_LoadByte (state, temp); - } else -#endif - DEST = ARMul_SwapByte (state, temp, state->Reg[RHSReg]); - if (state->abortSig || state->Aborted) - TAKEABORT; - } else if ((BITS (0, 11) == 0) - && (LHSReg == 15)) { - /* MRS SPSR */ - UNDEF_MRSPC; - DEST = GETSPSR (state->Bank); - } else - UNDEF_Test; - - break; - - case 0x15: /* CMPP reg. */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, no write-back, down, pre indexed. */ - LHPREDOWN (); - /* Continue with remaining instruction decode. */ -#endif - if (DESTReg == 15) { - /* CMPP reg. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS - rhs; - SETR15PSR (temp); -#endif - } else { - /* CMP reg. */ - lhs = LHS; - rhs = DPRegRHS; - dest = lhs - rhs; - ARMul_NegZero (state, dest); - if ((lhs >= rhs) - || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, dest); - ARMul_SubOverflow (state, lhs, rhs, dest); - } else { - CLEARC; - CLEARV; - } - } - break; - - case 0x16: /* CMN reg and MSR reg to SPSR */ - if (state->is_v5e) { - if (BIT (4) == 0 && BIT (7) == 1 && BITS (12, 15) == 0) { - /* ElSegundo SMULxy insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - ARMword op2 = state->Reg[BITS (8, 11)]; - ARMword Rn = state->Reg[BITS (12, 15)]; - - if (BIT (5)) - op1 >>= 16; - if (BIT (6)) - op2 >>= 16; - op1 &= 0xFFFF; - op2 &= 0xFFFF; - if (op1 & 0x8000) - op1 -= 65536; - if (op2 & 0x8000) - op2 -= 65536; - - state->Reg[BITS (16, 19)] = op1 * op2; - break; - } - - if (BITS (4, 11) == 5) { - /* ElSegundo QDSUB insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - ARMword op2 = state->Reg[BITS (16, 19)]; - ARMword op2d = op2 + op2; - ARMword result; - - if (AddOverflow(op2, op2, op2d)) { - SETQ; - op2d = POS (op2d) ? 0x80000000 : 0x7fffffff; - } - - result = op1 - op2d; - if (SubOverflow(op1, op2d, result)) { - SETQ; - result = POS (result) ? 0x80000000 : 0x7fffffff; - } - - state->Reg[BITS (12, 15)] = result; - break; - } - } - - if (state->is_v5) { - if (BITS (4, 11) == 0xF1 - && BITS (16, 19) == 0xF) { - /* ARM5 CLZ insn. */ - ARMword op1 = state->Reg[BITS (0, 3)]; - int result = 32; - - if (op1) - for (result = 0; (op1 & 0x80000000) == 0; op1 <<= 1) - result++; - state->Reg[BITS (12, 15)] = result; - break; - } - } - -#ifdef MODET - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, down, pre indexed. */ - SHPREDOWNWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - if (DESTReg == 15) { - /* MSR */ - UNDEF_MSRPC; - /*ARMul_FixSPSR (state, instr, - DPRegRHS);*/ - } else { - UNDEF_Test; - } - break; - - case 0x17: /* CMNP reg */ -#ifdef MODET - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, down, pre indexed. */ - LHPREDOWNWB (); - /* Continue with remaining instruction decoding. */ -#endif - if (DESTReg == 15) { -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - rhs = DPRegRHS; - temp = LHS + rhs; - SETR15PSR (temp); -#endif - break; - } else { - /* CMN reg. */ - lhs = LHS; - rhs = DPRegRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, dest); - ARMul_AddOverflow (state, lhs, rhs, dest); - } else { - CLEARN; - CLEARC; - CLEARV; - } - } - break; - - case 0x18: /* ORR reg */ -#ifdef MODET - /* dyf add armv6 instr strex 2010.9.17 */ - if (state->is_v6) { - if (BITS (4, 7) == 0x9) - if (handle_v6_insn (state, instr)) - break; - } - - if (BITS (4, 11) == 0xB) { - /* STRH register offset, no write-back, up, pre indexed. */ - SHPREUP (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS | rhs; - WRITEDEST (dest); - break; - - case 0x19: /* ORRS reg */ -#ifdef MODET - /* dyf add armv6 instr ldrex */ - if (state->is_v6) { - if (BITS (4, 7) == 0x9) { - if (handle_v6_insn (state, instr)) - break; - } - } - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, no write-back, up, pre indexed. */ - LHPREUP (); - /* Continue with remaining instruction decoding. */ -#endif - rhs = DPSRegRHS; - dest = LHS | rhs; - WRITESDEST (dest); - break; - - case 0x1a: /* MOV reg */ -#ifdef MODET - if (BITS (4, 11) == 0xB) { - /* STRH register offset, write-back, up, pre indexed. */ - SHPREUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } - if (BITS(4, 11) == 0xF9) { //strexd - u32 l = LHSReg; - - bool enter = false; - - if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr)&& - state->currentexvald == (u32)ARMul_ReadWord(state, state->currentexaddr + 4)) - enter = true; - - //todo bug this and STREXD and LDREXD http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360e/CHDGJGGC.html - - if (enter) { - ARMul_StoreWordN(state, LHS, state->Reg[RHSReg]); - ARMul_StoreWordN(state,LHS + 4 , state->Reg[RHSReg + 1]); - state->Reg[DESTReg] = 0; - } else { - state->Reg[DESTReg] = 1; - } - - break; - } -#endif - dest = DPRegRHS; - WRITEDEST (dest); - break; - - case 0x1B: /* MOVS reg */ -#ifdef MODET - /* ldrexd ichfly */ - if (BITS(0, 11) == 0xF9F) { //strexd - lhs = LHS; - - state->currentexaddr = lhs; - state->currentexval = (u32)ARMul_ReadWord(state, lhs); - state->currentexvald = (u32)ARMul_ReadWord(state, lhs + 4); - - state->Reg[DESTReg] = ARMul_LoadWordN(state, lhs); - state->Reg[DESTReg] = ARMul_LoadWordN(state, lhs + 4); - break; - } - - if ((BITS (4, 11) & 0xF9) == 0x9) - /* LDR register offset, write-back, up, pre indexed. */ - LHPREUPWB (); - /* Continue with remaining instruction decoding. */ - -#endif - dest = DPSRegRHS; - WRITESDEST (dest); - break; - - case 0x1c: /* BIC reg */ -#ifdef MODET - /* dyf add for STREXB */ - if (state->is_v6) { - if (BITS (4, 7) == 0x9) { - if (handle_v6_insn (state, instr)) - break; - } - } - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, no write-back, up, pre indexed. */ - SHPREUP (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } else if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - rhs = DPRegRHS; - dest = LHS & ~rhs; - WRITEDEST (dest); - break; - - case 0x1d: /* BICS reg */ -#ifdef MODET - /* ladsh P=1 U=1 W=0 L=1 S=1 H=1 */ - if (BITS(4, 7) == 0xF) { - temp = LHS + GetLS7RHS (state, instr); - LoadHalfWord (state, instr, temp, LSIGNED); - break; - } - if (BITS (4, 7) == 0xb) { - /* LDRH immediate offset, no write-back, up, pre indexed. */ - temp = LHS + GetLS7RHS (state, instr); - LoadHalfWord (state, instr, temp, LUNSIGNED); - break; - } - if (BITS (4, 7) == 0xd) { - // alex-ykl fix: 2011-07-20 missing ldrsb instruction - temp = LHS + GetLS7RHS (state, instr); - LoadByte (state, instr, temp, LSIGNED); - break; - } - - /* Continue with instruction decoding. */ - /*if ((BITS (4, 7) & 0x9) == 0x9) */ - if ((BITS (4, 7)) == 0x9) { - /* ldrexb */ - if (state->is_v6) { - if (handle_v6_insn (state, instr)) - break; - } - /* LDR immediate offset, no write-back, up, pre indexed. */ - LHPREUP (); - } - -#endif - rhs = DPSRegRHS; - dest = LHS & ~rhs; - WRITESDEST (dest); - break; - - case 0x1e: /* MVN reg */ -#ifdef MODET - if ((instr & 0x00000FF0) == 0x00000F90) { //if ((instr & 0x0FF00FF0) == 0x01e00f90) { //todo make that better ichfly - /* strexh ichfly */ - u32 l = LHSReg; - u32 r = RHSReg; - lhs = LHS; - - bool enter = false; - - if (state->currentexval == (u32)ARMul_LoadHalfWord(state, state->currentexaddr))enter = true; - - //StoreWord(state, lhs, RHS) - if (state->Aborted) { - TAKEABORT; - } - if (enter) { - ARMul_StoreHalfWord(state, lhs, RHS); - state->Reg[DESTReg] = 0; - } else { - state->Reg[DESTReg] = 1; - } - break; - } - if (BITS (4, 7) == 0xB) { - /* STRH immediate offset, write-back, up, pre indexed. */ - SHPREUPWB (); - break; - } - if (BITS (4, 7) == 0xD) { - Handle_Load_Double (state, instr); - break; - } - if (BITS (4, 7) == 0xF) { - Handle_Store_Double (state, instr); - break; - } -#endif - dest = ~DPRegRHS; - WRITEDEST (dest); - break; - - case 0x1f: /* MVNS reg */ -#ifdef MODET - - if ((instr & 0x00000FF0) == 0x00000F90) { //(instr & 0x0FF00FF0) == 0x01f00f90)//if ((instr & 0x0FF00FF0) == 0x01f00f90) { - /* ldrexh ichfly */ - lhs = LHS; - - state->currentexaddr = lhs; - state->currentexval = (u32)ARMul_LoadHalfWord(state, lhs); - - LoadHalfWord(state, instr, lhs,0); - break; - } - - if ((BITS (4, 7) & 0x9) == 0x9) - /* LDR immediate offset, write-back, up, pre indexed. */ - LHPREUPWB (); - /* Continue instruction decoding. */ -#endif - dest = ~DPSRegRHS; - WRITESDEST (dest); - break; - - /* Data Processing Immediate RHS Instructions. */ - - case 0x20: /* AND immed */ - dest = LHS & DPImmRHS; - WRITEDEST (dest); - break; - - case 0x21: /* ANDS immed */ - DPSImmRHS; - dest = LHS & rhs; - WRITESDEST (dest); - break; - - case 0x22: /* EOR immed */ - dest = LHS ^ DPImmRHS; - WRITEDEST (dest); - break; - - case 0x23: /* EORS immed */ - DPSImmRHS; - dest = LHS ^ rhs; - WRITESDEST (dest); - break; - - case 0x24: /* SUB immed */ - dest = LHS - DPImmRHS; - WRITEDEST (dest); - break; - - case 0x25: /* SUBS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs - rhs; - - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, dest); - ARMul_SubOverflow (state, lhs, rhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x26: /* RSB immed */ - dest = DPImmRHS - LHS; - WRITEDEST (dest); - break; - - case 0x27: /* RSBS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = rhs - lhs; - - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, dest); - ARMul_SubOverflow (state, rhs, lhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x28: /* ADD immed */ - dest = LHS + DPImmRHS; - WRITEDEST (dest); - break; - - case 0x29: /* ADDS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, dest); - ARMul_AddOverflow (state, lhs, rhs, dest); - } else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x2a: /* ADC immed */ - dest = LHS + DPImmRHS + CFLAG; - WRITEDEST (dest); - break; - - case 0x2b: /* ADCS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs + rhs + CFLAG; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, dest); - ARMul_AddOverflow (state, lhs, rhs, dest); - } else { - CLEARN; - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x2c: /* SBC immed */ - dest = LHS - DPImmRHS - !CFLAG; - WRITEDEST (dest); - break; - - case 0x2d: /* SBCS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs - rhs - !CFLAG; - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, dest); - ARMul_SubOverflow (state, lhs, rhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x2e: /* RSC immed */ - dest = DPImmRHS - LHS - !CFLAG; - WRITEDEST (dest); - break; - - case 0x2f: /* RSCS immed */ - lhs = LHS; - rhs = DPImmRHS; - dest = rhs - lhs - !CFLAG; - if ((rhs >= lhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, rhs, lhs, dest); - ARMul_SubOverflow (state, rhs, lhs, dest); - } else { - CLEARC; - CLEARV; - } - WRITESDEST (dest); - break; - - case 0x30: /* TST immed */ - /* shenoubang 2012-3-14*/ - if (state->is_v6) { /* movw, ARMV6, ARMv7 */ - dest ^= dest; - dest = BITS(16, 19); - dest = ((dest<<12) | BITS(0, 11)); - WRITEDEST(dest); - break; - } else { - UNDEF_Test; - break; - } - - case 0x31: /* TSTP immed */ - if (DESTReg == 15) { - /* TSTP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS & DPImmRHS; - SETR15PSR (temp); -#endif - } else { - /* TST immed. */ - DPSImmRHS; - dest = LHS & rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x32: /* TEQ immed and MSR immed to CPSR */ - if (DESTReg == 15) - /* MSR immed to CPSR. */ - ARMul_FixCPSR (state, instr, - DPImmRHS); - else - UNDEF_Test; - break; - - case 0x33: /* TEQP immed */ - if (DESTReg == 15) { - /* TEQP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS ^ DPImmRHS; - SETR15PSR (temp); -#endif - } else { - DPSImmRHS; /* TEQ immed */ - dest = LHS ^ rhs; - ARMul_NegZero (state, dest); - } - break; - - case 0x34: /* CMP immed */ - UNDEF_Test; - break; - - case 0x35: /* CMPP immed */ - if (DESTReg == 15) { - /* CMPP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS - DPImmRHS; - SETR15PSR (temp); -#endif - break; - } else { - /* CMP immed. */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs - rhs; - ARMul_NegZero (state, dest); - - if ((lhs >= rhs) || ((rhs | lhs) >> 31)) { - ARMul_SubCarry (state, lhs, rhs, dest); - ARMul_SubOverflow (state, lhs, rhs, dest); - } else { - CLEARC; - CLEARV; - } - } - break; - - case 0x36: /* CMN immed and MSR immed to SPSR */ - //if (DESTReg == 15) - /*ARMul0_FixSPSR (state, instr, - DPImmRHS);*/ - //else - UNDEF_Test; - break; - - case 0x37: /* CMNP immed. */ - if (DESTReg == 15) { - /* CMNP immed. */ -#ifdef MODE32 - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); -#else - temp = LHS + DPImmRHS; - SETR15PSR (temp); -#endif - break; - } else { - /* CMN immed. */ - lhs = LHS; - rhs = DPImmRHS; - dest = lhs + rhs; - ASSIGNZ (dest == 0); - if ((lhs | rhs) >> 30) { - /* Possible C,V,N to set. */ - ASSIGNN (NEG (dest)); - ARMul_AddCarry (state, lhs, rhs, dest); - ARMul_AddOverflow (state, lhs, rhs, dest); - } else { - CLEARN; - CLEARC; - CLEARV; - } - } - break; - - case 0x38: /* ORR immed. */ - dest = LHS | DPImmRHS; - WRITEDEST (dest); - break; - - case 0x39: /* ORRS immed. */ - DPSImmRHS; - dest = LHS | rhs; - WRITESDEST (dest); - break; - - case 0x3a: /* MOV immed. */ - dest = DPImmRHS; - WRITEDEST (dest); - break; - - case 0x3b: /* MOVS immed. */ - DPSImmRHS; - WRITESDEST (rhs); - break; - - case 0x3c: /* BIC immed. */ - dest = LHS & ~DPImmRHS; - WRITEDEST (dest); - break; - - case 0x3d: /* BICS immed. */ - DPSImmRHS; - dest = LHS & ~rhs; - WRITESDEST (dest); - break; - - case 0x3e: /* MVN immed. */ - dest = ~DPImmRHS; - WRITEDEST (dest); - break; - - case 0x3f: /* MVNS immed. */ - DPSImmRHS; - WRITESDEST (~rhs); - break; - - /* Single Data Transfer Immediate RHS Instructions. */ - - case 0x40: /* Store Word, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - break; - - case 0x41: /* Load Word, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (LoadWord (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - break; - - case 0x42: /* Store Word, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - temp = lhs - LSImmRHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = temp; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x43: /* Load Word, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x44: /* Store Byte, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - break; - - case 0x45: /* Load Byte, No WriteBack, Post Dec, Immed. */ - lhs = LHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs - LSImmRHS; - break; - - case 0x46: /* Store Byte, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x47: /* Load Byte, WriteBack, Post Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs - LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x48: /* Store Word, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - break; - - case 0x49: /* Load Word, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (LoadWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - break; - - case 0x4a: /* Store Word, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x4b: /* Load Word, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x4c: /* Store Byte, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - break; - - case 0x4d: /* Load Byte, No WriteBack, Post Inc, Immed. */ - lhs = LHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs + LSImmRHS; - break; - - case 0x4e: /* Store Byte, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x4f: /* Load Byte, WriteBack, Post Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - lhs = LHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = lhs + LSImmRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x50: /* Store Word, No WriteBack, Pre Dec, Immed. */ - (void) StoreWord (state, instr, LHS - LSImmRHS); - break; - - case 0x51: /* Load Word, No WriteBack, Pre Dec, Immed. */ - (void) LoadWord (state, instr, LHS - LSImmRHS); - break; - - case 0x52: /* Store Word, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x53: /* Load Word, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x54: /* Store Byte, No WriteBack, Pre Dec, Immed. */ - (void) StoreByte (state, instr, LHS - LSImmRHS); - break; - - case 0x55: /* Load Byte, No WriteBack, Pre Dec, Immed. */ - (void) LoadByte (state, instr, LHS - LSImmRHS, LUNSIGNED); - break; - - case 0x56: /* Store Byte, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x57: /* Load Byte, WriteBack, Pre Dec, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS - LSImmRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - case 0x58: /* Store Word, No WriteBack, Pre Inc, Immed. */ - (void) StoreWord (state, instr, LHS + LSImmRHS); - break; - - case 0x59: /* Load Word, No WriteBack, Pre Inc, Immed. */ - (void) LoadWord (state, instr, LHS + LSImmRHS); - break; - - case 0x5a: /* Store Word, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x5b: /* Load Word, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x5c: /* Store Byte, No WriteBack, Pre Inc, Immed. */ - (void) StoreByte (state, instr, LHS + LSImmRHS); - break; - - case 0x5d: /* Load Byte, No WriteBack, Pre Inc, Immed. */ - (void) LoadByte (state, instr, LHS + LSImmRHS, LUNSIGNED); - break; - - case 0x5e: /* Store Byte, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x5f: /* Load Byte, WriteBack, Pre Inc, Immed. */ - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - temp = LHS + LSImmRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - /* Single Data Transfer Register RHS Instructions. */ - - case 0x60: /* Store Word, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - break; - - case 0x61: /* Load Word, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - break; - - case 0x62: /* Store Word, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x63: /* Load Word, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x64: /* Store Byte, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - break; - - case 0x65: /* Load Byte, No WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - break; - - case 0x66: /* Store Byte, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs - LSRegRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x67: /* Load Byte, WriteBack, Post Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs - LSRegRHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ - if ((instr & 0x70) == 0x10) { //pkhbt - u8 idest = BITS(12, 15); - u8 rfis = BITS(16, 19); - u8 rlast = BITS(0, 3); - u8 ishi = BITS(7,11); - state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); - break; - } else if ((instr & 0x70) == 0x50) { //pkhtb - u8 rd_idx = BITS(12, 15); - u8 rn_idx = BITS(16, 19); - u8 rm_idx = BITS(0, 3); - u8 imm5 = BITS(7, 11) ? BITS(7, 11) : 31; - state->Reg[rd_idx] = ((static_cast<s32>(state->Reg[rm_idx]) >> imm5) & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000); - break; - } else if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - break; - - case 0x69: /* Load Word, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - break; - - case 0x6a: /* Store Word, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreWord (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x6b: /* Load Word, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - state->NtransSig = LOW; - if (LoadWord (state, instr, lhs)) - LSBase = temp; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x6c: /* Store Byte, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - break; - - case 0x6d: /* Load Byte, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - break; - - case 0x6e: /* Store Byte, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - state->NtransSig = LOW; - if (StoreByte (state, instr, lhs)) - LSBase = lhs + LSRegRHS; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x6f: /* Load Byte, WriteBack, Post Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 - && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - lhs = LHS; - temp = lhs + LSRegRHS; - state->NtransSig = LOW; - if (LoadByte (state, instr, lhs, LUNSIGNED)) - LSBase = temp; - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - break; - - case 0x70: /* Store Word, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreWord (state, instr, LHS - LSRegRHS); - break; - - case 0x71: /* Load Word, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadWord (state, instr, LHS - LSRegRHS); - break; - - case 0x72: /* Store Word, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x73: /* Load Word, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x74: /* Store Byte, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreByte (state, instr, LHS - LSRegRHS); - break; - - case 0x75: /* Load Byte, No WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadByte (state, instr, LHS - LSRegRHS, LUNSIGNED); - break; - - case 0x76: /* Store Byte, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x77: /* Load Byte, WriteBack, Pre Dec, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS - LSRegRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - case 0x78: /* Store Word, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreWord (state, instr, LHS + LSRegRHS); - break; - - case 0x79: /* Load Word, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadWord (state, instr, LHS + LSRegRHS); - break; - - case 0x7a: /* Store Word, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (StoreWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x7b: /* Load Word, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (LoadWord (state, instr, temp)) - LSBase = temp; - break; - - case 0x7c: /* Store Byte, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { -#ifdef MODE32 - if (state->is_v6 && handle_v6_insn (state, instr)) - break; -#endif - - ARMul_UndefInstr (state, instr); - break; - } - (void) StoreByte (state, instr, LHS + LSRegRHS); - break; - - case 0x7d: /* Load Byte, No WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - (void) LoadByte (state, instr, LHS + LSRegRHS, LUNSIGNED); - break; - - case 0x7e: /* Store Byte, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - ARMul_UndefInstr (state, instr); - break; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (StoreByte (state, instr, temp)) - LSBase = temp; - break; - - case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */ - if (BIT (4)) { - LOG_DEBUG(Core_ARM11, "got unhandled special breakpoint"); - return 1; - } - UNDEF_LSRBaseEQOffWb; - UNDEF_LSRBaseEQDestWb; - UNDEF_LSRPCBaseWb; - UNDEF_LSRPCOffWb; - temp = LHS + LSRegRHS; - if (LoadByte (state, instr, temp, LUNSIGNED)) - LSBase = temp; - break; - - /* Multiple Data Transfer Instructions. */ - - case 0x80: /* Store, No WriteBack, Post Dec. */ - STOREMULT (instr, LSBase - LSMNumRegs + 4L, 0L); - break; - - case 0x81: /* Load, No WriteBack, Post Dec. */ - LOADMULT (instr, LSBase - LSMNumRegs + 4L, 0L); - break; - - case 0x82: /* Store, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - STOREMULT (instr, temp + 4L, temp); - break; - - case 0x83: /* Load, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - LOADMULT (instr, temp + 4L, temp); - break; - - case 0x84: /* Store, Flags, No WriteBack, Post Dec. */ - STORESMULT (instr, LSBase - LSMNumRegs + 4L, 0L); - break; - - case 0x85: /* Load, Flags, No WriteBack, Post Dec. */ - LOADSMULT (instr, LSBase - LSMNumRegs + 4L, 0L); - break; - - case 0x86: /* Store, Flags, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - STORESMULT (instr, temp + 4L, temp); - break; - - case 0x87: /* Load, Flags, WriteBack, Post Dec. */ - temp = LSBase - LSMNumRegs; - LOADSMULT (instr, temp + 4L, temp); - break; - - case 0x88: /* Store, No WriteBack, Post Inc. */ - STOREMULT (instr, LSBase, 0L); - break; - - case 0x89: /* Load, No WriteBack, Post Inc. */ - LOADMULT (instr, LSBase, 0L); - break; - - case 0x8a: /* Store, WriteBack, Post Inc. */ - temp = LSBase; - STOREMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x8b: /* Load, WriteBack, Post Inc. */ - temp = LSBase; - LOADMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x8c: /* Store, Flags, No WriteBack, Post Inc. */ - STORESMULT (instr, LSBase, 0L); - break; - - case 0x8d: /* Load, Flags, No WriteBack, Post Inc. */ - LOADSMULT (instr, LSBase, 0L); - break; - - case 0x8e: /* Store, Flags, WriteBack, Post Inc. */ - temp = LSBase; - STORESMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x8f: /* Load, Flags, WriteBack, Post Inc. */ - temp = LSBase; - LOADSMULT (instr, temp, temp + LSMNumRegs); - break; - - case 0x90: /* Store, No WriteBack, Pre Dec. */ - STOREMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x91: /* Load, No WriteBack, Pre Dec. */ - LOADMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x92: /* Store, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - STOREMULT (instr, temp, temp); - break; - - case 0x93: /* Load, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - LOADMULT (instr, temp, temp); - break; - - case 0x94: /* Store, Flags, No WriteBack, Pre Dec. */ - STORESMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x95: /* Load, Flags, No WriteBack, Pre Dec. */ - LOADSMULT (instr, LSBase - LSMNumRegs, 0L); - break; - - case 0x96: /* Store, Flags, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - STORESMULT (instr, temp, temp); - break; - - case 0x97: /* Load, Flags, WriteBack, Pre Dec. */ - temp = LSBase - LSMNumRegs; - LOADSMULT (instr, temp, temp); - break; - - case 0x98: /* Store, No WriteBack, Pre Inc. */ - STOREMULT (instr, LSBase + 4L, 0L); - break; - - case 0x99: /* Load, No WriteBack, Pre Inc. */ - LOADMULT (instr, LSBase + 4L, 0L); - break; - - case 0x9a: /* Store, WriteBack, Pre Inc. */ - temp = LSBase; - STOREMULT (instr, temp + 4L, temp + LSMNumRegs); - break; - - case 0x9b: /* Load, WriteBack, Pre Inc. */ - temp = LSBase; - LOADMULT (instr, temp + 4L, temp + LSMNumRegs); - break; - - case 0x9c: /* Store, Flags, No WriteBack, Pre Inc. */ - STORESMULT (instr, LSBase + 4L, 0L); - break; - - case 0x9d: /* Load, Flags, No WriteBack, Pre Inc. */ - LOADSMULT (instr, LSBase + 4L, 0L); - break; - - case 0x9e: /* Store, Flags, WriteBack, Pre Inc. */ - temp = LSBase; - STORESMULT (instr, temp + 4L, temp + LSMNumRegs); - break; - - case 0x9f: /* Load, Flags, WriteBack, Pre Inc. */ - temp = LSBase; - LOADSMULT (instr, temp + 4L, temp + LSMNumRegs); - break; - - /* Branch forward. */ - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - state->Reg[15] = pc + 8 + POSBRANCH; - FLUSHPIPE; - break; - - /* Branch backward. */ - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - state->Reg[15] = pc + 8 + NEGBRANCH; - FLUSHPIPE; - break; - - /* Branch and Link forward. */ - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - - /* Put PC into Link. */ -#ifdef MODE32 - state->Reg[14] = pc + 4; -#else - state->Reg[14] = (pc + 4) | ECC | ER15INT | EMODE; -#endif - state->Reg[15] = pc + 8 + POSBRANCH; - FLUSHPIPE; - break; - - /* Branch and Link backward. */ - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: - /* Put PC into Link. */ -#ifdef MODE32 - state->Reg[14] = pc + 4; -#else - state->Reg[14] = (pc + 4) | ECC | ER15INT | EMODE; -#endif - state->Reg[15] = pc + 8 + NEGBRANCH; - FLUSHPIPE; - break; - - /* Co-Processor Data Transfers. */ - case 0xc4: - if ((instr & 0x0FF00FF0) == 0xC400B10) { //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0 - state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)]; - state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)]; - break; - } else if (state->is_v5) { - /* Reading from R15 is UNPREDICTABLE. */ - if (BITS (12, 15) == 15 || BITS (16, 19) == 15) - ARMul_UndefInstr (state, instr); - /* Is access to coprocessor 0 allowed ? */ - else if (!CP_ACCESS_ALLOWED(state, CPNum)) - ARMul_UndefInstr (state, instr); - else { - /* MCRR, ARMv5TE and up */ - ARMul_MCRR (state, instr, DEST, state->Reg[LHSReg]); - break; - } - } - /* Drop through. */ - - case 0xc0: /* Store , No WriteBack , Post Dec. */ - ARMul_STC (state, instr, LHS); - break; - - case 0xc5: - if ((instr & 0x00000FF0) == 0xB10) { //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0 - state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1]; - state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1]; - break; - } else if (state->is_v5) { - /* Writes to R15 are UNPREDICATABLE. */ - if (DESTReg == 15 || LHSReg == 15) - ARMul_UndefInstr (state, instr); - /* Is access to the coprocessor allowed ? */ - else if (!CP_ACCESS_ALLOWED(state, CPNum)) { - ARMul_UndefInstr(state, instr); - } else { - /* MRRC, ARMv5TE and up */ - ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); - break; - } - } - /* Drop through. */ - - case 0xc1: /* Load , No WriteBack , Post Dec. */ - ARMul_LDC (state, instr, LHS); - break; - - case 0xc2: - case 0xc6: /* Store , WriteBack , Post Dec. */ - lhs = LHS; - state->Base = lhs - LSCOff; - ARMul_STC (state, instr, lhs); - break; - - case 0xc3: - case 0xc7: /* Load , WriteBack , Post Dec. */ - lhs = LHS; - state->Base = lhs - LSCOff; - ARMul_LDC (state, instr, lhs); - break; - - case 0xc8: - case 0xcc: /* Store , No WriteBack , Post Inc. */ - ARMul_STC (state, instr, LHS); - break; - - case 0xc9: - case 0xcd: /* Load , No WriteBack , Post Inc. */ - ARMul_LDC (state, instr, LHS); - break; - - case 0xca: - case 0xce: /* Store , WriteBack , Post Inc. */ - lhs = LHS; - state->Base = lhs + LSCOff; - ARMul_STC (state, instr, LHS); - break; - - case 0xcb: - case 0xcf: /* Load , WriteBack , Post Inc. */ - lhs = LHS; - state->Base = lhs + LSCOff; - ARMul_LDC (state, instr, LHS); - break; - - case 0xd0: - case 0xd4: /* Store , No WriteBack , Pre Dec. */ - ARMul_STC (state, instr, LHS - LSCOff); - break; - - case 0xd1: - case 0xd5: /* Load , No WriteBack , Pre Dec. */ - ARMul_LDC (state, instr, LHS - LSCOff); - break; - - case 0xd2: - case 0xd6: /* Store , WriteBack , Pre Dec. */ - lhs = LHS - LSCOff; - state->Base = lhs; - ARMul_STC (state, instr, lhs); - break; - - case 0xd3: - case 0xd7: /* Load , WriteBack , Pre Dec. */ - lhs = LHS - LSCOff; - state->Base = lhs; - ARMul_LDC (state, instr, lhs); - break; - - case 0xd8: - case 0xdc: /* Store , No WriteBack , Pre Inc. */ - ARMul_STC (state, instr, LHS + LSCOff); - break; - - case 0xd9: - case 0xdd: /* Load , No WriteBack , Pre Inc. */ - ARMul_LDC (state, instr, LHS + LSCOff); - break; - - case 0xda: - case 0xde: /* Store , WriteBack , Pre Inc. */ - lhs = LHS + LSCOff; - state->Base = lhs; - ARMul_STC (state, instr, lhs); - break; - - case 0xdb: - case 0xdf: /* Load , WriteBack , Pre Inc. */ - lhs = LHS + LSCOff; - state->Base = lhs; - ARMul_LDC (state, instr, lhs); - break; - - /* Co-Processor Register Transfers (MCR) and Data Ops. */ - - case 0xe2: - /*if (!CP_ACCESS_ALLOWED (state, CPNum)) { - ARMul_UndefInstr (state, instr); - break; - }*/ - - case 0xe0: - case 0xe4: - case 0xe6: - case 0xe8: - case 0xea: - case 0xec: - case 0xee: - if (BIT (4)) { - /* MCR. */ - if (DESTReg == 15) { - UNDEF_MCRPC; -#ifdef MODE32 - ARMul_MCR (state, instr, state->Reg[15] + isize); -#else - ARMul_MCR (state, instr, ECC | ER15INT | EMODE | ((state->Reg[15] + isize) & R15PCBITS)); -#endif - } else - ARMul_MCR (state, instr, DEST); - } else - /* CDP Part 1. */ - ARMul_CDP (state, instr); - break; - - /* Co-Processor Register Transfers (MRC) and Data Ops. */ - case 0xe1: - case 0xe3: - case 0xe5: - case 0xe7: - case 0xe9: - case 0xeb: - case 0xed: - case 0xef: - if (BIT (4)) { - /* MRC */ - temp = ARMul_MRC (state, instr); - if (DESTReg == 15) { - ASSIGNN ((temp & NBIT) != 0); - ASSIGNZ ((temp & ZBIT) != 0); - ASSIGNC ((temp & CBIT) != 0); - ASSIGNV ((temp & VBIT) != 0); - } else - DEST = temp; - } else - /* CDP Part 2. */ - ARMul_CDP (state, instr); - break; - - /* SWI instruction. */ - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - case 0xf8: - case 0xf9: - case 0xfa: - case 0xfb: - case 0xfc: - case 0xfd: - case 0xfe: - case 0xff: - //svc_Execute(state, BITS(0, 23)); - HLE::CallSVC(instr); - - break; - } - } - -#ifdef MODET -donext: -#endif - state->pc = pc; - - /* jump out every time */ - //state->EndCondition = 0; - //state->Emulate = STOP; -//chy 2006-04-12 for ICE debug -TEST_EMULATE: - if (state->Emulate == ONCE) - state->Emulate = STOP; - else if (state->Emulate != RUN) - break; - } - - while (state->NumInstrsToExecute); -exit: - state->decoded = decoded; - state->loaded = loaded; - state->pc = pc; - //chy 2006-04-12, for ICE debug - state->decoded_addr=decoded_addr; - state->loaded_addr=loaded_addr; - - return pc; - } - - static volatile void (*gen_func) (void); - - static volatile uint32_t tmp_st; - static volatile uint32_t save_st; - static volatile uint32_t save_T0; - static volatile uint32_t save_T1; - static volatile uint32_t save_T2; - - /* This routine evaluates most Data Processing register RHS's with the S - bit clear. It is intended to be called from the macro DPRegRHS, which - filters the common case of an unshifted register with in line code. */ - - static ARMword - GetDPRegRHS (ARMul_State * state, ARMword instr) { - ARMword shamt, base; - - base = RHSReg; - if (BIT (4)) { - /* Shift amount in a register. */ - UNDEF_Shift; - INCPC; -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - ARMul_Icycles (state, 1, 0L); - shamt = state->Reg[BITS (8, 11)] & 0xff; - switch ((int) BITS (5, 6)) { - case LSL: - if (shamt == 0) - return (base); - else if (shamt >= 32) - return (0); - else - return (base << shamt); - case LSR: - if (shamt == 0) - return (base); - else if (shamt >= 32) - return (0); - else - return (base >> shamt); - case ASR: - if (shamt == 0) - return (base); - else if (shamt >= 32) - return ((ARMword) ((int) base >> 31L)); - else - return ((ARMword) - (( int) base >> (int) shamt)); - case ROR: - shamt &= 0x1f; - if (shamt == 0) - return (base); - else - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } else { - /* Shift amount is a constant. */ -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - shamt = BITS (7, 11); - switch ((int) BITS (5, 6)) { - case LSL: - return (base << shamt); - case LSR: - if (shamt == 0) - return (0); - else - return (base >> shamt); - case ASR: - if (shamt == 0) - return ((ARMword) (( int) base >> 31L)); - else - return ((ARMword) - (( int) base >> (int) shamt)); - case ROR: - if (shamt == 0) - /* It's an RRX. */ - return ((base >> 1) | (CFLAG << 31)); - else - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - - return 0; - } - - /* This routine evaluates most Logical Data Processing register RHS's - with the S bit set. It is intended to be called from the macro - DPSRegRHS, which filters the common case of an unshifted register - with in line code. */ - - static ARMword - GetDPSRegRHS (ARMul_State * state, ARMword instr) { - ARMword shamt, base; - - base = RHSReg; - if (BIT (4)) { - /* Shift amount in a register. */ - UNDEF_Shift; - INCPC; -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - ARMul_Icycles (state, 1, 0L); - shamt = state->Reg[BITS (8, 11)] & 0xff; - switch ((int) BITS (5, 6)) { - case LSL: - if (shamt == 0) - return (base); - else if (shamt == 32) { - ASSIGNC (base & 1); - return (0); - } else if (shamt > 32) { - CLEARC; - return (0); - } else { - ASSIGNC ((base >> (32 - shamt)) & 1); - return (base << shamt); - } - case LSR: - if (shamt == 0) - return (base); - else if (shamt == 32) { - ASSIGNC (base >> 31); - return (0); - } else if (shamt > 32) { - CLEARC; - return (0); - } else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return (base >> shamt); - } - case ASR: - if (shamt == 0) - return (base); - else if (shamt >= 32) { - ASSIGNC (base >> 31L); - return ((ARMword) (( int) base >> 31L)); - } else { - ASSIGNC ((ARMword) - (( int) base >> - (int) (shamt - 1)) & 1); - return ((ARMword) - ((int) base >> (int) shamt)); - } - case ROR: - if (shamt == 0) - return (base); - shamt &= 0x1f; - if (shamt == 0) { - ASSIGNC (base >> 31); - return (base); - } else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - } else { - /* Shift amount is a constant. */ -#ifndef MODE32 - if (base == 15) - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - shamt = BITS (7, 11); - - switch ((int) BITS (5, 6)) { - case LSL: - ASSIGNC ((base >> (32 - shamt)) & 1); - return (base << shamt); - case LSR: - if (shamt == 0) { - ASSIGNC (base >> 31); - return (0); - } else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return (base >> shamt); - } - case ASR: - if (shamt == 0) { - ASSIGNC (base >> 31L); - return ((ARMword) ((int) base >> 31L)); - } else { - ASSIGNC ((ARMword) - ((int) base >> - (int) (shamt - 1)) & 1); - return ((ARMword) - (( int) base >> (int) shamt)); - } - case ROR: - if (shamt == 0) { - /* It's an RRX. */ - shamt = CFLAG; - ASSIGNC (base & 1); - return ((base >> 1) | (shamt << 31)); - } else { - ASSIGNC ((base >> (shamt - 1)) & 1); - return ((base << (32 - shamt)) | - (base >> shamt)); - } - } - } - - return 0; - } - - /* This routine handles writes to register 15 when the S bit is not set. */ - - static void - WriteR15 (ARMul_State * state, ARMword src) { - /* The ARM documentation states that the two least significant bits - are discarded when setting PC, except in the cases handled by - WriteR15Branch() below. It's probably an oversight: in THUMB - mode, the second least significant bit should probably not be - discarded. */ -#ifdef MODET - if (TFLAG) - src &= 0xfffffffe; - else -#endif - src &= 0xfffffffc; - -#ifdef MODE32 - state->Reg[15] = src & PCBITS; -#else - state->Reg[15] = (src & R15PCBITS) | ECC | ER15INT | EMODE; - ARMul_R15Altered (state); -#endif - - FLUSHPIPE; - } - - /* This routine handles writes to register 15 when the S bit is set. */ - - static void - WriteSR15 (ARMul_State * state, ARMword src) { -#ifdef MODE32 - if (state->Bank > 0) { - state->Cpsr = state->Spsr[state->Bank]; - ARMul_CPSRAltered (state); - } -#ifdef MODET - if (TFLAG) - src &= 0xfffffffe; - else -#endif - src &= 0xfffffffc; - state->Reg[15] = src & PCBITS; -#else -#ifdef MODET - if (TFLAG) - /* ARMul_R15Altered would have to support it. */ - abort (); - else -#endif - src &= 0xfffffffc; - - if (state->Bank == USERBANK) - state->Reg[15] = - (src & (CCBITS | R15PCBITS)) | ER15INT | EMODE; - else - state->Reg[15] = src; - - ARMul_R15Altered (state); -#endif - FLUSHPIPE; - } - - /* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM - will switch to Thumb mode if the least significant bit is set. */ - - static void - WriteR15Branch (ARMul_State * state, ARMword src) { -#ifdef MODET - if (src & 1) { - /* Thumb bit. */ - SETT; - state->Reg[15] = src & 0xfffffffe; - } else { - CLEART; - state->Reg[15] = src & 0xfffffffc; - } - state->Cpsr = ARMul_GetCPSR (state); - FLUSHPIPE; -#else - WriteR15 (state, src); -#endif - } - - /* This routine evaluates most Load and Store register RHS's. It is - intended to be called from the macro LSRegRHS, which filters the - common case of an unshifted register with in line code. */ - - static ARMword - GetLSRegRHS (ARMul_State * state, ARMword instr) { - ARMword shamt, base; - - base = RHSReg; -#ifndef MODE32 - if (base == 15) - /* Now forbidden, but ... */ - base = ECC | ER15INT | R15PC | EMODE; - else -#endif - base = state->Reg[base]; - - shamt = BITS (7, 11); - switch ((int) BITS (5, 6)) { - case LSL: - return (base << shamt); - case LSR: - if (shamt == 0) - return (0); - else - return (base >> shamt); - case ASR: - if (shamt == 0) - return ((ARMword) (( int) base >> 31L)); - else - return ((ARMword) (( int) base >> (int) shamt)); - case ROR: - if (shamt == 0) - /* It's an RRX. */ - return ((base >> 1) | (CFLAG << 31)); - else - return ((base << (32 - shamt)) | (base >> shamt)); - default: - break; - } - return 0; - } - - /* This routine evaluates the ARM7T halfword and signed transfer RHS's. */ - - static ARMword - GetLS7RHS (ARMul_State * state, ARMword instr) { - if (BIT (22) == 0) { - /* Register. */ -#ifndef MODE32 - if (RHSReg == 15) - /* Now forbidden, but ... */ - return ECC | ER15INT | R15PC | EMODE; -#endif - return state->Reg[RHSReg]; - } - - /* Immediate. */ - return BITS (0, 3) | (BITS (8, 11) << 4); - } - - static unsigned - LoadWord (ARMul_State * state, ARMword instr, ARMword address) { - ARMword dest; - - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - - dest = ARMul_LoadWordN (state, address); - - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - if (address & 3) - dest = ARMul_Align (state, address, dest); - WRITEDESTB (dest); - ARMul_Icycles (state, 1, 0L); - - return (DESTReg != LHSReg); - } - -#ifdef MODET - /* This function does the work of loading a halfword. */ - - static unsigned - LoadHalfWord (ARMul_State * state, ARMword instr, ARMword address, - int signextend) { - ARMword dest; - - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - dest = ARMul_LoadHalfWord (state, address); - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - UNDEF_LSRBPC; - if (signextend) - if (dest & 1 << (16 - 1)) - dest = (dest & ((1 << 16) - 1)) - (1 << 16); - - WRITEDEST (dest); - ARMul_Icycles (state, 1, 0L); - - return (DESTReg != LHSReg); - } - -#endif /* MODET */ - - /* This function does the work of loading a byte for a LDRB instruction. */ - - static unsigned - LoadByte (ARMul_State * state, ARMword instr, ARMword address, int signextend) { - ARMword dest; - - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - dest = ARMul_LoadByte (state, address); - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - UNDEF_LSRBPC; - if (signextend) - if (dest & 1 << (8 - 1)) - dest = (dest & ((1 << 8) - 1)) - (1 << 8); - - WRITEDEST (dest); - ARMul_Icycles (state, 1, 0L); - - return (DESTReg != LHSReg); - } - - /* This function does the work of loading two words for a LDRD instruction. */ - - static void - Handle_Load_Double (ARMul_State * state, ARMword instr) { - ARMword dest_reg; - ARMword addr_reg; - ARMword write_back = BIT (21); - ARMword immediate = BIT (22); - ARMword add_to_base = BIT (23); - ARMword pre_indexed = BIT (24); - ARMword offset; - ARMword addr; - ARMword sum; - ARMword base; - ARMword value1; - ARMword value2; - - BUSUSEDINCPCS; - - /* If the writeback bit is set, the pre-index bit must be clear. */ - if (write_back && !pre_indexed) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Extract the base address register. */ - addr_reg = LHSReg; - - /* Extract the destination register and check it. */ - dest_reg = DESTReg; - - /* Destination register must be even. */ - if ((dest_reg & 1) - /* Destination register cannot be LR. */ - || (dest_reg == 14)) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Compute the base address. */ - base = state->Reg[addr_reg]; - - /* Compute the offset. */ - offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state-> - Reg[RHSReg]; - - /* Compute the sum of the two. */ - if (add_to_base) - sum = base + offset; - else - sum = base - offset; - - /* If this is a pre-indexed mode use the sum. */ - if (pre_indexed) - addr = sum; - else - addr = base; - - /* The address must be aligned on a 8 byte boundary. */ - /*if (addr & 0x7) { - #ifdef ABORTS - ARMul_DATAABORT (addr); - #else - ARMul_UndefInstr (state, instr); - #endif - return; - }*/ - /* Lets just forcibly align it for now */ - //addr = (addr + 7) & ~7; - - /* For pre indexed or post indexed addressing modes, - check that the destination registers do not overlap - the address registers. */ - if ((!pre_indexed || write_back) - && (addr_reg == dest_reg || addr_reg == dest_reg + 1)) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Load the words. */ - value1 = ARMul_LoadWordN (state, addr); - value2 = ARMul_LoadWordN (state, addr + 4); - - /* Check for data aborts. */ - if (state->Aborted) { - TAKEABORT; - return; - } - - ARMul_Icycles (state, 2, 0L); - - /* Store the values. */ - state->Reg[dest_reg] = value1; - state->Reg[dest_reg + 1] = value2; - - /* Do the post addressing and writeback. */ - if (!pre_indexed) - addr = sum; - - if (!pre_indexed || write_back) - state->Reg[addr_reg] = addr; - } - - /* This function does the work of storing two words for a STRD instruction. */ - - static void - Handle_Store_Double (ARMul_State * state, ARMword instr) { - ARMword src_reg; - ARMword addr_reg; - ARMword write_back = BIT (21); - ARMword immediate = BIT (22); - ARMword add_to_base = BIT (23); - ARMword pre_indexed = BIT (24); - ARMword offset; - ARMword addr; - ARMword sum; - ARMword base; - - BUSUSEDINCPCS; - - /* If the writeback bit is set, the pre-index bit must be clear. */ - if (write_back && !pre_indexed) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Extract the base address register. */ - addr_reg = LHSReg; - - /* Base register cannot be PC. */ - if (addr_reg == 15) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Extract the source register. */ - src_reg = DESTReg; - - /* Source register must be even. */ - if (src_reg & 1) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Compute the base address. */ - base = state->Reg[addr_reg]; - - /* Compute the offset. */ - offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state-> - Reg[RHSReg]; - - /* Compute the sum of the two. */ - if (add_to_base) - sum = base + offset; - else - sum = base - offset; - - /* If this is a pre-indexed mode use the sum. */ - if (pre_indexed) - addr = sum; - else - addr = base; - - /* The address must be aligned on a 8 byte boundary. */ - /*if (addr & 0x7) { - #ifdef ABORTS - ARMul_DATAABORT (addr); - #else - ARMul_UndefInstr (state, instr); - #endif - return; - }*/ - /* Lets just forcibly align it for now */ - //addr = (addr + 7) & ~7; - - /* For pre indexed or post indexed addressing modes, - check that the destination registers do not overlap - the address registers. */ - if ((!pre_indexed || write_back) - && (addr_reg == src_reg || addr_reg == src_reg + 1)) { - ARMul_UndefInstr (state, instr); - return; - } - - /* Load the words. */ - ARMul_StoreWordN (state, addr, state->Reg[src_reg]); - ARMul_StoreWordN (state, addr + 4, state->Reg[src_reg + 1]); - - if (state->Aborted) { - TAKEABORT; - return; - } - - /* Do the post addressing and writeback. */ - if (!pre_indexed) - addr = sum; - - if (!pre_indexed || write_back) - state->Reg[addr_reg] = addr; - } - - /* This function does the work of storing a word from a STR instruction. */ - - static unsigned - StoreWord (ARMul_State * state, ARMword instr, ARMword address) { - BUSUSEDINCPCN; -#ifndef MODE32 - if (DESTReg == 15) - state->Reg[15] = ECC | ER15INT | R15PC | EMODE; -#endif -#ifdef MODE32 - ARMul_StoreWordN (state, address, DEST); -#else - if (VECTORACCESS (address) || ADDREXCEPT (address)) { - INTERNALABORT (address); - (void) ARMul_LoadWordN (state, address); - } else - ARMul_StoreWordN (state, address, DEST); -#endif - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - - return TRUE; - } - -#ifdef MODET - /* This function does the work of storing a byte for a STRH instruction. */ - - static unsigned - StoreHalfWord (ARMul_State * state, ARMword instr, ARMword address) { - BUSUSEDINCPCN; - -#ifndef MODE32 - if (DESTReg == 15) - state->Reg[15] = ECC | ER15INT | R15PC | EMODE; -#endif - -#ifdef MODE32 - ARMul_StoreHalfWord (state, address, DEST); -#else - if (VECTORACCESS (address) || ADDREXCEPT (address)) { - INTERNALABORT (address); - (void) ARMul_LoadHalfWord (state, address); - } else - ARMul_StoreHalfWord (state, address, DEST); -#endif - - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - return TRUE; - } - -#endif /* MODET */ - - /* This function does the work of storing a byte for a STRB instruction. */ - - static unsigned - StoreByte (ARMul_State * state, ARMword instr, ARMword address) { - BUSUSEDINCPCN; -#ifndef MODE32 - if (DESTReg == 15) - state->Reg[15] = ECC | ER15INT | R15PC | EMODE; -#endif -#ifdef MODE32 - ARMul_StoreByte (state, address, DEST); -#else - if (VECTORACCESS (address) || ADDREXCEPT (address)) { - INTERNALABORT (address); - (void) ARMul_LoadByte (state, address); - } else - ARMul_StoreByte (state, address, DEST); -#endif - if (state->Aborted) { - TAKEABORT; - return state->lateabtSig; - } - //UNDEF_LSRBPC; - return TRUE; - } - - /* This function does the work of loading the registers listed in an LDM - instruction, when the S bit is clear. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - - static void - LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase) { - ARMword dest, temp; - - //UNDEF_LSMNoRegs; - //UNDEF_LSMPCBase; - //UNDEF_LSMBaseInListWb; - BUSUSEDINCPCS; -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - /*chy 2004-05-23 may write twice - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - */ - /* N cycle first. */ - for (temp = 0; !BIT (temp); temp++); - - dest = ARMul_LoadWordN (state, address); - - if (!state->abortSig && !state->Aborted) - state->Reg[temp++] = dest; - else if (!state->Aborted) { - //XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - /*chy 2004-05-23 chy goto end*/ - if (state->Aborted) - goto L_ldm_makeabort; - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Load this register. */ - address += 4; - dest = ARMul_LoadWordS (state, address); - - if (!state->abortSig && !state->Aborted) - state->Reg[temp] = dest; - else if (!state->Aborted) { - /*XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address);*/ - state->Aborted = ARMul_DataAbortV; - } - /*chy 2004-05-23 chy goto end */ - if (state->Aborted) - goto L_ldm_makeabort; - } - - if (BIT (15) && !state->Aborted) - /* PC is in the reg list. */ - WriteR15Branch (state, PC); - - /* To write back the final register. */ - /* ARMul_Icycles (state, 1, 0L);*/ - /*chy 2004-05-23, see below - if (state->Aborted) - { - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - TAKEABORT; - } - */ - /*chy 2004-05-23 should compare the Abort Models*/ -L_ldm_makeabort: - /* To write back the final register. */ - ARMul_Icycles (state, 1, 0L); - - /* chy 2005-11-24, bug found by benjl@cse.unsw.edu.au, etc */ - /* - if (state->Aborted) - { - if (BIT (21) && LHSReg != 15) - if (!(state->abortSig && state->Aborted && state->lateabtSig == LOW)) - LSBase = WBBase; - TAKEABORT; - }else if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - */ - if (state->Aborted) { - if (BIT (21) && LHSReg != 15) { - if (!(state->abortSig)) { - } - } - TAKEABORT; - } else if (BIT (21) && LHSReg != 15) { - LSBase = WBBase; - } - /* chy 2005-11-24, over */ - } - - /* This function does the work of loading the registers listed in an LDM - instruction, when the S bit is set. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - - static void - LoadSMult (ARMul_State * state, - ARMword instr, ARMword address, ARMword WBBase) { - ARMword dest, temp; - - //UNDEF_LSMNoRegs; - //UNDEF_LSMPCBase; - //UNDEF_LSMBaseInListWb; - - BUSUSEDINCPCS; - -#ifndef MODE32 - if (ADDREXCEPT (address)) - INTERNALABORT (address); -#endif - /* chy 2004-05-23, may write twice - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - */ - if (!BIT (15) && state->Bank != USERBANK) { - /* Temporary reg bank switch. */ - (void) ARMul_SwitchMode (state, state->Mode, USER26MODE); - UNDEF_LSMUserBankWb; - } - - /* N cycle first. */ - for (temp = 0; !BIT (temp); temp++); - - dest = ARMul_LoadWordN (state, address); - - if (!state->abortSig) - state->Reg[temp++] = dest; - else if (!state->Aborted) { - //XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - - /*chy 2004-05-23 chy goto end*/ - if (state->Aborted) - goto L_ldm_s_makeabort; - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Load this register. */ - address += 4; - dest = ARMul_LoadWordS (state, address); - - if (!state->abortSig && !state->Aborted) - state->Reg[temp] = dest; - else if (!state->Aborted) { - /*XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address);*/ - state->Aborted = ARMul_DataAbortV; - } - /*chy 2004-05-23 chy goto end */ - if (state->Aborted) - goto L_ldm_s_makeabort; - } - - /*chy 2004-05-23 label of ldm_s_makeabort*/ -L_ldm_s_makeabort: - /*chy 2004-06-06 LSBase process should be here, not in the end of this function. Because ARMul_CPSRAltered maybe change R13(SP) R14(lr). If not, simulate INSTR ldmia sp!,[....pc]^ error.*/ - /*chy 2004-05-23 should compare the Abort Models*/ - if (state->Aborted) { - if (BIT (21) && LHSReg != 15) - if (! - (state->abortSig && state->Aborted - && state->lateabtSig == LOW)) - LSBase = WBBase; - TAKEABORT; - } else if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - if (BIT (15) && !state->Aborted) { - /* PC is in the reg list. */ -#ifdef MODE32 - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { - state->Cpsr = GETSPSR (state->Bank); - ARMul_CPSRAltered (state); - } - - WriteR15 (state, PC); -#else - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode == USER26MODE || state->Mode == USER32MODE ) { - /* Protect bits in user mode. */ - ASSIGNN ((state->Reg[15] & NBIT) != 0); - ASSIGNZ ((state->Reg[15] & ZBIT) != 0); - ASSIGNC ((state->Reg[15] & CBIT) != 0); - ASSIGNV ((state->Reg[15] & VBIT) != 0); - } else - ARMul_R15Altered (state); - - FLUSHPIPE; -#endif - } - - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (!BIT (15) && state->Mode != USER26MODE - && state->Mode != USER32MODE ) - /* Restore the correct bank. */ - (void) ARMul_SwitchMode (state, USER26MODE, state->Mode); - - /* To write back the final register. */ - ARMul_Icycles (state, 1, 0L); - /* chy 2004-05-23, see below - if (state->Aborted) - { - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - TAKEABORT; - } - */ - } - - /* This function does the work of storing the registers listed in an STM - instruction, when the S bit is clear. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - - static void - StoreMult (ARMul_State * state, - ARMword instr, ARMword address, ARMword WBBase) { - ARMword temp; - - UNDEF_LSMNoRegs; - UNDEF_LSMPCBase; - UNDEF_LSMBaseInListWb; - - if (!TFLAG) - /* N-cycle, increment the PC and update the NextInstr state. */ - BUSUSEDINCPCN; - -#ifndef MODE32 - if (VECTORACCESS (address) || ADDREXCEPT (address)) - INTERNALABORT (address); - - if (BIT (15)) - PATCHR15; -#endif - - /* N cycle first. */ - for (temp = 0; !BIT (temp); temp++); - -#ifdef MODE32 - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#else - if (state->Aborted) { - (void) ARMul_LoadWordN (state, address); - - /* Fake the Stores as Loads. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Save this register. */ - address += 4; - (void) ARMul_LoadWordS (state, address); - } - - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - TAKEABORT; - return; - } else - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#endif - - if (state->abortSig && !state->Aborted) { - //XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - -//chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_takeabort; - - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Save this register. */ - address += 4; - - ARMul_StoreWordS (state, address, state->Reg[temp]); - - if (state->abortSig && !state->Aborted) { - /*XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address);*/ - state->Aborted = ARMul_DataAbortV; - } - //chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_takeabort; - } - -//chy 2004-05-23,should compare the Abort Models -L_stm_takeabort: - if (BIT (21) && LHSReg != 15) { - if (! - (state->abortSig && state->Aborted - && state->lateabtSig == LOW)) - LSBase = WBBase; - } - if (state->Aborted) - TAKEABORT; - } - - /* This function does the work of storing the registers listed in an STM - instruction when the S bit is set. The code here is always increment - after, it's up to the caller to get the input address correct and to - handle base register modification. */ - - static void - StoreSMult (ARMul_State * state, - ARMword instr, ARMword address, ARMword WBBase) { - ARMword temp; - - UNDEF_LSMNoRegs; - UNDEF_LSMPCBase; - UNDEF_LSMBaseInListWb; - - BUSUSEDINCPCN; - -#ifndef MODE32 - if (VECTORACCESS (address) || ADDREXCEPT (address)) - INTERNALABORT (address); - - if (BIT (15)) - PATCHR15; -#endif - - if (state->Bank != USERBANK) { - /* Force User Bank. */ - (void) ARMul_SwitchMode (state, state->Mode, USER26MODE); - UNDEF_LSMUserBankWb; - } - - for (temp = 0; !BIT (temp); temp++); /* N cycle first. */ - -#ifdef MODE32 - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#else - if (state->Aborted) { - (void) ARMul_LoadWordN (state, address); - - for (; temp < 16; temp++) - /* Fake the Stores as Loads. */ - if (BIT (temp)) { - /* Save this register. */ - address += 4; - - (void) ARMul_LoadWordS (state, address); - } - - if (BIT (21) && LHSReg != 15) - LSBase = WBBase; - - TAKEABORT; - return; - } else - ARMul_StoreWordN (state, address, state->Reg[temp++]); -#endif - - if (state->abortSig && !state->Aborted) { - //XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address); - state->Aborted = ARMul_DataAbortV; - } - -//chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_s_takeabort; - /* S cycles from here on. */ - for (; temp < 16; temp++) - if (BIT (temp)) { - /* Save this register. */ - address += 4; - - ARMul_StoreWordS (state, address, state->Reg[temp]); - - if (state->abortSig && !state->Aborted) { - /*XScale_set_fsr_far (state, - ARMul_CP15_R5_ST_ALIGN, - address);*/ - state->Aborted = ARMul_DataAbortV; - } - //chy 2004-05-23, needn't store other when aborted - if (state->Aborted) - goto L_stm_s_takeabort; - } - - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode != USER26MODE && state->Mode != USER32MODE ) - /* Restore the correct bank. */ - (void) ARMul_SwitchMode (state, USER26MODE, state->Mode); - -//chy 2004-05-23,should compare the Abort Models -L_stm_s_takeabort: - if (BIT (21) && LHSReg != 15) { - if (! - (state->abortSig && state->Aborted - && state->lateabtSig == LOW)) - LSBase = WBBase; - } - - if (state->Aborted) - TAKEABORT; - } - - /* This function does the work of adding two 32bit values - together, and calculating if a carry has occurred. */ - - static ARMword - Add32 (ARMword a1, ARMword a2, int *carry) { - ARMword result = (a1 + a2); - unsigned int uresult = (unsigned int) result; - unsigned int ua1 = (unsigned int) a1; - - /* If (result == RdLo) and (state->Reg[nRdLo] == 0), - or (result > RdLo) then we have no carry. */ - if ((uresult == ua1) ? (a2 != 0) : (uresult < ua1)) - *carry = 1; - else - *carry = 0; - - return result; - } - - /* This function does the work of multiplying - two 32bit values to give a 64bit result. */ - - static unsigned - Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc) { - /* Operand register numbers. */ - int nRdHi, nRdLo, nRs, nRm; - ARMword RdHi = 0, RdLo = 0, Rm; - /* Cycle count. */ - int scount; - - nRdHi = BITS (16, 19); - nRdLo = BITS (12, 15); - nRs = BITS (8, 11); - nRm = BITS (0, 3); - - /* Needed to calculate the cycle count. */ - Rm = state->Reg[nRm]; - - /* Check for illegal operand combinations first. */ - if (nRdHi != 15 - && nRdLo != 15 - && nRs != 15 - //&& nRm != 15 && nRdHi != nRdLo && nRdHi != nRm && nRdLo != nRm) { - && nRm != 15 && nRdHi != nRdLo ) { - /* Intermediate results. */ - ARMword lo, mid1, mid2, hi; - int carry; - ARMword Rs = state->Reg[nRs]; - int sign = 0; - - if (msigned) { - /* Compute sign of result and adjust operands if necessary. */ - sign = (Rm ^ Rs) & 0x80000000; - - if (((signed int) Rm) < 0) - Rm = -Rm; - - if (((signed int) Rs) < 0) - Rs = -Rs; - } - - /* We can split the 32x32 into four 16x16 operations. This - ensures that we do not lose precision on 32bit only hosts. */ - lo = ((Rs & 0xFFFF) * (Rm & 0xFFFF)); - mid1 = ((Rs & 0xFFFF) * ((Rm >> 16) & 0xFFFF)); - mid2 = (((Rs >> 16) & 0xFFFF) * (Rm & 0xFFFF)); - hi = (((Rs >> 16) & 0xFFFF) * ((Rm >> 16) & 0xFFFF)); - - /* We now need to add all of these results together, taking - care to propogate the carries from the additions. */ - RdLo = Add32 (lo, (mid1 << 16), &carry); - RdHi = carry; - RdLo = Add32 (RdLo, (mid2 << 16), &carry); - RdHi += (carry + ((mid1 >> 16) & 0xFFFF) + - ((mid2 >> 16) & 0xFFFF) + hi); - - if (sign) { - /* Negate result if necessary. */ - RdLo = ~RdLo; - RdHi = ~RdHi; - if (RdLo == 0xFFFFFFFF) { - RdLo = 0; - RdHi += 1; - } else - RdLo += 1; - } - - state->Reg[nRdLo] = RdLo; - state->Reg[nRdHi] = RdHi; - } else { - fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS, instr=0x%x\n", instr); - } - if (scc) - /* Ensure that both RdHi and RdLo are used to compute Z, - but don't let RdLo's sign bit make it to N. */ - ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF)); - - /* The cycle count depends on whether the instruction is a signed or - unsigned multiply, and what bits are clear in the multiplier. */ - if (msigned && (Rm & ((unsigned) 1 << 31))) - /* Invert the bits to make the check against zero. */ - Rm = ~Rm; - - if ((Rm & 0xFFFFFF00) == 0) - scount = 1; - else if ((Rm & 0xFFFF0000) == 0) - scount = 2; - else if ((Rm & 0xFF000000) == 0) - scount = 3; - else - scount = 4; - - return 2 + scount; - } - - /* This function does the work of multiplying two 32bit - values and adding a 64bit value to give a 64bit result. */ - - static unsigned - MultiplyAdd64 (ARMul_State * state, ARMword instr, int msigned, int scc) { - unsigned scount; - ARMword RdLo, RdHi; - int nRdHi, nRdLo; - int carry = 0; - - nRdHi = BITS (16, 19); - nRdLo = BITS (12, 15); - - RdHi = state->Reg[nRdHi]; - RdLo = state->Reg[nRdLo]; - - scount = Multiply64 (state, instr, msigned, LDEFAULT); - - RdLo = Add32 (RdLo, state->Reg[nRdLo], &carry); - RdHi = (RdHi + state->Reg[nRdHi]) + carry; - - state->Reg[nRdLo] = RdLo; - state->Reg[nRdHi] = RdHi; - - if (scc) - /* Ensure that both RdHi and RdLo are used to compute Z, - but don't let RdLo's sign bit make it to N. */ - ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF)); - - /* Extra cycle for addition. */ - return scount + 1; - } - - /* Attempt to emulate an ARMv6 instruction. - Returns non-zero upon success. */ - - static int handle_v6_insn(ARMul_State* state, ARMword instr) { - switch (BITS(20, 27)) { - case 0x03: - printf ("Unhandled v6 insn: ldr\n"); - break; - case 0x04: // UMAAL - { - const u8 rm_idx = BITS(8, 11); - const u8 rn_idx = BITS(0, 3); - const u8 rd_lo_idx = BITS(12, 15); - const u8 rd_hi_idx = BITS(16, 19); - - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - const u32 rd_lo_val = state->Reg[rd_lo_idx]; - const u32 rd_hi_val = state->Reg[rd_hi_idx]; - - const u64 result = (rn_val * rm_val) + rd_lo_val + rd_hi_val; - - state->Reg[rd_lo_idx] = (result & 0xFFFFFFFF); - state->Reg[rd_hi_idx] = ((result >> 32) & 0xFFFFFFFF); - return 1; - } - break; - case 0x06: - printf ("Unhandled v6 insn: mls/str\n"); - break; - case 0x16: - printf ("Unhandled v6 insn: smi\n"); - break; - case 0x18: - if (BITS(4, 7) == 0x9) { - /* strex */ - u32 l = LHSReg; - u32 r = RHSReg; - u32 lhs = LHS; - - bool enter = false; - - if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr))enter = true; - //StoreWord(state, lhs, RHS) - if (state->Aborted) { - TAKEABORT; - } - - if (enter) { - ARMul_StoreWordS(state, lhs, RHS); - state->Reg[DESTReg] = 0; - } - else { - state->Reg[DESTReg] = 1; - } - - return 1; - } - printf ("Unhandled v6 insn: strex\n"); - break; - case 0x19: - /* ldrex */ - if (BITS(4, 7) == 0x9) { - u32 lhs = LHS; - - state->currentexaddr = lhs; - state->currentexval = ARMul_ReadWord(state, lhs); - - LoadWord(state, instr, lhs); - return 1; - } - printf ("Unhandled v6 insn: ldrex\n"); - break; - case 0x1a: - printf ("Unhandled v6 insn: strexd\n"); - break; - case 0x1b: - printf ("Unhandled v6 insn: ldrexd\n"); - break; - case 0x1c: - if (BITS(4, 7) == 0x9) { - /* strexb */ - u32 lhs = LHS; - - bool enter = false; - - if (state->currentexval == (u32)ARMul_ReadByte(state, state->currentexaddr))enter = true; - - BUSUSEDINCPCN; - if (state->Aborted) { - TAKEABORT; - } - - if (enter) { - ARMul_StoreByte(state, lhs, RHS); - state->Reg[DESTReg] = 0; - } - else { - state->Reg[DESTReg] = 1; - } - - //printf("In %s, strexb not implemented\n", __FUNCTION__); - UNDEF_LSRBPC; - /* WRITESDEST (dest); */ - return 1; - } - printf ("Unhandled v6 insn: strexb\n"); - break; - case 0x1d: - if ((BITS(4, 7)) == 0x9) { - /* ldrexb */ - u32 lhs = LHS; - LoadByte(state, instr, lhs, LUNSIGNED); - - state->currentexaddr = lhs; - state->currentexval = (u32)ARMul_ReadByte(state, lhs); - - //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); - //printf("ldrexb\n"); - //printf("instr is %x rm is %d\n", instr, BITS(16, 19)); - //exit(-1); - - //printf("In %s, ldrexb not implemented\n", __FUNCTION__); - return 1; - } - printf ("Unhandled v6 insn: ldrexb\n"); - break; - case 0x1e: - printf ("Unhandled v6 insn: strexh\n"); - break; - case 0x1f: - printf ("Unhandled v6 insn: ldrexh\n"); - break; - case 0x30: - printf ("Unhandled v6 insn: movw\n"); - break; - case 0x32: - printf ("Unhandled v6 insn: nop/sev/wfe/wfi/yield\n"); - break; - case 0x34: - printf ("Unhandled v6 insn: movt\n"); - break; - case 0x3f: - printf ("Unhandled v6 insn: rbit\n"); - break; - case 0x61: // SADD16, SASX, SSAX, and SSUB16 - if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || - (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) - { - const u8 rd_idx = BITS(12, 15); - const u8 rm_idx = BITS(0, 3); - const u8 rn_idx = BITS(16, 19); - const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); - const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); - const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); - const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); - - s32 lo_result; - s32 hi_result; - - // SADD16 - if ((instr & 0xFF0) == 0xf10) { - lo_result = (rn_lo + rm_lo); - hi_result = (rn_hi + rm_hi); - } - // SASX - else if ((instr & 0xFF0) == 0xf30) { - lo_result = (rn_lo - rm_hi); - hi_result = (rn_hi + rm_lo); - } - // SSAX - else if ((instr & 0xFF0) == 0xf50) { - lo_result = (rn_lo + rm_hi); - hi_result = (rn_hi - rm_lo); - } - // SSUB16 - else { - lo_result = (rn_lo - rm_lo); - hi_result = (rn_hi - rm_hi); - } - - state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); - - if (lo_result >= 0) { - state->GEFlag |= (1 << 16); - state->GEFlag |= (1 << 17); - } else { - state->GEFlag &= ~(1 << 16); - state->GEFlag &= ~(1 << 17); - } - - if (hi_result >= 0) { - state->GEFlag |= (1 << 18); - state->GEFlag |= (1 << 19); - } else { - state->GEFlag &= ~(1 << 18); - state->GEFlag &= ~(1 << 19); - } - - return 1; - } - // SADD8/SSUB8 - else if ((instr & 0xFF0) == 0xf90 || (instr & 0xFF0) == 0xff0) - { - const u8 rd_idx = BITS(12, 15); - const u8 rm_idx = BITS(0, 3); - const u8 rn_idx = BITS(16, 19); - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - - s32 lo_val1, lo_val2; - s32 hi_val1, hi_val2; - - // SADD8 - if ((instr & 0xFF0) == 0xf90) { - lo_val1 = (s32)(s8)(rn_val & 0xFF) + (s32)(s8)(rm_val & 0xFF); - lo_val2 = (s32)(s8)((rn_val >> 8) & 0xFF) + (s32)(s8)((rm_val >> 8) & 0xFF); - hi_val1 = (s32)(s8)((rn_val >> 16) & 0xFF) + (s32)(s8)((rm_val >> 16) & 0xFF); - hi_val2 = (s32)(s8)((rn_val >> 24) & 0xFF) + (s32)(s8)((rm_val >> 24) & 0xFF); - } - // SSUB8 - else { - lo_val1 = (s32)(s8)(rn_val & 0xFF) - (s32)(s8)(rm_val & 0xFF); - lo_val2 = (s32)(s8)((rn_val >> 8) & 0xFF) - (s32)(s8)((rm_val >> 8) & 0xFF); - hi_val1 = (s32)(s8)((rn_val >> 16) & 0xFF) - (s32)(s8)((rm_val >> 16) & 0xFF); - hi_val2 = (s32)(s8)((rn_val >> 24) & 0xFF) - (s32)(s8)((rm_val >> 24) & 0xFF); - } - - if (lo_val1 >= 0) - state->GEFlag |= (1 << 16); - else - state->GEFlag &= ~(1 << 16); - - if (lo_val2 >= 0) - state->GEFlag |= (1 << 17); - else - state->GEFlag &= ~(1 << 17); - - if (hi_val1 >= 0) - state->GEFlag |= (1 << 18); - else - state->GEFlag &= ~(1 << 18); - - if (hi_val2 >= 0) - state->GEFlag |= (1 << 19); - else - state->GEFlag &= ~(1 << 19); - - state->Reg[rd_idx] = ((lo_val1 & 0xFF) | ((lo_val2 & 0xFF) << 8) | ((hi_val1 & 0xFF) << 16) | ((hi_val2 & 0xFF) << 24)); - return 1; - } - else { - printf("Unhandled v6 insn: %08x", instr); - } - break; - case 0x62: // QADD16, QASX, QSAX, QSUB16, QADD8, and QSUB8 - { - const u8 op2 = BITS(5, 7); - - const u8 rd_idx = BITS(12, 15); - const u8 rn_idx = BITS(16, 19); - const u8 rm_idx = BITS(0, 3); - const u16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); - const u16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF); - const u16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); - const u16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF); - - u16 lo_result = 0; - u16 hi_result = 0; - - // QADD16 - if (op2 == 0x00) { - lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_lo); - hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_hi); - } - // QASX - else if (op2 == 0x01) { - lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_hi); - hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_lo); - } - // QSAX - else if (op2 == 0x02) { - lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_hi); - hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_lo); - } - // QSUB16 - else if (op2 == 0x03) { - lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_lo); - hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_hi); - } - // QADD8 - else if (op2 == 0x04) { - lo_result = ARMul_SignedSaturatedAdd8(rn_lo & 0xFF, rm_lo & 0xFF) | - ARMul_SignedSaturatedAdd8(rn_lo >> 8, rm_lo >> 8) << 8; - hi_result = ARMul_SignedSaturatedAdd8(rn_hi & 0xFF, rm_hi & 0xFF) | - ARMul_SignedSaturatedAdd8(rn_hi >> 8, rm_hi >> 8) << 8; - } - // QSUB8 - else if (op2 == 0x07) { - lo_result = ARMul_SignedSaturatedSub8(rn_lo & 0xFF, rm_lo & 0xFF) | - ARMul_SignedSaturatedSub8(rn_lo >> 8, rm_lo >> 8) << 8; - hi_result = ARMul_SignedSaturatedSub8(rn_hi & 0xFF, rm_hi & 0xFF) | - ARMul_SignedSaturatedSub8(rn_hi >> 8, rm_hi >> 8) << 8; - } - - state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); - return 1; - } - break; - case 0x63: - printf ("Unhandled v6 insn: shadd/shsub\n"); - break; - case 0x65: - { - u32 rd = (instr >> 12) & 0xF; - u32 rn = (instr >> 16) & 0xF; - u32 rm = (instr >> 0) & 0xF; - u32 from = state->Reg[rn]; - u32 to = state->Reg[rm]; - - if ((instr & 0xFF0) == 0xF10 || (instr & 0xFF0) == 0xF70) { // UADD16/USUB16 - u32 h1, h2; - state->Cpsr &= 0xfff0ffff; - if ((instr & 0x0F0) == 0x070) { // USUB16 - h1 = ((u16)from - (u16)to); - h2 = ((u16)(from >> 16) - (u16)(to >> 16)); - - if (!(h1 & 0xffff0000)) - state->GEFlag |= (3 << 16); - else - state->GEFlag &= ~(3 << 16); - - if (!(h2 & 0xffff0000)) - state->GEFlag |= (3 << 18); - else - state->GEFlag &= ~(3 << 18); - } - else { // UADD16 - h1 = ((u16)from + (u16)to); - h2 = ((u16)(from >> 16) + (u16)(to >> 16)); - - if (h1 & 0xffff0000) - state->GEFlag |= (3 << 16); - else - state->GEFlag &= ~(3 << 16); - - if (h2 & 0xffff0000) - state->GEFlag |= (3 << 18); - else - state->GEFlag &= ~(3 << 18); - } - - state->Reg[rd] = (u32)((h1 & 0xffff) | ((h2 & 0xffff) << 16)); - return 1; - } - else - if ((instr & 0xFF0) == 0xF90 || (instr & 0xFF0) == 0xFF0) { // UADD8/USUB8 - u32 b1, b2, b3, b4; - state->Cpsr &= 0xfff0ffff; - if ((instr & 0x0F0) == 0x0F0) { // USUB8 - b1 = ((u8)from - (u8)to); - b2 = ((u8)(from >> 8) - (u8)(to >> 8)); - b3 = ((u8)(from >> 16) - (u8)(to >> 16)); - b4 = ((u8)(from >> 24) - (u8)(to >> 24)); - - if (!(b1 & 0xffffff00)) - state->GEFlag |= (1 << 16); - else - state->GEFlag &= ~(1 << 16); - - if (!(b2 & 0xffffff00)) - state->GEFlag |= (1 << 17); - else - state->GEFlag &= ~(1 << 17); - - if (!(b3 & 0xffffff00)) - state->GEFlag |= (1 << 18); - else - state->GEFlag &= ~(1 << 18); - - if (!(b4 & 0xffffff00)) - state->GEFlag |= (1 << 19); - else - state->GEFlag &= ~(1 << 19); - } - else { // UADD8 - b1 = ((u8)from + (u8)to); - b2 = ((u8)(from >> 8) + (u8)(to >> 8)); - b3 = ((u8)(from >> 16) + (u8)(to >> 16)); - b4 = ((u8)(from >> 24) + (u8)(to >> 24)); - - if (b1 & 0xffffff00) - state->GEFlag |= (1 << 16); - else - state->GEFlag &= ~(1 << 16); - - if (b2 & 0xffffff00) - state->GEFlag |= (1 << 17); - else - state->GEFlag &= ~(1 << 17); - - if (b3 & 0xffffff00) - state->GEFlag |= (1 << 18); - else - state->GEFlag &= ~(1 << 18); - - if (b4 & 0xffffff00) - state->GEFlag |= (1 << 19); - else - state->GEFlag &= ~(1 << 19); - } - - state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24); - return 1; - } - } - printf("Unhandled v6 insn: uasx/usax\n"); - break; - case 0x66: // UQADD16, UQASX, UQSAX, UQSUB16, UQADD8, and UQSUB8 - { - const u8 rd_idx = BITS(12, 15); - const u8 rm_idx = BITS(0, 3); - const u8 rn_idx = BITS(16, 19); - const u8 op2 = BITS(5, 7); - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - - u16 lo_val = 0; - u16 hi_val = 0; - - // UQADD16 - if (op2 == 0x00) { - lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); - hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF); - } - // UQASX - else if (op2 == 0x01) { - lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF); - hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF); - } - // UQSAX - else if (op2 == 0x02) { - lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF); - hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF); - } - // UQSUB16 - else if (op2 == 0x03) { - lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, rm_val & 0xFFFF); - hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF); - } - // UQADD8 - else if (op2 == 0x04) { - lo_val = ARMul_UnsignedSaturatedAdd8(rn_val, rm_val) | - ARMul_UnsignedSaturatedAdd8(rn_val >> 8, rm_val >> 8) << 8; - hi_val = ARMul_UnsignedSaturatedAdd8(rn_val >> 16, rm_val >> 16) | - ARMul_UnsignedSaturatedAdd8(rn_val >> 24, rm_val >> 24) << 8; - } - // UQSUB8 - else { - lo_val = ARMul_UnsignedSaturatedSub8(rn_val, rm_val) | - ARMul_UnsignedSaturatedSub8(rn_val >> 8, rm_val >> 8) << 8; - hi_val = ARMul_UnsignedSaturatedSub8(rn_val >> 16, rm_val >> 16) | - ARMul_UnsignedSaturatedSub8(rn_val >> 24, rm_val >> 24) << 8; - } - - state->Reg[rd_idx] = ((lo_val & 0xFFFF) | hi_val << 16); - return 1; - } - break; - case 0x67: // UHADD16, UHASX, UHSAX, UHSUB16, UHADD8, and UHSUB8. - { - const u8 op2 = BITS(5, 7); - - const u8 rm_idx = BITS(0, 3); - const u8 rn_idx = BITS(16, 19); - const u8 rd_idx = BITS(12, 15); - - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - - if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) - { - u32 lo_val = 0; - u32 hi_val = 0; - - // UHADD16 - if (op2 == 0x00) { - lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); - hi_val = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); - } - // UHASX - else if (op2 == 0x01) { - lo_val = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); - hi_val = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF); - } - // UHSAX - else if (op2 == 0x02) { - lo_val = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); - hi_val = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF); - } - // UHSUB16 - else if (op2 == 0x03) { - lo_val = (rn_val & 0xFFFF) - (rm_val & 0xFFFF); - hi_val = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); - } - - lo_val >>= 1; - hi_val >>= 1; - - state->Reg[rd_idx] = (lo_val & 0xFFFF) | ((hi_val & 0xFFFF) << 16); - return 1; - } - else if (op2 == 0x04 || op2 == 0x07) { - u32 sum1; - u32 sum2; - u32 sum3; - u32 sum4; - - // UHADD8 - if (op2 == 0x04) { - sum1 = (rn_val & 0xFF) + (rm_val & 0xFF); - sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF); - sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF); - sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF); - } - // UHSUB8 - else { - sum1 = (rn_val & 0xFF) - (rm_val & 0xFF); - sum2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF); - sum3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF); - sum4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF); - } - - sum1 >>= 1; - sum2 >>= 1; - sum3 >>= 1; - sum4 >>= 1; - - state->Reg[rd_idx] = (sum1 & 0xFF) | ((sum2 & 0xFF) << 8) | ((sum3 & 0xFF) << 16) | ((sum4 & 0xFF) << 24); - return 1; - } - } - break; - case 0x68: - { - u32 rd = (instr >> 12) & 0xF; - u32 rn = (instr >> 16) & 0xF; - u32 rm = (instr >> 0) & 0xF; - u32 from = state->Reg[rn]; - u32 to = state->Reg[rm]; - u32 cpsr = ARMul_GetCPSR(state); - if ((instr & 0xFF0) == 0xFB0) { // SEL - u32 result; - if (cpsr & (1 << 16)) - result = from & 0xff; - else - result = to & 0xff; - if (cpsr & (1 << 17)) - result |= from & 0x0000ff00; - else - result |= to & 0x0000ff00; - if (cpsr & (1 << 18)) - result |= from & 0x00ff0000; - else - result |= to & 0x00ff0000; - if (cpsr & (1 << 19)) - result |= from & 0xff000000; - else - result |= to & 0xff000000; - state->Reg[rd] = result; - return 1; - } - } - printf("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); - break; - - case 0x6a: // SSAT, SSAT16, SXTB, and SXTAB - { - const u8 op2 = BITS(5, 7); - - // SSAT16 - if (op2 == 0x01) { - const u8 rd_idx = BITS(12, 15); - const u8 rn_idx = BITS(0, 3); - const u8 num_bits = BITS(16, 19) + 1; - const s16 min = -(0x8000 >> (16 - num_bits)); - const s16 max = (0x7FFF >> (16 - num_bits)); - s16 rn_lo = (state->Reg[rn_idx]); - s16 rn_hi = (state->Reg[rn_idx] >> 16); - - if (rn_lo > max) { - rn_lo = max; - SETQ; - } else if (rn_lo < min) { - rn_lo = min; - SETQ; - } - - if (rn_hi > max) { - rn_hi = max; - SETQ; - } else if (rn_hi < min) { - rn_hi = min; - SETQ; - } - - state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); - return 1; - } - else if (op2 == 0x03) { - const u8 rotation = BITS(10, 11) * 8; - u32 rm = ((state->Reg[BITS(0, 3)] >> rotation) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - rotation)) & 0xFF) & 0xFF); - if (rm & 0x80) - rm |= 0xffffff00; - - // SXTB, otherwise SXTAB - if (BITS(16, 19) == 0xf) - state->Reg[BITS(12, 15)] = rm; - else - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - - return 1; - } - else { - printf("Unimplemented op: SSAT"); - } - } - break; - - case 0x6b: // REV, REV16, SXTH, and SXTAH - { - const u8 op2 = BITS(5, 7); - - // REV - if (op2 == 0x01) { - DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); - return 1; - } - // REV16 - else if (op2 == 0x05) { - DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); - return 1; - } - else if (op2 == 0x03) { - const u8 rotate = BITS(10, 11) * 8; - - u32 rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFFFF) & 0xFFFF); - if (rm & 0x8000) - rm |= 0xffff0000; - - // SXTH, otherwise SXTAH - if (BITS(16, 19) == 15) - state->Reg[BITS(12, 15)] = rm; - else - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - - return 1; - } - } - break; - - case 0x6c: // UXTB16 and UXTAB16 - { - const u8 rm_idx = BITS(0, 3); - const u8 rn_idx = BITS(16, 19); - const u8 rd_idx = BITS(12, 15); - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - const u32 rotation = BITS(10, 11) * 8; - const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); - - // UXTB16 - if ((instr & 0xf03f0) == 0xf0070) { - state->Reg[rd_idx] = rotated_rm & 0x00FF00FF; - } - else { // UXTAB16 - const u8 lo_rotated = (rotated_rm & 0xFF); - const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated; - - const u8 hi_rotated = (rotated_rm >> 16) & 0xFF; - const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated; - - state->Reg[rd_idx] = ((hi_result << 16) | (lo_result & 0xFFFF)); - } - - return 1; - } - break; - case 0x6e: // USAT, USAT16, UXTB, and UXTAB - { - const u8 op2 = BITS(5, 7); - - // USAT16 - if (op2 == 0x01) { - const u8 rd_idx = BITS(12, 15); - const u8 rn_idx = BITS(0, 3); - const u8 num_bits = BITS(16, 19); - const s16 max = 0xFFFF >> (16 - num_bits); - s16 rn_lo = (state->Reg[rn_idx]); - s16 rn_hi = (state->Reg[rn_idx] >> 16); - - if (max < rn_lo) { - rn_lo = max; - SETQ; - } else if (rn_lo < 0) { - rn_lo = 0; - SETQ; - } - - if (max < rn_hi) { - rn_hi = max; - SETQ; - } else if (rn_hi < 0) { - rn_hi = 0; - SETQ; - } - - state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); - return 1; - } - else if (op2 == 0x03) { - const u8 rotate = BITS(10, 11) * 8; - const u32 rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFF) & 0xFF); - - if (BITS(16, 19) == 0xf) - /* UXTB */ - state->Reg[BITS(12, 15)] = rm; - else - /* UXTAB */ - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - - return 1; - } - else { - printf("Unimplemented op: USAT"); - } - } - break; - - case 0x6f: // UXTH, UXTAH, and REVSH. - { - const u8 op2 = BITS(5, 7); - - // REVSH - if (op2 == 0x05) { - DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8); - if (DEST & 0x8000) - DEST |= 0xffff0000; - return 1; - } - // UXTH and UXTAH - else if (op2 == 0x03) { - const u8 rotate = BITS(10, 11) * 8; - const ARMword rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFFFF) & 0xFFFF); - - // UXTH - if (BITS(16, 19) == 0xf) { - state->Reg[BITS(12, 15)] = rm; - } - // UXTAH - else { - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - } - - return 1; - } - } - case 0x70: - // ichfly - // SMUAD, SMUSD, SMLAD, and SMLSD - if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || - (instr & 0xd0) == 0x10 || (instr & 0xd0) == 0x50) - { - const u8 rd_idx = BITS(16, 19); - const u8 rn_idx = BITS(0, 3); - const u8 rm_idx = BITS(8, 11); - const u8 ra_idx = BITS(12, 15); - const bool do_swap = (BIT(5) == 1); - - u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - - if (do_swap) - rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); - - const s16 rm_lo = (rm_val & 0xFFFF); - const s16 rm_hi = ((rm_val >> 16) & 0xFFFF); - const s16 rn_lo = (rn_val & 0xFFFF); - const s16 rn_hi = ((rn_val >> 16) & 0xFFFF); - - const u32 product1 = (rn_lo * rm_lo); - const u32 product2 = (rn_hi * rm_hi); - - // SMUAD and SMLAD - if (BIT(6) == 0) { - state->Reg[rd_idx] = product1 + product2; - - if (BITS(12, 15) != 15) { - state->Reg[rd_idx] += state->Reg[ra_idx]; - if (ARMul_AddOverflowQ(product1 + product2, state->Reg[ra_idx])) - SETQ; - } - - if (ARMul_AddOverflowQ(product1, product2)) - SETQ; - } - // SMUSD and SMLSD - else { - state->Reg[rd_idx] = product1 - product2; - - if (BITS(12, 15) != 15) { - state->Reg[rd_idx] += state->Reg[ra_idx]; - - if (ARMul_AddOverflowQ(product1 - product2, state->Reg[ra_idx])) - SETQ; - } - } - - return 1; - } - break; - case 0x74: // SMLALD and SMLSLD - { - const u8 rm_idx = BITS(8, 11); - const u8 rn_idx = BITS(0, 3); - const u8 rdlo_idx = BITS(12, 15); - const u8 rdhi_idx = BITS(16, 19); - const bool do_swap = (BIT(5) == 1); - - const u32 rdlo_val = state->Reg[rdlo_idx]; - const u32 rdhi_val = state->Reg[rdhi_idx]; - const u32 rn_val = state->Reg[rn_idx]; - u32 rm_val = state->Reg[rm_idx]; - - if (do_swap) - rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); - - const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); - const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); - s64 result; - - // SMLALD - if (BIT(6) == 0) { - result = (product1 + product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32)); - } - // SMLSLD - else { - result = (product1 - product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32)); - } - - state->Reg[rdlo_idx] = (result & 0xFFFFFFFF); - state->Reg[rdhi_idx] = ((result >> 32) & 0xFFFFFFFF); - return 1; - } - break; - case 0x75: // SMMLA, SMMUL, and SMMLS - { - const u8 rm_idx = BITS(8, 11); - const u8 rn_idx = BITS(0, 3); - const u8 ra_idx = BITS(12, 15); - const u8 rd_idx = BITS(16, 19); - const bool do_round = (BIT(5) == 1); - - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - - // Assume SMMUL by default. - s64 result = (s64)(s32)rn_val * (s64)(s32)rm_val; - - if (ra_idx != 15) { - const u32 ra_val = state->Reg[ra_idx]; - - // SMMLA, otherwise SMMLS - if (BIT(6) == 0) - result += ((s64)ra_val << 32); - else - result = ((s64)ra_val << 32) - result; - } - - if (do_round) - result += 0x80000000; - - state->Reg[rd_idx] = ((result >> 32) & 0xFFFFFFFF); - return 1; - } - break; - case 0x78: - if (BITS(20, 24) == 0x18) - { - const u8 rm_idx = BITS(8, 11); - const u8 rn_idx = BITS(0, 3); - const u8 rd_idx = BITS(16, 19); - - const u32 rm_val = state->Reg[rm_idx]; - const u32 rn_val = state->Reg[rn_idx]; - - const u8 diff1 = ARMul_UnsignedAbsoluteDifference(rn_val & 0xFF, rm_val & 0xFF); - const u8 diff2 = ARMul_UnsignedAbsoluteDifference((rn_val >> 8) & 0xFF, (rm_val >> 8) & 0xFF); - const u8 diff3 = ARMul_UnsignedAbsoluteDifference((rn_val >> 16) & 0xFF, (rm_val >> 16) & 0xFF); - const u8 diff4 = ARMul_UnsignedAbsoluteDifference((rn_val >> 24) & 0xFF, (rm_val >> 24) & 0xFF); - - u32 finalDif = (diff1 + diff2 + diff3 + diff4); - - // Op is USADA8 if true. - const u8 ra_idx = BITS(12, 15); - if (ra_idx != 15) - finalDif += state->Reg[ra_idx]; - - state->Reg[rd_idx] = finalDif; - return 1; - } - break; - case 0x7a: - printf ("Unhandled v6 insn: usbfx\n"); - break; - case 0x7c: - printf ("Unhandled v6 insn: bfc/bfi\n"); - break; - case 0x84: - printf ("Unhandled v6 insn: srs\n"); - break; - default: - break; - } - printf("Unhandled v6 insn: UNKNOWN: %08x %08X\n", instr, BITS(20, 27)); - return 0; - }
\ No newline at end of file diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 8ab5ef160..7b502e240 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -25,24 +25,13 @@ void ARMul_EmulateInit(); ARMul_State* ARMul_NewState(ARMul_State* state); void ARMul_Reset (ARMul_State* state); -ARMword ARMul_DoCycle(ARMul_State* state); -unsigned ARMul_DoCoPro(ARMul_State* state); -ARMword ARMul_DoProg(ARMul_State* state); -ARMword ARMul_DoInstr(ARMul_State* state); -void ARMul_Abort(ARMul_State* state, ARMword address); unsigned ARMul_MultTable[32] = { 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16 }; -ARMword ARMul_ImmedTable[4096]; /* immediate DP LHS values */ -char ARMul_BitList[256]; /* number of bits in a byte table */ - -void arm_dyncom_Abort(ARMul_State * state, ARMword vector) -{ - ARMul_Abort(state, vector); -} - +ARMword ARMul_ImmedTable[4096]; // immediate DP LHS values +char ARMul_BitList[256]; // number of bits in a byte table /***************************************************************************\ * Call this routine once to set up the emulator's tables. * @@ -51,18 +40,21 @@ void ARMul_EmulateInit() { unsigned int i, j; - for (i = 0; i < 4096; i++) { /* the values of 12 bit dp rhs's */ + // the values of 12 bit dp rhs's + for (i = 0; i < 4096; i++) { ARMul_ImmedTable[i] = ROTATER (i & 0xffL, (i >> 7L) & 0x1eL); } - for (i = 0; i < 256; ARMul_BitList[i++] = 0); /* how many bits in LSM */ + // how many bits in LSM + for (i = 0; i < 256; ARMul_BitList[i++] = 0); for (j = 1; j < 256; j <<= 1) for (i = 0; i < 256; i++) if ((i & j) > 0) ARMul_BitList[i]++; + // you always need 4 times these values for (i = 0; i < 256; i++) - ARMul_BitList[i] *= 4; /* you always need 4 times these values */ + ARMul_BitList[i] *= 4; } @@ -71,24 +63,22 @@ void ARMul_EmulateInit() \***************************************************************************/ ARMul_State* ARMul_NewState(ARMul_State* state) { - unsigned i, j; - memset (state, 0, sizeof (ARMul_State)); state->Emulate = RUN; - for (i = 0; i < 16; i++) { + for (unsigned int i = 0; i < 16; i++) { state->Reg[i] = 0; - for (j = 0; j < 7; j++) + for (unsigned int j = 0; j < 7; j++) state->RegBank[j][i] = 0; } - for (i = 0; i < 7; i++) + for (unsigned int i = 0; i < 7; i++) state->Spsr[i] = 0; + state->Mode = 0; - state->Debug = FALSE; state->VectorCatch = 0; - state->Aborted = FALSE; - state->Reseted = FALSE; + state->Aborted = false; + state->Reseted = false; state->Inted = 3; state->LastInted = 3; @@ -103,12 +93,6 @@ ARMul_State* ARMul_NewState(ARMul_State* state) state->lateabtSig = HIGH; state->bigendSig = LOW; - //chy:2003-08-19 - state->CP14R0_CCD = -1; - - memset(&state->exclusive_tag_array[0], 0xFF, sizeof(state->exclusive_tag_array[0]) * 128); - state->exclusive_access_state = 0; - return state; } @@ -126,15 +110,15 @@ void ARMul_SelectProcessor(ARMul_State* state, unsigned properties) state->data32Sig = HIGH; } - state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) ? HIGH : LOW; - state->is_v5 = (properties & ARM_v5_Prop) ? HIGH : LOW; - state->is_v5e = (properties & ARM_v5e_Prop) ? HIGH : LOW; - state->is_XScale = (properties & ARM_XScale_Prop) ? HIGH : LOW; - state->is_iWMMXt = (properties & ARM_iWMMXt_Prop) ? HIGH : LOW; - state->is_v6 = (properties & ARM_v6_Prop) ? HIGH : LOW; - state->is_ep9312 = (properties & ARM_ep9312_Prop) ? HIGH : LOW; - state->is_pxa27x = (properties & ARM_PXA27X_Prop) ? HIGH : LOW; - state->is_v7 = (properties & ARM_v7_Prop) ? HIGH : LOW; + state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0; + state->is_v5 = (properties & ARM_v5_Prop) != 0; + state->is_v5e = (properties & ARM_v5e_Prop) != 0; + state->is_XScale = (properties & ARM_XScale_Prop) != 0; + state->is_iWMMXt = (properties & ARM_iWMMXt_Prop) != 0; + state->is_v6 = (properties & ARM_v6_Prop) != 0; + state->is_ep9312 = (properties & ARM_ep9312_Prop) != 0; + state->is_pxa27x = (properties & ARM_PXA27X_Prop) != 0; + state->is_v7 = (properties & ARM_v7_Prop) != 0; /* Only initialse the coprocessor support once we know what kind of chip we are dealing with. */ @@ -172,121 +156,4 @@ void ARMul_Reset(ARMul_State* state) state->AbortAddr = 1; state->NumInstrs = 0; - state->NumNcycles = 0; - state->NumScycles = 0; - state->NumIcycles = 0; - state->NumCcycles = 0; - state->NumFcycles = 0; -} - - -/***************************************************************************\ -* Emulate the execution of an entire program. Start the correct emulator * -* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * -* address of the last instruction that is executed. * -\***************************************************************************/ -ARMword ARMul_DoProg(ARMul_State* state) -{ - ARMword pc = 0; - - state->Emulate = RUN; - while (state->Emulate != STOP) { - state->Emulate = RUN; - - if (state->prog32Sig && ARMul_MODE32BIT) { - pc = ARMul_Emulate32 (state); - } - else { - //pc = ARMul_Emulate26 (state); - } - } - - return pc; -} - -/***************************************************************************\ -* Emulate the execution of one instruction. Start the correct emulator * -* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * -* address of the instruction that is executed. * -\***************************************************************************/ -ARMword ARMul_DoInstr(ARMul_State* state) -{ - ARMword pc = 0; - - state->Emulate = ONCE; - - if (state->prog32Sig && ARMul_MODE32BIT) { - pc = ARMul_Emulate32 (state); - } - - return pc; -} - -/***************************************************************************\ -* This routine causes an Abort to occur, including selecting the correct * -* mode, register bank, and the saving of registers. Call with the * -* appropriate vector's memory address (0,4,8 ....) * -\***************************************************************************/ -void ARMul_Abort(ARMul_State* state, ARMword vector) -{ - ARMword temp; - int isize = INSN_SIZE; - int esize = (TFLAG ? 0 : 4); - int e2size = (TFLAG ? -4 : 0); - - state->Aborted = FALSE; - - if (state->prog32Sig) - if (ARMul_MODE26BIT) - temp = R15PC; - else - temp = state->Reg[15]; - else - temp = R15PC | ECC | ER15INT | EMODE; - - switch (vector) { - case ARMul_ResetV: /* RESET */ - SETABORT (INTBITS, state->prog32Sig ? SVC32MODE : SVC26MODE, - 0); - break; - case ARMul_UndefinedInstrV: /* Undefined Instruction */ - SETABORT (IBIT, state->prog32Sig ? UNDEF32MODE : SVC26MODE, - isize); - break; - case ARMul_SWIV: /* Software Interrupt */ - SETABORT (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE, - isize); - break; - case ARMul_PrefetchAbortV: /* Prefetch Abort */ - state->AbortAddr = 1; - SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, - esize); - break; - case ARMul_DataAbortV: /* Data Abort */ - SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, - e2size); - break; - case ARMul_AddrExceptnV: /* Address Exception */ - SETABORT (IBIT, SVC26MODE, isize); - break; - case ARMul_IRQV: /* IRQ */ - SETABORT (IBIT, - state->prog32Sig ? IRQ32MODE : IRQ26MODE, - esize); - break; - case ARMul_FIQV: /* FIQ */ - SETABORT (INTBITS, - state->prog32Sig ? FIQ32MODE : FIQ26MODE, - esize); - break; - } - - if (ARMul_MODE32BIT) { - /*if (state->mmu.control & CONTROL_VECTOR) - vector += 0xffff0000; //for v4 high exception address*/ - if (state->vector_remap_flag) - vector += state->vector_remap_addr; /* support some remap function in LPC processor */ - ARMul_SetR15 (state, vector); - } else - ARMul_SetR15 (state, R15CCINTMODE | vector); } diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 5a8f09b22..fd90fb0a4 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -20,395 +20,13 @@ #include "core/arm/disassembler/arm_disasm.h" #include "core/mem_map.h" - -static ARMword ModeToBank (ARMword); - -/* This routine returns the value of a register from a mode. */ - -ARMword -ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg) -{ - mode &= MODEBITS; - if (mode != state->Mode) - return (state->RegBank[ModeToBank ((ARMword) mode)][reg]); - else - return (state->Reg[reg]); -} - -/* This routine sets the value of a register for a mode. */ - -void -ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value) -{ - mode &= MODEBITS; - if (mode != state->Mode) - state->RegBank[ModeToBank ((ARMword) mode)][reg] = value; - else - state->Reg[reg] = value; -} - -/* This routine returns the value of the PC, mode independently. */ - -ARMword -ARMul_GetPC (ARMul_State * state) -{ - if (state->Mode > SVC26MODE) - return state->Reg[15]; - else - return R15PC; -} - -/* This routine returns the value of the PC, mode independently. */ - -ARMword -ARMul_GetNextPC (ARMul_State * state) -{ - if (state->Mode > SVC26MODE) - return state->Reg[15] + INSN_SIZE; - else - return (state->Reg[15] + INSN_SIZE) & R15PCBITS; -} - -/* This routine sets the value of the PC. */ - -void -ARMul_SetPC (ARMul_State * state, ARMword value) -{ - if (ARMul_MODE32BIT) - state->Reg[15] = value & PCBITS; - else - state->Reg[15] = R15CCINTMODE | (value & R15PCBITS); - FLUSHPIPE; -} - -/* This routine returns the value of register 15, mode independently. */ - -ARMword -ARMul_GetR15 (ARMul_State * state) -{ - if (state->Mode > SVC26MODE) - return (state->Reg[15]); - else - return (R15PC | ECC | ER15INT | EMODE); -} - -/* This routine sets the value of Register 15. */ - -void -ARMul_SetR15 (ARMul_State * state, ARMword value) -{ - if (ARMul_MODE32BIT) - state->Reg[15] = value & PCBITS; - else { - state->Reg[15] = value; - ARMul_R15Altered (state); - } - FLUSHPIPE; -} - -/* This routine returns the value of the CPSR. */ - -ARMword -ARMul_GetCPSR (ARMul_State * state) -{ - //chy 2003-08-20: below is from gdb20030716, maybe isn't suitable for system simulator - //return (CPSR | state->Cpsr); for gdb20030716 - return (CPSR); //had be tested in old skyeye with gdb5.0-5.3 -} - -/* This routine sets the value of the CPSR. */ - -void -ARMul_SetCPSR (ARMul_State * state, ARMword value) -{ - state->Cpsr = value; - ARMul_CPSRAltered (state); -} - -/* This routine does all the nasty bits involved in a write to the CPSR, - including updating the register bank, given a MSR instruction. */ - -void -ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs) -{ - state->Cpsr = ARMul_GetCPSR (state); - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { - /* In user mode, only write flags. */ - if (BIT (16)) - SETPSR_C (state->Cpsr, rhs); - if (BIT (17)) - SETPSR_X (state->Cpsr, rhs); - if (BIT (18)) - SETPSR_S (state->Cpsr, rhs); - } - if (BIT (19)) - SETPSR_F (state->Cpsr, rhs); - ARMul_CPSRAltered (state); -} - -/* Get an SPSR from the specified mode. */ - -ARMword -ARMul_GetSPSR (ARMul_State * state, ARMword mode) -{ - ARMword bank = ModeToBank (mode & MODEBITS); - - if (!BANK_CAN_ACCESS_SPSR (bank)) - return ARMul_GetCPSR (state); - - return state->Spsr[bank]; -} - -/* This routine does a write to an SPSR. */ - -void -ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) -{ - ARMword bank = ModeToBank (mode & MODEBITS); - - if (BANK_CAN_ACCESS_SPSR (bank)) - state->Spsr[bank] = value; -} - -/* This routine does a write to the current SPSR, given an MSR instruction. */ - -void -ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs) -{ - if (BANK_CAN_ACCESS_SPSR (state->Bank)) { - if (BIT (16)) - SETPSR_C (state->Spsr[state->Bank], rhs); - if (BIT (17)) - SETPSR_X (state->Spsr[state->Bank], rhs); - if (BIT (18)) - SETPSR_S (state->Spsr[state->Bank], rhs); - if (BIT (19)) - SETPSR_F (state->Spsr[state->Bank], rhs); - } -} - -/* This routine updates the state of the emulator after the Cpsr has been - changed. Both the processor flags and register bank are updated. */ - -void -ARMul_CPSRAltered (ARMul_State * state) -{ - ARMword oldmode; - - if (state->prog32Sig == LOW) - state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS); - - oldmode = state->Mode; - - /*if (state->Mode != (state->Cpsr & MODEBITS)) { - state->Mode = - ARMul_SwitchMode (state, state->Mode, - state->Cpsr & MODEBITS); - - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - }*/ - //state->Cpsr &= ~MODEBITS; - - ASSIGNINT (state->Cpsr & INTBITS); - //state->Cpsr &= ~INTBITS; - ASSIGNN ((state->Cpsr & NBIT) != 0); - //state->Cpsr &= ~NBIT; - ASSIGNZ ((state->Cpsr & ZBIT) != 0); - //state->Cpsr &= ~ZBIT; - ASSIGNC ((state->Cpsr & CBIT) != 0); - //state->Cpsr &= ~CBIT; - ASSIGNV ((state->Cpsr & VBIT) != 0); - //state->Cpsr &= ~VBIT; - ASSIGNQ ((state->Cpsr & QBIT) != 0); - //state->Cpsr &= ~QBIT; - state->GEFlag = (state->Cpsr & 0x000F0000); -#ifdef MODET - ASSIGNT ((state->Cpsr & TBIT) != 0); - //state->Cpsr &= ~TBIT; -#endif - - if (oldmode > SVC26MODE) { - if (state->Mode <= SVC26MODE) { - state->Emulate = CHANGEMODE; - state->Reg[15] = ECC | ER15INT | EMODE | R15PC; - } - } else { - if (state->Mode > SVC26MODE) { - state->Emulate = CHANGEMODE; - state->Reg[15] = R15PC; - } else - state->Reg[15] = ECC | ER15INT | EMODE | R15PC; - } -} - -/* This routine updates the state of the emulator after register 15 has - been changed. Both the processor flags and register bank are updated. - This routine should only be called from a 26 bit mode. */ - -void -ARMul_R15Altered (ARMul_State * state) -{ - if (state->Mode != R15MODE) { - state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE); - state->NtransSig = (state->Mode & 3) ? HIGH : LOW; - } - - if (state->Mode > SVC26MODE) - state->Emulate = CHANGEMODE; - - ASSIGNR15INT (R15INT); - - ASSIGNN ((state->Reg[15] & NBIT) != 0); - ASSIGNZ ((state->Reg[15] & ZBIT) != 0); - ASSIGNC ((state->Reg[15] & CBIT) != 0); - ASSIGNV ((state->Reg[15] & VBIT) != 0); -} - -/* This routine controls the saving and restoring of registers across mode - changes. The regbank matrix is largely unused, only rows 13 and 14 are - used across all modes, 8 to 14 are used for FIQ, all others use the USER - column. It's easier this way. old and new parameter are modes numbers. - Notice the side effect of changing the Bank variable. */ - -ARMword -ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode) -{ - unsigned i; - ARMword oldbank; - ARMword newbank; - static int revision_value = 53; - - oldbank = ModeToBank (oldmode); - newbank = state->Bank = ModeToBank (newmode); - - /* Do we really need to do it? */ - if (oldbank != newbank) { - if (oldbank == 3 && newbank == 2) { - //printf("icounter is %d PC is %x MODE CHANGED : %d --> %d\n", state->NumInstrs, state->pc, oldbank, newbank); - if (state->NumInstrs >= 5832487) { -// printf("%d, ", state->NumInstrs + revision_value); -// printf("revision_value : %d\n", revision_value); - revision_value ++; - } - } - /* Save away the old registers. */ - switch (oldbank) { - case USERBANK: - case IRQBANK: - case SVCBANK: - case ABORTBANK: - case UNDEFBANK: - if (newbank == FIQBANK) - for (i = 8; i < 13; i++) - state->RegBank[USERBANK][i] = - state->Reg[i]; - state->RegBank[oldbank][13] = state->Reg[13]; - state->RegBank[oldbank][14] = state->Reg[14]; - break; - case FIQBANK: - for (i = 8; i < 15; i++) - state->RegBank[FIQBANK][i] = state->Reg[i]; - break; - case DUMMYBANK: - for (i = 8; i < 15; i++) - state->RegBank[DUMMYBANK][i] = 0; - break; - default: - abort (); - } - - /* Restore the new registers. */ - switch (newbank) { - case USERBANK: - case IRQBANK: - case SVCBANK: - case ABORTBANK: - case UNDEFBANK: - if (oldbank == FIQBANK) - for (i = 8; i < 13; i++) - state->Reg[i] = - state->RegBank[USERBANK][i]; - state->Reg[13] = state->RegBank[newbank][13]; - state->Reg[14] = state->RegBank[newbank][14]; - break; - case FIQBANK: - for (i = 8; i < 15; i++) - state->Reg[i] = state->RegBank[FIQBANK][i]; - break; - case DUMMYBANK: - for (i = 8; i < 15; i++) - state->Reg[i] = 0; - break; - default: - abort (); - } - } - - return newmode; -} - -/* Given a processor mode, this routine returns the - register bank that will be accessed in that mode. */ - -static ARMword -ModeToBank (ARMword mode) -{ - static ARMword bankofmode[] = { - USERBANK, FIQBANK, IRQBANK, SVCBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, - USERBANK, FIQBANK, IRQBANK, SVCBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK, - DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK - }; - - if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0]))) - return DUMMYBANK; - - return bankofmode[mode]; -} - -/* Returns the register number of the nth register in a reg list. */ - -unsigned -ARMul_NthReg (ARMword instr, unsigned number) -{ - unsigned bit, upto; - - for (bit = 0, upto = 0; upto <= number; bit++) - if (BIT (bit)) - upto++; - - return (bit - 1); -} - -/* Unsigned sum of absolute difference */ +// Unsigned sum of absolute difference u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) { - if (left > right) - return left - right; + if (left > right) + return left - right; - return right - left; -} - -/* Assigns the N and Z flags depending on the value of result. */ - -void -ARMul_NegZero (ARMul_State * state, ARMword result) -{ - if (NEG (result)) { - SETN; - CLEARZ; - } else if (result == 0) { - CLEARN; - SETZ; - } else { - CLEARN; - CLEARZ; - } + return right - left; } // Add with carry, indicates if a carry-out or signed overflow occurred. @@ -441,23 +59,6 @@ bool SubOverflow(ARMword a, ARMword b, ARMword result) (POS(a) && NEG(b) && NEG(result))); } -/* Assigns the C flag after an addition of a and b to give result. */ - -void -ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNC ((NEG (a) && NEG (b)) || - (NEG (a) && POS (result)) || (NEG (b) && POS (result))); -} - -/* Assigns the V flag after an addition of a and b to give result. */ - -void -ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNV (AddOverflow (a, b, result)); -} - // Returns true if the Q flag should be set as a result of overflow. bool ARMul_AddOverflowQ(ARMword a, ARMword b) { @@ -468,24 +69,7 @@ bool ARMul_AddOverflowQ(ARMword a, ARMword b) return false; } -/* Assigns the C flag after an subtraction of a and b to give result. */ - -void -ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNC ((NEG (a) && POS (b)) || - (NEG (a) && POS (result)) || (POS (b) && POS (result))); -} - -/* Assigns the V flag after an subtraction of a and b to give result. */ - -void -ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) -{ - ASSIGNV (SubOverflow (a, b, result)); -} - -/* 8-bit signed saturated addition */ +// 8-bit signed saturated addition u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) { u8 result = left + right; @@ -500,7 +84,7 @@ u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) return result; } -/* 8-bit signed saturated subtraction */ +// 8-bit signed saturated subtraction u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) { u8 result = left - right; @@ -515,7 +99,7 @@ u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) return result; } -/* 16-bit signed saturated addition */ +// 16-bit signed saturated addition u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) { u16 result = left + right; @@ -530,7 +114,7 @@ u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) return result; } -/* 16-bit signed saturated subtraction */ +// 16-bit signed saturated subtraction u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) { u16 result = left - right; @@ -545,7 +129,7 @@ u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) return result; } -/* 8-bit unsigned saturated addition */ +// 8-bit unsigned saturated addition u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) { u8 result = left + right; @@ -556,7 +140,7 @@ u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) return result; } -/* 16-bit unsigned saturated addition */ +// 16-bit unsigned saturated addition u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) { u16 result = left + right; @@ -567,7 +151,7 @@ u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) return result; } -/* 8-bit unsigned saturated subtraction */ +// 8-bit unsigned saturated subtraction u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) { if (left <= right) @@ -576,7 +160,7 @@ u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) return left - right; } -/* 16-bit unsigned saturated subtraction */ +// 16-bit unsigned saturated subtraction u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) { if (left <= right) @@ -620,444 +204,3 @@ u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) *saturation_occurred = false; return (u32)value; } - -/* This function does the work of generating the addresses used in an - LDC instruction. The code here is always post-indexed, it's up to the - caller to get the input address correct and to handle base register - modification. It also handles the Busy-Waiting. */ - -void -ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address) -{ - unsigned cpab; - ARMword data; - - UNDEF_LSCPCBaseWb; - //printf("SKYEYE ARMul_LDC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); - /*chy 2004-05-23 should update this function in the future,should concern dataabort*/ -// chy 2004-05-25 , fix it now,so needn't printf -// printf("SKYEYE ARMul_LDC, should update this function!!!!!\n"); - //exit(-1); - - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->LDC[CPNum]) { - /* - printf - ("SKYEYE ARMul_LDC,NOT ALLOW, underinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - ARMul_UndefInstr (state, instr); - return; - } - - /*if (ADDREXCEPT (address)) - INTERNALABORT (address);*/ - - cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - - if (IntPending (state)) { - cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } else - cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, - 0); - } - if (cpab == ARMul_CANT) { - /* - printf - ("SKYEYE ARMul_LDC,NOT CAN, underinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - CPTAKEABORT; - return; - } - - cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0); - data = ARMul_LoadWordN (state, address); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_ldc_takeabort; - - BUSUSEDINCPCN; -//chy 2004-05-25 - /* - if (BIT (21)) - LSBase = state->Base; - */ - - cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); - - while (cpab == ARMul_INC) { - address += 4; - data = ARMul_LoadWordN (state, address); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_ldc_takeabort; - - cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); - } - -//chy 2004-05-25 -L_ldc_takeabort: - if (BIT (21)) { - if (! - ((state->abortSig || state->Aborted) - && state->lateabtSig == LOW)) - LSBase = state->Base; - } - - if (state->abortSig || state->Aborted) - TAKEABORT; -} - -/* This function does the work of generating the addresses used in an - STC instruction. The code here is always post-indexed, it's up to the - caller to get the input address correct and to handle base register - modification. It also handles the Busy-Waiting. */ - -void -ARMul_STC (ARMul_State * state, ARMword instr, ARMword address) -{ - unsigned cpab; - ARMword data; - - UNDEF_LSCPCBaseWb; - - //printf("SKYEYE ARMul_STC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); - /*chy 2004-05-23 should update this function in the future,should concern dataabort */ -// skyeye_instr_debug=0;printf("SKYEYE debug end!!!!\n"); -// chy 2004-05-25 , fix it now,so needn't printf -// printf("SKYEYE ARMul_STC, should update this function!!!!!\n"); - - //exit(-1); - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->STC[CPNum]) { - /* - printf - ("SKYEYE ARMul_STC,NOT ALLOW, undefinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - ARMul_UndefInstr (state, instr); - return; - } - - /*if (ADDREXCEPT (address) || VECTORACCESS (address)) - INTERNALABORT (address);*/ - - cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } else - cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, - &data); - } - - if (cpab == ARMul_CANT) { - /* - printf - ("SKYEYE ARMul_STC,CANT, undefinstr, CPnum is %x, instr %x, addr %x\n", - CPNum, instr, address); - */ - CPTAKEABORT; - return; - } - /*#ifndef MODE32 - if (ADDREXCEPT (address) || VECTORACCESS (address)) - INTERNALABORT (address); - #endif*/ - BUSUSEDINCPCN; -//chy 2004-05-25 - /* - if (BIT (21)) - LSBase = state->Base; - */ - cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); - ARMul_StoreWordN (state, address, data); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_stc_takeabort; - - while (cpab == ARMul_INC) { - address += 4; - cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); - ARMul_StoreWordN (state, address, data); - //chy 2004-05-25 - if (state->abortSig || state->Aborted) - goto L_stc_takeabort; - } -//chy 2004-05-25 -L_stc_takeabort: - if (BIT (21)) { - if (! - ((state->abortSig || state->Aborted) - && state->lateabtSig == LOW)) - LSBase = state->Base; - } - - if (state->abortSig || state->Aborted) - TAKEABORT; -} - -/* This function does the Busy-Waiting for an MCR instruction. */ - -void -ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source) -{ - unsigned cpab; - int cm = BITS(0, 3) & 0xf; - int cp = BITS(5, 7) & 0x7; - int rd = BITS(12, 15) & 0xf; - int cn = BITS(16, 19) & 0xf; - int cpopc = BITS(21, 23) & 0x7; - - if (CPNum == 15 && source == 0) //Cache flush - { - return; - } - - //printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source); - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->MCR[CPNum]) { - //chy 2004-07-19 should fix in the future ????!!!! - LOG_ERROR(Core_ARM11, "SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x",CPNum, source); - ARMul_UndefInstr (state, instr); - return; - } - - //DEBUG("SKYEYE ARMul_MCR p%d, %d, r%d, c%d, c%d, %d\n", CPNum, cpopc, rd, cn, cm, cp); - //DEBUG("plutoo: MCR not implemented\n"); - //exit(1); - //return; - - cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); - - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - - if (IntPending (state)) { - cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } else - cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, - source); - } - - if (cpab == ARMul_CANT) { - LOG_ERROR(Core_ARM11, "SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x", instr, CPNum, source); //ichfly todo - //ARMul_Abort (state, ARMul_UndefinedInstrV); - } else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - } -} - -/* This function does the Busy-Waiting for an MCRR instruction. */ - -void -ARMul_MCRR (ARMul_State * state, ARMword instr, ARMword source1, ARMword source2) -{ - unsigned cpab; - - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->MCRR[CPNum]) { - ARMul_UndefInstr (state, instr); - return; - } - - cpab = (state->MCRR[CPNum]) (state, ARMul_FIRST, instr, source1, source2); - - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - - if (IntPending (state)) { - cpab = (state->MCRR[CPNum]) (state, ARMul_INTERRUPT, - instr, 0, 0); - return; - } else - cpab = (state->MCRR[CPNum]) (state, ARMul_BUSY, instr, - source1, source2); - } - if (cpab == ARMul_CANT) { - printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x, source %x %x\n", __FUNCTION__, CPNum, instr, source1, source2); - ARMul_Abort (state, ARMul_UndefinedInstrV); - } else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - } -} - -/* This function does the Busy-Waiting for an MRC instruction. */ - -ARMword ARMul_MRC (ARMul_State * state, ARMword instr) -{ - int cm = BITS(0, 3) & 0xf; - int cp = BITS(5, 7) & 0x7; - int rd = BITS(12, 15) & 0xf; - int cn = BITS(16, 19) & 0xf; - int cpopc = BITS(21, 23) & 0x7; - - if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer - ARMword result = Memory::KERNEL_MEMORY_VADDR; - - if (result != -1) { - return result; - } - } - - //DEBUG("SKYEYE ARMul_MRC p%d, %d, r%d, c%d, c%d, %d\n", CPNum, cpopc, rd, cn, cm, cp); - //DEBUG("plutoo: MRC not implemented\n"); - //return; - - unsigned cpab; - ARMword result = 0; - - //printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->MRC[CPNum]) { - //chy 2004-07-19 should fix in the future????!!!! - LOG_ERROR(Core_ARM11, "SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x", CPNum, instr); - ARMul_UndefInstr (state, instr); - return -1; - } - - cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return (0); - } else - cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, - &result); - } - if (cpab == ARMul_CANT) { - printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr); - ARMul_Abort (state, ARMul_UndefinedInstrV); - /* Parent will destroy the flags otherwise. */ - result = ECC; - } else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - ARMul_Icycles (state, 1, 0); - } - - return result; -} - -/* This function does the Busy-Waiting for an MRRC instruction. (to verify) */ - -void -ARMul_MRRC (ARMul_State * state, ARMword instr, ARMword * dest1, ARMword * dest2) -{ - unsigned cpab; - ARMword result1 = 0; - ARMword result2 = 0; - - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->MRRC[CPNum]) { - ARMul_UndefInstr (state, instr); - return; - } - - cpab = (state->MRRC[CPNum]) (state, ARMul_FIRST, instr, &result1, &result2); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->MRRC[CPNum]) (state, ARMul_INTERRUPT, - instr, 0, 0); - return; - } else - cpab = (state->MRRC[CPNum]) (state, ARMul_BUSY, instr, - &result1, &result2); - } - if (cpab == ARMul_CANT) { - printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x\n", __FUNCTION__, CPNum, instr); - ARMul_Abort (state, ARMul_UndefinedInstrV); - } else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - ARMul_Icycles (state, 1, 0); - } - - *dest1 = result1; - *dest2 = result2; -} - -/* This function does the Busy-Waiting for an CDP instruction. */ - -void -ARMul_CDP (ARMul_State * state, ARMword instr) -{ - unsigned cpab; - - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - if (!state->CDP[CPNum]) { - ARMul_UndefInstr (state, instr); - return; - } - cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, - instr); - return; - } else - cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr); - } - if (cpab == ARMul_CANT) - ARMul_Abort (state, ARMul_UndefinedInstrV); - else - BUSUSEDN; -} - -/* This function handles Undefined instructions, as CP isntruction. */ - -void -ARMul_UndefInstr (ARMul_State * state, ARMword instr) -{ - std::string disasm = ARM_Disasm::Disassemble(state->pc, instr); - LOG_ERROR(Core_ARM11, "Undefined instruction!! Disasm: %s Opcode: 0x%x", disasm.c_str(), instr); - ARMul_Abort (state, ARMul_UndefinedInstrV); -} - -/* Return TRUE if an interrupt is pending, FALSE otherwise. */ - -unsigned -IntPending (ARMul_State * state) -{ - /* Any exceptions. */ - if (state->NresetSig == LOW) { - ARMul_Abort (state, ARMul_ResetV); - return TRUE; - } else if (!state->NfiqSig && !FFLAG) { - ARMul_Abort (state, ARMul_FIQV); - return TRUE; - } else if (!state->NirqSig && !IFLAG) { - ARMul_Abort (state, ARMul_IRQV); - return TRUE; - } - - return FALSE; -} - -/* Align a word access to a non word boundary. */ - -ARMword -ARMul_Align (ARMul_State* state, ARMword address, ARMword data) -{ - /* This code assumes the address is really unaligned, - as a shift by 32 is undefined in C. */ - - address = (address & 3) << 3; /* Get the word address. */ - return ((data >> address) | (data << (32 - address))); /* rot right */ -} diff --git a/src/core/arm/interpreter/armvirt.cpp b/src/core/arm/interpreter/armvirt.cpp deleted file mode 100644 index 7845d1042..000000000 --- a/src/core/arm/interpreter/armvirt.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* armvirt.c -- ARMulator virtual memory interace: ARM6 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* This file contains a complete ARMulator memory model, modelling a -"virtual memory" system. A much simpler model can be found in armfast.c, -and that model goes faster too, but has a fixed amount of memory. This -model's memory has 64K pages, allocated on demand from a 64K entry page -table. The routines PutWord and GetWord implement this. Pages are never -freed as they might be needed again. A single area of memory may be -defined to generate aborts. */ - -#include "core/arm/skyeye_common/armdefs.h" -#include "core/arm/skyeye_common/armemu.h" - -#include "core/mem_map.h" - -#define dumpstack 1 -#define dumpstacksize 0x10 -#define maxdmupaddr 0x0033a850 - -/*ARMword ARMul_GetCPSR (ARMul_State * state) { -return 0; -} -ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode) { -return 0; -} -void ARMul_SetCPSR (ARMul_State * state, ARMword value) { - -} -void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) { - -}*/ - -void ARMul_Icycles(ARMul_State * state, unsigned number, ARMword address) { -} - -void ARMul_Ccycles(ARMul_State * state, unsigned number, ARMword address) { -} - -ARMword ARMul_LoadInstrS(ARMul_State * state, ARMword address, ARMword isize) { - state->NumScycles++; - -#ifdef HOURGLASS - if ((state->NumScycles & HOURGLASS_RATE) == 0) { - HOURGLASS; - } -#endif - if (isize == 2) - return (u16)Memory::Read16(address); - else - return (u32)Memory::Read32(address); -} - -ARMword ARMul_LoadInstrN(ARMul_State * state, ARMword address, ARMword isize) { - state->NumNcycles++; - - if (isize == 2) - return (u16)Memory::Read16(address); - else - return (u32)Memory::Read32(address); -} - -ARMword ARMul_ReLoadInstr(ARMul_State * state, ARMword address, ARMword isize) { - ARMword data; - - if ((isize == 2) && (address & 0x2)) { - ARMword lo; - lo = (u16)Memory::Read16(address); - return lo; - } - - data = (u32)Memory::Read32(address); - return data; -} - -ARMword ARMul_ReadWord(ARMul_State * state, ARMword address) { - ARMword data; - data = Memory::Read32(address); - return data; -} - -ARMword ARMul_LoadWordS(ARMul_State * state, ARMword address) { - state->NumScycles++; - return ARMul_ReadWord(state, address); -} - -ARMword ARMul_LoadWordN(ARMul_State * state, ARMword address) { - state->NumNcycles++; - return ARMul_ReadWord(state, address); -} - -ARMword ARMul_LoadHalfWord(ARMul_State * state, ARMword address) { - state->NumNcycles++; - return (u16)Memory::Read16(address);; -} - -ARMword ARMul_ReadByte(ARMul_State * state, ARMword address) { - return (u8)Memory::Read8(address); -} - -ARMword ARMul_LoadByte(ARMul_State * state, ARMword address) { - state->NumNcycles++; - return ARMul_ReadByte(state, address); -} - -void ARMul_StoreHalfWord(ARMul_State * state, ARMword address, ARMword data) { - state->NumNcycles++; - Memory::Write16(address, data); -} - -void ARMul_StoreByte(ARMul_State * state, ARMword address, ARMword data) { - state->NumNcycles++; - ARMul_WriteByte(state, address, data); -} - -ARMword ARMul_SwapWord(ARMul_State * state, ARMword address, ARMword data) { - ARMword temp; - state->NumNcycles++; - temp = ARMul_ReadWord(state, address); - state->NumNcycles++; - Memory::Write32(address, data); - return temp; -} - -ARMword ARMul_SwapByte(ARMul_State * state, ARMword address, ARMword data) { - ARMword temp; - temp = ARMul_LoadByte(state, address); - Memory::Write8(address, data); - return temp; -} - -void ARMul_WriteWord(ARMul_State * state, ARMword address, ARMword data) { - Memory::Write32(address, data); -} - -void ARMul_WriteByte(ARMul_State * state, ARMword address, ARMword data) -{ - Memory::Write8(address, data); -} - -void ARMul_StoreWordS(ARMul_State * state, ARMword address, ARMword data) -{ - state->NumScycles++; - ARMul_WriteWord(state, address, data); -} - -void ARMul_StoreWordN(ARMul_State * state, ARMword address, ARMword data) -{ - state->NumNcycles++; - ARMul_WriteWord(state, address, data); -} diff --git a/src/core/arm/interpreter/thumbemu.cpp b/src/core/arm/interpreter/thumbemu.cpp deleted file mode 100644 index 9cf80672d..000000000 --- a/src/core/arm/interpreter/thumbemu.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/* thumbemu.c -- Thumb instruction emulation. - Copyright (C) 1996, Cygnus Software Technologies Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* We can provide simple Thumb simulation by decoding the Thumb -instruction into its corresponding ARM instruction, and using the -existing ARM simulator. */ - -#include "core/arm/skyeye_common/skyeye_defs.h" - -#ifndef MODET /* required for the Thumb instruction support */ -#if 1 -#error "MODET needs to be defined for the Thumb world to work" -#else -#define MODET (1) -#endif -#endif - -#include "core/arm/skyeye_common/armdefs.h" -#include "core/arm/skyeye_common/armemu.h" -#include "core/arm/skyeye_common/armos.h" - - -/* Decode a 16bit Thumb instruction. The instruction is in the low - 16-bits of the tinstr field, with the following Thumb instruction - held in the high 16-bits. Passing in two Thumb instructions allows - easier simulation of the special dual BL instruction. */ - -tdstate -ARMul_ThumbDecode ( - ARMul_State *state, - ARMword pc, - ARMword tinstr, - ARMword *ainstr) -{ - tdstate valid = t_decoded; /* default assumes a valid instruction */ - ARMword next_instr; - - if (state->bigendSig) { - next_instr = tinstr & 0xFFFF; - tinstr >>= 16; - } - else { - next_instr = tinstr >> 16; - tinstr &= 0xFFFF; - } - -#if 1 /* debugging to catch non updates */ - *ainstr = 0xDEADC0DE; -#endif - - switch ((tinstr & 0xF800) >> 11) { - case 0: /* LSL */ - case 1: /* LSR */ - case 2: /* ASR */ - /* Format 1 */ - *ainstr = 0xE1B00000 /* base opcode */ - | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */ - |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */ - |((tinstr & 0x0038) >> 3) /* Rs */ - |((tinstr & 0x0007) << 12); /* Rd */ - break; - case 3: /* ADD/SUB */ - /* Format 2 */ - { - ARMword subset[4] = { - 0xE0900000, /* ADDS Rd,Rs,Rn */ - 0xE0500000, /* SUBS Rd,Rs,Rn */ - 0xE2900000, /* ADDS Rd,Rs,#imm3 */ - 0xE2500000 /* SUBS Rd,Rs,#imm3 */ - }; - /* It is quicker indexing into a table, than performing switch - or conditionals: */ - *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */ - |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */ - |((tinstr & 0x0038) << (16 - 3)) /* Rs */ - |((tinstr & 0x0007) << (12 - 0)); /* Rd */ - } - break; - case 4: /* MOV */ - case 5: /* CMP */ - case 6: /* ADD */ - case 7: /* SUB */ - /* Format 3 */ - { - ARMword subset[4] = { - 0xE3B00000, /* MOVS Rd,#imm8 */ - 0xE3500000, /* CMP Rd,#imm8 */ - 0xE2900000, /* ADDS Rd,Rd,#imm8 */ - 0xE2500000, /* SUBS Rd,Rd,#imm8 */ - }; - *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */ - |((tinstr & 0x00FF) >> 0) /* imm8 */ - |((tinstr & 0x0700) << (16 - 8)) /* Rn */ - |((tinstr & 0x0700) << (12 - 8)); /* Rd */ - } - break; - case 8: /* Arithmetic and high register transfers */ - /* TODO: Since the subsets for both Format 4 and Format 5 - instructions are made up of different ARM encodings, we could - save the following conditional, and just have one large - subset. */ - if ((tinstr & (1 << 10)) == 0) { - /* Format 4 */ - enum OpcodeType { t_norm, t_shift, t_neg, t_mul }; - struct ThumbOpcode { - ARMword opcode; - OpcodeType otype; - }; - - ThumbOpcode subset[16] = { - { - 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */ - { - 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */ - { - 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */ - { - 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */ - { - 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */ - { - 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */ - { - 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */ - { - 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */ - { - 0xE1100000, t_norm}, /* TST Rd,Rs */ - { - 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */ - { - 0xE1500000, t_norm}, /* CMP Rd,Rs */ - { - 0xE1700000, t_norm}, /* CMN Rd,Rs */ - { - 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */ - { - 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */ - { - 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */ - { - 0xE1F00000, t_norm} /* MVNS Rd,Rs */ - }; - *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */ - switch (subset[(tinstr & 0x03C0) >> 6].otype) { - case t_norm: - *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */ - |((tinstr & 0x0007) << 12) /* Rd */ - |((tinstr & 0x0038) >> 3); /* Rs */ - break; - case t_shift: - *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ - |((tinstr & 0x0007) >> 0) /* Rm */ - |((tinstr & 0x0038) << (8 - 3)); /* Rs */ - break; - case t_neg: - *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)); /* Rn */ - break; - case t_mul: - *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */ - |((tinstr & 0x0007) << 8) /* Rs */ - |((tinstr & 0x0038) >> 3); /* Rm */ - break; - } - } - else { - /* Format 5 */ - ARMword Rd = ((tinstr & 0x0007) >> 0); - ARMword Rs = ((tinstr & 0x0038) >> 3); - if (tinstr & (1 << 7)) - Rd += 8; - if (tinstr & (1 << 6)) - Rs += 8; - switch ((tinstr & 0x03C0) >> 6) { - case 0x1: /* ADD Rd,Rd,Hs */ - case 0x2: /* ADD Hd,Hd,Rs */ - case 0x3: /* ADD Hd,Hd,Hs */ - *ainstr = 0xE0800000 /* base */ - | (Rd << 16) /* Rn */ - |(Rd << 12) /* Rd */ - |(Rs << 0); /* Rm */ - break; - case 0x5: /* CMP Rd,Hs */ - case 0x6: /* CMP Hd,Rs */ - case 0x7: /* CMP Hd,Hs */ - *ainstr = 0xE1500000 /* base */ - | (Rd << 16) /* Rn */ - |(Rd << 12) /* Rd */ - |(Rs << 0); /* Rm */ - break; - case 0x9: /* MOV Rd,Hs */ - case 0xA: /* MOV Hd,Rs */ - case 0xB: /* MOV Hd,Hs */ - *ainstr = 0xE1A00000 /* base */ - | (Rd << 16) /* Rn */ - |(Rd << 12) /* Rd */ - |(Rs << 0); /* Rm */ - break; - case 0xC: /* BX Rs */ - case 0xD: /* BX Hs */ - *ainstr = 0xE12FFF10 /* base */ - | ((tinstr & 0x0078) >> 3); /* Rd */ - break; - case 0x0: /* UNDEFINED */ - case 0x4: /* UNDEFINED */ - case 0x8: /* UNDEFINED */ - valid = t_undefined; - break; - case 0xE: /* BLX */ - case 0xF: /* BLX */ - if (state->is_v5) { - *ainstr = 0xE1200030 /* base */ - |(Rs << 0); /* Rm */ - } else { - valid = t_undefined; - } - break; - } - } - break; - case 9: /* LDR Rd,[PC,#imm8] */ - /* Format 6 */ - *ainstr = 0xE59F0000 /* base */ - | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |((tinstr & 0x00FF) << (2 - 0)); /* off8 */ - break; - case 10: - case 11: - /* TODO: Format 7 and Format 8 perform the same ARM encoding, so - the following could be merged into a single subset, saving on - the following boolean: */ - if ((tinstr & (1 << 9)) == 0) { - /* Format 7 */ - ARMword subset[4] = { - 0xE7800000, /* STR Rd,[Rb,Ro] */ - 0xE7C00000, /* STRB Rd,[Rb,Ro] */ - 0xE7900000, /* LDR Rd,[Rb,Ro] */ - 0xE7D00000 /* LDRB Rd,[Rb,Ro] */ - }; - *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x01C0) >> 6); /* Ro */ - } - else { - /* Format 8 */ - ARMword subset[4] = { - 0xE18000B0, /* STRH Rd,[Rb,Ro] */ - 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */ - 0xE19000B0, /* LDRH Rd,[Rb,Ro] */ - 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */ - }; - *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x01C0) >> 6); /* Ro */ - } - break; - case 12: /* STR Rd,[Rb,#imm5] */ - case 13: /* LDR Rd,[Rb,#imm5] */ - case 14: /* STRB Rd,[Rb,#imm5] */ - case 15: /* LDRB Rd,[Rb,#imm5] */ - /* Format 9 */ - { - ARMword subset[4] = { - 0xE5800000, /* STR Rd,[Rb,#imm5] */ - 0xE5900000, /* LDR Rd,[Rb,#imm5] */ - 0xE5C00000, /* STRB Rd,[Rb,#imm5] */ - 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */ - }; - /* The offset range defends on whether we are transferring a - byte or word value: */ - *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */ - } - break; - case 16: /* STRH Rd,[Rb,#imm5] */ - case 17: /* LDRH Rd,[Rb,#imm5] */ - /* Format 10 */ - *ainstr = ((tinstr & (1 << 11)) /* base */ - ? 0xE1D000B0 /* LDRH */ - : 0xE1C000B0) /* STRH */ - |((tinstr & 0x0007) << (12 - 0)) /* Rd */ - |((tinstr & 0x0038) << (16 - 3)) /* Rb */ - |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */ - |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */ - break; - case 18: /* STR Rd,[SP,#imm8] */ - case 19: /* LDR Rd,[SP,#imm8] */ - /* Format 11 */ - *ainstr = ((tinstr & (1 << 11)) /* base */ - ? 0xE59D0000 /* LDR */ - : 0xE58D0000) /* STR */ - |((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |((tinstr & 0x00FF) << 2); /* off8 */ - break; - case 20: /* ADD Rd,PC,#imm8 */ - case 21: /* ADD Rd,SP,#imm8 */ - /* Format 12 */ - if ((tinstr & (1 << 11)) == 0) { - /* NOTE: The PC value used here should by word aligned */ - /* We encode shift-left-by-2 in the rotate immediate field, - so no shift of off8 is needed. */ - *ainstr = 0xE28F0F00 /* base */ - | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |(tinstr & 0x00FF); /* off8 */ - } - else { - /* We encode shift-left-by-2 in the rotate immediate field, - so no shift of off8 is needed. */ - *ainstr = 0xE28D0F00 /* base */ - | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ - |(tinstr & 0x00FF); /* off8 */ - } - break; - case 22: - case 23: - if ((tinstr & 0x0F00) == 0x0000) { - /* Format 13 */ - /* NOTE: The instruction contains a shift left of 2 - equivalent (implemented as ROR #30): */ - *ainstr = ((tinstr & (1 << 7)) /* base */ - ? 0xE24DDF00 /* SUB */ - : 0xE28DDF00) /* ADD */ - |(tinstr & 0x007F); /* off7 */ - } - else if ((tinstr & 0x0F00) == 0x0e00) - *ainstr = 0xEF000000 | SWI_Breakpoint; - else { - /* Format 14 */ - ARMword subset[4] = { - 0xE92D0000, /* STMDB sp!,{rlist} */ - 0xE92D4000, /* STMDB sp!,{rlist,lr} */ - 0xE8BD0000, /* LDMIA sp!,{rlist} */ - 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */ - }; - *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */ - |(tinstr & 0x00FF); /* mask8 */ - } - break; - case 24: /* STMIA */ - case 25: /* LDMIA */ - /* Format 15 */ - *ainstr = ((tinstr & (1 << 11)) /* base */ - ? 0xE8B00000 /* LDMIA */ - : 0xE8A00000) /* STMIA */ - |((tinstr & 0x0700) << (16 - 8)) /* Rb */ - |(tinstr & 0x00FF); /* mask8 */ - break; - case 26: /* Bcc */ - case 27: /* Bcc/SWI */ - if ((tinstr & 0x0F00) == 0x0F00) { - if (tinstr == (ARMul_ABORTWORD & 0xffff) && - state->AbortAddr == pc) { - *ainstr = ARMul_ABORTWORD; - break; - } - /* Format 17 : SWI */ - *ainstr = 0xEF000000; - /* Breakpoint must be handled specially. */ - if ((tinstr & 0x00FF) == 0x18) - *ainstr |= ((tinstr & 0x00FF) << 16); - /* New breakpoint value. See gdb/arm-tdep.c */ - else if ((tinstr & 0x00FF) == 0xFE) - *ainstr |= SWI_Breakpoint; - else - *ainstr |= (tinstr & 0x00FF); - } - else if ((tinstr & 0x0F00) != 0x0E00) { - /* Format 16 */ - int doit = FALSE; - /* TODO: Since we are doing a switch here, we could just add - the SWI and undefined instruction checks into this - switch to same on a couple of conditionals: */ - switch ((tinstr & 0x0F00) >> 8) { - case EQ: - doit = ZFLAG; - break; - case NE: - doit = !ZFLAG; - break; - case VS: - doit = VFLAG; - break; - case VC: - doit = !VFLAG; - break; - case MI: - doit = NFLAG; - break; - case PL: - doit = !NFLAG; - break; - case CS: - doit = CFLAG; - break; - case CC: - doit = !CFLAG; - break; - case HI: - doit = (CFLAG && !ZFLAG); - break; - case LS: - doit = (!CFLAG || ZFLAG); - break; - case GE: - doit = ((!NFLAG && !VFLAG) - || (NFLAG && VFLAG)); - break; - case LT: - doit = ((NFLAG && !VFLAG) - || (!NFLAG && VFLAG)); - break; - case GT: - doit = ((!NFLAG && !VFLAG && !ZFLAG) - || (NFLAG && VFLAG && !ZFLAG)); - break; - case LE: - doit = ((NFLAG && !VFLAG) - || (!NFLAG && VFLAG)) || ZFLAG; - break; - } - if (doit) { - state->Reg[15] = (pc + 4 - + (((tinstr & 0x7F) << 1) - | ((tinstr & (1 << 7)) ? - 0xFFFFFF00 : 0))); - FLUSHPIPE; - } - valid = t_branch; - } - else /* UNDEFINED : cc=1110(AL) uses different format */ - valid = t_undefined; - break; - case 28: /* B */ - /* Format 18 */ - state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1) - | ((tinstr & (1 << 10)) ? - 0xFFFFF800 : 0))); - FLUSHPIPE; - valid = t_branch; - break; - case 29: - if(tinstr & 0x1) - valid = t_undefined; - else{ - /* BLX 1 for armv5t and above */ - ARMword tmp = (pc + 2); - state->Reg[15] = - (state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; - state->Reg[14] = (tmp | 1); - CLEART; - LOG_DEBUG(Core_ARM11, "After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x", state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1); - valid = t_branch; - FLUSHPIPE; - } - break; - case 30: /* BL instruction 1 */ - /* Format 19 */ - /* There is no single ARM instruction equivalent for this Thumb - instruction. To keep the simulation simple (from the user - perspective) we check if the following instruction is the - second half of this BL, and if it is we simulate it - immediately. */ - state->Reg[14] = state->Reg[15] - + (((tinstr & 0x07FF) << 12) - | ((tinstr & (1 << 10)) ? 0xFF800000 : 0)); - valid = t_branch; /* in-case we don't have the 2nd half */ - //tinstr = next_instr; /* move the instruction down */ - //if (((tinstr & 0xF800) >> 11) != 31) - // break; /* exit, since not correct instruction */ - /* else we fall through to process the second half of the BL */ - //pc += 2; /* point the pc at the 2nd half */ - state->Reg[15] = pc + 2; - FLUSHPIPE; - break; - case 31: /* BL instruction 2 */ - /* Format 19 */ - /* There is no single ARM instruction equivalent for this - instruction. Also, it should only ever be matched with the - fmt19 "BL instruction 1" instruction. However, we do allow - the simulation of it on its own, with undefined results if - r14 is not suitably initialised. */ - { - ARMword tmp = (pc + 2); - state->Reg[15] = - (state->Reg[14] + ((tinstr & 0x07FF) << 1)); - state->Reg[14] = (tmp | 1); - valid = t_branch; - FLUSHPIPE; - } - break; - } - - return valid; -} diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index 997874764..5be3a561f 100644 --- a/src/core/arm/skyeye_common/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h @@ -86,7 +86,9 @@ enum { CP15_IFAR, CP15_PID, CP15_CONTEXT_ID, - CP15_THREAD_URO, + CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write + CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W) + CP15_THREAD_PRW, // Thread ID register - Privileged R/W only. CP15_TLB_FAULT_ADDR, /* defined by SkyEye */ CP15_TLB_FAULT_STATUS, /* defined by SkyEye */ /* VFP registers */ diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index a9c41ce5a..ff9296e0f 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -32,10 +32,8 @@ #include "core/arm/skyeye_common/armmmu.h" #include "core/arm/skyeye_common/skyeye_defs.h" -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif +#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) +#define BIT(s, n) ((s >> (n)) & 1) #define LOW 0 #define HIGH 1 @@ -71,88 +69,68 @@ typedef unsigned ARMul_CPWrites(ARMul_State* state, unsigned reg, ARMword value) #define VFP_REG_NUM 64 struct ARMul_State { - ARMword Emulate; /* to start and stop emulation */ - unsigned EndCondition; /* reason for stopping */ - unsigned ErrorCode; /* type of illegal instruction */ + ARMword Emulate; // To start and stop emulation + unsigned EndCondition; // Reason for stopping + unsigned ErrorCode; // Type of illegal instruction - /* Order of the following register should not be modified */ - ARMword Reg[16]; /* the current register file */ - ARMword Cpsr; /* the current psr */ + // Order of the following register should not be modified + ARMword Reg[16]; // The current register file + ARMword Cpsr; // The current PSR ARMword Spsr_copy; ARMword phys_pc; ARMword Reg_usr[2]; - ARMword Reg_svc[2]; /* R13_SVC R14_SVC */ - ARMword Reg_abort[2]; /* R13_ABORT R14_ABORT */ - ARMword Reg_undef[2]; /* R13 UNDEF R14 UNDEF */ - ARMword Reg_irq[2]; /* R13_IRQ R14_IRQ */ - ARMword Reg_firq[7]; /* R8---R14 FIRQ */ - ARMword Spsr[7]; /* the exception psr's */ - ARMword Mode; /* the current mode */ - ARMword Bank; /* the current register bank */ - ARMword exclusive_tag; /* the address for which the local monitor is in exclusive access mode */ + ARMword Reg_svc[2]; // R13_SVC R14_SVC + ARMword Reg_abort[2]; // R13_ABORT R14_ABORT + ARMword Reg_undef[2]; // R13 UNDEF R14 UNDEF + ARMword Reg_irq[2]; // R13_IRQ R14_IRQ + ARMword Reg_firq[7]; // R8---R14 FIRQ + ARMword Spsr[7]; // The exception psr's + ARMword Mode; // The current mode + ARMword Bank; // The current register bank + ARMword exclusive_tag; // The address for which the local monitor is in exclusive access mode ARMword exclusive_state; ARMword exclusive_result; ARMword CP15[VFP_BASE - CP15_BASE]; - ARMword VFP[3]; /* FPSID, FPSCR, and FPEXC */ - /* VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). - VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), - and only 32 singleword registers are accessible (S0-S31). */ + ARMword VFP[3]; // FPSID, FPSCR, and FPEXC + // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). + // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), + // and only 32 singleword registers are accessible (S0-S31). ARMword ExtReg[VFP_REG_NUM]; /* ---- End of the ordered registers ---- */ - ARMword RegBank[7][16]; /* all the registers */ - //chy:2003-08-19, used in arm xscale - /* 40 bit accumulator. We always keep this 64 bits wide, - and move only 40 bits out of it in an MRA insn. */ - ARMdword Accumulator; - - ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; /* dummy flags for speed */ - unsigned long long int icounter, debug_icounter, kernel_icounter; + ARMword RegBank[7][16]; // all the registers + + ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed unsigned int shifter_carry_out; - /* add armv6 flags dyf:2010-08-09 */ + // Add armv6 flags dyf:2010-08-09 ARMword GEFlag, EFlag, AFlag, QFlag; - //chy:2003-08-19, used in arm v5e|xscale - ARMword SFlag; + #ifdef MODET - ARMword TFlag; /* Thumb state */ + ARMword TFlag; // Thumb state #endif - ARMword instr, pc, temp; /* saved register state */ - ARMword loaded, decoded; /* saved pipeline state */ - //chy 2006-04-12 for ICE breakpoint - ARMword loaded_addr, decoded_addr; /* saved pipeline state addr*/ - unsigned int NumScycles, NumNcycles, NumIcycles, NumCcycles, NumFcycles; /* emulated cycles used */ - unsigned long long NumInstrs; /* the number of instructions executed */ - unsigned NumInstrsToExecute; - ARMword currentexaddr; - ARMword currentexval; - ARMword currentexvald; - ARMword servaddr; + unsigned long long NumInstrs; // The number of instructions executed + unsigned NumInstrsToExecute; unsigned NextInstr; - unsigned VectorCatch; /* caught exception mask */ - unsigned CallDebug; /* set to call the debugger */ - unsigned CanWatch; /* set by memory interface if its willing to suffer the - overhead of checking for watchpoints on each memory - access */ - - ARMul_CPInits *CPInit[16]; /* coprocessor initialisers */ - ARMul_CPExits *CPExit[16]; /* coprocessor finalisers */ - ARMul_LDCs *LDC[16]; /* LDC instruction */ - ARMul_STCs *STC[16]; /* STC instruction */ - ARMul_MRCs *MRC[16]; /* MRC instruction */ - ARMul_MCRs *MCR[16]; /* MCR instruction */ - ARMul_MRRCs *MRRC[16]; /* MRRC instruction */ - ARMul_MCRRs *MCRR[16]; /* MCRR instruction */ - ARMul_CDPs *CDP[16]; /* CDP instruction */ - ARMul_CPReads *CPRead[16]; /* Read CP register */ - ARMul_CPWrites *CPWrite[16]; /* Write CP register */ - unsigned char *CPData[16]; /* Coprocessor data */ - unsigned char const *CPRegWords[16]; /* map of coprocessor register sizes */ - - unsigned Debug; /* show instructions as they are executed */ - unsigned NresetSig; /* reset the processor */ + unsigned VectorCatch; // Caught exception mask + + ARMul_CPInits* CPInit[16]; // Coprocessor initialisers + ARMul_CPExits* CPExit[16]; // Coprocessor finalisers + ARMul_LDCs* LDC[16]; // LDC instruction + ARMul_STCs* STC[16]; // STC instruction + ARMul_MRCs* MRC[16]; // MRC instruction + ARMul_MCRs* MCR[16]; // MCR instruction + ARMul_MRRCs* MRRC[16]; // MRRC instruction + ARMul_MCRRs* MCRR[16]; // MCRR instruction + ARMul_CDPs* CDP[16]; // CDP instruction + ARMul_CPReads* CPRead[16]; // Read CP register + ARMul_CPWrites* CPWrite[16]; // Write CP register + unsigned char* CPData[16]; // Coprocessor data + unsigned char const* CPRegWords[16]; // Map of coprocessor register sizes + + unsigned NresetSig; // Reset the processor unsigned NfiqSig; unsigned NirqSig; @@ -196,54 +174,34 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) */ unsigned lateabtSig; - ARMword Vector; /* synthesize aborts in cycle modes */ - ARMword Aborted; /* sticky flag for aborts */ - ARMword Reseted; /* sticky flag for Reset */ - ARMword Inted, LastInted; /* sticky flags for interrupts */ - ARMword Base; /* extra hand for base writeback */ - ARMword AbortAddr; /* to keep track of Prefetch aborts */ - - int verbose; /* non-zero means print various messages like the banner */ - - int mmu_inited; - - //chy: 2003-08-11, for different arm core type - unsigned is_v4; /* Are we emulating a v4 architecture (or higher) ? */ - unsigned is_v5; /* Are we emulating a v5 architecture ? */ - unsigned is_v5e; /* Are we emulating a v5e architecture ? */ - unsigned is_v6; /* Are we emulating a v6 architecture ? */ - unsigned is_v7; /* Are we emulating a v7 architecture ? */ - unsigned is_XScale; /* Are we emulating an XScale architecture ? */ - unsigned is_iWMMXt; /* Are we emulating an iWMMXt co-processor ? */ - unsigned is_ep9312; /* Are we emulating a Cirrus Maverick co-processor ? */ - unsigned is_pxa27x; /* Are we emulating a Intel PXA27x co-processor ? */ - - //chy: seems only used in xscale's CP14 - ARMword CP14R0_CCD; /* used to count 64 clock cycles with CP14 R0 bit 3 set */ - - //teawater add for arm2x86 2005.07.05------------------------------------------- - //arm_arm A2-18 - int abort_model; //0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model - - /*added by ksh in 2005-10-1*/ - cpu_config_t *cpu; - - /* added LPC remap function */ - int vector_remap_flag; - u32 vector_remap_addr; - u32 vector_remap_size; - - u32 step; - u32 cycle; - - /* monitored memory for exclusice access */ - ARMword exclusive_tag_array[128]; - /* 1 means exclusive access and 0 means open access */ - ARMword exclusive_access_state; + bool Aborted; // Sticky flag for aborts + bool Reseted; // Sticky flag for Reset + ARMword Inted, LastInted; // Sticky flags for interrupts + ARMword Base; // Extra hand for base writeback + ARMword AbortAddr; // To keep track of Prefetch aborts + ARMword Vector; // Synthesize aborts in cycle modes + + // For differentiating ARM core emulaiton. + bool is_v4; // Are we emulating a v4 architecture (or higher)? + bool is_v5; // Are we emulating a v5 architecture? + bool is_v5e; // Are we emulating a v5e architecture? + bool is_v6; // Are we emulating a v6 architecture? + bool is_v7; // Are we emulating a v7 architecture? + bool is_XScale; // Are we emulating an XScale architecture? + bool is_iWMMXt; // Are we emulating an iWMMXt co-processor? + bool is_ep9312; // Are we emulating a Cirrus Maverick co-processor? + bool is_pxa27x; // Are we emulating a Intel PXA27x co-processor? + + // ARM_ARM A2-18 + // 0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model + int abort_model; + + // Added by ksh in 2005-10-1 + cpu_config_t* cpu; u32 CurrInstr; - u32 last_pc; /* the last pc executed */ - u32 last_instr; /* the last inst executed */ + u32 last_pc; // The last PC executed + u32 last_instr; // The last instruction executed u32 WriteAddr[17]; u32 WriteData[17]; u32 WritePc[17]; @@ -287,15 +245,6 @@ enum { ARM620 = ARM6 }; - -/***************************************************************************\ -* Macros to extract instruction fields * -\***************************************************************************/ - -#define BIT(n) ( (ARMword)(instr>>(n))&1) /* bit n of instruction */ -#define BITS(m,n) ( (ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) ) /* bits m to n of instr */ -#define TOPBITS(n) (instr >> (n)) /* bits 31 to n of instr */ - /***************************************************************************\ * The hardware vector addresses * \***************************************************************************/ @@ -339,13 +288,6 @@ enum { SYSTEM32MODE = 31 }; -#define ARM32BITMODE (state->Mode > 3) -#define ARM26BITMODE (state->Mode <= 3) -#define ARMMODE (state->Mode) -#define ARMul_MODEBITS 0x1fL -#define ARMul_MODE32BIT ARM32BITMODE -#define ARMul_MODE26BIT ARM26BITMODE - enum { USERBANK = 0, FIQBANK = 1, @@ -357,10 +299,6 @@ enum { SYSTEMBANK = USERBANK }; -#define BANK_CAN_ACCESS_SPSR(bank) \ - ((bank) != USERBANK && (bank) != SYSTEMBANK && (bank) != DUMMYBANK) - - /***************************************************************************\ * Definitons of things in the emulator * \***************************************************************************/ @@ -372,85 +310,7 @@ extern void ARMul_Reset(ARMul_State* state); #ifdef __cplusplus } #endif -extern ARMul_State *ARMul_NewState(ARMul_State* state); -extern ARMword ARMul_DoProg(ARMul_State* state); -extern ARMword ARMul_DoInstr(ARMul_State* state); - -/***************************************************************************\ -* Useful support routines * -\***************************************************************************/ - -extern ARMword ARMul_GetReg (ARMul_State* state, unsigned mode, unsigned reg); -extern void ARMul_SetReg (ARMul_State* state, unsigned mode, unsigned reg, ARMword value); -extern ARMword ARMul_GetPC(ARMul_State* state); -extern ARMword ARMul_GetNextPC(ARMul_State* state); -extern void ARMul_SetPC(ARMul_State* state, ARMword value); -extern ARMword ARMul_GetR15(ARMul_State* state); -extern void ARMul_SetR15(ARMul_State* state, ARMword value); - -extern ARMword ARMul_GetCPSR(ARMul_State* state); -extern void ARMul_SetCPSR(ARMul_State* state, ARMword value); -extern ARMword ARMul_GetSPSR(ARMul_State* state, ARMword mode); -extern void ARMul_SetSPSR(ARMul_State* state, ARMword mode, ARMword value); - -/***************************************************************************\ -* Definitons of things to handle aborts * -\***************************************************************************/ - -extern void ARMul_Abort(ARMul_State* state, ARMword address); -#ifdef MODET -#define ARMul_ABORTWORD (state->TFlag ? 0xefffdfff : 0xefffffff) /* SWI -1 */ -#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ - state->AbortAddr = (address & (state->TFlag ? ~1L : ~3L)) -#else -#define ARMul_ABORTWORD 0xefffffff /* SWI -1 */ -#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ - state->AbortAddr = (address & ~3L) -#endif -#define ARMul_DATAABORT(address) state->abortSig = HIGH ; \ - state->Aborted = ARMul_DataAbortV ; -#define ARMul_CLEARABORT state->abortSig = LOW - -/***************************************************************************\ -* Definitons of things in the memory interface * -\***************************************************************************/ - -extern unsigned ARMul_MemoryInit(ARMul_State* state, unsigned int initmemsize); -extern void ARMul_MemoryExit(ARMul_State* state); - -extern ARMword ARMul_LoadInstrS(ARMul_State* state, ARMword address, ARMword isize); -extern ARMword ARMul_LoadInstrN(ARMul_State* state, ARMword address, ARMword isize); -#ifdef __cplusplus -extern "C" { -#endif -extern ARMword ARMul_ReLoadInstr(ARMul_State* state, ARMword address, ARMword isize); -#ifdef __cplusplus - } -#endif -extern ARMword ARMul_LoadWordS(ARMul_State* state, ARMword address); -extern ARMword ARMul_LoadWordN(ARMul_State* state, ARMword address); -extern ARMword ARMul_LoadHalfWord(ARMul_State* state, ARMword address); -extern ARMword ARMul_LoadByte(ARMul_State* state, ARMword address); - -extern void ARMul_StoreWordS(ARMul_State* state, ARMword address, ARMword data); -extern void ARMul_StoreWordN(ARMul_State* state, ARMword address, ARMword data); -extern void ARMul_StoreHalfWord(ARMul_State* state, ARMword address, ARMword data); -extern void ARMul_StoreByte(ARMul_State* state, ARMword address, ARMword data); - -extern ARMword ARMul_SwapWord(ARMul_State* state, ARMword address, ARMword data); -extern ARMword ARMul_SwapByte(ARMul_State* state, ARMword address, ARMword data); - -extern void ARMul_Icycles(ARMul_State* state, unsigned number, ARMword address); -extern void ARMul_Ccycles(ARMul_State* state, unsigned number, ARMword address); - -extern ARMword ARMul_ReadWord(ARMul_State* state, ARMword address); -extern ARMword ARMul_ReadByte(ARMul_State* state, ARMword address); -extern void ARMul_WriteWord(ARMul_State* state, ARMword address, ARMword data); -extern void ARMul_WriteByte(ARMul_State* state, ARMword address, ARMword data); - -extern ARMword ARMul_MemAccess(ARMul_State* state, ARMword, ARMword, - ARMword, ARMword, ARMword, ARMword, ARMword, - ARMword, ARMword, ARMword); +extern ARMul_State* ARMul_NewState(ARMul_State* state); /***************************************************************************\ * Definitons of things in the co-processor interface * @@ -495,37 +355,10 @@ enum { ARMul_CP15_DBCON_E0 = 0x0003 }; -extern unsigned ARMul_CoProInit(ARMul_State* state); -extern void ARMul_CoProExit(ARMul_State* state); -extern void ARMul_CoProAttach (ARMul_State* state, unsigned number, - ARMul_CPInits* init, ARMul_CPExits* exit, - ARMul_LDCs* ldc, ARMul_STCs* stc, - ARMul_MRCs* mrc, ARMul_MCRs* mcr, - ARMul_MRRCs* mrrc, ARMul_MCRRs* mcrr, - ARMul_CDPs* cdp, - ARMul_CPReads* read, ARMul_CPWrites* write); -extern void ARMul_CoProDetach(ARMul_State* state, unsigned number); - /***************************************************************************\ * Definitons of things in the host environment * \***************************************************************************/ -extern unsigned ARMul_OSInit(ARMul_State* state); -extern void ARMul_OSExit(ARMul_State* state); - -#ifdef __cplusplus - extern "C" { -#endif - -extern unsigned ARMul_OSHandleSWI(ARMul_State* state, ARMword number); -#ifdef __cplusplus -} -#endif - -extern ARMword ARMul_OSLastErrorP(ARMul_State* state); -extern ARMword ARMul_Debug(ARMul_State* state, ARMword pc, ARMword instr); -extern unsigned ARMul_OSException(ARMul_State* state, ARMword vector, ARMword pc); - enum ConditionCode { EQ = 0, NE = 1, @@ -545,40 +378,9 @@ enum ConditionCode { NV = 15, }; -#ifndef NFLAG -#define NFLAG state->NFlag -#endif //NFLAG - -#ifndef ZFLAG -#define ZFLAG state->ZFlag -#endif //ZFLAG - -#ifndef CFLAG -#define CFLAG state->CFlag -#endif //CFLAG - -#ifndef VFLAG -#define VFLAG state->VFlag -#endif //VFLAG - -#ifndef IFLAG -#define IFLAG (state->IFFlags >> 1) -#endif //IFLAG - -#ifndef FFLAG -#define FFLAG (state->IFFlags & 1) -#endif //FFLAG - -#ifndef IFFLAGS -#define IFFLAGS state->IFFlags -#endif //VFLAG - extern bool AddOverflow(ARMword, ARMword, ARMword); extern bool SubOverflow(ARMword, ARMword, ARMword); -extern void ARMul_UndefInstr(ARMul_State*, ARMword); -extern void ARMul_FixCPSR(ARMul_State*, ARMword, ARMword); -extern void ARMul_FixSPSR(ARMul_State*, ARMword, ARMword); extern void ARMul_SelectProcessor(ARMul_State*, unsigned); extern u32 AddWithCarry(u32, u32, u32, bool*, bool*); diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h index 7e10dad86..beee54c9a 100644 --- a/src/core/arm/skyeye_common/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h @@ -19,12 +19,6 @@ #include "core/arm/skyeye_common/armdefs.h" -/* Shift Opcodes. */ -#define LSL 0 -#define LSR 1 -#define ASR 2 -#define ROR 3 - /* Macros to twiddle the status flags and mode. */ #define NBIT ((unsigned)1L << 31) #define ZBIT (1L << 30) @@ -38,73 +32,6 @@ #define R15FBIT (1L << 26) #define R15IFBITS (3L << 26) -#ifdef MODET /* Thumb support. */ -/* ??? This bit is actually in the low order bit of the PC in the hardware. - It isn't clear if the simulator needs to model that or not. */ -#define TBIT (1L << 5) -#define TFLAG state->TFlag -#define SETT state->TFlag = 1 -#define CLEART state->TFlag = 0 -#define ASSIGNT(res) state->TFlag = res -#define INSN_SIZE (TFLAG ? 2 : 4) -#else -#define INSN_SIZE 4 -#endif - -/*add armv6 CPSR feature*/ -#define EFLAG state->EFlag -#define SETE state->EFlag = 1 -#define CLEARE state->EFlag = 0 -#define ASSIGNE(res) state->NFlag = res - -#define AFLAG state->AFlag -#define SETA state->AFlag = 1 -#define CLEARA state->AFlag = 0 -#define ASSIGNA(res) state->NFlag = res - -#define QFLAG state->QFlag -#define SETQ state->QFlag = 1 -#define CLEARQ state->AFlag = 0 -#define ASSIGNQ(res) state->QFlag = res - -/* add end */ - -#define NFLAG state->NFlag -#define SETN state->NFlag = 1 -#define CLEARN state->NFlag = 0 -#define ASSIGNN(res) state->NFlag = res - -#define ZFLAG state->ZFlag -#define SETZ state->ZFlag = 1 -#define CLEARZ state->ZFlag = 0 -#define ASSIGNZ(res) state->ZFlag = res - -#define CFLAG state->CFlag -#define SETC state->CFlag = 1 -#define CLEARC state->CFlag = 0 -#define ASSIGNC(res) state->CFlag = res - -#define VFLAG state->VFlag -#define SETV state->VFlag = 1 -#define CLEARV state->VFlag = 0 -#define ASSIGNV(res) state->VFlag = res - -#define SFLAG state->SFlag -#define SETS state->SFlag = 1 -#define CLEARS state->SFlag = 0 -#define ASSIGNS(res) state->SFlag = res - -#define IFLAG (state->IFFlags >> 1) -#define FFLAG (state->IFFlags & 1) -#define IFFLAGS state->IFFlags -#define ASSIGNINT(res) state->IFFlags = (((res) >> 6) & 3) -#define ASSIGNR15INT(res) state->IFFlags = (((res) >> 26) & 3) ; - -#define PSR_FBITS (0xff000000L) -#define PSR_SBITS (0x00ff0000L) -#define PSR_XBITS (0x0000ff00L) -#define PSR_CBITS (0x000000ffL) - #if defined MODE32 || defined MODET #define CCBITS (0xf8000000L) #else @@ -128,7 +55,6 @@ #define R15PCBITS (0x03fffffcL) #endif -#define R15PCMODEBITS (0x03ffffffL) #define R15MODEBITS (0x3L) #ifdef MODE32 @@ -149,106 +75,7 @@ #define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS)) #define R15MODE (state->Reg[15] & R15MODEBITS) -#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (QFLAG << 27)) -#define EINT (IFFLAGS << 6) -#define ER15INT (IFFLAGS << 26) -#define EMODE (state->Mode) -#define EGEBITS (state->GEFlag & 0x000F0000) - -#ifdef MODET -#define CPSR (ECC | EGEBITS | (EFLAG << 9) | (AFLAG << 8) | EINT | (TFLAG << 5) | EMODE) -#else -#define CPSR (ECC | EINT | EMODE) -#endif - -#ifdef MODE32 -#define PATCHR15 -#else -#define PATCHR15 state->Reg[15] = ECC | ER15INT | EMODE | R15PC -#endif - -#define GETSPSR(bank) (ARMul_GetSPSR (state, EMODE)) -#define SETPSR_F(d,s) d = ((d) & ~PSR_FBITS) | ((s) & PSR_FBITS) -#define SETPSR_S(d,s) d = ((d) & ~PSR_SBITS) | ((s) & PSR_SBITS) -#define SETPSR_X(d,s) d = ((d) & ~PSR_XBITS) | ((s) & PSR_XBITS) -#define SETPSR_C(d,s) d = ((d) & ~PSR_CBITS) | ((s) & PSR_CBITS) - -#define SETR15PSR(s) \ - do \ - { \ - if (state->Mode == USER26MODE) \ - { \ - state->Reg[15] = ((s) & CCBITS) | R15PC | ER15INT | EMODE; \ - ASSIGNN ((state->Reg[15] & NBIT) != 0); \ - ASSIGNZ ((state->Reg[15] & ZBIT) != 0); \ - ASSIGNC ((state->Reg[15] & CBIT) != 0); \ - ASSIGNV ((state->Reg[15] & VBIT) != 0); \ - } \ - else \ - { \ - state->Reg[15] = R15PC | ((s) & (CCBITS | R15INTBITS | R15MODEBITS)); \ - ARMul_R15Altered (state); \ - } \ - } \ - while (0) - -#define SETABORT(i, m, d) \ - do \ - { \ - int SETABORT_mode = (m); \ - \ - ARMul_SetSPSR (state, SETABORT_mode, ARMul_GetCPSR (state)); \ - ARMul_SetCPSR (state, ((ARMul_GetCPSR (state) & ~(EMODE | TBIT)) \ - | (i) | SETABORT_mode)); \ - state->Reg[14] = temp - (d); \ - } \ - while (0) - -#ifndef MODE32 -#define VECTORS 0x20 -#define LEGALADDR 0x03ffffff -#define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig) -#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig) -#endif - -#define INTERNALABORT(address) \ - do \ - { \ - if (address < VECTORS) \ - state->Aborted = ARMul_DataAbortV; \ - else \ - state->Aborted = ARMul_AddrExceptnV; \ - } \ - while (0) - -#ifdef MODE32 -#define TAKEABORT ARMul_Abort (state, ARMul_DataAbortV) -#else -#define TAKEABORT \ - do \ - { \ - if (state->Aborted == ARMul_AddrExceptnV) \ - ARMul_Abort (state, ARMul_AddrExceptnV); \ - else \ - ARMul_Abort (state, ARMul_DataAbortV); \ - } \ - while (0) -#endif - -#define CPTAKEABORT \ - do \ - { \ - if (!state->Aborted) \ - ARMul_Abort (state, ARMul_UndefinedInstrV); \ - else if (state->Aborted == ARMul_AddrExceptnV) \ - ARMul_Abort (state, ARMul_AddrExceptnV); \ - else \ - ARMul_Abort (state, ARMul_DataAbortV); \ - } \ - while (0); - - -/* Different ways to start the next instruction. */ +// Different ways to start the next instruction. #define SEQ 0 #define NONSEQ 1 #define PCINCEDSEQ 2 @@ -256,368 +83,27 @@ #define PRIMEPIPE 4 #define RESUME 8 -/************************************/ -/* shenoubang 2012-3-11 */ -/* for armv7 DBG DMB DSB instr*/ -/************************************/ -#define MBReqTypes_Writes 0 -#define MBReqTypes_All 1 - -#define NORMALCYCLE state->NextInstr = 0 -#define BUSUSEDN state->NextInstr |= 1 /* The next fetch will be an N cycle. */ -#define BUSUSEDINCPCS \ - do \ - { \ - if (! state->is_v4) \ - { \ - /* A standard PC inc and an S cycle. */ \ - state->Reg[15] += INSN_SIZE; \ - state->NextInstr = (state->NextInstr & 0xff) | 2; \ - } \ - } \ - while (0) - -#define BUSUSEDINCPCN \ - do \ - { \ - if (state->is_v4) \ - BUSUSEDN; \ - else \ - { \ - /* A standard PC inc and an N cycle. */ \ - state->Reg[15] += INSN_SIZE; \ - state->NextInstr |= 3; \ - } \ - } \ - while (0) - -#define INCPC \ - do \ - { \ - /* A standard PC inc. */ \ - state->Reg[15] += INSN_SIZE; \ - state->NextInstr |= 2; \ - } \ - while (0) - #define FLUSHPIPE state->NextInstr |= PRIMEPIPE -/* Cycle based emulation. */ - -#define OUTPUTCP(i,a,b) -#define NCYCLE -#define SCYCLE -#define ICYCLE -#define CCYCLE -#define NEXTCYCLE(c) - -/* Macros to extract parts of instructions. */ -#define DESTReg (BITS (12, 15)) -#define LHSReg (BITS (16, 19)) -#define RHSReg (BITS ( 0, 3)) - -#define DEST (state->Reg[DESTReg]) - -#ifdef MODE32 -#ifdef MODET -#define LHS ((LHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC) : (state->Reg[LHSReg])) -#define RHS ((RHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC) : (state->Reg[RHSReg])) -#else -#define LHS (state->Reg[LHSReg]) -#define RHS (state->Reg[RHSReg]) -#endif -#else -#define LHS ((LHSReg == 15) ? R15PC : (state->Reg[LHSReg])) -#define RHS ((RHSReg == 15) ? R15PC : (state->Reg[RHSReg])) -#endif - -#define MULDESTReg (BITS (16, 19)) -#define MULLHSReg (BITS ( 0, 3)) -#define MULRHSReg (BITS ( 8, 11)) -#define MULACCReg (BITS (12, 15)) - -#define DPImmRHS (ARMul_ImmedTable[BITS(0, 11)]) -#define DPSImmRHS temp = BITS(0,11) ; \ - rhs = ARMul_ImmedTable[temp] ; \ - if (temp > 255) /* There was a shift. */ \ - ASSIGNC (rhs >> 31) ; - -#ifdef MODE32 -#define DPRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \ - : GetDPRegRHS (state, instr)) -#define DPSRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \ - : GetDPSRegRHS (state, instr)) -#else -#define DPRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ - : GetDPRegRHS (state, instr)) -#define DPSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ - : GetDPSRegRHS (state, instr)) -#endif - -#define LSBase state->Reg[LHSReg] -#define LSImmRHS (BITS(0,11)) - -#ifdef MODE32 -#define LSRegRHS ((BITS (4, 11) == 0) ? state->Reg[RHSReg] \ - : GetLSRegRHS (state, instr)) -#else -#define LSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \ - : GetLSRegRHS (state, instr)) -#endif - -#define LSMNumRegs ((ARMword) ARMul_BitList[BITS (0, 7)] + \ - (ARMword) ARMul_BitList[BITS (8, 15)] ) -#define LSMBaseFirst ((LHSReg == 0 && BIT (0)) || \ - (BIT (LHSReg) && BITS (0, LHSReg - 1) == 0)) - -#define SWAPSRC (state->Reg[RHSReg]) - -#define LSCOff (BITS (0, 7) << 2) -#define CPNum BITS (8, 11) - -/* Determine if access to coprocessor CP is permitted. - The XScale has a register in CP15 which controls access to CP0 - CP13. */ -//chy 2003-09-03, new CP_ACCESS_ALLOWED -/* -#define CP_ACCESS_ALLOWED(STATE, CP) \ - ( ((CP) >= 14) \ - || (! (STATE)->is_XScale) \ - || (read_cp15_reg (15, 0, 1) & (1 << (CP)))) -*/ -#define CP_ACCESS_ALLOWED(STATE, CP) \ - ( ((CP) >= 14) ) \ - -/* Macro to rotate n right by b bits. */ +// Macro to rotate n right by b bits. #define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) -/* Macros to store results of instructions. */ -#define WRITEDEST(d) \ - do \ - { \ - if (DESTReg == 15) \ - WriteR15 (state, d); \ - else \ - DEST = d; \ - } \ - while (0) - -#define WRITESDEST(d) \ - do \ - { \ - if (DESTReg == 15) \ - WriteSR15 (state, d); \ - else \ - { \ - DEST = d; \ - ARMul_NegZero (state, d); \ - } \ - } \ - while (0) - -#define WRITEDESTB(d) \ - do \ - { \ - if (DESTReg == 15){ \ - WriteR15Branch (state, d); \ - } \ - else{ \ - DEST = d; \ - } \ - } \ - while (0) - -#define BYTETOBUS(data) ((data & 0xff) | \ - ((data & 0xff) << 8) | \ - ((data & 0xff) << 16) | \ - ((data & 0xff) << 24)) - -#define BUSTOBYTE(address, data) \ - do \ - { \ - if (state->bigendSig) \ - temp = (data >> (((address ^ 3) & 3) << 3)) & 0xff; \ - else \ - temp = (data >> ((address & 3) << 3)) & 0xff; \ - } \ - while (0) - -#define LOADMULT(instr, address, wb) LoadMult (state, instr, address, wb) -#define LOADSMULT(instr, address, wb) LoadSMult (state, instr, address, wb) -#define STOREMULT(instr, address, wb) StoreMult (state, instr, address, wb) -#define STORESMULT(instr, address, wb) StoreSMult (state, instr, address, wb) - -#define POSBRANCH ((instr & 0x7fffff) << 2) -#define NEGBRANCH ((0xff000000 |(instr & 0xffffff)) << 2) - - -/* Values for Emulate. */ -#define STOP 0 /* stop */ -#define CHANGEMODE 1 /* change mode */ -#define ONCE 2 /* execute just one interation */ -#define RUN 3 /* continuous execution */ - -/* Stuff that is shared across modes. */ -extern unsigned ARMul_MultTable[]; /* Number of I cycles for a mult. */ -extern ARMword ARMul_ImmedTable[]; /* Immediate DP LHS values. */ -extern char ARMul_BitList[]; /* Number of bits in a byte table. */ - -#define EVENTLISTSIZE 1024L - -/* Thumb support. */ -typedef enum -{ - t_undefined, /* Undefined Thumb instruction. */ - t_decoded, /* Instruction decoded to ARM equivalent. */ - t_branch /* Thumb branch (already processed). */ -} -tdstate; - -/********************************************************************************* - * Check all the possible undef or unpredict behavior, Some of them probably is - * out-of-updated with the newer ISA. - * -- Michael.Kang - ********************************************************************************/ -#define UNDEF_WARNING LOG_WARNING(Core_ARM11, "undefined or unpredicted behavior for arm instruction."); - -/* Macros to scrutinize instructions. */ -#define UNDEF_Test UNDEF_WARNING -//#define UNDEF_Test - -//#define UNDEF_Shift UNDEF_WARNING -#define UNDEF_Shift - -//#define UNDEF_MSRPC UNDEF_WARNING -#define UNDEF_MSRPC - -//#define UNDEF_MRSPC UNDEF_WARNING -#define UNDEF_MRSPC - -#define UNDEF_MULPCDest UNDEF_WARNING -//#define UNDEF_MULPCDest - -#define UNDEF_MULDestEQOp1 UNDEF_WARNING -//#define UNDEF_MULDestEQOp1 - -//#define UNDEF_LSRBPC UNDEF_WARNING -#define UNDEF_LSRBPC - -//#define UNDEF_LSRBaseEQOffWb UNDEF_WARNING -#define UNDEF_LSRBaseEQOffWb - -//#define UNDEF_LSRBaseEQDestWb UNDEF_WARNING -#define UNDEF_LSRBaseEQDestWb - -//#define UNDEF_LSRPCBaseWb UNDEF_WARNING -#define UNDEF_LSRPCBaseWb - -//#define UNDEF_LSRPCOffWb UNDEF_WARNING -#define UNDEF_LSRPCOffWb - -//#define UNDEF_LSMNoRegs UNDEF_WARNING -#define UNDEF_LSMNoRegs - -//#define UNDEF_LSMPCBase UNDEF_WARNING -#define UNDEF_LSMPCBase - -//#define UNDEF_LSMUserBankWb UNDEF_WARNING -#define UNDEF_LSMUserBankWb - -//#define UNDEF_LSMBaseInListWb UNDEF_WARNING -#define UNDEF_LSMBaseInListWb - -#define UNDEF_SWPPC UNDEF_WARNING -//#define UNDEF_SWPPC - -#define UNDEF_CoProHS UNDEF_WARNING -//#define UNDEF_CoProHS - -#define UNDEF_MCRPC UNDEF_WARNING -//#define UNDEF_MCRPC - -//#define UNDEF_LSCPCBaseWb UNDEF_WARNING -#define UNDEF_LSCPCBaseWb - -#define UNDEF_UndefNotBounced UNDEF_WARNING -//#define UNDEF_UndefNotBounced - -#define UNDEF_ShortInt UNDEF_WARNING -//#define UNDEF_ShortInt - -#define UNDEF_IllegalMode UNDEF_WARNING -//#define UNDEF_IllegalMode - -#define UNDEF_Prog32SigChange UNDEF_WARNING -//#define UNDEF_Prog32SigChange - -#define UNDEF_Data32SigChange UNDEF_WARNING -//#define UNDEF_Data32SigChange - -/* Prototypes for exported functions. */ -extern unsigned ARMul_NthReg (ARMword, unsigned); - -/* Prototypes for exported functions. */ -#ifdef __cplusplus - extern "C" { -#endif -extern ARMword ARMul_Emulate26 (ARMul_State *); -extern ARMword ARMul_Emulate32 (ARMul_State *); -#ifdef __cplusplus - } -#endif -extern unsigned IntPending (ARMul_State *); -extern void ARMul_CPSRAltered (ARMul_State *); -extern void ARMul_R15Altered (ARMul_State *); -extern ARMword ARMul_GetPC (ARMul_State *); -extern ARMword ARMul_GetNextPC (ARMul_State *); -extern ARMword ARMul_GetR15 (ARMul_State *); -extern ARMword ARMul_GetCPSR (ARMul_State *); -extern void ARMul_NegZero (ARMul_State *, ARMword); -extern void ARMul_SetPC (ARMul_State *, ARMword); -extern void ARMul_SetR15 (ARMul_State *, ARMword); -extern void ARMul_SetCPSR (ARMul_State *, ARMword); -extern ARMword ARMul_GetSPSR (ARMul_State *, ARMword); -extern void ARMul_Abort26 (ARMul_State *, ARMword); -extern void ARMul_Abort32 (ARMul_State *, ARMword); -extern ARMword ARMul_MRC (ARMul_State *, ARMword); -extern void ARMul_MRRC (ARMul_State *, ARMword, ARMword *, ARMword *); -extern void ARMul_CDP (ARMul_State *, ARMword); -extern void ARMul_LDC (ARMul_State *, ARMword, ARMword); -extern void ARMul_STC (ARMul_State *, ARMword, ARMword); -extern void ARMul_MCR (ARMul_State *, ARMword, ARMword); -extern void ARMul_MCRR (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_SetSPSR (ARMul_State *, ARMword, ARMword); -extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); -extern ARMword ARMul_Align (ARMul_State *, ARMword, ARMword); -extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); -extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword); -extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword); -extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword); -extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *); -extern ARMword ARMul_GetReg (ARMul_State *, unsigned, unsigned); -extern void ARMul_SetReg (ARMul_State *, unsigned, unsigned, ARMword); - -/* Coprocessor support functions. */ -extern unsigned ARMul_CoProInit (ARMul_State *); -extern void ARMul_CoProExit (ARMul_State *); -extern void ARMul_CoProAttach (ARMul_State *, unsigned, ARMul_CPInits *, - ARMul_CPExits *, ARMul_LDCs *, ARMul_STCs *, - ARMul_MRCs *, ARMul_MCRs *, ARMul_MRRCs *, ARMul_MCRRs *, - ARMul_CDPs *, ARMul_CPReads *, ARMul_CPWrites *); -extern void ARMul_CoProDetach (ARMul_State *, unsigned); -extern ARMword read_cp15_reg (unsigned, unsigned, unsigned); - -extern unsigned DSPLDC4 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMCR4 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMRC4 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPSTC4 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPCDP4 (ARMul_State *, unsigned, ARMword); -extern unsigned DSPMCR5 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMRC5 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPLDC5 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPSTC5 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPCDP5 (ARMul_State *, unsigned, ARMword); -extern unsigned DSPMCR6 (ARMul_State *, unsigned, ARMword, ARMword); -extern unsigned DSPMRC6 (ARMul_State *, unsigned, ARMword, ARMword *); -extern unsigned DSPCDP6 (ARMul_State *, unsigned, ARMword); +// Values for Emulate. +#define STOP 0 // stop +#define CHANGEMODE 1 // change mode +#define ONCE 2 // execute just one interation +#define RUN 3 // continuous execution + +// Stuff that is shared across modes. +extern unsigned ARMul_MultTable[]; // Number of I cycles for a mult. +extern ARMword ARMul_ImmedTable[]; // Immediate DP LHS values. +extern char ARMul_BitList[]; // Number of bits in a byte table. + +// Coprocessor support functions. +extern void ARMul_CoProInit(ARMul_State*); +extern void ARMul_CoProExit(ARMul_State*); +extern void ARMul_CoProAttach(ARMul_State*, unsigned, ARMul_CPInits*, + ARMul_CPExits*, ARMul_LDCs*, ARMul_STCs*, + ARMul_MRCs*, ARMul_MCRs*, ARMul_MRRCs*, ARMul_MCRRs*, + ARMul_CDPs*, ARMul_CPReads*, ARMul_CPWrites*); +extern void ARMul_CoProDetach(ARMul_State*, unsigned); diff --git a/src/core/arm/skyeye_common/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h index e113eaf29..ccb7cf4d7 100644 --- a/src/core/arm/skyeye_common/vfp/asm_vfp.h +++ b/src/core/arm/skyeye_common/vfp/asm_vfp.h @@ -7,80 +7,77 @@ #pragma once -#define FPSID cr0 -#define FPSCR cr1 -#define MVFR1 cr6 -#define MVFR0 cr7 -#define FPEXC cr8 -#define FPINST cr9 -#define FPINST2 cr10 +// FPSID Information +// Note that these are used as values and not as flags. +enum : u32 { + VFP_FPSID_IMPLMEN = 0, // Implementation code. Should be the same as cp15 0 c0 0 + VFP_FPSID_SW = 0, // Software emulation bit value + VFP_FPSID_SUBARCH = 0x2, // Subarchitecture version number + VFP_FPSID_PARTNUM = 0x1, // Part number + VFP_FPSID_VARIANT = 0x1, // Variant number + VFP_FPSID_REVISION = 0x1 // Revision number +}; -/* FPSID bits */ -#define FPSID_IMPLEMENTER_BIT (24) -#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT) -#define FPSID_SOFTWARE (1<<23) -#define FPSID_FORMAT_BIT (21) -#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT) -#define FPSID_NODOUBLE (1<<20) -#define FPSID_ARCH_BIT (16) -#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT) -#define FPSID_PART_BIT (8) -#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT) -#define FPSID_VARIANT_BIT (4) -#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT) -#define FPSID_REV_BIT (0) -#define FPSID_REV_MASK (0xF << FPSID_REV_BIT) +// FPEXC bits +enum : u32 { + FPEXC_EX = (1U << 31U), + FPEXC_EN = (1 << 30), + FPEXC_DEX = (1 << 29), + FPEXC_FP2V = (1 << 28), + FPEXC_VV = (1 << 27), + FPEXC_TFV = (1 << 26), + FPEXC_LENGTH_BIT = (8), + FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT), + FPEXC_IDF = (1 << 7), + FPEXC_IXF = (1 << 4), + FPEXC_UFF = (1 << 3), + FPEXC_OFF = (1 << 2), + FPEXC_DZF = (1 << 1), + FPEXC_IOF = (1 << 0), + FPEXC_TRAP_MASK = (FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF) +}; -/* FPEXC bits */ -#define FPEXC_EX (1 << 31) -#define FPEXC_EN (1 << 30) -#define FPEXC_DEX (1 << 29) -#define FPEXC_FP2V (1 << 28) -#define FPEXC_VV (1 << 27) -#define FPEXC_TFV (1 << 26) -#define FPEXC_LENGTH_BIT (8) -#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT) -#define FPEXC_IDF (1 << 7) -#define FPEXC_IXF (1 << 4) -#define FPEXC_UFF (1 << 3) -#define FPEXC_OFF (1 << 2) -#define FPEXC_DZF (1 << 1) -#define FPEXC_IOF (1 << 0) -#define FPEXC_TRAP_MASK (FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF) +// FPSCR Flags +enum : u32 { + FPSCR_NFLAG = (1U << 31U), // Negative condition flag + FPSCR_ZFLAG = (1 << 30), // Zero condition flag + FPSCR_CFLAG = (1 << 29), // Carry condition flag + FPSCR_VFLAG = (1 << 28), // Overflow condition flag -/* FPSCR bits */ -#define FPSCR_DEFAULT_NAN (1<<25) -#define FPSCR_FLUSHTOZERO (1<<24) -#define FPSCR_ROUND_NEAREST (0<<22) -#define FPSCR_ROUND_PLUSINF (1<<22) -#define FPSCR_ROUND_MINUSINF (2<<22) -#define FPSCR_ROUND_TOZERO (3<<22) -#define FPSCR_RMODE_BIT (22) -#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT) -#define FPSCR_STRIDE_BIT (20) -#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT) -#define FPSCR_LENGTH_BIT (16) -#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT) -#define FPSCR_IOE (1<<8) -#define FPSCR_DZE (1<<9) -#define FPSCR_OFE (1<<10) -#define FPSCR_UFE (1<<11) -#define FPSCR_IXE (1<<12) -#define FPSCR_IDE (1<<15) -#define FPSCR_IOC (1<<0) -#define FPSCR_DZC (1<<1) -#define FPSCR_OFC (1<<2) -#define FPSCR_UFC (1<<3) -#define FPSCR_IXC (1<<4) -#define FPSCR_IDC (1<<7) + FPSCR_QC = (1 << 27), // Cumulative saturation bit + FPSCR_AHP = (1 << 26), // Alternative half-precision control bit + FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit + FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit + FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask + FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask + FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask -/* MVFR0 bits */ -#define MVFR0_A_SIMD_BIT (0) -#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT) + FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable. + FPSCR_IXE = (1 << 12), // Inexact exception trap enable + FPSCR_UFE = (1 << 11), // Undeflow exception trap enable + FPSCR_OFE = (1 << 10), // Overflow exception trap enable + FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable + FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable -/* Bit patterns for decoding the packaged operation descriptors */ -#define VFPOPDESC_LENGTH_BIT (9) -#define VFPOPDESC_LENGTH_MASK (0x07 << VFPOPDESC_LENGTH_BIT) -#define VFPOPDESC_UNUSED_BIT (24) -#define VFPOPDESC_UNUSED_MASK (0xFF << VFPOPDESC_UNUSED_BIT) -#define VFPOPDESC_OPDESC_MASK (~(VFPOPDESC_LENGTH_MASK | VFPOPDESC_UNUSED_MASK)) + FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit + FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit + FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit + FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit + FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit + FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit +}; + +// FPSCR bit offsets +enum : u32 { + FPSCR_RMODE_BIT = 22, + FPSCR_STRIDE_BIT = 20, + FPSCR_LENGTH_BIT = 16, +}; + +// FPSCR rounding modes +enum : u32 { + FPSCR_ROUND_NEAREST = (0 << 22), + FPSCR_ROUND_PLUSINF = (1 << 22), + FPSCR_ROUND_MINUSINF = (2 << 22), + FPSCR_ROUND_TOZERO = (3 << 22) +}; diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index bff296448..1cf146c53 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp @@ -23,6 +23,7 @@ #include "common/common.h" #include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/vfp/asm_vfp.h" #include "core/arm/skyeye_common/vfp/vfp.h" //ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ @@ -43,12 +44,12 @@ unsigned VFPInit(ARMul_State* state) unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value) { /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (21, 23); - int Rt = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int OPC_1 = BITS(instr, 21, 23); + int Rt = BITS(instr, 12, 15); + int CRn = BITS(instr, 16, 19); + int CRm = BITS(instr, 0, 3); + int OPC_2 = BITS(instr, 5, 7); /* TODO check access permission */ @@ -60,7 +61,7 @@ unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value) { /* VMOV r to s */ /* Transfering Rt is not mandatory, as the value of interest is pointed by value */ - VMOVBRS(state, BIT(20), Rt, BIT(7)|CRn<<1, value); + VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, value); return ARMul_DONE; } @@ -79,12 +80,12 @@ unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value) unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value) { /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (21, 23); - int Rt = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int OPC_1 = BITS(instr, 21, 23); + int Rt = BITS(instr, 12, 15); + int CRn = BITS(instr, 16, 19); + int CRm = BITS(instr, 0, 3); + int OPC_2 = BITS(instr, 5, 7); /* TODO check access permission */ @@ -95,7 +96,7 @@ unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value) { /* VMOV s to r */ /* Transfering Rt is not mandatory, as the value of interest is pointed by value */ - VMOVBRS(state, BIT(20), Rt, BIT(7)|CRn<<1, &value); + VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, &value); return ARMul_DONE; } @@ -126,24 +127,24 @@ unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value) unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* value2) { /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (4, 7); - int Rt = BITS (12, 15); - int Rt2 = BITS (16, 19); - int CRm = BITS (0, 3); + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int OPC_1 = BITS(instr, 4, 7); + int Rt = BITS(instr, 12, 15); + int Rt2 = BITS(instr, 16, 19); + int CRm = BITS(instr, 0, 3); if (CoProc == 10 || CoProc == 11) { if (CoProc == 10 && (OPC_1 & 0xD) == 1) { - VMOVBRRSS(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, value1, value2); + VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2); return ARMul_DONE; } if (CoProc == 11 && (OPC_1 & 0xD) == 1) { /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */ - VMOVBRRD(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, value1, value2); + VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2); return ARMul_DONE; } } @@ -156,11 +157,11 @@ unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 value2) { /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (4, 7); - int Rt = BITS (12, 15); - int Rt2 = BITS (16, 19); - int CRm = BITS (0, 3); + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int OPC_1 = BITS(instr, 4, 7); + int Rt = BITS(instr, 12, 15); + int Rt2 = BITS(instr, 16, 19); + int CRm = BITS(instr, 0, 3); /* TODO check access permission */ @@ -170,14 +171,14 @@ unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 v { if (CoProc == 10 && (OPC_1 & 0xD) == 1) { - VMOVBRRSS(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, &value1, &value2); + VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2); return ARMul_DONE; } if (CoProc == 11 && (OPC_1 & 0xD) == 1) { /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */ - VMOVBRRD(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, &value1, &value2); + VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2); return ARMul_DONE; } } @@ -190,14 +191,14 @@ unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 v unsigned VFPSTC(ARMul_State* state, unsigned type, u32 instr, u32 * value) { /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int CRd = BITS (12, 15); - int Rn = BITS (16, 19); - int imm8 = BITS (0, 7); - int P = BIT(24); - int U = BIT(23); - int D = BIT(22); - int W = BIT(21); + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int CRd = BITS(instr, 12, 15); + int Rn = BITS(instr, 16, 19); + int imm8 = BITS(instr, 0, 7); + int P = BIT(instr, 24); + int U = BIT(instr, 23); + int D = BIT(instr, 22); + int W = BIT(instr, 21); /* TODO check access permission */ @@ -239,14 +240,14 @@ unsigned VFPSTC(ARMul_State* state, unsigned type, u32 instr, u32 * value) unsigned VFPLDC(ARMul_State* state, unsigned type, u32 instr, u32 value) { /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int CRd = BITS (12, 15); - int Rn = BITS (16, 19); - int imm8 = BITS (0, 7); - int P = BIT(24); - int U = BIT(23); - int D = BIT(22); - int W = BIT(21); + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int CRd = BITS(instr, 12, 15); + int Rn = BITS(instr, 16, 19); + int imm8 = BITS(instr, 0, 7); + int P = BIT(instr, 24); + int U = BIT(instr, 23); + int D = BIT(instr, 22); + int W = BIT(instr, 21); /* TODO check access permission */ @@ -277,57 +278,12 @@ unsigned VFPLDC(ARMul_State* state, unsigned type, u32 instr, u32 value) unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr) { /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (20, 23); - int CRd = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - //ichfly - /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6) - { - struct vfp_double vdd; - struct vfp_single vsd; - int dn = BITS(12, 15) + (BIT(22) << 4); - int sd = (BITS(0, 3) << 1) + BIT(5); - s32 n = vfp_get_float(state, sd); - vfp_single_unpack(&vsd, n); - if (vsd.exponent & 0x80) - { - vdd.exponent = (vsd.exponent&~0x80) | 0x400; - } - else - { - vdd.exponent = vsd.exponent | 0x380; - } - vdd.sign = vsd.sign; - vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand - vfp_put_double(state, vfp_double_pack(&vdd), dn); - return ARMul_DONE; - } - if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6 - { - struct vfp_double vdd; - struct vfp_single vsd; - int sd = BITS(0, 3) + (BIT(5) << 4); - int dn = (BITS(12, 15) << 1) + BIT(22); - vfp_double_unpack(&vdd, vfp_get_double(state, sd)); - if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert - { - vsd.exponent = (vdd.exponent) | 0x80; - } - else - { - vsd.exponent = vdd.exponent & ~0x80; - } - vsd.exponent &= 0xFF; - // vsd.exponent = vdd.exponent >> 3; - vsd.sign = vdd.sign; - vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000; - vfp_put_float(state, vfp_single_pack(&vsd), dn); - return ARMul_DONE; - }*/ + int CoProc = BITS(instr, 8, 11); /* 10 or 11 */ + int OPC_1 = BITS(instr, 20, 23); + int CRd = BITS(instr, 12, 15); + int CRn = BITS(instr, 16, 19); + int CRm = BITS(instr, 0, 3); + int OPC_2 = BITS(instr, 5, 7); /* TODO check access permission */ @@ -335,17 +291,17 @@ unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr) if (CoProc == 10 || CoProc == 11) { - if ((OPC_1 & 0xB) == 0xB && BITS(4, 7) == 0) + if ((OPC_1 & 0xB) == 0xB && BITS(instr, 4, 7) == 0) { - unsigned int single = BIT(8) == 0; - unsigned int d = (single ? BITS(12,15)<<1 | BIT(22) : BITS(12,15) | BIT(22)<<4); + unsigned int single = BIT(instr, 8) == 0; + unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4); unsigned int imm; - instr = BITS(16, 19) << 4 | BITS(0, 3); /* FIXME dirty workaround to get a correct imm */ + instr = BITS(instr, 16, 19) << 4 | BITS(instr, 0, 3); // FIXME dirty workaround to get a correct imm if (single) - imm = BIT(7)<<31 | (BIT(6)==0)<<30 | (BIT(6) ? 0x1f : 0)<<25 | BITS(0, 5)<<19; + imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0x1f : 0)<<25 | BITS(instr, 0, 5)<<19; else - imm = BIT(7)<<31 | (BIT(6)==0)<<30 | (BIT(6) ? 0xff : 0)<<22 | BITS(0, 5)<<16; + imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0xff : 0)<<22 | BITS(instr, 0, 5)<<16; VMOVI(state, single, d, imm); return ARMul_DONE; @@ -353,9 +309,9 @@ unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr) if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x6) == 0x2) { - unsigned int single = BIT(8) == 0; - unsigned int d = (single ? BITS(12,15)<<1 | BIT(22) : BITS(12,15) | BIT(22)<<4); - unsigned int m = (single ? BITS( 0, 3)<<1 | BIT( 5) : BITS( 0, 3) | BIT( 5)<<4);; + unsigned int single = BIT(instr, 8) == 0; + unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4); + unsigned int m = (single ? BITS(instr, 0, 3)<<1 | BIT(instr, 5) : BITS(instr, 0, 3) | BIT(instr, 5)<<4); VMOVR(state, single, d, m); return ARMul_DONE; } @@ -477,11 +433,11 @@ int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value) static int single_reg, add, d, n, imm32, regs; if (type == ARMul_FIRST) { - single_reg = BIT(8) == 0; /* Double precision */ - add = BIT(23); /* */ - imm32 = BITS(0,7)<<2; /* may not be used */ - d = single_reg ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */ - n = BITS(16, 19); /* destination register */ + single_reg = BIT(instr, 8) == 0; // Double precision + add = BIT(instr, 23); + imm32 = BITS(instr, 0,7)<<2; // may not be used + d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); /* Base register */ + n = BITS(instr, 16, 19); // destination register i = 0; regs = 1; @@ -516,13 +472,13 @@ int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value) int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value) { static int i = 0; - static int single_regs, add, wback, d, n, imm32, regs; + static int single_regs, d, imm32, regs; if (type == ARMul_FIRST) { - single_regs = BIT(8) == 0; /* Single precision */ - d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */ - imm32 = BITS(0,7)<<2; /* may not be used */ - regs = single_regs ? BITS(0, 7) : BITS(1, 7); /* FSTMX if regs is odd */ + single_regs = BIT(instr, 8) == 0; // Single precision + d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register + imm32 = BITS(instr, 0,7)<<2; // may not be used + regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FSTMX if regs is odd state->Reg[R13] = state->Reg[R13] - imm32; @@ -561,13 +517,13 @@ int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value) static int single_regs, add, wback, d, n, imm32, regs; if (type == ARMul_FIRST) { - single_regs = BIT(8) == 0; /* Single precision */ - add = BIT(23); /* */ - wback = BIT(21); /* write-back */ - d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */ - n = BITS(16, 19); /* destination register */ - imm32 = BITS(0,7) * 4; /* may not be used */ - regs = single_regs ? BITS(0, 7) : BITS(0, 7)>>1; /* FSTMX if regs is odd */ + single_regs = BIT(instr, 8) == 0; // Single precision + add = BIT(instr, 23); + wback = BIT(instr, 21); // write-back + d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register + n = BITS(instr, 16, 19); // destination register + imm32 = BITS(instr, 0,7) * 4; // may not be used + regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FSTMX if regs is odd if (wback) { state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32); @@ -607,13 +563,13 @@ int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value) int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value) { static int i = 0; - static int single_regs, add, wback, d, n, imm32, regs; + static int single_regs, d, imm32, regs; if (type == ARMul_FIRST) { - single_regs = BIT(8) == 0; /* Single precision */ - d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */ - imm32 = BITS(0,7)<<2; /* may not be used */ - regs = single_regs ? BITS(0, 7) : BITS(1, 7); /* FLDMX if regs is odd */ + single_regs = BIT(instr, 8) == 0; // Single precision + d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register + imm32 = BITS(instr, 0, 7)<<2; // may not be used + regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FLDMX if regs is odd state->Reg[R13] = state->Reg[R13] + imm32; @@ -656,11 +612,11 @@ int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value) static int single_reg, add, d, n, imm32, regs; if (type == ARMul_FIRST) { - single_reg = BIT(8) == 0; /* Double precision */ - add = BIT(23); /* */ - imm32 = BITS(0,7)<<2; /* may not be used */ - d = single_reg ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */ - n = BITS(16, 19); /* destination register */ + single_reg = BIT(instr, 8) == 0; // Double precision + add = BIT(instr, 23); + imm32 = BITS(instr, 0, 7)<<2; // may not be used + d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register + n = BITS(instr, 16, 19); // destination register i = 0; regs = 1; @@ -702,13 +658,13 @@ int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value) static int single_regs, add, wback, d, n, imm32, regs; if (type == ARMul_FIRST) { - single_regs = BIT(8) == 0; /* Single precision */ - add = BIT(23); /* */ - wback = BIT(21); /* write-back */ - d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */ - n = BITS(16, 19); /* destination register */ - imm32 = BITS(0,7) * 4; /* may not be used */ - regs = single_regs ? BITS(0, 7) : BITS(0, 7)>>1; /* FLDMX if regs is odd */ + single_regs = BIT(instr, 8) == 0; // Single precision + add = BIT(instr, 23); + wback = BIT(instr, 21); // write-back + d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register + n = BITS(instr, 16, 19); // destination register + imm32 = BITS(instr, 0, 7) * 4; // may not be used + regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FLDMX if regs is odd if (wback) { state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32); @@ -787,8 +743,7 @@ void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg) uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) { - uint64_t result; - result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; + uint64_t result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]\n", reg * 2 + 1, reg * 2, result); return result; } @@ -805,8 +760,6 @@ void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) */ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) { - int si_code = 0; - LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); if (exceptions == VFP_EXCEPTION_ERROR) { @@ -820,8 +773,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc * Comparison instructions always return at least one of * these flags set. */ - if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) - fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); + if (exceptions & (FPSCR_NFLAG|FPSCR_ZFLAG|FPSCR_CFLAG|FPSCR_VFLAG)) + fpscr &= ~(FPSCR_NFLAG|FPSCR_ZFLAG|FPSCR_CFLAG|FPSCR_VFLAG); fpscr |= exceptions; diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index 09c7520db..445a224bc 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h @@ -25,86 +25,42 @@ #define VFP_DEBUG_UNIMPLEMENTED(x) LOG_ERROR(Core_ARM11, "in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1); #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested\n", __FUNCTION__); #define CHECK_VFP_ENABLED -#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); //if (ret == -1) {printf("VFP CDP FAILURE %x\n", inst_cream->instr); exit(-1);} - -unsigned VFPInit (ARMul_State *state); -unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); -unsigned VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value); -unsigned VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2); -unsigned VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2); -unsigned VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); -unsigned VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value); -unsigned VFPCDP (ARMul_State * state, unsigned type, ARMword instr); - -/* FPSID Information */ -#define VFP_FPSID_IMPLMEN 0 /* should be the same as cp15 0 c0 0*/ -#define VFP_FPSID_SW 0 -#define VFP_FPSID_SUBARCH 0x2 /* VFP version. Current is v3 (not strict) */ -#define VFP_FPSID_PARTNUM 0x1 -#define VFP_FPSID_VARIANT 0x1 -#define VFP_FPSID_REVISION 0x1 - -/* FPEXC Flags */ -#define VFP_FPEXC_EX 1<<31 -#define VFP_FPEXC_EN 1<<30 - -/* FPSCR Flags */ -#define VFP_FPSCR_NFLAG 1<<31 -#define VFP_FPSCR_ZFLAG 1<<30 -#define VFP_FPSCR_CFLAG 1<<29 -#define VFP_FPSCR_VFLAG 1<<28 - -#define VFP_FPSCR_AHP 1<<26 /* Alternative Half Precision */ -#define VFP_FPSCR_DN 1<<25 /* Default NaN */ -#define VFP_FPSCR_FZ 1<<24 /* Flush-to-zero */ -#define VFP_FPSCR_RMODE 3<<22 /* Rounding Mode */ -#define VFP_FPSCR_STRIDE 3<<20 /* Stride (vector) */ -#define VFP_FPSCR_LEN 7<<16 /* Stride (vector) */ - -#define VFP_FPSCR_IDE 1<<15 /* Input Denormal exc */ -#define VFP_FPSCR_IXE 1<<12 /* Inexact exc */ -#define VFP_FPSCR_UFE 1<<11 /* Undeflow exc */ -#define VFP_FPSCR_OFE 1<<10 /* Overflow exc */ -#define VFP_FPSCR_DZE 1<<9 /* Division by Zero exc */ -#define VFP_FPSCR_IOE 1<<8 /* Invalid Operation exc */ - -#define VFP_FPSCR_IDC 1<<7 /* Input Denormal cum exc */ -#define VFP_FPSCR_IXC 1<<4 /* Inexact cum exc */ -#define VFP_FPSCR_UFC 1<<3 /* Undeflow cum exc */ -#define VFP_FPSCR_OFC 1<<2 /* Overflow cum exc */ -#define VFP_FPSCR_DZC 1<<1 /* Division by Zero cum exc */ -#define VFP_FPSCR_IOC 1<<0 /* Invalid Operation cum exc */ - -/* Inline instructions. Note: Used in a cpp file as well */ -#ifdef __cplusplus - extern "C" { -#endif -int32_t vfp_get_float(ARMul_State * state, unsigned int reg); -void vfp_put_float(ARMul_State * state, int32_t val, unsigned int reg); -uint64_t vfp_get_double(ARMul_State * state, unsigned int reg); -void vfp_put_double(ARMul_State * state, uint64_t val, unsigned int reg); -void vfp_raise_exceptions(ARMul_State * state, uint32_t exceptions, uint32_t inst, uint32_t fpscr); +#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); //if (ret == -1) {printf("VFP CDP FAILURE %x\n", inst_cream->instr); exit(-1);} + +unsigned VFPInit(ARMul_State* state); +unsigned VFPMRC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value); +unsigned VFPMCR(ARMul_State* state, unsigned type, ARMword instr, ARMword value); +unsigned VFPMRRC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value1, ARMword* value2); +unsigned VFPMCRR(ARMul_State* state, unsigned type, ARMword instr, ARMword value1, ARMword value2); +unsigned VFPSTC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value); +unsigned VFPLDC(ARMul_State* state, unsigned type, ARMword instr, ARMword value); +unsigned VFPCDP(ARMul_State* state, unsigned type, ARMword instr); + +s32 vfp_get_float(ARMul_State* state, u32 reg); +void vfp_put_float(ARMul_State* state, s32 val, u32 reg); +u64 vfp_get_double(ARMul_State* state, u32 reg); +void vfp_put_double(ARMul_State* state, u64 val, u32 reg); +void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr); u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); -/* MRC */ -void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); -void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); -void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); +// MRC +void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value); +void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value); +void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); -void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); -void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); -/* MCR */ -void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); -/* STC */ -int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); -int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); -int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); -/* LDC */ -int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); -int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); -int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); +void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm); +void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm); + +// MCR +void VMSR(ARMul_State* state, ARMword reg, ARMword Rt); + +// STC +int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value); +int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value); +int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value); -#ifdef __cplusplus - } -#endif +// LDC +int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value); +int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value); +int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value); diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 55e63f553..b68090b80 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h @@ -43,495 +43,402 @@ #define pr_info //printf #define pr_debug //printf -static u32 fls(ARMword x); #define do_div(n, base) {n/=base;} -/* From vfpinstr.h */ - -#define INST_CPRTDO(inst) (((inst) & 0x0f000000) == 0x0e000000) -#define INST_CPRT(inst) ((inst) & (1 << 4)) -#define INST_CPRT_L(inst) ((inst) & (1 << 20)) -#define INST_CPRT_Rd(inst) (((inst) & (15 << 12)) >> 12) -#define INST_CPRT_OP(inst) (((inst) >> 21) & 7) -#define INST_CPNUM(inst) ((inst) & 0xf00) -#define CPNUM(cp) ((cp) << 8) - -#define FOP_MASK (0x00b00040) -#define FOP_FMAC (0x00000000) -#define FOP_FNMAC (0x00000040) -#define FOP_FMSC (0x00100000) -#define FOP_FNMSC (0x00100040) -#define FOP_FMUL (0x00200000) -#define FOP_FNMUL (0x00200040) -#define FOP_FADD (0x00300000) -#define FOP_FSUB (0x00300040) -#define FOP_FDIV (0x00800000) -#define FOP_EXT (0x00b00040) - -#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4) - -#define FEXT_MASK (0x000f0080) -#define FEXT_FCPY (0x00000000) -#define FEXT_FABS (0x00000080) -#define FEXT_FNEG (0x00010000) -#define FEXT_FSQRT (0x00010080) -#define FEXT_FCMP (0x00040000) -#define FEXT_FCMPE (0x00040080) -#define FEXT_FCMPZ (0x00050000) -#define FEXT_FCMPEZ (0x00050080) -#define FEXT_FCVT (0x00070080) -#define FEXT_FUITO (0x00080000) -#define FEXT_FSITO (0x00080080) -#define FEXT_FTOUI (0x000c0000) -#define FEXT_FTOUIZ (0x000c0080) -#define FEXT_FTOSI (0x000d0000) -#define FEXT_FTOSIZ (0x000d0080) - -#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) - -#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) -#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18) -#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) -#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1) -#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) -#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3) - -#define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) - -#define FPSCR_N (1 << 31) -#define FPSCR_Z (1 << 30) -#define FPSCR_C (1 << 29) -#define FPSCR_V (1 << 28) - -/* -------------- */ - -/* From asm/include/vfp.h */ - -/* FPSCR bits */ -#define FPSCR_DEFAULT_NAN (1<<25) -#define FPSCR_FLUSHTOZERO (1<<24) -#define FPSCR_ROUND_NEAREST (0<<22) -#define FPSCR_ROUND_PLUSINF (1<<22) -#define FPSCR_ROUND_MINUSINF (2<<22) -#define FPSCR_ROUND_TOZERO (3<<22) -#define FPSCR_RMODE_BIT (22) -#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT) -#define FPSCR_STRIDE_BIT (20) -#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT) -#define FPSCR_LENGTH_BIT (16) -#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT) -#define FPSCR_IOE (1<<8) -#define FPSCR_DZE (1<<9) -#define FPSCR_OFE (1<<10) -#define FPSCR_UFE (1<<11) -#define FPSCR_IXE (1<<12) -#define FPSCR_IDE (1<<15) -#define FPSCR_IOC (1<<0) -#define FPSCR_DZC (1<<1) -#define FPSCR_OFC (1<<2) -#define FPSCR_UFC (1<<3) -#define FPSCR_IXC (1<<4) -#define FPSCR_IDC (1<<7) - -/* ---------------- */ +enum : u32 { + FOP_MASK = 0x00b00040, + FOP_FMAC = 0x00000000, + FOP_FNMAC = 0x00000040, + FOP_FMSC = 0x00100000, + FOP_FNMSC = 0x00100040, + FOP_FMUL = 0x00200000, + FOP_FNMUL = 0x00200040, + FOP_FADD = 0x00300000, + FOP_FSUB = 0x00300040, + FOP_FDIV = 0x00800000, + FOP_EXT = 0x00b00040 +}; + +#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4) + +enum : u32 { + FEXT_MASK = 0x000f0080, + FEXT_FCPY = 0x00000000, + FEXT_FABS = 0x00000080, + FEXT_FNEG = 0x00010000, + FEXT_FSQRT = 0x00010080, + FEXT_FCMP = 0x00040000, + FEXT_FCMPE = 0x00040080, + FEXT_FCMPZ = 0x00050000, + FEXT_FCMPEZ = 0x00050080, + FEXT_FCVT = 0x00070080, + FEXT_FUITO = 0x00080000, + FEXT_FSITO = 0x00080080, + FEXT_FTOUI = 0x000c0000, + FEXT_FTOUIZ = 0x000c0080, + FEXT_FTOSI = 0x000d0000, + FEXT_FTOSIZ = 0x000d0080 +}; + +#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) + +#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) +#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18) +#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) +#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1) +#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) +#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3) + +#define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) { - if (shift) { - if (shift < 32) - val = val >> shift | ((val << (32 - shift)) != 0); - else - val = val != 0; - } - return val; + if (shift) { + if (shift < 32) + val = val >> shift | ((val << (32 - shift)) != 0); + else + val = val != 0; + } + return val; } static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) { - if (shift) { - if (shift < 64) - val = val >> shift | ((val << (64 - shift)) != 0); - else - val = val != 0; - } - return val; + if (shift) { + if (shift < 64) + val = val >> shift | ((val << (64 - shift)) != 0); + else + val = val != 0; + } + return val; } static inline u32 vfp_hi64to32jamming(u64 val) { - u32 v; - u32 highval = val >> 32; - u32 lowval = val & 0xffffffff; + u32 v; + u32 highval = val >> 32; + u32 lowval = val & 0xffffffff; - if (lowval >= 1) - v = highval | 1; - else - v = highval; + if (lowval >= 1) + v = highval | 1; + else + v = highval; - return v; + return v; } -static inline void add128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml) +static inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { - *resl = nl + ml; - *resh = nh + mh; - if (*resl < nl) - *resh += 1; + *resl = nl + ml; + *resh = nh + mh; + if (*resl < nl) + *resh += 1; } -static inline void sub128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml) +static inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { - *resl = nl - ml; - *resh = nh - mh; - if (*resl > nl) - *resh -= 1; + *resl = nl - ml; + *resh = nh - mh; + if (*resl > nl) + *resh -= 1; } -static inline void mul64to128(u64 *resh, u64 *resl, u64 n, u64 m) +static inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) { - u32 nh, nl, mh, ml; - u64 rh, rma, rmb, rl; + u32 nh, nl, mh, ml; + u64 rh, rma, rmb, rl; - nl = n; - ml = m; - rl = (u64)nl * ml; + nl = n; + ml = m; + rl = (u64)nl * ml; - nh = n >> 32; - rma = (u64)nh * ml; + nh = n >> 32; + rma = (u64)nh * ml; - mh = m >> 32; - rmb = (u64)nl * mh; - rma += rmb; + mh = m >> 32; + rmb = (u64)nl * mh; + rma += rmb; - rh = (u64)nh * mh; - rh += ((u64)(rma < rmb) << 32) + (rma >> 32); + rh = (u64)nh * mh; + rh += ((u64)(rma < rmb) << 32) + (rma >> 32); - rma <<= 32; - rl += rma; - rh += (rl < rma); + rma <<= 32; + rl += rma; + rh += (rl < rma); - *resl = rl; - *resh = rh; + *resl = rl; + *resh = rh; } -static inline void shift64left(u64 *resh, u64 *resl, u64 n) +static inline void shift64left(u64* resh, u64* resl, u64 n) { - *resh = n >> 63; - *resl = n << 1; + *resh = n >> 63; + *resl = n << 1; } static inline u64 vfp_hi64multiply64(u64 n, u64 m) { - u64 rh, rl; - mul64to128(&rh, &rl, n, m); - return rh | (rl != 0); + u64 rh, rl; + mul64to128(&rh, &rl, n, m); + return rh | (rl != 0); } static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) { - u64 mh, ml, remh, reml, termh, terml, z; - - if (nh >= m) - return ~0ULL; - mh = m >> 32; - if (mh << 32 <= nh) { - z = 0xffffffff00000000ULL; - } else { - z = nh; - do_div(z, mh); - z <<= 32; - } - mul64to128(&termh, &terml, m, z); - sub128(&remh, &reml, nh, nl, termh, terml); - ml = m << 32; - while ((s64)remh < 0) { - z -= 0x100000000ULL; - add128(&remh, &reml, remh, reml, mh, ml); - } - remh = (remh << 32) | (reml >> 32); - if (mh << 32 <= remh) { - z |= 0xffffffff; - } else { - do_div(remh, mh); - z |= remh; - } - return z; + u64 mh, ml, remh, reml, termh, terml, z; + + if (nh >= m) + return ~0ULL; + mh = m >> 32; + if (mh << 32 <= nh) { + z = 0xffffffff00000000ULL; + } else { + z = nh; + do_div(z, mh); + z <<= 32; + } + mul64to128(&termh, &terml, m, z); + sub128(&remh, &reml, nh, nl, termh, terml); + ml = m << 32; + while ((s64)remh < 0) { + z -= 0x100000000ULL; + add128(&remh, &reml, remh, reml, mh, ml); + } + remh = (remh << 32) | (reml >> 32); + if (mh << 32 <= remh) { + z |= 0xffffffff; + } else { + do_div(remh, mh); + z |= remh; + } + return z; } -/* - * Operations on unpacked elements - */ -#define vfp_sign_negate(sign) (sign ^ 0x8000) +// Operations on unpacked elements +#define vfp_sign_negate(sign) (sign ^ 0x8000) -/* - * Single-precision - */ +// Single-precision struct vfp_single { - s16 exponent; - u16 sign; - u32 significand; + s16 exponent; + u16 sign; + u32 significand; }; -#ifdef __cplusplus - extern "C" { -#endif -extern s32 vfp_get_float(ARMul_State * state, unsigned int reg); -extern void vfp_put_float(ARMul_State * state, s32 val, unsigned int reg); -#ifdef __cplusplus - } -#endif - -/* - * VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa - * VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent - * VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand - * which are not propagated to the float upon packing. - */ -#define VFP_SINGLE_MANTISSA_BITS (23) -#define VFP_SINGLE_EXPONENT_BITS (8) -#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2) -#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1) +// VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa +// VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent +// VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand +// which are not propagated to the float upon packing. +#define VFP_SINGLE_MANTISSA_BITS (23) +#define VFP_SINGLE_EXPONENT_BITS (8) +#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2) +#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1) -/* - * The bit in an unpacked float which indicates that it is a quiet NaN - */ +// The bit in an unpacked float which indicates that it is a quiet NaN #define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS)) -/* - * Operations on packed single-precision numbers - */ -#define vfp_single_packed_sign(v) ((v) & 0x80000000) -#define vfp_single_packed_negate(v) ((v) ^ 0x80000000) -#define vfp_single_packed_abs(v) ((v) & ~0x80000000) -#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1)) -#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1)) - -/* - * Unpack a single-precision float. Note that this returns the magnitude - * of the single-precision float mantissa with the 1. if necessary, - * aligned to bit 30. - */ -static inline void vfp_single_unpack(struct vfp_single *s, s32 val) +// Operations on packed single-precision numbers +#define vfp_single_packed_sign(v) ((v) & 0x80000000) +#define vfp_single_packed_negate(v) ((v) ^ 0x80000000) +#define vfp_single_packed_abs(v) ((v) & ~0x80000000) +#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1)) +#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1)) + +// Unpack a single-precision float. Note that this returns the magnitude +// of the single-precision float mantissa with the 1. if necessary, +// aligned to bit 30. +static inline void vfp_single_unpack(vfp_single* s, s32 val) { - u32 significand; + u32 significand; - s->sign = vfp_single_packed_sign(val) >> 16, - s->exponent = vfp_single_packed_exponent(val); + s->sign = vfp_single_packed_sign(val) >> 16, + s->exponent = vfp_single_packed_exponent(val); - significand = (u32) val; - significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2; - if (s->exponent && s->exponent != 255) - significand |= 0x40000000; - s->significand = significand; + significand = (u32) val; + significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2; + if (s->exponent && s->exponent != 255) + significand |= 0x40000000; + s->significand = significand; } -/* - * Re-pack a single-precision float. This assumes that the float is - * already normalised such that the MSB is bit 30, _not_ bit 31. - */ -static inline s32 vfp_single_pack(struct vfp_single *s) +// Re-pack a single-precision float. This assumes that the float is +// already normalised such that the MSB is bit 30, _not_ bit 31. +static inline s32 vfp_single_pack(vfp_single* s) { - u32 val; - val = (s->sign << 16) + - (s->exponent << VFP_SINGLE_MANTISSA_BITS) + - (s->significand >> VFP_SINGLE_LOW_BITS); - return (s32)val; + u32 val = (s->sign << 16) + + (s->exponent << VFP_SINGLE_MANTISSA_BITS) + + (s->significand >> VFP_SINGLE_LOW_BITS); + return (s32)val; } -#define VFP_NUMBER (1<<0) -#define VFP_ZERO (1<<1) -#define VFP_DENORMAL (1<<2) -#define VFP_INFINITY (1<<3) -#define VFP_NAN (1<<4) -#define VFP_NAN_SIGNAL (1<<5) +enum : u32 { + VFP_NUMBER = (1 << 0), + VFP_ZERO = (1 << 1), + VFP_DENORMAL = (1 << 2), + VFP_INFINITY = (1 << 3), + VFP_NAN = (1 << 4), + VFP_NAN_SIGNAL = (1 << 5), -#define VFP_QNAN (VFP_NAN) -#define VFP_SNAN (VFP_NAN|VFP_NAN_SIGNAL) + VFP_QNAN = (VFP_NAN), + VFP_SNAN = (VFP_NAN|VFP_NAN_SIGNAL) +}; -static inline int vfp_single_type(struct vfp_single *s) +static inline int vfp_single_type(vfp_single* s) { - int type = VFP_NUMBER; - if (s->exponent == 255) { - if (s->significand == 0) - type = VFP_INFINITY; - else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN) - type = VFP_QNAN; - else - type = VFP_SNAN; - } else if (s->exponent == 0) { - if (s->significand == 0) - type |= VFP_ZERO; - else - type |= VFP_DENORMAL; - } - return type; + int type = VFP_NUMBER; + if (s->exponent == 255) { + if (s->significand == 0) + type = VFP_INFINITY; + else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN) + type = VFP_QNAN; + else + type = VFP_SNAN; + } else if (s->exponent == 0) { + if (s->significand == 0) + type |= VFP_ZERO; + else + type |= VFP_DENORMAL; + } + return type; } -u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func); +u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions, const char* func); -/* - * Double-precision - */ +// Double-precision struct vfp_double { - s16 exponent; - u16 sign; - u64 significand; + s16 exponent; + u16 sign; + u64 significand; }; -/* - * VFP_REG_ZERO is a special register number for vfp_get_double - * which returns (double)0.0. This is useful for the compare with - * zero instructions. - */ +// VFP_REG_ZERO is a special register number for vfp_get_double +// which returns (double)0.0. This is useful for the compare with +// zero instructions. #ifdef CONFIG_VFPv3 -#define VFP_REG_ZERO 32 +#define VFP_REG_ZERO 32 #else -#define VFP_REG_ZERO 16 -#endif -#ifdef __cplusplus - extern "C" { +#define VFP_REG_ZERO 16 #endif -extern u64 vfp_get_double(ARMul_State * state, unsigned int reg); -extern void vfp_put_double(ARMul_State * state, u64 val, unsigned int reg); -#ifdef __cplusplus - } -#endif -#define VFP_DOUBLE_MANTISSA_BITS (52) -#define VFP_DOUBLE_EXPONENT_BITS (11) -#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2) -#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1) -/* - * The bit in an unpacked double which indicates that it is a quiet NaN - */ -#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS)) - -/* - * Operations on packed single-precision numbers - */ -#define vfp_double_packed_sign(v) ((v) & (1ULL << 63)) -#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63)) -#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63)) -#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) -#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) - -/* - * Unpack a double-precision float. Note that this returns the magnitude - * of the double-precision float mantissa with the 1. if necessary, - * aligned to bit 62. - */ -static inline void vfp_double_unpack(struct vfp_double *s, s64 val) +#define VFP_DOUBLE_MANTISSA_BITS (52) +#define VFP_DOUBLE_EXPONENT_BITS (11) +#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2) +#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1) + +// The bit in an unpacked double which indicates that it is a quiet NaN +#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS)) + +// Operations on packed single-precision numbers +#define vfp_double_packed_sign(v) ((v) & (1ULL << 63)) +#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63)) +#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63)) +#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) +#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) + +// Unpack a double-precision float. Note that this returns the magnitude +// of the double-precision float mantissa with the 1. if necessary, +// aligned to bit 62. +static inline void vfp_double_unpack(vfp_double* s, s64 val) { - u64 significand; + u64 significand; - s->sign = vfp_double_packed_sign(val) >> 48; - s->exponent = vfp_double_packed_exponent(val); + s->sign = vfp_double_packed_sign(val) >> 48; + s->exponent = vfp_double_packed_exponent(val); - significand = (u64) val; - significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2; - if (s->exponent && s->exponent != 2047) - significand |= (1ULL << 62); - s->significand = significand; + significand = (u64) val; + significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2; + if (s->exponent && s->exponent != 2047) + significand |= (1ULL << 62); + s->significand = significand; } -/* - * Re-pack a double-precision float. This assumes that the float is - * already normalised such that the MSB is bit 30, _not_ bit 31. - */ -static inline s64 vfp_double_pack(struct vfp_double *s) +// Re-pack a double-precision float. This assumes that the float is +// already normalised such that the MSB is bit 30, _not_ bit 31. +static inline s64 vfp_double_pack(vfp_double* s) { - u64 val; - val = ((u64)s->sign << 48) + - ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + - (s->significand >> VFP_DOUBLE_LOW_BITS); - return (s64)val; + u64 val = ((u64)s->sign << 48) + + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + + (s->significand >> VFP_DOUBLE_LOW_BITS); + return (s64)val; } -static inline int vfp_double_type(struct vfp_double *s) +static inline int vfp_double_type(vfp_double* s) { - int type = VFP_NUMBER; - if (s->exponent == 2047) { - if (s->significand == 0) - type = VFP_INFINITY; - else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN) - type = VFP_QNAN; - else - type = VFP_SNAN; - } else if (s->exponent == 0) { - if (s->significand == 0) - type |= VFP_ZERO; - else - type |= VFP_DENORMAL; - } - return type; + int type = VFP_NUMBER; + if (s->exponent == 2047) { + if (s->significand == 0) + type = VFP_INFINITY; + else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN) + type = VFP_QNAN; + else + type = VFP_SNAN; + } else if (s->exponent == 0) { + if (s->significand == 0) + type |= VFP_ZERO; + else + type |= VFP_DENORMAL; + } + return type; } -u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); - u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand); -/* - * A special flag to tell the normalisation code not to normalise. - */ -#define VFP_NAN_FLAG 0x100 - -/* - * A bit pattern used to indicate the initial (unset) value of the - * exception mask, in case nothing handles an instruction. This - * doesn't include the NAN flag, which get masked out before - * we check for an error. - */ -#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG) - -/* - * A flag to tell vfp instruction type. - * OP_SCALAR - this operation always operates in scalar mode - * OP_SD - the instruction exceptionally writes to a single precision result. - * OP_DD - the instruction exceptionally writes to a double precision result. - * OP_SM - the instruction exceptionally reads from a single precision operand. - */ -#define OP_SCALAR (1 << 0) -#define OP_SD (1 << 1) -#define OP_DD (1 << 1) -#define OP_SM (1 << 2) +// A special flag to tell the normalisation code not to normalise. +#define VFP_NAN_FLAG 0x100 + +// A bit pattern used to indicate the initial (unset) value of the +// exception mask, in case nothing handles an instruction. This +// doesn't include the NAN flag, which get masked out before +// we check for an error. +#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG) + +// A flag to tell vfp instruction type. +// OP_SCALAR - This operation always operates in scalar mode +// OP_SD - The instruction exceptionally writes to a single precision result. +// OP_DD - The instruction exceptionally writes to a double precision result. +// OP_SM - The instruction exceptionally reads from a single precision operand. +enum : u32 { + OP_SCALAR = (1 << 0), + OP_SD = (1 << 1), + OP_DD = (1 << 1), + OP_SM = (1 << 2) +}; struct op { - u32 (* const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr); - u32 flags; + u32 (* const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr); + u32 flags; }; -static u32 fls(ARMword x) +static inline u32 fls(ARMword x) { - int r = 32; - - if (!x) - return 0; - if (!(x & 0xffff0000u)) { - x <<= 16; - r -= 16; - } - if (!(x & 0xff000000u)) { - x <<= 8; - r -= 8; - } - if (!(x & 0xf0000000u)) { - x <<= 4; - r -= 4; - } - if (!(x & 0xc0000000u)) { - x <<= 2; - r -= 2; - } - if (!(x & 0x80000000u)) { - x <<= 1; - r -= 1; - } - return r; + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; } -u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); -u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); -u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); -u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr); +u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); +u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double *vdm, u32 fpscr); +u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, u32 exceptions, const char* func); diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 15a5d1265..9a7088088 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp @@ -83,134 +83,6 @@ static void vfp_double_normalise_denormal(struct vfp_double *vd) vfp_double_dump("normalise_denormal: out", vd); } -u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) -{ - u64 significand, incr; - int exponent, shift, underflow; - u32 rmode; - - vfp_double_dump("pack: in", vd); - - /* - * Infinities and NaNs are a special case. - */ - if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vd->significand == 0) { - vd->exponent = 0; - goto pack; - } - - exponent = vd->exponent; - significand = vd->significand; - - shift = 32 - fls((ARMword)(significand >> 32)); - if (shift == 32) - shift = 64 - fls((ARMword)significand); - if (shift) { - exponent -= shift; - significand <<= shift; - } - -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: normalised", vd); -#endif - - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright64jamming(significand, -exponent); - exponent = 0; -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: tiny number", vd); -#endif - if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) - underflow = 0; - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1ULL << VFP_DOUBLE_LOW_BITS; - if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) - incr -= 1; - } - else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } - else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) - incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; - - LOG_TRACE(Core_ARM11, "VFP: rounding increment = 0x%08llx\n", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: overflow", vd); -#endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 2046) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vd->exponent = 2045; - vd->significand = 0x7fffffffffffffffULL; - } - else { - vd->exponent = 2047; /* infinity */ - vd->significand = 0; - } - } - else { - if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x8000000000000000ULL) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vd->exponent = exponent; - vd->significand = significand >> 1; - } - pack: - return 0; -} - u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) { u64 significand, incr; @@ -511,7 +383,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u LOG_TRACE(Core_ARM11, "In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); m = vfp_get_double(state, dm); if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { - ret |= FPSCR_C | FPSCR_V; + ret |= FPSCR_CFLAG | FPSCR_VFLAG; if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) /* * Signalling NaN, or signalling on quiet NaN @@ -521,7 +393,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u d = vfp_get_double(state, dd); if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { - ret |= FPSCR_C | FPSCR_V; + ret |= FPSCR_CFLAG | FPSCR_VFLAG; if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) /* * Signalling NaN, or signalling on quiet NaN @@ -535,7 +407,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u /* * equal */ - ret |= FPSCR_Z | FPSCR_C; + ret |= FPSCR_ZFLAG | FPSCR_CFLAG; //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); } else if (vfp_double_packed_sign(d ^ m)) { /* @@ -545,22 +417,22 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u /* * d is negative, so d < m */ - ret |= FPSCR_N; + ret |= FPSCR_NFLAG; else /* * d is positive, so d > m */ - ret |= FPSCR_C; + ret |= FPSCR_CFLAG; } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { /* * d < m */ - ret |= FPSCR_N; + ret |= FPSCR_NFLAG; } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { /* * d > m */ - ret |= FPSCR_C; + ret |= FPSCR_CFLAG; } } LOG_TRACE(Core_ARM11, "In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); @@ -592,49 +464,6 @@ static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); } -u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only -{ - struct vfp_single vsd; - int tm; - u32 exceptions = 0; - - LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); - - tm = vfp_double_type(dm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(dm); - - vsd.sign = dm->sign; - vsd.significand = vfp_hi64to32jamming(dm->significand); - - /* - * If we have an infinity or a NaN, the exponent must be 255 - */ - if (tm & (VFP_INFINITY | VFP_NAN)) { - vsd.exponent = 255; - if (tm == VFP_QNAN) - vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - goto pack_nan; - } - else if (tm & VFP_ZERO) - vsd.exponent = 0; - else - vsd.exponent = dm->exponent - (1023 - 127); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); - -pack_nan: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; -} - static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { struct vfp_double vdm; @@ -723,7 +552,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 exceptions |= FPSCR_IDC; if (tm & VFP_NAN) - vdm.sign = 0; + vdm.sign = 1; if (vdm.exponent >= 1023 + 32) { d = vdm.sign ? 0 : 0xffffffff; @@ -880,18 +709,18 @@ static struct op fops_ext[] = { { NULL, 0 }, { NULL, 0 }, { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT - { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO - { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO + { vfp_double_fuito, OP_SCALAR|OP_SM }, //0x00000010 - FEXT_FUITO + { vfp_double_fsito, OP_SCALAR|OP_SM }, //0x00000011 - FEXT_FSITO { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, - { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI - { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ - { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI - { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ + { vfp_double_ftoui, OP_SCALAR|OP_SD }, //0x00000018 - FEXT_FTOUI + { vfp_double_ftouiz, OP_SCALAR|OP_SD }, //0x00000019 - FEXT_FTOUIZ + { vfp_double_ftosi, OP_SCALAR|OP_SD }, //0x0000001A - FEXT_FTOSI + { vfp_double_ftosiz, OP_SCALAR|OP_SD }, //0x0000001B - FEXT_FTOSIZ }; static u32 @@ -1079,6 +908,9 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f vdp.sign = vfp_sign_negate(vdp.sign); vfp_double_unpack(&vdn, vfp_get_double(state, dd)); + if (vdn.exponent == 0 && vdn.significand != 0) + vfp_double_normalise_denormal(&vdn); + if (negate & NEG_SUBTRACT) vdn.sign = vfp_sign_negate(vdn.sign); diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 1bdbfec8e..0aa2d5089 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -59,73 +59,6 @@ VMLA_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmla), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmla)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmla)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int add = (BIT(6) == 0); - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG32(tmp); - mm = FR32(d); - tmp = FPADD(mm,tmp); - //LETS(d,tmp); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - //mm = SITOFP(32,RSPR(m)); - //LETS(d,tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * m))); - nn = ZEXT64(IBITCAST32(FR32(2 * m + 1))); - tmp = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(tmp); - tmp = ZEXT64(IBITCAST32(FR32(2 * n))); - nn = ZEXT64(IBITCAST32(FR32(2 * n + 1))); - nn = OR(SHL(nn,CONST64(32)),tmp); - nn = FPBITCAST64(nn); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG64(tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * d))); - nn = ZEXT64(IBITCAST32(FR32(2 * d + 1))); - mm = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(mm); - tmp = FPADD(mm,tmp); - mm = TRUNC32(LSHR(IBITCAST64(tmp),CONST64(32))); - nn = TRUNC32(AND(IBITCAST64(tmp),CONST64(0xffffffff))); - LETFPS(2*d ,FPBITCAST32(nn)); - LETFPS(d*2 + 1 , FPBITCAST32(mm)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VNMLS */ /* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */ @@ -176,74 +109,6 @@ VMLS_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmls), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmls)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmls)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s VMLS instruction is executed out of here.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int add = (BIT(6) == 0); - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG32(tmp); - mm = FR32(d); - tmp = FPADD(mm,tmp); - //LETS(d,tmp); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - //mm = SITOFP(32,RSPR(m)); - //LETS(d,tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * m))); - nn = ZEXT64(IBITCAST32(FR32(2 * m + 1))); - tmp = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(tmp); - tmp = ZEXT64(IBITCAST32(FR32(2 * n))); - nn = ZEXT64(IBITCAST32(FR32(2 * n + 1))); - nn = OR(SHL(nn,CONST64(32)),tmp); - nn = FPBITCAST64(nn); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG64(tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * d))); - nn = ZEXT64(IBITCAST32(FR32(2 * d + 1))); - mm = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(mm); - tmp = FPADD(mm,tmp); - mm = TRUNC32(LSHR(IBITCAST64(tmp),CONST64(32))); - nn = TRUNC32(AND(IBITCAST64(tmp),CONST64(0xffffffff))); - LETFPS(2*d ,FPBITCAST32(nn)); - LETFPS(d*2 + 1 , FPBITCAST32(mm)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VNMLA */ /* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */ @@ -294,75 +159,6 @@ VNMLA_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vnmla), -DYNCOM_FILL_ACTION(vnmla), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vnmla)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vnmla)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s VNMLA instruction is executed out of here.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int add = (BIT(6) == 0); - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG32(tmp); - mm = FR32(d); - tmp = FPADD(FPNEG32(mm),tmp); - //LETS(d,tmp); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - //mm = SITOFP(32,RSPR(m)); - //LETS(d,tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * m))); - nn = ZEXT64(IBITCAST32(FR32(2 * m + 1))); - tmp = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(tmp); - tmp = ZEXT64(IBITCAST32(FR32(2 * n))); - nn = ZEXT64(IBITCAST32(FR32(2 * n + 1))); - nn = OR(SHL(nn,CONST64(32)),tmp); - nn = FPBITCAST64(nn); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG64(tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * d))); - nn = ZEXT64(IBITCAST32(FR32(2 * d + 1))); - mm = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(mm); - tmp = FPADD(FPNEG64(mm),tmp); - mm = TRUNC32(LSHR(IBITCAST64(tmp),CONST64(32))); - nn = TRUNC32(AND(IBITCAST64(tmp),CONST64(0xffffffff))); - LETFPS(2*d ,FPBITCAST32(nn)); - LETFPS(d*2 + 1 , FPBITCAST32(mm)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VNMLS */ /* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */ @@ -414,75 +210,6 @@ VNMLS_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vnmls), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vnmls)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vnmls)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int add = (BIT(6) == 0); - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG32(tmp); - mm = FR32(d); - tmp = FPADD(FPNEG32(mm),tmp); - //LETS(d,tmp); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - //mm = SITOFP(32,RSPR(m)); - //LETS(d,tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * m))); - nn = ZEXT64(IBITCAST32(FR32(2 * m + 1))); - tmp = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(tmp); - tmp = ZEXT64(IBITCAST32(FR32(2 * n))); - nn = ZEXT64(IBITCAST32(FR32(2 * n + 1))); - nn = OR(SHL(nn,CONST64(32)),tmp); - nn = FPBITCAST64(nn); - tmp = FPMUL(nn,mm); - if(!add) - tmp = FPNEG64(tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * d))); - nn = ZEXT64(IBITCAST32(FR32(2 * d + 1))); - mm = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(mm); - tmp = FPADD(FPNEG64(mm),tmp); - mm = TRUNC32(LSHR(IBITCAST64(tmp),CONST64(32))); - nn = TRUNC32(AND(IBITCAST64(tmp),CONST64(0xffffffff))); - LETFPS(2*d ,FPBITCAST32(nn)); - LETFPS(d*2 + 1 , FPBITCAST32(mm)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VNMUL */ /* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ @@ -533,65 +260,6 @@ VNMUL_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vnmul), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vnmul)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vnmul)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int add = (BIT(6) == 0); - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPMUL(nn,mm); - //LETS(d,tmp); - LETFPS(d,FPNEG32(tmp)); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - //mm = SITOFP(32,RSPR(m)); - //LETS(d,tmp); - mm = ZEXT64(IBITCAST32(FR32(2 * m))); - nn = ZEXT64(IBITCAST32(FR32(2 * m + 1))); - tmp = OR(SHL(nn,CONST64(32)),mm); - mm = FPBITCAST64(tmp); - tmp = ZEXT64(IBITCAST32(FR32(2 * n))); - nn = ZEXT64(IBITCAST32(FR32(2 * n + 1))); - nn = OR(SHL(nn,CONST64(32)),tmp); - nn = FPBITCAST64(nn); - tmp = FPMUL(nn,mm); - tmp = FPNEG64(tmp); - mm = TRUNC32(LSHR(IBITCAST64(tmp),CONST64(32))); - nn = TRUNC32(AND(IBITCAST64(tmp),CONST64(0xffffffff))); - LETFPS(2*d ,FPBITCAST32(nn)); - LETFPS(d*2 + 1 , FPBITCAST32(mm)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMUL */ /* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ @@ -642,77 +310,6 @@ VMUL_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmul), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmul)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmul)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - //mm = SITOFP(32,FR(m)); - //nn = SITOFP(32,FRn)); - mm = FR32(m); - nn = FR32(n); - tmp = FPMUL(nn,mm); - //LETS(d,tmp); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - //mm = SITOFP(32,RSPR(m)); - //LETS(d,tmp); - Value *lo = FR32(2 * m); - Value *hi = FR32(2 * m + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - Value *hi64 = ZEXT64(hi); - Value* lo64 = ZEXT64(lo); - Value* v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value* m0 = FPBITCAST64(v64); - lo = FR32(2 * n); - hi = FR32(2 * n + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - hi64 = ZEXT64(hi); - lo64 = ZEXT64(lo); - v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value *n0 = FPBITCAST64(v64); - tmp = FPMUL(n0,m0); - Value *val64 = IBITCAST64(tmp); - hi = LSHR(val64,CONST64(32)); - lo = AND(val64,CONST64(0xffffffff)); - hi = TRUNC32(hi); - lo = TRUNC32(lo); - hi = FPBITCAST32(hi); - lo = FPBITCAST32(lo); - LETFPS(2*d ,lo); - LETFPS(d*2 + 1 , hi); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VADD */ /* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */ @@ -763,73 +360,6 @@ VADD_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vadd), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vadd)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vadd)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction will implement out of JIT.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPADD(nn,mm); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - Value *lo = FR32(2 * m); - Value *hi = FR32(2 * m + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - Value *hi64 = ZEXT64(hi); - Value* lo64 = ZEXT64(lo); - Value* v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value* m0 = FPBITCAST64(v64); - lo = FR32(2 * n); - hi = FR32(2 * n + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - hi64 = ZEXT64(hi); - lo64 = ZEXT64(lo); - v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value *n0 = FPBITCAST64(v64); - tmp = FPADD(n0,m0); - Value *val64 = IBITCAST64(tmp); - hi = LSHR(val64,CONST64(32)); - lo = AND(val64,CONST64(0xffffffff)); - hi = TRUNC32(hi); - lo = TRUNC32(lo); - hi = FPBITCAST32(hi); - lo = FPBITCAST32(lo); - LETFPS(2*d ,lo); - LETFPS(d*2 + 1 , hi); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VSUB */ /* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */ @@ -879,71 +409,6 @@ VSUB_INST: GOTO_NEXT_INST; } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vsub), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vsub)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vsub)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instr=0x%x, instruction is executed out of JIT.\n", __FUNCTION__, instr); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPSUB(nn,mm); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - Value *lo = FR32(2 * m); - Value *hi = FR32(2 * m + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - Value *hi64 = ZEXT64(hi); - Value* lo64 = ZEXT64(lo); - Value* v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value* m0 = FPBITCAST64(v64); - lo = FR32(2 * n); - hi = FR32(2 * n + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - hi64 = ZEXT64(hi); - lo64 = ZEXT64(lo); - v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value *n0 = FPBITCAST64(v64); - tmp = FPSUB(n0,m0); - Value *val64 = IBITCAST64(tmp); - hi = LSHR(val64,CONST64(32)); - lo = AND(val64,CONST64(0xffffffff)); - hi = TRUNC32(hi); - lo = TRUNC32(lo); - hi = FPBITCAST32(hi); - lo = FPBITCAST32(lo); - LETFPS(2*d ,lo); - LETFPS(d*2 + 1 , hi); - } - return No_exp; -} -#endif /* ----------------------------------------------------------------------- */ /* VDIV */ @@ -995,73 +460,6 @@ VDIV_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vdiv), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vdiv)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vdiv)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int m; - int n; - int d ; - int s = BIT(8) == 0; - Value *mm; - Value *nn; - Value *tmp; - if(s){ - m = BIT(5) | BITS(0,3) << 1; - n = BIT(7) | BITS(16,19) << 1; - d = BIT(22) | BITS(12,15) << 1; - mm = FR32(m); - nn = FR32(n); - tmp = FPDIV(nn,mm); - LETFPS(d,tmp); - }else { - m = BITS(0,3) | BIT(5) << 4; - n = BITS(16,19) | BIT(7) << 4; - d = BIT(22) << 4 | BITS(12,15); - Value *lo = FR32(2 * m); - Value *hi = FR32(2 * m + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - Value *hi64 = ZEXT64(hi); - Value* lo64 = ZEXT64(lo); - Value* v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value* m0 = FPBITCAST64(v64); - lo = FR32(2 * n); - hi = FR32(2 * n + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - hi64 = ZEXT64(hi); - lo64 = ZEXT64(lo); - v64 = OR(SHL(hi64,CONST64(32)),lo64); - Value *n0 = FPBITCAST64(v64); - tmp = FPDIV(n0,m0); - Value *val64 = IBITCAST64(tmp); - hi = LSHR(val64,CONST64(32)); - lo = AND(val64,CONST64(0xffffffff)); - hi = TRUNC32(hi); - lo = TRUNC32(lo); - hi = FPBITCAST32(hi); - lo = FPBITCAST32(lo); - LETFPS(2*d ,lo); - LETFPS(d*2 + 1 , hi); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMOVI move immediate */ /* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */ @@ -1111,46 +509,6 @@ VMOVI_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovi), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovi)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovi)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int single = (BIT(8) == 0); - int d; - int imm32; - Value *v; - Value *tmp; - v = CONST32(BITS(0,3) | BITS(16,19) << 4); - //v = CONST64(0x3ff0000000000000); - if(single){ - d = BIT(22) | BITS(12,15) << 1; - }else { - d = BITS(12,15) | BIT(22) << 4; - } - if(single){ - LETFPS(d,FPBITCAST32(v)); - }else { - //v = UITOFP(64,v); - //tmp = IBITCAST64(v); - LETFPS(d*2 ,FPBITCAST32(TRUNC32(AND(v,CONST64(0xffffffff))))); - LETFPS(d * 2 + 1,FPBITCAST32(TRUNC32(LSHR(v,CONST64(32))))); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMOVR move register */ /* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */ @@ -1196,40 +554,6 @@ VMOVR_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovr), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - int single = BIT(8) == 0; - int d = (single ? BITS(12,15)<<1 | BIT(22) : BIT(22) << 4 | BITS(12,15)); - int m = (single ? BITS(0, 3)<<1 | BIT(5) : BITS(0, 3) | BIT(5)<<4); - - if (single) - { - LETFPS(d, FR32(m)); - } - else - { - /* Check endian please */ - LETFPS((d*2 + 1), FR32(m*2 + 1)); - LETFPS((d * 2), FR32(m * 2)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VABS */ /* cond 1110 1D11 0000 Vd-- 101X 11M0 Vm-- */ @@ -1280,57 +604,6 @@ VABS_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vabs), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vabs)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vabs)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - int single = BIT(8) == 0; - int d = (single ? BITS(12,15)<<1 | BIT(22) : BIT(22) << 4 | BITS(12,15)); - int m = (single ? BITS(0, 3)<<1 | BIT(5) : BITS(0, 3) | BIT(5)<<4); - Value* m0; - if (single) - { - m0 = FR32(m); - m0 = SELECT(FPCMP_OLT(m0,FPCONST32(0.0)),FPNEG32(m0),m0); - LETFPS(d,m0); - } - else - { - /* Check endian please */ - Value *lo = FR32(2 * m); - Value *hi = FR32(2 * m + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - Value *hi64 = ZEXT64(hi); - Value* lo64 = ZEXT64(lo); - Value* v64 = OR(SHL(hi64,CONST64(32)),lo64); - m0 = FPBITCAST64(v64); - m0 = SELECT(FPCMP_OLT(m0,FPCONST64(0.0)),FPNEG64(m0),m0); - Value *val64 = IBITCAST64(m0); - hi = LSHR(val64,CONST64(32)); - lo = AND(val64,CONST64(0xffffffff)); - hi = TRUNC32(hi); - lo = TRUNC32(lo); - hi = FPBITCAST32(hi); - lo = FPBITCAST32(lo); - LETFPS(2*d ,lo); - LETFPS(d*2 + 1 , hi); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VNEG */ /* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ @@ -1382,59 +655,6 @@ VNEG_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vneg), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vneg)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vneg)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int single = BIT(8) == 0; - int d = (single ? BITS(12,15)<<1 | BIT(22) : BIT(22) << 4 | BITS(12,15)); - int m = (single ? BITS(0, 3)<<1 | BIT(5) : BITS(0, 3) | BIT(5)<<4); - Value* m0; - if (single) - { - m0 = FR32(m); - m0 = FPNEG32(m0); - LETFPS(d,m0); - } - else - { - /* Check endian please */ - Value *lo = FR32(2 * m); - Value *hi = FR32(2 * m + 1); - hi = IBITCAST32(hi); - lo = IBITCAST32(lo); - Value *hi64 = ZEXT64(hi); - Value* lo64 = ZEXT64(lo); - Value* v64 = OR(SHL(hi64,CONST64(32)),lo64); - m0 = FPBITCAST64(v64); - m0 = FPNEG64(m0); - Value *val64 = IBITCAST64(m0); - hi = LSHR(val64,CONST64(32)); - lo = AND(val64,CONST64(0xffffffff)); - hi = TRUNC32(hi); - lo = TRUNC32(lo); - hi = FPBITCAST32(hi); - lo = FPBITCAST32(lo); - LETFPS(2*d ,lo); - LETFPS(d*2 + 1 , hi); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VSQRT */ /* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ @@ -1485,47 +705,6 @@ VSQRT_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vsqrt), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vsqrt)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vsqrt)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int dp_op = (BIT(8) == 1); - int d = dp_op ? BITS(12,15) | BIT(22) << 4 : BIT(22) | BITS(12,15) << 1; - int m = dp_op ? BITS(0,3) | BIT(5) << 4 : BIT(5) | BITS(0,3) << 1; - Value* v; - Value* tmp; - if(dp_op){ - v = SHL(ZEXT64(IBITCAST32(FR32(2 * m + 1))),CONST64(32)); - tmp = ZEXT64(IBITCAST32(FR32(2 * m))); - v = OR(v,tmp); - v = FPSQRT(FPBITCAST64(v)); - tmp = TRUNC32(LSHR(IBITCAST64(v),CONST64(32))); - v = TRUNC32(AND(IBITCAST64(v),CONST64( 0xffffffff))); - LETFPS(2 * d , FPBITCAST32(v)); - LETFPS(2 * d + 1, FPBITCAST32(tmp)); - }else { - v = FR32(m); - v = FPSQRT(FPEXT(64,v)); - v = FPTRUNC(32,v); - LETFPS(d,v); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VCMP VCMPE */ /* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */ @@ -1576,74 +755,6 @@ VCMP_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vcmp), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vcmp)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vcmp)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is executed out of JIT.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int dp_op = (BIT(8) == 1); - int d = dp_op ? BITS(12,15) | BIT(22) << 4 : BIT(22) | BITS(12,15) << 1; - int m = dp_op ? BITS(0,3) | BIT(5) << 4 : BIT(5) | BITS(0,3) << 1; - Value* v; - Value* tmp; - Value* n; - Value* z; - Value* c; - Value* vt; - Value* v1; - Value* nzcv; - if(dp_op){ - v = SHL(ZEXT64(IBITCAST32(FR32(2 * m + 1))),CONST64(32)); - tmp = ZEXT64(IBITCAST32(FR32(2 * m))); - v1 = OR(v,tmp); - v = SHL(ZEXT64(IBITCAST32(FR32(2 * d + 1))),CONST64(32)); - tmp = ZEXT64(IBITCAST32(FR32(2 * d))); - v = OR(v,tmp); - z = FPCMP_OEQ(FPBITCAST64(v),FPBITCAST64(v1)); - n = FPCMP_OLT(FPBITCAST64(v),FPBITCAST64(v1)); - c = FPCMP_OGE(FPBITCAST64(v),FPBITCAST64(v1)); - tmp = FPCMP_UNO(FPBITCAST64(v),FPBITCAST64(v1)); - v1 = tmp; - c = OR(c,tmp); - n = SHL(ZEXT32(n),CONST32(31)); - z = SHL(ZEXT32(z),CONST32(30)); - c = SHL(ZEXT32(c),CONST32(29)); - v1 = SHL(ZEXT32(v1),CONST(28)); - nzcv = OR(OR(OR(n,z),c),v1); - v = R(VFP_FPSCR); - tmp = OR(nzcv,AND(v,CONST32(0x0fffffff))); - LET(VFP_FPSCR,tmp); - }else { - z = FPCMP_OEQ(FR32(d),FR32(m)); - n = FPCMP_OLT(FR32(d),FR32(m)); - c = FPCMP_OGE(FR32(d),FR32(m)); - tmp = FPCMP_UNO(FR32(d),FR32(m)); - c = OR(c,tmp); - v1 = tmp; - n = SHL(ZEXT32(n),CONST32(31)); - z = SHL(ZEXT32(z),CONST32(30)); - c = SHL(ZEXT32(c),CONST32(29)); - v1 = SHL(ZEXT32(v1),CONST(28)); - nzcv = OR(OR(OR(n,z),c),v1); - v = R(VFP_FPSCR); - tmp = OR(nzcv,AND(v,CONST32(0x0fffffff))); - LET(VFP_FPSCR,tmp); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VCMP VCMPE */ /* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */ @@ -1694,74 +805,6 @@ VCMP2_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vcmp2), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vcmp2)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vcmp2)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction will executed out of JIT.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int dp_op = (BIT(8) == 1); - int d = dp_op ? BITS(12,15) | BIT(22) << 4 : BIT(22) | BITS(12,15) << 1; - //int m = dp_op ? BITS(0,3) | BIT(5) << 4 : BIT(5) | BITS(0,3) << 1; - Value* v; - Value* tmp; - Value* n; - Value* z; - Value* c; - Value* vt; - Value* v1; - Value* nzcv; - if(dp_op){ - v1 = CONST64(0); - v = SHL(ZEXT64(IBITCAST32(FR32(2 * d + 1))),CONST64(32)); - tmp = ZEXT64(IBITCAST32(FR32(2 * d))); - v = OR(v,tmp); - z = FPCMP_OEQ(FPBITCAST64(v),FPBITCAST64(v1)); - n = FPCMP_OLT(FPBITCAST64(v),FPBITCAST64(v1)); - c = FPCMP_OGE(FPBITCAST64(v),FPBITCAST64(v1)); - tmp = FPCMP_UNO(FPBITCAST64(v),FPBITCAST64(v1)); - v1 = tmp; - c = OR(c,tmp); - n = SHL(ZEXT32(n),CONST32(31)); - z = SHL(ZEXT32(z),CONST32(30)); - c = SHL(ZEXT32(c),CONST32(29)); - v1 = SHL(ZEXT32(v1),CONST(28)); - nzcv = OR(OR(OR(n,z),c),v1); - v = R(VFP_FPSCR); - tmp = OR(nzcv,AND(v,CONST32(0x0fffffff))); - LET(VFP_FPSCR,tmp); - }else { - v1 = CONST(0); - v1 = FPBITCAST32(v1); - z = FPCMP_OEQ(FR32(d),v1); - n = FPCMP_OLT(FR32(d),v1); - c = FPCMP_OGE(FR32(d),v1); - tmp = FPCMP_UNO(FR32(d),v1); - c = OR(c,tmp); - v1 = tmp; - n = SHL(ZEXT32(n),CONST32(31)); - z = SHL(ZEXT32(z),CONST32(30)); - c = SHL(ZEXT32(c),CONST32(29)); - v1 = SHL(ZEXT32(v1),CONST(28)); - nzcv = OR(OR(OR(n,z),c),v1); - v = R(VFP_FPSCR); - tmp = OR(nzcv,AND(v,CONST32(0x0fffffff))); - LET(VFP_FPSCR,tmp); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VCVTBDS between double and single */ /* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */ @@ -1812,48 +855,6 @@ VCVTBDS_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vcvtbds), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vcvtbds)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vcvtbds)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is executed out.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - int dp_op = (BIT(8) == 1); - int d = dp_op ? BITS(12,15) << 1 | BIT(22) : BIT(22) << 4 | BITS(12,15); - int m = dp_op ? BITS(0,3) | BIT(5) << 4 : BIT(5) | BITS(0,3) << 1; - int d2s = dp_op; - Value* v; - Value* tmp; - Value* v1; - if(d2s){ - v = SHL(ZEXT64(IBITCAST32(FR32(2 * m + 1))),CONST64(32)); - tmp = ZEXT64(IBITCAST32(FR32(2 * m))); - v1 = OR(v,tmp); - tmp = FPTRUNC(32,FPBITCAST64(v1)); - LETFPS(d,tmp); - }else { - v = FR32(m); - tmp = FPEXT(64,v); - v = IBITCAST64(tmp); - tmp = TRUNC32(AND(v,CONST64(0xffffffff))); - v1 = TRUNC32(LSHR(v,CONST64(32))); - LETFPS(2 * d, FPBITCAST32(tmp) ); - LETFPS(2 * d + 1, FPBITCAST32(v1)); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VCVTBFF between floating point and fixed point */ /* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ @@ -1906,26 +907,6 @@ VCVTBFF_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vcvtbff), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vcvtbff)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vcvtbff)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arch_arm_undef(cpu, bb, instr); - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VCVTBFI between floating point and integer */ /* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ @@ -1976,114 +957,6 @@ VCVTBFI_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vcvtbfi), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vcvtbfi)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s, instruction will be executed out of JIT.\n", __FUNCTION__); - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vcvtbfi)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s, instruction will be executed out of JIT.\n", __FUNCTION__); - //arch_arm_undef(cpu, bb, instr); - unsigned int opc2 = BITS(16,18); - int to_integer = ((opc2 >> 2) == 1); - int dp_op = (BIT(8) == 1); - unsigned int op = BIT(7); - int m,d; - Value* v; - Value* hi; - Value* lo; - Value* v64; - if(to_integer){ - d = BIT(22) | (BITS(12,15) << 1); - if(dp_op) - m = BITS(0,3) | BIT(5) << 4; - else - m = BIT(5) | BITS(0,3) << 1; - }else { - m = BIT(5) | BITS(0,3) << 1; - if(dp_op) - d = BITS(12,15) | BIT(22) << 4; - else - d = BIT(22) | BITS(12,15) << 1; - } - if(to_integer){ - if(dp_op){ - lo = FR32(m * 2); - hi = FR32(m * 2 + 1); - hi = ZEXT64(IBITCAST32(hi)); - lo = ZEXT64(IBITCAST32(lo)); - v64 = OR(SHL(hi,CONST64(32)),lo); - if(BIT(16)){ - v = FPTOSI(32,FPBITCAST64(v64)); - } - else - v = FPTOUI(32,FPBITCAST64(v64)); - - v = FPBITCAST32(v); - LETFPS(d,v); - }else { - v = FR32(m); - if(BIT(16)){ - v = FPTOSI(32,v); - } - else - v = FPTOUI(32,v); - LETFPS(d,FPBITCAST32(v)); - } - }else { - if(dp_op){ - v = IBITCAST32(FR32(m)); - if(BIT(7)) - v64 = SITOFP(64,v); - else - v64 = UITOFP(64,v); - v = IBITCAST64(v64); - hi = FPBITCAST32(TRUNC32(LSHR(v,CONST64(32)))); - lo = FPBITCAST32(TRUNC32(AND(v,CONST64(0xffffffff)))); - LETFPS(2 * d , lo); - LETFPS(2 * d + 1, hi); - }else { - v = IBITCAST32(FR32(m)); - if(BIT(7)) - v = SITOFP(32,v); - else - v = UITOFP(32,v); - LETFPS(d,v); - } - } - return No_exp; -} - -/** -* @brief The implementation of c language for vcvtbfi instruction of dyncom -* -* @param cpu -* @param instr -* -* @return -*/ -int vcvtbfi_instr_impl(arm_core_t* cpu, uint32 instr){ - int dp_operation = BIT(8); - int ret; - if (dp_operation) - ret = vfp_double_cpdo(cpu, instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); - else - ret = vfp_single_cpdo(cpu, instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); - - vfp_raise_exceptions(cpu, ret, instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); - return 0; -} -#endif - /* ----------------------------------------------------------------------- */ /* MRC / MCR instructions */ /* cond 1110 AAAL XXXX XXXX 101C XBB1 XXXX */ @@ -2135,35 +1008,6 @@ VMOVBRS_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovbrs), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovbrs)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovbrs)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - int to_arm = BIT(20) == 1; - int t = BITS(12, 15); - int n = BIT(7) | BITS(16, 19)<<1; - - if (to_arm) - { - LET(t, IBITCAST32(FR32(n))); - } - else - { - LETFPS(n, FPBITCAST32(R(t))); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMSR */ /* cond 1110 1110 reg- Rt-- 1010 0001 0000 */ @@ -2211,48 +1055,6 @@ VMSR_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmsr), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmsr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmsr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - if(RD == 15) { - LOG_ERROR(Core_ARM11, "in %s is not implementation.\n", __FUNCTION__); - exit(-1); - } - - Value *data = NULL; - int reg = RN; - int Rt = RD; - if (reg == 1) - { - LET(VFP_FPSCR, R(Rt)); - } - else - { - switch (reg) - { - case 8: - LET(VFP_FPEXC, R(Rt)); - break; - default: - break; - } - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMOVBRC register to scalar */ /* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */ @@ -2302,26 +1104,6 @@ VMOVBRC_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovbrc), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovbrc)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovbrc)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arch_arm_undef(cpu, bb, instr); - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMRS */ /* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */ @@ -2404,64 +1186,6 @@ VMRS_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmrs), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmrs)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmrs)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - - Value *data = NULL; - int reg = BITS(16, 19);; - int Rt = BITS(12, 15); - if (reg == 1) - { - if (Rt != 15) - { - LET(Rt, R(VFP_FPSCR)); - } - else - { - //LET(Rt, R(VFP_FPSCR)); - update_cond_from_fpscr(cpu, instr, bb, pc); - } - } - else - { - switch (reg) - { - case 0: - LET(Rt, R(VFP_FPSID)); - break; - case 6: - /* MVFR1, VFPv3 only ? */ - LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", Rt); - break; - case 7: - /* MVFR0, VFPv3 only? */ - LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", Rt); - break; - case 8: - LET(Rt, R(VFP_FPEXC)); - break; - default: - break; - } - } - - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VMOVBCR scalar to register */ /* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */ @@ -2511,26 +1235,6 @@ VMOVBCR_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovbcr), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovbcr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovbcr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - LOG_TRACE(Core_ARM11, "\t\tin %s instruction is not implemented.\n", __FUNCTION__); - arch_arm_undef(cpu, bb, instr); - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* MRRC / MCRR instructions */ /* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ @@ -2584,39 +1288,6 @@ VMOVBRRSS_INST: GOTO_NEXT_INST; } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovbrrss), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovbrrss)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - if (instr >> 28 != 0xE) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovbrrss)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc) -{ - int to_arm = BIT(20) == 1; - int t = BITS(12, 15); - int t2 = BITS(16, 19); - int n = BIT(5)<<4 | BITS(0, 3); - if (to_arm) { - LET(t, IBITCAST32(FR32(n + 0))); - LET(t2, IBITCAST32(FR32(n + 1))); - } - else { - LETFPS(n + 0, FPBITCAST32(R(t))); - LETFPS(n + 1, FPBITCAST32(R(t2))); - } - return No_exp; -} -#endif /* ----------------------------------------------------------------------- */ /* VMOVBRRD between 2 registers and 1 double */ @@ -2667,38 +1338,6 @@ VMOVBRRD_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vmovbrrd), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vmovbrrd)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vmovbrrd)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - int to_arm = BIT(20) == 1; - int t = BITS(12, 15); - int t2 = BITS(16, 19); - int n = BIT(5)<<4 | BITS(0, 3); - if(to_arm){ - LET(t, IBITCAST32(FR32(n * 2))); - LET(t2, IBITCAST32(FR32(n * 2 + 1))); - } - else{ - LETFPS(n * 2, FPBITCAST32(R(t))); - LETFPS(n * 2 + 1, FPBITCAST32(R(t2))); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* LDC/STC between 2 registers and 1 double */ /* cond 110X XXX1 Rn-- CRd- copr imm- imm- LDC */ @@ -2764,53 +1403,6 @@ VSTR_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vstr), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - *tag |= TAG_NEW_BB; - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - int single = BIT(8) == 0; - int add = BIT(23); - int imm32 = BITS(0,7) << 2; - int d = (single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4)); - int n = BITS(16, 19); - - Value* base = (n == 15) ? ADD(AND(R(n), CONST(0xFFFFFFFC)), CONST(8)): R(n); - Value* Addr = add ? ADD(base, CONST(imm32)) : SUB(base, CONST(imm32)); - //if(single) - // bb = arch_check_mm(cpu, bb, Addr, 4, 0, cpu->dyncom_engine->bb_trap); - //else - // bb = arch_check_mm(cpu, bb, Addr, 8, 0, cpu->dyncom_engine->bb_trap); - //Value* phys_addr; - if(single){ - //memory_write(cpu, bb, Addr, RSPR(d), 32); - memory_write(cpu, bb, Addr, IBITCAST32(FR32(d)), 32); - bb = cpu->dyncom_engine->bb; - } - else{ - //memory_write(cpu, bb, Addr, RSPR(d * 2), 32); - memory_write(cpu, bb, Addr, IBITCAST32(FR32(d * 2)), 32); - bb = cpu->dyncom_engine->bb; - //memory_write(cpu, bb, ADD(Addr, CONST(4)), RSPR(d * 2 + 1), 32); - memory_write(cpu, bb, ADD(Addr, CONST(4)), IBITCAST32(FR32(d * 2 + 1)), 32); - bb = cpu->dyncom_engine->bb; - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VPUSH */ /* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */ @@ -2873,63 +1465,6 @@ VPUSH_INST: GOTO_NEXT_INST; } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vpush), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vpush)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - *tag |= TAG_NEW_BB; - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vpush)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - int single = BIT(8) == 0; - int d = (single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4)); - int imm32 = BITS(0, 7)<<2; - int regs = (single ? BITS(0, 7) : BITS(1, 7)); - - Value* Addr = SUB(R(13), CONST(imm32)); - //if(single) - // bb = arch_check_mm(cpu, bb, Addr, regs * 4, 0, cpu->dyncom_engine->bb_trap); - //else - // bb = arch_check_mm(cpu, bb, Addr, regs * 8, 0, cpu->dyncom_engine->bb_trap); - //Value* phys_addr; - - for (int i = 0; i < regs; i++) - { - if (single) - { - //Memory::Write32(addr, cpu->ExtReg[inst_cream->d+i]); - //memory_write(cpu, bb, Addr, RSPR(d + i), 32); - memory_write(cpu, bb, Addr, IBITCAST32(FR32(d + i)), 32); - bb = cpu->dyncom_engine->bb; - Addr = ADD(Addr, CONST(4)); - } - else - { - /* Careful of endianness, little by default */ - //memory_write(cpu, bb, Addr, RSPR((d + i) * 2), 32); - memory_write(cpu, bb, Addr, IBITCAST32(FR32((d + i) * 2)), 32); - bb = cpu->dyncom_engine->bb; - //memory_write(cpu, bb, ADD(Addr, CONST(4)), RSPR((d + i) * 2 + 1), 32); - memory_write(cpu, bb, ADD(Addr, CONST(4)), IBITCAST32(FR32((d + i) * 2 + 1)), 32); - bb = cpu->dyncom_engine->bb; - - Addr = ADD(Addr, CONST(8)); - } - } - LET(13, SUB(R(13), CONST(imm32))); - - return No_exp; -} -#endif /* ----------------------------------------------------------------------- */ /* VSTM */ @@ -3004,76 +1539,6 @@ VSTM_INST: /* encoding 1 */ } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vstm), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vstm)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - *tag |= TAG_NEW_BB; - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vstm)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - int single = BIT(8) == 0; - int add = BIT(23); - int wback = BIT(21); - int d = single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4); - int n = BITS(16, 19); - int imm32 = BITS(0, 7)<<2; - int regs = single ? BITS(0, 7) : BITS(1, 7); - - Value* Addr = SELECT(CONST1(add), R(n), SUB(R(n), CONST(imm32))); - //if(single) - // bb = arch_check_mm(cpu, bb, Addr, regs * 4, 0, cpu->dyncom_engine->bb_trap); - //else - // bb = arch_check_mm(cpu, bb, Addr, regs * 8, 0, cpu->dyncom_engine->bb_trap); - - int i; - Value* phys_addr; - for (i = 0; i < regs; i++) - { - if (single) - { - //Memory::Write32(addr, cpu->ExtReg[inst_cream->d+i]); - /* if R(i) is R15? */ - //memory_write(cpu, bb, Addr, RSPR(d + i), 32); - memory_write(cpu, bb, Addr, IBITCAST32(FR32(d + i)),32); - bb = cpu->dyncom_engine->bb; - Addr = ADD(Addr, CONST(4)); - } - else - { - //Memory::Write32(addr, cpu->ExtReg[(inst_cream->d+i)*2]); - //memory_write(cpu, bb, Addr, RSPR((d + i) * 2), 32); - memory_write(cpu, bb, Addr, IBITCAST32(FR32((d + i) * 2)),32); - bb = cpu->dyncom_engine->bb; - - //Memory::Write32(addr + 4, cpu->ExtReg[(inst_cream->d+i)*2 + 1]); - //memory_write(cpu, bb, ADD(Addr, CONST(4)), RSPR((d + i) * 2 + 1), 32); - memory_write(cpu, bb, ADD(Addr, CONST(4)), IBITCAST32(FR32((d + i) * 2 + 1)), 32); - bb = cpu->dyncom_engine->bb; - //addr += 8; - Addr = ADD(Addr, CONST(8)); - } - } - if (wback){ - //cpu->Reg[n] = (add ? cpu->Reg[n] + imm32 : - // cpu->Reg[n] - imm32); - LET(n, SELECT(CONST1(add), ADD(R(n), CONST(imm32)), SUB(R(n), CONST(imm32)))); - } - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VPOP */ /* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */ @@ -3142,70 +1607,6 @@ VPOP_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vpop), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vpop)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - /* Should check if PC is destination register */ - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - *tag |= TAG_NEW_BB; - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vpop)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - //arch_arm_undef(cpu, bb, instr); - int single = BIT(8) == 0; - int d = (single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4)); - int imm32 = BITS(0, 7)<<2; - int regs = (single ? BITS(0, 7) : BITS(1, 7)); - - int i; - unsigned int value1, value2; - - Value* Addr = R(13); - Value* val; - //if(single) - // bb = arch_check_mm(cpu, bb, Addr, regs * 4, 1, cpu->dyncom_engine->bb_trap); - //else - // bb = arch_check_mm(cpu, bb, Addr, regs * 4, 1, cpu->dyncom_engine->bb_trap); - //Value* phys_addr; - for (i = 0; i < regs; i++) - { - if (single) - { - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - LETFPS(d + i, FPBITCAST32(val)); - Addr = ADD(Addr, CONST(4)); - } - else - { - /* Careful of endianness, little by default */ - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - LETFPS((d + i) * 2, FPBITCAST32(val)); - memory_read(cpu, bb, ADD(Addr, CONST(4)), 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - LETFPS((d + i) * 2 + 1, FPBITCAST32(val)); - - Addr = ADD(Addr, CONST(8)); - } - } - LET(13, ADD(R(13), CONST(imm32))); - return No_exp; -} -#endif /* ----------------------------------------------------------------------- */ /* VLDR */ @@ -3271,67 +1672,6 @@ VLDR_INST: } #endif -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vldr), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vldr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - /* Should check if PC is destination register */ - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - *tag |= TAG_NEW_BB; - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vldr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - int single = BIT(8) == 0; - int add = BIT(23); - int wback = BIT(21); - int d = (single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4)); - int n = BITS(16, 19); - int imm32 = BITS(0, 7)<<2; - int regs = (single ? BITS(0, 7) : BITS(1, 7)); - Value* base = R(n); - if(n == 15){ - base = ADD(AND(base, CONST(0xFFFFFFFC)), CONST(8)); - } - Value* Addr = add ? (ADD(base, CONST(imm32))) : (SUB(base, CONST(imm32))); - //if(single) - // bb = arch_check_mm(cpu, bb, Addr, 4, 1, cpu->dyncom_engine->bb_trap); - //else - // bb = arch_check_mm(cpu, bb, Addr, 8, 1, cpu->dyncom_engine->bb_trap); - //Value* phys_addr; - Value* val; - if(single){ - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - //LETS(d, val); - LETFPS(d,FPBITCAST32(val)); - } - else{ - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - //LETS(d * 2, val); - LETFPS(d * 2,FPBITCAST32(val)); - memory_read(cpu, bb, ADD(Addr, CONST(4)), 0,32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - //LETS(d * 2 + 1, val); - LETFPS( d * 2 + 1,FPBITCAST32(val)); - } - - return No_exp; -} -#endif - /* ----------------------------------------------------------------------- */ /* VLDM */ /* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */ @@ -3403,76 +1743,3 @@ VLDM_INST: GOTO_NEXT_INST; } #endif - -#ifdef VFP_DYNCOM_TABLE -DYNCOM_FILL_ACTION(vldm), -#endif -#ifdef VFP_DYNCOM_TAG -int DYNCOM_TAG(vldm)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) -{ - int instr_size = INSTR_SIZE; - //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); - arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); - *tag |= TAG_NEW_BB; - if(instr >> 28 != 0xe) - *tag |= TAG_CONDITIONAL; - - return instr_size; -} -#endif -#ifdef VFP_DYNCOM_TRANS -int DYNCOM_TRANS(vldm)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ - int single = BIT(8) == 0; - int add = BIT(23); - int wback = BIT(21); - int d = single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|BIT(22)<<4; - int n = BITS(16, 19); - int imm32 = BITS(0, 7)<<2; - int regs = single ? BITS(0, 7) : BITS(1, 7); - - Value* Addr = SELECT(CONST1(add), R(n), SUB(R(n), CONST(imm32))); - //if(single) - // bb = arch_check_mm(cpu, bb, Addr, regs * 4, 1, cpu->dyncom_engine->bb_trap); - //else - // bb = arch_check_mm(cpu, bb, Addr, regs * 4, 1, cpu->dyncom_engine->bb_trap); - - int i; - //Value* phys_addr; - Value* val; - for (i = 0; i < regs; i++) - { - if (single) - { - //Memory::Write32(addr, cpu->ExtReg[inst_cream->d+i]); - /* if R(i) is R15? */ - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - //LETS(d + i, val); - LETFPS(d + i, FPBITCAST32(val)); - Addr = ADD(Addr, CONST(4)); - } - else - { - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - LETFPS((d + i) * 2, FPBITCAST32(val)); - memory_read(cpu, bb, Addr, 0, 32); - bb = cpu->dyncom_engine->bb; - val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); - LETFPS((d + i) * 2 + 1, FPBITCAST32(val)); - - //Memory::Write(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); - //addr += 8; - Addr = ADD(Addr, CONST(8)); - } - } - if (wback){ - //cpu->Reg[n] = (add ? cpu->Reg[n] + imm32 : - // cpu->Reg[n] - imm32); - LET(n, SELECT(CONST1(add), ADD(R(n), CONST(imm32)), SUB(R(n), CONST(imm32)))); - } - return No_exp; -} -#endif diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index b7872bdc4..8b2dfa388 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp @@ -419,7 +419,7 @@ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u3 d = vfp_get_float(state, sd); if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { - ret |= FPSCR_C | FPSCR_V; + ret |= FPSCR_CFLAG | FPSCR_VFLAG; if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) /* * Signalling NaN, or signalling on quiet NaN @@ -428,7 +428,7 @@ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u3 } if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { - ret |= FPSCR_C | FPSCR_V; + ret |= FPSCR_CFLAG | FPSCR_VFLAG; if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) /* * Signalling NaN, or signalling on quiet NaN @@ -441,7 +441,7 @@ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u3 /* * equal */ - ret |= FPSCR_Z | FPSCR_C; + ret |= FPSCR_ZFLAG | FPSCR_CFLAG; } else if (vfp_single_packed_sign(d ^ m)) { /* * different signs @@ -450,22 +450,22 @@ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u3 /* * d is negative, so d < m */ - ret |= FPSCR_N; + ret |= FPSCR_NFLAG; else /* * d is positive, so d > m */ - ret |= FPSCR_C; + ret |= FPSCR_CFLAG; } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { /* * d < m */ - ret |= FPSCR_N; + ret |= FPSCR_NFLAG; } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { /* * d > m */ - ret |= FPSCR_C; + ret |= FPSCR_CFLAG; } } return ret; @@ -491,46 +491,6 @@ static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 return vfp_compare(state, sd, 1, 0, fpscr); } -static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only -{ - struct vfp_single vsm; - struct vfp_double vdd; - int tm; - u32 exceptions = 0; - - vfp_single_unpack(&vsm, m); - - tm = vfp_single_type(&vsm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - vdd.sign = vsm.sign; - vdd.significand = (u64)vsm.significand << 32; - - /* - * If we have an infinity or NaN, the exponent must be 2047. - */ - if (tm & (VFP_INFINITY | VFP_NAN)) { - vdd.exponent = 2047; - if (tm == VFP_QNAN) - vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vdd.exponent = 0; - else - vdd.exponent = vsm.exponent + (1023 - 127); -pack_nan: - vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd"); - return vfp_double_pack(&vdd); -} - static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) { struct vfp_single vsm; @@ -981,6 +941,9 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp v = vfp_get_float(state, sd); pr_debug("VFP: s%u = %08x\n", sd, v); vfp_single_unpack(&vsn, v); + if (vsn.exponent == 0 && vsn.significand != 0) + vfp_single_normalise_denormal(&vsn); + if (negate & NEG_SUBTRACT) vsn.sign = vfp_sign_negate(vsn.sign); diff --git a/src/core/core.cpp b/src/core/core.cpp index e9e5c35cc..63be27be2 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -10,7 +10,6 @@ #include "core/settings.h" #include "core/arm/arm_interface.h" #include "core/arm/disassembler/arm_disasm.h" -#include "core/arm/interpreter/arm_interpreter.h" #include "core/arm/dyncom/arm_dyncom.h" #include "core/hle/hle.h" #include "core/hle/kernel/thread.h" @@ -59,17 +58,8 @@ void Stop() { int Init() { LOG_DEBUG(Core, "initialized OK"); - g_sys_core = new ARM_Interpreter(); - - switch (Settings::values.cpu_core) { - case CPU_Interpreter: - g_app_core = new ARM_DynCom(); - break; - case CPU_OldInterpreter: - default: - g_app_core = new ARM_Interpreter(); - break; - } + g_sys_core = new ARM_DynCom(); + g_app_core = new ARM_DynCom(); return 0; } diff --git a/src/core/core.h b/src/core/core.h index 2f5e8bc6b..5e132cb5a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -12,11 +12,6 @@ class ARM_Interface; namespace Core { -enum CPUCore { - CPU_Interpreter, - CPU_OldInterpreter, -}; - struct ThreadContext { u32 cpu_registers[13]; u32 sp; @@ -28,7 +23,6 @@ struct ThreadContext { u32 fpexc; // These are not part of native ThreadContext, but needed by emu - u32 reg_15; u32 mode; }; diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 390178f67..43a106549 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -181,20 +181,6 @@ public: } /** - * Tries to open the archive of this type with the specified path - * @param path Path to the archive - * @return ResultCode of the operation - */ - virtual ResultCode Open(const Path& path) = 0; - - /** - * Deletes the archive contents and then re-creates the base folder - * @param path Path to the archive - * @return ResultCode of the operation, 0 on success - */ - virtual ResultCode Format(const Path& path) const = 0; - - /** * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) */ virtual std::string GetName() const = 0; @@ -260,4 +246,29 @@ public: virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; }; +class ArchiveFactory : NonCopyable { +public: + virtual ~ArchiveFactory() { + } + + /** + * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) + */ + virtual std::string GetName() const = 0; + + /** + * Tries to open the archive of this type with the specified path + * @param path Path to the archive + * @return An ArchiveBackend corresponding operating specified archive path. + */ + virtual ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) = 0; + + /** + * Deletes the archive contents and then re-creates the base folder + * @param path Path to the archive + * @return ResultCode of the operation, 0 on success + */ + virtual ResultCode Format(const Path& path) = 0; +}; + } // namespace FileSys diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 33e4e76f8..0363c9771 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -6,6 +6,7 @@ #include "common/common_types.h" #include "common/file_util.h" +#include "common/make_unique.h" #include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/disk_archive.h" @@ -33,12 +34,12 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) SYSTEM_ID.c_str(), SDCARD_ID.c_str()); } -Archive_ExtSaveData::Archive_ExtSaveData(const std::string& mount_location, bool shared) - : DiskArchive(GetExtDataContainerPath(mount_location, shared)) { +ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared) + : mount_point(GetExtDataContainerPath(mount_location, shared)) { LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); } -bool Archive_ExtSaveData::Initialize() { +bool ArchiveFactory_ExtSaveData::Initialize() { if (!FileUtil::CreateFullPath(mount_point)) { LOG_ERROR(Service_FS, "Unable to create ExtSaveData base path."); return false; @@ -47,18 +48,18 @@ bool Archive_ExtSaveData::Initialize() { return true; } -ResultCode Archive_ExtSaveData::Open(const Path& path) { +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { std::string fullpath = GetExtSaveDataPath(mount_point, path); if (!FileUtil::Exists(fullpath)) { // TODO(Subv): Check error code, this one is probably wrong return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); } - concrete_mount_point = fullpath; - return RESULT_SUCCESS; + auto archive = Common::make_unique<DiskArchive>(fullpath); + return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); } -ResultCode Archive_ExtSaveData::Format(const Path& path) const { +ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { std::string fullpath = GetExtSaveDataPath(mount_point, path); FileUtil::CreateFullPath(fullpath); return RESULT_SUCCESS; diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index 802a11b5f..83c6b0291 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -15,9 +15,9 @@ namespace FileSys { /// File system interface to the ExtSaveData archive -class Archive_ExtSaveData final : public DiskArchive { +class ArchiveFactory_ExtSaveData final : public ArchiveFactory { public: - Archive_ExtSaveData(const std::string& mount_point, bool shared); + ArchiveFactory_ExtSaveData(const std::string& mount_point, bool shared); /** * Initialize the archive. @@ -25,21 +25,20 @@ public: */ bool Initialize(); - ResultCode Open(const Path& path) override; - ResultCode Format(const Path& path) const override; std::string GetName() const override { return "ExtSaveData"; } - const std::string& GetMountPoint() const override { - return concrete_mount_point; - } + ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; + ResultCode Format(const Path& path) override; -protected: + const std::string& GetMountPoint() const { return mount_point; } + +private: /** - * This holds the full directory path for this archive, it is only set after a successful call to Open, - * this is formed as <base extsavedatapath>/<type>/<high>/<low>. + * This holds the full directory path for this archive, it is only set after a successful call + * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. * See GetExtSaveDataPath for the code that extracts this data from an archive path. */ - std::string concrete_mount_point; + std::string mount_point; }; /** diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index a30f73d0e..bf54a3866 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -15,11 +15,24 @@ namespace FileSys { -Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) { +ArchiveFactory_RomFS::ArchiveFactory_RomFS(const Loader::AppLoader& app_loader) + : romfs_data(std::make_shared<std::vector<u8>>()) { // Load the RomFS from the app - if (Loader::ResultStatus::Success != app_loader.ReadRomFS(raw_data)) { + if (Loader::ResultStatus::Success != app_loader.ReadRomFS(*romfs_data)) { LOG_ERROR(Service_FS, "Unable to read RomFS!"); } } +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) { + auto archive = Common::make_unique<IVFCArchive>(romfs_data); + return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); +} + +ResultCode ArchiveFactory_RomFS::Format(const Path& path) { + LOG_ERROR(Service_FS, "Attempted to format a RomFS archive."); + // TODO: Verify error code + return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, + ErrorSummary::NotSupported, ErrorLevel::Permanent); +} + } // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 5cb75e04d..409bc670a 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -4,6 +4,7 @@ #pragma once +#include <memory> #include <vector> #include "common/common_types.h" @@ -17,12 +18,16 @@ namespace FileSys { /// File system interface to the RomFS archive -class Archive_RomFS final : public IVFCArchive { +class ArchiveFactory_RomFS final : public ArchiveFactory { public: - Archive_RomFS(const Loader::AppLoader& app_loader); + ArchiveFactory_RomFS(const Loader::AppLoader& app_loader); std::string GetName() const override { return "RomFS"; } - ResultCode Open(const Path& path) override { return RESULT_SUCCESS; } + ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; + ResultCode Format(const Path& path) override; + +private: + std::shared_ptr<std::vector<u8>> romfs_data; }; } // namespace FileSys diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index 3baee5294..8496e06f3 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp @@ -6,6 +6,7 @@ #include "common/common_types.h" #include "common/file_util.h" +#include "common/make_unique.h" #include "core/file_sys/archive_savedata.h" #include "core/file_sys/disk_archive.h" @@ -28,26 +29,28 @@ static std::string GetSaveDataPath(const std::string& mount_location, u64 progra return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low); } -Archive_SaveData::Archive_SaveData(const std::string& sdmc_directory) - : DiskArchive(GetSaveDataContainerPath(sdmc_directory)) { +ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory) + : mount_point(GetSaveDataContainerPath(sdmc_directory)) { LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); } -ResultCode Archive_SaveData::Open(const Path& path) { - if (concrete_mount_point.empty()) - concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id); +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { + std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id); if (!FileUtil::Exists(concrete_mount_point)) { // When a SaveData archive is created for the first time, it is not yet formatted - // and the save file/directory structure expected by the game has not yet been initialized. - // Returning the NotFormatted error code will signal the game to provision the SaveData archive - // with the files and folders that it expects. + // and the save file/directory structure expected by the game has not yet been initialized. + // Returning the NotFormatted error code will signal the game to provision the SaveData archive + // with the files and folders that it expects. return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); } - return RESULT_SUCCESS; + + auto archive = Common::make_unique<DiskArchive>(std::move(concrete_mount_point)); + return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); } -ResultCode Archive_SaveData::Format(const Path& path) const { +ResultCode ArchiveFactory_SaveData::Format(const Path& path) { + std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id); FileUtil::DeleteDirRecursively(concrete_mount_point); FileUtil::CreateFullPath(concrete_mount_point); return RESULT_SUCCESS; diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h index 07c7f7eff..db17afc92 100644 --- a/src/core/file_sys/archive_savedata.h +++ b/src/core/file_sys/archive_savedata.h @@ -15,22 +15,17 @@ namespace FileSys { /// File system interface to the SaveData archive -class Archive_SaveData final : public DiskArchive { +class ArchiveFactory_SaveData final : public ArchiveFactory { public: - Archive_SaveData(const std::string& mount_point); + ArchiveFactory_SaveData(const std::string& mount_point); std::string GetName() const override { return "SaveData"; } - ResultCode Open(const Path& path) override; + ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; + ResultCode Format(const Path& path) override; - ResultCode Format(const Path& path) const override; - - const std::string& GetMountPoint() const override { - return concrete_mount_point; - } - -protected: - std::string concrete_mount_point; +private: + std::string mount_point; }; } // namespace FileSys diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp index a7a507536..47d8a9d25 100644 --- a/src/core/file_sys/archive_savedatacheck.cpp +++ b/src/core/file_sys/archive_savedatacheck.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/file_util.h" +#include "common/make_unique.h" #include "core/file_sys/archive_savedatacheck.h" #include "core/hle/service/fs/archive.h" @@ -21,32 +22,33 @@ static std::string GetSaveDataCheckPath(const std::string& mount_point, u32 high mount_point.c_str(), high, low); } -Archive_SaveDataCheck::Archive_SaveDataCheck(const std::string& nand_directory) : +ArchiveFactory_SaveDataCheck::ArchiveFactory_SaveDataCheck(const std::string& nand_directory) : mount_point(GetSaveDataCheckContainerPath(nand_directory)) { } -ResultCode Archive_SaveDataCheck::Open(const Path& path) { - // TODO(Subv): We should not be overwriting raw_data everytime this function is called, - // but until we use factory classes to create the archives at runtime instead of creating them beforehand - // and allow multiple archives of the same type to be open at the same time without clobbering each other, - // we won't be able to maintain the state of each archive, hence we overwrite it every time it's needed. - // There are a number of problems with this, for example opening a file in this archive, then opening - // this archive again with a different path, will corrupt the previously open file. +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(const Path& path) { auto vec = path.AsBinary(); const u32* data = reinterpret_cast<u32*>(vec.data()); std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); FileUtil::IOFile file(file_path, "rb"); - std::fill(raw_data.begin(), raw_data.end(), 0); - if (!file.IsOpen()) { return ResultCode(-1); // TODO(Subv): Find the right error code } auto size = file.GetSize(); - raw_data.resize(size); - file.ReadBytes(raw_data.data(), size); + auto raw_data = std::make_shared<std::vector<u8>>(size); + file.ReadBytes(raw_data->data(), size); file.Close(); - return RESULT_SUCCESS; + + auto archive = Common::make_unique<IVFCArchive>(std::move(raw_data)); + return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); +} + +ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path) { + LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive."); + // TODO: Verify error code + return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, + ErrorSummary::NotSupported, ErrorLevel::Permanent); } } // namespace FileSys diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h index f6e73e803..f78a6f02e 100644 --- a/src/core/file_sys/archive_savedatacheck.h +++ b/src/core/file_sys/archive_savedatacheck.h @@ -17,12 +17,14 @@ namespace FileSys { /// File system interface to the SaveDataCheck archive -class Archive_SaveDataCheck final : public IVFCArchive { +class ArchiveFactory_SaveDataCheck final : public ArchiveFactory { public: - Archive_SaveDataCheck(const std::string& mount_point); + ArchiveFactory_SaveDataCheck(const std::string& mount_point); std::string GetName() const override { return "SaveDataCheck"; } - ResultCode Open(const Path& path) override; + + ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; + ResultCode Format(const Path& path) override; private: std::string mount_point; diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 26b03e82f..92b20c7f6 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -6,6 +6,7 @@ #include "common/common_types.h" #include "common/file_util.h" +#include "common/make_unique.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/disk_archive.h" @@ -16,17 +17,17 @@ namespace FileSys { -Archive_SDMC::Archive_SDMC(const std::string& sdmc_directory) : DiskArchive(sdmc_directory) { +ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory) : sdmc_directory(sdmc_directory) { LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str()); } -bool Archive_SDMC::Initialize() { +bool ArchiveFactory_SDMC::Initialize() { if (!Settings::values.use_virtual_sd) { LOG_WARNING(Service_FS, "SDMC disabled by config."); return false; } - if (!FileUtil::CreateFullPath(mount_point)) { + if (!FileUtil::CreateFullPath(sdmc_directory)) { LOG_ERROR(Service_FS, "Unable to create SDMC path."); return false; } @@ -34,4 +35,14 @@ bool Archive_SDMC::Initialize() { return true; } +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path) { + auto archive = Common::make_unique<DiskArchive>(sdmc_directory); + return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); +} + +ResultCode ArchiveFactory_SDMC::Format(const Path& path) { + // This is kind of an undesirable operation, so let's just ignore it. :) + return RESULT_SUCCESS; +} + } // namespace FileSys diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 1b801f217..1becf6c0f 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -15,9 +15,9 @@ namespace FileSys { /// File system interface to the SDMC archive -class Archive_SDMC final : public DiskArchive { +class ArchiveFactory_SDMC final : public ArchiveFactory { public: - Archive_SDMC(const std::string& mount_point); + ArchiveFactory_SDMC(const std::string& mount_point); /** * Initialize the archive. @@ -26,6 +26,12 @@ public: bool Initialize(); std::string GetName() const override { return "SDMC"; } + + ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; + ResultCode Format(const Path& path) override; + +private: + std::string sdmc_directory; }; } // namespace FileSys diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index c6e033fcd..f53fd57db 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp @@ -18,26 +18,26 @@ namespace FileSys { std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const { LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); - auto file = Common::make_unique<DiskFile>(this, path, mode); + auto file = Common::make_unique<DiskFile>(*this, path, mode); if (!file->Open()) return nullptr; return std::move(file); } bool DiskArchive::DeleteFile(const Path& path) const { - return FileUtil::Delete(GetMountPoint() + path.AsString()); + return FileUtil::Delete(mount_point + path.AsString()); } bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const { - return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); + return FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString()); } bool DiskArchive::DeleteDirectory(const Path& path) const { - return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); + return FileUtil::DeleteDir(mount_point + path.AsString()); } ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const { - std::string full_path = GetMountPoint() + path.AsString(); + std::string full_path = mount_point + path.AsString(); if (FileUtil::Exists(full_path)) return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info); @@ -58,16 +58,16 @@ ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const { bool DiskArchive::CreateDirectory(const Path& path) const { - return FileUtil::CreateDir(GetMountPoint() + path.AsString()); + return FileUtil::CreateDir(mount_point + path.AsString()); } bool DiskArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { - return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); + return FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString()); } std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const { LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); - auto directory = Common::make_unique<DiskDirectory>(this, path); + auto directory = Common::make_unique<DiskDirectory>(*this, path); if (!directory->Open()) return nullptr; return std::move(directory); @@ -75,13 +75,12 @@ std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) c //////////////////////////////////////////////////////////////////////////////////////////////////// -DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) { +DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode) { // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass // the root directory we set while opening the archive. // For example, opening /../../etc/passwd can give the emulated program your users list. - this->path = archive->GetMountPoint() + path.AsString(); + this->path = archive.mount_point + path.AsString(); this->mode.hex = mode.hex; - this->archive = archive; } bool DiskFile::Open() { @@ -134,12 +133,11 @@ bool DiskFile::Close() const { //////////////////////////////////////////////////////////////////////////////////////////////////// -DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) { +DiskDirectory::DiskDirectory(const DiskArchive& archive, const Path& path) { // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass // the root directory we set while opening the archive. // For example, opening /../../usr/bin can give the emulated program your installed programs. - this->path = archive->GetMountPoint() + path.AsString(); - this->archive = archive; + this->path = archive.mount_point + path.AsString(); } bool DiskDirectory::Open() { diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index 3472f6874..dbbdced74 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h @@ -24,8 +24,8 @@ class DiskArchive : public ArchiveBackend { public: DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} - virtual std::string GetName() const = 0; - virtual ResultCode Format(const Path& path) const { return RESULT_SUCCESS; } + virtual std::string GetName() const { return "DiskArchive: " + mount_point; } + std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; bool DeleteFile(const Path& path) const override; bool RenameFile(const Path& src_path, const Path& dest_path) const override; @@ -35,26 +35,17 @@ public: bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; - virtual ResultCode Open(const Path& path) override { - return RESULT_SUCCESS; - } - - /** - * Getter for the path used for this Archive - * @return Mount point of that passthrough archive - */ - virtual const std::string& GetMountPoint() const { - return mount_point; - } - protected: + friend class DiskFile; + friend class DiskDirectory; + std::string mount_point; }; class DiskFile : public FileBackend { public: DiskFile(); - DiskFile(const DiskArchive* archive, const Path& path, const Mode mode); + DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); bool Open() override; size_t Read(const u64 offset, const u32 length, u8* buffer) const override; @@ -68,7 +59,6 @@ public: } protected: - const DiskArchive* archive; std::string path; Mode mode; std::unique_ptr<FileUtil::IOFile> file; @@ -77,7 +67,7 @@ protected: class DiskDirectory : public DirectoryBackend { public: DiskDirectory(); - DiskDirectory(const DiskArchive* archive, const Path& path); + DiskDirectory(const DiskArchive& archive, const Path& path); ~DiskDirectory() override { Close(); @@ -91,7 +81,6 @@ public: } protected: - const DiskArchive* archive; std::string path; u32 total_entries_in_directory; FileUtil::FSTEntry directory; diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp index 68c3c8b81..35aca54fa 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp @@ -15,11 +15,15 @@ namespace FileSys { -IVFCArchive::IVFCArchive() { +IVFCArchive::IVFCArchive(std::shared_ptr<const std::vector<u8>> data) : data(data) { +} + +std::string IVFCArchive::GetName() const { + return "IVFC"; } std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { - return Common::make_unique<IVFCFile>(this); + return Common::make_unique<IVFCFile>(data); } bool IVFCArchive::DeleteFile(const Path& path) const { @@ -57,31 +61,25 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c return Common::make_unique<IVFCDirectory>(); } -ResultCode IVFCArchive::Format(const Path& path) const { - LOG_CRITICAL(Service_FS, "Attempted to format an IVFC archive (%s).", GetName().c_str()); - // TODO: Verify error code - return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent); -} - //////////////////////////////////////////////////////////////////////////////////////////////////// size_t IVFCFile::Read(const u64 offset, const u32 length, u8* buffer) const { LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); - memcpy(buffer, &archive->raw_data[(u32)offset], length); + memcpy(buffer, data->data() + offset, length); return length; } size_t IVFCFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { - LOG_CRITICAL(Service_FS, "Attempted to write to IVFC file in archive %s.", archive->GetName().c_str()); + LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); return 0; } size_t IVFCFile::GetSize() const { - return sizeof(u8) * archive->raw_data.size(); + return sizeof(u8) * data->size(); } bool IVFCFile::SetSize(const u64 size) const { - LOG_CRITICAL(Service_FS, "Attempted to set the size of an IVFC file in archive %s", archive->GetName().c_str()); + LOG_ERROR(Service_FS, "Attempted to set the size of an IVFC file"); return false; } diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index 6f4cc86df..1aff9e0a4 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h @@ -4,6 +4,7 @@ #pragma once +#include <memory> #include <vector> #include "common/common_types.h" @@ -23,7 +24,9 @@ namespace FileSys { */ class IVFCArchive : public ArchiveBackend { public: - IVFCArchive(); + IVFCArchive(std::shared_ptr<const std::vector<u8>> data); + + std::string GetName() const override; std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; bool DeleteFile(const Path& path) const override; @@ -33,16 +36,14 @@ public: bool CreateDirectory(const Path& path) const override; bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; - ResultCode Format(const Path& path) const override; protected: - friend class IVFCFile; - std::vector<u8> raw_data; + std::shared_ptr<const std::vector<u8>> data; }; class IVFCFile : public FileBackend { public: - IVFCFile(const IVFCArchive* archive) : archive(archive) {} + IVFCFile(std::shared_ptr<const std::vector<u8>> data) : data(data) {} bool Open() override { return true; } size_t Read(const u64 offset, const u32 length, u8* buffer) const override; @@ -53,7 +54,7 @@ public: void Flush() const override { } private: - const IVFCArchive* archive; + std::shared_ptr<const std::vector<u8>> data; }; class IVFCDirectory : public DirectoryBackend { diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 2d01e2ef5..42f8ce2d9 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -15,14 +15,15 @@ namespace Kernel { -ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { +AddressArbiter::AddressArbiter() {} +AddressArbiter::~AddressArbiter() {} + +SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) { SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter)); address_arbiter->name = std::move(name); - return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); + return address_arbiter; } ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, @@ -51,7 +52,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, case ArbitrationType::WaitIfLessThanWithTimeout: if ((s32)Memory::Read32(address) <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); - Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); + GetCurrentThread()->WakeAfterDelay(nanoseconds); HLE::Reschedule(__func__); } break; @@ -71,7 +72,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, Memory::Write32(address, memory_value); if (memory_value <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); - Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); + GetCurrentThread()->WakeAfterDelay(nanoseconds); HLE::Reschedule(__func__); } break; diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 638afff9e..8f6a1a8df 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -34,7 +34,7 @@ public: * @param name Optional name used for debugging. * @returns The created AddressArbiter. */ - static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); + static SharedPtr<AddressArbiter> Create(std::string name = "Unknown"); std::string GetTypeName() const override { return "Arbiter"; } std::string GetName() const override { return name; } @@ -47,7 +47,8 @@ public: ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); private: - AddressArbiter() = default; + AddressArbiter(); + ~AddressArbiter() override; }; } // namespace FileSys diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index d9ad40c6a..898e1c98f 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -14,16 +14,17 @@ namespace Kernel { -ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { +Event::Event() {} +Event::~Event() {} + +SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { SharedPtr<Event> evt(new Event); - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt)); evt->signaled = false; evt->reset_type = evt->intitial_reset_type = reset_type; evt->name = std::move(name); - return MakeResult<SharedPtr<Event>>(evt); + return evt; } bool Event::ShouldWait() { diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index 2c3e6b14e..fba960d2a 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -18,7 +18,7 @@ public: * @param reset_type ResetType describing how to create event * @param name Optional name of event */ - static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); + static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown"); std::string GetTypeName() const override { return "Event"; } std::string GetName() const override { return name; } @@ -39,7 +39,8 @@ public: void Clear(); private: - Event() = default; + Event(); + ~Event() override; }; } // namespace diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d7fa4dcea..a2ffbcdb7 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -14,14 +14,16 @@ namespace Kernel { +unsigned int Object::next_object_id = 0; + SharedPtr<Thread> g_main_thread = nullptr; HandleTable g_handle_table; u64 g_program_id = 0; -void WaitObject::AddWaitingThread(Thread* thread) { +void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr == waiting_threads.end()) - waiting_threads.push_back(thread); + waiting_threads.push_back(std::move(thread)); } void WaitObject::RemoveWaitingThread(Thread* thread) { @@ -30,11 +32,11 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -Thread* WaitObject::WakeupNextThread() { +SharedPtr<Thread> WaitObject::WakeupNextThread() { if (waiting_threads.empty()) return nullptr; - auto next_thread = waiting_threads.front(); + auto next_thread = std::move(waiting_threads.front()); waiting_threads.erase(waiting_threads.begin()); next_thread->ReleaseWaitObject(this); @@ -74,13 +76,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { // CTR-OS doesn't use generation 0, so skip straight to 1. if (next_generation >= (1 << 15)) next_generation = 1; - Handle handle = generation | (slot << 15); - if (obj->handle == INVALID_HANDLE) - obj->handle = handle; - generations[slot] = generation; objects[slot] = std::move(obj); + Handle handle = generation | (slot << 15); return MakeResult<Handle>(handle); } @@ -98,11 +97,10 @@ ResultCode HandleTable::Close(Handle handle) { return ERR_INVALID_HANDLE; size_t slot = GetSlot(handle); - u16 generation = GetGeneration(handle); objects[slot] = nullptr; - generations[generation] = next_free_slot; + generations[slot] = next_free_slot; next_free_slot = slot; return RESULT_SUCCESS; } @@ -155,12 +153,8 @@ void Shutdown() { * @return True on success, otherwise false */ bool LoadExec(u32 entry_point) { - Core::g_app_core->SetPC(entry_point); - // 0x30 is the typical main thread priority I've seen used so far - g_main_thread = Kernel::SetupMainThread(0x30, Kernel::DEFAULT_STACK_SIZE); - // Setup the idle thread - Kernel::SetupIdleThread(); + g_main_thread = Kernel::SetupMainThread(Kernel::DEFAULT_STACK_SIZE, entry_point, 0x30); return true; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9860479ac..4d8e388b6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -58,14 +58,12 @@ enum { DEFAULT_STACK_SIZE = 0x4000, }; -class HandleTable; - class Object : NonCopyable { - friend class HandleTable; - u32 handle = INVALID_HANDLE; public: virtual ~Object() {} - Handle GetHandle() const { return handle; } + + /// Returns a unique identifier for the object. For debugging purposes only. + unsigned int GetObjectId() const { return object_id; } virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } @@ -101,7 +99,10 @@ private: friend void intrusive_ptr_add_ref(Object*); friend void intrusive_ptr_release(Object*); + static unsigned int next_object_id; + unsigned int ref_count = 0; + unsigned int object_id = next_object_id++; }; // Special functions used by boost::instrusive_ptr to do automatic ref-counting @@ -135,25 +136,26 @@ public: * Add a thread to wait on this object * @param thread Pointer to thread to add */ - void AddWaitingThread(Thread* thread); + void AddWaitingThread(SharedPtr<Thread> thread); /** * Removes a thread from waiting on this object (e.g. if it was resumed already) * @param thread Pointer to thread to remove */ - void RemoveWaitingThread(Thread* thead); + void RemoveWaitingThread(Thread* thread); /** * Wake up the next thread waiting on this object * @return Pointer to the thread that was resumed, nullptr if no threads are waiting */ - Thread* WakeupNextThread(); + SharedPtr<Thread> WakeupNextThread(); /// Wake up all threads waiting on this object void WakeupAllWaitingThreads(); private: - std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available + /// Threads waiting for this object to become available + std::vector<SharedPtr<Thread>> waiting_threads; }; /** @@ -274,7 +276,6 @@ private: }; extern HandleTable g_handle_table; -extern SharedPtr<Thread> g_main_thread; /// The ID code of the currently running game /// TODO(Subv): This variable should not be here, diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index acf484659..a811db392 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -5,6 +5,8 @@ #include <map> #include <vector> +#include <boost/range/algorithm_ext/erase.hpp> + #include "common/common.h" #include "core/hle/kernel/kernel.h" @@ -13,16 +15,13 @@ namespace Kernel { -typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; -static MutexMap g_mutex_held_locks; - /** * Resumes a thread waiting for the specified mutex * @param mutex The mutex that some thread is waiting on */ static void ResumeWaitingThread(Mutex* mutex) { // Reset mutex lock thread handle, nothing is waiting - mutex->locked = false; + mutex->lock_count = 0; mutex->holding_thread = nullptr; // Find the next waiting thread for the mutex... @@ -33,24 +32,19 @@ static void ResumeWaitingThread(Mutex* mutex) { } void ReleaseThreadMutexes(Thread* thread) { - auto locked_range = g_mutex_held_locks.equal_range(thread); - - // Release every mutex that the thread holds, and resume execution on the waiting threads - for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { - ResumeWaitingThread(iter->second.get()); + for (auto& mtx : thread->held_mutexes) { + ResumeWaitingThread(mtx.get()); } - - // Erase all the locks that this thread holds - g_mutex_held_locks.erase(thread); + thread->held_mutexes.clear(); } -ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { +Mutex::Mutex() {} +Mutex::~Mutex() {} + +SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { SharedPtr<Mutex> mutex(new Mutex); - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); - mutex->initial_locked = initial_locked; - mutex->locked = false; + mutex->lock_count = 0; mutex->name = std::move(name); mutex->holding_thread = nullptr; @@ -58,42 +52,40 @@ ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) if (initial_locked) mutex->Acquire(); - return MakeResult<SharedPtr<Mutex>>(mutex); + return mutex; } bool Mutex::ShouldWait() { - return locked && holding_thread != GetCurrentThread(); + return lock_count > 0 && holding_thread != GetCurrentThread();; } void Mutex::Acquire() { Acquire(GetCurrentThread()); } -void Mutex::Acquire(Thread* thread) { +void Mutex::Acquire(SharedPtr<Thread> thread) { _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); - if (locked) - return; - locked = true; + // Actually "acquire" the mutex only if we don't already have it... + if (lock_count == 0) { + thread->held_mutexes.insert(this); + holding_thread = std::move(thread); + } - g_mutex_held_locks.insert(std::make_pair(thread, this)); - holding_thread = thread; + lock_count++; } void Mutex::Release() { - if (!locked) - return; - - auto locked_range = g_mutex_held_locks.equal_range(holding_thread); - - for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) { - if (iter->second == this) { - g_mutex_held_locks.erase(iter); - break; + // Only release if the mutex is held... + if (lock_count > 0) { + lock_count--; + + // Yield to the next thread only if we've fully released the mutex... + if (lock_count == 0) { + holding_thread->held_mutexes.erase(this); + ResumeWaitingThread(this); } } - - ResumeWaitingThread(this); } } // namespace diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 1e69528f1..d6d5328be 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -22,7 +22,7 @@ public: * @param name Optional name of mutex * @return Pointer to new Mutex object */ - static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); + static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown"); std::string GetTypeName() const override { return "Mutex"; } std::string GetName() const override { return name; } @@ -30,8 +30,7 @@ public: static const HandleType HANDLE_TYPE = HandleType::Mutex; HandleType GetHandleType() const override { return HANDLE_TYPE; } - bool initial_locked; ///< Initial lock state when mutex was created - bool locked; ///< Current locked state + int lock_count; ///< Number of times the mutex has been acquired std::string name; ///< Name of mutex (optional) SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex @@ -43,11 +42,12 @@ public: * @param mutex Mutex that is to be acquired * @param thread Thread that will acquire the mutex */ - void Acquire(Thread* thread); + void Acquire(SharedPtr<Thread> thread); void Release(); private: - Mutex() = default; + Mutex(); + ~Mutex() override; }; /** diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index a9e406ef4..c8cf8b9a2 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -10,6 +10,9 @@ namespace Kernel { +Semaphore::Semaphore() {} +Semaphore::~Semaphore() {} + ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, std::string name) { @@ -18,8 +21,6 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou ErrorSummary::WrongArgument, ErrorLevel::Permanent); SharedPtr<Semaphore> semaphore(new Semaphore); - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore)); // When the semaphore is created, some slots are reserved for other threads, // and the rest is reserved for the caller thread diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 9bb404ab6..d8dc1fd78 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h @@ -47,7 +47,8 @@ public: ResultVal<s32> Release(s32 release_count); private: - Semaphore() = default; + Semaphore(); + ~Semaphore() override; }; } // namespace diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp new file mode 100644 index 000000000..0594967f8 --- /dev/null +++ b/src/core/hle/kernel/session.cpp @@ -0,0 +1,13 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/session.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +Session::Session() {} +Session::~Session() {} + +} diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 1788e4375..7cc9332c9 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -5,6 +5,7 @@ #pragma once #include "core/hle/kernel/kernel.h" +#include "core/mem_map.h" namespace Kernel { @@ -43,6 +44,9 @@ inline static u32* GetCommandBuffer(const int offset=0) { */ class Session : public WaitObject { public: + Session(); + ~Session() override; + std::string GetTypeName() const override { return "Session"; } static const HandleType HANDLE_TYPE = HandleType::Session; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 536d134b0..4211fcf04 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -9,30 +9,31 @@ namespace Kernel { -ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { - SharedPtr<SharedMemory> shared_memory(new SharedMemory); +SharedMemory::SharedMemory() {} +SharedMemory::~SharedMemory() {} - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); +SharedPtr<SharedMemory> SharedMemory::Create(std::string name) { + SharedPtr<SharedMemory> shared_memory(new SharedMemory); shared_memory->name = std::move(name); - return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); + + return shared_memory; } ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { - LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", - GetHandle(), address); + LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!", + GetObjectId(), address); // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } - base_address = address; - permissions = permissions; - other_permissions = other_permissions; + this->base_address = address; + this->permissions = permissions; + this->other_permissions = other_permissions; return RESULT_SUCCESS; } @@ -41,7 +42,7 @@ ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { if (base_address != 0) return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); - LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); + LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); // TODO(yuriks): Verify error code. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidState, ErrorLevel::Permanent); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index f9ae23e93..5833b411c 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -29,7 +29,7 @@ public: * Creates a shared memory object * @param name Optional object name, used only for debugging purposes. */ - static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); + static SharedPtr<SharedMemory> Create(std::string name = "Unknown"); std::string GetTypeName() const override { return "SharedMemory"; } @@ -51,13 +51,14 @@ public: */ ResultVal<u8*> GetPointer(u32 offset = 0); - VAddr base_address; ///< Address of shared memory block in RAM + VAddr base_address; ///< Address of shared memory block in RAM MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) std::string name; ///< Name of shared memory object (optional) private: - SharedMemory() = default; + SharedMemory(); + ~SharedMemory() override; }; } // namespace diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 03b492c75..7f629c20e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -4,7 +4,6 @@ #include <algorithm> #include <list> -#include <map> #include <vector> #include "common/common.h" @@ -22,8 +21,11 @@ namespace Kernel { +/// Event type for the thread wake up event +static int ThreadWakeupEventType = -1; + bool Thread::ShouldWait() { - return status != THREADSTATUS_DORMANT; + return status != THREADSTATUS_DEAD; } void Thread::Acquire() { @@ -34,94 +36,75 @@ void Thread::Acquire() { static std::vector<SharedPtr<Thread>> thread_list; // Lists only ready thread ids. -static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> thread_ready_queue; +static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue; static Thread* current_thread; -static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup -static u32 next_thread_id; ///< The next available thread id +// The first available thread id at startup +static u32 next_thread_id = 1; -Thread* GetCurrentThread() { - return current_thread; +/** + * Creates a new thread ID + * @return The new thread ID + */ +inline static u32 const NewThreadId() { + return next_thread_id++; } -/// Resets a thread -static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { - memset(&t->context, 0, sizeof(Core::ThreadContext)); +Thread::Thread() {} +Thread::~Thread() {} - t->context.cpu_registers[0] = arg; - t->context.pc = t->context.reg_15 = t->entry_point; - t->context.sp = t->stack_top; - t->context.cpsr = 0x1F; // Usermode - - // TODO(bunnei): This instructs the CPU core to start the execution as if it is "resuming" a - // thread. This is somewhat Sky-Eye specific, and should be re-architected in the future to be - // agnostic of the CPU core. - t->context.mode = 8; - - if (t->current_priority < lowest_priority) { - t->current_priority = t->initial_priority; - } - - t->wait_objects.clear(); - t->wait_address = 0; -} - -/// Change a thread to "ready" state -static void ChangeReadyState(Thread* t, bool ready) { - if (t->IsReady()) { - if (!ready) { - thread_ready_queue.remove(t->current_priority, t); - } - } else if (ready) { - if (t->IsRunning()) { - thread_ready_queue.push_front(t->current_priority, t); - } else { - thread_ready_queue.push_back(t->current_priority, t); - } - t->status = THREADSTATUS_READY; - } +Thread* GetCurrentThread() { + return current_thread; } -/// Check if a thread is waiting on a the specified wait object +/** + * Check if a thread is waiting on the specified wait object + * @param thread The thread to test + * @param wait_object The object to test against + * @return True if the thread is waiting, false otherwise + */ static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { - auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + if (thread->status != THREADSTATUS_WAIT_SYNCH) + return false; - if (itr != thread->wait_objects.end()) - return thread->IsWaiting(); - - return false; + auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + return itr != thread->wait_objects.end(); } -/// Check if the specified thread is waiting on the specified address to be arbitrated +/** + * Check if the specified thread is waiting on the specified address to be arbitrated + * @param thread The thread to test + * @param wait_address The address to test against + * @return True if the thread is waiting, false otherwise + */ static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { - return thread->IsWaiting() && thread->wait_objects.empty() && wait_address == thread->wait_address; + return thread->status == THREADSTATUS_WAIT_ARB && wait_address == thread->wait_address; } -/// Stops the current thread -void Thread::Stop(const char* reason) { +void Thread::Stop() { // Release all the mutexes that this thread holds ReleaseThreadMutexes(this); - ChangeReadyState(this, false); - status = THREADSTATUS_DORMANT; - WakeupAllWaitingThreads(); + // Cancel any outstanding wakeup events for this thread + CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); - // Stopped threads are never waiting. - wait_objects.clear(); - wait_address = 0; -} + // Clean up thread from ready queue + // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) + if (status == THREADSTATUS_READY){ + ready_queue.remove(current_priority, this); + } -/// Changes a threads state -static void ChangeThreadState(Thread* t, ThreadStatus new_status) { - if (!t || t->status == new_status) { - return; + status = THREADSTATUS_DEAD; + + WakeupAllWaitingThreads(); + + // Clean up any dangling references in objects that this thread was waiting for + for (auto& wait_object : wait_objects) { + wait_object->RemoveWaitingThread(this); } - ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); - t->status = new_status; } -/// Arbitrate the highest priority thread that is waiting Thread* ArbitrateHighestPriorityThread(u32 address) { Thread* highest_priority_thread = nullptr; s32 priority = THREADPRIO_LOWEST; @@ -148,118 +131,124 @@ Thread* ArbitrateHighestPriorityThread(u32 address) { return highest_priority_thread; } -/// Arbitrate all threads currently waiting void ArbitrateAllThreads(u32 address) { - - // Iterate through threads, find highest priority thread that is waiting to be arbitrated... + // Resume all threads found to be waiting on the address for (auto& thread : thread_list) { if (CheckWait_AddressArbiter(thread.get(), address)) thread->ResumeFromWait(); } } -/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) -static void CallThread(Thread* t) { - // Stop waiting - ChangeThreadState(t, THREADSTATUS_READY); -} +/** + * Switches the CPU's active thread context to that of the specified thread + * @param new_thread The thread to switch to + */ +static void SwitchContext(Thread* new_thread) { + _dbg_assert_msg_(Kernel, new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); -/// Switches CPU context to that of the specified thread -static void SwitchContext(Thread* t) { - Thread* cur = GetCurrentThread(); + Thread* previous_thread = GetCurrentThread(); - // Save context for current thread - if (cur) { - Core::g_app_core->SaveContext(cur->context); + // Save context for previous thread + if (previous_thread) { + Core::g_app_core->SaveContext(previous_thread->context); - if (cur->IsRunning()) { - ChangeReadyState(cur, true); + if (previous_thread->status == THREADSTATUS_RUNNING) { + // This is only the case when a reschedule is triggered without the current thread + // yielding execution (i.e. an event triggered, system core time-sliced, etc) + ready_queue.push_front(previous_thread->current_priority, previous_thread); + previous_thread->status = THREADSTATUS_READY; } } + // Load context of new thread - if (t) { - current_thread = t; - ChangeReadyState(t, false); - t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; - Core::g_app_core->LoadContext(t->context); + if (new_thread) { + current_thread = new_thread; + + ready_queue.remove(new_thread->current_priority, new_thread); + new_thread->status = THREADSTATUS_RUNNING; + + Core::g_app_core->LoadContext(new_thread->context); } else { current_thread = nullptr; } } -/// Gets the next thread that is ready to be run by priority -static Thread* NextThread() { +/** + * Pops and returns the next thread from the thread queue + * @return A pointer to the next ready thread + */ +static Thread* PopNextReadyThread() { Thread* next; - Thread* cur = GetCurrentThread(); + Thread* thread = GetCurrentThread(); - if (cur && cur->IsRunning()) { - next = thread_ready_queue.pop_first_better(cur->current_priority); + if (thread && thread->status == THREADSTATUS_RUNNING) { + // We have to do better than the current thread. + // This call returns null when that's not possible. + next = ready_queue.pop_first_better(thread->current_priority); } else { - next = thread_ready_queue.pop_first(); - } - if (next == 0) { - return nullptr; + next = ready_queue.pop_first(); } + return next; } void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); - ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); + thread->status = THREADSTATUS_WAIT_SLEEP; } -void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all) { +void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all) { Thread* thread = GetCurrentThread(); thread->wait_set_output = wait_set_output; thread->wait_all = wait_all; - - // It's possible to call WaitSynchronizationN without any objects passed in... - if (wait_object != nullptr) - thread->wait_objects.push_back(wait_object); - - ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); + thread->wait_objects = std::move(wait_objects); + thread->status = THREADSTATUS_WAIT_SYNCH; } void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { Thread* thread = GetCurrentThread(); thread->wait_address = wait_address; - ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); + thread->status = THREADSTATUS_WAIT_ARB; } -/// Event type for the thread wake up event -static int ThreadWakeupEventType = -1; - -/// Callback that will wake up the thread it was scheduled for -static void ThreadWakeupCallback(u64 parameter, int cycles_late) { - Handle handle = static_cast<Handle>(parameter); - SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(handle); +// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing +// us to simply use a pool index or similar. +static Kernel::HandleTable wakeup_callback_handle_table; + +/** + * Callback that will wake up the thread it was scheduled for + * @param thread_handle The handle of the thread that's been awoken + * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time + */ +static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { + SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle); if (thread == nullptr) { - LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); + LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", (Handle)thread_handle); return; } - thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, - ErrorSummary::StatusChanged, ErrorLevel::Info)); + if (thread->status == THREADSTATUS_WAIT_SYNCH) { + thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, + ErrorSummary::StatusChanged, ErrorLevel::Info)); - if (thread->wait_set_output) - thread->SetWaitSynchronizationOutput(-1); + if (thread->wait_set_output) + thread->SetWaitSynchronizationOutput(-1); + } thread->ResumeFromWait(); } - -void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { +void Thread::WakeAfterDelay(s64 nanoseconds) { // Don't schedule a wakeup if the thread wants to wait forever if (nanoseconds == -1) return; - _dbg_assert_(Kernel, thread != nullptr); u64 microseconds = nanoseconds / 1000; - CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); + CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); } void Thread::ReleaseWaitObject(WaitObject* wait_object) { - if (wait_objects.empty()) { + if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) { LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); return; } @@ -301,49 +290,56 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { } void Thread::ResumeFromWait() { - // Cancel any outstanding wakeup events - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); - - status &= ~THREADSTATUS_WAIT; - - // Remove this thread from all other WaitObjects - for (auto wait_object : wait_objects) - wait_object->RemoveWaitingThread(this); - - wait_objects.clear(); - wait_set_output = false; - wait_all = false; - wait_address = 0; - - if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { - ChangeReadyState(this, true); + // Cancel any outstanding wakeup events for this thread + CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); + + switch (status) { + case THREADSTATUS_WAIT_SYNCH: + // Remove this thread from all other WaitObjects + for (auto wait_object : wait_objects) + wait_object->RemoveWaitingThread(this); + break; + case THREADSTATUS_WAIT_ARB: + case THREADSTATUS_WAIT_SLEEP: + break; + case THREADSTATUS_RUNNING: + case THREADSTATUS_READY: + LOG_ERROR(Kernel, "Thread with object id %u has already resumed.", GetObjectId()); + _dbg_assert_(Kernel, false); + return; + case THREADSTATUS_DEAD: + // This should never happen, as threads must complete before being stopped. + LOG_CRITICAL(Kernel, "Thread with object id %u cannot be resumed because it's DEAD.", + GetObjectId()); + _dbg_assert_(Kernel, false); + return; } + + ready_queue.push_back(current_priority, this); + status = THREADSTATUS_READY; } -/// Prints the thread queue for debugging purposes +/** + * Prints the thread queue for debugging purposes + */ static void DebugThreadQueue() { Thread* thread = GetCurrentThread(); if (!thread) { - return; + LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); + } else { + LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId()); } - LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle()); + for (auto& t : thread_list) { - s32 priority = thread_ready_queue.contains(t.get()); + s32 priority = ready_queue.contains(t.get()); if (priority != -1) { - LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle()); + LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId()); } } } ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, - u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size) { - if (stack_size < 0x200) { - LOG_ERROR(Kernel, "(name=%s): invalid stack_size=0x%08X", name.c_str(), stack_size); - // TODO: Verify error - return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Kernel, - ErrorSummary::InvalidArgument, ErrorLevel::Permanent); - } - + u32 arg, s32 processor_id, VAddr stack_top) { if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", @@ -362,22 +358,13 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, SharedPtr<Thread> thread(new Thread); - // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for - // the time being. Create a handle here, it will be copied to the handle field in - // the object and use by the rest of the code. This should be removed when other - // code doesn't rely on the handle anymore. - ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread); - if (handle.Failed()) - return handle.Code(); - thread_list.push_back(thread); - thread_ready_queue.prepare(priority); + ready_queue.prepare(priority); - thread->thread_id = next_thread_id++; + thread->thread_id = NewThreadId(); thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; thread->stack_top = stack_top; - thread->stack_size = stack_size; thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; thread->wait_set_output = false; @@ -385,88 +372,86 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); + thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); + + // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used + // to initialize the context + Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg); - ResetThread(thread.get(), arg, 0); - CallThread(thread.get()); + ready_queue.push_back(thread->current_priority, thread.get()); + thread->status = THREADSTATUS_READY; return MakeResult<SharedPtr<Thread>>(std::move(thread)); } -/// Set the priority of the thread specified by handle -void Thread::SetPriority(s32 priority) { - // If priority is invalid, clamp to valid range - if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { - s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); - LOG_WARNING(Kernel_SVC, "invalid priority=%d, clamping to %d", priority, new_priority); +// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be returned. +static void ClampPriority(const Thread* thread, s32* priority) { + if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) { + _dbg_assert_msg_(Kernel, false, "Application passed an out of range priority. An error should be returned."); + + s32 new_priority = CLAMP(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); + LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", + thread->name.c_str(), *priority, new_priority); // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm // validity of this - priority = new_priority; + *priority = new_priority; } +} - // Change thread priority - s32 old = current_priority; - thread_ready_queue.remove(old, this); - current_priority = priority; - thread_ready_queue.prepare(current_priority); +void Thread::SetPriority(s32 priority) { + ClampPriority(this, &priority); - // Change thread status to "ready" and push to ready queue - if (IsRunning()) { - status = (status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; + if (current_priority == priority) { + return; } - if (IsReady()) { - thread_ready_queue.push_back(current_priority, this); + + if (status == THREADSTATUS_READY) { + // If thread was ready, adjust queues + ready_queue.remove(current_priority, this); + ready_queue.prepare(priority); + ready_queue.push_back(priority, this); } + + current_priority = priority; } -Handle SetupIdleThread() { +SharedPtr<Thread> SetupIdleThread() { // We need to pass a few valid values to get around parameter checking in Thread::Create. - auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, - THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE); - _dbg_assert_(Kernel, thread_res.Succeeded()); - SharedPtr<Thread> thread = std::move(*thread_res); + auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, + THREADPROCESSORID_0, 0).MoveFrom(); thread->idle = true; - CallThread(thread.get()); - return thread->GetHandle(); + return thread; } -SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) { +SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority) { + _dbg_assert_(Kernel, !GetCurrentThread()); + // Initialize new "main" thread - auto thread_res = Thread::Create("main", Core::g_app_core->GetPC(), priority, 0, - THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); - // TODO(yuriks): Propagate error - _dbg_assert_(Kernel, thread_res.Succeeded()); - SharedPtr<Thread> thread = std::move(*thread_res); - - // If running another thread already, set it to "ready" state - Thread* cur = GetCurrentThread(); - if (cur && cur->IsRunning()) { - ChangeReadyState(cur, true); - } + auto thread_res = Thread::Create("main", entry_point, priority, 0, + THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END); + + SharedPtr<Thread> thread = thread_res.MoveFrom(); // Run new "main" thread - current_thread = thread.get(); - thread->status = THREADSTATUS_RUNNING; - Core::g_app_core->LoadContext(thread->context); + SwitchContext(thread.get()); return thread; } - -/// Reschedules to the next available thread (call after current thread is suspended) void Reschedule() { Thread* prev = GetCurrentThread(); - Thread* next = NextThread(); + Thread* next = PopNextReadyThread(); HLE::g_reschedule = false; if (next != nullptr) { - LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); + LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId()); SwitchContext(next); } else { - LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); + LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId()); for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(), + LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(), thread->current_priority, thread->status); } } @@ -483,8 +468,10 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { //////////////////////////////////////////////////////////////////////////////////////////////////// void ThreadingInit() { - next_thread_id = INITIAL_THREAD_ID; ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); + + // Setup the idle thread + SetupIdleThread(); } void ThreadingShutdown() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d6299364a..cfd073a70 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -7,6 +7,8 @@ #include <string> #include <vector> +#include <boost/container/flat_set.hpp> + #include "common/common_types.h" #include "core/core.h" @@ -29,21 +31,34 @@ enum ThreadProcessorId { }; enum ThreadStatus { - THREADSTATUS_RUNNING = 1, - THREADSTATUS_READY = 2, - THREADSTATUS_WAIT = 4, - THREADSTATUS_SUSPEND = 8, - THREADSTATUS_DORMANT = 16, - THREADSTATUS_DEAD = 32, - THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND + THREADSTATUS_RUNNING, ///< Currently running + THREADSTATUS_READY, ///< Ready to run + THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter + THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC + THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC + THREADSTATUS_DORMANT, ///< Created but not yet made ready + THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated }; namespace Kernel { +class Mutex; + class Thread final : public WaitObject { public: + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param stack_size The size of the thread's stack + * @return A shared pointer to the newly created thread + */ static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, - u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); + u32 arg, s32 processor_id, VAddr stack_top); std::string GetName() const override { return name; } std::string GetTypeName() const override { return "Thread"; } @@ -51,22 +66,32 @@ public: static const HandleType HANDLE_TYPE = HandleType::Thread; HandleType GetHandleType() const override { return HANDLE_TYPE; } - inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } - inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } - inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } - inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } - inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } - inline bool IsIdle() const { return idle; } - bool ShouldWait() override; void Acquire() override; + /** + * Checks if the thread is an idle (stub) thread + * @return True if the thread is an idle (stub) thread, false otherwise + */ + inline bool IsIdle() const { return idle; } + + /** + * Gets the thread's current priority + * @return The current thread's priority + */ s32 GetPriority() const { return current_priority; } + + /** + * Sets the thread's current priority + * @param priority The new priority + */ void SetPriority(s32 priority); + /** + * Gets the thread's thread ID + * @return The thread's ID + */ u32 GetThreadId() const { return thread_id; } - - void Stop(const char* reason); /** * Release an acquired wait object @@ -74,10 +99,18 @@ public: */ void ReleaseWaitObject(WaitObject* wait_object); - /// Resumes a thread from waiting by marking it as "ready" + /** + * Resumes a thread from waiting + */ void ResumeFromWait(); /** + * Schedules an event to wake up the specified thread after the specified delay + * @param nanoseconds The time this thread will be allowed to sleep for + */ + void WakeAfterDelay(s64 nanoseconds); + + /** * Sets the result after the thread awakens (from either WaitSynchronization SVC) * @param result Value to set to the returned result */ @@ -89,6 +122,11 @@ public: */ void SetWaitSynchronizationOutput(s32 output); + /** + * Stops a thread, invalidating it from further use + */ + void Stop(); + Core::ThreadContext context; u32 thread_id; @@ -96,15 +134,16 @@ public: u32 status; u32 entry_point; u32 stack_top; - u32 stack_size; s32 initial_priority; s32 current_priority; s32 processor_id; - std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on + /// Mutexes currently held by this thread, which will be released when it exits. + boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; + std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address bool wait_all; ///< True if the thread is waiting on all objects before resuming bool wait_set_output; ///< True if the output parameter should be set on thread wakeup @@ -115,34 +154,58 @@ public: bool idle = false; private: - Thread() = default; + Thread(); + ~Thread() override; + + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. + Handle callback_handle; }; -/// Sets up the primary application thread -SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); +extern SharedPtr<Thread> g_main_thread; + +/** + * Sets up the primary application thread + * @param stack_size The size of the thread's stack + * @param entry_point The address at which the thread should start execution + * @param priority The priority to give the main thread + * @return A shared pointer to the main thread + */ +SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority); -/// Reschedules to the next available thread (call after current thread is suspended) +/** + * Reschedules to the next available thread (call after current thread is suspended) + */ void Reschedule(); -/// Arbitrate the highest priority thread that is waiting +/** + * Arbitrate the highest priority thread that is waiting + * @param address The address for which waiting threads should be arbitrated + */ Thread* ArbitrateHighestPriorityThread(u32 address); -/// Arbitrate all threads currently waiting... +/** + * Arbitrate all threads currently waiting. + * @param address The address for which waiting threads should be arbitrated + */ void ArbitrateAllThreads(u32 address); -/// Gets the current thread +/** + * Gets the current thread + */ Thread* GetCurrentThread(); -/// Waits the current thread on a sleep +/** + * Waits the current thread on a sleep + */ void WaitCurrentThread_Sleep(); /** * Waits the current thread from a WaitSynchronization call - * @param wait_object Kernel object that we are waiting on + * @param wait_objects Kernel objects that we are waiting on * @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only) * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) */ -void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all); +void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all); /** * Waits the current thread from an ArbitrateAddress call @@ -151,24 +214,21 @@ void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bo void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); /** - * Schedules an event to wake up the specified thread after the specified delay. - * @param handle The thread handle. - * @param nanoseconds The time this thread will be allowed to sleep for. - */ -void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); - -/** * Sets up the idle thread, this is a thread that is intended to never execute instructions, * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue * and will try to yield on every call. - * @returns The handle of the idle thread + * @return The handle of the idle thread */ -Handle SetupIdleThread(); +SharedPtr<Thread> SetupIdleThread(); -/// Initialize threading +/** + * Initialize threading + */ void ThreadingInit(); -/// Shutdown threading +/** + * Shutdown threading + */ void ThreadingShutdown(); } // namespace diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 503a5d2ce..4352fc99c 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <set> - #include "common/common.h" #include "core/core_timing.h" @@ -15,18 +13,24 @@ namespace Kernel { /// The event type of the generic timer callback event static int timer_callback_event_type = -1; +// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing +// us to simply use a pool index or similar. +static Kernel::HandleTable timer_callback_handle_table; + +Timer::Timer() {} +Timer::~Timer() {} -ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { +SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) { SharedPtr<Timer> timer(new Timer); - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer)); timer->reset_type = reset_type; timer->signaled = false; timer->name = std::move(name); timer->initial_delay = 0; timer->interval_delay = 0; - return MakeResult<SharedPtr<Timer>>(timer); + timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom(); + + return timer; } bool Timer::ShouldWait() { @@ -38,17 +42,19 @@ void Timer::Acquire() { } void Timer::Set(s64 initial, s64 interval) { + // Ensure we get rid of any previous scheduled event + Cancel(); + initial_delay = initial; interval_delay = interval; u64 initial_microseconds = initial / 1000; - // TODO(yuriks): Figure out a replacement for GetHandle here - CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, - GetHandle()); + CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), + timer_callback_event_type, callback_handle); } void Timer::Cancel() { - CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); + CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); } void Timer::Clear() { @@ -57,7 +63,7 @@ void Timer::Clear() { /// The timer callback event, called when a timer is fired static void TimerCallback(u64 timer_handle, int cycles_late) { - SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); + SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(timer_handle); if (timer == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index c45e79954..540e4e187 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -19,7 +19,7 @@ public: * @param name Optional name of timer * @return The created Timer */ - static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); + static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown"); std::string GetTypeName() const override { return "Timer"; } std::string GetName() const override { return name; } @@ -49,7 +49,11 @@ public: void Clear(); private: - Timer() = default; + Timer(); + ~Timer() override; + + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. + Handle callback_handle; }; /// Initializes the required variables for timers diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 948b9e38e..9c6ca29e5 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -307,14 +307,14 @@ public: } ResultVal& operator=(const ResultVal& o) { - if (*this) { - if (o) { + if (!empty()) { + if (!o.empty()) { *GetPointer() = *o.GetPointer(); } else { GetPointer()->~T(); } } else { - if (o) { + if (!o.empty()) { new (&storage) T(*o.GetPointer()); } } diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp index 20a3fa2e5..53d920de1 100644 --- a/src/core/hle/service/ac_u.cpp +++ b/src/core/hle/service/ac_u.cpp @@ -53,7 +53,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act_u.cpp index 10870f14b..4ea7a9fb2 100644 --- a/src/core/hle/service/act_u.cpp +++ b/src/core/hle/service/act_u.cpp @@ -18,7 +18,7 @@ namespace ACT_U { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp index 0b396b6d3..df10db87f 100644 --- a/src/core/hle/service/am_app.cpp +++ b/src/core/hle/service/am_app.cpp @@ -18,7 +18,7 @@ namespace AM_APP { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am_net.cpp index 112844e5b..c74012d9d 100644 --- a/src/core/hle/service/am_net.cpp +++ b/src/core/hle/service/am_net.cpp @@ -38,7 +38,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp index b63c8c087..c5df8abda 100644 --- a/src/core/hle/service/am_sys.cpp +++ b/src/core/hle/service/am_sys.cpp @@ -18,7 +18,7 @@ namespace AM_SYS { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/apt_a.cpp b/src/core/hle/service/apt_a.cpp index 42f2879c1..e1dd2a5fb 100644 --- a/src/core/hle/service/apt_a.cpp +++ b/src/core/hle/service/apt_a.cpp @@ -39,7 +39,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/apt_s.cpp b/src/core/hle/service/apt_s.cpp index 7ad428ee7..686335428 100644 --- a/src/core/hle/service/apt_s.cpp +++ b/src/core/hle/service/apt_s.cpp @@ -117,7 +117,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp index 4c3f621d0..ccfd04591 100644 --- a/src/core/hle/service/apt_u.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -69,8 +69,8 @@ void Initialize(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(bunnei): Check if these are created in Initialize or on APT process startup. - notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification").MoveFrom(); - pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause").MoveFrom(); + notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); + pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause"); cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); @@ -512,15 +512,15 @@ Interface::Interface() { file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); // Create shared font memory object - shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem").MoveFrom(); + shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem"); } else { LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); shared_font_mem = nullptr; } - lock = Kernel::Mutex::Create(false, "APT_U:Lock").MoveFrom(); + lock = Kernel::Mutex::Create(false, "APT_U:Lock"); - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/boss_p.cpp b/src/core/hle/service/boss_p.cpp index f245a38e9..b3aa6acee 100644 --- a/src/core/hle/service/boss_p.cpp +++ b/src/core/hle/service/boss_p.cpp @@ -18,7 +18,7 @@ namespace BOSS_P { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp index 1820ea7ad..50bb5d426 100644 --- a/src/core/hle/service/boss_u.cpp +++ b/src/core/hle/service/boss_u.cpp @@ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp index 549095339..cf3b27664 100644 --- a/src/core/hle/service/cam_u.cpp +++ b/src/core/hle/service/cam_u.cpp @@ -18,7 +18,7 @@ namespace CAM_U { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/cecd_s.cpp b/src/core/hle/service/cecd_s.cpp index 9c4992f13..2c707baff 100644 --- a/src/core/hle/service/cecd_s.cpp +++ b/src/core/hle/service/cecd_s.cpp @@ -18,7 +18,7 @@ namespace CECD_S { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp index b7655ef0b..b7ea3a186 100644 --- a/src/core/hle/service/cecd_u.cpp +++ b/src/core/hle/service/cecd_u.cpp @@ -18,7 +18,7 @@ namespace CECD_U { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index 7c1ee8ac3..555b7884a 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp @@ -104,7 +104,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index cf4e82152..2170894d6 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -92,7 +92,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp index 5d212a9a2..5aa53cf75 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp @@ -246,7 +246,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp index 3a557efe1..39b00982c 100644 --- a/src/core/hle/service/csnd_snd.cpp +++ b/src/core/hle/service/csnd_snd.cpp @@ -29,7 +29,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index f413c6f54..a720b63f3 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -261,12 +261,11 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, - "DSP_DSP::semaphore_event").MoveFrom(); + semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event"); interrupt_event = nullptr; read_pipe_count = 0; - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 8c900eabc..962de2170 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/frd_a.cpp b/src/core/hle/service/frd_a.cpp index 53edc2cd8..79140a756 100644 --- a/src/core/hle/service/frd_a.cpp +++ b/src/core/hle/service/frd_a.cpp @@ -18,7 +18,7 @@ namespace FRD_A { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp index 021186e57..59faca77a 100644 --- a/src/core/hle/service/frd_u.cpp +++ b/src/core/hle/service/frd_u.cpp @@ -27,7 +27,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 43eef034e..e197d3599 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -5,6 +5,8 @@ #include <memory> #include <unordered_map> +#include <boost/container/flat_map.hpp> + #include "common/common_types.h" #include "common/file_util.h" #include "common/make_unique.h" @@ -18,7 +20,6 @@ #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/directory_backend.h" #include "core/hle/service/fs/archive.h" -#include "core/hle/kernel/session.h" #include "core/hle/result.h" // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. @@ -74,43 +75,19 @@ enum class DirectoryCommand : u32 { Close = 0x08020000, }; -class Archive { -public: - Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) - : id_code(id_code), backend(std::move(backend)) { - } - - std::string GetName() const { return "Archive: " + backend->GetName(); } - - ArchiveIdCode id_code; ///< Id code of the archive - std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface -}; - -class File : public Kernel::Session { -public: - File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) - : path(path), priority(0), backend(std::move(backend)) { - } - - std::string GetName() const override { return "Path: " + path.DebugStr(); } - - FileSys::Path path; ///< Path of the file - u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means - std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface - - ResultVal<bool> SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); - switch (cmd) { +ResultVal<bool> File::SyncRequest() { + u32* cmd_buff = Kernel::GetCommandBuffer(); + FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); + switch (cmd) { // Read from file... case FileCommand::Read: { - u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; - u32 length = cmd_buff[3]; + u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32; + u32 length = cmd_buff[3]; u32 address = cmd_buff[5]; LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address); + GetTypeName().c_str(), GetName().c_str(), offset, length, address); cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); break; } @@ -118,12 +95,12 @@ public: // Write to file... case FileCommand::Write: { - u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; - u32 length = cmd_buff[3]; - u32 flush = cmd_buff[4]; + u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32; + u32 length = cmd_buff[3]; + u32 flush = cmd_buff[4]; u32 address = cmd_buff[6]; LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); + GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); break; } @@ -141,7 +118,7 @@ public: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", - GetTypeName().c_str(), GetName().c_str(), size); + GetTypeName().c_str(), GetName().c_str(), size); backend->SetSize(size); break; } @@ -163,7 +140,7 @@ public: case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); - cmd_buff[3] = GetHandle(); + cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); break; } @@ -187,27 +164,15 @@ public: ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. return error; - } - cmd_buff[1] = 0; // No error - return MakeResult<bool>(false); } -}; - -class Directory : public Kernel::Session { -public: - Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) - : path(path), backend(std::move(backend)) { - } - - std::string GetName() const override { return "Directory: " + path.DebugStr(); } - - FileSys::Path path; ///< Path of the directory - std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + return MakeResult<bool>(false); +} - ResultVal<bool> SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); - switch (cmd) { +ResultVal<bool> Directory::SyncRequest() { + u32* cmd_buff = Kernel::GetCommandBuffer(); + DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); + switch (cmd) { // Read from directory... case DirectoryCommand::Read: @@ -216,7 +181,7 @@ public: u32 address = cmd_buff[3]; auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); LOG_TRACE(Service_FS, "Read %s %s: count=%d", - GetTypeName().c_str(), GetName().c_str(), count); + GetTypeName().c_str(), GetName().c_str(), count); // Number of entries actually read cmd_buff[2] = backend->Read(count, entries); @@ -236,29 +201,31 @@ public: ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. return MakeResult<bool>(false); - } - cmd_buff[1] = 0; // No error - return MakeResult<bool>(false); } -}; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + return MakeResult<bool>(false); +} //////////////////////////////////////////////////////////////////////////////////////////////////// +using FileSys::ArchiveBackend; +using FileSys::ArchiveFactory; + /** * Map of registered archives, identified by id code. Once an archive is registered here, it is * never removed until the FS service is shut down. */ -static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map; +static boost::container::flat_map<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map; /** * Map of active archive handles. Values are pointers to the archives in `idcode_map`. */ -static std::unordered_map<ArchiveHandle, Archive*> handle_map; +static std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map; static ArchiveHandle next_handle; -static Archive* GetArchive(ArchiveHandle handle) { +static ArchiveBackend* GetArchive(ArchiveHandle handle) { auto itr = handle_map.find(handle); - return (itr == handle_map.end()) ? nullptr : itr->second; + return (itr == handle_map.end()) ? nullptr : itr->second.get(); } ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) { @@ -271,15 +238,13 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi ErrorSummary::NotFound, ErrorLevel::Permanent); } - ResultCode res = itr->second->backend->Open(archive_path); - if (!res.IsSuccess()) - return res; + CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); // This should never even happen in the first place with 64-bit handles, while (handle_map.count(next_handle) != 0) { ++next_handle; } - handle_map.emplace(next_handle, itr->second.get()); + handle_map.emplace(next_handle, std::move(res)); return MakeResult<ArchiveHandle>(next_handle++); } @@ -292,40 +257,39 @@ ResultCode CloseArchive(ArchiveHandle handle) { // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 -ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { - auto result = id_code_map.emplace(id_code, Common::make_unique<Archive>(std::move(backend), id_code)); +ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, ArchiveIdCode id_code) { + auto result = id_code_map.emplace(id_code, std::move(factory)); bool inserted = result.second; - _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); + _assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); auto& archive = result.first->second; LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code); return RESULT_SUCCESS; } -ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { - Archive* archive = GetArchive(archive_handle); +ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, const FileSys::Mode mode) { + ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; - std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); + std::unique_ptr<FileSys::FileBackend> backend = archive->OpenFile(path, mode); if (backend == nullptr) { return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status); } - auto file = Common::make_unique<File>(std::move(backend), path); - // TOOD(yuriks): Fix error reporting - Handle handle = Kernel::g_handle_table.Create(file.release()).ValueOr(INVALID_HANDLE); - return MakeResult<Handle>(handle); + auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path)); + return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); } ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { - Archive* archive = GetArchive(archive_handle); + ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; - if (archive->backend->DeleteFile(path)) + if (archive->DeleteFile(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); @@ -333,13 +297,13 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { - Archive* src_archive = GetArchive(src_archive_handle); - Archive* dest_archive = GetArchive(dest_archive_handle); + ArchiveBackend* src_archive = GetArchive(src_archive_handle); + ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) return ERR_INVALID_HANDLE; if (src_archive == dest_archive) { - if (src_archive->backend->RenameFile(src_path, dest_path)) + if (src_archive->RenameFile(src_path, dest_path)) return RESULT_SUCCESS; } else { // TODO: Implement renaming across archives @@ -353,30 +317,30 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil } ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { - Archive* archive = GetArchive(archive_handle); + ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; - if (archive->backend->DeleteDirectory(path)) + if (archive->DeleteDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); } ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { - Archive* archive = GetArchive(archive_handle); + ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; - return archive->backend->CreateFile(path, file_size); + return archive->CreateFile(path, file_size); } ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { - Archive* archive = GetArchive(archive_handle); + ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; - if (archive->backend->CreateDirectory(path)) + if (archive->CreateDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); @@ -384,13 +348,13 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { - Archive* src_archive = GetArchive(src_archive_handle); - Archive* dest_archive = GetArchive(dest_archive_handle); + ArchiveBackend* src_archive = GetArchive(src_archive_handle); + ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) return ERR_INVALID_HANDLE; if (src_archive == dest_archive) { - if (src_archive->backend->RenameDirectory(src_path, dest_path)) + if (src_archive->RenameDirectory(src_path, dest_path)) return RESULT_SUCCESS; } else { // TODO: Implement renaming across archives @@ -403,38 +367,29 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons ErrorSummary::NothingHappened, ErrorLevel::Status); } -/** - * Open a Directory from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the Directory inside of the Archive - * @return Opened Directory object - */ -ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { - Archive* archive = GetArchive(archive_handle); +ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { + ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; - std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); + std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path); if (backend == nullptr) { return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Permanent); } - auto directory = Common::make_unique<Directory>(std::move(backend), path); - // TOOD(yuriks): Fix error reporting - Handle handle = Kernel::g_handle_table.Create(directory.release()).ValueOr(INVALID_HANDLE); - return MakeResult<Handle>(handle); + auto directory = Kernel::SharedPtr<Directory>(new Directory(std::move(backend), path)); + return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); } -ResultCode FormatSaveData() { - // Do not create the archive again if it already exists - auto archive_itr = id_code_map.find(ArchiveIdCode::SaveData); +ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { + auto archive_itr = id_code_map.find(id_code); if (archive_itr == id_code_map.end()) { return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error } - // Use an empty path, we do not use it when formatting the savedata - return archive_itr->second->backend->Format(FileSys::Path()); + return archive_itr->second->Format(path); } ResultCode CreateExtSaveData(u32 high, u32 low) { @@ -468,32 +423,32 @@ void ArchiveInit() { std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); - auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory); - if (sdmc_archive->Initialize()) - CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); + auto sdmc_factory = Common::make_unique<FileSys::ArchiveFactory_SDMC>(sdmc_directory); + if (sdmc_factory->Initialize()) + RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC); else LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); // Create the SaveData archive - auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(sdmc_directory); - CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); + auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory); + RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); - auto extsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(sdmc_directory, false); - if (extsavedata_archive->Initialize()) - CreateArchive(std::move(extsavedata_archive), ArchiveIdCode::ExtSaveData); + auto extsavedata_factory = Common::make_unique<FileSys::ArchiveFactory_ExtSaveData>(sdmc_directory, false); + if (extsavedata_factory->Initialize()) + RegisterArchiveType(std::move(extsavedata_factory), ArchiveIdCode::ExtSaveData); else - LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_archive->GetMountPoint().c_str()); + LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_factory->GetMountPoint().c_str()); - auto sharedextsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(nand_directory, true); - if (sharedextsavedata_archive->Initialize()) - CreateArchive(std::move(sharedextsavedata_archive), ArchiveIdCode::SharedExtSaveData); + auto sharedextsavedata_factory = Common::make_unique<FileSys::ArchiveFactory_ExtSaveData>(nand_directory, true); + if (sharedextsavedata_factory->Initialize()) + RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); else LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", - sharedextsavedata_archive->GetMountPoint().c_str()); + sharedextsavedata_factory->GetMountPoint().c_str()); // Create the SaveDataCheck archive, basically a small variation of the RomFS archive - auto savedatacheck_archive = Common::make_unique<FileSys::Archive_SaveDataCheck>(nand_directory); - CreateArchive(std::move(savedatacheck_archive), ArchiveIdCode::SaveDataCheck); + auto savedatacheck_factory = Common::make_unique<FileSys::ArchiveFactory_SaveDataCheck>(nand_directory); + RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::SaveDataCheck); } /// Shutdown archives diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index ba674d7f6..c490327d0 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -8,6 +8,7 @@ #include "core/file_sys/archive_backend.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/session.h" #include "core/hle/result.h" /// The unique system identifier hash, also known as ID0 @@ -15,6 +16,10 @@ extern const std::string SYSTEM_ID; /// The scrambled SD card CID, also known as ID1 extern const std::string SDCARD_ID; +namespace Kernel { + class Session; +} + namespace Service { namespace FS { @@ -32,6 +37,35 @@ enum class ArchiveIdCode : u32 { typedef u64 ArchiveHandle; +class File : public Kernel::Session { +public: + File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) + : path(path), priority(0), backend(std::move(backend)) { + } + + std::string GetName() const override { return "Path: " + path.DebugStr(); } + + FileSys::Path path; ///< Path of the file + u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means + std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface + + ResultVal<bool> SyncRequest() override; +}; + +class Directory : public Kernel::Session { +public: + Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) + : path(path), backend(std::move(backend)) { + } + + std::string GetName() const override { return "Directory: " + path.DebugStr(); } + + FileSys::Path path; ///< Path of the directory + std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface + + ResultVal<bool> SyncRequest() override; +}; + /** * Opens an archive * @param id_code IdCode of the archive to open @@ -47,20 +81,21 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi ResultCode CloseArchive(ArchiveHandle handle); /** - * Creates an Archive + * Registers an Archive type, instances of which can later be opened using its IdCode. * @param backend File system backend interface to the archive * @param id_code Id code used to access this type of archive */ -ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code); +ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, ArchiveIdCode id_code); /** * Open a File from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the File inside of the Archive * @param mode Mode under which to open the File - * @return Handle to the opened File object + * @return The opened File object as a Session */ -ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); +ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, const FileSys::Mode mode); /** * Delete a File from an Archive @@ -121,15 +156,19 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return Handle to the opened File object + * @return The opened Directory object as a Session */ -ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); +ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path); /** - * Creates a blank SaveData archive. + * Erases the contents of the physical folder that contains the archive + * identified by the specified id code and path + * @param id_code The id of the archive to format + * @param path The path to the archive, if relevant. * @return ResultCode 0 on success or the corresponding code on error */ -ResultCode FormatSaveData(); +ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = FileSys::Path()); /** * Creates a blank SharedExtSaveData archive for the specified extdata ID diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index c495b6f3c..71ee4ff55 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -14,6 +14,9 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace FS_User +using Kernel::SharedPtr; +using Kernel::Session; + namespace Service { namespace FS { @@ -58,10 +61,10 @@ static void OpenFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - ResultVal<Handle> handle = OpenFileFromArchive(archive_handle, file_path, mode); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - cmd_buff[3] = *handle; + ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); + cmd_buff[1] = file_res.Code().raw; + if (file_res.Succeeded()) { + cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -114,10 +117,10 @@ static void OpenFileDirectly(Service::Interface* self) { } SCOPE_EXIT({ CloseArchive(*archive_handle); }); - ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - cmd_buff[3] = *handle; + ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); + cmd_buff[1] = file_res.Code().raw; + if (file_res.Succeeded()) { + cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -334,10 +337,10 @@ static void OpenDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - ResultVal<Handle> handle = OpenDirectoryFromArchive(archive_handle, dir_path); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - cmd_buff[3] = *handle; + ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); + cmd_buff[1] = dir_res.Code().raw; + if (dir_res.Succeeded()) { + cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory"); } @@ -465,7 +468,7 @@ static void FormatSaveData(Service::Interface* self) { return; } - cmd_buff[1] = FormatSaveData().raw; + cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; } /** @@ -481,7 +484,7 @@ static void FormatThisUserSaveData(Service::Interface* self) { // TODO(Subv): Find out what the inputs and outputs of this function are - cmd_buff[1] = FormatSaveData().raw; + cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; } static void CreateExtSaveData(Service::Interface* self) { @@ -588,7 +591,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { // Interface class FSUserInterface::FSUserInterface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace FS diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 5b91f17d2..495c117ee 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -187,7 +187,7 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); _assert_msg_(GSP, (g_interrupt_event != nullptr), "handle is not valid!"); - g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem").MoveFrom(); + g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem"); Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); @@ -389,7 +389,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); g_interrupt_event = 0; g_shared_memory = 0; diff --git a/src/core/hle/service/gsp_lcd.cpp b/src/core/hle/service/gsp_lcd.cpp index 6213472ff..d63fa1ee2 100644 --- a/src/core/hle/service/gsp_lcd.cpp +++ b/src/core/hle/service/gsp_lcd.cpp @@ -20,7 +20,7 @@ namespace GSP_LCD { // Interface class Interface::Interface() { - //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + //Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 835055af4..7cb01729e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -30,6 +30,8 @@ static s16 next_circle_y = 0; * Gets a pointer to the PadData structure inside HID shared memory */ static inline PadData* GetPadData() { + if (g_shared_mem == nullptr) + return nullptr; return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); } @@ -122,14 +124,14 @@ void PadUpdateComplete() { void HIDInit() { using namespace Kernel; - g_shared_mem = SharedMemory::Create("HID:SharedMem").MoveFrom(); + g_shared_mem = SharedMemory::Create("HID:SharedMem"); // Create event handles - g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1").MoveFrom(); - g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2").MoveFrom(); - g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer").MoveFrom(); - g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope").MoveFrom(); - g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad").MoveFrom(); + g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); + g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); + g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); + g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); + g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); } void HIDShutdown() { diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index 76c40b659..054aa8b59 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -32,7 +32,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index 5444aa5ee..68edafebb 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -72,7 +72,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp index d0bff552f..6595ca572 100644 --- a/src/core/hle/service/http_c.cpp +++ b/src/core/hle/service/http_c.cpp @@ -58,7 +58,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp index d49bd5335..31da8e160 100644 --- a/src/core/hle/service/ir_rst.cpp +++ b/src/core/hle/service/ir_rst.cpp @@ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir_u.cpp index da6f38e41..7fa233048 100644 --- a/src/core/hle/service/ir_u.cpp +++ b/src/core/hle/service/ir_u.cpp @@ -36,7 +36,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp index 83bb9eabe..ea96f64af 100644 --- a/src/core/hle/service/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro.cpp @@ -87,7 +87,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp index 82bce9180..af967b5b6 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic_u.cpp @@ -34,7 +34,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ndm_u.cpp b/src/core/hle/service/ndm_u.cpp index 0f03de6ae..df3c97193 100644 --- a/src/core/hle/service/ndm_u.cpp +++ b/src/core/hle/service/ndm_u.cpp @@ -24,7 +24,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/news_s.cpp b/src/core/hle/service/news_s.cpp index 1850f59bd..d7537875b 100644 --- a/src/core/hle/service/news_s.cpp +++ b/src/core/hle/service/news_s.cpp @@ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/news_u.cpp b/src/core/hle/service/news_u.cpp index b5adad4c6..a9e161c23 100644 --- a/src/core/hle/service/news_u.cpp +++ b/src/core/hle/service/news_u.cpp @@ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim_aoc.cpp index 17d1c4ff5..ab2ef4429 100644 --- a/src/core/hle/service/nim_aoc.cpp +++ b/src/core/hle/service/nim_aoc.cpp @@ -25,7 +25,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp index b9aca4257..5cf3e2039 100644 --- a/src/core/hle/service/ns_s.cpp +++ b/src/core/hle/service/ns_s.cpp @@ -21,7 +21,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp index ce456a966..61fcb54ce 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm_uds.cpp @@ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp index 529dccafb..d61eaf80f 100644 --- a/src/core/hle/service/pm_app.cpp +++ b/src/core/hle/service/pm_app.cpp @@ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ptm_play.cpp b/src/core/hle/service/ptm_play.cpp index ae9e2925c..b357057fd 100644 --- a/src/core/hle/service/ptm_play.cpp +++ b/src/core/hle/service/ptm_play.cpp @@ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ptm_sysm.cpp b/src/core/hle/service/ptm_sysm.cpp index 4b5f86a47..b6f688de3 100644 --- a/src/core/hle/service/ptm_sysm.cpp +++ b/src/core/hle/service/ptm_sysm.cpp @@ -50,7 +50,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp index 753180add..7c8d9ce8c 100644 --- a/src/core/hle/service/ptm_u.cpp +++ b/src/core/hle/service/ptm_u.cpp @@ -4,8 +4,9 @@ #include "common/log.h" #include "common/make_unique.h" -#include "core/file_sys/archive_extsavedata.h" + #include "core/hle/hle.h" +#include "core/hle/service/fs/archive.h" #include "core/hle/service/ptm_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -28,7 +29,6 @@ struct GameCoin { u8 day; }; static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; -static std::unique_ptr<FileSys::Archive_ExtSaveData> ptm_shared_extsavedata; static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; /// Charge levels used by PTM functions @@ -137,32 +137,29 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); - // Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file - // TODO(Subv): In the future we should use the FS service to query this archive - std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); - ptm_shared_extsavedata = Common::make_unique<FileSys::Archive_ExtSaveData>(nand_directory, true); - if (!ptm_shared_extsavedata->Initialize()) { - LOG_CRITICAL(Service_PTM, "Could not initialize SharedExtSaveData archive for the PTM:U service"); - return; - } + Register(FunctionTable); + + // Open the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file FileSys::Path archive_path(ptm_shared_extdata_id); - ResultCode result = ptm_shared_extsavedata->Open(archive_path); + auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); // If the archive didn't exist, create the files inside - if (result.description == ErrorDescription::FS_NotFormatted) { - // Format the archive to clear the directories - ptm_shared_extsavedata->Format(archive_path); + if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { + // Format the archive to create the directories + Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); // Open it again to get a valid archive now that the folder exists - ptm_shared_extsavedata->Open(archive_path); + archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + _assert_msg_(Service_PTM, archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); + FileSys::Path gamecoin_path("gamecoin.dat"); FileSys::Mode open_mode = {}; open_mode.write_flag = 1; open_mode.create_flag = 1; // Open the file and write the default gamecoin information - auto gamecoin = ptm_shared_extsavedata->OpenFile(gamecoin_path, open_mode); - if (gamecoin != nullptr) { - gamecoin->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); - gamecoin->Close(); + auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); + if (gamecoin_result.Succeeded()) { + auto gamecoin = gamecoin_result.MoveFrom(); + gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); + gamecoin->backend->Close(); } } } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 355196fd3..e0979ea5d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -54,96 +54,76 @@ namespace Service { -Manager* g_manager = nullptr; ///< Service manager +std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; +std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; //////////////////////////////////////////////////////////////////////////////////////////////////// -// Service Manager class - -void Manager::AddService(Interface* service) { - // TOOD(yuriks): Fix error reporting - m_port_map[service->GetPortName()] = Kernel::g_handle_table.Create(service).ValueOr(INVALID_HANDLE); - m_services.push_back(service); -} - -void Manager::DeleteService(const std::string& port_name) { - Interface* service = FetchFromPortName(port_name); - m_services.erase(std::remove(m_services.begin(), m_services.end(), service), m_services.end()); - m_port_map.erase(port_name); -} +// Module interface -Interface* Manager::FetchFromHandle(Handle handle) { - // TODO(yuriks): This function is very suspicious and should probably be exterminated. - return Kernel::g_handle_table.Get<Interface>(handle).get(); +static void AddNamedPort(Interface* interface) { + g_kernel_named_ports.emplace(interface->GetPortName(), interface); } -Interface* Manager::FetchFromPortName(const std::string& port_name) { - auto itr = m_port_map.find(port_name); - if (itr == m_port_map.end()) { - return nullptr; - } - return FetchFromHandle(itr->second); +static void AddService(Interface* interface) { + g_srv_services.emplace(interface->GetPortName(), interface); } - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Module interface - /// Initialize ServiceManager void Init() { - g_manager = new Manager; - - g_manager->AddService(new SRV::Interface); - g_manager->AddService(new AC_U::Interface); - g_manager->AddService(new ACT_U::Interface); - g_manager->AddService(new AM_APP::Interface); - g_manager->AddService(new AM_NET::Interface); - g_manager->AddService(new AM_SYS::Interface); - g_manager->AddService(new APT_A::Interface); - g_manager->AddService(new APT_S::Interface); - g_manager->AddService(new APT_U::Interface); - g_manager->AddService(new BOSS_P::Interface); - g_manager->AddService(new BOSS_U::Interface); - g_manager->AddService(new CAM_U::Interface); - g_manager->AddService(new CECD_S::Interface); - g_manager->AddService(new CECD_U::Interface); - g_manager->AddService(new CFG_I::Interface); - g_manager->AddService(new CFG_S::Interface); - g_manager->AddService(new CFG_U::Interface); - g_manager->AddService(new CSND_SND::Interface); - g_manager->AddService(new DSP_DSP::Interface); - g_manager->AddService(new ERR_F::Interface); - g_manager->AddService(new FRD_A::Interface); - g_manager->AddService(new FRD_U::Interface); - g_manager->AddService(new FS::FSUserInterface); - g_manager->AddService(new GSP_GPU::Interface); - g_manager->AddService(new GSP_LCD::Interface); - g_manager->AddService(new HID_User::Interface); - g_manager->AddService(new HID_SPVR::Interface); - g_manager->AddService(new HTTP_C::Interface); - g_manager->AddService(new IR_RST::Interface); - g_manager->AddService(new IR_U::Interface); - g_manager->AddService(new LDR_RO::Interface); - g_manager->AddService(new MIC_U::Interface); - g_manager->AddService(new NDM_U::Interface); - g_manager->AddService(new NEWS_S::Interface); - g_manager->AddService(new NEWS_U::Interface); - g_manager->AddService(new NIM_AOC::Interface); - g_manager->AddService(new NS_S::Interface); - g_manager->AddService(new NWM_UDS::Interface); - g_manager->AddService(new PM_APP::Interface); - g_manager->AddService(new PTM_PLAY::Interface); - g_manager->AddService(new PTM_U::Interface); - g_manager->AddService(new PTM_SYSM::Interface); - g_manager->AddService(new SOC_U::Interface); - g_manager->AddService(new SSL_C::Interface); - g_manager->AddService(new Y2R_U::Interface); + AddNamedPort(new SRV::Interface); + + AddService(new AC_U::Interface); + AddService(new ACT_U::Interface); + AddService(new AM_APP::Interface); + AddService(new AM_NET::Interface); + AddService(new AM_SYS::Interface); + AddService(new APT_A::Interface); + AddService(new APT_S::Interface); + AddService(new APT_U::Interface); + AddService(new BOSS_P::Interface); + AddService(new BOSS_U::Interface); + AddService(new CAM_U::Interface); + AddService(new CECD_S::Interface); + AddService(new CECD_U::Interface); + AddService(new CFG_I::Interface); + AddService(new CFG_S::Interface); + AddService(new CFG_U::Interface); + AddService(new CSND_SND::Interface); + AddService(new DSP_DSP::Interface); + AddService(new ERR_F::Interface); + AddService(new FRD_A::Interface); + AddService(new FRD_U::Interface); + AddService(new FS::FSUserInterface); + AddService(new GSP_GPU::Interface); + AddService(new GSP_LCD::Interface); + AddService(new HID_User::Interface); + AddService(new HID_SPVR::Interface); + AddService(new HTTP_C::Interface); + AddService(new IR_RST::Interface); + AddService(new IR_U::Interface); + AddService(new LDR_RO::Interface); + AddService(new MIC_U::Interface); + AddService(new NDM_U::Interface); + AddService(new NEWS_S::Interface); + AddService(new NEWS_U::Interface); + AddService(new NIM_AOC::Interface); + AddService(new NS_S::Interface); + AddService(new NWM_UDS::Interface); + AddService(new PM_APP::Interface); + AddService(new PTM_PLAY::Interface); + AddService(new PTM_U::Interface); + AddService(new PTM_SYSM::Interface); + AddService(new SOC_U::Interface); + AddService(new SSL_C::Interface); + AddService(new Y2R_U::Interface); LOG_DEBUG(Service, "initialized OK"); } /// Shutdown ServiceManager void Shutdown() { - delete g_manager; + g_srv_services.clear(); + g_kernel_named_ports.clear(); LOG_DEBUG(Service, "shutdown OK"); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index e75d5008b..3370f9f9b 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -5,9 +5,11 @@ #pragma once #include <algorithm> -#include <vector> -#include <map> #include <string> +#include <unordered_map> +#include <vector> + +#include <boost/container/flat_map.hpp> #include "common/common.h" #include "common/string_util.h" @@ -27,7 +29,7 @@ static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 character class Manager; /// Interface to a CTROS service -class Interface : public Kernel::Session { +class Interface : public Kernel::Session { // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be // just something that encapsulates a session and acts as a helper to implement service // processes. @@ -38,11 +40,11 @@ class Interface : public Kernel::Session { * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. */ - std::string MakeFunctionString(const std::string& name, const std::string& port_name, const u32* cmd_buff) { + std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { // Number of params == bits 0-5 + bits 6-11 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); - std::string function_string = Common::StringFromFormat("function '%s': port=%s", name.c_str(), port_name.c_str()); + std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); for (int i = 1; i <= num_params; ++i) { function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); } @@ -57,7 +59,7 @@ public: struct FunctionInfo { u32 id; Function func; - std::string name; + const char* name; }; /** @@ -68,34 +70,19 @@ public: return "[UNKNOWN SERVICE PORT]"; } - /// Allocates a new handle for the service - Handle CreateHandle(Kernel::Object *obj) { - // TODO(yuriks): Fix error reporting - Handle handle = Kernel::g_handle_table.Create(obj).ValueOr(INVALID_HANDLE); - m_handles.push_back(handle); - return handle; - } - - /// Frees a handle from the service - template <class T> - void DeleteHandle(const Handle handle) { - Kernel::g_handle_table.Close(handle); - m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); - } - ResultVal<bool> SyncRequest() override { u32* cmd_buff = Kernel::GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); if (itr == m_functions.end() || itr->second.func == nullptr) { std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name; - LOG_ERROR(Service, "%s %s", "unknown/unimplemented", MakeFunctionString(function_name, GetPortName(), cmd_buff).c_str()); + LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str()); // TODO(bunnei): Hack - ignore error cmd_buff[1] = 0; return MakeResult<bool>(false); } else { - LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName(), cmd_buff).c_str()); + LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); } itr->second.func(this); @@ -108,37 +95,18 @@ protected: /** * Registers the functions in the service */ - void Register(const FunctionInfo* functions, int len) { - for (int i = 0; i < len; i++) { - m_functions[functions[i].id] = functions[i]; + template <size_t N> + void Register(const FunctionInfo (&functions)[N]) { + m_functions.reserve(N); + for (auto& fn : functions) { + // Usually this array is sorted by id already, so hint to instead at the end + m_functions.emplace_hint(m_functions.cend(), fn.id, fn); } } private: + boost::container::flat_map<u32, FunctionInfo> m_functions; - std::vector<Handle> m_handles; - std::map<u32, FunctionInfo> m_functions; - -}; - -/// Simple class to manage accessing services from ports and UID handles -class Manager { -public: - /// Add a service to the manager - void AddService(Interface* service); - - /// Removes a service from the manager - void DeleteService(const std::string& port_name); - - /// Get a Service Interface from its Handle - Interface* FetchFromHandle(Handle handle); - - /// Get a Service Interface from its port - Interface* FetchFromPortName(const std::string& port_name); - -private: - std::vector<Interface*> m_services; - std::map<std::string, u32> m_port_map; }; /// Initialize ServiceManager @@ -147,8 +115,9 @@ void Init(); /// Shutdown ServiceManager void Shutdown(); - -extern Manager* g_manager; ///< Service manager - +/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. +extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; +/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. +extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; } // namespace diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index bb8ee86be..414c53c54 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -734,7 +734,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } Interface::~Interface() { diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index aa0aac3bb..cc59a03ce 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -23,7 +23,7 @@ static void GetProcSemaphore(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(bunnei): Change to a semaphore once these have been implemented - event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event").MoveFrom(); + event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event"); event_handle->Clear(); cmd_buff[1] = 0; // No error @@ -35,10 +35,10 @@ static void GetServiceHandle(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); - Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); + auto it = Service::g_srv_services.find(port_name); - if (nullptr != service) { - cmd_buff[3] = service->GetHandle(); + if (it != Service::g_srv_services.end()) { + cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); } else { LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); @@ -63,7 +63,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp index 360516cdf..3f49c1c97 100644 --- a/src/core/hle/service/ssl_c.cpp +++ b/src/core/hle/service/ssl_c.cpp @@ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index b3d873ef0..fc76d2721 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -54,7 +54,7 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 88813c2ce..96da29923 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -30,6 +30,11 @@ using Kernel::ERR_INVALID_HANDLE; namespace SVC { +const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, + ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA +const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E + /// An invalid result code that is meant to be overwritten when a thread resumes from waiting const ResultCode RESULT_INVALID(0xDEADC0DE); @@ -94,14 +99,21 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o } /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToPort(Handle* out, const char* port_name) { - Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); +static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { + if (port_name == nullptr) + return ERR_NOT_FOUND; + if (std::strlen(port_name) > 11) + return ERR_PORT_NAME_TOO_LONG; LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); - _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!"); - *out = service->GetHandle(); + auto it = Service::g_kernel_named_ports.find(port_name); + if (it == Service::g_kernel_named_ports.end()) { + LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name); + return ERR_NOT_FOUND; + } + CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second)); return RESULT_SUCCESS; } @@ -119,9 +131,8 @@ static ResultCode SendSyncRequest(Handle handle) { /// Close a handle static ResultCode CloseHandle(Handle handle) { - // ImplementMe - LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); - return RESULT_SUCCESS; + LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); + return Kernel::g_handle_table.Close(handle); } /// Wait for a handle to synchronize, timeout after the specified nanoseconds @@ -133,16 +144,16 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); + HLE::Reschedule(__func__); + // Check for next thread to schedule if (object->ShouldWait()) { object->AddWaitingThread(Kernel::GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(object, false, false); + Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); // Create an event to wake the thread up after the specified nanosecond delay has passed - Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); - - HLE::Reschedule(__func__); + Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); // NOTE: output of this SVC will be set later depending on how the thread resumes return RESULT_INVALID; @@ -201,24 +212,28 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // NOTE: This should deadlock the current thread if no timeout was specified if (!wait_all) { wait_thread = true; - Kernel::WaitCurrentThread_WaitSynchronization(nullptr, true, wait_all); } } + HLE::Reschedule(__func__); + // If thread should wait, then set its state to waiting and then reschedule... if (wait_thread) { // Actually wait the current thread on each object if we decided to wait... + std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; + wait_objects.reserve(handle_count); + for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); object->AddWaitingThread(Kernel::GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(object, true, wait_all); + wait_objects.push_back(object); } - // Create an event to wake the thread up after the specified nanosecond delay has passed - Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); + Kernel::WaitCurrentThread_WaitSynchronization(std::move(wait_objects), true, wait_all); - HLE::Reschedule(__func__); + // Create an event to wake the thread up after the specified nanosecond delay has passed + Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); // NOTE: output of this SVC will be set later depending on how the thread resumes return RESULT_INVALID; @@ -250,7 +265,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou static ResultCode CreateAddressArbiter(Handle* out_handle) { using Kernel::AddressArbiter; - CASCADE_RESULT(SharedPtr<AddressArbiter> arbiter, AddressArbiter::Create()); + SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create(); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); return RESULT_SUCCESS; @@ -308,7 +323,7 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u } CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create( - name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE)); + name, entry_point, priority, arg, processor_id, stack_top)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " @@ -327,7 +342,7 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u static void ExitThread() { LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); - Kernel::GetCurrentThread()->Stop(__func__); + Kernel::GetCurrentThread()->Stop(); HLE::Reschedule(__func__); } @@ -355,7 +370,7 @@ static ResultCode SetThreadPriority(Handle handle, s32 priority) { static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { using Kernel::Mutex; - CASCADE_RESULT(SharedPtr<Mutex> mutex, Mutex::Create(initial_locked != 0)); + SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", @@ -423,7 +438,9 @@ static ResultCode QueryMemory(void* info, void* out, u32 addr) { /// Create an event static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { - CASCADE_RESULT(auto evt, Kernel::Event::Create(static_cast<ResetType>(reset_type))); + using Kernel::Event; + + SharedPtr<Event> evt = Kernel::Event::Create(static_cast<ResetType>(reset_type)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", @@ -433,19 +450,17 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { /// Duplicates a kernel handle static ResultCode DuplicateHandle(Handle* out, Handle handle) { - ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); - if (out_h.Succeeded()) { - *out = *out_h; - LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); - } - return out_h.Code(); + CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle)); + LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); + return RESULT_SUCCESS; } /// Signals an event static ResultCode SignalEvent(Handle handle) { + using Kernel::Event; LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); - auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); + SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); if (evt == nullptr) return ERR_INVALID_HANDLE; @@ -456,9 +471,10 @@ static ResultCode SignalEvent(Handle handle) { /// Clears an event static ResultCode ClearEvent(Handle handle) { + using Kernel::Event; LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); - auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); + SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); if (evt == nullptr) return ERR_INVALID_HANDLE; @@ -470,7 +486,7 @@ static ResultCode ClearEvent(Handle handle) { static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { using Kernel::Timer; - CASCADE_RESULT(auto timer, Timer::Create(static_cast<ResetType>(reset_type))); + SharedPtr<Timer> timer = Timer::Create(static_cast<ResetType>(reset_type)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", @@ -528,7 +544,7 @@ static void SleepThread(s64 nanoseconds) { Kernel::WaitCurrentThread_Sleep(); // Create an event to wake the thread up after the specified nanosecond delay has passed - Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); + Kernel::GetCurrentThread()->WakeAfterDelay(nanoseconds); HLE::Reschedule(__func__); } @@ -544,7 +560,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 using Kernel::SharedMemory; // TODO(Subv): Implement this function - CASCADE_RESULT(auto shared_memory, SharedMemory::Create()); + SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 58eec3005..aad0e5d0d 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -202,8 +202,6 @@ template void Write<u8>(u32 addr, const u8 data); /// Update hardware static void VBlankCallback(u64 userdata, int cycles_late) { - auto& framebuffer_top = g_regs.framebuffer_config[0]; - frame_count++; last_skip_frame = g_skip_frame; g_skip_frame = (frame_count & Settings::values.frame_skip) != 0; diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index e7e5df408..773eaf771 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -212,7 +212,7 @@ public: return GetPtr(segments[segment].p_offset); } u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } - int GetSectionSize(SectionID section) const { return sections[section].sh_size; } + unsigned int GetSectionSize(SectionID section) const { return sections[section].sh_size; } SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found bool DidRelocate() const { @@ -298,7 +298,7 @@ bool ElfReader::LoadSymbols() { //We have a symbol table! Elf32_Sym* symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); - int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); + unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); for (unsigned sym = 0; sym < numSymbols; sym++) { int size = symtab[sym].st_size; if (size == 0) diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 52730a7b4..94dcc50f9 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -127,7 +127,7 @@ ResultStatus LoadFile(const std::string& filename) { // Load application and RomFS if (ResultStatus::Success == app_loader.Load()) { Kernel::g_program_id = app_loader.GetProgramId(); - Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); + Service::FS::RegisterArchiveType(Common::make_unique<FileSys::ArchiveFactory_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); return ResultStatus::Success; } break; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 7456b019b..3510c6b28 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -38,7 +38,7 @@ enum class ResultStatus { ErrorMemoryAllocationFailed, }; -static u32 MakeMagic(char a, char b, char c, char d) { +static inline u32 MakeMagic(char a, char b, char c, char d) { return a | b << 8 | c << 16 | d << 24; } diff --git a/src/core/settings.h b/src/core/settings.h index 9b52be259..e62dd4358 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -29,7 +29,6 @@ struct Values { int pad_sright_key; // Core - int cpu_core; int gpu_refresh_rate; int frame_skip; diff --git a/src/video_core/math.h b/src/video_core/math.h index 9622e7614..c176b225a 100644 --- a/src/video_core/math.h +++ b/src/video_core/math.h @@ -457,27 +457,41 @@ public: const T& b() const { return z; } const T& a() const { return w; } - // swizzlers - create a subvector of specific components + // Swizzlers - Create a subvector of specific components // e.g. Vec2 uv() { return Vec2(x,y); } - // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all component names (x<->r) and permutations (xy<->yx) + + // _DEFINE_SWIZZLER2 defines a single such function + // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) + // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) #define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } -#define DEFINE_SWIZZLER2(a, b, a2, b2) \ +#define DEFINE_SWIZZLER2_COMP1(a, a2) \ + _DEFINE_SWIZZLER2(a, a, a##a); \ + _DEFINE_SWIZZLER2(a, a, a2##a2) +#define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ _DEFINE_SWIZZLER2(a, b, a##b); \ _DEFINE_SWIZZLER2(a, b, a2##b2); \ _DEFINE_SWIZZLER2(b, a, b##a); \ _DEFINE_SWIZZLER2(b, a, b2##a2) - DEFINE_SWIZZLER2(x, y, r, g); - DEFINE_SWIZZLER2(x, z, r, b); - DEFINE_SWIZZLER2(x, w, r, a); - DEFINE_SWIZZLER2(y, z, g, b); - DEFINE_SWIZZLER2(y, w, g, a); - DEFINE_SWIZZLER2(z, w, b, a); -#undef DEFINE_SWIZZLER2 + DEFINE_SWIZZLER2_COMP2(x, y, r, g); + DEFINE_SWIZZLER2_COMP2(x, z, r, b); + DEFINE_SWIZZLER2_COMP2(x, w, r, a); + DEFINE_SWIZZLER2_COMP2(y, z, g, b); + DEFINE_SWIZZLER2_COMP2(y, w, g, a); + DEFINE_SWIZZLER2_COMP2(z, w, b, a); + DEFINE_SWIZZLER2_COMP1(x, r); + DEFINE_SWIZZLER2_COMP1(y, g); + DEFINE_SWIZZLER2_COMP1(z, b); + DEFINE_SWIZZLER2_COMP1(w, a); +#undef DEFINE_SWIZZLER2_COMP1 +#undef DEFINE_SWIZZLER2_COMP2 #undef _DEFINE_SWIZZLER2 #define _DEFINE_SWIZZLER3(a, b, c, name) const Vec3<T> name() const { return Vec3<T>(a, b, c); } -#define DEFINE_SWIZZLER3(a, b, c, a2, b2, c2) \ +#define DEFINE_SWIZZLER3_COMP1(a, a2) \ + _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ + _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) +#define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ @@ -491,11 +505,16 @@ public: _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) - DEFINE_SWIZZLER3(x, y, z, r, g, b); - DEFINE_SWIZZLER3(x, y, w, r, g, a); - DEFINE_SWIZZLER3(x, z, w, r, b, a); - DEFINE_SWIZZLER3(y, z, w, g, b, a); -#undef DEFINE_SWIZZLER3 + DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); + DEFINE_SWIZZLER3_COMP3(x, y, w, r, g, a); + DEFINE_SWIZZLER3_COMP3(x, z, w, r, b, a); + DEFINE_SWIZZLER3_COMP3(y, z, w, g, b, a); + DEFINE_SWIZZLER3_COMP1(x, r); + DEFINE_SWIZZLER3_COMP1(y, g); + DEFINE_SWIZZLER3_COMP1(z, b); + DEFINE_SWIZZLER3_COMP1(w, a); +#undef DEFINE_SWIZZLER3_COMP1 +#undef DEFINE_SWIZZLER3_COMP3 #undef _DEFINE_SWIZZLER3 }; diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 78603ebdf..9c1a12dc8 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -233,19 +233,29 @@ struct Regs { }; enum class ColorModifier : u32 { - SourceColor = 0, - OneMinusSourceColor = 1, - SourceAlpha = 2, - OneMinusSourceAlpha = 3, - - // Other values seem to be non-standard extensions + SourceColor = 0x0, + OneMinusSourceColor = 0x1, + SourceAlpha = 0x2, + OneMinusSourceAlpha = 0x3, + SourceRed = 0x4, + OneMinusSourceRed = 0x5, + + SourceGreen = 0x8, + OneMinusSourceGreen = 0x9, + + SourceBlue = 0xc, + OneMinusSourceBlue = 0xd, }; enum class AlphaModifier : u32 { - SourceAlpha = 0, - OneMinusSourceAlpha = 1, - - // Other values seem to be non-standard extensions + SourceAlpha = 0x0, + OneMinusSourceAlpha = 0x1, + SourceRed = 0x2, + OneMinusSourceRed = 0x3, + SourceGreen = 0x4, + OneMinusSourceGreen = 0x5, + SourceBlue = 0x6, + OneMinusSourceBlue = 0x7, }; enum class Operation : u32 { @@ -328,15 +338,29 @@ struct Regs { union { enum BlendEquation : u32 { - Add = 0, + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4 }; enum BlendFactor : u32 { - Zero = 0, - One = 1, - - SourceAlpha = 6, - OneMinusSourceAlpha = 7, + Zero = 0, + One = 1, + SourceColor = 2, + OneMinusSourceColor = 3, + DestColor = 4, + OneMinusDestColor = 5, + SourceAlpha = 6, + OneMinusSourceAlpha = 7, + DestAlpha = 8, + OneMinusDestAlpha = 9, + ConstantColor = 10, + OneMinusConstantColor = 11, + ConstantAlpha = 12, + OneMinusConstantAlpha = 13, + SourceAlphaSaturate = 14 }; BitField< 0, 8, BlendEquation> blend_equation_rgb; @@ -357,7 +381,12 @@ struct Regs { BitField<0, 4, Op> op; } logic_op; - INSERT_PADDING_WORDS(0x1); + union { + BitField< 0, 8, u32> r; + BitField< 8, 8, u32> g; + BitField<16, 8, u32> b; + BitField<24, 8, u32> a; + } blend_const; union { BitField< 0, 1, u32> enable; diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 7f66c6d42..06fd8d140 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -260,7 +260,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, using AlphaModifier = Regs::TevStageConfig::AlphaModifier; using Operation = Regs::TevStageConfig::Operation; - auto GetColorSource = [&](Source source) -> Math::Vec4<u8> { + auto GetSource = [&](Source source) -> Math::Vec4<u8> { switch (source) { case Source::PrimaryColor: return primary_color; @@ -287,36 +287,8 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, } }; - auto GetAlphaSource = [&](Source source) -> u8 { - switch (source) { - case Source::PrimaryColor: - return primary_color.a(); - - case Source::Texture0: - return texture_color[0].a(); - - case Source::Texture1: - return texture_color[1].a(); - - case Source::Texture2: - return texture_color[2].a(); - - case Source::Constant: - return tev_stage.const_a; - - case Source::Previous: - return combiner_output.a(); - - default: - LOG_ERROR(HW_GPU, "Unknown alpha combiner source %d\n", (int)source); - _dbg_assert_(HW_GPU, 0); - return 0; - } - }; - static auto GetColorModifier = [](ColorModifier factor, const Math::Vec4<u8>& values) -> Math::Vec3<u8> { - switch (factor) - { + switch (factor) { case ColorModifier::SourceColor: return values.rgb(); @@ -324,27 +296,56 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, return (Math::Vec3<u8>(255, 255, 255) - values.rgb()).Cast<u8>(); case ColorModifier::SourceAlpha: - return { values.a(), values.a(), values.a() }; + return values.aaa(); - default: - LOG_ERROR(HW_GPU, "Unknown color factor %d\n", (int)factor); - _dbg_assert_(HW_GPU, 0); - return {}; + case ColorModifier::OneMinusSourceAlpha: + return (Math::Vec3<u8>(255, 255, 255) - values.aaa()).Cast<u8>(); + + case ColorModifier::SourceRed: + return values.rrr(); + + case ColorModifier::OneMinusSourceRed: + return (Math::Vec3<u8>(255, 255, 255) - values.rrr()).Cast<u8>(); + + case ColorModifier::SourceGreen: + return values.ggg(); + + case ColorModifier::OneMinusSourceGreen: + return (Math::Vec3<u8>(255, 255, 255) - values.ggg()).Cast<u8>(); + + case ColorModifier::SourceBlue: + return values.bbb(); + + case ColorModifier::OneMinusSourceBlue: + return (Math::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>(); } }; - static auto GetAlphaModifier = [](AlphaModifier factor, u8 value) -> u8 { + static auto GetAlphaModifier = [](AlphaModifier factor, const Math::Vec4<u8>& values) -> u8 { switch (factor) { case AlphaModifier::SourceAlpha: - return value; + return values.a(); case AlphaModifier::OneMinusSourceAlpha: - return 255 - value; + return 255 - values.a(); - default: - LOG_ERROR(HW_GPU, "Unknown alpha factor %d\n", (int)factor); - _dbg_assert_(HW_GPU, 0); - return 0; + case AlphaModifier::SourceRed: + return values.r(); + + case AlphaModifier::OneMinusSourceRed: + return 255 - values.r(); + + case AlphaModifier::SourceGreen: + return values.g(); + + case AlphaModifier::OneMinusSourceGreen: + return 255 - values.g(); + + case AlphaModifier::SourceBlue: + return values.b(); + + case AlphaModifier::OneMinusSourceBlue: + return 255 - values.b(); } }; @@ -414,17 +415,17 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, // combiner_output.rgb(), but instead store it in a temporary variable until // alpha combining has been done. Math::Vec3<u8> color_result[3] = { - GetColorModifier(tev_stage.color_modifier1, GetColorSource(tev_stage.color_source1)), - GetColorModifier(tev_stage.color_modifier2, GetColorSource(tev_stage.color_source2)), - GetColorModifier(tev_stage.color_modifier3, GetColorSource(tev_stage.color_source3)) + GetColorModifier(tev_stage.color_modifier1, GetSource(tev_stage.color_source1)), + GetColorModifier(tev_stage.color_modifier2, GetSource(tev_stage.color_source2)), + GetColorModifier(tev_stage.color_modifier3, GetSource(tev_stage.color_source3)) }; auto color_output = ColorCombine(tev_stage.color_op, color_result); // alpha combiner std::array<u8,3> alpha_result = { - GetAlphaModifier(tev_stage.alpha_modifier1, GetAlphaSource(tev_stage.alpha_source1)), - GetAlphaModifier(tev_stage.alpha_modifier2, GetAlphaSource(tev_stage.alpha_source2)), - GetAlphaModifier(tev_stage.alpha_modifier3, GetAlphaSource(tev_stage.alpha_source3)) + GetAlphaModifier(tev_stage.alpha_modifier1, GetSource(tev_stage.alpha_source1)), + GetAlphaModifier(tev_stage.alpha_modifier2, GetSource(tev_stage.alpha_source2)), + GetAlphaModifier(tev_stage.alpha_modifier3, GetSource(tev_stage.alpha_source3)) }; auto alpha_output = AlphaCombine(tev_stage.alpha_op, alpha_result); @@ -528,18 +529,48 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, auto params = registers.output_merger.alpha_blending; auto LookupFactorRGB = [&](decltype(params)::BlendFactor factor) -> Math::Vec3<u8> { - switch(factor) { + switch (factor) { case params.Zero: return Math::Vec3<u8>(0, 0, 0); case params.One: return Math::Vec3<u8>(255, 255, 255); + case params.SourceColor: + return combiner_output.rgb(); + + case params.OneMinusSourceColor: + return Math::Vec3<u8>(255 - combiner_output.r(), 255 - combiner_output.g(), 255 - combiner_output.b()); + + case params.DestColor: + return dest.rgb(); + + case params.OneMinusDestColor: + return Math::Vec3<u8>(255 - dest.r(), 255 - dest.g(), 255 - dest.b()); + case params.SourceAlpha: - return Math::MakeVec(combiner_output.a(), combiner_output.a(), combiner_output.a()); + return Math::Vec3<u8>(combiner_output.a(), combiner_output.a(), combiner_output.a()); case params.OneMinusSourceAlpha: - return Math::Vec3<u8>(255-combiner_output.a(), 255-combiner_output.a(), 255-combiner_output.a()); + return Math::Vec3<u8>(255 - combiner_output.a(), 255 - combiner_output.a(), 255 - combiner_output.a()); + + case params.DestAlpha: + return Math::Vec3<u8>(dest.a(), dest.a(), dest.a()); + + case params.OneMinusDestAlpha: + return Math::Vec3<u8>(255 - dest.a(), 255 - dest.a(), 255 - dest.a()); + + case params.ConstantColor: + return Math::Vec3<u8>(registers.output_merger.blend_const.r, registers.output_merger.blend_const.g, registers.output_merger.blend_const.b); + + case params.OneMinusConstantColor: + return Math::Vec3<u8>(255 - registers.output_merger.blend_const.r, 255 - registers.output_merger.blend_const.g, 255 - registers.output_merger.blend_const.b); + + case params.ConstantAlpha: + return Math::Vec3<u8>(registers.output_merger.blend_const.a, registers.output_merger.blend_const.a, registers.output_merger.blend_const.a); + + case params.OneMinusConstantAlpha: + return Math::Vec3<u8>(255 - registers.output_merger.blend_const.a, 255 - registers.output_merger.blend_const.a, 255 - registers.output_merger.blend_const.a); default: LOG_CRITICAL(HW_GPU, "Unknown color blend factor %x", factor); @@ -549,7 +580,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, }; auto LookupFactorA = [&](decltype(params)::BlendFactor factor) -> u8 { - switch(factor) { + switch (factor) { case params.Zero: return 0; @@ -562,6 +593,18 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, case params.OneMinusSourceAlpha: return 255 - combiner_output.a(); + case params.DestAlpha: + return dest.a(); + + case params.OneMinusDestAlpha: + return 255 - dest.a(); + + case params.ConstantAlpha: + return registers.output_merger.blend_const.a; + + case params.OneMinusConstantAlpha: + return 255 - registers.output_merger.blend_const.a; + default: LOG_CRITICAL(HW_GPU, "Unknown alpha blend factor %x", factor); exit(0); @@ -573,17 +616,60 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, LookupFactorA(params.factor_source_a)); auto dstfactor = Math::MakeVec(LookupFactorRGB(params.factor_dest_rgb), LookupFactorA(params.factor_dest_a)); + + auto src_result = (combiner_output * srcfactor).Cast<int>(); + auto dst_result = (dest * dstfactor).Cast<int>(); switch (params.blend_equation_rgb) { case params.Add: { - auto result = (combiner_output * srcfactor + dest * dstfactor) / 255; + auto result = (src_result + dst_result) / 255; result.r() = std::min(255, result.r()); result.g() = std::min(255, result.g()); result.b() = std::min(255, result.b()); combiner_output = result.Cast<u8>(); break; } + + case params.Subtract: + { + auto result = (src_result - dst_result) / 255; + result.r() = std::max(0, result.r()); + result.g() = std::max(0, result.g()); + result.b() = std::max(0, result.b()); + combiner_output = result.Cast<u8>(); + break; + } + + case params.ReverseSubtract: + { + auto result = (dst_result - src_result) / 255; + result.r() = std::max(0, result.r()); + result.g() = std::max(0, result.g()); + result.b() = std::max(0, result.b()); + combiner_output = result.Cast<u8>(); + break; + } + + case params.Min: + { + Math::Vec4<int> result; + result.r() = std::min(src_result.r(),dst_result.r()); + result.g() = std::min(src_result.g(),dst_result.g()); + result.b() = std::min(src_result.b(),dst_result.b()); + combiner_output = result.Cast<u8>(); + break; + } + + case params.Max: + { + Math::Vec4<int> result; + result.r() = std::max(src_result.r(),dst_result.r()); + result.g() = std::max(src_result.g(),dst_result.g()); + result.b() = std::max(src_result.b(),dst_result.b()); + combiner_output = result.Cast<u8>(); + break; + } default: LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", params.blend_equation_rgb.Value()); |