web-a2e 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.clangd +5 -0
- package/.mcp.json +12 -0
- package/CLAUDE.md +362 -0
- package/CMakeLists.txt +774 -0
- package/LICENSE +21 -0
- package/README.md +392 -0
- package/build-wasm/generated/roms.cpp +2447 -0
- package/docker-compose.staging.yml +9 -0
- package/docs/basic-rom-disassembly.md +6663 -0
- package/docs/softswitch-comparison.md +273 -0
- package/docs/thunderclock-debug.md +89 -0
- package/examples/cube.bas +72 -0
- package/examples/hello.s +55 -0
- package/examples/scroll.s +140 -0
- package/package.json +18 -0
- package/public/assets/apple-logo-old.png +0 -0
- package/public/assets/apple-logo.png +0 -0
- package/public/assets/drive-closed-light-on.png +0 -0
- package/public/assets/drive-closed.png +0 -0
- package/public/assets/drive-open-light-on.png +0 -0
- package/public/assets/drive-open.png +0 -0
- package/public/audio-worklet.js +82 -0
- package/public/disks/Apple DOS 3.3 January 1983.dsk +0 -0
- package/public/disks/ProDOS 2.4.3.po +0 -0
- package/public/disks/h32mb.2mg +0 -0
- package/public/disks/library.json +26 -0
- package/public/docs/llms/llm-assembler.txt +90 -0
- package/public/docs/llms/llm-basic-program.txt +256 -0
- package/public/docs/llms/llm-disk-drives.txt +72 -0
- package/public/docs/llms/llm-file-explorer.txt +50 -0
- package/public/docs/llms/llm-hard-drives.txt +80 -0
- package/public/docs/llms/llm-main.txt +51 -0
- package/public/docs/llms/llm-slot-configuration.txt +66 -0
- package/public/icons/icon-192.svg +4 -0
- package/public/icons/icon-512.svg +4 -0
- package/public/index.html +661 -0
- package/public/llms.txt +49 -0
- package/public/manifest.json +29 -0
- package/public/shaders/burnin.glsl +22 -0
- package/public/shaders/crt.glsl +706 -0
- package/public/shaders/edge.glsl +109 -0
- package/public/shaders/vertex.glsl +8 -0
- package/public/sw.js +186 -0
- package/roms/341-0027.bin +0 -0
- package/roms/341-0160-A-US-UK.bin +0 -0
- package/roms/341-0160-A.bin +0 -0
- package/roms/342-0273-A-US-UK.bin +0 -0
- package/roms/342-0349-B-C0-FF.bin +0 -0
- package/roms/Apple Mouse Interface Card ROM - 342-0270-C.bin +0 -0
- package/roms/Thunderclock Plus ROM.bin +0 -0
- package/scripts/generate_roms.sh +69 -0
- package/src/bindings/wasm_interface.cpp +1940 -0
- package/src/core/assembler/assembler.cpp +1239 -0
- package/src/core/assembler/assembler.hpp +115 -0
- package/src/core/audio/audio.cpp +160 -0
- package/src/core/audio/audio.hpp +81 -0
- package/src/core/basic/basic_detokenizer.cpp +436 -0
- package/src/core/basic/basic_detokenizer.hpp +41 -0
- package/src/core/basic/basic_tokenizer.cpp +286 -0
- package/src/core/basic/basic_tokenizer.hpp +26 -0
- package/src/core/basic/basic_tokens.hpp +295 -0
- package/src/core/cards/disk2_card.cpp +568 -0
- package/src/core/cards/disk2_card.hpp +316 -0
- package/src/core/cards/expansion_card.hpp +185 -0
- package/src/core/cards/mockingboard/ay8910.cpp +616 -0
- package/src/core/cards/mockingboard/ay8910.hpp +159 -0
- package/src/core/cards/mockingboard/via6522.cpp +530 -0
- package/src/core/cards/mockingboard/via6522.hpp +163 -0
- package/src/core/cards/mockingboard_card.cpp +312 -0
- package/src/core/cards/mockingboard_card.hpp +159 -0
- package/src/core/cards/mouse_card.cpp +654 -0
- package/src/core/cards/mouse_card.hpp +190 -0
- package/src/core/cards/smartport/block_device.cpp +202 -0
- package/src/core/cards/smartport/block_device.hpp +60 -0
- package/src/core/cards/smartport/smartport_card.cpp +603 -0
- package/src/core/cards/smartport/smartport_card.hpp +120 -0
- package/src/core/cards/thunderclock_card.cpp +237 -0
- package/src/core/cards/thunderclock_card.hpp +122 -0
- package/src/core/cpu/cpu6502.cpp +1609 -0
- package/src/core/cpu/cpu6502.hpp +203 -0
- package/src/core/debug/condition_evaluator.cpp +470 -0
- package/src/core/debug/condition_evaluator.hpp +87 -0
- package/src/core/disassembler/disassembler.cpp +552 -0
- package/src/core/disassembler/disassembler.hpp +171 -0
- package/src/core/disk-image/disk_image.hpp +267 -0
- package/src/core/disk-image/dsk_disk_image.cpp +827 -0
- package/src/core/disk-image/dsk_disk_image.hpp +204 -0
- package/src/core/disk-image/gcr_encoding.cpp +147 -0
- package/src/core/disk-image/gcr_encoding.hpp +78 -0
- package/src/core/disk-image/woz_disk_image.cpp +1049 -0
- package/src/core/disk-image/woz_disk_image.hpp +343 -0
- package/src/core/emulator.cpp +2126 -0
- package/src/core/emulator.hpp +434 -0
- package/src/core/filesystem/dos33.cpp +178 -0
- package/src/core/filesystem/dos33.hpp +66 -0
- package/src/core/filesystem/pascal.cpp +262 -0
- package/src/core/filesystem/pascal.hpp +87 -0
- package/src/core/filesystem/prodos.cpp +369 -0
- package/src/core/filesystem/prodos.hpp +119 -0
- package/src/core/input/keyboard.cpp +227 -0
- package/src/core/input/keyboard.hpp +111 -0
- package/src/core/mmu/mmu.cpp +1387 -0
- package/src/core/mmu/mmu.hpp +236 -0
- package/src/core/types.hpp +196 -0
- package/src/core/video/video.cpp +680 -0
- package/src/core/video/video.hpp +156 -0
- package/src/css/assembler-editor.css +1617 -0
- package/src/css/base.css +470 -0
- package/src/css/basic-debugger.css +791 -0
- package/src/css/basic-editor.css +792 -0
- package/src/css/controls.css +783 -0
- package/src/css/cpu-debugger.css +1413 -0
- package/src/css/debug-base.css +160 -0
- package/src/css/debug-windows.css +6455 -0
- package/src/css/disk-drives.css +406 -0
- package/src/css/documentation.css +392 -0
- package/src/css/file-explorer.css +867 -0
- package/src/css/hard-drive.css +180 -0
- package/src/css/layout.css +217 -0
- package/src/css/memory-windows.css +798 -0
- package/src/css/modals.css +510 -0
- package/src/css/monitor.css +425 -0
- package/src/css/release-notes.css +101 -0
- package/src/css/responsive.css +400 -0
- package/src/css/rule-builder.css +340 -0
- package/src/css/save-states.css +201 -0
- package/src/css/settings-windows.css +1231 -0
- package/src/css/window-switcher.css +150 -0
- package/src/js/agent/agent-manager.js +643 -0
- package/src/js/agent/agent-tools.js +293 -0
- package/src/js/agent/agent-version-tools.js +131 -0
- package/src/js/agent/assembler-tools.js +357 -0
- package/src/js/agent/basic-program-tools.js +894 -0
- package/src/js/agent/disk-tools.js +417 -0
- package/src/js/agent/file-explorer-tools.js +269 -0
- package/src/js/agent/index.js +13 -0
- package/src/js/agent/main-tools.js +222 -0
- package/src/js/agent/slot-tools.js +303 -0
- package/src/js/agent/smartport-tools.js +257 -0
- package/src/js/agent/window-tools.js +80 -0
- package/src/js/audio/audio-driver.js +417 -0
- package/src/js/audio/audio-worklet.js +85 -0
- package/src/js/audio/index.js +8 -0
- package/src/js/config/default-layout.js +34 -0
- package/src/js/config/version.js +8 -0
- package/src/js/data/apple2-rom-routines.js +577 -0
- package/src/js/debug/assembler-editor-window.js +2993 -0
- package/src/js/debug/basic-breakpoint-manager.js +529 -0
- package/src/js/debug/basic-program-parser.js +436 -0
- package/src/js/debug/basic-program-window.js +2594 -0
- package/src/js/debug/basic-variable-inspector.js +447 -0
- package/src/js/debug/breakpoint-manager.js +472 -0
- package/src/js/debug/cpu-debugger-window.js +2396 -0
- package/src/js/debug/index.js +22 -0
- package/src/js/debug/label-manager.js +238 -0
- package/src/js/debug/memory-browser-window.js +416 -0
- package/src/js/debug/memory-heat-map-window.js +481 -0
- package/src/js/debug/memory-map-window.js +206 -0
- package/src/js/debug/mockingboard-window.js +882 -0
- package/src/js/debug/mouse-card-window.js +355 -0
- package/src/js/debug/rule-builder-window.js +648 -0
- package/src/js/debug/soft-switch-window.js +458 -0
- package/src/js/debug/stack-viewer-window.js +221 -0
- package/src/js/debug/symbols.js +416 -0
- package/src/js/debug/trace-panel.js +291 -0
- package/src/js/debug/zero-page-watch-window.js +297 -0
- package/src/js/disk-manager/disk-drives-window.js +212 -0
- package/src/js/disk-manager/disk-operations.js +284 -0
- package/src/js/disk-manager/disk-persistence.js +301 -0
- package/src/js/disk-manager/disk-surface-renderer.js +388 -0
- package/src/js/disk-manager/drive-sounds.js +139 -0
- package/src/js/disk-manager/hard-drive-manager.js +481 -0
- package/src/js/disk-manager/hard-drive-persistence.js +187 -0
- package/src/js/disk-manager/hard-drive-window.js +57 -0
- package/src/js/disk-manager/index.js +890 -0
- package/src/js/display/display-settings-window.js +383 -0
- package/src/js/display/index.js +10 -0
- package/src/js/display/screen-window.js +342 -0
- package/src/js/display/webgl-renderer.js +705 -0
- package/src/js/file-explorer/disassembler.js +574 -0
- package/src/js/file-explorer/dos33.js +266 -0
- package/src/js/file-explorer/file-viewer.js +359 -0
- package/src/js/file-explorer/index.js +1261 -0
- package/src/js/file-explorer/prodos.js +549 -0
- package/src/js/file-explorer/utils.js +67 -0
- package/src/js/help/documentation-window.js +1096 -0
- package/src/js/help/index.js +10 -0
- package/src/js/help/release-notes-window.js +85 -0
- package/src/js/help/release-notes.js +612 -0
- package/src/js/input/gamepad-handler.js +176 -0
- package/src/js/input/index.js +12 -0
- package/src/js/input/input-handler.js +396 -0
- package/src/js/input/joystick-window.js +404 -0
- package/src/js/input/mouse-handler.js +99 -0
- package/src/js/input/text-selection.js +462 -0
- package/src/js/main.js +653 -0
- package/src/js/state/index.js +15 -0
- package/src/js/state/save-states-window.js +393 -0
- package/src/js/state/state-manager.js +409 -0
- package/src/js/state/state-persistence.js +218 -0
- package/src/js/ui/confirm.js +43 -0
- package/src/js/ui/disk-drive-positioner.js +347 -0
- package/src/js/ui/reminder-controller.js +129 -0
- package/src/js/ui/slot-configuration-window.js +560 -0
- package/src/js/ui/theme-manager.js +61 -0
- package/src/js/ui/toast.js +44 -0
- package/src/js/ui/ui-controller.js +897 -0
- package/src/js/ui/window-switcher.js +275 -0
- package/src/js/utils/basic-autocomplete.js +832 -0
- package/src/js/utils/basic-highlighting.js +473 -0
- package/src/js/utils/basic-tokenizer.js +153 -0
- package/src/js/utils/basic-tokens.js +117 -0
- package/src/js/utils/constants.js +28 -0
- package/src/js/utils/indexeddb-helper.js +225 -0
- package/src/js/utils/merlin-editor-support.js +905 -0
- package/src/js/utils/merlin-highlighting.js +551 -0
- package/src/js/utils/storage.js +125 -0
- package/src/js/utils/string-utils.js +19 -0
- package/src/js/utils/wasm-memory.js +54 -0
- package/src/js/windows/base-window.js +690 -0
- package/src/js/windows/index.js +9 -0
- package/src/js/windows/window-manager.js +375 -0
- package/tests/catch2/catch.hpp +17976 -0
- package/tests/common/basic_program_builder.cpp +119 -0
- package/tests/common/basic_program_builder.hpp +209 -0
- package/tests/common/disk_image_builder.cpp +444 -0
- package/tests/common/disk_image_builder.hpp +141 -0
- package/tests/common/test_helpers.hpp +118 -0
- package/tests/gcr/gcr-test.cpp +142 -0
- package/tests/integration/check-rom.js +70 -0
- package/tests/integration/compare-boot.js +239 -0
- package/tests/integration/crash-trace.js +102 -0
- package/tests/integration/disk-boot-test.js +264 -0
- package/tests/integration/memory-crash.js +108 -0
- package/tests/integration/nibble-read-test.js +249 -0
- package/tests/integration/phase-test.js +159 -0
- package/tests/integration/test_emulator.cpp +291 -0
- package/tests/integration/test_emulator_basic.cpp +91 -0
- package/tests/integration/test_emulator_debug.cpp +344 -0
- package/tests/integration/test_emulator_disk.cpp +153 -0
- package/tests/integration/test_emulator_state.cpp +163 -0
- package/tests/klaus/6502_functional_test.bin +0 -0
- package/tests/klaus/65C02_extended_opcodes_test.bin +0 -0
- package/tests/klaus/klaus_6502_test.cpp +184 -0
- package/tests/klaus/klaus_65c02_test.cpp +197 -0
- package/tests/thunderclock/thunderclock_mmu_test.cpp +304 -0
- package/tests/thunderclock/thunderclock_test.cpp +550 -0
- package/tests/unit/test_assembler.cpp +521 -0
- package/tests/unit/test_audio.cpp +196 -0
- package/tests/unit/test_ay8910.cpp +311 -0
- package/tests/unit/test_basic_detokenizer.cpp +265 -0
- package/tests/unit/test_basic_tokenizer.cpp +382 -0
- package/tests/unit/test_block_device.cpp +259 -0
- package/tests/unit/test_condition_evaluator.cpp +219 -0
- package/tests/unit/test_cpu6502.cpp +1301 -0
- package/tests/unit/test_cpu_addressing.cpp +361 -0
- package/tests/unit/test_cpu_cycle_counts.cpp +409 -0
- package/tests/unit/test_cpu_decimal.cpp +166 -0
- package/tests/unit/test_cpu_interrupts.cpp +285 -0
- package/tests/unit/test_disassembler.cpp +323 -0
- package/tests/unit/test_disk2_card.cpp +330 -0
- package/tests/unit/test_dos33.cpp +273 -0
- package/tests/unit/test_dsk_disk_image.cpp +315 -0
- package/tests/unit/test_expansion_card.cpp +178 -0
- package/tests/unit/test_gcr_encoding.cpp +232 -0
- package/tests/unit/test_keyboard.cpp +262 -0
- package/tests/unit/test_mmu.cpp +555 -0
- package/tests/unit/test_mmu_slots.cpp +323 -0
- package/tests/unit/test_mockingboard.cpp +352 -0
- package/tests/unit/test_mouse_card.cpp +386 -0
- package/tests/unit/test_pascal.cpp +248 -0
- package/tests/unit/test_prodos.cpp +259 -0
- package/tests/unit/test_smartport_card.cpp +321 -0
- package/tests/unit/test_thunderclock.cpp +354 -0
- package/tests/unit/test_via6522.cpp +323 -0
- package/tests/unit/test_video.cpp +319 -0
- package/tests/unit/test_woz_disk_image.cpp +257 -0
- package/vite.config.js +96 -0
- package/wiki/AI-Agent.md +372 -0
- package/wiki/Architecture-Overview.md +303 -0
- package/wiki/Audio-System.md +449 -0
- package/wiki/CPU-Emulation.md +477 -0
- package/wiki/Debugger.md +516 -0
- package/wiki/Disk-Drives.md +161 -0
- package/wiki/Disk-System-Internals.md +547 -0
- package/wiki/Display-Settings.md +88 -0
- package/wiki/Expansion-Slots.md +187 -0
- package/wiki/File-Explorer.md +259 -0
- package/wiki/Getting-Started.md +156 -0
- package/wiki/Home.md +69 -0
- package/wiki/Input-Devices.md +183 -0
- package/wiki/Keyboard-Shortcuts.md +158 -0
- package/wiki/Memory-System.md +364 -0
- package/wiki/Save-States.md +172 -0
- package/wiki/Video-Rendering.md +658 -0
package/.clangd
ADDED
package/.mcp.json
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Apple //e Browser Based Emulator - A cycle-accurate Apple II Enhanced emulator running in the browser using WebAssembly (C++ backend) and WebGL rendering. No JavaScript frameworks; vanilla ES6 modules with Vite for bundling.
|
|
8
|
+
|
|
9
|
+
## Build Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install # Install dependencies
|
|
13
|
+
npm run build:wasm # Build WASM module (required first time and after C++ changes)
|
|
14
|
+
npm run dev # Start dev server at localhost:3000 (hot-reload for JS only)
|
|
15
|
+
npm run build # Full production build (WASM + Vite bundle)
|
|
16
|
+
npm run clean # Clean build artifacts
|
|
17
|
+
npm run deploy # Deploy to VPS via rsync
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Testing
|
|
21
|
+
|
|
22
|
+
### CPU Compliance Tests
|
|
23
|
+
|
|
24
|
+
Klaus Dormann's 6502/65C02 functional test suites (`tests/klaus/`):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
mkdir -p build-native && cd build-native
|
|
28
|
+
cmake ..
|
|
29
|
+
make -j$(sysctl -n hw.ncpu)
|
|
30
|
+
ctest --verbose
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Test executables: `klaus_6502_test` (NMOS 6502), `klaus_65c02_test` (65C02 extended opcodes)
|
|
34
|
+
|
|
35
|
+
### Thunderclock Tests
|
|
36
|
+
|
|
37
|
+
Native C++ tests for Thunderclock card emulation (`tests/thunderclock/`), including MMU integration. Built and run via the same native CMake build above.
|
|
38
|
+
|
|
39
|
+
### GCR Encoding Tests
|
|
40
|
+
|
|
41
|
+
GCR (Group Code Recording) encoding tests (`tests/gcr/`). Native C++ tests for disk encoding logic.
|
|
42
|
+
|
|
43
|
+
### Integration Tests
|
|
44
|
+
|
|
45
|
+
Ad-hoc JavaScript tests for disk, memory, and boot debugging (`tests/integration/`). Run with Node.js:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node tests/integration/disk-boot-test.js
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Architecture
|
|
52
|
+
|
|
53
|
+
### Two-Layer Design
|
|
54
|
+
|
|
55
|
+
**C++ Core (src/core/)** - Pure emulation logic compiled to WebAssembly:
|
|
56
|
+
|
|
57
|
+
- `cpu/cpu6502.cpp` - Cycle-accurate 65C02 processor (1.023 MHz)
|
|
58
|
+
- `mmu/mmu.cpp` - 128KB memory management, soft switches ($C000-$CFFF), expansion slots
|
|
59
|
+
- `video/video.cpp` - TEXT/LORES/HIRES/DHIRES per-scanline rendering
|
|
60
|
+
- `audio/audio.cpp` - Speaker emulation from $C030 toggles
|
|
61
|
+
- `disk-image/` - Disk image format support (DSK/DO/PO/NIB/WOZ) with GCR encoding
|
|
62
|
+
- `disassembler/` - 65C02 instruction disassembler
|
|
63
|
+
- `input/keyboard.cpp` - Keyboard input handling
|
|
64
|
+
- `cards/` - Pluggable expansion card system (ExpansionCard interface)
|
|
65
|
+
- `cards/mockingboard/` - AY-3-8910 sound chip + VIA 6522 timer
|
|
66
|
+
- `cards/smartport/` - SmartPort hard drive controller (2 block devices, self-built ROM)
|
|
67
|
+
- `filesystem/` - DOS 3.3 and ProDOS filesystem parsers
|
|
68
|
+
- `basic/` - Applesoft and Integer BASIC detokenizer and tokenizer
|
|
69
|
+
- `debug/` - Condition evaluator for breakpoint expressions (supports BV/BA/BA2 for BASIC variable/array reads)
|
|
70
|
+
- `emulator.cpp` - Core coordinator, state serialization
|
|
71
|
+
|
|
72
|
+
**JavaScript Layer (src/js/)** - Browser integration:
|
|
73
|
+
|
|
74
|
+
- `main.js` - AppleIIeEmulator class orchestrating all subsystems
|
|
75
|
+
- `audio/` - Web Audio API driver and AudioWorklet
|
|
76
|
+
- `display/` - WebGL renderer, CRT shader effects, display settings, screen window
|
|
77
|
+
- `disk-manager/` - Disk drive UI, SmartPort hard drives, persistence, surface rendering, drive sounds
|
|
78
|
+
- `file-explorer/` - DOS 3.3 and ProDOS disk browser with disassembler
|
|
79
|
+
- `debug/` - Debug window implementations (see Debugging section)
|
|
80
|
+
- `help/` - Documentation and release notes windows
|
|
81
|
+
- `input/` - Keyboard input, text selection, joystick, mouse
|
|
82
|
+
- `ui/` - Menu wiring, reminders, slot configuration, custom confirm dialogs
|
|
83
|
+
- `state/` - State serialization and persistence (autosave + 5 manual slots)
|
|
84
|
+
- `config/` - App version
|
|
85
|
+
- `utils/` - Shared utilities (storage, string, BASIC)
|
|
86
|
+
- `windows/` - Base window class and window manager
|
|
87
|
+
|
|
88
|
+
### Theming
|
|
89
|
+
|
|
90
|
+
Light, dark, and system-follow themes controlled by `ThemeManager` (`src/js/ui/theme-manager.js`). Sets `data-theme` attribute on `<html>` for CSS variable switching. All accent and syntax highlighting colours are derived from the six-stripe Apple rainbow logo palette (Green `#61BB46`, Yellow `#FDB827`, Orange `#F5821F`, Red `#E03A3E`, Purple `#963D97`, Blue `#009DDC`), with brightness adjusted per theme for contrast. Speaker, Mockingboard, and disk drive sound volumes are all wired to a single main volume slider with a unified mute toggle.
|
|
91
|
+
|
|
92
|
+
Control sytles, sizes and layout must be consistent across the entire app.
|
|
93
|
+
|
|
94
|
+
### Audio-Driven Timing
|
|
95
|
+
|
|
96
|
+
The emulator uses Web Audio API for precise timing:
|
|
97
|
+
|
|
98
|
+
1. AudioWorklet requests samples at 48kHz
|
|
99
|
+
2. WASM runs ~21.3 CPU cycles per audio sample
|
|
100
|
+
3. Frame ready when cycles cross ~17,030 (60Hz)
|
|
101
|
+
|
|
102
|
+
This ensures consistent speed and works when the browser tab is backgrounded.
|
|
103
|
+
|
|
104
|
+
### WASM Interface Pattern
|
|
105
|
+
|
|
106
|
+
Single global `Emulator` instance in C++ (`wasm_interface.cpp`). JS allocates WASM heap with `_malloc`/`_free`, uses `stringToUTF8()`/`UTF8ToString()` for string conversion. New WASM exports must be added to `CMakeLists.txt` EXPORTED_FUNCTIONS list.
|
|
107
|
+
|
|
108
|
+
### Key Constants (src/core/types.hpp)
|
|
109
|
+
|
|
110
|
+
- CPU: 1.023 MHz clock
|
|
111
|
+
- Audio: 48kHz sample rate
|
|
112
|
+
- Screen: 560x384 pixels (280x192 doubled)
|
|
113
|
+
- Memory: 64KB main + 64KB aux RAM, 16KB ROM
|
|
114
|
+
|
|
115
|
+
## Development Workflow
|
|
116
|
+
|
|
117
|
+
**C++ changes** require rebuilding WASM: `npm run build:wasm`
|
|
118
|
+
|
|
119
|
+
**JavaScript changes** auto-reload via Vite dev server
|
|
120
|
+
|
|
121
|
+
**Full build** for production: `npm run build` (outputs to `dist/`)
|
|
122
|
+
|
|
123
|
+
**ROM files** are embedded into WASM at compile time. Place in `roms/` directory before building:
|
|
124
|
+
|
|
125
|
+
- `342-0349-B-C0-FF.bin` (16KB system ROM)
|
|
126
|
+
- `342-0273-A-US-UK.bin` (4KB character ROM, US/UK)
|
|
127
|
+
- `341-0160-A-US-UK.bin` (alternate character ROM variant)
|
|
128
|
+
- `341-0027.bin` (256 bytes Disk II ROM)
|
|
129
|
+
- `Thunderclock Plus ROM.bin` (2KB Thunderclock card ROM)
|
|
130
|
+
- `Apple Mouse Interface Card ROM - 342-0270-C.bin` (2KB Mouse Interface Card ROM)
|
|
131
|
+
|
|
132
|
+
## Code Organization
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
src/
|
|
136
|
+
├── core/ # C++ emulator (namespace a2e::)
|
|
137
|
+
│ ├── cpu/ # 65C02 processor
|
|
138
|
+
│ ├── mmu/ # Memory management and soft switches
|
|
139
|
+
│ ├── video/ # Per-scanline video rendering
|
|
140
|
+
│ ├── audio/ # Speaker audio
|
|
141
|
+
│ ├── disk-image/ # Disk image formats (DSK/DO/PO/NIB/WOZ) and GCR encoding
|
|
142
|
+
│ ├── disassembler/ # 65C02 disassembler
|
|
143
|
+
│ ├── input/ # Keyboard handling
|
|
144
|
+
│ ├── cards/ # Expansion card system
|
|
145
|
+
│ │ ├── mockingboard/ # AY-3-8910 + VIA 6522
|
|
146
|
+
│ │ └── smartport/ # SmartPort hard drive controller
|
|
147
|
+
│ ├── filesystem/ # DOS 3.3 and ProDOS parsers
|
|
148
|
+
│ ├── basic/ # BASIC tokenizer and detokenizer
|
|
149
|
+
│ ├── debug/ # Condition evaluator
|
|
150
|
+
│ ├── emulator.cpp # Core coordinator, state serialization
|
|
151
|
+
│ └── types.hpp # Shared constants and types
|
|
152
|
+
├── bindings/ # wasm_interface.cpp - WASM export glue
|
|
153
|
+
└── js/ # ES6 modules, no framework
|
|
154
|
+
├── main.js # Entry point, AppleIIeEmulator class
|
|
155
|
+
├── audio/ # Web Audio API driver and worklet
|
|
156
|
+
├── config/ # App version
|
|
157
|
+
├── debug/ # Debug window implementations
|
|
158
|
+
├── disk-manager/ # Disk drive operations, persistence, surface rendering, sounds
|
|
159
|
+
├── display/ # WebGL renderer, CRT shaders, display settings, screen window
|
|
160
|
+
├── file-explorer/ # DOS 3.3 and ProDOS file browser, disassembler
|
|
161
|
+
├── help/ # Documentation and release notes
|
|
162
|
+
├── input/ # Keyboard input, text selection, joystick, mouse
|
|
163
|
+
├── state/ # Save state manager and persistence
|
|
164
|
+
├── ui/ # Menu wiring, reminders, slot configuration
|
|
165
|
+
├── utils/ # Shared utilities (storage, string, BASIC)
|
|
166
|
+
└── windows/ # Base window class and window manager
|
|
167
|
+
├── css/ # Stylesheets (bundled by Vite)
|
|
168
|
+
public/ # Static assets, built WASM files, shaders
|
|
169
|
+
├── shaders/ # CRT vertex/fragment shaders
|
|
170
|
+
├── assets/ # Images and sounds
|
|
171
|
+
└── index.html # Main HTML entry point
|
|
172
|
+
tests/
|
|
173
|
+
├── klaus/ # Klaus Dormann CPU compliance tests
|
|
174
|
+
├── thunderclock/ # Thunderclock card tests
|
|
175
|
+
├── integration/ # JS integration/debug tests
|
|
176
|
+
└── gcr/ # GCR encoding tests
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### File Naming Convention
|
|
180
|
+
|
|
181
|
+
All JavaScript files use **kebab-case** (e.g., `audio-driver.js`, `cpu-debugger-window.js`). Class names remain PascalCase in the code.
|
|
182
|
+
|
|
183
|
+
## Expansion Card Architecture
|
|
184
|
+
|
|
185
|
+
The MMU supports pluggable expansion cards matching real Apple IIe hardware. Cards implement the `ExpansionCard` interface (`src/core/cards/expansion_card.hpp`).
|
|
186
|
+
|
|
187
|
+
### Slot Memory Map
|
|
188
|
+
|
|
189
|
+
| Slot | I/O Space | ROM Space | Default Card |
|
|
190
|
+
| ---- | ----------- | ----------- | --------------------------- |
|
|
191
|
+
| 1 | $C090-$C09F | $C100-$C1FF | Empty |
|
|
192
|
+
| 2 | $C0A0-$C0AF | $C200-$C2FF | Empty |
|
|
193
|
+
| 3 | $C0B0-$C0BF | $C300-$C3FF | 80-column (built-in, fixed) |
|
|
194
|
+
| 4 | $C0C0-$C0CF | $C400-$C4FF | Mockingboard |
|
|
195
|
+
| 5 | $C0D0-$C0DF | $C500-$C5FF | Thunderclock |
|
|
196
|
+
| 6 | $C0E0-$C0EF | $C600-$C6FF | Disk II |
|
|
197
|
+
| 7 | $C0F0-$C0FF | $C700-$C7FF | Empty |
|
|
198
|
+
|
|
199
|
+
### Card Interface Methods
|
|
200
|
+
|
|
201
|
+
```cpp
|
|
202
|
+
class ExpansionCard {
|
|
203
|
+
virtual uint8_t readIO(uint8_t offset); // I/O space ($C0x0-$C0xF)
|
|
204
|
+
virtual void writeIO(uint8_t offset, uint8_t value);
|
|
205
|
+
virtual uint8_t readROM(uint8_t offset); // ROM space ($Cx00-$CxFF)
|
|
206
|
+
virtual void writeROM(uint8_t offset, uint8_t value);
|
|
207
|
+
virtual void reset();
|
|
208
|
+
virtual void update(int cycles);
|
|
209
|
+
// ... serialization, IRQ callbacks, etc.
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Available Cards
|
|
214
|
+
|
|
215
|
+
- `Disk2Card` - Wraps Disk2Controller (slot 6)
|
|
216
|
+
- `MockingboardCard` - Dual AY-3-8910 + VIA 6522, stereo output (slot 4)
|
|
217
|
+
- `MouseCard` - Apple Mouse Interface Card via MC6821 PIA command protocol (slot 4)
|
|
218
|
+
- `SmartPortCard` - SmartPort hard drive controller, 2 block devices, self-built ROM (user-configurable slot)
|
|
219
|
+
- `ThunderclockCard` - ProDOS-compatible real-time clock (slots 5, 7)
|
|
220
|
+
|
|
221
|
+
## State Serialization
|
|
222
|
+
|
|
223
|
+
Binary format with versioned header. Includes CPU state, 128KB RAM, Language Card (16KB), soft switches, disk images with modifications, filenames, and debugger state. Autosave slot plus 5 manual save slots. Stored in browser IndexedDB. Window option state (toggles, view modes, mute states) is persisted separately via localStorage.
|
|
224
|
+
|
|
225
|
+
## Release Process
|
|
226
|
+
|
|
227
|
+
When the user says "release", perform all of the following steps:
|
|
228
|
+
|
|
229
|
+
1. **Review git log** since the last release notes entry to identify all changes
|
|
230
|
+
2. **Bump version** in `src/js/config/version.js`
|
|
231
|
+
3. **Update release notes** in both `src/js/help/release-notes.js` and `src/js/config/release-notes.json`
|
|
232
|
+
4. **Update README.md** to reflect any new features, changed commands, or updated project information
|
|
233
|
+
5. **Update CLAUDE.md** to reflect any architectural changes, new files/directories, new build steps, new expansion cards, new debug windows, or other structural changes to the codebase
|
|
234
|
+
|
|
235
|
+
## Debugging
|
|
236
|
+
|
|
237
|
+
Built-in debug windows accessible via Debug menu:
|
|
238
|
+
|
|
239
|
+
- CPU Debugger: registers (REGS, FLAGS, TIMING, BEAM sections), breakpoints, stepping, disassembly with symbols
|
|
240
|
+
- Memory Browser: hex/ASCII view of 128KB address space with search
|
|
241
|
+
- Memory Heat Map: real-time memory access visualization (read/write/combined modes)
|
|
242
|
+
- Memory Map: address space layout overview
|
|
243
|
+
- Stack Viewer: live stack contents
|
|
244
|
+
- Zero Page Watch: monitor zero page locations with predefined and custom watches
|
|
245
|
+
- Soft Switch Monitor: Apple II switch states ($C000-$C0FF)
|
|
246
|
+
- Mockingboard: unified channel-centric view with AY-3-8910 and VIA registers, inline waveforms, level meters, and per-channel mute controls
|
|
247
|
+
- Mouse Card: PIA registers, position, mode, interrupt state, protocol activity
|
|
248
|
+
- BASIC Program Viewer: view, load, and tokenize BASIC programs from memory, line heat map, trace toggle, statement-level breakpoints, conditional breakpoints on variables/arrays, condition-only rules, variable inspector, run/stop/pause/step controls
|
|
249
|
+
- Rule Builder: complex conditional breakpoints with C-style expressions, supports CPU registers/memory and BASIC variables/arrays as subjects
|
|
250
|
+
|
|
251
|
+
## Keyboard Shortcuts
|
|
252
|
+
|
|
253
|
+
| Shortcut | Action |
|
|
254
|
+
| ---------------- | ------------------------ |
|
|
255
|
+
| F1 | Open/close Help window |
|
|
256
|
+
| Ctrl+Escape | Exit full page mode |
|
|
257
|
+
| Ctrl+V | Paste text into emulator |
|
|
258
|
+
| Ctrl+` | Open window switcher |
|
|
259
|
+
| Option+Tab | Cycle to next window |
|
|
260
|
+
| Option+Shift+Tab | Cycle to previous window |
|
|
261
|
+
| F5 | Run / Continue execution |
|
|
262
|
+
| F10 | Step Over |
|
|
263
|
+
| F11 | Step Into |
|
|
264
|
+
| Shift+F11 | Step Out |
|
|
265
|
+
|
|
266
|
+
## Agent / MCP Integration
|
|
267
|
+
|
|
268
|
+
The emulator exposes an AI agent interface via the Model Context Protocol (MCP) and AG-UI event protocol. This allows AI agents (including Claude Code) to fully control the emulator programmatically.
|
|
269
|
+
|
|
270
|
+
### Architecture
|
|
271
|
+
|
|
272
|
+
Two coordinated components:
|
|
273
|
+
|
|
274
|
+
- **MCP Server** (`mcp/appleii-agent/`) — Node.js process providing MCP tools over stdio + an HTTP/HTTPS server (port 3033) implementing the AG-UI event protocol (SSE)
|
|
275
|
+
- **Frontend Agent Manager** (`src/js/agent/agent-manager.js`) — Browser-side AG-UI client that connects to the server, receives tool calls via SSE, executes them against the emulator, and returns results
|
|
276
|
+
|
|
277
|
+
### Configuration
|
|
278
|
+
|
|
279
|
+
- `.mcp.json` (repo root) — MCP client config for running the agent
|
|
280
|
+
- Recommended: `bunx -y @retrotech71/appleii-agent` (auto-installs with Bun)
|
|
281
|
+
- Development: `node /path/to/appleii-agent/src/index.js` (local source)
|
|
282
|
+
- Environment variables: `PORT` (default 3033), `HTTPS=true` for TLS mode
|
|
283
|
+
|
|
284
|
+
### MCP Server Tools (`mcp/appleii-agent/src/tools/`)
|
|
285
|
+
|
|
286
|
+
| Tool | Description |
|
|
287
|
+
| ---- | ----------- |
|
|
288
|
+
| `emma_command` | Generic command wrapper — delegates to any frontend tool |
|
|
289
|
+
| `server_control` | Start/stop/restart the agent server |
|
|
290
|
+
| `set_https` | Enable/disable HTTPS mode |
|
|
291
|
+
| `set_debug` | Set debug logging level |
|
|
292
|
+
| `get_state` | Return current emulator state |
|
|
293
|
+
| `show_window` / `hide_window` / `focus_window` | Window management |
|
|
294
|
+
| `load_disk_image` | Load disk image (.dsk/.do/.po/.nib/.woz) from filesystem, returns base64 |
|
|
295
|
+
| `load_file` | Load arbitrary file from filesystem |
|
|
296
|
+
| `save_basic_file` | Save BASIC program to disk |
|
|
297
|
+
| `save_asm_file` | Save assembler source to disk |
|
|
298
|
+
| `save_disk_file` | Save extracted disk file to filesystem |
|
|
299
|
+
| `load_smartport_image` | Load hard drive image (.hdv/.po/.2mg) from filesystem |
|
|
300
|
+
|
|
301
|
+
### Frontend Agent Tools (`src/js/agent/`)
|
|
302
|
+
|
|
303
|
+
Registered in `agent-tools.js`, organized by category:
|
|
304
|
+
|
|
305
|
+
**Emulator Control** (`main-tools.js`)
|
|
306
|
+
- `emulatorPower` — on/off/toggle
|
|
307
|
+
- `emulatorCtrlReset` — warm reset (Ctrl+Reset)
|
|
308
|
+
- `emulatorReboot` — cold reset
|
|
309
|
+
- `directLoadBinaryAt` — load base64 data to memory address
|
|
310
|
+
- `directSaveBinaryRangeTo` — read memory range as base64
|
|
311
|
+
|
|
312
|
+
**BASIC Program** (`basic-program-tools.js`)
|
|
313
|
+
- `directReadBasic` / `directWriteBasic` / `directRunBasic` / `directNewBasic` — direct memory operations
|
|
314
|
+
- `basicProgramLoadFromMemory` / `basicProgramLoadIntoEmulator` — transfer between editor and emulator
|
|
315
|
+
- `basicProgramRun` / `basicProgramPause` / `basicProgramNew` / `basicProgramRenumber` / `basicProgramFormat`
|
|
316
|
+
- `basicProgramGet` / `basicProgramSet` / `basicProgramLineCount`
|
|
317
|
+
- `saveBasicInEditorToLocal` — export from editor
|
|
318
|
+
|
|
319
|
+
**Assembler** (`assembler-tools.js`)
|
|
320
|
+
- `asmAssemble` — compile source code
|
|
321
|
+
- `asmWrite` — load assembled code into memory
|
|
322
|
+
- `asmLoadExample` — load template program
|
|
323
|
+
- `asmNew` / `asmGet` / `asmSet` — editor operations
|
|
324
|
+
- `asmGetStatus` — compilation status (origin, size, errors)
|
|
325
|
+
- `directExecuteAssemblyAt` — execute at address with optional return address
|
|
326
|
+
|
|
327
|
+
**Disk Drives** (`disk-tools.js`)
|
|
328
|
+
- `driveInsertDisc` — load disk image (calls MCP `load_disk_image`)
|
|
329
|
+
- `driveRecentsList` / `driveInsertRecent` / `driveLoadRecent` / `drivesClearRecent` — recent disk management
|
|
330
|
+
|
|
331
|
+
**SmartPort Hard Drives** (`smartport-tools.js`)
|
|
332
|
+
- `smartportInsertImage` — load hard drive image (calls MCP `load_smartport_image`)
|
|
333
|
+
- `smartportRecentsList` / `smartportInsertRecent` / `smartportClearRecent` — recent image management
|
|
334
|
+
- Validates SmartPort card is installed before operations
|
|
335
|
+
|
|
336
|
+
**File Explorer** (`file-explorer-tools.js`)
|
|
337
|
+
- `listDiskFiles` — enumerate DOS 3.3/ProDOS catalog (returns filename, type, size, locked status)
|
|
338
|
+
- `getDiskFileContent` — read file from disk (base64 for binary, plaintext for text)
|
|
339
|
+
|
|
340
|
+
**Window Management** (`window-tools.js`)
|
|
341
|
+
- `showWindow` / `hideWindow` / `focusWindow`
|
|
342
|
+
|
|
343
|
+
**Expansion Slots** (`slot-tools.js`)
|
|
344
|
+
- `slotsListAll` — list all slots with current cards and available options
|
|
345
|
+
- `slotsInstallCard` / `slotsRemoveCard` / `slotsMoveCard` — card management
|
|
346
|
+
- Persists to localStorage, triggers emulator reset after changes
|
|
347
|
+
|
|
348
|
+
### WASM APIs Used by Agent Tools
|
|
349
|
+
|
|
350
|
+
The frontend tools hook into these WASM exports (changes to these require updating agent tools):
|
|
351
|
+
|
|
352
|
+
- **CPU/Execution**: `_isPaused()`, `_setPaused(bool)`, `_getPC()`, `_setRegPC()`, `_getA/X/Y/SP()`, `_setRegA/X/Y/SP()`, `_getTotalCycles()`, `_reset()`, `_warmReset()`
|
|
353
|
+
- **Memory**: `_readMemory(addr)`, `_writeMemory(addr, val)`, `_peekMemory(addr)`, `_malloc()`, `_free()`
|
|
354
|
+
- **Disk**: `_isDiskInserted(drive)`, `_getDiskSectorData()`, `_isDOS33Format()`, `_isProDOSFormat()`, `_getDOS33Catalog()`, `_getProDOSCatalog()`, `_readDOS33File()`, `_readProDOSFile()`, `_getDOS33FileBuffer()`, `_getProDOSFileBuffer()`
|
|
355
|
+
- **Slots**: `_getSlotCard(slot)`, `_setSlotCard(slot, cardId)`, `_isSmartPortCardInstalled()`
|
|
356
|
+
- **Strings**: `stringToUTF8()`, `UTF8ToString()`
|
|
357
|
+
|
|
358
|
+
### Data Flow
|
|
359
|
+
|
|
360
|
+
1. Agent calls MCP tool (e.g., `load_disk_image`) → MCP server reads file from filesystem → returns base64
|
|
361
|
+
2. Agent calls frontend tool (e.g., `driveInsertDisc`) via `emma_command` → AG-UI SSE delivers tool call to browser
|
|
362
|
+
3. Frontend decodes data, calls disk manager / WASM APIs → emulator state updates → result returned via `/tool-result` POST
|