├── README.md ├── tests └── thumb │ ├── add01.o │ ├── cmp01.o │ ├── ldr01.o │ ├── sub01.o │ ├── loop01.o │ ├── shift01.o │ ├── add01.ok │ ├── cmp01.ok │ ├── ldr01.ok │ ├── loop01.ok │ ├── sub01.ok │ ├── shift01.ok │ ├── shift01.s │ ├── add01.s │ ├── loop01.s │ ├── ldr01.s │ ├── sub01.s │ └── cmp01.s ├── arch ├── arm.cc ├── arm.h ├── thumb.h └── thumb.cc ├── .gitignore ├── main.cc ├── exception.cc ├── common.h ├── emulator.cc ├── memory.cc ├── emulator.h ├── memory.h ├── LICENSE ├── exception.h ├── CMakeLists.txt ├── test.cc └── tools └── CodeCoverage.cmake /README.md: -------------------------------------------------------------------------------- 1 | VirtualPI 2 | ========= 3 | 4 | Raspberry Pi Emulator 5 | -------------------------------------------------------------------------------- /tests/thumb/add01.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICTeam28/VirtualPI/HEAD/tests/thumb/add01.o -------------------------------------------------------------------------------- /tests/thumb/cmp01.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICTeam28/VirtualPI/HEAD/tests/thumb/cmp01.o -------------------------------------------------------------------------------- /tests/thumb/ldr01.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICTeam28/VirtualPI/HEAD/tests/thumb/ldr01.o -------------------------------------------------------------------------------- /tests/thumb/sub01.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICTeam28/VirtualPI/HEAD/tests/thumb/sub01.o -------------------------------------------------------------------------------- /tests/thumb/loop01.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICTeam28/VirtualPI/HEAD/tests/thumb/loop01.o -------------------------------------------------------------------------------- /tests/thumb/shift01.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICTeam28/VirtualPI/HEAD/tests/thumb/shift01.o -------------------------------------------------------------------------------- /arch/arm.cc: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #include "common.h" 5 | 6 | -------------------------------------------------------------------------------- /tests/thumb/add01.ok: -------------------------------------------------------------------------------- 1 | THUMB State: 2 | $r0: 00000000 3 | $r1: 00000003 4 | $r2: 00000001 5 | $r3: 00000000 6 | $r4: 00000000 7 | $r5: 00000000 8 | $r6: 00000000 9 | $r7: 00000000 10 | N:0 Z:0 C:0 V:0 11 | -------------------------------------------------------------------------------- /tests/thumb/cmp01.ok: -------------------------------------------------------------------------------- 1 | THUMB State: 2 | $r0: 00000000 3 | $r1: 00000064 4 | $r2: 000000c8 5 | $r3: 00000001 6 | $r4: 00000000 7 | $r5: 00000000 8 | $r6: 00000000 9 | $r7: 00000000 10 | N:0 Z:0 C:1 V:0 11 | -------------------------------------------------------------------------------- /tests/thumb/ldr01.ok: -------------------------------------------------------------------------------- 1 | THUMB State: 2 | $r0: 00000000 3 | $r1: 01234567 4 | $r2: 07654321 5 | $r3: 9b004a03 6 | $r4: 00000000 7 | $r5: 00000000 8 | $r6: 00000000 9 | $r7: 00000000 10 | N:0 Z:0 C:0 V:0 11 | -------------------------------------------------------------------------------- /tests/thumb/loop01.ok: -------------------------------------------------------------------------------- 1 | THUMB State: 2 | $r0: 00000000 3 | $r1: 00000000 4 | $r2: 00000000 5 | $r3: 00000000 6 | $r4: 00000000 7 | $r5: 00000000 8 | $r6: 00000000 9 | $r7: 00000000 10 | N:0 Z:1 C:0 V:0 11 | -------------------------------------------------------------------------------- /tests/thumb/sub01.ok: -------------------------------------------------------------------------------- 1 | THUMB State: 2 | $r0: 00000000 3 | $r1: 00000000 4 | $r2: 000000ff 5 | $r3: 00000000 6 | $r4: 00000000 7 | $r5: 00000000 8 | $r6: 00000000 9 | $r7: 00000000 10 | N:0 Z:1 C:0 V:0 11 | -------------------------------------------------------------------------------- /tests/thumb/shift01.ok: -------------------------------------------------------------------------------- 1 | THUMB State: 2 | $r0: 00000000 3 | $r1: 80000000 4 | $r2: 00000000 5 | $r3: 00000000 6 | $r4: 00000000 7 | $r5: 00000000 8 | $r6: 00000000 9 | $r7: 00000000 10 | N:1 Z:0 C:1 V:0 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | 23 | # Sublime 24 | *sublime* 25 | 26 | # CMake 27 | build -------------------------------------------------------------------------------- /tests/thumb/shift01.s: -------------------------------------------------------------------------------- 1 | @ This file is part of the PiEMU Project 2 | @ Licensing information can be found in the LICENSE file 3 | @ (C) 2014 Nandor Licker. All rights reserved. 4 | 5 | entry: 6 | .code 32 7 | ldr r6, =thumb 8 | bx r6 9 | thumb: 10 | .code 16 11 | 1: 12 | mov r1, #255 13 | lsl r1, #31 14 | swi 0xF 15 | -------------------------------------------------------------------------------- /tests/thumb/add01.s: -------------------------------------------------------------------------------- 1 | @ This file is part of the PiEMU Project 2 | @ Licensing information can be found in the LICENSE file 3 | @ (C) 2014 Nandor Licker. All rights reserved. 4 | 5 | entry: 6 | .code 32 7 | ldr r6, =thumb 8 | bx r6 9 | thumb: 10 | .code 16 11 | 1: 12 | mov r1, #2 13 | mov r2, #1 14 | add r1, r2 15 | swi 0x0 16 | -------------------------------------------------------------------------------- /tests/thumb/loop01.s: -------------------------------------------------------------------------------- 1 | @ This file is part of the PiEMU Project 2 | @ Licensing information can be found in the LICENSE file 3 | @ (C) 2014 Nandor Licker. All rights reserved. 4 | 5 | entry: 6 | .code 32 7 | ldr r6, =thumb 8 | bx r6 9 | thumb: 10 | .code 16 11 | mov r1, #255 12 | 1: 13 | sub r1, #1 14 | bne 1b 15 | swi 0x0 16 | -------------------------------------------------------------------------------- /tests/thumb/ldr01.s: -------------------------------------------------------------------------------- 1 | @ This file is part of the PiEMU Project 2 | @ Licensing information can be found in the LICENSE file 3 | @ (C) 2014 Nandor Licker. All rights reserved. 4 | 5 | entry: 6 | .code 32 7 | ldr r6, =thumb 8 | bx r6 9 | thumb: 10 | .code 16 11 | mov sp, pc 12 | ldr r1, =0x1234567 13 | ldr r2, =0x7654321 14 | ldr r3, [sp] 15 | swi 0xF 16 | -------------------------------------------------------------------------------- /tests/thumb/sub01.s: -------------------------------------------------------------------------------- 1 | @ This file is part of the PiEMU Project 2 | @ Licensing information can be found in the LICENSE file 3 | @ (C) 2014 Nandor Licker. All rights reserved. 4 | 5 | entry: 6 | .code 32 7 | ldr r6, =thumb 8 | bx r6 9 | thumb: 10 | .code 16 11 | 1: 12 | mov r1, #255 13 | mov r2, #255 14 | sub r1, r2 15 | mov r4, #255 16 | sub r4, #255 17 | swi 0x0 18 | -------------------------------------------------------------------------------- /tests/thumb/cmp01.s: -------------------------------------------------------------------------------- 1 | @ This file is part of the PiEMU Project 2 | @ Licensing information can be found in the LICENSE file 3 | @ (C) 2014 Nandor Licker. All rights reserved. 4 | 5 | entry: 6 | .code 32 7 | ldr r6, =thumb 8 | bx r6 9 | thumb: 10 | .code 16 11 | mov r1, #100 12 | mov r2, #200 13 | cmp r1, r2 14 | bge 1f 15 | mov r3, #1 16 | b 2f 17 | 1: 18 | mov r3, #2 19 | 2: 20 | swi #0xF 21 | -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #include "common.h" 5 | 6 | 7 | // ----------------------------------------------------------------------------- 8 | int main(int argc, char **argv) 9 | { 10 | int a, b; 11 | try 12 | { 13 | return EXIT_SUCCESS; 14 | } 15 | catch (std::exception &e) 16 | { 17 | std::cerr << e.what() << std::endl; 18 | return EXIT_FAILURE; 19 | } 20 | catch (...) 21 | { 22 | std::cerr << "Unknown exception" << std::endl; 23 | return EXIT_FAILURE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /exception.cc: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #include "common.h" 5 | 6 | 7 | // ----------------------------------------------------------------------------- 8 | Exception::Exception(const std::string& file, int line, const std::string& func) 9 | { 10 | size_t len; 11 | std::string name; 12 | 13 | if ((len = file.find_last_of('/')) != std::string::npos) 14 | { 15 | name = file.substr(len + 1); 16 | } 17 | else 18 | { 19 | name = file; 20 | } 21 | 22 | os << "[" << name << ":" << line << " " << func << "] "; 23 | } 24 | -------------------------------------------------------------------------------- /arch/arm.h: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #ifndef __ARM_H__ 5 | #define __ARM_H__ 6 | 7 | /** 8 | * Forward declaration of the memory module 9 | */ 10 | class Memory; 11 | 12 | /** 13 | * ARM operation mode 14 | */ 15 | enum ARMMode 16 | { 17 | 18 | }; 19 | 20 | /** 21 | * ARM unit state 22 | */ 23 | struct ARMState 24 | { 25 | /// r0 - r15 26 | uint32_t r[0xF]; 27 | 28 | /// Program counter 29 | uint8_t PC; 30 | 31 | /// Negative flag 32 | uint8_t N; 33 | 34 | /// Zero flag 35 | uint8_t Z; 36 | 37 | /// Carry flag 38 | uint8_t C; 39 | 40 | /// Overflow flag 41 | uint8_t V; 42 | 43 | /// IRQ bit 44 | uint8_t I; 45 | 46 | /// FIQ bit 47 | uint8_t F; 48 | 49 | /// Thumb bit 50 | uint8_t T; 51 | }; 52 | 53 | #endif /*__ARM_H__*/ 54 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #ifndef __COMMON_H__ 5 | #define __COMMON_H__ 6 | 7 | 8 | // C includes 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | // C++ includes 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | // Linux includes 27 | #include 28 | 29 | 30 | // Compiler specific macros 31 | #define FORCEINLINE __attribute__((always_inline)) 32 | 33 | 34 | // Emulator includes 35 | #include "exception.h" 36 | #include "memory.h" 37 | #include "arch/arm.h" 38 | #include "arch/thumb.h" 39 | #include "emulator.h" 40 | 41 | 42 | #endif /*__COMMON_H__*/ 43 | -------------------------------------------------------------------------------- /arch/thumb.h: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #ifndef __THUMB_H__ 5 | #define __THUMB_H__ 6 | 7 | 8 | /** 9 | * THUMB state 10 | */ 11 | struct THUMBState 12 | { 13 | union 14 | { 15 | struct 16 | { 17 | uint32_t r0; 18 | uint32_t r1; 19 | uint32_t r2; 20 | uint32_t r3; 21 | uint32_t r4; 22 | uint32_t r5; 23 | uint32_t r6; 24 | uint32_t r7; 25 | uint32_t r8; 26 | uint32_t r9; 27 | uint32_t r10; 28 | uint32_t r11; 29 | uint32_t r12; 30 | uint32_t sp; 31 | uint32_t lr; 32 | uint32_t pc; 33 | }; 34 | 35 | int32_t r[0x10]; 36 | }; 37 | 38 | union 39 | { 40 | struct 41 | { 42 | uint8_t n; 43 | uint8_t z; 44 | uint8_t c; 45 | uint8_t v; 46 | }; 47 | 48 | /// Combined flags 49 | uint32_t flags; 50 | }; 51 | 52 | /// ITT state 53 | uint8_t itt; 54 | }; 55 | 56 | 57 | /** 58 | * Executes a thumb instruction 59 | * @param emu Pointer to the emulator state 60 | */ 61 | void ThumbExecute(Emulator *emu); 62 | 63 | 64 | /** 65 | * Switch to THUMB mode 66 | */ 67 | void ThumbSwitch(Emulator *emu); 68 | 69 | 70 | #endif /*__THUMB_H__*/ -------------------------------------------------------------------------------- /emulator.cc: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #include "common.h" 5 | 6 | 7 | // ----------------------------------------------------------------------------- 8 | Emulator::Emulator(const Args& args) 9 | : args(args) 10 | , mem(*this, args.ram, args.vram) 11 | { 12 | memset(&thumbState, 0, sizeof(THUMBState)); 13 | mem.LoadImage(args.image, 0); 14 | thumbState.pc = 8; 15 | } 16 | 17 | 18 | // ----------------------------------------------------------------------------- 19 | Emulator::~Emulator() 20 | { 21 | } 22 | 23 | 24 | // ----------------------------------------------------------------------------- 25 | void Emulator::Run() 26 | { 27 | ThumbExecute(this); 28 | } 29 | 30 | 31 | // ----------------------------------------------------------------------------- 32 | void Emulator::DumpTHUMB(std::ostream& os) 33 | { 34 | os << "THUMB State:" << std::endl; 35 | 36 | for (int i = 0; i < 8; ++i) 37 | { 38 | os << "$r" << i << ": " 39 | << std::setfill('0') << std::setw(8) << std::hex 40 | << thumbState.r[i] << std::endl; 41 | } 42 | 43 | os << "N:" << (thumbState.n ? 1 : 0) << " " 44 | << "Z:" << (thumbState.z ? 1 : 0) << " " 45 | << "C:" << (thumbState.c ? 1 : 0) << " " 46 | << "V:" << (thumbState.v ? 1 : 0) << std::endl; 47 | } -------------------------------------------------------------------------------- /memory.cc: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #include "common.h" 5 | 6 | 7 | // ----------------------------------------------------------------------------- 8 | Memory::Memory(Emulator &emu, uint32_t ramSize, uint32_t vramSize) 9 | : emu(emu) 10 | , ramSize(ramSize) 11 | , ram(nullptr) 12 | , vramSize(vramSize) 13 | , vram(nullptr) 14 | { 15 | ram = new uint8_t[ramSize]; 16 | memset(ram, 0, ramSize); 17 | vram = ram + ramSize - vramSize; 18 | } 19 | 20 | 21 | // ----------------------------------------------------------------------------- 22 | Memory::~Memory() 23 | { 24 | delete[] ram; 25 | } 26 | 27 | 28 | // ----------------------------------------------------------------------------- 29 | void Memory::LoadImage(const std::string& image, size_t start) 30 | { 31 | std::ifstream file; 32 | size_t size; 33 | 34 | file.open(image, std::ios::binary); 35 | if (!file.is_open()) 36 | { 37 | EXCEPT << "Cannot open file '" << image << "'"; 38 | } 39 | 40 | file.seekg(0, file.end); 41 | size = file.tellg(); 42 | file.seekg(0, file.beg); 43 | 44 | if (start + size >= ramSize - vramSize) 45 | { 46 | EXCEPT << "Image '" << image << "' too large"; 47 | } 48 | 49 | if (!file.read((char*)(ram + start), size)) 50 | { 51 | EXCEPT << "Cannot read '" << image << "'"; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /emulator.h: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #ifndef __EMULATOR_H__ 5 | #define __EMULATOR_H__ 6 | 7 | /** 8 | * Emulator instance 9 | */ 10 | class Emulator 11 | { 12 | public: 13 | 14 | /** 15 | * Emulator arguments 16 | */ 17 | struct Args 18 | { 19 | /** 20 | * RAM + VRAM 21 | */ 22 | size_t ram; 23 | 24 | /** 25 | * VRAM 26 | */ 27 | size_t vram; 28 | 29 | /** 30 | * Path to image 31 | */ 32 | std::string image; 33 | }; 34 | 35 | /** 36 | * Creates a new emulator instance 37 | */ 38 | Emulator(const Args& args); 39 | 40 | /** 41 | * Copy constructor forbidden 42 | */ 43 | Emulator(const Emulator&) =delete; 44 | 45 | /** 46 | * Destroys an emulator instance 47 | */ 48 | ~Emulator(); 49 | 50 | /** 51 | * Runs the emulator 52 | */ 53 | void Run(); 54 | 55 | /** 56 | * Copying forbidden 57 | */ 58 | Emulator& operator = (const Emulator&) =delete; 59 | 60 | /** 61 | * Dumps the THUMB state 62 | */ 63 | void DumpTHUMB(std::ostream& os); 64 | 65 | private: 66 | 67 | /// Configuration 68 | const Args &args; 69 | 70 | /// Memory module 71 | Memory mem; 72 | 73 | /// ARM state 74 | ARMState armState; 75 | 76 | /// THUMB state 77 | THUMBState thumbState; 78 | 79 | /// Thumb 80 | friend void ThumbExecute(Emulator *emu); 81 | }; 82 | 83 | #endif /*__EMULATOR_H__*/ 84 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #ifndef __MEMORY_H__ 5 | #define __MEMORY_H__ 6 | 7 | 8 | /** 9 | * Emulator foward declaration 10 | */ 11 | class Emulator; 12 | 13 | 14 | /** 15 | * Memory module 16 | */ 17 | class Memory 18 | { 19 | public: 20 | 21 | /** 22 | * Creates a new memory module 23 | */ 24 | Memory(Emulator &emu, uint32_t sdramSize, uint32_t vramSize); 25 | 26 | /** 27 | * Destroys the memory module 28 | */ 29 | ~Memory(); 30 | 31 | /** 32 | * Loads an image into RAM 33 | * @param image Path to an image file 34 | * @param start Address of the image file 35 | */ 36 | void LoadImage(const std::string& image, size_t start); 37 | 38 | /** 39 | * Returns a word from memory 40 | */ 41 | uint16_t GetInstrWord(uint32_t addr) 42 | { 43 | return *((uint16_t*)(ram + addr)); 44 | } 45 | 46 | /** 47 | * Returns a long from memory 48 | */ 49 | uint32_t GetLong(uint32_t addr) 50 | { 51 | return *((uint32_t*)(ram + addr)); 52 | } 53 | 54 | private: 55 | 56 | /// Reference to the emulator 57 | Emulator &emu; 58 | 59 | /// Size of SDRAM 60 | uint32_t ramSize; 61 | 62 | /// RAM 63 | uint8_t *ram; 64 | 65 | /// Size of VRAM 66 | uint32_t vramSize; 67 | 68 | /// VRAM (pointer inside sdram) 69 | uint8_t *vram; 70 | 71 | /// ROM (pointer inside sdram) 72 | uint8_t *rom; 73 | }; 74 | 75 | 76 | #endif /*__MEMORY_H__*/ 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Team 28 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /exception.h: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #ifndef __EXCEPTION_H__ 5 | #define __EXCEPTION_H__ 6 | 7 | /** 8 | * Class supporting formatted error messages 9 | */ 10 | class Exception : public std::exception 11 | { 12 | public: 13 | 14 | /** 15 | * Constructs a new exception object 16 | */ 17 | Exception() 18 | : os("") 19 | { 20 | } 21 | 22 | /** 23 | * Copy constructor 24 | */ 25 | Exception(const Exception& e) 26 | : os(e.os.str()) 27 | { 28 | } 29 | 30 | /** 31 | * Constructs a new exception object, including source information 32 | * @param file Name of the throwing file 33 | * @param line Line number 34 | * @param func Name of the function 35 | */ 36 | Exception(const std::string& file, int line, const std::string& func); 37 | 38 | /** 39 | * Returns the error message 40 | */ 41 | const char *what() const throw() 42 | { 43 | return os.str().c_str(); 44 | } 45 | 46 | /** 47 | * Appends a message to the end of stream 48 | * @param T type of data 49 | * @param t stuff to be written 50 | */ 51 | template 52 | Exception& operator << (const T& t) 53 | { 54 | os << t; 55 | return *this; 56 | } 57 | 58 | private: 59 | 60 | /** 61 | * Format stream 62 | */ 63 | std::ostringstream os; 64 | 65 | }; 66 | 67 | /** 68 | * Macro to throw nice exceptions 69 | */ 70 | #define EXCEPT throw Exception(__FILE__, __LINE__, __FUNCTION__) 71 | 72 | #endif /*__EXCEPTION_H__*/ 73 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file is part of the Team 28 Project 2 | # Licensing information can be found in the LICENSE file 3 | # (C) 2014 The Team 28 Authors. All rights reserved. 4 | cmake_minimum_required(VERSION 2.8) 5 | project(vpi) 6 | 7 | 8 | # Dependencies 9 | find_package(SDL REQUIRED) 10 | include_directories(${SDL_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}) 11 | 12 | 13 | # Enable coverage in debug mode 14 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") 17 | set(CMAKE_EXE_LINKER_FLAGS "-fprofile-arcs -ftest-coverage") 18 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/tools) 19 | include(CodeCoverage) 20 | endif() 21 | 22 | 23 | # C++ flags 24 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 -m32") 25 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -m32") 26 | 27 | 28 | # C++ sources 29 | set(SOURCES 30 | memory.cc 31 | emulator.cc 32 | exception.cc 33 | arch/arm.cc 34 | arch/thumb.cc 35 | ) 36 | 37 | 38 | # C++ headers 39 | set(HEADERS 40 | common.h 41 | memory.h 42 | exception.h 43 | emulator.h 44 | arch/arm.h 45 | arch/thumb.h 46 | ) 47 | 48 | 49 | # Libraries 50 | set(LIBS 51 | m 52 | ${SDL_LIBRARY} 53 | ) 54 | 55 | 56 | # Executable 57 | add_executable(vpi main.cc ${SOURCES} ${HEADERS}) 58 | target_link_libraries(vpi ${LIBS}) 59 | 60 | 61 | # Test executable 62 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 63 | 64 | # Set up a test wrapper 65 | add_executable(vpi_test test.cc ${SOURCES} ${HEADERS}) 66 | target_link_libraries(vpi_test gcov ${LIBS}) 67 | 68 | 69 | # Set up gcov 70 | setup_target_for_coverage( 71 | piemu_coverage 72 | piemu_test 73 | coverage 74 | ${CMAKE_SOURCE_DIR}/tests 75 | ) 76 | endif() 77 | -------------------------------------------------------------------------------- /test.cc: -------------------------------------------------------------------------------- 1 | // This file is part of the PiEMU Project 2 | // Licensing information can be found in the LICENSE file 3 | // (C) 2014 Nandor Licker. All rights reserved. 4 | #include "common.h" 5 | 6 | // ----------------------------------------------------------------------------- 7 | static int testCount = 0; 8 | static int testPass = 0; 9 | 10 | 11 | // ----------------------------------------------------------------------------- 12 | int RunTest(const char *path, const struct stat *sb, int type) 13 | { 14 | size_t len; 15 | std::string name, ext, output, expected; 16 | std::ostringstream out; 17 | 18 | Emulator::Args args; 19 | args.ram = 64 << 20; 20 | args.vram = 32 << 20; 21 | args.image = ""; 22 | 23 | try 24 | { 25 | name = path; 26 | ext = ""; 27 | if ((len = name.find_last_of('/')) != std::string::npos) 28 | { 29 | name = name.substr(len + 1); 30 | } 31 | 32 | if ((len = name.find_last_of('.')) != std::string::npos) 33 | { 34 | ext = name.substr(len + 1); 35 | output = std::string(path) + "k"; 36 | } 37 | 38 | if (type == FTW_F && ext == "o") 39 | { 40 | std::cerr << "[Running " << name << "] "; 41 | ++testCount; 42 | 43 | // Read in reference output 44 | std::ifstream t(output.c_str()); 45 | if (!t.is_open()) 46 | { 47 | throw std::runtime_error("Cannot open '" + output + "'"); 48 | } 49 | 50 | expected = std::string(std::istreambuf_iterator(t), 51 | std::istreambuf_iterator()); 52 | 53 | // Run the emulator 54 | out.clear(); 55 | { 56 | args.image = path; 57 | Emulator emu(args); 58 | emu.Run(); 59 | emu.DumpTHUMB(out); 60 | } 61 | 62 | if (expected == out.str()) 63 | { 64 | ++testPass; 65 | std::cerr << "Passed" << std::endl; 66 | } 67 | else 68 | { 69 | std::cerr << "Failed" << std::endl 70 | << "Output:" << std::endl << out.str() << std::endl 71 | << "Expected:" << std::endl <> 8) & 0xF) 64 | { 65 | case 0x0: t->pc += (t->z) ? off : 0; return; 66 | case 0x1: t->pc += (!t->z) ? off : 0; return; 67 | case 0x2: t->pc += (t->c) ? off : 0; return; 68 | case 0x3: t->pc += (!t->c) ? off : 0; return; 69 | case 0x4: t->pc += (t->n) ? off : 0; return; 70 | case 0x5: t->pc += (!t->n) ? off : 0; return; 71 | case 0x6: t->pc += (t->v) ? off : 0; return; 72 | case 0x7: t->pc += (!t->v) ? off : 0; return; 73 | case 0x8: t->pc += (t->c && !t->z) ? off : 0; return; 74 | case 0x9: t->pc += (!t->c || t->z) ? off : 0; return; 75 | case 0xA: t->pc += (t->n == t->v) ? off : 0; return; 76 | case 0xB: t->pc += (t->n != t->v) ? off : 0; return; 77 | case 0xC: t->pc += (!t->z && t->n == t->v) ? off : 0; return; 78 | case 0xD: t->pc += (t->z || t->n != t->v) ? off : 0; return; 79 | default: /* LCOV_EXCL_START */ __builtin_unreachable(); 80 | } 81 | } 82 | 83 | // ------------------------------------------------------------------------------------------------- 84 | static inline void BAL(THUMBState *t, uint16_t op) 85 | { 86 | int32_t off; 87 | 88 | if ((off = (op & 0x7FF)) & 0x80) 89 | { 90 | off |= ~0x7FF; 91 | } 92 | 93 | t->pc += off + 2; 94 | } 95 | 96 | 97 | // ------------------------------------------------------------------------------------------------- 98 | static inline void BLO(THUMBState*, uint16_t) 99 | { 100 | 101 | } 102 | 103 | 104 | // ------------------------------------------------------------------------------------------------- 105 | static inline void BLH(THUMBState*, uint16_t) 106 | { 107 | 108 | } 109 | 110 | 111 | // ------------------------------------------------------------------------------------------------- 112 | static inline void ADD(THUMBState *t, int32_t &r, int32_t a) 113 | { 114 | asm volatile 115 | ( "addl %[A], %[R] \n\t" 116 | "sets %[N] \n\t" 117 | "setz %[Z] \n\t" 118 | "setc %[C] \n\t" 119 | "seto %[V] \n\t" 120 | : [N] "=m" (t->n) 121 | , [Z] "=m" (t->z) 122 | , [C] "=m" (t->c) 123 | , [V] "=m" (t->v) 124 | , [R] "=r" (r) 125 | : [A] "g" (a) 126 | : "memory", "cc" 127 | ); 128 | } 129 | 130 | 131 | // ------------------------------------------------------------------------------------------------- 132 | static inline void AND(THUMBState *t, int32_t &d, int32_t s) 133 | { 134 | __builtin_trap(); 135 | } 136 | 137 | 138 | // ------------------------------------------------------------------------------------------------- 139 | static inline void EOR(THUMBState *t, int32_t &d, int32_t s) 140 | { 141 | __builtin_trap(); 142 | } 143 | 144 | 145 | // ------------------------------------------------------------------------------------------------- 146 | static inline void LSL(THUMBState *t, int32_t &d, int32_t s) 147 | { 148 | __builtin_trap(); 149 | } 150 | 151 | 152 | // ------------------------------------------------------------------------------------------------- 153 | static inline void LSR(THUMBState *t, int32_t &d, int32_t s) 154 | { 155 | __builtin_trap(); 156 | } 157 | 158 | 159 | // ------------------------------------------------------------------------------------------------- 160 | static inline void ASR(THUMBState *t, int32_t &d, int32_t s) 161 | { 162 | __builtin_trap(); 163 | } 164 | 165 | 166 | // ------------------------------------------------------------------------------------------------- 167 | static inline void ADC(THUMBState *t, int32_t &d, int32_t s) 168 | { 169 | __builtin_trap(); 170 | } 171 | 172 | 173 | // ------------------------------------------------------------------------------------------------- 174 | static inline void SBC(THUMBState *t, int32_t &d, int32_t s) 175 | { 176 | __builtin_trap(); 177 | } 178 | 179 | 180 | // ------------------------------------------------------------------------------------------------- 181 | static inline void ROR(THUMBState *t, int32_t &d, int32_t s) 182 | { 183 | __builtin_trap(); 184 | } 185 | 186 | 187 | // ------------------------------------------------------------------------------------------------- 188 | static inline void TST(THUMBState *t, int32_t &d, int32_t s) 189 | { 190 | __builtin_trap(); 191 | } 192 | 193 | 194 | // ------------------------------------------------------------------------------------------------- 195 | static inline void NEG(THUMBState *t, int32_t &d, int32_t s) 196 | { 197 | __builtin_trap(); 198 | } 199 | 200 | 201 | // ------------------------------------------------------------------------------------------------- 202 | static inline void CMP(THUMBState *t, int32_t &d, int32_t s) 203 | { 204 | asm volatile 205 | ( "movl %[D], %%eax \n\t" 206 | "cmpl %[S], %%eax \n\t" 207 | "sets %[N] \n\t" 208 | "setz %[Z] \n\t" 209 | "setc %[C] \n\t" 210 | "seto %[V] \n\t" 211 | : [N] "=m" (t->n) 212 | , [Z] "=m" (t->z) 213 | , [C] "=m" (t->c) 214 | , [V] "=m" (t->v) 215 | : [D] "g" (d) 216 | , [S] "g" (s) 217 | : "memory", "cc", "eax" 218 | ); 219 | } 220 | 221 | 222 | // ------------------------------------------------------------------------------------------------- 223 | static inline void CMN(THUMBState *t, int32_t &d, int32_t s) 224 | { 225 | asm volatile 226 | ( "movl %[D], %%eax \n\t" 227 | "addl %[S], %%eax \n\t" 228 | "sets %[N] \n\t" 229 | "setz %[Z] \n\t" 230 | "setc %[C] \n\t" 231 | "seto %[V] \n\t" 232 | : [N] "=m" (t->n) 233 | , [Z] "=m" (t->z) 234 | , [C] "=m" (t->c) 235 | , [V] "=m" (t->v) 236 | : [D] "g" (d) 237 | , [S] "g" (s) 238 | : "memory", "cc", "eax" 239 | ); 240 | } 241 | 242 | 243 | // ------------------------------------------------------------------------------------------------- 244 | static inline void ORR(THUMBState *t, int32_t &d, int32_t s) 245 | { 246 | __builtin_trap(); 247 | } 248 | 249 | 250 | // ------------------------------------------------------------------------------------------------- 251 | static inline void MUL(THUMBState *t, int32_t &d, int32_t s) 252 | { 253 | __builtin_trap(); 254 | } 255 | 256 | 257 | // ------------------------------------------------------------------------------------------------- 258 | static inline void BIC(THUMBState *t, int32_t &d, int32_t s) 259 | { 260 | __builtin_trap(); 261 | } 262 | 263 | 264 | // ------------------------------------------------------------------------------------------------- 265 | static inline void MVN(THUMBState *t, int32_t &d, int32_t s) 266 | { 267 | asm volatile 268 | ( "movl %[S], %[D] \n\t" 269 | "notl %[D] \n\t" 270 | "test %[D], %[D] \n\t" 271 | "sets %[N] \n\t" 272 | "setz %[Z] \n\t" 273 | : [N] "=g" (t->n) 274 | , [Z] "=g" (t->z) 275 | , [D] "=r" (d) 276 | : [S] "r" (s) 277 | : "memory", "cc" 278 | ); 279 | } 280 | 281 | 282 | // ------------------------------------------------------------------------------------------------- 283 | static inline void MOV(THUMBState *t, int32_t &d, int32_t s) 284 | { 285 | asm volatile 286 | ( "movl %[S], %[D] \n\t" 287 | "test %[S], %[S] \n\t" 288 | "sets %[N] \n\t" 289 | "setz %[Z] \n\t" 290 | : [N] "=g" (t->n) 291 | , [Z] "=g" (t->z) 292 | , [D] "=r" (d) 293 | : [S] "r" (s) 294 | : "memory", "cc" 295 | ); 296 | } 297 | 298 | 299 | // ------------------------------------------------------------------------------------------------- 300 | static inline void LSL(THUMBState *t, int32_t &r, int32_t a, int32_t b) 301 | { 302 | asm volatile 303 | ( "movl %[A], %%eax \n\t" 304 | "shll %%cl, %%eax \n\t" 305 | "movl %%eax, %[R] \n\t" 306 | "sets %[N] \n\t" 307 | "setz %[Z] \n\t" 308 | "setc %[C] \n\t" 309 | : [N] "=g" (t->n) 310 | , [Z] "=g" (t->z) 311 | , [C] "=g" (t->c) 312 | , [R] "=g" (r) 313 | : [A] "g" (a) 314 | , [B] "c" (b) 315 | : "memory", "cc", "eax" 316 | ); 317 | } 318 | 319 | 320 | // ------------------------------------------------------------------------------------------------- 321 | static inline void LSR(THUMBState *t, int32_t &r, int32_t a, int32_t b) 322 | { 323 | asm volatile 324 | ( "movl %[A], %%eax \n\t" 325 | "shrl %%cl, %%eax \n\t" 326 | "movl %%eax, %[R] \n\t" 327 | "sets %[N] \n\t" 328 | "setz %[Z] \n\t" 329 | "setc %[C] \n\t" 330 | : [N] "=g" (t->n) 331 | , [Z] "=g" (t->z) 332 | , [C] "=g" (t->c) 333 | , [R] "=g" (r) 334 | : [A] "g" (a) 335 | , [B] "c" (b) 336 | : "memory", "cc", "eax" 337 | ); 338 | } 339 | 340 | 341 | // ------------------------------------------------------------------------------------------------- 342 | static inline void ASR(THUMBState *t, int32_t &r, int32_t a, int32_t b) 343 | { 344 | asm volatile 345 | ( "movl %[A], %%eax \n\t" 346 | "sarl %%cl, %%eax \n\t" 347 | "movl %%eax, %[R] \n\t" 348 | "sets %[N] \n\t" 349 | "setz %[Z] \n\t" 350 | "setc %[C] \n\t" 351 | : [N] "=g" (t->n) 352 | , [Z] "=g" (t->z) 353 | , [C] "=g" (t->c) 354 | , [R] "=g" (r) 355 | : [A] "g" (a) 356 | , [B] "c" (b) 357 | : "memory", "cc", "eax" 358 | ); 359 | } 360 | 361 | 362 | // ------------------------------------------------------------------------------------------------- 363 | static inline void ADD(THUMBState *t, int32_t &r, int32_t a, int32_t b) 364 | { 365 | asm volatile 366 | ( "movl %[B], %%eax \n\t" 367 | "addl %[A], %%eax \n\t" 368 | "movl %%eax, %[R] \n\t" 369 | "sets %[N] \n\t" 370 | "setz %[Z] \n\t" 371 | "setc %[C] \n\t" 372 | "seto %[V] \n\t" 373 | : [N] "=m" (t->n) 374 | , [Z] "=m" (t->z) 375 | , [C] "=m" (t->c) 376 | , [V] "=m" (t->v) 377 | , [R] "=m" (r) 378 | : [A] "g" (a) 379 | , [B] "g" (b) 380 | : "memory", "cc", "eax" 381 | ); 382 | } 383 | 384 | 385 | // ------------------------------------------------------------------------------------------------- 386 | static inline void SUB(THUMBState *t, int32_t &r, int32_t a, int32_t b) 387 | { 388 | asm volatile 389 | ( "movl %[B], %%eax \n\t" 390 | "subl %[A], %%eax \n\t" 391 | "movl %%eax, %[R] \n\t" 392 | "sets %[N] \n\t" 393 | "setz %[Z] \n\t" 394 | "setc %[C] \n\t" 395 | "seto %[V] \n\t" 396 | : [N] "=m" (t->n) 397 | , [Z] "=m" (t->z) 398 | , [C] "=m" (t->c) 399 | , [V] "=m" (t->v) 400 | , [R] "=m" (r) 401 | : [A] "g" (a) 402 | , [B] "g" (b) 403 | : "memory", "cc", "eax" 404 | ); 405 | } 406 | 407 | 408 | // ------------------------------------------------------------------------------------------------- 409 | static inline void LDR(Memory *m, int32_t &r, uint32_t addr) 410 | { 411 | r = m->GetLong(addr); 412 | } 413 | 414 | 415 | // ------------------------------------------------------------------------------------------------- 416 | static inline void STR(Memory*, int32_t&, uint32_t) 417 | { 418 | std::cerr << "STR" << std::endl; 419 | } 420 | 421 | 422 | // ------------------------------------------------------------------------------------------------- 423 | static inline void LDRB(Memory*, int32_t&, uint32_t) 424 | { 425 | std::cerr << "LDRB" << std::endl; 426 | } 427 | 428 | 429 | // ------------------------------------------------------------------------------------------------- 430 | static inline void STRB(Memory*, int32_t&, uint32_t) 431 | { 432 | std::cerr << "STRB" << std::endl; 433 | } 434 | 435 | 436 | // ------------------------------------------------------------------------------------------------- 437 | static inline void LDRH(Memory*, int32_t&, uint32_t) 438 | { 439 | std::cerr << "LDRH" << std::endl; 440 | } 441 | 442 | 443 | // ------------------------------------------------------------------------------------------------- 444 | static inline void STRH(Memory*, int32_t&, uint32_t) 445 | { 446 | std::cerr << "STRH" << std::endl; 447 | } 448 | 449 | 450 | // ------------------------------------------------------------------------------------------------- 451 | static inline void LDSB(Memory*, int32_t&, uint32_t) 452 | { 453 | std::cerr << "LDSB" << std::endl; 454 | } 455 | 456 | 457 | // ------------------------------------------------------------------------------------------------- 458 | static inline void LDSH(Memory*, int32_t&, uint32_t) 459 | { 460 | std::cerr << "LDSH" << std::endl; 461 | } 462 | 463 | 464 | // ------------------------------------------------------------------------------------------------- 465 | static inline void STMIA(Memory*, int32_t&, uint8_t) 466 | { 467 | std::cerr << "STMIA" << std::endl; 468 | } 469 | 470 | 471 | // ------------------------------------------------------------------------------------------------- 472 | static inline void LDMIA(Memory*, int32_t&, uint8_t) 473 | { 474 | std::cerr << "LDMIA" << std::endl; 475 | } 476 | 477 | 478 | // ------------------------------------------------------------------------------------------------- 479 | void ThumbExecute(Emulator *emu) 480 | { 481 | register uint32_t flags; 482 | register uint16_t op = 1; 483 | register Memory *m; 484 | register int32_t *r; 485 | register int hilo; 486 | THUMBState *t; 487 | int32_t off; 488 | 489 | // Cache some pointers 490 | t = &emu->thumbState; 491 | r = t->r; 492 | m = &emu->mem; 493 | 494 | // Initial PC adjustment 495 | hilo = (t->pc >> 1) & 1; 496 | t->pc += hilo ? 2 : 0; 497 | 498 | while (1) 499 | { 500 | // If instruction is in ITT block, it does not affect flags. 501 | // In order to avoid affecting flags, we save the flags at 502 | // the start of every cycle and restore them afterwards 503 | if (t->itt) 504 | { 505 | t->flags = flags; 506 | } 507 | flags = t->flags; 508 | 509 | 510 | // Ajust PC for the pipelining effect. If the address is not 511 | // a multiple of 4, PC must point to the next 4 byte aligned 512 | // address, otherwise PC is advanced by 4 relative to the 513 | // current address 514 | if ((hilo = !hilo)) 515 | { 516 | op = emu->mem.GetInstrWord(t->pc); 517 | t->pc += 4; 518 | } 519 | else 520 | { 521 | op = emu->mem.GetInstrWord(t->pc - 2); 522 | } 523 | 524 | 525 | // Decode the instructions. The most significant 7 bits should 526 | // be enough to distinguish most instrucitions, but additional 527 | // switch statements are required for some categories such as 528 | // ALU operations and miscellaneous instructions 529 | switch (op >> 9) 530 | { 531 | case 0x00 ... 0x03: LSL (t, r[op & 7], r[(op >> 3) & 7], (op >> 6) & 31); continue; 532 | case 0x04 ... 0x07: LSR (t, r[op & 7], r[(op >> 3) & 7], (op >> 6) & 31); continue; 533 | case 0x08 ... 0x0B: ASR (t, r[op & 7], r[(op >> 3) & 7], (op >> 6) & 31); continue; 534 | case 0x28: STR (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 535 | case 0x29: STRH (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 536 | case 0x2A: STRB (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 537 | case 0x2B: LDRH (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 538 | case 0x2C: LDR (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 539 | case 0x2D: LDSB (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 540 | case 0x2E: LDRB (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 541 | case 0x2F: LDSH (m, r[op & 7], r[(op >> 3) & 7] + r[(op >> 6) & 7]); continue; 542 | case 0x30 ... 0x33: STR (m, r[op & 7], r[(op >> 3) & 7] + ((op >> 6 << 2) & 0x7F)); continue; 543 | case 0x34 ... 0x37: LDR (m, r[op & 7], r[(op >> 3) & 7] + ((op >> 6 << 2) & 0x7F)); continue; 544 | case 0x38 ... 0x3B: STRB (m, r[op & 7], r[(op >> 3) & 7] + ((op >> 6) & 0x1F)); continue; 545 | case 0x3C ... 0x3F: LDRB (m, r[op & 7], r[(op >> 3) & 7] + ((op >> 6) & 0x1F)); continue; 546 | case 0x40 ... 0x43: STRH (m, r[op & 7], r[(op >> 3) & 7] + ((op >> 6 << 1) & 0x3F)); continue; 547 | case 0x44 ... 0x47: LDRH (m, r[op & 7], r[(op >> 3) & 7] + ((op >> 6 << 1) & 0x3F)); continue; 548 | case 0x0C: ADD (t, r[op & 7], r[(op >> 6) & 7], r[(op >> 3) & 7]); continue; 549 | case 0x0D: SUB (t, r[op & 7], r[(op >> 6) & 7], r[(op >> 3) & 7]); continue; 550 | case 0x0E: ADD (t, r[op & 7], (op >> 6) & 7, r[(op >> 3) & 7]); continue; 551 | case 0x0F: SUB (t, r[op & 7], (op >> 6) & 7, r[(op >> 3) & 7]); continue; 552 | case 0x24 ... 0x27: LDR (m, r[(op >> 8) & 7], t->pc + ((op & 0xFF) << 2)); continue; 553 | case 0x10 ... 0x13: MOV (t, r[(op >> 8) & 7], op & 0xFF); continue; 554 | case 0x14 ... 0x17: CMP (t, r[(op >> 8) & 7], op & 0xFF); continue; 555 | case 0x18 ... 0x1B: ADD (t, r[(op >> 8) & 7], op & 0xFF, r[(op >> 8) & 7]); continue; 556 | case 0x1C ... 0x1F: SUB (t, r[(op >> 8) & 7], op & 0xFF, r[(op >> 8) & 7]); continue; 557 | case 0x48 ... 0x4B: STR (m, r[(op >> 8) & 7], t->sp + ((op & 0xFF) << 2)); continue; 558 | case 0x4C ... 0x4F: LDR (m, r[(op >> 8) & 7], t->sp + ((op & 0xFF) << 2)); continue; 559 | case 0x60 ... 0x63: STMIA(m, r[(op >> 8) & 7], op & 0xFF); continue; 560 | case 0x64 ... 0x67: LDMIA(m, r[(op >> 8) & 7], op & 0xFF); continue; 561 | case 0x68 ... 0x6E: BCC (t, op); continue; 562 | case 0x70 ... 0x73: BAL (t, op); continue; 563 | case 0x78 ... 0x7B: BLO (t, op >> 9); continue; 564 | case 0x7C ... 0x7F: BLH (t, op >> 9); continue; 565 | case 0x50 ... 0x53: r[(op >> 8) & 3] = t->pc + ((op & 0xFF) << 2); continue; 566 | case 0x54 ... 0x57: r[(op >> 8) & 3] = t->sp + ((op & 0xFF) << 2); continue; 567 | case 0x22 ... 0x23: 568 | switch ((op >> 6) & 0xF) 569 | { 570 | case 0x1: ADD(t, r[0 + (op & 7)], r[8 + ((op >> 3) & 7)]); continue; 571 | case 0x2: ADD(t, r[8 + (op & 7)], r[0 + ((op >> 3) & 7)]); continue; 572 | case 0x3: ADD(t, r[8 + (op & 7)], r[8 + ((op >> 3) & 7)]); continue; 573 | case 0x5: CMP(t, r[0 + (op & 7)], r[8 + ((op >> 3) & 7)]); continue; 574 | case 0x6: CMP(t, r[8 + (op & 7)], r[0 + ((op >> 3) & 7)]); continue; 575 | case 0x7: CMP(t, r[8 + (op & 7)], r[8 + ((op >> 3) & 7)]); continue; 576 | case 0x9: MOV(t, r[0 + (op & 7)], r[8 + ((op >> 3) & 7)]); continue; 577 | case 0xA: MOV(t, r[8 + (op & 7)], r[0 + ((op >> 3) & 7)]); continue; 578 | case 0xB: MOV(t, r[8 + (op & 7)], r[8 + ((op >> 3) & 7)]); continue; 579 | case 0xC: // Bx 580 | case 0xD: // Bx 581 | default: goto und; 582 | } 583 | case 0x20 ... 0x21: 584 | switch ((op >> 6) & 0xF) 585 | { 586 | case 0x0: AND(t, r[op & 7], r[(op >> 3) & 7]); continue; 587 | case 0x1: EOR(t, r[op & 7], r[(op >> 3) & 7]); continue; 588 | case 0x2: LSL(t, r[op & 7], r[(op >> 3) & 7]); continue; 589 | case 0x3: LSR(t, r[op & 7], r[(op >> 3) & 7]); continue; 590 | case 0x4: ASR(t, r[op & 7], r[(op >> 3) & 7]); continue; 591 | case 0x5: ADC(t, r[op & 7], r[(op >> 3) & 7]); continue; 592 | case 0x6: SBC(t, r[op & 7], r[(op >> 3) & 7]); continue; 593 | case 0x7: ROR(t, r[op & 7], r[(op >> 3) & 7]); continue; 594 | case 0x8: TST(t, r[op & 7], r[(op >> 3) & 7]); continue; 595 | case 0x9: NEG(t, r[op & 7], r[(op >> 3) & 7]); continue; 596 | case 0xA: CMP(t, r[op & 7], r[(op >> 3) & 7]); continue; 597 | case 0xB: CMN(t, r[op & 7], r[(op >> 3) & 7]); continue; 598 | case 0xC: ORR(t, r[op & 7], r[(op >> 3) & 7]); continue; 599 | case 0xD: MUL(t, r[op & 7], r[(op >> 3) & 7]); continue; 600 | case 0xE: BIC(t, r[op & 7], r[(op >> 3) & 7]); continue; 601 | case 0xF: MVN(t, r[op & 7], r[(op >> 3) & 7]); continue; 602 | default: /* LCOV_EXCL_START */ __builtin_unreachable(); 603 | } 604 | case 0x58 ... 0x5F: 605 | switch ((op >> 5) & 0x7F) 606 | { 607 | case 0x00 ... 0x03: /*ADD SP, SP, #Imm7*/ continue; 608 | case 0x04 ... 0x07: /*SUB SP, SP, #Imm7*/ continue; 609 | case 0x10 ... 0x11: /*SXTH*/ continue; 610 | case 0x12 ... 0x13: /*SXTB*/ continue; 611 | case 0x14 ... 0x15: /*UXTH*/ continue; 612 | case 0x16 ... 0x17: /*UXTB*/ continue; 613 | case 0x20 ... 0x2F: /*PUSH*/ continue; 614 | case 0x33: /*CPS*/ continue; 615 | case 0x50 ... 0x51: /*REV*/ continue; 616 | case 0x52 ... 0x53: /*REV16*/ continue; 617 | case 0x54 ... 0x55: /*REVSH*/ continue; 618 | case 0x60 ... 0x6F: /*POP*/ continue; 619 | case 0x70 ... 0x77: /*BKPT*/ continue; 620 | case 0x78 ... 0x7F: 621 | { 622 | if (op & 0xF) 623 | { 624 | // IT 625 | continue; 626 | } 627 | 628 | switch ((op >> 4) & 0xF) 629 | { 630 | case 0x0: /*NOP*/ continue; 631 | case 0x1: /*YIELD*/ continue; 632 | case 0x2: /*WFE*/ continue; 633 | case 0x3: /*WFI*/ continue; 634 | case 0x4: /*SEV*/ continue; 635 | } 636 | } 637 | default: goto und; 638 | } 639 | case 0x74 ... 0x77: /*THUMB2*/ __builtin_trap(); continue; 640 | case 0x6F: 641 | { 642 | if ((op >> 8) & 0x1) 643 | { 644 | goto swi; 645 | } 646 | else 647 | { 648 | goto und; 649 | } 650 | } 651 | } 652 | } 653 | 654 | // Swap to ARM 655 | bx: 656 | { 657 | return; 658 | } 659 | 660 | // Software interrupt 661 | swi: 662 | { 663 | return; 664 | } 665 | 666 | // Undefined interrupt 667 | und: 668 | { 669 | return; 670 | } 671 | } 672 | --------------------------------------------------------------------------------