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.
Files changed (295) hide show
  1. package/.clangd +5 -0
  2. package/.mcp.json +12 -0
  3. package/CLAUDE.md +362 -0
  4. package/CMakeLists.txt +774 -0
  5. package/LICENSE +21 -0
  6. package/README.md +392 -0
  7. package/build-wasm/generated/roms.cpp +2447 -0
  8. package/docker-compose.staging.yml +9 -0
  9. package/docs/basic-rom-disassembly.md +6663 -0
  10. package/docs/softswitch-comparison.md +273 -0
  11. package/docs/thunderclock-debug.md +89 -0
  12. package/examples/cube.bas +72 -0
  13. package/examples/hello.s +55 -0
  14. package/examples/scroll.s +140 -0
  15. package/package.json +18 -0
  16. package/public/assets/apple-logo-old.png +0 -0
  17. package/public/assets/apple-logo.png +0 -0
  18. package/public/assets/drive-closed-light-on.png +0 -0
  19. package/public/assets/drive-closed.png +0 -0
  20. package/public/assets/drive-open-light-on.png +0 -0
  21. package/public/assets/drive-open.png +0 -0
  22. package/public/audio-worklet.js +82 -0
  23. package/public/disks/Apple DOS 3.3 January 1983.dsk +0 -0
  24. package/public/disks/ProDOS 2.4.3.po +0 -0
  25. package/public/disks/h32mb.2mg +0 -0
  26. package/public/disks/library.json +26 -0
  27. package/public/docs/llms/llm-assembler.txt +90 -0
  28. package/public/docs/llms/llm-basic-program.txt +256 -0
  29. package/public/docs/llms/llm-disk-drives.txt +72 -0
  30. package/public/docs/llms/llm-file-explorer.txt +50 -0
  31. package/public/docs/llms/llm-hard-drives.txt +80 -0
  32. package/public/docs/llms/llm-main.txt +51 -0
  33. package/public/docs/llms/llm-slot-configuration.txt +66 -0
  34. package/public/icons/icon-192.svg +4 -0
  35. package/public/icons/icon-512.svg +4 -0
  36. package/public/index.html +661 -0
  37. package/public/llms.txt +49 -0
  38. package/public/manifest.json +29 -0
  39. package/public/shaders/burnin.glsl +22 -0
  40. package/public/shaders/crt.glsl +706 -0
  41. package/public/shaders/edge.glsl +109 -0
  42. package/public/shaders/vertex.glsl +8 -0
  43. package/public/sw.js +186 -0
  44. package/roms/341-0027.bin +0 -0
  45. package/roms/341-0160-A-US-UK.bin +0 -0
  46. package/roms/341-0160-A.bin +0 -0
  47. package/roms/342-0273-A-US-UK.bin +0 -0
  48. package/roms/342-0349-B-C0-FF.bin +0 -0
  49. package/roms/Apple Mouse Interface Card ROM - 342-0270-C.bin +0 -0
  50. package/roms/Thunderclock Plus ROM.bin +0 -0
  51. package/scripts/generate_roms.sh +69 -0
  52. package/src/bindings/wasm_interface.cpp +1940 -0
  53. package/src/core/assembler/assembler.cpp +1239 -0
  54. package/src/core/assembler/assembler.hpp +115 -0
  55. package/src/core/audio/audio.cpp +160 -0
  56. package/src/core/audio/audio.hpp +81 -0
  57. package/src/core/basic/basic_detokenizer.cpp +436 -0
  58. package/src/core/basic/basic_detokenizer.hpp +41 -0
  59. package/src/core/basic/basic_tokenizer.cpp +286 -0
  60. package/src/core/basic/basic_tokenizer.hpp +26 -0
  61. package/src/core/basic/basic_tokens.hpp +295 -0
  62. package/src/core/cards/disk2_card.cpp +568 -0
  63. package/src/core/cards/disk2_card.hpp +316 -0
  64. package/src/core/cards/expansion_card.hpp +185 -0
  65. package/src/core/cards/mockingboard/ay8910.cpp +616 -0
  66. package/src/core/cards/mockingboard/ay8910.hpp +159 -0
  67. package/src/core/cards/mockingboard/via6522.cpp +530 -0
  68. package/src/core/cards/mockingboard/via6522.hpp +163 -0
  69. package/src/core/cards/mockingboard_card.cpp +312 -0
  70. package/src/core/cards/mockingboard_card.hpp +159 -0
  71. package/src/core/cards/mouse_card.cpp +654 -0
  72. package/src/core/cards/mouse_card.hpp +190 -0
  73. package/src/core/cards/smartport/block_device.cpp +202 -0
  74. package/src/core/cards/smartport/block_device.hpp +60 -0
  75. package/src/core/cards/smartport/smartport_card.cpp +603 -0
  76. package/src/core/cards/smartport/smartport_card.hpp +120 -0
  77. package/src/core/cards/thunderclock_card.cpp +237 -0
  78. package/src/core/cards/thunderclock_card.hpp +122 -0
  79. package/src/core/cpu/cpu6502.cpp +1609 -0
  80. package/src/core/cpu/cpu6502.hpp +203 -0
  81. package/src/core/debug/condition_evaluator.cpp +470 -0
  82. package/src/core/debug/condition_evaluator.hpp +87 -0
  83. package/src/core/disassembler/disassembler.cpp +552 -0
  84. package/src/core/disassembler/disassembler.hpp +171 -0
  85. package/src/core/disk-image/disk_image.hpp +267 -0
  86. package/src/core/disk-image/dsk_disk_image.cpp +827 -0
  87. package/src/core/disk-image/dsk_disk_image.hpp +204 -0
  88. package/src/core/disk-image/gcr_encoding.cpp +147 -0
  89. package/src/core/disk-image/gcr_encoding.hpp +78 -0
  90. package/src/core/disk-image/woz_disk_image.cpp +1049 -0
  91. package/src/core/disk-image/woz_disk_image.hpp +343 -0
  92. package/src/core/emulator.cpp +2126 -0
  93. package/src/core/emulator.hpp +434 -0
  94. package/src/core/filesystem/dos33.cpp +178 -0
  95. package/src/core/filesystem/dos33.hpp +66 -0
  96. package/src/core/filesystem/pascal.cpp +262 -0
  97. package/src/core/filesystem/pascal.hpp +87 -0
  98. package/src/core/filesystem/prodos.cpp +369 -0
  99. package/src/core/filesystem/prodos.hpp +119 -0
  100. package/src/core/input/keyboard.cpp +227 -0
  101. package/src/core/input/keyboard.hpp +111 -0
  102. package/src/core/mmu/mmu.cpp +1387 -0
  103. package/src/core/mmu/mmu.hpp +236 -0
  104. package/src/core/types.hpp +196 -0
  105. package/src/core/video/video.cpp +680 -0
  106. package/src/core/video/video.hpp +156 -0
  107. package/src/css/assembler-editor.css +1617 -0
  108. package/src/css/base.css +470 -0
  109. package/src/css/basic-debugger.css +791 -0
  110. package/src/css/basic-editor.css +792 -0
  111. package/src/css/controls.css +783 -0
  112. package/src/css/cpu-debugger.css +1413 -0
  113. package/src/css/debug-base.css +160 -0
  114. package/src/css/debug-windows.css +6455 -0
  115. package/src/css/disk-drives.css +406 -0
  116. package/src/css/documentation.css +392 -0
  117. package/src/css/file-explorer.css +867 -0
  118. package/src/css/hard-drive.css +180 -0
  119. package/src/css/layout.css +217 -0
  120. package/src/css/memory-windows.css +798 -0
  121. package/src/css/modals.css +510 -0
  122. package/src/css/monitor.css +425 -0
  123. package/src/css/release-notes.css +101 -0
  124. package/src/css/responsive.css +400 -0
  125. package/src/css/rule-builder.css +340 -0
  126. package/src/css/save-states.css +201 -0
  127. package/src/css/settings-windows.css +1231 -0
  128. package/src/css/window-switcher.css +150 -0
  129. package/src/js/agent/agent-manager.js +643 -0
  130. package/src/js/agent/agent-tools.js +293 -0
  131. package/src/js/agent/agent-version-tools.js +131 -0
  132. package/src/js/agent/assembler-tools.js +357 -0
  133. package/src/js/agent/basic-program-tools.js +894 -0
  134. package/src/js/agent/disk-tools.js +417 -0
  135. package/src/js/agent/file-explorer-tools.js +269 -0
  136. package/src/js/agent/index.js +13 -0
  137. package/src/js/agent/main-tools.js +222 -0
  138. package/src/js/agent/slot-tools.js +303 -0
  139. package/src/js/agent/smartport-tools.js +257 -0
  140. package/src/js/agent/window-tools.js +80 -0
  141. package/src/js/audio/audio-driver.js +417 -0
  142. package/src/js/audio/audio-worklet.js +85 -0
  143. package/src/js/audio/index.js +8 -0
  144. package/src/js/config/default-layout.js +34 -0
  145. package/src/js/config/version.js +8 -0
  146. package/src/js/data/apple2-rom-routines.js +577 -0
  147. package/src/js/debug/assembler-editor-window.js +2993 -0
  148. package/src/js/debug/basic-breakpoint-manager.js +529 -0
  149. package/src/js/debug/basic-program-parser.js +436 -0
  150. package/src/js/debug/basic-program-window.js +2594 -0
  151. package/src/js/debug/basic-variable-inspector.js +447 -0
  152. package/src/js/debug/breakpoint-manager.js +472 -0
  153. package/src/js/debug/cpu-debugger-window.js +2396 -0
  154. package/src/js/debug/index.js +22 -0
  155. package/src/js/debug/label-manager.js +238 -0
  156. package/src/js/debug/memory-browser-window.js +416 -0
  157. package/src/js/debug/memory-heat-map-window.js +481 -0
  158. package/src/js/debug/memory-map-window.js +206 -0
  159. package/src/js/debug/mockingboard-window.js +882 -0
  160. package/src/js/debug/mouse-card-window.js +355 -0
  161. package/src/js/debug/rule-builder-window.js +648 -0
  162. package/src/js/debug/soft-switch-window.js +458 -0
  163. package/src/js/debug/stack-viewer-window.js +221 -0
  164. package/src/js/debug/symbols.js +416 -0
  165. package/src/js/debug/trace-panel.js +291 -0
  166. package/src/js/debug/zero-page-watch-window.js +297 -0
  167. package/src/js/disk-manager/disk-drives-window.js +212 -0
  168. package/src/js/disk-manager/disk-operations.js +284 -0
  169. package/src/js/disk-manager/disk-persistence.js +301 -0
  170. package/src/js/disk-manager/disk-surface-renderer.js +388 -0
  171. package/src/js/disk-manager/drive-sounds.js +139 -0
  172. package/src/js/disk-manager/hard-drive-manager.js +481 -0
  173. package/src/js/disk-manager/hard-drive-persistence.js +187 -0
  174. package/src/js/disk-manager/hard-drive-window.js +57 -0
  175. package/src/js/disk-manager/index.js +890 -0
  176. package/src/js/display/display-settings-window.js +383 -0
  177. package/src/js/display/index.js +10 -0
  178. package/src/js/display/screen-window.js +342 -0
  179. package/src/js/display/webgl-renderer.js +705 -0
  180. package/src/js/file-explorer/disassembler.js +574 -0
  181. package/src/js/file-explorer/dos33.js +266 -0
  182. package/src/js/file-explorer/file-viewer.js +359 -0
  183. package/src/js/file-explorer/index.js +1261 -0
  184. package/src/js/file-explorer/prodos.js +549 -0
  185. package/src/js/file-explorer/utils.js +67 -0
  186. package/src/js/help/documentation-window.js +1096 -0
  187. package/src/js/help/index.js +10 -0
  188. package/src/js/help/release-notes-window.js +85 -0
  189. package/src/js/help/release-notes.js +612 -0
  190. package/src/js/input/gamepad-handler.js +176 -0
  191. package/src/js/input/index.js +12 -0
  192. package/src/js/input/input-handler.js +396 -0
  193. package/src/js/input/joystick-window.js +404 -0
  194. package/src/js/input/mouse-handler.js +99 -0
  195. package/src/js/input/text-selection.js +462 -0
  196. package/src/js/main.js +653 -0
  197. package/src/js/state/index.js +15 -0
  198. package/src/js/state/save-states-window.js +393 -0
  199. package/src/js/state/state-manager.js +409 -0
  200. package/src/js/state/state-persistence.js +218 -0
  201. package/src/js/ui/confirm.js +43 -0
  202. package/src/js/ui/disk-drive-positioner.js +347 -0
  203. package/src/js/ui/reminder-controller.js +129 -0
  204. package/src/js/ui/slot-configuration-window.js +560 -0
  205. package/src/js/ui/theme-manager.js +61 -0
  206. package/src/js/ui/toast.js +44 -0
  207. package/src/js/ui/ui-controller.js +897 -0
  208. package/src/js/ui/window-switcher.js +275 -0
  209. package/src/js/utils/basic-autocomplete.js +832 -0
  210. package/src/js/utils/basic-highlighting.js +473 -0
  211. package/src/js/utils/basic-tokenizer.js +153 -0
  212. package/src/js/utils/basic-tokens.js +117 -0
  213. package/src/js/utils/constants.js +28 -0
  214. package/src/js/utils/indexeddb-helper.js +225 -0
  215. package/src/js/utils/merlin-editor-support.js +905 -0
  216. package/src/js/utils/merlin-highlighting.js +551 -0
  217. package/src/js/utils/storage.js +125 -0
  218. package/src/js/utils/string-utils.js +19 -0
  219. package/src/js/utils/wasm-memory.js +54 -0
  220. package/src/js/windows/base-window.js +690 -0
  221. package/src/js/windows/index.js +9 -0
  222. package/src/js/windows/window-manager.js +375 -0
  223. package/tests/catch2/catch.hpp +17976 -0
  224. package/tests/common/basic_program_builder.cpp +119 -0
  225. package/tests/common/basic_program_builder.hpp +209 -0
  226. package/tests/common/disk_image_builder.cpp +444 -0
  227. package/tests/common/disk_image_builder.hpp +141 -0
  228. package/tests/common/test_helpers.hpp +118 -0
  229. package/tests/gcr/gcr-test.cpp +142 -0
  230. package/tests/integration/check-rom.js +70 -0
  231. package/tests/integration/compare-boot.js +239 -0
  232. package/tests/integration/crash-trace.js +102 -0
  233. package/tests/integration/disk-boot-test.js +264 -0
  234. package/tests/integration/memory-crash.js +108 -0
  235. package/tests/integration/nibble-read-test.js +249 -0
  236. package/tests/integration/phase-test.js +159 -0
  237. package/tests/integration/test_emulator.cpp +291 -0
  238. package/tests/integration/test_emulator_basic.cpp +91 -0
  239. package/tests/integration/test_emulator_debug.cpp +344 -0
  240. package/tests/integration/test_emulator_disk.cpp +153 -0
  241. package/tests/integration/test_emulator_state.cpp +163 -0
  242. package/tests/klaus/6502_functional_test.bin +0 -0
  243. package/tests/klaus/65C02_extended_opcodes_test.bin +0 -0
  244. package/tests/klaus/klaus_6502_test.cpp +184 -0
  245. package/tests/klaus/klaus_65c02_test.cpp +197 -0
  246. package/tests/thunderclock/thunderclock_mmu_test.cpp +304 -0
  247. package/tests/thunderclock/thunderclock_test.cpp +550 -0
  248. package/tests/unit/test_assembler.cpp +521 -0
  249. package/tests/unit/test_audio.cpp +196 -0
  250. package/tests/unit/test_ay8910.cpp +311 -0
  251. package/tests/unit/test_basic_detokenizer.cpp +265 -0
  252. package/tests/unit/test_basic_tokenizer.cpp +382 -0
  253. package/tests/unit/test_block_device.cpp +259 -0
  254. package/tests/unit/test_condition_evaluator.cpp +219 -0
  255. package/tests/unit/test_cpu6502.cpp +1301 -0
  256. package/tests/unit/test_cpu_addressing.cpp +361 -0
  257. package/tests/unit/test_cpu_cycle_counts.cpp +409 -0
  258. package/tests/unit/test_cpu_decimal.cpp +166 -0
  259. package/tests/unit/test_cpu_interrupts.cpp +285 -0
  260. package/tests/unit/test_disassembler.cpp +323 -0
  261. package/tests/unit/test_disk2_card.cpp +330 -0
  262. package/tests/unit/test_dos33.cpp +273 -0
  263. package/tests/unit/test_dsk_disk_image.cpp +315 -0
  264. package/tests/unit/test_expansion_card.cpp +178 -0
  265. package/tests/unit/test_gcr_encoding.cpp +232 -0
  266. package/tests/unit/test_keyboard.cpp +262 -0
  267. package/tests/unit/test_mmu.cpp +555 -0
  268. package/tests/unit/test_mmu_slots.cpp +323 -0
  269. package/tests/unit/test_mockingboard.cpp +352 -0
  270. package/tests/unit/test_mouse_card.cpp +386 -0
  271. package/tests/unit/test_pascal.cpp +248 -0
  272. package/tests/unit/test_prodos.cpp +259 -0
  273. package/tests/unit/test_smartport_card.cpp +321 -0
  274. package/tests/unit/test_thunderclock.cpp +354 -0
  275. package/tests/unit/test_via6522.cpp +323 -0
  276. package/tests/unit/test_video.cpp +319 -0
  277. package/tests/unit/test_woz_disk_image.cpp +257 -0
  278. package/vite.config.js +96 -0
  279. package/wiki/AI-Agent.md +372 -0
  280. package/wiki/Architecture-Overview.md +303 -0
  281. package/wiki/Audio-System.md +449 -0
  282. package/wiki/CPU-Emulation.md +477 -0
  283. package/wiki/Debugger.md +516 -0
  284. package/wiki/Disk-Drives.md +161 -0
  285. package/wiki/Disk-System-Internals.md +547 -0
  286. package/wiki/Display-Settings.md +88 -0
  287. package/wiki/Expansion-Slots.md +187 -0
  288. package/wiki/File-Explorer.md +259 -0
  289. package/wiki/Getting-Started.md +156 -0
  290. package/wiki/Home.md +69 -0
  291. package/wiki/Input-Devices.md +183 -0
  292. package/wiki/Keyboard-Shortcuts.md +158 -0
  293. package/wiki/Memory-System.md +364 -0
  294. package/wiki/Save-States.md +172 -0
  295. package/wiki/Video-Rendering.md +658 -0
@@ -0,0 +1,357 @@
1
+ /*
2
+ * assembler-tools.js - Assembler window tools
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ export const assemblerTools = {
9
+ /**
10
+ * Assemble the current source code
11
+ */
12
+ asmAssemble: async (args) => {
13
+ const windowManager = window.emulator?.windowManager;
14
+ if (!windowManager) {
15
+ throw new Error("Window manager not available");
16
+ }
17
+
18
+ const asmWindow = windowManager.getWindow("assembler-editor");
19
+ if (!asmWindow) {
20
+ throw new Error("Assembler window not found");
21
+ }
22
+
23
+ asmWindow.doAssemble();
24
+
25
+ return {
26
+ success: true,
27
+ message: "Assembly completed",
28
+ };
29
+ },
30
+
31
+ /**
32
+ * Write assembled code into emulator memory
33
+ */
34
+ asmWrite: async (args) => {
35
+ const windowManager = window.emulator?.windowManager;
36
+ if (!windowManager) {
37
+ throw new Error("Window manager not available");
38
+ }
39
+
40
+ const asmWindow = windowManager.getWindow("assembler-editor");
41
+ if (!asmWindow) {
42
+ throw new Error("Assembler window not found");
43
+ }
44
+
45
+ asmWindow.doLoad();
46
+
47
+ return {
48
+ success: true,
49
+ message: "Assembled code written to memory",
50
+ };
51
+ },
52
+
53
+ /**
54
+ * Load example program into the editor
55
+ */
56
+ asmLoadExample: async (args) => {
57
+ const windowManager = window.emulator?.windowManager;
58
+ if (!windowManager) {
59
+ throw new Error("Window manager not available");
60
+ }
61
+
62
+ const asmWindow = windowManager.getWindow("assembler-editor");
63
+ if (!asmWindow) {
64
+ throw new Error("Assembler window not found");
65
+ }
66
+
67
+ asmWindow.loadExample();
68
+
69
+ return {
70
+ success: true,
71
+ message: "Example program loaded into editor",
72
+ };
73
+ },
74
+
75
+ /**
76
+ * Clear editor and start new file
77
+ * Emulates the newFile() method without confirmation dialog
78
+ */
79
+ asmNew: async (args) => {
80
+ const windowManager = window.emulator?.windowManager;
81
+ if (!windowManager) {
82
+ throw new Error("Window manager not available");
83
+ }
84
+
85
+ const asmWindow = windowManager.getWindow("assembler-editor");
86
+ if (!asmWindow) {
87
+ throw new Error("Assembler window not found");
88
+ }
89
+
90
+ // Emulate newFile() behavior without confirmation
91
+ if (asmWindow.textarea) {
92
+ asmWindow.textarea.value = "";
93
+ asmWindow.currentFileName = null;
94
+ asmWindow._fileHandle = null;
95
+ asmWindow.updateTitle("Assembler");
96
+ asmWindow.updateHighlighting();
97
+ asmWindow.updateGutter();
98
+ asmWindow.errors.clear();
99
+ asmWindow.syntaxErrors.clear();
100
+ asmWindow.clearOutputPanels();
101
+ asmWindow.setStatus("", true);
102
+ }
103
+
104
+ return {
105
+ success: true,
106
+ message: "Assembler editor cleared",
107
+ };
108
+ },
109
+
110
+ /**
111
+ * Get current assembly source code from editor
112
+ */
113
+ asmGet: async (args) => {
114
+ const windowManager = window.emulator?.windowManager;
115
+ if (!windowManager) {
116
+ throw new Error("Window manager not available");
117
+ }
118
+
119
+ const asmWindow = windowManager.getWindow("assembler-editor");
120
+ if (!asmWindow) {
121
+ throw new Error("Assembler window not found");
122
+ }
123
+
124
+ const text = asmWindow.textarea ? asmWindow.textarea.value : "";
125
+
126
+ return {
127
+ success: true,
128
+ source: text,
129
+ lines: text ? text.split("\n").length : 0,
130
+ message: "Assembly source retrieved",
131
+ };
132
+ },
133
+
134
+ /**
135
+ * Set assembly source code in editor (replace entire content)
136
+ */
137
+ asmSet: async (args) => {
138
+ const { source } = args;
139
+
140
+ if (source === undefined) {
141
+ throw new Error("source parameter is required");
142
+ }
143
+
144
+ const windowManager = window.emulator?.windowManager;
145
+ if (!windowManager) {
146
+ throw new Error("Window manager not available");
147
+ }
148
+
149
+ const asmWindow = windowManager.getWindow("assembler-editor");
150
+ if (!asmWindow) {
151
+ throw new Error("Assembler window not found");
152
+ }
153
+
154
+ if (asmWindow.textarea) {
155
+ asmWindow.textarea.value = source;
156
+ asmWindow.updateHighlighting();
157
+ asmWindow.validateAllLines();
158
+ asmWindow.encodeAllLineBytes();
159
+ asmWindow.updateGutter();
160
+ }
161
+
162
+ return {
163
+ success: true,
164
+ message: "Assembly source set",
165
+ };
166
+ },
167
+
168
+ /**
169
+ * Get assembly source content from editor (used with save file MCP tool)
170
+ */
171
+ saveAsmInEditorToLocal: async (args) => {
172
+ const windowManager = window.emulator?.windowManager;
173
+ if (!windowManager) {
174
+ throw new Error("Window manager not available");
175
+ }
176
+
177
+ const asmWindow = windowManager.getWindow("assembler-editor");
178
+ if (!asmWindow) {
179
+ throw new Error("Assembler window not found");
180
+ }
181
+
182
+ const content = asmWindow.textarea ? asmWindow.textarea.value : "";
183
+ if (!content.trim()) {
184
+ throw new Error("No source code in editor to save");
185
+ }
186
+
187
+ return {
188
+ success: true,
189
+ content: content,
190
+ lines: content.split("\n").length,
191
+ message: "Assembly source content retrieved from editor",
192
+ };
193
+ },
194
+
195
+ /**
196
+ * Get assembly status, origin address, and size
197
+ */
198
+ asmGetStatus: async (args) => {
199
+ const windowManager = window.emulator?.windowManager;
200
+ if (!windowManager) {
201
+ throw new Error("Window manager not available");
202
+ }
203
+
204
+ const asmWindow = windowManager.getWindow("assembler-editor");
205
+ if (!asmWindow) {
206
+ throw new Error("Assembler window not found");
207
+ }
208
+
209
+ const statusText = asmWindow.statusSpan
210
+ ? asmWindow.statusSpan.textContent
211
+ : "";
212
+ const statusClass = asmWindow.statusSpan
213
+ ? asmWindow.statusSpan.className
214
+ : "";
215
+ const isError = statusClass.includes("asm-status-error");
216
+ const origin = asmWindow.lastOrigin || 0;
217
+ const size = asmWindow.lastAssembledSize || 0;
218
+
219
+ // Determine status: none if no assembly, error if failed, ok if successful
220
+ let status;
221
+ if (!statusText.trim() || size === 0) {
222
+ status = "none";
223
+ } else if (isError) {
224
+ status = "error";
225
+ } else {
226
+ status = "ok";
227
+ }
228
+
229
+ return {
230
+ success: true,
231
+ status: status,
232
+ statusText: statusText,
233
+ origin: origin,
234
+ originHex: "$" + origin.toString(16).toUpperCase().padStart(4, "0"),
235
+ size: size,
236
+ message: "Assembly status retrieved",
237
+ };
238
+ },
239
+
240
+ /**
241
+ * Execute code at a specific address (like monitor's G command)
242
+ * Sets PC to address and optionally resumes execution
243
+ */
244
+ directExecuteAssemblyAt: async (args) => {
245
+ const { paused = false, addr } = args;
246
+
247
+ const emulator = window.emulator;
248
+ if (!emulator) {
249
+ throw new Error("Emulator not available");
250
+ }
251
+
252
+ const windowManager = emulator.windowManager;
253
+ if (!windowManager) {
254
+ throw new Error("Window manager not available");
255
+ }
256
+
257
+ const wasmModule = emulator.wasmModule;
258
+ if (!wasmModule) {
259
+ throw new Error("WASM module not available");
260
+ }
261
+
262
+ // Determine address to execute
263
+ let address;
264
+ if (addr !== undefined) {
265
+ // Support hex ($xxxx or 0xXXXX) or decimal
266
+ if (typeof addr === "string") {
267
+ const trimmed = addr.trim();
268
+ if (trimmed.startsWith("$")) {
269
+ address = parseInt(trimmed.substring(1), 16);
270
+ } else if (trimmed.toLowerCase().startsWith("0x")) {
271
+ address = parseInt(trimmed, 16);
272
+ } else {
273
+ address = parseInt(trimmed, 10);
274
+ }
275
+ } else {
276
+ address = addr;
277
+ }
278
+ } else {
279
+ // Use origin from last successful assembly
280
+ const asmWindow = windowManager.getWindow("assembler-editor");
281
+ if (!asmWindow) {
282
+ throw new Error("Assembler window not found");
283
+ }
284
+ address = asmWindow.lastOrigin || 0;
285
+ if (address === 0) {
286
+ throw new Error(
287
+ "No address specified and no assembled program origin available",
288
+ );
289
+ }
290
+ }
291
+
292
+ // Pause first to ensure clean state
293
+ wasmModule._setPaused(true);
294
+
295
+ // Push return address onto stack if specified
296
+ const { returnTo = "auto" } = args;
297
+ let returnAddr = null;
298
+ if (returnTo !== undefined) {
299
+ const NAMED_RETURNS = {
300
+ "monitor": 0xFF69,
301
+ "basic": 0xE003,
302
+ "auto": wasmModule._getPC(),
303
+ };
304
+
305
+ if (typeof returnTo === "string") {
306
+ const lower = returnTo.trim().toLowerCase();
307
+ if (NAMED_RETURNS[lower] !== undefined) {
308
+ returnAddr = NAMED_RETURNS[lower];
309
+ } else if (returnTo.trim().startsWith("$")) {
310
+ returnAddr = parseInt(returnTo.trim().substring(1), 16);
311
+ } else if (returnTo.trim().toLowerCase().startsWith("0x")) {
312
+ returnAddr = parseInt(returnTo.trim(), 16);
313
+ } else {
314
+ returnAddr = parseInt(returnTo.trim(), 10);
315
+ }
316
+ } else {
317
+ returnAddr = returnTo;
318
+ }
319
+
320
+ if (isNaN(returnAddr)) {
321
+ throw new Error(`Invalid returnTo address: ${returnTo}`);
322
+ }
323
+
324
+ // RTS pops address and adds 1, so push (returnAddr - 1)
325
+ const rtsAddr = (returnAddr - 1) & 0xFFFF;
326
+ const sp = wasmModule._getSP();
327
+ wasmModule._writeMemory(0x0100 + sp, (rtsAddr >> 8) & 0xFF);
328
+ wasmModule._writeMemory(0x0100 + ((sp - 1) & 0xFF), rtsAddr & 0xFF);
329
+ wasmModule._setRegSP((sp - 2) & 0xFF);
330
+ }
331
+
332
+ // Set PC to target address
333
+ wasmModule._setRegPC(address);
334
+
335
+ // Set final paused state: true = stay paused, false = resume execution
336
+ wasmModule._setPaused(paused);
337
+
338
+ const addrHex = "$" + address.toString(16).toUpperCase().padStart(4, "0");
339
+ const returnHex = returnAddr !== null
340
+ ? "$" + returnAddr.toString(16).toUpperCase().padStart(4, "0")
341
+ : null;
342
+ const returnMsg = returnHex ? `, return to ${returnHex}` : "";
343
+ const statusMsg = paused
344
+ ? `PC set to ${addrHex} (paused${returnMsg})`
345
+ : `Executing at ${addrHex}${returnMsg}`;
346
+
347
+ return {
348
+ success: true,
349
+ address: address,
350
+ addressHex: addrHex,
351
+ returnTo: returnAddr,
352
+ returnToHex: returnHex,
353
+ paused: paused,
354
+ message: statusMsg,
355
+ };
356
+ },
357
+ };