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,316 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* disk2_card.hpp - Disk II controller card
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "expansion_card.hpp"
|
|
11
|
+
#include "../disk-image/disk_image.hpp"
|
|
12
|
+
#include <array>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <functional>
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <string>
|
|
17
|
+
|
|
18
|
+
namespace a2e {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Disk2Card - Disk II Controller Card
|
|
22
|
+
*
|
|
23
|
+
* Complete implementation of the Disk II controller card for Apple IIe.
|
|
24
|
+
* The Disk II typically occupies slot 6, providing:
|
|
25
|
+
* - I/O space: $C0E0-$C0EF (16 soft switches for disk control)
|
|
26
|
+
* - ROM space: $C600-$C6FF (256 byte bootstrap ROM, P5A 341-0027)
|
|
27
|
+
*
|
|
28
|
+
* The card does not use expansion ROM ($C800-$CFFF).
|
|
29
|
+
*
|
|
30
|
+
* Soft switch addresses (offset from slot base):
|
|
31
|
+
* $00 - Phase 0 off $01 - Phase 0 on
|
|
32
|
+
* $02 - Phase 1 off $03 - Phase 1 on
|
|
33
|
+
* $04 - Phase 2 off $05 - Phase 2 on
|
|
34
|
+
* $06 - Phase 3 off $07 - Phase 3 on
|
|
35
|
+
* $08 - Motor off $09 - Motor on
|
|
36
|
+
* $0A - Drive 1 select $0B - Drive 2 select
|
|
37
|
+
* $0C - Q6L (read) $0D - Q6H (WP sense/write load)
|
|
38
|
+
* $0E - Q7L (read mode) $0F - Q7H (write mode)
|
|
39
|
+
*/
|
|
40
|
+
class Disk2Card : public ExpansionCard {
|
|
41
|
+
public:
|
|
42
|
+
Disk2Card();
|
|
43
|
+
explicit Disk2Card(const uint8_t* rom, size_t romSize);
|
|
44
|
+
~Disk2Card() override = default;
|
|
45
|
+
|
|
46
|
+
// Delete copy (disk images are non-copyable)
|
|
47
|
+
Disk2Card(const Disk2Card&) = delete;
|
|
48
|
+
Disk2Card& operator=(const Disk2Card&) = delete;
|
|
49
|
+
|
|
50
|
+
// Allow move
|
|
51
|
+
Disk2Card(Disk2Card&&) = default;
|
|
52
|
+
Disk2Card& operator=(Disk2Card&&) = default;
|
|
53
|
+
|
|
54
|
+
// ===== ExpansionCard Interface =====
|
|
55
|
+
|
|
56
|
+
uint8_t readIO(uint8_t offset) override;
|
|
57
|
+
void writeIO(uint8_t offset, uint8_t value) override;
|
|
58
|
+
uint8_t peekIO(uint8_t offset) const override;
|
|
59
|
+
|
|
60
|
+
uint8_t readROM(uint8_t offset) override;
|
|
61
|
+
bool hasROM() const override { return true; }
|
|
62
|
+
|
|
63
|
+
bool hasExpansionROM() const override { return false; }
|
|
64
|
+
|
|
65
|
+
void reset() override;
|
|
66
|
+
void update(int cycles) override;
|
|
67
|
+
|
|
68
|
+
void setCycleCallback(CycleCallback callback) override;
|
|
69
|
+
|
|
70
|
+
size_t getStateSize() const override;
|
|
71
|
+
size_t serialize(uint8_t* buffer, size_t maxSize) const override;
|
|
72
|
+
size_t deserialize(const uint8_t* buffer, size_t size) override;
|
|
73
|
+
|
|
74
|
+
const char* getName() const override { return "Disk II"; }
|
|
75
|
+
uint8_t getPreferredSlot() const override { return 6; }
|
|
76
|
+
|
|
77
|
+
// ===== Disk II Specific Methods =====
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Load the P5A ROM (341-0027)
|
|
81
|
+
* @param rom ROM data
|
|
82
|
+
* @param size ROM size (should be 256 bytes)
|
|
83
|
+
*/
|
|
84
|
+
void loadROM(const uint8_t* rom, size_t size);
|
|
85
|
+
|
|
86
|
+
// ===== Disk Operations =====
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Insert a disk image into a drive
|
|
90
|
+
* @param drive Drive number (0 or 1)
|
|
91
|
+
* @param data Pointer to disk image data
|
|
92
|
+
* @param size Size of the data
|
|
93
|
+
* @param filename Original filename (for format detection)
|
|
94
|
+
* @return true on success
|
|
95
|
+
*/
|
|
96
|
+
bool insertDisk(int drive, const uint8_t* data, size_t size, const std::string& filename);
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Insert a blank, unformatted disk into a drive
|
|
100
|
+
* @param drive Drive number (0 or 1)
|
|
101
|
+
* @return true on success
|
|
102
|
+
*/
|
|
103
|
+
bool insertBlankDisk(int drive);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Eject disk from a drive
|
|
107
|
+
* @param drive Drive number (0 or 1)
|
|
108
|
+
*/
|
|
109
|
+
void ejectDisk(int drive);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if a drive has a disk inserted
|
|
113
|
+
* @param drive Drive number (0 or 1)
|
|
114
|
+
* @return true if disk is inserted
|
|
115
|
+
*/
|
|
116
|
+
bool hasDisk(int drive) const;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get the disk data for saving (DSK format)
|
|
120
|
+
* @param drive Drive number (0 or 1)
|
|
121
|
+
* @param size Output: size of the data
|
|
122
|
+
* @return Pointer to disk data, or nullptr if no disk
|
|
123
|
+
*/
|
|
124
|
+
const uint8_t* getDiskData(int drive, size_t* size) const;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Export disk data in its native format for saving
|
|
128
|
+
* This works for both DSK and WOZ formats.
|
|
129
|
+
* @param drive Drive number (0 or 1)
|
|
130
|
+
* @param size Output: size of the exported data
|
|
131
|
+
* @return Pointer to exported data, or nullptr if no disk
|
|
132
|
+
*/
|
|
133
|
+
const uint8_t* exportDiskData(int drive, size_t* size);
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get the disk image for a drive (for UI display)
|
|
137
|
+
* @param drive Drive number (0 or 1)
|
|
138
|
+
* @return Pointer to disk image, or nullptr if no disk
|
|
139
|
+
*/
|
|
140
|
+
const DiskImage* getDiskImage(int drive) const;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get mutable disk image for a drive (for state restoration)
|
|
144
|
+
* @param drive Drive number (0 or 1)
|
|
145
|
+
* @return Pointer to disk image, or nullptr if no disk
|
|
146
|
+
*/
|
|
147
|
+
DiskImage* getMutableDiskImage(int drive);
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Check if motor is currently on
|
|
151
|
+
* @return true if motor is running
|
|
152
|
+
*/
|
|
153
|
+
bool isMotorOn() const;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Stop the motor immediately (for warm reset)
|
|
157
|
+
* Does not reset other controller state like track position
|
|
158
|
+
*/
|
|
159
|
+
void stopMotor();
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get currently selected drive (0 or 1)
|
|
163
|
+
* @return Selected drive number
|
|
164
|
+
*/
|
|
165
|
+
int getSelectedDrive() const { return selectedDrive_; }
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get the current track position from the selected drive's disk image
|
|
169
|
+
* @return Track number (0-34), or -1 if no disk
|
|
170
|
+
*/
|
|
171
|
+
int getCurrentTrack() const;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get the current quarter-track position from the selected drive's disk image
|
|
175
|
+
* @return Quarter-track number (0-139), or -1 if no disk
|
|
176
|
+
*/
|
|
177
|
+
int getQuarterTrack() const;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get the current phase magnet states
|
|
181
|
+
* @return Bit field where bit 0-3 represent phases 0-3 (1 = on, 0 = off)
|
|
182
|
+
*/
|
|
183
|
+
uint8_t getPhaseStates() const { return phaseStates_; }
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get Q6 latch state
|
|
187
|
+
* @return true if Q6 is high, false if low
|
|
188
|
+
*/
|
|
189
|
+
bool getQ6() const { return q6_; }
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get Q7 latch state
|
|
193
|
+
* @return true if Q7 is high (write mode), false if low (read mode)
|
|
194
|
+
*/
|
|
195
|
+
bool getQ7() const { return q7_; }
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get the data register value (LSS shift register)
|
|
199
|
+
* @return Current data register value
|
|
200
|
+
*/
|
|
201
|
+
uint8_t getDataLatch() const { return dataRegister_; }
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get the sequencer state (4-bit, 0-15)
|
|
205
|
+
*/
|
|
206
|
+
uint8_t getSequencerState() const { return sequencerState_; }
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get the bus data value (last value written by CPU)
|
|
210
|
+
*/
|
|
211
|
+
uint8_t getBusData() const { return busData_; }
|
|
212
|
+
|
|
213
|
+
// ===== State Restoration Methods =====
|
|
214
|
+
|
|
215
|
+
void setSelectedDrive(int drive) { selectedDrive_ = (drive == 0) ? 0 : 1; }
|
|
216
|
+
void setQ6(bool q6) { q6_ = q6; }
|
|
217
|
+
void setQ7(bool q7) { q7_ = q7; }
|
|
218
|
+
void setPhaseStates(uint8_t states) { phaseStates_ = states; }
|
|
219
|
+
void setDataLatch(uint8_t latch) { dataRegister_ = latch; }
|
|
220
|
+
void setMotorOn(bool on) { motorOn_ = on; }
|
|
221
|
+
void setSequencerState(uint8_t s) { sequencerState_ = s & 0x0F; }
|
|
222
|
+
void setBusData(uint8_t d) { busData_ = d; }
|
|
223
|
+
uint8_t getLSSClock() const { return lssClock_; }
|
|
224
|
+
void setLSSClock(uint8_t c) { lssClock_ = c & 0x07; }
|
|
225
|
+
|
|
226
|
+
private:
|
|
227
|
+
// Soft switch offsets
|
|
228
|
+
static constexpr uint8_t PHASE0_OFF = 0x00;
|
|
229
|
+
static constexpr uint8_t PHASE0_ON = 0x01;
|
|
230
|
+
static constexpr uint8_t PHASE1_OFF = 0x02;
|
|
231
|
+
static constexpr uint8_t PHASE1_ON = 0x03;
|
|
232
|
+
static constexpr uint8_t PHASE2_OFF = 0x04;
|
|
233
|
+
static constexpr uint8_t PHASE2_ON = 0x05;
|
|
234
|
+
static constexpr uint8_t PHASE3_OFF = 0x06;
|
|
235
|
+
static constexpr uint8_t PHASE3_ON = 0x07;
|
|
236
|
+
static constexpr uint8_t MOTOR_OFF = 0x08;
|
|
237
|
+
static constexpr uint8_t MOTOR_ON = 0x09;
|
|
238
|
+
static constexpr uint8_t DRIVE1_SELECT = 0x0A;
|
|
239
|
+
static constexpr uint8_t DRIVE2_SELECT = 0x0B;
|
|
240
|
+
static constexpr uint8_t Q6L = 0x0C;
|
|
241
|
+
static constexpr uint8_t Q6H = 0x0D;
|
|
242
|
+
static constexpr uint8_t Q7L = 0x0E;
|
|
243
|
+
static constexpr uint8_t Q7H = 0x0F;
|
|
244
|
+
|
|
245
|
+
// Motor timeout: ~1 second at 1.023 MHz
|
|
246
|
+
static constexpr uint64_t MOTOR_OFF_DELAY_CYCLES = 1023000;
|
|
247
|
+
|
|
248
|
+
// LSS timing: 4 CPU cycles per bit cell
|
|
249
|
+
static constexpr int CYCLES_PER_BIT = 4;
|
|
250
|
+
|
|
251
|
+
// Maximum catch-up: ~one disk revolution (~51200 bits for standard track)
|
|
252
|
+
static constexpr uint32_t MAX_CATCHUP_BITS = 53000;
|
|
253
|
+
|
|
254
|
+
// P6 sequencer ROM (341-0028, 256x4 bits, de-scrambled to logical format)
|
|
255
|
+
static const uint8_t P6_ROM[256];
|
|
256
|
+
|
|
257
|
+
// P5A ROM (256 bytes)
|
|
258
|
+
std::array<uint8_t, 256> rom_;
|
|
259
|
+
|
|
260
|
+
// Controller state
|
|
261
|
+
mutable bool motorOn_ = false;
|
|
262
|
+
mutable uint64_t motorOffCycle_ = 0;
|
|
263
|
+
int selectedDrive_ = 0;
|
|
264
|
+
bool q6_ = false;
|
|
265
|
+
bool q7_ = false;
|
|
266
|
+
uint8_t phaseStates_ = 0;
|
|
267
|
+
|
|
268
|
+
// Timing state
|
|
269
|
+
uint64_t totalCycles_ = 0;
|
|
270
|
+
|
|
271
|
+
// LSS state (P6 ROM clocked at 2x CPU rate = 8 ticks per bit cell)
|
|
272
|
+
uint8_t sequencerState_ = 0; // 4-bit state (0-15)
|
|
273
|
+
uint8_t dataRegister_ = 0; // 8-bit shift register
|
|
274
|
+
uint64_t lastLSSCycle_ = 0; // Last cycle LSS was clocked
|
|
275
|
+
uint8_t busData_ = 0; // CPU bus data for LOAD operations
|
|
276
|
+
uint8_t lssClock_ = 0; // 8-phase clock (0-7), disk I/O at phase 4
|
|
277
|
+
uint8_t writeLevel_ = 0; // Previous write amplifier level for transition encoding
|
|
278
|
+
|
|
279
|
+
// Disk images for each drive
|
|
280
|
+
std::unique_ptr<DiskImage> diskImages_[2];
|
|
281
|
+
|
|
282
|
+
// Cycle callback
|
|
283
|
+
CycleCallback cycleCallback_;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Get current cycle count, using callback if available
|
|
287
|
+
*/
|
|
288
|
+
uint64_t getCycles() const {
|
|
289
|
+
if (cycleCallback_) {
|
|
290
|
+
return cycleCallback_();
|
|
291
|
+
}
|
|
292
|
+
return totalCycles_;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Handle soft switch access
|
|
297
|
+
* @param offset Offset (0x00-0x0F)
|
|
298
|
+
* @param isWrite true if write access, false if read
|
|
299
|
+
* @return byte value for reads
|
|
300
|
+
*/
|
|
301
|
+
uint8_t handleSoftSwitch(uint8_t offset, bool isWrite);
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Clock the Logic State Sequencer by one tick (runs at 2x CPU rate).
|
|
305
|
+
* 8 ticks = 1 bit cell. Disk read/write occurs at phase 4 only.
|
|
306
|
+
*/
|
|
307
|
+
void clockLSS();
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Advance the LSS to the current CPU cycle
|
|
311
|
+
* @param currentCycle Current total CPU cycle count
|
|
312
|
+
*/
|
|
313
|
+
void catchUpLSS(uint64_t currentCycle);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
} // namespace a2e
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* expansion_card.hpp - Base class for expansion cards
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <cstddef>
|
|
12
|
+
#include <functional>
|
|
13
|
+
|
|
14
|
+
namespace a2e {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ExpansionCard - Abstract interface for Apple IIe expansion slot cards
|
|
18
|
+
*
|
|
19
|
+
* The Apple IIe has 7 expansion slots (1-7), each with:
|
|
20
|
+
* - I/O space: $C0n0-$C0nF (16 bytes, where n = slot + 8)
|
|
21
|
+
* - ROM space: $Cn00-$CnFF (256 bytes)
|
|
22
|
+
* - Expansion ROM: $C800-$CFFF (shared 2KB, active when card's ROM is accessed)
|
|
23
|
+
*
|
|
24
|
+
* Slot assignments by convention:
|
|
25
|
+
* - Slot 1: Printer cards
|
|
26
|
+
* - Slot 2: Serial/modem cards
|
|
27
|
+
* - Slot 3: 80-column card (built-in on //e, controlled by SLOTC3ROM)
|
|
28
|
+
* - Slot 4: Mockingboard / other sound cards
|
|
29
|
+
* - Slot 5: Hard drive / accelerator cards
|
|
30
|
+
* - Slot 6: Disk II controller
|
|
31
|
+
* - Slot 7: ProDOS RAM disk / other cards
|
|
32
|
+
*/
|
|
33
|
+
class ExpansionCard {
|
|
34
|
+
public:
|
|
35
|
+
using IRQCallback = std::function<void()>;
|
|
36
|
+
using CycleCallback = std::function<uint64_t()>;
|
|
37
|
+
|
|
38
|
+
virtual ~ExpansionCard() = default;
|
|
39
|
+
|
|
40
|
+
// ===== I/O Space Access ($C0n0-$C0nF) =====
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Read from the card's I/O space
|
|
44
|
+
* @param offset Offset within slot I/O (0-15)
|
|
45
|
+
* @return Byte value
|
|
46
|
+
*/
|
|
47
|
+
virtual uint8_t readIO(uint8_t offset) = 0;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Write to the card's I/O space
|
|
51
|
+
* @param offset Offset within slot I/O (0-15)
|
|
52
|
+
* @param value Byte value
|
|
53
|
+
*/
|
|
54
|
+
virtual void writeIO(uint8_t offset, uint8_t value) = 0;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Peek at I/O without side effects (for debugger)
|
|
58
|
+
* @param offset Offset within slot I/O (0-15)
|
|
59
|
+
* @return Byte value
|
|
60
|
+
*/
|
|
61
|
+
virtual uint8_t peekIO(uint8_t offset) const { return 0xFF; }
|
|
62
|
+
|
|
63
|
+
// ===== ROM Space Access ($Cn00-$CnFF) =====
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Read from the card's ROM space
|
|
67
|
+
* @param offset Offset within slot ROM (0-255)
|
|
68
|
+
* @return Byte value
|
|
69
|
+
*/
|
|
70
|
+
virtual uint8_t readROM(uint8_t offset) = 0;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if this card has ROM (most cards do)
|
|
74
|
+
* @return true if card provides ROM at $Cn00-$CnFF
|
|
75
|
+
*/
|
|
76
|
+
virtual bool hasROM() const { return true; }
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Write to the card's ROM space (unusual - used by cards like Mockingboard
|
|
80
|
+
* that put I/O registers in ROM space instead of I/O space)
|
|
81
|
+
* @param offset Offset within slot ROM (0-255)
|
|
82
|
+
* @param value Byte value
|
|
83
|
+
*/
|
|
84
|
+
virtual void writeROM(uint8_t offset, uint8_t value) {}
|
|
85
|
+
|
|
86
|
+
// ===== Expansion ROM Space ($C800-$CFFF) =====
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if this card has expansion ROM
|
|
90
|
+
* @return true if card provides expansion ROM at $C800-$CFFF
|
|
91
|
+
*/
|
|
92
|
+
virtual bool hasExpansionROM() const { return false; }
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Read from the card's expansion ROM space
|
|
96
|
+
* @param offset Offset within expansion ROM (0-2047)
|
|
97
|
+
* @return Byte value
|
|
98
|
+
*/
|
|
99
|
+
virtual uint8_t readExpansionROM(uint16_t offset) { return 0xFF; }
|
|
100
|
+
|
|
101
|
+
// ===== Lifecycle =====
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Reset the card to power-on state
|
|
105
|
+
*/
|
|
106
|
+
virtual void reset() = 0;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Update the card's internal state (call each CPU cycle)
|
|
110
|
+
* @param cycles Number of CPU cycles elapsed
|
|
111
|
+
*/
|
|
112
|
+
virtual void update(int cycles) {}
|
|
113
|
+
|
|
114
|
+
// ===== Callbacks =====
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Set callback for generating IRQ
|
|
118
|
+
* @param callback Function to call when IRQ is asserted
|
|
119
|
+
*/
|
|
120
|
+
virtual void setIRQCallback(IRQCallback callback) {}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Set callback for getting current CPU cycle count
|
|
124
|
+
* @param callback Function that returns current cycle count
|
|
125
|
+
*/
|
|
126
|
+
virtual void setCycleCallback(CycleCallback callback) {}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Check if IRQ is currently active
|
|
130
|
+
* @return true if IRQ line is asserted
|
|
131
|
+
*/
|
|
132
|
+
virtual bool isIRQActive() const { return false; }
|
|
133
|
+
|
|
134
|
+
// ===== State Serialization =====
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get the size of the serialized state
|
|
138
|
+
* @return Size in bytes
|
|
139
|
+
*/
|
|
140
|
+
virtual size_t getStateSize() const { return 0; }
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Serialize card state for save
|
|
144
|
+
* @param buffer Output buffer
|
|
145
|
+
* @param maxSize Maximum bytes to write
|
|
146
|
+
* @return Bytes written
|
|
147
|
+
*/
|
|
148
|
+
virtual size_t serialize(uint8_t* buffer, size_t maxSize) const { return 0; }
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Deserialize card state from save
|
|
152
|
+
* @param buffer Input buffer
|
|
153
|
+
* @param size Size of input data
|
|
154
|
+
* @return Bytes read
|
|
155
|
+
*/
|
|
156
|
+
virtual size_t deserialize(const uint8_t* buffer, size_t size) { return 0; }
|
|
157
|
+
|
|
158
|
+
// ===== Card Information =====
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get the card's name for display
|
|
162
|
+
* @return Human-readable name
|
|
163
|
+
*/
|
|
164
|
+
virtual const char* getName() const = 0;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get the card's preferred slot (0 = any)
|
|
168
|
+
* @return Preferred slot number (1-7) or 0 for no preference
|
|
169
|
+
*/
|
|
170
|
+
virtual uint8_t getPreferredSlot() const { return 0; }
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Check if card is currently enabled
|
|
174
|
+
* @return true if card is active
|
|
175
|
+
*/
|
|
176
|
+
virtual bool isEnabled() const { return true; }
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Enable or disable the card
|
|
180
|
+
* @param enabled true to enable
|
|
181
|
+
*/
|
|
182
|
+
virtual void setEnabled(bool enabled) {}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
} // namespace a2e
|