web-a2e 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.clangd +5 -0
- package/.mcp.json +12 -0
- package/CLAUDE.md +362 -0
- package/CMakeLists.txt +774 -0
- package/LICENSE +21 -0
- package/README.md +392 -0
- package/build-wasm/generated/roms.cpp +2447 -0
- package/docker-compose.staging.yml +9 -0
- package/docs/basic-rom-disassembly.md +6663 -0
- package/docs/softswitch-comparison.md +273 -0
- package/docs/thunderclock-debug.md +89 -0
- package/examples/cube.bas +72 -0
- package/examples/hello.s +55 -0
- package/examples/scroll.s +140 -0
- package/package.json +18 -0
- package/public/assets/apple-logo-old.png +0 -0
- package/public/assets/apple-logo.png +0 -0
- package/public/assets/drive-closed-light-on.png +0 -0
- package/public/assets/drive-closed.png +0 -0
- package/public/assets/drive-open-light-on.png +0 -0
- package/public/assets/drive-open.png +0 -0
- package/public/audio-worklet.js +82 -0
- package/public/disks/Apple DOS 3.3 January 1983.dsk +0 -0
- package/public/disks/ProDOS 2.4.3.po +0 -0
- package/public/disks/h32mb.2mg +0 -0
- package/public/disks/library.json +26 -0
- package/public/docs/llms/llm-assembler.txt +90 -0
- package/public/docs/llms/llm-basic-program.txt +256 -0
- package/public/docs/llms/llm-disk-drives.txt +72 -0
- package/public/docs/llms/llm-file-explorer.txt +50 -0
- package/public/docs/llms/llm-hard-drives.txt +80 -0
- package/public/docs/llms/llm-main.txt +51 -0
- package/public/docs/llms/llm-slot-configuration.txt +66 -0
- package/public/icons/icon-192.svg +4 -0
- package/public/icons/icon-512.svg +4 -0
- package/public/index.html +661 -0
- package/public/llms.txt +49 -0
- package/public/manifest.json +29 -0
- package/public/shaders/burnin.glsl +22 -0
- package/public/shaders/crt.glsl +706 -0
- package/public/shaders/edge.glsl +109 -0
- package/public/shaders/vertex.glsl +8 -0
- package/public/sw.js +186 -0
- package/roms/341-0027.bin +0 -0
- package/roms/341-0160-A-US-UK.bin +0 -0
- package/roms/341-0160-A.bin +0 -0
- package/roms/342-0273-A-US-UK.bin +0 -0
- package/roms/342-0349-B-C0-FF.bin +0 -0
- package/roms/Apple Mouse Interface Card ROM - 342-0270-C.bin +0 -0
- package/roms/Thunderclock Plus ROM.bin +0 -0
- package/scripts/generate_roms.sh +69 -0
- package/src/bindings/wasm_interface.cpp +1940 -0
- package/src/core/assembler/assembler.cpp +1239 -0
- package/src/core/assembler/assembler.hpp +115 -0
- package/src/core/audio/audio.cpp +160 -0
- package/src/core/audio/audio.hpp +81 -0
- package/src/core/basic/basic_detokenizer.cpp +436 -0
- package/src/core/basic/basic_detokenizer.hpp +41 -0
- package/src/core/basic/basic_tokenizer.cpp +286 -0
- package/src/core/basic/basic_tokenizer.hpp +26 -0
- package/src/core/basic/basic_tokens.hpp +295 -0
- package/src/core/cards/disk2_card.cpp +568 -0
- package/src/core/cards/disk2_card.hpp +316 -0
- package/src/core/cards/expansion_card.hpp +185 -0
- package/src/core/cards/mockingboard/ay8910.cpp +616 -0
- package/src/core/cards/mockingboard/ay8910.hpp +159 -0
- package/src/core/cards/mockingboard/via6522.cpp +530 -0
- package/src/core/cards/mockingboard/via6522.hpp +163 -0
- package/src/core/cards/mockingboard_card.cpp +312 -0
- package/src/core/cards/mockingboard_card.hpp +159 -0
- package/src/core/cards/mouse_card.cpp +654 -0
- package/src/core/cards/mouse_card.hpp +190 -0
- package/src/core/cards/smartport/block_device.cpp +202 -0
- package/src/core/cards/smartport/block_device.hpp +60 -0
- package/src/core/cards/smartport/smartport_card.cpp +603 -0
- package/src/core/cards/smartport/smartport_card.hpp +120 -0
- package/src/core/cards/thunderclock_card.cpp +237 -0
- package/src/core/cards/thunderclock_card.hpp +122 -0
- package/src/core/cpu/cpu6502.cpp +1609 -0
- package/src/core/cpu/cpu6502.hpp +203 -0
- package/src/core/debug/condition_evaluator.cpp +470 -0
- package/src/core/debug/condition_evaluator.hpp +87 -0
- package/src/core/disassembler/disassembler.cpp +552 -0
- package/src/core/disassembler/disassembler.hpp +171 -0
- package/src/core/disk-image/disk_image.hpp +267 -0
- package/src/core/disk-image/dsk_disk_image.cpp +827 -0
- package/src/core/disk-image/dsk_disk_image.hpp +204 -0
- package/src/core/disk-image/gcr_encoding.cpp +147 -0
- package/src/core/disk-image/gcr_encoding.hpp +78 -0
- package/src/core/disk-image/woz_disk_image.cpp +1049 -0
- package/src/core/disk-image/woz_disk_image.hpp +343 -0
- package/src/core/emulator.cpp +2126 -0
- package/src/core/emulator.hpp +434 -0
- package/src/core/filesystem/dos33.cpp +178 -0
- package/src/core/filesystem/dos33.hpp +66 -0
- package/src/core/filesystem/pascal.cpp +262 -0
- package/src/core/filesystem/pascal.hpp +87 -0
- package/src/core/filesystem/prodos.cpp +369 -0
- package/src/core/filesystem/prodos.hpp +119 -0
- package/src/core/input/keyboard.cpp +227 -0
- package/src/core/input/keyboard.hpp +111 -0
- package/src/core/mmu/mmu.cpp +1387 -0
- package/src/core/mmu/mmu.hpp +236 -0
- package/src/core/types.hpp +196 -0
- package/src/core/video/video.cpp +680 -0
- package/src/core/video/video.hpp +156 -0
- package/src/css/assembler-editor.css +1617 -0
- package/src/css/base.css +470 -0
- package/src/css/basic-debugger.css +791 -0
- package/src/css/basic-editor.css +792 -0
- package/src/css/controls.css +783 -0
- package/src/css/cpu-debugger.css +1413 -0
- package/src/css/debug-base.css +160 -0
- package/src/css/debug-windows.css +6455 -0
- package/src/css/disk-drives.css +406 -0
- package/src/css/documentation.css +392 -0
- package/src/css/file-explorer.css +867 -0
- package/src/css/hard-drive.css +180 -0
- package/src/css/layout.css +217 -0
- package/src/css/memory-windows.css +798 -0
- package/src/css/modals.css +510 -0
- package/src/css/monitor.css +425 -0
- package/src/css/release-notes.css +101 -0
- package/src/css/responsive.css +400 -0
- package/src/css/rule-builder.css +340 -0
- package/src/css/save-states.css +201 -0
- package/src/css/settings-windows.css +1231 -0
- package/src/css/window-switcher.css +150 -0
- package/src/js/agent/agent-manager.js +643 -0
- package/src/js/agent/agent-tools.js +293 -0
- package/src/js/agent/agent-version-tools.js +131 -0
- package/src/js/agent/assembler-tools.js +357 -0
- package/src/js/agent/basic-program-tools.js +894 -0
- package/src/js/agent/disk-tools.js +417 -0
- package/src/js/agent/file-explorer-tools.js +269 -0
- package/src/js/agent/index.js +13 -0
- package/src/js/agent/main-tools.js +222 -0
- package/src/js/agent/slot-tools.js +303 -0
- package/src/js/agent/smartport-tools.js +257 -0
- package/src/js/agent/window-tools.js +80 -0
- package/src/js/audio/audio-driver.js +417 -0
- package/src/js/audio/audio-worklet.js +85 -0
- package/src/js/audio/index.js +8 -0
- package/src/js/config/default-layout.js +34 -0
- package/src/js/config/version.js +8 -0
- package/src/js/data/apple2-rom-routines.js +577 -0
- package/src/js/debug/assembler-editor-window.js +2993 -0
- package/src/js/debug/basic-breakpoint-manager.js +529 -0
- package/src/js/debug/basic-program-parser.js +436 -0
- package/src/js/debug/basic-program-window.js +2594 -0
- package/src/js/debug/basic-variable-inspector.js +447 -0
- package/src/js/debug/breakpoint-manager.js +472 -0
- package/src/js/debug/cpu-debugger-window.js +2396 -0
- package/src/js/debug/index.js +22 -0
- package/src/js/debug/label-manager.js +238 -0
- package/src/js/debug/memory-browser-window.js +416 -0
- package/src/js/debug/memory-heat-map-window.js +481 -0
- package/src/js/debug/memory-map-window.js +206 -0
- package/src/js/debug/mockingboard-window.js +882 -0
- package/src/js/debug/mouse-card-window.js +355 -0
- package/src/js/debug/rule-builder-window.js +648 -0
- package/src/js/debug/soft-switch-window.js +458 -0
- package/src/js/debug/stack-viewer-window.js +221 -0
- package/src/js/debug/symbols.js +416 -0
- package/src/js/debug/trace-panel.js +291 -0
- package/src/js/debug/zero-page-watch-window.js +297 -0
- package/src/js/disk-manager/disk-drives-window.js +212 -0
- package/src/js/disk-manager/disk-operations.js +284 -0
- package/src/js/disk-manager/disk-persistence.js +301 -0
- package/src/js/disk-manager/disk-surface-renderer.js +388 -0
- package/src/js/disk-manager/drive-sounds.js +139 -0
- package/src/js/disk-manager/hard-drive-manager.js +481 -0
- package/src/js/disk-manager/hard-drive-persistence.js +187 -0
- package/src/js/disk-manager/hard-drive-window.js +57 -0
- package/src/js/disk-manager/index.js +890 -0
- package/src/js/display/display-settings-window.js +383 -0
- package/src/js/display/index.js +10 -0
- package/src/js/display/screen-window.js +342 -0
- package/src/js/display/webgl-renderer.js +705 -0
- package/src/js/file-explorer/disassembler.js +574 -0
- package/src/js/file-explorer/dos33.js +266 -0
- package/src/js/file-explorer/file-viewer.js +359 -0
- package/src/js/file-explorer/index.js +1261 -0
- package/src/js/file-explorer/prodos.js +549 -0
- package/src/js/file-explorer/utils.js +67 -0
- package/src/js/help/documentation-window.js +1096 -0
- package/src/js/help/index.js +10 -0
- package/src/js/help/release-notes-window.js +85 -0
- package/src/js/help/release-notes.js +612 -0
- package/src/js/input/gamepad-handler.js +176 -0
- package/src/js/input/index.js +12 -0
- package/src/js/input/input-handler.js +396 -0
- package/src/js/input/joystick-window.js +404 -0
- package/src/js/input/mouse-handler.js +99 -0
- package/src/js/input/text-selection.js +462 -0
- package/src/js/main.js +653 -0
- package/src/js/state/index.js +15 -0
- package/src/js/state/save-states-window.js +393 -0
- package/src/js/state/state-manager.js +409 -0
- package/src/js/state/state-persistence.js +218 -0
- package/src/js/ui/confirm.js +43 -0
- package/src/js/ui/disk-drive-positioner.js +347 -0
- package/src/js/ui/reminder-controller.js +129 -0
- package/src/js/ui/slot-configuration-window.js +560 -0
- package/src/js/ui/theme-manager.js +61 -0
- package/src/js/ui/toast.js +44 -0
- package/src/js/ui/ui-controller.js +897 -0
- package/src/js/ui/window-switcher.js +275 -0
- package/src/js/utils/basic-autocomplete.js +832 -0
- package/src/js/utils/basic-highlighting.js +473 -0
- package/src/js/utils/basic-tokenizer.js +153 -0
- package/src/js/utils/basic-tokens.js +117 -0
- package/src/js/utils/constants.js +28 -0
- package/src/js/utils/indexeddb-helper.js +225 -0
- package/src/js/utils/merlin-editor-support.js +905 -0
- package/src/js/utils/merlin-highlighting.js +551 -0
- package/src/js/utils/storage.js +125 -0
- package/src/js/utils/string-utils.js +19 -0
- package/src/js/utils/wasm-memory.js +54 -0
- package/src/js/windows/base-window.js +690 -0
- package/src/js/windows/index.js +9 -0
- package/src/js/windows/window-manager.js +375 -0
- package/tests/catch2/catch.hpp +17976 -0
- package/tests/common/basic_program_builder.cpp +119 -0
- package/tests/common/basic_program_builder.hpp +209 -0
- package/tests/common/disk_image_builder.cpp +444 -0
- package/tests/common/disk_image_builder.hpp +141 -0
- package/tests/common/test_helpers.hpp +118 -0
- package/tests/gcr/gcr-test.cpp +142 -0
- package/tests/integration/check-rom.js +70 -0
- package/tests/integration/compare-boot.js +239 -0
- package/tests/integration/crash-trace.js +102 -0
- package/tests/integration/disk-boot-test.js +264 -0
- package/tests/integration/memory-crash.js +108 -0
- package/tests/integration/nibble-read-test.js +249 -0
- package/tests/integration/phase-test.js +159 -0
- package/tests/integration/test_emulator.cpp +291 -0
- package/tests/integration/test_emulator_basic.cpp +91 -0
- package/tests/integration/test_emulator_debug.cpp +344 -0
- package/tests/integration/test_emulator_disk.cpp +153 -0
- package/tests/integration/test_emulator_state.cpp +163 -0
- package/tests/klaus/6502_functional_test.bin +0 -0
- package/tests/klaus/65C02_extended_opcodes_test.bin +0 -0
- package/tests/klaus/klaus_6502_test.cpp +184 -0
- package/tests/klaus/klaus_65c02_test.cpp +197 -0
- package/tests/thunderclock/thunderclock_mmu_test.cpp +304 -0
- package/tests/thunderclock/thunderclock_test.cpp +550 -0
- package/tests/unit/test_assembler.cpp +521 -0
- package/tests/unit/test_audio.cpp +196 -0
- package/tests/unit/test_ay8910.cpp +311 -0
- package/tests/unit/test_basic_detokenizer.cpp +265 -0
- package/tests/unit/test_basic_tokenizer.cpp +382 -0
- package/tests/unit/test_block_device.cpp +259 -0
- package/tests/unit/test_condition_evaluator.cpp +219 -0
- package/tests/unit/test_cpu6502.cpp +1301 -0
- package/tests/unit/test_cpu_addressing.cpp +361 -0
- package/tests/unit/test_cpu_cycle_counts.cpp +409 -0
- package/tests/unit/test_cpu_decimal.cpp +166 -0
- package/tests/unit/test_cpu_interrupts.cpp +285 -0
- package/tests/unit/test_disassembler.cpp +323 -0
- package/tests/unit/test_disk2_card.cpp +330 -0
- package/tests/unit/test_dos33.cpp +273 -0
- package/tests/unit/test_dsk_disk_image.cpp +315 -0
- package/tests/unit/test_expansion_card.cpp +178 -0
- package/tests/unit/test_gcr_encoding.cpp +232 -0
- package/tests/unit/test_keyboard.cpp +262 -0
- package/tests/unit/test_mmu.cpp +555 -0
- package/tests/unit/test_mmu_slots.cpp +323 -0
- package/tests/unit/test_mockingboard.cpp +352 -0
- package/tests/unit/test_mouse_card.cpp +386 -0
- package/tests/unit/test_pascal.cpp +248 -0
- package/tests/unit/test_prodos.cpp +259 -0
- package/tests/unit/test_smartport_card.cpp +321 -0
- package/tests/unit/test_thunderclock.cpp +354 -0
- package/tests/unit/test_via6522.cpp +323 -0
- package/tests/unit/test_video.cpp +319 -0
- package/tests/unit/test_woz_disk_image.cpp +257 -0
- package/vite.config.js +96 -0
- package/wiki/AI-Agent.md +372 -0
- package/wiki/Architecture-Overview.md +303 -0
- package/wiki/Audio-System.md +449 -0
- package/wiki/CPU-Emulation.md +477 -0
- package/wiki/Debugger.md +516 -0
- package/wiki/Disk-Drives.md +161 -0
- package/wiki/Disk-System-Internals.md +547 -0
- package/wiki/Display-Settings.md +88 -0
- package/wiki/Expansion-Slots.md +187 -0
- package/wiki/File-Explorer.md +259 -0
- package/wiki/Getting-Started.md +156 -0
- package/wiki/Home.md +69 -0
- package/wiki/Input-Devices.md +183 -0
- package/wiki/Keyboard-Shortcuts.md +158 -0
- package/wiki/Memory-System.md +364 -0
- package/wiki/Save-States.md +172 -0
- package/wiki/Video-Rendering.md +658 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* condition_evaluator.hpp - Expression parser for debugger breakpoint conditions and watches
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <cstring>
|
|
12
|
+
|
|
13
|
+
namespace a2e {
|
|
14
|
+
|
|
15
|
+
class Emulator;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Evaluates breakpoint condition expressions.
|
|
19
|
+
*
|
|
20
|
+
* Syntax:
|
|
21
|
+
* Registers: A, X, Y, SP, PC, P
|
|
22
|
+
* Flags: C, Z, I, D, B, V, N (return 0 or 1)
|
|
23
|
+
* Memory: PEEK($addr), DEEK($addr) (16-bit little-endian)
|
|
24
|
+
* Hex literals: #$FF, $FFFF
|
|
25
|
+
* Decimal literals: 42
|
|
26
|
+
* BASIC vars: BV(b1,b2) - simple variable, BA(b1,b2,idx) - array element
|
|
27
|
+
* b1,b2 are the encoded name bytes; type bits in high bits
|
|
28
|
+
* Comparisons: ==, !=, >=, <=, >, <
|
|
29
|
+
* Arithmetic: +, -, *
|
|
30
|
+
* Logic: &&, ||
|
|
31
|
+
* Grouping: ( )
|
|
32
|
+
*/
|
|
33
|
+
class ConditionEvaluator {
|
|
34
|
+
public:
|
|
35
|
+
/**
|
|
36
|
+
* Evaluate a condition expression as a boolean.
|
|
37
|
+
* Returns true if the condition is satisfied.
|
|
38
|
+
*/
|
|
39
|
+
static bool evaluate(const char* expr, const Emulator& emu);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Evaluate an expression and return the raw numeric value.
|
|
43
|
+
* Used for watch expressions.
|
|
44
|
+
*/
|
|
45
|
+
static int32_t evaluateNumeric(const char* expr, const Emulator& emu);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the last error message (empty string if no error).
|
|
49
|
+
*/
|
|
50
|
+
static const char* getLastError();
|
|
51
|
+
|
|
52
|
+
private:
|
|
53
|
+
// Token types
|
|
54
|
+
enum TokenType : uint8_t {
|
|
55
|
+
TOK_NUM, // Numeric literal
|
|
56
|
+
TOK_ID, // Identifier (register, PEEK, etc.)
|
|
57
|
+
TOK_OP2, // Two-character operator (==, !=, >=, <=, &&, ||)
|
|
58
|
+
TOK_OP1, // Single-character operator (<, >, +, -, *, (, ))
|
|
59
|
+
TOK_END // End of tokens
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
struct Token {
|
|
63
|
+
TokenType type;
|
|
64
|
+
int32_t numVal; // For TOK_NUM
|
|
65
|
+
char strVal[8]; // For TOK_ID or TOK_OP (null-terminated)
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
static constexpr int MAX_TOKENS = 128;
|
|
69
|
+
|
|
70
|
+
struct ParseState {
|
|
71
|
+
Token tokens[MAX_TOKENS];
|
|
72
|
+
int count;
|
|
73
|
+
int pos;
|
|
74
|
+
const Emulator* emu;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
static int tokenize(const char* expr, Token* tokens, int maxTokens);
|
|
78
|
+
static bool parseOr(ParseState& s);
|
|
79
|
+
static bool parseAnd(ParseState& s);
|
|
80
|
+
static bool parseComparison(ParseState& s);
|
|
81
|
+
static int32_t parseExpr(ParseState& s);
|
|
82
|
+
static int32_t parseAtom(ParseState& s);
|
|
83
|
+
|
|
84
|
+
static char errorBuf_[128];
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
} // namespace a2e
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* disassembler.cpp - 65C02 instruction disassembler with flow analysis
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "disassembler.hpp"
|
|
9
|
+
#include <algorithm>
|
|
10
|
+
#include <queue>
|
|
11
|
+
#include <unordered_set>
|
|
12
|
+
|
|
13
|
+
namespace a2e {
|
|
14
|
+
|
|
15
|
+
// Internal addressing mode enum for opcode table
|
|
16
|
+
enum AddrModeInt {
|
|
17
|
+
IMP = 0, ACC, IMM, ZP, ZPX, ZPY, ABS, ABX, ABY, IND, IZX, IZY, REL, ZPI, AIX, ZPR
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Internal category enum for opcode table
|
|
21
|
+
enum CategoryInt {
|
|
22
|
+
CAT_BRANCH = 0, CAT_LOAD, CAT_MATH, CAT_STACK, CAT_FLAG, CAT_UNKNOWN
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// OpcodeInfo is defined in disassembler.hpp
|
|
26
|
+
|
|
27
|
+
// Mnemonic table - index corresponds to mnemonicIndex in DisasmInstruction
|
|
28
|
+
static const char* MNEMONICS[] = {
|
|
29
|
+
"???", // 0 - unknown
|
|
30
|
+
"ADC", // 1
|
|
31
|
+
"AND", // 2
|
|
32
|
+
"ASL", // 3
|
|
33
|
+
"BBR0", // 4
|
|
34
|
+
"BBR1", // 5
|
|
35
|
+
"BBR2", // 6
|
|
36
|
+
"BBR3", // 7
|
|
37
|
+
"BBR4", // 8
|
|
38
|
+
"BBR5", // 9
|
|
39
|
+
"BBR6", // 10
|
|
40
|
+
"BBR7", // 11
|
|
41
|
+
"BBS0", // 12
|
|
42
|
+
"BBS1", // 13
|
|
43
|
+
"BBS2", // 14
|
|
44
|
+
"BBS3", // 15
|
|
45
|
+
"BBS4", // 16
|
|
46
|
+
"BBS5", // 17
|
|
47
|
+
"BBS6", // 18
|
|
48
|
+
"BBS7", // 19
|
|
49
|
+
"BCC", // 20
|
|
50
|
+
"BCS", // 21
|
|
51
|
+
"BEQ", // 22
|
|
52
|
+
"BIT", // 23
|
|
53
|
+
"BMI", // 24
|
|
54
|
+
"BNE", // 25
|
|
55
|
+
"BPL", // 26
|
|
56
|
+
"BRA", // 27
|
|
57
|
+
"BRK", // 28
|
|
58
|
+
"BVC", // 29
|
|
59
|
+
"BVS", // 30
|
|
60
|
+
"CLC", // 31
|
|
61
|
+
"CLD", // 32
|
|
62
|
+
"CLI", // 33
|
|
63
|
+
"CLV", // 34
|
|
64
|
+
"CMP", // 35
|
|
65
|
+
"CPX", // 36
|
|
66
|
+
"CPY", // 37
|
|
67
|
+
"DEC", // 38
|
|
68
|
+
"DEX", // 39
|
|
69
|
+
"DEY", // 40
|
|
70
|
+
"EOR", // 41
|
|
71
|
+
"INC", // 42
|
|
72
|
+
"INX", // 43
|
|
73
|
+
"INY", // 44
|
|
74
|
+
"JMP", // 45
|
|
75
|
+
"JSR", // 46
|
|
76
|
+
"LDA", // 47
|
|
77
|
+
"LDX", // 48
|
|
78
|
+
"LDY", // 49
|
|
79
|
+
"LSR", // 50
|
|
80
|
+
"NOP", // 51
|
|
81
|
+
"ORA", // 52
|
|
82
|
+
"PHA", // 53
|
|
83
|
+
"PHP", // 54
|
|
84
|
+
"PHX", // 55
|
|
85
|
+
"PHY", // 56
|
|
86
|
+
"PLA", // 57
|
|
87
|
+
"PLP", // 58
|
|
88
|
+
"PLX", // 59
|
|
89
|
+
"PLY", // 60
|
|
90
|
+
"RMB0", // 61
|
|
91
|
+
"RMB1", // 62
|
|
92
|
+
"RMB2", // 63
|
|
93
|
+
"RMB3", // 64
|
|
94
|
+
"RMB4", // 65
|
|
95
|
+
"RMB5", // 66
|
|
96
|
+
"RMB6", // 67
|
|
97
|
+
"RMB7", // 68
|
|
98
|
+
"ROL", // 69
|
|
99
|
+
"ROR", // 70
|
|
100
|
+
"RTI", // 71
|
|
101
|
+
"RTS", // 72
|
|
102
|
+
"SBC", // 73
|
|
103
|
+
"SEC", // 74
|
|
104
|
+
"SED", // 75
|
|
105
|
+
"SEI", // 76
|
|
106
|
+
"SMB0", // 77
|
|
107
|
+
"SMB1", // 78
|
|
108
|
+
"SMB2", // 79
|
|
109
|
+
"SMB3", // 80
|
|
110
|
+
"SMB4", // 81
|
|
111
|
+
"SMB5", // 82
|
|
112
|
+
"SMB6", // 83
|
|
113
|
+
"SMB7", // 84
|
|
114
|
+
"STA", // 85
|
|
115
|
+
"STP", // 86
|
|
116
|
+
"STX", // 87
|
|
117
|
+
"STY", // 88
|
|
118
|
+
"STZ", // 89
|
|
119
|
+
"TAX", // 90
|
|
120
|
+
"TAY", // 91
|
|
121
|
+
"TRB", // 92
|
|
122
|
+
"TSB", // 93
|
|
123
|
+
"TSX", // 94
|
|
124
|
+
"TXA", // 95
|
|
125
|
+
"TXS", // 96
|
|
126
|
+
"TYA", // 97
|
|
127
|
+
"WAI", // 98
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Mnemonic indices
|
|
131
|
+
enum MnemIdx {
|
|
132
|
+
M_UNK = 0,
|
|
133
|
+
M_ADC = 1, M_AND, M_ASL,
|
|
134
|
+
M_BBR0, M_BBR1, M_BBR2, M_BBR3, M_BBR4, M_BBR5, M_BBR6, M_BBR7,
|
|
135
|
+
M_BBS0, M_BBS1, M_BBS2, M_BBS3, M_BBS4, M_BBS5, M_BBS6, M_BBS7,
|
|
136
|
+
M_BCC, M_BCS, M_BEQ, M_BIT, M_BMI, M_BNE, M_BPL, M_BRA, M_BRK, M_BVC, M_BVS,
|
|
137
|
+
M_CLC, M_CLD, M_CLI, M_CLV, M_CMP, M_CPX, M_CPY,
|
|
138
|
+
M_DEC, M_DEX, M_DEY,
|
|
139
|
+
M_EOR,
|
|
140
|
+
M_INC, M_INX, M_INY,
|
|
141
|
+
M_JMP, M_JSR,
|
|
142
|
+
M_LDA, M_LDX, M_LDY, M_LSR,
|
|
143
|
+
M_NOP,
|
|
144
|
+
M_ORA,
|
|
145
|
+
M_PHA, M_PHP, M_PHX, M_PHY, M_PLA, M_PLP, M_PLX, M_PLY,
|
|
146
|
+
M_RMB0, M_RMB1, M_RMB2, M_RMB3, M_RMB4, M_RMB5, M_RMB6, M_RMB7,
|
|
147
|
+
M_ROL, M_ROR, M_RTI, M_RTS,
|
|
148
|
+
M_SBC, M_SEC, M_SED, M_SEI,
|
|
149
|
+
M_SMB0, M_SMB1, M_SMB2, M_SMB3, M_SMB4, M_SMB5, M_SMB6, M_SMB7,
|
|
150
|
+
M_STA, M_STP, M_STX, M_STY, M_STZ,
|
|
151
|
+
M_TAX, M_TAY, M_TRB, M_TSB, M_TSX, M_TXA, M_TXS, M_TYA,
|
|
152
|
+
M_WAI
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Full 65C02 opcode table: {mnemonicIndex, mode, category}
|
|
156
|
+
static const OpcodeInfo opcodes[256] = {
|
|
157
|
+
// 0x00-0x0F
|
|
158
|
+
{M_BRK, IMP, CAT_STACK}, {M_ORA, IZX, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
159
|
+
{M_TSB, ZP, CAT_MATH}, {M_ORA, ZP, CAT_MATH}, {M_ASL, ZP, CAT_MATH}, {M_RMB0, ZP, CAT_MATH},
|
|
160
|
+
{M_PHP, IMP, CAT_STACK}, {M_ORA, IMM, CAT_MATH}, {M_ASL, ACC, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
161
|
+
{M_TSB, ABS, CAT_MATH}, {M_ORA, ABS, CAT_MATH}, {M_ASL, ABS, CAT_MATH}, {M_BBR0, ZPR, CAT_BRANCH},
|
|
162
|
+
// 0x10-0x1F
|
|
163
|
+
{M_BPL, REL, CAT_BRANCH}, {M_ORA, IZY, CAT_MATH}, {M_ORA, ZPI, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
164
|
+
{M_TRB, ZP, CAT_MATH}, {M_ORA, ZPX, CAT_MATH}, {M_ASL, ZPX, CAT_MATH}, {M_RMB1, ZP, CAT_MATH},
|
|
165
|
+
{M_CLC, IMP, CAT_FLAG}, {M_ORA, ABY, CAT_MATH}, {M_INC, ACC, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
166
|
+
{M_TRB, ABS, CAT_MATH}, {M_ORA, ABX, CAT_MATH}, {M_ASL, ABX, CAT_MATH}, {M_BBR1, ZPR, CAT_BRANCH},
|
|
167
|
+
// 0x20-0x2F
|
|
168
|
+
{M_JSR, ABS, CAT_BRANCH}, {M_AND, IZX, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
169
|
+
{M_BIT, ZP, CAT_MATH}, {M_AND, ZP, CAT_MATH}, {M_ROL, ZP, CAT_MATH}, {M_RMB2, ZP, CAT_MATH},
|
|
170
|
+
{M_PLP, IMP, CAT_STACK}, {M_AND, IMM, CAT_MATH}, {M_ROL, ACC, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
171
|
+
{M_BIT, ABS, CAT_MATH}, {M_AND, ABS, CAT_MATH}, {M_ROL, ABS, CAT_MATH}, {M_BBR2, ZPR, CAT_BRANCH},
|
|
172
|
+
// 0x30-0x3F
|
|
173
|
+
{M_BMI, REL, CAT_BRANCH}, {M_AND, IZY, CAT_MATH}, {M_AND, ZPI, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
174
|
+
{M_BIT, ZPX, CAT_MATH}, {M_AND, ZPX, CAT_MATH}, {M_ROL, ZPX, CAT_MATH}, {M_RMB3, ZP, CAT_MATH},
|
|
175
|
+
{M_SEC, IMP, CAT_FLAG}, {M_AND, ABY, CAT_MATH}, {M_DEC, ACC, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
176
|
+
{M_BIT, ABX, CAT_MATH}, {M_AND, ABX, CAT_MATH}, {M_ROL, ABX, CAT_MATH}, {M_BBR3, ZPR, CAT_BRANCH},
|
|
177
|
+
// 0x40-0x4F
|
|
178
|
+
{M_RTI, IMP, CAT_BRANCH}, {M_EOR, IZX, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
179
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_EOR, ZP, CAT_MATH}, {M_LSR, ZP, CAT_MATH}, {M_RMB4, ZP, CAT_MATH},
|
|
180
|
+
{M_PHA, IMP, CAT_STACK}, {M_EOR, IMM, CAT_MATH}, {M_LSR, ACC, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
181
|
+
{M_JMP, ABS, CAT_BRANCH}, {M_EOR, ABS, CAT_MATH}, {M_LSR, ABS, CAT_MATH}, {M_BBR4, ZPR, CAT_BRANCH},
|
|
182
|
+
// 0x50-0x5F
|
|
183
|
+
{M_BVC, REL, CAT_BRANCH}, {M_EOR, IZY, CAT_MATH}, {M_EOR, ZPI, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
184
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_EOR, ZPX, CAT_MATH}, {M_LSR, ZPX, CAT_MATH}, {M_RMB5, ZP, CAT_MATH},
|
|
185
|
+
{M_CLI, IMP, CAT_FLAG}, {M_EOR, ABY, CAT_MATH}, {M_PHY, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
186
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_EOR, ABX, CAT_MATH}, {M_LSR, ABX, CAT_MATH}, {M_BBR5, ZPR, CAT_BRANCH},
|
|
187
|
+
// 0x60-0x6F
|
|
188
|
+
{M_RTS, IMP, CAT_BRANCH}, {M_ADC, IZX, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
189
|
+
{M_STZ, ZP, CAT_LOAD}, {M_ADC, ZP, CAT_MATH}, {M_ROR, ZP, CAT_MATH}, {M_RMB6, ZP, CAT_MATH},
|
|
190
|
+
{M_PLA, IMP, CAT_STACK}, {M_ADC, IMM, CAT_MATH}, {M_ROR, ACC, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
191
|
+
{M_JMP, IND, CAT_BRANCH}, {M_ADC, ABS, CAT_MATH}, {M_ROR, ABS, CAT_MATH}, {M_BBR6, ZPR, CAT_BRANCH},
|
|
192
|
+
// 0x70-0x7F
|
|
193
|
+
{M_BVS, REL, CAT_BRANCH}, {M_ADC, IZY, CAT_MATH}, {M_ADC, ZPI, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
194
|
+
{M_STZ, ZPX, CAT_LOAD}, {M_ADC, ZPX, CAT_MATH}, {M_ROR, ZPX, CAT_MATH}, {M_RMB7, ZP, CAT_MATH},
|
|
195
|
+
{M_SEI, IMP, CAT_FLAG}, {M_ADC, ABY, CAT_MATH}, {M_PLY, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
196
|
+
{M_JMP, AIX, CAT_BRANCH}, {M_ADC, ABX, CAT_MATH}, {M_ROR, ABX, CAT_MATH}, {M_BBR7, ZPR, CAT_BRANCH},
|
|
197
|
+
// 0x80-0x8F
|
|
198
|
+
{M_BRA, REL, CAT_BRANCH}, {M_STA, IZX, CAT_LOAD}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
199
|
+
{M_STY, ZP, CAT_LOAD}, {M_STA, ZP, CAT_LOAD}, {M_STX, ZP, CAT_LOAD}, {M_SMB0, ZP, CAT_MATH},
|
|
200
|
+
{M_DEY, IMP, CAT_STACK}, {M_BIT, IMM, CAT_MATH}, {M_TXA, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
201
|
+
{M_STY, ABS, CAT_LOAD}, {M_STA, ABS, CAT_LOAD}, {M_STX, ABS, CAT_LOAD}, {M_BBS0, ZPR, CAT_BRANCH},
|
|
202
|
+
// 0x90-0x9F
|
|
203
|
+
{M_BCC, REL, CAT_BRANCH}, {M_STA, IZY, CAT_LOAD}, {M_STA, ZPI, CAT_LOAD}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
204
|
+
{M_STY, ZPX, CAT_LOAD}, {M_STA, ZPX, CAT_LOAD}, {M_STX, ZPY, CAT_LOAD}, {M_SMB1, ZP, CAT_MATH},
|
|
205
|
+
{M_TYA, IMP, CAT_STACK}, {M_STA, ABY, CAT_LOAD}, {M_TXS, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
206
|
+
{M_STZ, ABS, CAT_LOAD}, {M_STA, ABX, CAT_LOAD}, {M_STZ, ABX, CAT_LOAD}, {M_BBS1, ZPR, CAT_BRANCH},
|
|
207
|
+
// 0xA0-0xAF
|
|
208
|
+
{M_LDY, IMM, CAT_LOAD}, {M_LDA, IZX, CAT_LOAD}, {M_LDX, IMM, CAT_LOAD}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
209
|
+
{M_LDY, ZP, CAT_LOAD}, {M_LDA, ZP, CAT_LOAD}, {M_LDX, ZP, CAT_LOAD}, {M_SMB2, ZP, CAT_MATH},
|
|
210
|
+
{M_TAY, IMP, CAT_STACK}, {M_LDA, IMM, CAT_LOAD}, {M_TAX, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
211
|
+
{M_LDY, ABS, CAT_LOAD}, {M_LDA, ABS, CAT_LOAD}, {M_LDX, ABS, CAT_LOAD}, {M_BBS2, ZPR, CAT_BRANCH},
|
|
212
|
+
// 0xB0-0xBF
|
|
213
|
+
{M_BCS, REL, CAT_BRANCH}, {M_LDA, IZY, CAT_LOAD}, {M_LDA, ZPI, CAT_LOAD}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
214
|
+
{M_LDY, ZPX, CAT_LOAD}, {M_LDA, ZPX, CAT_LOAD}, {M_LDX, ZPY, CAT_LOAD}, {M_SMB3, ZP, CAT_MATH},
|
|
215
|
+
{M_CLV, IMP, CAT_FLAG}, {M_LDA, ABY, CAT_LOAD}, {M_TSX, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
216
|
+
{M_LDY, ABX, CAT_LOAD}, {M_LDA, ABX, CAT_LOAD}, {M_LDX, ABY, CAT_LOAD}, {M_BBS3, ZPR, CAT_BRANCH},
|
|
217
|
+
// 0xC0-0xCF
|
|
218
|
+
{M_CPY, IMM, CAT_MATH}, {M_CMP, IZX, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
219
|
+
{M_CPY, ZP, CAT_MATH}, {M_CMP, ZP, CAT_MATH}, {M_DEC, ZP, CAT_MATH}, {M_SMB4, ZP, CAT_MATH},
|
|
220
|
+
{M_INY, IMP, CAT_STACK}, {M_CMP, IMM, CAT_MATH}, {M_DEX, IMP, CAT_STACK}, {M_WAI, IMP, CAT_STACK},
|
|
221
|
+
{M_CPY, ABS, CAT_MATH}, {M_CMP, ABS, CAT_MATH}, {M_DEC, ABS, CAT_MATH}, {M_BBS4, ZPR, CAT_BRANCH},
|
|
222
|
+
// 0xD0-0xDF
|
|
223
|
+
{M_BNE, REL, CAT_BRANCH}, {M_CMP, IZY, CAT_MATH}, {M_CMP, ZPI, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
224
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_CMP, ZPX, CAT_MATH}, {M_DEC, ZPX, CAT_MATH}, {M_SMB5, ZP, CAT_MATH},
|
|
225
|
+
{M_CLD, IMP, CAT_FLAG}, {M_CMP, ABY, CAT_MATH}, {M_PHX, IMP, CAT_STACK}, {M_STP, IMP, CAT_STACK},
|
|
226
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_CMP, ABX, CAT_MATH}, {M_DEC, ABX, CAT_MATH}, {M_BBS5, ZPR, CAT_BRANCH},
|
|
227
|
+
// 0xE0-0xEF
|
|
228
|
+
{M_CPX, IMM, CAT_MATH}, {M_SBC, IZX, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
229
|
+
{M_CPX, ZP, CAT_MATH}, {M_SBC, ZP, CAT_MATH}, {M_INC, ZP, CAT_MATH}, {M_SMB6, ZP, CAT_MATH},
|
|
230
|
+
{M_INX, IMP, CAT_STACK}, {M_SBC, IMM, CAT_MATH}, {M_NOP, IMP, CAT_FLAG}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
231
|
+
{M_CPX, ABS, CAT_MATH}, {M_SBC, ABS, CAT_MATH}, {M_INC, ABS, CAT_MATH}, {M_BBS6, ZPR, CAT_BRANCH},
|
|
232
|
+
// 0xF0-0xFF
|
|
233
|
+
{M_BEQ, REL, CAT_BRANCH}, {M_SBC, IZY, CAT_MATH}, {M_SBC, ZPI, CAT_MATH}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
234
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_SBC, ZPX, CAT_MATH}, {M_INC, ZPX, CAT_MATH}, {M_SMB7, ZP, CAT_MATH},
|
|
235
|
+
{M_SED, IMP, CAT_FLAG}, {M_SBC, ABY, CAT_MATH}, {M_PLX, IMP, CAT_STACK}, {M_UNK, IMP, CAT_UNKNOWN},
|
|
236
|
+
{M_UNK, IMP, CAT_UNKNOWN},{M_SBC, ABX, CAT_MATH}, {M_INC, ABX, CAT_MATH}, {M_BBS7, ZPR, CAT_BRANCH}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
int getInstructionLength(uint8_t opcode) {
|
|
240
|
+
switch (opcodes[opcode].mode) {
|
|
241
|
+
case IMP:
|
|
242
|
+
case ACC:
|
|
243
|
+
return 1;
|
|
244
|
+
case IMM:
|
|
245
|
+
case ZP:
|
|
246
|
+
case ZPX:
|
|
247
|
+
case ZPY:
|
|
248
|
+
case IZX:
|
|
249
|
+
case IZY:
|
|
250
|
+
case ZPI:
|
|
251
|
+
case REL:
|
|
252
|
+
return 2;
|
|
253
|
+
case ABS:
|
|
254
|
+
case ABX:
|
|
255
|
+
case ABY:
|
|
256
|
+
case IND:
|
|
257
|
+
case AIX:
|
|
258
|
+
case ZPR:
|
|
259
|
+
return 3;
|
|
260
|
+
}
|
|
261
|
+
return 1;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const char* getMnemonic(uint8_t opcode) {
|
|
265
|
+
return MNEMONICS[opcodes[opcode].mnemonicIndex];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const char* getMnemonicByIndex(uint8_t index) {
|
|
269
|
+
if (index >= sizeof(MNEMONICS) / sizeof(MNEMONICS[0])) {
|
|
270
|
+
return "???";
|
|
271
|
+
}
|
|
272
|
+
return MNEMONICS[index];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
AddrMode getAddressingMode(uint8_t opcode) {
|
|
276
|
+
return static_cast<AddrMode>(opcodes[opcode].mode);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
InstrCategory getInstructionCategory(uint8_t opcode) {
|
|
280
|
+
return static_cast<InstrCategory>(opcodes[opcode].category);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const OpcodeInfo* getOpcodeTable() {
|
|
284
|
+
return opcodes;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
int getMnemonicCount() {
|
|
288
|
+
return static_cast<int>(sizeof(MNEMONICS) / sizeof(MNEMONICS[0]));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
DisasmInstruction disassembleInstruction(const uint8_t *data, size_t size,
|
|
292
|
+
uint16_t address) {
|
|
293
|
+
DisasmInstruction instr = {};
|
|
294
|
+
instr.address = address;
|
|
295
|
+
|
|
296
|
+
if (size == 0 || data == nullptr) {
|
|
297
|
+
instr.length = 0;
|
|
298
|
+
instr.mnemonic[0] = '?';
|
|
299
|
+
instr.mnemonic[1] = '?';
|
|
300
|
+
instr.mnemonic[2] = '?';
|
|
301
|
+
instr.mnemonic[3] = '\0';
|
|
302
|
+
return instr;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
uint8_t opcode = data[0];
|
|
306
|
+
const OpcodeInfo &info = opcodes[opcode];
|
|
307
|
+
int instrLen = getInstructionLength(opcode);
|
|
308
|
+
|
|
309
|
+
instr.opcode = opcode;
|
|
310
|
+
instr.length = static_cast<uint8_t>(instrLen);
|
|
311
|
+
instr.mode = info.mode;
|
|
312
|
+
instr.category = info.category;
|
|
313
|
+
|
|
314
|
+
// Read operand bytes (if available)
|
|
315
|
+
instr.operand1 = (size > 1 && instrLen >= 2) ? data[1] : 0;
|
|
316
|
+
instr.operand2 = (size > 2 && instrLen >= 3) ? data[2] : 0;
|
|
317
|
+
|
|
318
|
+
// Calculate target address for branches and jumps
|
|
319
|
+
instr.target = 0;
|
|
320
|
+
switch (info.mode) {
|
|
321
|
+
case REL: {
|
|
322
|
+
int8_t offset = static_cast<int8_t>(instr.operand1);
|
|
323
|
+
instr.target = static_cast<uint16_t>(address + 2 + offset);
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
case ZPR: {
|
|
327
|
+
int8_t offset = static_cast<int8_t>(instr.operand2);
|
|
328
|
+
instr.target = static_cast<uint16_t>(address + 3 + offset);
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
case ABS:
|
|
332
|
+
case ABX:
|
|
333
|
+
case ABY:
|
|
334
|
+
case IND:
|
|
335
|
+
case AIX:
|
|
336
|
+
instr.target = static_cast<uint16_t>(instr.operand1 | (instr.operand2 << 8));
|
|
337
|
+
break;
|
|
338
|
+
default:
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Copy mnemonic string (max 4 chars, null-padded)
|
|
343
|
+
const char* mnem = MNEMONICS[info.mnemonicIndex];
|
|
344
|
+
for (int i = 0; i < 4; i++) {
|
|
345
|
+
instr.mnemonic[i] = mnem[i];
|
|
346
|
+
if (mnem[i] == '\0') {
|
|
347
|
+
// Null-pad remainder
|
|
348
|
+
for (int j = i + 1; j < 4; j++) {
|
|
349
|
+
instr.mnemonic[j] = '\0';
|
|
350
|
+
}
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return instr;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
DisasmResult disassembleBlock(const uint8_t *data, size_t size,
|
|
359
|
+
uint16_t baseAddress) {
|
|
360
|
+
DisasmResult result;
|
|
361
|
+
|
|
362
|
+
if (size == 0 || data == nullptr) {
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Reserve approximate space
|
|
367
|
+
result.instructions.reserve(size / 2);
|
|
368
|
+
|
|
369
|
+
size_t offset = 0;
|
|
370
|
+
while (offset < size) {
|
|
371
|
+
DisasmInstruction instr = disassembleInstruction(
|
|
372
|
+
data + offset, size - offset,
|
|
373
|
+
static_cast<uint16_t>(baseAddress + offset));
|
|
374
|
+
|
|
375
|
+
if (instr.length == 0) {
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
result.instructions.push_back(instr);
|
|
380
|
+
offset += instr.length;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
FlowType getFlowType(uint8_t opcode) {
|
|
387
|
+
const OpcodeInfo &info = opcodes[opcode];
|
|
388
|
+
uint8_t mnem = info.mnemonicIndex;
|
|
389
|
+
|
|
390
|
+
// Return instructions - stop tracing this path
|
|
391
|
+
if (mnem == M_RTS || mnem == M_RTI) {
|
|
392
|
+
return FlowType::RETURN;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Halt instructions - stop tracing
|
|
396
|
+
if (mnem == M_BRK || mnem == M_STP || mnem == M_WAI) {
|
|
397
|
+
return FlowType::HALT;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// JSR - subroutine call, will return
|
|
401
|
+
if (mnem == M_JSR) {
|
|
402
|
+
return FlowType::CALL;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// JMP - depends on addressing mode
|
|
406
|
+
if (mnem == M_JMP) {
|
|
407
|
+
// Indirect jumps can't be traced statically
|
|
408
|
+
if (info.mode == IND || info.mode == AIX) {
|
|
409
|
+
return FlowType::INDIRECT;
|
|
410
|
+
}
|
|
411
|
+
// Absolute JMP is unconditional
|
|
412
|
+
return FlowType::UNCONDITIONAL;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// BRA (65C02) - unconditional branch
|
|
416
|
+
if (mnem == M_BRA) {
|
|
417
|
+
return FlowType::UNCONDITIONAL;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Conditional branches - Bxx instructions
|
|
421
|
+
if (mnem == M_BPL || mnem == M_BMI || mnem == M_BVC || mnem == M_BVS ||
|
|
422
|
+
mnem == M_BCC || mnem == M_BCS || mnem == M_BEQ || mnem == M_BNE) {
|
|
423
|
+
return FlowType::CONDITIONAL;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// BBR/BBS (65C02) - conditional branches
|
|
427
|
+
if ((mnem >= M_BBR0 && mnem <= M_BBR7) ||
|
|
428
|
+
(mnem >= M_BBS0 && mnem <= M_BBS7)) {
|
|
429
|
+
return FlowType::CONDITIONAL;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Everything else is sequential
|
|
433
|
+
return FlowType::SEQUENTIAL;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
DisasmResult disassembleWithFlowAnalysis(const uint8_t *data, size_t size,
|
|
437
|
+
uint16_t baseAddress,
|
|
438
|
+
const std::vector<uint16_t> &entryPoints) {
|
|
439
|
+
DisasmResult result;
|
|
440
|
+
|
|
441
|
+
if (size == 0 || data == nullptr || entryPoints.empty()) {
|
|
442
|
+
return result;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Calculate valid address range
|
|
446
|
+
uint16_t endAddress = static_cast<uint16_t>(baseAddress + size);
|
|
447
|
+
|
|
448
|
+
// Track visited addresses to avoid re-processing
|
|
449
|
+
std::unordered_set<uint16_t> visited;
|
|
450
|
+
|
|
451
|
+
// Work queue of addresses to visit
|
|
452
|
+
std::queue<uint16_t> toVisit;
|
|
453
|
+
|
|
454
|
+
// Initialize with entry points
|
|
455
|
+
for (uint16_t entry : entryPoints) {
|
|
456
|
+
if (entry >= baseAddress && entry < endAddress) {
|
|
457
|
+
toVisit.push(entry);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Reserve approximate space
|
|
462
|
+
result.instructions.reserve(size / 2);
|
|
463
|
+
|
|
464
|
+
// Process addresses until queue is empty
|
|
465
|
+
while (!toVisit.empty()) {
|
|
466
|
+
uint16_t addr = toVisit.front();
|
|
467
|
+
toVisit.pop();
|
|
468
|
+
|
|
469
|
+
// Skip if already visited or out of range
|
|
470
|
+
if (visited.count(addr) || addr < baseAddress || addr >= endAddress) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Mark as visited
|
|
475
|
+
visited.insert(addr);
|
|
476
|
+
|
|
477
|
+
// Calculate offset into data buffer
|
|
478
|
+
size_t offset = addr - baseAddress;
|
|
479
|
+
|
|
480
|
+
// Disassemble instruction at this address
|
|
481
|
+
DisasmInstruction instr = disassembleInstruction(
|
|
482
|
+
data + offset, size - offset, addr);
|
|
483
|
+
|
|
484
|
+
if (instr.length == 0) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
result.instructions.push_back(instr);
|
|
489
|
+
|
|
490
|
+
// Determine what addresses to visit next based on flow type
|
|
491
|
+
FlowType flow = getFlowType(instr.opcode);
|
|
492
|
+
uint16_t nextAddr = static_cast<uint16_t>(addr + instr.length);
|
|
493
|
+
|
|
494
|
+
switch (flow) {
|
|
495
|
+
case FlowType::SEQUENTIAL:
|
|
496
|
+
// Continue to next instruction
|
|
497
|
+
if (nextAddr >= baseAddress && nextAddr < endAddress) {
|
|
498
|
+
toVisit.push(nextAddr);
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
|
|
502
|
+
case FlowType::CONDITIONAL:
|
|
503
|
+
// Add both target and fall-through
|
|
504
|
+
if (nextAddr >= baseAddress && nextAddr < endAddress) {
|
|
505
|
+
toVisit.push(nextAddr);
|
|
506
|
+
}
|
|
507
|
+
if (instr.target >= baseAddress && instr.target < endAddress) {
|
|
508
|
+
toVisit.push(instr.target);
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
|
|
512
|
+
case FlowType::CALL:
|
|
513
|
+
// JSR: add target AND return address (next instruction)
|
|
514
|
+
if (nextAddr >= baseAddress && nextAddr < endAddress) {
|
|
515
|
+
toVisit.push(nextAddr);
|
|
516
|
+
}
|
|
517
|
+
if (instr.target >= baseAddress && instr.target < endAddress) {
|
|
518
|
+
toVisit.push(instr.target);
|
|
519
|
+
}
|
|
520
|
+
break;
|
|
521
|
+
|
|
522
|
+
case FlowType::UNCONDITIONAL:
|
|
523
|
+
// JMP/BRA: only add target, don't fall through
|
|
524
|
+
if (instr.target >= baseAddress && instr.target < endAddress) {
|
|
525
|
+
toVisit.push(instr.target);
|
|
526
|
+
}
|
|
527
|
+
break;
|
|
528
|
+
|
|
529
|
+
case FlowType::RETURN:
|
|
530
|
+
case FlowType::INDIRECT:
|
|
531
|
+
case FlowType::HALT:
|
|
532
|
+
// Stop tracing this path
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Sort instructions by address for consistent output
|
|
538
|
+
std::sort(result.instructions.begin(), result.instructions.end(),
|
|
539
|
+
[](const DisasmInstruction &a, const DisasmInstruction &b) {
|
|
540
|
+
return a.address < b.address;
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
DisasmResult disassembleWithFlowAnalysis(const uint8_t *data, size_t size,
|
|
547
|
+
uint16_t baseAddress) {
|
|
548
|
+
std::vector<uint16_t> entryPoints = {baseAddress};
|
|
549
|
+
return disassembleWithFlowAnalysis(data, size, baseAddress, entryPoints);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
} // namespace a2e
|