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,236 @@
1
+ /*
2
+ * mmu.hpp - Memory management unit with soft switches
3
+ *
4
+ * Written by
5
+ * Mike Daley <michael_daley@icloud.com>
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #include "../types.hpp"
11
+ #include <array>
12
+ #include <cstdint>
13
+ #include <functional>
14
+ #include <memory>
15
+
16
+ namespace a2e {
17
+
18
+ // Forward declaration
19
+ class ExpansionCard;
20
+
21
+ class MMU {
22
+ public:
23
+ using KeyboardCallback = std::function<uint8_t()>;
24
+ using KeyStrobeCallback = std::function<void()>;
25
+ using AnyKeyDownCallback = std::function<bool()>; // Returns true if any key is currently held
26
+ using SpeakerCallback = std::function<void()>;
27
+ using ButtonCallback = std::function<uint8_t(int)>; // Returns button state for button 0-2
28
+ using CycleCallback = std::function<uint64_t()>; // Returns current CPU cycle count
29
+ using VideoSwitchCallback = std::function<void()>; // Called when video-relevant switches change
30
+ using WatchpointReadCallback = std::function<void(uint16_t, uint8_t)>;
31
+ using WatchpointWriteCallback = std::function<void(uint16_t, uint8_t)>;
32
+
33
+ MMU();
34
+ ~MMU(); // Defined in mmu.cpp (needed for unique_ptr<ExpansionCard>)
35
+
36
+ // Memory access
37
+ uint8_t read(uint16_t address);
38
+ void write(uint16_t address, uint8_t value);
39
+
40
+ // Non-side-effecting read for debugger/memory viewer
41
+ uint8_t peek(uint16_t address) const;
42
+
43
+ // Non-side-effecting read of auxiliary memory (for text selection in 80-col mode)
44
+ uint8_t peekAux(uint16_t address) const;
45
+
46
+ // Direct memory access (bypasses soft switches)
47
+ uint8_t readRAM(uint16_t address, bool aux = false) const;
48
+ void writeRAM(uint16_t address, uint8_t value, bool aux = false);
49
+
50
+ // Language card RAM access (for state serialization)
51
+ const uint8_t *getLCBank1(bool aux = false) const {
52
+ return aux ? auxLcBank1_.data() : lcBank1_.data();
53
+ }
54
+ const uint8_t *getLCBank2(bool aux = false) const {
55
+ return aux ? auxLcBank2_.data() : lcBank2_.data();
56
+ }
57
+ const uint8_t *getLCHighRAM(bool aux = false) const {
58
+ return aux ? auxLcHighRAM_.data() : lcHighRAM_.data();
59
+ }
60
+ void setLCBank1(const uint8_t *data, bool aux = false) {
61
+ auto &bank = aux ? auxLcBank1_ : lcBank1_;
62
+ std::copy(data, data + bank.size(), bank.begin());
63
+ }
64
+ void setLCBank2(const uint8_t *data, bool aux = false) {
65
+ auto &bank = aux ? auxLcBank2_ : lcBank2_;
66
+ std::copy(data, data + bank.size(), bank.begin());
67
+ }
68
+ void setLCHighRAM(const uint8_t *data, bool aux = false) {
69
+ auto &bank = aux ? auxLcHighRAM_ : lcHighRAM_;
70
+ std::copy(data, data + bank.size(), bank.begin());
71
+ }
72
+
73
+ // ROM loading - combined 16KB system ROM ($C000-$FFFF)
74
+ void loadROM(const uint8_t *systemRom, size_t systemSize,
75
+ const uint8_t *charRom, size_t charSize);
76
+
77
+ // Character ROM access (for video)
78
+ uint8_t readCharROM(uint16_t address) const;
79
+
80
+ // Soft switch state
81
+ const SoftSwitches &getSoftSwitches() const { return switches_; }
82
+
83
+ // Callbacks
84
+ void setKeyboardCallback(KeyboardCallback cb) {
85
+ keyboardCallback_ = std::move(cb);
86
+ }
87
+ void setKeyStrobeCallback(KeyStrobeCallback cb) {
88
+ keyStrobeCallback_ = std::move(cb);
89
+ }
90
+ void setAnyKeyDownCallback(AnyKeyDownCallback cb) {
91
+ anyKeyDownCallback_ = std::move(cb);
92
+ }
93
+ void setSpeakerCallback(SpeakerCallback cb) {
94
+ speakerCallback_ = std::move(cb);
95
+ }
96
+ void setButtonCallback(ButtonCallback cb) { buttonCallback_ = std::move(cb); }
97
+ void setCycleCallback(CycleCallback cb) { cycleCallback_ = std::move(cb); }
98
+ void setVideoSwitchCallback(VideoSwitchCallback cb) { videoSwitchCallback_ = std::move(cb); }
99
+ void setWatchpointCallbacks(WatchpointReadCallback readCb, WatchpointWriteCallback writeCb) {
100
+ watchpointReadCallback_ = std::move(readCb);
101
+ watchpointWriteCallback_ = std::move(writeCb);
102
+ }
103
+ void setWatchpointsActive(bool active) { watchpointsActive_ = active; }
104
+
105
+ // Paddle/joystick input
106
+ void setPaddleValue(int paddle, uint8_t value) {
107
+ if (paddle >= 0 && paddle < 4) {
108
+ paddleValues_[paddle] = value;
109
+ }
110
+ }
111
+ uint8_t getPaddleValue(int paddle) const {
112
+ return (paddle >= 0 && paddle < 4) ? paddleValues_[paddle] : 128;
113
+ }
114
+
115
+
116
+ // ===== Expansion Slot Management =====
117
+
118
+ /**
119
+ * Insert a card into an expansion slot
120
+ * @param slot Slot number (1-7)
121
+ * @param card Card to insert (ownership transferred)
122
+ * @return Previously installed card, or nullptr if slot was empty
123
+ */
124
+ std::unique_ptr<ExpansionCard> insertCard(uint8_t slot, std::unique_ptr<ExpansionCard> card);
125
+
126
+ /**
127
+ * Remove a card from an expansion slot
128
+ * @param slot Slot number (1-7)
129
+ * @return The removed card, or nullptr if slot was empty
130
+ */
131
+ std::unique_ptr<ExpansionCard> removeCard(uint8_t slot);
132
+
133
+ /**
134
+ * Get a card from a slot (non-owning)
135
+ * @param slot Slot number (1-7)
136
+ * @return Pointer to card, or nullptr if slot is empty
137
+ */
138
+ ExpansionCard* getCard(uint8_t slot) const;
139
+
140
+ /**
141
+ * Check if a slot is empty
142
+ * @param slot Slot number (1-7)
143
+ * @return true if no card is installed
144
+ */
145
+ bool isSlotEmpty(uint8_t slot) const;
146
+
147
+ /**
148
+ * Get which slot's expansion ROM is active
149
+ * @return Active slot (1-7), or 0 if none
150
+ */
151
+ uint8_t getActiveExpansionSlot() const { return activeExpansionSlot_; }
152
+
153
+ // Reset
154
+ void reset();
155
+ void warmReset(); // Reset soft switches and cards, preserve RAM
156
+
157
+ // Memory access tracking for debugger heat map
158
+ void enableTracking(bool enable) { trackingEnabled_ = enable; }
159
+ bool isTrackingEnabled() const { return trackingEnabled_; }
160
+ void clearTracking();
161
+ void decayTracking(uint8_t amount = 1); // Reduce all counts for real-time visualization
162
+ const uint8_t* getReadCounts() const { return readCounts_.data(); }
163
+ const uint8_t* getWriteCounts() const { return writeCounts_.data(); }
164
+
165
+ // Direct memory array access for heat map visualization
166
+ const uint8_t* getMainRAM() const { return mainRAM_.data(); }
167
+ const uint8_t* getAuxRAM() const { return auxRAM_.data(); }
168
+ const uint8_t* getSystemROM() const { return systemROM_.data(); }
169
+
170
+ private:
171
+ // Soft switch handling
172
+ uint8_t readSoftSwitch(uint16_t address);
173
+ uint8_t peekSoftSwitch(uint16_t address) const;
174
+ void writeSoftSwitch(uint16_t address, uint8_t value);
175
+
176
+ // Floating bus - returns value video hardware is currently reading
177
+ uint8_t getFloatingBusValue();
178
+
179
+ // Language card logic
180
+ uint8_t readLanguageCard(uint16_t address);
181
+ void writeLanguageCard(uint16_t address, uint8_t value);
182
+ uint8_t handleLanguageCardSwitch(uint8_t reg);
183
+ void handleLanguageCardSwitchWrite(uint8_t reg);
184
+
185
+ // Memory banks
186
+ std::array<uint8_t, MAIN_RAM_SIZE> mainRAM_{};
187
+ std::array<uint8_t, AUX_RAM_SIZE> auxRAM_{};
188
+
189
+ // Language card RAM banks
190
+ std::array<uint8_t, 0x1000> lcBank1_{}; // $D000-$DFFF bank 1
191
+ std::array<uint8_t, 0x1000> lcBank2_{}; // $D000-$DFFF bank 2
192
+ std::array<uint8_t, 0x2000> lcHighRAM_{}; // $E000-$FFFF
193
+
194
+ // Auxiliary language card banks
195
+ std::array<uint8_t, 0x1000> auxLcBank1_{};
196
+ std::array<uint8_t, 0x1000> auxLcBank2_{};
197
+ std::array<uint8_t, 0x2000> auxLcHighRAM_{};
198
+
199
+ // ROM - combined 16KB system ROM ($C000-$FFFF)
200
+ std::array<uint8_t, 0x4000> systemROM_{}; // $C000-$FFFF (16KB)
201
+ std::array<uint8_t, CHAR_ROM_SIZE> charROM_{};
202
+
203
+ // Soft switches
204
+ SoftSwitches switches_;
205
+
206
+ // Keyboard state
207
+ uint8_t keyboardLatch_ = 0;
208
+
209
+ // Paddle/joystick state
210
+ std::array<uint8_t, 4> paddleValues_ = {128, 128, 128, 128}; // Centered by default
211
+ uint64_t paddleTriggerCycle_ = 0;
212
+ static constexpr int PADDLE_CYCLES_PER_UNIT = 11; // ~11 cycles per paddle unit
213
+
214
+ // Callbacks
215
+ KeyboardCallback keyboardCallback_;
216
+ KeyStrobeCallback keyStrobeCallback_;
217
+ AnyKeyDownCallback anyKeyDownCallback_;
218
+ SpeakerCallback speakerCallback_;
219
+ ButtonCallback buttonCallback_;
220
+ CycleCallback cycleCallback_;
221
+ VideoSwitchCallback videoSwitchCallback_;
222
+ WatchpointReadCallback watchpointReadCallback_;
223
+ WatchpointWriteCallback watchpointWriteCallback_;
224
+ bool watchpointsActive_ = false;
225
+
226
+ // Expansion slots (1-7, index 0-6)
227
+ std::array<std::unique_ptr<ExpansionCard>, 7> slots_;
228
+ uint8_t activeExpansionSlot_ = 0; // Which card owns $C800-$CFFF (0 = none)
229
+
230
+ // Memory access tracking for debugger heat map
231
+ bool trackingEnabled_ = false;
232
+ std::array<uint8_t, 65536> readCounts_{};
233
+ std::array<uint8_t, 65536> writeCounts_{};
234
+ };
235
+
236
+ } // namespace a2e
@@ -0,0 +1,196 @@
1
+ /*
2
+ * types.hpp - Shared constants, types, and color palettes for the Apple IIe emulator
3
+ *
4
+ * Written by
5
+ * Mike Daley <michael_daley@icloud.com>
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #include <array>
11
+ #include <cstddef>
12
+ #include <cstdint>
13
+ #include <functional>
14
+
15
+ namespace a2e {
16
+
17
+ // Memory size constants
18
+ constexpr size_t MAIN_RAM_SIZE = 64 * 1024; // 64KB main RAM
19
+ constexpr size_t AUX_RAM_SIZE = 64 * 1024; // 64KB auxiliary RAM
20
+ constexpr size_t ROM_SIZE = 16 * 1024; // 16KB ROM ($C000-$FFFF)
21
+ constexpr size_t CHAR_ROM_SIZE = 8 * 1024; // 8KB character ROM (US + UK sets)
22
+ constexpr size_t DISK_ROM_SIZE = 256; // 256 bytes Disk II ROM
23
+
24
+ // Display constants
25
+ constexpr int SCREEN_WIDTH = 560; // 280 * 2 for double-width pixels
26
+ constexpr int SCREEN_HEIGHT = 384; // 192 * 2 for double-height pixels
27
+ constexpr int FRAMEBUFFER_SIZE = SCREEN_WIDTH * SCREEN_HEIGHT * 4; // RGBA
28
+
29
+ // Timing constants
30
+ constexpr double CPU_CLOCK_HZ = 1023000.0; // 1.023 MHz
31
+ constexpr int AUDIO_SAMPLE_RATE = 48000;
32
+ constexpr double CYCLES_PER_SAMPLE =
33
+ CPU_CLOCK_HZ / AUDIO_SAMPLE_RATE; // ~21.3125
34
+
35
+ constexpr int CYCLES_PER_SCANLINE = 65;
36
+ constexpr int SCANLINES_PER_FRAME = 262;
37
+ constexpr int CYCLES_PER_FRAME =
38
+ CYCLES_PER_SCANLINE * SCANLINES_PER_FRAME; // 17030
39
+
40
+ // Video mode flags
41
+ enum class VideoMode : uint8_t {
42
+ TEXT_40 = 0,
43
+ TEXT_80,
44
+ LORES,
45
+ HIRES,
46
+ DOUBLE_LORES,
47
+ DOUBLE_HIRES
48
+ };
49
+
50
+ // Soft switch state - comprehensive Apple IIe soft switches
51
+ struct SoftSwitches {
52
+ // Display switches ($C050-$C057)
53
+ bool text = true; // $C050/$C051: TEXT/GRAPHICS mode
54
+ bool mixed = false; // $C052/$C053: Mixed mode (4 lines text at bottom)
55
+ bool page2 = false; // $C054/$C055: PAGE1/PAGE2
56
+ bool hires = false; // $C056/$C057: LORES/HIRES
57
+
58
+ // 80-column switches ($C00C-$C00F)
59
+ bool col80 = false; // $C00C/$C00D: 40/80 column mode
60
+ bool altCharSet = false; // $C00E/$C00F: Primary/alternate character set
61
+
62
+ // Memory switches ($C000-$C00B)
63
+ bool store80 = false; // $C000/$C001: 80STORE
64
+ bool ramrd = false; // $C002/$C003: RAMRD - aux RAM read
65
+ bool ramwrt = false; // $C004/$C005: RAMWRT - aux RAM write
66
+ bool intcxrom = false; // $C006/$C007: INTCXROM - internal slot ROM
67
+ bool altzp = false; // $C008/$C009: ALTZP - aux zero page/stack
68
+ bool slotc3rom = false; // $C00A/$C00B: SLOTC3ROM - slot 3 ROM
69
+ bool intc8rom = false; // Internal $C800-$CFFF ROM active
70
+
71
+ // Language card ($C080-$C08F)
72
+ bool lcram = false; // LC RAM enabled for read
73
+ bool lcram2 = false; // LC RAM bank 2
74
+ bool lcwrite = false; // LC RAM write-enabled
75
+ bool lcprewrite = false; // LC pre-write state
76
+
77
+ // Annunciators ($C058-$C05F)
78
+ bool an0 = false; // $C058/$C059: Annunciator 0
79
+ bool an1 = false; // $C05A/$C05B: Annunciator 1
80
+ bool an2 = false; // $C05C/$C05D: Annunciator 2
81
+ bool an3 = false; // $C05E/$C05F: Annunciator 3 (DHIRES control)
82
+
83
+ // I/O state (read-only status)
84
+ bool vblBar = false; // $C019: Vertical blank (true = in VBL)
85
+
86
+ // Button states ($C061-$C063)
87
+ bool button0 = false; // $C061: Open Apple / Button 0
88
+ bool button1 = false; // $C062: Closed Apple / Button 1
89
+ bool button2 = false; // $C063: Button 2 / Shift key state
90
+
91
+ // Keyboard
92
+ uint8_t keyLatch = 0; // $C000: Keyboard latch (bit 7 = key available)
93
+ bool keyStrobe = false; // $C010: Keyboard strobe (key available)
94
+
95
+ // Paddle/Joystick
96
+ uint8_t paddle0 = 128; // $C064: PDL0 value (0-255, 128 = center)
97
+ uint8_t paddle1 = 128; // $C065: PDL1 value
98
+ uint8_t paddle2 = 128; // $C066: PDL2 value
99
+ uint8_t paddle3 = 128; // $C067: PDL3 value
100
+
101
+ // Cassette (stub)
102
+ bool cassetteOut = false; // $C020: Cassette output
103
+ bool cassetteIn = false; // $C060: Cassette input
104
+
105
+ // IOU / DHIRES
106
+ bool ioudis = false; // $C07E/$C07F: IOU disable (IIc specific)
107
+ bool dhires = false; // Double hi-res mode (AN3 off + 80COL + HIRES)
108
+ };
109
+
110
+ // Disk drive state
111
+ struct DriveState {
112
+ bool motorOn = false;
113
+ bool writeMode = false;
114
+ int currentTrack = 0; // 0-34
115
+ int currentPhase = 0; // Stepper motor phase
116
+ int headPosition = 0; // Bit position on track
117
+ uint8_t dataLatch = 0;
118
+ bool diskInserted = false;
119
+ };
120
+
121
+ // CPU status flags are defined in cpu/cpu6502.hpp
122
+
123
+ // Color palette for Apple II
124
+ constexpr std::array<uint32_t, 16> LORES_COLORS = {{
125
+ 0xFF000000, // 0: Black
126
+ 0xFFE31E60, // 1: Magenta
127
+ 0xFF604EBD, // 2: Dark Blue
128
+ 0xFFFF44FD, // 3: Purple
129
+ 0xFF00A360, // 4: Dark Green
130
+ 0xFF9C9C9C, // 5: Grey 1
131
+ 0xFF14CFFD, // 6: Medium Blue
132
+ 0xFFD0C3FF, // 7: Light Blue
133
+ 0xFF607203, // 8: Brown
134
+ 0xFFFF6A3C, // 9: Orange
135
+ 0xFF9C9C9C, // 10: Grey 2
136
+ 0xFFFFA0D0, // 11: Pink
137
+ 0xFF14F53C, // 12: Light Green
138
+ 0xFFD0DD8D, // 13: Yellow
139
+ 0xFF72FFD0, // 14: Aqua
140
+ 0xFFFFFFFF // 15: White
141
+ }};
142
+
143
+ // HiRes artifact colors (NTSC-accurate values)
144
+ // Group 1 (high bit = 0): Black, Green, Violet, White
145
+ // Group 2 (high bit = 1): Black, Orange, Blue, White
146
+ constexpr std::array<uint32_t, 6> HIRES_COLORS = {{
147
+ 0xFF000000, // 0: Black
148
+ 0xFF14F53C, // 1: Green (odd pixels, high bit = 0)
149
+ 0xFFFF44FD, // 2: Violet (even pixels, high bit = 0)
150
+ 0xFFFFFFFF, // 3: White
151
+ 0xFF14CFFD, // 4: Blue (even pixels, high bit = 1)
152
+ 0xFFFF6A3C // 5: Orange (odd pixels, high bit = 1)
153
+ }};
154
+
155
+ // Double Lo-Res / Double Hi-Res color palette
156
+ // Different from Lo-Res due to 14MHz dot rate vs 7MHz (changes NTSC phase
157
+ // relationship) Based on AppleWin's DoubleHiresPalIndex mapping See:
158
+ // https://github.com/AppleWin/AppleWin/blob/master/source/RGBMonitor.cpp
159
+ constexpr std::array<uint32_t, 16> DLGR_COLORS = {{
160
+ 0xFF000000, // 0: Black (LORES[0])
161
+ 0xFF604EBD, // 1: Dark Blue (LORES[2])
162
+ 0xFF00A360, // 2: Dark Green (LORES[4])
163
+ 0xFF14CFFD, // 3: Medium Blue (LORES[6])
164
+ 0xFF607203, // 4: Brown (LORES[8])
165
+ 0xFF9C9C9C, // 5: Grey (LORES[10])
166
+ 0xFF14F53C, // 6: Light Green (LORES[12])
167
+ 0xFF72FFD0, // 7: Aqua (LORES[14])
168
+ 0xFFE31E60, // 8: Magenta (LORES[1])
169
+ 0xFFFF44FD, // 9: Purple (LORES[3])
170
+ 0xFF9C9C9C, // 10: Grey (LORES[5])
171
+ 0xFFD0C3FF, // 11: Light Blue (LORES[7])
172
+ 0xFFFF6A3C, // 12: Orange (LORES[9])
173
+ 0xFFFFA0D0, // 13: Pink (LORES[11])
174
+ 0xFFD0DD8D, // 14: Yellow (LORES[13])
175
+ 0xFFFFFFFF // 15: White (LORES[15])
176
+ }};
177
+
178
+ // Snapshot of video-relevant soft switch state for per-scanline rendering
179
+ struct VideoSwitchState {
180
+ bool text;
181
+ bool mixed;
182
+ bool page2;
183
+ bool hires;
184
+ bool col80;
185
+ bool altCharSet;
186
+ bool store80;
187
+ bool an3;
188
+ };
189
+
190
+ // Records a video switch change at a specific cycle within a frame
191
+ struct VideoSwitchChange {
192
+ uint32_t cycleOffset; // Cycle offset from frame start
193
+ VideoSwitchState state; // Full snapshot after the change
194
+ };
195
+
196
+ } // namespace a2e