c64bridge 0.7.1 โ†’ 0.7.3

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.
@@ -0,0 +1,85 @@
1
+ # VICE Binary Monitor vs Ultimate 64 REST API
2
+
3
+ This document compares the [VICE Binary Monitor protocol](https://vice-emu.sourceforge.io/vice_13.html) of VICE 3.9 and the [Ultimate 64 REST API](https://1541u-documentation.readthedocs.io/en/latest/api/api_calls.html) using Ultimate 64 firmware 3.12a.
4
+
5
+ Each row shows how to invoke the feature through either interface and highlights functional gaps.
6
+
7
+ Legend: ๐ŸŸข green light (full support or best option), ๐ŸŸก amber light (partial or indirect support), ๐Ÿ”ด red light (not available here). Indicators appear at the start of each platform cell.
8
+
9
+ ## Memory and CPU State
10
+
11
+ | Capability | VICE Binary Monitor | Ultimate REST API | Notes |
12
+ | --- | --- | --- | --- |
13
+ | Memory read | ๐ŸŸข `0x01` Memory Get โ€” body `[sidefx,start_lo,start_hi,end_lo,end_hi,memspace,bank_lo,bank_hi]`; response `0x01` with length and data block. | ๐ŸŸก `GET /v1/machine:readmem?address=$ADDR&length=$LEN` (DMA map, default length 256). | Binary monitor supports memspaces and banks; REST access is limited to the flattened DMA-visible map and must not wrap past `$FFFF`. |
14
+ | Memory write | ๐ŸŸข `0x02` Memory Set โ€” request extends Memory Get body with the payload bytes for `[start,end]`. | ๐ŸŸก `PUT /v1/machine:writemem?address=$ADDR&data=...` or `POST /v1/machine:writemem` with binary attachment. | Monitor enforces payload length match and offers side-effect control; REST writes up to 128 bytes per call using the current DMA mapping. |
15
+ | Register snapshot | ๐ŸŸข `0x31` Registers Get โ€” body `[memspace]`; response lists `(size,id,value_lo,value_hi)` tuples. | ๐Ÿ”ด Not available (except `GET /v1/machine:debugreg` for `$D7FF`). | REST lacks general-purpose register visibility; only the Ultimate 64 debug register is exposed. |
16
+ | Register update | ๐ŸŸข `0x32` Registers Set โ€” `[memspace,count,{size,id,value_lo,value_hi,...}]`; response echoes `0x31`. | ๐Ÿ”ด Not available. | Direct CPU register writes require the monitor. |
17
+ | Banks enumeration | ๐ŸŸข `0x82` Banks Available โ€” lists bank IDs and names for `e_comp_space`. | ๐Ÿ”ด Not available. | REST cannot query cartridge banks; the monitor is needed for bank-aware tools. |
18
+ | Register catalog | ๐ŸŸข `0x83` Registers Available โ€” reports register IDs, bit widths, and names. | ๐Ÿ”ด Not available. | REST offers no equivalent metadata. |
19
+ | VICE info | ๐ŸŸก `0x85` VICE Info โ€” returns `VERSION_RC_NUMBER` and optional revision bytes. | ๐ŸŸข `GET /v1/version`, `GET /v1/info`. | REST delivers richer device metadata (product, firmware, FPGA); monitor only returns emulator build numbers. |
20
+ | Ping | ๐ŸŸข `0x81` Ping โ€” empty request/response. | ๐ŸŸข `GET /v1/version` (lightweight health check). | Monitor ping also verifies API negotiation (error `0x82` on bad version). |
21
+
22
+ ## Breakpoints, Conditions, and Execution Flow
23
+
24
+ | Capability | VICE Binary Monitor | Ultimate REST API | Notes |
25
+ | --- | --- | --- | --- |
26
+ | Create checkpoint | ๐ŸŸข `0x12` Checkpoint Set โ€” `[start,end,stop,enabled,op_mask,temporary,(optional)memspace]`; response `0x11`. | ๐Ÿ”ด Not available. | Only the monitor exposes code/data breakpoints. |
27
+ | Query checkpoint | ๐ŸŸข `0x11` Checkpoint Get โ€” `[checknum]`; response `0x11`. | ๐Ÿ”ด Not available. | REST has no breakpoint introspection. |
28
+ | Delete checkpoint | ๐ŸŸข `0x13` Checkpoint Delete โ€” `[checknum]`. | ๐Ÿ”ด Not available. | โ€” |
29
+ | Toggle checkpoint | ๐ŸŸข `0x15` Checkpoint Toggle โ€” `[checknum,enable]`. | ๐Ÿ”ด Not available. | โ€” |
30
+ | List checkpoints | ๐ŸŸข `0x14` Checkpoint List โ€” emits one `0x11` per entry then `0x14` with total count. | ๐Ÿ”ด Not available. | โ€” |
31
+ | Conditional breakpoint | ๐ŸŸข `0x22` Condition Set โ€” `[checknum,len,expr_bytes]`. | ๐Ÿ”ด Not available. | Expressions mirror CLI monitor syntax. |
32
+ | Step/advance | ๐ŸŸข `0x71` Advance Instructions โ€” `[step_over,count_lo,count_hi]`. | ๐Ÿ”ด Not available. | REST cannot single-step; use pause/resume only. |
33
+ | Execute until return | ๐ŸŸข `0x73` Execute Until Return. | ๐Ÿ”ด Not available. | โ€” |
34
+ | Keyboard feed | ๐ŸŸข `0x72` Keyboard Feed (API header must be `0x02`). | ๐Ÿ”ด Not available. | Useful for scripted monitor input; REST offers no keyboard injection. |
35
+ | Jam/stop/resume events | ๐ŸŸข Async responses `0x61/0x62/0x63` with request ID `0xffffffff`. | ๐Ÿ”ด Not available. | REST lacks push notifications; clients must poll status. |
36
+
37
+ ## Machine Lifecycle
38
+
39
+ | Capability | VICE Binary Monitor | Ultimate REST API | Notes |
40
+ | --- | --- | --- | --- |
41
+ | Exit monitor | ๐ŸŸข `0xAA` Exit โ€” releases control back to emulator loop. | ๐ŸŸก Not required. | REST calls run out-of-band and do not halt the CPU by default. |
42
+ | Quit emulator/device | ๐ŸŸก `0xBB` Quit โ€” invokes `mon_quit()`. | ๐ŸŸข `PUT /v1/machine:poweroff` (powers off), `PUT /v1/machine:reboot`. | Monitor quit terminates VICE; REST poweroff stops the Ultimate hardware. |
43
+ | Reset | ๐ŸŸข `0xCC` Reset โ€” `[reset_type]` (0 soft, 1 hard, 8โ€“11 drive IDs). | ๐ŸŸข `PUT /v1/machine:reset` (system), `PUT /v1/drives/{drive}:reset` (per-drive). | Monitor supports fine-grained drive resets via type codes; REST splits drive resets per endpoint. |
44
+ | Pause/resume | ๐ŸŸก Resume controlled by exiting monitor; stop state signaled with `0x62/0x63`. | ๐ŸŸข `PUT /v1/machine:pause` / `PUT /v1/machine:resume`. | REST offers explicit pause control without entering a monitor. |
45
+ | Autostart/run program | ๐ŸŸก `0xDD` Autostart โ€” `[run_flag,file_index,name_len,name_bytes]`. | ๐ŸŸข `PUT/POST /v1/runners:run_prg` (DMA load + run) or `...:load_prg` (load only). | Monitor autostart exits the monitor after queuing the autostart; REST runners reset the machine automatically. |
46
+
47
+ ## Snapshots, Display, and Peripherals
48
+
49
+ | Capability | VICE Binary Monitor | Ultimate REST API | Notes |
50
+ | --- | --- | --- | --- |
51
+ | Save snapshot | ๐ŸŸข `0x41` Dump Snapshot โ€” `[save_roms,save_disks,name_len,name_bytes]`. | ๐Ÿ”ด Not available. | REST has no snapshot API. |
52
+ | Load snapshot | ๐ŸŸข `0x42` Undump Snapshot โ€” `[name_len,name_bytes]`; response returns PC. | ๐Ÿ”ด Not available. | โ€” |
53
+ | Display capture | ๐ŸŸข `0x84` Display Get (API `0x02`) โ€” `[alt_canvas,mode]`; response includes geometry metadata and pixel buffer. | ๐ŸŸก `PUT /v1/streams/video:start?ip=host[:port]` for live UDP streaming (Ultimate 64 only). | Monitor provides immediate framebuffer dumps; REST streams continuous video but no single-frame capture. |
54
+ | Palette capture | ๐ŸŸข `0x91` Palette Get โ€” `[alt_canvas]`; returns RGB triples. | ๐Ÿ”ด Not available. | REST lacks palette inspection. |
55
+ | Joyport output | ๐ŸŸข `0xA2` Joyport Set โ€” `[port_lo,port_hi,value_lo,value_hi]`. | ๐Ÿ”ด Not available. | REST cannot toggle joystick lines. |
56
+ | Userport output | ๐ŸŸข `0xB2` Userport Set โ€” `[value_lo,value_hi]`. | ๐Ÿ”ด Not available. | โ€” |
57
+ | Keyboard injection | ๐ŸŸข `0x72` Keyboard Feed. | ๐Ÿ”ด Not available. | โ€” |
58
+
59
+ ## Configuration and Resources
60
+
61
+ | Capability | VICE Binary Monitor | Ultimate REST API | Notes |
62
+ | --- | --- | --- | --- |
63
+ | Resource read | ๐ŸŸก `0x51` Resource Get โ€” `[name_len,name_bytes]`; response indicates type and value. | ๐ŸŸก `GET /v1/configs`, `GET /v1/configs/{category}`, `GET /v1/configs/{category}/{item}`. | Monitor accesses emulator resource system; REST targets Ultimate firmware settings. |
64
+ | Resource write | ๐ŸŸก `0x52` Resource Set โ€” `[type,name_len,name_bytes,value_len,value_bytes]`. | ๐ŸŸก `PUT /v1/configs/{...}?value=...`, `POST /v1/configs` (batch). | Resource namespaces differ: monitor affects VICE runtime options, REST changes Ultimate firmware configuration. |
65
+ | Batch configuration | ๐Ÿ”ด Not available. | ๐ŸŸข `POST /v1/configs` (nested JSON). | โ€” |
66
+ | Load/save config to flash | ๐Ÿ”ด Not available. | ๐ŸŸข `PUT /v1/configs:load_from_flash`, `PUT /v1/configs:save_to_flash`. | Flash persistence is firmware-specific. |
67
+ | Factory reset config | ๐Ÿ”ด Not available. | ๐ŸŸข `PUT /v1/configs:reset_to_default`. | โ€” |
68
+
69
+ ## Media, Drives, and Audio (REST Exclusive)
70
+
71
+ | Capability | VICE Binary Monitor | Ultimate REST API | Notes |
72
+ | --- | --- | --- | --- |
73
+ | SID playback | ๐Ÿ”ด Not available. | ๐ŸŸข `PUT/POST /v1/runners:sidplay`. | Hardware audio runners are outside the scope of the monitor. |
74
+ | MOD playback | ๐Ÿ”ด Not available. | ๐ŸŸข `PUT/POST /v1/runners:modplay`. | โ€” |
75
+ | Cartridge/PRG DMA load | ๐ŸŸก Autostart (`0xDD`) accepts filenames from the host FS. | ๐ŸŸข `PUT/POST /v1/runners:run_crt`, `...:run_prg`, `...:load_prg`. | Monitor runs within VICE and uses its virtual FS; REST accesses the Ultimate storage or uploaded payloads. |
76
+ | Drive management | ๐Ÿ”ด Not available (except checkpointing on drive CPU via memspace). | ๐ŸŸข `/v1/drives` (info), `/v1/drives/{drive}:mount`, `:remove`, `:on`, `:off`, `:set_mode`, `:load_rom`. | REST controls physical drive emulation directly. |
77
+ | File image creation | ๐Ÿ”ด Not available. | ๐ŸŸข `PUT /v1/files/{path}:create_d64/d71/d81/dnp`. | Monitor has no disk image authoring commands. |
78
+ | Data streams | ๐Ÿ”ด Not available. | ๐ŸŸข `PUT /v1/streams/<stream>:start` / `PUT /v1/streams/<stream>:stop` (stream = `video`, `audio`, `debug`). | REST can export live video/audio/debug streams. |
79
+
80
+ ## Observations
81
+
82
+ - The VICE Binary Monitor is the only interface that exposes low-level debugger primitives (breakpoints, register manipulation, single-stepping, framebuffer snapshots, palette dumps, joystick/userport control).
83
+ - The Ultimate REST API focuses on machine orchestration and firmware-level services (DMA loading, media playback, drive management, persistent configuration, and streaming), none of which are available through the binary monitor.
84
+ - Memory access and reset operations overlap; however, the monitor supports banked address spaces and fine-grained CPU control, while the REST DMA endpoints operate on the flattened Ultimate memory view and offer coarse pause/resume semantics.
85
+ - Integrations needing both precise debugging and system management typically combine the monitor for CPU/memory inspection with REST calls for device control and file management.
@@ -0,0 +1,301 @@
1
+ # VICE Binary Monitor Protocol Specification
2
+
3
+ This document combines the [official documentation](https://vice-emu.sourceforge.io/vice_13.html) with research of the [monitor_binary.c](https://raw.githubusercontent.com/libretro/vice-libretro/refs/heads/master/vice/src/monitor/monitor_binary.c) source code for VICE 3.9 (Git ID
4
+ `a072441`).
5
+
6
+ ## 1. Overview
7
+
8
+ The Vice Binary Monitor exposes the built-in VICE monitor over a dedicated network socket (enable with `-binarymonitor`, configure the bind address with `-binarymonitoraddress` or the `BinaryMonitorServerAddress` resource).
9
+
10
+ Only one client may be connected at a time. When packets arrive the monitor traps execution (`monitor_startup_trap`), executes the requested operation, and resumes the emulated machine. The default bind target is `ip4://127.0.0.1:6502`.
11
+
12
+ All multi-byte scalar fields are encoded little endian on the wire. The monitor forwards most operations to the same helper routines used by the text monitor, so side effects, breakpoint semantics, and register layouts are identical to the CLI monitor.
13
+
14
+ ---
15
+
16
+ ## 2. Transport Format
17
+
18
+ ### 2.1 Command Packet
19
+
20
+ | Offset | Size | Field | Description |
21
+ |---------|------|--------|-------------|
22
+ | 0 | 1 | `0x02` | Start-of-text (STX) |
23
+ | 1 | 1 | API version | Client API version (`0x01` or `0x02`) |
24
+ | 2โ€“5 | 4 | Body length | Byte count of the command body |
25
+ | 6โ€“9 | 4 | Request ID | Caller-specified identifier echoed in responses |
26
+ | 10 | 1 | Command ID | See ยง5 |
27
+ | 11+ | N | Command body | Command payload |
28
+
29
+ The current implementation accepts headers tagged with API version `0x01` or `0x02`. Commands introduced in API 0x02 (`Keyboard Feed`, `Display Get`) require clients to transmit `0x02`; otherwise the monitor returns error `0x82`.
30
+
31
+ ### 2.2 Response Packet
32
+
33
+ | Offset | Size | Field | Description |
34
+ |---------|------|--------|-------------|
35
+ | 0 | 1 | `0x02` | Start-of-text (STX) |
36
+ | 1 | 1 | API version | Always `MON_BINARY_API_VERSION` (0x02) |
37
+ | 2โ€“5 | 4 | Body length | Byte count of the response body |
38
+ | 6 | 1 | Response type | Usually the command ID |
39
+ | 7 | 1 | Error code | See ยง2.3 |
40
+ | 8โ€“11 | 4 | Request ID | Mirrors the request; 0xffffffff for events |
41
+ | 12+ | N | Response body | Response payload (may be empty) |
42
+
43
+ ### 2.3 Error Codes
44
+
45
+ | Code | Meaning |
46
+ |------|---------|
47
+ | 0x00 | Success |
48
+ | 0x01 | Object missing (e.g. unknown breakpoint or joystick port) |
49
+ | 0x02 | Invalid memspace |
50
+ | 0x80 | Command length mismatch |
51
+ | 0x81 | Invalid parameter |
52
+ | 0x82 | Unsupported API version |
53
+ | 0x83 | Unknown command |
54
+ | 0x8F | Command failed |
55
+
56
+ ---
57
+
58
+ ## 3. Addressing and Metadata
59
+
60
+ | Value | Memspace |
61
+ |-------|----------|
62
+ | 0 | `e_comp_space` (main computer CPU) |
63
+ | 1 | `e_disk8_space` |
64
+ | 2 | `e_disk9_space` |
65
+ | 3 | `e_disk10_space` |
66
+ | 4 | `e_disk11_space` |
67
+ | other | invalid (`memspace_to_uint8_t` exports 0xff) |
68
+
69
+ Banks are 16-bit values. Use `0x82 Banks Available` to enumerate valid bank numbers for the main computer CPU; on memspaces without banks the monitor ignores the supplied bank value.
70
+
71
+ Register lists omit entries flagged with `MON_REGISTER_IS_FLAGS`. Register values are truncated to 16 bits in the binary protocol even if the underlying register is wider; the `size` metadata tells the real width in bits.
72
+
73
+ ---
74
+
75
+ ## 4. Asynchronous Messages
76
+
77
+ Responses sent with request ID `0xffffffff` are unsolicited events:
78
+
79
+ - Monitor open: emits `0x31 Register Info` (memspace `e_comp_space`) followed by `0x62 Stopped` with the current PC.
80
+ - Monitor close: emits `0x63 Resumed` with the current PC.
81
+ - Checkpoint hits: `mon_breakpoint.c` emits `0x11 Checkpoint Info` with `hit = 1`.
82
+ - CPU JAM: `0x61 Jam` is sent, currently with an empty body (the PC is not transmitted because the handler passes length 0).
83
+ - Other responses (e.g. `Checkpoint List`) reuse the same response types but keep the original request ID.
84
+
85
+ ---
86
+
87
+ ## 5. Command Reference
88
+
89
+ ### Memory (0x01โ€“0x02)
90
+
91
+ #### 0x01 โ€“ Memory Get
92
+
93
+ - Request: `[0] sidefx (0 = peek, 1 = normal read), [1โ€“2] start address, [3โ€“4] end address, [5] memspace, [6โ€“7] bank`
94
+ - Response (`0x01`): `[0โ€“1] byte count (uint16), [2+] data block`
95
+ - Notes: Addresses are inclusive; the monitor validates memspace and bank (`0x02` or `0x81` on failure). During the transfer `sidefx` temporarily overrides the global `sidefx` flag.
96
+
97
+ #### 0x02 โ€“ Memory Set
98
+
99
+ - Request: `[0] sidefx (0 = poke, 1 = write with side effects), [1โ€“2] start address, [3โ€“4] end address, [5] memspace, [6โ€“7] bank, [8+] payload`
100
+ - Response (`0x02`): empty body
101
+ - Notes: Payload length must equal `(end - start + 1)` or the monitor returns `0x80`. Writes loop byte-by-byte through `mon_set_mem_val_ex`, masking the address to 16 bits.
102
+
103
+ ### Checkpoints and Conditions (0x11โ€“0x22)
104
+
105
+ #### 0x11 โ€“ Checkpoint Get
106
+
107
+ - Request: `[0โ€“3] checkpoint number`
108
+ - Response (`0x11`): checkpoint info (see ยง6)
109
+ - Notes: Unknown checkpoints return `0x01`.
110
+
111
+ #### 0x12 โ€“ Checkpoint Set
112
+
113
+ - Request: `[0โ€“1] start address, [2โ€“3] end address, [4] stop flag, [5] enabled flag, [6] memory-op mask, [7] temporary flag`, optional byte `[8]` selects the memspace
114
+ - Response (`0x11`): the newly created checkpoint
115
+ - Notes: The memory-op mask uses bits `e_load`=1, `e_store`=2, and `e_exec`=4. If the body is at least 9 bytes the optional memspace overrides the default `e_comp_space`. The monitor disables the checkpoint if the enabled flag is zero.
116
+
117
+ #### 0x13 โ€“ Checkpoint Delete
118
+
119
+ - Request: `[0โ€“3] checkpoint number`
120
+ - Response (`0x13`): empty
121
+ - Notes: Fails with `0x01` if the checkpoint does not exist.
122
+
123
+ #### 0x14 โ€“ Checkpoint List
124
+
125
+ - Request: empty body
126
+ - Response: one or more `0x11` messages (same request ID) for each checkpoint, followed by a `0x14` containing `[0โ€“3] total checkpoint count`
127
+ - Notes: The per-checkpoint responses set `hit = 0`.
128
+
129
+ #### 0x15 โ€“ Checkpoint Toggle
130
+
131
+ - Request: `[0โ€“3] checkpoint number, [4] enable flag`
132
+ - Response (`0x15`): empty
133
+ - Notes: Returns `0x01` when the checkpoint is missing.
134
+
135
+ #### 0x22 โ€“ Condition Set
136
+
137
+ - Request: `[0โ€“3] checkpoint number, [4] expression length, [5+] expression text`
138
+ - Response (`0x22`): empty
139
+ - Notes: The monitor appends a NUL byte after the provided text and executes `cond <id> if (<expr>)`. Expression syntax matches the CLI monitor. Failure to parse or execute yields `0x8F`.
140
+
141
+ ### Register Access (0x31โ€“0x32)
142
+
143
+ #### 0x31 โ€“ Registers Get
144
+
145
+ - Request: `[0] memspace`
146
+ - Response (`0x31`): `[0โ€“1] register count`, followed by entries `[size,id,value_lo,value_hi]`
147
+ - Notes: Only registers without `MON_REGISTER_IS_FLAGS` are returned. `size` is always 3 and values carry the low 16 bits of the hardware register.
148
+
149
+ #### 0x32 โ€“ Registers Set
150
+
151
+ - Request: `[0] memspace, [1โ€“2] count, [3+] entries` where each entry begins `[size,id,value_lo,value_hi,โ€ฆ]`
152
+ - Response (`0x31`): refreshed register list for the same memspace
153
+ - Notes: The monitor validates each register with `mon_register_valid`. Only the first two value bytes are used; extra bytes (if any) are skipped.
154
+
155
+ ### Snapshots (0x41โ€“0x42)
156
+
157
+ #### 0x41 โ€“ Dump Snapshot
158
+
159
+ - Request: `[0] save ROMs flag, [1] save disks flag, [2] file name length, [3+] path`
160
+ - Response (`0x41`): empty
161
+ - Notes: The monitor inserts a trailing NUL before calling `mon_write_snapshot`. Failure yields `0x8F`.
162
+
163
+ #### 0x42 โ€“ Undump Snapshot
164
+
165
+ - Request: `[0] file name length, [1+] path`
166
+ - Response (`0x42`): `[0โ€“1] current PC`
167
+ - Notes: On success the monitor reloads the snapshot via `mon_read_snapshot`, updates the dot address, and reports the new program counter.
168
+
169
+ ### Resources (0x51โ€“0x52)
170
+
171
+ #### 0x51 โ€“ Resource Get
172
+
173
+ - Request: `[0] name length, [1+] name`
174
+ - Response (`0x51`): string resources โ†’ `[0]=0, [1] value length, [2+] bytes`; integer resources โ†’ `[0]=1, [1]=4, [2โ€“5] value`
175
+ - Notes: Name length must be โ‰ฅ1 and โ‰ค255; strings are limited to 255 bytes. Unknown resources return `0x01`.
176
+
177
+ #### 0x52 โ€“ Resource Set
178
+
179
+ - Request: `[0] value type (0=string,1=int), [1] name length, [2+] name, [N] value length, [N+] value`
180
+ - Response (`0x52`): empty
181
+ - Notes: Strings are NUL-terminated by the monitor before dispatch. Integer payloads may be 1, 2, or 4 bytes; other sizes trigger `0x80`. Type mismatches yield `0x81`.
182
+
183
+ ### Execution Control (0x71โ€“0x73)
184
+
185
+ #### 0x71 โ€“ Advance Instructions
186
+
187
+ - Request: `[0] step-over flag, [1โ€“2] instruction count`
188
+ - Response (`0x71`): empty
189
+ - Notes: When the flag is non-zero the monitor uses `mon_instructions_next`, otherwise `mon_instructions_step`.
190
+
191
+ #### 0x72 โ€“ Keyboard Feed
192
+
193
+ - Request: `[0] length, [1+] PETSCII text`
194
+ - Response (`0x72`): empty
195
+ - Notes: Requires command header API version `0x02`; otherwise the monitor returns `0x82`. The server appends a NUL before calling `kbdbuf_feed`.
196
+
197
+ #### 0x73 โ€“ Execute Until Return
198
+
199
+ - Request: empty
200
+ - Response (`0x73`): empty
201
+ - Notes: Invokes `mon_instruction_return()`.
202
+
203
+ ### Introspection (0x81โ€“0x85)
204
+
205
+ #### 0x81 โ€“ Ping
206
+
207
+ - Request: empty
208
+ - Response (`0x81`): empty
209
+
210
+ #### 0x82 โ€“ Banks Available
211
+
212
+ - Request: empty
213
+ - Response (`0x82`): `[0โ€“1] count, [2+] entries` where each entry is `[size,bank_lo,bank_hi,name_len,name]`
214
+ - Notes: Data is collected from `mon_interfaces[e_comp_space]`. Each size equals `3 + name_len`.
215
+
216
+ #### 0x83 โ€“ Registers Available
217
+
218
+ - Request: `[0] memspace`
219
+ - Response (`0x83`): `[0โ€“1] count, [2+] entries` where each entry is `[size,id,bits,name_len,name]`
220
+ - Notes: Size equals `3 + name_len`. The `bits` field is the register width reported by `mon_reg_list_t::size`. Entries flagged with `MON_REGISTER_IS_FLAGS` are skipped.
221
+
222
+ #### 0x84 โ€“ Display Get
223
+
224
+ - Request: `[0] use alternate canvas flag, [1] format (0 = indexed 8-bit)`
225
+ - Response (`0x84`): `[0โ€“3] info length (currently 13), [4โ€“5] debug width, [6โ€“7] debug height, [8โ€“9] debug X offset, [10โ€“11] debug Y offset, [12โ€“13] inner width, [14โ€“15] inner height, [16] bits per pixel (8), [17โ€“20] buffer length, [21+] pixel data`
226
+ - Notes: Requires API version `0x02`. For the C128, setting the flag selects `machine_video_canvas_get(1)` (VDC); other machines ignore the flag. The buffer contains `debug_width * debug_height` bytes. Areas outside the visible inner rectangle are zero-filled.
227
+
228
+ #### 0x85 โ€“ VICE Info
229
+
230
+ - Request: empty
231
+ - Response (`0x85`): `[0]=4, [1โ€“4]=VERSION_RC_NUMBER, [5]=4, [6โ€“9]=build revision (zero unless `USE_SVN_REVISION` is defined)`
232
+ - Notes: The first length covers the four RC number bytes (major, minor, build, patch).
233
+
234
+ ### Palette and I/O (0x91โ€“0xB2)
235
+
236
+ #### 0x91 โ€“ Palette Get
237
+
238
+ - Request: `[0] use alternate canvas flag`
239
+ - Response (`0x91`): `[0โ€“1] entry count, [2+] entries` where each entry is `[size, red, green, blue]`
240
+ - Notes: Shares the same canvas selection logic as `Display Get`. The `size` field is always 3.
241
+
242
+ #### 0xA2 โ€“ Joyport Set
243
+
244
+ - Request: `[0โ€“1] port number, [2โ€“3] value`
245
+ - Response (`0xA2`): empty
246
+ - Notes: Delegates to `mon_joyport_set_output`. Invalid port โ†’ `0x01`; illegal value โ†’ `0x81`; other failures โ†’ `0x8F`.
247
+
248
+ #### 0xB2 โ€“ Userport Set
249
+
250
+ - Request: `[0โ€“1] value`
251
+ - Response (`0xB2`): empty
252
+ - Notes: Delegates to `mon_userport_set_output`. Illegal values return `0x81`; other errors return `0x8F`.
253
+
254
+ ### Exit, Reset, Autostart (0xAAโ€“0xDD)
255
+
256
+ #### 0xAA โ€“ Exit
257
+
258
+ - Request: empty
259
+ - Response (`0xAA`): empty
260
+ - Notes: Sets `exit_mon = 1`, returning execution to the emulator while keeping VICE running.
261
+
262
+ #### 0xBB โ€“ Quit
263
+
264
+ - Request: empty
265
+ - Response (`0xBB`): empty
266
+ - Notes: Calls `mon_quit()` to terminate VICE.
267
+
268
+ #### 0xCC โ€“ Reset
269
+
270
+ - Request: `[0] reset type`
271
+ - Response (`0xCC`): empty
272
+ - Notes: Value is passed straight to `mon_reset_machine`. Common values are 0 (soft), 1 (power), 8โ€“11 (drive resets).
273
+
274
+ #### 0xDD โ€“ Autostart
275
+
276
+ - Request: `[0] run flag (0 = load only, 1 = run), [1โ€“2] file index, [3] file name length, [4+] path`
277
+ - Response (`0xDD`): empty
278
+ - Notes: The monitor NUL-terminates the name and calls `mon_autostart`. On success the monitor exits so the autostart can continue; failures return `0x8F`.
279
+
280
+ ---
281
+
282
+ ## 6. Response Types
283
+
284
+ | ID | Type | Description | Body |
285
+ |----|------|-------------|------|
286
+ | 0x00 | Invalid | Error container | usually empty |
287
+ | 0x11 | Checkpoint Info | Checkpoint state | `[0โ€“3] number, [4] hit, [5โ€“6] start, [7โ€“8] end, [9] stop, [10] enabled, [11] op mask, [12] temporary, [13โ€“16] hit count, [17โ€“20] ignore count, [21] has condition, [22] memspace` |
288
+ | 0x31 | Register Info | Register snapshot | `[0โ€“1] count` followed by entries `(size,id,value_lo,value_hi)` |
289
+ | 0x61 | Jam | CPU jammed | empty (PC is not transmitted in the current implementation) |
290
+ | 0x62 | Stopped | Execution halted | `[0โ€“1] current PC` |
291
+ | 0x63 | Resumed | Execution resumed | `[0โ€“1] current PC` |
292
+
293
+ ---
294
+
295
+ ## 7. Example Projects
296
+
297
+ - **C64Studio** โ€“ IDE with VICE binary monitor integration.
298
+ - **vice-bridge-net** โ€“ .NET binary bridge.
299
+ - **IceBroLite** โ€“ GUI debugger.
300
+ - **VS65 Debugger** โ€“ VS Code CC65 integration.
301
+ - **VS64** โ€“ C64 build/debug/run extension.
package/mcp.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c64bridge",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Stdio-based Model Context Protocol (MCP) server that bridges Commodore 64 Ultimate hardware with AI agents.",
5
5
  "entry": "dist/index.js",
6
6
  "type": "stdio",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c64bridge",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Local MCP server for controlling a Commodore 64 via Ultimate 64 REST API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,12 +26,84 @@ const run = (cmd) => execSync(cmd, { encoding: 'utf8' }).trim();
26
26
  const nowDate = new Date().toISOString().slice(0, 10);
27
27
  const root = process.cwd();
28
28
 
29
- function getLastTag() {
29
+ function normaliseVersion(value) {
30
+ return value.startsWith('v') ? value.slice(1) : value;
31
+ }
32
+
33
+ function parseSemver(value) {
34
+ const cleaned = normaliseVersion(value);
35
+ const parts = cleaned.split('.').map((n) => Number.parseInt(n, 10));
36
+ if (parts.length !== 3 || parts.some(Number.isNaN)) {
37
+ return null;
38
+ }
39
+ return { tag: value, cleaned, parts };
40
+ }
41
+
42
+ function compareParts(a, b) {
43
+ for (let i = 0; i < 3; i += 1) {
44
+ if (a.parts[i] !== b.parts[i]) {
45
+ return a.parts[i] - b.parts[i];
46
+ }
47
+ }
48
+ return 0;
49
+ }
50
+
51
+ function getLastTag(skipVersion = '') {
52
+ let raw;
30
53
  try {
31
- return run('git describe --tags --abbrev=0');
54
+ raw = run('git tag --sort=version:refname');
32
55
  } catch {
33
56
  return '';
34
57
  }
58
+
59
+ const entries = raw
60
+ .split('\n')
61
+ .map((line) => line.trim())
62
+ .filter(Boolean)
63
+ .map((tag) => parseSemver(tag))
64
+ .filter((info) => info !== null);
65
+
66
+ if (entries.length === 0) {
67
+ return '';
68
+ }
69
+
70
+ const grouped = new Map();
71
+ for (const entry of entries) {
72
+ if (!grouped.has(entry.cleaned)) {
73
+ grouped.set(entry.cleaned, []);
74
+ }
75
+ grouped.get(entry.cleaned).push(entry);
76
+ }
77
+
78
+ const ordered = Array.from(grouped.values())
79
+ .map((group) => ({ cleaned: group[0].cleaned, parts: group[0].parts, group }))
80
+ .sort((a, b) => compareParts(a, b));
81
+
82
+ if (ordered.length === 0) {
83
+ return '';
84
+ }
85
+
86
+ if (!skipVersion) {
87
+ const latest = ordered[ordered.length - 1];
88
+ return (latest.group.find((entry) => !entry.tag.startsWith('v')) || latest.group[latest.group.length - 1]).tag;
89
+ }
90
+
91
+ const skipCleaned = normaliseVersion(skipVersion);
92
+ let previous = null;
93
+ for (const entry of ordered) {
94
+ if (entry.cleaned === skipCleaned) {
95
+ break;
96
+ }
97
+ previous = entry;
98
+ }
99
+
100
+ if (previous) {
101
+ return (previous.group.find((entry) => !entry.tag.startsWith('v')) || previous.group[previous.group.length - 1]).tag;
102
+ }
103
+
104
+ // If skip version was not found among tags, fall back to latest tag.
105
+ const fallback = ordered[ordered.length - 1];
106
+ return (fallback.group.find((entry) => !entry.tag.startsWith('v')) || fallback.group[fallback.group.length - 1]).tag;
35
107
  }
36
108
 
37
109
  function getCommits(range) {
@@ -90,7 +162,7 @@ function renderSection(version, date, groups) {
90
162
 
91
163
  async function main() {
92
164
  const version = process.argv[2] || '';
93
- const lastTag = getLastTag();
165
+ const lastTag = getLastTag(version);
94
166
  const range = lastTag ? `${lastTag}..HEAD` : '';
95
167
  const rawCommits = getCommits(range)
96
168
  .filter((c) => c.subject && !/^Merge\s/.test(c.subject));