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,343 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* woz_disk_image.hpp - WOZ 1.0/2.0 bit-accurate disk image format support
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "disk_image.hpp"
|
|
11
|
+
#include <array>
|
|
12
|
+
#include <cstdint>
|
|
13
|
+
#include <memory>
|
|
14
|
+
#include <optional>
|
|
15
|
+
#include <string>
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
namespace a2e {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* WozDiskImage - WOZ format disk image implementation
|
|
22
|
+
*
|
|
23
|
+
* WOZ is a bit-accurate disk image format that captures the exact
|
|
24
|
+
* magnetic flux transitions on a 5.25" floppy disk. It supports:
|
|
25
|
+
*
|
|
26
|
+
* - Quarter-track positioning (160 positions for 40 tracks)
|
|
27
|
+
* - Variable track lengths (accurate timing)
|
|
28
|
+
* - Copy-protected disk preservation
|
|
29
|
+
* - Write protection status
|
|
30
|
+
*
|
|
31
|
+
* File format reference: https://applesaucefdc.com/woz/
|
|
32
|
+
*
|
|
33
|
+
* This implementation supports both WOZ 1.0 and WOZ 2.0 formats.
|
|
34
|
+
*/
|
|
35
|
+
class WozDiskImage : public DiskImage {
|
|
36
|
+
public:
|
|
37
|
+
WozDiskImage();
|
|
38
|
+
~WozDiskImage() override = default;
|
|
39
|
+
|
|
40
|
+
// Move operations
|
|
41
|
+
WozDiskImage(WozDiskImage &&) = default;
|
|
42
|
+
WozDiskImage &operator=(WozDiskImage &&) = default;
|
|
43
|
+
|
|
44
|
+
// ===== DiskImage interface implementation =====
|
|
45
|
+
|
|
46
|
+
bool load(const uint8_t *data, size_t size,
|
|
47
|
+
const std::string &filename) override;
|
|
48
|
+
bool isLoaded() const override;
|
|
49
|
+
Format getFormat() const override;
|
|
50
|
+
|
|
51
|
+
// Reset
|
|
52
|
+
void resetState() override;
|
|
53
|
+
|
|
54
|
+
// Head positioning
|
|
55
|
+
void setPhase(int phase, bool on) override;
|
|
56
|
+
int getQuarterTrack() const override;
|
|
57
|
+
int getTrack() const override;
|
|
58
|
+
void setQuarterTrack(int quarter_track) override;
|
|
59
|
+
|
|
60
|
+
// Geometry
|
|
61
|
+
int getTrackCount() const override;
|
|
62
|
+
bool hasData() const override;
|
|
63
|
+
|
|
64
|
+
// Data access
|
|
65
|
+
void advanceBitPosition(uint64_t current_cycles) override;
|
|
66
|
+
uint8_t readNibble() override;
|
|
67
|
+
|
|
68
|
+
// Write operations
|
|
69
|
+
void writeNibble(uint8_t nibble) override;
|
|
70
|
+
|
|
71
|
+
// Bit-level access (for LSS)
|
|
72
|
+
uint8_t readBit() override;
|
|
73
|
+
void writeBit(uint8_t bit) override;
|
|
74
|
+
|
|
75
|
+
bool isWriteProtected() const override;
|
|
76
|
+
bool isModified() const override { return modified_; }
|
|
77
|
+
std::string getFormatName() const override;
|
|
78
|
+
const uint8_t *getSectorData(size_t *size) const override;
|
|
79
|
+
const uint8_t *exportData(size_t *size) override;
|
|
80
|
+
|
|
81
|
+
// ===== Debug Methods =====
|
|
82
|
+
uint8_t getNibbleAt(int track, int position) const override;
|
|
83
|
+
int getTrackNibbleCount(int track) const override;
|
|
84
|
+
size_t getCurrentNibblePosition() const override { return bit_position_ / 8; }
|
|
85
|
+
|
|
86
|
+
// ===== WOZ-specific methods =====
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create a blank, unformatted WOZ2 disk
|
|
90
|
+
* The disk will have 35 empty tracks filled with sync bytes
|
|
91
|
+
*/
|
|
92
|
+
void createBlank();
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get the disk type from INFO chunk
|
|
96
|
+
* @return 1 = 5.25", 2 = 3.5"
|
|
97
|
+
*/
|
|
98
|
+
uint8_t getDiskType() const;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get disk type as a human-readable string
|
|
102
|
+
* @return "5.25\"" or "3.5\""
|
|
103
|
+
*/
|
|
104
|
+
std::string getDiskTypeString() const;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get the optimal bit timing from INFO chunk
|
|
108
|
+
* @return Bit timing in 125ns units (default 32 = 4us)
|
|
109
|
+
*/
|
|
110
|
+
uint8_t getOptimalBitTiming() const;
|
|
111
|
+
|
|
112
|
+
private:
|
|
113
|
+
// WOZ file signature constants
|
|
114
|
+
static constexpr uint32_t WOZ1_SIGNATURE = 0x315A4F57; // "WOZ1"
|
|
115
|
+
static constexpr uint32_t WOZ2_SIGNATURE = 0x325A4F57; // "WOZ2"
|
|
116
|
+
static constexpr uint32_t INFO_CHUNK_ID = 0x4F464E49; // "INFO"
|
|
117
|
+
static constexpr uint32_t TMAP_CHUNK_ID = 0x50414D54; // "TMAP"
|
|
118
|
+
static constexpr uint32_t TRKS_CHUNK_ID = 0x534B5254; // "TRKS"
|
|
119
|
+
|
|
120
|
+
// Quarter-track mapping
|
|
121
|
+
static constexpr int QUARTER_TRACK_COUNT = 160;
|
|
122
|
+
static constexpr uint8_t NO_TRACK = 0xFF;
|
|
123
|
+
|
|
124
|
+
// WOZ2 track storage
|
|
125
|
+
static constexpr size_t WOZ2_TRACK_BLOCK_SIZE = 512;
|
|
126
|
+
|
|
127
|
+
#pragma pack(push, 1)
|
|
128
|
+
/**
|
|
129
|
+
* WOZ file header (12 bytes)
|
|
130
|
+
*/
|
|
131
|
+
struct WozHeader {
|
|
132
|
+
uint32_t signature; // "WOZ1" or "WOZ2"
|
|
133
|
+
uint8_t high_bits; // 0xFF
|
|
134
|
+
uint8_t lfcrlf[3]; // 0x0A 0x0D 0x0A
|
|
135
|
+
uint32_t crc32; // CRC32 of all data after this field
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Chunk header (8 bytes)
|
|
140
|
+
*/
|
|
141
|
+
struct ChunkHeader {
|
|
142
|
+
uint32_t chunk_id; // 4-character chunk identifier
|
|
143
|
+
uint32_t size; // Size of chunk data (not including header)
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* INFO chunk data (60 bytes in WOZ2)
|
|
148
|
+
*/
|
|
149
|
+
struct InfoChunk {
|
|
150
|
+
uint8_t version; // INFO chunk version (1 or 2)
|
|
151
|
+
uint8_t disk_type; // 1 = 5.25", 2 = 3.5"
|
|
152
|
+
uint8_t write_protected; // 1 = write protected
|
|
153
|
+
uint8_t synchronized; // 1 = tracks are synchronized
|
|
154
|
+
uint8_t cleaned; // 1 = MC3470 fake bits removed
|
|
155
|
+
char creator[32]; // Creator software name
|
|
156
|
+
uint8_t disk_sides; // 1 or 2
|
|
157
|
+
uint8_t boot_sector_format; // 0=unknown, 1=16-sector, 2=13-sector, 3=both
|
|
158
|
+
uint8_t optimal_bit_timing; // 125ns units (default 32 = 4us)
|
|
159
|
+
uint16_t compatible_hardware; // Bit field of compatible hardware
|
|
160
|
+
uint16_t required_ram; // Minimum RAM in KB
|
|
161
|
+
uint16_t largest_track; // Block count of largest track
|
|
162
|
+
uint8_t reserved[10]; // Padding to 60 bytes
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* WOZ2 TRKS chunk entry (8 bytes per track)
|
|
167
|
+
*/
|
|
168
|
+
struct Woz2TrackEntry {
|
|
169
|
+
uint16_t starting_block; // Starting 512-byte block
|
|
170
|
+
uint16_t block_count; // Number of 512-byte blocks
|
|
171
|
+
uint32_t bit_count; // Number of valid bits in track
|
|
172
|
+
};
|
|
173
|
+
#pragma pack(pop)
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Internal track data storage
|
|
177
|
+
*/
|
|
178
|
+
struct TrackData {
|
|
179
|
+
std::vector<uint8_t> bits; // Raw bit data
|
|
180
|
+
uint32_t bit_count = 0; // Number of valid bits
|
|
181
|
+
bool valid = false; // Track has data
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Loaded file info
|
|
185
|
+
Format format_ = Format::Unknown;
|
|
186
|
+
bool loaded_ = false;
|
|
187
|
+
bool modified_ = false;
|
|
188
|
+
|
|
189
|
+
// Export buffer for saving
|
|
190
|
+
mutable std::vector<uint8_t> export_buffer_;
|
|
191
|
+
|
|
192
|
+
// Decoded sector data cache (for file explorer support)
|
|
193
|
+
mutable std::vector<uint8_t> decoded_sectors_;
|
|
194
|
+
mutable bool sectors_decoded_ = false;
|
|
195
|
+
|
|
196
|
+
// INFO chunk data
|
|
197
|
+
InfoChunk info_{};
|
|
198
|
+
|
|
199
|
+
// TMAP: quarter-track to track index mapping
|
|
200
|
+
std::array<uint8_t, QUARTER_TRACK_COUNT> tmap_{};
|
|
201
|
+
|
|
202
|
+
// Track data storage (indexed by TMAP values, not quarter-track)
|
|
203
|
+
std::vector<TrackData> tracks_;
|
|
204
|
+
|
|
205
|
+
// ===== Head positioning state =====
|
|
206
|
+
uint8_t phase_states_ = 0; // Bit field for phase magnet states (bits 0-3)
|
|
207
|
+
int quarter_track_ = 0; // Current head position (0-159)
|
|
208
|
+
int current_phase_ = 0; // Current phase where head is settled (for stepper)
|
|
209
|
+
|
|
210
|
+
// ===== Bit position =====
|
|
211
|
+
uint32_t bit_position_ = 0; // Current bit position within track
|
|
212
|
+
|
|
213
|
+
// Cycle count for disk rotation timing
|
|
214
|
+
uint64_t last_cycle_count_ = 0;
|
|
215
|
+
|
|
216
|
+
// ===== Internal methods =====
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Reset all state to unloaded
|
|
220
|
+
*/
|
|
221
|
+
void reset();
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Parse INFO chunk
|
|
225
|
+
* @param data Chunk data
|
|
226
|
+
* @param size Chunk size
|
|
227
|
+
* @return true on success
|
|
228
|
+
*/
|
|
229
|
+
bool parseInfoChunk(const uint8_t *data, uint32_t size);
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Parse TMAP chunk
|
|
233
|
+
* @param data Chunk data
|
|
234
|
+
* @param size Chunk size
|
|
235
|
+
* @return true on success
|
|
236
|
+
*/
|
|
237
|
+
bool parseTmapChunk(const uint8_t *data, uint32_t size);
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Parse TRKS chunk for WOZ1 format
|
|
241
|
+
* @param data Chunk data
|
|
242
|
+
* @param size Chunk size
|
|
243
|
+
* @return true on success
|
|
244
|
+
*/
|
|
245
|
+
bool parseTrksChunkWoz1(const uint8_t *data, uint32_t size);
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Parse TRKS chunk for WOZ2 format
|
|
249
|
+
* @param file_data Full file data
|
|
250
|
+
* @param file_size File size
|
|
251
|
+
* @param trks_data TRKS chunk data
|
|
252
|
+
* @param trks_size TRKS chunk size
|
|
253
|
+
* @return true on success
|
|
254
|
+
*/
|
|
255
|
+
bool parseTrksChunkWoz2(const uint8_t *file_data, size_t file_size,
|
|
256
|
+
const uint8_t *trks_data, uint32_t trks_size);
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Get track data at current head position
|
|
260
|
+
* @return Pointer to track data, or nullptr if no data
|
|
261
|
+
*/
|
|
262
|
+
const TrackData *getCurrentTrackData() const;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Read a raw bit from the disk at current position (internal helper)
|
|
266
|
+
* @return 0 or 1
|
|
267
|
+
*/
|
|
268
|
+
uint8_t readBitInternal() const;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Update head position based on phase magnet states
|
|
272
|
+
* Called when a phase is turned OFF to check if stepping should occur
|
|
273
|
+
* Uses 4-phase stepper motor physics matching real hardware
|
|
274
|
+
*/
|
|
275
|
+
void updateHeadPosition();
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get mutable track data at current head position
|
|
279
|
+
* @return Pointer to track data, or nullptr if no data
|
|
280
|
+
*/
|
|
281
|
+
TrackData *getMutableCurrentTrackData();
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Write a single bit to the disk at current position
|
|
285
|
+
* @param bit The bit value (0 or 1)
|
|
286
|
+
*/
|
|
287
|
+
void writeBitInternal(uint8_t bit);
|
|
288
|
+
|
|
289
|
+
// ===== Sector Decoding (for file explorer support) =====
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Decode all sectors from the WOZ bit stream.
|
|
293
|
+
* This converts the flux-level data back into standard sector data,
|
|
294
|
+
* enabling file explorer support for standard DOS 3.3 and ProDOS disks.
|
|
295
|
+
* Copy-protected disks may not decode successfully.
|
|
296
|
+
*
|
|
297
|
+
* @return true if decoding succeeded, false otherwise
|
|
298
|
+
*/
|
|
299
|
+
bool decodeSectors() const;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Read nibbles from a track's bit stream.
|
|
303
|
+
* Handles the bit-to-nibble conversion including sync byte detection.
|
|
304
|
+
*
|
|
305
|
+
* @param track_index Index of track in tracks_ array
|
|
306
|
+
* @return Vector of nibbles read from the track
|
|
307
|
+
*/
|
|
308
|
+
std::vector<uint8_t> readTrackNibbles(size_t track_index) const;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Find and decode sectors from a nibble stream.
|
|
312
|
+
* Searches for address and data field markers, decodes the 6-and-2 data.
|
|
313
|
+
*
|
|
314
|
+
* @param nibbles Nibble stream from a track
|
|
315
|
+
* @param track Expected track number
|
|
316
|
+
* @param sectors Output: 16 decoded sectors (256 bytes each)
|
|
317
|
+
* @return Number of sectors successfully decoded (0-16)
|
|
318
|
+
*/
|
|
319
|
+
int decodeSectorsFromNibbles(const std::vector<uint8_t> &nibbles, int track,
|
|
320
|
+
std::array<std::array<uint8_t, 256>, 16> §ors) const;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Decode 4-and-4 encoded byte.
|
|
324
|
+
* Used for address field values (volume, track, sector, checksum).
|
|
325
|
+
*
|
|
326
|
+
* @param odd First nibble (odd bits)
|
|
327
|
+
* @param even Second nibble (even bits)
|
|
328
|
+
* @return Decoded byte value
|
|
329
|
+
*/
|
|
330
|
+
static uint8_t decode4and4(uint8_t odd, uint8_t even);
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Decode 6-and-2 encoded sector data.
|
|
334
|
+
* Converts 342 disk nibbles back into 256 data bytes.
|
|
335
|
+
*
|
|
336
|
+
* @param nibbles Pointer to 343 nibbles (342 data + 1 checksum)
|
|
337
|
+
* @param output Output buffer for 256 decoded bytes
|
|
338
|
+
* @return true if checksum valid, false otherwise
|
|
339
|
+
*/
|
|
340
|
+
static bool decode6and2(const uint8_t *nibbles, uint8_t *output);
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
} // namespace a2e
|