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,654 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* mouse_card.cpp - Apple Mouse Interface card implementation
|
|
3
|
+
*
|
|
4
|
+
* Written by
|
|
5
|
+
* Mike Daley <michael_daley@icloud.com>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "mouse_card.hpp"
|
|
9
|
+
#include "roms.cpp" // For embedded ROM data
|
|
10
|
+
#include "../types.hpp"
|
|
11
|
+
#include <algorithm>
|
|
12
|
+
#include <cstring>
|
|
13
|
+
|
|
14
|
+
namespace a2e {
|
|
15
|
+
|
|
16
|
+
// Mode byte bits
|
|
17
|
+
static constexpr uint8_t MODE_MOUSE_ON = (1 << 0);
|
|
18
|
+
static constexpr uint8_t MODE_INT_MOVEMENT = (1 << 1);
|
|
19
|
+
static constexpr uint8_t MODE_INT_BUTTON = (1 << 2);
|
|
20
|
+
static constexpr uint8_t MODE_INT_VBL = (1 << 3);
|
|
21
|
+
|
|
22
|
+
// Status byte bits
|
|
23
|
+
static constexpr uint8_t STAT_PREV_BUTTON1 = (1 << 0);
|
|
24
|
+
static constexpr uint8_t STAT_INT_MOVEMENT = (1 << 1);
|
|
25
|
+
static constexpr uint8_t STAT_INT_BUTTON = (1 << 2);
|
|
26
|
+
static constexpr uint8_t STAT_INT_VBL = (1 << 3);
|
|
27
|
+
static constexpr uint8_t STAT_CURR_BUTTON1 = (1 << 4);
|
|
28
|
+
static constexpr uint8_t STAT_MOVEMENT_SINCE_READMOUSE = (1 << 5);
|
|
29
|
+
static constexpr uint8_t STAT_PREV_BUTTON0 = (1 << 6);
|
|
30
|
+
static constexpr uint8_t STAT_CURR_BUTTON0 = (1 << 7);
|
|
31
|
+
|
|
32
|
+
// PIA register select (lower 2 bits of offset)
|
|
33
|
+
static constexpr uint8_t PIA_PORT_A = 0; // Port A data / DDRA
|
|
34
|
+
static constexpr uint8_t PIA_CRA = 1; // Control Register A
|
|
35
|
+
static constexpr uint8_t PIA_PORT_B = 2; // Port B data / DDRB
|
|
36
|
+
static constexpr uint8_t PIA_CRB = 3; // Control Register B
|
|
37
|
+
|
|
38
|
+
// Command codes (high nibble of command byte)
|
|
39
|
+
static constexpr uint8_t CMD_SET = 0x00;
|
|
40
|
+
static constexpr uint8_t CMD_READ = 0x10;
|
|
41
|
+
static constexpr uint8_t CMD_SERV = 0x20;
|
|
42
|
+
static constexpr uint8_t CMD_CLEAR = 0x30;
|
|
43
|
+
static constexpr uint8_t CMD_POS = 0x40;
|
|
44
|
+
static constexpr uint8_t CMD_INIT = 0x50;
|
|
45
|
+
static constexpr uint8_t CMD_CLAMP = 0x60;
|
|
46
|
+
static constexpr uint8_t CMD_HOME = 0x70;
|
|
47
|
+
|
|
48
|
+
MouseCard::MouseCard()
|
|
49
|
+
: rom_(roms::ROM_MOUSE)
|
|
50
|
+
, romSize_(roms::ROM_MOUSE_SIZE)
|
|
51
|
+
{
|
|
52
|
+
reset();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void MouseCard::reset() {
|
|
56
|
+
// Reset PIA
|
|
57
|
+
ddra_ = 0;
|
|
58
|
+
ddrb_ = 0;
|
|
59
|
+
ora_ = 0;
|
|
60
|
+
orb_ = 0;
|
|
61
|
+
ira_ = 0;
|
|
62
|
+
irb_ = 0;
|
|
63
|
+
cra_ = 0;
|
|
64
|
+
crb_ = 0;
|
|
65
|
+
|
|
66
|
+
// Reset mouse state
|
|
67
|
+
mouseX_ = 0;
|
|
68
|
+
mouseY_ = 0;
|
|
69
|
+
mouseButton_ = false;
|
|
70
|
+
lastButton_ = false;
|
|
71
|
+
moved_ = false;
|
|
72
|
+
buttonChanged_ = false;
|
|
73
|
+
mode_ = 0;
|
|
74
|
+
|
|
75
|
+
// Default clamp bounds
|
|
76
|
+
clampMinX_ = 0;
|
|
77
|
+
clampMaxX_ = 1023;
|
|
78
|
+
clampMinY_ = 0;
|
|
79
|
+
clampMaxY_ = 1023;
|
|
80
|
+
|
|
81
|
+
// Reset interrupt state
|
|
82
|
+
irqActive_ = false;
|
|
83
|
+
vblInterruptPending_ = false;
|
|
84
|
+
moveInterruptPending_ = false;
|
|
85
|
+
buttonInterruptPending_ = false;
|
|
86
|
+
|
|
87
|
+
// Reset VBL tracking
|
|
88
|
+
wasInVBL_ = false;
|
|
89
|
+
|
|
90
|
+
// Reset protocol state machine
|
|
91
|
+
byState_ = 0;
|
|
92
|
+
std::memset(byBuff_, 0, sizeof(byBuff_));
|
|
93
|
+
nBuffPos_ = 0;
|
|
94
|
+
nDataLen_ = 1;
|
|
95
|
+
by6821B_ = 0x40; // BIT6 set (MCU ready signal)
|
|
96
|
+
irb_ = by6821B_; // Reflect in Port B input
|
|
97
|
+
lastCommand_ = 0;
|
|
98
|
+
|
|
99
|
+
// Reset snapshot
|
|
100
|
+
snapX_ = 0;
|
|
101
|
+
snapY_ = 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// PIA Register Access
|
|
106
|
+
// ============================================================================
|
|
107
|
+
|
|
108
|
+
uint8_t MouseCard::readIO(uint8_t offset) {
|
|
109
|
+
uint8_t reg = offset & 0x03;
|
|
110
|
+
|
|
111
|
+
switch (reg) {
|
|
112
|
+
case PIA_PORT_A: {
|
|
113
|
+
if (cra_ & 0x04) {
|
|
114
|
+
// Data register selected: return (output & DDR) | (input & ~DDR)
|
|
115
|
+
uint8_t value = (ora_ & ddra_) | (ira_ & ~ddra_);
|
|
116
|
+
// Reading data port clears IRQ flags (bits 7,6) in CRA
|
|
117
|
+
cra_ &= 0x3F;
|
|
118
|
+
updateIRQState();
|
|
119
|
+
return value;
|
|
120
|
+
} else {
|
|
121
|
+
// DDR selected
|
|
122
|
+
return ddra_;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
case PIA_CRA:
|
|
127
|
+
return cra_;
|
|
128
|
+
|
|
129
|
+
case PIA_PORT_B: {
|
|
130
|
+
if (crb_ & 0x04) {
|
|
131
|
+
// Data register selected
|
|
132
|
+
uint8_t value = (orb_ & ddrb_) | (irb_ & ~ddrb_);
|
|
133
|
+
// Reading data port clears IRQ flags (bits 7,6) in CRB
|
|
134
|
+
crb_ &= 0x3F;
|
|
135
|
+
updateIRQState();
|
|
136
|
+
return value;
|
|
137
|
+
} else {
|
|
138
|
+
return ddrb_;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case PIA_CRB:
|
|
143
|
+
return crb_;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return 0xFF;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
void MouseCard::writeIO(uint8_t offset, uint8_t value) {
|
|
150
|
+
uint8_t reg = offset & 0x03;
|
|
151
|
+
|
|
152
|
+
switch (reg) {
|
|
153
|
+
case PIA_PORT_A: {
|
|
154
|
+
if (cra_ & 0x04) {
|
|
155
|
+
// Write to output register A
|
|
156
|
+
ora_ = value;
|
|
157
|
+
} else {
|
|
158
|
+
// Write to DDR A
|
|
159
|
+
ddra_ = value;
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
case PIA_CRA:
|
|
165
|
+
// Bits 6,7 are read-only IRQ flags
|
|
166
|
+
cra_ = (cra_ & 0xC0) | (value & 0x3F);
|
|
167
|
+
updateIRQState();
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
case PIA_PORT_B: {
|
|
171
|
+
if (crb_ & 0x04) {
|
|
172
|
+
// Write to output register B
|
|
173
|
+
orb_ = value;
|
|
174
|
+
on6821_B(value); // Detect clock transitions
|
|
175
|
+
} else {
|
|
176
|
+
// Write to DDR B
|
|
177
|
+
ddrb_ = value;
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
case PIA_CRB:
|
|
183
|
+
crb_ = (crb_ & 0xC0) | (value & 0x3F);
|
|
184
|
+
updateIRQState();
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
uint8_t MouseCard::peekIO(uint8_t offset) const {
|
|
190
|
+
uint8_t reg = offset & 0x03;
|
|
191
|
+
switch (reg) {
|
|
192
|
+
case PIA_PORT_A:
|
|
193
|
+
if (cra_ & 0x04) {
|
|
194
|
+
return (ora_ & ddra_) | (ira_ & ~ddra_);
|
|
195
|
+
}
|
|
196
|
+
return ddra_;
|
|
197
|
+
case PIA_CRA: return cra_;
|
|
198
|
+
case PIA_PORT_B:
|
|
199
|
+
if (crb_ & 0x04) {
|
|
200
|
+
return (orb_ & ddrb_) | (irb_ & ~ddrb_);
|
|
201
|
+
}
|
|
202
|
+
return ddrb_;
|
|
203
|
+
case PIA_CRB: return crb_;
|
|
204
|
+
}
|
|
205
|
+
return 0xFF;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// ROM Access (banked, firmware runs natively)
|
|
210
|
+
// ============================================================================
|
|
211
|
+
|
|
212
|
+
uint8_t MouseCard::readROM(uint8_t offset) {
|
|
213
|
+
// Port B bits 1-3 select which 256-byte page of the 2KB ROM
|
|
214
|
+
uint16_t romBank = static_cast<uint16_t>(by6821B_ & 0x0E) << 7;
|
|
215
|
+
uint16_t romOffset = romBank | offset;
|
|
216
|
+
if (rom_ && romOffset < romSize_) {
|
|
217
|
+
return rom_[romOffset];
|
|
218
|
+
}
|
|
219
|
+
return 0xFF;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// PIA Command Protocol (AppleWin-style)
|
|
224
|
+
// ============================================================================
|
|
225
|
+
|
|
226
|
+
void MouseCard::on6821_B(uint8_t byData) {
|
|
227
|
+
// Detect transitions on Port B bits 1-5 to determine when the firmware
|
|
228
|
+
// is writing a command/data byte or reading a response byte.
|
|
229
|
+
// Matches AppleWin's CMouseInterface::On6821_B() exactly.
|
|
230
|
+
|
|
231
|
+
uint8_t byDiff = (by6821B_ ^ byData) & 0x3E; // Only check bits 1-5
|
|
232
|
+
if (!byDiff) return;
|
|
233
|
+
|
|
234
|
+
// Update bits 1-5 from firmware output; bits 0,6,7 are MCU-managed
|
|
235
|
+
by6821B_ &= ~0x3E;
|
|
236
|
+
by6821B_ |= byData & 0x3E;
|
|
237
|
+
|
|
238
|
+
// BIT5: Write strobe (firmware writing data to MCU)
|
|
239
|
+
if (byDiff & 0x20) {
|
|
240
|
+
if (byData & 0x20) {
|
|
241
|
+
// Rising edge: MCU signals "ready to read"
|
|
242
|
+
by6821B_ |= 0x80; // Set BIT7
|
|
243
|
+
} else {
|
|
244
|
+
// Falling edge: clock data in from Port A
|
|
245
|
+
byBuff_[nBuffPos_++] = ora_;
|
|
246
|
+
if (nBuffPos_ == 1) {
|
|
247
|
+
onCommand();
|
|
248
|
+
}
|
|
249
|
+
if (nBuffPos_ == nDataLen_ || nBuffPos_ > 7) {
|
|
250
|
+
onWrite();
|
|
251
|
+
nBuffPos_ = 0;
|
|
252
|
+
}
|
|
253
|
+
by6821B_ &= ~0x80; // Clear BIT7 for next reading
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// BIT4: Read strobe (firmware reading data from MCU)
|
|
258
|
+
if (byDiff & 0x10) {
|
|
259
|
+
if (byData & 0x10) {
|
|
260
|
+
// Rising edge: MCU prepares next value
|
|
261
|
+
by6821B_ &= ~0x40; // Clear BIT6
|
|
262
|
+
} else {
|
|
263
|
+
// Falling edge: advance buffer and load next byte
|
|
264
|
+
if (nBuffPos_) {
|
|
265
|
+
nBuffPos_++;
|
|
266
|
+
}
|
|
267
|
+
if (nBuffPos_ == nDataLen_ || nBuffPos_ > 7) {
|
|
268
|
+
nBuffPos_ = 0; // Read complete, ready for next command
|
|
269
|
+
} else {
|
|
270
|
+
ira_ = byBuff_[nBuffPos_]; // Load next response byte
|
|
271
|
+
}
|
|
272
|
+
by6821B_ |= 0x40; // Set BIT6 for next writing
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Reflect MCU handshake signals in Port B input register
|
|
277
|
+
irb_ = by6821B_;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void MouseCard::onCommand() {
|
|
281
|
+
// Dispatch based on command byte high nibble.
|
|
282
|
+
// Matches AppleWin's CMouseInterface::OnCommand() exactly.
|
|
283
|
+
// nDataLen_ = total bytes in this transaction (command + data).
|
|
284
|
+
// For read-back commands, byBuff_[1..N] are filled with response data.
|
|
285
|
+
|
|
286
|
+
uint8_t cmd = byBuff_[0] & 0xF0;
|
|
287
|
+
lastCommand_ = byBuff_[0];
|
|
288
|
+
|
|
289
|
+
switch (cmd) {
|
|
290
|
+
case CMD_SET:
|
|
291
|
+
// Mode is in the low nibble of the command byte itself
|
|
292
|
+
nDataLen_ = 1;
|
|
293
|
+
mode_ = byBuff_[0] & 0x0F;
|
|
294
|
+
break;
|
|
295
|
+
|
|
296
|
+
case CMD_READ: {
|
|
297
|
+
// Snapshot position, build 5-byte read response
|
|
298
|
+
nDataLen_ = 6; // command + 5 response bytes
|
|
299
|
+
|
|
300
|
+
// Build status: keep only "moved since last read", then add buttons
|
|
301
|
+
uint8_t status = 0;
|
|
302
|
+
if (moved_) status |= STAT_MOVEMENT_SINCE_READMOUSE;
|
|
303
|
+
snapX_ = mouseX_;
|
|
304
|
+
snapY_ = mouseY_;
|
|
305
|
+
|
|
306
|
+
if (lastButton_) status |= STAT_PREV_BUTTON0;
|
|
307
|
+
lastButton_ = mouseButton_;
|
|
308
|
+
if (mouseButton_) status |= STAT_CURR_BUTTON0;
|
|
309
|
+
|
|
310
|
+
byBuff_[1] = static_cast<uint8_t>(snapX_ & 0xFF);
|
|
311
|
+
byBuff_[2] = static_cast<uint8_t>((snapX_ >> 8) & 0xFF);
|
|
312
|
+
byBuff_[3] = static_cast<uint8_t>(snapY_ & 0xFF);
|
|
313
|
+
byBuff_[4] = static_cast<uint8_t>((snapY_ >> 8) & 0xFF);
|
|
314
|
+
byBuff_[5] = status;
|
|
315
|
+
|
|
316
|
+
moved_ = false;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
case CMD_SERV: {
|
|
321
|
+
// Return interrupt status, deassert IRQ
|
|
322
|
+
nDataLen_ = 2;
|
|
323
|
+
|
|
324
|
+
uint8_t irqStatus = 0;
|
|
325
|
+
if (moveInterruptPending_) irqStatus |= STAT_INT_MOVEMENT;
|
|
326
|
+
if (buttonInterruptPending_) irqStatus |= STAT_INT_BUTTON;
|
|
327
|
+
if (vblInterruptPending_) irqStatus |= STAT_INT_VBL;
|
|
328
|
+
byBuff_[1] = irqStatus;
|
|
329
|
+
|
|
330
|
+
// Deassert IRQ (pending flags cleared so next event re-triggers)
|
|
331
|
+
vblInterruptPending_ = false;
|
|
332
|
+
moveInterruptPending_ = false;
|
|
333
|
+
buttonInterruptPending_ = false;
|
|
334
|
+
irqActive_ = false;
|
|
335
|
+
cra_ &= 0x3F;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
case CMD_CLEAR:
|
|
340
|
+
nDataLen_ = 1;
|
|
341
|
+
nBuffPos_ = 0;
|
|
342
|
+
mouseX_ = 0;
|
|
343
|
+
mouseY_ = 0;
|
|
344
|
+
snapX_ = 0;
|
|
345
|
+
snapY_ = 0;
|
|
346
|
+
lastButton_ = false;
|
|
347
|
+
moved_ = false;
|
|
348
|
+
break;
|
|
349
|
+
|
|
350
|
+
case CMD_POS:
|
|
351
|
+
nDataLen_ = 5; // command + 4 data bytes
|
|
352
|
+
break;
|
|
353
|
+
|
|
354
|
+
case CMD_INIT:
|
|
355
|
+
nDataLen_ = 3; // command + 2 protocol bytes
|
|
356
|
+
byBuff_[1] = 0xFF; // Acknowledgment byte
|
|
357
|
+
break;
|
|
358
|
+
|
|
359
|
+
case CMD_CLAMP:
|
|
360
|
+
nDataLen_ = 5; // command + 4 data bytes
|
|
361
|
+
break;
|
|
362
|
+
|
|
363
|
+
case CMD_HOME:
|
|
364
|
+
nDataLen_ = 1;
|
|
365
|
+
mouseX_ = 0;
|
|
366
|
+
mouseY_ = 0;
|
|
367
|
+
break;
|
|
368
|
+
|
|
369
|
+
default:
|
|
370
|
+
nDataLen_ = 1;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Preload first response byte into Port A input for firmware to read
|
|
375
|
+
ira_ = byBuff_[1];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
void MouseCard::onWrite() {
|
|
379
|
+
// Process buffered write data after all expected bytes received.
|
|
380
|
+
// Matches AppleWin's CMouseInterface::OnWrite() data format.
|
|
381
|
+
|
|
382
|
+
switch (byBuff_[0] & 0xF0) {
|
|
383
|
+
case CMD_CLAMP: {
|
|
384
|
+
// Buffer: [cmd, minLo, maxLo, minHi, maxHi]
|
|
385
|
+
// Axis from bit 0 of command: 0=X, 1=Y
|
|
386
|
+
int16_t minVal = static_cast<int16_t>(
|
|
387
|
+
byBuff_[1] | (byBuff_[3] << 8));
|
|
388
|
+
int16_t maxVal = static_cast<int16_t>(
|
|
389
|
+
byBuff_[2] | (byBuff_[4] << 8));
|
|
390
|
+
|
|
391
|
+
if (byBuff_[0] & 1) {
|
|
392
|
+
// Clamp Y
|
|
393
|
+
clampMinY_ = minVal;
|
|
394
|
+
clampMaxY_ = maxVal;
|
|
395
|
+
if (mouseY_ < clampMinY_) mouseY_ = clampMinY_;
|
|
396
|
+
if (mouseY_ > clampMaxY_) mouseY_ = clampMaxY_;
|
|
397
|
+
} else {
|
|
398
|
+
// Clamp X
|
|
399
|
+
clampMinX_ = minVal;
|
|
400
|
+
clampMaxX_ = maxVal;
|
|
401
|
+
if (mouseX_ < clampMinX_) mouseX_ = clampMinX_;
|
|
402
|
+
if (mouseX_ > clampMaxX_) mouseX_ = clampMaxX_;
|
|
403
|
+
}
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
case CMD_POS:
|
|
408
|
+
// Buffer: [cmd, Xlo, Xhi, Ylo, Yhi]
|
|
409
|
+
mouseX_ = static_cast<int16_t>(
|
|
410
|
+
byBuff_[1] | (byBuff_[2] << 8));
|
|
411
|
+
mouseY_ = static_cast<int16_t>(
|
|
412
|
+
byBuff_[3] | (byBuff_[4] << 8));
|
|
413
|
+
// Apply clamping
|
|
414
|
+
if (mouseX_ < clampMinX_) mouseX_ = clampMinX_;
|
|
415
|
+
if (mouseX_ > clampMaxX_) mouseX_ = clampMaxX_;
|
|
416
|
+
if (mouseY_ < clampMinY_) mouseY_ = clampMinY_;
|
|
417
|
+
if (mouseY_ > clampMaxY_) mouseY_ = clampMaxY_;
|
|
418
|
+
break;
|
|
419
|
+
|
|
420
|
+
case CMD_INIT:
|
|
421
|
+
clampMinX_ = 0;
|
|
422
|
+
clampMaxX_ = 1023;
|
|
423
|
+
clampMinY_ = 0;
|
|
424
|
+
clampMaxY_ = 1023;
|
|
425
|
+
mouseX_ = 0;
|
|
426
|
+
mouseY_ = 0;
|
|
427
|
+
snapX_ = 0;
|
|
428
|
+
snapY_ = 0;
|
|
429
|
+
break;
|
|
430
|
+
|
|
431
|
+
default:
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// ============================================================================
|
|
437
|
+
// VBL Interrupt Generation
|
|
438
|
+
// ============================================================================
|
|
439
|
+
|
|
440
|
+
void MouseCard::update(int cycles) {
|
|
441
|
+
if (!cycleCallback_) return;
|
|
442
|
+
|
|
443
|
+
uint64_t totalCycles = cycleCallback_();
|
|
444
|
+
|
|
445
|
+
// Detect VBL transition (scanline 192, start of vertical blank)
|
|
446
|
+
uint64_t cycleInFrame = totalCycles % CYCLES_PER_FRAME;
|
|
447
|
+
int scanline = static_cast<int>(cycleInFrame / CYCLES_PER_SCANLINE);
|
|
448
|
+
bool inVBL = (scanline >= 192);
|
|
449
|
+
|
|
450
|
+
// Detect transition into VBL
|
|
451
|
+
if (inVBL && !wasInVBL_) {
|
|
452
|
+
if (mode_ & MODE_INT_VBL) {
|
|
453
|
+
vblInterruptPending_ = true;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Also check for movement/button interrupts at VBL
|
|
457
|
+
if ((mode_ & MODE_INT_MOVEMENT) && moved_) {
|
|
458
|
+
moveInterruptPending_ = true;
|
|
459
|
+
}
|
|
460
|
+
if ((mode_ & MODE_INT_BUTTON) && buttonChanged_) {
|
|
461
|
+
buttonInterruptPending_ = true;
|
|
462
|
+
buttonChanged_ = false;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Fire IRQ if any interrupt is pending and mouse is enabled
|
|
466
|
+
if ((mode_ & MODE_MOUSE_ON) &&
|
|
467
|
+
(vblInterruptPending_ || moveInterruptPending_ || buttonInterruptPending_)) {
|
|
468
|
+
irqActive_ = true;
|
|
469
|
+
cra_ |= 0x80;
|
|
470
|
+
if (irqCallback_) {
|
|
471
|
+
irqCallback_();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
wasInVBL_ = inVBL;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ============================================================================
|
|
480
|
+
// Mouse Input
|
|
481
|
+
// ============================================================================
|
|
482
|
+
|
|
483
|
+
void MouseCard::addDelta(int dx, int dy) {
|
|
484
|
+
if (dx == 0 && dy == 0) return;
|
|
485
|
+
|
|
486
|
+
mouseX_ += static_cast<int16_t>(dx);
|
|
487
|
+
mouseY_ += static_cast<int16_t>(dy);
|
|
488
|
+
|
|
489
|
+
// Apply clamping
|
|
490
|
+
if (mouseX_ < clampMinX_) mouseX_ = clampMinX_;
|
|
491
|
+
if (mouseX_ > clampMaxX_) mouseX_ = clampMaxX_;
|
|
492
|
+
if (mouseY_ < clampMinY_) mouseY_ = clampMinY_;
|
|
493
|
+
if (mouseY_ > clampMaxY_) mouseY_ = clampMaxY_;
|
|
494
|
+
|
|
495
|
+
moved_ = true;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
void MouseCard::setMouseButton(bool pressed) {
|
|
499
|
+
if (pressed != mouseButton_) {
|
|
500
|
+
lastButton_ = mouseButton_;
|
|
501
|
+
mouseButton_ = pressed;
|
|
502
|
+
buttonChanged_ = true;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
void MouseCard::updateIRQState() {
|
|
507
|
+
// IRQ is active if any PIA IRQ flag is set and the corresponding
|
|
508
|
+
// control register enables it
|
|
509
|
+
bool piaIRQ = (cra_ & 0x80) || (crb_ & 0x80);
|
|
510
|
+
if (!piaIRQ) {
|
|
511
|
+
irqActive_ = false;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
uint8_t MouseCard::readExpansionROM(uint16_t offset) {
|
|
516
|
+
// The mouse card does not use expansion ROM - all firmware is
|
|
517
|
+
// accessed through banked slot ROM. This should not be called.
|
|
518
|
+
(void)offset;
|
|
519
|
+
return 0xFF;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// ============================================================================
|
|
523
|
+
// State Serialization
|
|
524
|
+
// ============================================================================
|
|
525
|
+
|
|
526
|
+
size_t MouseCard::serialize(uint8_t* buffer, size_t maxSize) const {
|
|
527
|
+
if (maxSize < STATE_SIZE) return 0;
|
|
528
|
+
|
|
529
|
+
size_t off = 0;
|
|
530
|
+
|
|
531
|
+
// PIA state (8 bytes)
|
|
532
|
+
buffer[off++] = ddra_;
|
|
533
|
+
buffer[off++] = ddrb_;
|
|
534
|
+
buffer[off++] = ora_;
|
|
535
|
+
buffer[off++] = orb_;
|
|
536
|
+
buffer[off++] = ira_;
|
|
537
|
+
buffer[off++] = irb_;
|
|
538
|
+
buffer[off++] = cra_;
|
|
539
|
+
buffer[off++] = crb_;
|
|
540
|
+
|
|
541
|
+
// Mouse position (8 bytes)
|
|
542
|
+
buffer[off++] = static_cast<uint8_t>(mouseX_ & 0xFF);
|
|
543
|
+
buffer[off++] = static_cast<uint8_t>((mouseX_ >> 8) & 0xFF);
|
|
544
|
+
buffer[off++] = static_cast<uint8_t>(mouseY_ & 0xFF);
|
|
545
|
+
buffer[off++] = static_cast<uint8_t>((mouseY_ >> 8) & 0xFF);
|
|
546
|
+
|
|
547
|
+
// Clamp bounds (8 bytes)
|
|
548
|
+
buffer[off++] = static_cast<uint8_t>(clampMinX_ & 0xFF);
|
|
549
|
+
buffer[off++] = static_cast<uint8_t>((clampMinX_ >> 8) & 0xFF);
|
|
550
|
+
buffer[off++] = static_cast<uint8_t>(clampMaxX_ & 0xFF);
|
|
551
|
+
buffer[off++] = static_cast<uint8_t>((clampMaxX_ >> 8) & 0xFF);
|
|
552
|
+
buffer[off++] = static_cast<uint8_t>(clampMinY_ & 0xFF);
|
|
553
|
+
buffer[off++] = static_cast<uint8_t>((clampMinY_ >> 8) & 0xFF);
|
|
554
|
+
buffer[off++] = static_cast<uint8_t>(clampMaxY_ & 0xFF);
|
|
555
|
+
buffer[off++] = static_cast<uint8_t>((clampMaxY_ >> 8) & 0xFF);
|
|
556
|
+
|
|
557
|
+
// Flags (4 bytes)
|
|
558
|
+
buffer[off++] = (mouseButton_ ? 1 : 0) | (lastButton_ ? 2 : 0)
|
|
559
|
+
| (moved_ ? 4 : 0) | (buttonChanged_ ? 8 : 0);
|
|
560
|
+
buffer[off++] = (irqActive_ ? 1 : 0) | (vblInterruptPending_ ? 2 : 0)
|
|
561
|
+
| (moveInterruptPending_ ? 4 : 0) | (buttonInterruptPending_ ? 8 : 0);
|
|
562
|
+
buffer[off++] = lastCommand_;
|
|
563
|
+
buffer[off++] = mode_;
|
|
564
|
+
|
|
565
|
+
// Slot number (1 byte)
|
|
566
|
+
buffer[off++] = slotNum_;
|
|
567
|
+
|
|
568
|
+
// VBL tracking (1 byte)
|
|
569
|
+
buffer[off++] = wasInVBL_ ? 1 : 0;
|
|
570
|
+
|
|
571
|
+
// Protocol state (4 bytes: by6821B_, byState_, nBuffPos_, nDataLen_)
|
|
572
|
+
buffer[off++] = by6821B_;
|
|
573
|
+
buffer[off++] = byState_;
|
|
574
|
+
buffer[off++] = nBuffPos_;
|
|
575
|
+
buffer[off++] = nDataLen_;
|
|
576
|
+
|
|
577
|
+
// Reserved (to reach STATE_SIZE=36)
|
|
578
|
+
while (off < STATE_SIZE) {
|
|
579
|
+
buffer[off++] = 0;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return off;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
size_t MouseCard::deserialize(const uint8_t* buffer, size_t size) {
|
|
586
|
+
if (size < STATE_SIZE) return 0;
|
|
587
|
+
|
|
588
|
+
size_t off = 0;
|
|
589
|
+
|
|
590
|
+
// PIA state
|
|
591
|
+
ddra_ = buffer[off++];
|
|
592
|
+
ddrb_ = buffer[off++];
|
|
593
|
+
ora_ = buffer[off++];
|
|
594
|
+
orb_ = buffer[off++];
|
|
595
|
+
ira_ = buffer[off++];
|
|
596
|
+
irb_ = buffer[off++];
|
|
597
|
+
cra_ = buffer[off++];
|
|
598
|
+
crb_ = buffer[off++];
|
|
599
|
+
|
|
600
|
+
// Mouse position
|
|
601
|
+
mouseX_ = static_cast<int16_t>(buffer[off] | (buffer[off + 1] << 8));
|
|
602
|
+
off += 2;
|
|
603
|
+
mouseY_ = static_cast<int16_t>(buffer[off] | (buffer[off + 1] << 8));
|
|
604
|
+
off += 2;
|
|
605
|
+
|
|
606
|
+
// Clamp bounds
|
|
607
|
+
clampMinX_ = static_cast<int16_t>(buffer[off] | (buffer[off + 1] << 8));
|
|
608
|
+
off += 2;
|
|
609
|
+
clampMaxX_ = static_cast<int16_t>(buffer[off] | (buffer[off + 1] << 8));
|
|
610
|
+
off += 2;
|
|
611
|
+
clampMinY_ = static_cast<int16_t>(buffer[off] | (buffer[off + 1] << 8));
|
|
612
|
+
off += 2;
|
|
613
|
+
clampMaxY_ = static_cast<int16_t>(buffer[off] | (buffer[off + 1] << 8));
|
|
614
|
+
off += 2;
|
|
615
|
+
|
|
616
|
+
// Flags
|
|
617
|
+
uint8_t flags1 = buffer[off++];
|
|
618
|
+
mouseButton_ = (flags1 & 1) != 0;
|
|
619
|
+
lastButton_ = (flags1 & 2) != 0;
|
|
620
|
+
moved_ = (flags1 & 4) != 0;
|
|
621
|
+
buttonChanged_ = (flags1 & 8) != 0;
|
|
622
|
+
|
|
623
|
+
uint8_t flags2 = buffer[off++];
|
|
624
|
+
irqActive_ = (flags2 & 1) != 0;
|
|
625
|
+
vblInterruptPending_ = (flags2 & 2) != 0;
|
|
626
|
+
moveInterruptPending_ = (flags2 & 4) != 0;
|
|
627
|
+
buttonInterruptPending_ = (flags2 & 8) != 0;
|
|
628
|
+
|
|
629
|
+
lastCommand_ = buffer[off++];
|
|
630
|
+
mode_ = buffer[off++];
|
|
631
|
+
|
|
632
|
+
// Slot number
|
|
633
|
+
slotNum_ = buffer[off++];
|
|
634
|
+
|
|
635
|
+
// VBL tracking
|
|
636
|
+
wasInVBL_ = buffer[off++] != 0;
|
|
637
|
+
|
|
638
|
+
// Protocol state
|
|
639
|
+
by6821B_ = buffer[off++];
|
|
640
|
+
byState_ = buffer[off++];
|
|
641
|
+
nBuffPos_ = buffer[off++];
|
|
642
|
+
nDataLen_ = buffer[off++];
|
|
643
|
+
|
|
644
|
+
// Restore snapshot from current position
|
|
645
|
+
snapX_ = mouseX_;
|
|
646
|
+
snapY_ = mouseY_;
|
|
647
|
+
|
|
648
|
+
// Skip reserved
|
|
649
|
+
off = STATE_SIZE;
|
|
650
|
+
|
|
651
|
+
return off;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
} // namespace a2e
|