mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2026-10-24 08:02:27 +00:00
67 lines
2.8 KiB
JavaScript
67 lines
2.8 KiB
JavaScript
"use strict";
|
|
|
|
// Determinism regression tests: record a run with input, replay it from the
|
|
// first checkpoint, and require every frame to come back bit for bit.
|
|
//
|
|
// This is the guard that keeps rewinding meaningful. Without it, a field that
|
|
// is written but never saved (ANTIC's left/right, the WASM machines' joymask)
|
|
// leaks across a rewind and nothing notices until a user is staring at a
|
|
// debugger that shows the wrong past.
|
|
|
|
var assert = require('assert');
|
|
var fs = require('fs');
|
|
var path = require('path');
|
|
|
|
var emutarget = require('../../gen/tools/emutarget.js');
|
|
var verifyreplay = require('../../gen/tools/verifyreplay.js');
|
|
|
|
function firstROM(platid) {
|
|
var dir = path.join('test', 'roms', platid);
|
|
return path.join(dir, fs.readdirSync(dir)[0]);
|
|
}
|
|
|
|
/** Record `frames` frames with input, then replay and compare every frame. */
|
|
async function checkDeterministic(platid, frames, romid) {
|
|
var target = await emutarget.loadPlatform(platid);
|
|
await target.start();
|
|
await target.loadROM(new Uint8Array(fs.readFileSync(firstROM(romid || platid))));
|
|
var r = verifyreplay.verifyReplay(target, { frames: frames });
|
|
// the input has to actually reach the machine, or a pass means nothing
|
|
assert.ok(r.controlStates > 1,
|
|
platid + ': the exerciser never changed the controls, so nothing was tested');
|
|
assert.deepStrictEqual(r.diverged, [], platid + ': replay diverged at frame ' + r.diverged[0] + ' of ' + frames);
|
|
return r.granularity;
|
|
}
|
|
|
|
describe('Deterministic replay', function () {
|
|
this.timeout(120000);
|
|
|
|
// a JS scanline machine, the two that had state-restore bugs, and a WASM
|
|
// machine of each kind
|
|
it('should replay mw8080bw exactly', async function () {
|
|
assert.strictEqual(await checkDeterministic('mw8080bw', 20), 'insn');
|
|
});
|
|
it('should replay apple2 exactly', async function () {
|
|
await checkDeterministic('apple2', 20);
|
|
});
|
|
it('should replay atari8-800 exactly (ANTIC left/right must round-trip)', async function () {
|
|
await checkDeterministic('atari8-800', 20);
|
|
});
|
|
it('should replay atari8-5200 exactly (key-down IRQ must be redelivered)', async function () {
|
|
await checkDeterministic('atari8-5200', 20);
|
|
});
|
|
it('should replay c64 exactly (joymask must round-trip)', async function () {
|
|
assert.strictEqual(await checkDeterministic('c64', 20), 'clock');
|
|
});
|
|
it('should replay zx exactly (joymask must round-trip)', async function () {
|
|
await checkDeterministic('zx', 20);
|
|
});
|
|
it('should replay nes exactly (jsnes save states must not alias live arrays)', async function () {
|
|
assert.strictEqual(await checkDeterministic('nes', 20), 'insn');
|
|
});
|
|
it('should replay vcs.jt4 exactly (Javatari power-on noise and TIA colors)', async function () {
|
|
// the ROMs live under the base platform's folder
|
|
assert.strictEqual(await checkDeterministic('vcs.jt4', 20, 'vcs'), 'insn');
|
|
});
|
|
});
|