@henols/vice-mcp 0.2.1 → 0.2.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.
- package/README.md +4 -3
- package/THIRD-PARTY-NOTICES.md +423 -25
- package/{r2000-acme-ident.ts → anno-acme-ident.ts} +13 -13
- package/anno-bank.ts +171 -0
- package/anno-cli.ts +3040 -0
- package/{r2000-confidence.ts → anno-confidence.ts} +22 -22
- package/anno-coverage.ts +2465 -0
- package/anno-derive.ts +590 -0
- package/anno-details.ts +169 -0
- package/anno-enum-gen.ts +919 -0
- package/anno-export-asm.ts +2396 -0
- package/anno-graphics.ts +338 -0
- package/anno-hazard-report.ts +1367 -0
- package/anno-import.ts +495 -0
- package/anno-index.ts +150 -0
- package/anno-join.ts +480 -0
- package/{r2000-memmap-render.ts → anno-memmap-render.ts} +236 -95
- package/anno-provenance-ledger.ts +472 -0
- package/{r2000-regbits-gen.ts → anno-regbits-gen.ts} +20 -15
- package/{r2000-regbits.json → anno-regbits.json} +2 -2
- package/anno-register.ts +399 -0
- package/anno-store-export.ts +661 -0
- package/anno-store.ts +4002 -0
- package/anno-symbols.ts +266 -0
- package/anno-tools.ts +3264 -0
- package/anno-types.ts +1909 -0
- package/backend-detect.mts +124 -312
- package/block-class.ts +201 -0
- package/build.ts +4 -2
- package/capture-predicate.ts +597 -0
- package/channel-lock.ts +349 -0
- package/disasm-decoder.ts +14 -14
- package/disasm-opcodes.ts +4 -4
- package/disasm-renderer.ts +2 -2
- package/evid-ingest.ts +217 -0
- package/evid-reconcile.ts +316 -0
- package/host-tool-client.ts +430 -0
- package/hostpath.ts +1 -1
- package/incident-record.ts +23 -12
- package/install-resources.ts +30 -14
- package/memmap-lookup.ts +285 -0
- package/package.json +48 -23
- package/prg-image.ts +118 -0
- package/repo-root.ts +107 -8
- package/resources/backend-detect.mjs +98 -236
- package/resources/broker-control.mjs +189 -16
- package/resources/broker-epoch.mjs +1 -1
- package/resources/broker-kill.mjs +8 -2
- package/resources/broker-launch.mjs +373 -214
- package/resources/broker-state.mjs +64 -18
- package/resources/container-guard.mjs +1 -1
- package/resources/ghidra-project.mjs +790 -0
- package/resources/host-tool.mjs +2561 -0
- package/resources/vice-broker.mjs +330 -184
- package/resources/vice-launcher.sh +130 -12
- package/stock-address.ts +6 -6
- package/stock-cia.ts +2 -2
- package/stock-condition.ts +8 -8
- package/stock-connect.ts +10 -6
- package/stock-derived.ts +29 -37
- package/stock-diagnose.ts +200 -36
- package/stock-dispatch.ts +200 -68
- package/stock-execution.ts +5 -3
- package/stock-handler.ts +1 -1
- package/stock-input.ts +9 -9
- package/stock-machine.ts +17 -6
- package/stock-paths.ts +18 -14
- package/stock-petscii.ts +1 -1
- package/stock-protocol.ts +17 -12
- package/stock-recycle.ts +83 -2
- package/stock-registers.ts +54 -29
- package/stock-reproducible-run.ts +811 -0
- package/stock-run-until.ts +100 -1
- package/stock-sprites.ts +3 -3
- package/stock-symbols.ts +13 -13
- package/stock-timing.ts +2 -2
- package/stock-vicii.ts +1 -1
- package/stop-oracle.ts +167 -0
- package/text-capability-probe.ts +660 -0
- package/text-connect.ts +157 -0
- package/text-protocol.ts +810 -0
- package/text-tools.ts +778 -0
- package/textmon-backtrace.ts +385 -0
- package/textmon-cpuhistory.ts +335 -0
- package/textmon-memmap.ts +494 -0
- package/textmon-profile.ts +458 -0
- package/textmon-registers.ts +748 -0
- package/tools-manifest.stock.json +864 -3
- package/version.ts +1 -1
- package/vice-broker-client.ts +189 -42
- package/vice-errors.ts +268 -0
- package/vice-proxy.ts +392 -2175
- package/vsf-slice.ts +640 -0
- package/capability-registry.ts +0 -388
- package/r2000-cli.ts +0 -1103
- package/r2000-d64.ts +0 -310
- package/r2000-enum-gen.ts +0 -574
- package/r2000-launch.ts +0 -357
- package/r2000-mcp-client.ts +0 -596
- package/r2000-project.ts +0 -190
- package/r2000-symbols.ts +0 -388
- package/r2000-tools.ts +0 -914
- package/r2000-verify.ts +0 -184
- package/refresh-manifest.ts +0 -124
- package/tools-manifest.json +0 -1223
- package/vice-probe.ts +0 -278
- package/vice-sync.ts +0 -336
- package/vice.ts +0 -772
package/anno-bank.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// anno-bank.ts
|
|
3
|
+
//
|
|
4
|
+
// Phase 37, plan 37-06 (AUTO-04/AUTO-05): the processor-port bit decode, the
|
|
5
|
+
// per-range banked-region resolution, and the region-to-map-entry
|
|
6
|
+
// consistency table `anno-join.ts`'s candidate-constraint step calls BEFORE
|
|
7
|
+
// `selectMemmapEntry()` ever runs. This is the phase's highest-risk
|
|
8
|
+
// requirement pair -- both are recorded UNVALIDATED, not narrowed, and a
|
|
9
|
+
// measured survey found no prior art to copy (SVD-Loader, radare2's
|
|
10
|
+
// device-description import, IDA's device definitions all annotate
|
|
11
|
+
// unconditionally, because their domain has no path-dependent address
|
|
12
|
+
// meaning). Resolve bank state BEFORE the address; decline with a reason
|
|
13
|
+
// where the program itself does not determine one.
|
|
14
|
+
//
|
|
15
|
+
// THIS MODULE NEVER NAMES THE PERSISTENCE DEPENDENCY, NEVER OPENS THE STORE,
|
|
16
|
+
// and NEVER IMPORTS `hostpath.ts`/`containerpath.ts` -- the same posture
|
|
17
|
+
// `memmap-lookup.ts` takes. It takes plain data (a raw `$01` value, a
|
|
18
|
+
// `MemmapEntry`) and returns plain data.
|
|
19
|
+
//
|
|
20
|
+
// WHAT THIS IS THE ONE AUTHORITATIVE PLACE FOR: D-37-21's bit arithmetic
|
|
21
|
+
// (`decodeBankState`), the not-applicable-outside-the-three-ranges rule
|
|
22
|
+
// (`resolveBankedRegion`), the address-is-bank-conditional-at-all membership
|
|
23
|
+
// test (`isBankConditionalAddress`), and the region-to-map-entry consistency
|
|
24
|
+
// table (`regionAdmitsEntry`) `anno-join.ts`'s candidate constraint uses.
|
|
25
|
+
//
|
|
26
|
+
// The REACHING-VALUES SET computation -- which recovered processor-port
|
|
27
|
+
// value(s) reach a given program point, over the recovered const-write facts
|
|
28
|
+
// and the stored cross-reference graph (D-37-24) -- lives in `anno-join.ts`
|
|
29
|
+
// itself, not here. This module only ever decodes a SINGLE already-resolved
|
|
30
|
+
// value; it has no notion of "which value(s) reach this address" and never
|
|
31
|
+
// will (that is the join's own responsibility, since it alone holds the
|
|
32
|
+
// store handle and the cross-reference graph).
|
|
33
|
+
//
|
|
34
|
+
// WHAT NOT TO DO:
|
|
35
|
+
// - Never derive "is this region io/basic/kernal/character-rom" from
|
|
36
|
+
// memmap.json's `desc` field by regex (37-RESEARCH.md Pitfall 2 /
|
|
37
|
+
// `BANK_CONDITIONAL_RANGES`'s own header comment in `memmap-lookup.ts`).
|
|
38
|
+
// `regionAdmitsEntry()` below matches against the STRUCTURED `section`
|
|
39
|
+
// field (plus one whole-word "RAM" label fallback, since no committed
|
|
40
|
+
// section names RAM specifically within any of the three ranges) --
|
|
41
|
+
// never `desc`.
|
|
42
|
+
// - Never default an unresolved region to RAM (the power-on state). The
|
|
43
|
+
// caller (`anno-join.ts`) declines instead; this module only ever
|
|
44
|
+
// returns a decoded/resolved answer or the explicit "not applicable"
|
|
45
|
+
// member -- it never invents a fallback of its own.
|
|
46
|
+
// - Never write the store's reserved `bank` column (D-37-25). This module
|
|
47
|
+
// does not touch the store at all, so that prohibition is satisfied by
|
|
48
|
+
// construction here -- restated because this is the plan that would be
|
|
49
|
+
// tempted.
|
|
50
|
+
|
|
51
|
+
import { BANK_CONDITIONAL_RANGES } from "./memmap-lookup.ts";
|
|
52
|
+
import type { MemmapEntry } from "./memmap-lookup.ts";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* D-37-21: what a bank-conditional range currently contains. `not_applicable`
|
|
56
|
+
* exists so a caller can tell "this address is outside all three
|
|
57
|
+
* bank-conditional ranges" from "the constraint resolved to RAM" -- collapsing
|
|
58
|
+
* the two would make an out-of-range address silently RAM-constrained, which
|
|
59
|
+
* is exactly the confident-wrong-comment failure `AUTO-04` exists to prevent.
|
|
60
|
+
*/
|
|
61
|
+
export type BankedRegion = "io_area" | "character_rom" | "ram" | "basic_rom" | "kernal_rom" | "not_applicable";
|
|
62
|
+
|
|
63
|
+
/** The decoded triple, plus the raw value it was decoded from. Each field
|
|
64
|
+
* answers "what does THIS ONE range currently hold", independent of whether
|
|
65
|
+
* the address a caller cares about actually falls inside it -- that mapping
|
|
66
|
+
* is `resolveBankedRegion()`'s job. */
|
|
67
|
+
export interface BankState {
|
|
68
|
+
raw: number;
|
|
69
|
+
ioRange: BankedRegion;
|
|
70
|
+
basicRange: BankedRegion;
|
|
71
|
+
kernalRange: BankedRegion;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* D-37-21's bit arithmetic, stated as bit tests rather than left for a reader
|
|
76
|
+
* to re-derive from `bank.a`'s own inline comment -- which mislabels the
|
|
77
|
+
* all-RAM value's own bit 2 as clear (it is SET; the RAM outcome it states is
|
|
78
|
+
* right anyway, because the RAM case never depends on bit 2). Masks to bits
|
|
79
|
+
* 2-0 FIRST, so two values differing only above bit 2 decode identically --
|
|
80
|
+
* asserted as its own test case rather than merely trusted.
|
|
81
|
+
*
|
|
82
|
+
* - `$D000-$DFFF` (the I/O range): when bits #1-#0 are both clear, the
|
|
83
|
+
* region is RAM regardless of bit #2. Otherwise, bit #2 clear is
|
|
84
|
+
* Character ROM; bit #2 set is the I/O area.
|
|
85
|
+
* - `$A000-$BFFF` (the BASIC range): BASIC ROM only when BOTH bits #1 and
|
|
86
|
+
* #0 are set; otherwise RAM.
|
|
87
|
+
* - `$E000-$FFFF` (the KERNAL range): KERNAL ROM when bit #1 is set;
|
|
88
|
+
* otherwise RAM.
|
|
89
|
+
*/
|
|
90
|
+
export function decodeBankState(value: number): BankState {
|
|
91
|
+
const raw = value;
|
|
92
|
+
const b = value & 0x07; // bits #2-#0: CHAREN(2) HIRAM(1) LORAM(0)
|
|
93
|
+
const bits10 = b & 0x03;
|
|
94
|
+
const bit2Set = (b & 0x04) !== 0;
|
|
95
|
+
|
|
96
|
+
const ioRange: BankedRegion = bits10 === 0 ? "ram" : bit2Set ? "io_area" : "character_rom";
|
|
97
|
+
const basicRange: BankedRegion = bits10 === 0x03 ? "basic_rom" : "ram";
|
|
98
|
+
const kernalRange: BankedRegion = (b & 0x02) !== 0 ? "kernal_rom" : "ram";
|
|
99
|
+
|
|
100
|
+
return { raw, ioRange, basicRange, kernalRange };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Does `address` fall inside ANY of the three bank-conditional ranges,
|
|
104
|
+
* regardless of the current `$01` value? The join uses this to decide
|
|
105
|
+
* whether the whole reaching-values/decline machinery applies to an address
|
|
106
|
+
* at all -- outside these three ranges, bank state is irrelevant and the
|
|
107
|
+
* candidate set stays unconstrained (D-37-22). */
|
|
108
|
+
export function isBankConditionalAddress(address: number): boolean {
|
|
109
|
+
for (const range of BANK_CONDITIONAL_RANGES) {
|
|
110
|
+
if (address >= range.start && address <= range.end) return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* D-37-22: resolves a single address against an already-decoded `state`,
|
|
117
|
+
* returning the NOT-APPLICABLE member for any address outside all three
|
|
118
|
+
* `BANK_CONDITIONAL_RANGES` -- never RAM. The three ranges are disjoint by
|
|
119
|
+
* construction (each a fixed, hand-maintained, non-overlapping span), so the
|
|
120
|
+
* first (and only) match determines the answer.
|
|
121
|
+
*/
|
|
122
|
+
export function resolveBankedRegion(address: number, state: BankState): BankedRegion {
|
|
123
|
+
for (const range of BANK_CONDITIONAL_RANGES) {
|
|
124
|
+
if (address < range.start || address > range.end) continue;
|
|
125
|
+
if (range.start === 0xd000) return state.ioRange;
|
|
126
|
+
if (range.start === 0xa000) return state.basicRange;
|
|
127
|
+
if (range.start === 0xe000) return state.kernalRange;
|
|
128
|
+
}
|
|
129
|
+
return "not_applicable";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The region-to-map-entry consistency table (D-37-22's candidate constraint,
|
|
134
|
+
* T-37-29's mitigation). Matches the STRUCTURED `section` field, never
|
|
135
|
+
* `desc` (Pitfall 2) -- a small, explicit, hand-maintained keyword set per
|
|
136
|
+
* region, cross-checked against the real committed `memmap.json`'s own
|
|
137
|
+
* section vocabulary (37-RESEARCH.md §C; MEASURED this plan against the
|
|
138
|
+
* real file's `$D000-$DFFF` overlap).
|
|
139
|
+
*
|
|
140
|
+
* RAM has NO dedicated `section` anywhere in the three bank-conditional
|
|
141
|
+
* ranges -- there is nothing chip-specific to document about plain program
|
|
142
|
+
* RAM sitting underneath a ROM/IO window -- so it is matched instead against
|
|
143
|
+
* the entry's own LABEL for a whole-word "RAM" token, which is exactly how
|
|
144
|
+
* the map's own "depends on the processor port" entries describe the RAM
|
|
145
|
+
* alternative (e.g. "I/O Area (memory mapped chip registers), Character ROM
|
|
146
|
+
* or RAM area"; "KERNAL ROM or RAM area"; "BASIC ROM or RAM area").
|
|
147
|
+
*/
|
|
148
|
+
const SECTION_MARKERS: Readonly<Record<Exclude<BankedRegion, "ram" | "not_applicable">, readonly string[]>> = Object.freeze({
|
|
149
|
+
io_area: Object.freeze(["I/O Area", "VIC", "SID", "CIA", "Color RAM"]),
|
|
150
|
+
character_rom: Object.freeze(["Character ROM"]),
|
|
151
|
+
basic_rom: Object.freeze(["BASIC ROM"]),
|
|
152
|
+
kernal_rom: Object.freeze(["KERNAL ROM"]),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
/** Whole-word "RAM" -- deliberately NOT a bare substring match, so a label
|
|
156
|
+
* like "PROGRAM" or "RAMPAGE" (neither of which exists in the committed map
|
|
157
|
+
* today, but the rule should not depend on that) never false-matches. */
|
|
158
|
+
const RAM_LABEL_WORD = /\bRAM\b/;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Does `entry` represent `region`? `not_applicable` never reaches here -- the
|
|
162
|
+
* join only calls this once a real bank-conditional region has been
|
|
163
|
+
* resolved for a specific address. An entry matching NO region member
|
|
164
|
+
* returns `false`, so the caller's candidate-narrowing EXCLUDES it rather
|
|
165
|
+
* than silently admitting it (D-37-22's own prohibition).
|
|
166
|
+
*/
|
|
167
|
+
export function regionAdmitsEntry(entry: MemmapEntry, region: Exclude<BankedRegion, "not_applicable">): boolean {
|
|
168
|
+
if (region === "ram") return RAM_LABEL_WORD.test(entry.label);
|
|
169
|
+
const markers = SECTION_MARKERS[region];
|
|
170
|
+
return typeof entry.section === "string" && markers.some((marker) => entry.section.includes(marker));
|
|
171
|
+
}
|