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,364 @@
1
+ # Memory System
2
+
3
+ This page describes the MMU (Memory Management Unit) implementation, covering the 128KB memory layout, bank switching, Language Card, soft switch map, expansion slot ROM routing, floating bus behavior, and memory visibility rules.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Overview](#overview)
10
+ - [Memory Layout](#memory-layout)
11
+ - [Bank Switching](#bank-switching)
12
+ - [80STORE Mode](#80store-mode)
13
+ - [Language Card](#language-card)
14
+ - [Soft Switch Map](#soft-switch-map)
15
+ - [Slot ROM Space](#slot-rom-space)
16
+ - [Floating Bus](#floating-bus)
17
+ - [Keyboard and Input](#keyboard-and-input)
18
+ - [Paddle Timers](#paddle-timers)
19
+ - [Memory Access Tracking](#memory-access-tracking)
20
+
21
+ ---
22
+
23
+ ## Overview
24
+
25
+ The MMU is implemented in `src/core/mmu/mmu.cpp` and `mmu.hpp`. It manages the full 128KB address space of the Apple IIe Enhanced (64KB main + 64KB auxiliary RAM), plus 16KB of system ROM, 8KB of character ROM, and the Language Card RAM banks. All CPU memory accesses route through the MMU, which decodes addresses and dispatches to the appropriate memory bank, soft switch handler, or expansion card.
26
+
27
+ The MMU provides two read interfaces:
28
+ - `read()` -- Normal read with full side effects (soft switch triggers, watchpoint callbacks, access tracking)
29
+ - `peek()` -- Non-side-effecting read for the debugger and memory viewer
30
+
31
+ ---
32
+
33
+ ## Memory Layout
34
+
35
+ ### Physical Memory
36
+
37
+ | Memory | Size | Storage |
38
+ |--------|------|---------|
39
+ | Main RAM | 64 KB | `mainRAM_[65536]` |
40
+ | Auxiliary RAM | 64 KB | `auxRAM_[65536]` |
41
+ | Language Card Bank 1 (main) | 4 KB | `lcBank1_[4096]` |
42
+ | Language Card Bank 2 (main) | 4 KB | `lcBank2_[4096]` |
43
+ | Language Card High (main) | 8 KB | `lcHighRAM_[8192]` |
44
+ | Language Card Bank 1 (aux) | 4 KB | `auxLcBank1_[4096]` |
45
+ | Language Card Bank 2 (aux) | 4 KB | `auxLcBank2_[4096]` |
46
+ | Language Card High (aux) | 8 KB | `auxLcHighRAM_[8192]` |
47
+ | System ROM | 16 KB | `systemROM_[16384]` |
48
+ | Character ROM | 8 KB | `charROM_[8192]` |
49
+
50
+ ### Address Map
51
+
52
+ | Address Range | Default Mapping | Notes |
53
+ |---------------|----------------|-------|
54
+ | `$0000`-`$01FF` | Main zero page and stack | ALTZP switches to aux |
55
+ | `$0200`-`$03FF` | Main RAM | RAMRD/RAMWRT for aux |
56
+ | `$0400`-`$07FF` | Text page 1 | 80STORE overrides RAMRD/RAMWRT |
57
+ | `$0800`-`$0BFF` | Text page 2 | RAMRD/RAMWRT for aux |
58
+ | `$0C00`-`$1FFF` | Main RAM | RAMRD/RAMWRT for aux |
59
+ | `$2000`-`$3FFF` | HiRes page 1 | 80STORE+HIRES overrides RAMRD/RAMWRT |
60
+ | `$4000`-`$5FFF` | HiRes page 2 | RAMRD/RAMWRT for aux |
61
+ | `$6000`-`$BFFF` | Main RAM | RAMRD/RAMWRT for aux |
62
+ | `$C000`-`$C00F` | Soft switches (write) / Keyboard (read) | Write-only switches; reads return keyboard latch |
63
+ | `$C010`-`$C01F` | Status reads / Keyboard strobe | Bit 7 = status, bits 0-6 = floating bus |
64
+ | `$C020` | Cassette output toggle | |
65
+ | `$C030` | Speaker toggle | |
66
+ | `$C050`-`$C05F` | Display and annunciator switches | Both read and write trigger |
67
+ | `$C060`-`$C063` | Cassette input, buttons | |
68
+ | `$C064`-`$C067` | Paddle inputs | Timer-based |
69
+ | `$C070` | Paddle trigger | |
70
+ | `$C07F` | DHIRES status | |
71
+ | `$C080`-`$C08F` | Language Card switches | See Language Card section |
72
+ | `$C090`-`$C0FF` | Slot I/O (16 bytes per slot) | Routes to expansion cards |
73
+ | `$C100`-`$C7FF` | Slot ROM (256 bytes per slot) | INTCXROM can override |
74
+ | `$C800`-`$CFFF` | Expansion ROM / Internal ROM | Shared 2KB expansion space |
75
+ | `$D000`-`$DFFF` | ROM or Language Card bank 1/2 | |
76
+ | `$E000`-`$FFFF` | ROM or Language Card high RAM | Contains reset/IRQ vectors |
77
+
78
+ ---
79
+
80
+ ## Bank Switching
81
+
82
+ The Apple IIe has several soft switches that control which physical memory bank is visible at a given address range:
83
+
84
+ ### RAMRD / RAMWRT (`$C002`-`$C005`)
85
+
86
+ | Switch | Address | Effect |
87
+ |--------|---------|--------|
88
+ | RAMRD off | `$C002` (write) | Reads from `$0200`-`$BFFF` go to main RAM |
89
+ | RAMRD on | `$C003` (write) | Reads from `$0200`-`$BFFF` go to aux RAM |
90
+ | RAMWRT off | `$C004` (write) | Writes to `$0200`-`$BFFF` go to main RAM |
91
+ | RAMWRT on | `$C005` (write) | Writes to `$0200`-`$BFFF` go to aux RAM |
92
+
93
+ ### ALTZP (`$C008`-`$C009`)
94
+
95
+ | Switch | Address | Effect |
96
+ |--------|---------|--------|
97
+ | ALTZP off | `$C008` (write) | Zero page (`$00`-`$FF`) and stack (`$100`-`$1FF`) use main RAM; Language Card uses main banks |
98
+ | ALTZP on | `$C009` (write) | Zero page and stack use aux RAM; Language Card uses aux banks |
99
+
100
+ ### INTCXROM (`$C006`-`$C007`)
101
+
102
+ | Switch | Address | Effect |
103
+ |--------|---------|--------|
104
+ | INTCXROM off | `$C006` (write) | `$C100`-`$CFFF` uses slot card ROMs |
105
+ | INTCXROM on | `$C007` (write) | `$C100`-`$CFFF` uses internal system ROM |
106
+
107
+ ### SLOTC3ROM (`$C00A`-`$C00B`)
108
+
109
+ | Switch | Address | Effect |
110
+ |--------|---------|--------|
111
+ | SLOTC3ROM off | `$C00A` (write) | `$C300`-`$C3FF` uses internal 80-column ROM; activates `$C800` internal ROM |
112
+ | SLOTC3ROM on | `$C00B` (write) | `$C300`-`$C3FF` uses slot 3 card ROM (if present) |
113
+
114
+ ---
115
+
116
+ ## 80STORE Mode
117
+
118
+ When 80STORE is enabled (`$C001`), the PAGE2 switch (`$C054`/`$C055`) controls main/aux bank selection for display memory, overriding RAMRD and RAMWRT:
119
+
120
+ - **Text page 1** (`$0400`-`$07FF`): PAGE2 off = main RAM, PAGE2 on = aux RAM
121
+ - **HiRes page 1** (`$2000`-`$3FFF`): Only when both 80STORE and HIRES are on. PAGE2 off = main RAM, PAGE2 on = aux RAM
122
+
123
+ This is the mechanism used by 80-column text and Double Hi-Res modes to access auxiliary display memory. When 80STORE is off, RAMRD/RAMWRT control bank selection for these regions normally.
124
+
125
+ ---
126
+
127
+ ## Language Card
128
+
129
+ The Language Card provides 16KB of RAM that overlays the ROM at `$D000`-`$FFFF`. The `$D000`-`$DFFF` region has two switchable 4KB banks.
130
+
131
+ ### Switch Registers (`$C080`-`$C08F`)
132
+
133
+ The Language Card is controlled by soft switches at `$C080`-`$C08F`. The switch behavior depends on read vs. write access and uses a "double read" mechanism for write-enable.
134
+
135
+ | Bits | Meaning |
136
+ |------|---------|
137
+ | Bit 3 | Bank select: 0 = bank 2, 1 = bank 1 |
138
+ | Bits 0-1 | Mode (see table below) |
139
+
140
+ | Bits 0-1 | Read Source | Write Enable |
141
+ |----------|------------|--------------|
142
+ | 00 | RAM | Disabled |
143
+ | 01 | ROM | Enabled (after 2 consecutive reads) |
144
+ | 10 | ROM | Disabled |
145
+ | 11 | RAM | Enabled (after 2 consecutive reads) |
146
+
147
+ ### Common Switch Combinations
148
+
149
+ | Address | Read | Bank | Read Source | Write |
150
+ |---------|------|------|------------|-------|
151
+ | `$C080` | R | 2 | RAM | Off |
152
+ | `$C081` | RR | 2 | ROM | On (double read) |
153
+ | `$C082` | R | 2 | ROM | Off |
154
+ | `$C083` | RR | 2 | RAM | On (double read) |
155
+ | `$C088` | R | 1 | RAM | Off |
156
+ | `$C089` | RR | 1 | ROM | On (double read) |
157
+ | `$C08A` | R | 1 | ROM | Off |
158
+ | `$C08B` | RR | 1 | RAM | On (double read) |
159
+
160
+ ### Double-Read Write-Enable
161
+
162
+ Writes to Language Card switches reset the "prewrite" counter without counting toward the double-read requirement. This means:
163
+
164
+ - `LDA $C083` + `LDA $C083` enables writes (two reads)
165
+ - `LDA $C083` + `STA $C083` + `LDA $C083` does NOT enable writes (the STA resets the counter)
166
+ - `INC $C083` DOES enable writes (INC performs two reads before its write)
167
+
168
+ ### Auxiliary Language Card
169
+
170
+ When ALTZP is on, the Language Card reads/writes go to the auxiliary banks (`auxLcBank1_`, `auxLcBank2_`, `auxLcHighRAM_`) instead of the main banks.
171
+
172
+ ---
173
+
174
+ ## Soft Switch Map
175
+
176
+ ### Write-Only Switches (`$C000`-`$C00F`)
177
+
178
+ These switches are triggered by writes. Reads to this range return the keyboard latch value.
179
+
180
+ | Address | Switch | Description |
181
+ |---------|--------|-------------|
182
+ | `$C000` | 80STORE off | Disable 80STORE |
183
+ | `$C001` | 80STORE on | Enable 80STORE |
184
+ | `$C002` | RAMRD off | Main RAM read |
185
+ | `$C003` | RAMRD on | Aux RAM read |
186
+ | `$C004` | RAMWRT off | Main RAM write |
187
+ | `$C005` | RAMWRT on | Aux RAM write |
188
+ | `$C006` | INTCXROM off | Slot card ROMs |
189
+ | `$C007` | INTCXROM on | Internal ROM |
190
+ | `$C008` | ALTZP off | Main zero page |
191
+ | `$C009` | ALTZP on | Aux zero page |
192
+ | `$C00A` | SLOTC3ROM off | Internal slot 3 ROM |
193
+ | `$C00B` | SLOTC3ROM on | Slot 3 card ROM |
194
+ | `$C00C` | 80COL off | 40-column mode |
195
+ | `$C00D` | 80COL on | 80-column mode |
196
+ | `$C00E` | ALTCHAR off | Primary character set |
197
+ | `$C00F` | ALTCHAR on | Alternate character set (MouseText) |
198
+
199
+ ### Status Reads (`$C010`-`$C01F`)
200
+
201
+ Status switches return the switch state in bit 7 and floating bus data in bits 0-6.
202
+
203
+ | Address | Read | Description |
204
+ |---------|------|-------------|
205
+ | `$C010` | KBDSTRB | Clear keyboard strobe; bit 7 = any key down |
206
+ | `$C011` | RDLCBNK2 | Language Card bank 2 selected |
207
+ | `$C012` | RDLCRAM | Language Card RAM read enabled |
208
+ | `$C013` | RDRAMRD | Aux RAM read enabled |
209
+ | `$C014` | RDRAMWRT | Aux RAM write enabled |
210
+ | `$C015` | RDCXROM | Internal CX ROM active |
211
+ | `$C016` | RDALTZP | Aux zero page active |
212
+ | `$C017` | RDC3ROM | Slot 3 ROM active |
213
+ | `$C018` | RD80STORE | 80STORE active |
214
+ | `$C019` | RDVBLBAR | Bit 7: 0 during VBL, 1 during active display |
215
+ | `$C01A` | RDTEXT | Text mode active |
216
+ | `$C01B` | RDMIXED | Mixed mode active |
217
+ | `$C01C` | RDPAGE2 | Page 2 active |
218
+ | `$C01D` | RDHIRES | HiRes mode active |
219
+ | `$C01E` | RDALTCHAR | Alternate character set active |
220
+ | `$C01F` | RD80COL | 80-column mode active |
221
+
222
+ ### Display and Annunciator Switches (`$C050`-`$C05F`)
223
+
224
+ These switches are activated by both reads and writes.
225
+
226
+ | Address | Switch | Description |
227
+ |---------|--------|-------------|
228
+ | `$C050` | TXTCLR | Graphics mode |
229
+ | `$C051` | TXTSET | Text mode |
230
+ | `$C052` | MIXCLR | Full-screen mode |
231
+ | `$C053` | MIXSET | Mixed mode (4 lines text) |
232
+ | `$C054` | LOWSCR | Page 1 |
233
+ | `$C055` | HISCR | Page 2 |
234
+ | `$C056` | LORES | Low-resolution mode |
235
+ | `$C057` | HIRES | High-resolution mode |
236
+ | `$C058`/`$C059` | AN0 off/on | Annunciator 0 |
237
+ | `$C05A`/`$C05B` | AN1 off/on | Annunciator 1 |
238
+ | `$C05C`/`$C05D` | AN2 off/on | Annunciator 2 |
239
+ | `$C05E`/`$C05F` | AN3 off/on | Annunciator 3 (controls DHIRES) |
240
+
241
+ ### I/O Devices
242
+
243
+ | Address | Device | Description |
244
+ |---------|--------|-------------|
245
+ | `$C000` | Keyboard | Read: key latch (bit 7 = key available) |
246
+ | `$C010` | Keyboard Strobe | Read: clear strobe, return any-key-down in bit 7 |
247
+ | `$C020` | Cassette Out | Toggle cassette output |
248
+ | `$C030` | Speaker | Toggle speaker state |
249
+ | `$C060` | Cassette In | Cassette input (always low, no cassette) |
250
+ | `$C061` | Button 0 | Open Apple key (bit 7 = pressed) |
251
+ | `$C062` | Button 1 | Closed Apple key (bit 7 = pressed) |
252
+ | `$C063` | Button 2 | Shift key / button 2 |
253
+ | `$C064`-`$C067` | Paddles 0-3 | Timer countdown (bit 7 = counting) |
254
+ | `$C070` | PTRIG | Reset all paddle timers |
255
+ | `$C07F` | IOUDIS/DHIRES | Bit 7 = DHIRES status (AN3 inverted) |
256
+
257
+ ---
258
+
259
+ ## Slot ROM Space
260
+
261
+ ### Per-Slot I/O (`$C080`-`$C0FF`)
262
+
263
+ Each expansion slot has 16 bytes of I/O space:
264
+
265
+ | Address Range | Slot |
266
+ |---------------|------|
267
+ | `$C080`-`$C08F` | Language Card (special) |
268
+ | `$C090`-`$C09F` | Slot 1 |
269
+ | `$C0A0`-`$C0AF` | Slot 2 |
270
+ | `$C0B0`-`$C0BF` | Slot 3 (80-column, built-in) |
271
+ | `$C0C0`-`$C0CF` | Slot 4 |
272
+ | `$C0D0`-`$C0DF` | Slot 5 |
273
+ | `$C0E0`-`$C0EF` | Slot 6 |
274
+ | `$C0F0`-`$C0FF` | Slot 7 |
275
+
276
+ Reads and writes to slot I/O are dispatched to the installed card's `readIO()` / `writeIO()` methods with a 4-bit offset (0-15).
277
+
278
+ ### Per-Slot ROM (`$C100`-`$C7FF`)
279
+
280
+ Each slot has 256 bytes of ROM space at `$CN00`-`$CNFF`. Accessing a slot's ROM page activates that card's expansion ROM at `$C800`-`$CFFF`. The card's `readROM()` method is called with an 8-bit offset.
281
+
282
+ ### Expansion ROM (`$C800`-`$CFFF`)
283
+
284
+ This 2KB region is shared among all expansion cards. Only one card's expansion ROM can be active at a time, determined by the last slot ROM page accessed. The `activeExpansionSlot_` variable tracks which card currently owns this region.
285
+
286
+ A read from `$CFFF` deactivates the current expansion ROM after returning its data.
287
+
288
+ ### Slot 3 Special Handling
289
+
290
+ Slot 3 is normally the built-in 80-column firmware. When SLOTC3ROM is off (default), reads to `$C300`-`$C3FF` return internal system ROM and also activate the internal ROM for `$C800`-`$CFFF` (via `intc8rom`). When SLOTC3ROM is on, the region uses the slot 3 card ROM if one is installed.
291
+
292
+ ---
293
+
294
+ ## Floating Bus
295
+
296
+ When the CPU reads an unoccupied or unmapped I/O address, it gets the "floating bus" value -- whatever byte the video circuitry is currently fetching from memory. The MMU computes this from the current CPU cycle count:
297
+
298
+ 1. Calculate the frame cycle position: `cycles % CYCLES_PER_FRAME`
299
+ 2. Derive the scanline and horizontal position
300
+ 3. During horizontal blanking (cycles 0-24 of each scanline), return `$00`
301
+ 4. During vertical blanking, wrap the scanline into the visible range
302
+ 5. Compute the address the video hardware would be reading based on the current video mode (text/lores or hires) and display page
303
+ 6. Return the byte at that address from the appropriate memory bank
304
+
305
+ This behavior is important for some copy protection schemes and timing-sensitive software that reads floating bus values to detect the beam position.
306
+
307
+ ---
308
+
309
+ ## Keyboard and Input
310
+
311
+ ### Keyboard Latch (`$C000`)
312
+
313
+ Reading `$C000` returns the keyboard latch. Bit 7 is set when a key has been pressed and not yet read. Bits 0-6 contain the ASCII code of the key (or Apple II-specific code). The latch retains its value until explicitly cleared.
314
+
315
+ ### Keyboard Strobe (`$C010`)
316
+
317
+ Reading `$C010` clears the keyboard strobe (bit 7 of the latch) and returns the any-key-down status in bit 7 with the key code in bits 0-6. Writing to `$C010` also clears the strobe.
318
+
319
+ ### Buttons (`$C061`-`$C063`)
320
+
321
+ Button state is returned in bit 7 (pressed = `$80`, released = `$00`). Bits 0-6 contain floating bus data. The buttons map to:
322
+
323
+ | Address | Button | Physical Key |
324
+ |---------|--------|-------------|
325
+ | `$C061` | Button 0 | Open Apple (left Alt/Option) |
326
+ | `$C062` | Button 1 | Closed Apple (right Alt/Option) |
327
+ | `$C063` | Button 2 | Shift key state |
328
+
329
+ ---
330
+
331
+ ## Paddle Timers
332
+
333
+ The Apple IIe uses a timer-based paddle reading mechanism:
334
+
335
+ 1. Software writes to `$C070` (PTRIG) to start all four paddle timers
336
+ 2. The MMU records the current CPU cycle count as `paddleTriggerCycle_`
337
+ 3. Reading `$C064`-`$C067` returns bit 7 = 1 while the timer is running, 0 when expired
338
+ 4. Timer duration is `paddleValue * 11 cycles` (approximately 11 cycles per unit)
339
+ 5. Paddle values range from 0-255, with 128 as center
340
+
341
+ This means a centered joystick axis produces a timer of about 1,408 cycles (128 * 11).
342
+
343
+ ---
344
+
345
+ ## Memory Access Tracking
346
+
347
+ The MMU includes optional access tracking for the debugger heat map visualization:
348
+
349
+ - `enableTracking(bool)` -- Enable/disable tracking
350
+ - `readCounts_[65536]` -- Per-address read access counters (saturate at 255)
351
+ - `writeCounts_[65536]` -- Per-address write access counters
352
+ - `decayTracking(amount)` -- Reduce all counters by a fixed amount for real-time decay
353
+ - `clearTracking()` -- Reset all counters to zero
354
+
355
+ When tracking is enabled, every `read()` and `write()` call increments the corresponding counter for that address. The JavaScript heat map window periodically decays and reads these counters to produce a visual representation of memory access patterns.
356
+
357
+ ---
358
+
359
+ ## See Also
360
+
361
+ - [[Architecture-Overview]] -- How the MMU fits into the emulator
362
+ - [[CPU-Emulation]] -- CPU that reads/writes through MMU callbacks
363
+ - [[Video-Rendering]] -- Video modes controlled by soft switches
364
+ - [[Expansion-Slots]] -- Card architecture using MMU slot system
@@ -0,0 +1,172 @@
1
+ # Save States
2
+
3
+ The emulator provides a complete save state system that captures the entire machine state and stores it in the browser's IndexedDB. States can be saved and restored automatically or manually, and can be downloaded as files for backup or sharing.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Autosave](#autosave)
9
+ - [Save States Window](#save-states-window)
10
+ - [Manual Save Slots](#manual-save-slots)
11
+ - [Loading a State](#loading-a-state)
12
+ - [Clearing a Slot](#clearing-a-slot)
13
+ - [Downloading and Importing State Files](#downloading-and-importing-state-files)
14
+ - [What Is Included in a Save State](#what-is-included-in-a-save-state)
15
+ - [Screenshots and Previews](#screenshots-and-previews)
16
+ - [Storage](#storage)
17
+
18
+ ## Overview
19
+
20
+ The save state system consists of:
21
+
22
+ - **Autosave slot** -- Automatically saves the emulator state at regular intervals
23
+ - **5 manual slots** -- User-triggered save/load with individual screenshots
24
+ - **File import/export** -- Download states as `.a2state` files or load them back
25
+
26
+ ## Autosave
27
+
28
+ The autosave system runs in the background while the emulator is powered on. It captures the full machine state periodically so that your session is preserved if you close the browser tab or navigate away.
29
+
30
+ ### Autosave Behavior
31
+
32
+ - Saves every **5 seconds** while the emulator is running and the tab is visible
33
+ - Saves immediately when the browser tab becomes hidden (tab switch, minimize)
34
+ - Saves on page unload (closing the tab or navigating away)
35
+ - The autosave indicator briefly flashes in the menu bar each time a save occurs
36
+ - Autosave is enabled by default and can be toggled from the **System** menu
37
+
38
+ ### Toggling Autosave
39
+
40
+ The autosave toggle is available in the **System** menu. The setting persists across sessions via localStorage.
41
+
42
+ ### Restoring from Autosave
43
+
44
+ When the emulator starts, if an autosave state exists, it is automatically restored. You can also manually load the autosave from the Save States window.
45
+
46
+ ## Save States Window
47
+
48
+ Open the Save States window from the **System** menu. The window shows all available save slots arranged vertically:
49
+
50
+ - **Autosave row (A)** -- Shows the most recent autosave with a thumbnail, timestamp, and Load/Download buttons
51
+ - **Slots 1-5** -- Manual save slots, each with Save, Load, Clear, and Download buttons
52
+ - **Load from File** button -- At the bottom, allows importing a previously downloaded `.a2state` file
53
+
54
+ Each slot displays:
55
+
56
+ - A **slot number** (A for autosave, 1-5 for manual slots)
57
+ - A **thumbnail screenshot** of the emulator display at the time of the save
58
+ - A **status label** ("Saved", "Empty", or "Autosave")
59
+ - A **timestamp** showing when the state was saved (e.g. "just now", "5m ago", "2h ago", or a date)
60
+
61
+ Hovering over a slot's thumbnail shows a larger preview image.
62
+
63
+ ## Manual Save Slots
64
+
65
+ There are 5 manual save slots. Each slot supports four actions:
66
+
67
+ | Action | Description |
68
+ |--------|-------------|
69
+ | **Save** | Captures the current emulator state and screenshot into the slot. The emulator must be powered on. |
70
+ | **Load** | Restores the emulator to the saved state. Power-cycles the emulator first for a clean restore. |
71
+ | **Clear** | Removes the saved state from the slot, freeing storage space. |
72
+ | **DL** (Download) | Downloads the saved state as an `.a2state` file. |
73
+
74
+ The autosave slot only has Load and Download buttons -- it cannot be manually saved to or cleared.
75
+
76
+ ## Loading a State
77
+
78
+ When a state is loaded (from any slot or from a file):
79
+
80
+ 1. The emulator is stopped (power-cycled)
81
+ 2. A fresh emulator session is started
82
+ 3. The saved state data is imported into the WASM core
83
+ 4. Disk drive state is synchronized with the restored state
84
+ 5. Debugger breakpoints and watchpoints are re-synced
85
+ 6. The emulator continues running from the exact point where it was saved
86
+
87
+ ## Clearing a Slot
88
+
89
+ Clicking **Clear** on a manual slot removes the saved state data and screenshot from IndexedDB. The slot returns to the "Empty" state. The autosave slot cannot be manually cleared.
90
+
91
+ ## Downloading and Importing State Files
92
+
93
+ ### Downloading
94
+
95
+ Click the **DL** button on any populated slot to download the state as a file. The file is saved with the `.a2state` extension:
96
+
97
+ - Autosave downloads as `apple2e-autosave.a2state`
98
+ - Manual slots download as `apple2e-slot-N.a2state` (where N is the slot number)
99
+
100
+ If the browser supports the File System Access API, a native save dialog appears. Otherwise, the file downloads directly.
101
+
102
+ ### Importing from File
103
+
104
+ Click **Load from File...** at the bottom of the Save States window to import a previously downloaded `.a2state` file. The file is validated by checking for the `A2ES` magic bytes in the header before attempting to restore the state.
105
+
106
+ ## What Is Included in a Save State
107
+
108
+ A save state captures the complete machine state as a binary blob with a versioned header. The following data is serialized:
109
+
110
+ ### Header
111
+ - Magic bytes (`A2ES`)
112
+ - State format version number
113
+
114
+ ### CPU State
115
+ - Registers: A, X, Y, Stack Pointer, Status (P), Program Counter
116
+ - Total cycle count
117
+
118
+ ### Memory
119
+ - **Main RAM** -- Full 64 KB
120
+ - **Auxiliary RAM** -- Full 64 KB
121
+ - **Language Card RAM (Main)** -- 16 KB (Bank 1 + Bank 2 + High RAM)
122
+ - **Language Card RAM (Aux)** -- 16 KB (Bank 1 + Bank 2 + High RAM)
123
+
124
+ ### Soft Switches
125
+ All Apple IIe soft switch states are packed into a single 32-bit word, including:
126
+ - Video switches: TEXT, MIXED, PAGE2, HIRES, 80COL, ALTCHARSET
127
+ - Memory switches: STORE80, RAMRD, RAMWRT, ALTZP
128
+ - ROM switches: INTCXROM, SLOTC3ROM, INTC8ROM
129
+ - Language Card: LCRAM, LCRAM2, LCWRITE, LCPREWRITE
130
+ - Annunciators: AN0-AN3
131
+ - I/O: IOUDIS
132
+
133
+ ### Input State
134
+ - Keyboard latch and key-down flag
135
+ - Button states (3 buttons)
136
+
137
+ ### Timing
138
+ - Last frame cycle count
139
+ - Audio samples generated count
140
+
141
+ ### Disk Controller
142
+ - Motor state, selected drive, Q6/Q7 latches
143
+ - Phase states, data latch, sequencer state, bus data, LSS clock
144
+ - Per-drive: quarter-track position, full disk image data (with any in-memory modifications), and filename
145
+
146
+ ### Audio
147
+ - Speaker toggle state
148
+
149
+ ### Expansion Cards
150
+ - **Mockingboard** -- Full serialized state (AY-3-8910 registers, VIA 6522 timers)
151
+ - **Thunderclock** -- Card-specific state
152
+ - **Mouse Card** -- Card-specific state
153
+ - Other expansion cards in slots 1-7 (excluding slot 4 Mockingboard and slot 6 Disk II, which use dedicated serialization)
154
+
155
+ ## Screenshots and Previews
156
+
157
+ Each save state includes two screenshots captured at the time of saving:
158
+
159
+ - **Thumbnail** -- 140 x 96 pixels, displayed in the slot list
160
+ - **Preview** -- 560 x 384 pixels (full emulator resolution), shown on hover
161
+
162
+ Screenshots are stored as PNG data URLs alongside the state data in IndexedDB.
163
+
164
+ ## Storage
165
+
166
+ All save state data is stored in the browser's **IndexedDB** under the database name `a2e-state-persistence`. The `emulatorState` object store holds the autosave and all 5 manual slots.
167
+
168
+ State data size varies depending on disk images. A typical save state with one disk inserted is approximately 200-400 KB. States with two disks or larger disk images will be correspondingly larger.
169
+
170
+ The autosave toggle setting is stored separately in **localStorage** under the key `a2e-autosave-state`.
171
+
172
+ See also: [[Getting-Started]], [[Disk-Drives]]