nes: fix write() bug

This commit is contained in:
Steven Hugg committed 2026-09-29 14:51:29 +02:00
1 parent b49d273d10
commit 54cd3e4823
5 files changed
+35 -4

No files matched your search

+1 -1
View File
@@ -75,7 +75,7 @@ In a folder with a launch configuration, <kbd>F5</kbd> does the same, and
of memory, `#mem16[addr]` for a word.
- **Memory:** the binary-data icon next to a register or symbol opens
memory at that address in the Hex Editor (VS Code offers to install
it). On most platforms you can edit it there; NES, VCS and MAME-based
it). On most platforms you can edit it there; VCS and MAME-based
platforms are read-only.
- **Disassembly:** right-click in the Call Stack and choose **Open
Disassembly View**. It shows instructions with their symbols and source
+3 -2
View File
@@ -1871,8 +1871,9 @@ runs has to be a webview too.
- **Memory writes.** `EmuCore.write()` goes through the machine's bus, so
writing an I/O address does what a store there does. It restarts the
timeline (the past can't be replayed into the edited state). It needs a
`Machine`, so NES (JSNES), VCS and the MAME platforms
can't write; `DebugCapabilities.write` says so and the adapter turns on
`Machine` with `write()`, so VCS and the MAME platforms can't write
(NES's `JSNESMachine` writes RAM or the mapper directly, skipping
`cpu.write()`'s bus cycle); `DebugCapabilities.write` says so and the adapter turns on
`supportsWriteMemoryRequest` only when it can. After a write the adapter
sends `invalidated` (variables); after every stop it sends a `memory`
event for the whole space so the Hex Editor reads again.
+25
View File
@@ -295,6 +295,31 @@ describe('extension emuworker', function () {
await debug('setBreakpoints', []);
});
it('browses the NES machine state and symbols', async function () {
var dir = path.join(ROOT, 'presets/nes');
var read = async (rel: string) => {
var p = path.join(dir, rel);
return fs.existsSync(p) ? new Uint8Array(fs.readFileSync(p)) : null;
};
var nes = await new Builder(ROOT).build({
platform: 'nes', mainPath: 'scroll.c', mainText: fs.readFileSync(path.join(dir, 'scroll.c'), 'utf-8'),
files: new ProjectFileProvider(read, ROOT, 'nes'),
});
await rpc.call('start', 'nes', nes.output, nes.files, { paused: true });
await debug('setBuild', { listings: nes.listings, symbols: nes.symbolmap, mainPath: 'scroll.c', paths: nes.paths });
var caps = await debug('capabilities');
assert.equal(caps.tree, true);
assert.equal(caps.write, true);
assert.deepEqual(await debug('debugTree', []), [{ name: 'state', value: '', expandable: true }]);
var cpu = await debug('debugTree', ['state', 'c']);
assert.ok(cpu.find((e: any) => e.name === 'PC'));
var syms = await debug('symbols');
assert.ok(syms.find((s: any) => s.name === '_main'));
// zero page, through the machine's write
assert.equal(await debug('writeMemory', 0x10, [0x5a]), 1);
assert.deepEqual(await debug('readMemory', 0x10, 1), [0x5a]);
});
it('drives the debug adapter through the worker, as the extension does', async function () {
var backend = new WorkerDebugBackend((method, ...args) => rpc.call('debug', method, ...args), async () => {
await rpc.call('start', 'mw8080bw', built.output, built.files, { paused: true });
+1 -1
View File
@@ -305,7 +305,7 @@ export class EmuCore {
throw new Error(`platform '${this.id}' cannot read memory`);
}
get supportsWrite(): boolean { return !!this.machine; }
get supportsWrite(): boolean { return typeof this.machine?.write === 'function'; }
/**
* Write a byte through the machine's bus, as the CPU would (so an I/O
+5
View File
@@ -107,6 +107,11 @@ class JSNESMachine {
loadState(s) { this.p.loadState(s); }
read(a: number) { return this.p.readAddress(a); }
readConst(a: number) { return this.p.readAddress(a); }
// for the debugger: RAM, or the mapper, without cpu.write()'s bus cycle
write(a: number, v: number) {
if (a < 0x2000) this.p.nes.cpu.mem[a & 0x7ff] = v;
else this.p.nes.mmap.write(a, v);
}
connectProbe(probe: ProbeAll) { this.p.connectProbe(probe); }
}