diff --git a/README.md b/README.md index 08f9c1cd..d1336e04 100644 --- a/README.md +++ b/README.md @@ -37,3 +37,124 @@ Plans * ARMv7A guest support * ARMv5 guest support * ARMv8 host support + +Usage Example +------------- + +The below is a minimal example. Bring-your-own memory system. + +```cpp +#include +#include +#include +#include + +#include +#include + +using u8 = std::uint8_t; +using u16 = std::uint16_t; +using u32 = std::uint32_t; +using u64 = std::uint64_t; + +class MyEnvironment final : public Dynarmic::A32::UserCallbacks { +public: + u64 ticks_left = 0; + std::array memory{}; + + u8 MemoryRead8(u32 vaddr) override { + if (vaddr >= memory.size()) { + return 0; + } + return memory[vaddr]; + } + + u16 MemoryRead16(u32 vaddr) override { + return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8; + } + + u32 MemoryRead32(u32 vaddr) override { + return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16; + } + + u64 MemoryRead64(u32 vaddr) override { + return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32; + } + + void MemoryWrite8(u32 vaddr, u8 value) override { + if (vaddr >= memory.size()) { + return; + } + memory[vaddr] = value; + } + + void MemoryWrite16(u32 vaddr, u16 value) override { + MemoryWrite8(vaddr, u8(value)); + MemoryWrite8(vaddr + 1, u8(value >> 8)); + } + + void MemoryWrite32(u32 vaddr, u32 value) override { + MemoryWrite16(vaddr, u16(value)); + MemoryWrite16(vaddr + 2, u16(value >> 16)); + } + + void MemoryWrite64(u32 vaddr, u64 value) override { + MemoryWrite32(vaddr, u32(value)); + MemoryWrite32(vaddr + 4, u32(value >> 32)); + } + + void InterpreterFallback(u32 pc, size_t num_instructions) override { + // This is never called in practice. + std::terminate(); + } + + void CallSVC(u32 swi) override { + // Do something. + } + + void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { + // Do something. + } + + void AddTicks(u64 ticks) override { + if (ticks > ticks_left) { + ticks_left = 0; + return; + } + ticks_left -= ticks; + } + + u64 GetTicksRemaining() override { + return ticks_left; + } +}; + +int main(int argc, char** argv) { + MyEnvironment env; + Dynarmic::A32::UserConfig user_config; + user_config.callbacks = &env; + Dynarmic::A32::Jit cpu{user_config}; + + // Execute at least 1 instruction. + // (Note: More than one instruction may be executed.) + env.ticks_left = 1; + + // Write some code to memory. + env.MemoryWrite16(0, 0x0088); // lsls r0, r1, #2 + env.MemoryWrite16(2, 0xE7FE); // b +#0 (infinite loop) + + // Setup registers. + cpu.Regs()[0] = 1; + cpu.Regs()[1] = 2; + cpu.Regs()[15] = 0; // PC = 0 + cpu.SetCpsr(0x00000030); // Thumb mode + + // Execute! + cpu.Run(); + + // Here we would expect jit.Regs()[0] == 8 + printf("R0: %u\n", jit.Regs()[0]); + + return 0; +} +```