diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 89aae7ce6..76e0c68c3 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -23,6 +23,7 @@ #include "core/system.h" #include "core/loader.h" #include "core/core.h" +#include "core/arm/disassembler/load_symbol_map.h" #include "version.h" @@ -74,6 +75,7 @@ GMainWindow::GMainWindow() // Setup connections connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile())); + connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap())); connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame())); connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); @@ -140,11 +142,17 @@ void GMainWindow::BootGame(const char* filename) void GMainWindow::OnMenuLoadFile() { - QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.dat)")); + QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.dat *.bin)")); if (filename.size()) BootGame(filename.toLatin1().data()); } +void GMainWindow::OnMenuLoadSymbolMap() { + QString filename = QFileDialog::getOpenFileName(this, tr("Load symbol map"), QString(), tr("Symbol map (*)")); + if (filename.size()) + LoadSymbolMap(filename.toLatin1().data()); +} + void GMainWindow::OnStartGame() { render_window->GetEmuThread().SetCpuRunning(true); diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index b4b1c533c..fa122f76e 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -33,10 +33,11 @@ private: void closeEvent(QCloseEvent* event); private slots: - void OnStartGame(); - void OnPauseGame(); - void OnStopGame(); - void OnMenuLoadFile(); + void OnStartGame(); + void OnPauseGame(); + void OnStopGame(); + void OnMenuLoadFile(); + void OnMenuLoadSymbolMap(); void OnOpenHotkeysDialog(); void OnConfigure(); void ToggleWindowMode(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index c0cb11a10..f3596716f 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -40,6 +40,7 @@ &File + @@ -72,12 +73,17 @@ - - - Load file... - - - + + + Load file... + + + + + Load symbol map... + + + E&xit diff --git a/src/citra_qt/ui_main.h b/src/citra_qt/ui_main.h index cd3906ecc..04979e5ab 100644 --- a/src/citra_qt/ui_main.h +++ b/src/citra_qt/ui_main.h @@ -27,6 +27,7 @@ class Ui_MainWindow { public: QAction *action_Load_File; + QAction *action_Load_Symbol_Map; QAction *action_Exit; QAction *action_Start; QAction *action_Pause; @@ -56,6 +57,8 @@ public: MainWindow->setDockNestingEnabled(true); action_Load_File = new QAction(MainWindow); action_Load_File->setObjectName(QString::fromUtf8("action_Load_File")); + action_Load_Symbol_Map = new QAction(MainWindow); + action_Load_Symbol_Map->setObjectName(QString::fromUtf8("action_Load_Symbol_Map")); action_Exit = new QAction(MainWindow); action_Exit->setObjectName(QString::fromUtf8("action_Exit")); action_Start = new QAction(MainWindow); @@ -101,6 +104,7 @@ public: menubar->addAction(menu_View->menuAction()); menubar->addAction(menu_Help->menuAction()); menu_File->addAction(action_Load_File); + menu_File->addAction(action_Load_Symbol_Map); menu_File->addSeparator(); menu_File->addAction(action_Exit); menu_Emulation->addAction(action_Start); @@ -123,6 +127,7 @@ public: { MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Citra", 0, QApplication::UnicodeUTF8)); action_Load_File->setText(QApplication::translate("MainWindow", "Load file...", 0, QApplication::UnicodeUTF8)); + action_Load_Symbol_Map->setText(QApplication::translate("MainWindow", "Load symbol map...", 0, QApplication::UnicodeUTF8)); action_Exit->setText(QApplication::translate("MainWindow", "E&xit", 0, QApplication::UnicodeUTF8)); action_Start->setText(QApplication::translate("MainWindow", "&Start", 0, QApplication::UnicodeUTF8)); action_Pause->setText(QApplication::translate("MainWindow", "&Pause", 0, QApplication::UnicodeUTF8)); diff --git a/src/common/bit_field.h b/src/common/bit_field.h new file mode 100644 index 000000000..dfd00d198 --- /dev/null +++ b/src/common/bit_field.h @@ -0,0 +1,172 @@ +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +// Copyright 2014 Tony Wasserka +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the owner nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +#include +#include + +#include "common/common.h" + +/* + * Abstract bitfield class + * + * Allows endianness-independent access to individual bitfields within some raw + * integer value. The assembly generated by this class is identical to the + * usage of raw bitfields, so it's a perfectly fine replacement. + * + * For BitField, X is the distance of the bitfield to the LSB of the + * raw value, Y is the length in bits of the bitfield. Z is an integer type + * which determines the sign of the bitfield. Z must have the same size as the + * raw integer. + * + * + * General usage: + * + * Create a new union with the raw integer value as a member. + * Then for each bitfield you want to expose, add a BitField member + * in the union. The template parameters are the bit offset and the number + * of desired bits. + * + * Changes in the bitfield members will then get reflected in the raw integer + * value and vice-versa. + * + * + * Sample usage: + * + * union SomeRegister + * { + * u32 hex; + * + * BitField<0,7,u32> first_seven_bits; // unsigned + * BitField<7,8,32> next_eight_bits; // unsigned + * BitField<3,15,s32> some_signed_fields; // signed + * }; + * + * This is equivalent to the little-endian specific code: + * + * union SomeRegister + * { + * u32 hex; + * + * struct + * { + * u32 first_seven_bits : 7; + * u32 next_eight_bits : 8; + * }; + * struct + * { + * u32 : 3; // padding + * s32 some_signed_fields : 15; + * }; + * }; + * + * + * Caveats: + * + * 1) + * BitField provides automatic casting from and to the storage type where + * appropriate. However, when using non-typesafe functions like printf, an + * explicit cast must be performed on the BitField object to make sure it gets + * passed correctly, e.g.: + * printf("Value: %d", (s32)some_register.some_signed_fields); + * + * 2) + * Not really a caveat, but potentially irritating: This class is used in some + * packed structures that do not guarantee proper alignment. Therefore we have + * to use #pragma pack here not to pack the members of the class, but instead + * to break GCC's assumption that the members of the class are aligned on + * sizeof(StorageType). + * TODO(neobrain): Confirm that this is a proper fix and not just masking + * symptoms. + */ +#pragma pack(1) +template +struct BitField +{ +private: + // This constructor might be considered ambiguous: + // Would it initialize the storage or just the bitfield? + // Hence, delete it. Use the assignment operator to set bitfield values! + BitField(T val) = delete; + +public: + // Force default constructor to be created + // so that we can use this within unions + BitField() = default; + + __forceinline BitField& operator=(T val) + { + storage = (storage & ~GetMask()) | ((val << position) & GetMask()); + return *this; + } + + __forceinline operator T() const + { + if (std::numeric_limits::is_signed) + { + std::size_t shift = 8 * sizeof(T)-bits; + return (T)(((storage & GetMask()) << (shift - position)) >> shift); + } + else + { + return (T)((storage & GetMask()) >> position); + } + } + +private: + // StorageType is T for non-enum types and the underlying type of T if + // T is an enumeration. Note that T is wrapped within an enable_if in the + // former case to workaround compile errors which arise when using + // std::underlying_type::type directly. + typedef typename std::conditional < std::is_enum::value, + std::underlying_type, + std::enable_if < true, T >> ::type::type StorageType; + + // Unsigned version of StorageType + typedef typename std::make_unsigned::type StorageTypeU; + + __forceinline StorageType GetMask() const + { + return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position; + } + + StorageType storage; + + static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); + + // And, you know, just in case people specify something stupid like bits=position=0x80000000 + static_assert(position < 8 * sizeof(T), "Invalid position"); + static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); + static_assert(bits > 0, "Invalid number of bits"); +}; +#pragma pack() diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 5048bebff..5dc6ff790 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -157,6 +157,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index e9ea40022..268730228 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -39,6 +39,7 @@ + diff --git a/src/common/log.h b/src/common/log.h index 02db8bd55..d95f51f56 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -33,7 +33,7 @@ enum LOG_TYPE { EXPANSIONINTERFACE, GDB_STUB, ARM11, - GPFIFO, + GSP, OSHLE, MASTER_LOG, MEMMAP, @@ -54,7 +54,7 @@ enum LOG_TYPE { WII_IPC_FILEIO, WII_IPC_HID, WII_IPC_HLE, - WII_IPC_NET, + SVC, NDMA, HLE, RENDER, diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 8e56deb8f..80fd473b9 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -42,7 +42,7 @@ LogManager::LogManager() m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt"); m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); - m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); + m_Log[LogTypes::GSP] = new LogContainer("GSP", "GSP"); m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); @@ -66,7 +66,7 @@ LogManager::LogManager() m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); - m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); + m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call"); m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA"); m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation"); m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware"); @@ -147,7 +147,7 @@ LogContainer::LogContainer(const char* shortName, const char* fullName, bool ena { strncpy(m_fullName, fullName, 128); strncpy(m_shortName, shortName, 32); - m_level = LogTypes::LWARNING; + m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL; } // LogContainer diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 11b90434d..f96f04b15 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -5,7 +5,9 @@ set(SRCS core.cpp mem_map_funcs.cpp system.cpp arm/disassembler/arm_disasm.cpp + arm/disassembler/load_symbol_map.cpp arm/interpreter/arm_interpreter.cpp + arm/interpreter/armcopro.cpp arm/interpreter/armemu.cpp arm/interpreter/arminit.cpp arm/interpreter/armmmu.cpp @@ -13,12 +15,24 @@ set(SRCS core.cpp arm/interpreter/armsupp.cpp arm/interpreter/armvirt.cpp arm/interpreter/thumbemu.cpp - arm/mmu/arm1176jzf_s_mmu.cpp + arm/interpreter/vfp/vfp.cpp + arm/interpreter/vfp/vfpdouble.cpp + arm/interpreter/vfp/vfpinstr.cpp + arm/interpreter/vfp/vfpsingle.cpp + arm/interpreter/mmu/arm1176jzf_s_mmu.cpp + arm/interpreter/mmu/cache.cpp + arm/interpreter/mmu/maverick.cpp + arm/interpreter/mmu/rb.cpp + arm/interpreter/mmu/sa_mmu.cpp + arm/interpreter/mmu/tlb.cpp + arm/interpreter/mmu/wb.cpp + arm/interpreter/mmu/xscale_copro.cpp elf/elf_reader.cpp file_sys/directory_file_system.cpp file_sys/meta_file_system.cpp hle/hle.cpp - hle/mrc.cpp + hle/config_mem.cpp + hle/coprocessor.cpp hle/syscall.cpp hle/service/apt.cpp hle/service/gsp.cpp diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp new file mode 100644 index 000000000..d7fc0a042 --- /dev/null +++ b/src/core/arm/disassembler/load_symbol_map.cpp @@ -0,0 +1,33 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "common/symbols.h" +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/arm/disassembler/load_symbol_map.h" + +/* + * Loads a symbol map file for use with the disassembler + * @param filename String filename path of symbol map file + */ +void LoadSymbolMap(std::string filename) { + std::ifstream infile(filename); + + std::string address_str, function_name, line; + u32 size, address; + + while (std::getline(infile, line)) { + std::istringstream iss(line); + if (!(iss >> address_str >> size >> function_name)) { + break; // Error parsing + } + u32 address = std::stoul(address_str, nullptr, 16); + + Symbols::Add(address, function_name, size, 2); + } +} diff --git a/src/core/arm/disassembler/load_symbol_map.h b/src/core/arm/disassembler/load_symbol_map.h new file mode 100644 index 000000000..837cca99b --- /dev/null +++ b/src/core/arm/disassembler/load_symbol_map.h @@ -0,0 +1,13 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +/* + * Loads a symbol map file for use with the disassembler + * @param filename String filename path of symbol map file + */ +void LoadSymbolMap(std::string filename); diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index 4045779d7..4652803de 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "arm_interpreter.h" +#include "core/arm/interpreter/arm_interpreter.h" const static cpu_config_t s_arm11_cpu_info = { "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp new file mode 100644 index 000000000..6a75e6601 --- /dev/null +++ b/src/core/arm/interpreter/armcopro.cpp @@ -0,0 +1,842 @@ +/* armcopro.c -- co-processor interface: ARM6 Instruction Emulator. + Copyright (C) 1994, 2000 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. */ + + +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/armos.h" +#include "core/arm/interpreter/armemu.h" +#include "core/arm/interpreter/vfp/vfp.h" + +//chy 2005-07-08 +//#include "ansidecl.h" +//chy ------- +//#include "iwmmxt.h" + + +//chy 2005-09-19 add CP6 MRC support (for get irq number and base) +extern unsigned xscale_cp6_mrc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +//chy 2005-09-19--------------- + +extern unsigned xscale_cp13_init (ARMul_State * state); +extern unsigned xscale_cp13_exit (ARMul_State * state); +extern unsigned xscale_cp13_ldc (ARMul_State * state, unsigned type, + ARMword instr, ARMword data); +extern unsigned xscale_cp13_stc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +extern unsigned xscale_cp13_mrc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +extern unsigned xscale_cp13_mcr (ARMul_State * state, unsigned type, + ARMword instr, ARMword data); +extern unsigned xscale_cp13_cdp (ARMul_State * state, unsigned type, + ARMword instr); +extern unsigned xscale_cp13_read_reg (ARMul_State * state, unsigned reg, + ARMword * data); +extern unsigned xscale_cp13_write_reg (ARMul_State * state, unsigned reg, + ARMword data); +extern unsigned xscale_cp14_init (ARMul_State * state); +extern unsigned xscale_cp14_exit (ARMul_State * state); +extern unsigned xscale_cp14_ldc (ARMul_State * state, unsigned type, + ARMword instr, ARMword data); +extern unsigned xscale_cp14_stc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +extern unsigned xscale_cp14_mrc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +extern unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, + ARMword instr, ARMword data); +extern unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, + ARMword instr); +extern unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, + ARMword * data); +extern unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, + ARMword data); +extern unsigned xscale_cp15_init (ARMul_State * state); +extern unsigned xscale_cp15_exit (ARMul_State * state); +extern unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, + ARMword instr, ARMword data); +extern unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +extern unsigned xscale_cp15_mrc (ARMul_State * state, unsigned type, + ARMword instr, ARMword * data); +extern unsigned xscale_cp15_mcr (ARMul_State * state, unsigned type, + ARMword instr, ARMword data); +extern unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, + ARMword instr); +extern unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, + ARMword * data); +extern unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg, + ARMword data); +extern unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, + unsigned cpnum); + +/* Dummy Co-processors. */ + +static unsigned +NoCoPro3R (ARMul_State * state, + unsigned a, ARMword b) +{ + return ARMul_CANT; +} + +static unsigned +NoCoPro4R (ARMul_State * state, + unsigned a, + ARMword b, ARMword c) +{ + return ARMul_CANT; +} + +static unsigned +NoCoPro4W (ARMul_State * state, + unsigned a, + ARMword b, ARMword * c) +{ + return ARMul_CANT; +} + +static unsigned +NoCoPro5R (ARMul_State * state, + unsigned a, + ARMword b, + ARMword c, ARMword d) +{ + return ARMul_CANT; +} + +static unsigned +NoCoPro5W (ARMul_State * state, + unsigned 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); + +/* There are two sets of registers for copro 15. + One set is available when opcode_2 is 0 and + the other set when opcode_2 >= 1. */ +static ARMword XScale_cp15_opcode_2_is_0_Regs[16]; +static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16]; +/* There are also a set of breakpoint registers + which are accessed via CRm instead of opcode_2. */ +static ARMword XScale_cp15_DBR1; +static ARMword XScale_cp15_DBCON; +static ARMword XScale_cp15_IBCR0; +static ARMword XScale_cp15_IBCR1; + +static unsigned +XScale_cp15_init (ARMul_State * state) +{ + int i; + + for (i = 16; i--;) { + XScale_cp15_opcode_2_is_0_Regs[i] = 0; + XScale_cp15_opcode_2_is_not_0_Regs[i] = 0; + } + + /* Initialise the processor ID. */ + //chy 2003-03-24, is same as cpu id in skyeye_options.c + //XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000; + XScale_cp15_opcode_2_is_0_Regs[0] = 0x69050000; + + /* Initialise the cache type. */ + XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA; + + /* Initialise the ARM Control Register. */ + XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078; + + return No_exp; +} + +/* 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; +} + +/* Coprocessor 13: Interrupt Controller and Bus Controller. */ + +/* There are two sets of registers for copro 13. + One set (of three registers) is available when CRm is 0 + and the other set (of six registers) when CRm is 1. */ + +static ARMword XScale_cp13_CR0_Regs[16]; +static ARMword XScale_cp13_CR1_Regs[16]; + +static unsigned +XScale_cp13_init (ARMul_State * state) +{ + int i; + + for (i = 16; i--;) { + XScale_cp13_CR0_Regs[i] = 0; + XScale_cp13_CR1_Regs[i] = 0; + } + + return No_exp; +} + +/* Check an access to a register. */ + +static unsigned +check_cp13_access (ARMul_State * state, + unsigned reg, + unsigned CRm, unsigned opcode_1, unsigned opcode_2) +{ + /* Do not allow access to these registers 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; + + /* The opcodes should be zero. */ + if ((opcode_1 != 0) || (opcode_2 != 0)) + return ARMul_CANT; + + /* Do not allow access to these register if bit + 13 of coprocessor 15's register 15 is zero. */ + if (!CP_ACCESS_ALLOWED (state, 13)) + return ARMul_CANT; + + /* Registers 0, 4 and 8 are defined when CRm == 0. + Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1. + For all other CRm values undefined behaviour results. */ + if (CRm == 0) { + if (reg == 0 || reg == 4 || reg == 8) + return ARMul_DONE; + } + else if (CRm == 1) { + if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8)) + return ARMul_DONE; + } + + return ARMul_CANT; +} + +/* Coprocessor 14: Performance Monitoring, Clock and Power management, + Software Debug. */ + +static ARMword XScale_cp14_Regs[16]; + +static unsigned +XScale_cp14_init (ARMul_State * state) +{ + int i; + + for (i = 16; i--;) + XScale_cp14_Regs[i] = 0; + + return No_exp; +} + +/* Check an access to a register. */ + +static unsigned +check_cp14_access (ARMul_State * state, + unsigned reg, + unsigned CRm, unsigned opcode1, unsigned opcode2) +{ + /* Not allowed to access 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; + + /* CRm should be zero. */ + if (CRm != 0) + return ARMul_CANT; + + /* OPcodes should be zero. */ + if (opcode1 != 0 || opcode2 != 0) + return ARMul_CANT; + + /* Accessing registers 4 or 5 has unpredicatable results. */ + if (reg >= 4 && reg <= 5) + return ARMul_CANT; + + return ARMul_DONE; +} + +/* Here's ARMulator's MMU definition. A few things to note: + 1) It has eight registers, but only two are defined. + 2) You can only access its registers with MCR and MRC. + 3) MMU Register 0 (ID) returns 0x41440110 + 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4 + controls 32/26 bit program space, bit 5 controls 32/26 bit data space, + bit 6 controls late abort timimg and bit 7 controls big/little endian. */ + +static ARMword MMUReg[8]; + +static unsigned +MMUInit (ARMul_State * state) +{ +/* 2004-05-09 chy +------------------------------------------------------------- +read ARM Architecture Reference Manual +2.6.5 Data Abort +There are three Abort Model in ARM arch. + +Early Abort Model: used in some ARMv3 and earlier implementations. In this +model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and +the base register was unchanged for all other instructions. (oldest) + +Base Restored Abort Model: If a Data Abort occurs in an instruction which +specifies base register writeback, the value in the base register is +unchanged. (strongarm, xscale) + +Base Updated Abort Model: If a Data Abort occurs in an instruction which +specifies base register writeback, the base register writeback still occurs. +(arm720T) + +read PART B +chap2 The System Control Coprocessor CP15 +2.4 Register1:control register +L(bit 6): in some ARMv3 and earlier implementations, the abort model of the +processor could be configured: +0=early Abort Model Selected(now obsolete) +1=Late Abort Model selceted(same as Base Updated Abort Model) + +on later processors, this bit reads as 1 and ignores writes. +------------------------------------------------------------- +So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) + if lateabtSig=0, then it means Base Restored Abort Model +because the ARMs which skyeye simulates are all belonged to ARMv4, +so I think MMUReg[1]'s bit 6 should always be 1 + +*/ + + MMUReg[1] = state->prog32Sig << 4 | + state->data32Sig << 5 | 1 << 6 | state->bigendSig << 7; + //state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7; + + + NOTICE_LOG(ARM11, "ARMul_ConsolePrint: MMU present"); + + return TRUE; +} + +static unsigned +MMUMRC (ARMul_State * state, unsigned type, + ARMword instr, ARMword * value) +{ + mmu_mrc (state, instr, value); + return (ARMul_DONE); +} + +static unsigned +MMUMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) +{ + mmu_mcr (state, instr, value); + return (ARMul_DONE); +} + +/* What follows is the Validation Suite Coprocessor. It uses two + co-processor numbers (4 and 5) and has the follwing functionality. + Sixteen registers. Both co-processor nuimbers can be used in an MCR + and MRC to access these registers. CP 4 can LDC and STC to and from + the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of + cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a + number of cycles (specified in a CP register), CDP 2 issues an IRQW + in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5 + stores a 32 bit time value in a CP register (actually it's the total + number of N, S, I, C and F cyles). */ + +static ARMword ValReg[16]; + +static unsigned +ValLDC (ARMul_State * state, + unsigned type, ARMword instr, ARMword data) +{ + static unsigned words; + + if (type != ARMul_DATA) + words = 0; + else { + ValReg[BITS (12, 15)] = data; + + if (BIT (22)) + /* It's a long access, get two words. */ + if (words++ != 4) + return ARMul_INC; + } + + return ARMul_DONE; +} + +static unsigned +ValSTC (ARMul_State * state, + unsigned type, ARMword instr, ARMword * data) +{ + static unsigned words; + + if (type != ARMul_DATA) + words = 0; + else { + *data = ValReg[BITS (12, 15)]; + + if (BIT (22)) + /* It's a long access, get two words. */ + if (words++ != 4) + return ARMul_INC; + } + + return ARMul_DONE; +} + +static unsigned +ValMRC (ARMul_State * state, + unsigned type, ARMword instr, ARMword * value) +{ + *value = ValReg[BITS (16, 19)]; + + return ARMul_DONE; +} + +static unsigned +ValMCR (ARMul_State * state, + unsigned type, ARMword instr, ARMword value) +{ + ValReg[BITS (16, 19)] = value; + + return ARMul_DONE; +} + +static unsigned +ValCDP (ARMul_State * state, unsigned type, ARMword instr) +{ + static unsigned int finish = 0; + + if (BITS (20, 23) != 0) + return ARMul_CANT; + + if (type == ARMul_FIRST) { + ARMword howlong; + + howlong = ValReg[BITS (0, 3)]; + + /* First cycle of a busy wait. */ + finish = ARMul_Time (state) + howlong; + + return howlong == 0 ? ARMul_DONE : ARMul_BUSY; + } + else if (type == ARMul_BUSY) { + if (ARMul_Time (state) >= finish) + return ARMul_DONE; + else + return ARMul_BUSY; + } + + return ARMul_CANT; +} + +static unsigned +DoAFIQ (ARMul_State * state) +{ + state->NfiqSig = LOW; + return 0; +} + +static unsigned +DoAIRQ (ARMul_State * state) +{ + state->NirqSig = LOW; + return 0; +} + +static unsigned +IntCDP (ARMul_State * state, unsigned type, ARMword instr) +{ + static unsigned int finish; + ARMword howlong; + + howlong = ValReg[BITS (0, 3)]; + + switch ((int) BITS (20, 23)) { + case 0: + if (type == ARMul_FIRST) { + /* First cycle of a busy wait. */ + finish = ARMul_Time (state) + howlong; + + return howlong == 0 ? ARMul_DONE : ARMul_BUSY; + } + else if (type == ARMul_BUSY) { + if (ARMul_Time (state) >= finish) + return ARMul_DONE; + else + return ARMul_BUSY; + } + return ARMul_DONE; + + case 1: + if (howlong == 0) + ARMul_Abort (state, ARMul_FIQV); + else + ARMul_ScheduleEvent (state, howlong, DoAFIQ); + return ARMul_DONE; + + case 2: + if (howlong == 0) + ARMul_Abort (state, ARMul_IRQV); + else + ARMul_ScheduleEvent (state, howlong, DoAIRQ); + return ARMul_DONE; + + case 3: + state->NfiqSig = HIGH; + return ARMul_DONE; + + case 4: + state->NirqSig = HIGH; + return ARMul_DONE; + + case 5: + ValReg[BITS (0, 3)] = ARMul_Time (state); + return ARMul_DONE; + } + + return ARMul_CANT; +} + +/* Install co-processor instruction handlers in this routine. */ + +unsigned +ARMul_CoProInit (ARMul_State * state) +{ + unsigned int i; + + /* Initialise tham all first. */ + for (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). */ + if (state->is_ep9312) { + ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4, + DSPMRC4, DSPMCR4, NULL, NULL, DSPCDP4, NULL, NULL); + ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5, + DSPMRC5, DSPMCR5, NULL, NULL, DSPCDP5, NULL, NULL); + ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL, + DSPMRC6, DSPMCR6, NULL, NULL, DSPCDP6, NULL, NULL); + } + else { + ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC, + ValMRC, ValMCR, NULL, NULL, ValCDP, NULL, NULL); + + ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL, + ValMRC, ValMCR, NULL, NULL, IntCDP, NULL, NULL); + } + + if (state->is_XScale) { + //chy 2005-09-19, for PXA27x's CP6 + if (state->is_pxa27x) { + ARMul_CoProAttach (state, 6, NULL, NULL, + NULL, NULL, xscale_cp6_mrc, + NULL, NULL, NULL, NULL, NULL, NULL); + } + //chy 2005-09-19 end------------- + ARMul_CoProAttach (state, 13, xscale_cp13_init, + xscale_cp13_exit, xscale_cp13_ldc, + xscale_cp13_stc, xscale_cp13_mrc, + xscale_cp13_mcr, NULL, NULL, xscale_cp13_cdp, + xscale_cp13_read_reg, + xscale_cp13_write_reg); + + ARMul_CoProAttach (state, 14, xscale_cp14_init, + xscale_cp14_exit, xscale_cp14_ldc, + xscale_cp14_stc, xscale_cp14_mrc, + xscale_cp14_mcr, NULL, NULL, xscale_cp14_cdp, + xscale_cp14_read_reg, + xscale_cp14_write_reg); + //chy: 2003-08-24. + ARMul_CoProAttach (state, 15, xscale_cp15_init, + xscale_cp15_exit, xscale_cp15_ldc, + xscale_cp15_stc, xscale_cp15_mrc, + xscale_cp15_mcr, NULL, NULL, xscale_cp15_cdp, + xscale_cp15_read_reg, + xscale_cp15_write_reg); + } + else if (state->is_v6) { + ARMul_CoProAttach (state, 10, VFPInit, NULL, VFPLDC, VFPSTC, + VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); + ARMul_CoProAttach (state, 11, VFPInit, NULL, VFPLDC, VFPSTC, + VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); + + ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, + MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL); + } + else { //all except xscale + ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, + // MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); + 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 + //----------------------------------------------------------------------------- + //chy 2004-05-25, found the user/system code visit CP 1,2, so I add below code. + ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, + ValMRC, ValMCR, NULL, NULL, NULL, NULL, NULL); + ARMul_CoProAttach (state, 2, NULL, NULL, ValLDC, ValSTC, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + //------------------------------------------------------------------------------ + /* No handlers below here. */ + + /* Call all the initialisation routines. */ + for (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) +{ + register unsigned i; + + for (i = 0; i < 16; i++) + if (state->CPExit[i]) + (state->CPExit[i]) (state); + + for (i = 0; i < 16; i++) /* Detach all handlers. */ + ARMul_CoProDetach (state, i); +} + +/* Routines to hook Co-processors into ARMulator. */ + +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) +{ + if (init != NULL) + state->CPInit[number] = init; + if (exit != NULL) + state->CPExit[number] = exit; + if (ldc != NULL) + state->LDC[number] = ldc; + if (stc != NULL) + state->STC[number] = stc; + if (mrc != NULL) + state->MRC[number] = mrc; + if (mcr != NULL) + state->MCR[number] = mcr; + if (mrrc != NULL) + state->MRRC[number] = mrrc; + if (mcrr != NULL) + state->MCRR[number] = mcrr; + if (cdp != NULL) + state->CDP[number] = cdp; + if (read != NULL) + state->CPRead[number] = read; + if (write != NULL) + state->CPWrite[number] = write; +} + +void +ARMul_CoProDetach (ARMul_State * state, unsigned number) +{ + ARMul_CoProAttach (state, number, NULL, NULL, + NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, + NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL); + + state->CPInit[number] = NULL; + state->CPExit[number] = NULL; + state->CPRead[number] = NULL; + state->CPWrite[number] = NULL; +} + +//chy 2003-09-03:below funs just replace the old ones + +/* Set the XScale FSR and FAR registers. */ + +void +XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far) +{ + //if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0) + if (!state->is_XScale) + return; + //assume opcode2=0 crm =0 + xscale_cp15_write_reg (state, 5, fsr); + xscale_cp15_write_reg (state, 6, _far); +} + +//chy 2003-09-03 seems 0 is CANT, 1 is DONE ???? +int +XScale_debug_moe (ARMul_State * state, int moe) +{ + //chy 2003-09-03 , W/R CP14 reg, now it's no use ???? + printf ("SKYEYE: XScale_debug_moe called !!!!\n"); + return 1; +} diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index a35c5c8dc..87141653f 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -23,17 +23,6 @@ #include "armemu.h" #include "armos.h" -void -XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword _far) -{ - _dbg_assert_msg_(ARM11, false, "ImplementMe: XScale_set_fsr_far!"); - //if (!state->is_XScale || (read_cp14_reg(10) & (1UL << 31)) == 0) - // return; - // - //write_cp15_reg(state, 5, 0, 0, fsr); - //write_cp15_reg(state, 6, 0, 0, _far); -} - #define ARMul_Debug(x,y,z) 0 // Disabling this /bunnei //#include "skyeye_callback.h" @@ -5536,14 +5525,15 @@ Handle_Load_Double (ARMul_State * state, ARMword instr) 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; - } + // FIX(Normatt): Disable strict alignment on LDRD/STRD +// if (addr & 0x7) { +//#ifdef ABORTS +// ARMul_DATAABORT (addr); +//#else +// ARMul_UndefInstr (state, instr); +//#endif +// return; +// } /* For pre indexed or post indexed addressing modes, check that the destination registers do not overlap @@ -5640,14 +5630,15 @@ Handle_Store_Double (ARMul_State * state, ARMword instr) 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; - } + // FIX(Normatt): Disable strict alignment on LDRD/STRD +// if (addr & 0x7) { +//#ifdef ABORTS +// ARMul_DATAABORT (addr); +//#else +// ARMul_UndefInstr (state, instr); +//#endif +// return; +// } /* For pre indexed or post indexed addressing modes, check that the destination registers do not overlap @@ -6405,6 +6396,8 @@ handle_v6_insn (ARMul_State * state, ARMword instr) if (state->Aborted) { TAKEABORT; } + // FIX(Normmatt): Handle RD in STREX/STREXB + state->Reg[DESTReg] = 0; //Always succeed return 1; } @@ -6432,7 +6425,8 @@ handle_v6_insn (ARMul_State * state, ARMword instr) if (state->Aborted) { TAKEABORT; } - + // FIX(Normmatt): Handle RD in STREX/STREXB + state->Reg[DESTReg] = 0; //Always succeed //printf("In %s, strexb not implemented\n", __FUNCTION__); UNDEF_LSRBPC; /* WRITESDEST (dest); */ diff --git a/src/core/arm/interpreter/armemu.h b/src/core/arm/interpreter/armemu.h index 7c118948a..7ccb07e8d 100644 --- a/src/core/arm/interpreter/armemu.h +++ b/src/core/arm/interpreter/armemu.h @@ -17,9 +17,9 @@ #ifndef __ARMEMU_H__ #define __ARMEMU_H__ -#include "common/common.h" -#include "armdefs.h" -//#include "skyeye.h" + +#include "core/arm/interpreter/skyeye_defs.h" +#include "core/arm/interpreter/armdefs.h" extern ARMword isize; @@ -73,9 +73,7 @@ extern ARMword isize; #define ASSIGNT(res) state->TFlag = res #define INSN_SIZE (TFLAG ? 2 : 4) #else -#define TBIT (1L << 5) #define INSN_SIZE 4 -#define TFLAG 0 #endif /*add armv6 CPSR feature*/ @@ -166,6 +164,7 @@ extern ARMword isize; #define PCWRAP(pc) ((pc) & R15PCBITS) #endif +#define PC (state->Reg[15] & PCMASK) #define R15CCINTMODE (state->Reg[15] & (CCBITS | R15INTBITS | R15MODEBITS)) #define R15INT (state->Reg[15] & R15INTBITS) #define R15INTPC (state->Reg[15] & (R15INTBITS | R15PCBITS)) @@ -180,11 +179,11 @@ extern ARMword isize; #define ER15INT (IFFLAGS << 26) #define EMODE (state->Mode) -//#ifdef MODET -//#define CPSR (ECC | EINT | EMODE | (TFLAG << 5)) -//#else -//#define CPSR (ECC | EINT | EMODE) -//#endif +#ifdef MODET +#define CPSR (ECC | EINT | EMODE | (TFLAG << 5)) +#else +#define CPSR (ECC | EINT | EMODE) +#endif #ifdef MODE32 #define PATCHR15 @@ -240,12 +239,12 @@ extern ARMword isize; } \ while (0) -//#ifndef MODE32 +#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 +#endif #define INTERNALABORT(address) \ do \ @@ -420,12 +419,10 @@ extern ARMword isize; || (! (STATE)->is_XScale) \ || (read_cp15_reg (15, 0, 1) & (1 << (CP)))) */ -//#define CP_ACCESS_ALLOWED(STATE, CP) \ -// (((CP) >= 14) \ -// || (!(STATE)->is_XScale) \ -// || (xscale_cp15_cp_access_allowed(STATE, 15, CP))) - -#define CP_ACCESS_ALLOWED(STATE, CP) false // Disabled coprocessor shit /bunnei +#define CP_ACCESS_ALLOWED(STATE, CP) \ + ( ((CP) >= 14) \ + || (! (STATE)->is_XScale) \ + || (xscale_cp15_cp_access_allowed(STATE,15,CP))) /* Macro to rotate n right by b bits. */ #define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) @@ -517,7 +514,7 @@ tdstate; * out-of-updated with the newer ISA. * -- Michael.Kang ********************************************************************************/ -#define UNDEF_WARNING ERROR_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n"); +#define UNDEF_WARNING WARN_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n"); /* Macros to scrutinize instructions. */ #define UNDEF_Test UNDEF_WARNING diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index a8aeecdea..2c771cdda 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -23,8 +23,8 @@ #include -#include "armdefs.h" -#include "armemu.h" +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/armemu.h" /***************************************************************************\ * Definitions for the emulator architecture * @@ -271,7 +271,7 @@ below line sould be in skyeye_mach_XXX.c 's XXX_mach_init function /* Only initialse the coprocessor support once we know what kind of chip we are dealing with. */ - //ARMul_CoProInit (state); Commented out /bunnei + ARMul_CoProInit (state); } @@ -318,7 +318,7 @@ ARMul_Reset (ARMul_State * state) state->NumFcycles = 0; //fprintf(stderr,"armul_reset 3: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - //mmu_reset (state); Commented out /bunnei + mmu_reset (state); //fprintf(stderr,"armul_reset 4: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); //mem_reset (state); /* move to memory/ram.c */ diff --git a/src/core/arm/interpreter/armmmu.h b/src/core/arm/interpreter/armmmu.h index 8b24e6151..818108c9c 100644 --- a/src/core/arm/interpreter/armmmu.h +++ b/src/core/arm/interpreter/armmmu.h @@ -172,18 +172,18 @@ typedef struct mmu_ops_s } mmu_ops_t; -#include "core/arm/mmu/tlb.h" -#include "core/arm/mmu/rb.h" -#include "core/arm/mmu/wb.h" -#include "core/arm/mmu/cache.h" +#include "core/arm/interpreter/mmu/tlb.h" +#include "core/arm/interpreter/mmu/rb.h" +#include "core/arm/interpreter/mmu/wb.h" +#include "core/arm/interpreter/mmu/cache.h" /*special process mmu.h*/ -//#include "core/arm/mmu/sa_mmu.h" -//#include "core/arm/mmu/arm7100_mmu.h" -//#include "core/arm/mmu/arm920t_mmu.h" -//#include "core/arm/mmu/arm926ejs_mmu.h" -#include "core/arm/mmu/arm1176jzf_s_mmu.h" -//#include "core/arm/mmu/cortex_a9_mmu.h" +#include "core/arm/interpreter/mmu/sa_mmu.h" +//#include "core/arm/interpreter/mmu/arm7100_mmu.h" +//#include "core/arm/interpreter/mmu/arm920t_mmu.h" +//#include "core/arm/interpreter/mmu/arm926ejs_mmu.h" +#include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h" +//#include "core/arm/interpreter/mmu/cortex_a9_mmu.h" typedef struct mmu_state_t { @@ -213,13 +213,13 @@ typedef struct mmu_state_t ARMword copro_access; // 15 mmu_ops_t ops; - //union - //{ - //sa_mmu_t sa_mmu; + union + { + sa_mmu_t sa_mmu; //arm7100_mmu_t arm7100_mmu; //arm920t_mmu_t arm920t_mmu; //arm926ejs_mmu_t arm926ejs_mmu; - //} u; + } u; } mmu_state_t; int mmu_init (ARMul_State * state); diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index b2bbedc18..7816c4c42 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -15,12 +15,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "armdefs.h" -#include "armemu.h" - -//#include "ansidecl.h" -#include "skyeye_defs.h" -#include "core/hle/mrc.h" +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/armemu.h" +#include "core/arm/interpreter/skyeye_defs.h" +#include "core/hle/coprocessor.h" #include "core/arm/disassembler/arm_disasm.h" unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, @@ -127,8 +125,7 @@ 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 - // NOTE(bunnei): Changed this from [now] commented out macro "CPSR" - return ((ECC | EINT | EMODE | (TFLAG << 5))); //had be tested in old skyeye with gdb5.0-5.3 + return (CPSR); //had be tested in old skyeye with gdb5.0-5.3 } /* This routine sets the value of the CPSR. */ @@ -145,7 +142,7 @@ ARMul_SetCPSR (ARMul_State * state, ARMword value) 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 ) { @@ -500,8 +497,8 @@ ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address) return; } - if (ADDREXCEPT (address)) - INTERNALABORT (address); + //if (ADDREXCEPT (address)) + // INTERNALABORT (address); cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0); while (cpab == ARMul_BUSY) { @@ -594,8 +591,8 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address) return; } - if (ADDREXCEPT (address) || VECTORACCESS (address)) - INTERNALABORT (address); + //if (ADDREXCEPT (address) || VECTORACCESS (address)) + // INTERNALABORT (address); cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data); while (cpab == ARMul_BUSY) { @@ -739,39 +736,43 @@ ARMul_MRC (ARMul_State * state, ARMword instr) { unsigned cpab; - ARMword result = HLE::CallMRC((HLE::ARM11_MRC_OPERATION)BITS(20, 27)); + ARMword result = HLE::CallMRC(instr); - ////printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); - //if (!CP_ACCESS_ALLOWED (state, CPNum)) { - // //chy 2004-07-19 should fix in the future????!!!! - // //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr); - // ARMul_UndefInstr (state, instr); - // return -1; - //} + if (result != -1) { + return result; + } - //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); - //} + //printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + //chy 2004-07-19 should fix in the future????!!!! + //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",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; } @@ -906,9 +907,7 @@ ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, state->Now = ARMul_Time (state); when = (state->Now + delay) % EVENTLISTSIZE; event = (struct EventNode *) malloc (sizeof (struct EventNode)); - _dbg_assert_msg_(ARM11, event, "SKYEYE:ARMul_ScheduleEvent: malloc event error\n"); - event->func = what; event->next = *(state->EventPtr + when); *(state->EventPtr + when) = event; diff --git a/src/core/arm/mmu/arm1176jzf_s_mmu.cpp b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp similarity index 99% rename from src/core/arm/mmu/arm1176jzf_s_mmu.cpp rename to src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp index 7e7fbfbfa..a32f076b9 100644 --- a/src/core/arm/mmu/arm1176jzf_s_mmu.cpp +++ b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp @@ -355,7 +355,7 @@ arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) static int debug_count = 0; /* used for debug */ - DEBUG_LOG(ARM11, "va = %x\n", va); + //DEBUG_LOG(ARM11, "va = %x\n", va); va = mmu_pid_va_map (va); if (MMU_Enabled) { @@ -444,7 +444,7 @@ arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, ARMword perm; /* physical addr access permissions */ int ap, sop; - DEBUG_LOG(ARM11, "va = %x\n", va); + //DEBUG_LOG(ARM11, "va = %x\n", va); va = mmu_pid_va_map (va); real_va = va; @@ -629,7 +629,7 @@ arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, } #endif - DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + //DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); va = mmu_pid_va_map (va); real_va = va; diff --git a/src/core/arm/mmu/arm1176jzf_s_mmu.h b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h similarity index 100% rename from src/core/arm/mmu/arm1176jzf_s_mmu.h rename to src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h diff --git a/src/core/arm/interpreter/mmu/cache.cpp b/src/core/arm/interpreter/mmu/cache.cpp new file mode 100644 index 000000000..f3c4e0531 --- /dev/null +++ b/src/core/arm/interpreter/mmu/cache.cpp @@ -0,0 +1,370 @@ +#include "core/arm/interpreter/armdefs.h" + +/* mmu cache init + * + * @cache_t :cache_t to init + * @width :cache line width in byte + * @way :way of each cache set + * @set :cache set num + * + * $ -1: error + * 0: sucess + */ +int +mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode) +{ + int i, j; + cache_set_t *sets; + cache_line_t *lines; + + /*alloc cache set */ + sets = NULL; + lines = NULL; + //fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets); + //exit(-1); + sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set); + if (sets == NULL) { + ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set); + goto sets_error; + } + //fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets); + cache_t->sets = sets; + + /*init cache set */ + for (i = 0; i < set; i++) { + /*alloc cache line */ + lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way); + if (lines == NULL) { + ERROR_LOG(ARM11, "line malloc size %d\n", + sizeof (cache_line_t) * way); + goto lines_error; + } + /*init cache line */ + for (j = 0; j < way; j++) { + lines[j].tag = 0; //invalid + lines[j].data = (ARMword *) malloc (width); + if (lines[j].data == NULL) { + ERROR_LOG(ARM11, "data alloc size %d\n", width); + goto data_error; + } + } + + sets[i].lines = lines; + sets[i].cycle = 0; + + } + cache_t->width = width; + cache_t->set = set; + cache_t->way = way; + cache_t->w_mode = w_mode; + return 0; + + data_error: + /*free data */ + while (j-- > 0) + free (lines[j].data); + /*free data error line */ + free (lines); + lines_error: + /*free lines already alloced */ + while (i-- > 0) { + for (j = 0; j < way; j++) + free (sets[i].lines[j].data); + free (sets[i].lines); + } + /*free sets */ + free (sets); + sets_error: + return -1; +}; + +/* free a cache_t's inner data, the ptr self is not freed, + * when needed do like below: + * mmu_cache_exit(cache); + * free(cache_t); + * + * @cache_t : the cache_t to free + */ + +void +mmu_cache_exit (cache_s * cache_t) +{ + int i, j; + cache_set_t *sets, *set; + cache_line_t *lines, *line; + + /*free all set */ + sets = cache_t->sets; + for (set = sets, i = 0; i < cache_t->set; i++, set++) { + /*free all line */ + lines = set->lines; + for (line = lines, j = 0; j < cache_t->way; j++, line++) + free (line->data); + free (lines); + } + free (sets); +} + +/* mmu cache search + * + * @state :ARMul_State + * @cache_t :cache_t to search + * @va :virtual address + * + * $ NULL: no cache match + * cache :cache matched + */ +cache_line_t * +mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va) +{ + int i; + int set = va_cache_set (va, cache_t); + ARMword tag = va_cache_align (va, cache_t); + cache_line_t *cache; + + cache_set_t *cache_set = cache_t->sets + set; + for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) { + if ((cache->tag & TAG_VALID_FLAG) + && (tag == va_cache_align (cache->tag, cache_t))) + return cache; + } + return NULL; +} + +/* mmu cache search by set/index + * + * @state :ARMul_State + * @cache_t :cache_t to search + * @index :set/index value. + * + * $ NULL: no cache match + * cache :cache matched + */ +cache_line_t * +mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index) +{ + int way = cache_t->way; + int set_v = index_cache_set (index, cache_t); + int i = 0, index_v = 0; + cache_set_t *set; + + while ((way >>= 1) >= 1) + i++; + index_v = index >> (32 - i); + set = cache_t->sets + set_v; + + return set->lines + index_v; +} + + +/* mmu cache alloc + * + * @state :ARMul_State + * @cache_t :cache_t to alloc from + * @va :virtual address that require cache alloc, need not cache aligned + * @pa :physical address of va + * + * $ cache_alloced, always alloc OK + */ +cache_line_t * +mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va, + ARMword pa) +{ + cache_line_t *cache; + cache_set_t *set; + int i; + + va = va_cache_align (va, cache_t); + pa = va_cache_align (pa, cache_t); + + set = &cache_t->sets[va_cache_set (va, cache_t)]; + + /*robin-round */ + cache = &set->lines[set->cycle++]; + if (set->cycle == cache_t->way) + set->cycle = 0; + + if (cache_t->w_mode == CACHE_WRITE_BACK) { + ARMword t; + + /*if cache valid, try to write back */ + if (cache->tag & TAG_VALID_FLAG) { + mmu_cache_write_back (state, cache_t, cache); + } + /*read in cache_line */ + t = pa; + for (i = 0; i < (cache_t->width >> WORD_SHT); + i++, t += WORD_SIZE) { + //cache->data[i] = mem_read_word (state, t); + bus_read(32, t, &cache->data[i]); + } + } + /*store tag and pa */ + cache->tag = va | TAG_VALID_FLAG; + cache->pa = pa; + + return cache; +}; + +/* mmu_cache_write_back write cache data to memory + * @state + * @cache_t :cache_t of the cache line + * @cache : cache line + */ +void +mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, + cache_line_t * cache) +{ + ARMword pa = cache->pa; + int nw = cache_t->width >> WORD_SHT; + ARMword *data = cache->data; + int i; + int t0, t1, t2; + + if ((cache->tag & 1) == 0) + return; + + switch (cache-> + tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) { + case 0: + return; + case TAG_FIRST_HALF_DIRTY: + nw /= 2; + break; + case TAG_LAST_HALF_DIRTY: + nw /= 2; + pa += nw << WORD_SHT; + data += nw; + break; + case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY: + break; + } + for (i = 0; i < nw; i++, data++, pa += WORD_SIZE) + //mem_write_word (state, pa, *data); + bus_write(32, pa, *data); + + cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY); +}; + + +/* mmu_cache_clean: clean a cache of va in cache_t + * + * @state :ARMul_State + * @cache_t :cache_t to clean + * @va :virtaul address + */ +void +mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va) +{ + cache_line_t *cache; + + cache = mmu_cache_search (state, cache_t, va); + if (cache) + mmu_cache_write_back (state, cache_t, cache); +} + +/* mmu_cache_clean_by_index: clean a cache by set/index format value + * + * @state :ARMul_State + * @cache_t :cache_t to clean + * @va :set/index format value + */ +void +mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index) +{ + cache_line_t *cache; + + cache = mmu_cache_search_by_index (state, cache_t, index); + if (cache) + mmu_cache_write_back (state, cache_t, cache); +} + +/* mmu_cache_invalidate : invalidate a cache of va + * + * @state :ARMul_State + * @cache_t :cache_t to invalid + * @va :virt_addr to invalid + */ +void +mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va) +{ + cache_line_t *cache; + + cache = mmu_cache_search (state, cache_t, va); + if (cache) { + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; + } +} + +/* mmu_cache_invalidate_by_index : invalidate a cache by index format + * + * @state :ARMul_State + * @cache_t :cache_t to invalid + * @index :set/index data + */ +void +mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index) +{ + cache_line_t *cache; + + cache = mmu_cache_search_by_index (state, cache_t, index); + if (cache) { + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; + } +} + +/* mmu_cache_invalidate_all + * + * @state: + * @cache_t + * */ +void +mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t) +{ + int i, j; + cache_set_t *set; + cache_line_t *cache; + + set = cache_t->sets; + for (i = 0; i < cache_t->set; i++, set++) { + cache = set->lines; + for (j = 0; j < cache_t->way; j++, cache++) { + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; + } + } +}; + +void +mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa) +{ + ARMword set, way; + cache_line_t *cache; + pa = (pa / cache_t->width); + way = pa & (cache_t->way - 1); + set = (pa / cache_t->way) & (cache_t->set - 1); + cache = &cache_t->sets[set].lines[way]; + + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; +} + +cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){ + int i; + int j; + cache_line_t *cache_line = NULL; + cache_set_t *cache_set = cache->sets; + int sets = cache->set; + for (i = 0; i < sets; i++){ + for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){ + if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY)) + return cache_line; + } + } + return NULL; +} diff --git a/src/core/arm/mmu/cache.h b/src/core/arm/interpreter/mmu/cache.h similarity index 100% rename from src/core/arm/mmu/cache.h rename to src/core/arm/interpreter/mmu/cache.h diff --git a/src/core/arm/interpreter/mmu/maverick.cpp b/src/core/arm/interpreter/mmu/maverick.cpp new file mode 100644 index 000000000..0e98ef22b --- /dev/null +++ b/src/core/arm/interpreter/mmu/maverick.cpp @@ -0,0 +1,1206 @@ +/* maverick.c -- Cirrus/DSP co-processor interface. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Aldy Hernandez (aldyh@redhat.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 + +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/armemu.h" + + +/*#define CIRRUS_DEBUG 1 */ +#if CIRRUS_DEBUG +# define printfdbg printf +#else +# define printfdbg printf_nothing +#endif + +#define POS64(i) ( (~(i)) >> 63 ) +#define NEG64(i) ( (i) >> 63 ) + +/* Define Co-Processor instruction handlers here. */ + +/* Here's ARMulator's DSP definition. A few things to note: + 1) it has 16 64-bit registers and 4 72-bit accumulators + 2) you can only access its registers with MCR and MRC. */ + +/* We can't define these in here because this file might not be linked + unless the target is arm9e-*. They are defined in wrapper.c. + Eventually the simulator should be made to handle any coprocessor + at run time. */ +struct maverick_regs +{ + union + { + int i; + float f; + } upper; + + union + { + int i; + float f; + } lower; +}; + +union maverick_acc_regs +{ + long double ld; /* Acc registers are 72-bits. */ +}; + +struct maverick_regs DSPregs[16]; +union maverick_acc_regs DSPacc[4]; +ARMword DSPsc; + +#define DEST_REG (BITS (12, 15)) +#define SRC1_REG (BITS (16, 19)) +#define SRC2_REG (BITS (0, 3)) + +static int lsw_int_index, msw_int_index; +static int lsw_float_index, msw_float_index; + +static double mv_getRegDouble (int); +static long long mv_getReg64int (int); +static void mv_setRegDouble (int, double val); +static void mv_setReg64int (int, long long val); + +static union +{ + double d; + long long ll; + int ints[2]; +} reg_conv; + +static void +printf_nothing (void *foo, ...) +{ +} + +static void +cirrus_not_implemented (char *insn) +{ + fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn); + fprintf (stderr, "aborting!\n"); + + // skyeye_exit (1); +} + +static unsigned +DSPInit (ARMul_State * state) +{ + NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present"); + return TRUE; +} + +unsigned +DSPMRC4 (ARMul_State * state, + unsigned type, ARMword instr, ARMword * value) +{ + switch (BITS (5, 7)) { + case 0: /* cfmvrdl */ + /* Move lower half of a DF stored in a DSP reg into an Arm reg. */ + printfdbg ("cfmvrdl\n"); + printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i); + printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); + + *value = (ARMword) DSPregs[SRC1_REG].lower.i; + break; + + case 1: /* cfmvrdh */ + /* Move upper half of a DF stored in a DSP reg into an Arm reg. */ + printfdbg ("cfmvrdh\n"); + printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i); + printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); + + *value = (ARMword) DSPregs[SRC1_REG].upper.i; + break; + + case 2: /* cfmvrs */ + /* Move SF from upper half of a DSP register to an Arm register. */ + *value = (ARMword) DSPregs[SRC1_REG].upper.i; + printfdbg ("cfmvrs = mvf%d <-- %f\n", + SRC1_REG, DSPregs[SRC1_REG].upper.f); + break; + +#ifdef doesnt_work + case 4: /* cfcmps */ + { + float a, b; + int n, z, c, v; + + a = DSPregs[SRC1_REG].upper.f; + b = DSPregs[SRC2_REG].upper.f; + + printfdbg ("cfcmps\n"); + printfdbg ("\tcomparing %f and %f\n", a, b); + + z = a == b; /* zero */ + n = a != b; /* negative */ + v = a > b; /* overflow */ + c = 0; /* carry */ + *value = (n << 31) | (z << 30) | (c << 29) | (v << + 28); + break; + } + + case 5: /* cfcmpd */ + { + double a, b; + int n, z, c, v; + + a = mv_getRegDouble (SRC1_REG); + b = mv_getRegDouble (SRC2_REG); + + printfdbg ("cfcmpd\n"); + printfdbg ("\tcomparing %g and %g\n", a, b); + + z = a == b; /* zero */ + n = a != b; /* negative */ + v = a > b; /* overflow */ + c = 0; /* carry */ + *value = (n << 31) | (z << 30) | (c << 29) | (v << + 28); + break; + } +#else + case 4: /* cfcmps */ + { + float a, b; + int n, z, c, v; + + a = DSPregs[SRC1_REG].upper.f; + b = DSPregs[SRC2_REG].upper.f; + + printfdbg ("cfcmps\n"); + printfdbg ("\tcomparing %f and %f\n", a, b); + + z = a == b; /* zero */ + n = a < b; /* negative */ + c = a > b; /* carry */ + v = 0; /* fixme */ + printfdbg ("\tz = %d, n = %d\n", z, n); + *value = (n << 31) | (z << 30) | (c << 29) | (v << + 28); + break; + } + + case 5: /* cfcmpd */ + { + double a, b; + int n, z, c, v; + + a = mv_getRegDouble (SRC1_REG); + b = mv_getRegDouble (SRC2_REG); + + printfdbg ("cfcmpd\n"); + printfdbg ("\tcomparing %g and %g\n", a, b); + + z = a == b; /* zero */ + n = a < b; /* negative */ + c = a > b; /* carry */ + v = 0; /* fixme */ + *value = (n << 31) | (z << 30) | (c << 29) | (v << + 28); + break; + } +#endif + default: + fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMRC5 (ARMul_State * state, + unsigned type, ARMword instr, ARMword * value) +{ + switch (BITS (5, 7)) { + case 0: /* cfmvr64l */ + /* Move lower half of 64bit int from Cirrus to Arm. */ + *value = (ARMword) DSPregs[SRC1_REG].lower.i; + printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n", + DEST_REG, (int) *value); + break; + + case 1: /* cfmvr64h */ + /* Move upper half of 64bit int from Cirrus to Arm. */ + *value = (ARMword) DSPregs[SRC1_REG].upper.i; + printfdbg ("cfmvr64h <-- %d\n", (int) *value); + break; + + case 4: /* cfcmp32 */ + { + int res; + int n, z, c, v; + unsigned int a, b; + + printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG, + SRC2_REG); + + /* FIXME: see comment for cfcmps. */ + a = DSPregs[SRC1_REG].lower.i; + b = DSPregs[SRC2_REG].lower.i; + + res = DSPregs[SRC1_REG].lower.i - + DSPregs[SRC2_REG].lower.i; + /* zero */ + z = res == 0; + /* negative */ + n = res < 0; + /* overflow */ + v = SubOverflow (DSPregs[SRC1_REG].lower.i, + DSPregs[SRC2_REG].lower.i, res); + /* carry */ + c = (NEG (a) && POS (b) || + (NEG (a) && POS (res)) || (POS (b) + && POS (res))); + + *value = (n << 31) | (z << 30) | (c << 29) | (v << + 28); + break; + } + + case 5: /* cfcmp64 */ + { + long long res; + int n, z, c, v; + unsigned long long a, b; + + printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG, + SRC2_REG); + + /* fixme: see comment for cfcmps. */ + + a = mv_getReg64int (SRC1_REG); + b = mv_getReg64int (SRC2_REG); + + res = mv_getReg64int (SRC1_REG) - + mv_getReg64int (SRC2_REG); + /* zero */ + z = res == 0; + /* negative */ + n = res < 0; + /* overflow */ + v = ((NEG64 (a) && POS64 (b) && POS64 (res)) + || (POS64 (a) && NEG64 (b) && NEG64 (res))); + /* carry */ + c = (NEG64 (a) && POS64 (b) || + (NEG64 (a) && POS64 (res)) || (POS64 (b) + && POS64 (res))); + + *value = (n << 31) | (z << 30) | (c << 29) | (v << + 28); + break; + } + + default: + fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMRC6 (ARMul_State * state, + unsigned type, ARMword instr, ARMword * value) +{ + switch (BITS (5, 7)) { + case 0: /* cfmval32 */ + cirrus_not_implemented ("cfmval32"); + break; + + case 1: /* cfmvam32 */ + cirrus_not_implemented ("cfmvam32"); + break; + + case 2: /* cfmvah32 */ + cirrus_not_implemented ("cfmvah32"); + break; + + case 3: /* cfmva32 */ + cirrus_not_implemented ("cfmva32"); + break; + + case 4: /* cfmva64 */ + cirrus_not_implemented ("cfmva64"); + break; + + case 5: /* cfmvsc32 */ + cirrus_not_implemented ("cfmvsc32"); + break; + + default: + fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMCR4 (ARMul_State * state, + unsigned type, ARMword instr, ARMword value) +{ + switch (BITS (5, 7)) { + case 0: /* cfmvdlr */ + /* Move the lower half of a DF value from an Arm register into + the lower half of a Cirrus register. */ + printfdbg ("cfmvdlr <-- 0x%x\n", (int) value); + DSPregs[SRC1_REG].lower.i = (int) value; + break; + + case 1: /* cfmvdhr */ + /* Move the upper half of a DF value from an Arm register into + the upper half of a Cirrus register. */ + printfdbg ("cfmvdhr <-- 0x%x\n", (int) value); + DSPregs[SRC1_REG].upper.i = (int) value; + break; + + case 2: /* cfmvsr */ + /* Move SF from Arm register into upper half of Cirrus register. */ + printfdbg ("cfmvsr <-- 0x%x\n", (int) value); + DSPregs[SRC1_REG].upper.i = (int) value; + break; + + default: + fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMCR5 (ARMul_State * state, + unsigned type, ARMword instr, ARMword value) +{ + union + { + int s; + unsigned int us; + } val; + + switch (BITS (5, 7)) { + case 0: /* cfmv64lr */ + /* Move lower half of a 64bit int from an ARM register into the + lower half of a DSP register and sign extend it. */ + printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, + (int) value); + DSPregs[SRC1_REG].lower.i = (int) value; + break; + + case 1: /* cfmv64hr */ + /* Move upper half of a 64bit int from an ARM register into the + upper half of a DSP register. */ + printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n", + SRC1_REG, (int) value); + DSPregs[SRC1_REG].upper.i = (int) value; + break; + + case 2: /* cfrshl32 */ + printfdbg ("cfrshl32\n"); + val.us = value; + if (val.s > 0) + DSPregs[SRC2_REG].lower.i = + DSPregs[SRC1_REG].lower.i << value; + else + DSPregs[SRC2_REG].lower.i = + DSPregs[SRC1_REG].lower.i >> -value; + break; + + case 3: /* cfrshl64 */ + printfdbg ("cfrshl64\n"); + val.us = value; + if (val.s > 0) + mv_setReg64int (SRC2_REG, + mv_getReg64int (SRC1_REG) << value); + else + mv_setReg64int (SRC2_REG, + mv_getReg64int (SRC1_REG) >> -value); + break; + + default: + fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMCR6 (ARMul_State * state, + unsigned type, ARMword instr, ARMword value) +{ + switch (BITS (5, 7)) { + case 0: /* cfmv32al */ + cirrus_not_implemented ("cfmv32al"); + break; + + case 1: /* cfmv32am */ + cirrus_not_implemented ("cfmv32am"); + break; + + case 2: /* cfmv32ah */ + cirrus_not_implemented ("cfmv32ah"); + break; + + case 3: /* cfmv32a */ + cirrus_not_implemented ("cfmv32a"); + break; + + case 4: /* cfmv64a */ + cirrus_not_implemented ("cfmv64a"); + break; + + case 5: /* cfmv32sc */ + cirrus_not_implemented ("cfmv32sc"); + break; + + default: + fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPLDC4 (ARMul_State * state, + unsigned type, ARMword instr, ARMword data) +{ + static unsigned words; + + if (type != ARMul_DATA) { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) { /* it's a long access, get two words */ + /* cfldrd */ + + printfdbg + ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n", + data, words, state->bigendSig, DEST_REG); + + if (words == 0) { + if (state->bigendSig) + DSPregs[DEST_REG].upper.i = (int) data; + else + DSPregs[DEST_REG].lower.i = (int) data; + } + else { + if (state->bigendSig) + DSPregs[DEST_REG].lower.i = (int) data; + else + DSPregs[DEST_REG].upper.i = (int) data; + } + + ++words; + + if (words == 2) { + printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG, + mv_getRegDouble (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else { + /* Get just one word. */ + + /* cfldrs */ + printfdbg ("cfldrs\n"); + + DSPregs[DEST_REG].upper.i = (int) data; + + printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG, + DSPregs[DEST_REG].upper.f); + + return ARMul_DONE; + } +} + +unsigned +DSPLDC5 (ARMul_State * state, + unsigned type, ARMword instr, ARMword data) +{ + static unsigned words; + + if (type != ARMul_DATA) { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) { + /* It's a long access, get two words. */ + + /* cfldr64 */ + printfdbg ("cfldr64: %d\n", data); + + if (words == 0) { + if (state->bigendSig) + DSPregs[DEST_REG].upper.i = (int) data; + else + DSPregs[DEST_REG].lower.i = (int) data; + } + else { + if (state->bigendSig) + DSPregs[DEST_REG].lower.i = (int) data; + else + DSPregs[DEST_REG].upper.i = (int) data; + } + + ++words; + + if (words == 2) { + printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG, + mv_getReg64int (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else { + /* Get just one word. */ + + /* cfldr32 */ + printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data); + + /* 32bit ints should be sign extended to 64bits when loaded. */ + mv_setReg64int (DEST_REG, (long long) data); + + return ARMul_DONE; + } +} + +unsigned +DSPSTC4 (ARMul_State * state, + unsigned type, ARMword instr, ARMword * data) +{ + static unsigned words; + + if (type != ARMul_DATA) { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) { + /* It's a long access, get two words. */ + /* cfstrd */ + printfdbg ("cfstrd\n"); + + if (words == 0) { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].upper.i; + else + *data = (ARMword) DSPregs[DEST_REG].lower.i; + } + else { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].lower.i; + else + *data = (ARMword) DSPregs[DEST_REG].upper.i; + } + + ++words; + + if (words == 2) { + printfdbg ("\tmem = mvd%d = %g\n", DEST_REG, + mv_getRegDouble (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else { + /* Get just one word. */ + /* cfstrs */ + printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG, + DSPregs[DEST_REG].upper.f); + + *data = (ARMword) DSPregs[DEST_REG].upper.i; + + return ARMul_DONE; + } +} + +unsigned +DSPSTC5 (ARMul_State * state, + unsigned type, ARMword instr, ARMword * data) +{ + static unsigned words; + + if (type != ARMul_DATA) { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) { + /* It's a long access, store two words. */ + /* cfstr64 */ + printfdbg ("cfstr64\n"); + + if (words == 0) { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].upper.i; + else + *data = (ARMword) DSPregs[DEST_REG].lower.i; + } + else { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].lower.i; + else + *data = (ARMword) DSPregs[DEST_REG].upper.i; + } + + ++words; + + if (words == 2) { + printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG, + mv_getReg64int (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else { + /* Store just one word. */ + /* cfstr32 */ + *data = (ARMword) DSPregs[DEST_REG].lower.i; + + printfdbg ("cfstr32 MEM = %d\n", (int) *data); + + return ARMul_DONE; + } +} + +unsigned +DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr) +{ + int opcode2; + + opcode2 = BITS (5, 7); + + switch (BITS (20, 21)) { + case 0: + switch (opcode2) { + case 0: /* cfcpys */ + printfdbg ("cfcpys mvf%d = mvf%d = %f\n", + DEST_REG, SRC1_REG, + DSPregs[SRC1_REG].upper.f); + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f; + break; + + case 1: /* cfcpyd */ + printfdbg ("cfcpyd mvd%d = mvd%d = %g\n", + DEST_REG, SRC1_REG, + mv_getRegDouble (SRC1_REG)); + mv_setRegDouble (DEST_REG, + mv_getRegDouble (SRC1_REG)); + break; + + case 2: /* cfcvtds */ + printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n", + DEST_REG, SRC1_REG, + (float) mv_getRegDouble (SRC1_REG)); + DSPregs[DEST_REG].upper.f = + (float) mv_getRegDouble (SRC1_REG); + break; + + case 3: /* cfcvtsd */ + printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n", + DEST_REG, SRC1_REG, + (double) DSPregs[SRC1_REG].upper.f); + mv_setRegDouble (DEST_REG, + (double) DSPregs[SRC1_REG].upper.f); + break; + + case 4: /* cfcvt32s */ + printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n", + DEST_REG, SRC1_REG, + (float) DSPregs[SRC1_REG].lower.i); + DSPregs[DEST_REG].upper.f = + (float) DSPregs[SRC1_REG].lower.i; + break; + + case 5: /* cfcvt32d */ + printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n", + DEST_REG, SRC1_REG, + (double) DSPregs[SRC1_REG].lower.i); + mv_setRegDouble (DEST_REG, + (double) DSPregs[SRC1_REG].lower.i); + break; + + case 6: /* cfcvt64s */ + printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n", + DEST_REG, SRC1_REG, + (float) mv_getReg64int (SRC1_REG)); + DSPregs[DEST_REG].upper.f = + (float) mv_getReg64int (SRC1_REG); + break; + + case 7: /* cfcvt64d */ + printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n", + DEST_REG, SRC1_REG, + (double) mv_getReg64int (SRC1_REG)); + mv_setRegDouble (DEST_REG, + (double) mv_getReg64int (SRC1_REG)); + break; + } + break; + + case 1: + switch (opcode2) { + case 0: /* cfmuls */ + printfdbg ("cfmuls mvf%d = mvf%d = %f\n", + DEST_REG, + SRC1_REG, + DSPregs[SRC1_REG].upper.f * + DSPregs[SRC2_REG].upper.f); + + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f + * DSPregs[SRC2_REG].upper.f; + break; + + case 1: /* cfmuld */ + printfdbg ("cfmuld mvd%d = mvd%d = %g\n", + DEST_REG, + SRC1_REG, + mv_getRegDouble (SRC1_REG) * + mv_getRegDouble (SRC2_REG)); + + mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) + * mv_getRegDouble (SRC2_REG)); + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", + instr); + cirrus_not_implemented ("unknown"); + break; + } + break; + + case 3: + switch (opcode2) { + case 0: /* cfabss */ + DSPregs[DEST_REG].upper.f = + (DSPregs[SRC1_REG].upper.f < + 0.0F ? -DSPregs[SRC1_REG].upper. + f : DSPregs[SRC1_REG].upper.f); + printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG, + SRC1_REG, DSPregs[DEST_REG].upper.f); + break; + + case 1: /* cfabsd */ + mv_setRegDouble (DEST_REG, + (mv_getRegDouble (SRC1_REG) < 0.0 ? + -mv_getRegDouble (SRC1_REG) + : mv_getRegDouble (SRC1_REG))); + printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n", + DEST_REG, SRC1_REG, + mv_getRegDouble (DEST_REG)); + break; + + case 2: /* cfnegs */ + DSPregs[DEST_REG].upper.f = + -DSPregs[SRC1_REG].upper.f; + printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG, + SRC1_REG, DSPregs[DEST_REG].upper.f); + break; + + case 3: /* cfnegd */ + mv_setRegDouble (DEST_REG, + -mv_getRegDouble (SRC1_REG)); + printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG, + mv_getRegDouble (DEST_REG)); + break; + + case 4: /* cfadds */ + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f + + DSPregs[SRC2_REG].upper.f; + printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].upper.f); + break; + + case 5: /* cfaddd */ + mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) + + mv_getRegDouble (SRC2_REG)); + printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n", + DEST_REG, + SRC1_REG, SRC2_REG, + mv_getRegDouble (DEST_REG)); + break; + + case 6: /* cfsubs */ + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f + - DSPregs[SRC2_REG].upper.f; + printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].upper.f); + break; + + case 7: /* cfsubd */ + mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) + - mv_getRegDouble (SRC2_REG)); + printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n", + DEST_REG, + SRC1_REG, SRC2_REG, + mv_getRegDouble (DEST_REG)); + break; + } + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr) +{ + int opcode2; + char shift; + + opcode2 = BITS (5, 7); + + /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */ + shift = BITS (0, 3) | (BITS (5, 7)) << 4; + if (shift & 0x40) + shift |= 0xc0; + + switch (BITS (20, 21)) { + case 0: + /* cfsh32 */ + printfdbg ("cfsh32 %s amount=%d\n", + shift < 0 ? "right" : "left", shift); + if (shift < 0) + /* Negative shift is a right shift. */ + DSPregs[DEST_REG].lower.i = + DSPregs[SRC1_REG].lower.i >> -shift; + else + /* Positive shift is a left shift. */ + DSPregs[DEST_REG].lower.i = + DSPregs[SRC1_REG].lower.i << shift; + break; + + case 1: + switch (opcode2) { + case 0: /* cfmul32 */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i + * DSPregs[SRC2_REG].lower.i; + printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 1: /* cfmul64 */ + mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) + * mv_getReg64int (SRC2_REG)); + printfdbg + ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n", + DEST_REG, SRC1_REG, SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 2: /* cfmac32 */ + DSPregs[DEST_REG].lower.i + += + DSPregs[SRC1_REG].lower.i * + DSPregs[SRC2_REG].lower.i; + printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 3: /* cfmsc32 */ + DSPregs[DEST_REG].lower.i + -= + DSPregs[SRC1_REG].lower.i * + DSPregs[SRC2_REG].lower.i; + printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 4: /* cfcvts32 */ + /* fixme: this should round */ + DSPregs[DEST_REG].lower.i = + (int) DSPregs[SRC1_REG].upper.f; + printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG, + SRC1_REG, DSPregs[DEST_REG].lower.i); + break; + + case 5: /* cfcvtd32 */ + /* fixme: this should round */ + DSPregs[DEST_REG].lower.i = + (int) mv_getRegDouble (SRC1_REG); + printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG, + SRC1_REG, DSPregs[DEST_REG].lower.i); + break; + + case 6: /* cftruncs32 */ + DSPregs[DEST_REG].lower.i = + (int) DSPregs[SRC1_REG].upper.f; + printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n", + DEST_REG, SRC1_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 7: /* cftruncd32 */ + DSPregs[DEST_REG].lower.i = + (int) mv_getRegDouble (SRC1_REG); + printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n", + DEST_REG, SRC1_REG, + DSPregs[DEST_REG].lower.i); + break; + } + break; + + case 2: + /* cfsh64 */ + printfdbg ("cfsh64\n"); + + if (shift < 0) + /* Negative shift is a right shift. */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) >> -shift); + else + /* Positive shift is a left shift. */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) << shift); + printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG)); + break; + + case 3: + switch (opcode2) { + case 0: /* cfabs32 */ + DSPregs[DEST_REG].lower.i = + (DSPregs[SRC1_REG].lower.i < + 0 ? -DSPregs[SRC1_REG].lower. + i : DSPregs[SRC1_REG].lower.i); + printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 1: /* cfabs64 */ + mv_setReg64int (DEST_REG, + (mv_getReg64int (SRC1_REG) < 0 + ? -mv_getReg64int (SRC1_REG) + : mv_getReg64int (SRC1_REG))); + printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n", + DEST_REG, SRC1_REG, SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 2: /* cfneg32 */ + DSPregs[DEST_REG].lower.i = + -DSPregs[SRC1_REG].lower.i; + printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 3: /* cfneg64 */ + mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG)); + printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n", + DEST_REG, SRC1_REG, SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 4: /* cfadd32 */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i + + DSPregs[SRC2_REG].lower.i; + printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 5: /* cfadd64 */ + mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) + + mv_getReg64int (SRC2_REG)); + printfdbg + ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n", + DEST_REG, SRC1_REG, SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 6: /* cfsub32 */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i + - DSPregs[SRC2_REG].lower.i; + printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 7: /* cfsub64 */ + mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) + - mv_getReg64int (SRC2_REG)); + printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n", + DEST_REG, SRC1_REG, SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + } + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr) +{ + int opcode2; + + opcode2 = BITS (5, 7); + + switch (BITS (20, 21)) { + case 0: + /* cfmadd32 */ + cirrus_not_implemented ("cfmadd32"); + break; + + case 1: + /* cfmsub32 */ + cirrus_not_implemented ("cfmsub32"); + break; + + case 2: + /* cfmadda32 */ + cirrus_not_implemented ("cfmadda32"); + break; + + case 3: + /* cfmsuba32 */ + cirrus_not_implemented ("cfmsuba32"); + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr); + } + + return ARMul_DONE; +} + +/* Conversion functions. + + 32-bit integers are stored in the LOWER half of a 64-bit physical + register. + + Single precision floats are stored in the UPPER half of a 64-bit + physical register. */ + +static double +mv_getRegDouble (int regnum) +{ + reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i; + reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i; + return reg_conv.d; +} + +static void +mv_setRegDouble (int regnum, double val) +{ + reg_conv.d = val; + DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index]; + DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index]; +} + +static long long +mv_getReg64int (int regnum) +{ + reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i; + reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i; + return reg_conv.ll; +} + +static void +mv_setReg64int (int regnum, long long val) +{ + reg_conv.ll = val; + DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index]; + DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index]; +} + +/* Compute LSW in a double and a long long. */ + +void +mv_compute_host_endianness (ARMul_State * state) +{ + static union + { + long long ll; + int ints[2]; + int i; + double d; + float floats[2]; + float f; + } conv; + + /* Calculate where's the LSW in a 64bit int. */ + conv.ll = 45; + + if (conv.ints[0] == 0) { + msw_int_index = 0; + lsw_int_index = 1; + } + else { + assert (conv.ints[1] == 0); + msw_int_index = 1; + lsw_int_index = 0; + } + + /* Calculate where's the LSW in a double. */ + conv.d = 3.0; + + if (conv.ints[0] == 0) { + msw_float_index = 0; + lsw_float_index = 1; + } + else { + assert (conv.ints[1] == 0); + msw_float_index = 1; + lsw_float_index = 0; + } + + printfdbg ("lsw_int_index %d\n", lsw_int_index); + printfdbg ("lsw_float_index %d\n", lsw_float_index); +} diff --git a/src/core/arm/interpreter/mmu/rb.cpp b/src/core/arm/interpreter/mmu/rb.cpp new file mode 100644 index 000000000..07b11e311 --- /dev/null +++ b/src/core/arm/interpreter/mmu/rb.cpp @@ -0,0 +1,126 @@ +#include "core/arm/interpreter/armdefs.h" + +/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/ +ARMword rb_masks[] = { + 0x0, //RB_INVALID + 4, //RB_1 + 16, //RB_4 + 32, //RB_8 +}; + +/*mmu_rb_init + * @rb_t :rb_t to init + * @num :number of entry + * */ +int +mmu_rb_init (rb_s * rb_t, int num) +{ + int i; + rb_entry_t *entrys; + + entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num); + if (entrys == NULL) { + printf ("SKYEYE:mmu_rb_init malloc error\n"); + return -1; + } + for (i = 0; i < num; i++) { + entrys[i].type = RB_INVALID; + entrys[i].fault = NO_FAULT; + } + + rb_t->entrys = entrys; + rb_t->num = num; + return 0; +} + +/*mmu_rb_exit*/ +void +mmu_rb_exit (rb_s * rb_t) +{ + free (rb_t->entrys); +}; + +/*mmu_rb_search + * @rb_t :rb_t to serach + * @va :va address to math + * + * $ NULL :not match + * NO-NULL: + * */ +rb_entry_t * +mmu_rb_search (rb_s * rb_t, ARMword va) +{ + int i; + rb_entry_t *rb = rb_t->entrys; + + DEBUG_LOG(ARM11, "va = %x\n", va); + for (i = 0; i < rb_t->num; i++, rb++) { + //2004-06-06 lyh bug from wenye@cs.ucsb.edu + if (rb->type) { + if ((va >= rb->va) + && (va < (rb->va + rb_masks[rb->type]))) + return rb; + } + } + return NULL; +}; + +void +mmu_rb_invalidate_entry (rb_s * rb_t, int i) +{ + rb_t->entrys[i].type = RB_INVALID; +} + +void +mmu_rb_invalidate_all (rb_s * rb_t) +{ + int i; + + for (i = 0; i < rb_t->num; i++) + mmu_rb_invalidate_entry (rb_t, i); +}; + +void +mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va) +{ + rb_entry_t *rb; + int i; + ARMword max_start, min_end; + fault_t fault; + tlb_entry_t *tlb; + + /*align va according to type */ + va &= ~(rb_masks[type] - 1); + /*invalidate all RB match [va, va + rb_masks[type]] */ + for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) { + if (rb->type) { + max_start = max (va, rb->va); + min_end = + min (va + rb_masks[type], + rb->va + rb_masks[rb->type]); + if (max_start < min_end) + rb->type = RB_INVALID; + } + } + /*load word */ + rb = &rb_t->entrys[i_rb]; + rb->type = type; + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + rb->fault = fault; + return; + } + fault = check_access (state, va, tlb, 1); + if (fault) { + rb->fault = fault; + return; + } + + rb->fault = NO_FAULT; + va = tlb_va_to_pa (tlb, va); + //2004-06-06 lyh bug from wenye@cs.ucsb.edu + for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) { + //rb->data[i] = mem_read_word (state, va); + bus_read(32, va, &rb->data[i]); + }; +} diff --git a/src/core/arm/mmu/rb.h b/src/core/arm/interpreter/mmu/rb.h similarity index 100% rename from src/core/arm/mmu/rb.h rename to src/core/arm/interpreter/mmu/rb.h diff --git a/src/core/arm/interpreter/mmu/sa_mmu.cpp b/src/core/arm/interpreter/mmu/sa_mmu.cpp new file mode 100644 index 000000000..eff5002de --- /dev/null +++ b/src/core/arm/interpreter/mmu/sa_mmu.cpp @@ -0,0 +1,864 @@ +/* + armmmu.c - Memory Management Unit emulation. + ARMulator extensions for the ARM7100 family. + Copyright (C) 1999 Ben Williamson + + 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 +#include + +#include "core/arm/interpreter/armdefs.h" + +/** + * The interface of read data from bus + */ +int bus_read(short size, int addr, uint32_t * value) { + ERROR_LOG(ARM11, "unimplemented bus_read"); + return 0; +} + +/** + * The interface of write data from bus + */ +int bus_write(short size, int addr, uint32_t value) { + ERROR_LOG(ARM11, "unimplemented bus_write"); + return 0; +} + + +typedef struct sa_mmu_desc_s +{ + int i_tlb; + cache_desc_t i_cache; + + int d_tlb; + cache_desc_t main_d_cache; + cache_desc_t mini_d_cache; + int rb; + wb_desc_t wb; +} sa_mmu_desc_t; + +static sa_mmu_desc_t sa11xx_mmu_desc = { + 32, + {32, 32, 16, CACHE_WRITE_BACK}, + + 32, + {32, 32, 8, CACHE_WRITE_BACK}, + {32, 2, 8, CACHE_WRITE_BACK}, + 4, + //{8, 4}, for word size + {8, 16}, //for byte size, chy 2003-07-11 +}; + +static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, + ARMword datatype); +static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, + ARMword datatype); +static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data, + ARMword datatype, cache_line_t * cache, + cache_s * cache_t, ARMword real_va); + +void +mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, + ARMbyte * data, int n); +int +sa_mmu_init (ARMul_State * state) +{ + sa_mmu_desc_t *desc; + cache_desc_t *c_desc; + + state->mmu.control = 0x70; + state->mmu.translation_table_base = 0xDEADC0DE; + state->mmu.domain_access_control = 0xDEADC0DE; + state->mmu.fault_status = 0; + state->mmu.fault_address = 0; + state->mmu.process_id = 0; + + desc = &sa11xx_mmu_desc; + if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { + ERROR_LOG(ARM11, "i_tlb init %d\n", -1); + goto i_tlb_init_error; + } + + c_desc = &desc->i_cache; + if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "i_cache init %d\n", -1); + goto i_cache_init_error; + } + + if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { + ERROR_LOG(ARM11, "d_tlb init %d\n", -1); + goto d_tlb_init_error; + } + + c_desc = &desc->main_d_cache; + if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); + goto main_d_cache_init_error; + } + + c_desc = &desc->mini_d_cache; + if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); + goto mini_d_cache_init_error; + } + + if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { + ERROR_LOG(ARM11, "wb init %d\n", -1); + goto wb_init_error; + } + + if (mmu_rb_init (RB (), desc->rb)) { + ERROR_LOG(ARM11, "rb init %d\n", -1); + goto rb_init_error; + } + return 0; + + rb_init_error: + mmu_wb_exit (WB ()); + wb_init_error: + mmu_cache_exit (MINI_D_CACHE ()); + mini_d_cache_init_error: + mmu_cache_exit (MAIN_D_CACHE ()); + main_d_cache_init_error: + mmu_tlb_exit (D_TLB ()); + d_tlb_init_error: + mmu_cache_exit (I_CACHE ()); + i_cache_init_error: + mmu_tlb_exit (I_TLB ()); + i_tlb_init_error: + return -1; +} + +void +sa_mmu_exit (ARMul_State * state) +{ + mmu_rb_exit (RB ()); + mmu_wb_exit (WB ()); + mmu_cache_exit (MINI_D_CACHE ()); + mmu_cache_exit (MAIN_D_CACHE ()); + mmu_tlb_exit (D_TLB ()); + mmu_cache_exit (I_CACHE ()); + mmu_tlb_exit (I_TLB ()); +}; + + +static fault_t +sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr) +{ + fault_t fault; + tlb_entry_t *tlb; + cache_line_t *cache; + int c; //cache bit + ARMword pa; //physical addr + + static int debug_count = 0; //used for debug + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + if (MMU_Enabled) { + /*align check */ + if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + va &= ~(WORD_SIZE - 1); + + /*translate tlb */ + fault = translate (state, va, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, va, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + + /*search cache no matter MMU enabled/disabled */ + cache = mmu_cache_search (state, I_CACHE (), va); + if (cache) { + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + return NO_FAULT; + } + + /*if MMU disabled or C flag is set alloc cache */ + if (MMU_Disabled) { + c = 1; + pa = va; + } + else { + c = tlb_c_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + } + + if (c) { + int index; + + debug_count++; + cache = mmu_cache_alloc (state, I_CACHE (), va, pa); + index = va_cache_index (va, I_CACHE ()); + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + } + else + //*instr = mem_read_word (state, pa); + bus_read(32, pa, instr); + + return NO_FAULT; +}; + + + +static fault_t +sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); + return fault; +} + +static fault_t +sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); + return fault; +} + +static fault_t +sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); +} + + + + +static fault_t +sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, + ARMword datatype) +{ + fault_t fault; + rb_entry_t *rb; + tlb_entry_t *tlb; + cache_line_t *cache; + ARMword pa, real_va, temp, offset; + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + real_va = va; + /*if MMU disabled, memory_read */ + if (MMU_Disabled) { + //*data = mem_read_word(state, va); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, va); + bus_read(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, va); + bus_read(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, va); + bus_read(32, va, data); + else { + printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + + /*align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } // else + + va &= ~(WORD_SIZE - 1); + + /*translate va to tlb */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*check access permission */ + fault = check_access (state, va, tlb, 1); + if (fault) + return fault; + /*search in read buffer */ + rb = mmu_rb_search (RB (), va); + if (rb) { + if (rb->fault) + return rb->fault; + *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; + goto datatrans; + //return 0; + }; + /*search main cache */ + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; + goto datatrans; + //return 0; + } + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; + goto datatrans; + //return 0; + } + + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, va); + if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { + if (tlb_c_flag (tlb)) { + if (tlb_b_flag (tlb)) { + mmu_cache_soft_flush (state, MAIN_D_CACHE (), + pa); + } + else { + mmu_cache_soft_flush (state, MINI_D_CACHE (), + pa); + } + } + return NO_FAULT; + } + + /*if Buffer, drain Write Buffer first */ + if (tlb_b_flag (tlb)) + mmu_wb_drain_all (state, WB ()); + + /*alloc cache or mem_read */ + if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { + cache_s *cache_t; + + if (tlb_b_flag (tlb)) + cache_t = MAIN_D_CACHE (); + else + cache_t = MINI_D_CACHE (); + cache = mmu_cache_alloc (state, cache_t, va, pa); + *data = cache->data[va_cache_index (va, cache_t)]; + } + else { + //*data = mem_read_word(state, pa); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, pa | (real_va & 3)); + bus_read(8, pa | (real_va & 3), data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, pa | (real_va & 2)); + bus_read(16, pa | (real_va & 2), data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, pa); + bus_read(32, pa, data); + else { + printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + return NO_FAULT; + } + + + datatrans: + if (datatype == ARM_HALFWORD_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + *data = (temp >> offset) & 0xffff; + } + else if (datatype == ARM_BYTE_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + *data = (temp >> offset & 0xffL); + } + end: + return NO_FAULT; +} + + +static fault_t +sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); +} + +static fault_t +sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); +} + +static fault_t +sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); +} + + + +static fault_t +sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype) +{ + tlb_entry_t *tlb; + cache_line_t *cache; + int b; + ARMword pa, real_va; + fault_t fault; + + DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + va = mmu_pid_va_map (va); + real_va = va; + + /*search instruction cache */ + cache = mmu_cache_search (state, I_CACHE (), va); + if (cache) { + update_cache (state, va, data, datatype, cache, I_CACHE (), + real_va); + } + + if (MMU_Disabled) { + //mem_write_word(state, va, data); + if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, va, data); + bus_write(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, va, data); + bus_write(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, va, data); + bus_write(32, va, data); + else { + printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + /*align check */ + //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } //else + va &= ~(WORD_SIZE - 1); + /*tlb translate */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*tlb check access */ + fault = check_access (state, va, tlb, 0); + if (fault) { + DEBUG_LOG(ARM11, "check_access\n"); + return fault; + } + /*search main cache */ + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + update_cache (state, va, data, datatype, cache, + MAIN_D_CACHE (), real_va); + } + else { + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + update_cache (state, va, data, datatype, cache, + MINI_D_CACHE (), real_va); + } + } + + if (!cache) { + b = tlb_b_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + if (b) { + if (MMU_WBEnabled) { + if (datatype == ARM_WORD_TYPE) + mmu_wb_write_bytes (state, WB (), pa, + (ARMbyte*)&data, 4); + else if (datatype == ARM_HALFWORD_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | + (real_va & 2)), + (ARMbyte*)&data, 2); + else if (datatype == ARM_BYTE_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | + (real_va & 3)), + (ARMbyte*)&data, 1); + + } + else { + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + /* + mem_write_halfword (state, + (pa | + (real_va & 2)), + data); + */ + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + /* + mem_write_byte (state, + (pa | (real_va & 3)), + data); + */ + bus_write(8, pa | (real_va & 3), data); + } + } + else { + mmu_wb_drain_all (state, WB ()); + + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + /* + mem_write_halfword (state, + (pa | (real_va & 2)), + data); + */ + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + /* + mem_write_byte (state, (pa | (real_va & 3)), + data); + */ + bus_write(8, pa | (real_va & 3), data); + } + } + return NO_FAULT; +} + +static fault_t +update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype, + cache_line_t * cache, cache_s * cache_t, ARMword real_va) +{ + ARMword temp, offset; + + ARMword index = va_cache_index (va, cache_t); + + //cache->data[index] = data; + + if (datatype == ARM_WORD_TYPE) + cache->data[index] = data; + else if (datatype == ARM_HALFWORD_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << + offset); + } + else if (datatype == ARM_BYTE_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffL << offset)) | ((data & 0xffL) << + offset); + } + + if (index < (cache_t->width >> (WORD_SHT + 1))) + cache->tag |= TAG_FIRST_HALF_DIRTY; + else + cache->tag |= TAG_LAST_HALF_DIRTY; + + return NO_FAULT; +} + +ARMword +sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) +{ + mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); + ARMword data; + + switch (creg) { + case MMU_ID: +// printf("mmu_mrc read ID "); + data = 0x41007100; /* v3 */ + data = state->cpu->cpu_val; + break; + case MMU_CONTROL: +// printf("mmu_mrc read CONTROL"); + data = state->mmu.control; + break; + case MMU_TRANSLATION_TABLE_BASE: +// printf("mmu_mrc read TTB "); + data = state->mmu.translation_table_base; + break; + case MMU_DOMAIN_ACCESS_CONTROL: +// printf("mmu_mrc read DACR "); + data = state->mmu.domain_access_control; + break; + case MMU_FAULT_STATUS: +// printf("mmu_mrc read FSR "); + data = state->mmu.fault_status; + break; + case MMU_FAULT_ADDRESS: +// printf("mmu_mrc read FAR "); + data = state->mmu.fault_address; + break; + case MMU_PID: + data = state->mmu.process_id; + default: + printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); + data = 0; + break; + } +// printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); + *value = data; + return data; +} + +void +sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + if (OPC_2 == 0 && CRm == 7) { + mmu_cache_invalidate_all (state, I_CACHE ()); + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + mmu_cache_invalidate_all (state, MINI_D_CACHE ()); + return; + } + + if (OPC_2 == 0 && CRm == 5) { + mmu_cache_invalidate_all (state, I_CACHE ()); + return; + } + + if (OPC_2 == 0 && CRm == 6) { + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + mmu_cache_invalidate_all (state, MINI_D_CACHE ()); + return; + } + + if (OPC_2 == 1 && CRm == 6) { + mmu_cache_invalidate (state, MAIN_D_CACHE (), value); + mmu_cache_invalidate (state, MINI_D_CACHE (), value); + return; + } + + if (OPC_2 == 1 && CRm == 0xa) { + mmu_cache_clean (state, MAIN_D_CACHE (), value); + mmu_cache_clean (state, MINI_D_CACHE (), value); + return; + } + + if (OPC_2 == 4 && CRm == 0xa) { + mmu_wb_drain_all (state, WB ()); + return; + } + ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); +} + +static void +sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + + if (OPC_2 == 0 && CRm == 0x7) { + mmu_tlb_invalidate_all (state, I_TLB ()); + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 0 && CRm == 0x5) { + mmu_tlb_invalidate_all (state, I_TLB ()); + return; + } + + if (OPC_2 == 0 && CRm == 0x6) { + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 1 && CRm == 0x6) { + mmu_tlb_invalidate_entry (state, D_TLB (), value); + return; + } + + ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); +} + +static void +sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + if (OPC_2 == 0x0 && CRm == 0x0) { + mmu_rb_invalidate_all (RB ()); + return; + } + + if (OPC_2 == 0x2) { + int idx = CRm & 0x3; + int type = ((CRm >> 2) & 0x3) + 1; + + if ((idx < 4) && (type < 4)) + mmu_rb_load (state, RB (), idx, type, value); + return; + } + + if ((OPC_2 == 1) && (CRm < 4)) { + mmu_rb_invalidate_entry (RB (), CRm); + return; + } + + ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); +} + +static ARMword +sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) +{ + mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); + if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) { + switch (creg) { + case MMU_CONTROL: +// printf("mmu_mcr wrote CONTROL "); + state->mmu.control = (value | 0x70) & 0xFFFD; + break; + case MMU_TRANSLATION_TABLE_BASE: +// printf("mmu_mcr wrote TTB "); + state->mmu.translation_table_base = + value & 0xFFFFC000; + break; + case MMU_DOMAIN_ACCESS_CONTROL: +// printf("mmu_mcr wrote DACR "); + state->mmu.domain_access_control = value; + break; + + case MMU_FAULT_STATUS: + state->mmu.fault_status = value & 0xFF; + break; + case MMU_FAULT_ADDRESS: + state->mmu.fault_address = value; + break; + + case MMU_CACHE_OPS: + sa_mmu_cache_ops (state, instr, value); + break; + case MMU_TLB_OPS: + sa_mmu_tlb_ops (state, instr, value); + break; + case MMU_SA_RB_OPS: + sa_mmu_rb_ops (state, instr, value); + break; + case MMU_SA_DEBUG: + break; + case MMU_SA_CP15_R15: + break; + case MMU_PID: + //2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu + state->mmu.process_id = value & 0x7e000000; + break; + + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + break; + } + } + return 0; +} + +//teawater add for arm2x86 2005.06.24------------------------------------------- +static int +sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) +{ + fault_t fault; + tlb_entry_t *tlb; + + virt_addr = mmu_pid_va_map (virt_addr); + if (MMU_Enabled) { + + /*align check */ + if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + virt_addr &= ~(WORD_SIZE - 1); + + /*translate tlb */ + fault = translate (state, virt_addr, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, virt_addr, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + + if (MMU_Disabled) { + *phys_addr = virt_addr; + } + else { + *phys_addr = tlb_va_to_pa (tlb, virt_addr); + } + + return (0); +} + +//AJ2D-------------------------------------------------------------------------- + +/*sa mmu_ops_t*/ +mmu_ops_t sa_mmu_ops = { + sa_mmu_init, + sa_mmu_exit, + sa_mmu_read_byte, + sa_mmu_write_byte, + sa_mmu_read_halfword, + sa_mmu_write_halfword, + sa_mmu_read_word, + sa_mmu_write_word, + sa_mmu_load_instr, + sa_mmu_mcr, + sa_mmu_mrc, +//teawater add for arm2x86 2005.06.24------------------------------------------- + sa_mmu_v2p_dbct, +//AJ2D-------------------------------------------------------------------------- +}; diff --git a/src/core/arm/interpreter/mmu/sa_mmu.h b/src/core/arm/interpreter/mmu/sa_mmu.h new file mode 100644 index 000000000..64b1c5470 --- /dev/null +++ b/src/core/arm/interpreter/mmu/sa_mmu.h @@ -0,0 +1,58 @@ +/* + sa_mmu.h - StrongARM Memory Management Unit emulation. + ARMulator extensions for SkyEye. + + + 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 +*/ + +#ifndef _SA_MMU_H_ +#define _SA_MMU_H_ + + +/** + * The interface of read data from bus + */ +int bus_read(short size, int addr, uint32_t * value); + +/** + * The interface of write data from bus + */ +int bus_write(short size, int addr, uint32_t value); + + +typedef struct sa_mmu_s +{ + tlb_s i_tlb; + cache_s i_cache; + + tlb_s d_tlb; + cache_s main_d_cache; + cache_s mini_d_cache; + rb_s rb_t; + wb_s wb_t; +} sa_mmu_t; + +#define I_TLB() (&state->mmu.u.sa_mmu.i_tlb) +#define I_CACHE() (&state->mmu.u.sa_mmu.i_cache) + +#define D_TLB() (&state->mmu.u.sa_mmu.d_tlb) +#define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache) +#define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache) +#define WB() (&state->mmu.u.sa_mmu.wb_t) +#define RB() (&state->mmu.u.sa_mmu.rb_t) + +extern mmu_ops_t sa_mmu_ops; +#endif /*_SA_MMU_H_*/ diff --git a/src/core/arm/interpreter/mmu/tlb.cpp b/src/core/arm/interpreter/mmu/tlb.cpp new file mode 100644 index 000000000..ca60ac1a1 --- /dev/null +++ b/src/core/arm/interpreter/mmu/tlb.cpp @@ -0,0 +1,307 @@ +#include + +#include "core/arm/interpreter/armdefs.h" + +ARMword tlb_masks[] = { + 0x00000000, /* TLB_INVALID */ + 0xFFFFF000, /* TLB_SMALLPAGE */ + 0xFFFF0000, /* TLB_LARGEPAGE */ + 0xFFF00000, /* TLB_SECTION */ + 0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */ + 0xFFFFFC00 /* TLB_TINYPAGE */ +}; + +/* This function encodes table 8-2 Interpreting AP bits, + returning non-zero if access is allowed. */ +static int +check_perms (ARMul_State * state, int ap, int read) +{ + int s, r, user; + + s = state->mmu.control & CONTROL_SYSTEM; + r = state->mmu.control & CONTROL_ROM; + //chy 2006-02-15 , should consider system mode, don't conside 26bit mode + user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); + + switch (ap) { + case 0: + return read && ((s && !user) || r); + case 1: + return !user; + case 2: + return read || !user; + case 3: + return 1; + } + return 0; +} + +fault_t +check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, + int read) +{ + int access; + + state->mmu.last_domain = tlb->domain; + access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; + if ((access == 0) || (access == 2)) { + /* It's unclear from the documentation whether this + should always raise a section domain fault, or if + it should be a page domain fault in the case of an + L1 that describes a page table. In the ARM710T + datasheets, "Figure 8-9: Sequence for checking faults" + seems to indicate the former, while "Table 8-4: Priority + encoding of fault status" gives a value for FS[3210] in + the event of a domain fault for a page. Hmm. */ + return SECTION_DOMAIN_FAULT; + } + if (access == 1) { + /* client access - check perms */ + int subpage, ap; + + switch (tlb->mapping) { + /*ks 2004-05-09 + * only for XScale + * Extend Small Page(ESP) Format + * 31-12 bits the base addr of ESP + * 11-10 bits SBZ + * 9-6 bits TEX + * 5-4 bits AP + * 3 bit C + * 2 bit B + * 1-0 bits 11 + * */ + case TLB_ESMALLPAGE: //xj + subpage = 0; + //printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); + break; + + case TLB_TINYPAGE: + subpage = 0; + //printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); + break; + + case TLB_SMALLPAGE: + subpage = (virt_addr >> 10) & 3; + break; + case TLB_LARGEPAGE: + subpage = (virt_addr >> 14) & 3; + break; + case TLB_SECTION: + subpage = 3; + break; + default: + assert (0); + subpage = 0; /* cleans a warning */ + } + ap = (tlb->perms >> (subpage * 2 + 4)) & 3; + if (!check_perms (state, ap, read)) { + if (tlb->mapping == TLB_SECTION) { + return SECTION_PERMISSION_FAULT; + } + else { + return SUBPAGE_PERMISSION_FAULT; + } + } + } + else { /* access == 3 */ + /* manager access - don't check perms */ + } + return NO_FAULT; +} + +fault_t +translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, + tlb_entry_t ** tlb) +{ + *tlb = mmu_tlb_search (state, tlb_t, virt_addr); + if (!*tlb) { + /* walk the translation tables */ + ARMword l1addr, l1desc; + tlb_entry_t entry; + + l1addr = state->mmu.translation_table_base & 0xFFFFC000; + l1addr = (l1addr | (virt_addr >> 18)) & ~3; + //l1desc = mem_read_word (state, l1addr); + bus_read(32, l1addr, &l1desc); + switch (l1desc & 3) { + case 0: + /* + * according to Figure 3-9 Sequence for checking faults in arm manual, + * section translation fault should be returned here. + */ + { + return SECTION_TRANSLATION_FAULT; + } + case 3: + /* fine page table */ + // dcl 2006-01-08 + { + ARMword l2addr, l2desc; + + l2addr = l1desc & 0xFFFFF000; + l2addr = (l2addr | + ((virt_addr & 0x000FFC00) >> 8)) & + ~3; + //l2desc = mem_read_word (state, l2addr); + bus_read(32, l2addr, &l2desc); + + entry.virt_addr = virt_addr; + entry.phys_addr = l2desc; + entry.perms = l2desc & 0x00000FFC; + entry.domain = (l1desc >> 5) & 0x0000000F; + switch (l2desc & 3) { + case 0: + state->mmu.last_domain = entry.domain; + return PAGE_TRANSLATION_FAULT; + case 3: + entry.mapping = TLB_TINYPAGE; + break; + case 1: + // this is untested + entry.mapping = TLB_LARGEPAGE; + break; + case 2: + // this is untested + entry.mapping = TLB_SMALLPAGE; + break; + } + } + break; + case 1: + /* coarse page table */ + { + ARMword l2addr, l2desc; + + l2addr = l1desc & 0xFFFFFC00; + l2addr = (l2addr | + ((virt_addr & 0x000FF000) >> 10)) & + ~3; + //l2desc = mem_read_word (state, l2addr); + bus_read(32, l2addr, &l2desc); + + entry.virt_addr = virt_addr; + entry.phys_addr = l2desc; + entry.perms = l2desc & 0x00000FFC; + entry.domain = (l1desc >> 5) & 0x0000000F; + //printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr); + //chy 2003-09-02 for xscale + switch (l2desc & 3) { + case 0: + state->mmu.last_domain = entry.domain; + return PAGE_TRANSLATION_FAULT; + case 3: + if (!state->is_XScale) { + state->mmu.last_domain = + entry.domain; + return PAGE_TRANSLATION_FAULT; + }; + //ks 2004-05-09 xscale shold use Extend Small Page + //entry.mapping = TLB_SMALLPAGE; + entry.mapping = TLB_ESMALLPAGE; //xj + break; + case 1: + entry.mapping = TLB_LARGEPAGE; + break; + case 2: + entry.mapping = TLB_SMALLPAGE; + break; + } + } + break; + case 2: + /* section */ + //printf("SKYEYE:WARNING: not implement section mapping incompletely\n"); + //printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc); + //return SECTION_DOMAIN_FAULT; + //#if 0 + entry.virt_addr = virt_addr; + entry.phys_addr = l1desc; + entry.perms = l1desc & 0x00000C0C; + entry.domain = (l1desc >> 5) & 0x0000000F; + entry.mapping = TLB_SECTION; + break; + //#endif + } + entry.virt_addr &= tlb_masks[entry.mapping]; + entry.phys_addr &= tlb_masks[entry.mapping]; + + /* place entry in the tlb */ + *tlb = &tlb_t->entrys[tlb_t->cycle]; + tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num; + **tlb = entry; + } + state->mmu.last_domain = (*tlb)->domain; + return NO_FAULT; +} + +int +mmu_tlb_init (tlb_s * tlb_t, int num) +{ + tlb_entry_t *e; + int i; + + e = (tlb_entry_t *) malloc (sizeof (*e) * num); + if (e == NULL) { + ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num); + goto tlb_malloc_error; + } + tlb_t->entrys = e; + for (i = 0; i < num; i++, e++) + e->mapping = TLB_INVALID; + tlb_t->cycle = 0; + tlb_t->num = num; + return 0; + + tlb_malloc_error: + return -1; +} + +void +mmu_tlb_exit (tlb_s * tlb_t) +{ + free (tlb_t->entrys); +}; + +void +mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t) +{ + int entry; + + for (entry = 0; entry < tlb_t->num; entry++) { + tlb_t->entrys[entry].mapping = TLB_INVALID; + } + tlb_t->cycle = 0; +} + +void +mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr) +{ + tlb_entry_t *tlb; + + tlb = mmu_tlb_search (state, tlb_t, addr); + if (tlb) { + tlb->mapping = TLB_INVALID; + } +} + +tlb_entry_t * +mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr) +{ + int entry; + + for (entry = 0; entry < tlb_t->num; entry++) { + tlb_entry_t *tlb; + ARMword mask; + + tlb = &(tlb_t->entrys[entry]); + if (tlb->mapping == TLB_INVALID) { + continue; + } + mask = tlb_masks[tlb->mapping]; + if ((virt_addr & mask) == (tlb->virt_addr & mask)) { + return tlb; + } + } + return NULL; +} diff --git a/src/core/arm/mmu/tlb.h b/src/core/arm/interpreter/mmu/tlb.h similarity index 93% rename from src/core/arm/mmu/tlb.h rename to src/core/arm/interpreter/mmu/tlb.h index 938c01786..40856567b 100644 --- a/src/core/arm/mmu/tlb.h +++ b/src/core/arm/interpreter/mmu/tlb.h @@ -63,14 +63,7 @@ typedef struct tlb_s #define tlb_b_flag(tlb) \ ((tlb)->perms & 0x4) -#define tlb_va_to_pa(tlb, va) \ -(\ - {\ - ARMword mask = tlb_masks[tlb->mapping]; \ - (tlb->phys_addr & mask) | (va & ~mask);\ - }\ -) - +#define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping])) fault_t check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, int read); diff --git a/src/core/arm/interpreter/mmu/wb.cpp b/src/core/arm/interpreter/mmu/wb.cpp new file mode 100644 index 000000000..82c0cec02 --- /dev/null +++ b/src/core/arm/interpreter/mmu/wb.cpp @@ -0,0 +1,149 @@ +#include "core/arm/interpreter/armdefs.h" + +/* wb_init + * @wb_t :wb_t to init + * @num :num of entrys + * @nb :num of byte of each entry + * + * $ -1:error + * 0:ok + * */ +int +mmu_wb_init (wb_s * wb_t, int num, int nb) +{ + int i; + wb_entry_t *entrys, *wb; + + entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num); + if (entrys == NULL) { + ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num); + goto entrys_malloc_error; + } + + for (wb = entrys, i = 0; i < num; i++, wb++) { + /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */ + //wb->data = (ARMword *)malloc(sizeof(ARMword) * nb); + wb->data = (ARMbyte *) malloc (nb); + if (wb->data == NULL) { + ERROR_LOG(ARM11, "malloc size of %d\n", nb); + goto data_malloc_error; + } + + }; + + wb_t->first = wb_t->last = wb_t->used = 0; + wb_t->num = num; + wb_t->nb = nb; + wb_t->entrys = entrys; + return 0; + + data_malloc_error: + while (--i >= 0) + free (entrys[i].data); + free (entrys); + entrys_malloc_error: + return -1; +}; + +/* wb_exit + * @wb_t :wb_t to exit + * */ +void +mmu_wb_exit (wb_s * wb_t) +{ + int i; + wb_entry_t *wb; + + wb = wb_t->entrys; + for (i = 0; i < wb_t->num; i++, wb++) { + free (wb->data); + } + free (wb_t->entrys); +}; + +/* wb_write_words :put words in Write Buffer + * @state: ARMul_State + * @wb_t: write buffer + * @pa: physical address + * @data: data ptr + * @n number of word to write + * + * Note: write buffer merge is not implemented, can be done late + * */ +void +mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, + ARMbyte * data, int n) +{ + int i; + wb_entry_t *wb; + + while (n) { + if (wb_t->num == wb_t->used) { + /*clean the last wb entry */ + ARMword t; + + wb = &wb_t->entrys[wb_t->last]; + t = wb->pa; + for (i = 0; i < wb->nb; i++) { + //mem_write_byte (state, t, wb->data[i]); + bus_write(8, t, wb->data[i]); + //t += WORD_SIZE; + t++; + } + wb_t->last++; + if (wb_t->last == wb_t->num) + wb_t->last = 0; + wb_t->used--; + } + + wb = &wb_t->entrys[wb_t->first]; + i = (n < wb_t->nb) ? n : wb_t->nb; + + wb->pa = pa; + //pa += i << WORD_SHT; + pa += i; + + wb->nb = i; + //memcpy(wb->data, data, i << WORD_SHT); + memcpy (wb->data, data, i); + data += i; + n -= i; + wb_t->first++; + if (wb_t->first == wb_t->num) + wb_t->first = 0; + wb_t->used++; + }; +//teawater add for set_dirty fflash cache function 2005.07.18------------------- +#ifdef DBCT + if (!skyeye_config.no_dbct) { + tb_setdirty (state, pa, NULL); + } +#endif +//AJ2D-------------------------------------------------------------------------- +} + +/* wb_drain_all + * @wb_t wb_t to drain + * */ +void +mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t) +{ + ARMword pa; + wb_entry_t *wb; + int i; + + while (wb_t->used) { + wb = &wb_t->entrys[wb_t->last]; + pa = wb->pa; + for (i = 0; i < wb->nb; i++) { + //mem_write_byte (state, pa, wb->data[i]); + bus_write(8, pa, wb->data[i]); + //pa += WORD_SIZE; + pa++; + } + wb_t->last++; + if (wb_t->last == wb_t->num) + wb_t->last = 0; + wb_t->used--; + }; +} diff --git a/src/core/arm/mmu/wb.h b/src/core/arm/interpreter/mmu/wb.h similarity index 100% rename from src/core/arm/mmu/wb.h rename to src/core/arm/interpreter/mmu/wb.h diff --git a/src/core/arm/interpreter/mmu/xscale_copro.cpp b/src/core/arm/interpreter/mmu/xscale_copro.cpp new file mode 100644 index 000000000..433ce8e02 --- /dev/null +++ b/src/core/arm/interpreter/mmu/xscale_copro.cpp @@ -0,0 +1,1391 @@ +/* + armmmu.c - Memory Management Unit emulation. + ARMulator extensions for the ARM7100 family. + Copyright (C) 1999 Ben Williamson + + 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 +#include + +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/armemu.h" + +/*#include "pxa.h" */ + +/* chy 2005-09-19 */ + +/* extern pxa270_io_t pxa270_io; */ +/* chy 2005-09-19 -----end */ + +typedef struct xscale_mmu_desc_s +{ + int i_tlb; + cache_desc_t i_cache; + + int d_tlb; + cache_desc_t main_d_cache; + cache_desc_t mini_d_cache; + //int rb; xscale has no read buffer + wb_desc_t wb; +} xscale_mmu_desc_t; + +static xscale_mmu_desc_t pxa_mmu_desc = { + 32, + {32, 32, 32, CACHE_WRITE_BACK}, + + 32, + {32, 32, 32, CACHE_WRITE_BACK}, + {32, 2, 8, CACHE_WRITE_BACK}, + {8, 16}, //for byte size, +}; + +//chy 2005-09-19 for cp6 +#define CR0_ICIP 0 +#define CR1_ICMR 1 +//chy 2005-09-19 ---end +//----------- for cp14----------------- +#define CCLKCFG 6 +#define PWRMODE 7 +typedef struct xscale_cp14_reg_s +{ + unsigned cclkcfg; //reg6 + unsigned pwrmode; //reg7 +} xscale_cp14_reg_s; + +xscale_cp14_reg_s pxa_cp14_regs; + +//-------------------------------------- + +static fault_t xscale_mmu_write (ARMul_State * state, ARMword va, + ARMword data, ARMword datatype); +static fault_t xscale_mmu_read (ARMul_State * state, ARMword va, + ARMword * data, ARMword datatype); + +ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); +ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); + + +/* jeff add 2010.9.26 for pxa270 cp6*/ +#define PXA270_ICMR 0x40D00004 +#define PXA270_ICPR 0x40D00010 +#define PXA270_ICLR 0x40D00008 +//chy 2005-09-19 for xscale pxa27x cp6 +unsigned +xscale_cp6_mrc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + + //printf("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,state->Reg[15], instr); + + switch (reg) { + case CR0_ICIP: { // cp 6 reg 0 + //printf("cp6_mrc cr0 ICIP \n"); + /* *data = (pxa270_io.icmr & pxa270_io.icpr) & ~pxa270_io.iclr; */ + /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ + int icmr, icpr, iclr; + bus_read(32, PXA270_ICMR, (uint32_t*)&icmr); + bus_read(32, PXA270_ICPR, (uint32_t*)&icpr); + bus_read(32, PXA270_ICLR, (uint32_t*)&iclr); + *data = (icmr & icpr) & ~iclr; + } + break; + case CR1_ICMR: { // cp 6 reg 1 + //printf("cp6_mrc cr1 ICMR\n"); + /* *data = pxa270_io.icmr; */ + int icmr; + /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ + bus_read(32, PXA270_ICMR, (uint32_t*)&icmr); + *data = icmr; + } + break; + default: + *data = 0; + printf ("SKYEYE:cp6_mrc unknown cp6 regs!!!!!!\n"); + printf ("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n", opcode_2, CRm, reg, state->Reg[15], instr); + break; + } + return 0; +} + +//chy 2005-09-19 end +//xscale cp13 ---------------------------------------------------- +unsigned +xscale_cp13_init (ARMul_State * state) +{ + //printf("SKYEYE: xscale_cp13_init: begin\n"); + return 0; +} + +unsigned +xscale_cp13_exit (ARMul_State * state) +{ + //printf("SKYEYE: xscale_cp13_exit: begin\n"); + return 0; +} + +unsigned +xscale_cp13_ldc (ARMul_State * state, unsigned type, ARMword instr, + ARMword data) +{ + printf ("SKYEYE: xscale_cp13_ldc: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp13_stc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + printf ("SKYEYE: xscale_cp13_stc: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp13_mrc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + printf ("SKYEYE: xscale_cp13_mrc: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp13_mcr (ARMul_State * state, unsigned type, ARMword instr, + ARMword data) +{ + printf ("SKYEYE: xscale_cp13_mcr: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp13_cdp (ARMul_State * state, unsigned type, ARMword instr) +{ + printf ("SKYEYE: xscale_cp13_cdp: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp13_read_reg (ARMul_State * state, unsigned reg, ARMword * data) +{ + printf ("SKYEYE: xscale_cp13_read_reg: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + return 0; + //exit(-1); +} + +unsigned +xscale_cp13_write_reg (ARMul_State * state, unsigned reg, ARMword data) +{ + printf ("SKYEYE: xscale_cp13_write_reg: ERROR isn't existed,"); + SKYEYE_OUTREGS (stderr); + fprintf (stderr, "\n"); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +//------------------------------------------------------------------ +//xscale cp14 ---------------------------------------------------- +unsigned +xscale_cp14_init (ARMul_State * state) +{ + //printf("SKYEYE: xscale_cp14_init: begin\n"); + pxa_cp14_regs.cclkcfg = 0; + pxa_cp14_regs.pwrmode = 0; + return 0; +} + +unsigned +xscale_cp14_exit (ARMul_State * state) +{ + //printf("SKYEYE: xscale_cp14_exit: begin\n"); + return 0; +} + +unsigned +xscale_cp14_ldc (ARMul_State * state, unsigned type, ARMword instr, + ARMword data) +{ + printf ("SKYEYE: xscale_cp14_ldc: ERROR isn't existed, reg15 0x%x\n", + state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp14_stc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + printf ("SKYEYE: xscale_cp14_stc: ERROR isn't existed, reg15 0x%x\n", + state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} + +unsigned +xscale_cp14_mrc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + + //printf("SKYEYE: xscale_cp14_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ + state->Reg[15], instr); + + switch (reg) { + case CCLKCFG: // cp 14 reg 6 + //printf("cp14_mrc cclkcfg \n"); + *data = pxa_cp14_regs.cclkcfg; + break; + case PWRMODE: // cp 14 reg 7 + //printf("cp14_mrc pwrmode \n"); + *data = pxa_cp14_regs.pwrmode; + break; + default: + *data = 0; + printf ("SKYEYE:cp14_mrc unknown cp14 regs!!!!!!\n"); + break; + } + return 0; +} +unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, ARMword instr, + ARMword data) +{ + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + + //printf("SKYEYE: xscale_cp14_mcr:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ + state->Reg[15], instr); + + switch (reg) { + case CCLKCFG: // cp 14 reg 6 + //printf("cp14_mcr cclkcfg \n"); + pxa_cp14_regs.cclkcfg = data & 0xf; + break; + case PWRMODE: // cp 14 reg 7 + //printf("cp14_mcr pwrmode \n"); + pxa_cp14_regs.pwrmode = data & 0x3; + break; + default:printf ("SKYEYE: cp14_mcr unknown cp14 regs!!!!!!\n"); + break; + } + return 0; +} +unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, ARMword instr) +{ + printf ("SKYEYE: xscale_cp14_cdp: ERROR isn't existed, reg15 0x%x\n", + state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, + ARMword * data) +{ + printf ("SKYEYE: xscale_cp14_read_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, + ARMword data) +{ + printf ("SKYEYE: xscale_cp14_write_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} + +//------------------------------------------------------------------ +//cp15 ------------------------------------- +unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, ARMword instr, + ARMword data) +{ + printf ("SKYEYE: xscale_cp15_ldc: ERROR isn't existed\n"); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + printf ("SKYEYE: xscale_cp15_stc: ERROR isn't existed\n"); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, ARMword instr) +{ + printf ("SKYEYE: xscale_cp15_cdp: ERROR isn't existed\n"); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, + ARMword * data) +{ +//chy 2003-09-03: for xsacle_cp15_cp_access_allowed + if (reg == 15) { + *data = state->mmu.copro_access; + //printf("SKYEYE: xscale_cp15_read_reg: reg 0x%x,data %x\n",reg,*data); + return 0; + } + printf ("SKYEYE: xscale_cp15_read_reg: reg 0x%x, ERROR isn't existed\n", reg); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} + +//chy 2003-09-03 used by macro CP_ACCESS_ALLOWED in armemu.h +unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, + unsigned cpnum) +{ + unsigned data; + + xscale_cp15_read_reg (state, reg, &data); + //printf("SKYEYE: cp15_cp_access_allowed data %x, cpnum %x, result %x\n", data, cpnum, (data & 1<mmu.fault_status = value & 0x6FF; + break; + case MMU_FAULT_ADDRESS: + //printf("SKYEYE:cp15_write_reg wrote FA val 0x%x \n",value); + state->mmu.fault_address = value; + break; + default: + printf ("SKYEYE: xscale_cp15_write_reg: reg 0x%x R15 %x ERROR isn't existed\n", reg, state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + } + return 0; +} + +unsigned +xscale_cp15_init (ARMul_State * state) +{ + xscale_mmu_desc_t *desc; + cache_desc_t *c_desc; + + state->mmu.control = 0; + state->mmu.translation_table_base = 0xDEADC0DE; + state->mmu.domain_access_control = 0xDEADC0DE; + state->mmu.fault_status = 0; + state->mmu.fault_address = 0; + state->mmu.process_id = 0; + state->mmu.cache_type = 0xB1AA1AA; //0000 1011 0001 1010 1010 0001 1010 1010 + state->mmu.aux_control = 0; + + desc = &pxa_mmu_desc; + + if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { + ERROR_LOG(ARM11, "i_tlb init %d\n", -1); + goto i_tlb_init_error; + } + + c_desc = &desc->i_cache; + if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "i_cache init %d\n", -1); + goto i_cache_init_error; + } + + if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { + ERROR_LOG(ARM11, "d_tlb init %d\n", -1); + goto d_tlb_init_error; + } + + c_desc = &desc->main_d_cache; + if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); + goto main_d_cache_init_error; + } + + c_desc = &desc->mini_d_cache; + if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); + goto mini_d_cache_init_error; + } + + if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { + ERROR_LOG(ARM11, "wb init %d\n", -1); + goto wb_init_error; + } +#if 0 + if (mmu_rb_init (RB (), desc->rb)) { + ERROR_LOG(ARM11, "rb init %d\n", -1); + goto rb_init_error; + } +#endif + + return 0; +#if 0 + rb_init_error: + mmu_wb_exit (WB ()); +#endif + wb_init_error: + mmu_cache_exit (MINI_D_CACHE ()); + mini_d_cache_init_error: + mmu_cache_exit (MAIN_D_CACHE ()); + main_d_cache_init_error: + mmu_tlb_exit (D_TLB ()); + d_tlb_init_error: + mmu_cache_exit (I_CACHE ()); + i_cache_init_error: + mmu_tlb_exit (I_TLB ()); + i_tlb_init_error: + return -1; +} + +unsigned +xscale_cp15_exit (ARMul_State * state) +{ + //mmu_rb_exit(RB()); + mmu_wb_exit (WB ()); + mmu_cache_exit (MINI_D_CACHE ()); + mmu_cache_exit (MAIN_D_CACHE ()); + mmu_tlb_exit (D_TLB ()); + mmu_cache_exit (I_CACHE ()); + mmu_tlb_exit (I_TLB ()); + return 0; +}; + + +static fault_t + xscale_mmu_load_instr (ARMul_State * state, ARMword va, + ARMword * instr) +{ + fault_t fault; + tlb_entry_t *tlb; + cache_line_t *cache; + int c; //cache bit + ARMword pa; //physical addr + + static int debug_count = 0; //used for debug + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + if (MMU_Enabled) { + /*align check */ + if ((va & (INSN_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + va &= ~(INSN_SIZE - 1); + + /*translate tlb */ + fault = translate (state, va, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, va, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + //chy 2003-09-02 for test, don't use cache ????? +#if 0 + /*search cache no matter MMU enabled/disabled */ + cache = mmu_cache_search (state, I_CACHE (), va); + if (cache) { + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + return 0; + } +#endif + /*if MMU disabled or C flag is set alloc cache */ + if (MMU_Disabled) { + c = 1; + pa = va; + } + else { + c = tlb_c_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + } + + //chy 2003-09-03 only read mem, don't use cache now,will change later ???? + //*instr = mem_read_word (state, pa); + bus_read(32, pa, instr); +#if 0 +//----------------------------------------------------------- + //chy 2003-09-02 for test???? + if (pa >= 0xa01c8000 && pa <= 0xa01c8020) { + printf ("SKYEYE:load_instr: pa %x, va %x,instr %x, R15 %x\n", + pa, va, *instr, state->Reg[15]); + } + +//---------------------------------------------------------------------- +#endif + return NO_FAULT; + + if (c) { + int index; + + debug_count++; + cache = mmu_cache_alloc (state, I_CACHE (), va, pa); + index = va_cache_index (va, I_CACHE ()); + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + } + else + //*instr = mem_read_word (state, pa); + bus_read(32, pa, instr); + + return NO_FAULT; +}; + + + +static fault_t + xscale_mmu_read_byte (ARMul_State * state, ARMword virt_addr, + ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = xscale_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); + return fault; +} + +static fault_t + xscale_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, + ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = xscale_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); + return fault; +} + +static fault_t + xscale_mmu_read_word (ARMul_State * state, ARMword virt_addr, + ARMword * data) +{ + return xscale_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); +} + + + + +static fault_t + xscale_mmu_read (ARMul_State * state, ARMword va, ARMword * data, + ARMword datatype) +{ + fault_t fault; +// rb_entry_t *rb; + tlb_entry_t *tlb; + cache_line_t *cache; + ARMword pa, real_va, temp, offset; + //chy 2003-09-02 for test ???? + static unsigned chyst1 = 0, chyst2 = 0; + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + real_va = va; + /*if MMU disabled, memory_read */ + if (MMU_Disabled) { + //*data = mem_read_word(state, va); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, va); + bus_read(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, va); + bus_read(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, va); + bus_read(32, va, data); + else { + printf ("SKYEYE:1 xscale_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + + /*align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } // else + + va &= ~(WORD_SIZE - 1); + + /*translate va to tlb */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*check access permission */ + fault = check_access (state, va, tlb, 1); + if (fault) + return fault; + +#if 0 +//------------------------------------------------ +//chy 2003-09-02 for test only ,should commit ???? + if (datatype == ARM_WORD_TYPE) { + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + pa = tlb_va_to_pa (tlb, va); + *data = mem_read_word (state, pa); + chyst1++; + printf ("**SKYEYE:mmu_read word %d: pa %x, va %x, data %x, R15 %x\n", chyst1, pa, real_va, *data, state->Reg[15]); + /* + cache==mmu_cache_search(state,MAIN_D_CACHE(),va); + if(cache){ + *data = cache->data[va_cache_index(va, MAIN_D_CACHE())]; + printf("cached data %x\n",*data); + }else printf("no cached data\n"); + */ + } + } +//------------------------------------------------- +#endif +#if 0 + /*search in read buffer */ + rb = mmu_rb_search (RB (), va); + if (rb) { + if (rb->fault) + return rb->fault; + *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; + goto datatrans; + //return 0; + }; +#endif + + /*2004-07-19 chy: add support of xscale MMU CacheDisabled option */ + if (MMU_CacheDisabled) { + //if(1){ can be used to test cache error + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, real_va); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, pa); + bus_read(8, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, pa); + bus_read(16, pa, data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, pa); + bus_read(32, pa, data); + else { + printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + return NO_FAULT; + } + + + /*search main cache */ + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; +#if 0 +//------------------------------------------------------------------------ +//chy 2003-09-02 for test only ,should commit ???? + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + pa = tlb_va_to_pa (tlb, va); + chyst2++; + printf ("**SKYEYE:mmu_read wordk:cache %d: pa %x, va %x, data %x, R15 %x\n", chyst2, pa, real_va, *data, state->Reg[15]); + } +//------------------------------------------------------------------- +#endif + goto datatrans; + //return 0; + } + //chy 2003-08-24, now maybe we don't need minidcache ???? +#if 0 + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; + goto datatrans; + //return 0; + } +#endif + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, va); + //chy 2003-08-24 , in xscale it means what ????? +#if 0 + if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { + + if (tlb_c_flag (tlb)) { + if (tlb_b_flag (tlb)) { + mmu_cache_soft_flush (state, MAIN_D_CACHE (), + pa); + } + else { + mmu_cache_soft_flush (state, MINI_D_CACHE (), + pa); + } + } + return 0; + } +#endif + //chy 2003-08-24, check phy addr + //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address + /* + if(pa >= 0xb0000000){ + printf("SKYEYE:xscale_mmu_read: phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); + return 0; + } + */ + + //chy 2003-08-24, now maybe we don't need wb ???? +#if 0 + /*if Buffer, drain Write Buffer first */ + if (tlb_b_flag (tlb)) + mmu_wb_drain_all (state, WB ()); +#endif + /*alloc cache or mem_read */ + if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { + cache_s *cache_t; + + if (tlb_b_flag (tlb)) + cache_t = MAIN_D_CACHE (); + else + cache_t = MINI_D_CACHE (); + cache = mmu_cache_alloc (state, cache_t, va, pa); + *data = cache->data[va_cache_index (va, cache_t)]; + } + else { + //*data = mem_read_word(state, pa); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, pa | (real_va & 3)); + bus_read(8, pa | (real_va & 3), data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, pa | (real_va & 2)); + bus_read(16, pa | (real_va & 2), data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, pa); + bus_read(32, pa, data); + else { + printf ("SKYEYE:2 xscale_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + return NO_FAULT; + } + + + datatrans: + if (datatype == ARM_HALFWORD_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + *data = (temp >> offset) & 0xffff; + } + else if (datatype == ARM_BYTE_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + *data = (temp >> offset & 0xffL); + } + end: + return NO_FAULT; +} + + +static fault_t + xscale_mmu_write_byte (ARMul_State * state, ARMword virt_addr, + ARMword data) +{ + return xscale_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); +} + +static fault_t + xscale_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, + ARMword data) +{ + return xscale_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); +} + +static fault_t + xscale_mmu_write_word (ARMul_State * state, ARMword virt_addr, + ARMword data) +{ + return xscale_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); +} + + + +static fault_t + xscale_mmu_write (ARMul_State * state, ARMword va, ARMword data, + ARMword datatype) +{ + tlb_entry_t *tlb; + cache_line_t *cache; + cache_s *cache_t; + int b; + ARMword pa, real_va, temp, offset; + fault_t fault; + + ARMword index; +//chy 2003-09-02 for test ???? +// static unsigned chyst1=0,chyst2=0; + + DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + va = mmu_pid_va_map (va); + real_va = va; + + if (MMU_Disabled) { + //mem_write_word(state, va, data); + if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, va, data); + bus_write(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, va, data); + bus_write(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, va, data); + bus_write(32, va, data); + else { + printf ("SKYEYE:1 xscale_mmu_write error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + /*align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } //else + va &= ~(WORD_SIZE - 1); + /*tlb translate */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*tlb check access */ + fault = check_access (state, va, tlb, 0); + if (fault) { + DEBUG_LOG(ARM11, "check_access\n"); + return fault; + } + + /*2004-07-19 chy: add support for xscale MMU_CacheDisabled */ + if (MMU_CacheDisabled) { + //if(1){ can be used to test the cache error + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, real_va); + if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, pa, data); + bus_write(8, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, pa, data); + bus_write(16, pa, data); + else if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa , data); + else { + printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_write error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + + /*search main cache */ + b = tlb_b_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + cache_t = MAIN_D_CACHE (); + goto has_cache; + } + //chy 2003-08-24, now maybe we don't need minidcache ???? +#if 0 + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + cache_t = MINI_D_CACHE (); + goto has_cache; + } +#endif + b = tlb_b_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + //chy 2003-08-24, check phy addr 0xa0000000, size 0x04000000 + //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address + /* + if(pa >= 0xb0000000){ + printf("SKYEYE:xscale_mmu_write phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); + return 0; + } + */ + + //chy 2003-08-24, now maybe we don't need WB ???? +#if 0 + if (b) { + if (MMU_WBEnabled) { + if (datatype == ARM_WORD_TYPE) + mmu_wb_write_bytes (state, WB (), pa, &data, + 4); + else if (datatype == ARM_HALFWORD_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | (real_va & 2)), + &data, 2); + else if (datatype == ARM_BYTE_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | (real_va & 3)), + &data, 1); + + } + else { + if (datatype == ARM_WORD_TYPE) + mem_write_word (state, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + mem_write_halfword (state, + (pa | (real_va & 2)), + data); + else if (datatype == ARM_BYTE_TYPE) + mem_write_byte (state, (pa | (real_va & 3)), + data); + } + } + else { + + mmu_wb_drain_all (state, WB ()); + + if (datatype == ARM_WORD_TYPE) + mem_write_word (state, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + mem_write_halfword (state, (pa | (real_va & 2)), + data); + else if (datatype == ARM_BYTE_TYPE) + mem_write_byte (state, (pa | (real_va & 3)), data); + } +#endif + //chy 2003-08-24, just write phy addr + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, (pa | (real_va & 2)), data); + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, (pa | (real_va & 3)), data); + bus_write(8, (pa | (real_va & 3)), data); +#if 0 +//------------------------------------------------------------- +//chy 2003-09-02 for test ???? + if (datatype == ARM_WORD_TYPE) { + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + printf ("**SKYEYE:mmu_write word: pa %x, va %x, data %x, R15 %x \n", pa, real_va, data, state->Reg[15]); + } + } +//-------------------------------------------------------------- +#endif + return NO_FAULT; + + has_cache: + index = va_cache_index (va, cache_t); + //cache->data[index] = data; + + if (datatype == ARM_WORD_TYPE) + cache->data[index] = data; + else if (datatype == ARM_HALFWORD_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << + offset); + } + else if (datatype == ARM_BYTE_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffL << offset)) | ((data & 0xffL) << + offset); + } + + if (index < (cache_t->width >> (WORD_SHT + 1))) + cache->tag |= TAG_FIRST_HALF_DIRTY; + else + cache->tag |= TAG_LAST_HALF_DIRTY; +//------------------------------------------------------------- +//chy 2003-09-03 be sure the changed value will be in memory as soon as possible, so I cache can get the newest value +#if 0 + { + if (datatype == ARM_WORD_TYPE) + mem_write_word (state, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + mem_write_halfword (state, (pa | (real_va & 2)), + data); + else if (datatype == ARM_BYTE_TYPE) + mem_write_byte (state, (pa | (real_va & 3)), data); + } +#endif +#if 0 +//chy 2003-09-02 for test ???? + if (datatype == ARM_WORD_TYPE) { + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + printf ("**SKYEYE:mmu_write word:cache: pa %x, va %x, data %x, R15 %x\n", pa, real_va, data, state->Reg[15]); + } + } +//------------------------------------------------------------- +#endif + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, (pa | (real_va & 2)), data); + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, (pa | (real_va & 3)), data); + bus_write(8, (pa | (real_va & 3)), data); + return NO_FAULT; +} + +ARMword xscale_cp15_mrc (ARMul_State * state, + unsigned type, ARMword instr, ARMword * value) +{ + return xscale_mmu_mrc (state, instr, value); +} + +ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) +{ + ARMword data; + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + mmu_regnum_t creg = (mmu_regnum_t)reg; + +/* + printf("SKYEYE: xscale_cp15_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ + state->Reg[15], instr); +*/ + switch (creg) { + case MMU_ID: //XSCALE_CP15 + //printf("mmu_mrc read ID \n"); + data = (opcode_2 ? state->mmu.cache_type : state->cpu-> + cpu_val); + break; + case MMU_CONTROL: //XSCALE_CP15_AUX_CONTROL + //printf("mmu_mrc read CONTROL \n"); + data = (opcode_2 ? state->mmu.aux_control : state->mmu. + control); + break; + case MMU_TRANSLATION_TABLE_BASE: + //printf("mmu_mrc read TTB \n"); + data = state->mmu.translation_table_base; + break; + case MMU_DOMAIN_ACCESS_CONTROL: + //printf("mmu_mrc read DACR \n"); + data = state->mmu.domain_access_control; + break; + case MMU_FAULT_STATUS: + //printf("mmu_mrc read FSR \n"); + data = state->mmu.fault_status; + break; + case MMU_FAULT_ADDRESS: + //printf("mmu_mrc read FAR \n"); + data = state->mmu.fault_address; + break; + case MMU_PID: + //printf("mmu_mrc read PID \n"); + data = state->mmu.process_id; + case XSCALE_CP15_COPRO_ACCESS: + //printf("xscale cp15 read coprocessor access\n"); + data = state->mmu.copro_access; + break; + default: + data = 0; + printf ("SKYEYE: xscale_cp15_mrc read UNKNOWN - reg %d, pc 0x%x\n", creg, state->Reg[15]); + // skyeye_exit (-1); + break; + } + *value = data; + //printf("SKYEYE: xscale_cp15_mrc:end value 0x%x\n",data); + return ARMul_DONE; +} + +void xscale_cp15_cache_ops (ARMul_State * state, ARMword instr, ARMword value) +{ +//chy: 2003-08-24 now, the BTB isn't simualted ....???? + + unsigned CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + //err_msg("SKYEYE: xscale cp15_cache_ops:OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm,state->Reg[15]); + + if (OPC_2 == 0 && CRm == 7) { + mmu_cache_invalidate_all (state, I_CACHE ()); + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + return; + } + + if (OPC_2 == 0 && CRm == 5) { + mmu_cache_invalidate_all (state, I_CACHE ()); + return; + } + if (OPC_2 == 1 && CRm == 5) { + mmu_cache_invalidate (state, I_CACHE (), value); + return; + } + + if (OPC_2 == 0 && CRm == 6) { + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + return; + } + + if (OPC_2 == 1 && CRm == 6) { + mmu_cache_invalidate (state, MAIN_D_CACHE (), value); + return; + } + + if (OPC_2 == 1 && CRm == 0xa) { + mmu_cache_clean (state, MAIN_D_CACHE (), value); + return; + } + + if (OPC_2 == 4 && CRm == 0xa) { + mmu_wb_drain_all (state, WB ()); + return; + } + + if (OPC_2 == 6 && CRm == 5) { + //chy 2004-07-19 shoud fix in the future????!!!! + //printf("SKYEYE: xscale_cp15_cache_ops:invalidate BTB CANT!!!!!!!!!!\n"); + //exit(-1); + return; + } + + if (OPC_2 == 5 && CRm == 2) { + //printf("SKYEYE: cp15_c_o: A L in D C, value %x, reg15 %x\n",value, state->Reg[15]); + //exit(-1); + //chy 2003-09-01 for test + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + return; + } + + ERROR_LOG(ARM11, "SKYEYE: xscale cp15_cache_ops:Unknown OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm, state->Reg[15]); + // skyeye_exit (-1); +} + +static void + xscale_cp15_tlb_ops (ARMul_State * state, ARMword instr, + ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + + //err_msg("SKYEYE:xscale_cp15_tlb_ops:OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm,state->Reg[15]); + if (OPC_2 == 0 && CRm == 0x7) { + mmu_tlb_invalidate_all (state, I_TLB ()); + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 0 && CRm == 0x5) { + mmu_tlb_invalidate_all (state, I_TLB ()); + return; + } + + if (OPC_2 == 1 && CRm == 0x5) { + mmu_tlb_invalidate_entry (state, I_TLB (), value); + return; + } + + if (OPC_2 == 0 && CRm == 0x6) { + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 1 && CRm == 0x6) { + mmu_tlb_invalidate_entry (state, D_TLB (), value); + return; + } + + ERROR_LOG(ARM11, "SKYEYE:xscale_cp15_tlb_ops:Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm, state->Reg[15]); + // skyeye_exit (-1); +} + + +ARMword xscale_cp15_mcr (ARMul_State * state, + unsigned type, ARMword instr, ARMword value) +{ + return xscale_mmu_mcr (state, instr, value); +} + +ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) +{ + ARMword data; + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + mmu_regnum_t creg = (mmu_regnum_t)reg; + + //printf("SKYEYE: xscale_cp15_mcr: opcode_2 0x%x, CRm 0x%x, reg ox%x, value 0x%x, reg[15] 0x%x, instr 0x%x\n",opcode_2,CRm,reg, value, state->Reg[15], instr); + + switch (creg) { + case MMU_CONTROL: + //printf("mmu_mcr wrote CONTROL val 0x%x \n",value); + state->mmu.control = + (opcode_2 ? (value & 0x33) : (value & 0x3FFF)); + break; + case MMU_TRANSLATION_TABLE_BASE: + //printf("mmu_mcr wrote TTB val 0x%x \n",value); + state->mmu.translation_table_base = value & 0xFFFFC000; + break; + case MMU_DOMAIN_ACCESS_CONTROL: + //printf("mmu_mcr wrote DACR val 0x%x \n",value); + state->mmu.domain_access_control = value; + break; + + case MMU_FAULT_STATUS: + //printf("mmu_mcr wrote FS val 0x%x \n",value); + state->mmu.fault_status = value & 0x6FF; + break; + case MMU_FAULT_ADDRESS: + //printf("mmu_mcr wrote FA val 0x%x \n",value); + state->mmu.fault_address = value; + break; + + case MMU_CACHE_OPS: +// printf("mmu_mcr wrote CO val 0x%x \n",value); + xscale_cp15_cache_ops (state, instr, value); + break; + case MMU_TLB_OPS: + //printf("mmu_mcr wrote TO val 0x%x \n",value); + xscale_cp15_tlb_ops (state, instr, value); + break; + case MMU_PID: + //printf("mmu_mcr wrote PID val 0x%x \n",value); + state->mmu.process_id = value & 0xfe000000; + break; + case XSCALE_CP15_COPRO_ACCESS: + //printf("xscale cp15 write coprocessor access val 0x %x\n",value); + state->mmu.copro_access = value & 0x3ff; + break; + + default: + printf ("SKYEYE: xscale_cp15_mcr wrote UNKNOWN - reg %d, reg15 0x%x\n", creg, state->Reg[15]); + break; + } + //printf("SKYEYE: xscale_cp15_mcr wrote val 0x%x\n", value); + return 0; +} + +//teawater add for arm2x86 2005.06.24------------------------------------------- +static int xscale_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, + ARMword * phys_addr) +{ + fault_t fault; + tlb_entry_t *tlb; + + virt_addr = mmu_pid_va_map (virt_addr); + if (MMU_Enabled) { + + /*align check */ + if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + virt_addr &= ~(WORD_SIZE - 1); + + /*translate tlb */ + fault = translate (state, virt_addr, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, virt_addr, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + + if (MMU_Disabled) { + *phys_addr = virt_addr; + } + else { + *phys_addr = tlb_va_to_pa (tlb, virt_addr); + } + + return (0); +} + +//AJ2D-------------------------------------------------------------------------- + +/*xscale mmu_ops_t*/ +//mmu_ops_t xscale_mmu_ops = { +// xscale_cp15_init, +// xscale_cp15_exit, +// xscale_mmu_read_byte, +// xscale_mmu_write_byte, +// xscale_mmu_read_halfword, +// xscale_mmu_write_halfword, +// xscale_mmu_read_word, +// xscale_mmu_write_word, +// xscale_mmu_load_instr, xscale_mmu_mcr, xscale_mmu_mrc, +////teawater add for arm2x86 2005.06.24------------------------------------------- +// xscale_mmu_v2p_dbct, +////AJ2D-------------------------------------------------------------------------- +//}; diff --git a/src/core/arm/interpreter/vfp/asm_vfp.h b/src/core/arm/interpreter/vfp/asm_vfp.h new file mode 100644 index 000000000..f4ab34fd4 --- /dev/null +++ b/src/core/arm/interpreter/vfp/asm_vfp.h @@ -0,0 +1,84 @@ +/* + * arch/arm/include/asm/vfp.h + * + * VFP register definitions. + * First, the standard VFP set. + */ + +#define FPSID cr0 +#define FPSCR cr1 +#define MVFR1 cr6 +#define MVFR0 cr7 +#define FPEXC cr8 +#define FPINST cr9 +#define FPINST2 cr10 + +/* 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 */ +#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 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) + +/* MVFR0 bits */ +#define MVFR0_A_SIMD_BIT (0) +#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT) + +/* 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)) diff --git a/src/core/arm/interpreter/vfp/vfp.cpp b/src/core/arm/interpreter/vfp/vfp.cpp new file mode 100644 index 000000000..eea5e24a9 --- /dev/null +++ b/src/core/arm/interpreter/vfp/vfp.cpp @@ -0,0 +1,357 @@ +/* + armvfp.c - ARM VFPv3 emulation unit + Copyright (C) 2003 Skyeye Develop Group + for help please send mail to + + 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 +*/ + +/* Note: this file handles interface with arm core and vfp registers */ + +/* Opens debug for classic interpreter only */ +//#define DEBUG + +#include "common/common.h" + +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/vfp/vfp.h" + +//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ + +unsigned +VFPInit (ARMul_State *state) +{ + state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | + VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; + state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; + state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; + + //persistent_state = state; + /* Reset only specify VFP_FPEXC_EN = '0' */ + + return No_exp; +} + +unsigned +VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) +{ + /* MRC ,,,,{,} */ + 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); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 10 || CoProc == 11) + { + #define VFP_MRC_TRANS + #include "core/arm/interpreter/vfp/vfpinstr.cpp" + #undef VFP_MRC_TRANS + } + DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", + instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); + + return ARMul_CANT; +} + +unsigned +VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) +{ + /* MCR ,,,,{,} */ + 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); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + if (CoProc == 10 || CoProc == 11) + { + #define VFP_MCR_TRANS + #include "core/arm/interpreter/vfp/vfpinstr.cpp" + #undef VFP_MCR_TRANS + } + DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", + instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); + + return ARMul_CANT; +} + +unsigned +VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2) +{ + /* MCRR ,,,, */ + 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); + + if (CoProc == 10 || CoProc == 11) + { + #define VFP_MRRC_TRANS + #include "core/arm/interpreter/vfp/vfpinstr.cpp" + #undef VFP_MRRC_TRANS + } + DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", + instr, CoProc, OPC_1, Rt, Rt2, CRm); + + return ARMul_CANT; +} + +unsigned +VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2) +{ + /* MCRR ,,,, */ + 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); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 11 || CoProc == 10) + { + #define VFP_MCRR_TRANS + #include "core/arm/interpreter/vfp/vfpinstr.cpp" + #undef VFP_MCRR_TRANS + } + DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", + instr, CoProc, OPC_1, Rt, Rt2, CRm); + + return ARMul_CANT; +} + +unsigned +VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) +{ + /* STC{L} ,,[], + + @@ -145,15 +147,27 @@ + + + + + + + + - + + + + + + - @@ -171,6 +185,7 @@ + @@ -178,12 +193,16 @@ + + + + + + - - - - - + + + @@ -191,9 +210,10 @@ + + - diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index b5473bc41..edf34ce2f 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -7,9 +7,6 @@ {61100188-a726-4024-ab16-95ee242b446e} - - {a64d3c8a-747a-491b-b782-6e2622bedf24} - {7f618562-73d1-4f55-9628-887497c27654} @@ -28,6 +25,12 @@ {812c5189-ca49-4704-b842-3ffad09092d3} + + {de62238f-a28e-4a33-8495-23fed6784588} + + + {13ef9860-2ba0-47e9-a93d-b4052adab269} + @@ -57,9 +60,6 @@ arm\interpreter - - arm\mmu - file_sys @@ -105,9 +105,54 @@ hw - + + arm\disassembler + + hle + + hle + + + arm\interpreter\vfp + + + arm\interpreter\vfp + + + arm\interpreter\vfp + + + arm\interpreter\vfp + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm + + + arm\interpreter\mmu + @@ -137,21 +182,6 @@ arm\interpreter - - arm\mmu - - - arm\mmu - - - arm\mmu - - - arm\mmu - - - arm\mmu - file_sys @@ -208,9 +238,42 @@ hw - + + arm\disassembler + + hle + + hle + + + arm\interpreter\vfp + + + arm\interpreter\vfp + + + arm\interpreter\vfp + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + + + arm\interpreter\mmu + diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp new file mode 100644 index 000000000..48aa878cc --- /dev/null +++ b/src/core/hle/config_mem.cpp @@ -0,0 +1,70 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/log.h" + +#include "core/hle/config_mem.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace ConfigMem { + +enum { + KERNEL_VERSIONREVISION = 0x1FF80001, + KERNEL_VERSIONMINOR = 0x1FF80002, + KERNEL_VERSIONMAJOR = 0x1FF80003, + UPDATEFLAG = 0x1FF80004, + NSTID = 0x1FF80008, + SYSCOREVER = 0x1FF80010, + UNITINFO = 0x1FF80014, + KERNEL_CTRSDKVERSION = 0x1FF80018, + APPMEMTYPE = 0x1FF80030, + APPMEMALLOC = 0x1FF80040, + FIRM_VERSIONREVISION = 0x1FF80061, + FIRM_VERSIONMINOR = 0x1FF80062, + FIRM_VERSIONMAJOR = 0x1FF80063, + FIRM_SYSCOREVER = 0x1FF80064, + FIRM_CTRSDKVERSION = 0x1FF80068, +}; + +template +inline void Read(T &var, const u32 addr) { + switch (addr) { + + // Bit 0 set for Retail + case UNITINFO: + var = 0x00000001; + break; + + // Set app memory size to 64MB? + case APPMEMALLOC: + var = 0x04000000; + break; + + // Unknown - normally set to: 0x08000000 - (APPMEMALLOC + *0x1FF80048) + // (Total FCRAM size - APPMEMALLOC - *0x1FF80048) + case 0x1FF80044: + var = 0x08000000 - (0x04000000 + 0x1400000); + break; + + // Unknown - normally set to: 0x1400000 (20MB) + case 0x1FF80048: + var = 0x1400000; + break; + + default: + ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); + } +} + +// Explicitly instantiate template functions because we aren't defining this in the header: + +template void Read(u64 &var, const u32 addr); +template void Read(u32 &var, const u32 addr); +template void Read(u16 &var, const u32 addr); +template void Read(u8 &var, const u32 addr); + + +} // namespace diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h new file mode 100644 index 000000000..da396a3e6 --- /dev/null +++ b/src/core/hle/config_mem.h @@ -0,0 +1,21 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// Configuration memory stores various hardware/kernel configuration settings. This memory page is +// read-only for ARM11 processes. I'm guessing this would normally be written to by the firmware/ +// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm +// putting this as a subset of HLE for now. + +#include "common/common_types.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace ConfigMem { + +template +inline void Read(T &var, const u32 addr); + +} // namespace diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp new file mode 100644 index 000000000..39674ee64 --- /dev/null +++ b/src/core/hle/coprocessor.cpp @@ -0,0 +1,34 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "core/hle/coprocessor.h" +#include "core/hle/hle.h" +#include "core/mem_map.h" +#include "core/core.h" + +namespace HLE { + +/// Returns the coprocessor (in this case, syscore) command buffer pointer +Addr GetThreadCommandBuffer() { + // Called on insruction: mrc p15, 0, r0, c13, c0, 3 + return Memory::KERNEL_MEMORY_VADDR; +} + +/// Call an MRC (move to ARM register from coprocessor) instruction in HLE +s32 CallMRC(u32 instruction) { + CoprocessorOperation operation = (CoprocessorOperation)((instruction >> 20) & 0xFF); + + switch (operation) { + + case CALL_GET_THREAD_COMMAND_BUFFER: + return GetThreadCommandBuffer(); + + default: + //DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); + break; + } + return -1; +} + +} // namespace diff --git a/src/core/hle/mrc.h b/src/core/hle/coprocessor.h similarity index 61% rename from src/core/hle/mrc.h rename to src/core/hle/coprocessor.h index d6b9f162f..b08d6f3ee 100644 --- a/src/core/hle/mrc.h +++ b/src/core/hle/coprocessor.h @@ -8,13 +8,13 @@ namespace HLE { -/// MRC operations (ARM register from coprocessor), decoded as instr[20:27] -enum ARM11_MRC_OPERATION { +/// Coprocessor operations +enum CoprocessorOperation { DATA_SYNCHRONIZATION_BARRIER = 0xE0, CALL_GET_THREAD_COMMAND_BUFFER = 0xE1, }; -/// Call an MRC operation in HLE -u32 CallMRC(ARM11_MRC_OPERATION operation); +/// Call an MRC (move to ARM register from coprocessor) instruction in HLE +s32 CallMRC(u32 instruction); } // namespace diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index cab772004..d934eafb4 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -143,8 +143,8 @@ template void WrapI_UUUUU() { RETURN(retval); } -template void WrapI_V() { - int retval = func(); +template void WrapI_V() { + u32 retval = func(Memory::GetPointer(PARAM(0))); RETURN(retval); } @@ -623,6 +623,10 @@ template void WrapU_CC() { RETURN(retval); } +template void WrapV_C() { + func(Memory::GetCharPointer(PARAM(0))); +} + template void WrapV_CI() { func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); } @@ -701,18 +705,28 @@ template void WrapI_ICI() { } template void WrapI_IVVVVUI(){ - u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); - RETURN(retval); + u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); + RETURN(retval); } template void WrapI_ICUVIII(){ - u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6)); - RETURN(retval); + u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6)); + RETURN(retval); } -template void WrapI_VUUUUU(){ - u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); - RETURN(retval); +template void WrapI_VU(){ + u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1)); + RETURN(retval); +} + +template void WrapI_VUVI(){ + u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3)); + RETURN(retval); +} + +template void WrapI_VUUUUU(){ + u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); + RETURN(retval); } template void WrapI_US64() { diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index aae9a3943..be151665b 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -15,49 +15,6 @@ namespace HLE { static std::vector g_module_db; -u8* g_command_buffer = NULL; ///< Command buffer used for sharing between appcore and syscore - -// Read from memory used by CTROS HLE functions -template -inline void Read(T &var, const u32 addr) { - if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) { - var = *((const T*)&g_command_buffer[addr & CMD_BUFFER_MASK]); - } else { - ERROR_LOG(HLE, "unknown read from address %08X", addr); - } -} - -// Write to memory used by CTROS HLE functions -template -inline void Write(u32 addr, const T data) { - if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) { - *(T*)&g_command_buffer[addr & CMD_BUFFER_MASK] = data; - } else { - ERROR_LOG(HLE, "unknown write to address %08X", addr); - } -} - -u8 *GetPointer(const u32 addr) { - if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) { - return g_command_buffer + (addr & CMD_BUFFER_MASK); - } else { - ERROR_LOG(HLE, "unknown pointer from address %08X", addr); - return 0; - } -} - -// Explicitly instantiate template functions because we aren't defining this in the header: - -template void Read(u64 &var, const u32 addr); -template void Read(u32 &var, const u32 addr); -template void Read(u16 &var, const u32 addr); -template void Read(u8 &var, const u32 addr); - -template void Write(u32 addr, const u64 data); -template void Write(u32 addr, const u32 data); -template void Write(u32 addr, const u16 data); -template void Write(u32 addr, const u8 data); - const FunctionDef* GetSyscallInfo(u32 opcode) { u32 func_num = opcode & 0xFFFFFF; // 8 bits if (func_num > 0xFF) { @@ -91,8 +48,6 @@ void RegisterAllModules() { void Init() { Service::Init(); - - g_command_buffer = new u8[CMD_BUFFER_SIZE]; RegisterAllModules(); @@ -102,8 +57,6 @@ void Init() { void Shutdown() { Service::Shutdown(); - delete g_command_buffer; - g_module_db.clear(); NOTICE_LOG(HLE, "shutdown OK"); diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index 907e2d741..42f37e29c 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h @@ -17,13 +17,6 @@ namespace HLE { -enum { - CMD_BUFFER_ADDR = 0xA0010000, ///< Totally arbitrary unused address space - CMD_BUFFER_SIZE = 0x10000, - CMD_BUFFER_MASK = (CMD_BUFFER_SIZE - 1), - CMD_BUFFER_ADDR_END = (CMD_BUFFER_ADDR + CMD_BUFFER_SIZE), -}; - typedef u32 Addr; typedef void (*Func)(); @@ -39,20 +32,6 @@ struct ModuleDef { const FunctionDef* func_table; }; -// Read from memory used by CTROS HLE functions -template -inline void Read(T &var, const u32 addr); - -// Write to memory used by CTROS HLE functions -template -inline void Write(u32 addr, const T data); - -u8* GetPointer(const u32 Address); - -inline const char* GetCharPointer(const u32 address) { - return (const char *)GetPointer(address); -} - void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table); void CallSyscall(u32 opcode); diff --git a/src/core/hle/mrc.cpp b/src/core/hle/mrc.cpp deleted file mode 100644 index 5223be7c9..000000000 --- a/src/core/hle/mrc.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "core/hle/mrc.h" -#include "core/hle/hle.h" -#include "core/mem_map.h" -#include "core/core.h" - -namespace HLE { - -enum { - CMD_GX_REQUEST_DMA = 0x00000000, -}; - -/// Data synchronization barrier -u32 DataSynchronizationBarrier(u32* command_buffer) { - u32 command = command_buffer[0]; - - switch (command) { - - case CMD_GX_REQUEST_DMA: - { - u32* src = (u32*)Memory::GetPointer(command_buffer[1]); - u32* dst = (u32*)Memory::GetPointer(command_buffer[2]); - u32 size = command_buffer[3]; - memcpy(dst, src, size); - } - break; - - default: - ERROR_LOG(OSHLE, "MRC::DataSynchronizationBarrier unknown command 0x%08X", command); - return -1; - } - - return 0; -} - -/// Returns the coprocessor (in this case, syscore) command buffer pointer -Addr GetThreadCommandBuffer() { - // Called on insruction: mrc p15, 0, r0, c13, c0, 3 - // Returns an address in OSHLE memory for the CPU to read/write to - RETURN(CMD_BUFFER_ADDR); - return CMD_BUFFER_ADDR; -} - -/// Call an MRC operation in HLE -u32 CallMRC(ARM11_MRC_OPERATION operation) { - switch (operation) { - - case DATA_SYNCHRONIZATION_BARRIER: - return DataSynchronizationBarrier((u32*)Memory::GetPointer(PARAM(0))); - - case CALL_GET_THREAD_COMMAND_BUFFER: - return GetThreadCommandBuffer(); - - default: - ERROR_LOG(OSHLE, "unimplemented MRC operation 0x%02X", operation); - break; - } - return -1; -} - -} // namespace diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp index 4a1e8c992..709ac5493 100644 --- a/src/core/hle/service/apt.cpp +++ b/src/core/hle/service/apt.cpp @@ -18,7 +18,7 @@ void Initialize(Service::Interface* self) { } void GetLockHandle(Service::Interface* self) { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); cmd_buff[5] = 0x00000000; // TODO: This should be an actual mutex handle } diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 88c1f1a0f..12c7dabcd 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -4,6 +4,7 @@ #include "common/log.h" +#include "common/bit_field.h" #include "core/mem_map.h" #include "core/hle/hle.h" @@ -11,11 +12,52 @@ #include "core/hw/lcd.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// GSP shared memory GX command buffer header +union GX_CmdBufferHeader { + u32 hex; + + // Current command index. This index is updated by GSP module after loading the command data, + // right before the command is processed. When this index is updated by GSP module, the total + // commands field is decreased by one as well. + BitField<0,8,u32> index; + + // Total commands to process, must not be value 0 when GSP module handles commands. This must be + // <=15 when writing a command to shared memory. This is incremented by the application when + // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only + // used if this field is value 1. + BitField<8,8,u32> number_commands; + +}; + +/// Gets the address of the start (header) of a command buffer in GSP shared memory +static inline u32 GX_GetCmdBufferAddress(u32 thread_id) { + return (0x10002000 + 0x800 + (thread_id * 0x200)); +} + +/// Gets a pointer to the start (header) of a command buffer in GSP shared memory +static inline u8* GX_GetCmdBufferPointer(u32 thread_id, u32 offset=0) { + return Memory::GetPointer(GX_GetCmdBufferAddress(thread_id) + offset); +} + +/// Finishes execution of a GSP command +void GX_FinishCommand(u32 thread_id) { + GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(thread_id); + header->number_commands = header->number_commands - 1; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace GSP_GPU namespace GSP_GPU { +u32 g_thread_id = 0; + +enum { + CMD_GX_REQUEST_DMA = 0x00000000, +}; + enum { REG_FRAMEBUFFER_1 = 0x00400468, REG_FRAMEBUFFER_2 = 0x00400494, @@ -26,7 +68,7 @@ void ReadHWRegs(Service::Interface* self) { static const u32 framebuffer_1[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME1, LCD::PADDR_VRAM_TOP_RIGHT_FRAME1}; static const u32 framebuffer_2[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME2, LCD::PADDR_VRAM_TOP_RIGHT_FRAME2}; - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); @@ -50,18 +92,37 @@ void ReadHWRegs(Service::Interface* self) { break; default: - ERROR_LOG(OSHLE, "GSP_GPU::ReadHWRegs unknown register read at address %08X", reg_addr); + ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); } } void RegisterInterruptRelayQueue(Service::Interface* self) { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling + + cmd_buff[2] = g_thread_id; // ThreadID cmd_buff[4] = self->NewHandle(); +} - return; +/// This triggers handling of the GX command written to the command buffer in shared memory. +void TriggerCmdReqQueue(Service::Interface* self) { + GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(g_thread_id); + u32* cmd_buff = (u32*)GX_GetCmdBufferPointer(g_thread_id, 0x20 + (header->index * 0x20)); + + switch (cmd_buff[0]) { + + // GX request DMA - typically used for copying memory from GSP heap to VRAM + case CMD_GX_REQUEST_DMA: + memcpy(Memory::GetPointer(cmd_buff[2]), Memory::GetPointer(cmd_buff[1]), cmd_buff[3]); + break; + + default: + ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); + } + + GX_FinishCommand(g_thread_id); } const Interface::FunctionInfo FunctionTable[] = { @@ -76,7 +137,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00090082, NULL, "InvalidateDataCache"}, {0x000A0044, NULL, "RegisterInterruptEvents"}, {0x000B0040, NULL, "SetLcdForceBlack"}, - {0x000C0000, NULL, "TriggerCmdReqQueue"}, + {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, {0x000D0140, NULL, "SetDisplayTransfer"}, {0x000E0180, NULL, "SetTextureCopy"}, {0x000F0200, NULL, "SetMemoryFill"}, diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index b79dc9458..b260a290a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -10,6 +10,7 @@ #include "common/common.h" #include "common/common_types.h" +#include "core/mem_map.h" #include "core/hle/syscall.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -22,6 +23,15 @@ typedef s32 NativeUID; ///< Native handle for a service static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters) static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header +/** + * Returns a pointer to the command buffer in kernel memory + * @param offset Optional offset into command buffer + * @return Pointer to command buffer + */ +inline static u32* GetCommandBuffer(const int offset=0) { + return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset); +} + class Manager; /// Interface to a CTROS service @@ -81,7 +91,7 @@ public: * @return Return result of svcSendSyncRequest passed back to user app */ Syscall::Result Sync() { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + kCommandHeaderOffset); + u32* cmd_buff = GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); if (itr == m_functions.end()) { diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 9437868c5..071741444 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -18,7 +18,7 @@ void Initialize(Service::Interface* self) { void GetServiceHandle(Service::Interface* self) { Syscall::Result res = 0; - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp index df6412743..d47df6038 100644 --- a/src/core/hle/syscall.cpp +++ b/src/core/hle/syscall.cpp @@ -29,6 +29,9 @@ enum MapMemoryPermission { Result ControlMemory(u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { u32 virtual_address = 0x00000000; + DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", + operation, addr0, addr1, size, permissions); + switch (operation) { // Map normal heap memory @@ -43,16 +46,18 @@ Result ControlMemory(u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissi // Unknown ControlMemory operation default: - ERROR_LOG(OSHLE, "Unknown ControlMemory operation %08X", operation); + ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); } Core::g_app_core->SetReg(1, virtual_address); + return 0; } /// Maps a memory block to specified address Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { - int x = 0; + DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", + memblock, addr, mypermissions, otherpermission); switch (mypermissions) { case MEMORY_PERMISSION_NORMAL: case MEMORY_PERMISSION_NORMAL + 1: @@ -60,20 +65,23 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper Memory::MapBlock_Shared(memblock, addr, mypermissions); break; default: - ERROR_LOG(OSHLE, "Unknown MapMemoryBlock permissions %08X", mypermissions); + ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); } return 0; } /// Connect to an OS service given the port name, returns the handle to the port to out Result ConnectToPort(void* out, const char* port_name) { + Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); Core::g_app_core->SetReg(1, service->GetUID()); + DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); return 0; } /// Synchronize to an OS service Result SendSyncRequest(Handle session) { + DEBUG_LOG(SVC, "SendSyncRequest called session=0x%08X"); Service::Interface* service = Service::g_manager->FetchFromUID(session); service->Sync(); return 0; @@ -82,142 +90,177 @@ Result SendSyncRequest(Handle session) { /// Close a handle Result CloseHandle(Handle handle) { // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); return 0; } /// Wait for a handle to synchronize, timeout after the specified nanoseconds Result WaitSynchronization1(Handle handle, s64 nanoseconds) { // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", + handle, nanoseconds); + return 0; +} + +/// Create an address arbiter (to allocate access to shared resources) +Result CreateAddressArbiter(void* arbiter) { + // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); + Core::g_app_core->SetReg(1, 0xDEADBEEF); + return 0; +} + +/// Used to output a message on a debug hardware unit - does nothing on a retail unit +void OutputDebugString(const char* string) { + NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); +} + +/// Get resource limit +Result GetResourceLimit(void* resource_limit, Handle process) { + // With regards to proceess values: + // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for + // the current KThread. + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); + Core::g_app_core->SetReg(1, 0xDEADBEEF); + return 0; +} + +/// Get resource limit current values +Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { + //s64* values = (s64*)_values; + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", + resource_limit, names, name_count); + Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now return 0; } const HLE::FunctionDef Syscall_Table[] = { - {0x00, NULL, "Unknown"}, - {0x01, WrapI_UUUUU, "ControlMemory"}, - {0x02, NULL, "QueryMemory"}, - {0x03, NULL, "ExitProcess"}, - {0x04, NULL, "GetProcessAffinityMask"}, - {0x05, NULL, "SetProcessAffinityMask"}, - {0x06, NULL, "GetProcessIdealProcessor"}, - {0x07, NULL, "SetProcessIdealProcessor"}, - {0x08, NULL, "CreateThread"}, - {0x09, NULL, "ExitThread"}, - {0x0A, NULL, "SleepThread"}, - {0x0B, NULL, "GetThreadPriority"}, - {0x0C, NULL, "SetThreadPriority"}, - {0x0D, NULL, "GetThreadAffinityMask"}, - {0x0E, NULL, "SetThreadAffinityMask"}, - {0x0F, NULL, "GetThreadIdealProcessor"}, - {0x10, NULL, "SetThreadIdealProcessor"}, - {0x11, NULL, "GetCurrentProcessorNumber"}, - {0x12, NULL, "Run"}, - {0x13, NULL, "CreateMutex"}, - {0x14, NULL, "ReleaseMutex"}, - {0x15, NULL, "CreateSemaphore"}, - {0x16, NULL, "ReleaseSemaphore"}, - {0x17, NULL, "CreateEvent"}, - {0x18, NULL, "SignalEvent"}, - {0x19, NULL, "ClearEvent"}, - {0x1A, NULL, "CreateTimer"}, - {0x1B, NULL, "SetTimer"}, - {0x1C, NULL, "CancelTimer"}, - {0x1D, NULL, "ClearTimer"}, - {0x1E, NULL, "CreateMemoryBlock"}, - {0x1F, WrapI_UUUU, "MapMemoryBlock"}, - {0x20, NULL, "UnmapMemoryBlock"}, - {0x21, NULL, "CreateAddressArbiter"}, - {0x22, NULL, "ArbitrateAddress"}, - {0x23, WrapI_U, "CloseHandle"}, - {0x24, WrapI_US64, "WaitSynchronization1"}, - {0x25, NULL, "WaitSynchronizationN"}, - {0x26, NULL, "SignalAndWait"}, - {0x27, NULL, "DuplicateHandle"}, - {0x28, NULL, "GetSystemTick"}, - {0x29, NULL, "GetHandleInfo"}, - {0x2A, NULL, "GetSystemInfo"}, - {0x2B, NULL, "GetProcessInfo"}, - {0x2C, NULL, "GetThreadInfo"}, - {0x2D, WrapI_VC, "ConnectToPort"}, - {0x2E, NULL, "SendSyncRequest1"}, - {0x2F, NULL, "SendSyncRequest2"}, - {0x30, NULL, "SendSyncRequest3"}, - {0x31, NULL, "SendSyncRequest4"}, - {0x32, WrapI_U, "SendSyncRequest"}, - {0x33, NULL, "OpenProcess"}, - {0x34, NULL, "OpenThread"}, - {0x35, NULL, "GetProcessId"}, - {0x36, NULL, "GetProcessIdOfThread"}, - {0x37, NULL, "GetThreadId"}, - {0x38, NULL, "GetResourceLimit"}, - {0x39, NULL, "GetResourceLimitLimitValues"}, - {0x3A, NULL, "GetResourceLimitCurrentValues"}, - {0x3B, NULL, "GetThreadContext"}, - {0x3C, NULL, "Break"}, - {0x3D, NULL, "OutputDebugString"}, - {0x3E, NULL, "ControlPerformanceCounter"}, - {0x3F, NULL, "Unknown"}, - {0x40, NULL, "Unknown"}, - {0x41, NULL, "Unknown"}, - {0x42, NULL, "Unknown"}, - {0x43, NULL, "Unknown"}, - {0x44, NULL, "Unknown"}, - {0x45, NULL, "Unknown"}, - {0x46, NULL, "Unknown"}, - {0x47, NULL, "CreatePort"}, - {0x48, NULL, "CreateSessionToPort"}, - {0x49, NULL, "CreateSession"}, - {0x4A, NULL, "AcceptSession"}, - {0x4B, NULL, "ReplyAndReceive1"}, - {0x4C, NULL, "ReplyAndReceive2"}, - {0x4D, NULL, "ReplyAndReceive3"}, - {0x4E, NULL, "ReplyAndReceive4"}, - {0x4F, NULL, "ReplyAndReceive"}, - {0x50, NULL, "BindInterrupt"}, - {0x51, NULL, "UnbindInterrupt"}, - {0x52, NULL, "InvalidateProcessDataCache"}, - {0x53, NULL, "StoreProcessDataCache"}, - {0x54, NULL, "FlushProcessDataCache"}, - {0x55, NULL, "StartInterProcessDma"}, - {0x56, NULL, "StopDma"}, - {0x57, NULL, "GetDmaState"}, - {0x58, NULL, "RestartDma"}, - {0x59, NULL, "Unknown"}, - {0x5A, NULL, "Unknown"}, - {0x5B, NULL, "Unknown"}, - {0x5C, NULL, "Unknown"}, - {0x5D, NULL, "Unknown"}, - {0x5E, NULL, "Unknown"}, - {0x5F, NULL, "Unknown"}, - {0x60, NULL, "DebugActiveProcess"}, - {0x61, NULL, "BreakDebugProcess"}, - {0x62, NULL, "TerminateDebugProcess"}, - {0x63, NULL, "GetProcessDebugEvent"}, - {0x64, NULL, "ContinueDebugEvent"}, - {0x65, NULL, "GetProcessList"}, - {0x66, NULL, "GetThreadList"}, - {0x67, NULL, "GetDebugThreadContext"}, - {0x68, NULL, "SetDebugThreadContext"}, - {0x69, NULL, "QueryDebugProcessMemory"}, - {0x6A, NULL, "ReadProcessMemory"}, - {0x6B, NULL, "WriteProcessMemory"}, - {0x6C, NULL, "SetHardwareBreakPoint"}, - {0x6D, NULL, "GetDebugThreadParam"}, - {0x6E, NULL, "Unknown"}, - {0x6F, NULL, "Unknown"}, - {0x70, NULL, "ControlProcessMemory"}, - {0x71, NULL, "MapProcessMemory"}, - {0x72, NULL, "UnmapProcessMemory"}, - {0x73, NULL, "Unknown"}, - {0x74, NULL, "Unknown"}, - {0x75, NULL, "Unknown"}, - {0x76, NULL, "TerminateProcess"}, - {0x77, NULL, "Unknown"}, - {0x78, NULL, "CreateResourceLimit"}, - {0x79, NULL, "Unknown"}, - {0x7A, NULL, "Unknown"}, - {0x7B, NULL, "Unknown"}, - {0x7C, NULL, "KernelSetState"}, - {0x7D, NULL, "QueryProcessMemory"}, + {0x00, NULL, "Unknown"}, + {0x01, WrapI_UUUUU, "ControlMemory"}, + {0x02, NULL, "QueryMemory"}, + {0x03, NULL, "ExitProcess"}, + {0x04, NULL, "GetProcessAffinityMask"}, + {0x05, NULL, "SetProcessAffinityMask"}, + {0x06, NULL, "GetProcessIdealProcessor"}, + {0x07, NULL, "SetProcessIdealProcessor"}, + {0x08, NULL, "CreateThread"}, + {0x09, NULL, "ExitThread"}, + {0x0A, NULL, "SleepThread"}, + {0x0B, NULL, "GetThreadPriority"}, + {0x0C, NULL, "SetThreadPriority"}, + {0x0D, NULL, "GetThreadAffinityMask"}, + {0x0E, NULL, "SetThreadAffinityMask"}, + {0x0F, NULL, "GetThreadIdealProcessor"}, + {0x10, NULL, "SetThreadIdealProcessor"}, + {0x11, NULL, "GetCurrentProcessorNumber"}, + {0x12, NULL, "Run"}, + {0x13, NULL, "CreateMutex"}, + {0x14, NULL, "ReleaseMutex"}, + {0x15, NULL, "CreateSemaphore"}, + {0x16, NULL, "ReleaseSemaphore"}, + {0x17, NULL, "CreateEvent"}, + {0x18, NULL, "SignalEvent"}, + {0x19, NULL, "ClearEvent"}, + {0x1A, NULL, "CreateTimer"}, + {0x1B, NULL, "SetTimer"}, + {0x1C, NULL, "CancelTimer"}, + {0x1D, NULL, "ClearTimer"}, + {0x1E, NULL, "CreateMemoryBlock"}, + {0x1F, WrapI_UUUU, "MapMemoryBlock"}, + {0x20, NULL, "UnmapMemoryBlock"}, + {0x21, WrapI_V, "CreateAddressArbiter"}, + {0x22, NULL, "ArbitrateAddress"}, + {0x23, WrapI_U, "CloseHandle"}, + {0x24, WrapI_US64, "WaitSynchronization1"}, + {0x25, NULL, "WaitSynchronizationN"}, + {0x26, NULL, "SignalAndWait"}, + {0x27, NULL, "DuplicateHandle"}, + {0x28, NULL, "GetSystemTick"}, + {0x29, NULL, "GetHandleInfo"}, + {0x2A, NULL, "GetSystemInfo"}, + {0x2B, NULL, "GetProcessInfo"}, + {0x2C, NULL, "GetThreadInfo"}, + {0x2D, WrapI_VC, "ConnectToPort"}, + {0x2E, NULL, "SendSyncRequest1"}, + {0x2F, NULL, "SendSyncRequest2"}, + {0x30, NULL, "SendSyncRequest3"}, + {0x31, NULL, "SendSyncRequest4"}, + {0x32, WrapI_U, "SendSyncRequest"}, + {0x33, NULL, "OpenProcess"}, + {0x34, NULL, "OpenThread"}, + {0x35, NULL, "GetProcessId"}, + {0x36, NULL, "GetProcessIdOfThread"}, + {0x37, NULL, "GetThreadId"}, + {0x38, WrapI_VU, "GetResourceLimit"}, + {0x39, NULL, "GetResourceLimitLimitValues"}, + {0x3A, WrapI_VUVI, "GetResourceLimitCurrentValues"}, + {0x3B, NULL, "GetThreadContext"}, + {0x3C, NULL, "Break"}, + {0x3D, WrapV_C, "OutputDebugString"}, + {0x3E, NULL, "ControlPerformanceCounter"}, + {0x3F, NULL, "Unknown"}, + {0x40, NULL, "Unknown"}, + {0x41, NULL, "Unknown"}, + {0x42, NULL, "Unknown"}, + {0x43, NULL, "Unknown"}, + {0x44, NULL, "Unknown"}, + {0x45, NULL, "Unknown"}, + {0x46, NULL, "Unknown"}, + {0x47, NULL, "CreatePort"}, + {0x48, NULL, "CreateSessionToPort"}, + {0x49, NULL, "CreateSession"}, + {0x4A, NULL, "AcceptSession"}, + {0x4B, NULL, "ReplyAndReceive1"}, + {0x4C, NULL, "ReplyAndReceive2"}, + {0x4D, NULL, "ReplyAndReceive3"}, + {0x4E, NULL, "ReplyAndReceive4"}, + {0x4F, NULL, "ReplyAndReceive"}, + {0x50, NULL, "BindInterrupt"}, + {0x51, NULL, "UnbindInterrupt"}, + {0x52, NULL, "InvalidateProcessDataCache"}, + {0x53, NULL, "StoreProcessDataCache"}, + {0x54, NULL, "FlushProcessDataCache"}, + {0x55, NULL, "StartInterProcessDma"}, + {0x56, NULL, "StopDma"}, + {0x57, NULL, "GetDmaState"}, + {0x58, NULL, "RestartDma"}, + {0x59, NULL, "Unknown"}, + {0x5A, NULL, "Unknown"}, + {0x5B, NULL, "Unknown"}, + {0x5C, NULL, "Unknown"}, + {0x5D, NULL, "Unknown"}, + {0x5E, NULL, "Unknown"}, + {0x5F, NULL, "Unknown"}, + {0x60, NULL, "DebugActiveProcess"}, + {0x61, NULL, "BreakDebugProcess"}, + {0x62, NULL, "TerminateDebugProcess"}, + {0x63, NULL, "GetProcessDebugEvent"}, + {0x64, NULL, "ContinueDebugEvent"}, + {0x65, NULL, "GetProcessList"}, + {0x66, NULL, "GetThreadList"}, + {0x67, NULL, "GetDebugThreadContext"}, + {0x68, NULL, "SetDebugThreadContext"}, + {0x69, NULL, "QueryDebugProcessMemory"}, + {0x6A, NULL, "ReadProcessMemory"}, + {0x6B, NULL, "WriteProcessMemory"}, + {0x6C, NULL, "SetHardwareBreakPoint"}, + {0x6D, NULL, "GetDebugThreadParam"}, + {0x6E, NULL, "Unknown"}, + {0x6F, NULL, "Unknown"}, + {0x70, NULL, "ControlProcessMemory"}, + {0x71, NULL, "MapProcessMemory"}, + {0x72, NULL, "UnmapProcessMemory"}, + {0x73, NULL, "Unknown"}, + {0x74, NULL, "Unknown"}, + {0x75, NULL, "Unknown"}, + {0x76, NULL, "TerminateProcess"}, + {0x77, NULL, "Unknown"}, + {0x78, NULL, "CreateResourceLimit"}, + {0x79, NULL, "Unknown"}, + {0x7A, NULL, "Unknown"}, + {0x7B, NULL, "Unknown"}, + {0x7C, NULL, "KernelSetState"}, + {0x7D, NULL, "QueryProcessMemory"}, }; void Register() { diff --git a/src/core/loader.cpp b/src/core/loader.cpp index 7c1dfef61..8756588ae 100644 --- a/src/core/loader.cpp +++ b/src/core/loader.cpp @@ -89,8 +89,8 @@ bool Load_DAT(std::string &filename) { * but for the sake of making it easier... we'll temporarily/hackishly * allow it. No sense in making a proper reader for this. */ - u32 entrypoint = 0x080c3ee0; // write to same entrypoint as elf - u32 payload_offset = 0x6F4; + u32 entrypoint = 0x00100000; // write to same entrypoint as elf + u32 payload_offset = 0xA150; const u8 *src = &buffer[payload_offset]; u8 *dst = Memory::GetPointer(entrypoint); @@ -114,6 +114,47 @@ bool Load_DAT(std::string &filename) { return true; } + +/// Loads a CTR BIN file extracted from an ExeFS +bool Load_BIN(std::string &filename) { + std::string full_path = filename; + std::string path, file, extension; + SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); +#if EMU_PLATFORM == PLATFORM_WINDOWS + path = ReplaceAll(path, "/", "\\"); +#endif + File::IOFile f(filename, "rb"); + + if (f.IsOpen()) { + u64 size = f.GetSize(); + u8* buffer = new u8[size]; + + f.ReadBytes(buffer, size); + + u32 entrypoint = 0x00100000; // Hardcoded, read from exheader + + const u8 *src = buffer; + u8 *dst = Memory::GetPointer(entrypoint); + u32 srcSize = size; + u32 *s = (u32*)src; + u32 *d = (u32*)dst; + for (int j = 0; j < (int)(srcSize + 3) / 4; j++) + { + *d++ = (*s++); + } + + Core::g_app_core->SetPC(entrypoint); + + delete[] buffer; + } + else { + return false; + } + f.Close(); + + return true; +} + namespace Loader { bool IsBootableDirectory() { @@ -145,6 +186,9 @@ FileType IdentifyFile(std::string &filename) { else if (!strcasecmp(extension.c_str(), ".elf")) { return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p } + else if (!strcasecmp(extension.c_str(), ".bin")) { + return FILETYPE_CTR_BIN; + } else if (!strcasecmp(extension.c_str(), ".dat")) { return FILETYPE_LAUNCHER_DAT; } @@ -178,6 +222,9 @@ bool LoadFile(std::string &filename, std::string *error_string) { case FILETYPE_CTR_ELF: return Load_ELF(filename); + case FILETYPE_CTR_BIN: + return Load_BIN(filename); + case FILETYPE_LAUNCHER_DAT: return Load_DAT(filename); @@ -215,7 +262,7 @@ bool LoadFile(std::string &filename, std::string *error_string) { case FILETYPE_UNKNOWN: default: ERROR_LOG(LOADER, "Failed to identify file"); - *error_string = "Failed to identify file"; + *error_string = " Failed to identify file"; break; } return false; diff --git a/src/core/loader.h b/src/core/loader.h index df30f16c7..9d4aaa874 100644 --- a/src/core/loader.h +++ b/src/core/loader.h @@ -17,19 +17,21 @@ enum FileType { FILETYPE_CTR_CIA, FILETYPE_CTR_CXI, FILETYPE_CTR_ELF, + FILETYPE_CTR_BIN, + FILETYPE_LAUNCHER_DAT, - FILETYPE_DIRECTORY_CXI, - - FILETYPE_UNKNOWN_BIN, - FILETYPE_UNKNOWN_ELF, - - FILETYPE_ARCHIVE_RAR, - FILETYPE_ARCHIVE_ZIP, - - FILETYPE_NORMAL_DIRECTORY, - - FILETYPE_UNKNOWN + FILETYPE_DIRECTORY_CXI, + + FILETYPE_UNKNOWN_BIN, + FILETYPE_UNKNOWN_ELF, + + FILETYPE_ARCHIVE_RAR, + FILETYPE_ARCHIVE_ZIP, + + FILETYPE_NORMAL_DIRECTORY, + + FILETYPE_UNKNOWN }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index af99cbe32..59560b87d 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp @@ -21,6 +21,7 @@ u8* g_heap = NULL; ///< Application heap (main memo u8* g_heap_gsp = NULL; ///< GSP heap (main memory) u8* g_vram = NULL; ///< Video memory (VRAM) pointer u8* g_shared_mem = NULL; ///< Shared memory +u8* g_kernel_mem; ///< Kernel memory u8* g_physical_bootrom = NULL; ///< Bootrom physical memory u8* g_uncached_bootrom = NULL; @@ -30,6 +31,7 @@ u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) u8* g_physical_shared_mem = NULL; ///< Physical shared memory +u8* g_physical_kernel_mem; ///< Kernel memory // We don't declare the IO region in here since its handled by other means. static MemoryView g_views[] = { @@ -37,6 +39,7 @@ static MemoryView g_views[] = { {&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, {&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, {&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, + {&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, {&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, }; diff --git a/src/core/mem_map.h b/src/core/mem_map.h index 00c3b47fc..af2212a5f 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -32,10 +32,20 @@ enum { SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE), SHARED_MEMORY_MASK = (SHARED_MEMORY_SIZE - 1), + CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size + CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address + CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE), + CONFIG_MEMORY_MASK = (CONFIG_MEMORY_SIZE - 1), + + KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size + KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are + KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE), + KERNEL_MEMORY_MASK = (KERNEL_MEMORY_SIZE - 1), + EXEFS_CODE_SIZE = 0x03F00000, EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE), - EXEFS_CODE_MASK = (EXEFS_CODE_VADDR - 1), + EXEFS_CODE_MASK = 0x03FFFFFF, HEAP_SIZE = FCRAM_SIZE, ///< Application heap size //HEAP_PADDR = HEAP_GSP_SIZE, @@ -105,6 +115,7 @@ extern u8* g_heap_gsp; ///< GSP heap (main memory) extern u8* g_heap; ///< Application heap (main memory) extern u8* g_vram; ///< Video memory (VRAM) extern u8* g_shared_mem; ///< Shared memory +extern u8* g_kernel_mem; ///< Kernel memory extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here void Init(); diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 2284b535c..8ab647714 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -9,6 +9,7 @@ #include "core/mem_map.h" #include "core/hw/hw.h" #include "hle/hle.h" +#include "hle/config_mem.h" namespace Memory { @@ -46,12 +47,10 @@ inline void _Read(T &var, const u32 addr) { // Could just do a base-relative read, too.... TODO const u32 vaddr = _VirtualAddress(addr); - - // Memory allocated for HLE use that can be addressed from the emulated application - // The primary use of this is sharing a commandbuffer between the HLE OS (syscore) and the LLE - // core running the user application (appcore) - if (vaddr >= HLE::CMD_BUFFER_ADDR && vaddr < HLE::CMD_BUFFER_ADDR_END) { - HLE::Read(var, vaddr); + + // Kernel memory command buffer + if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { + var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]); // Hardware I/O register reads // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space @@ -74,6 +73,10 @@ inline void _Read(T &var, const u32 addr) { } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]); + // Config memory + } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { + ConfigMem::Read(var, vaddr); + // VRAM } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { var = *((const T*)&g_vram[vaddr & VRAM_MASK]); @@ -87,11 +90,9 @@ template inline void _Write(u32 addr, const T data) { u32 vaddr = _VirtualAddress(addr); - // Memory allocated for HLE use that can be addressed from the emulated application - // The primary use of this is sharing a commandbuffer between the HLE OS (syscore) and the LLE - // core running the user application (appcore) - if (vaddr >= HLE::CMD_BUFFER_ADDR && vaddr < HLE::CMD_BUFFER_ADDR_END) { - HLE::Write(vaddr, data); + // Kernel memory command buffer + if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { + *(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data; // Hardware I/O register writes // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space @@ -118,12 +119,12 @@ inline void _Write(u32 addr, const T data) { } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { *(T*)&g_vram[vaddr & VRAM_MASK] = data; - } else if ((vaddr & 0xFFF00000) == 0x1FF00000) { - _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); - } else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { - _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); - } else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { - _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); + //} else if ((vaddr & 0xFFF00000) == 0x1FF00000) { + // _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); + //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { + // _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); + //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { + // _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); // Error out... } else { @@ -135,8 +136,12 @@ inline void _Write(u32 addr, const T data) { u8 *GetPointer(const u32 addr) { const u32 vaddr = _VirtualAddress(addr); + // Kernel memory command buffer + if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { + return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK); + // ExeFS:/.code is loaded here - if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { + } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { return g_exefs_code + (vaddr & EXEFS_CODE_MASK); // FCRAM - GSP heap diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 314b1a8ed..f2e809b1d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -58,15 +58,14 @@ void RendererOpenGL::SwapBuffers() { * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei */ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { - for (int y = 0; y < VideoCore::kScreenTopHeight; y++) { - for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { - int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3) - - (3 * y + 3); - int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3); - - out[out_coord + 0] = in[in_coord + 0]; + int in_coord = 0; + for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { + for (int y = VideoCore::kScreenTopHeight-1; y >= 0; y--) { + int out_coord = (x + y * VideoCore::kScreenTopWidth) * 3; + out[out_coord] = in[in_coord]; out[out_coord + 1] = in[in_coord + 1]; out[out_coord + 2] = in[in_coord + 2]; + in_coord+=3; } } }