web-a2e 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.clangd +5 -0
- package/.mcp.json +12 -0
- package/CLAUDE.md +362 -0
- package/CMakeLists.txt +774 -0
- package/LICENSE +21 -0
- package/README.md +392 -0
- package/build-wasm/generated/roms.cpp +2447 -0
- package/docker-compose.staging.yml +9 -0
- package/docs/basic-rom-disassembly.md +6663 -0
- package/docs/softswitch-comparison.md +273 -0
- package/docs/thunderclock-debug.md +89 -0
- package/examples/cube.bas +72 -0
- package/examples/hello.s +55 -0
- package/examples/scroll.s +140 -0
- package/package.json +18 -0
- package/public/assets/apple-logo-old.png +0 -0
- package/public/assets/apple-logo.png +0 -0
- package/public/assets/drive-closed-light-on.png +0 -0
- package/public/assets/drive-closed.png +0 -0
- package/public/assets/drive-open-light-on.png +0 -0
- package/public/assets/drive-open.png +0 -0
- package/public/audio-worklet.js +82 -0
- package/public/disks/Apple DOS 3.3 January 1983.dsk +0 -0
- package/public/disks/ProDOS 2.4.3.po +0 -0
- package/public/disks/h32mb.2mg +0 -0
- package/public/disks/library.json +26 -0
- package/public/docs/llms/llm-assembler.txt +90 -0
- package/public/docs/llms/llm-basic-program.txt +256 -0
- package/public/docs/llms/llm-disk-drives.txt +72 -0
- package/public/docs/llms/llm-file-explorer.txt +50 -0
- package/public/docs/llms/llm-hard-drives.txt +80 -0
- package/public/docs/llms/llm-main.txt +51 -0
- package/public/docs/llms/llm-slot-configuration.txt +66 -0
- package/public/icons/icon-192.svg +4 -0
- package/public/icons/icon-512.svg +4 -0
- package/public/index.html +661 -0
- package/public/llms.txt +49 -0
- package/public/manifest.json +29 -0
- package/public/shaders/burnin.glsl +22 -0
- package/public/shaders/crt.glsl +706 -0
- package/public/shaders/edge.glsl +109 -0
- package/public/shaders/vertex.glsl +8 -0
- package/public/sw.js +186 -0
- package/roms/341-0027.bin +0 -0
- package/roms/341-0160-A-US-UK.bin +0 -0
- package/roms/341-0160-A.bin +0 -0
- package/roms/342-0273-A-US-UK.bin +0 -0
- package/roms/342-0349-B-C0-FF.bin +0 -0
- package/roms/Apple Mouse Interface Card ROM - 342-0270-C.bin +0 -0
- package/roms/Thunderclock Plus ROM.bin +0 -0
- package/scripts/generate_roms.sh +69 -0
- package/src/bindings/wasm_interface.cpp +1940 -0
- package/src/core/assembler/assembler.cpp +1239 -0
- package/src/core/assembler/assembler.hpp +115 -0
- package/src/core/audio/audio.cpp +160 -0
- package/src/core/audio/audio.hpp +81 -0
- package/src/core/basic/basic_detokenizer.cpp +436 -0
- package/src/core/basic/basic_detokenizer.hpp +41 -0
- package/src/core/basic/basic_tokenizer.cpp +286 -0
- package/src/core/basic/basic_tokenizer.hpp +26 -0
- package/src/core/basic/basic_tokens.hpp +295 -0
- package/src/core/cards/disk2_card.cpp +568 -0
- package/src/core/cards/disk2_card.hpp +316 -0
- package/src/core/cards/expansion_card.hpp +185 -0
- package/src/core/cards/mockingboard/ay8910.cpp +616 -0
- package/src/core/cards/mockingboard/ay8910.hpp +159 -0
- package/src/core/cards/mockingboard/via6522.cpp +530 -0
- package/src/core/cards/mockingboard/via6522.hpp +163 -0
- package/src/core/cards/mockingboard_card.cpp +312 -0
- package/src/core/cards/mockingboard_card.hpp +159 -0
- package/src/core/cards/mouse_card.cpp +654 -0
- package/src/core/cards/mouse_card.hpp +190 -0
- package/src/core/cards/smartport/block_device.cpp +202 -0
- package/src/core/cards/smartport/block_device.hpp +60 -0
- package/src/core/cards/smartport/smartport_card.cpp +603 -0
- package/src/core/cards/smartport/smartport_card.hpp +120 -0
- package/src/core/cards/thunderclock_card.cpp +237 -0
- package/src/core/cards/thunderclock_card.hpp +122 -0
- package/src/core/cpu/cpu6502.cpp +1609 -0
- package/src/core/cpu/cpu6502.hpp +203 -0
- package/src/core/debug/condition_evaluator.cpp +470 -0
- package/src/core/debug/condition_evaluator.hpp +87 -0
- package/src/core/disassembler/disassembler.cpp +552 -0
- package/src/core/disassembler/disassembler.hpp +171 -0
- package/src/core/disk-image/disk_image.hpp +267 -0
- package/src/core/disk-image/dsk_disk_image.cpp +827 -0
- package/src/core/disk-image/dsk_disk_image.hpp +204 -0
- package/src/core/disk-image/gcr_encoding.cpp +147 -0
- package/src/core/disk-image/gcr_encoding.hpp +78 -0
- package/src/core/disk-image/woz_disk_image.cpp +1049 -0
- package/src/core/disk-image/woz_disk_image.hpp +343 -0
- package/src/core/emulator.cpp +2126 -0
- package/src/core/emulator.hpp +434 -0
- package/src/core/filesystem/dos33.cpp +178 -0
- package/src/core/filesystem/dos33.hpp +66 -0
- package/src/core/filesystem/pascal.cpp +262 -0
- package/src/core/filesystem/pascal.hpp +87 -0
- package/src/core/filesystem/prodos.cpp +369 -0
- package/src/core/filesystem/prodos.hpp +119 -0
- package/src/core/input/keyboard.cpp +227 -0
- package/src/core/input/keyboard.hpp +111 -0
- package/src/core/mmu/mmu.cpp +1387 -0
- package/src/core/mmu/mmu.hpp +236 -0
- package/src/core/types.hpp +196 -0
- package/src/core/video/video.cpp +680 -0
- package/src/core/video/video.hpp +156 -0
- package/src/css/assembler-editor.css +1617 -0
- package/src/css/base.css +470 -0
- package/src/css/basic-debugger.css +791 -0
- package/src/css/basic-editor.css +792 -0
- package/src/css/controls.css +783 -0
- package/src/css/cpu-debugger.css +1413 -0
- package/src/css/debug-base.css +160 -0
- package/src/css/debug-windows.css +6455 -0
- package/src/css/disk-drives.css +406 -0
- package/src/css/documentation.css +392 -0
- package/src/css/file-explorer.css +867 -0
- package/src/css/hard-drive.css +180 -0
- package/src/css/layout.css +217 -0
- package/src/css/memory-windows.css +798 -0
- package/src/css/modals.css +510 -0
- package/src/css/monitor.css +425 -0
- package/src/css/release-notes.css +101 -0
- package/src/css/responsive.css +400 -0
- package/src/css/rule-builder.css +340 -0
- package/src/css/save-states.css +201 -0
- package/src/css/settings-windows.css +1231 -0
- package/src/css/window-switcher.css +150 -0
- package/src/js/agent/agent-manager.js +643 -0
- package/src/js/agent/agent-tools.js +293 -0
- package/src/js/agent/agent-version-tools.js +131 -0
- package/src/js/agent/assembler-tools.js +357 -0
- package/src/js/agent/basic-program-tools.js +894 -0
- package/src/js/agent/disk-tools.js +417 -0
- package/src/js/agent/file-explorer-tools.js +269 -0
- package/src/js/agent/index.js +13 -0
- package/src/js/agent/main-tools.js +222 -0
- package/src/js/agent/slot-tools.js +303 -0
- package/src/js/agent/smartport-tools.js +257 -0
- package/src/js/agent/window-tools.js +80 -0
- package/src/js/audio/audio-driver.js +417 -0
- package/src/js/audio/audio-worklet.js +85 -0
- package/src/js/audio/index.js +8 -0
- package/src/js/config/default-layout.js +34 -0
- package/src/js/config/version.js +8 -0
- package/src/js/data/apple2-rom-routines.js +577 -0
- package/src/js/debug/assembler-editor-window.js +2993 -0
- package/src/js/debug/basic-breakpoint-manager.js +529 -0
- package/src/js/debug/basic-program-parser.js +436 -0
- package/src/js/debug/basic-program-window.js +2594 -0
- package/src/js/debug/basic-variable-inspector.js +447 -0
- package/src/js/debug/breakpoint-manager.js +472 -0
- package/src/js/debug/cpu-debugger-window.js +2396 -0
- package/src/js/debug/index.js +22 -0
- package/src/js/debug/label-manager.js +238 -0
- package/src/js/debug/memory-browser-window.js +416 -0
- package/src/js/debug/memory-heat-map-window.js +481 -0
- package/src/js/debug/memory-map-window.js +206 -0
- package/src/js/debug/mockingboard-window.js +882 -0
- package/src/js/debug/mouse-card-window.js +355 -0
- package/src/js/debug/rule-builder-window.js +648 -0
- package/src/js/debug/soft-switch-window.js +458 -0
- package/src/js/debug/stack-viewer-window.js +221 -0
- package/src/js/debug/symbols.js +416 -0
- package/src/js/debug/trace-panel.js +291 -0
- package/src/js/debug/zero-page-watch-window.js +297 -0
- package/src/js/disk-manager/disk-drives-window.js +212 -0
- package/src/js/disk-manager/disk-operations.js +284 -0
- package/src/js/disk-manager/disk-persistence.js +301 -0
- package/src/js/disk-manager/disk-surface-renderer.js +388 -0
- package/src/js/disk-manager/drive-sounds.js +139 -0
- package/src/js/disk-manager/hard-drive-manager.js +481 -0
- package/src/js/disk-manager/hard-drive-persistence.js +187 -0
- package/src/js/disk-manager/hard-drive-window.js +57 -0
- package/src/js/disk-manager/index.js +890 -0
- package/src/js/display/display-settings-window.js +383 -0
- package/src/js/display/index.js +10 -0
- package/src/js/display/screen-window.js +342 -0
- package/src/js/display/webgl-renderer.js +705 -0
- package/src/js/file-explorer/disassembler.js +574 -0
- package/src/js/file-explorer/dos33.js +266 -0
- package/src/js/file-explorer/file-viewer.js +359 -0
- package/src/js/file-explorer/index.js +1261 -0
- package/src/js/file-explorer/prodos.js +549 -0
- package/src/js/file-explorer/utils.js +67 -0
- package/src/js/help/documentation-window.js +1096 -0
- package/src/js/help/index.js +10 -0
- package/src/js/help/release-notes-window.js +85 -0
- package/src/js/help/release-notes.js +612 -0
- package/src/js/input/gamepad-handler.js +176 -0
- package/src/js/input/index.js +12 -0
- package/src/js/input/input-handler.js +396 -0
- package/src/js/input/joystick-window.js +404 -0
- package/src/js/input/mouse-handler.js +99 -0
- package/src/js/input/text-selection.js +462 -0
- package/src/js/main.js +653 -0
- package/src/js/state/index.js +15 -0
- package/src/js/state/save-states-window.js +393 -0
- package/src/js/state/state-manager.js +409 -0
- package/src/js/state/state-persistence.js +218 -0
- package/src/js/ui/confirm.js +43 -0
- package/src/js/ui/disk-drive-positioner.js +347 -0
- package/src/js/ui/reminder-controller.js +129 -0
- package/src/js/ui/slot-configuration-window.js +560 -0
- package/src/js/ui/theme-manager.js +61 -0
- package/src/js/ui/toast.js +44 -0
- package/src/js/ui/ui-controller.js +897 -0
- package/src/js/ui/window-switcher.js +275 -0
- package/src/js/utils/basic-autocomplete.js +832 -0
- package/src/js/utils/basic-highlighting.js +473 -0
- package/src/js/utils/basic-tokenizer.js +153 -0
- package/src/js/utils/basic-tokens.js +117 -0
- package/src/js/utils/constants.js +28 -0
- package/src/js/utils/indexeddb-helper.js +225 -0
- package/src/js/utils/merlin-editor-support.js +905 -0
- package/src/js/utils/merlin-highlighting.js +551 -0
- package/src/js/utils/storage.js +125 -0
- package/src/js/utils/string-utils.js +19 -0
- package/src/js/utils/wasm-memory.js +54 -0
- package/src/js/windows/base-window.js +690 -0
- package/src/js/windows/index.js +9 -0
- package/src/js/windows/window-manager.js +375 -0
- package/tests/catch2/catch.hpp +17976 -0
- package/tests/common/basic_program_builder.cpp +119 -0
- package/tests/common/basic_program_builder.hpp +209 -0
- package/tests/common/disk_image_builder.cpp +444 -0
- package/tests/common/disk_image_builder.hpp +141 -0
- package/tests/common/test_helpers.hpp +118 -0
- package/tests/gcr/gcr-test.cpp +142 -0
- package/tests/integration/check-rom.js +70 -0
- package/tests/integration/compare-boot.js +239 -0
- package/tests/integration/crash-trace.js +102 -0
- package/tests/integration/disk-boot-test.js +264 -0
- package/tests/integration/memory-crash.js +108 -0
- package/tests/integration/nibble-read-test.js +249 -0
- package/tests/integration/phase-test.js +159 -0
- package/tests/integration/test_emulator.cpp +291 -0
- package/tests/integration/test_emulator_basic.cpp +91 -0
- package/tests/integration/test_emulator_debug.cpp +344 -0
- package/tests/integration/test_emulator_disk.cpp +153 -0
- package/tests/integration/test_emulator_state.cpp +163 -0
- package/tests/klaus/6502_functional_test.bin +0 -0
- package/tests/klaus/65C02_extended_opcodes_test.bin +0 -0
- package/tests/klaus/klaus_6502_test.cpp +184 -0
- package/tests/klaus/klaus_65c02_test.cpp +197 -0
- package/tests/thunderclock/thunderclock_mmu_test.cpp +304 -0
- package/tests/thunderclock/thunderclock_test.cpp +550 -0
- package/tests/unit/test_assembler.cpp +521 -0
- package/tests/unit/test_audio.cpp +196 -0
- package/tests/unit/test_ay8910.cpp +311 -0
- package/tests/unit/test_basic_detokenizer.cpp +265 -0
- package/tests/unit/test_basic_tokenizer.cpp +382 -0
- package/tests/unit/test_block_device.cpp +259 -0
- package/tests/unit/test_condition_evaluator.cpp +219 -0
- package/tests/unit/test_cpu6502.cpp +1301 -0
- package/tests/unit/test_cpu_addressing.cpp +361 -0
- package/tests/unit/test_cpu_cycle_counts.cpp +409 -0
- package/tests/unit/test_cpu_decimal.cpp +166 -0
- package/tests/unit/test_cpu_interrupts.cpp +285 -0
- package/tests/unit/test_disassembler.cpp +323 -0
- package/tests/unit/test_disk2_card.cpp +330 -0
- package/tests/unit/test_dos33.cpp +273 -0
- package/tests/unit/test_dsk_disk_image.cpp +315 -0
- package/tests/unit/test_expansion_card.cpp +178 -0
- package/tests/unit/test_gcr_encoding.cpp +232 -0
- package/tests/unit/test_keyboard.cpp +262 -0
- package/tests/unit/test_mmu.cpp +555 -0
- package/tests/unit/test_mmu_slots.cpp +323 -0
- package/tests/unit/test_mockingboard.cpp +352 -0
- package/tests/unit/test_mouse_card.cpp +386 -0
- package/tests/unit/test_pascal.cpp +248 -0
- package/tests/unit/test_prodos.cpp +259 -0
- package/tests/unit/test_smartport_card.cpp +321 -0
- package/tests/unit/test_thunderclock.cpp +354 -0
- package/tests/unit/test_via6522.cpp +323 -0
- package/tests/unit/test_video.cpp +319 -0
- package/tests/unit/test_woz_disk_image.cpp +257 -0
- package/vite.config.js +96 -0
- package/wiki/AI-Agent.md +372 -0
- package/wiki/Architecture-Overview.md +303 -0
- package/wiki/Audio-System.md +449 -0
- package/wiki/CPU-Emulation.md +477 -0
- package/wiki/Debugger.md +516 -0
- package/wiki/Disk-Drives.md +161 -0
- package/wiki/Disk-System-Internals.md +547 -0
- package/wiki/Display-Settings.md +88 -0
- package/wiki/Expansion-Slots.md +187 -0
- package/wiki/File-Explorer.md +259 -0
- package/wiki/Getting-Started.md +156 -0
- package/wiki/Home.md +69 -0
- package/wiki/Input-Devices.md +183 -0
- package/wiki/Keyboard-Shortcuts.md +158 -0
- package/wiki/Memory-System.md +364 -0
- package/wiki/Save-States.md +172 -0
- package/wiki/Video-Rendering.md +658 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* memory-heat-map-window.js - Real-time memory access heat map visualization
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { BaseWindow } from "../windows/base-window.js";
|
|
9
|
+
|
|
10
|
+
// Memory region labels for main memory
|
|
11
|
+
const MAIN_MEMORY_REGIONS = [
|
|
12
|
+
{ name: "Zero Page", start: 0x0000, end: 0x00ff },
|
|
13
|
+
{ name: "Stack", start: 0x0100, end: 0x01ff },
|
|
14
|
+
{ name: "Input Buffer", start: 0x0200, end: 0x02ff },
|
|
15
|
+
{ name: "Vectors/Data", start: 0x0300, end: 0x03ff },
|
|
16
|
+
{ name: "Text Page 1", start: 0x0400, end: 0x07ff },
|
|
17
|
+
{ name: "Text Page 2", start: 0x0800, end: 0x0bff },
|
|
18
|
+
{ name: "Free RAM", start: 0x0c00, end: 0x1fff },
|
|
19
|
+
{ name: "HiRes Page 1", start: 0x2000, end: 0x3fff },
|
|
20
|
+
{ name: "HiRes Page 2", start: 0x4000, end: 0x5fff },
|
|
21
|
+
{ name: "Free RAM", start: 0x6000, end: 0x95ff },
|
|
22
|
+
{ name: "DOS 3.3", start: 0x9600, end: 0xbfff },
|
|
23
|
+
{ name: "I/O Space", start: 0xc000, end: 0xc0ff },
|
|
24
|
+
{ name: "Slot ROMs", start: 0xc100, end: 0xcfff },
|
|
25
|
+
{ name: "ROM/LC RAM", start: 0xd000, end: 0xffff },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// Memory region labels for auxiliary memory
|
|
29
|
+
const AUX_MEMORY_REGIONS = [
|
|
30
|
+
{ name: "Aux Zero Page", start: 0x0000, end: 0x00ff },
|
|
31
|
+
{ name: "Aux Stack", start: 0x0100, end: 0x01ff },
|
|
32
|
+
{ name: "Aux $0200", start: 0x0200, end: 0x03ff },
|
|
33
|
+
{ name: "Aux Text Page 1", start: 0x0400, end: 0x07ff },
|
|
34
|
+
{ name: "Aux Text Page 2", start: 0x0800, end: 0x0bff },
|
|
35
|
+
{ name: "Aux RAM", start: 0x0c00, end: 0x1fff },
|
|
36
|
+
{ name: "Aux HiRes Page 1", start: 0x2000, end: 0x3fff },
|
|
37
|
+
{ name: "Aux HiRes Page 2", start: 0x4000, end: 0x5fff },
|
|
38
|
+
{ name: "Aux RAM", start: 0x6000, end: 0xbfff },
|
|
39
|
+
{ name: "Aux $C000-$FFFF", start: 0xc000, end: 0xffff },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export class MemoryHeatMapWindow extends BaseWindow {
|
|
43
|
+
constructor(wasmModule) {
|
|
44
|
+
super({
|
|
45
|
+
id: "memory-heatmap",
|
|
46
|
+
title: "Memory Heat Map",
|
|
47
|
+
defaultWidth: 580,
|
|
48
|
+
defaultHeight: 435,
|
|
49
|
+
minWidth: 580,
|
|
50
|
+
minHeight: 435,
|
|
51
|
+
maxWidth: 580,
|
|
52
|
+
maxHeight: 435,
|
|
53
|
+
|
|
54
|
+
});
|
|
55
|
+
this.wasmModule = wasmModule;
|
|
56
|
+
this.isTracking = false;
|
|
57
|
+
this.viewMode = "combined"; // combined, reads, writes
|
|
58
|
+
this.decayEnabled = false;
|
|
59
|
+
this.onJumpToAddress = null; // Callback for Memory Browser integration
|
|
60
|
+
this.activeCanvas = "main"; // Which canvas is being hovered
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
renderContent() {
|
|
64
|
+
return `
|
|
65
|
+
<div class="heatmap-toolbar">
|
|
66
|
+
<button class="heatmap-toggle-btn">Start</button>
|
|
67
|
+
<button class="heatmap-clear-btn">Clear</button>
|
|
68
|
+
<select class="heatmap-mode-select">
|
|
69
|
+
<option value="combined">Combined</option>
|
|
70
|
+
<option value="reads">Reads Only</option>
|
|
71
|
+
<option value="writes">Writes Only</option>
|
|
72
|
+
</select>
|
|
73
|
+
<label class="heatmap-decay-label">
|
|
74
|
+
<input type="checkbox" class="heatmap-decay-check" />
|
|
75
|
+
Decay
|
|
76
|
+
</label>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="heatmap-dual-container">
|
|
79
|
+
<div class="heatmap-panel">
|
|
80
|
+
<div class="heatmap-panel-title">Main RAM + ROM</div>
|
|
81
|
+
<div class="heatmap-canvas-container">
|
|
82
|
+
<canvas class="heatmap-canvas heatmap-canvas-main" width="256" height="256"></canvas>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="heatmap-panel">
|
|
86
|
+
<div class="heatmap-panel-title">Auxiliary RAM</div>
|
|
87
|
+
<div class="heatmap-canvas-container">
|
|
88
|
+
<canvas class="heatmap-canvas heatmap-canvas-aux" width="256" height="256"></canvas>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="heatmap-legend">
|
|
93
|
+
<span class="heatmap-legend-item"><span class="legend-color reads"></span> Reads</span>
|
|
94
|
+
<span class="heatmap-legend-item"><span class="legend-color writes"></span> Writes</span>
|
|
95
|
+
<span class="heatmap-legend-item"><span class="legend-color both"></span> Both</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="heatmap-info">
|
|
98
|
+
<span class="heatmap-addr">$0000</span>
|
|
99
|
+
<span class="heatmap-region">Zero Page</span>
|
|
100
|
+
<span class="heatmap-counts">R: 0 W: 0</span>
|
|
101
|
+
</div>
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
onContentRendered() {
|
|
106
|
+
this.canvasMain = this.contentElement.querySelector(".heatmap-canvas-main");
|
|
107
|
+
this.canvasAux = this.contentElement.querySelector(".heatmap-canvas-aux");
|
|
108
|
+
this.ctxMain = this.canvasMain.getContext("2d");
|
|
109
|
+
this.ctxAux = this.canvasAux.getContext("2d");
|
|
110
|
+
this.toggleBtn = this.contentElement.querySelector(".heatmap-toggle-btn");
|
|
111
|
+
this.modeSelect = this.contentElement.querySelector(".heatmap-mode-select");
|
|
112
|
+
this.decayCheck = this.contentElement.querySelector(".heatmap-decay-check");
|
|
113
|
+
this.addrSpan = this.contentElement.querySelector(".heatmap-addr");
|
|
114
|
+
this.regionSpan = this.contentElement.querySelector(".heatmap-region");
|
|
115
|
+
this.countsSpan = this.contentElement.querySelector(".heatmap-counts");
|
|
116
|
+
|
|
117
|
+
// Pre-allocate image data for both canvases
|
|
118
|
+
this.imageDataMain = this.ctxMain.createImageData(256, 256);
|
|
119
|
+
this.imageDataAux = this.ctxAux.createImageData(256, 256);
|
|
120
|
+
|
|
121
|
+
this.setupHeatmapEventListeners();
|
|
122
|
+
|
|
123
|
+
// Apply restored state to UI elements
|
|
124
|
+
this.modeSelect.value = this.viewMode;
|
|
125
|
+
this.decayCheck.checked = this.decayEnabled;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
setupHeatmapEventListeners() {
|
|
129
|
+
// Toggle tracking
|
|
130
|
+
this.toggleBtn.addEventListener("click", () => {
|
|
131
|
+
this.isTracking = !this.isTracking;
|
|
132
|
+
this.toggleBtn.textContent = this.isTracking ? "Stop" : "Start";
|
|
133
|
+
this.toggleBtn.classList.toggle("active", this.isTracking);
|
|
134
|
+
this.wasmModule._enableMemoryTracking(this.isTracking);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Clear tracking data
|
|
138
|
+
this.contentElement
|
|
139
|
+
.querySelector(".heatmap-clear-btn")
|
|
140
|
+
.addEventListener("click", () => {
|
|
141
|
+
this.wasmModule._clearMemoryTracking();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// View mode selection
|
|
145
|
+
this.modeSelect.addEventListener("change", (e) => {
|
|
146
|
+
this.viewMode = e.target.value;
|
|
147
|
+
if (this.onStateChange) this.onStateChange();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Decay toggle
|
|
151
|
+
this.decayCheck.addEventListener("change", (e) => {
|
|
152
|
+
this.decayEnabled = e.target.checked;
|
|
153
|
+
if (this.onStateChange) this.onStateChange();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Canvas hover for main memory
|
|
157
|
+
this.canvasMain.addEventListener("mousemove", (e) => {
|
|
158
|
+
this.activeCanvas = "main";
|
|
159
|
+
const addr = this.getAddressFromEvent(e, this.canvasMain);
|
|
160
|
+
this.showAddressInfo(addr, MAIN_MEMORY_REGIONS, "Main");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Canvas hover for aux memory
|
|
164
|
+
this.canvasAux.addEventListener("mousemove", (e) => {
|
|
165
|
+
this.activeCanvas = "aux";
|
|
166
|
+
const addr = this.getAddressFromEvent(e, this.canvasAux);
|
|
167
|
+
this.showAddressInfo(addr, AUX_MEMORY_REGIONS, "Aux");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
this.canvasMain.addEventListener("mouseleave", () =>
|
|
171
|
+
this.clearAddressInfo(),
|
|
172
|
+
);
|
|
173
|
+
this.canvasAux.addEventListener("mouseleave", () =>
|
|
174
|
+
this.clearAddressInfo(),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// Click to jump to Memory Browser
|
|
178
|
+
this.canvasMain.addEventListener("click", (e) => {
|
|
179
|
+
const addr = this.getAddressFromEvent(e, this.canvasMain);
|
|
180
|
+
if (this.onJumpToAddress) {
|
|
181
|
+
this.onJumpToAddress(addr);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
this.canvasAux.addEventListener("click", (e) => {
|
|
186
|
+
const addr = this.getAddressFromEvent(e, this.canvasAux);
|
|
187
|
+
if (this.onJumpToAddress) {
|
|
188
|
+
this.onJumpToAddress(addr);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
getAddressFromEvent(e, canvas) {
|
|
194
|
+
const rect = canvas.getBoundingClientRect();
|
|
195
|
+
const x = Math.floor(((e.clientX - rect.left) / rect.width) * 256);
|
|
196
|
+
const y = Math.floor(((e.clientY - rect.top) / rect.height) * 256);
|
|
197
|
+
return y * 256 + x;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
clearAddressInfo() {
|
|
201
|
+
this.addrSpan.textContent = "$----";
|
|
202
|
+
this.regionSpan.textContent = "";
|
|
203
|
+
this.countsSpan.textContent = "";
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
showAddressInfo(addr, regions, prefix) {
|
|
207
|
+
if (addr < 0 || addr > 0xffff) return;
|
|
208
|
+
|
|
209
|
+
this.addrSpan.textContent = `${prefix} $${this.formatHex(addr, 4)}`;
|
|
210
|
+
|
|
211
|
+
// Find region
|
|
212
|
+
for (const region of regions) {
|
|
213
|
+
if (addr >= region.start && addr <= region.end) {
|
|
214
|
+
this.regionSpan.textContent = region.name;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Get counts from WASM memory
|
|
220
|
+
const readCountsPtr = this.wasmModule._getMemoryReadCounts();
|
|
221
|
+
const writeCountsPtr = this.wasmModule._getMemoryWriteCounts();
|
|
222
|
+
|
|
223
|
+
if (readCountsPtr && writeCountsPtr) {
|
|
224
|
+
const readCount = this.wasmModule.HEAPU8[readCountsPtr + addr];
|
|
225
|
+
const writeCount = this.wasmModule.HEAPU8[writeCountsPtr + addr];
|
|
226
|
+
this.countsSpan.textContent = `R: ${readCount} W: ${writeCount}`;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
update(wasmModule) {
|
|
231
|
+
if (!this.isVisible || !this.canvasMain || !this.canvasAux) return;
|
|
232
|
+
|
|
233
|
+
const readCountsPtr = wasmModule._getMemoryReadCounts();
|
|
234
|
+
const writeCountsPtr = wasmModule._getMemoryWriteCounts();
|
|
235
|
+
const mainRAMPtr = wasmModule._getMainRAM();
|
|
236
|
+
const auxRAMPtr = wasmModule._getAuxRAM();
|
|
237
|
+
const systemROMPtr = wasmModule._getSystemROM();
|
|
238
|
+
|
|
239
|
+
if (!readCountsPtr || !writeCountsPtr) return;
|
|
240
|
+
|
|
241
|
+
// Update main memory canvas
|
|
242
|
+
this.updateCanvas(
|
|
243
|
+
this.imageDataMain,
|
|
244
|
+
this.ctxMain,
|
|
245
|
+
readCountsPtr,
|
|
246
|
+
writeCountsPtr,
|
|
247
|
+
mainRAMPtr,
|
|
248
|
+
systemROMPtr,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Update aux memory canvas
|
|
252
|
+
this.updateCanvasAux(
|
|
253
|
+
this.imageDataAux,
|
|
254
|
+
this.ctxAux,
|
|
255
|
+
readCountsPtr,
|
|
256
|
+
writeCountsPtr,
|
|
257
|
+
auxRAMPtr,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
// Apply decay if enabled
|
|
261
|
+
if (this.decayEnabled && this.isTracking) {
|
|
262
|
+
wasmModule._decayMemoryTracking(2);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Render the memory heat map for main RAM and system ROM.
|
|
268
|
+
*
|
|
269
|
+
* Color encoding scheme:
|
|
270
|
+
* - Background brightness: Based on memory content value (0-255 → visible gray level).
|
|
271
|
+
* This shows the actual memory contents.
|
|
272
|
+
* - Read activity: Blue/cyan channel. Higher read count = brighter blue.
|
|
273
|
+
* - Write activity: Red/orange channel. Higher write count = brighter red.
|
|
274
|
+
* - Combined read+write: Purple/magenta blend.
|
|
275
|
+
*
|
|
276
|
+
* Each pixel represents one memory address. The canvas is 256x256 = 65536 pixels,
|
|
277
|
+
* covering the entire 64KB address space. Addresses are laid out left-to-right,
|
|
278
|
+
* top-to-bottom (address 0 at top-left, address 65535 at bottom-right).
|
|
279
|
+
*
|
|
280
|
+
* Memory regions:
|
|
281
|
+
* - $0000-$BFFF: Main RAM (48KB)
|
|
282
|
+
* - $C000-$CFFF: I/O and soft switches
|
|
283
|
+
* - $D000-$FFFF: ROM or bank-switched RAM
|
|
284
|
+
*/
|
|
285
|
+
updateCanvas(
|
|
286
|
+
imageData,
|
|
287
|
+
ctx,
|
|
288
|
+
readCountsPtr,
|
|
289
|
+
writeCountsPtr,
|
|
290
|
+
mainRAMPtr,
|
|
291
|
+
systemROMPtr,
|
|
292
|
+
) {
|
|
293
|
+
const data = imageData.data;
|
|
294
|
+
const wasmModule = this.wasmModule;
|
|
295
|
+
|
|
296
|
+
for (let addr = 0; addr < 65536; addr++) {
|
|
297
|
+
const readCount = wasmModule.HEAPU8[readCountsPtr + addr];
|
|
298
|
+
const writeCount = wasmModule.HEAPU8[writeCountsPtr + addr];
|
|
299
|
+
|
|
300
|
+
// Get memory content for background brightness
|
|
301
|
+
let memValue = 0;
|
|
302
|
+
if (mainRAMPtr && addr < 0xc000) {
|
|
303
|
+
memValue = wasmModule.HEAPU8[mainRAMPtr + addr];
|
|
304
|
+
} else if (systemROMPtr && addr >= 0xc000) {
|
|
305
|
+
memValue = wasmModule.HEAPU8[systemROMPtr + (addr - 0xc000)];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const pixelIndex = addr * 4;
|
|
309
|
+
|
|
310
|
+
// Base background: visible gray based on memory content (20-60 range)
|
|
311
|
+
const bgLevel = 20 + Math.floor(memValue * 0.16);
|
|
312
|
+
|
|
313
|
+
let r, g, b;
|
|
314
|
+
|
|
315
|
+
// Scale activity to be more visible (multiply by 3, cap at 200)
|
|
316
|
+
const readIntensity = Math.min(200, readCount * 3);
|
|
317
|
+
const writeIntensity = Math.min(200, writeCount * 3);
|
|
318
|
+
|
|
319
|
+
switch (this.viewMode) {
|
|
320
|
+
case "reads":
|
|
321
|
+
// Apple Blue (#18ABEA) for reads
|
|
322
|
+
r = Math.min(255, bgLevel + Math.floor(readIntensity * 0.1));
|
|
323
|
+
g = Math.min(255, bgLevel + Math.floor(readIntensity * 0.73));
|
|
324
|
+
b = Math.min(255, bgLevel + readIntensity);
|
|
325
|
+
break;
|
|
326
|
+
case "writes":
|
|
327
|
+
// Apple Orange (#F68D35) for writes
|
|
328
|
+
r = Math.min(255, bgLevel + writeIntensity);
|
|
329
|
+
g = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.57));
|
|
330
|
+
b = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.22));
|
|
331
|
+
break;
|
|
332
|
+
case "combined":
|
|
333
|
+
default:
|
|
334
|
+
if (readCount > 0 && writeCount > 0) {
|
|
335
|
+
// Apple Purple (#B55DB6) for both
|
|
336
|
+
r = Math.min(255, bgLevel + writeIntensity);
|
|
337
|
+
g = Math.min(
|
|
338
|
+
255,
|
|
339
|
+
bgLevel +
|
|
340
|
+
Math.floor(Math.min(readIntensity, writeIntensity) * 0.51),
|
|
341
|
+
);
|
|
342
|
+
b = Math.min(255, bgLevel + readIntensity);
|
|
343
|
+
} else if (readCount > 0) {
|
|
344
|
+
// Apple Blue (#18ABEA) for reads only
|
|
345
|
+
r = Math.min(255, bgLevel + Math.floor(readIntensity * 0.1));
|
|
346
|
+
g = Math.min(255, bgLevel + Math.floor(readIntensity * 0.73));
|
|
347
|
+
b = Math.min(255, bgLevel + readIntensity);
|
|
348
|
+
} else if (writeCount > 0) {
|
|
349
|
+
// Apple Orange (#F68D35) for writes only
|
|
350
|
+
r = Math.min(255, bgLevel + writeIntensity);
|
|
351
|
+
g = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.57));
|
|
352
|
+
b = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.22));
|
|
353
|
+
} else {
|
|
354
|
+
// No activity - gray background
|
|
355
|
+
r = bgLevel;
|
|
356
|
+
g = bgLevel;
|
|
357
|
+
b = bgLevel;
|
|
358
|
+
}
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
data[pixelIndex] = r;
|
|
363
|
+
data[pixelIndex + 1] = g;
|
|
364
|
+
data[pixelIndex + 2] = b;
|
|
365
|
+
data[pixelIndex + 3] = 255;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
ctx.putImageData(imageData, 0, 0);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
updateCanvasAux(imageData, ctx, readCountsPtr, writeCountsPtr, auxRAMPtr) {
|
|
372
|
+
const data = imageData.data;
|
|
373
|
+
const wasmModule = this.wasmModule;
|
|
374
|
+
|
|
375
|
+
for (let addr = 0; addr < 65536; addr++) {
|
|
376
|
+
// Note: tracking counts are for the main address space
|
|
377
|
+
// Aux memory accesses happen when RAMRD/RAMWRT are set
|
|
378
|
+
// For now, show aux memory content with dimmed tracking overlay
|
|
379
|
+
const readCount = wasmModule.HEAPU8[readCountsPtr + addr];
|
|
380
|
+
const writeCount = wasmModule.HEAPU8[writeCountsPtr + addr];
|
|
381
|
+
|
|
382
|
+
// Get aux memory content
|
|
383
|
+
let memValue = 0;
|
|
384
|
+
if (auxRAMPtr) {
|
|
385
|
+
memValue = wasmModule.HEAPU8[auxRAMPtr + addr];
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const pixelIndex = addr * 4;
|
|
389
|
+
|
|
390
|
+
// Base background: visible gray based on memory content (20-60 range)
|
|
391
|
+
const bgLevel = 20 + Math.floor(memValue * 0.16);
|
|
392
|
+
|
|
393
|
+
let r, g, b;
|
|
394
|
+
|
|
395
|
+
// Scale activity (dimmed for aux since tracking is address-based)
|
|
396
|
+
const readIntensity = Math.min(200, readCount * 2);
|
|
397
|
+
const writeIntensity = Math.min(200, writeCount * 2);
|
|
398
|
+
|
|
399
|
+
switch (this.viewMode) {
|
|
400
|
+
case "reads":
|
|
401
|
+
// Apple Blue (#18ABEA) for reads
|
|
402
|
+
r = Math.min(255, bgLevel + Math.floor(readIntensity * 0.1));
|
|
403
|
+
g = Math.min(255, bgLevel + Math.floor(readIntensity * 0.73));
|
|
404
|
+
b = Math.min(255, bgLevel + readIntensity);
|
|
405
|
+
break;
|
|
406
|
+
case "writes":
|
|
407
|
+
// Apple Orange (#F68D35) for writes
|
|
408
|
+
r = Math.min(255, bgLevel + writeIntensity);
|
|
409
|
+
g = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.57));
|
|
410
|
+
b = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.22));
|
|
411
|
+
break;
|
|
412
|
+
case "combined":
|
|
413
|
+
default:
|
|
414
|
+
if (readCount > 0 && writeCount > 0) {
|
|
415
|
+
// Apple Purple (#B55DB6) for both
|
|
416
|
+
r = Math.min(255, bgLevel + writeIntensity);
|
|
417
|
+
g = Math.min(
|
|
418
|
+
255,
|
|
419
|
+
bgLevel +
|
|
420
|
+
Math.floor(Math.min(readIntensity, writeIntensity) * 0.51),
|
|
421
|
+
);
|
|
422
|
+
b = Math.min(255, bgLevel + readIntensity);
|
|
423
|
+
} else if (readCount > 0) {
|
|
424
|
+
// Apple Blue (#18ABEA) for reads only
|
|
425
|
+
r = Math.min(255, bgLevel + Math.floor(readIntensity * 0.1));
|
|
426
|
+
g = Math.min(255, bgLevel + Math.floor(readIntensity * 0.73));
|
|
427
|
+
b = Math.min(255, bgLevel + readIntensity);
|
|
428
|
+
} else if (writeCount > 0) {
|
|
429
|
+
// Apple Orange (#F68D35) for writes only
|
|
430
|
+
r = Math.min(255, bgLevel + writeIntensity);
|
|
431
|
+
g = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.57));
|
|
432
|
+
b = Math.min(255, bgLevel + Math.floor(writeIntensity * 0.22));
|
|
433
|
+
} else {
|
|
434
|
+
// No activity - gray background
|
|
435
|
+
r = bgLevel;
|
|
436
|
+
g = bgLevel;
|
|
437
|
+
b = bgLevel;
|
|
438
|
+
}
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
data[pixelIndex] = r;
|
|
443
|
+
data[pixelIndex + 1] = g;
|
|
444
|
+
data[pixelIndex + 2] = b;
|
|
445
|
+
data[pixelIndex + 3] = 255;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
ctx.putImageData(imageData, 0, 0);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
setJumpCallback(callback) {
|
|
452
|
+
this.onJumpToAddress = callback;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
getState() {
|
|
456
|
+
const base = super.getState();
|
|
457
|
+
base.viewMode = this.viewMode;
|
|
458
|
+
base.decayEnabled = this.decayEnabled;
|
|
459
|
+
return base;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
restoreState(state) {
|
|
463
|
+
if (state.viewMode) {
|
|
464
|
+
this.viewMode = state.viewMode;
|
|
465
|
+
}
|
|
466
|
+
if (state.decayEnabled !== undefined) {
|
|
467
|
+
this.decayEnabled = state.decayEnabled;
|
|
468
|
+
}
|
|
469
|
+
super.restoreState(state);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
hide() {
|
|
473
|
+
if (this.isTracking) {
|
|
474
|
+
this.isTracking = false;
|
|
475
|
+
this.toggleBtn.textContent = "Start";
|
|
476
|
+
this.toggleBtn.classList.remove("active");
|
|
477
|
+
this.wasmModule._enableMemoryTracking(false);
|
|
478
|
+
}
|
|
479
|
+
super.hide();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* memory-map-window.js - Memory bank configuration overview window
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { BaseWindow } from "../windows/base-window.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* MemoryMapWindow - Visual representation of memory bank configuration
|
|
12
|
+
* Shows which memory banks are currently active based on soft switch states
|
|
13
|
+
*/
|
|
14
|
+
export class MemoryMapWindow extends BaseWindow {
|
|
15
|
+
constructor(wasmModule) {
|
|
16
|
+
super({
|
|
17
|
+
id: "memory-map",
|
|
18
|
+
title: "Memory Map",
|
|
19
|
+
minWidth: 260,
|
|
20
|
+
minHeight: 405,
|
|
21
|
+
maxWidth: 260,
|
|
22
|
+
maxHeight: 405,
|
|
23
|
+
defaultWidth: 260,
|
|
24
|
+
defaultHeight: 405,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
this.wasmModule = wasmModule;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
renderContent() {
|
|
31
|
+
return `
|
|
32
|
+
<div class="memory-map-content">
|
|
33
|
+
<div class="bank-map">
|
|
34
|
+
<div class="bank-row" id="bank-zp">
|
|
35
|
+
<span class="bank-addr">$0000-$01FF</span>
|
|
36
|
+
<span class="bank-region bank-main" id="bank-zp-main">Main ZP/Stack</span>
|
|
37
|
+
<span class="bank-region bank-aux hidden" id="bank-zp-aux">Aux ZP/Stack</span>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="bank-row" id="bank-0200">
|
|
40
|
+
<span class="bank-addr">$0200-$03FF</span>
|
|
41
|
+
<span class="bank-region bank-main" id="bank-0200-main">Main RAM</span>
|
|
42
|
+
<span class="bank-region bank-aux hidden" id="bank-0200-aux">Aux RAM</span>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="bank-row" id="bank-text1">
|
|
45
|
+
<span class="bank-addr">$0400-$07FF</span>
|
|
46
|
+
<span class="bank-region bank-main" id="bank-text1-main">Main Text 1</span>
|
|
47
|
+
<span class="bank-region bank-aux hidden" id="bank-text1-aux">Aux Text 1</span>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="bank-row" id="bank-0800">
|
|
50
|
+
<span class="bank-addr">$0800-$1FFF</span>
|
|
51
|
+
<span class="bank-region bank-main" id="bank-0800-main">Main RAM</span>
|
|
52
|
+
<span class="bank-region bank-aux hidden" id="bank-0800-aux">Aux RAM</span>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="bank-row" id="bank-hires1">
|
|
55
|
+
<span class="bank-addr">$2000-$3FFF</span>
|
|
56
|
+
<span class="bank-region bank-main" id="bank-hires1-main">Main HiRes 1</span>
|
|
57
|
+
<span class="bank-region bank-aux hidden" id="bank-hires1-aux">Aux HiRes 1</span>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="bank-row" id="bank-hires2">
|
|
60
|
+
<span class="bank-addr">$4000-$5FFF</span>
|
|
61
|
+
<span class="bank-region bank-main" id="bank-hires2-main">Main HiRes 2</span>
|
|
62
|
+
<span class="bank-region bank-aux hidden" id="bank-hires2-aux">Aux HiRes 2</span>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="bank-row" id="bank-6000">
|
|
65
|
+
<span class="bank-addr">$6000-$BFFF</span>
|
|
66
|
+
<span class="bank-region bank-main" id="bank-6000-main">Main RAM</span>
|
|
67
|
+
<span class="bank-region bank-aux hidden" id="bank-6000-aux">Aux RAM</span>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="bank-row" id="bank-c000">
|
|
70
|
+
<span class="bank-addr">$C000-$C0FF</span>
|
|
71
|
+
<span class="bank-region bank-io">I/O Space</span>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="bank-row" id="bank-slot">
|
|
74
|
+
<span class="bank-addr">$C100-$CFFF</span>
|
|
75
|
+
<span class="bank-region bank-rom" id="bank-slot-int">Internal ROM</span>
|
|
76
|
+
<span class="bank-region bank-slot hidden" id="bank-slot-card">Slot ROMs</span>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="bank-row" id="bank-lc">
|
|
79
|
+
<span class="bank-addr">$D000-$FFFF</span>
|
|
80
|
+
<span class="bank-region bank-rom" id="bank-lc-rom">System ROM</span>
|
|
81
|
+
<span class="bank-region bank-ram hidden" id="bank-lc-ram">LC RAM Bnk1</span>
|
|
82
|
+
<span class="bank-region bank-ram hidden" id="bank-lc-ram2">LC RAM Bnk2</span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="bank-legend">
|
|
86
|
+
<span class="legend-item"><span class="legend-box bank-main"></span>Main</span>
|
|
87
|
+
<span class="legend-item"><span class="legend-box bank-aux"></span>Aux</span>
|
|
88
|
+
<span class="legend-item"><span class="legend-box bank-rom"></span>ROM</span>
|
|
89
|
+
<span class="legend-item"><span class="legend-box bank-ram"></span>LC RAM</span>
|
|
90
|
+
<span class="legend-item"><span class="legend-box bank-io"></span>I/O</span>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="bank-status">
|
|
93
|
+
<div class="bank-status-row">
|
|
94
|
+
<span class="bank-status-label">Read:</span>
|
|
95
|
+
<span class="bank-status-value" id="bank-read-status">Main RAM</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="bank-status-row">
|
|
98
|
+
<span class="bank-status-label">Write:</span>
|
|
99
|
+
<span class="bank-status-value" id="bank-write-status">Main RAM</span>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Update the memory bank map visualization
|
|
108
|
+
*/
|
|
109
|
+
update(wasmModule) {
|
|
110
|
+
this.wasmModule = wasmModule;
|
|
111
|
+
|
|
112
|
+
// Get soft switch states
|
|
113
|
+
const stateLow = wasmModule._getSoftSwitchState();
|
|
114
|
+
const stateHigh = wasmModule._getSoftSwitchStateHigh
|
|
115
|
+
? wasmModule._getSoftSwitchStateHigh()
|
|
116
|
+
: 0;
|
|
117
|
+
|
|
118
|
+
// Bit positions for relevant switches
|
|
119
|
+
const ALTZP = 10;
|
|
120
|
+
const STORE80 = 6;
|
|
121
|
+
const PAGE2 = 2;
|
|
122
|
+
const HIRES = 3;
|
|
123
|
+
const RAMRD = 7;
|
|
124
|
+
const RAMWRT = 8;
|
|
125
|
+
const INTCXROM = 9;
|
|
126
|
+
const LCRAM = 13;
|
|
127
|
+
const LCBANK2 = 14;
|
|
128
|
+
const LCWRITE = 15;
|
|
129
|
+
|
|
130
|
+
const altzp = (stateLow & (1 << ALTZP)) !== 0;
|
|
131
|
+
const store80 = (stateLow & (1 << STORE80)) !== 0;
|
|
132
|
+
const page2 = (stateLow & (1 << PAGE2)) !== 0;
|
|
133
|
+
const hires = (stateLow & (1 << HIRES)) !== 0;
|
|
134
|
+
const ramrd = (stateLow & (1 << RAMRD)) !== 0;
|
|
135
|
+
const ramwrt = (stateLow & (1 << RAMWRT)) !== 0;
|
|
136
|
+
const intcxrom = (stateLow & (1 << INTCXROM)) !== 0;
|
|
137
|
+
const lcram = (stateLow & (1 << LCRAM)) !== 0;
|
|
138
|
+
const lcbank2 = (stateLow & (1 << LCBANK2)) !== 0;
|
|
139
|
+
const lcwrite = (stateLow & (1 << LCWRITE)) !== 0;
|
|
140
|
+
|
|
141
|
+
// Zero Page / Stack: ALTZP controls
|
|
142
|
+
this.toggleBankRegion("bank-zp-main", !altzp);
|
|
143
|
+
this.toggleBankRegion("bank-zp-aux", altzp);
|
|
144
|
+
|
|
145
|
+
// $0200-$03FF: RAMRD/RAMWRT controls (not affected by 80STORE)
|
|
146
|
+
this.toggleBankRegion("bank-0200-main", !ramrd);
|
|
147
|
+
this.toggleBankRegion("bank-0200-aux", ramrd);
|
|
148
|
+
|
|
149
|
+
// Text Page 1 ($0400-$07FF): 80STORE + PAGE2 or RAMRD controls
|
|
150
|
+
const text1Aux = store80 ? page2 : ramrd;
|
|
151
|
+
this.toggleBankRegion("bank-text1-main", !text1Aux);
|
|
152
|
+
this.toggleBankRegion("bank-text1-aux", text1Aux);
|
|
153
|
+
|
|
154
|
+
// $0800-$1FFF: RAMRD/RAMWRT controls
|
|
155
|
+
this.toggleBankRegion("bank-0800-main", !ramrd);
|
|
156
|
+
this.toggleBankRegion("bank-0800-aux", ramrd);
|
|
157
|
+
|
|
158
|
+
// HiRes Page 1 ($2000-$3FFF): 80STORE + HIRES + PAGE2 or RAMRD controls
|
|
159
|
+
const hires1Aux = store80 && hires ? page2 : ramrd;
|
|
160
|
+
this.toggleBankRegion("bank-hires1-main", !hires1Aux);
|
|
161
|
+
this.toggleBankRegion("bank-hires1-aux", hires1Aux);
|
|
162
|
+
|
|
163
|
+
// HiRes Page 2 ($4000-$5FFF): RAMRD/RAMWRT controls
|
|
164
|
+
this.toggleBankRegion("bank-hires2-main", !ramrd);
|
|
165
|
+
this.toggleBankRegion("bank-hires2-aux", ramrd);
|
|
166
|
+
|
|
167
|
+
// $6000-$BFFF: RAMRD/RAMWRT controls
|
|
168
|
+
this.toggleBankRegion("bank-6000-main", !ramrd);
|
|
169
|
+
this.toggleBankRegion("bank-6000-aux", ramrd);
|
|
170
|
+
|
|
171
|
+
// Slot ROM ($C100-$CFFF): INTCXROM controls
|
|
172
|
+
this.toggleBankRegion("bank-slot-int", intcxrom);
|
|
173
|
+
this.toggleBankRegion("bank-slot-card", !intcxrom);
|
|
174
|
+
|
|
175
|
+
// Language Card ($D000-$FFFF): LCRAM and LCBANK2 control
|
|
176
|
+
this.toggleBankRegion("bank-lc-rom", !lcram);
|
|
177
|
+
this.toggleBankRegion("bank-lc-ram", lcram && !lcbank2);
|
|
178
|
+
this.toggleBankRegion("bank-lc-ram2", lcram && lcbank2);
|
|
179
|
+
|
|
180
|
+
// Update status display
|
|
181
|
+
const readStatus = this.contentElement.querySelector("#bank-read-status");
|
|
182
|
+
const writeStatus = this.contentElement.querySelector("#bank-write-status");
|
|
183
|
+
|
|
184
|
+
if (readStatus) {
|
|
185
|
+
let readBank = ramrd ? "Aux RAM" : "Main RAM";
|
|
186
|
+
if (altzp) readBank += " (Aux ZP)";
|
|
187
|
+
readStatus.textContent = readBank;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (writeStatus) {
|
|
191
|
+
let writeBank = ramwrt ? "Aux RAM" : "Main RAM";
|
|
192
|
+
if (lcwrite) writeBank += " + LC";
|
|
193
|
+
writeStatus.textContent = writeBank;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Toggle visibility of a bank region element
|
|
199
|
+
*/
|
|
200
|
+
toggleBankRegion(id, show) {
|
|
201
|
+
const el = this.contentElement.querySelector(`#${id}`);
|
|
202
|
+
if (el) {
|
|
203
|
+
el.classList.toggle("hidden", !show);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|