From e4bd60ae42b00332a652181816af827ef3cc6cd8 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Mon, 19 Apr 2021 22:21:44 +0100 Subject: [PATCH] Import the mgba-test-runner --- mgba-test-runner/Cargo.lock | 72 +++ mgba-test-runner/Cargo.toml | 14 + mgba-test-runner/build.rs | 23 + .../c/include/mgba-util/circle-buffer.h | 38 ++ mgba-test-runner/c/include/mgba-util/common.h | 306 +++++++++ .../c/include/mgba-util/configuration.h | 46 ++ mgba-test-runner/c/include/mgba-util/crc32.h | 26 + .../c/include/mgba-util/dllexports.h | 19 + .../c/include/mgba-util/elf-read.h | 45 ++ mgba-test-runner/c/include/mgba-util/export.h | 20 + .../c/include/mgba-util/formatting.h | 36 ++ mgba-test-runner/c/include/mgba-util/gui.h | 92 +++ .../c/include/mgba-util/gui/file-select.h | 21 + .../c/include/mgba-util/gui/font-metrics.h | 14 + .../c/include/mgba-util/gui/font.h | 97 +++ .../c/include/mgba-util/gui/menu.h | 83 +++ mgba-test-runner/c/include/mgba-util/hash.h | 17 + mgba-test-runner/c/include/mgba-util/math.h | 106 +++ mgba-test-runner/c/include/mgba-util/memory.h | 18 + mgba-test-runner/c/include/mgba-util/patch.h | 26 + .../c/include/mgba-util/patch/fast.h | 38 ++ .../c/include/mgba-util/patch/ips.h | 19 + .../c/include/mgba-util/patch/ups.h | 19 + .../include/mgba-util/platform/3ds/3ds-vfs.h | 17 + .../mgba-util/platform/3ds/threading.h | 87 +++ .../mgba-util/platform/posix/threading.h | 119 ++++ .../include/mgba-util/platform/psp2/sce-vfs.h | 18 + .../mgba-util/platform/psp2/threading.h | 162 +++++ .../mgba-util/platform/switch/threading.h | 87 +++ .../mgba-util/platform/windows/getopt.h | 607 ++++++++++++++++++ .../mgba-util/platform/windows/threading.h | 104 +++ mgba-test-runner/c/include/mgba-util/png-io.h | 55 ++ .../c/include/mgba-util/ring-fifo.h | 30 + mgba-test-runner/c/include/mgba-util/socket.h | 418 ++++++++++++ mgba-test-runner/c/include/mgba-util/string.h | 52 ++ mgba-test-runner/c/include/mgba-util/table.h | 57 ++ .../c/include/mgba-util/text-codec.h | 36 ++ .../c/include/mgba-util/threading.h | 121 ++++ mgba-test-runner/c/include/mgba-util/vector.h | 104 +++ mgba-test-runner/c/include/mgba-util/vfs.h | 115 ++++ .../c/include/mgba/core/bitmap-cache.h | 64 ++ .../c/include/mgba/core/blip_buf.h | 72 +++ .../c/include/mgba/core/cache-set.h | 38 ++ mgba-test-runner/c/include/mgba/core/cheats.h | 129 ++++ mgba-test-runner/c/include/mgba/core/config.h | 115 ++++ mgba-test-runner/c/include/mgba/core/core.h | 214 ++++++ mgba-test-runner/c/include/mgba/core/cpu.h | 31 + .../c/include/mgba/core/directories.h | 42 ++ mgba-test-runner/c/include/mgba/core/input.h | 89 +++ .../c/include/mgba/core/interface.h | 288 +++++++++ .../c/include/mgba/core/library.h | 53 ++ .../c/include/mgba/core/lockstep.h | 58 ++ mgba-test-runner/c/include/mgba/core/log.h | 72 +++ .../c/include/mgba/core/map-cache.h | 79 +++ .../c/include/mgba/core/mem-search.h | 62 ++ mgba-test-runner/c/include/mgba/core/rewind.h | 46 ++ .../c/include/mgba/core/scripting.h | 52 ++ .../c/include/mgba/core/serialize.h | 56 ++ mgba-test-runner/c/include/mgba/core/sync.h | 43 ++ mgba-test-runner/c/include/mgba/core/thread.h | 123 ++++ .../c/include/mgba/core/tile-cache.h | 63 ++ mgba-test-runner/c/include/mgba/core/timing.h | 49 ++ .../c/include/mgba/core/version.h | 27 + .../c/include/mgba/debugger/debugger.h | 157 +++++ .../c/include/mgba/feature/commandline.h | 60 ++ .../c/include/mgba/feature/thread-proxy.h | 41 ++ .../c/include/mgba/feature/video-logger.h | 139 ++++ mgba-test-runner/c/include/mgba/gb/core.h | 21 + .../c/include/mgba/gb/interface.h | 74 +++ mgba-test-runner/c/include/mgba/gba/core.h | 21 + .../c/include/mgba/gba/interface.h | 105 +++ .../c/include/mgba/internal/arm/arm.h | 208 ++++++ .../mgba/internal/arm/debugger/cli-debugger.h | 18 + .../mgba/internal/arm/debugger/debugger.h | 52 ++ .../internal/arm/debugger/memory-debugger.h | 20 + .../mgba/internal/arm/decoder-inlines.h | 37 ++ .../c/include/mgba/internal/arm/decoder.h | 231 +++++++ .../c/include/mgba/internal/arm/emitter-arm.h | 335 ++++++++++ .../mgba/internal/arm/emitter-inlines.h | 32 + .../include/mgba/internal/arm/emitter-thumb.h | 113 ++++ .../c/include/mgba/internal/arm/isa-arm.h | 22 + .../c/include/mgba/internal/arm/isa-inlines.h | 171 +++++ .../c/include/mgba/internal/arm/isa-thumb.h | 20 + .../c/include/mgba/internal/arm/macros.h | 18 + .../mgba/internal/debugger/cli-debugger.h | 105 +++ .../include/mgba/internal/debugger/gdb-stub.h | 54 ++ .../c/include/mgba/internal/debugger/parser.h | 78 +++ .../mgba/internal/debugger/stack-trace.h | 62 ++ .../include/mgba/internal/debugger/symbols.h | 29 + .../c/include/mgba/internal/gb/audio.h | 257 ++++++++ .../c/include/mgba/internal/gb/cheats.h | 26 + .../mgba/internal/gb/debugger/debugger.h | 20 + .../mgba/internal/gb/debugger/symbols.h | 19 + .../c/include/mgba/internal/gb/extra/cli.h | 28 + .../c/include/mgba/internal/gb/gb.h | 189 ++++++ .../c/include/mgba/internal/gb/input.h | 31 + .../c/include/mgba/internal/gb/io.h | 127 ++++ .../c/include/mgba/internal/gb/mbc.h | 50 ++ .../c/include/mgba/internal/gb/memory.h | 251 ++++++++ .../c/include/mgba/internal/gb/overrides.h | 34 + .../mgba/internal/gb/renderers/cache-set.h | 23 + .../mgba/internal/gb/renderers/proxy.h | 29 + .../mgba/internal/gb/renderers/software.h | 71 ++ .../c/include/mgba/internal/gb/serialize.h | 445 +++++++++++++ .../c/include/mgba/internal/gb/sio.h | 52 ++ .../c/include/mgba/internal/gb/sio/lockstep.h | 49 ++ .../c/include/mgba/internal/gb/sio/printer.h | 74 +++ .../c/include/mgba/internal/gb/timer.h | 45 ++ .../c/include/mgba/internal/gb/video.h | 198 ++++++ .../c/include/mgba/internal/gba/audio.h | 319 +++++++++ .../c/include/mgba/internal/gba/bios.h | 73 +++ .../c/include/mgba/internal/gba/cheats.h | 175 +++++ .../c/include/mgba/internal/gba/dma.h | 67 ++ .../mgba/internal/gba/extra/audio-mixer.h | 19 + .../c/include/mgba/internal/gba/extra/cli.h | 30 + .../c/include/mgba/internal/gba/gba.h | 185 ++++++ .../c/include/mgba/internal/gba/hardware.h | 215 +++++++ .../c/include/mgba/internal/gba/input.h | 34 + .../c/include/mgba/internal/gba/io.h | 181 ++++++ .../c/include/mgba/internal/gba/matrix.h | 35 + .../c/include/mgba/internal/gba/memory.h | 181 ++++++ .../c/include/mgba/internal/gba/overrides.h | 36 ++ .../mgba/internal/gba/renderers/cache-set.h | 22 + .../mgba/internal/gba/renderers/common.h | 27 + .../include/mgba/internal/gba/renderers/gl.h | 207 ++++++ .../mgba/internal/gba/renderers/proxy.h | 28 + .../internal/gba/renderers/video-software.h | 153 +++++ .../c/include/mgba/internal/gba/savedata.h | 128 ++++ .../c/include/mgba/internal/gba/serialize.h | 390 +++++++++++ .../c/include/mgba/internal/gba/sharkport.h | 21 + .../c/include/mgba/internal/gba/sio.h | 89 +++ .../c/include/mgba/internal/gba/sio/dolphin.h | 41 ++ .../include/mgba/internal/gba/sio/lockstep.h | 53 ++ .../c/include/mgba/internal/gba/timer.h | 36 ++ .../c/include/mgba/internal/gba/vfame.h | 38 ++ .../c/include/mgba/internal/gba/video.h | 240 +++++++ .../internal/sm83/debugger/cli-debugger.h | 18 + .../mgba/internal/sm83/debugger/debugger.h | 43 ++ .../internal/sm83/debugger/memory-debugger.h | 20 + .../c/include/mgba/internal/sm83/decoder.h | 112 ++++ .../include/mgba/internal/sm83/emitter-sm83.h | 528 +++++++++++++++ .../c/include/mgba/internal/sm83/isa-sm83.h | 20 + .../c/include/mgba/internal/sm83/sm83.h | 172 +++++ mgba-test-runner/c/test-runner.c | 135 ++++ mgba-test-runner/c/test-runner.h | 17 + mgba-test-runner/src/main.rs | 89 +++ mgba-test-runner/src/runner/bindings.rs | 274 ++++++++ mgba-test-runner/src/runner/mod.rs | 86 +++ 148 files changed, 14027 insertions(+) create mode 100644 mgba-test-runner/Cargo.lock create mode 100644 mgba-test-runner/Cargo.toml create mode 100644 mgba-test-runner/build.rs create mode 100644 mgba-test-runner/c/include/mgba-util/circle-buffer.h create mode 100644 mgba-test-runner/c/include/mgba-util/common.h create mode 100644 mgba-test-runner/c/include/mgba-util/configuration.h create mode 100644 mgba-test-runner/c/include/mgba-util/crc32.h create mode 100644 mgba-test-runner/c/include/mgba-util/dllexports.h create mode 100644 mgba-test-runner/c/include/mgba-util/elf-read.h create mode 100644 mgba-test-runner/c/include/mgba-util/export.h create mode 100644 mgba-test-runner/c/include/mgba-util/formatting.h create mode 100644 mgba-test-runner/c/include/mgba-util/gui.h create mode 100644 mgba-test-runner/c/include/mgba-util/gui/file-select.h create mode 100644 mgba-test-runner/c/include/mgba-util/gui/font-metrics.h create mode 100644 mgba-test-runner/c/include/mgba-util/gui/font.h create mode 100644 mgba-test-runner/c/include/mgba-util/gui/menu.h create mode 100644 mgba-test-runner/c/include/mgba-util/hash.h create mode 100644 mgba-test-runner/c/include/mgba-util/math.h create mode 100644 mgba-test-runner/c/include/mgba-util/memory.h create mode 100644 mgba-test-runner/c/include/mgba-util/patch.h create mode 100644 mgba-test-runner/c/include/mgba-util/patch/fast.h create mode 100644 mgba-test-runner/c/include/mgba-util/patch/ips.h create mode 100644 mgba-test-runner/c/include/mgba-util/patch/ups.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/3ds/3ds-vfs.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/3ds/threading.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/posix/threading.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/psp2/sce-vfs.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/psp2/threading.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/switch/threading.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/windows/getopt.h create mode 100644 mgba-test-runner/c/include/mgba-util/platform/windows/threading.h create mode 100644 mgba-test-runner/c/include/mgba-util/png-io.h create mode 100644 mgba-test-runner/c/include/mgba-util/ring-fifo.h create mode 100644 mgba-test-runner/c/include/mgba-util/socket.h create mode 100644 mgba-test-runner/c/include/mgba-util/string.h create mode 100644 mgba-test-runner/c/include/mgba-util/table.h create mode 100644 mgba-test-runner/c/include/mgba-util/text-codec.h create mode 100644 mgba-test-runner/c/include/mgba-util/threading.h create mode 100644 mgba-test-runner/c/include/mgba-util/vector.h create mode 100644 mgba-test-runner/c/include/mgba-util/vfs.h create mode 100644 mgba-test-runner/c/include/mgba/core/bitmap-cache.h create mode 100644 mgba-test-runner/c/include/mgba/core/blip_buf.h create mode 100644 mgba-test-runner/c/include/mgba/core/cache-set.h create mode 100644 mgba-test-runner/c/include/mgba/core/cheats.h create mode 100644 mgba-test-runner/c/include/mgba/core/config.h create mode 100644 mgba-test-runner/c/include/mgba/core/core.h create mode 100644 mgba-test-runner/c/include/mgba/core/cpu.h create mode 100644 mgba-test-runner/c/include/mgba/core/directories.h create mode 100644 mgba-test-runner/c/include/mgba/core/input.h create mode 100644 mgba-test-runner/c/include/mgba/core/interface.h create mode 100644 mgba-test-runner/c/include/mgba/core/library.h create mode 100644 mgba-test-runner/c/include/mgba/core/lockstep.h create mode 100644 mgba-test-runner/c/include/mgba/core/log.h create mode 100644 mgba-test-runner/c/include/mgba/core/map-cache.h create mode 100644 mgba-test-runner/c/include/mgba/core/mem-search.h create mode 100644 mgba-test-runner/c/include/mgba/core/rewind.h create mode 100644 mgba-test-runner/c/include/mgba/core/scripting.h create mode 100644 mgba-test-runner/c/include/mgba/core/serialize.h create mode 100644 mgba-test-runner/c/include/mgba/core/sync.h create mode 100644 mgba-test-runner/c/include/mgba/core/thread.h create mode 100644 mgba-test-runner/c/include/mgba/core/tile-cache.h create mode 100644 mgba-test-runner/c/include/mgba/core/timing.h create mode 100644 mgba-test-runner/c/include/mgba/core/version.h create mode 100644 mgba-test-runner/c/include/mgba/debugger/debugger.h create mode 100644 mgba-test-runner/c/include/mgba/feature/commandline.h create mode 100644 mgba-test-runner/c/include/mgba/feature/thread-proxy.h create mode 100644 mgba-test-runner/c/include/mgba/feature/video-logger.h create mode 100644 mgba-test-runner/c/include/mgba/gb/core.h create mode 100644 mgba-test-runner/c/include/mgba/gb/interface.h create mode 100644 mgba-test-runner/c/include/mgba/gba/core.h create mode 100644 mgba-test-runner/c/include/mgba/gba/interface.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/arm.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/debugger/cli-debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/debugger/debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/debugger/memory-debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/decoder-inlines.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/decoder.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/emitter-arm.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/emitter-inlines.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/emitter-thumb.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/isa-arm.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/isa-inlines.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/isa-thumb.h create mode 100644 mgba-test-runner/c/include/mgba/internal/arm/macros.h create mode 100644 mgba-test-runner/c/include/mgba/internal/debugger/cli-debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/debugger/gdb-stub.h create mode 100644 mgba-test-runner/c/include/mgba/internal/debugger/parser.h create mode 100644 mgba-test-runner/c/include/mgba/internal/debugger/stack-trace.h create mode 100644 mgba-test-runner/c/include/mgba/internal/debugger/symbols.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/audio.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/cheats.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/debugger/debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/debugger/symbols.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/extra/cli.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/gb.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/input.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/io.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/mbc.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/memory.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/overrides.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/renderers/cache-set.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/renderers/proxy.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/renderers/software.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/serialize.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/sio.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/sio/lockstep.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/sio/printer.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/timer.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gb/video.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/audio.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/bios.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/cheats.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/dma.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/extra/audio-mixer.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/extra/cli.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/gba.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/hardware.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/input.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/io.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/matrix.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/memory.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/overrides.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/renderers/cache-set.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/renderers/common.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/renderers/gl.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/renderers/proxy.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/renderers/video-software.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/savedata.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/serialize.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/sharkport.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/sio.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/sio/dolphin.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/sio/lockstep.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/timer.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/vfame.h create mode 100644 mgba-test-runner/c/include/mgba/internal/gba/video.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/debugger/cli-debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/debugger/debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/debugger/memory-debugger.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/decoder.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/emitter-sm83.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/isa-sm83.h create mode 100644 mgba-test-runner/c/include/mgba/internal/sm83/sm83.h create mode 100644 mgba-test-runner/c/test-runner.c create mode 100644 mgba-test-runner/c/test-runner.h create mode 100644 mgba-test-runner/src/main.rs create mode 100644 mgba-test-runner/src/runner/bindings.rs create mode 100644 mgba-test-runner/src/runner/mod.rs diff --git a/mgba-test-runner/Cargo.lock b/mgba-test-runner/Cargo.lock new file mode 100644 index 00000000..59fb5207 --- /dev/null +++ b/mgba-test-runner/Cargo.lock @@ -0,0 +1,72 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +dependencies = [ + "jobserver", +] + +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "mgba-test-runner" +version = "0.1.0" +dependencies = [ + "anyhow", + "cc", + "regex", +] + +[[package]] +name = "regex" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" diff --git a/mgba-test-runner/Cargo.toml b/mgba-test-runner/Cargo.toml new file mode 100644 index 00000000..bbe3e53d --- /dev/null +++ b/mgba-test-runner/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mgba-test-runner" +version = "0.1.0" +authors = ["Corwin Kuiper "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "1" +anyhow = "1.0" + +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } diff --git a/mgba-test-runner/build.rs b/mgba-test-runner/build.rs new file mode 100644 index 00000000..72261004 --- /dev/null +++ b/mgba-test-runner/build.rs @@ -0,0 +1,23 @@ +use std::path; + +fn find_mgba_library() -> Option<&'static str> { + const POTENTIAL_LIBRARY_LOCATIONS: &[&str] = &[ + "/usr/lib/libmgba.so.0.9.0", + "/usr/local/lib/libmgba.so.0.9.0", + ]; + + POTENTIAL_LIBRARY_LOCATIONS + .iter() + .find(|file_path| path::Path::new(file_path).exists()) + .copied() +} + +fn main() { + let mgba_library = find_mgba_library().expect("Need mgba 0.9.0 installed"); + + cc::Build::new() + .file("c/test-runner.c") + .object(mgba_library) + .include("c/include") + .compile("test-runner"); +} diff --git a/mgba-test-runner/c/include/mgba-util/circle-buffer.h b/mgba-test-runner/c/include/mgba-util/circle-buffer.h new file mode 100644 index 00000000..dee1f1f2 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/circle-buffer.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CIRCLE_BUFFER_H +#define CIRCLE_BUFFER_H + +#include + +CXX_GUARD_START + +struct CircleBuffer { + void* data; + size_t capacity; + size_t size; + void* readPtr; + void* writePtr; +}; + +void CircleBufferInit(struct CircleBuffer* buffer, unsigned capacity); +void CircleBufferDeinit(struct CircleBuffer* buffer); +size_t CircleBufferSize(const struct CircleBuffer* buffer); +size_t CircleBufferCapacity(const struct CircleBuffer* buffer); +void CircleBufferClear(struct CircleBuffer* buffer); +int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value); +int CircleBufferWrite16(struct CircleBuffer* buffer, int16_t value); +int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value); +size_t CircleBufferWrite(struct CircleBuffer* buffer, const void* input, size_t length); +int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value); +int CircleBufferRead16(struct CircleBuffer* buffer, int16_t* value); +int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value); +size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length); +size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/common.h b/mgba-test-runner/c/include/mgba-util/common.h new file mode 100644 index 00000000..50dfec94 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/common.h @@ -0,0 +1,306 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef COMMON_H +#define COMMON_H + +#ifdef __cplusplus +#define CXX_GUARD_START extern "C" { +#define CXX_GUARD_END } +#else +#define CXX_GUARD_START +#define CXX_GUARD_END +#endif + +#ifdef __MINGW32__ +#define __USE_MINGW_ANSI_STDIO 1 +#endif + +CXX_GUARD_START + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +// WinSock2 gets very angry if it's included too late +#include +#endif + +#if defined(_MSC_VER) || defined(__cplusplus) +#define restrict __restrict +#endif + +#ifdef _MSC_VER +#include +#include +typedef intptr_t ssize_t; +#define PATH_MAX MAX_PATH +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define ftruncate _chsize +#define snprintf _snprintf +#define strdup _strdup +#define lseek _lseek +#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) +#else +#include +#include +#include +#endif +#ifdef GEKKO +typedef intptr_t ssize_t; +#endif + +#ifdef PSP2 +// For PATH_MAX on modern toolchains +#include +#endif + +#include + +#ifndef SSIZE_MAX +#define SSIZE_MAX ((ssize_t) (SIZE_MAX >> 1)) +#endif + +#ifndef UNUSED +#define UNUSED(V) (void)(V) +#endif + +#ifndef M_PI +#define M_PI 3.141592654f +#endif + +#if !defined(_MSC_VER) && (defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +#define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE) +#define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE) +#define ATOMIC_ADD(DST, OP) __atomic_add_fetch(&DST, OP, __ATOMIC_RELEASE) +#define ATOMIC_SUB(DST, OP) __atomic_sub_fetch(&DST, OP, __ATOMIC_RELEASE) +#define ATOMIC_OR(DST, OP) __atomic_or_fetch(&DST, OP, __ATOMIC_RELEASE) +#define ATOMIC_AND(DST, OP) __atomic_and_fetch(&DST, OP, __ATOMIC_RELEASE) +#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) __atomic_compare_exchange_n(&DST, &EXPECTED, SRC, true,__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE) +#define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC) +#define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC) +#elif defined _MSC_VER +#define ATOMIC_STORE(DST, SRC) InterlockedExchange(&DST, SRC) +#define ATOMIC_LOAD(DST, SRC) DST = InterlockedOrAcquire(&SRC, 0) +#define ATOMIC_ADD(DST, OP) InterlockedAddRelease(&DST, OP) +#define ATOMIC_SUB(DST, OP) InterlockedAddRelease(&DST, -OP) +#define ATOMIC_OR(DST, OP) InterlockedOrRelease(&DST, OP) +#define ATOMIC_AND(DST, OP) InterlockedAndRelease(&DST, OP) +#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) (InterlockedCompareExchange(&DST, SRC, EXPECTED) == EXPECTED) +#define ATOMIC_STORE_PTR(DST, SRC) InterlockedExchangePointer(&DST, SRC) +#define ATOMIC_LOAD_PTR(DST, SRC) DST = InterlockedCompareExchangePointer(&SRC, 0, 0) +#else +// TODO +#define ATOMIC_STORE(DST, SRC) DST = SRC +#define ATOMIC_LOAD(DST, SRC) DST = SRC +#define ATOMIC_ADD(DST, OP) DST += OP +#define ATOMIC_SUB(DST, OP) DST -= OP +#define ATOMIC_OR(DST, OP) DST |= OP +#define ATOMIC_AND(DST, OP) DST &= OP +#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false) +#define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC) +#define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC) +#endif + +#if defined(_3DS) || defined(GEKKO) || defined(PSP2) +// newlib doesn't support %z properly by default +#define PRIz "" +#elif defined(_MSC_VER) +#define PRIz "I" +#else +#define PRIz "z" +#endif + +#if defined __BIG_ENDIAN__ +#define LOAD_64BE(DEST, ADDR, ARR) DEST = *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_32BE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_16BE(DEST, ADDR, ARR) DEST = *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define STORE_64BE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_32BE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_16BE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#if defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(*(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_32LE(DEST, ADDR, ARR) DEST = __builtin_bswap32(*(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_16LE(DEST, ADDR, ARR) DEST = __builtin_bswap16(*(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap64(SRC) +#define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap32(SRC) +#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap16(SRC) +#elif defined(__PPC__) || defined(__POWERPC__) +#define LOAD_32LE(DEST, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + const void* _ptr = (ARR); \ + __asm__("lwbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ +} + +#define LOAD_16LE(DEST, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + const void* _ptr = (ARR); \ + __asm__("lhbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ +} + +#define STORE_32LE(SRC, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + void* _ptr = (ARR); \ + __asm__("stwbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \ +} + +#define STORE_16LE(SRC, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + void* _ptr = (ARR); \ + __asm__("sthbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \ +} + +#ifndef _ARCH_PWR7 +#define LOAD_64LE(DEST, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + union { \ + struct { \ + uint32_t hi; \ + uint32_t lo; \ + }; \ + uint64_t b64; \ + } bswap; \ + const void* _ptr = (ARR); \ + __asm__( \ + "lwbrx %0, %2, %3 \n" \ + "lwbrx %1, %2, %4 \n" \ + : "=&r"(bswap.lo), "=&r"(bswap.hi) : "b"(_ptr), "r"(_addr), "r"(_addr + 4)) ; \ + DEST = bswap.b64; \ +} + +#define STORE_64LE(SRC, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + union { \ + struct { \ + uint32_t hi; \ + uint32_t lo; \ + }; \ + uint64_t b64; \ + } bswap = { .b64 = SRC }; \ + const void* _ptr = (ARR); \ + __asm__( \ + "stwbrx %0, %2, %3 \n" \ + "stwbrx %1, %2, %4 \n" \ + : : "r"(bswap.hi), "r"(bswap.lo), "b"(_ptr), "r"(_addr), "r"(_addr + 4) : "memory"); \ +} +#else +#define LOAD_64LE(DEST, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + const void* _ptr = (ARR); \ + __asm__("ldbrx %0, %1, %2" : "=r"(DEST) : "b"(_ptr), "r"(_addr)); \ +} + +#define STORE_64LE(SRC, ADDR, ARR) { \ + size_t _addr = (ADDR); \ + void* _ptr = (ARR); \ + __asm__("stdbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr) : "memory"); \ +} +#endif +#else +#error Big endian build not supported on this platform. +#endif +#else +#define LOAD_64LE(DEST, ADDR, ARR) DEST = *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_32LE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_16LE(DEST, ADDR, ARR) DEST = *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#ifdef _MSC_VER +#define LOAD_64BE(DEST, ADDR, ARR) DEST = _byteswap_uint64(*(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_32BE(DEST, ADDR, ARR) DEST = _byteswap_ulong(*(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_16BE(DEST, ADDR, ARR) DEST = _byteswap_ushort(*(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define STORE_64BE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = _byteswap_uint64(SRC) +#define STORE_32BE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = _byteswap_ulong(SRC) +#define STORE_16BE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = _byteswap_ushort(SRC) +#else +#define LOAD_64BE(DEST, ADDR, ARR) DEST = __builtin_bswap64(*(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_32BE(DEST, ADDR, ARR) DEST = __builtin_bswap32(*(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define LOAD_16BE(DEST, ADDR, ARR) DEST = __builtin_bswap16(*(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))) +#define STORE_64BE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap64(SRC) +#define STORE_32BE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap32(SRC) +#define STORE_16BE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = __builtin_bswap16(SRC) +#endif +#endif + +#define MAKE_MASK(START, END) (((1 << ((END) - (START))) - 1) << (START)) +#define CHECK_BITS(SRC, START, END) ((SRC) & MAKE_MASK(START, END)) +#define EXT_BITS(SRC, START, END) (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1)) +#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END))) +#define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END)) +#define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END)) +#define TEST_FILL_BITS(SRC, START, END, TEST) ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END))) + +#ifdef _MSC_VER +#pragma section(".CRT$XCU",read) +#define ATTRIBUTE_UNUSED +#define ATTRIBUTE_FORMAT(X, Y, Z) +#define ATTRIBUTE_NOINLINE +// Adapted from https://stackoverflow.com/a/2390626 +#define _CONSTRUCTOR(FN, PRE) \ + static void FN(void); \ + __declspec(allocate(".CRT$XCU")) void (*_CONSTRUCTOR_ ## FN)(void) = FN; \ + static void FN(void) +#ifdef _WIN64 +#define CONSTRUCTOR(FN) _CONSTRUCTOR(FN, "") +#else +#define CONSTRUCTOR(FN) _CONSTRUCTOR(FN, "_") +#endif +#else +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#define ATTRIBUTE_FORMAT(X, Y, Z) __attribute__((format(X, Y, Z))) +#define ATTRIBUTE_NOINLINE __attribute__((noinline)) +#define CONSTRUCTOR(FN) static __attribute__((constructor)) void FN(void) +#endif + +#define DECL_BITFIELD(NAME, TYPE) typedef TYPE NAME + +#define DECL_BITS(TYPE, FIELD, START, SIZE) \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## Is ## FIELD (TYPE src) { \ + return CHECK_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## Get ## FIELD (TYPE src) { \ + return EXT_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## Clear ## FIELD (TYPE src) { \ + return CLEAR_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## Fill ## FIELD (TYPE src) { \ + return FILL_BITS(src, (START), (START) + (SIZE)); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \ + return INS_BITS(src, (START), (START) + (SIZE), bits); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## TestFill ## FIELD (TYPE src, bool test) { \ + return TEST_FILL_BITS(src, (START), (START) + (SIZE), test); \ + } + +#define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1) + +#ifndef _MSC_VER +#define LIKELY(X) __builtin_expect(!!(X), 1) +#define UNLIKELY(X) __builtin_expect(!!(X), 0) +#else +#define LIKELY(X) (!!(X)) +#define UNLIKELY(X) (!!(X)) +#endif + +#define ROR(I, ROTATE) ((((uint32_t) (I)) >> ROTATE) | ((uint32_t) (I) << ((-ROTATE) & 31))) + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/configuration.h b/mgba-test-runner/c/include/mgba-util/configuration.h new file mode 100644 index 00000000..3409db0e --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/configuration.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include + +CXX_GUARD_START + +#include + +struct VFile; + +struct Configuration { + struct Table sections; + struct Table root; +}; + +void ConfigurationInit(struct Configuration*); +void ConfigurationDeinit(struct Configuration*); + +void ConfigurationSetValue(struct Configuration*, const char* section, const char* key, const char* value); +void ConfigurationSetIntValue(struct Configuration*, const char* section, const char* key, int value); +void ConfigurationSetUIntValue(struct Configuration*, const char* section, const char* key, unsigned value); +void ConfigurationSetFloatValue(struct Configuration*, const char* section, const char* key, float value); + +bool ConfigurationHasSection(const struct Configuration*, const char* section); +const char* ConfigurationGetValue(const struct Configuration*, const char* section, const char* key); + +void ConfigurationClearValue(struct Configuration*, const char* section, const char* key); + +bool ConfigurationRead(struct Configuration*, const char* path); +bool ConfigurationReadVFile(struct Configuration*, struct VFile* vf); +bool ConfigurationWrite(const struct Configuration*, const char* path); +bool ConfigurationWriteSection(const struct Configuration*, const char* path, const char* section); +bool ConfigurationWriteVFile(const struct Configuration*, struct VFile* vf); + +void ConfigurationEnumerateSections(const struct Configuration* configuration, void (*handler)(const char* sectionName, void* user), void* user); +void ConfigurationEnumerate(const struct Configuration* configuration, const char* section, void (*handler)(const char* key, const char* value, void* user), void* user); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/crc32.h b/mgba-test-runner/c/include/mgba-util/crc32.h new file mode 100644 index 00000000..ba5e694f --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/crc32.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CRC32_H +#define CRC32_H + +#include + +CXX_GUARD_START + +struct VFile; + +#ifndef HAVE_CRC32 +uint32_t crc32(uint32_t crc, const void* buf, size_t size); +#else +#include +#endif + +uint32_t doCrc32(const void* buf, size_t size); +uint32_t fileCrc32(struct VFile* file, size_t endOffset); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/dllexports.h b/mgba-test-runner/c/include/mgba-util/dllexports.h new file mode 100644 index 00000000..a44480df --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/dllexports.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2020 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef MGBA_EXPORT_H +#define MGBA_EXPORT_H + +#if defined(BUILD_STATIC) || !defined(_MSC_VER) || defined(MGBA_STANDALONE) +#define MGBA_EXPORT +#else +#ifdef MGBA_DLL +#define MGBA_EXPORT __declspec(dllexport) +#else +#define MGBA_EXPORT __declspec(dllimport) +#endif +#endif + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/elf-read.h b/mgba-test-runner/c/include/mgba-util/elf-read.h new file mode 100644 index 00000000..86683ea8 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/elf-read.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ELF_READ_H +#define ELF_READ_H + +#include + +CXX_GUARD_START + +#ifdef USE_ELF + +#include + +#include + +struct ELF; +struct VFile; + +DECLARE_VECTOR(ELFProgramHeaders, Elf32_Phdr); +DECLARE_VECTOR(ELFSectionHeaders, Elf32_Shdr); + +struct ELF* ELFOpen(struct VFile*); +void ELFClose(struct ELF*); + +void* ELFBytes(struct ELF*, size_t* size); + +uint16_t ELFMachine(struct ELF*); +uint32_t ELFEntry(struct ELF*); + +void ELFGetProgramHeaders(struct ELF*, struct ELFProgramHeaders*); + +size_t ELFFindSection(struct ELF*, const char* name); +void ELFGetSectionHeaders(struct ELF*, struct ELFSectionHeaders*); +Elf32_Shdr* ELFGetSectionHeader(struct ELF*, size_t index); + +const char* ELFGetString(struct ELF*, size_t section, size_t string); + +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/export.h b/mgba-test-runner/c/include/mgba-util/export.h new file mode 100644 index 00000000..92047b93 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/export.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef EXPORT_H +#define EXPORT_H + +#include + +CXX_GUARD_START + +struct VFile; + +bool exportPaletteRIFF(struct VFile* vf, size_t entries, const uint16_t* colors); +bool exportPaletteACT(struct VFile* vf, size_t entries, const uint16_t* colors); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/formatting.h b/mgba-test-runner/c/include/mgba-util/formatting.h new file mode 100644 index 00000000..6eb01ffa --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/formatting.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef FORMATTING_H +#define FORMATTING_H + +#include + +CXX_GUARD_START + +#include "locale.h" + +#ifdef HAVE_XLOCALE +#include +#elif !defined(HAVE_LOCALE) +typedef const char* locale_t; +#endif + +int ftostr_l(char* restrict str, size_t size, float f, locale_t locale); + +#ifndef HAVE_STRTOF_L +float strtof_l(const char* restrict str, char** restrict end, locale_t locale); +#endif + +int ftostr_u(char* restrict str, size_t size, float f); +float strtof_u(const char* restrict str, char** restrict end); + +#ifndef HAVE_LOCALTIME_R +struct tm* localtime_r(const time_t* timep, struct tm* result); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/gui.h b/mgba-test-runner/c/include/mgba-util/gui.h new file mode 100644 index 00000000..9ac225eb --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/gui.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_H +#define GUI_H + +#include + +CXX_GUARD_START + +// TODO: Fix layering violation +#include +#include + +struct GUIFont; + +enum GUIInput { + GUI_INPUT_NONE = -1, + GUI_INPUT_SELECT = 0, + GUI_INPUT_BACK, + GUI_INPUT_CANCEL, + + GUI_INPUT_UP, + GUI_INPUT_DOWN, + GUI_INPUT_LEFT, + GUI_INPUT_RIGHT, + + GUI_INPUT_USER_START = 0x8, + + GUI_INPUT_MAX = 0x20 +}; + +enum GUICursorState { + GUI_CURSOR_NOT_PRESENT = 0, + GUI_CURSOR_UP, + GUI_CURSOR_DOWN, + GUI_CURSOR_CLICKED, + GUI_CURSOR_DRAGGING +}; + +enum { + BATTERY_EMPTY = 0, + BATTERY_LOW = 25, + BATTERY_HALF = 50, + BATTERY_HIGH = 75, + BATTERY_FULL = 100, + BATTERY_VALUE = 0x7F, + BATTERY_PERCENTAGE_VALID = 0x80, + + BATTERY_CHARGING = 0x100, + BATTERY_NOT_PRESENT = 0x200, +}; + +struct GUIBackground { + void (*draw)(struct GUIBackground*, void* context); +}; + +struct GUIParams { + unsigned width; + unsigned height; + struct GUIFont* font; + const char* basePath; + + void (*drawStart)(void); + void (*drawEnd)(void); + uint32_t (*pollInput)(const struct mInputMap*); + enum GUICursorState (*pollCursor)(unsigned* x, unsigned* y); + int (*batteryState)(void); + void (*guiPrepare)(void); + void (*guiFinish)(void); + + // State + struct mInputMap keyMap; + int inputHistory[GUI_INPUT_MAX]; + enum GUICursorState cursorState; + int cx, cy; + + // Directories + char currentPath[PATH_MAX]; + size_t fileIndex; +}; + +void GUIInit(struct GUIParams* params); +void GUIPollInput(struct GUIParams* params, uint32_t* newInput, uint32_t* heldInput); +enum GUICursorState GUIPollCursor(struct GUIParams* params, unsigned* x, unsigned* y); +void GUIInvalidateKeys(struct GUIParams* params); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/gui/file-select.h b/mgba-test-runner/c/include/mgba-util/gui/file-select.h new file mode 100644 index 00000000..fcbb7b78 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/gui/file-select.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_FILE_CHOOSER_H +#define GUI_FILE_CHOOSER_H + +#include + +CXX_GUARD_START + +#include + +struct VFile; + +bool GUISelectFile(struct GUIParams*, char* outPath, size_t outLen, bool (*filterName)(const char* name), bool (*filterContents)(struct VFile*), const char* preselect); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/gui/font-metrics.h b/mgba-test-runner/c/include/mgba-util/gui/font-metrics.h new file mode 100644 index 00000000..c60d6dfc --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/gui/font-metrics.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DEFAULT_FONT_METRICS_H +#define DEFAULT_FONT_METRICS_H + +#include + +extern struct GUIFontGlyphMetric defaultFontMetrics[]; +extern struct GUIIconMetric defaultIconMetrics[]; + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/gui/font.h b/mgba-test-runner/c/include/mgba-util/gui/font.h new file mode 100644 index 00000000..40394095 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/gui/font.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_FONT_H +#define GUI_FONT_H + +#include + +CXX_GUARD_START + +struct GUIFont; +struct GUIFont* GUIFontCreate(void); +void GUIFontDestroy(struct GUIFont*); + +enum GUIAlignment { + GUI_ALIGN_LEFT = 1, + GUI_ALIGN_HCENTER = 3, + GUI_ALIGN_RIGHT = 2, + + GUI_ALIGN_TOP = 4, + GUI_ALIGN_VCENTER = 12, + GUI_ALIGN_BOTTOM = 8, +}; + +enum GUIOrientation { + GUI_ORIENT_0, + GUI_ORIENT_90_CCW, + GUI_ORIENT_180, + GUI_ORIENT_270_CCW, + + GUI_ORIENT_VMIRROR, + GUI_ORIENT_HMIRROR, + + GUI_ORIENT_90_CW = GUI_ORIENT_270_CCW, + GUI_ORIENT_270_CW = GUI_ORIENT_90_CCW +}; + +enum GUIIcon { + GUI_ICON_BATTERY_FULL, + GUI_ICON_BATTERY_HIGH, + GUI_ICON_BATTERY_HALF, + GUI_ICON_BATTERY_LOW, + GUI_ICON_BATTERY_EMPTY, + GUI_ICON_SCROLLBAR_THUMB, + GUI_ICON_SCROLLBAR_TRACK, + GUI_ICON_SCROLLBAR_BUTTON, + GUI_ICON_CURSOR, + GUI_ICON_POINTER, + GUI_ICON_BUTTON_CIRCLE, + GUI_ICON_BUTTON_CROSS, + GUI_ICON_BUTTON_TRIANGLE, + GUI_ICON_BUTTON_SQUARE, + GUI_ICON_BUTTON_HOME, + GUI_ICON_STATUS_FAST_FORWARD, + GUI_ICON_STATUS_MUTE, + GUI_ICON_MAX, +}; + +struct GUIFontGlyphMetric { + int width; + int height; + struct { + int top; + int right; + int bottom; + int left; + } padding; +}; + +struct GUIIconMetric { + int x; + int y; + int width; + int height; +}; + +unsigned GUIFontHeight(const struct GUIFont*); +unsigned GUIFontGlyphWidth(const struct GUIFont*, uint32_t glyph); +unsigned GUIFontSpanWidth(const struct GUIFont*, const char* text); +void GUIFontIconMetrics(const struct GUIFont*, enum GUIIcon icon, unsigned* w, unsigned* h); + +ATTRIBUTE_FORMAT(printf, 6, 7) +void GUIFontPrintf(struct GUIFont*, int x, int y, enum GUIAlignment, uint32_t color, const char* text, ...); +void GUIFontPrint(struct GUIFont*, int x, int y, enum GUIAlignment, uint32_t color, const char* text); +void GUIFontDrawGlyph(struct GUIFont*, int x, int y, uint32_t color, uint32_t glyph); +void GUIFontDrawIcon(struct GUIFont*, int x, int y, enum GUIAlignment, enum GUIOrientation, uint32_t color, enum GUIIcon); +void GUIFontDrawIconSize(struct GUIFont* font, int x, int y, int w, int h, uint32_t color, enum GUIIcon icon); + +#ifdef __SWITCH__ +void GUIFontDrawSubmit(struct GUIFont* font); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/gui/menu.h b/mgba-test-runner/c/include/mgba-util/gui/menu.h new file mode 100644 index 00000000..dca1d60b --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/gui/menu.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_MENU_H +#define GUI_MENU_H + +#include + +CXX_GUARD_START + +#include + +#define GUI_V_V (struct GUIVariant) { .type = GUI_VARIANT_VOID } +#define GUI_V_U(U) (struct GUIVariant) { .type = GUI_VARIANT_UNSIGNED, .v.u = (U) } +#define GUI_V_I(I) (struct GUIVariant) { .type = GUI_VARIANT_INT, .v.i = (I) } +#define GUI_V_F(F) (struct GUIVariant) { .type = GUI_VARIANT_FLOAT, .v.f = (F) } +#define GUI_V_S(S) (struct GUIVariant) { .type = GUI_VARIANT_STRING, .v.s = (S) } + +enum GUIVariantType { + GUI_VARIANT_VOID = 0, + GUI_VARIANT_UNSIGNED, + GUI_VARIANT_INT, + GUI_VARIANT_FLOAT, + GUI_VARIANT_STRING +}; + +struct GUIVariant { + enum GUIVariantType type; + union { + unsigned u; + int i; + float f; + const char* s; + } v; +}; + +struct GUIMenu; +struct GUIMenuItem { + const char* title; + void* data; + unsigned state; + const char* const* validStates; + const struct GUIVariant* stateMappings; + unsigned nStates; + struct GUIMenu* submenu; +}; + +DECLARE_VECTOR(GUIMenuItemList, struct GUIMenuItem); + +struct GUIBackground; +struct GUIMenu { + const char* title; + const char* subtitle; + struct GUIMenuItemList items; + size_t index; + struct GUIBackground* background; +}; + +enum GUIMenuExitReason { + GUI_MENU_EXIT_ACCEPT, + GUI_MENU_EXIT_BACK, + GUI_MENU_EXIT_CANCEL, +}; + +enum GUIMessageBoxButtons { + GUI_MESSAGE_BOX_OK = 1, + GUI_MESSAGE_BOX_CANCEL = 2 +}; + +struct GUIParams; +enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* menu, struct GUIMenuItem** item); + +ATTRIBUTE_FORMAT(printf, 4, 5) +enum GUIMenuExitReason GUIShowMessageBox(struct GUIParams* params, int buttons, int frames, const char* format, ...); + +void GUIDrawBattery(struct GUIParams* params); +void GUIDrawClock(struct GUIParams* params); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/hash.h b/mgba-test-runner/c/include/mgba-util/hash.h new file mode 100644 index 00000000..7376ba42 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/hash.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef HASH_H +#define HASH_H + +#include + +CXX_GUARD_START + +uint32_t hash32(const void* key, int len, uint32_t seed); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/math.h b/mgba-test-runner/c/include/mgba-util/math.h new file mode 100644 index 00000000..05a5c1bb --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/math.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef UTIL_MATH_H +#define UTIL_MATH_H + +#include + +CXX_GUARD_START + +static inline uint32_t popcount32(unsigned bits) { + bits = bits - ((bits >> 1) & 0x55555555); + bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); + return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} + +static inline unsigned clz32(uint32_t bits) { +#if defined(__GNUC__) || __clang__ + if (!bits) { + return 32; + } + return __builtin_clz(bits); +#else + static const int table[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (bits & 0xFF000000) { + return table[bits >> 24]; + } else if (bits & 0x00FF0000) { + return table[bits >> 16] + 8; + } else if (bits & 0x0000FF00) { + return table[bits >> 8] + 16; + } + return table[bits] + 24; +#endif +} + +static inline uint32_t toPow2(uint32_t bits) { + if (!bits) { + return 0; + } + unsigned lz = clz32(bits - 1); + return 1 << (32 - lz); +} + +static inline int reduceFraction(int* num, int* den) { + int n = *num; + int d = *den; + while (d != 0) { + int temp = n % d; + n = d; + d = temp; + } + *num /= n; + *den /= n; + return n; +} + +#define TYPE_GENERICIZE(MACRO) \ + MACRO(int, Int) \ + MACRO(unsigned, UInt) + +#define LOCK_ASPECT_RATIO(T, t) \ + static inline void lockAspectRatio ## t(T refW, T refH, T* w, T* h) { \ + if (*w * refH > *h * refW) { \ + *w = *h * refW / refH; \ + } else if (*w * refH < *h * refW) { \ + *h = *w * refH / refW; \ + } \ + } + +TYPE_GENERICIZE(LOCK_ASPECT_RATIO) +#undef LOCK_ASPECT_RATIO + +#define LOCK_INTEGER_RATIO(T, t) \ + static inline void lockIntegerRatio ## t(T ref, T* val) { \ + if (*val >= ref) { \ + *val -= *val % ref; \ + } \ + } + +TYPE_GENERICIZE(LOCK_INTEGER_RATIO) +#undef LOCK_INTEGER_RATIO + +#undef TYPE_GENERICIZE +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/memory.h b/mgba-test-runner/c/include/mgba-util/memory.h new file mode 100644 index 00000000..325f748f --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/memory.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef MEMORY_H +#define MEMORY_H + +#include + +CXX_GUARD_START + +void* anonymousMemoryMap(size_t size); +void mappedMemoryFree(void* memory, size_t size); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/patch.h b/mgba-test-runner/c/include/mgba-util/patch.h new file mode 100644 index 00000000..7bf81dc9 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/patch.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PATCH_H +#define PATCH_H + +#include + +CXX_GUARD_START + +struct VFile; + +struct Patch { + struct VFile* vf; + + size_t (*outputSize)(struct Patch* patch, size_t inSize); + bool (*applyPatch)(struct Patch* patch, const void* in, size_t inSize, void* out, size_t outSize); +}; + +bool loadPatch(struct VFile* vf, struct Patch* patch); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/patch/fast.h b/mgba-test-runner/c/include/mgba-util/patch/fast.h new file mode 100644 index 00000000..ee59cd23 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/patch/fast.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PATCH_FAST_H +#define PATCH_FAST_H + +#include + +CXX_GUARD_START + +#include +#include + +#define PATCH_FAST_EXTENT 128 + +struct PatchFastExtent { + size_t length; + size_t offset; + uint32_t extent[PATCH_FAST_EXTENT]; +}; + +DECLARE_VECTOR(PatchFastExtents, struct PatchFastExtent); + +struct PatchFast { + struct Patch d; + + struct PatchFastExtents extents; +}; + +void initPatchFast(struct PatchFast*); +void deinitPatchFast(struct PatchFast*); +bool diffPatchFast(struct PatchFast* patch, const void* restrict in, const void* restrict out, size_t size); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/patch/ips.h b/mgba-test-runner/c/include/mgba-util/patch/ips.h new file mode 100644 index 00000000..2047d21e --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/patch/ips.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PATCH_IPS_H +#define PATCH_IPS_H + +#include + +CXX_GUARD_START + +struct Patch; + +bool loadPatchIPS(struct Patch* patch); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/patch/ups.h b/mgba-test-runner/c/include/mgba-util/patch/ups.h new file mode 100644 index 00000000..2e53cda4 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/patch/ups.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PATCH_UPS_H +#define PATCH_UPS_H + +#include + +CXX_GUARD_START + +struct Patch; + +bool loadPatchUPS(struct Patch* patch); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/3ds/3ds-vfs.h b/mgba-test-runner/c/include/mgba-util/platform/3ds/3ds-vfs.h new file mode 100644 index 00000000..71344b76 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/3ds/3ds-vfs.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef N3DS_VFS_H +#define N3DS_VFS_H + +#include + +#include <3ds.h> + +extern FS_Archive sdmcArchive; + +struct VFile* VFileOpen3DS(FS_Archive* archive, const char* path, int flags); + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/3ds/threading.h b/mgba-test-runner/c/include/mgba-util/platform/3ds/threading.h new file mode 100644 index 00000000..dfc03342 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/3ds/threading.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef N3DS_THREADING_H +#define N3DS_THREADING_H + +#include + +#include <3ds.h> +#include + +#define THREAD_ENTRY void +typedef ThreadFunc ThreadEntry; + +typedef LightLock Mutex; +typedef CondVar Condition; + +static inline int MutexInit(Mutex* mutex) { + LightLock_Init(mutex); + return 0; +} + +static inline int MutexDeinit(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexLock(Mutex* mutex) { + LightLock_Lock(mutex); + return 0; +} + +static inline int MutexTryLock(Mutex* mutex) { + return LightLock_TryLock(mutex); +} + +static inline int MutexUnlock(Mutex* mutex) { + LightLock_Unlock(mutex); + return 0; +} + +static inline int ConditionInit(Condition* cond) { + CondVar_Init(cond); + return 0; +} + +static inline int ConditionDeinit(Condition* cond) { + UNUSED(cond); + return 0; +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + CondVar_Wait(cond, mutex); + return 0; +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + return CondVar_WaitTimeout(cond, mutex, timeoutMs * 10000000LL); +} + +static inline int ConditionWake(Condition* cond) { + CondVar_Signal(cond); + return 0; +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + if (!entry || !thread) { + return 1; + } + *thread = threadCreate(entry, context, 0x8000, 0x18, 2, false); + return !*thread; +} + +static inline int ThreadJoin(Thread* thread) { + Result res = threadJoin(*thread, U64_MAX); + threadFree(*thread); + return res; +} + +static inline void ThreadSetName(const char* name) { + UNUSED(name); + // Unimplemented +} + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/posix/threading.h b/mgba-test-runner/c/include/mgba-util/platform/posix/threading.h new file mode 100644 index 00000000..32d2ea4b --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/posix/threading.h @@ -0,0 +1,119 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef POSIX_THREADING_H +#define POSIX_THREADING_H + +#include + +CXX_GUARD_START + +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#elif defined(__HAIKU__) +#include +#endif + +#define THREAD_ENTRY void* +typedef THREAD_ENTRY (*ThreadEntry)(void*); + +typedef pthread_t Thread; +typedef pthread_mutex_t Mutex; +typedef pthread_cond_t Condition; +typedef pthread_key_t ThreadLocal; + +static inline int MutexInit(Mutex* mutex) { + return pthread_mutex_init(mutex, 0); +} + +static inline int MutexDeinit(Mutex* mutex) { + return pthread_mutex_destroy(mutex); +} + +static inline int MutexLock(Mutex* mutex) { + return pthread_mutex_lock(mutex); +} + +static inline int MutexTryLock(Mutex* mutex) { + return pthread_mutex_trylock(mutex); +} + +static inline int MutexUnlock(Mutex* mutex) { + return pthread_mutex_unlock(mutex); +} + +static inline int ConditionInit(Condition* cond) { + return pthread_cond_init(cond, 0); +} + +static inline int ConditionDeinit(Condition* cond) { + return pthread_cond_destroy(cond); +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + return pthread_cond_wait(cond, mutex); +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + struct timespec ts; + struct timeval tv; + + gettimeofday(&tv, 0); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = (tv.tv_usec + timeoutMs * 1000L) * 1000L; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_nsec -= 1000000000L; + ++ts.tv_sec; + } + + return pthread_cond_timedwait(cond, mutex, &ts); +} + +static inline int ConditionWake(Condition* cond) { + return pthread_cond_broadcast(cond); +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + return pthread_create(thread, 0, entry, context); +} + +static inline int ThreadJoin(Thread* thread) { + return pthread_join(*thread, 0); +} + +static inline int ThreadSetName(const char* name) { +#if defined(__APPLE__) && defined(HAVE_PTHREAD_SETNAME_NP) + return pthread_setname_np(name); +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(pthread_self(), name); + return 0; +#elif defined(__HAIKU__) + rename_thread(find_thread(NULL), name); + return 0; +#elif defined(HAVE_PTHREAD_SETNAME_NP) + return pthread_setname_np(pthread_self(), name); +#else + UNUSED(name); + return 0; +#endif +} + +static inline void ThreadLocalInitKey(ThreadLocal* key) { + pthread_key_create(key, 0); +} + +static inline void ThreadLocalSetKey(ThreadLocal key, void* value) { + pthread_setspecific(key, value); +} + +static inline void* ThreadLocalGetValue(ThreadLocal key) { + return pthread_getspecific(key); +} + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/psp2/sce-vfs.h b/mgba-test-runner/c/include/mgba-util/platform/psp2/sce-vfs.h new file mode 100644 index 00000000..998b8d5b --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/psp2/sce-vfs.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SCE_VFS_H +#define SCE_VFS_H + +#ifdef PSP2 +#include +#include +#else +#include +#endif + +struct VFile* VFileOpenSce(const char* path, int flags, SceMode mode); + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/psp2/threading.h b/mgba-test-runner/c/include/mgba-util/platform/psp2/threading.h new file mode 100644 index 00000000..96e21e85 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/psp2/threading.h @@ -0,0 +1,162 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SCE_THREADING_H +#define SCE_THREADING_H + +#include + +typedef SceUID Thread; +typedef SceUID Mutex; +typedef struct { + Mutex mutex; + SceUID semaphore; + int waiting; +} Condition; +#define THREAD_ENTRY int +typedef THREAD_ENTRY (*ThreadEntry)(void*); +typedef int ThreadLocal; + +static inline int MutexInit(Mutex* mutex) { + Mutex id = sceKernelCreateMutex("mutex", 0, 0, 0); + if (id < 0) { + return id; + } + *mutex = id; + return 0; +} + +static inline int MutexDeinit(Mutex* mutex) { + return sceKernelDeleteMutex(*mutex); +} + +static inline int MutexLock(Mutex* mutex) { + return sceKernelLockMutex(*mutex, 1, 0); +} + +static inline int MutexTryLock(Mutex* mutex) { + return sceKernelTryLockMutex(*mutex, 1); +} + +static inline int MutexUnlock(Mutex* mutex) { + return sceKernelUnlockMutex(*mutex, 1); +} + +static inline int ConditionInit(Condition* cond) { + int res = MutexInit(&cond->mutex); + if (res < 0) { + return res; + } + cond->semaphore = sceKernelCreateSema("SceCondSema", 0, 0, 1, 0); + if (cond->semaphore < 0) { + MutexDeinit(&cond->mutex); + res = cond->semaphore; + } + cond->waiting = 0; + return res; +} + +static inline int ConditionDeinit(Condition* cond) { + MutexDeinit(&cond->mutex); + return sceKernelDeleteSema(cond->semaphore); +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + int ret = MutexLock(&cond->mutex); + if (ret < 0) { + return ret; + } + ++cond->waiting; + MutexUnlock(mutex); + MutexUnlock(&cond->mutex); + ret = sceKernelWaitSema(cond->semaphore, 1, 0); + if (ret < 0) { + printf("Premature wakeup: %08X", ret); + } + MutexLock(mutex); + return ret; +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + int ret = MutexLock(&cond->mutex); + if (ret < 0) { + return ret; + } + ++cond->waiting; + MutexUnlock(mutex); + MutexUnlock(&cond->mutex); + SceUInt timeout = 0; + if (timeoutMs > 0) { + timeout = timeoutMs; + } + ret = sceKernelWaitSema(cond->semaphore, 1, &timeout); + if (ret < 0) { + printf("Premature wakeup: %08X", ret); + } + MutexLock(mutex); + return ret; +} + +static inline int ConditionWake(Condition* cond) { + MutexLock(&cond->mutex); + if (cond->waiting) { + --cond->waiting; + sceKernelSignalSema(cond->semaphore, 1); + } + MutexUnlock(&cond->mutex); + return 0; +} + +struct SceThreadEntryArgs { + void* context; + ThreadEntry entry; +}; + +static inline int _sceThreadEntry(SceSize args, void* argp) { + UNUSED(args); + struct SceThreadEntryArgs* arg = argp; + return arg->entry(arg->context); +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + Thread id = sceKernelCreateThread("SceThread", _sceThreadEntry, 0x10000100, 0x10000, 0, 0, 0); + if (id < 0) { + *thread = 0; + return id; + } + *thread = id; + struct SceThreadEntryArgs args = { context, entry }; + sceKernelStartThread(id, sizeof(args), &args); + return 0; +} + +static inline int ThreadJoin(Thread* thread) { + int res = sceKernelWaitThreadEnd(*thread, 0, 0); + if (res < 0) { + return res; + } + return sceKernelDeleteThread(*thread); +} + +static inline int ThreadSetName(const char* name) { + UNUSED(name); + return -1; +} + +static inline void ThreadLocalInitKey(ThreadLocal* key) { + static int base = 0x90; + *key = __atomic_fetch_add(&base, 1, __ATOMIC_SEQ_CST); +} + +static inline void ThreadLocalSetKey(ThreadLocal key, void* value) { + void** tls = sceKernelGetTLSAddr(key); + *tls = value; +} + +static inline void* ThreadLocalGetValue(ThreadLocal key) { + void** tls = sceKernelGetTLSAddr(key); + return *tls; +} +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/switch/threading.h b/mgba-test-runner/c/include/mgba-util/platform/switch/threading.h new file mode 100644 index 00000000..76f1ae8b --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/switch/threading.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2013-2018 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SWITCH_THREADING_H +#define SWITCH_THREADING_H + +#include + +#include + +#define THREAD_ENTRY void +typedef ThreadFunc ThreadEntry; +typedef CondVar Condition; + +static inline int MutexInit(Mutex* mutex) { + mutexInit(mutex); + return 0; +} + +static inline int MutexDeinit(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexLock(Mutex* mutex) { + mutexLock(mutex); + return 0; +} + +static inline int MutexTryLock(Mutex* mutex) { + return mutexTryLock(mutex); +} + +static inline int MutexUnlock(Mutex* mutex) { + mutexUnlock(mutex); + return 0; +} + +static inline int ConditionInit(Condition* cond) { + condvarInit(cond); + return 0; +} + +static inline int ConditionDeinit(Condition* cond) { + UNUSED(cond); + return 0; +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + return condvarWait(cond, mutex); +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + return condvarWaitTimeout(cond, mutex, timeoutMs * 1000000LL); +} + +static inline int ConditionWake(Condition* cond) { + return condvarWakeOne(cond); +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + if (!entry || !thread) { + return 1; + } + int res = threadCreate(thread, entry, context, NULL, 0x8000, 0x3B, 1); + if(R_FAILED(res)) { + return res; + } + return threadStart(thread); +} + +static inline int ThreadJoin(Thread* thread) { + int res = threadWaitForExit(thread); + if(R_FAILED(res)) { + return res; + } + return threadClose(thread); +} + +static inline void ThreadSetName(const char* name) { + UNUSED(name); + // Unimplemented +} + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/platform/windows/getopt.h b/mgba-test-runner/c/include/mgba-util/platform/windows/getopt.h new file mode 100644 index 00000000..5ea2dbe6 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/windows/getopt.h @@ -0,0 +1,607 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#pragma warning(disable:4996); + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +//extern int optind; /* index of first non-option in argv */ +//extern int optopt; /* single option character, as parsed */ +//extern int opterr; /* flag to enable built-in diagnostics... */ +// /* (user may set to zero, to suppress) */ +// +//extern char *optarg; /* pointer to argument of current option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) *__progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void +_vwarnx(const char *fmt,va_list ap) +{ + (void)fprintf(stderr,"%s: ",__progname); + if (fmt != NULL) + (void)vfprintf(stderr,fmt,ap); + (void)fprintf(stderr,"\n"); +} + +static void +warnx(const char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + _vwarnx(fmt,ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +//extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = (char*)strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} + +//extern int getopt_long(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +//extern int getopt_long_only(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ diff --git a/mgba-test-runner/c/include/mgba-util/platform/windows/threading.h b/mgba-test-runner/c/include/mgba-util/platform/windows/threading.h new file mode 100644 index 00000000..d7a7b553 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/platform/windows/threading.h @@ -0,0 +1,104 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef WINDOWS_THREADING_H +#define WINDOWS_THREADING_H + +#include + +#define _WIN32_WINNT 0x0600 +#include +#define THREAD_ENTRY DWORD WINAPI +typedef THREAD_ENTRY ThreadEntry(LPVOID); + +typedef HANDLE Thread; +typedef CRITICAL_SECTION Mutex; +typedef CONDITION_VARIABLE Condition; +typedef DWORD ThreadLocal; + +static inline int MutexInit(Mutex* mutex) { + InitializeCriticalSection(mutex); + return GetLastError(); +} + +static inline int MutexDeinit(Mutex* mutex) { + DeleteCriticalSection(mutex); + return GetLastError(); +} + +static inline int MutexLock(Mutex* mutex) { + EnterCriticalSection(mutex); + return GetLastError(); +} + +static inline int MutexTryLock(Mutex* mutex) { + if (TryEnterCriticalSection(mutex)) { + return 0; + } + return 1; +} + +static inline int MutexUnlock(Mutex* mutex) { + LeaveCriticalSection(mutex); + return GetLastError(); +} + +static inline int ConditionInit(Condition* cond) { + InitializeConditionVariable(cond); + return GetLastError(); +} + +static inline int ConditionDeinit(Condition* cond) { + // This is a no-op on Windows + UNUSED(cond); + return 0; +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + SleepConditionVariableCS(cond, mutex, INFINITE); + return GetLastError(); +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + SleepConditionVariableCS(cond, mutex, timeoutMs); + return GetLastError(); +} + +static inline int ConditionWake(Condition* cond) { + WakeAllConditionVariable(cond); + return GetLastError(); +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + *thread = CreateThread(NULL, 0, entry, context, 0, 0); + return GetLastError(); +} + +static inline int ThreadJoin(Thread* thread) { + DWORD error = WaitForSingleObject(*thread, INFINITE); + if (error == WAIT_FAILED) { + return GetLastError(); + } + return 0; +} + +static inline int ThreadSetName(const char* name) { + UNUSED(name); + return -1; +} + +static inline void ThreadLocalInitKey(ThreadLocal* key) { + *key = TlsAlloc(); +} + +static inline void ThreadLocalSetKey(ThreadLocal key, void* value) { + TlsSetValue(key, value); +} + +static inline void* ThreadLocalGetValue(ThreadLocal key) { + return TlsGetValue(key); +} + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/png-io.h b/mgba-test-runner/c/include/mgba-util/png-io.h new file mode 100644 index 00000000..4156b5d2 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/png-io.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PNG_IO_H +#define PNG_IO_H + +#include + +CXX_GUARD_START + +#ifdef USE_PNG + +// png.h defines its own version of restrict which conflicts with mGBA's. +#ifdef restrict +#undef restrict +#endif +#include + +struct VFile; + +enum { + PNG_HEADER_BYTES = 8 +}; + +png_structp PNGWriteOpen(struct VFile* source); +png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height); +png_infop PNGWriteHeaderA(png_structp png, unsigned width, unsigned height); +png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height); +bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries); +bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); +bool PNGWritePixelsA(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); +bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); +bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data); +void PNGWriteClose(png_structp png, png_infop info); + +typedef int (*ChunkHandler)(png_structp, png_unknown_chunkp); + +bool isPNG(struct VFile* source); +png_structp PNGReadOpen(struct VFile* source, unsigned offset); +bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName); +bool PNGReadHeader(png_structp png, png_infop info); +bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride); +bool PNGReadPixelsA(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride); +bool PNGReadPixels8(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride); +bool PNGIgnorePixels(png_structp png, png_infop info); +bool PNGReadFooter(png_structp png, png_infop end); +void PNGReadClose(png_structp png, png_infop info, png_infop end); + +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/ring-fifo.h b/mgba-test-runner/c/include/mgba-util/ring-fifo.h new file mode 100644 index 00000000..1cfaa3d0 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/ring-fifo.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef RING_FIFO_H +#define RING_FIFO_H + +#include + +CXX_GUARD_START + +struct RingFIFO { + void* data; + size_t capacity; + void* readPtr; + void* writePtr; +}; + +void RingFIFOInit(struct RingFIFO* buffer, size_t capacity); +void RingFIFODeinit(struct RingFIFO* buffer); +size_t RingFIFOCapacity(const struct RingFIFO* buffer); +size_t RingFIFOSize(const struct RingFIFO* buffer); +void RingFIFOClear(struct RingFIFO* buffer); +size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length); +size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/socket.h b/mgba-test-runner/c/include/mgba-util/socket.h new file mode 100644 index 00000000..377d53a2 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/socket.h @@ -0,0 +1,418 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SOCKET_H +#define SOCKET_H + +#include + +CXX_GUARD_START + +#if defined(__cplusplus) && !defined(restrict) +#define restrict __restrict__ +#endif + +#ifdef _WIN32 +#include + +#define SOCKET_FAILED(s) ((s) == INVALID_SOCKET) +typedef SOCKET Socket; +#else +#ifdef GEKKO +#include +#else +#include +#include +#include +#include +#endif +#include +#include +#include + +#ifndef GEKKO +#define INVALID_SOCKET (-1) +#endif +#define SOCKET_FAILED(s) ((s) < 0) +typedef int Socket; +#endif + +enum IP { + IPV4, + IPV6 +}; + +struct Address { + enum IP version; + union { + uint32_t ipv4; + uint8_t ipv6[16]; + }; +}; + +#ifdef _3DS +#include <3ds.h> +#include + +#define SOCU_ALIGN 0x1000 +#define SOCU_BUFFERSIZE 0x100000 + +extern u32* SOCUBuffer; +#endif +#ifdef __SWITCH__ +#include +#endif +#ifdef PSP2 +#include +#include +#endif + +static inline void SocketSubsystemInit() { +#ifdef _WIN32 + WSADATA data; + WSAStartup(MAKEWORD(2, 2), &data); +#elif defined(_3DS) + if (!SOCUBuffer) { + SOCUBuffer = memalign(SOCU_ALIGN, SOCU_BUFFERSIZE); + socInit(SOCUBuffer, SOCU_BUFFERSIZE); + } +#elif defined(__SWITCH__) + socketInitializeDefault(); +#elif defined(GEKKO) + net_init(); +#elif defined(PSP2) + static uint8_t netMem[1024*1024]; + sceSysmoduleLoadModule(SCE_SYSMODULE_NET); + sceNetInit(&(SceNetInitParam) { netMem, sizeof(netMem) }); +#endif +} + +static inline void SocketSubsystemDeinit() { +#ifdef _WIN32 + WSACleanup(); +#elif defined(_3DS) + socExit(); + free(SOCUBuffer); + SOCUBuffer = NULL; +#elif defined(__SWITCH__) + socketExit(); +#elif defined(GEKKO) + net_deinit(); +#elif defined(PSP2) + sceNetTerm(); + sceSysmoduleUnloadModule(SCE_SYSMODULE_NET); +#endif +} + +static inline int SocketError() { +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +static inline bool SocketWouldBlock() { +#ifdef _WIN32 + return SocketError() == WSAEWOULDBLOCK; +#else + return SocketError() == EWOULDBLOCK || SocketError() == EAGAIN; +#endif +} + +static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) { +#ifdef _WIN32 + return send(socket, (const char*) buffer, size, 0); +#elif defined(GEKKO) + return net_write(socket, buffer, size); +#else + return write(socket, buffer, size); +#endif +} + +static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) { +#if defined(_WIN32) || defined(__SWITCH__) + return recv(socket, (char*) buffer, size, 0); +#elif defined(GEKKO) + return net_read(socket, buffer, size); +#else + return read(socket, buffer, size); +#endif +} + +static inline int SocketClose(Socket socket) { +#ifdef _WIN32 + return closesocket(socket) == 0; +#elif defined(GEKKO) + return net_close(socket) >= 0; +#else + return close(socket) >= 0; +#endif +} + +static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) { +#ifdef GEKKO + Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); +#else + Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); +#endif + if (SOCKET_FAILED(sock)) { + return sock; + } + + int err; + if (!bindAddress) { + struct sockaddr_in bindInfo; + memset(&bindInfo, 0, sizeof(bindInfo)); + bindInfo.sin_family = AF_INET; + bindInfo.sin_port = htons(port); +#ifndef _3DS + bindInfo.sin_addr.s_addr = INADDR_ANY; +#else + bindInfo.sin_addr.s_addr = gethostid(); +#endif +#ifdef GEKKO + err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#else + err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif + } else if (bindAddress->version == IPV4) { + struct sockaddr_in bindInfo; + memset(&bindInfo, 0, sizeof(bindInfo)); + bindInfo.sin_family = AF_INET; + bindInfo.sin_port = htons(port); + bindInfo.sin_addr.s_addr = htonl(bindAddress->ipv4); +#ifdef GEKKO + err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#else + err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif +#if !defined(_3DS) && !defined(GEKKO) + } else { + struct sockaddr_in6 bindInfo; + memset(&bindInfo, 0, sizeof(bindInfo)); + bindInfo.sin6_family = AF_INET6; + bindInfo.sin6_port = htons(port); + memcpy(bindInfo.sin6_addr.s6_addr, bindAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr)); + err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif + } + if (err) { + SocketClose(sock); + return INVALID_SOCKET; + } + return sock; +} + +static inline Socket SocketConnectTCP(int port, const struct Address* destinationAddress) { +#ifdef GEKKO + Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); +#else + Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); +#endif + if (SOCKET_FAILED(sock)) { + return sock; + } + + int err; + if (!destinationAddress) { + struct sockaddr_in bindInfo; + memset(&bindInfo, 0, sizeof(bindInfo)); + bindInfo.sin_family = AF_INET; + bindInfo.sin_port = htons(port); +#ifdef GEKKO + err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#else + err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif + } else if (destinationAddress->version == IPV4) { + struct sockaddr_in bindInfo; + memset(&bindInfo, 0, sizeof(bindInfo)); + bindInfo.sin_family = AF_INET; + bindInfo.sin_port = htons(port); + bindInfo.sin_addr.s_addr = htonl(destinationAddress->ipv4); +#ifdef GEKKO + err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#else + err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif +#if !defined(_3DS) && !defined(GEKKO) + } else { + struct sockaddr_in6 bindInfo; + memset(&bindInfo, 0, sizeof(bindInfo)); + bindInfo.sin6_family = AF_INET6; + bindInfo.sin6_port = htons(port); + memcpy(bindInfo.sin6_addr.s6_addr, destinationAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr)); + err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif + } + + if (err) { + SocketClose(sock); + return INVALID_SOCKET; + } + return sock; +} + +static inline Socket SocketListen(Socket socket, int queueLength) { +#ifdef GEKKO + return net_listen(socket, queueLength); +#else +#ifdef PSP2 + if (queueLength <= 0) { + queueLength = 1; + } +#endif + return listen(socket, queueLength); +#endif +} + +static inline Socket SocketAccept(Socket socket, struct Address* address) { + if (!address) { +#ifdef GEKKO + struct sockaddr_in addrInfo; + memset(&addrInfo, 0, sizeof(addrInfo)); + socklen_t len = sizeof(addrInfo); + return net_accept(socket, (struct sockaddr*) &addrInfo, &len); +#else + return accept(socket, 0, 0); +#endif + } + if (address->version == IPV4) { + struct sockaddr_in addrInfo; + memset(&addrInfo, 0, sizeof(addrInfo)); + addrInfo.sin_family = AF_INET; + addrInfo.sin_addr.s_addr = address->ipv4; + socklen_t len = sizeof(addrInfo); +#ifdef GEKKO + return net_accept(socket, (struct sockaddr*) &addrInfo, &len); +#else + return accept(socket, (struct sockaddr*) &addrInfo, &len); +#endif +#if !defined(_3DS) && !defined(GEKKO) + } else { + struct sockaddr_in6 addrInfo; + memset(&addrInfo, 0, sizeof(addrInfo)); + addrInfo.sin6_family = AF_INET6; + memcpy(addrInfo.sin6_addr.s6_addr, address->ipv6, sizeof(addrInfo.sin6_addr.s6_addr)); + socklen_t len = sizeof(addrInfo); + return accept(socket, (struct sockaddr*) &addrInfo, &len); +#endif + } + return INVALID_SOCKET; +} + +static inline int SocketSetBlocking(Socket socket, bool blocking) { +#ifdef _WIN32 + u_long unblocking = !blocking; + return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR; +#else +#ifdef GEKKO + int flags = net_fcntl(socket, F_GETFL, 0); +#else + int flags = fcntl(socket, F_GETFL); +#endif + if (flags == -1) { + return 0; + } + if (blocking) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } +#ifdef GEKKO + return net_fcntl(socket, F_SETFL, flags) >= 0; +#else + return fcntl(socket, F_SETFL, flags) >= 0; +#endif +#endif +} + +static inline int SocketSetTCPPush(Socket socket, int push) { +#ifdef GEKKO + return net_setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0; +#else + return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0; +#endif +} + +static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Socket* errors, int64_t timeoutMillis) { + fd_set rset; + fd_set wset; + fd_set eset; + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&eset); + size_t i; + Socket maxFd = 0; + if (reads) { + for (i = 0; i < nSockets; ++i) { + if (SOCKET_FAILED(reads[i])) { + break; + } + if (reads[i] > maxFd) { + maxFd = reads[i]; + } + FD_SET(reads[i], &rset); + reads[i] = INVALID_SOCKET; + } + } + if (writes) { + for (i = 0; i < nSockets; ++i) { + if (SOCKET_FAILED(writes[i])) { + break; + } + if (writes[i] > maxFd) { + maxFd = writes[i]; + } + FD_SET(writes[i], &wset); + writes[i] = INVALID_SOCKET; + } + } + if (errors) { + for (i = 0; i < nSockets; ++i) { + if (SOCKET_FAILED(errors[i])) { + break; + } + if (errors[i] > maxFd) { + maxFd = errors[i]; + } + FD_SET(errors[i], &eset); + errors[i] = INVALID_SOCKET; + } + } + ++maxFd; + struct timeval tv; + tv.tv_sec = timeoutMillis / 1000; + tv.tv_usec = (timeoutMillis % 1000) * 1000; +#ifdef GEKKO + int result = net_select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv); +#else + int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv); +#endif + int r = 0; + int w = 0; + int e = 0; + Socket j; + for (j = 0; j < maxFd; ++j) { + if (reads && FD_ISSET(j, &rset)) { + reads[r] = j; + ++r; + } + if (writes && FD_ISSET(j, &wset)) { + writes[w] = j; + ++w; + } + if (errors && FD_ISSET(j, &eset)) { + errors[e] = j; + ++e; + } + } + return result; +} + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/string.h b/mgba-test-runner/c/include/mgba-util/string.h new file mode 100644 index 00000000..38186981 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/string.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef UTIL_STRING_H +#define UTIL_STRING_H + +#include + +CXX_GUARD_START + +#ifndef HAVE_STRNDUP +// This is sometimes a macro +char* strndup(const char* start, size_t len); +#endif + +#ifndef HAVE_STRDUP +char* strdup(const char* str); +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char* restrict dst, const char* restrict src, size_t dstsize); +#endif + +char* strnrstr(const char* restrict s1, const char* restrict s2, size_t len); +bool endswith(const char* restrict s1, const char* restrict end); +bool startswith(const char* restrict s1, const char* restrict start); + +size_t toUtf8(uint32_t unichar, char* buffer); +int utfcmp(const uint16_t* utf16, const char* utf8, size_t utf16Length, size_t utf8Length); +char* utf16to8(const uint16_t* utf16, size_t length); +uint32_t utf8Char(const char** unicode, size_t* length); +uint32_t utf16Char(const uint16_t** unicode, size_t* length); +char* gbkToUtf8(const char* gbk, size_t length); + +int hexDigit(char digit); +const char* hex32(const char* line, uint32_t* out); +const char* hex24(const char* line, uint32_t* out); +const char* hex16(const char* line, uint16_t* out); +const char* hex12(const char* line, uint16_t* out); +const char* hex8(const char* line, uint8_t* out); +const char* hex4(const char* line, uint8_t* out); + +void rtrim(char* string); + +ssize_t parseQuotedString(const char* unparsed, ssize_t unparsedLen, char* parsed, ssize_t parsedLen); +bool wildcard(const char* search, const char* string); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/table.h b/mgba-test-runner/c/include/mgba-util/table.h new file mode 100644 index 00000000..8e668b76 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/table.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef TABLE_H +#define TABLE_H + +#include + +CXX_GUARD_START + +struct TableList; + +struct Table { + struct TableList* table; + size_t tableSize; + size_t size; + void (*deinitializer)(void*); + uint32_t seed; +}; + +void TableInit(struct Table*, size_t initialSize, void (*deinitializer)(void*)); +void TableDeinit(struct Table*); + +void* TableLookup(const struct Table*, uint32_t key); +void TableInsert(struct Table*, uint32_t key, void* value); + +void TableRemove(struct Table*, uint32_t key); +void TableClear(struct Table*); + +void TableEnumerate(const struct Table*, void (*handler)(uint32_t key, void* value, void* user), void* user); +size_t TableSize(const struct Table*); + +void HashTableInit(struct Table* table, size_t initialSize, void (*deinitializer)(void*)); +void HashTableDeinit(struct Table* table); + +void* HashTableLookup(const struct Table*, const char* key); +void* HashTableLookupBinary(const struct Table*, const void* key, size_t keylen); +void HashTableInsert(struct Table*, const char* key, void* value); +void HashTableInsertBinary(struct Table*, const void* key, size_t keylen, void* value); + +void HashTableRemove(struct Table*, const char* key); +void HashTableRemoveBinary(struct Table*, const void* key, size_t keylen); +void HashTableClear(struct Table*); + +void HashTableEnumerate(const struct Table*, void (*handler)(const char* key, void* value, void* user), void* user); +void HashTableEnumerateBinary(const struct Table*, void (*handler)(const char* key, size_t keylen, void* value, void* user), void* user); +const char* HashTableSearch(const struct Table* table, bool (*predicate)(const char* key, const void* value, const void* user), const void* user); +const char* HashTableSearchPointer(const struct Table* table, const void* value); +const char* HashTableSearchData(const struct Table* table, const void* value, size_t bytes); +const char* HashTableSearchString(const struct Table* table, const char* value); +size_t HashTableSize(const struct Table*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/text-codec.h b/mgba-test-runner/c/include/mgba-util/text-codec.h new file mode 100644 index 00000000..284705a1 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/text-codec.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef TEXT_CODEC_H +#define TEXT_CODEC_H + +#include + +CXX_GUARD_START + +struct TextCodecNode; +struct TextCodec { + struct TextCodecNode* forwardRoot; + struct TextCodecNode* reverseRoot; +}; + +struct TextCodecIterator { + struct TextCodecNode* root; + struct TextCodecNode* current; +}; + +struct VFile; +bool TextCodecLoadTBL(struct TextCodec*, struct VFile*, bool createReverse); +void TextCodecDeinit(struct TextCodec*); + +void TextCodecStartDecode(struct TextCodec*, struct TextCodecIterator*); +void TextCodecStartEncode(struct TextCodec*, struct TextCodecIterator*); + +ssize_t TextCodecAdvance(struct TextCodecIterator*, uint8_t byte, uint8_t* output, size_t outputLength); +ssize_t TextCodecFinish(struct TextCodecIterator*, uint8_t* output, size_t outputLength); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/threading.h b/mgba-test-runner/c/include/mgba-util/threading.h new file mode 100644 index 00000000..779a533a --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/threading.h @@ -0,0 +1,121 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef THREADING_H +#define THREADING_H + +#include + +CXX_GUARD_START + +#ifndef DISABLE_THREADING +#if __STDC_VERSION__ >= 201112L +#define ThreadLocal _Thread_local void* +#define ThreadLocalInitKey(X) +#define ThreadLocalSetKey(K, V) K = V +#define ThreadLocalGetValue(K) K +#endif +#ifdef USE_PTHREADS +#include +#elif defined(_WIN32) +#include +#elif defined(PSP2) +#include +#elif defined(_3DS) +#include +#elif defined(__SWITCH__) +#include +#else +#define DISABLE_THREADING +#endif +#endif +#ifdef DISABLE_THREADING +#ifdef _3DS +// ctrulib already has a type called Thread +#include <3ds/thread.h> +#elif defined(__SWITCH__) +#include +#else +typedef void* Thread; +#endif +#ifdef __SWITCH__ +#include +#else +typedef void* Mutex; +#endif +typedef void* Condition; +typedef int ThreadLocal; + +static inline int MutexInit(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexDeinit(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexLock(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexTryLock(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexUnlock(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int ConditionInit(Condition* cond) { + UNUSED(cond); + return 0; +} + +static inline int ConditionDeinit(Condition* cond) { + UNUSED(cond); + return 0; +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + UNUSED(cond); + UNUSED(mutex); + return 0; +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + UNUSED(cond); + UNUSED(mutex); + UNUSED(timeoutMs); + return 0; +} + +static inline int ConditionWake(Condition* cond) { + UNUSED(cond); + return 0; +} + +static inline void ThreadLocalInitKey(ThreadLocal* key) { + UNUSED(key); +} + +static inline void ThreadLocalSetKey(ThreadLocal key, void* value) { + UNUSED(key); + UNUSED(value); +} + +static inline void* ThreadLocalGetValue(ThreadLocal key) { + UNUSED(key); + return NULL; +} +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/vector.h b/mgba-test-runner/c/include/mgba-util/vector.h new file mode 100644 index 00000000..ba412d7d --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/vector.h @@ -0,0 +1,104 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VECTOR_H +#define VECTOR_H + +#include + +CXX_GUARD_START + +#ifdef vector +#undef vector +#endif + +#define DECLARE_VECTOR(NAME, TYPE) \ + struct NAME { \ + TYPE* vector; \ + size_t size; \ + size_t capacity; \ + }; \ + void NAME ## Init(struct NAME* vector, size_t capacity); \ + void NAME ## Deinit(struct NAME* vector); \ + TYPE* NAME ## GetPointer(struct NAME* vector, size_t location); \ + TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location); \ + TYPE* NAME ## Append(struct NAME* vector); \ + void NAME ## Clear(struct NAME* vector); \ + void NAME ## Resize(struct NAME* vector, ssize_t change); \ + void NAME ## Shift(struct NAME* vector, size_t location, size_t difference); \ + void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference); \ + void NAME ## EnsureCapacity(struct NAME* vector, size_t capacity); \ + size_t NAME ## Size(const struct NAME* vector); \ + size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \ + void NAME ## Copy(struct NAME* dest, const struct NAME* src); + +#define DEFINE_VECTOR(NAME, TYPE) \ + void NAME ## Init(struct NAME* vector, size_t capacity) { \ + vector->size = 0; \ + if (capacity == 0) { \ + capacity = 4; \ + } \ + vector->capacity = capacity; \ + vector->vector = calloc(capacity, sizeof(TYPE)); \ + } \ + void NAME ## Deinit(struct NAME* vector) { \ + free(vector->vector); \ + vector->vector = 0; \ + vector->capacity = 0; \ + vector->size = 0; \ + } \ + TYPE* NAME ## GetPointer(struct NAME* vector, size_t location) { \ + return &vector->vector[location]; \ + } \ + TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location) { \ + return &vector->vector[location]; \ + } \ + TYPE* NAME ## Append(struct NAME* vector) { \ + NAME ## Resize(vector, 1); \ + return &vector->vector[vector->size - 1]; \ + } \ + void NAME ## Resize(struct NAME* vector, ssize_t change) { \ + if (change > 0) { \ + NAME ## EnsureCapacity(vector, vector->size + change); \ + } \ + vector->size += change; \ + } \ + void NAME ## Clear(struct NAME* vector) { \ + vector->size = 0; \ + } \ + void NAME ## EnsureCapacity(struct NAME* vector, size_t capacity) { \ + if (capacity <= vector->capacity) { \ + return; \ + } \ + while (capacity > vector->capacity) { \ + vector->capacity <<= 1; \ + } \ + vector->vector = realloc(vector->vector, vector->capacity * sizeof(TYPE)); \ + } \ + void NAME ## Shift(struct NAME* vector, size_t location, size_t difference) { \ + memmove(&vector->vector[location], &vector->vector[location + difference], (vector->size - location - difference) * sizeof(TYPE)); \ + vector->size -= difference; \ + } \ + void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference) { \ + NAME ## Resize(vector, difference); \ + memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \ + } \ + size_t NAME ## Size(const struct NAME* vector) { \ + return vector->size; \ + } \ + size_t NAME ## Index(const struct NAME* vector, const TYPE* member) { \ + return member - (const TYPE*) vector->vector; \ + } \ + void NAME ## Copy(struct NAME* dest, const struct NAME* src) { \ + NAME ## EnsureCapacity(dest, src->size); \ + memcpy(dest->vector, src->vector, src->size * sizeof(TYPE)); \ + dest->size = src->size; \ + } \ + +DECLARE_VECTOR(StringList, char*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba-util/vfs.h b/mgba-test-runner/c/include/mgba-util/vfs.h new file mode 100644 index 00000000..c9faded6 --- /dev/null +++ b/mgba-test-runner/c/include/mgba-util/vfs.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VFS_H +#define VFS_H + +#include + +CXX_GUARD_START + +#ifdef _WIN32 +#include +#include +#define PATH_SEP "/" // Windows can handle slashes, and backslashes confuse some libraries +#else +#define PATH_SEP "/" +#endif + +#ifndef PATH_MAX +#ifdef MAX_PATH +#define PATH_MAX MAX_PATH +#else +#define PATH_MAX 128 +#endif +#endif + +enum { + MAP_READ = 1, + MAP_WRITE = 2 +}; + +enum VFSType { + VFS_UNKNOWN = 0, + VFS_FILE, + VFS_DIRECTORY +}; + +struct VFile { + bool (*close)(struct VFile* vf); + off_t (*seek)(struct VFile* vf, off_t offset, int whence); + ssize_t (*read)(struct VFile* vf, void* buffer, size_t size); + ssize_t (*readline)(struct VFile* vf, char* buffer, size_t size); + ssize_t (*write)(struct VFile* vf, const void* buffer, size_t size); + void* (*map)(struct VFile* vf, size_t size, int flags); + void (*unmap)(struct VFile* vf, void* memory, size_t size); + void (*truncate)(struct VFile* vf, size_t size); + ssize_t (*size)(struct VFile* vf); + bool (*sync)(struct VFile* vf, void* buffer, size_t size); +}; + +struct VDirEntry { + const char* (*name)(struct VDirEntry* vde); + enum VFSType (*type)(struct VDirEntry* vde); +}; + +struct VDir { + bool (*close)(struct VDir* vd); + void (*rewind)(struct VDir* vd); + struct VDirEntry* (*listNext)(struct VDir* vd); + struct VFile* (*openFile)(struct VDir* vd, const char* name, int mode); + struct VDir* (*openDir)(struct VDir* vd, const char* name); + bool (*deleteFile)(struct VDir* vd, const char* name); +}; + +struct VFile* VFileOpen(const char* path, int flags); + +struct VFile* VFileOpenFD(const char* path, int flags); +struct VFile* VFileFromFD(int fd); + +struct VFile* VFileFromMemory(void* mem, size_t size); +struct VFile* VFileFromConstMemory(const void* mem, size_t size); +struct VFile* VFileMemChunk(const void* mem, size_t size); + +struct CircleBuffer; +struct VFile* VFileFIFO(struct CircleBuffer* backing); + +struct VDir* VDirOpen(const char* path); +struct VDir* VDirOpenArchive(const char* path); + +#if defined(USE_LIBZIP) || defined(USE_MINIZIP) +struct VDir* VDirOpenZip(const char* path, int flags); +#endif + +#ifdef USE_LZMA +struct VDir* VDirOpen7z(const char* path, int flags); +#endif + +#if defined(__wii__) || defined(_3DS) || defined(PSP2) +struct VDir* VDeviceList(void); +#endif + +bool VDirCreate(const char* path); + +#ifdef USE_VFS_FILE +struct VFile* VFileFOpen(const char* path, const char* mode); +struct VFile* VFileFromFILE(FILE* file); +#endif + +void separatePath(const char* path, char* dirname, char* basename, char* extension); + +struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)); +struct VFile* VDirFindNextAvailable(struct VDir*, const char* basename, const char* infix, const char* suffix, int mode); + +ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size); + +ssize_t VFileWrite32LE(struct VFile* vf, int32_t word); +ssize_t VFileWrite16LE(struct VFile* vf, int16_t hword); +ssize_t VFileRead32LE(struct VFile* vf, void* word); +ssize_t VFileRead16LE(struct VFile* vf, void* hword); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/bitmap-cache.h b/mgba-test-runner/c/include/mgba/core/bitmap-cache.h new file mode 100644 index 00000000..d8bd416e --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/bitmap-cache.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2013-2019 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_BITMAP_CACHE_H +#define M_BITMAP_CACHE_H + +#include + +CXX_GUARD_START + +#include + +DECL_BITFIELD(mBitmapCacheConfiguration, uint32_t); +DECL_BIT(mBitmapCacheConfiguration, ShouldStore, 0); + +DECL_BITFIELD(mBitmapCacheSystemInfo, uint32_t); +DECL_BITS(mBitmapCacheSystemInfo, EntryBPP, 0, 3); +DECL_BIT(mBitmapCacheSystemInfo, UsesPalette, 3); +DECL_BITS(mBitmapCacheSystemInfo, Width, 4, 10); +DECL_BITS(mBitmapCacheSystemInfo, Height, 14, 10); +DECL_BITS(mBitmapCacheSystemInfo, Buffers, 24, 2); + +struct mBitmapCacheEntry { + uint32_t paletteVersion; + uint32_t vramVersion; + uint8_t vramClean; +}; + +struct mBitmapCache { + color_t* cache; + struct mBitmapCacheEntry* status; + + uint32_t globalPaletteVersion; + + uint8_t* vram; + color_t* palette; + + uint32_t bitsSize; + uint32_t bitsStart[2]; + uint32_t stride; + uint8_t buffer; + + mBitmapCacheConfiguration config; + mBitmapCacheSystemInfo sysConfig; + + void* context; +}; + +void mBitmapCacheInit(struct mBitmapCache* cache); +void mBitmapCacheDeinit(struct mBitmapCache* cache); +void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config); +void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config); +void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address); +void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color); + +void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y); +bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y); +const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/blip_buf.h b/mgba-test-runner/c/include/mgba/core/blip_buf.h new file mode 100644 index 00000000..22b0a3ec --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/blip_buf.h @@ -0,0 +1,72 @@ +/** \file +Sample buffer that resamples from input clock rate to output sample rate */ + +/* blip_buf 1.1.0 */ +#ifndef BLIP_BUF_H +#define BLIP_BUF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/** First parameter of most functions is blip_t*, or const blip_t* if nothing +is changed. */ +typedef struct blip_t blip_t; + +/** Creates new buffer that can hold at most sample_count samples. Sets rates +so that there are blip_max_ratio clocks per sample. Returns pointer to new +buffer, or NULL if insufficient memory. */ +blip_t* blip_new( int sample_count ); + +/** Sets approximate input clock rate and output sample rate. For every +clock_rate input clocks, approximately sample_rate samples are generated. */ +void blip_set_rates( blip_t*, double clock_rate, double sample_rate ); + +enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, +clock_rate must not be greater than sample_rate*blip_max_ratio. */ +blip_max_ratio = 0x100000 }; + +/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ +void blip_clear( blip_t* ); + +/** Adds positive/negative delta into buffer at specified clock time. */ +void blip_add_delta( blip_t*, unsigned int clock_time, int delta ); + +/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */ +void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta ); + +/** Length of time frame, in clocks, needed to make sample_count additional +samples available. */ +int blip_clocks_needed( const blip_t*, int sample_count ); + +enum { /** Maximum number of samples that can be generated from one time frame. */ +blip_max_frame = 4000 }; + +/** Makes input clocks before clock_duration available for reading as output +samples. Also begins new time frame at clock_duration, so that clock time 0 in +the new time frame specifies the same clock as clock_duration in the old time +frame specified. Deltas can have been added slightly past clock_duration (up to +however many clocks there are in two output samples). */ +void blip_end_frame( blip_t*, unsigned int clock_duration ); + +/** Number of buffered samples available for reading. */ +int blip_samples_avail( const blip_t* ); + +/** Reads and removes at most 'count' samples and writes them to 'out'. If +'stereo' is true, writes output to every other element of 'out', allowing easy +interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed +samples. Returns number of samples actually read. */ +int blip_read_samples( blip_t*, short out [], int count, int stereo ); + +/** Frees buffer. No effect if NULL is passed. */ +void blip_delete( blip_t* ); + + +/* Deprecated */ +typedef blip_t blip_buffer_t; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/cache-set.h b/mgba-test-runner/c/include/mgba/core/cache-set.h new file mode 100644 index 00000000..5749c0e6 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/cache-set.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CACHE_SET_H +#define M_CACHE_SET_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include + +DECLARE_VECTOR(mMapCacheSet, struct mMapCache); +DECLARE_VECTOR(mBitmapCacheSet, struct mBitmapCache); +DECLARE_VECTOR(mTileCacheSet, struct mTileCache); + +struct mCacheSet { + struct mMapCacheSet maps; + struct mBitmapCacheSet bitmaps; + struct mTileCacheSet tiles; +}; + +void mCacheSetInit(struct mCacheSet*, size_t nMaps, size_t nBitmaps, size_t nTiles); +void mCacheSetDeinit(struct mCacheSet*); + +void mCacheSetAssignVRAM(struct mCacheSet*, void* vram); + +void mCacheSetWriteVRAM(struct mCacheSet*, uint32_t address); +void mCacheSetWritePalette(struct mCacheSet*, uint32_t entry, color_t color); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/cheats.h b/mgba-test-runner/c/include/mgba/core/cheats.h new file mode 100644 index 00000000..4d7bd909 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/cheats.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CHEATS_H +#define CHEATS_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include + +enum mCheatType { + CHEAT_ASSIGN, + CHEAT_ASSIGN_INDIRECT, + CHEAT_AND, + CHEAT_ADD, + CHEAT_OR, + CHEAT_IF_EQ, + CHEAT_IF_NE, + CHEAT_IF_LT, + CHEAT_IF_GT, + CHEAT_IF_ULT, + CHEAT_IF_UGT, + CHEAT_IF_AND, + CHEAT_IF_LAND, + CHEAT_IF_NAND, + CHEAT_IF_BUTTON, +}; + +struct mCheat { + enum mCheatType type; + int width; + uint32_t address; + uint32_t operand; + uint32_t repeat; + uint32_t negativeRepeat; + + int32_t addressOffset; + int32_t operandOffset; +}; + +struct mCheatPatch { + uint32_t address; + int segment; + uint32_t value; + int width; + bool applied; + uint32_t checkValue; + bool check; +}; + +mLOG_DECLARE_CATEGORY(CHEATS); + +DECLARE_VECTOR(mCheatList, struct mCheat); +DECLARE_VECTOR(mCheatPatchList, struct mCheatPatch); + +struct mCheatDevice; +struct mCheatSet { + struct mCheatList list; + + void (*deinit)(struct mCheatSet* set); + void (*add)(struct mCheatSet* set, struct mCheatDevice* device); + void (*remove)(struct mCheatSet* set, struct mCheatDevice* device); + + bool (*addLine)(struct mCheatSet* set, const char* cheat, int type); + void (*copyProperties)(struct mCheatSet* set, struct mCheatSet* oldSet); + + void (*parseDirectives)(struct mCheatSet* set, const struct StringList* directives); + void (*dumpDirectives)(struct mCheatSet* set, struct StringList* directives); + + void (*refresh)(struct mCheatSet* set, struct mCheatDevice* device); + + char* name; + bool enabled; + struct mCheatPatchList romPatches; + struct StringList lines; +}; + +DECLARE_VECTOR(mCheatSets, struct mCheatSet*); + +struct mCheatDevice { + struct mCPUComponent d; + struct mCore* p; + + struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name); + + struct mCheatSets cheats; + struct Table unpatchedMemory; + bool autosave; + bool buttonDown; +}; + +struct VFile; + +void mCheatDeviceCreate(struct mCheatDevice*); +void mCheatDeviceDestroy(struct mCheatDevice*); +void mCheatDeviceClear(struct mCheatDevice*); + +void mCheatSetInit(struct mCheatSet*, const char* name); +void mCheatSetDeinit(struct mCheatSet*); +void mCheatSetRename(struct mCheatSet*, const char* name); + +bool mCheatAddLine(struct mCheatSet*, const char* line, int type); + +void mCheatAddSet(struct mCheatDevice*, struct mCheatSet*); +void mCheatRemoveSet(struct mCheatDevice*, struct mCheatSet*); + +bool mCheatParseFile(struct mCheatDevice*, struct VFile*); +bool mCheatSaveFile(struct mCheatDevice*, struct VFile*); + +bool mCheatParseLibretroFile(struct mCheatDevice*, struct VFile*); +bool mCheatParseEZFChtFile(struct mCheatDevice*, struct VFile*); + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +void mCheatAutosave(struct mCheatDevice*); +#endif + +void mCheatRefresh(struct mCheatDevice*, struct mCheatSet*); +void mCheatPressButton(struct mCheatDevice*, bool down); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/config.h b/mgba-test-runner/c/include/mgba/core/config.h new file mode 100644 index 00000000..063b14e0 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/config.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_CONFIG_H +#define M_CORE_CONFIG_H + +#include + +CXX_GUARD_START + +#include + +struct mCoreConfig { + struct Configuration configTable; + struct Configuration defaultsTable; + struct Configuration overridesTable; + char* port; +}; + +enum mCoreConfigLevel { + mCONFIG_LEVEL_DEFAULT = 0, + mCONFIG_LEVEL_CUSTOM, + mCONFIG_LEVEL_OVERRIDE, +}; + +struct mCoreOptions { + char* bios; + bool skipBios; + bool useBios; + int logLevel; + int frameskip; + bool rewindEnable; + int rewindBufferCapacity; + float fpsTarget; + size_t audioBuffers; + unsigned sampleRate; + + int fullscreen; + int width; + int height; + bool lockAspectRatio; + bool lockIntegerScaling; + bool interframeBlending; + bool resampleVideo; + bool suspendScreensaver; + char* shader; + + char* savegamePath; + char* savestatePath; + char* screenshotPath; + char* patchPath; + char* cheatsPath; + + int volume; + bool mute; + + bool videoSync; + bool audioSync; +}; + +void mCoreConfigInit(struct mCoreConfig*, const char* port); +void mCoreConfigDeinit(struct mCoreConfig*); + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +bool mCoreConfigLoad(struct mCoreConfig*); +bool mCoreConfigSave(const struct mCoreConfig*); +bool mCoreConfigLoadPath(struct mCoreConfig*, const char* path); +bool mCoreConfigSavePath(const struct mCoreConfig*, const char* path); +bool mCoreConfigLoadVFile(struct mCoreConfig*, struct VFile* vf); +bool mCoreConfigSaveVFile(const struct mCoreConfig*, struct VFile* vf); + +void mCoreConfigMakePortable(const struct mCoreConfig*); +void mCoreConfigDirectory(char* out, size_t outLength); +void mCoreConfigPortablePath(char* out, size_t outLength); +bool mCoreConfigIsPortable(void); +#endif + +const char* mCoreConfigGetValue(const struct mCoreConfig*, const char* key); +bool mCoreConfigGetIntValue(const struct mCoreConfig*, const char* key, int* value); +bool mCoreConfigGetUIntValue(const struct mCoreConfig*, const char* key, unsigned* value); +bool mCoreConfigGetFloatValue(const struct mCoreConfig*, const char* key, float* value); + +void mCoreConfigSetValue(struct mCoreConfig*, const char* key, const char* value); +void mCoreConfigSetIntValue(struct mCoreConfig*, const char* key, int value); +void mCoreConfigSetUIntValue(struct mCoreConfig*, const char* key, unsigned value); +void mCoreConfigSetFloatValue(struct mCoreConfig*, const char* key, float value); + +void mCoreConfigSetDefaultValue(struct mCoreConfig*, const char* key, const char* value); +void mCoreConfigSetDefaultIntValue(struct mCoreConfig*, const char* key, int value); +void mCoreConfigSetDefaultUIntValue(struct mCoreConfig*, const char* key, unsigned value); +void mCoreConfigSetDefaultFloatValue(struct mCoreConfig*, const char* key, float value); + +void mCoreConfigSetOverrideValue(struct mCoreConfig*, const char* key, const char* value); +void mCoreConfigSetOverrideIntValue(struct mCoreConfig*, const char* key, int value); +void mCoreConfigSetOverrideUIntValue(struct mCoreConfig*, const char* key, unsigned value); +void mCoreConfigSetOverrideFloatValue(struct mCoreConfig*, const char* key, float value); + +void mCoreConfigCopyValue(struct mCoreConfig* config, const struct mCoreConfig* src, const char* key); + +void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts); +void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts); + +void mCoreConfigEnumerate(const struct mCoreConfig* config, const char* prefix, void (*handler)(const char* key, const char* value, enum mCoreConfigLevel type, void* user), void* user); + +struct Configuration* mCoreConfigGetInput(struct mCoreConfig*); +struct Configuration* mCoreConfigGetOverrides(struct mCoreConfig*); +const struct Configuration* mCoreConfigGetOverridesConst(const struct mCoreConfig*); + +void mCoreConfigFreeOpts(struct mCoreOptions* opts); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/core.h b/mgba-test-runner/c/include/mgba/core/core.h new file mode 100644 index 00000000..3475c393 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/core.h @@ -0,0 +1,214 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_H +#define M_CORE_H + +#include + +CXX_GUARD_START + +#include +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +#include +#endif +#ifndef MINIMAL_CORE +#include +#endif +#include +#ifdef USE_DEBUGGERS +#include +#endif + +enum mPlatform { + mPLATFORM_NONE = -1, + mPLATFORM_GBA = 0, + mPLATFORM_GB = 1, +}; + +enum mCoreChecksumType { + mCHECKSUM_CRC32, +}; + +struct mCoreConfig; +struct mCoreSync; +struct mDebuggerSymbols; +struct mStateExtdata; +struct mVideoLogContext; +struct mCore { + void* cpu; + void* board; + struct mTiming* timing; + struct mDebugger* debugger; + struct mDebuggerSymbols* symbolTable; + struct mVideoLogger* videoLogger; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + struct mDirectorySet dirs; +#endif +#ifndef MINIMAL_CORE + struct mInputMap inputMap; +#endif + struct mCoreConfig config; + struct mCoreOptions opts; + + struct mRTCGenericSource rtc; + + bool (*init)(struct mCore*); + void (*deinit)(struct mCore*); + + enum mPlatform (*platform)(const struct mCore*); + bool (*supportsFeature)(const struct mCore*, enum mCoreFeature); + + void (*setSync)(struct mCore*, struct mCoreSync*); + void (*loadConfig)(struct mCore*, const struct mCoreConfig*); + void (*reloadConfigOption)(struct mCore*, const char* option, const struct mCoreConfig*); + + void (*desiredVideoDimensions)(const struct mCore*, unsigned* width, unsigned* height); + void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride); + void (*setVideoGLTex)(struct mCore*, unsigned texid); + + void (*getPixels)(struct mCore*, const void** buffer, size_t* stride); + void (*putPixels)(struct mCore*, const void* buffer, size_t stride); + + struct blip_t* (*getAudioChannel)(struct mCore*, int ch); + void (*setAudioBufferSize)(struct mCore*, size_t samples); + size_t (*getAudioBufferSize)(struct mCore*); + + void (*addCoreCallbacks)(struct mCore*, struct mCoreCallbacks*); + void (*clearCoreCallbacks)(struct mCore*); + void (*setAVStream)(struct mCore*, struct mAVStream*); + + bool (*isROM)(struct VFile* vf); + bool (*loadROM)(struct mCore*, struct VFile* vf); + bool (*loadSave)(struct mCore*, struct VFile* vf); + bool (*loadTemporarySave)(struct mCore*, struct VFile* vf); + void (*unloadROM)(struct mCore*); + void (*checksum)(const struct mCore*, void* data, enum mCoreChecksumType type); + + bool (*loadBIOS)(struct mCore*, struct VFile* vf, int biosID); + bool (*selectBIOS)(struct mCore*, int biosID); + + bool (*loadPatch)(struct mCore*, struct VFile* vf); + + void (*reset)(struct mCore*); + void (*runFrame)(struct mCore*); + void (*runLoop)(struct mCore*); + void (*step)(struct mCore*); + + size_t (*stateSize)(struct mCore*); + bool (*loadState)(struct mCore*, const void* state); + bool (*saveState)(struct mCore*, void* state); + + void (*setKeys)(struct mCore*, uint32_t keys); + void (*addKeys)(struct mCore*, uint32_t keys); + void (*clearKeys)(struct mCore*, uint32_t keys); + + int32_t (*frameCounter)(const struct mCore*); + int32_t (*frameCycles)(const struct mCore*); + int32_t (*frequency)(const struct mCore*); + + void (*getGameTitle)(const struct mCore*, char* title); + void (*getGameCode)(const struct mCore*, char* title); + + void (*setPeripheral)(struct mCore*, int type, void*); + + uint32_t (*busRead8)(struct mCore*, uint32_t address); + uint32_t (*busRead16)(struct mCore*, uint32_t address); + uint32_t (*busRead32)(struct mCore*, uint32_t address); + + void (*busWrite8)(struct mCore*, uint32_t address, uint8_t); + void (*busWrite16)(struct mCore*, uint32_t address, uint16_t); + void (*busWrite32)(struct mCore*, uint32_t address, uint32_t); + + uint32_t (*rawRead8)(struct mCore*, uint32_t address, int segment); + uint32_t (*rawRead16)(struct mCore*, uint32_t address, int segment); + uint32_t (*rawRead32)(struct mCore*, uint32_t address, int segment); + + void (*rawWrite8)(struct mCore*, uint32_t address, int segment, uint8_t); + void (*rawWrite16)(struct mCore*, uint32_t address, int segment, uint16_t); + void (*rawWrite32)(struct mCore*, uint32_t address, int segment, uint32_t); + + size_t (*listMemoryBlocks)(const struct mCore*, const struct mCoreMemoryBlock**); + void* (*getMemoryBlock)(struct mCore*, size_t id, size_t* sizeOut); + +#ifdef USE_DEBUGGERS + bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType); + struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*); + struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*); + void (*attachDebugger)(struct mCore*, struct mDebugger*); + void (*detachDebugger)(struct mCore*); + + void (*loadSymbols)(struct mCore*, struct VFile*); + bool (*lookupIdentifier)(struct mCore*, const char* name, int32_t* value, int* segment); +#endif + + struct mCheatDevice* (*cheatDevice)(struct mCore*); + + size_t (*savedataClone)(struct mCore*, void** sram); + bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback); + + size_t (*listVideoLayers)(const struct mCore*, const struct mCoreChannelInfo**); + size_t (*listAudioChannels)(const struct mCore*, const struct mCoreChannelInfo**); + void (*enableVideoLayer)(struct mCore*, size_t id, bool enable); + void (*enableAudioChannel)(struct mCore*, size_t id, bool enable); + void (*adjustVideoLayer)(struct mCore*, size_t id, int32_t x, int32_t y); + +#ifndef MINIMAL_CORE + void (*startVideoLog)(struct mCore*, struct mVideoLogContext*); + void (*endVideoLog)(struct mCore*); +#endif +}; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +struct mCore* mCoreFind(const char* path); +bool mCoreLoadFile(struct mCore* core, const char* path); + +bool mCorePreloadVF(struct mCore* core, struct VFile* vf); +bool mCorePreloadFile(struct mCore* core, const char* path); + +bool mCorePreloadVFCB(struct mCore* core, struct VFile* vf, void (cb)(size_t, size_t, void*), void* context); +bool mCorePreloadFileCB(struct mCore* core, const char* path, void (cb)(size_t, size_t, void*), void* context); + +bool mCoreAutoloadSave(struct mCore* core); +bool mCoreAutoloadPatch(struct mCore* core); +bool mCoreAutoloadCheats(struct mCore* core); + +bool mCoreSaveState(struct mCore* core, int slot, int flags); +bool mCoreLoadState(struct mCore* core, int slot, int flags); +struct VFile* mCoreGetState(struct mCore* core, int slot, bool write); +void mCoreDeleteState(struct mCore* core, int slot); + +void mCoreTakeScreenshot(struct mCore* core); +#endif + +struct mCore* mCoreFindVF(struct VFile* vf); +enum mPlatform mCoreIsCompatible(struct VFile* vf); +struct mCore* mCoreCreate(enum mPlatform); + +bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags); +bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags); + +void mCoreInitConfig(struct mCore* core, const char* port); +void mCoreLoadConfig(struct mCore* core); +void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config); + +void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc); + +void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size); +void* mCoreGetMemoryBlockMasked(struct mCore* core, uint32_t start, size_t* size, uint32_t mask); +const struct mCoreMemoryBlock* mCoreGetMemoryBlockInfo(struct mCore* core, uint32_t address); + +#ifdef USE_ELF +struct ELF; +bool mCoreLoadELF(struct mCore* core, struct ELF* elf); +#ifdef USE_DEBUGGERS +void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF*); +#endif +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/cpu.h b/mgba-test-runner/c/include/mgba/core/cpu.h new file mode 100644 index 00000000..71f3398c --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/cpu.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CPU_H +#define M_CPU_H + +#include + +CXX_GUARD_START + +enum mCPUComponentType { + CPU_COMPONENT_DEBUGGER, + CPU_COMPONENT_CHEAT_DEVICE, + CPU_COMPONENT_MISC_1, + CPU_COMPONENT_MISC_2, + CPU_COMPONENT_MISC_3, + CPU_COMPONENT_MISC_4, + CPU_COMPONENT_MAX +}; + +struct mCPUComponent { + uint32_t id; + void (*init)(void* cpu, struct mCPUComponent* component); + void (*deinit)(struct mCPUComponent* component); +}; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/directories.h b/mgba-test-runner/c/include/mgba/core/directories.h new file mode 100644 index 00000000..d421e7f5 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/directories.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DIRECTORIES_H +#define DIRECTORIES_H + +#include + +CXX_GUARD_START + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +struct VDir; + +struct mDirectorySet { + char baseName[PATH_MAX]; + struct VDir* base; + struct VDir* archive; + struct VDir* save; + struct VDir* patch; + struct VDir* state; + struct VDir* screenshot; + struct VDir* cheats; +}; + +void mDirectorySetInit(struct mDirectorySet* dirs); +void mDirectorySetDeinit(struct mDirectorySet* dirs); + +void mDirectorySetAttachBase(struct mDirectorySet* dirs, struct VDir* base); +void mDirectorySetDetachBase(struct mDirectorySet* dirs); + +struct VFile* mDirectorySetOpenPath(struct mDirectorySet* dirs, const char* path, bool (*filter)(struct VFile*)); +struct VFile* mDirectorySetOpenSuffix(struct mDirectorySet* dirs, struct VDir* dir, const char* suffix, int mode); + +struct mCoreOptions; +void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/input.h b/mgba-test-runner/c/include/mgba/core/input.h new file mode 100644 index 00000000..e5f64d72 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/input.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_INPUT_H +#define M_INPUT_H + +#include + +CXX_GUARD_START + +struct Configuration; + +enum mInputHat { + M_INPUT_HAT_NEUTRAL = 0, + M_INPUT_HAT_UP = 1, + M_INPUT_HAT_RIGHT = 2, + M_INPUT_HAT_DOWN = 4, + M_INPUT_HAT_LEFT = 8 +}; + +struct mInputHatBindings { + int up; + int right; + int down; + int left; +}; + +struct mInputPlatformInfo { + const char* platformName; + const char** keyId; + size_t nKeys; + struct mInputHatBindings hat; +}; + +struct mInputMap { + struct mInputMapImpl* maps; + size_t numMaps; + const struct mInputPlatformInfo* info; +}; + +struct mInputAxis { + int highDirection; + int lowDirection; + int32_t deadHigh; + int32_t deadLow; +}; + +void mInputMapInit(struct mInputMap*, const struct mInputPlatformInfo* info); +void mInputMapDeinit(struct mInputMap*); + +int mInputMapKey(const struct mInputMap*, uint32_t type, int key); +int mInputMapKeyBits(const struct mInputMap* map, uint32_t type, uint32_t bits, unsigned offset); +void mInputBindKey(struct mInputMap*, uint32_t type, int key, int input); +int mInputQueryBinding(const struct mInputMap*, uint32_t type, int input); +void mInputUnbindKey(struct mInputMap*, uint32_t type, int input); + +int mInputMapAxis(const struct mInputMap*, uint32_t type, int axis, int value); +int mInputClearAxis(const struct mInputMap*, uint32_t type, int axis, int keys); +void mInputBindAxis(struct mInputMap*, uint32_t type, int axis, const struct mInputAxis* description); +void mInputUnbindAxis(struct mInputMap*, uint32_t type, int axis); +void mInputUnbindAllAxes(struct mInputMap*, uint32_t type); +const struct mInputAxis* mInputQueryAxis(const struct mInputMap*, uint32_t type, int axis); +void mInputEnumerateAxes(const struct mInputMap*, uint32_t type, void (handler(int axis, const struct mInputAxis* description, void* user)), void* user); + +int mInputMapHat(const struct mInputMap*, uint32_t type, int id, int direction); +void mInputBindHat(struct mInputMap*, uint32_t type, int id, const struct mInputHatBindings* bindings); +bool mInputQueryHat(const struct mInputMap*, uint32_t type, int id, struct mInputHatBindings* bindings); +void mInputUnbindHat(struct mInputMap*, uint32_t type, int id); +void mInputUnbindAllHats(struct mInputMap*, uint32_t type); + +void mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*); +void mInputMapSave(const struct mInputMap*, uint32_t type, struct Configuration*); + +bool mInputProfileLoad(struct mInputMap*, uint32_t type, const struct Configuration*, const char* profile); +void mInputProfileSave(const struct mInputMap*, uint32_t type, struct Configuration*, const char* profile); + +const char* mInputGetPreferredDevice(const struct Configuration*, const char* platformName, uint32_t type, int playerId); +void mInputSetPreferredDevice(struct Configuration*, const char* platformName, uint32_t type, int playerId, const char* deviceName); + +const char* mInputGetCustomValue(const struct Configuration* config, const char* platformName, uint32_t type, const char* key, + const char* profile); +void mInputSetCustomValue(struct Configuration* config, const char* platformName, uint32_t type, const char* key, const char* value, + const char* profile); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/interface.h b/mgba-test-runner/c/include/mgba/core/interface.h new file mode 100644 index 00000000..ca42bca7 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/interface.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CORE_INTERFACE_H +#define CORE_INTERFACE_H + +#include + +CXX_GUARD_START + +#include + +struct mCore; +struct mStateExtdataItem; + +#ifdef COLOR_16_BIT +typedef uint16_t color_t; +#define BYTES_PER_PIXEL 2 +#else +typedef uint32_t color_t; +#define BYTES_PER_PIXEL 4 +#endif + +#define M_R5(X) ((X) & 0x1F) +#define M_G5(X) (((X) >> 5) & 0x1F) +#define M_B5(X) (((X) >> 10) & 0x1F) + +#define M_R8(X) (((((X) << 3) & 0xF8) * 0x21) >> 5) +#define M_G8(X) (((((X) >> 2) & 0xF8) * 0x21) >> 5) +#define M_B8(X) (((((X) >> 7) & 0xF8) * 0x21) >> 5) + +#define M_RGB5_TO_BGR8(X) ((M_R5(X) << 3) | (M_G5(X) << 11) | (M_B5(X) << 19)) +#define M_RGB5_TO_RGB8(X) ((M_R5(X) << 19) | (M_G5(X) << 11) | (M_B5(X) << 3)) +#define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9)) +#define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19)) + +#ifndef COLOR_16_BIT +#define M_COLOR_RED 0x000000FF +#define M_COLOR_GREEN 0x0000FF00 +#define M_COLOR_BLUE 0x00FF0000 +#define M_COLOR_ALPHA 0xFF000000 +#define M_COLOR_WHITE 0x00FFFFFF + +#define M_RGB8_TO_NATIVE(X) (((X) & 0x00FF00) | (((X) & 0x0000FF) << 16) | (((X) & 0xFF0000) >> 16)) +#elif defined(COLOR_5_6_5) +#define M_COLOR_RED 0x001F +#define M_COLOR_GREEN 0x07E0 +#define M_COLOR_BLUE 0xF800 +#define M_COLOR_ALPHA 0x0000 +#define M_COLOR_WHITE 0xFFDF + +#define M_RGB8_TO_NATIVE(X) ((((X) & 0xF8) << 8) | (((X) & 0xFC00) >> 5) | (((X) & 0xF80000) >> 19)) +#else +#define M_COLOR_RED 0x001F +#define M_COLOR_GREEN 0x03E0 +#define M_COLOR_BLUE 0x7C00 +#define M_COLOR_ALPHA 0x1000 +#define M_COLOR_WHITE 0x7FFF + +#define M_RGB8_TO_NATIVE(X) M_RGB8_TO_BGR5(X) +#endif + +#ifndef PYCPARSE +static inline color_t mColorFrom555(uint16_t value) { +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + color_t color = 0; + color |= (value & 0x001F) << 11; + color |= (value & 0x03E0) << 1; + color |= (value & 0x7C00) >> 10; +#else + color_t color = value; +#endif +#else + color_t color = M_RGB5_TO_BGR8(value); + color |= (color >> 5) & 0x070707; +#endif + return color; +} + +ATTRIBUTE_UNUSED static unsigned mColorMix5Bit(int weightA, unsigned colorA, int weightB, unsigned colorB) { + unsigned c = 0; + unsigned a, b; +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + a = colorA & 0xF81F; + b = colorB & 0xF81F; + a |= (colorA & 0x7C0) << 16; + b |= (colorB & 0x7C0) << 16; + c = ((a * weightA + b * weightB) / 16); + if (c & 0x08000000) { + c = (c & ~0x0FC00000) | 0x07C00000; + } + if (c & 0x0020) { + c = (c & ~0x003F) | 0x001F; + } + if (c & 0x10000) { + c = (c & ~0x1F800) | 0xF800; + } + c = (c & 0xF81F) | ((c >> 16) & 0x07C0); +#else + a = colorA & 0x7C1F; + b = colorB & 0x7C1F; + a |= (colorA & 0x3E0) << 16; + b |= (colorB & 0x3E0) << 16; + c = ((a * weightA + b * weightB) / 16); + if (c & 0x04000000) { + c = (c & ~0x07E00000) | 0x03E00000; + } + if (c & 0x0020) { + c = (c & ~0x003F) | 0x001F; + } + if (c & 0x8000) { + c = (c & ~0xF800) | 0x7C00; + } + c = (c & 0x7C1F) | ((c >> 16) & 0x03E0); +#endif +#else + a = colorA & 0xFF; + b = colorB & 0xFF; + c |= ((a * weightA + b * weightB) / 16) & 0x1FF; + if (c & 0x00000100) { + c = 0x000000FF; + } + + a = colorA & 0xFF00; + b = colorB & 0xFF00; + c |= ((a * weightA + b * weightB) / 16) & 0x1FF00; + if (c & 0x00010000) { + c = (c & 0x000000FF) | 0x0000FF00; + } + + a = colorA & 0xFF0000; + b = colorB & 0xFF0000; + c |= ((a * weightA + b * weightB) / 16) & 0x1FF0000; + if (c & 0x01000000) { + c = (c & 0x0000FFFF) | 0x00FF0000; + } +#endif + return c; +} +#endif + +struct blip_t; + +enum mColorFormat { + mCOLOR_XBGR8 = 0x00001, + mCOLOR_XRGB8 = 0x00002, + mCOLOR_BGRX8 = 0x00004, + mCOLOR_RGBX8 = 0x00008, + mCOLOR_ABGR8 = 0x00010, + mCOLOR_ARGB8 = 0x00020, + mCOLOR_BGRA8 = 0x00040, + mCOLOR_RGBA8 = 0x00080, + mCOLOR_RGB5 = 0x00100, + mCOLOR_BGR5 = 0x00200, + mCOLOR_RGB565 = 0x00400, + mCOLOR_BGR565 = 0x00800, + mCOLOR_ARGB5 = 0x01000, + mCOLOR_ABGR5 = 0x02000, + mCOLOR_RGBA5 = 0x04000, + mCOLOR_BGRA5 = 0x08000, + mCOLOR_RGB8 = 0x10000, + mCOLOR_BGR8 = 0x20000, + + mCOLOR_ANY = -1 +}; + +enum mCoreFeature { + mCORE_FEATURE_OPENGL = 1, +}; + +struct mCoreCallbacks { + void* context; + void (*videoFrameStarted)(void* context); + void (*videoFrameEnded)(void* context); + void (*coreCrashed)(void* context); + void (*sleep)(void* context); + void (*shutdown)(void* context); + void (*keysRead)(void* context); + void (*savedataUpdated)(void* context); +}; + +DECLARE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks); + +struct mAVStream { + void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height); + void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride); + void (*postAudioFrame)(struct mAVStream*, int16_t left, int16_t right); + void (*postAudioBuffer)(struct mAVStream*, struct blip_t* left, struct blip_t* right); +}; + +struct mKeyCallback { + uint16_t (*readKeys)(struct mKeyCallback*); +}; + +enum mPeripheral { + mPERIPH_ROTATION = 1, + mPERIPH_RUMBLE, + mPERIPH_IMAGE_SOURCE, + mPERIPH_CUSTOM = 0x1000 +}; + +struct mRotationSource { + void (*sample)(struct mRotationSource*); + + int32_t (*readTiltX)(struct mRotationSource*); + int32_t (*readTiltY)(struct mRotationSource*); + + int32_t (*readGyroZ)(struct mRotationSource*); +}; + +struct mRTCSource { + void (*sample)(struct mRTCSource*); + + time_t (*unixTime)(struct mRTCSource*); + + void (*serialize)(struct mRTCSource*, struct mStateExtdataItem*); + bool (*deserialize)(struct mRTCSource*, const struct mStateExtdataItem*); +}; + +struct mImageSource { + void (*startRequestImage)(struct mImageSource*, unsigned w, unsigned h, int colorFormats); + void (*stopRequestImage)(struct mImageSource*); + void (*requestImage)(struct mImageSource*, const void** buffer, size_t* stride, enum mColorFormat* colorFormat); +}; + +enum mRTCGenericType { + RTC_NO_OVERRIDE, + RTC_FIXED, + RTC_FAKE_EPOCH, + RTC_CUSTOM_START = 0x1000 +}; + +struct mRTCGenericSource { + struct mRTCSource d; + struct mCore* p; + enum mRTCGenericType override; + int64_t value; + struct mRTCSource* custom; +}; + +struct mRTCGenericState { + int32_t type; + int32_t padding; + int64_t value; +}; + +void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core); + +struct mRumble { + void (*setRumble)(struct mRumble*, int enable); +}; + +struct mCoreChannelInfo { + size_t id; + const char* internalName; + const char* visibleName; + const char* visibleType; +}; + +enum mCoreMemoryBlockFlags { + mCORE_MEMORY_READ = 0x01, + mCORE_MEMORY_WRITE = 0x02, + mCORE_MEMORY_RW = 0x03, + mCORE_MEMORY_WORM = 0x04, + mCORE_MEMORY_MAPPED = 0x10, + mCORE_MEMORY_VIRTUAL = 0x20, +}; + +struct mCoreMemoryBlock { + size_t id; + const char* internalName; + const char* shortName; + const char* longName; + uint32_t start; + uint32_t end; + uint32_t size; + uint32_t flags; + uint16_t maxSegment; + uint32_t segmentStart; +}; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/library.h b/mgba-test-runner/c/include/mgba/core/library.h new file mode 100644 index 00000000..d12aa041 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/library.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_LIBRARY_H +#define M_LIBRARY_H + +#include + +CXX_GUARD_START + +#include +#include + +struct mLibraryEntry { + const char* base; + const char* filename; + const char* title; + char internalTitle[17]; + char internalCode[9]; + enum mPlatform platform; + size_t filesize; + uint32_t crc32; +}; + +#ifdef USE_SQLITE3 + +DECLARE_VECTOR(mLibraryListing, struct mLibraryEntry); + +struct mLibrary; +struct mLibrary* mLibraryCreateEmpty(void); +struct mLibrary* mLibraryLoad(const char* filename); +void mLibraryDestroy(struct mLibrary*); + +struct VDir; +struct VFile; +void mLibraryLoadDirectory(struct mLibrary* library, const char* base, bool recursive); +void mLibraryClear(struct mLibrary* library); + +size_t mLibraryCount(struct mLibrary* library, const struct mLibraryEntry* constraints); +size_t mLibraryGetEntries(struct mLibrary* library, struct mLibraryListing* out, size_t numEntries, size_t offset, const struct mLibraryEntry* constraints); +void mLibraryEntryFree(struct mLibraryEntry* entry); +struct VFile* mLibraryOpenVFile(struct mLibrary* library, const struct mLibraryEntry* entry); + +struct NoIntroDB; +void mLibraryAttachGameDB(struct mLibrary* library, const struct NoIntroDB* db); + +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/lockstep.h b/mgba-test-runner/c/include/mgba/core/lockstep.h new file mode 100644 index 00000000..ac6cb3f8 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/lockstep.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SIO_LOCKSTEP_H +#define SIO_LOCKSTEP_H + +#include + +CXX_GUARD_START + +enum mLockstepPhase { + TRANSFER_IDLE = 0, + TRANSFER_STARTING, + TRANSFER_STARTED, + TRANSFER_FINISHING, + TRANSFER_FINISHED +}; + +struct mLockstep { + int attached; + enum mLockstepPhase transferActive; + int32_t transferCycles; + + void (*lock)(struct mLockstep*); + void (*unlock)(struct mLockstep*); + + bool (*signal)(struct mLockstep*, unsigned mask); + bool (*wait)(struct mLockstep*, unsigned mask); + void (*addCycles)(struct mLockstep*, int id, int32_t cycles); + int32_t (*useCycles)(struct mLockstep*, int id, int32_t cycles); + int32_t (*unusedCycles)(struct mLockstep*, int id); + void (*unload)(struct mLockstep*, int id); + void* context; +#ifndef NDEBUG + int transferId; +#endif +}; + +void mLockstepInit(struct mLockstep*); +void mLockstepDeinit(struct mLockstep*); + +static inline void mLockstepLock(struct mLockstep* lockstep) { + if (lockstep->lock) { + lockstep->lock(lockstep); + } +} + +static inline void mLockstepUnlock(struct mLockstep* lockstep) { + if (lockstep->unlock) { + lockstep->unlock(lockstep); + } +} + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/log.h b/mgba-test-runner/c/include/mgba/core/log.h new file mode 100644 index 00000000..e2ac55e4 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/log.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_LOG_H +#define M_LOG_H + +#include + +CXX_GUARD_START + +#include + +enum mLogLevel { + mLOG_FATAL = 0x01, + mLOG_ERROR = 0x02, + mLOG_WARN = 0x04, + mLOG_INFO = 0x08, + mLOG_DEBUG = 0x10, + mLOG_STUB = 0x20, + mLOG_GAME_ERROR = 0x40, + + mLOG_ALL = 0x7F +}; + +struct Table; +struct mLogFilter { + int defaultLevels; + struct Table categories; + struct Table levels; +}; + +struct mLogger { + void (*log)(struct mLogger*, int category, enum mLogLevel level, const char* format, va_list args); + struct mLogFilter* filter; +}; + +struct mLogger* mLogGetContext(void); +void mLogSetDefaultLogger(struct mLogger*); +int mLogGenerateCategory(const char*, const char*); +const char* mLogCategoryName(int); +const char* mLogCategoryId(int); +int mLogCategoryById(const char*); + +struct mCoreConfig; +void mLogFilterInit(struct mLogFilter*); +void mLogFilterDeinit(struct mLogFilter*); +void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*); +void mLogFilterSave(const struct mLogFilter*, struct mCoreConfig*); +void mLogFilterSet(struct mLogFilter*, const char* category, int levels); +void mLogFilterReset(struct mLogFilter*, const char* category); +bool mLogFilterTest(const struct mLogFilter*, int category, enum mLogLevel level); +int mLogFilterLevels(const struct mLogFilter*, int category); + +ATTRIBUTE_FORMAT(printf, 3, 4) +void mLog(int category, enum mLogLevel level, const char* format, ...); + +#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY, mLOG_ ## LEVEL, __VA_ARGS__) + +#define mLOG_DECLARE_CATEGORY(CATEGORY) extern int _mLOG_CAT_ ## CATEGORY; +#define mLOG_DEFINE_CATEGORY(CATEGORY, NAME, ID) \ + int _mLOG_CAT_ ## CATEGORY; \ + CONSTRUCTOR(_mLOG_CAT_ ## CATEGORY ## _INIT) { \ + _mLOG_CAT_ ## CATEGORY = mLogGenerateCategory(NAME, ID); \ + } + +MGBA_EXPORT mLOG_DECLARE_CATEGORY(STATUS) + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/map-cache.h b/mgba-test-runner/c/include/mgba/core/map-cache.h new file mode 100644 index 00000000..6dc9e72f --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/map-cache.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_MAP_CACHE_H +#define M_MAP_CACHE_H + +#include + +CXX_GUARD_START + +#include +#include + +DECL_BITFIELD(mMapCacheConfiguration, uint32_t); +DECL_BIT(mMapCacheConfiguration, ShouldStore, 0); + +DECL_BITFIELD(mMapCacheSystemInfo, uint32_t); +DECL_BITS(mMapCacheSystemInfo, PaletteBPP, 0, 2); +DECL_BITS(mMapCacheSystemInfo, PaletteCount, 2, 4); +DECL_BITS(mMapCacheSystemInfo, TilesWide, 8, 4); +DECL_BITS(mMapCacheSystemInfo, TilesHigh, 12, 4); +DECL_BITS(mMapCacheSystemInfo, MacroTileSize, 16, 7); +DECL_BITS(mMapCacheSystemInfo, MapAlign, 23, 2); + +DECL_BITFIELD(mMapCacheEntryFlags, uint16_t); +DECL_BITS(mMapCacheEntryFlags, PaletteId, 0, 4); +DECL_BIT(mMapCacheEntryFlags, VramClean, 4); +DECL_BIT(mMapCacheEntryFlags, HMirror, 5); +DECL_BIT(mMapCacheEntryFlags, VMirror, 6); +DECL_BITS(mMapCacheEntryFlags, Mirror, 5, 2); + +struct mMapCacheEntry { + uint32_t vramVersion; + uint16_t tileId; + mMapCacheEntryFlags flags; + struct mTileCacheEntry tileStatus[16]; +}; + +struct mTileCache; +struct mTileCacheEntry; +struct mMapCache { + color_t* cache; + struct mTileCache* tileCache; + struct mMapCacheEntry* status; + + uint8_t* vram; + + uint32_t mapStart; + uint32_t mapSize; + + uint32_t tileStart; + + mMapCacheConfiguration config; + mMapCacheSystemInfo sysConfig; + + void (*mapParser)(struct mMapCache*, struct mMapCacheEntry* entry, void* vram); + void* context; +}; + +void mMapCacheInit(struct mMapCache* cache); +void mMapCacheDeinit(struct mMapCache* cache); +void mMapCacheConfigure(struct mMapCache* cache, mMapCacheConfiguration config); +void mMapCacheConfigureSystem(struct mMapCache* cache, mMapCacheSystemInfo config); +void mMapCacheConfigureMap(struct mMapCache* cache, uint32_t mapStart); +void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address); + +uint32_t mMapCacheTileId(struct mMapCache* cache, unsigned x, unsigned y); + +bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y); +void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y); + +void mMapCacheCleanRow(struct mMapCache* cache, unsigned y); +const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/mem-search.h b/mgba-test-runner/c/include/mgba/core/mem-search.h new file mode 100644 index 00000000..d4560155 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/mem-search.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CORE_MEM_SEARCH_H +#define CORE_MEM_SEARCH_H + +#include + +CXX_GUARD_START + +#include + +enum mCoreMemorySearchType { + mCORE_MEMORY_SEARCH_INT, + mCORE_MEMORY_SEARCH_STRING, + mCORE_MEMORY_SEARCH_GUESS, +}; + +enum mCoreMemorySearchOp { + mCORE_MEMORY_SEARCH_EQUAL, + mCORE_MEMORY_SEARCH_GREATER, + mCORE_MEMORY_SEARCH_LESS, + mCORE_MEMORY_SEARCH_ANY, + mCORE_MEMORY_SEARCH_DELTA, + mCORE_MEMORY_SEARCH_DELTA_POSITIVE, + mCORE_MEMORY_SEARCH_DELTA_NEGATIVE, + mCORE_MEMORY_SEARCH_DELTA_ANY, +}; + +struct mCoreMemorySearchParams { + int memoryFlags; + enum mCoreMemorySearchType type; + enum mCoreMemorySearchOp op; + int align; + int width; + union { + const char* valueStr; + int32_t valueInt; + }; +}; + +struct mCoreMemorySearchResult { + uint32_t address; + int segment; + uint32_t guessDivisor; + uint32_t guessMultiplier; + enum mCoreMemorySearchType type; + int width; + int32_t oldValue; +}; + +DECLARE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult); + +struct mCore; +void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit); +void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* inout); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/rewind.h b/mgba-test-runner/c/include/mgba/core/rewind.h new file mode 100644 index 00000000..04549761 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/rewind.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_REWIND_H +#define M_CORE_REWIND_H + +#include + +CXX_GUARD_START + +#include +#ifndef DISABLE_THREADING +#include +#endif + +DECLARE_VECTOR(mCoreRewindPatches, struct PatchFast); + +struct VFile; +struct mCoreRewindContext { + struct mCoreRewindPatches patchMemory; + size_t current; + size_t size; + struct VFile* previousState; + struct VFile* currentState; + +#ifndef DISABLE_THREADING + bool onThread; + Thread thread; + Condition cond; + Mutex mutex; + bool ready; +#endif +}; + +void mCoreRewindContextInit(struct mCoreRewindContext*, size_t entries, bool onThread); +void mCoreRewindContextDeinit(struct mCoreRewindContext*); + +struct mCore; +void mCoreRewindAppend(struct mCoreRewindContext*, struct mCore*); +bool mCoreRewindRestore(struct mCoreRewindContext*, struct mCore*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/scripting.h b/mgba-test-runner/c/include/mgba/core/scripting.h new file mode 100644 index 00000000..ebf8f88c --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/scripting.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_SCRIPTING_H +#define M_SCRIPTING_H + +#include + +CXX_GUARD_START + +#ifdef USE_DEBUGGERS +#include +#endif + +struct mScriptBridge; +struct VFile; +struct mScriptEngine { + const char* (*name)(struct mScriptEngine*); + + bool (*init)(struct mScriptEngine*, struct mScriptBridge*); + void (*deinit)(struct mScriptEngine*); + bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf); + bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf); + void (*run)(struct mScriptEngine*); + bool (*lookupSymbol)(struct mScriptEngine*, const char* name, int32_t* out); + +#ifdef USE_DEBUGGERS + void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +#endif +}; + +struct mScriptBridge* mScriptBridgeCreate(void); +void mScriptBridgeDestroy(struct mScriptBridge*); + +void mScriptBridgeInstallEngine(struct mScriptBridge*, struct mScriptEngine*); + +#ifdef USE_DEBUGGERS +void mScriptBridgeSetDebugger(struct mScriptBridge*, struct mDebugger*); +struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge*); +void mScriptBridgeDebuggerEntered(struct mScriptBridge*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +#endif + +void mScriptBridgeRun(struct mScriptBridge*); +bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name); + +bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/serialize.h b/mgba-test-runner/c/include/mgba/core/serialize.h new file mode 100644 index 00000000..968f3f16 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/serialize.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_SERIALIZE_H +#define M_SERIALIZE_H + +#include + +CXX_GUARD_START + +enum mStateExtdataTag { + EXTDATA_NONE = 0, + EXTDATA_SCREENSHOT = 1, + EXTDATA_SAVEDATA = 2, + EXTDATA_CHEATS = 3, + EXTDATA_RTC = 4, + EXTDATA_META_TIME = 0x101, + EXTDATA_MAX +}; + +#define SAVESTATE_SCREENSHOT 1 +#define SAVESTATE_SAVEDATA 2 +#define SAVESTATE_CHEATS 4 +#define SAVESTATE_RTC 8 +#define SAVESTATE_METADATA 16 + +struct mStateExtdataItem { + int32_t size; + void* data; + void (*clean)(void*); +}; + +struct mStateExtdata { + struct mStateExtdataItem data[EXTDATA_MAX]; +}; + +void mStateExtdataInit(struct mStateExtdata*); +void mStateExtdataDeinit(struct mStateExtdata*); +void mStateExtdataPut(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*); +bool mStateExtdataGet(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*); + +struct VFile; +bool mStateExtdataSerialize(struct mStateExtdata* extdata, struct VFile* vf); +bool mStateExtdataDeserialize(struct mStateExtdata* extdata, struct VFile* vf); + +struct mCore; +bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags); +bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags); +void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata); +bool mCoreExtractExtdata(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/sync.h b/mgba-test-runner/c/include/mgba/core/sync.h new file mode 100644 index 00000000..a44994b0 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/sync.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_SYNC_H +#define M_CORE_SYNC_H + +#include + +CXX_GUARD_START + +#include + +struct mCoreSync { + int videoFramePending; + bool videoFrameWait; + Mutex videoFrameMutex; + Condition videoFrameAvailableCond; + Condition videoFrameRequiredCond; + + bool audioWait; + Condition audioRequiredCond; + Mutex audioBufferMutex; + + float fpsTarget; +}; + +void mCoreSyncPostFrame(struct mCoreSync* sync); +void mCoreSyncForceFrame(struct mCoreSync* sync); +bool mCoreSyncWaitFrameStart(struct mCoreSync* sync); +void mCoreSyncWaitFrameEnd(struct mCoreSync* sync); +void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait); + +struct blip_t; +bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct blip_t*, size_t samples); +void mCoreSyncLockAudio(struct mCoreSync* sync); +void mCoreSyncUnlockAudio(struct mCoreSync* sync); +void mCoreSyncConsumeAudio(struct mCoreSync* sync); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/thread.h b/mgba-test-runner/c/include/mgba/core/thread.h new file mode 100644 index 00000000..f5b26a18 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/thread.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_THREAD_H +#define M_CORE_THREAD_H + +#include + +CXX_GUARD_START + +#include + +struct mCoreThread; +struct mCore; + +typedef void (*ThreadCallback)(struct mCoreThread* threadContext); + +struct mCoreThread; +struct mThreadLogger { + struct mLogger d; + struct mCoreThread* p; +}; + +struct mCoreThreadInternal; +struct mCoreThread { + // Input + struct mCore* core; + + struct mThreadLogger logger; + ThreadCallback startCallback; + ThreadCallback resetCallback; + ThreadCallback cleanCallback; + ThreadCallback frameCallback; + ThreadCallback sleepCallback; + ThreadCallback pauseCallback; + ThreadCallback unpauseCallback; + void* userData; + void (*run)(struct mCoreThread*); + + struct mCoreThreadInternal* impl; +}; + +#ifndef OPAQUE_THREADING +#include +#include +#include + +enum mCoreThreadState { + mTHREAD_INITIALIZED = -1, + mTHREAD_RUNNING = 0, + mTHREAD_REQUEST, + + mTHREAD_INTERRUPTED, + mTHREAD_PAUSED, + mTHREAD_MIN_WAITING = mTHREAD_INTERRUPTED, + mTHREAD_MAX_WAITING = mTHREAD_PAUSED, + + mTHREAD_INTERRUPTING, + mTHREAD_EXITING, + + mTHREAD_SHUTDOWN, + mTHREAD_CRASHED +}; + +enum mCoreThreadRequest { + mTHREAD_REQ_PAUSE = 1, // User-set pause + mTHREAD_REQ_WAIT = 2, // Core-set pause + mTHREAD_REQ_RESET = 4, + mTHREAD_REQ_RUN_ON = 8, +}; + +struct mCoreThreadInternal { + Thread thread; + enum mCoreThreadState state; + bool rewinding; + int requested; + + Mutex stateMutex; + Condition stateCond; + int interruptDepth; + bool frameWasOn; + + struct mCoreSync sync; + struct mCoreRewindContext rewind; +}; + +#endif + +bool mCoreThreadStart(struct mCoreThread* threadContext); +bool mCoreThreadHasStarted(struct mCoreThread* threadContext); +bool mCoreThreadHasExited(struct mCoreThread* threadContext); +bool mCoreThreadHasCrashed(struct mCoreThread* threadContext); +void mCoreThreadMarkCrashed(struct mCoreThread* threadContext); +void mCoreThreadEnd(struct mCoreThread* threadContext); +void mCoreThreadReset(struct mCoreThread* threadContext); +void mCoreThreadJoin(struct mCoreThread* threadContext); + +bool mCoreThreadIsActive(struct mCoreThread* threadContext); +void mCoreThreadInterrupt(struct mCoreThread* threadContext); +void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext); +void mCoreThreadContinue(struct mCoreThread* threadContext); + +void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)); + +void mCoreThreadPause(struct mCoreThread* threadContext); +void mCoreThreadUnpause(struct mCoreThread* threadContext); +bool mCoreThreadIsPaused(struct mCoreThread* threadContext); +void mCoreThreadTogglePause(struct mCoreThread* threadContext); +void mCoreThreadPauseFromThread(struct mCoreThread* threadContext); +void mCoreThreadWaitFromThread(struct mCoreThread* threadContext); +void mCoreThreadStopWaiting(struct mCoreThread* threadContext); + +void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool); +void mCoreThreadRewindParamsChanged(struct mCoreThread* threadContext); + +struct mCoreThread* mCoreThreadGet(void); +struct mLogger* mCoreThreadLogger(void); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/tile-cache.h b/mgba-test-runner/c/include/mgba/core/tile-cache.h new file mode 100644 index 00000000..f8600b3a --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/tile-cache.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_TILE_CACHE_H +#define M_TILE_CACHE_H + +#include + +CXX_GUARD_START + +#include + +DECL_BITFIELD(mTileCacheConfiguration, uint32_t); +DECL_BIT(mTileCacheConfiguration, ShouldStore, 0); + +DECL_BITFIELD(mTileCacheSystemInfo, uint32_t); +DECL_BITS(mTileCacheSystemInfo, PaletteBPP, 0, 2); +DECL_BITS(mTileCacheSystemInfo, PaletteCount, 2, 4); +DECL_BITS(mTileCacheSystemInfo, MaxTiles, 16, 13); + +struct mTileCacheEntry { + uint32_t paletteVersion; + uint32_t vramVersion; + uint8_t vramClean; + uint8_t paletteId; + uint16_t padding; +}; + +struct mTileCache { + color_t* cache; + struct mTileCacheEntry* status; + uint32_t* globalPaletteVersion; + + uint32_t tileBase; + uint32_t paletteBase; + unsigned entriesPerTile; + unsigned bpp; + + uint16_t* vram; + color_t* palette; + color_t temporaryTile[64]; + + mTileCacheConfiguration config; + mTileCacheSystemInfo sysConfig; +}; + +void mTileCacheInit(struct mTileCache* cache); +void mTileCacheDeinit(struct mTileCache* cache); +void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config); +void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config, uint32_t tileBase, uint32_t paletteBase); +void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address); +void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, color_t color); + +const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId); +const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId); +const color_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId); +const uint16_t* mTileCacheGetVRAM(struct mTileCache* cache, unsigned tileId); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/timing.h b/mgba-test-runner/c/include/mgba/core/timing.h new file mode 100644 index 00000000..3db79493 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/timing.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_TIMING +#define M_CORE_TIMING + +#include + +CXX_GUARD_START + +struct mTiming; +struct mTimingEvent { + void* context; + void (*callback)(struct mTiming*, void* context, uint32_t); + const char* name; + uint32_t when; + unsigned priority; + + struct mTimingEvent* next; +}; + +struct mTiming { + struct mTimingEvent* root; + struct mTimingEvent* reroot; + + uint64_t globalCycles; + uint32_t masterCycles; + int32_t* relativeCycles; + int32_t* nextEvent; +}; + +void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent); +void mTimingDeinit(struct mTiming* timing); +void mTimingClear(struct mTiming* timing); +void mTimingSchedule(struct mTiming* timing, struct mTimingEvent*, int32_t when); +void mTimingScheduleAbsolute(struct mTiming* timing, struct mTimingEvent*, int32_t when); +void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*); +bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent*); +int32_t mTimingTick(struct mTiming* timing, int32_t cycles); +int32_t mTimingCurrentTime(const struct mTiming* timing); +uint64_t mTimingGlobalTime(const struct mTiming* timing); +int32_t mTimingNextEvent(struct mTiming* timing); +int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/core/version.h b/mgba-test-runner/c/include/mgba/core/version.h new file mode 100644 index 00000000..b261ab6d --- /dev/null +++ b/mgba-test-runner/c/include/mgba/core/version.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VERSION_H +#define VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern MGBA_EXPORT const char* const gitCommit; +extern MGBA_EXPORT const char* const gitCommitShort; +extern MGBA_EXPORT const char* const gitBranch; +extern MGBA_EXPORT const int gitRevision; +extern MGBA_EXPORT const char* const binaryName; +extern MGBA_EXPORT const char* const projectName; +extern MGBA_EXPORT const char* const projectVersion; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mgba-test-runner/c/include/mgba/debugger/debugger.h b/mgba-test-runner/c/include/mgba/debugger/debugger.h new file mode 100644 index 00000000..2adfa117 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/debugger/debugger.h @@ -0,0 +1,157 @@ +/* Copyright (c) 2013-2019 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DEBUGGER_H +#define DEBUGGER_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include + +mLOG_DECLARE_CATEGORY(DEBUGGER); + +extern const uint32_t DEBUGGER_ID; + +enum mDebuggerType { + DEBUGGER_NONE = 0, + DEBUGGER_CUSTOM, + DEBUGGER_CLI, + DEBUGGER_GDB, + DEBUGGER_MAX +}; + +enum mDebuggerState { + DEBUGGER_PAUSED, + DEBUGGER_RUNNING, + DEBUGGER_CALLBACK, + DEBUGGER_SHUTDOWN +}; + +enum mWatchpointType { + WATCHPOINT_WRITE = 1, + WATCHPOINT_READ = 2, + WATCHPOINT_RW = 3, + WATCHPOINT_CHANGE = 4, + WATCHPOINT_WRITE_CHANGE = 5, +}; + +enum mBreakpointType { + BREAKPOINT_HARDWARE, + BREAKPOINT_SOFTWARE +}; + +enum mDebuggerEntryReason { + DEBUGGER_ENTER_MANUAL, + DEBUGGER_ENTER_ATTACHED, + DEBUGGER_ENTER_BREAKPOINT, + DEBUGGER_ENTER_WATCHPOINT, + DEBUGGER_ENTER_ILLEGAL_OP, + DEBUGGER_ENTER_STACK +}; + +struct mDebuggerEntryInfo { + uint32_t address; + union { + struct { + uint32_t oldValue; + uint32_t newValue; + enum mWatchpointType watchType; + enum mWatchpointType accessType; + } wp; + + struct { + uint32_t opcode; + enum mBreakpointType breakType; + } bp; + + struct { + enum mStackTraceMode traceType; + } st; + } type; + ssize_t pointId; +}; + +struct mBreakpoint { + ssize_t id; + uint32_t address; + int segment; + enum mBreakpointType type; + struct ParseTree* condition; +}; + +struct mWatchpoint { + ssize_t id; + uint32_t address; + int segment; + enum mWatchpointType type; + struct ParseTree* condition; +}; + +DECLARE_VECTOR(mBreakpointList, struct mBreakpoint); +DECLARE_VECTOR(mWatchpointList, struct mWatchpoint); + +struct mDebugger; +struct ParseTree; +struct mDebuggerPlatform { + struct mDebugger* p; + + void (*init)(void* cpu, struct mDebuggerPlatform*); + void (*deinit)(struct mDebuggerPlatform*); + void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + + bool (*hasBreakpoints)(struct mDebuggerPlatform*); + void (*checkBreakpoints)(struct mDebuggerPlatform*); + bool (*clearBreakpoint)(struct mDebuggerPlatform*, ssize_t id); + + ssize_t (*setBreakpoint)(struct mDebuggerPlatform*, const struct mBreakpoint*); + void (*listBreakpoints)(struct mDebuggerPlatform*, struct mBreakpointList*); + + ssize_t (*setWatchpoint)(struct mDebuggerPlatform*, const struct mWatchpoint*); + void (*listWatchpoints)(struct mDebuggerPlatform*, struct mWatchpointList*); + + void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length); + + bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value); + bool (*setRegister)(struct mDebuggerPlatform*, const char* name, int32_t value); + bool (*lookupIdentifier)(struct mDebuggerPlatform*, const char* name, int32_t* value, int* segment); + + uint32_t (*getStackTraceMode)(struct mDebuggerPlatform*); + void (*setStackTraceMode)(struct mDebuggerPlatform*, uint32_t mode); + bool (*updateStackTrace)(struct mDebuggerPlatform* d); +}; + +struct mDebugger { + struct mCPUComponent d; + struct mDebuggerPlatform* platform; + enum mDebuggerState state; + enum mDebuggerType type; + struct mCore* core; + struct mScriptBridge* bridge; + struct mStackTrace stackTrace; + + void (*init)(struct mDebugger*); + void (*deinit)(struct mDebugger*); + + void (*paused)(struct mDebugger*); + void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + void (*custom)(struct mDebugger*); +}; + +struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore*); +void mDebuggerAttach(struct mDebugger*, struct mCore*); +void mDebuggerRun(struct mDebugger*); +void mDebuggerRunFrame(struct mDebugger*); +void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + +bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/feature/commandline.h b/mgba-test-runner/c/include/mgba/feature/commandline.h new file mode 100644 index 00000000..c543652e --- /dev/null +++ b/mgba-test-runner/c/include/mgba/feature/commandline.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef COMMAND_LINE_H +#define COMMAND_LINE_H + +#include + +CXX_GUARD_START + +#include + +#include + +struct mArguments { + char* fname; + char* patch; + char* cheatsFile; + char* savestate; + char* bios; + int logLevel; + int frameskip; + + struct Table configOverrides; + + enum mDebuggerType debuggerType; + bool debugAtStart; + bool showHelp; + bool showVersion; +}; + +struct mCoreConfig; +struct mSubParser { + const char* usage; + bool (*parse)(struct mSubParser* parser, int option, const char* arg); + void (*apply)(struct mSubParser* parser, struct mCoreConfig* config); + const char* extraOptions; + void* opts; +}; + +struct mGraphicsOpts { + int multiplier; + bool fullscreen; +}; + +bool parseArguments(struct mArguments* args, int argc, char* const* argv, + struct mSubParser* subparser); +void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config); +void freeArguments(struct mArguments* args); + +void usage(const char* arg0, const char* extraOptions); +void version(const char* arg0); + +void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/feature/thread-proxy.h b/mgba-test-runner/c/include/mgba/feature/thread-proxy.h new file mode 100644 index 00000000..36f432b0 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/feature/thread-proxy.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VIDEO_THREAD_PROXY_H +#define VIDEO_THREAD_PROXY_H + +#include + +CXX_GUARD_START + +#include +#include "video-logger.h" +#include +#include + +enum mVideoThreadProxyState { + PROXY_THREAD_STOPPED = 0, + PROXY_THREAD_IDLE, + PROXY_THREAD_BUSY +}; + +struct mVideoThreadProxy { + struct mVideoLogger d; + + Thread thread; + Condition fromThreadCond; + Condition toThreadCond; + Mutex mutex; + enum mVideoThreadProxyState threadState; + enum mVideoLoggerEvent event; + + struct RingFIFO dirtyQueue; +}; + +void mVideoThreadProxyCreate(struct mVideoThreadProxy* renderer); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/feature/video-logger.h b/mgba-test-runner/c/include/mgba/feature/video-logger.h new file mode 100644 index 00000000..cf50dd58 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/feature/video-logger.h @@ -0,0 +1,139 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VIDEO_LOGGER_H +#define VIDEO_LOGGER_H + +#include + +CXX_GUARD_START + +#include + +#include + +#define mVL_MAX_CHANNELS 32 + +enum mVideoLoggerDirtyType { + DIRTY_DUMMY = 0, + DIRTY_FLUSH, + DIRTY_SCANLINE, + DIRTY_REGISTER, + DIRTY_OAM, + DIRTY_PALETTE, + DIRTY_VRAM, + DIRTY_FRAME, + DIRTY_RANGE, + DIRTY_BUFFER, +}; + +enum mVideoLoggerEvent { + LOGGER_EVENT_NONE = 0, + LOGGER_EVENT_INIT, + LOGGER_EVENT_DEINIT, + LOGGER_EVENT_RESET, + LOGGER_EVENT_GET_PIXELS, +}; + +enum mVideoLoggerInjectionPoint { + LOGGER_INJECTION_IMMEDIATE = 0, + LOGGER_INJECTION_FIRST_SCANLINE, +}; + +struct mVideoLoggerDirtyInfo { + enum mVideoLoggerDirtyType type; + uint32_t address; + uint32_t value; + uint32_t value2; +}; + +struct VFile; +struct mVideoLogger { + bool (*writeData)(struct mVideoLogger* logger, const void* data, size_t length); + bool (*readData)(struct mVideoLogger* logger, void* data, size_t length, bool block); + void (*postEvent)(struct mVideoLogger* logger, enum mVideoLoggerEvent event); + void* dataContext; + + bool block; + bool waitOnFlush; + void (*init)(struct mVideoLogger*); + void (*deinit)(struct mVideoLogger*); + void (*reset)(struct mVideoLogger*); + + void (*lock)(struct mVideoLogger*); + void (*unlock)(struct mVideoLogger*); + void (*wait)(struct mVideoLogger*); + void (*wake)(struct mVideoLogger*, int y); + void* context; + + bool (*parsePacket)(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet); + void (*handleEvent)(struct mVideoLogger* logger, enum mVideoLoggerEvent event); + uint16_t* (*vramBlock)(struct mVideoLogger* logger, uint32_t address); + + size_t vramSize; + size_t oamSize; + size_t paletteSize; + + uint32_t* vramDirtyBitmap; + uint32_t* oamDirtyBitmap; + + uint16_t* vram; + uint16_t* oam; + uint16_t* palette; + + const void* pixelBuffer; + size_t pixelStride; +}; + +void mVideoLoggerRendererCreate(struct mVideoLogger* logger, bool readonly); +void mVideoLoggerRendererInit(struct mVideoLogger* logger); +void mVideoLoggerRendererDeinit(struct mVideoLogger* logger); +void mVideoLoggerRendererReset(struct mVideoLogger* logger); + +void mVideoLoggerRendererWriteVideoRegister(struct mVideoLogger* logger, uint32_t address, uint16_t value); +void mVideoLoggerRendererWriteVRAM(struct mVideoLogger* logger, uint32_t address); +void mVideoLoggerRendererWritePalette(struct mVideoLogger* logger, uint32_t address, uint16_t value); +void mVideoLoggerRendererWriteOAM(struct mVideoLogger* logger, uint32_t address, uint16_t value); + +void mVideoLoggerWriteBuffer(struct mVideoLogger* logger, uint32_t bufferId, uint32_t offset, uint32_t length, const void* data); + +void mVideoLoggerRendererDrawScanline(struct mVideoLogger* logger, int y); +void mVideoLoggerRendererDrawRange(struct mVideoLogger* logger, int startX, int endX, int y); +void mVideoLoggerRendererFlush(struct mVideoLogger* logger); +void mVideoLoggerRendererFinishFrame(struct mVideoLogger* logger); + +bool mVideoLoggerRendererRun(struct mVideoLogger* logger, bool block); +bool mVideoLoggerRendererRunInjected(struct mVideoLogger* logger); + +struct mVideoLogContext; +void mVideoLoggerAttachChannel(struct mVideoLogger* logger, struct mVideoLogContext* context, size_t channelId); + +struct mCore; +struct mVideoLogContext* mVideoLogContextCreate(struct mCore* core); + +void mVideoLogContextSetCompression(struct mVideoLogContext*, bool enable); +void mVideoLogContextSetOutput(struct mVideoLogContext*, struct VFile*); +void mVideoLogContextWriteHeader(struct mVideoLogContext*, struct mCore* core); + +bool mVideoLogContextLoad(struct mVideoLogContext*, struct VFile*); +void mVideoLogContextDestroy(struct mCore* core, struct mVideoLogContext*, bool closeVF); + +void mVideoLogContextRewind(struct mVideoLogContext*, struct mCore*); +void* mVideoLogContextInitialState(struct mVideoLogContext*, size_t* size); + +int mVideoLoggerAddChannel(struct mVideoLogContext*); + +void mVideoLoggerInjectionPoint(struct mVideoLogger* logger, enum mVideoLoggerInjectionPoint); +void mVideoLoggerIgnoreAfterInjection(struct mVideoLogger* logger, uint32_t mask); +void mVideoLoggerInjectVideoRegister(struct mVideoLogger* logger, uint32_t address, uint16_t value); +void mVideoLoggerInjectPalette(struct mVideoLogger* logger, uint32_t address, uint16_t value); +void mVideoLoggerInjectOAM(struct mVideoLogger* logger, uint32_t address, uint16_t value); + +enum mPlatform mVideoLogIsCompatible(struct VFile*); +struct mCore* mVideoLogCoreFind(struct VFile*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/gb/core.h b/mgba-test-runner/c/include/mgba/gb/core.h new file mode 100644 index 00000000..90ddccad --- /dev/null +++ b/mgba-test-runner/c/include/mgba/gb/core.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_CORE_H +#define GB_CORE_H + +#include + +CXX_GUARD_START + +struct mCore; +struct mCore* GBCoreCreate(void); +#ifndef MINIMAL_CORE +struct mCore* GBVideoLogPlayerCreate(void); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/gb/interface.h b/mgba-test-runner/c/include/mgba/gb/interface.h new file mode 100644 index 00000000..20eccd38 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/gb/interface.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_INTERFACE_H +#define GB_INTERFACE_H + +#include + +CXX_GUARD_START + +#include + +enum GBModel { + GB_MODEL_AUTODETECT = 0xFF, + GB_MODEL_DMG = 0x00, + GB_MODEL_SGB = 0x20, + GB_MODEL_MGB = 0x40, + GB_MODEL_SGB2 = 0x60, + GB_MODEL_CGB = 0x80, + GB_MODEL_AGB = 0xC0 +}; + +enum GBMemoryBankControllerType { + GB_MBC_AUTODETECT = -1, + GB_MBC_NONE = 0, + GB_MBC1 = 1, + GB_MBC2 = 2, + GB_MBC3 = 3, + GB_MBC5 = 5, + GB_MBC6 = 6, + GB_MBC7 = 7, + GB_MMM01 = 0x10, + GB_HuC1 = 0x11, + GB_HuC3 = 0x12, + GB_POCKETCAM = 0x13, + GB_TAMA5 = 0x14, + GB_MBC3_RTC = 0x103, + GB_MBC5_RUMBLE = 0x105, + GB_UNL_WISDOM_TREE = 0x200, + GB_UNL_PKJD = 0x203, + GB_UNL_BBD = 0x220, // Also used as a mask for MBCs that need special read behavior + GB_UNL_HITEK = 0x221, +}; + +enum GBVideoLayer { + GB_LAYER_BACKGROUND = 0, + GB_LAYER_WINDOW, + GB_LAYER_OBJ +}; + +struct GBSIODriver { + struct GBSIO* p; + + bool (*init)(struct GBSIODriver* driver); + void (*deinit)(struct GBSIODriver* driver); + void (*writeSB)(struct GBSIODriver* driver, uint8_t value); + uint8_t (*writeSC)(struct GBSIODriver* driver, uint8_t value); +}; + +struct VFile; + +bool GBIsROM(struct VFile* vf); +bool GBIsBIOS(struct VFile* vf); + +enum GBModel GBNameToModel(const char*); +const char* GBModelToName(enum GBModel); + +int GBValidModels(const uint8_t* bank0); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/gba/core.h b/mgba-test-runner/c/include/mgba/gba/core.h new file mode 100644 index 00000000..5cb0e468 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/gba/core.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_CORE_H +#define GBA_CORE_H + +#include + +CXX_GUARD_START + +struct mCore; +struct mCore* GBACoreCreate(void); +#ifndef MINIMAL_CORE +struct mCore* GBAVideoLogPlayerCreate(void); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/gba/interface.h b/mgba-test-runner/c/include/mgba/gba/interface.h new file mode 100644 index 00000000..aedd8895 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/gba/interface.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_INTERFACE_H +#define GBA_INTERFACE_H + +#include + +CXX_GUARD_START + +#include +#include + +enum { + GBA_VIDEO_HORIZONTAL_PIXELS = 240, + GBA_VIDEO_VERTICAL_PIXELS = 160, +}; + +enum GBASIOMode { + SIO_NORMAL_8 = 0, + SIO_NORMAL_32 = 1, + SIO_MULTI = 2, + SIO_UART = 3, + SIO_GPIO = 8, + SIO_JOYBUS = 12 +}; + +enum GBASIOJOYCommand { + JOY_RESET = 0xFF, + JOY_POLL = 0x00, + JOY_TRANS = 0x14, + JOY_RECV = 0x15 +}; + +enum GBAVideoLayer { + GBA_LAYER_BG0 = 0, + GBA_LAYER_BG1, + GBA_LAYER_BG2, + GBA_LAYER_BG3, + GBA_LAYER_OBJ, + GBA_LAYER_WIN0, + GBA_LAYER_WIN1, + GBA_LAYER_OBJWIN, +}; + +struct GBA; +struct GBAAudio; +struct GBASIO; +struct GBAVideoRenderer; +struct VFile; + +extern MGBA_EXPORT const int GBA_LUX_LEVELS[10]; + +enum { + mPERIPH_GBA_LUMINANCE = 0x1000, + mPERIPH_GBA_BATTLECHIP_GATE, +}; + +bool GBAIsROM(struct VFile* vf); +bool GBAIsMB(struct VFile* vf); +bool GBAIsBIOS(struct VFile* vf); + +struct GBALuminanceSource { + void (*sample)(struct GBALuminanceSource*); + + uint8_t (*readLuminance)(struct GBALuminanceSource*); +}; + +struct GBASIODriver { + struct GBASIO* p; + + bool (*init)(struct GBASIODriver* driver); + void (*deinit)(struct GBASIODriver* driver); + bool (*load)(struct GBASIODriver* driver); + bool (*unload)(struct GBASIODriver* driver); + uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); +}; + +void GBASIOJOYCreate(struct GBASIODriver* sio); + +enum GBASIOBattleChipGateFlavor { + GBA_FLAVOR_BATTLECHIP_GATE = 4, + GBA_FLAVOR_PROGRESS_GATE = 5, + GBA_FLAVOR_BEAST_LINK_GATE = 6, + GBA_FLAVOR_BEAST_LINK_GATE_US = 7, +}; + +struct GBASIOBattlechipGate { + struct GBASIODriver d; + struct mTimingEvent event; + uint16_t chipId; + uint16_t data[2]; + int state; + int flavor; +}; + +void GBASIOBattlechipGateCreate(struct GBASIOBattlechipGate*); + +void GBAEReaderQueueCard(struct GBA* gba, const void* data, size_t size); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/arm.h b/mgba-test-runner/c/include/mgba/internal/arm/arm.h new file mode 100644 index 00000000..f9eeafdb --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/arm.h @@ -0,0 +1,208 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ARM_H +#define ARM_H + +#include + +CXX_GUARD_START + +#include + +enum { + ARM_SP = 13, + ARM_LR = 14, + ARM_PC = 15 +}; + +enum ExecutionMode { + MODE_ARM = 0, + MODE_THUMB = 1 +}; + +enum PrivilegeMode { + MODE_USER = 0x10, + MODE_FIQ = 0x11, + MODE_IRQ = 0x12, + MODE_SUPERVISOR = 0x13, + MODE_ABORT = 0x17, + MODE_UNDEFINED = 0x1B, + MODE_SYSTEM = 0x1F +}; + +enum WordSize { + WORD_SIZE_ARM = 4, + WORD_SIZE_THUMB = 2 +}; + +enum ExecutionVector { + BASE_RESET = 0x00000000, + BASE_UNDEF = 0x00000004, + BASE_SWI = 0x00000008, + BASE_PABT = 0x0000000C, + BASE_DABT = 0x00000010, + BASE_IRQ = 0x00000018, + BASE_FIQ = 0x0000001C +}; + +enum RegisterBank { + BANK_NONE = 0, + BANK_FIQ = 1, + BANK_IRQ = 2, + BANK_SUPERVISOR = 3, + BANK_ABORT = 4, + BANK_UNDEFINED = 5 +}; + +enum LSMDirection { + LSM_B = 1, + LSM_D = 2, + LSM_IA = 0, + LSM_IB = 1, + LSM_DA = 2, + LSM_DB = 3 +}; + +struct ARMCore; + +union PSR { + struct { +#ifdef __BIG_ENDIAN__ + unsigned n : 1; + unsigned z : 1; + unsigned c : 1; + unsigned v : 1; + unsigned unused : 20; + unsigned i : 1; + unsigned f : 1; + unsigned t : 1; + unsigned priv : 5; +#else + unsigned priv : 5; + unsigned t : 1; + unsigned f : 1; + unsigned i : 1; + unsigned unused : 20; + unsigned v : 1; + unsigned c : 1; + unsigned z : 1; + unsigned n : 1; +#endif + }; + + struct { +#ifdef __BIG_ENDIAN__ + uint8_t flags; + uint8_t status; + uint8_t extension; + uint8_t control; +#else + uint8_t control; + uint8_t extension; + uint8_t status; + uint8_t flags; +#endif + }; + + int32_t packed; +}; + +struct ARMMemory { + uint32_t (*load32)(struct ARMCore*, uint32_t address, int* cycleCounter); + uint32_t (*load16)(struct ARMCore*, uint32_t address, int* cycleCounter); + uint32_t (*load8)(struct ARMCore*, uint32_t address, int* cycleCounter); + + void (*store32)(struct ARMCore*, uint32_t address, int32_t value, int* cycleCounter); + void (*store16)(struct ARMCore*, uint32_t address, int16_t value, int* cycleCounter); + void (*store8)(struct ARMCore*, uint32_t address, int8_t value, int* cycleCounter); + + uint32_t (*loadMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, + int* cycleCounter); + uint32_t (*storeMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, + int* cycleCounter); + + const uint32_t* activeRegion; + uint32_t activeMask; + uint32_t activeSeqCycles32; + uint32_t activeSeqCycles16; + uint32_t activeNonseqCycles32; + uint32_t activeNonseqCycles16; + int32_t (*stall)(struct ARMCore*, int32_t wait); + void (*setActiveRegion)(struct ARMCore*, uint32_t address); +}; + +struct ARMInterruptHandler { + void (*reset)(struct ARMCore* cpu); + void (*processEvents)(struct ARMCore* cpu); + void (*swi16)(struct ARMCore* cpu, int immediate); + void (*swi32)(struct ARMCore* cpu, int immediate); + void (*hitIllegal)(struct ARMCore* cpu, uint32_t opcode); + void (*bkpt16)(struct ARMCore* cpu, int immediate); + void (*bkpt32)(struct ARMCore* cpu, int immediate); + void (*readCPSR)(struct ARMCore* cpu); + + void (*hitStub)(struct ARMCore* cpu, uint32_t opcode); +}; + +#define ARM_REGISTER_FILE struct { \ + int32_t gprs[16]; \ + union PSR cpsr; \ + union PSR spsr; \ +} + +struct ARMRegisterFile { + ARM_REGISTER_FILE; +}; + +struct ARMCore { + union { + struct ARMRegisterFile regs; + ARM_REGISTER_FILE; + }; + + int32_t cycles; + int32_t nextEvent; + int halted; + + int32_t bankedRegisters[6][7]; + int32_t bankedSPSRs[6]; + + int32_t shifterOperand; + int32_t shifterCarryOut; + + uint32_t prefetch[2]; + enum ExecutionMode executionMode; + enum PrivilegeMode privilegeMode; + + struct ARMMemory memory; + struct ARMInterruptHandler irqh; + + struct mCPUComponent* master; + + size_t numComponents; + struct mCPUComponent** components; +}; +#undef ARM_REGISTER_FILE + +void ARMInit(struct ARMCore* cpu); +void ARMDeinit(struct ARMCore* cpu); +void ARMSetComponents(struct ARMCore* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras); +void ARMHotplugAttach(struct ARMCore* cpu, size_t slot); +void ARMHotplugDetach(struct ARMCore* cpu, size_t slot); + +void ARMReset(struct ARMCore* cpu); +void ARMSetPrivilegeMode(struct ARMCore*, enum PrivilegeMode); +void ARMRaiseIRQ(struct ARMCore*); +void ARMRaiseSWI(struct ARMCore*); +void ARMRaiseUndefined(struct ARMCore*); + +void ARMRun(struct ARMCore* cpu); +void ARMRunLoop(struct ARMCore* cpu); +void ARMRunFake(struct ARMCore* cpu, uint32_t opcode); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/debugger/cli-debugger.h b/mgba-test-runner/c/include/mgba/internal/arm/debugger/cli-debugger.h new file mode 100644 index 00000000..70f9b188 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/debugger/cli-debugger.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ARM_CLI_DEBUGGER_H +#define ARM_CLI_DEBUGGER_H + +#include + +CXX_GUARD_START + +struct CLIDebuggerSystem; +void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/debugger/debugger.h b/mgba-test-runner/c/include/mgba/internal/arm/debugger/debugger.h new file mode 100644 index 00000000..cbce4f12 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/debugger/debugger.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ARM_DEBUGGER_H +#define ARM_DEBUGGER_H + +#include + +CXX_GUARD_START + +#include + +#include +#include + +struct ParseTree; +struct ARMDebugBreakpoint { + struct mBreakpoint d; + struct { + uint32_t opcode; + enum ExecutionMode mode; + } sw; +}; + +DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); + +struct ARMDebugger { + struct mDebuggerPlatform d; + struct ARMCore* cpu; + + struct ARMDebugBreakpointList breakpoints; + struct ARMDebugBreakpointList swBreakpoints; + struct mWatchpointList watchpoints; + struct ARMMemory originalMemory; + + ssize_t nextId; + uint32_t stackTraceMode; + + void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + + bool (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode); + void (*clearSoftwareBreakpoint)(struct ARMDebugger*, const struct ARMDebugBreakpoint*); +}; + +struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void); +ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/debugger/memory-debugger.h b/mgba-test-runner/c/include/mgba/internal/arm/debugger/memory-debugger.h new file mode 100644 index 00000000..1ec67599 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/debugger/memory-debugger.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef MEMORY_DEBUGGER_H +#define MEMORY_DEBUGGER_H + +#include + +CXX_GUARD_START + +struct ARMDebugger; + +void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger); +void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/decoder-inlines.h b/mgba-test-runner/c/include/mgba/internal/arm/decoder-inlines.h new file mode 100644 index 00000000..11d41d52 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/decoder-inlines.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ARM_DECODER_INLINES_H +#define ARM_DECODER_INLINES_H + +#include "decoder.h" + +#include "arm.h" + +#include +#include + +#define LOAD_CYCLES \ + info->iCycles = 1; \ + info->nDataCycles = 1; + +#define STORE_CYCLES \ + info->sInstructionCycles = 0; \ + info->nInstructionCycles = 1; \ + info->nDataCycles = 1; + +static inline bool ARMInstructionIsBranch(enum ARMMnemonic mnemonic) { + switch (mnemonic) { + case ARM_MN_B: + case ARM_MN_BL: + case ARM_MN_BX: + // TODO: case: ARM_MN_BLX: + return true; + default: + return false; + } +} + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/decoder.h b/mgba-test-runner/c/include/mgba/internal/arm/decoder.h new file mode 100644 index 00000000..61226f8c --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/decoder.h @@ -0,0 +1,231 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ARM_DECODER_H +#define ARM_DECODER_H + +#include + +CXX_GUARD_START + +#include + +// Bit 0: a register is involved with this operand +// Bit 1: an immediate is invovled with this operand +// Bit 2: a memory access is involved with this operand +// Bit 3: the destination of this operand is affected by this opcode +// Bit 4: this operand is shifted by a register +// Bit 5: this operand is shifted by an immediate +#define ARM_OPERAND_NONE 0x00000000 +#define ARM_OPERAND_REGISTER_1 0x00000001 +#define ARM_OPERAND_IMMEDIATE_1 0x00000002 +#define ARM_OPERAND_MEMORY_1 0x00000004 +#define ARM_OPERAND_AFFECTED_1 0x00000008 +#define ARM_OPERAND_SHIFT_REGISTER_1 0x00000010 +#define ARM_OPERAND_SHIFT_IMMEDIATE_1 0x00000020 +#define ARM_OPERAND_1 0x000000FF + +#define ARM_OPERAND_REGISTER_2 0x00000100 +#define ARM_OPERAND_IMMEDIATE_2 0x00000200 +#define ARM_OPERAND_MEMORY_2 0x00000400 +#define ARM_OPERAND_AFFECTED_2 0x00000800 +#define ARM_OPERAND_SHIFT_REGISTER_2 0x00001000 +#define ARM_OPERAND_SHIFT_IMMEDIATE_2 0x00002000 +#define ARM_OPERAND_2 0x0000FF00 + +#define ARM_OPERAND_REGISTER_3 0x00010000 +#define ARM_OPERAND_IMMEDIATE_3 0x00020000 +#define ARM_OPERAND_MEMORY_3 0x00040000 +#define ARM_OPERAND_AFFECTED_3 0x00080000 +#define ARM_OPERAND_SHIFT_REGISTER_3 0x00100000 +#define ARM_OPERAND_SHIFT_IMMEDIATE_3 0x00200000 +#define ARM_OPERAND_3 0x00FF0000 + +#define ARM_OPERAND_REGISTER_4 0x01000000 +#define ARM_OPERAND_IMMEDIATE_4 0x02000000 +#define ARM_OPERAND_MEMORY_4 0x04000000 +#define ARM_OPERAND_AFFECTED_4 0x08000000 +#define ARM_OPERAND_SHIFT_REGISTER_4 0x10000000 +#define ARM_OPERAND_SHIFT_IMMEDIATE_4 0x20000000 +#define ARM_OPERAND_4 0xFF000000 + +#define ARM_OPERAND_MEMORY (ARM_OPERAND_MEMORY_1 | ARM_OPERAND_MEMORY_2 | ARM_OPERAND_MEMORY_3 | ARM_OPERAND_MEMORY_4) + +#define ARM_MEMORY_REGISTER_BASE 0x0001 +#define ARM_MEMORY_IMMEDIATE_OFFSET 0x0002 +#define ARM_MEMORY_REGISTER_OFFSET 0x0004 +#define ARM_MEMORY_SHIFTED_OFFSET 0x0008 +#define ARM_MEMORY_PRE_INCREMENT 0x0010 +#define ARM_MEMORY_POST_INCREMENT 0x0020 +#define ARM_MEMORY_OFFSET_SUBTRACT 0x0040 +#define ARM_MEMORY_WRITEBACK 0x0080 +#define ARM_MEMORY_DECREMENT_AFTER 0x0000 +#define ARM_MEMORY_INCREMENT_AFTER 0x0100 +#define ARM_MEMORY_DECREMENT_BEFORE 0x0200 +#define ARM_MEMORY_INCREMENT_BEFORE 0x0300 +#define ARM_MEMORY_SPSR_SWAP 0x0400 +#define ARM_MEMORY_STORE 0x1000 +#define ARM_MEMORY_LOAD 0x2000 +#define ARM_MEMORY_SWAP 0x3000 + +#define ARM_PSR_C 1 +#define ARM_PSR_X 2 +#define ARM_PSR_S 4 +#define ARM_PSR_F 8 +#define ARM_PSR_MASK 0xF + +#define MEMORY_FORMAT_TO_DIRECTION(F) (((F) >> 8) & 0x3) + +enum ARMCondition { + ARM_CONDITION_EQ = 0x0, + ARM_CONDITION_NE = 0x1, + ARM_CONDITION_CS = 0x2, + ARM_CONDITION_CC = 0x3, + ARM_CONDITION_MI = 0x4, + ARM_CONDITION_PL = 0x5, + ARM_CONDITION_VS = 0x6, + ARM_CONDITION_VC = 0x7, + ARM_CONDITION_HI = 0x8, + ARM_CONDITION_LS = 0x9, + ARM_CONDITION_GE = 0xA, + ARM_CONDITION_LT = 0xB, + ARM_CONDITION_GT = 0xC, + ARM_CONDITION_LE = 0xD, + ARM_CONDITION_AL = 0xE, + ARM_CONDITION_NV = 0xF +}; + +enum ARMShifterOperation { + ARM_SHIFT_NONE = 0, + ARM_SHIFT_LSL, + ARM_SHIFT_LSR, + ARM_SHIFT_ASR, + ARM_SHIFT_ROR, + ARM_SHIFT_RRX +}; + +union ARMOperand { + struct { + uint8_t reg; + uint8_t shifterOp; + union { + uint8_t shifterReg; + uint8_t shifterImm; + uint8_t psrBits; + }; + }; + int32_t immediate; +}; + +enum ARMMemoryAccessType { + ARM_ACCESS_WORD = 4, + ARM_ACCESS_HALFWORD = 2, + ARM_ACCESS_SIGNED_HALFWORD = 10, + ARM_ACCESS_BYTE = 1, + ARM_ACCESS_SIGNED_BYTE = 9, + ARM_ACCESS_TRANSLATED_WORD = 20, + ARM_ACCESS_TRANSLATED_BYTE = 17 +}; + +enum ARMBranchType { + ARM_BRANCH_NONE = 0, + ARM_BRANCH = 1, + ARM_BRANCH_INDIRECT = 2, + ARM_BRANCH_LINKED = 4 +}; + +struct ARMMemoryAccess { + uint8_t baseReg; + uint8_t width; + uint16_t format; + union ARMOperand offset; +}; + +enum ARMMnemonic { + ARM_MN_ILL = 0, + ARM_MN_ADC, + ARM_MN_ADD, + ARM_MN_AND, + ARM_MN_ASR, + ARM_MN_B, + ARM_MN_BIC, + ARM_MN_BKPT, + ARM_MN_BL, + ARM_MN_BX, + ARM_MN_CMN, + ARM_MN_CMP, + ARM_MN_EOR, + ARM_MN_LDM, + ARM_MN_LDR, + ARM_MN_LSL, + ARM_MN_LSR, + ARM_MN_MLA, + ARM_MN_MOV, + ARM_MN_MRS, + ARM_MN_MSR, + ARM_MN_MUL, + ARM_MN_MVN, + ARM_MN_NEG, + ARM_MN_ORR, + ARM_MN_ROR, + ARM_MN_RSB, + ARM_MN_RSC, + ARM_MN_SBC, + ARM_MN_SMLAL, + ARM_MN_SMULL, + ARM_MN_STM, + ARM_MN_STR, + ARM_MN_SUB, + ARM_MN_SWI, + ARM_MN_SWP, + ARM_MN_TEQ, + ARM_MN_TST, + ARM_MN_UMLAL, + ARM_MN_UMULL, + + ARM_MN_MAX +}; + +enum { + ARM_CPSR = 16, + ARM_SPSR = 17 +}; + +struct ARMInstructionInfo { + uint32_t opcode; + union ARMOperand op1; + union ARMOperand op2; + union ARMOperand op3; + union ARMOperand op4; + struct ARMMemoryAccess memory; + int operandFormat; + unsigned execMode : 1; + bool traps : 1; + bool affectsCPSR : 1; + unsigned branchType : 3; + unsigned condition : 4; + unsigned mnemonic : 6; + unsigned iCycles : 3; + unsigned cCycles : 4; + unsigned sInstructionCycles : 4; + unsigned nInstructionCycles : 4; + unsigned sDataCycles : 10; + unsigned nDataCycles : 10; +}; + +void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); +void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info); +bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, + struct ARMInstructionInfo* out); +uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc); + +#ifdef USE_DEBUGGERS +struct mDebuggerSymbols; +int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* core, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/emitter-arm.h b/mgba-test-runner/c/include/mgba/internal/arm/emitter-arm.h new file mode 100644 index 00000000..e99a1b7e --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/emitter-arm.h @@ -0,0 +1,335 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef EMITTER_ARM_H +#define EMITTER_ARM_H + +#include "emitter-inlines.h" + +#define DECLARE_INSTRUCTION_ARM(EMITTER, NAME) \ + EMITTER ## NAME + +#define DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ALU) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## I)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## I)) + +#define DECLARE_ARM_ALU_BLOCK(EMITTER, ALU, EX1, EX2, EX3, EX4) \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ASR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ASR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ROR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ROR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX1), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _LSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX2), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ASR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX3), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ALU ## _ROR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, EX4) + +#define DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, NAME, P, U, W) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## I ## P ## U ## W)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## I ## P ## U ## W)) + +#define DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, NAME, P, U, W) \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSL_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSR_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ASR_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ROR_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSL_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _LSR_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ASR_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## _ROR_ ## P ## U ## W), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL) + +#define DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, NAME, MODE, W) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## MODE ## W)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME ## MODE ## W)) + +#define DECLARE_ARM_BRANCH_BLOCK(EMITTER, NAME) \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) + +// TODO: Support coprocessors +#define DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, NAME, P, U, N, W) \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)), \ + DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) + +#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2) \ + DO_8(DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME2)))) + +#define DECLARE_ARM_SWI_BLOCK(EMITTER) \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, SWI)) + +#define DECLARE_ARM_EMITTER_BLOCK(EMITTER) \ + DECLARE_ARM_ALU_BLOCK(EMITTER, AND, MUL, STRH, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ANDS, MULS, LDRH, LDRSB, LDRSH), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, EOR, MLA, STRH, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, EORS, MLAS, LDRH, LDRSB, LDRSH), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SUB, ILL, STRHI, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SUBS, ILL, LDRHI, LDRSBI, LDRSHI), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSB, ILL, STRHI, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSBS, ILL, LDRHI, LDRSBI, LDRSHI), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADD, UMULL, STRHU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADDS, UMULLS, LDRHU, LDRSBU, LDRSHU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADC, UMLAL, STRHU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADCS, UMLALS, LDRHU, LDRSBU, LDRSHU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SBC, SMULL, STRHIU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, SBCS, SMULLS, LDRHIU, LDRSBIU, LDRSHIU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSC, SMLAL, STRHIU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSCS, SMLALS, LDRHIU, LDRSBIU, LDRSHIU), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MRS), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, SWP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, TST, ILL, LDRHP, LDRSBP, LDRSHP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, BX), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, BKPT), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHPW), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, TEQ, ILL, LDRHPW, LDRSBPW, LDRSHPW), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MRSR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, SWPB), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHIP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, CMP, ILL, LDRHIP, LDRSBIP, LDRSHIP), \ + DECLARE_INSTRUCTION_ARM(EMITTER, MSRR), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, STRHIPW), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, CMN, ILL, LDRHIPW, LDRSBIPW, LDRSHIPW), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ORR, SMLAL, STRHPU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ORRS, SMLALS, LDRHPU, LDRSBPU, LDRSHPU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MOV, SMLAL, STRHPUW, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MOVS, SMLALS, LDRHPUW, LDRSBPUW, LDRSHPUW), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, BIC, SMLAL, STRHIPU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, BICS, SMLALS, LDRHIPU, LDRSBIPU, LDRSHIPU), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MVN, SMLAL, STRHIPUW, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, MVNS, SMLALS, LDRHIPUW, LDRSBIPUW, LDRSHIPUW), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, AND), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ANDS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EOR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EORS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUB), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUBS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSB), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSBS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADD), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADDS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADCS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBCS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSCS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TEQ), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSRR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMN), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORR), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORRS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOV), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOVS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BIC), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BICS), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVN), \ + DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVNS), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, ), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, ), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, W), \ + DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, W), \ + DECLARE_ARM_BRANCH_BLOCK(EMITTER, B), \ + DECLARE_ARM_BRANCH_BLOCK(EMITTER, BL), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ + DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ + DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR), \ + DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MRC), \ + DECLARE_ARM_SWI_BLOCK(EMITTER) + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/emitter-inlines.h b/mgba-test-runner/c/include/mgba/internal/arm/emitter-inlines.h new file mode 100644 index 00000000..38bab70b --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/emitter-inlines.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef EMITTER_INLINES_H +#define EMITTER_INLINES_H + +#define DO_4(DIRECTIVE) \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE + +#define DO_8(DIRECTIVE) \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE, \ + DIRECTIVE + +#define DO_256(DIRECTIVE) \ + DO_4(DO_8(DO_8(DIRECTIVE))) + +#define DO_INTERLACE(LEFT, RIGHT) \ + LEFT, \ + RIGHT + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/emitter-thumb.h b/mgba-test-runner/c/include/mgba/internal/arm/emitter-thumb.h new file mode 100644 index 00000000..7d27524b --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/emitter-thumb.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef EMITTER_THUMB_H +#define EMITTER_THUMB_H + +#include "emitter-inlines.h" + +#define DECLARE_INSTRUCTION_THUMB(EMITTER, NAME) \ + EMITTER ## NAME + +#define DECLARE_INSTRUCTION_WITH_HIGH_THUMB(EMITTER, NAME) \ + DECLARE_INSTRUCTION_THUMB(EMITTER, NAME ## 00), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, NAME ## 01), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, NAME ## 10), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, NAME ## 11) + +#define DECLARE_THUMB_EMITTER_BLOCK(EMITTER) \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LSL1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LSR1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ASR1))), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, ADD3)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, SUB3)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, ADD1)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, SUB1)), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, MOV1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, CMP1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ADD2))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, SUB2))), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, AND), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, EOR), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, LSL2), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, LSR2), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ASR2), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ADC), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, SBC), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ROR), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, TST), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, NEG), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, CMP2), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, CMN), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ORR), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, MUL), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, BIC), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, MVN), \ + DECLARE_INSTRUCTION_WITH_HIGH_THUMB(EMITTER, ADD4), \ + DECLARE_INSTRUCTION_WITH_HIGH_THUMB(EMITTER, CMP3), \ + DECLARE_INSTRUCTION_WITH_HIGH_THUMB(EMITTER, MOV3), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, BX), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, BX), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ILL), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ILL), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LDR3))), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, STR2)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, STRH2)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, STRB2)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, LDRSB)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, LDR2)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, LDRH2)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, LDRB2)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, LDRSH)), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, STR1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LDR1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, STRB1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LDRB1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, STRH1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LDRH1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, STR3))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LDR4))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ADD5))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ADD6))), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ADD7), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, ADD7), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, SUB4), \ + DECLARE_INSTRUCTION_THUMB(EMITTER, SUB4), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, PUSH)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, PUSHR)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_8(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, POP)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, POPR)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BKPT)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, STMIA))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, LDMIA))), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BEQ)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BNE)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BCS)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BCC)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BMI)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BPL)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BVS)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BVC)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BHI)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BLS)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BGE)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BLT)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BGT)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BLE)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL)), \ + DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, SWI)), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, B))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, ILL))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BL1))), \ + DO_8(DO_4(DECLARE_INSTRUCTION_THUMB(EMITTER, BL2))) \ + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/isa-arm.h b/mgba-test-runner/c/include/mgba/internal/arm/isa-arm.h new file mode 100644 index 00000000..fb347cd8 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/isa-arm.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ISA_ARM_H +#define ISA_ARM_H + +#include + +CXX_GUARD_START + +#define ARM_PREFETCH_CYCLES (1 + cpu->memory.activeSeqCycles32) + +struct ARMCore; + +typedef void (*ARMInstruction)(struct ARMCore*, uint32_t opcode); +extern const ARMInstruction _armTable[0x1000]; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/isa-inlines.h b/mgba-test-runner/c/include/mgba/internal/arm/isa-inlines.h new file mode 100644 index 00000000..2ee6aee7 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/isa-inlines.h @@ -0,0 +1,171 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ISA_INLINES_H +#define ISA_INLINES_H + +#include "macros.h" + +#include "arm.h" + +#define ARM_COND_EQ (cpu->cpsr.z) +#define ARM_COND_NE (!cpu->cpsr.z) +#define ARM_COND_CS (cpu->cpsr.c) +#define ARM_COND_CC (!cpu->cpsr.c) +#define ARM_COND_MI (cpu->cpsr.n) +#define ARM_COND_PL (!cpu->cpsr.n) +#define ARM_COND_VS (cpu->cpsr.v) +#define ARM_COND_VC (!cpu->cpsr.v) +#define ARM_COND_HI (cpu->cpsr.c && !cpu->cpsr.z) +#define ARM_COND_LS (!cpu->cpsr.c || cpu->cpsr.z) +#define ARM_COND_GE (!cpu->cpsr.n == !cpu->cpsr.v) +#define ARM_COND_LT (!cpu->cpsr.n != !cpu->cpsr.v) +#define ARM_COND_GT (!cpu->cpsr.z && !cpu->cpsr.n == !cpu->cpsr.v) +#define ARM_COND_LE (cpu->cpsr.z || !cpu->cpsr.n != !cpu->cpsr.v) +#define ARM_COND_AL 1 + +#define ARM_SIGN(I) ((I) >> 31) +#define ARM_SXT_8(I) (((int8_t) (I) << 24) >> 24) +#define ARM_SXT_16(I) (((int16_t) (I) << 16) >> 16) +#define ARM_UXT_64(I) (uint64_t)(uint32_t) (I) + +#define ARM_CARRY_FROM(M, N, D) (((uint32_t) (M) >> 31) + ((uint32_t) (N) >> 31) > ((uint32_t) (D) >> 31)) +#define ARM_BORROW_FROM(M, N, D) (((uint32_t) (M)) >= ((uint32_t) (N))) +#define ARM_BORROW_FROM_CARRY(M, N, D, C) (ARM_UXT_64(M) >= (ARM_UXT_64(N)) + (uint64_t) (C)) +#define ARM_V_ADDITION(M, N, D) (!(ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) +#define ARM_V_SUBTRACTION(M, N, D) ((ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) + +#define ARM_WAIT_MUL(R, WAIT) \ + { \ + int32_t wait = WAIT; \ + if ((R & 0xFFFFFF00) == 0xFFFFFF00 || !(R & 0xFFFFFF00)) { \ + wait += 1; \ + } else if ((R & 0xFFFF0000) == 0xFFFF0000 || !(R & 0xFFFF0000)) { \ + wait += 2; \ + } else if ((R & 0xFF000000) == 0xFF000000 || !(R & 0xFF000000)) { \ + wait += 3; \ + } else { \ + wait += 4; \ + } \ + currentCycles += cpu->memory.stall(cpu, wait); \ + } + +#define ARM_STUB cpu->irqh.hitStub(cpu, opcode) +#define ARM_ILL cpu->irqh.hitIllegal(cpu, opcode) + +static inline int32_t ARMWritePC(struct ARMCore* cpu) { + uint32_t pc = cpu->gprs[ARM_PC] & -WORD_SIZE_THUMB; + cpu->memory.setActiveRegion(cpu, pc); + LOAD_32(cpu->prefetch[0], pc & cpu->memory.activeMask, cpu->memory.activeRegion); + pc += WORD_SIZE_ARM; + LOAD_32(cpu->prefetch[1], pc & cpu->memory.activeMask, cpu->memory.activeRegion); + cpu->gprs[ARM_PC] = pc; + return 2 + cpu->memory.activeNonseqCycles32 + cpu->memory.activeSeqCycles32; +} + +static inline int32_t ThumbWritePC(struct ARMCore* cpu) { + uint32_t pc = cpu->gprs[ARM_PC] & -WORD_SIZE_THUMB; + cpu->memory.setActiveRegion(cpu, pc); + LOAD_16(cpu->prefetch[0], pc & cpu->memory.activeMask, cpu->memory.activeRegion); + pc += WORD_SIZE_THUMB; + LOAD_16(cpu->prefetch[1], pc & cpu->memory.activeMask, cpu->memory.activeRegion); + cpu->gprs[ARM_PC] = pc; + return 2 + cpu->memory.activeNonseqCycles16 + cpu->memory.activeSeqCycles16; +} + +static inline int _ARMModeHasSPSR(enum PrivilegeMode mode) { + return mode != MODE_SYSTEM && mode != MODE_USER; +} + +static inline void _ARMSetMode(struct ARMCore* cpu, enum ExecutionMode executionMode) { + if (executionMode == cpu->executionMode) { + return; + } + + cpu->executionMode = executionMode; + switch (executionMode) { + case MODE_ARM: + cpu->cpsr.t = 0; + cpu->memory.activeMask &= ~2; + break; + case MODE_THUMB: + cpu->cpsr.t = 1; + cpu->memory.activeMask |= 2; + } + cpu->nextEvent = cpu->cycles; +} + +static inline void _ARMReadCPSR(struct ARMCore* cpu) { + _ARMSetMode(cpu, cpu->cpsr.t); + ARMSetPrivilegeMode(cpu, cpu->cpsr.priv); + cpu->irqh.readCPSR(cpu); +} + +static inline uint32_t _ARMInstructionLength(struct ARMCore* cpu) { + return cpu->cpsr.t == MODE_ARM ? WORD_SIZE_ARM : WORD_SIZE_THUMB; +} + +static inline uint32_t _ARMPCAddress(struct ARMCore* cpu) { + return cpu->gprs[ARM_PC] - _ARMInstructionLength(cpu) * 2; +} + +static inline bool ARMTestCondition(struct ARMCore* cpu, unsigned condition) { + switch (condition) { + case 0x0: + return ARM_COND_EQ; + case 0x1: + return ARM_COND_NE; + case 0x2: + return ARM_COND_CS; + case 0x3: + return ARM_COND_CC; + case 0x4: + return ARM_COND_MI; + case 0x5: + return ARM_COND_PL; + case 0x6: + return ARM_COND_VS; + case 0x7: + return ARM_COND_VC; + case 0x8: + return ARM_COND_HI; + case 0x9: + return ARM_COND_LS; + case 0xA: + return ARM_COND_GE; + case 0xB: + return ARM_COND_LT; + case 0xC: + return ARM_COND_GT; + case 0xD: + return ARM_COND_LE; + default: + return true; + } +} + +static inline enum RegisterBank ARMSelectBank(enum PrivilegeMode mode) { + switch (mode) { + case MODE_USER: + case MODE_SYSTEM: + // No banked registers + return BANK_NONE; + case MODE_FIQ: + return BANK_FIQ; + case MODE_IRQ: + return BANK_IRQ; + case MODE_SUPERVISOR: + return BANK_SUPERVISOR; + case MODE_ABORT: + return BANK_ABORT; + case MODE_UNDEFINED: + return BANK_UNDEFINED; + default: + // This should be unreached + return BANK_NONE; + } +} + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/isa-thumb.h b/mgba-test-runner/c/include/mgba/internal/arm/isa-thumb.h new file mode 100644 index 00000000..69839d47 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/isa-thumb.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ISA_THUMB_H +#define ISA_THUMB_H + +#include + +CXX_GUARD_START + +struct ARMCore; + +typedef void (*ThumbInstruction)(struct ARMCore*, unsigned opcode); +extern const ThumbInstruction _thumbTable[0x400]; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/arm/macros.h b/mgba-test-runner/c/include/mgba/internal/arm/macros.h new file mode 100644 index 00000000..4832f054 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/arm/macros.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef MACROS_H +#define MACROS_H + +#include + +#define LOAD_64 LOAD_64LE +#define LOAD_32 LOAD_32LE +#define LOAD_16 LOAD_16LE +#define STORE_64 STORE_64LE +#define STORE_32 STORE_32LE +#define STORE_16 STORE_16LE + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/debugger/cli-debugger.h b/mgba-test-runner/c/include/mgba/internal/debugger/cli-debugger.h new file mode 100644 index 00000000..6175ce62 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/debugger/cli-debugger.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CLI_DEBUGGER_H +#define CLI_DEBUGGER_H + +#include + +CXX_GUARD_START + +#include + +extern const char* ERROR_MISSING_ARGS; +extern const char* ERROR_OVERFLOW; +extern const char* ERROR_INVALID_ARGS; +extern const char* INFO_BREAKPOINT_ADDED; +extern const char* INFO_WATCHPOINT_ADDED; + +struct CLIDebugger; +struct VFile; + +struct CLIDebugVector { + struct CLIDebugVector* next; + enum CLIDVType { + CLIDV_ERROR_TYPE, + CLIDV_INT_TYPE, + CLIDV_CHAR_TYPE, + } type; + char* charValue; + int32_t intValue; + int segmentValue; +}; + +typedef void (*CLIDebuggerCommand)(struct CLIDebugger*, struct CLIDebugVector*); + +struct CLIDebuggerCommandSummary { + const char* name; + CLIDebuggerCommand command; + const char* format; + const char* summary; +}; + +struct CLIDebuggerCommandAlias { + const char* name; + const char* original; +}; + +struct CLIDebuggerSystem { + struct CLIDebugger* p; + + void (*init)(struct CLIDebuggerSystem*); + void (*deinit)(struct CLIDebuggerSystem*); + bool (*custom)(struct CLIDebuggerSystem*); + + void (*disassemble)(struct CLIDebuggerSystem*, struct CLIDebugVector* dv); + void (*printStatus)(struct CLIDebuggerSystem*); + + struct CLIDebuggerCommandSummary* commands; + struct CLIDebuggerCommandAlias* commandAliases; + const char* name; + struct CLIDebuggerCommandSummary* platformCommands; + struct CLIDebuggerCommandAlias* platformCommandAliases; + const char* platformName; +}; + +struct CLIDebuggerBackend { + struct CLIDebugger* p; + + void (*init)(struct CLIDebuggerBackend*); + void (*deinit)(struct CLIDebuggerBackend*); + + ATTRIBUTE_FORMAT(printf, 2, 3) + void (*printf)(struct CLIDebuggerBackend*, const char* fmt, ...); + const char* (*readline)(struct CLIDebuggerBackend*, size_t* len); + void (*lineAppend)(struct CLIDebuggerBackend*, const char* line); + const char* (*historyLast)(struct CLIDebuggerBackend*, size_t* len); + void (*historyAppend)(struct CLIDebuggerBackend*, const char* line); +}; + +struct CLIDebugger { + struct mDebugger d; + + struct CLIDebuggerSystem* system; + struct CLIDebuggerBackend* backend; + + int traceRemaining; + struct VFile* traceVf; +}; + +void CLIDebuggerCreate(struct CLIDebugger*); +void CLIDebuggerAttachSystem(struct CLIDebugger*, struct CLIDebuggerSystem*); +void CLIDebuggerAttachBackend(struct CLIDebugger*, struct CLIDebuggerBackend*); + +bool CLIDebuggerTabComplete(struct CLIDebugger*, const char* token, bool initial, size_t len); + +bool CLIDebuggerRunCommand(struct CLIDebugger* debugger, const char* line, size_t count); +#ifdef ENABLE_SCRIPTING +void CLIDebuggerScriptEngineInstall(struct mScriptBridge* sb); +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/debugger/gdb-stub.h b/mgba-test-runner/c/include/mgba/internal/debugger/gdb-stub.h new file mode 100644 index 00000000..5743834a --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/debugger/gdb-stub.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GDB_STUB_H +#define GDB_STUB_H + +#include + +CXX_GUARD_START + +#include + +#include + +#define GDB_STUB_MAX_LINE 1200 +#define GDB_STUB_INTERVAL 32 + +enum GDBStubAckState { + GDB_ACK_PENDING = 0, + GDB_ACK_RECEIVED, + GDB_NAK_RECEIVED, + GDB_ACK_OFF +}; + +struct GDBStub { + struct mDebugger d; + + char line[GDB_STUB_MAX_LINE]; + char outgoing[GDB_STUB_MAX_LINE]; + enum GDBStubAckState lineAck; + + Socket socket; + Socket connection; + + bool shouldBlock; + int untilPoll; + + bool supportsSwbreak; + bool supportsHwbreak; +}; + +void GDBStubCreate(struct GDBStub*); +bool GDBStubListen(struct GDBStub*, int port, const struct Address* bindAddress); + +void GDBStubHangup(struct GDBStub*); +void GDBStubShutdown(struct GDBStub*); + +void GDBStubUpdate(struct GDBStub*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/debugger/parser.h b/mgba-test-runner/c/include/mgba/internal/debugger/parser.h new file mode 100644 index 00000000..37f194dd --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/debugger/parser.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2013-2014 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PARSER_H +#define PARSER_H + +#include + +#include + +CXX_GUARD_START + +struct Token; +DECLARE_VECTOR(LexVector, struct Token); + +enum Operation { + OP_ASSIGN, + OP_ADD, + OP_SUBTRACT, + OP_MULTIPLY, + OP_DIVIDE, + OP_MODULO, + OP_AND, + OP_OR, + OP_XOR, + OP_LESS, + OP_GREATER, + OP_EQUAL, + OP_NOT_EQUAL, + OP_LOGICAL_AND, + OP_LOGICAL_OR, + OP_LE, + OP_GE, + OP_NEGATE, + OP_FLIP, + OP_NOT, + OP_SHIFT_L, + OP_SHIFT_R, + OP_DEREFERENCE, +}; + +struct Token { + enum TokenType { + TOKEN_ERROR_TYPE, + TOKEN_UINT_TYPE, + TOKEN_IDENTIFIER_TYPE, + TOKEN_OPERATOR_TYPE, + TOKEN_OPEN_PAREN_TYPE, + TOKEN_CLOSE_PAREN_TYPE, + TOKEN_SEGMENT_TYPE, + } type; + union { + uint32_t uintValue; + char* identifierValue; + enum Operation operatorValue; + }; +}; + +struct ParseTree { + struct Token token; + struct ParseTree* lhs; + struct ParseTree* rhs; +}; + +size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol); +void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv); + +void lexFree(struct LexVector* lv); +void parseFree(struct ParseTree* tree); + +struct mDebugger; +bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, int32_t* value, int* segment); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/debugger/stack-trace.h b/mgba-test-runner/c/include/mgba/internal/debugger/stack-trace.h new file mode 100644 index 00000000..11268aae --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/debugger/stack-trace.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2013-2020 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef STACK_TRACE_H +#define STACK_TRACE_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +struct mDebuggerSymbols; + +enum mStackTraceMode { + STACK_TRACE_DISABLED = 0, + STACK_TRACE_ENABLED = 1, + STACK_TRACE_BREAK_ON_RETURN = 2, + STACK_TRACE_BREAK_ON_CALL = 4, + STACK_TRACE_BREAK_ON_BOTH = STACK_TRACE_BREAK_ON_RETURN | STACK_TRACE_BREAK_ON_CALL +}; + +struct mStackFrame { + int callSegment; + uint32_t callAddress; + int entrySegment; + uint32_t entryAddress; + int frameBaseSegment; + uint32_t frameBaseAddress; + void* regs; + bool finished; + bool breakWhenFinished; + bool interrupt; +}; + +DECLARE_VECTOR(mStackFrames, struct mStackFrame); + +struct mStackTrace { + struct mStackFrames stack; + size_t registersSize; + + void (*formatRegisters)(struct mStackFrame* frame, char* out, size_t* length); +}; + +void mStackTraceInit(struct mStackTrace* stack, size_t registersSize); +void mStackTraceDeinit(struct mStackTrace* stack); + +void mStackTraceClear(struct mStackTrace* stack); +size_t mStackTraceGetDepth(struct mStackTrace* stack); +struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs); +struct mStackFrame* mStackTracePushSegmented(struct mStackTrace* stack, int pcSegment, uint32_t pc, int destSegment, uint32_t destAddress, int spSegment, uint32_t sp, void* regs); +struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, uint32_t frame); +void mStackTraceFormatFrame(struct mStackTrace* stack, struct mDebuggerSymbols* st, uint32_t frame, char* out, size_t* length); +void mStackTracePop(struct mStackTrace* stack); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/debugger/symbols.h b/mgba-test-runner/c/include/mgba/internal/debugger/symbols.h new file mode 100644 index 00000000..12af3256 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/debugger/symbols.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DEBUGGER_SYMBOLS_H +#define DEBUGGER_SYMBOLS_H + +#include + +CXX_GUARD_START + +struct mDebuggerSymbols; + +struct mDebuggerSymbols* mDebuggerSymbolTableCreate(void); +void mDebuggerSymbolTableDestroy(struct mDebuggerSymbols*); + +bool mDebuggerSymbolLookup(const struct mDebuggerSymbols*, const char* name, int32_t* value, int* segment); +const char* mDebuggerSymbolReverseLookup(const struct mDebuggerSymbols*, int32_t value, int segment); + +void mDebuggerSymbolAdd(struct mDebuggerSymbols*, const char* name, int32_t value, int segment); +void mDebuggerSymbolRemove(struct mDebuggerSymbols*, const char* name); + +struct VFile; +void mDebuggerLoadARMIPSSymbols(struct mDebuggerSymbols*, struct VFile* vf); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/audio.h b/mgba-test-runner/c/include/mgba/internal/gb/audio.h new file mode 100644 index 00000000..4f4fdef3 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/audio.h @@ -0,0 +1,257 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_AUDIO_H +#define GB_AUDIO_H + +#include + +CXX_GUARD_START + +#include + +DECL_BITFIELD(GBAudioRegisterDuty, uint8_t); +DECL_BITS(GBAudioRegisterDuty, Length, 0, 6); +DECL_BITS(GBAudioRegisterDuty, Duty, 6, 2); + +DECL_BITFIELD(GBAudioRegisterSweep, uint8_t); +DECL_BITS(GBAudioRegisterSweep, StepTime, 0, 3); +DECL_BIT(GBAudioRegisterSweep, Direction, 3); +DECL_BITS(GBAudioRegisterSweep, InitialVolume, 4, 4); + +DECL_BITFIELD(GBAudioRegisterControl, uint16_t); +DECL_BITS(GBAudioRegisterControl, Rate, 0, 11); +DECL_BITS(GBAudioRegisterControl, Frequency, 0, 11); +DECL_BIT(GBAudioRegisterControl, Stop, 14); +DECL_BIT(GBAudioRegisterControl, Restart, 15); + +DECL_BITFIELD(GBAudioRegisterSquareSweep, uint8_t); +DECL_BITS(GBAudioRegisterSquareSweep, Shift, 0, 3); +DECL_BIT(GBAudioRegisterSquareSweep, Direction, 3); +DECL_BITS(GBAudioRegisterSquareSweep, Time, 4, 3); + +DECL_BITFIELD(GBAudioRegisterBank, uint8_t); +DECL_BIT(GBAudioRegisterBank, Size, 5); +DECL_BIT(GBAudioRegisterBank, Bank, 6); +DECL_BIT(GBAudioRegisterBank, Enable, 7); + +DECL_BITFIELD(GBAudioRegisterBankVolume, uint8_t); +DECL_BITS(GBAudioRegisterBankVolume, VolumeGB, 5, 2); +DECL_BITS(GBAudioRegisterBankVolume, VolumeGBA, 5, 3); + +DECL_BITFIELD(GBAudioRegisterNoiseFeedback, uint8_t); +DECL_BITS(GBAudioRegisterNoiseFeedback, Ratio, 0, 3); +DECL_BIT(GBAudioRegisterNoiseFeedback, Power, 3); +DECL_BITS(GBAudioRegisterNoiseFeedback, Frequency, 4, 4); + +DECL_BITFIELD(GBAudioRegisterNoiseControl, uint8_t); +DECL_BIT(GBAudioRegisterNoiseControl, Stop, 6); +DECL_BIT(GBAudioRegisterNoiseControl, Restart, 7); + +DECL_BITFIELD(GBRegisterNR50, uint8_t); +DECL_BITS(GBRegisterNR50, VolumeRight, 0, 3); +DECL_BITS(GBRegisterNR50, VolumeLeft, 4, 3); + +DECL_BITFIELD(GBRegisterNR51, uint8_t); +DECL_BIT(GBRegisterNR51, Ch1Right, 0); +DECL_BIT(GBRegisterNR51, Ch2Right, 1); +DECL_BIT(GBRegisterNR51, Ch3Right, 2); +DECL_BIT(GBRegisterNR51, Ch4Right, 3); +DECL_BIT(GBRegisterNR51, Ch1Left, 4); +DECL_BIT(GBRegisterNR51, Ch2Left, 5); +DECL_BIT(GBRegisterNR51, Ch3Left, 6); +DECL_BIT(GBRegisterNR51, Ch4Left, 7); + +DECL_BITFIELD(GBAudioEnable, uint8_t); +DECL_BIT(GBAudioEnable, PlayingCh1, 0); +DECL_BIT(GBAudioEnable, PlayingCh2, 1); +DECL_BIT(GBAudioEnable, PlayingCh3, 2); +DECL_BIT(GBAudioEnable, PlayingCh4, 3); +DECL_BIT(GBAudioEnable, Enable, 7); + +struct GB; +struct GBAudioEnvelope { + int length; + int duty; + int stepTime; + int initialVolume; + int currentVolume; + bool direction; + int dead; + int nextStep; +}; + +struct GBAudioSquareControl { + int frequency; + int length; + bool stop; + int hi; +}; + +struct GBAudioSweep { + int shift; + int time; + int step; + bool direction; + bool enable; + bool occurred; + int realFrequency; +}; + +struct GBAudioSquareChannel { + struct GBAudioSweep sweep; + struct GBAudioEnvelope envelope; + struct GBAudioSquareControl control; + int8_t sample; +}; + +struct GBAudioWaveChannel { + bool size; + bool bank; + bool enable; + + unsigned length; + int volume; + + int rate; + bool stop; + + int window; + bool readable; + union { + uint32_t wavedata32[8]; + uint8_t wavedata8[16]; + }; + int8_t sample; +}; + +struct GBAudioNoiseChannel { + struct GBAudioEnvelope envelope; + + int ratio; + int frequency; + bool power; + bool stop; + int length; + + uint32_t lfsr; + int nSamples; + int samples; + uint32_t lastEvent; + + int8_t sample; +}; + +enum GBAudioStyle { + GB_AUDIO_DMG, + GB_AUDIO_MGB = GB_AUDIO_DMG, // TODO + GB_AUDIO_CGB, + GB_AUDIO_AGB, // GB in GBA + GB_AUDIO_GBA, // GBA PSG +}; + +struct GBAudio { + struct GB* p; + struct mTiming* timing; + unsigned timingFactor; + struct GBAudioSquareChannel ch1; + struct GBAudioSquareChannel ch2; + struct GBAudioWaveChannel ch3; + struct GBAudioNoiseChannel ch4; + + struct blip_t* left; + struct blip_t* right; + int16_t lastLeft; + int16_t lastRight; + int32_t capLeft; + int32_t capRight; + int clock; + int32_t clockRate; + + uint8_t volumeRight; + uint8_t volumeLeft; + bool ch1Right; + bool ch2Right; + bool ch3Right; + bool ch4Right; + bool ch1Left; + bool ch2Left; + bool ch3Left; + bool ch4Left; + + bool playingCh1; + bool playingCh2; + bool playingCh3; + bool playingCh4; + uint8_t* nr52; + + int frame; + bool skipFrame; + + int32_t sampleInterval; + enum GBAudioStyle style; + + struct mTimingEvent frameEvent; + struct mTimingEvent ch1Event; + struct mTimingEvent ch2Event; + struct mTimingEvent ch3Event; + struct mTimingEvent ch3Fade; + struct mTimingEvent ch4Event; + struct mTimingEvent sampleEvent; + bool enable; + + size_t samples; + bool forceDisableCh[4]; + int masterVolume; +}; + +void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style); +void GBAudioDeinit(struct GBAudio* audio); +void GBAudioReset(struct GBAudio* audio); + +void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples); + +void GBAudioWriteNR10(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR11(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR12(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR13(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR14(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR21(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR22(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR23(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR24(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR30(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR31(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR32(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR33(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR34(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR41(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR42(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR43(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR44(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR50(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR51(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR52(struct GBAudio* audio, uint8_t); + +void GBAudioUpdateFrame(struct GBAudio* audio); +void GBAudioUpdateChannel4(struct GBAudio* audio); + +void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right); + +struct GBSerializedPSGState; +void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut); +void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGState* state, const uint32_t* flagsIn); + +struct GBSerializedState; +void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state); +void GBAudioDeserialize(struct GBAudio* audio, const struct GBSerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/cheats.h b/mgba-test-runner/c/include/mgba/internal/gb/cheats.h new file mode 100644 index 00000000..7f74cb96 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/cheats.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_CHEATS_H +#define GB_CHEATS_H + +#include + +CXX_GUARD_START + +#include + +enum GBCheatType { + GB_CHEAT_AUTODETECT, + GB_CHEAT_GAMESHARK, + GB_CHEAT_GAME_GENIE, + GB_CHEAT_VBA +}; + +struct mCheatDevice* GBCheatDeviceCreate(void); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/debugger/debugger.h b/mgba-test-runner/c/include/mgba/internal/gb/debugger/debugger.h new file mode 100644 index 00000000..2eeee8ed --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/debugger/debugger.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2019 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_DEBUGGER_H +#define GB_DEBUGGER_H + +#include + +CXX_GUARD_START + +struct GB; +struct mDebuggerPlatform; + +struct mDebuggerPlatform* GBDebuggerCreate(struct GB* gb); + +CXX_GUARD_END + +#endif \ No newline at end of file diff --git a/mgba-test-runner/c/include/mgba/internal/gb/debugger/symbols.h b/mgba-test-runner/c/include/mgba/internal/gb/debugger/symbols.h new file mode 100644 index 00000000..ae893f28 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/debugger/symbols.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_SYMBOLS_H +#define GB_SYMBOLS_H + +#include + +CXX_GUARD_START + +struct mDebuggerSymbols; +struct VFile; +void GBLoadSymbols(struct mDebuggerSymbols*, struct VFile* vf); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/extra/cli.h b/mgba-test-runner/c/include/mgba/internal/gb/extra/cli.h new file mode 100644 index 00000000..19c2c711 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/extra/cli.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_CLI_H +#define GB_CLI_H + +#include + +CXX_GUARD_START + +#include + +struct GBCLIDebugger { + struct CLIDebuggerSystem d; + + struct mCore* core; + + bool frameAdvance; + bool inVblank; +}; + +struct CLIDebuggerSystem* GBCLIDebuggerCreate(struct mCore*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/gb.h b/mgba-test-runner/c/include/mgba/internal/gb/gb.h new file mode 100644 index 00000000..d0e59e07 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/gb.h @@ -0,0 +1,189 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_H +#define GB_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern const uint32_t DMG_SM83_FREQUENCY; +extern const uint32_t CGB_SM83_FREQUENCY; +extern const uint32_t SGB_SM83_FREQUENCY; + +mLOG_DECLARE_CATEGORY(GB); + +// TODO: Prefix GBAIRQ +enum GBIRQ { + GB_IRQ_VBLANK = 0x0, + GB_IRQ_LCDSTAT = 0x1, + GB_IRQ_TIMER = 0x2, + GB_IRQ_SIO = 0x3, + GB_IRQ_KEYPAD = 0x4, +}; + +enum GBIRQVector { + GB_VECTOR_VBLANK = 0x40, + GB_VECTOR_LCDSTAT = 0x48, + GB_VECTOR_TIMER = 0x50, + GB_VECTOR_SIO = 0x58, + GB_VECTOR_KEYPAD = 0x60, +}; + +enum GBSGBCommand { + SGB_PAL01 = 0, + SGB_PAL23, + SGB_PAL03, + SGB_PAL12, + SGB_ATTR_BLK, + SGB_ATTR_LIN, + SGB_ATTR_DIV, + SGB_ATTR_CHR, + SGB_SOUND, + SGB_SOU_TRN, + SGB_PAL_SET, + SGB_PAL_TRN, + SGB_ATRC_EN, + SGB_TEST_EN, + SGB_PICON_EN, + SGB_DATA_SND, + SGB_DATA_TRN, + SGB_MLT_REQ, + SGB_JUMP, + SGB_CHR_TRN, + SGB_PCT_TRN, + SGB_ATTR_TRN, + SGB_ATTR_SET, + SGB_MASK_EN, + SGB_OBJ_TRN +}; + +struct SM83Core; +struct mCoreSync; +struct mAVStream; +struct GB { + struct mCPUComponent d; + + struct SM83Core* cpu; + struct GBMemory memory; + struct GBVideo video; + struct GBTimer timer; + struct GBAudio audio; + struct GBSIO sio; + enum GBModel model; + + struct mCoreSync* sync; + struct mTiming timing; + + uint8_t* keySource; + + bool isPristine; + size_t pristineRomSize; + size_t yankedRomSize; + enum GBMemoryBankControllerType yankedMbc; + uint32_t romCrc32; + struct VFile* romVf; + struct VFile* biosVf; + struct VFile* sramVf; + struct VFile* sramRealVf; + uint32_t sramSize; + int sramDirty; + int32_t sramDirtAge; + bool sramMaskWriteback; + + int sgbBit; + int currentSgbBits; + uint8_t sgbPacket[16]; + uint8_t sgbControllers; + uint8_t sgbCurrentController; + bool sgbIncrement; + + struct mCoreCallbacksList coreCallbacks; + struct mAVStream* stream; + + bool cpuBlocked; + bool earlyExit; + struct mTimingEvent eiPending; + unsigned doubleSpeed; + + bool allowOpposingDirections; +}; + +struct GBCartridge { + uint8_t entry[4]; + uint8_t logo[48]; + union { + char titleLong[16]; + struct { + char titleShort[11]; + char maker[4]; + uint8_t cgb; + }; + }; + char licensee[2]; + uint8_t sgb; + uint8_t type; + uint8_t romSize; + uint8_t ramSize; + uint8_t region; + uint8_t oldLicensee; + uint8_t version; + uint8_t headerChecksum; + uint16_t globalChecksum; + // And ROM data... +}; + +void GBCreate(struct GB* gb); +void GBDestroy(struct GB* gb); + +void GBReset(struct SM83Core* cpu); +void GBSkipBIOS(struct GB* gb); +void GBMapBIOS(struct GB* gb); +void GBUnmapBIOS(struct GB* gb); +void GBDetectModel(struct GB* gb); + +void GBUpdateIRQs(struct GB* gb); +void GBHalt(struct SM83Core* cpu); + +struct VFile; +bool GBLoadROM(struct GB* gb, struct VFile* vf); +bool GBLoadSave(struct GB* gb, struct VFile* vf); +void GBUnloadROM(struct GB* gb); +void GBSynthesizeROM(struct VFile* vf); +void GBYankROM(struct GB* gb); + +void GBLoadBIOS(struct GB* gb, struct VFile* vf); + +void GBSramClean(struct GB* gb, uint32_t frameCount); +void GBResizeSram(struct GB* gb, size_t size); +void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback); +void GBSavedataUnmask(struct GB* gb); + +struct Patch; +void GBApplyPatch(struct GB* gb, struct Patch* patch); + +void GBGetGameTitle(const struct GB* gba, char* out); +void GBGetGameCode(const struct GB* gba, char* out); + +void GBTestKeypadIRQ(struct GB* gb); + +void GBFrameStarted(struct GB* gb); +void GBFrameEnded(struct GB* gb); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/input.h b/mgba-test-runner/c/include/mgba/internal/gb/input.h new file mode 100644 index 00000000..9fa95eb5 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/input.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2013-2019 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_INPUT_H +#define GB_INPUT_H + +#include + +CXX_GUARD_START + +#include + +extern MGBA_EXPORT const struct mInputPlatformInfo GBInputInfo; + +enum GBKey { + GB_KEY_A = 0, + GB_KEY_B = 1, + GB_KEY_SELECT = 2, + GB_KEY_START = 3, + GB_KEY_RIGHT = 4, + GB_KEY_LEFT = 5, + GB_KEY_UP = 6, + GB_KEY_DOWN = 7, + GB_KEY_MAX, +}; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/io.h b/mgba-test-runner/c/include/mgba/internal/gb/io.h new file mode 100644 index 00000000..44d83290 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/io.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_IO_H +#define GB_IO_H + +#include + +CXX_GUARD_START + +#include + +mLOG_DECLARE_CATEGORY(GB_IO); + +enum GBIORegisters { + GB_REG_JOYP = 0x00, + GB_REG_SB = 0x01, + GB_REG_SC = 0x02, + + // Timing + GB_REG_DIV = 0x04, + GB_REG_TIMA = 0x05, + GB_REG_TMA = 0x06, + GB_REG_TAC = 0x07, + + // Interrupts + GB_REG_IF = 0x0F, + GB_REG_IE = 0xFF, + + // Audio + GB_REG_NR10 = 0x10, + GB_REG_NR11 = 0x11, + GB_REG_NR12 = 0x12, + GB_REG_NR13 = 0x13, + GB_REG_NR14 = 0x14, + GB_REG_NR21 = 0x16, + GB_REG_NR22 = 0x17, + GB_REG_NR23 = 0x18, + GB_REG_NR24 = 0x19, + GB_REG_NR30 = 0x1A, + GB_REG_NR31 = 0x1B, + GB_REG_NR32 = 0x1C, + GB_REG_NR33 = 0x1D, + GB_REG_NR34 = 0x1E, + GB_REG_NR41 = 0x20, + GB_REG_NR42 = 0x21, + GB_REG_NR43 = 0x22, + GB_REG_NR44 = 0x23, + GB_REG_NR50 = 0x24, + GB_REG_NR51 = 0x25, + GB_REG_NR52 = 0x26, + + GB_REG_WAVE_0 = 0x30, + GB_REG_WAVE_1 = 0x31, + GB_REG_WAVE_2 = 0x32, + GB_REG_WAVE_3 = 0x33, + GB_REG_WAVE_4 = 0x34, + GB_REG_WAVE_5 = 0x35, + GB_REG_WAVE_6 = 0x36, + GB_REG_WAVE_7 = 0x37, + GB_REG_WAVE_8 = 0x38, + GB_REG_WAVE_9 = 0x39, + GB_REG_WAVE_A = 0x3A, + GB_REG_WAVE_B = 0x3B, + GB_REG_WAVE_C = 0x3C, + GB_REG_WAVE_D = 0x3D, + GB_REG_WAVE_E = 0x3E, + GB_REG_WAVE_F = 0x3F, + + // Video + GB_REG_LCDC = 0x40, + GB_REG_STAT = 0x41, + GB_REG_SCY = 0x42, + GB_REG_SCX = 0x43, + GB_REG_LY = 0x44, + GB_REG_LYC = 0x45, + GB_REG_DMA = 0x46, + GB_REG_BGP = 0x47, + GB_REG_OBP0 = 0x48, + GB_REG_OBP1 = 0x49, + GB_REG_WY = 0x4A, + GB_REG_WX = 0x4B, + + // CGB + GB_REG_KEY0 = 0x4C, + GB_REG_KEY1 = 0x4D, + GB_REG_VBK = 0x4F, + GB_REG_BANK = 0x50, + GB_REG_HDMA1 = 0x51, + GB_REG_HDMA2 = 0x52, + GB_REG_HDMA3 = 0x53, + GB_REG_HDMA4 = 0x54, + GB_REG_HDMA5 = 0x55, + GB_REG_RP = 0x56, + GB_REG_BCPS = 0x68, + GB_REG_BCPD = 0x69, + GB_REG_OCPS = 0x6A, + GB_REG_OCPD = 0x6B, + GB_REG_OPRI = 0x6C, + GB_REG_SVBK = 0x70, + GB_REG_UNK72 = 0x72, + GB_REG_UNK73 = 0x73, + GB_REG_UNK74 = 0x74, + GB_REG_UNK75 = 0x75, + GB_REG_PCM12 = 0x76, + GB_REG_PCM34 = 0x77, + GB_REG_MAX = 0x100 +}; + +extern MGBA_EXPORT const char* const GBIORegisterNames[]; + +struct GB; +void GBIOInit(struct GB* gb); +void GBIOReset(struct GB* gb); + +void GBIOWrite(struct GB* gb, unsigned address, uint8_t value); +uint8_t GBIORead(struct GB* gb, unsigned address); + +struct GBSerializedState; +void GBIOSerialize(const struct GB* gb, struct GBSerializedState* state); +void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/mbc.h b/mgba-test-runner/c/include/mgba/internal/gb/mbc.h new file mode 100644 index 00000000..2a6c5a3b --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/mbc.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_MBC_H +#define GB_MBC_H + +#include + +CXX_GUARD_START + +#include + +mLOG_DECLARE_CATEGORY(GB_MBC); + +struct GB; +struct GBMemory; +void GBMBCInit(struct GB* gb); +void GBMBCReset(struct GB* gb); +void GBMBCSwitchBank(struct GB* gb, int bank); +void GBMBCSwitchBank0(struct GB* gb, int bank); +void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank); +void GBMBCSwitchSramBank(struct GB* gb, int bank); +void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank); + +enum GBCam { + GBCAM_WIDTH = 128, + GBCAM_HEIGHT = 112 +}; + +struct GBMBCRTCSaveBuffer { + uint32_t sec; + uint32_t min; + uint32_t hour; + uint32_t days; + uint32_t daysHi; + uint32_t latchedSec; + uint32_t latchedMin; + uint32_t latchedHour; + uint32_t latchedDays; + uint32_t latchedDaysHi; + uint64_t unixTime; +}; +void GBMBCRTCRead(struct GB* gb); +void GBMBCRTCWrite(struct GB* gb); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/memory.h b/mgba-test-runner/c/include/mgba/internal/gb/memory.h new file mode 100644 index 00000000..e2eecca4 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/memory.h @@ -0,0 +1,251 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_MEMORY_H +#define GB_MEMORY_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +mLOG_DECLARE_CATEGORY(GB_MBC); +mLOG_DECLARE_CATEGORY(GB_MEM); + +struct GB; + +enum { + GB_BASE_CART_BANK0 = 0x0000, + GB_BASE_CART_BANK1 = 0x4000, + GB_BASE_CART_HALFBANK1 = 0x4000, + GB_BASE_CART_HALFBANK2 = 0x6000, + GB_BASE_VRAM = 0x8000, + GB_BASE_EXTERNAL_RAM = 0xA000, + GB_BASE_EXTERNAL_RAM_HALFBANK0 = 0xA000, + GB_BASE_EXTERNAL_RAM_HALFBANK1 = 0xB000, + GB_BASE_WORKING_RAM_BANK0 = 0xC000, + GB_BASE_WORKING_RAM_BANK1 = 0xD000, + GB_BASE_OAM = 0xFE00, + GB_BASE_UNUSABLE = 0xFEA0, + GB_BASE_IO = 0xFF00, + GB_BASE_HRAM = 0xFF80, + GB_BASE_IE = 0xFFFF +}; + +enum { + GB_REGION_CART_BANK0 = 0x0, + GB_REGION_CART_BANK1 = 0x4, + GB_REGION_VRAM = 0x8, + GB_REGION_EXTERNAL_RAM = 0xA, + GB_REGION_WORKING_RAM_BANK0 = 0xC, + GB_REGION_WORKING_RAM_BANK1 = 0xD, + GB_REGION_WORKING_RAM_BANK1_MIRROR = 0xE, + GB_REGION_OTHER = 0xF, +}; + +enum { + GB_SIZE_CART_BANK0 = 0x4000, + GB_SIZE_CART_HALFBANK = 0x2000, + GB_SIZE_CART_MAX = 0x800000, + GB_SIZE_VRAM = 0x4000, + GB_SIZE_VRAM_BANK0 = 0x2000, + GB_SIZE_EXTERNAL_RAM = 0x2000, + GB_SIZE_EXTERNAL_RAM_HALFBANK = 0x1000, + GB_SIZE_WORKING_RAM = 0x8000, + GB_SIZE_WORKING_RAM_BANK0 = 0x1000, + GB_SIZE_OAM = 0xA0, + GB_SIZE_IO = 0x80, + GB_SIZE_HRAM = 0x7F, + + GB_SIZE_MBC6_FLASH = 0x100000, +}; + +enum { + GB_SRAM_DIRT_NEW = 1, + GB_SRAM_DIRT_SEEN = 2 +}; + +struct GBMemory; +typedef void (*GBMemoryBankControllerWrite)(struct GB*, uint16_t address, uint8_t value); +typedef uint8_t (*GBMemoryBankControllerRead)(struct GBMemory*, uint16_t address); + +DECL_BITFIELD(GBMBC7Field, uint8_t); +DECL_BIT(GBMBC7Field, CS, 7); +DECL_BIT(GBMBC7Field, CLK, 6); +DECL_BIT(GBMBC7Field, DI, 1); +DECL_BIT(GBMBC7Field, DO, 0); + +enum GBMBC7MachineState { + GBMBC7_STATE_IDLE = 0, + GBMBC7_STATE_READ_COMMAND = 1, + GBMBC7_STATE_DO = 2, + + GBMBC7_STATE_EEPROM_EWDS = 0x10, + GBMBC7_STATE_EEPROM_WRAL = 0x11, + GBMBC7_STATE_EEPROM_ERAL = 0x12, + GBMBC7_STATE_EEPROM_EWEN = 0x13, + GBMBC7_STATE_EEPROM_WRITE = 0x14, + GBMBC7_STATE_EEPROM_READ = 0x18, + GBMBC7_STATE_EEPROM_ERASE = 0x1C, +}; + +enum GBTAMA5Register { + GBTAMA5_BANK_LO = 0x0, + GBTAMA5_BANK_HI = 0x1, + GBTAMA5_WRITE_LO = 0x4, + GBTAMA5_WRITE_HI = 0x5, + GBTAMA5_CS = 0x6, + GBTAMA5_ADDR_LO = 0x7, + GBTAMA5_MAX = 0x8, + GBTAMA5_ACTIVE = 0xA, + GBTAMA5_READ_LO = 0xC, + GBTAMA5_READ_HI = 0xD, +}; + +struct GBMBC1State { + int mode; + int multicartStride; + uint8_t bankLo; + uint8_t bankHi; +}; + +struct GBMBC6State { + int currentBank1; + uint8_t* romBank1; + bool sramAccess; + int currentSramBank1; + uint8_t* sramBank1; + bool flashBank0; + bool flashBank1; +}; + +struct GBMBC7State { + enum GBMBC7MachineState state; + uint16_t sr; + uint8_t address; + bool writable; + int srBits; + uint8_t access; + uint8_t latch; + GBMBC7Field eeprom; +}; + +struct GBMMM01State { + bool locked; + int currentBank0; +}; + +struct GBPocketCamState { + bool registersActive; + uint8_t registers[0x36]; +}; + +struct GBTAMA5State { + uint8_t reg; + uint8_t registers[GBTAMA5_MAX]; +}; + +struct GBPKJDState { + uint8_t reg[2]; +}; + +struct GBBBDState { + int dataSwapMode; + int bankSwapMode; +}; + +union GBMBCState { + struct GBMBC1State mbc1; + struct GBMBC6State mbc6; + struct GBMBC7State mbc7; + struct GBMMM01State mmm01; + struct GBPocketCamState pocketCam; + struct GBTAMA5State tama5; + struct GBPKJDState pkjd; + struct GBBBDState bbd; +}; + +struct mRotationSource; +struct GBMemory { + uint8_t* rom; + uint8_t* romBase; + uint8_t* romBank; + enum GBMemoryBankControllerType mbcType; + GBMemoryBankControllerWrite mbcWrite; + GBMemoryBankControllerRead mbcRead; + union GBMBCState mbcState; + int currentBank; + int currentBank0; + + uint8_t* wram; + uint8_t* wramBank; + int wramCurrentBank; + + bool sramAccess; + bool directSramAccess; + uint8_t* sram; + uint8_t* sramBank; + int sramCurrentBank; + + uint8_t io[GB_SIZE_IO]; + bool ime; + uint8_t ie; + + uint8_t hram[GB_SIZE_HRAM]; + + uint16_t dmaSource; + uint16_t dmaDest; + int dmaRemaining; + + uint16_t hdmaSource; + uint16_t hdmaDest; + int hdmaRemaining; + bool isHdma; + + struct mTimingEvent dmaEvent; + struct mTimingEvent hdmaEvent; + + size_t romSize; + + bool rtcAccess; + int activeRtcReg; + bool rtcLatched; + uint8_t rtcRegs[5]; + time_t rtcLastLatch; + struct mRTCSource* rtc; + struct mRotationSource* rotation; + struct mRumble* rumble; + struct mImageSource* cam; +}; + +struct SM83Core; +void GBMemoryInit(struct GB* gb); +void GBMemoryDeinit(struct GB* gb); + +void GBMemoryReset(struct GB* gb); +void GBMemorySwitchWramBank(struct GBMemory* memory, int bank); + +uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address); +void GBStore8(struct SM83Core* cpu, uint16_t address, int8_t value); + +int GBCurrentSegment(struct SM83Core* cpu, uint16_t address); + +uint8_t GBView8(struct SM83Core* cpu, uint16_t address, int segment); + +void GBMemoryDMA(struct GB* gb, uint16_t base); +uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value); + +void GBPatch8(struct SM83Core* cpu, uint16_t address, int8_t value, int8_t* old, int segment); + +struct GBSerializedState; +void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state); +void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/overrides.h b/mgba-test-runner/c/include/mgba/internal/gb/overrides.h new file mode 100644 index 00000000..5e0b2bbc --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/overrides.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_OVERRIDES_H +#define GB_OVERRIDES_H + +#include + +CXX_GUARD_START + +#include + +struct GBCartridgeOverride { + int headerCrc32; + enum GBModel model; + enum GBMemoryBankControllerType mbc; + + uint32_t gbColors[12]; +}; + +struct Configuration; +bool GBOverrideFind(const struct Configuration*, struct GBCartridgeOverride* override); +bool GBOverrideColorFind(struct GBCartridgeOverride* override); +void GBOverrideSave(struct Configuration*, const struct GBCartridgeOverride* override); + +struct GB; +void GBOverrideApply(struct GB*, const struct GBCartridgeOverride*); +void GBOverrideApplyDefaults(struct GB*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/renderers/cache-set.h b/mgba-test-runner/c/include/mgba/internal/gb/renderers/cache-set.h new file mode 100644 index 00000000..f11bdf45 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/renderers/cache-set.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_TILE_CACHE_H +#define GB_TILE_CACHE_H + +#include + +CXX_GUARD_START + +struct GBVideo; +struct mCacheSet; + +void GBVideoCacheInit(struct mCacheSet* cache); +void GBVideoCacheAssociate(struct mCacheSet* cache, struct GBVideo* video); + +void GBVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint16_t address, uint8_t value); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/renderers/proxy.h b/mgba-test-runner/c/include/mgba/internal/gb/renderers/proxy.h new file mode 100644 index 00000000..ca3b59f2 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/renderers/proxy.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_VIDEO_PROXY_H +#define GB_VIDEO_PROXY_H + +#include + +CXX_GUARD_START + +#include +#include + +struct GBVideoProxyRenderer { + struct GBVideoRenderer d; + struct GBVideoRenderer* backend; + struct mVideoLogger* logger; + enum GBModel model; +}; + +void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GBVideoRenderer* backend); +void GBVideoProxyRendererShim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer); +void GBVideoProxyRendererUnshim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/renderers/software.h b/mgba-test-runner/c/include/mgba/internal/gb/renderers/software.h new file mode 100644 index 00000000..57942a7d --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/renderers/software.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_RENDERER_SOFTWARE_H +#define GB_RENDERER_SOFTWARE_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +struct GBVideoRendererSprite { + struct GBObj obj; + int8_t index; +}; + +struct GBVideoSoftwareRenderer { + struct GBVideoRenderer d; + + color_t* outputBuffer; + int outputBufferStride; + + // TODO: Implement the pixel FIFO + uint16_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8]; + + color_t palette[192]; + uint8_t lookup[192]; + + uint32_t* temporaryBuffer; + + uint8_t scy; + uint8_t scx; + uint8_t wy; + uint8_t wx; + uint8_t currentWy; + uint8_t currentWx; + int lastY; + int lastX; + bool hasWindow; + + GBRegisterLCDC lcdc; + enum GBModel model; + + struct GBVideoRendererSprite obj[GB_VIDEO_MAX_LINE_OBJ]; + int objMax; + + int16_t objOffsetX; + int16_t objOffsetY; + int16_t offsetScx; + int16_t offsetScy; + int16_t offsetWx; + int16_t offsetWy; + + int sgbTransfer; + uint8_t sgbPacket[128]; + uint8_t sgbCommandHeader; + bool sgbBorders; + + uint8_t lastHighlightAmount; +}; + +void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/serialize.h b/mgba-test-runner/c/include/mgba/internal/gb/serialize.h new file mode 100644 index 00000000..18ac83b0 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/serialize.h @@ -0,0 +1,445 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_SERIALIZE_H +#define GB_SERIALIZE_H + +#include + +CXX_GUARD_START + +#include +#include + +extern MGBA_EXPORT const uint32_t GBSavestateMagic; +extern MGBA_EXPORT const uint32_t GBSavestateVersion; + +mLOG_DECLARE_CATEGORY(GB_STATE); + +/* Savestate format: + * 0x00000 - 0x00003: Version Magic (0x01000002) + * 0x00004 - 0x00007: ROM CRC32 + * 0x00008: Game Boy model + * 0x00009 - 0x0000B: Reserved (leave zero) + * 0x0000C - 0x0000F: Master cycles + * 0x00010 - 0x0001F: Game title/code (e.g. PM_CRYSTALBYTE) + * 0x00020 - 0x00047: CPU state: + * | 0x00020: A register + * | 0x00021: F register + * | 0x00022: B register + * | 0x00023: C register + * | 0x00024: D register + * | 0x00025: E register + * | 0x00026: H register + * | 0x00027: L register + * | 0x00028 - 0x00029: SP register + * | 0x0002A - 0x0002B: PC register + * | 0x0002C - 0x0002F: Cycles since last event + * | 0x00030 - 0x00033: Cycles until next event + * | 0x00034 - 0x00035: Reserved (current instruction) + * | 0x00036 - 0x00037: Index address + * | 0x00038: Bus value + * | 0x00039: Execution state + * | 0x0003A - 0x0003B: Reserved + * | 0x0003C - 0x0003F: EI pending cycles + * | 0x00040 - 0x00043: Reserved (DI pending cycles) + * | 0x00044 - 0x00047: Flags + * | bit 0: Is condition met? + * | bit 1: Is IRQ pending? + * | bit 2: Double speed + * | bit 3: Is EI pending? + * | bits 4 - 31: Reserved + * 0x00048 - 0x0005B: Audio channel 1/framer state + * | 0x00048 - 0x0004B: Envelepe timing + * | bits 0 - 6: Remaining length + * | bits 7 - 9: Next step + * | bits 10 - 20: Shadow frequency register + * | bits 21 - 31: Reserved + * | 0x0004C - 0x0004F: Next frame + * | 0x00050 - 0x00053: Next channel 3 fade + * | 0x00054 - 0x00057: Sweep state + * | bits 0 - 2: Timesteps + * | bits 3 - 31: Reserved + * | 0x00058 - 0x0005B: Next event + * 0x0005C - 0x0006B: Audio channel 2 state + * | 0x0005C - 0x0005F: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00060 - 0x00067: Reserved + * | 0x00068 - 0x0006B: Next event + * 0x0006C - 0x00093: Audio channel 3 state + * | 0x0006C - 0x0008B: Wave banks + * | 0x0008C - 0x0008D: Remaining length + * | 0x0008E - 0x0008F: Reserved + * | 0x00090 - 0x00093: Next event + * 0x00094 - 0x000A3: Audio channel 4 state + * | 0x00094 - 0x00097: Linear feedback shift register state + * | 0x00098 - 0x0009B: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x0009C - 0x0009F: Last event + * | 0x000A0 - 0x000A3: Next event + * 0x000A4 - 0x000B7: Audio miscellaneous state + * | TODO: Fix this, they're in big-endian order, but field is little-endian + * | 0x000A4: Channel 1 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bit 7: Reserved + * | 0x000A5: Channel 2 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bit 7: Reserved + * | 0x000A6: Channel 4 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bits 6 - 7: Current frame (continued) + * | 0x000A7: Miscellaneous audio flags + * | bit 0: Current frame (continuation) + * | bit 1: Is channel 1 sweep enabled? + * | bit 2: Has channel 1 sweep occurred? + * | bit 3: Is channel 3's memory readable? + * | bit 4: Skip frame + * | bits 5 - 7: Reserved + * | 0x000A8 - 0x000AB: Left capacitor charge + * | 0x000AC - 0x000AF: Right capacitor charge + * | 0x000B0 - 0x000B3: Next sample + * 0x000B4 - 0x000153: Video state + * | 0x000B4 - 0x000B5: Current x + * | 0x000B6 - 0x000B7: Current y (ly) + * | 0x000B8 - 0x000BB: Next frame + * | 0x000BC - 0x000BF: Reserved + * | 0x000C0 - 0x000C3: Next mode + * | 0x000C4 - 0x000C7: Dot cycle counter + * | 0x000C8 - 0x000CB: Frame counter + * | 0x000CC: Current VRAM bank + * | 0x000CD: Palette flags + * | bit 0: BCP increment + * | bit 1: OCP increment + * | bits 2 - 3: Mode + * | bits 4 - 7: Reserved + * | 0x000CE - 0x000CF: Reserved + * | 0x000D0 - 0x000D1: BCP index + * | 0x000D1 - 0x000D3: OCP index + * | 0x000D4 - 0x00153: Palette entries + * 0x00154 - 0x000167: Timer state + * | 0x00154 - 0x00157: Next event + * | 0x00158 - 0x0015B: Next IRQ + * | 0x0015C - 0x0015F: Next DIV + * | 0x00160 - 0x00163: Inernal DIV + * | 0x00164: TIMA period + * | 0x00165: Flags + * | bit 0: Is IRQ pending? + * | 0x00166 - 0x00167: Reserved + * 0x000168 - 0x000197: Memory state + * | 0x00168 - 0x00169: Current ROM bank + * | 0x0016A: Current WRAM bank + * | 0x0016B: Current SRAM bank + * | 0x0016C - 0x0016F: Next DMA + * | 0x00170 - 0x00171: Next DMA source + * | 0x00172 - 0x00173: Next DMA destination + * | 0x00174 - 0x00177: Next HDMA + * | 0x00178 - 0x00179: Next HDMA source + * | 0x0017A - 0x0017B: Next HDMA destination + * | 0x0017C - 0x0017D: HDMA remaining + * | 0x0017E: DMA remaining + * | 0x0017F - 0x00183: RTC registers + * | 0x00184 - 0x00193: MBC state + * | 0x00194 - 0x00195: Flags + * | bit 0: SRAM accessable + * | bit 1: RTC accessible + * | bit 2: RTC latched + * | bit 3: IME + * | bit 4: Is HDMA active? + * | bits 5 - 7: Active RTC register + * | 0x00196 - 0x00197: Reserved (leave zero) + * 0x00198 - 0x0019F: Global cycle counter + * 0x001A0 - 0x0025F: Reserved (leave zero) + * 0x00260 - 0x002FF: OAM + * 0x00300 - 0x0037F: I/O memory + * 0x00380 - 0x003FE: HRAM + * 0x003FF: Interrupts enabled + * 0x00400 - 0x043FF: VRAM + * 0x04400 - 0x0C3FF: WRAM + * 0x0C400 - 0x0C77F: Reserved + * 0x0C780 - 0x117FF: Super Game Boy + * | 0x0C780 - 0x0C7D9: Current attributes + * | 0x0C7DA: Current command + * | 0x0C7DB: Current bit count + * | 0x0C7DC - 0x0C7DF: Flags + * | bits 0 - 1: Current P1 bits + * | bits 2 - 3: Current render mode + * | bit 4: Is a mode event not scheduled? + * | bit 5: Is a frame event not scheduled? + * | bits 6 - 31: Reserved (leave 0) + * | 0x0C7E0 - 0x0C7EF: Current packet + * | 0x0C7F0 - 0x0C7FF: Reserved + * | 0x0C800 - 0x0E7FF: Character VRAM + * | 0x0E800 - 0x0F7FF: Tile map VRAM + * | 0x0F800 - 0x107FF: Palette VRAM + * | 0x10800 - 0x117FF: Attribute file + * Total size: 0x11800 (71,680) bytes +*/ + +DECL_BITFIELD(GBSerializedAudioFlags, uint32_t); +DECL_BITS(GBSerializedAudioFlags, Ch1Volume, 0, 4); +DECL_BITS(GBSerializedAudioFlags, Ch1Dead, 4, 2); +DECL_BIT(GBSerializedAudioFlags, Ch1Hi, 6); +DECL_BITS(GBSerializedAudioFlags, Ch2Volume, 8, 4); +DECL_BITS(GBSerializedAudioFlags, Ch2Dead, 12, 2); +DECL_BIT(GBSerializedAudioFlags, Ch2Hi, 14); +DECL_BITS(GBSerializedAudioFlags, Ch4Volume, 16, 4); +DECL_BITS(GBSerializedAudioFlags, Ch4Dead, 20, 2); +DECL_BITS(GBSerializedAudioFlags, Frame, 22, 3); +DECL_BIT(GBSerializedAudioFlags, Ch1SweepEnabled, 25); +DECL_BIT(GBSerializedAudioFlags, Ch1SweepOccurred, 26); +DECL_BIT(GBSerializedAudioFlags, Ch3Readable, 27); +DECL_BIT(GBSerializedAudioFlags, SkipFrame, 28); + +DECL_BITFIELD(GBSerializedAudioEnvelope, uint32_t); +DECL_BITS(GBSerializedAudioEnvelope, Length, 0, 7); +DECL_BITS(GBSerializedAudioEnvelope, NextStep, 7, 3); +DECL_BITS(GBSerializedAudioEnvelope, Frequency, 10, 11); + + +DECL_BITFIELD(GBSerializedAudioSweep, uint32_t); +DECL_BITS(GBSerializedAudioSweep, Time, 0, 3); + +struct GBSerializedPSGState { + struct { + GBSerializedAudioEnvelope envelope; + int32_t nextFrame; + int32_t nextCh3Fade; + GBSerializedAudioSweep sweep; + uint32_t nextEvent; + } ch1; + struct { + GBSerializedAudioEnvelope envelope; + int32_t reserved[2]; + int32_t nextEvent; + } ch2; + struct { + uint32_t wavebanks[8]; + int16_t length; + int16_t reserved; + uint32_t nextEvent; + } ch3; + struct { + int32_t lfsr; + GBSerializedAudioEnvelope envelope; + int32_t lastEvent; + uint32_t nextEvent; + } ch4; +}; + +DECL_BITFIELD(GBSerializedCpuFlags, uint32_t); +DECL_BIT(GBSerializedCpuFlags, Condition, 0); +DECL_BIT(GBSerializedCpuFlags, IrqPending, 1); +DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2); +DECL_BIT(GBSerializedCpuFlags, EiPending, 3); +DECL_BIT(GBSerializedCpuFlags, Halted, 4); +DECL_BIT(GBSerializedCpuFlags, Blocked, 5); + +DECL_BITFIELD(GBSerializedTimerFlags, uint8_t); +DECL_BIT(GBSerializedTimerFlags, IrqPending, 0); + +DECL_BITFIELD(GBSerializedVideoFlags, uint8_t); +DECL_BIT(GBSerializedVideoFlags, BcpIncrement, 0); +DECL_BIT(GBSerializedVideoFlags, OcpIncrement, 1); +DECL_BITS(GBSerializedVideoFlags, Mode, 2, 2); +DECL_BIT(GBSerializedVideoFlags, NotModeEventScheduled, 4); +DECL_BIT(GBSerializedVideoFlags, NotFrameEventScheduled, 5); + +DECL_BITFIELD(GBSerializedMBC7Flags, uint8_t); +DECL_BITS(GBSerializedMBC7Flags, Command, 0, 2); +DECL_BIT(GBSerializedMBC7Flags, Writable, 2); + +DECL_BITFIELD(GBSerializedMemoryFlags, uint16_t); +DECL_BIT(GBSerializedMemoryFlags, SramAccess, 0); +DECL_BIT(GBSerializedMemoryFlags, RtcAccess, 1); +DECL_BIT(GBSerializedMemoryFlags, RtcLatched, 2); +DECL_BIT(GBSerializedMemoryFlags, Ime, 3); +DECL_BIT(GBSerializedMemoryFlags, IsHdma, 4); +DECL_BITS(GBSerializedMemoryFlags, ActiveRtcReg, 5, 3); + +DECL_BITFIELD(GBSerializedSGBFlags, uint32_t); +DECL_BITS(GBSerializedSGBFlags, P1Bits, 0, 2); +DECL_BITS(GBSerializedSGBFlags, RenderMode, 2, 2); +DECL_BITS(GBSerializedSGBFlags, BufferIndex, 4, 3); +DECL_BITS(GBSerializedSGBFlags, CurrentController, 7, 2); +DECL_BITS(GBSerializedSGBFlags, ReqControllers, 9, 2); +DECL_BIT(GBSerializedSGBFlags, Increment, 11); + +#pragma pack(push, 1) +struct GBSerializedState { + uint32_t versionMagic; + uint32_t romCrc32; + uint8_t model; + uint8_t reservedHeader[3]; + uint32_t masterCycles; + + char title[16]; + + struct { + uint8_t a; + uint8_t f; + uint8_t b; + uint8_t c; + uint8_t d; + uint8_t e; + uint8_t h; + uint8_t l; + uint16_t sp; + uint16_t pc; + + int32_t cycles; + int32_t nextEvent; + + uint16_t reservedInstruction; + uint16_t index; + uint8_t bus; + uint8_t executionState; + + uint16_t reserved; + + uint32_t eiPending; + int32_t reservedDiPending; + GBSerializedCpuFlags flags; + } cpu; + + struct { + struct GBSerializedPSGState psg; + GBSerializedAudioFlags flags; + int32_t capLeft; + int32_t capRight; + uint32_t nextSample; + } audio; + + struct { + int16_t x; + int16_t ly; + uint32_t nextFrame; + uint32_t reserved; + uint32_t nextMode; + int32_t dotCounter; + int32_t frameCounter; + + uint8_t vramCurrentBank; + GBSerializedVideoFlags flags; + uint16_t reserved2; + + uint16_t bcpIndex; + uint16_t ocpIndex; + + uint16_t palette[64]; + } video; + + struct { + uint32_t nextEvent; + uint32_t nextIRQ; + + uint32_t nextDiv; + uint32_t internalDiv; + uint8_t timaPeriod; + GBSerializedTimerFlags flags; + uint16_t reserved; + } timer; + + struct { + uint16_t currentBank; + uint8_t wramCurrentBank; + uint8_t sramCurrentBank; + + uint32_t dmaNext; + uint16_t dmaSource; + uint16_t dmaDest; + + uint32_t hdmaNext; + uint16_t hdmaSource; + uint16_t hdmaDest; + + uint16_t hdmaRemaining; + uint8_t dmaRemaining; + uint8_t rtcRegs[5]; + + union { + struct { + uint8_t mode; + uint8_t multicartStride; + uint8_t bankLo; + uint8_t bankHi; + } mbc1; + struct { + uint64_t lastLatch; + } rtc; + struct { + uint8_t state; + GBMBC7Field eeprom; + uint8_t address; + uint8_t access; + uint8_t latch; + uint8_t srBits; + uint16_t sr; + uint32_t writable; + } mbc7; + struct { + uint8_t locked; + uint8_t bank0; + } mmm01; + struct { + uint8_t dataSwapMode; + uint8_t bankSwapMode; + } bbd; + struct { + uint8_t reserved[16]; + } padding; + }; + + GBSerializedMemoryFlags flags; + uint16_t reserved; + } memory; + + uint64_t globalCycles; + + uint32_t reserved[48]; + + uint8_t oam[GB_SIZE_OAM]; + + uint8_t io[GB_SIZE_IO]; + uint8_t hram[GB_SIZE_HRAM]; + uint8_t ie; + + uint8_t vram[GB_SIZE_VRAM]; + uint8_t wram[GB_SIZE_WORKING_RAM]; + + uint32_t reserved2[0xC4]; + + struct { + uint8_t attributes[90]; + uint8_t command; + uint8_t bits; + GBSerializedSGBFlags flags; + uint8_t inProgressPacket[16]; + uint8_t packet[128]; + uint8_t charRam[SGB_SIZE_CHAR_RAM]; + uint8_t mapRam[SGB_SIZE_MAP_RAM]; + uint8_t palRam[SGB_SIZE_PAL_RAM]; + uint8_t atfRam[SGB_SIZE_ATF_RAM]; + } sgb; +}; +#pragma pack(pop) + +bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state); +void GBSerialize(struct GB* gb, struct GBSerializedState* state); + +void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state); +void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/sio.h b/mgba-test-runner/c/include/mgba/internal/gb/sio.h new file mode 100644 index 00000000..50d62868 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/sio.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_SIO_H +#define GB_SIO_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +#define MAX_GBS 2 + +extern const int GBSIOCyclesPerTransfer[2]; + +mLOG_DECLARE_CATEGORY(GB_SIO); + +struct GB; +struct GBSIODriver; +struct GBSIO { + struct GB* p; + + struct mTimingEvent event; + struct GBSIODriver* driver; + + int32_t nextEvent; + int32_t period; + int remainingBits; + + uint8_t pendingSB; +}; + +DECL_BITFIELD(GBRegisterSC, uint8_t); +DECL_BIT(GBRegisterSC, ShiftClock, 0); +DECL_BIT(GBRegisterSC, ClockSpeed, 1); +DECL_BIT(GBRegisterSC, Enable, 7); + +void GBSIOInit(struct GBSIO* sio); +void GBSIOReset(struct GBSIO* sio); +void GBSIODeinit(struct GBSIO* sio); +void GBSIOSetDriver(struct GBSIO* sio, struct GBSIODriver* driver); +void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc); +void GBSIOWriteSB(struct GBSIO* sio, uint8_t sb); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/sio/lockstep.h b/mgba-test-runner/c/include/mgba/internal/gb/sio/lockstep.h new file mode 100644 index 00000000..25f6d9c7 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/sio/lockstep.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_SIO_LOCKSTEP_H +#define GB_SIO_LOCKSTEP_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +struct GBSIOLockstep { + struct mLockstep d; + struct GBSIOLockstepNode* players[MAX_GBS]; + + uint8_t pendingSB[MAX_GBS]; + bool masterClaimed; +}; + +struct GBSIOLockstepNode { + struct GBSIODriver d; + struct GBSIOLockstep* p; + struct mTimingEvent event; + + volatile int32_t nextEvent; + int32_t eventDiff; + int id; + bool transferFinished; +#ifndef NDEBUG + int transferId; + enum mLockstepPhase phase; +#endif +}; + +void GBSIOLockstepInit(struct GBSIOLockstep*); + +void GBSIOLockstepNodeCreate(struct GBSIOLockstepNode*); + +bool GBSIOLockstepAttachNode(struct GBSIOLockstep*, struct GBSIOLockstepNode*); +void GBSIOLockstepDetachNode(struct GBSIOLockstep*, struct GBSIOLockstepNode*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/sio/printer.h b/mgba-test-runner/c/include/mgba/internal/gb/sio/printer.h new file mode 100644 index 00000000..a5b42a83 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/sio/printer.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_PRINTER_H +#define GB_PRINTER_H + +#include + +CXX_GUARD_START + +#include + +enum GBPrinterPacketByte { + GB_PRINTER_BYTE_MAGIC_0, + GB_PRINTER_BYTE_MAGIC_1, + GB_PRINTER_BYTE_COMMAND, + GB_PRINTER_BYTE_COMPRESSION, + GB_PRINTER_BYTE_LENGTH_0, + GB_PRINTER_BYTE_LENGTH_1, + GB_PRINTER_BYTE_DATA, + GB_PRINTER_BYTE_CHECKSUM_0, + GB_PRINTER_BYTE_CHECKSUM_1, + GB_PRINTER_BYTE_KEEPALIVE, + GB_PRINTER_BYTE_STATUS, + + GB_PRINTER_BYTE_COMPRESSED_DATUM, + GB_PRINTER_BYTE_UNCOMPRESSED_DATA +}; + +enum GBPrinterStatus { + GB_PRINTER_STATUS_CHECKSUM_ERROR = 0x01, + GB_PRINTER_STATUS_PRINTING = 0x02, + GB_PRINTER_STATUS_PRINT_REQ = 0x04, + GB_PRINTER_STATUS_READY = 0x08, + GB_PRINTER_STATUS_LOW_BATTERY = 0x10, + GB_PRINTER_STATUS_TIMEOUT = 0x20, + GB_PRINTER_STATUS_PAPER_JAM = 0x40, + GB_PRINTER_STATUS_TEMPERATURE_ISSUE = 0x80 +}; + +enum GBPrinterCommand { + GB_PRINTER_COMMAND_INIT = 0x1, + GB_PRINTER_COMMAND_PRINT = 0x2, + GB_PRINTER_COMMAND_DATA = 0x4, + GB_PRINTER_COMMAND_STATUS = 0xF, +}; + +struct GBPrinter { + struct GBSIODriver d; + + void (*print)(struct GBPrinter*, int height, const uint8_t* data); + + uint8_t* buffer; + uint16_t checksum; + enum GBPrinterCommand command; + uint16_t remainingBytes; + uint8_t remainingCmpBytes; + unsigned currentIndex; + bool compression; + + uint8_t byte; + enum GBPrinterPacketByte next; + uint8_t status; + int printWait; +}; + +void GBPrinterCreate(struct GBPrinter* printer); +void GBPrinterDonePrinting(struct GBPrinter* printer); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/timer.h b/mgba-test-runner/c/include/mgba/internal/gb/timer.h new file mode 100644 index 00000000..b81ff1c3 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/timer.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_TIMER_H +#define GB_TIMER_H + +#include + +CXX_GUARD_START + +#include + +DECL_BITFIELD(GBRegisterTAC, uint8_t); +DECL_BITS(GBRegisterTAC, Clock, 0, 2); +DECL_BIT(GBRegisterTAC, Run, 2); + +enum { + GB_DMG_DIV_PERIOD = 16 +}; + +struct GB; +struct GBTimer { + struct GB* p; + + struct mTimingEvent event; + struct mTimingEvent irq; + + uint32_t internalDiv; + int32_t nextDiv; + uint32_t timaPeriod; +}; + +void GBTimerReset(struct GBTimer*); +void GBTimerDivReset(struct GBTimer*); +uint8_t GBTimerUpdateTAC(struct GBTimer*, GBRegisterTAC tac); + +struct GBSerializedState; +void GBTimerSerialize(const struct GBTimer* timer, struct GBSerializedState* state); +void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gb/video.h b/mgba-test-runner/c/include/mgba/internal/gb/video.h new file mode 100644 index 00000000..da83ebc2 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gb/video.h @@ -0,0 +1,198 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_VIDEO_H +#define GB_VIDEO_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +mLOG_DECLARE_CATEGORY(GB_VIDEO); + +enum { + GB_VIDEO_HORIZONTAL_PIXELS = 160, + GB_VIDEO_VERTICAL_PIXELS = 144, + GB_VIDEO_VBLANK_PIXELS = 10, + GB_VIDEO_VERTICAL_TOTAL_PIXELS = 154, + + // TODO: Figure out exact lengths + GB_VIDEO_MODE_2_LENGTH = 80, + GB_VIDEO_MODE_3_LENGTH_BASE = 172, + GB_VIDEO_MODE_0_LENGTH_BASE = 204, + + GB_VIDEO_HORIZONTAL_LENGTH = 456, + + GB_VIDEO_TOTAL_LENGTH = 70224, + + GB_VIDEO_MAX_OBJ = 40, + GB_VIDEO_MAX_LINE_OBJ = 10, + + GB_BASE_MAP = 0x1800, + GB_SIZE_MAP = 0x0400, + + SGB_SIZE_CHAR_RAM = 0x2000, + SGB_SIZE_MAP_RAM = 0x1000, + SGB_SIZE_PAL_RAM = 0x1000, + SGB_SIZE_ATF_RAM = 0x1000 +}; + +DECL_BITFIELD(GBObjAttributes, uint8_t); +DECL_BITS(GBObjAttributes, CGBPalette, 0, 3); +DECL_BIT(GBObjAttributes, Bank, 3); +DECL_BIT(GBObjAttributes, Palette, 4); +DECL_BIT(GBObjAttributes, XFlip, 5); +DECL_BIT(GBObjAttributes, YFlip, 6); +DECL_BIT(GBObjAttributes, Priority, 7); + +DECL_BITFIELD(SGBBgAttributes, uint16_t); +DECL_BITS(SGBBgAttributes, Tile, 0, 10); +DECL_BITS(SGBBgAttributes, Palette, 10, 3); +DECL_BIT(SGBBgAttributes, Priority, 13); +DECL_BIT(SGBBgAttributes, XFlip, 14); +DECL_BIT(SGBBgAttributes, YFlip, 15); + +struct GBObj { + uint8_t y; + uint8_t x; + uint8_t tile; + GBObjAttributes attr; +}; + +union GBOAM { + struct GBObj obj[GB_VIDEO_MAX_OBJ]; + uint8_t raw[GB_VIDEO_MAX_OBJ * 4]; +}; + +struct mCacheSet; +struct GBVideoRenderer { + void (*init)(struct GBVideoRenderer* renderer, enum GBModel model, bool borders); + void (*deinit)(struct GBVideoRenderer* renderer); + + uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); + void (*writeSGBPacket)(struct GBVideoRenderer* renderer, uint8_t* data); + void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address); + void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value); + void (*writeOAM)(struct GBVideoRenderer* renderer, uint16_t oam); + void (*drawRange)(struct GBVideoRenderer* renderer, int startX, int endX, int y); + void (*finishScanline)(struct GBVideoRenderer* renderer, int y); + void (*finishFrame)(struct GBVideoRenderer* renderer); + void (*enableSGBBorder)(struct GBVideoRenderer* renderer, bool enable); + + void (*getPixels)(struct GBVideoRenderer* renderer, size_t* stride, const void** pixels); + void (*putPixels)(struct GBVideoRenderer* renderer, size_t stride, const void* pixels); + + uint8_t* vram; + union GBOAM* oam; + struct mCacheSet* cache; + + uint8_t* sgbCharRam; + uint8_t* sgbMapRam; + uint8_t* sgbPalRam; + int sgbRenderMode; + uint8_t* sgbAttributes; + uint8_t* sgbAttributeFiles; + + bool disableBG; + bool disableOBJ; + bool disableWIN; + + bool highlightBG; + bool highlightOBJ[GB_VIDEO_MAX_OBJ]; + bool highlightWIN; + color_t highlightColor; + uint8_t highlightAmount; +}; + +DECL_BITFIELD(GBRegisterLCDC, uint8_t); +DECL_BIT(GBRegisterLCDC, BgEnable, 0); +DECL_BIT(GBRegisterLCDC, ObjEnable, 1); +DECL_BIT(GBRegisterLCDC, ObjSize, 2); +DECL_BIT(GBRegisterLCDC, TileMap, 3); +DECL_BIT(GBRegisterLCDC, TileData, 4); +DECL_BIT(GBRegisterLCDC, Window, 5); +DECL_BIT(GBRegisterLCDC, WindowTileMap, 6); +DECL_BIT(GBRegisterLCDC, Enable, 7); + +DECL_BITFIELD(GBRegisterSTAT, uint8_t); +DECL_BITS(GBRegisterSTAT, Mode, 0, 2); +DECL_BIT(GBRegisterSTAT, LYC, 2); +DECL_BIT(GBRegisterSTAT, HblankIRQ, 3); +DECL_BIT(GBRegisterSTAT, VblankIRQ, 4); +DECL_BIT(GBRegisterSTAT, OAMIRQ, 5); +DECL_BIT(GBRegisterSTAT, LYCIRQ, 6); + +struct GBVideo { + struct GB* p; + struct GBVideoRenderer* renderer; + + int x; + int ly; + GBRegisterSTAT stat; + + int mode; + + struct mTimingEvent modeEvent; + struct mTimingEvent frameEvent; + + int32_t dotClock; + + uint8_t* vram; + uint8_t* vramBank; + int vramCurrentBank; + + union GBOAM oam; + int objMax; + + int bcpIndex; + bool bcpIncrement; + int ocpIndex; + bool ocpIncrement; + uint8_t sgbCommandHeader; + int sgbBufferIndex; + uint8_t sgbPacketBuffer[128]; + + uint16_t dmgPalette[12]; + uint16_t palette[64]; + + bool sgbBorders; + + int32_t frameCounter; + int frameskip; + int frameskipCounter; +}; + +void GBVideoInit(struct GBVideo* video); +void GBVideoReset(struct GBVideo* video); +void GBVideoDeinit(struct GBVideo* video); + +void GBVideoDummyRendererCreate(struct GBVideoRenderer*); +void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer); + +void GBVideoSkipBIOS(struct GBVideo* video); +void GBVideoProcessDots(struct GBVideo* video, uint32_t cyclesLate); + +void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value); +void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value); +void GBVideoWriteLYC(struct GBVideo* video, uint8_t value); +void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value); +void GBVideoSwitchBank(struct GBVideo* video, uint8_t value); + +void GBVideoDisableCGB(struct GBVideo* video); +void GBVideoSetPalette(struct GBVideo* video, unsigned index, uint32_t color); + +void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data); + +struct GBSerializedState; +void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state); +void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/audio.h b/mgba-test-runner/c/include/mgba/internal/gba/audio.h new file mode 100644 index 00000000..c9fab3ae --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/audio.h @@ -0,0 +1,319 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_AUDIO_H +#define GBA_AUDIO_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include + +#define GBA_AUDIO_FIFO_SIZE 8 + +#define MP2K_MAGIC 0x68736D53 +#define MP2K_MAX_SOUND_CHANNELS 12 + +mLOG_DECLARE_CATEGORY(GBA_AUDIO); + +struct GBADMA; + +extern const unsigned GBA_AUDIO_SAMPLES; +extern const int GBA_AUDIO_VOLUME_MAX; + +struct GBAAudioFIFO { + uint32_t fifo[GBA_AUDIO_FIFO_SIZE]; + int fifoWrite; + int fifoRead; + uint32_t internalSample; + int internalRemaining; + int dmaSource; + int8_t sample; +}; + +DECL_BITFIELD(GBARegisterSOUNDCNT_HI, uint16_t); +DECL_BITS(GBARegisterSOUNDCNT_HI, Volume, 0, 2); +DECL_BIT(GBARegisterSOUNDCNT_HI, VolumeChA, 2); +DECL_BIT(GBARegisterSOUNDCNT_HI, VolumeChB, 3); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChARight, 8); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChALeft, 9); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChATimer, 10); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChAReset, 11); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChBRight, 12); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChBLeft, 13); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChBTimer, 14); +DECL_BIT(GBARegisterSOUNDCNT_HI, ChBReset, 15); + +DECL_BITFIELD(GBARegisterSOUNDBIAS, uint16_t); +DECL_BITS(GBARegisterSOUNDBIAS, Bias, 0, 10); +DECL_BITS(GBARegisterSOUNDBIAS, Resolution, 14, 2); + +struct GBAAudioMixer; +struct GBAAudio { + struct GBA* p; + + struct GBAudio psg; + struct GBAAudioFIFO chA; + struct GBAAudioFIFO chB; + + int16_t lastLeft; + int16_t lastRight; + int clock; + + uint8_t volume; + bool volumeChA; + bool volumeChB; + bool chARight; + bool chALeft; + bool chATimer; + bool chBRight; + bool chBLeft; + bool chBTimer; + bool enable; + + size_t samples; + unsigned sampleRate; + + GBARegisterSOUNDBIAS soundbias; + + struct GBAAudioMixer* mixer; + bool externalMixing; + int32_t sampleInterval; + + bool forceDisableChA; + bool forceDisableChB; + int masterVolume; + + struct mTimingEvent sampleEvent; +}; + +struct GBAStereoSample { + int16_t left; + int16_t right; +}; + +struct GBAMP2kADSR { + uint8_t attack; + uint8_t decay; + uint8_t sustain; + uint8_t release; +}; + +struct GBAMP2kSoundChannel { + uint8_t status; + uint8_t type; + uint8_t rightVolume; + uint8_t leftVolume; + struct GBAMP2kADSR adsr; + uint8_t ky; + uint8_t envelopeV; + uint8_t envelopeRight; + uint8_t envelopeLeft; + uint8_t echoVolume; + uint8_t echoLength; + uint8_t d1; + uint8_t d2; + uint8_t gt; + uint8_t midiKey; + uint8_t ve; + uint8_t pr; + uint8_t rp; + uint8_t d3[3]; + uint32_t ct; + uint32_t fw; + uint32_t freq; + uint32_t waveData; + uint32_t cp; + uint32_t track; + uint32_t pp; + uint32_t np; + uint32_t d4; + uint16_t xpi; + uint16_t xpc; +}; + +struct GBAMP2kContext { + uint32_t magic; + uint8_t pcmDmaCounter; + uint8_t reverb; + uint8_t maxChans; + uint8_t masterVolume; + uint8_t freq; + uint8_t mode; + uint8_t c15; + uint8_t pcmDmaPeriod; + uint8_t maxLines; + uint8_t gap[3]; + int32_t pcmSamplesPerVBlank; + int32_t pcmFreq; + int32_t divFreq; + uint32_t cgbChans; + uint32_t func; + uint32_t intp; + uint32_t cgbSound; + uint32_t cgbOscOff; + uint32_t midiKeyToCgbFreq; + uint32_t mPlayJumpTable; + uint32_t plynote; + uint32_t extVolPit; + uint8_t gap2[16]; + struct GBAMP2kSoundChannel chans[MP2K_MAX_SOUND_CHANNELS]; +}; + +struct GBAMP2kMusicPlayerInfo { + uint32_t songHeader; + uint32_t status; + uint8_t trackCount; + uint8_t priority; + uint8_t cmd; + uint8_t unk_B; + uint32_t clock; + uint8_t gap[8]; + uint32_t memAccArea; + uint16_t tempoD; + uint16_t tempoU; + uint16_t tempoI; + uint16_t tempoC; + uint16_t fadeOI; + uint16_t fadeOC; + uint16_t fadeOV; + uint32_t tracks; + uint32_t tone; + uint32_t magic; + uint32_t func; + uint32_t intp; +}; + +struct GBAMP2kInstrument { + uint8_t type; + uint8_t key; + uint8_t length; + union { + uint8_t pan; + uint8_t sweep; + } ps; + union { + uint32_t waveData; + uint32_t subTable; + } data; + union { + struct GBAMP2kADSR adsr; + uint32_t map; + } extInfo; +}; + +struct GBAMP2kMusicPlayerTrack { + uint8_t flags; + uint8_t wait; + uint8_t patternLevel; + uint8_t repN; + uint8_t gateTime; + uint8_t key; + uint8_t velocity; + uint8_t runningStatus; + uint8_t keyM; + uint8_t pitM; + int8_t keyShift; + int8_t keyShiftX; + int8_t tune; + uint8_t pitX; + int8_t bend; + uint8_t bendRange; + uint8_t volMR; + uint8_t volML; + uint8_t vol; + uint8_t volX; + int8_t pan; + int8_t panX; + int8_t modM; + uint8_t mod; + uint8_t modT; + uint8_t lfoSpeed; + uint8_t lfoSpeedC; + uint8_t lfoDelay; + uint8_t lfoDelayC; + uint8_t priority; + uint8_t echoVolume; + uint8_t echoLength; + uint32_t chan; + struct GBAMP2kInstrument instrument; + uint8_t gap[10]; + uint16_t unk_3A; + uint32_t unk_3C; + uint32_t cmdPtr; + uint32_t patternStack[3]; +}; + +struct GBAMP2kTrack { + struct GBAMP2kMusicPlayerTrack track; + struct GBAMP2kSoundChannel* channel; + uint8_t lastCommand; + struct CircleBuffer buffer; + uint32_t samplePlaying; + float currentOffset; + bool waiting; +}; + +struct GBAAudioMixer { + struct mCPUComponent d; + struct GBAAudio* p; + + uint32_t contextAddress; + + bool (*engage)(struct GBAAudioMixer* mixer, uint32_t address); + void (*vblank)(struct GBAAudioMixer* mixer); + void (*step)(struct GBAAudioMixer* mixer); + + struct GBAMP2kContext context; + struct GBAMP2kMusicPlayerInfo player; + struct GBAMP2kTrack activeTracks[MP2K_MAX_SOUND_CHANNELS]; + + double tempo; + double frame; + + struct GBAStereoSample last; +}; + +void GBAAudioInit(struct GBAAudio* audio, size_t samples); +void GBAAudioReset(struct GBAAudio* audio); +void GBAAudioDeinit(struct GBAAudio* audio); + +void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples); + +void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info); + +void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value); +void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value); + +void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value); +uint32_t GBAAudioReadWaveRAM(struct GBAAudio* audio, int address); +uint32_t GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value); +void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles); + +struct GBASerializedState; +void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state); +void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state); + +float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRatio); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/bios.h b/mgba-test-runner/c/include/mgba/internal/gba/bios.h new file mode 100644 index 00000000..40bbf323 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/bios.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_BIOS_H +#define GBA_BIOS_H + +#include + +CXX_GUARD_START + +#include + +mLOG_DECLARE_CATEGORY(GBA_BIOS); + +enum GBASwi { + GBA_SWI_SOFT_RESET = 0x00, + GBA_SWI_REGISTER_RAM_RESET = 0x01, + GBA_SWI_HALT = 0x02, + GBA_SWI_STOP = 0x03, + GBA_SWI_INTR_WAIT = 0x04, + GBA_SWI_VBLANK_INTR_WAIT = 0x05, + GBA_SWI_DIV = 0x06, + GBA_SWI_DIV_ARM = 0x07, + GBA_SWI_SQRT = 0x08, + GBA_SWI_ARCTAN = 0x09, + GBA_SWI_ARCTAN2 = 0x0A, + GBA_SWI_CPU_SET = 0x0B, + GBA_SWI_CPU_FAST_SET = 0x0C, + GBA_SWI_GET_BIOS_CHECKSUM = 0x0D, + GBA_SWI_BG_AFFINE_SET = 0x0E, + GBA_SWI_OBJ_AFFINE_SET = 0x0F, + GBA_SWI_BIT_UNPACK = 0x10, + GBA_SWI_LZ77_UNCOMP_WRAM = 0x11, + GBA_SWI_LZ77_UNCOMP_VRAM = 0x12, + GBA_SWI_HUFFMAN_UNCOMP = 0x13, + GBA_SWI_RL_UNCOMP_WRAM = 0x14, + GBA_SWI_RL_UNCOMP_VRAM = 0x15, + GBA_SWI_DIFF_8BIT_UNFILTER_WRAM = 0x16, + GBA_SWI_DIFF_8BIT_UNFILTER_VRAM = 0x17, + GBA_SWI_DIFF_16BIT_UNFILTER = 0x18, + GBA_SWI_SOUND_BIAS = 0x19, + GBA_SWI_SOUND_DRIVER_INIT = 0x1A, + GBA_SWI_SOUND_DRIVER_MODE = 0x1B, + GBA_SWI_SOUND_DRIVER_MAIN = 0x1C, + GBA_SWI_SOUND_DRIVER_VSYNC = 0x1D, + GBA_SWI_SOUND_CHANNEL_CLEAR = 0x1E, + GBA_SWI_MIDI_KEY_2_FREQ = 0x1F, + GBA_SWI_MUSIC_PLAYER_OPEN = 0x20, + GBA_SWI_MUSIC_PLAYER_START = 0x21, + GBA_SWI_MUSIC_PLAYER_STOP = 0x22, + GBA_SWI_MUSIC_PLAYER_CONTINUE = 0x23, + GBA_SWI_MUSIC_PLAYER_FADE_OUT = 0x24, + GBA_SWI_MULTI_BOOT = 0x25, + GBA_SWI_HARD_RESET = 0x26, + GBA_SWI_CUSTOM_HALT = 0x27, + GBA_SWI_SOUND_DRIVER_VSYNC_OFF = 0x28, + GBA_SWI_SOUND_DRIVER_VSYNC_ON = 0x29, + GBA_SWI_SOUND_DRIVER_GET_JUMP_LIST = 0x2A, +}; + +struct ARMCore; +void GBASwi16(struct ARMCore* cpu, int immediate); +void GBASwi32(struct ARMCore* cpu, int immediate); + +uint32_t GBAChecksum(uint32_t* memory, size_t size); +extern const uint32_t GBA_BIOS_CHECKSUM; +extern const uint32_t GBA_DS_BIOS_CHECKSUM; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/cheats.h b/mgba-test-runner/c/include/mgba/internal/gba/cheats.h new file mode 100644 index 00000000..69e58954 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/cheats.h @@ -0,0 +1,175 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_CHEATS_H +#define GBA_CHEATS_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +#define COMPLETE ((size_t) -1) + +enum GBACheatType { + GBA_CHEAT_AUTODETECT, + GBA_CHEAT_CODEBREAKER, + GBA_CHEAT_GAMESHARK, + GBA_CHEAT_PRO_ACTION_REPLAY, + GBA_CHEAT_VBA +}; + +enum GBACodeBreakerType { + CB_GAME_ID = 0x0, + CB_HOOK = 0x1, + CB_OR_2 = 0x2, + CB_ASSIGN_1 = 0x3, + CB_FILL = 0x4, + CB_FILL_8 = 0x5, + CB_AND_2 = 0x6, + CB_IF_EQ = 0x7, + CB_ASSIGN_2 = 0x8, + CB_ENCRYPT = 0x9, + CB_IF_NE = 0xA, + CB_IF_GT = 0xB, + CB_IF_LT = 0xC, + CB_IF_SPECIAL = 0xD, + CB_ADD_2 = 0xE, + CB_IF_AND = 0xF, +}; + +enum GBAGameSharkType { + GSA_ASSIGN_1 = 0x0, + GSA_ASSIGN_2 = 0x1, + GSA_ASSIGN_4 = 0x2, + GSA_ASSIGN_LIST = 0x3, + GSA_PATCH = 0x6, + GSA_BUTTON = 0x8, + GSA_IF_EQ = 0xD, + GSA_IF_EQ_RANGE = 0xE, + GSA_HOOK = 0xF +}; + +enum GBAActionReplay3Condition { + PAR3_COND_OTHER = 0x00000000, + PAR3_COND_EQ = 0x08000000, + PAR3_COND_NE = 0x10000000, + PAR3_COND_LT = 0x18000000, + PAR3_COND_GT = 0x20000000, + PAR3_COND_ULT = 0x28000000, + PAR3_COND_UGT = 0x30000000, + PAR3_COND_AND = 0x38000000, +}; + +enum GBAActionReplay3Width { + PAR3_WIDTH_1 = 0x00000000, + PAR3_WIDTH_2 = 0x02000000, + PAR3_WIDTH_4 = 0x04000000, + PAR3_WIDTH_FALSE = 0x06000000, +}; + +enum GBAActionReplay3Action { + PAR3_ACTION_NEXT = 0x00000000, + PAR3_ACTION_NEXT_TWO = 0x40000000, + PAR3_ACTION_BLOCK = 0x80000000, + PAR3_ACTION_DISABLE = 0xC0000000, +}; + +enum GBAActionReplay3Base { + PAR3_BASE_ASSIGN = 0x00000000, + PAR3_BASE_INDIRECT = 0x40000000, + PAR3_BASE_ADD = 0x80000000, + PAR3_BASE_OTHER = 0xC0000000, + + PAR3_BASE_ASSIGN_1 = 0x00000000, + PAR3_BASE_ASSIGN_2 = 0x02000000, + PAR3_BASE_ASSIGN_4 = 0x04000000, + PAR3_BASE_INDIRECT_1 = 0x40000000, + PAR3_BASE_INDIRECT_2 = 0x42000000, + PAR3_BASE_INDIRECT_4 = 0x44000000, + PAR3_BASE_ADD_1 = 0x80000000, + PAR3_BASE_ADD_2 = 0x82000000, + PAR3_BASE_ADD_4 = 0x84000000, + PAR3_BASE_HOOK = 0xC4000000, + PAR3_BASE_IO_2 = 0xC6000000, + PAR3_BASE_IO_3 = 0xC7000000, +}; + +enum GBAActionReplay3Other { + PAR3_OTHER_END = 0x00000000, + PAR3_OTHER_SLOWDOWN = 0x08000000, + PAR3_OTHER_BUTTON_1 = 0x10000000, + PAR3_OTHER_BUTTON_2 = 0x12000000, + PAR3_OTHER_BUTTON_4 = 0x14000000, + PAR3_OTHER_PATCH_1 = 0x18000000, + PAR3_OTHER_PATCH_2 = 0x1A000000, + PAR3_OTHER_PATCH_3 = 0x1C000000, + PAR3_OTHER_PATCH_4 = 0x1E000000, + PAR3_OTHER_ENDIF = 0x40000000, + PAR3_OTHER_ELSE = 0x60000000, + PAR3_OTHER_FILL_1 = 0x80000000, + PAR3_OTHER_FILL_2 = 0x82000000, + PAR3_OTHER_FILL_4 = 0x84000000, +}; + +enum { + PAR3_COND = 0x38000000, + PAR3_WIDTH = 0x06000000, + PAR3_ACTION = 0xC0000000, + PAR3_BASE = 0xC0000000, + + PAR3_WIDTH_BASE = 25 +}; + +struct GBACheatHook { + uint32_t address; + enum ExecutionMode mode; + uint32_t patchedOpcode; + size_t refs; + size_t reentries; +}; + +DECLARE_VECTOR(GBACheatPatchList, struct GBACheatPatch); + +struct GBACheatSet { + struct mCheatSet d; + struct GBACheatHook* hook; + + size_t incompleteCheat; + struct mCheatPatch* incompletePatch; + size_t currentBlock; + + int gsaVersion; + uint32_t gsaSeeds[4]; + uint32_t cbRngState; + uint32_t cbMaster; + uint8_t cbTable[0x30]; + uint32_t cbSeeds[4]; + int remainingAddresses; +}; + +struct VFile; + +struct mCheatDevice* GBACheatDeviceCreate(void); + +bool GBACheatAddCodeBreaker(struct GBACheatSet*, uint32_t op1, uint16_t op2); +bool GBACheatAddCodeBreakerLine(struct GBACheatSet*, const char* line); + +bool GBACheatAddGameShark(struct GBACheatSet*, uint32_t op1, uint32_t op2); +bool GBACheatAddGameSharkLine(struct GBACheatSet*, const char* line); + +bool GBACheatAddProActionReplay(struct GBACheatSet*, uint32_t op1, uint32_t op2); +bool GBACheatAddProActionReplayLine(struct GBACheatSet*, const char* line); + +bool GBACheatAddVBALine(struct GBACheatSet*, const char* line); + +int GBACheatAddressIsReal(uint32_t address); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/dma.h b/mgba-test-runner/c/include/mgba/internal/gba/dma.h new file mode 100644 index 00000000..6f880c97 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/dma.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_DMA_H +#define GBA_DMA_H + +#include + +CXX_GUARD_START + +enum GBADMAControl { + GBA_DMA_INCREMENT = 0, + GBA_DMA_DECREMENT = 1, + GBA_DMA_FIXED = 2, + GBA_DMA_INCREMENT_RELOAD = 3 +}; + +enum GBADMATiming { + GBA_DMA_TIMING_NOW = 0, + GBA_DMA_TIMING_VBLANK = 1, + GBA_DMA_TIMING_HBLANK = 2, + GBA_DMA_TIMING_CUSTOM = 3 +}; + +DECL_BITFIELD(GBADMARegister, uint16_t); +DECL_BITS(GBADMARegister, DestControl, 5, 2); +DECL_BITS(GBADMARegister, SrcControl, 7, 2); +DECL_BIT(GBADMARegister, Repeat, 9); +DECL_BIT(GBADMARegister, Width, 10); +DECL_BIT(GBADMARegister, DRQ, 11); +DECL_BITS(GBADMARegister, Timing, 12, 2); +DECL_BIT(GBADMARegister, DoIRQ, 14); +DECL_BIT(GBADMARegister, Enable, 15); + +struct GBADMA { + GBADMARegister reg; + + uint32_t source; + uint32_t dest; + int32_t count; + uint32_t nextSource; + uint32_t nextDest; + int32_t nextCount; + uint32_t when; +}; + +struct GBA; +void GBADMAInit(struct GBA* gba); +void GBADMAReset(struct GBA* gba); + +uint32_t GBADMAWriteSAD(struct GBA* gba, int dma, uint32_t address); +uint32_t GBADMAWriteDAD(struct GBA* gba, int dma, uint32_t address); +void GBADMAWriteCNT_LO(struct GBA* gba, int dma, uint16_t count); +uint16_t GBADMAWriteCNT_HI(struct GBA* gba, int dma, uint16_t control); + +struct GBADMA; +void GBADMASchedule(struct GBA* gba, int number, struct GBADMA* info); +void GBADMARunHblank(struct GBA* gba, int32_t cycles); +void GBADMARunVblank(struct GBA* gba, int32_t cycles); +void GBADMARunDisplayStart(struct GBA* gba, int32_t cycles); +void GBADMAUpdate(struct GBA* gba); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/extra/audio-mixer.h b/mgba-test-runner/c/include/mgba/internal/gba/extra/audio-mixer.h new file mode 100644 index 00000000..369a4aaa --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/extra/audio-mixer.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_AUDIO_MIXER_H +#define GBA_AUDIO_MIXER_H + +#include + +CXX_GUARD_START + +#include + +void GBAAudioMixerCreate(struct GBAAudioMixer* mixer); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/extra/cli.h b/mgba-test-runner/c/include/mgba/internal/gba/extra/cli.h new file mode 100644 index 00000000..2b2d407f --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/extra/cli.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_CLI_H +#define GBA_CLI_H + +#include + +CXX_GUARD_START + +#include + +struct mCore; + +struct GBACLIDebugger { + struct CLIDebuggerSystem d; + + struct mCore* core; + + bool frameAdvance; + bool inVblank; +}; + +struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/gba.h b/mgba-test-runner/c/include/mgba/internal/gba/gba.h new file mode 100644 index 00000000..6e8fe499 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/gba.h @@ -0,0 +1,185 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_H +#define GBA_H + +#include + +CXX_GUARD_START + +#include +#include + +#include +#include +#include +#include +#include + +#define GBA_ARM7TDMI_FREQUENCY 0x1000000U + +enum GBAIRQ { + IRQ_VBLANK = 0x0, + IRQ_HBLANK = 0x1, + IRQ_VCOUNTER = 0x2, + IRQ_TIMER0 = 0x3, + IRQ_TIMER1 = 0x4, + IRQ_TIMER2 = 0x5, + IRQ_TIMER3 = 0x6, + IRQ_SIO = 0x7, + IRQ_DMA0 = 0x8, + IRQ_DMA1 = 0x9, + IRQ_DMA2 = 0xA, + IRQ_DMA3 = 0xB, + IRQ_KEYPAD = 0xC, + IRQ_GAMEPAK = 0xD +}; + +enum GBAIdleLoopOptimization { + IDLE_LOOP_IGNORE = -1, + IDLE_LOOP_REMOVE = 0, + IDLE_LOOP_DETECT +}; + +enum { + SP_BASE_SYSTEM = 0x03007F00, + SP_BASE_IRQ = 0x03007FA0, + SP_BASE_SUPERVISOR = 0x03007FE0 +}; + +struct ARMCore; +struct GBA; +struct Patch; +struct VFile; + +mLOG_DECLARE_CATEGORY(GBA); +mLOG_DECLARE_CATEGORY(GBA_DEBUG); + +DECL_BITFIELD(GBADebugFlags, uint16_t); +DECL_BITS(GBADebugFlags, Level, 0, 3); +DECL_BIT(GBADebugFlags, Send, 8); + +struct GBA { + struct mCPUComponent d; + + struct ARMCore* cpu; + struct GBAMemory memory; + struct GBAVideo video; + struct GBAAudio audio; + struct GBASIO sio; + + struct mCoreSync* sync; + struct mTiming timing; + + struct ARMDebugger* debugger; + + uint32_t bus; + int performingDMA; + + struct GBATimer timers[4]; + + int springIRQ; + struct mTimingEvent irqEvent; + + uint32_t biosChecksum; + int* keySource; + struct mRotationSource* rotationSource; + struct GBALuminanceSource* luminanceSource; + struct mRTCSource* rtcSource; + struct mRumble* rumble; + + bool isPristine; + size_t pristineRomSize; + size_t yankedRomSize; + uint32_t romCrc32; + struct VFile* romVf; + struct VFile* biosVf; + + struct mAVStream* stream; + struct mKeyCallback* keyCallback; + struct mCoreCallbacksList coreCallbacks; + + enum GBAIdleLoopOptimization idleOptimization; + uint32_t idleLoop; + uint32_t lastJump; + bool haltPending; + bool cpuBlocked; + bool earlyExit; + uint32_t dmaPC; + uint32_t biosStall; + + int idleDetectionStep; + int idleDetectionFailures; + int32_t cachedRegisters[16]; + bool taintedRegisters[16]; + + bool vbaBugCompat; + bool hardCrash; + bool allowOpposingDirections; + + bool debug; + char debugString[0x100]; + GBADebugFlags debugFlags; +}; + +struct GBACartridge { + uint32_t entry; + uint8_t logo[156]; + char title[12]; + uint32_t id; + uint16_t maker; + uint8_t type; + uint8_t unit; + uint8_t device; + uint8_t reserved[7]; + uint8_t version; + uint8_t checksum; + // And ROM data... +}; + +void GBACreate(struct GBA* gba); +void GBADestroy(struct GBA* gba); + +void GBAReset(struct ARMCore* cpu); +void GBASkipBIOS(struct GBA* gba); + +void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq, uint32_t cyclesLate); +void GBATestIRQ(struct GBA* gba, uint32_t cyclesLate); +void GBAHalt(struct GBA* gba); +void GBAStop(struct GBA* gba); +void GBADebug(struct GBA* gba, uint16_t value); + +#ifdef USE_DEBUGGERS +struct mDebugger; +void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger); +void GBADetachDebugger(struct GBA* gba); +#endif + +void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, + uint32_t* opcode); +void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode); + +bool GBALoadROM(struct GBA* gba, struct VFile* vf); +bool GBALoadSave(struct GBA* gba, struct VFile* sav); +void GBAYankROM(struct GBA* gba); +void GBAUnloadROM(struct GBA* gba); +void GBALoadBIOS(struct GBA* gba, struct VFile* vf); +void GBAApplyPatch(struct GBA* gba, struct Patch* patch); + +bool GBALoadMB(struct GBA* gba, struct VFile* vf); +bool GBALoadNull(struct GBA* gba); + +void GBAGetGameCode(const struct GBA* gba, char* out); +void GBAGetGameTitle(const struct GBA* gba, char* out); + +void GBATestKeypadIRQ(struct GBA* gba); + +void GBAFrameStarted(struct GBA* gba); +void GBAFrameEnded(struct GBA* gba); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/hardware.h b/mgba-test-runner/c/include/mgba/internal/gba/hardware.h new file mode 100644 index 00000000..88ae5c29 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/hardware.h @@ -0,0 +1,215 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_HARDWARE_H +#define GBA_HARDWARE_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +mLOG_DECLARE_CATEGORY(GBA_HW); + +#define EREADER_DOTCODE_STRIDE 1420 +#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40) +#define EREADER_CARDS_MAX 16 + +#define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL) + +struct GBARTCGenericSource { + struct mRTCSource d; + struct GBA* p; + enum mRTCGenericType override; + int64_t value; +}; + +enum GBAHardwareDevice { + HW_NO_OVERRIDE = 0x8000, + HW_NONE = 0, + HW_RTC = 1, + HW_RUMBLE = 2, + HW_LIGHT_SENSOR = 4, + HW_GYRO = 8, + HW_TILT = 16, + HW_GB_PLAYER = 32, + HW_GB_PLAYER_DETECTION = 64, + HW_EREADER = 128 +}; + +enum GPIORegister { + GPIO_REG_DATA = 0xC4, + GPIO_REG_DIRECTION = 0xC6, + GPIO_REG_CONTROL = 0xC8 +}; + +enum GPIODirection { + GPIO_WRITE_ONLY = 0, + GPIO_READ_WRITE = 1 +}; + +DECL_BITFIELD(RTCControl, uint32_t); +DECL_BIT(RTCControl, MinIRQ, 3); +DECL_BIT(RTCControl, Hour24, 6); +DECL_BIT(RTCControl, Poweroff, 7); + +enum RTCCommand { + RTC_RESET = 0, + RTC_DATETIME = 2, + RTC_FORCE_IRQ = 3, + RTC_CONTROL = 4, + RTC_TIME = 6 +}; + +DECL_BITFIELD(RTCCommandData, uint32_t); +DECL_BITS(RTCCommandData, Magic, 0, 4); +DECL_BITS(RTCCommandData, Command, 4, 3); +DECL_BIT(RTCCommandData, Reading, 7); + +struct GBARTC { + int32_t bytesRemaining; + int32_t transferStep; + int32_t bitsRead; + int32_t bits; + int32_t commandActive; + RTCCommandData command; + RTCControl control; + uint8_t time[7]; +}; + +struct GBAGBPKeyCallback { + struct mKeyCallback d; + struct GBACartridgeHardware* p; +}; + +struct GBAGBPSIODriver { + struct GBASIODriver d; + struct GBACartridgeHardware* p; +}; + +DECL_BITFIELD(GPIOPin, uint16_t); + +DECL_BITFIELD(EReaderControl0, uint8_t); +DECL_BIT(EReaderControl0, Data, 0); +DECL_BIT(EReaderControl0, Clock, 1); +DECL_BIT(EReaderControl0, Direction, 2); +DECL_BIT(EReaderControl0, LedEnable, 3); +DECL_BIT(EReaderControl0, Scan, 4); +DECL_BIT(EReaderControl0, Phi, 5); +DECL_BIT(EReaderControl0, PowerEnable, 6); +DECL_BITFIELD(EReaderControl1, uint8_t); +DECL_BIT(EReaderControl1, Scanline, 1); +DECL_BIT(EReaderControl1, Unk1, 4); +DECL_BIT(EReaderControl1, Voltage, 5); + +enum EReaderStateMachine { + EREADER_SERIAL_INACTIVE = 0, + EREADER_SERIAL_STARTING, + EREADER_SERIAL_BIT_0, + EREADER_SERIAL_BIT_1, + EREADER_SERIAL_BIT_2, + EREADER_SERIAL_BIT_3, + EREADER_SERIAL_BIT_4, + EREADER_SERIAL_BIT_5, + EREADER_SERIAL_BIT_6, + EREADER_SERIAL_BIT_7, + EREADER_SERIAL_END_BIT, +}; + +enum EReaderCommand { + EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware + EREADER_COMMAND_WRITE_DATA = 1, + EREADER_COMMAND_SET_INDEX = 0x22, + EREADER_COMMAND_READ_DATA = 0x23, +}; + +struct EReaderCard { + void* data; + size_t size; +}; + +struct GBACartridgeHardware { + struct GBA* p; + uint32_t devices; + enum GPIODirection readWrite; + uint16_t* gpioBase; + + uint16_t pinState; + uint16_t direction; + + struct GBARTC rtc; + + uint16_t gyroSample; + bool gyroEdge; + + unsigned lightCounter : 12; + uint8_t lightSample; + bool lightEdge; + + uint16_t tiltX; + uint16_t tiltY; + int tiltState; + + unsigned gbpInputsPosted; + int gbpTxPosition; + struct mTimingEvent gbpNextEvent; + struct GBAGBPKeyCallback gbpCallback; + struct GBAGBPSIODriver gbpDriver; + + uint16_t eReaderData[44]; + uint8_t eReaderSerial[92]; + uint16_t eReaderRegisterUnk; + uint16_t eReaderRegisterReset; + EReaderControl0 eReaderRegisterControl0; + EReaderControl1 eReaderRegisterControl1; + uint16_t eReaderRegisterLed; + + // TODO: Serialize these + enum EReaderStateMachine eReaderState; + enum EReaderCommand eReaderCommand; + uint8_t eReaderActiveRegister; + uint8_t eReaderByte; + int eReaderX; + int eReaderY; + uint8_t* eReaderDots; + struct EReaderCard eReaderCards[EREADER_CARDS_MAX]; +}; + +void GBAHardwareInit(struct GBACartridgeHardware* gpio, uint16_t* gpioBase); +void GBAHardwareClear(struct GBACartridgeHardware* gpio); + +void GBAHardwareInitRTC(struct GBACartridgeHardware* gpio); +void GBAHardwareInitGyro(struct GBACartridgeHardware* gpio); +void GBAHardwareInitRumble(struct GBACartridgeHardware* gpio); +void GBAHardwareInitLight(struct GBACartridgeHardware* gpio); +void GBAHardwareInitTilt(struct GBACartridgeHardware* gpio); + +void GBAHardwareGPIOWrite(struct GBACartridgeHardware* gpio, uint32_t address, uint16_t value); +void GBAHardwareTiltWrite(struct GBACartridgeHardware* gpio, uint32_t address, uint8_t value); +uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* gpio, uint32_t address); + +struct GBAVideo; +void GBAHardwarePlayerUpdate(struct GBA* gba); +bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video); + +void GBAHardwareInitEReader(struct GBACartridgeHardware* hw); +void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value); +void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value); +uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address); +uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address); +void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size); + +void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba); + +struct GBASerializedState; +void GBAHardwareSerialize(const struct GBACartridgeHardware* gpio, struct GBASerializedState* state); +void GBAHardwareDeserialize(struct GBACartridgeHardware* gpio, const struct GBASerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/input.h b/mgba-test-runner/c/include/mgba/internal/gba/input.h new file mode 100644 index 00000000..cdfde6e1 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/input.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_INPUT_H +#define GBA_INPUT_H + +#include + +CXX_GUARD_START + +#include + +extern MGBA_EXPORT const struct mInputPlatformInfo GBAInputInfo; + +enum GBAKey { + GBA_KEY_A = 0, + GBA_KEY_B = 1, + GBA_KEY_SELECT = 2, + GBA_KEY_START = 3, + GBA_KEY_RIGHT = 4, + GBA_KEY_LEFT = 5, + GBA_KEY_UP = 6, + GBA_KEY_DOWN = 7, + GBA_KEY_R = 8, + GBA_KEY_L = 9, + GBA_KEY_MAX, + GBA_KEY_NONE = -1 +}; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/io.h b/mgba-test-runner/c/include/mgba/internal/gba/io.h new file mode 100644 index 00000000..9875061f --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/io.h @@ -0,0 +1,181 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_IO_H +#define GBA_IO_H + +#include + +CXX_GUARD_START + +#include + +enum GBAIORegisters { + // Video + REG_DISPCNT = 0x000, + REG_GREENSWP = 0x002, + REG_DISPSTAT = 0x004, + REG_VCOUNT = 0x006, + REG_BG0CNT = 0x008, + REG_BG1CNT = 0x00A, + REG_BG2CNT = 0x00C, + REG_BG3CNT = 0x00E, + REG_BG0HOFS = 0x010, + REG_BG0VOFS = 0x012, + REG_BG1HOFS = 0x014, + REG_BG1VOFS = 0x016, + REG_BG2HOFS = 0x018, + REG_BG2VOFS = 0x01A, + REG_BG3HOFS = 0x01C, + REG_BG3VOFS = 0x01E, + REG_BG2PA = 0x020, + REG_BG2PB = 0x022, + REG_BG2PC = 0x024, + REG_BG2PD = 0x026, + REG_BG2X_LO = 0x028, + REG_BG2X_HI = 0x02A, + REG_BG2Y_LO = 0x02C, + REG_BG2Y_HI = 0x02E, + REG_BG3PA = 0x030, + REG_BG3PB = 0x032, + REG_BG3PC = 0x034, + REG_BG3PD = 0x036, + REG_BG3X_LO = 0x038, + REG_BG3X_HI = 0x03A, + REG_BG3Y_LO = 0x03C, + REG_BG3Y_HI = 0x03E, + REG_WIN0H = 0x040, + REG_WIN1H = 0x042, + REG_WIN0V = 0x044, + REG_WIN1V = 0x046, + REG_WININ = 0x048, + REG_WINOUT = 0x04A, + REG_MOSAIC = 0x04C, + REG_BLDCNT = 0x050, + REG_BLDALPHA = 0x052, + REG_BLDY = 0x054, + + // Sound + REG_SOUND1CNT_LO = 0x060, + REG_SOUND1CNT_HI = 0x062, + REG_SOUND1CNT_X = 0x064, + REG_SOUND2CNT_LO = 0x068, + REG_SOUND2CNT_HI = 0x06C, + REG_SOUND3CNT_LO = 0x070, + REG_SOUND3CNT_HI = 0x072, + REG_SOUND3CNT_X = 0x074, + REG_SOUND4CNT_LO = 0x078, + REG_SOUND4CNT_HI = 0x07C, + REG_SOUNDCNT_LO = 0x080, + REG_SOUNDCNT_HI = 0x082, + REG_SOUNDCNT_X = 0x084, + REG_SOUNDBIAS = 0x088, + REG_WAVE_RAM0_LO = 0x090, + REG_WAVE_RAM0_HI = 0x092, + REG_WAVE_RAM1_LO = 0x094, + REG_WAVE_RAM1_HI = 0x096, + REG_WAVE_RAM2_LO = 0x098, + REG_WAVE_RAM2_HI = 0x09A, + REG_WAVE_RAM3_LO = 0x09C, + REG_WAVE_RAM3_HI = 0x09E, + REG_FIFO_A_LO = 0x0A0, + REG_FIFO_A_HI = 0x0A2, + REG_FIFO_B_LO = 0x0A4, + REG_FIFO_B_HI = 0x0A6, + + // DMA + REG_DMA0SAD_LO = 0x0B0, + REG_DMA0SAD_HI = 0x0B2, + REG_DMA0DAD_LO = 0x0B4, + REG_DMA0DAD_HI = 0x0B6, + REG_DMA0CNT_LO = 0x0B8, + REG_DMA0CNT_HI = 0x0BA, + REG_DMA1SAD_LO = 0x0BC, + REG_DMA1SAD_HI = 0x0BE, + REG_DMA1DAD_LO = 0x0C0, + REG_DMA1DAD_HI = 0x0C2, + REG_DMA1CNT_LO = 0x0C4, + REG_DMA1CNT_HI = 0x0C6, + REG_DMA2SAD_LO = 0x0C8, + REG_DMA2SAD_HI = 0x0CA, + REG_DMA2DAD_LO = 0x0CC, + REG_DMA2DAD_HI = 0x0CE, + REG_DMA2CNT_LO = 0x0D0, + REG_DMA2CNT_HI = 0x0D2, + REG_DMA3SAD_LO = 0x0D4, + REG_DMA3SAD_HI = 0x0D6, + REG_DMA3DAD_LO = 0x0D8, + REG_DMA3DAD_HI = 0x0DA, + REG_DMA3CNT_LO = 0x0DC, + REG_DMA3CNT_HI = 0x0DE, + + // Timers + REG_TM0CNT_LO = 0x100, + REG_TM0CNT_HI = 0x102, + REG_TM1CNT_LO = 0x104, + REG_TM1CNT_HI = 0x106, + REG_TM2CNT_LO = 0x108, + REG_TM2CNT_HI = 0x10A, + REG_TM3CNT_LO = 0x10C, + REG_TM3CNT_HI = 0x10E, + + // SIO (note: some of these are repeated) + REG_SIODATA32_LO = 0x120, + REG_SIOMULTI0 = 0x120, + REG_SIODATA32_HI = 0x122, + REG_SIOMULTI1 = 0x122, + REG_SIOMULTI2 = 0x124, + REG_SIOMULTI3 = 0x126, + REG_SIOCNT = 0x128, + REG_SIOMLT_SEND = 0x12A, + REG_SIODATA8 = 0x12A, + REG_RCNT = 0x134, + REG_JOYCNT = 0x140, + REG_JOY_RECV_LO = 0x150, + REG_JOY_RECV_HI = 0x152, + REG_JOY_TRANS_LO = 0x154, + REG_JOY_TRANS_HI = 0x156, + REG_JOYSTAT = 0x158, + + // Keypad + REG_KEYINPUT = 0x130, + REG_KEYCNT = 0x132, + + // Interrupts, etc + REG_IE = 0x200, + REG_IF = 0x202, + REG_WAITCNT = 0x204, + REG_IME = 0x208, + + REG_MAX = 0x20A, + + REG_POSTFLG = 0x300, + REG_HALTCNT = 0x301, + + REG_DEBUG_STRING = 0xFFF600, + REG_DEBUG_FLAGS = 0xFFF700, + REG_DEBUG_ENABLE = 0xFFF780, +}; + +mLOG_DECLARE_CATEGORY(GBA_IO); + +extern MGBA_EXPORT const char* const GBAIORegisterNames[]; + +struct GBA; +void GBAIOInit(struct GBA* gba); +void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value); +void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value); +void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value); +uint16_t GBAIORead(struct GBA* gba, uint32_t address); + +bool GBAIOIsReadConstant(uint32_t address); + +struct GBASerializedState; +void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state); +void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/matrix.h b/mgba-test-runner/c/include/mgba/internal/gba/matrix.h new file mode 100644 index 00000000..27e32a75 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/matrix.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2013-2018 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_MATRIX_H +#define GBA_MATRIX_H + +#include + +CXX_GUARD_START + +#define GBA_MATRIX_MAPPINGS_MAX 16 + +struct GBAMatrix { + uint32_t cmd; + uint32_t paddr; + uint32_t vaddr; + uint32_t size; + + uint32_t mappings[GBA_MATRIX_MAPPINGS_MAX]; +}; + +struct GBA; +void GBAMatrixReset(struct GBA*); +void GBAMatrixWrite(struct GBA*, uint32_t address, uint32_t value); +void GBAMatrixWrite16(struct GBA*, uint32_t address, uint16_t value); + +struct GBASerializedState; +void GBAMatrixSerialize(const struct GBA* memory, struct GBASerializedState* state); +void GBAMatrixDeserialize(struct GBA* memory, const struct GBASerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/memory.h b/mgba-test-runner/c/include/mgba/internal/gba/memory.h new file mode 100644 index 00000000..caf1d689 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/memory.h @@ -0,0 +1,181 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_MEMORY_H +#define GBA_MEMORY_H + +#include + +CXX_GUARD_START + +#include + +#include +#include +#include +#include +#include +#include + +enum GBAMemoryRegion { + REGION_BIOS = 0x0, + REGION_WORKING_RAM = 0x2, + REGION_WORKING_IRAM = 0x3, + REGION_IO = 0x4, + REGION_PALETTE_RAM = 0x5, + REGION_VRAM = 0x6, + REGION_OAM = 0x7, + REGION_CART0 = 0x8, + REGION_CART0_EX = 0x9, + REGION_CART1 = 0xA, + REGION_CART1_EX = 0xB, + REGION_CART2 = 0xC, + REGION_CART2_EX = 0xD, + REGION_CART_SRAM = 0xE, + REGION_CART_SRAM_MIRROR = 0xF +}; + +enum GBAMemoryBase { + BASE_BIOS = 0x00000000, + BASE_WORKING_RAM = 0x02000000, + BASE_WORKING_IRAM = 0x03000000, + BASE_IO = 0x04000000, + BASE_PALETTE_RAM = 0x05000000, + BASE_VRAM = 0x06000000, + BASE_OAM = 0x07000000, + BASE_CART0 = 0x08000000, + BASE_CART0_EX = 0x09000000, + BASE_CART1 = 0x0A000000, + BASE_CART1_EX = 0x0B000000, + BASE_CART2 = 0x0C000000, + BASE_CART2_EX = 0x0D000000, + BASE_CART_SRAM = 0x0E000000, + BASE_CART_SRAM_MIRROR = 0x0F000000 +}; + +enum { + SIZE_BIOS = 0x00004000, + SIZE_WORKING_RAM = 0x00040000, + SIZE_WORKING_IRAM = 0x00008000, + SIZE_IO = 0x00000400, + SIZE_PALETTE_RAM = 0x00000400, + SIZE_VRAM = 0x00018000, + SIZE_OAM = 0x00000400, + SIZE_CART0 = 0x02000000, + SIZE_CART1 = 0x02000000, + SIZE_CART2 = 0x02000000, + SIZE_CART_SRAM = 0x00008000, + SIZE_CART_FLASH512 = 0x00010000, + SIZE_CART_FLASH1M = 0x00020000, + SIZE_CART_EEPROM = 0x00002000, + SIZE_CART_EEPROM512 = 0x00000200, + + SIZE_AGB_PRINT = 0x10000 +}; + +enum { + OFFSET_MASK = 0x00FFFFFF, + BASE_OFFSET = 24 +}; + +enum { + AGB_PRINT_BASE = 0x00FD0000, + AGB_PRINT_TOP = 0x00FE0000, + AGB_PRINT_PROTECT = 0x00FE2FFE, + AGB_PRINT_STRUCT = 0x00FE20F8, + AGB_PRINT_FLUSH_ADDR = 0x00FE209C, +}; + +mLOG_DECLARE_CATEGORY(GBA_MEM); + +struct GBAPrintContext { + uint16_t request; + uint16_t bank; + uint16_t get; + uint16_t put; +}; + +struct GBAMemory { + uint32_t* bios; + uint32_t* wram; + uint32_t* iwram; + uint32_t* rom; + uint16_t io[512]; + + struct GBACartridgeHardware hw; + struct GBASavedata savedata; + struct GBAVFameCart vfame; + struct GBAMatrix matrix; + size_t romSize; + uint32_t romMask; + uint16_t romID; + int fullBios; + + char waitstatesSeq32[256]; + char waitstatesSeq16[256]; + char waitstatesNonseq32[256]; + char waitstatesNonseq16[256]; + int activeRegion; + bool prefetch; + uint32_t lastPrefetchedPc; + uint32_t biosPrefetch; + + struct GBADMA dma[4]; + struct mTimingEvent dmaEvent; + int activeDMA; + uint32_t dmaTransferRegister; + + uint32_t agbPrintBase; + uint16_t agbPrintProtect; + struct GBAPrintContext agbPrintCtx; + uint16_t* agbPrintBuffer; + uint16_t agbPrintProtectBackup; + struct GBAPrintContext agbPrintCtxBackup; + uint32_t agbPrintFuncBackup; + uint16_t* agbPrintBufferBackup; + + bool mirroring; +}; + +struct GBA; +void GBAMemoryInit(struct GBA* gba); +void GBAMemoryDeinit(struct GBA* gba); + +void GBAMemoryReset(struct GBA* gba); + +uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter); +uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter); +uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter); + +uint32_t GBALoadBad(struct ARMCore* cpu); + +void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter); +void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter); +void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter); + +uint32_t GBAView32(struct ARMCore* cpu, uint32_t address); +uint16_t GBAView16(struct ARMCore* cpu, uint32_t address); +uint8_t GBAView8(struct ARMCore* cpu, uint32_t address); + +void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old); +void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* old); +void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old); + +uint32_t GBALoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, + int* cycleCounter); +uint32_t GBAStoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, + int* cycleCounter); + +void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters); + +struct GBASerializedState; +void GBAMemorySerialize(const struct GBAMemory* memory, struct GBASerializedState* state); +void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedState* state); + +void GBAPrintFlush(struct GBA* gba); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/overrides.h b/mgba-test-runner/c/include/mgba/internal/gba/overrides.h new file mode 100644 index 00000000..c835a62a --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/overrides.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_OVERRIDES_H +#define GBA_OVERRIDES_H + +#include + +CXX_GUARD_START + +#include + +#define IDLE_LOOP_NONE 0xFFFFFFFF + +struct GBACartridgeOverride { + char id[4]; + enum SavedataType savetype; + int hardware; + uint32_t idleLoop; + bool mirroring; + bool vbaBugCompat; +}; + +struct Configuration; +bool GBAOverrideFind(const struct Configuration*, struct GBACartridgeOverride* override); +void GBAOverrideSave(struct Configuration*, const struct GBACartridgeOverride* override); + +struct GBA; +void GBAOverrideApply(struct GBA*, const struct GBACartridgeOverride*); +void GBAOverrideApplyDefaults(struct GBA*, const struct Configuration*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/renderers/cache-set.h b/mgba-test-runner/c/include/mgba/internal/gba/renderers/cache-set.h new file mode 100644 index 00000000..3ad4f619 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/renderers/cache-set.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_CACHE_SET_H +#define GBA_CACHE_SET_H + +#include + +CXX_GUARD_START + +struct GBAVideo; +struct mCacheSet; + +void GBAVideoCacheInit(struct mCacheSet* cache); +void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video); +void GBAVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint32_t address, uint16_t value); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/renderers/common.h b/mgba-test-runner/c/include/mgba/internal/gba/renderers/common.h new file mode 100644 index 00000000..ed16917b --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/renderers/common.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013-2019 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_RENDERER_COMMON_H +#define GBA_RENDERER_COMMON_H + +#include + +CXX_GUARD_START + +#include + +struct GBAVideoRendererSprite { + struct GBAObj obj; + int16_t y; + int16_t endY; + int16_t cycles; + int8_t index; +}; + +int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites, int offsetY); + +CXX_GUARD_END + +#endif \ No newline at end of file diff --git a/mgba-test-runner/c/include/mgba/internal/gba/renderers/gl.h b/mgba-test-runner/c/include/mgba/internal/gba/renderers/gl.h new file mode 100644 index 00000000..2908e48d --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/renderers/gl.h @@ -0,0 +1,207 @@ +/* Copyright (c) 2013-2019 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VIDEO_GL_H +#define VIDEO_GL_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include +#include + +#if defined(BUILD_GLES2) || defined(BUILD_GLES3) + +#ifdef USE_EPOXY +#include +#elif defined(BUILD_GL) +#ifdef __APPLE__ +#include +#else +#define GL_GLEXT_PROTOTYPES +#include +#include +#endif +#else +#include +#endif + +struct GBAVideoGLAffine { + int16_t dx; + int16_t dmx; + int16_t dy; + int16_t dmy; + int32_t sx; + int32_t sy; +}; + +struct GBAVideoGLBackground { + GLuint fbo; + GLuint tex; + + unsigned index; + int enabled; + unsigned priority; + uint32_t charBase; + int mosaic; + int multipalette; + uint32_t screenBase; + int overflow; + int size; + int target1; + int target2; + uint16_t x; + uint16_t y; + int32_t refx; + int32_t refy; + + struct GBAVideoGLAffine affine; + + GLint scanlineAffine[GBA_VIDEO_VERTICAL_PIXELS * 4]; + GLint scanlineOffset[GBA_VIDEO_VERTICAL_PIXELS]; +}; + +enum { + GBA_GL_FBO_OBJ = 0, + GBA_GL_FBO_BACKDROP, + GBA_GL_FBO_WINDOW, + GBA_GL_FBO_OUTPUT, + GBA_GL_FBO_MAX +}; + +enum { + GBA_GL_TEX_OBJ_COLOR = 0, + GBA_GL_TEX_OBJ_FLAGS, + GBA_GL_TEX_OBJ_DEPTH, + GBA_GL_TEX_BACKDROP, + GBA_GL_TEX_WINDOW, + GBA_GL_TEX_MAX +}; + +enum { + GBA_GL_VS_LOC = 0, + GBA_GL_VS_MAXPOS, + + GBA_GL_BG_VRAM = 2, + GBA_GL_BG_PALETTE, + GBA_GL_BG_SCREENBASE, + GBA_GL_BG_CHARBASE, + GBA_GL_BG_SIZE, + GBA_GL_BG_OFFSET, + GBA_GL_BG_TRANSFORM, + GBA_GL_BG_RANGE, + GBA_GL_BG_MOSAIC, + + GBA_GL_OBJ_VRAM = 2, + GBA_GL_OBJ_PALETTE, + GBA_GL_OBJ_CHARBASE, + GBA_GL_OBJ_STRIDE, + GBA_GL_OBJ_LOCALPALETTE, + GBA_GL_OBJ_INFLAGS, + GBA_GL_OBJ_TRANSFORM, + GBA_GL_OBJ_DIMS, + GBA_GL_OBJ_OBJWIN, + GBA_GL_OBJ_MOSAIC, + GBA_GL_OBJ_CYCLES, + + GBA_GL_WIN_DISPCNT = 2, + GBA_GL_WIN_BLEND, + GBA_GL_WIN_FLAGS, + GBA_GL_WIN_WIN0, + GBA_GL_WIN_WIN1, + + GBA_GL_FINALIZE_SCALE = 2, + GBA_GL_FINALIZE_LAYERS, + GBA_GL_FINALIZE_FLAGS, + GBA_GL_FINALIZE_WINDOW, + GBA_GL_FINALIZE_PALETTE, + GBA_GL_FINALIZE_BACKDROP, + + GBA_GL_UNIFORM_MAX = 14 +}; + +struct GBAVideoGLShader { + GLuint program; + GLuint vao; + GLuint uniforms[GBA_GL_UNIFORM_MAX]; +}; + +struct GBAVideoGLRenderer { + struct GBAVideoRenderer d; + + uint32_t* temporaryBuffer; + + struct GBAVideoGLBackground bg[4]; + + int oamMax; + bool oamDirty; + struct GBAVideoRendererSprite sprites[128]; + + GLuint fbo[GBA_GL_FBO_MAX]; + GLuint layers[GBA_GL_TEX_MAX]; + GLuint vbo; + + GLuint outputTex; + + GLuint paletteTex; + uint16_t shadowPalette[GBA_VIDEO_VERTICAL_PIXELS][512]; + int nextPalette; + int paletteDirtyScanlines; + bool paletteDirty; + + GLuint vramTex; + unsigned vramDirty; + + uint16_t shadowRegs[0x30]; + uint64_t regsDirty; + + struct GBAVideoGLShader bgShader[6]; + struct GBAVideoGLShader objShader[3]; + struct GBAVideoGLShader windowShader; + struct GBAVideoGLShader finalizeShader; + + GBARegisterDISPCNT dispcnt; + + unsigned target1Obj; + unsigned target1Bd; + unsigned target2Obj; + unsigned target2Bd; + enum GBAVideoBlendEffect blendEffect; + uint16_t blda; + uint16_t bldb; + uint16_t bldy; + + GBAMosaicControl mosaic; + + struct GBAVideoGLWindowN { + struct GBAVideoWindowRegion h; + struct GBAVideoWindowRegion v; + GBAWindowControl control; + } winN[2]; + + GLint winNHistory[2][GBA_VIDEO_VERTICAL_PIXELS * 4]; + GLint spriteCycles[GBA_VIDEO_VERTICAL_PIXELS]; + + GBAWindowControl winout; + GBAWindowControl objwin; + + int firstAffine; + int firstY; + + int scale; +}; + +void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer); +void GBAVideoGLRendererSetScale(struct GBAVideoGLRenderer* renderer, int scale); + +#endif + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/renderers/proxy.h b/mgba-test-runner/c/include/mgba/internal/gba/renderers/proxy.h new file mode 100644 index 00000000..c1044c77 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/renderers/proxy.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_VIDEO_PROXY_H +#define GBA_VIDEO_PROXY_H + +#include + +CXX_GUARD_START + +#include +#include + +struct GBAVideoProxyRenderer { + struct GBAVideoRenderer d; + struct GBAVideoRenderer* backend; + struct mVideoLogger* logger; +}; + +void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend); +void GBAVideoProxyRendererShim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer); +void GBAVideoProxyRendererUnshim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/renderers/video-software.h b/mgba-test-runner/c/include/mgba/internal/gba/renderers/video-software.h new file mode 100644 index 00000000..9c603905 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/renderers/video-software.h @@ -0,0 +1,153 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VIDEO_SOFTWARE_H +#define VIDEO_SOFTWARE_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include +#include + +struct GBAVideoSoftwareBackground { + unsigned index; + int enabled; + unsigned priority; + uint32_t charBase; + int mosaic; + int multipalette; + uint32_t screenBase; + int overflow; + int size; + int target1; + int target2; + uint16_t x; + uint16_t y; + int32_t refx; + int32_t refy; + int16_t dx; + int16_t dmx; + int16_t dy; + int16_t dmy; + int32_t sx; + int32_t sy; + int yCache; + uint16_t mapCache[64]; + int32_t offsetX; + int32_t offsetY; + bool highlight; +}; + +enum { + OFFSET_PRIORITY = 30, + OFFSET_INDEX = 28, +}; + +#define FLAG_PRIORITY 0xC0000000 +#define FLAG_INDEX 0x30000000 +#define FLAG_IS_BACKGROUND 0x08000000 +#define FLAG_UNWRITTEN 0xFC000000 +#define FLAG_REBLEND 0x04000000 +#define FLAG_TARGET_1 0x02000000 +#define FLAG_TARGET_2 0x01000000 +#define FLAG_OBJWIN 0x01000000 +#define FLAG_ORDER_MASK 0xF8000000 + +#define IS_WRITABLE(PIXEL) ((PIXEL) & 0xFE000000) + +struct WindowControl { + GBAWindowControl packed; + int8_t priority; +}; + +#define MAX_WINDOW 5 + +struct Window { + uint8_t endX; + struct WindowControl control; +}; + +struct GBAVideoSoftwareRenderer { + struct GBAVideoRenderer d; + + color_t* outputBuffer; + int outputBufferStride; + + uint32_t* temporaryBuffer; + + GBARegisterDISPCNT dispcnt; + + uint32_t row[GBA_VIDEO_HORIZONTAL_PIXELS]; + uint32_t spriteLayer[GBA_VIDEO_HORIZONTAL_PIXELS]; + int32_t spriteCyclesRemaining; + + // BLDCNT + unsigned target1Obj; + unsigned target1Bd; + unsigned target2Obj; + unsigned target2Bd; + bool blendDirty; + enum GBAVideoBlendEffect blendEffect; + color_t normalPalette[512]; + color_t variantPalette[512]; + color_t highlightPalette[512]; + color_t highlightVariantPalette[512]; + + uint16_t blda; + uint16_t bldb; + uint16_t bldy; + + GBAMosaicControl mosaic; + bool greenswap; + + struct WindowN { + struct GBAVideoWindowRegion h; + struct GBAVideoWindowRegion v; + struct WindowControl control; + int16_t offsetX; + int16_t offsetY; + } winN[2]; + + struct WindowControl winout; + struct WindowControl objwin; + + struct WindowControl currentWindow; + + int nWindows; + struct Window windows[MAX_WINDOW]; + + struct GBAVideoSoftwareBackground bg[4]; + + bool forceTarget1; + bool oamDirty; + int oamMax; + struct GBAVideoRendererSprite sprites[128]; + int16_t objOffsetX; + int16_t objOffsetY; + + uint32_t scanlineDirty[5]; + uint16_t nextIo[REG_SOUND1CNT_LO >> 1]; + struct ScanlineCache { + uint16_t io[REG_SOUND1CNT_LO >> 1]; + int32_t scale[2][2]; + } cache[GBA_VIDEO_VERTICAL_PIXELS]; + int nextY; + + int start; + int end; + + uint8_t lastHighlightAmount; +}; + +void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer); + +CXX_GUARD_START + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/savedata.h b/mgba-test-runner/c/include/mgba/internal/gba/savedata.h new file mode 100644 index 00000000..05cd6596 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/savedata.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_SAVEDATA_H +#define GBA_SAVEDATA_H + +#include + +CXX_GUARD_START + +#include +#include + +mLOG_DECLARE_CATEGORY(GBA_SAVE); + +struct VFile; + +enum SavedataType { + SAVEDATA_AUTODETECT = -1, + SAVEDATA_FORCE_NONE = 0, + SAVEDATA_SRAM = 1, + SAVEDATA_FLASH512 = 2, + SAVEDATA_FLASH1M = 3, + SAVEDATA_EEPROM = 4, + SAVEDATA_EEPROM512 = 5 +}; + +enum SavedataCommand { + EEPROM_COMMAND_NULL = 0, + EEPROM_COMMAND_PENDING = 1, + EEPROM_COMMAND_WRITE = 2, + EEPROM_COMMAND_READ_PENDING = 3, + EEPROM_COMMAND_READ = 4, + + FLASH_COMMAND_START = 0xAA, + FLASH_COMMAND_CONTINUE = 0x55, + + FLASH_COMMAND_ERASE_CHIP = 0x10, + FLASH_COMMAND_ERASE_SECTOR = 0x30, + + FLASH_COMMAND_NONE = 0, + FLASH_COMMAND_ERASE = 0x80, + FLASH_COMMAND_ID = 0x90, + FLASH_COMMAND_PROGRAM = 0xA0, + FLASH_COMMAND_SWITCH_BANK = 0xB0, + FLASH_COMMAND_TERMINATE = 0xF0 +}; + +enum FlashStateMachine { + FLASH_STATE_RAW = 0, + FLASH_STATE_START = 1, + FLASH_STATE_CONTINUE = 2, +}; + +enum FlashManufacturer { + FLASH_MFG_PANASONIC = 0x1B32, + FLASH_MFG_SANYO = 0x1362 +}; + +enum SavedataDirty { + SAVEDATA_DIRT_NEW = 1, + SAVEDATA_DIRT_SEEN = 2 +}; + +enum { + SAVEDATA_FLASH_BASE = 0x0E005555, + + FLASH_BASE_HI = 0x5555, + FLASH_BASE_LO = 0x2AAA +}; + +struct GBASavedata { + enum SavedataType type; + uint8_t* data; + enum SavedataCommand command; + struct VFile* vf; + + int mapMode; + bool maskWriteback; + struct VFile* realVf; + + int8_t readBitsRemaining; + uint32_t readAddress; + uint32_t writeAddress; + + uint8_t* currentBank; + + struct mTiming* timing; + unsigned settling; + struct mTimingEvent dust; + + enum SavedataDirty dirty; + uint32_t dirtAge; + + enum FlashStateMachine flashState; +}; + +void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf); +void GBASavedataDeinit(struct GBASavedata* savedata); + +void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback); +void GBASavedataUnmask(struct GBASavedata* savedata); +size_t GBASavedataSize(const struct GBASavedata* savedata); +bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out); +bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in); +void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type); + +void GBASavedataInitFlash(struct GBASavedata* savedata); +void GBASavedataInitEEPROM(struct GBASavedata* savedata); +void GBASavedataInitSRAM(struct GBASavedata* savedata); + +uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address); +void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value); + +uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata); +void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize); + +void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount); + +struct GBASerializedState; +void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state); +void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/serialize.h b/mgba-test-runner/c/include/mgba/internal/gba/serialize.h new file mode 100644 index 00000000..bf6a9377 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/serialize.h @@ -0,0 +1,390 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_SERIALIZE_H +#define GBA_SERIALIZE_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +extern MGBA_EXPORT const uint32_t GBASavestateMagic; +extern MGBA_EXPORT const uint32_t GBASavestateVersion; + +mLOG_DECLARE_CATEGORY(GBA_STATE); + +/* Savestate format: + * 0x00000 - 0x00003: Version Magic (0x01000004) + * 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS) + * 0x00008 - 0x0000B: ROM CRC32 + * 0x0000C - 0x0000F: Master cycles + * 0x00010 - 0x0001B: Game title (e.g. METROID4USA) + * 0x0001C - 0x0001F: Game code (e.g. AMTE) + * 0x00020 - 0x0012F: CPU state: + * | 0x00020 - 0x0005F: GPRs + * | 0x00060 - 0x00063: CPSR + * | 0x00064 - 0x00067: SPSR + * | 0x00068 - 0x0006B: Cycles since last event + * | 0x0006C - 0x0006F: Cycles until next event + * | 0x00070 - 0x00117: Banked registers + * | 0x00118 - 0x0012F: Banked SPSRs + * 0x00130 - 0x00143: Audio channel 1/framer state + * | 0x00130 - 0x00133: Envelepe timing + * | bits 0 - 6: Remaining length + * | bits 7 - 9: Next step + * | bits 10 - 20: Shadow frequency register + * | bits 21 - 31: Reserved + * | 0x00134 - 0x00137: Next frame + * | 0x00138 - 0x0013B: Next channel 3 fade + * | 0x0013C - 0x0013F: Sweep state + * | bits 0 - 2: Timesteps + * | bits 3 - 7: Reserved + * | 0x00140 - 0x00143: Next event + * 0x00144 - 0x00153: Audio channel 2 state + * | 0x00144 - 0x00147: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00148 - 0x0014F: Reserved + * | 0x00150 - 0x00153: Next event + * 0x00154 - 0x0017B: Audio channel 3 state + * | 0x00154 - 0x00173: Wave banks + * | 0x00174 - 0x00175: Remaining length + * | 0x00176 - 0x00177: Reserved + * | 0x00178 - 0x0017B: Next event + * 0x0017C - 0x0018B: Audio channel 4 state + * | 0x0017C - 0x0017F: Linear feedback shift register state + * | 0x00180 - 0x00183: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00184 - 0x00187: Last event + * | 0x00188 - 0x0018B: Next event + * 0x0018C - 0x001AB: Audio FIFO 1 + * 0x001AC - 0x001CB: Audio FIFO 2 + * 0x001CC - 0x001DF: Audio miscellaneous state + * | 0x001CC - 0x001CF: Channel A internal audio samples + * | 0x001D0 - 0x001D3: Channel B internal audio samples + * | 0x001D4 - 0x001D7: Next sample + * | 0x001D8: Channel A current sample + * | 0x001D9: Channel B current sample + * | 0x001DA - 0x001DB: Flags + * | bits 0 - 1: Channel B internal samples remaining + * | bits 2 - 4: Channel B readable words + * | bits 5 - 6: Channel A internal samples remaining + * | bits 7 - 9: Channel A readable words + * | TODO: Fix this, they're in big-endian order, but field is little-endian + * | 0x001DC - 0x001DC: Channel 1 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bit 7: Reserved + * | 0x001DD - 0x001DD: Channel 2 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bit 7: Reserved + * | 0x001DE - 0x001DE: Channel 4 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bits 6 - 7: Current frame (continued) + * | 0x001DF - 0x001DF: Miscellaneous audio flags + * | bit 0: Current frame (continuation) + * | bit 1: Is channel 1 sweep enabled? + * | bit 2: Has channel 1 sweep occurred? + * | bit 3: Is channel 3's memory readable? + * | bit 4: Skip frame + * | bits 5 - 7: Reserved + * 0x001E0 - 0x001FF: Video miscellaneous state + * | 0x001E0 - 0x001E3: Next event + * | 0x001E4 - 0x001F7: Reserved + * | 0x001F8 - 0x001FB: Miscellaneous flags + * | 0x001FC - 0x001FF: Frame counter + * 0x00200 - 0x00213: Timer 0 + * | 0x00200 - 0x00201: Reload value + * | 0x00202 - 0x00203: Old reload value + * | 0x00204 - 0x00207: Last event + * | 0x00208 - 0x0020B: Next event + * | 0x0020C - 0x0020F: Reserved + * | 0x00210 - 0x00213: Miscellaneous flags + * 0x00214 - 0x00227: Timer 1 + * | 0x00214 - 0x00215: Reload value + * | 0x00216 - 0x00217: Old reload value + * | 0x00218 - 0x0021B: Last event + * | 0x0021C - 0x0021F: Next event + * | 0x00220 - 0x00223: Reserved + * | 0x00224 - 0x00227: Miscellaneous flags + * 0x00228 - 0x0023B: Timer 2 + * | 0x00228 - 0x00229: Reload value + * | 0x0022A - 0x0022B: Old reload value + * | 0x0022C - 0x0022F: Last event + * | 0x00230 - 0x00233: Next event + * | 0x00234 - 0x00237: Reserved + * | 0x00238 - 0x0023B: Miscellaneous flags + * 0x0023C - 0x00250: Timer 3 + * | 0x0023C - 0x0023D: Reload value + * | 0x0023E - 0x0023F: Old reload value + * | 0x00240 - 0x00243: Last event + * | 0x00244 - 0x00247: Next event + * | 0x00248 - 0x0024B: Reserved + * | 0x0024C - 0x0024F: Miscellaneous flags + * 0x00250 - 0x0025F: DMA 0 + * | 0x00250 - 0x00253: DMA next source + * | 0x00254 - 0x00257: DMA next destination + * | 0x00258 - 0x0025B: DMA next count + * | 0x0025C - 0x0025F: DMA next event + * 0x00260 - 0x0026F: DMA 1 + * | 0x00260 - 0x00263: DMA next source + * | 0x00264 - 0x00267: DMA next destination + * | 0x00268 - 0x0026B: DMA next count + * | 0x0026C - 0x0026F: DMA next event + * 0x00270 - 0x0027F: DMA 2 + * | 0x00270 - 0x00273: DMA next source + * | 0x00274 - 0x00277: DMA next destination + * | 0x00278 - 0x0027B: DMA next count + * | 0x0027C - 0x0027F: DMA next event + * 0x00280 - 0x0028F: DMA 3 + * | 0x00280 - 0x00283: DMA next source + * | 0x00284 - 0x00287: DMA next destination + * | 0x00288 - 0x0028B: DMA next count + * | 0x0028C - 0x0028F: DMA next event + * 0x00290 - 0x002C3: GPIO state + * | 0x00290 - 0x00291: Pin state + * | 0x00292 - 0x00293: Direction state + * | 0x00294 - 0x002B6: RTC state (see hardware.h for format) + * | 0x002B7 - 0x002B7: GPIO devices + * | bit 0: Has RTC values + * | bit 1: Has rumble value (reserved) + * | bit 2: Has light sensor value + * | bit 3: Has gyroscope value + * | bit 4: Has tilt values + * | bit 5: Has Game Boy Player attached + * | bits 6 - 7: Reserved + * | 0x002B8 - 0x002B9: Gyroscope sample + * | 0x002BA - 0x002BB: Tilt x sample + * | 0x002BC - 0x002BD: Tilt y sample + * | 0x002BE - 0x002BF: Flags + * | bit 0: Is read enabled + * | bit 1: Gyroscope sample is edge + * | bit 2: Light sample is edge + * | bit 3: Reserved + * | bits 4 - 15: Light counter + * | 0x002C0 - 0x002C0: Light sample + * | 0x002C1 - 0x002C3: Flags + * | bits 0 - 1: Tilt state machine + * | bits 2 - 3: GB Player inputs posted + * | bits 4 - 8: GB Player transmit position + * | bits 9 - 23: Reserved + * 0x002C4 - 0x002C7: Game Boy Player next event + * 0x002C8 - 0x002CB: Current DMA transfer word + * 0x002CC - 0x002CF: Last DMA transfer PC + * 0x002D0 - 0x002DF: Reserved (leave zero) + * 0x002E0 - 0x002EF: Savedata state + * | 0x002E0 - 0x002E0: Savedata type + * | 0x002E1 - 0x002E1: Savedata command (see savedata.h) + * | 0x002E2 - 0x002E2: Flags + * | bits 0 - 1: Flash state machine + * | bits 2 - 3: Reserved + * | bit 4: Flash bank + * | bit 5: Is settling occurring? + * | bits 6 - 7: Reserved + * | 0x002E3 - 0x002E3: EEPROM read bits remaining + * | 0x002E4 - 0x002E7: Settling cycles remaining + * | 0x002E8 - 0x002EB: EEPROM read address + * | 0x002EC - 0x002EF: EEPROM write address + * | 0x002F0 - 0x002F1: Flash settling sector + * | 0x002F2 - 0x002F3: Reserved + * 0x002F4 - 0x002FF: Prefetch + * | 0x002F4 - 0x002F7: GBA BIOS bus prefetch + * | 0x002F8 - 0x002FB: CPU prefecth (decode slot) + * | 0x002FC - 0x002FF: CPU prefetch (fetch slot) + * 0x00300 - 0x0030F: Reserved (leave zero) + * 0x00310 - 0x00317: Global cycle counter + * 0x00318 - 0x0031B: Last prefetched program counter + * 0x0031C - 0x0031F: Miscellaneous flags + * | bit 0: Is CPU halted? + * | bit 1: POSTFLG + * | bit 2: Is IRQ pending? + * 0x00320 - 0x00323: Next IRQ event + * 0x00324 - 0x00327: Interruptable BIOS stall cycles + * 0x00328 - 0x003FF: Reserved (leave zero) + * 0x00400 - 0x007FF: I/O memory + * 0x00800 - 0x00BFF: Palette + * 0x00C00 - 0x00FFF: OAM + * 0x01000 - 0x18FFF: VRAM + * 0x19000 - 0x20FFF: IWRAM + * 0x21000 - 0x60FFF: WRAM + * Total size: 0x61000 (397,312) bytes + */ + +DECL_BITFIELD(GBASerializedAudioFlags, uint16_t); +DECL_BITS(GBASerializedAudioFlags, FIFOInternalSamplesB, 0, 2); +DECL_BITS(GBASerializedAudioFlags, FIFOSamplesB, 2, 3); // Yay legacy? +DECL_BITS(GBASerializedAudioFlags, FIFOInternalSamplesA, 5, 2); +DECL_BITS(GBASerializedAudioFlags, FIFOSamplesA, 7, 3); + +DECL_BITFIELD(GBASerializedVideoFlags, uint32_t); +DECL_BITS(GBASerializedVideoFlags, Mode, 0, 2); + +DECL_BITFIELD(GBASerializedHWFlags1, uint16_t); +DECL_BIT(GBASerializedHWFlags1, ReadWrite, 0); +DECL_BIT(GBASerializedHWFlags1, GyroEdge, 1); +DECL_BIT(GBASerializedHWFlags1, LightEdge, 2); +DECL_BITS(GBASerializedHWFlags1, LightCounter, 4, 12); + +DECL_BITFIELD(GBASerializedHWFlags2, uint8_t); +DECL_BITS(GBASerializedHWFlags2, TiltState, 0, 2); +DECL_BITS(GBASerializedHWFlags2, GbpInputsPosted, 2, 2); +DECL_BITS(GBASerializedHWFlags2, GbpTxPosition, 4, 5); + +DECL_BITFIELD(GBASerializedHWFlags3, uint16_t); + +DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t); +DECL_BITS(GBASerializedSavedataFlags, FlashState, 0, 2); +DECL_BIT(GBASerializedSavedataFlags, FlashBank, 4); +DECL_BIT(GBASerializedSavedataFlags, DustSettling, 5); + +DECL_BITFIELD(GBASerializedMiscFlags, uint32_t); +DECL_BIT(GBASerializedMiscFlags, Halted, 0); +DECL_BIT(GBASerializedMiscFlags, POSTFLG, 1); +DECL_BIT(GBASerializedMiscFlags, IrqPending, 2); +DECL_BIT(GBASerializedMiscFlags, Blocked, 3); + +struct GBASerializedState { + uint32_t versionMagic; + uint32_t biosChecksum; + uint32_t romCrc32; + uint32_t masterCycles; + + char title[12]; + uint32_t id; + + struct { + int32_t gprs[16]; + union PSR cpsr; + union PSR spsr; + + int32_t cycles; + int32_t nextEvent; + + int32_t bankedRegisters[6][7]; + int32_t bankedSPSRs[6]; + } cpu; + + struct { + struct GBSerializedPSGState psg; + uint32_t fifoA[8]; + uint32_t fifoB[8]; + uint32_t internalA; + uint32_t internalB; + int32_t nextSample; + int8_t sampleA; + int8_t sampleB; + GBASerializedAudioFlags gbaFlags; + GBSerializedAudioFlags flags; + } audio; + + struct { + int32_t nextEvent; + int32_t reserved[5]; + GBASerializedVideoFlags flags; + int32_t frameCounter; + } video; + + struct { + uint16_t reload; + uint16_t reserved0; + uint32_t lastEvent; + uint32_t nextEvent; + uint32_t reserved1; + GBATimerFlags flags; + } timers[4]; + + struct { + uint32_t nextSource; + uint32_t nextDest; + int32_t nextCount; + int32_t when; + } dma[4]; + + struct { + uint16_t pinState; + uint16_t pinDirection; + int32_t rtcBytesRemaining; + int32_t rtcTransferStep; + int32_t rtcBitsRead; + int32_t rtcBits; + int32_t rtcCommandActive; + RTCCommandData rtcCommand; + RTCControl rtcControl; + uint8_t time[7]; + uint8_t devices; + uint16_t gyroSample; + uint16_t tiltSampleX; + uint16_t tiltSampleY; + GBASerializedHWFlags1 flags1; + uint8_t lightSample; + GBASerializedHWFlags2 flags2; + GBASerializedHWFlags3 flags3; + uint32_t gbpNextEvent; + } hw; + + uint32_t dmaTransferRegister; + uint32_t dmaBlockPC; + + struct { + uint32_t cmd; + uint32_t paddr; + uint32_t vaddr; + uint32_t size; + } matrix; + + struct { + uint8_t type; + uint8_t command; + GBASerializedSavedataFlags flags; + int8_t readBitsRemaining; + uint32_t settlingDust; + uint32_t readAddress; + uint32_t writeAddress; + uint16_t settlingSector; + uint16_t reserved; + } savedata; + + uint32_t biosPrefetch; + uint32_t cpuPrefetch[2]; + + uint32_t reservedCpu[4]; + + uint64_t globalCycles; + uint32_t lastPrefetchedPc; + GBASerializedMiscFlags miscFlags; + uint32_t nextIrq; + int32_t biosStall; + + uint32_t matrixMappings[16]; + + uint32_t reserved[38]; + + uint16_t io[SIZE_IO >> 1]; + uint16_t pram[SIZE_PALETTE_RAM >> 1]; + uint16_t oam[SIZE_OAM >> 1]; + uint16_t vram[SIZE_VRAM >> 1]; + uint8_t iwram[SIZE_WORKING_IRAM]; + uint8_t wram[SIZE_WORKING_RAM]; +}; + +struct VDir; + +void GBASerialize(struct GBA* gba, struct GBASerializedState* state); +bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/sharkport.h b/mgba-test-runner/c/include/mgba/internal/gba/sharkport.h new file mode 100644 index 00000000..361d4eb4 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/sharkport.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_SHARKPORT_H +#define GBA_SHARKPORT_H + +#include + +CXX_GUARD_START + +struct GBA; +struct VFile; + +bool GBASavedataImportSharkPort(struct GBA* gba, struct VFile* vf, bool testChecksum); +bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/sio.h b/mgba-test-runner/c/include/mgba/internal/gba/sio.h new file mode 100644 index 00000000..2c06af69 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/sio.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_SIO_H +#define GBA_SIO_H + +#include + +CXX_GUARD_START + +#include +#include + +#define MAX_GBAS 4 + +extern const int GBASIOCyclesPerTransfer[4][MAX_GBAS]; + +mLOG_DECLARE_CATEGORY(GBA_SIO); + +enum { + RCNT_INITIAL = 0x8000 +}; + +enum { + JOY_CMD_RESET = 0xFF, + JOY_CMD_POLL = 0x00, + JOY_CMD_TRANS = 0x14, + JOY_CMD_RECV = 0x15, + + JOYSTAT_TRANS = 8, + JOYSTAT_RECV = 2, + + JOYCNT_RESET = 1, + JOYCNT_RECV = 2, + JOYCNT_TRANS = 4, +}; + +DECL_BITFIELD(GBASIONormal, uint16_t); +DECL_BIT(GBASIONormal, Sc, 0); +DECL_BIT(GBASIONormal, InternalSc, 1); +DECL_BIT(GBASIONormal, Si, 2); +DECL_BIT(GBASIONormal, IdleSo, 3); +DECL_BIT(GBASIONormal, Start, 7); +DECL_BIT(GBASIONormal, Length, 12); +DECL_BIT(GBASIONormal, Irq, 14); +DECL_BITFIELD(GBASIOMultiplayer, uint16_t); +DECL_BITS(GBASIOMultiplayer, Baud, 0, 2); +DECL_BIT(GBASIOMultiplayer, Slave, 2); +DECL_BIT(GBASIOMultiplayer, Ready, 3); +DECL_BITS(GBASIOMultiplayer, Id, 4, 2); +DECL_BIT(GBASIOMultiplayer, Error, 6); +DECL_BIT(GBASIOMultiplayer, Busy, 7); +DECL_BIT(GBASIOMultiplayer, Irq, 14); + +struct GBASIODriverSet { + struct GBASIODriver* normal; + struct GBASIODriver* multiplayer; + struct GBASIODriver* joybus; +}; + +struct GBASIO { + struct GBA* p; + + enum GBASIOMode mode; + struct GBASIODriverSet drivers; + struct GBASIODriver* activeDriver; + + uint16_t rcnt; + uint16_t siocnt; +}; + +void GBASIOInit(struct GBASIO* sio); +void GBASIODeinit(struct GBASIO* sio); +void GBASIOReset(struct GBASIO* sio); + +void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers); +void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode); + +void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value); +void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value); +uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t value); + +int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/sio/dolphin.h b/mgba-test-runner/c/include/mgba/internal/gba/sio/dolphin.h new file mode 100644 index 00000000..29d0c575 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/sio/dolphin.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SIO_DOLPHIN_H +#define SIO_DOLPHIN_H + +#include + +CXX_GUARD_START + +#include +#include + +#include + +extern const uint16_t DOLPHIN_CLOCK_PORT; +extern const uint16_t DOLPHIN_DATA_PORT; + +struct GBASIODolphin { + struct GBASIODriver d; + struct mTimingEvent event; + + Socket data; + Socket clock; + + int32_t clockSlice; + int state; + bool active; +}; + +void GBASIODolphinCreate(struct GBASIODolphin*); +void GBASIODolphinDestroy(struct GBASIODolphin*); + +bool GBASIODolphinConnect(struct GBASIODolphin*, const struct Address* address, short dataPort, short clockPort); +bool GBASIODolphinIsConnected(struct GBASIODolphin*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/sio/lockstep.h b/mgba-test-runner/c/include/mgba/internal/gba/sio/lockstep.h new file mode 100644 index 00000000..13c18103 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/sio/lockstep.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_SIO_LOCKSTEP_H +#define GBA_SIO_LOCKSTEP_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +struct GBASIOLockstep { + struct mLockstep d; + struct GBASIOLockstepNode* players[MAX_GBAS]; + int attachedMulti; + int attachedNormal; + + uint16_t multiRecv[MAX_GBAS]; + uint32_t normalRecv[MAX_GBAS]; +}; + +struct GBASIOLockstepNode { + struct GBASIODriver d; + struct GBASIOLockstep* p; + struct mTimingEvent event; + + volatile int32_t nextEvent; + int32_t eventDiff; + bool normalSO; + int id; + enum GBASIOMode mode; + bool transferFinished; +#ifndef NDEBUG + int transferId; + enum mLockstepPhase phase; +#endif +}; + +void GBASIOLockstepInit(struct GBASIOLockstep*); + +void GBASIOLockstepNodeCreate(struct GBASIOLockstepNode*); + +bool GBASIOLockstepAttachNode(struct GBASIOLockstep*, struct GBASIOLockstepNode*); +void GBASIOLockstepDetachNode(struct GBASIOLockstep*, struct GBASIOLockstepNode*); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/timer.h b/mgba-test-runner/c/include/mgba/internal/gba/timer.h new file mode 100644 index 00000000..664842e6 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/timer.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_TIMER_H +#define GBA_TIMER_H + +#include + +CXX_GUARD_START + +#include + +DECL_BITFIELD(GBATimerFlags, uint32_t); +DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4); +DECL_BIT(GBATimerFlags, CountUp, 4); +DECL_BIT(GBATimerFlags, DoIrq, 5); +DECL_BIT(GBATimerFlags, Enable, 6); + +struct GBA; +struct GBATimer { + uint16_t reload; + int32_t lastEvent; + struct mTimingEvent event; + GBATimerFlags flags; +}; + +void GBATimerInit(struct GBA* gba); +void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate); +void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t value); +void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t value); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/vfame.h b/mgba-test-runner/c/include/mgba/internal/gba/vfame.h new file mode 100644 index 00000000..eff24a03 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/vfame.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2016 taizou + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Support for copy protected unlicensed games from the company Vast Fame + +#ifndef GBA_VFAME_H +#define GBA_VFAME_H + +#include + +CXX_GUARD_START + +enum GBAVFameCartType { + VFAME_NO = 0, + VFAME_STANDARD = 1, + VFAME_GEORGE = 2 +}; + +struct GBAVFameCart { + enum GBAVFameCartType cartType; + int sramMode; + int romMode; + int8_t writeSequence[5]; + bool acceptingModeChange; +}; + +void GBAVFameInit(struct GBAVFameCart* cart); +void GBAVFameDetect(struct GBAVFameCart* cart, uint32_t* rom, size_t romSize); +void GBAVFameSramWrite(struct GBAVFameCart* cart, uint32_t address, uint8_t value, uint8_t* sramData); +uint32_t GBAVFameModifyRomAddress(struct GBAVFameCart* cart, uint32_t address, size_t romSize); +uint32_t GBAVFameGetPatternValue(uint32_t address, int bits); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/gba/video.h b/mgba-test-runner/c/include/mgba/internal/gba/video.h new file mode 100644 index 00000000..0a27807b --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/gba/video.h @@ -0,0 +1,240 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_VIDEO_H +#define GBA_VIDEO_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +mLOG_DECLARE_CATEGORY(GBA_VIDEO); + +enum { + VIDEO_HBLANK_PIXELS = 68, + VIDEO_HDRAW_LENGTH = 960, + VIDEO_HBLANK_LENGTH = 272, + VIDEO_HBLANK_FLIP = 46, + VIDEO_HORIZONTAL_LENGTH = 1232, + + VIDEO_VBLANK_PIXELS = 68, + VIDEO_VERTICAL_TOTAL_PIXELS = 228, + + VIDEO_TOTAL_LENGTH = 280896, + + OBJ_HBLANK_FREE_LENGTH = 954, + OBJ_LENGTH = 1210, + + BASE_TILE = 0x00010000 +}; + +enum GBAVideoObjMode { + OBJ_MODE_NORMAL = 0, + OBJ_MODE_SEMITRANSPARENT = 1, + OBJ_MODE_OBJWIN = 2 +}; + +enum GBAVideoObjShape { + OBJ_SHAPE_SQUARE = 0, + OBJ_SHAPE_HORIZONTAL = 1, + OBJ_SHAPE_VERTICAL = 2 +}; + +enum GBAVideoBlendEffect { + BLEND_NONE = 0, + BLEND_ALPHA = 1, + BLEND_BRIGHTEN = 2, + BLEND_DARKEN = 3 +}; + +DECL_BITFIELD(GBAObjAttributesA, uint16_t); +DECL_BITS(GBAObjAttributesA, Y, 0, 8); +DECL_BIT(GBAObjAttributesA, Transformed, 8); +DECL_BIT(GBAObjAttributesA, Disable, 9); +DECL_BIT(GBAObjAttributesA, DoubleSize, 9); +DECL_BITS(GBAObjAttributesA, Mode, 10, 2); +DECL_BIT(GBAObjAttributesA, Mosaic, 12); +DECL_BIT(GBAObjAttributesA, 256Color, 13); +DECL_BITS(GBAObjAttributesA, Shape, 14, 2); + +DECL_BITFIELD(GBAObjAttributesB, uint16_t); +DECL_BITS(GBAObjAttributesB, X, 0, 9); +DECL_BITS(GBAObjAttributesB, MatIndex, 9, 5); +DECL_BIT(GBAObjAttributesB, HFlip, 12); +DECL_BIT(GBAObjAttributesB, VFlip, 13); +DECL_BITS(GBAObjAttributesB, Size, 14, 2); + +DECL_BITFIELD(GBAObjAttributesC, uint16_t); +DECL_BITS(GBAObjAttributesC, Tile, 0, 10); +DECL_BITS(GBAObjAttributesC, Priority, 10, 2); +DECL_BITS(GBAObjAttributesC, Palette, 12, 4); + +struct GBAObj { + GBAObjAttributesA a; + GBAObjAttributesB b; + GBAObjAttributesC c; + uint16_t d; +}; + +struct GBAOAMMatrix { + int16_t padding0[3]; + int16_t a; + int16_t padding1[3]; + int16_t b; + int16_t padding2[3]; + int16_t c; + int16_t padding3[3]; + int16_t d; +}; + +union GBAOAM { + struct GBAObj obj[128]; + struct GBAOAMMatrix mat[32]; + uint16_t raw[512]; +}; + +struct GBAVideoWindowRegion { + uint8_t end; + uint8_t start; +}; + +#define GBA_TEXT_MAP_TILE(MAP) ((MAP) & 0x03FF) +#define GBA_TEXT_MAP_HFLIP(MAP) ((MAP) & 0x0400) +#define GBA_TEXT_MAP_VFLIP(MAP) ((MAP) & 0x0800) +#define GBA_TEXT_MAP_PALETTE(MAP) (((MAP) & 0xF000) >> 12) + +DECL_BITFIELD(GBARegisterDISPCNT, uint16_t); +DECL_BITS(GBARegisterDISPCNT, Mode, 0, 3); +DECL_BIT(GBARegisterDISPCNT, Cgb, 3); +DECL_BIT(GBARegisterDISPCNT, FrameSelect, 4); +DECL_BIT(GBARegisterDISPCNT, HblankIntervalFree, 5); +DECL_BIT(GBARegisterDISPCNT, ObjCharacterMapping, 6); +DECL_BIT(GBARegisterDISPCNT, ForcedBlank, 7); +DECL_BIT(GBARegisterDISPCNT, Bg0Enable, 8); +DECL_BIT(GBARegisterDISPCNT, Bg1Enable, 9); +DECL_BIT(GBARegisterDISPCNT, Bg2Enable, 10); +DECL_BIT(GBARegisterDISPCNT, Bg3Enable, 11); +DECL_BIT(GBARegisterDISPCNT, ObjEnable, 12); +DECL_BIT(GBARegisterDISPCNT, Win0Enable, 13); +DECL_BIT(GBARegisterDISPCNT, Win1Enable, 14); +DECL_BIT(GBARegisterDISPCNT, ObjwinEnable, 15); + +DECL_BITFIELD(GBARegisterDISPSTAT, uint16_t); +DECL_BIT(GBARegisterDISPSTAT, InVblank, 0); +DECL_BIT(GBARegisterDISPSTAT, InHblank, 1); +DECL_BIT(GBARegisterDISPSTAT, Vcounter, 2); +DECL_BIT(GBARegisterDISPSTAT, VblankIRQ, 3); +DECL_BIT(GBARegisterDISPSTAT, HblankIRQ, 4); +DECL_BIT(GBARegisterDISPSTAT, VcounterIRQ, 5); +DECL_BITS(GBARegisterDISPSTAT, VcountSetting, 8, 8); + +DECL_BITFIELD(GBARegisterBGCNT, uint16_t); +DECL_BITS(GBARegisterBGCNT, Priority, 0, 2); +DECL_BITS(GBARegisterBGCNT, CharBase, 2, 2); +DECL_BIT(GBARegisterBGCNT, Mosaic, 6); +DECL_BIT(GBARegisterBGCNT, 256Color, 7); +DECL_BITS(GBARegisterBGCNT, ScreenBase, 8, 5); +DECL_BIT(GBARegisterBGCNT, Overflow, 13); +DECL_BITS(GBARegisterBGCNT, Size, 14, 2); + +DECL_BITFIELD(GBARegisterBLDCNT, uint16_t); +DECL_BIT(GBARegisterBLDCNT, Target1Bg0, 0); +DECL_BIT(GBARegisterBLDCNT, Target1Bg1, 1); +DECL_BIT(GBARegisterBLDCNT, Target1Bg2, 2); +DECL_BIT(GBARegisterBLDCNT, Target1Bg3, 3); +DECL_BIT(GBARegisterBLDCNT, Target1Obj, 4); +DECL_BIT(GBARegisterBLDCNT, Target1Bd, 5); +DECL_BITS(GBARegisterBLDCNT, Effect, 6, 2); +DECL_BIT(GBARegisterBLDCNT, Target2Bg0, 8); +DECL_BIT(GBARegisterBLDCNT, Target2Bg1, 9); +DECL_BIT(GBARegisterBLDCNT, Target2Bg2, 10); +DECL_BIT(GBARegisterBLDCNT, Target2Bg3, 11); +DECL_BIT(GBARegisterBLDCNT, Target2Obj, 12); +DECL_BIT(GBARegisterBLDCNT, Target2Bd, 13); + +DECL_BITFIELD(GBAWindowControl, uint8_t); +DECL_BIT(GBAWindowControl, Bg0Enable, 0); +DECL_BIT(GBAWindowControl, Bg1Enable, 1); +DECL_BIT(GBAWindowControl, Bg2Enable, 2); +DECL_BIT(GBAWindowControl, Bg3Enable, 3); +DECL_BIT(GBAWindowControl, ObjEnable, 4); +DECL_BIT(GBAWindowControl, BlendEnable, 5); + +DECL_BITFIELD(GBAMosaicControl, uint16_t); +DECL_BITS(GBAMosaicControl, BgH, 0, 4); +DECL_BITS(GBAMosaicControl, BgV, 4, 4); +DECL_BITS(GBAMosaicControl, ObjH, 8, 4); +DECL_BITS(GBAMosaicControl, ObjV, 12, 4); + +struct GBAVideoRenderer { + void (*init)(struct GBAVideoRenderer* renderer); + void (*reset)(struct GBAVideoRenderer* renderer); + void (*deinit)(struct GBAVideoRenderer* renderer); + + uint16_t (*writeVideoRegister)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value); + void (*writeVRAM)(struct GBAVideoRenderer* renderer, uint32_t address); + void (*writePalette)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value); + void (*writeOAM)(struct GBAVideoRenderer* renderer, uint32_t oam); + void (*drawScanline)(struct GBAVideoRenderer* renderer, int y); + void (*finishFrame)(struct GBAVideoRenderer* renderer); + + void (*getPixels)(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels); + void (*putPixels)(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); + + uint16_t* palette; + uint16_t* vram; + union GBAOAM* oam; + struct mCacheSet* cache; + + bool disableBG[4]; + bool disableOBJ; + bool disableWIN[2]; + bool disableOBJWIN; + + bool highlightBG[4]; + bool highlightOBJ[128]; + color_t highlightColor; + uint8_t highlightAmount; +}; + +struct GBAVideo { + struct GBA* p; + struct GBAVideoRenderer* renderer; + struct mTimingEvent event; + + int vcount; + int shouldStall; + + uint16_t palette[512]; + uint16_t* vram; + union GBAOAM oam; + + int32_t frameCounter; + int frameskip; + int frameskipCounter; +}; + +void GBAVideoInit(struct GBAVideo* video); +void GBAVideoReset(struct GBAVideo* video); +void GBAVideoDeinit(struct GBAVideo* video); + +void GBAVideoDummyRendererCreate(struct GBAVideoRenderer*); +void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer* renderer); + +void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value); + +struct GBASerializedState; +void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* state); +void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState* state); + +extern MGBA_EXPORT const int GBAVideoObjSizes[16][2]; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/debugger/cli-debugger.h b/mgba-test-runner/c/include/mgba/internal/sm83/debugger/cli-debugger.h new file mode 100644 index 00000000..a3f10d2d --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/debugger/cli-debugger.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SM83_CLI_DEBUGGER_H +#define SM83_CLI_DEBUGGER_H + +#include + +CXX_GUARD_START + +struct CLIDebuggerSystem; +void SM83CLIDebuggerCreate(struct CLIDebuggerSystem* debugger); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/debugger/debugger.h b/mgba-test-runner/c/include/mgba/internal/sm83/debugger/debugger.h new file mode 100644 index 00000000..a2d7f2e7 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/debugger/debugger.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SM83_DEBUGGER_H +#define SM83_DEBUGGER_H + +#include + +CXX_GUARD_START + +#include + +#include + +struct SM83Segment { + uint16_t start; + uint16_t end; + const char* name; +}; + +struct CLIDebuggerSystem; +struct SM83Debugger { + struct mDebuggerPlatform d; + struct SM83Core* cpu; + + struct mBreakpointList breakpoints; + struct mWatchpointList watchpoints; + struct SM83Memory originalMemory; + + ssize_t nextId; + + const struct SM83Segment* segments; + + void (*printStatus)(struct CLIDebuggerSystem*); +}; + +struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/debugger/memory-debugger.h b/mgba-test-runner/c/include/mgba/internal/sm83/debugger/memory-debugger.h new file mode 100644 index 00000000..c6b1cfc8 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/debugger/memory-debugger.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SM83_MEMORY_DEBUGGER_H +#define SM83_MEMORY_DEBUGGER_H + +#include + +CXX_GUARD_START + +struct SM83Debugger; + +void SM83DebuggerInstallMemoryShim(struct SM83Debugger* debugger); +void SM83DebuggerRemoveMemoryShim(struct SM83Debugger* debugger); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/decoder.h b/mgba-test-runner/c/include/mgba/internal/sm83/decoder.h new file mode 100644 index 00000000..14104ef4 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/decoder.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SM83_DECODER_H +#define SM83_DECODER_H + +#include + +CXX_GUARD_START + +enum SM83Condition { + SM83_COND_NONE = 0x0, + SM83_COND_C = 0x1, + SM83_COND_Z = 0x2, + SM83_COND_NC = 0x3, + SM83_COND_NZ = 0x4 +}; + +enum SM83Mnemonic { + SM83_MN_ILL = 0, + SM83_MN_ADC, + SM83_MN_ADD, + SM83_MN_AND, + SM83_MN_BIT, + SM83_MN_CALL, + SM83_MN_CCF, + SM83_MN_CP, + SM83_MN_CPL, + SM83_MN_DAA, + SM83_MN_DEC, + SM83_MN_DI, + SM83_MN_EI, + SM83_MN_HALT, + SM83_MN_INC, + SM83_MN_JP, + SM83_MN_JR, + SM83_MN_LD, + SM83_MN_NOP, + SM83_MN_OR, + SM83_MN_POP, + SM83_MN_PUSH, + SM83_MN_RES, + SM83_MN_RET, + SM83_MN_RETI, + SM83_MN_RL, + SM83_MN_RLC, + SM83_MN_RR, + SM83_MN_RRC, + SM83_MN_RST, + SM83_MN_SBC, + SM83_MN_SCF, + SM83_MN_SET, + SM83_MN_SLA, + SM83_MN_SRA, + SM83_MN_SRL, + SM83_MN_STOP, + SM83_MN_SUB, + SM83_MN_SWAP, + SM83_MN_XOR, + + SM83_MN_MAX +}; + +enum SM83Register { + SM83_REG_B = 1, + SM83_REG_C, + SM83_REG_D, + SM83_REG_E, + SM83_REG_H, + SM83_REG_L, + SM83_REG_A, + SM83_REG_F, + SM83_REG_BC, + SM83_REG_DE, + SM83_REG_HL, + SM83_REG_AF, + + SM83_REG_SP, + SM83_REG_PC +}; + +enum { + SM83_OP_FLAG_IMPLICIT = 1, + SM83_OP_FLAG_MEMORY = 2, + SM83_OP_FLAG_INCREMENT = 4, + SM83_OP_FLAG_DECREMENT = 8, + SM83_OP_FLAG_RELATIVE = 16, +}; + +struct SM83Operand { + uint8_t reg; + uint8_t flags; + uint16_t immediate; +}; + +struct SM83InstructionInfo { + uint8_t opcode[3]; + uint8_t opcodeSize; + struct SM83Operand op1; + struct SM83Operand op2; + unsigned mnemonic; + unsigned condition; +}; + +size_t SM83Decode(uint8_t opcode, struct SM83InstructionInfo* info); +int SM83Disassemble(struct SM83InstructionInfo* info, uint16_t pc, char* buffer, int blen); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/emitter-sm83.h b/mgba-test-runner/c/include/mgba/internal/sm83/emitter-sm83.h new file mode 100644 index 00000000..d9366e26 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/emitter-sm83.h @@ -0,0 +1,528 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef EMITTER_SM83_H +#define EMITTER_SM83_H + +#define DECLARE_INSTRUCTION_SM83(EMITTER, NAME) \ + EMITTER ## NAME + +#define DECLARE_SM83_EMITTER_BLOCK(EMITTER) \ + DECLARE_INSTRUCTION_SM83(EMITTER, NOP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDBC_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCA_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDISP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDHL_BC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_BC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCA_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, STOP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDDE_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLA_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JR), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDHL_DE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_DE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRA_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JRNZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDIHLA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DAA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JRZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDHL_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_IHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPL_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JRNC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDSP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDDHLA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCSP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INC_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DEC_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SCF), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JRC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDHL_SP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_DHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECSP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, INCA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DECA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CCF), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDB_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDC_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDD_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDE_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDH_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDL_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, HALT), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDA_A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADCA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUBA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBCA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ANDA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XORA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ORA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CPA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RETNZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, POPBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JPNZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CALLNZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, PUSHBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST00), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RETZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RET), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JPZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CALLZ), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CALL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST08), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RETNC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, POPDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JPNC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CALLNC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, PUSHDE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SUB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST10), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RETC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RETI), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JPC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CALLC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SBC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST18), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDIOA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, POPHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDIOCA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, PUSHHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, AND), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST20), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ADDSP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, JPHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDIA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, XOR), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST28), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDAIO), \ + DECLARE_INSTRUCTION_SM83(EMITTER, POPAF), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDAIOC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, DI), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, PUSHAF), \ + DECLARE_INSTRUCTION_SM83(EMITTER, OR), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST30), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDHL_SP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDSP_HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, LDAI), \ + DECLARE_INSTRUCTION_SM83(EMITTER, EI), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, ILL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, CP), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RST38) + +#define DECLARE_SM83_CB_EMITTER_BLOCK(EMITTER) \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLCA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRCA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RLA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RRA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SLAA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRAA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SWAPA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLB), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLC), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLD), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLE), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLH), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLHL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SRLA), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT0A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT1A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT2A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT3A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT4A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT5A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT6A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, BIT7A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES0A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES1A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES2A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES3A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES4A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES5A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES6A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, RES7A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET0A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET1A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET2A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET3A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET4A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET5A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET6A), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7B), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7C), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7D), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7E), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7H), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7L), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7HL), \ + DECLARE_INSTRUCTION_SM83(EMITTER, SET7A) + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/isa-sm83.h b/mgba-test-runner/c/include/mgba/internal/sm83/isa-sm83.h new file mode 100644 index 00000000..7acf6fea --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/isa-sm83.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ISA_SM83_H +#define ISA_SM83_H + +#include + +CXX_GUARD_START + +struct SM83Core; + +typedef void (*SM83Instruction)(struct SM83Core*); +extern const SM83Instruction _sm83InstructionTable[0x100]; + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/include/mgba/internal/sm83/sm83.h b/mgba-test-runner/c/include/mgba/internal/sm83/sm83.h new file mode 100644 index 00000000..86b4d374 --- /dev/null +++ b/mgba-test-runner/c/include/mgba/internal/sm83/sm83.h @@ -0,0 +1,172 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SM83_H +#define SM83_H + +#include + +CXX_GUARD_START + +#include +#include + +struct SM83Core; + +#pragma pack(push, 1) +union FlagRegister { + struct { +#ifdef __BIG_ENDIAN__ + unsigned z : 1; + unsigned n : 1; + unsigned h : 1; + unsigned c : 1; + unsigned unused : 4; +#else + unsigned unused : 4; + unsigned c : 1; + unsigned h : 1; + unsigned n : 1; + unsigned z : 1; +#endif + }; + + uint8_t packed; +}; +#pragma pack(pop) + +enum SM83ExecutionState { + SM83_CORE_FETCH = 3, + SM83_CORE_IDLE_0 = 0, + SM83_CORE_IDLE_1 = 1, + SM83_CORE_EXECUTE = 2, + + SM83_CORE_MEMORY_LOAD = 7, + SM83_CORE_MEMORY_STORE = 11, + SM83_CORE_READ_PC = 15, + SM83_CORE_STALL = 19, + SM83_CORE_OP2 = 23, + SM83_CORE_HALT_BUG = 27, +}; +struct SM83Memory { + uint8_t (*cpuLoad8)(struct SM83Core*, uint16_t address); + uint8_t (*load8)(struct SM83Core*, uint16_t address); + void (*store8)(struct SM83Core*, uint16_t address, int8_t value); + + int (*currentSegment)(struct SM83Core*, uint16_t address); + + const uint8_t* activeRegion; + uint16_t activeMask; + uint16_t activeRegionEnd; + void (*setActiveRegion)(struct SM83Core*, uint16_t address); +}; + +struct SM83InterruptHandler { + void (*reset)(struct SM83Core* cpu); + void (*processEvents)(struct SM83Core* cpu); + void (*setInterrupts)(struct SM83Core* cpu, bool enable); + uint16_t (*irqVector)(struct SM83Core* cpu); + void (*halt)(struct SM83Core* cpu); + void (*stop)(struct SM83Core* cpu); + + void (*hitIllegal)(struct SM83Core* cpu); +}; + +#ifdef __BIG_ENDIAN__ +#define SM83_REGISTER_PAIR(HIGH, LOW) union { \ + struct { \ + uint8_t HIGH; \ + uint8_t LOW; \ + }; \ + uint16_t HIGH ## LOW; \ + } + +#define SM83_AF_REGISTER union { \ + struct { \ + uint8_t a; \ + union FlagRegister f; \ + }; \ + uint16_t af; \ + } +#else +#define SM83_REGISTER_PAIR(HIGH, LOW) union { \ + struct { \ + uint8_t LOW; \ + uint8_t HIGH; \ + }; \ + uint16_t HIGH ## LOW; \ + } + +#define SM83_AF_REGISTER union { \ + struct { \ + union FlagRegister f; \ + uint8_t a; \ + }; \ + uint16_t af; \ + } +#endif + +#define SM83_REGISTER_FILE struct { \ + SM83_AF_REGISTER; \ + SM83_REGISTER_PAIR(b, c); \ + SM83_REGISTER_PAIR(d, e); \ + SM83_REGISTER_PAIR(h, l); \ + uint16_t sp; \ + uint16_t pc; \ +} + +struct SM83RegisterFile { +#pragma pack(push, 1) + SM83_REGISTER_FILE; +#pragma pack(pop) +}; + +struct SM83Core { +#pragma pack(push, 1) + union { + struct SM83RegisterFile regs; + SM83_REGISTER_FILE; + }; +#pragma pack(pop) + + uint16_t index; + + int tMultiplier; + int32_t cycles; + int32_t nextEvent; + enum SM83ExecutionState executionState; + bool halted; + + uint8_t bus; + bool condition; + SM83Instruction instruction; + + bool irqPending; + + struct SM83Memory memory; + struct SM83InterruptHandler irqh; + + struct mCPUComponent* master; + + size_t numComponents; + struct mCPUComponent** components; +}; +#undef SM83_REGISTER_FILE + +void SM83Init(struct SM83Core* cpu); +void SM83Deinit(struct SM83Core* cpu); +void SM83SetComponents(struct SM83Core* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras); +void SM83HotplugAttach(struct SM83Core* cpu, size_t slot); +void SM83HotplugDetach(struct SM83Core* cpu, size_t slot); + +void SM83Reset(struct SM83Core* cpu); +void SM83RaiseIRQ(struct SM83Core* cpu); + +void SM83Tick(struct SM83Core* cpu); +void SM83Run(struct SM83Core* cpu); + +CXX_GUARD_END + +#endif diff --git a/mgba-test-runner/c/test-runner.c b/mgba-test-runner/c/test-runner.c new file mode 100644 index 00000000..fbd77028 --- /dev/null +++ b/mgba-test-runner/c/test-runner.c @@ -0,0 +1,135 @@ +#include "test-runner.h" + +#include +#include +#include + +_Static_assert(BYTES_PER_PIXEL == 4, "bytes per pixel MUST be four"); + +void log_output(struct mLogger* _log, int category, enum mLogLevel level, + const char* format, va_list args); +char* log_level_str(enum mLogLevel); + +static void (*EXTERNAL_LOGGING)(char*); + +struct mLogger LOGGER = {.log = log_output}; + +struct MGBA { + struct mCore* core; + struct video_buffer videoBuffer; + char* filename; +}; + +struct MGBA* new_runner(char* filename) { + struct MGBA* mgba = malloc(sizeof(struct MGBA)); + + mLogSetDefaultLogger(&LOGGER); + + char* filename_new = strdup(filename); + mgba->filename = filename_new; + + struct mCore* core = mCoreFind(mgba->filename); + if (!core) { + printf("failed to find core\n"); + return NULL; + } + + core->init(core); + + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + ssize_t videoBufferSize = width * height * BYTES_PER_PIXEL; + + uint32_t* videoBuffer = malloc(videoBufferSize * sizeof(*videoBuffer)); + + core->setVideoBuffer(core, videoBuffer, width); + + // load rom + mCoreLoadFile(core, mgba->filename); + + mCoreConfigInit(&core->config, NULL); + + core->reset(core); + + mgba->core = core; + mgba->videoBuffer = (struct video_buffer){ + .buffer = videoBuffer, + .width = width, + .height = height, + }; + + return mgba; +} + +void set_logger(void logger(char*)) { EXTERNAL_LOGGING = logger; } + +void free_runner(struct MGBA* mgba) { + mgba->core->deinit(mgba->core); + free(mgba->filename); + free(mgba->videoBuffer.buffer); + free(mgba); +} + +void advance_frame(struct MGBA* mgba) { mgba->core->runFrame(mgba->core); } + +struct video_buffer get_video_buffer(struct MGBA* mgba) { + return mgba->videoBuffer; +} + +void log_output(struct mLogger* _log, int category, enum mLogLevel level, + const char* format, va_list args) { + UNUSED(_log); + if (level & 31) { + int32_t size = 0; + + size += snprintf(NULL, 0, "[%s] %s: ", log_level_str(level), + mLogCategoryName(category)); + va_list args_copy; + va_copy(args_copy, args); + size += vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); + size += 1; + + char* str = calloc(size, sizeof(*str)); + + int32_t offset = snprintf(str, size, "[%s] %s: ", log_level_str(level), + mLogCategoryName(category)); + size -= offset; + vsnprintf(&str[offset], size, format, args); + + if (EXTERNAL_LOGGING != NULL) { + EXTERNAL_LOGGING(str); + } else { + printf("%s\n", str); + } + free(str); + } +} + +char* log_level_str(enum mLogLevel level) { + switch (level) { + case mLOG_FATAL: + return "FATAL"; + break; + case mLOG_ERROR: + return "ERROR"; + break; + case mLOG_WARN: + return "WARNING"; + break; + case mLOG_INFO: + return "INFO"; + break; + case mLOG_DEBUG: + return "DEBUG"; + break; + case mLOG_STUB: + return "STUB"; + break; + case mLOG_GAME_ERROR: + return "GAME ERROR"; + break; + default: + return "Unknown"; + } +} \ No newline at end of file diff --git a/mgba-test-runner/c/test-runner.h b/mgba-test-runner/c/test-runner.h new file mode 100644 index 00000000..de2bf0d4 --- /dev/null +++ b/mgba-test-runner/c/test-runner.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +struct MGBA; + +struct video_buffer { + uint32_t width; + uint32_t height; + uint32_t* buffer; +}; + +struct MGBA* new_runner(char filename[]); +void free_runner(struct MGBA* mgba); +void set_logger(void logger(char[])); +void advance_frame(struct MGBA* mgba); +struct video_buffer get_video_buffer(struct MGBA* mgba); \ No newline at end of file diff --git a/mgba-test-runner/src/main.rs b/mgba-test-runner/src/main.rs new file mode 100644 index 00000000..645cb5f8 --- /dev/null +++ b/mgba-test-runner/src/main.rs @@ -0,0 +1,89 @@ +#![allow(clippy::all)] + +mod runner; +use anyhow::{anyhow, Error}; +use io::Write; +use regex::Regex; +use std::cell::RefCell; +use std::io; +use std::path::Path; +use std::rc::Rc; + +#[derive(PartialEq, Eq, Debug, Clone)] +enum Status { + Running, + Failed, + Sucess, +} + +fn test_file(file_to_run: &str) -> Status { + let finished = Rc::new(RefCell::new(Status::Running)); + let debug_reader_mutex = Regex::new(r"^\[(.*)\] GBA Debug: (.*)$").unwrap(); + + let fin_closure = Rc::clone(&finished); + runner::set_logger(Box::new(move |message| { + if let Some(captures) = debug_reader_mutex.captures(message) { + let log_level = &captures[1]; + let out = &captures[2]; + + if out.ends_with("...") { + print!("{}", out); + io::stdout().flush().expect("can't flush stdout"); + } else { + println!("{}", out); + } + + if log_level == "FATAL" { + let mut done = fin_closure.borrow_mut(); + *done = Status::Failed; + } + + if out == "Tests finished successfully" { + let mut done = fin_closure.borrow_mut(); + *done = Status::Sucess; + } + } + })); + + let mut mgba = runner::MGBA::new(file_to_run); + + loop { + mgba.advance_frame(); + let done = finished.borrow(); + if *done != Status::Running { + break; + } + } + + runner::clear_logger(); + + return (*finished.borrow()).clone(); +} + +fn main() -> Result<(), Error> { + let args: Vec = std::env::args().collect(); + let file_to_run = args.get(1).expect("you should provide file to run"); + + if !Path::new(file_to_run).exists() { + return Err(anyhow!("File to run should exist!")); + } + + let output = test_file(file_to_run); + + match output { + Status::Failed => Err(anyhow!("Tests failed!")), + Status::Sucess => Ok(()), + _ => { + unreachable!("very bad thing happened"); + } + } +} + +fn gba_colour_to_rgba(colour: u32) -> [u8; 4] { + [ + (((((colour) << 3) & 0xF8) * 0x21) >> 5) as u8, + (((((colour) >> 2) & 0xF8) * 0x21) >> 5) as u8, + (((((colour) >> 7) & 0xF8) * 0x21) >> 5) as u8, + 255, + ] +} diff --git a/mgba-test-runner/src/runner/bindings.rs b/mgba-test-runner/src/runner/bindings.rs new file mode 100644 index 00000000..3332ee20 --- /dev/null +++ b/mgba-test-runner/src/runner/bindings.rs @@ -0,0 +1,274 @@ +/* automatically generated by rust-bindgen 0.58.1 */ + +pub const _STDINT_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const __GLIBC_USE_ISOC2X: u32 = 0; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_POSIX_IMPLICITLY: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 33; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; +pub const __HAVE_GENERIC_SELECTION: u32 = 1; +pub const __GLIBC_USE_LIB_EXT2: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 0; +pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0; +pub const _BITS_TYPES_H: u32 = 1; +pub const __TIMESIZE: u32 = 64; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __STATFS_MATCHES_STATFS64: u32 = 1; +pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const _BITS_TIME64_H: u32 = 1; +pub const _BITS_WCHAR_H: u32 = 1; +pub const _BITS_STDINT_INTN_H: u32 = 1; +pub const _BITS_STDINT_UINTN_H: u32 = 1; +pub const INT8_MIN: i32 = -128; +pub const INT16_MIN: i32 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; +pub const UINT8_MAX: u32 = 255; +pub const UINT16_MAX: u32 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: i32 = -128; +pub const INT_LEAST16_MIN: i32 = -32768; +pub const INT_LEAST32_MIN: i32 = -2147483648; +pub const INT_LEAST8_MAX: u32 = 127; +pub const INT_LEAST16_MAX: u32 = 32767; +pub const INT_LEAST32_MAX: u32 = 2147483647; +pub const UINT_LEAST8_MAX: u32 = 255; +pub const UINT_LEAST16_MAX: u32 = 65535; +pub const UINT_LEAST32_MAX: u32 = 4294967295; +pub const INT_FAST8_MIN: i32 = -128; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; +pub const INT_FAST8_MAX: u32 = 127; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; +pub const UINT_FAST8_MAX: u32 = 255; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; +pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINTPTR_MAX: i32 = -1; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; +pub const SIG_ATOMIC_MIN: i32 = -2147483648; +pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; +pub type __u_char = ::std::os::raw::c_uchar; +pub type __u_short = ::std::os::raw::c_ushort; +pub type __u_int = ::std::os::raw::c_uint; +pub type __u_long = ::std::os::raw::c_ulong; +pub type __int8_t = ::std::os::raw::c_schar; +pub type __uint8_t = ::std::os::raw::c_uchar; +pub type __int16_t = ::std::os::raw::c_short; +pub type __uint16_t = ::std::os::raw::c_ushort; +pub type __int32_t = ::std::os::raw::c_int; +pub type __uint32_t = ::std::os::raw::c_uint; +pub type __int64_t = ::std::os::raw::c_long; +pub type __uint64_t = ::std::os::raw::c_ulong; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; +pub type __quad_t = ::std::os::raw::c_long; +pub type __u_quad_t = ::std::os::raw::c_ulong; +pub type __intmax_t = ::std::os::raw::c_long; +pub type __uintmax_t = ::std::os::raw::c_ulong; +pub type __dev_t = ::std::os::raw::c_ulong; +pub type __uid_t = ::std::os::raw::c_uint; +pub type __gid_t = ::std::os::raw::c_uint; +pub type __ino_t = ::std::os::raw::c_ulong; +pub type __ino64_t = ::std::os::raw::c_ulong; +pub type __mode_t = ::std::os::raw::c_uint; +pub type __nlink_t = ::std::os::raw::c_ulong; +pub type __off_t = ::std::os::raw::c_long; +pub type __off64_t = ::std::os::raw::c_long; +pub type __pid_t = ::std::os::raw::c_int; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __fsid_t { + pub __val: [::std::os::raw::c_int; 2usize], +} +#[test] +fn bindgen_test_layout___fsid_t() { + assert_eq!( + ::std::mem::size_of::<__fsid_t>(), + 8usize, + concat!("Size of: ", stringify!(__fsid_t)) + ); + assert_eq!( + ::std::mem::align_of::<__fsid_t>(), + 4usize, + concat!("Alignment of ", stringify!(__fsid_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__fsid_t>())).__val as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__fsid_t), + "::", + stringify!(__val) + ) + ); +} +pub type __clock_t = ::std::os::raw::c_long; +pub type __rlim_t = ::std::os::raw::c_ulong; +pub type __rlim64_t = ::std::os::raw::c_ulong; +pub type __id_t = ::std::os::raw::c_uint; +pub type __time_t = ::std::os::raw::c_long; +pub type __useconds_t = ::std::os::raw::c_uint; +pub type __suseconds_t = ::std::os::raw::c_long; +pub type __suseconds64_t = ::std::os::raw::c_long; +pub type __daddr_t = ::std::os::raw::c_int; +pub type __key_t = ::std::os::raw::c_int; +pub type __clockid_t = ::std::os::raw::c_int; +pub type __timer_t = *mut ::std::os::raw::c_void; +pub type __blksize_t = ::std::os::raw::c_long; +pub type __blkcnt_t = ::std::os::raw::c_long; +pub type __blkcnt64_t = ::std::os::raw::c_long; +pub type __fsblkcnt_t = ::std::os::raw::c_ulong; +pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; +pub type __fsword_t = ::std::os::raw::c_long; +pub type __ssize_t = ::std::os::raw::c_long; +pub type __syscall_slong_t = ::std::os::raw::c_long; +pub type __syscall_ulong_t = ::std::os::raw::c_ulong; +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut ::std::os::raw::c_char; +pub type __intptr_t = ::std::os::raw::c_long; +pub type __socklen_t = ::std::os::raw::c_uint; +pub type __sig_atomic_t = ::std::os::raw::c_int; +pub type int_least8_t = __int_least8_t; +pub type int_least16_t = __int_least16_t; +pub type int_least32_t = __int_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least8_t = __uint_least8_t; +pub type uint_least16_t = __uint_least16_t; +pub type uint_least32_t = __uint_least32_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = ::std::os::raw::c_schar; +pub type int_fast16_t = ::std::os::raw::c_long; +pub type int_fast32_t = ::std::os::raw::c_long; +pub type int_fast64_t = ::std::os::raw::c_long; +pub type uint_fast8_t = ::std::os::raw::c_uchar; +pub type uint_fast16_t = ::std::os::raw::c_ulong; +pub type uint_fast32_t = ::std::os::raw::c_ulong; +pub type uint_fast64_t = ::std::os::raw::c_ulong; +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct MGBA { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct video_buffer { + pub width: u32, + pub height: u32, + pub buffer: *mut u32, +} +#[test] +fn bindgen_test_layout_video_buffer() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(video_buffer)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(video_buffer)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).width as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(video_buffer), + "::", + stringify!(width) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).height as *const _ as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(video_buffer), + "::", + stringify!(height) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).buffer as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(video_buffer), + "::", + stringify!(buffer) + ) + ); +} +extern "C" { + pub fn new_runner(filename: *mut ::std::os::raw::c_char) -> *mut MGBA; +} +extern "C" { + pub fn free_runner(mgba: *mut MGBA); +} +extern "C" { + pub fn set_logger( + logger: ::std::option::Option, + ); +} +extern "C" { + pub fn advance_frame(mgba: *mut MGBA); +} +extern "C" { + pub fn get_video_buffer(mgba: *mut MGBA) -> video_buffer; +} diff --git a/mgba-test-runner/src/runner/mod.rs b/mgba-test-runner/src/runner/mod.rs new file mode 100644 index 00000000..ac93c76c --- /dev/null +++ b/mgba-test-runner/src/runner/mod.rs @@ -0,0 +1,86 @@ +use std::ffi::CStr; +use std::ffi::CString; + +#[allow( + non_upper_case_globals, + dead_code, + non_camel_case_types, + non_snake_case +)] +mod bindings { + include!("bindings.rs"); +} + +pub struct MGBA { + mgba: *mut bindings::MGBA, +} + +pub struct VideoBuffer { + width: u32, + height: u32, + buffer: *mut u32, +} + +impl VideoBuffer { + pub fn get_size(&self) -> (u32, u32) { + (self.width, self.height) + } + pub fn get_pixel(&self, x: u32, y: u32) -> u32 { + let offset = (y * self.width + x) as isize; + assert!(x < self.width, "x must be in range 0 to {}", self.width); + assert!(y < self.height, "y must be in range 0 to {}", self.height); + unsafe { *self.buffer.offset(offset) } + } +} + +impl MGBA { + pub fn new(filename: &str) -> Self { + unsafe { bindings::set_logger(Some(logger)) }; + let c_str = CString::new(filename).expect("should be able to make cstring from filename"); + MGBA { + mgba: unsafe { bindings::new_runner(c_str.as_ptr() as *mut i8) }, + } + } + + pub fn get_video_buffer(&self) -> VideoBuffer { + let c_video_buffer = unsafe { bindings::get_video_buffer(self.mgba) }; + VideoBuffer { + width: c_video_buffer.width, + height: c_video_buffer.height, + buffer: c_video_buffer.buffer, + } + } + + pub fn advance_frame(&mut self) { + unsafe { bindings::advance_frame(self.mgba) } + } +} + +static mut CALLBACK: Option> = None; + +pub fn set_logger(x: Box) { + unsafe { + assert!(CALLBACK.is_none()); + CALLBACK = Some(x); + } +} + +pub fn clear_logger() { + unsafe { CALLBACK = None } +} + +extern "C" fn logger(c_str: *mut i8) { + unsafe { + if let Some(f) = &CALLBACK { + f(CStr::from_ptr(c_str) + .to_str() + .expect("should be able to convert logging message to rust String")); + } + } +} + +impl Drop for MGBA { + fn drop(&mut self) { + unsafe { bindings::free_runner(self.mgba) } + } +}