2018-08-21 22:32:07 +00:00
|
|
|
|
|
|
|
var assert = require('assert');
|
|
|
|
var fs = require('fs');
|
|
|
|
var wtu = require('./workertestutils.js');
|
2018-12-01 20:00:17 +00:00
|
|
|
var PNG = require('pngjs').PNG;
|
2018-08-21 22:32:07 +00:00
|
|
|
|
|
|
|
const jsdom = require('jsdom');
|
|
|
|
const { JSDOM } = jsdom;
|
2019-05-17 03:44:19 +00:00
|
|
|
//const { window } = new JSDOM();
|
2018-08-21 22:32:07 +00:00
|
|
|
|
2018-08-23 22:27:07 +00:00
|
|
|
const dom = new JSDOM(`<!DOCTYPE html><div id="emulator"><div id="javatari-screen"></div></div>`);
|
2018-08-23 20:02:13 +00:00
|
|
|
global.window = dom.window;
|
|
|
|
global.document = dom.window.document;
|
2018-08-21 22:32:07 +00:00
|
|
|
dom.window.Audio = null;
|
2018-08-23 20:02:13 +00:00
|
|
|
global.Image = function() { }
|
2019-08-21 15:14:30 +00:00
|
|
|
global['$'] = require("jquery/jquery-3.4.1.min.js");
|
2019-10-26 01:55:50 +00:00
|
|
|
includeInThisContext('src/common/cpu/z80.js');
|
|
|
|
includeInThisContext('src/common/cpu/6809.js');
|
2019-05-17 03:44:19 +00:00
|
|
|
global['buildZ80'] = global.window.buildZ80;
|
2018-08-23 20:02:13 +00:00
|
|
|
includeInThisContext("javatari.js/release/javatari/javatari.js");
|
|
|
|
Javatari.AUTO_START = false;
|
2018-10-11 15:08:15 +00:00
|
|
|
includeInThisContext('tss/js/Log.js');
|
|
|
|
//global.Log = require('tss/js/Log.js').Log;
|
2018-08-21 22:32:07 +00:00
|
|
|
includeInThisContext('tss/js/tss/PsgDeviceChannel.js');
|
|
|
|
includeInThisContext('tss/js/tss/MasterChannel.js');
|
|
|
|
includeInThisContext('tss/js/tss/AudioLooper.js');
|
2019-04-03 21:00:05 +00:00
|
|
|
//includeInThisContext("jsnes/dist/jsnes.min.js");
|
|
|
|
global.jsnes = require("jsnes/dist/jsnes.min.js");
|
2018-08-21 22:32:07 +00:00
|
|
|
|
2019-10-26 01:55:50 +00:00
|
|
|
//var devices = require('gen/common/devices.js');
|
|
|
|
var emu = require('gen/common/emu.js');
|
2018-08-23 22:52:56 +00:00
|
|
|
var Keys = emu.Keys;
|
2019-10-26 01:55:50 +00:00
|
|
|
var audio = require('gen/common/audio.js');
|
|
|
|
var recorder = require('gen/common/recorder.js');
|
|
|
|
//var _6502 = require('gen/common/cpu/MOS6502.js');
|
2018-08-23 22:27:07 +00:00
|
|
|
var _apple2 = require('gen/platform/apple2.js');
|
2019-08-23 14:37:30 +00:00
|
|
|
//var m_apple2 = require('gen/machine/apple2.js');
|
2018-08-23 22:27:07 +00:00
|
|
|
var _vcs = require('gen/platform/vcs.js');
|
2018-08-23 22:52:56 +00:00
|
|
|
var _nes = require('gen/platform/nes.js');
|
2018-08-23 23:45:36 +00:00
|
|
|
var _vicdual = require('gen/platform/vicdual.js');
|
|
|
|
var _mw8080bw = require('gen/platform/mw8080bw.js');
|
|
|
|
var _galaxian = require('gen/platform/galaxian.js');
|
|
|
|
var _vector = require('gen/platform/vector.js');
|
|
|
|
var _williams = require('gen/platform/williams.js');
|
|
|
|
var _sound_williams = require('gen/platform/sound_williams.js');
|
2018-09-14 13:10:41 +00:00
|
|
|
var _astrocade = require('gen/platform/astrocade.js');
|
2018-09-18 18:09:51 +00:00
|
|
|
var _atari8 = require('gen/platform/atari8.js');
|
2019-08-13 19:43:41 +00:00
|
|
|
var _atari7800 = require('gen/platform/atari7800.js');
|
2018-11-19 16:48:56 +00:00
|
|
|
var _coleco = require('gen/platform/coleco.js');
|
2018-11-30 17:37:00 +00:00
|
|
|
var _sms = require('gen/platform/sms.js');
|
2018-08-21 22:32:07 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
|
2018-08-23 22:27:07 +00:00
|
|
|
dom.window.HTMLCanvasElement.prototype.getContext = function() {
|
|
|
|
return {
|
|
|
|
getImageData: function(x,y,w,h) { return {data: new Uint32Array(w*h) }; },
|
|
|
|
fillRect: function(x,y,w,h) { },
|
|
|
|
drawImage: function(img,x,y,w,h) { },
|
2018-11-19 16:48:56 +00:00
|
|
|
putImageData: function(data,w,h) { },
|
2018-08-23 22:27:07 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
global.navigator = {};
|
|
|
|
|
|
|
|
var keycallback;
|
2018-12-01 20:00:17 +00:00
|
|
|
var lastrastervideo;
|
2018-08-23 22:27:07 +00:00
|
|
|
|
2018-08-21 22:32:07 +00:00
|
|
|
emu.RasterVideo = function(mainElement, width, height, options) {
|
2018-11-30 17:37:00 +00:00
|
|
|
var buffer;
|
|
|
|
var datau8;
|
2018-08-21 22:32:07 +00:00
|
|
|
var datau32;
|
|
|
|
this.create = function() {
|
2018-12-01 20:00:17 +00:00
|
|
|
this.width = width;
|
|
|
|
this.height = height;
|
2018-11-30 17:37:00 +00:00
|
|
|
buffer = new ArrayBuffer(width*height*4);
|
|
|
|
datau8 = new Uint8Array(buffer);
|
|
|
|
datau32 = new Uint32Array(buffer);
|
2018-12-01 20:00:17 +00:00
|
|
|
lastrastervideo = this;
|
2018-08-21 22:32:07 +00:00
|
|
|
}
|
|
|
|
this.setKeyboardEvents = function(callback) {
|
2018-08-23 22:27:07 +00:00
|
|
|
keycallback = callback;
|
2018-08-21 22:32:07 +00:00
|
|
|
}
|
|
|
|
this.getFrameData = function() { return datau32; }
|
2018-11-30 17:37:00 +00:00
|
|
|
this.getImageData = function() { return {data:datau8, width:width, height:height}; }
|
2018-08-23 23:45:36 +00:00
|
|
|
this.updateFrame = function() {}
|
2019-05-28 01:52:00 +00:00
|
|
|
this.clearRect = function() {}
|
2018-10-03 19:06:48 +00:00
|
|
|
this.setupMouseEvents = function() { }
|
2018-11-30 17:37:00 +00:00
|
|
|
this.canvas = this;
|
|
|
|
this.getContext = function() { return this; }
|
|
|
|
this.fillRect = function() { }
|
|
|
|
this.fillStyle = '';
|
|
|
|
this.putImageData = function() { }
|
2018-08-23 23:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
emu.VectorVideo = function(mainElement, width, height, options) {
|
|
|
|
this.create = function() {
|
|
|
|
this.drawops = 0;
|
|
|
|
}
|
|
|
|
this.setKeyboardEvents = function(callback) {
|
|
|
|
keycallback = callback;
|
|
|
|
}
|
|
|
|
this.clear = function() { }
|
|
|
|
this.drawLine = function() { this.drawops++; }
|
|
|
|
}
|
|
|
|
|
|
|
|
global.Worker = function() {
|
|
|
|
this.msgcount = 0;
|
|
|
|
this.postMessage = function() { this.msgcount++; }
|
2018-08-21 22:32:07 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 04:19:25 +00:00
|
|
|
global.Mousetrap = function() {
|
|
|
|
this.bind = function() { }
|
|
|
|
}
|
|
|
|
|
2018-08-21 22:32:07 +00:00
|
|
|
//
|
|
|
|
|
2018-08-23 20:02:13 +00:00
|
|
|
function testPlatform(platid, romname, maxframes, callback) {
|
2018-08-21 22:32:07 +00:00
|
|
|
var emudiv = document.getElementById('emulator');
|
|
|
|
var platform = new emu.PLATFORMS[platid](emudiv);
|
2018-08-23 20:02:13 +00:00
|
|
|
var rec = new recorder.StateRecorderImpl(platform);
|
2018-08-21 22:32:07 +00:00
|
|
|
platform.start();
|
2018-08-23 20:02:13 +00:00
|
|
|
var rom = fs.readFileSync('./test/roms/' + platid + '/' + romname);
|
|
|
|
rom = new Uint8Array(rom);
|
2018-08-23 22:27:07 +00:00
|
|
|
platform.loadROM("ROM", rom);
|
2019-08-23 19:05:12 +00:00
|
|
|
var state0a = platform.saveState();
|
|
|
|
platform.reset(); // reset again
|
|
|
|
var state0b = platform.saveState();
|
2019-08-24 02:32:10 +00:00
|
|
|
//TODO: vcs fails assert.deepEqual(state0a, state0b);
|
2019-08-24 15:28:04 +00:00
|
|
|
//if (platform.startProbing) platform.startProbing();
|
2018-08-23 20:02:13 +00:00
|
|
|
platform.resume(); // so that recorder works
|
|
|
|
platform.setRecorder(rec);
|
|
|
|
for (var i=0; i<maxframes; i++) {
|
|
|
|
if (callback) callback(platform, i);
|
|
|
|
platform.nextFrame();
|
2018-08-24 00:53:37 +00:00
|
|
|
if (i==10) {
|
|
|
|
for (var j=0; j<0x10000; j++)
|
2018-08-25 02:55:16 +00:00
|
|
|
platform.readAddress(j); // make sure readAddress() doesn't leave side effects
|
2018-08-24 00:53:37 +00:00
|
|
|
}
|
2018-08-23 20:02:13 +00:00
|
|
|
}
|
2018-08-25 02:55:16 +00:00
|
|
|
// test replay feature
|
2018-08-23 20:02:13 +00:00
|
|
|
platform.pause();
|
2018-08-25 02:55:16 +00:00
|
|
|
if (maxframes > 120*60)
|
|
|
|
maxframes = 120*60;
|
2018-08-23 20:02:13 +00:00
|
|
|
assert.equal(maxframes, rec.numFrames());
|
|
|
|
var state1 = platform.saveState();
|
2019-04-07 16:33:01 +00:00
|
|
|
platform.loadState(state1);
|
|
|
|
assert.deepEqual(state1, platform.saveState());
|
2018-08-23 20:02:13 +00:00
|
|
|
assert.equal(1, rec.loadFrame(1));
|
|
|
|
assert.equal(maxframes, rec.loadFrame(maxframes));
|
|
|
|
var state2 = platform.saveState();
|
|
|
|
assert.deepEqual(state1, state2);
|
2019-08-26 18:09:42 +00:00
|
|
|
// test memory reads not clearing stuff
|
|
|
|
for (var i=0; i<=0xffff; i++)
|
|
|
|
if (platform.readAddress) platform.readAddress(i);
|
|
|
|
var state3 = platform.saveState();
|
|
|
|
assert.deepEqual(state2, state3);
|
2018-08-25 02:55:16 +00:00
|
|
|
// test debug info
|
|
|
|
var debugs = platform.getDebugCategories();
|
|
|
|
for (var dcat of debugs) {
|
|
|
|
var dinfo = platform.getDebugInfo(dcat, state2);
|
|
|
|
console.log(dcat, dinfo);
|
|
|
|
assert.ok(dinfo && dinfo.length > 0, dcat + " empty");
|
|
|
|
assert.ok(dinfo.length < 80*24, dcat + " too long");
|
|
|
|
assert.ok(dinfo.indexOf('undefined') < 0, dcat + " undefined");
|
|
|
|
}
|
2018-12-01 20:00:17 +00:00
|
|
|
if (lastrastervideo) {
|
|
|
|
var png = new PNG({width:lastrastervideo.width, height:lastrastervideo.height});
|
|
|
|
png.data = lastrastervideo.getImageData().data;
|
|
|
|
var pngbuffer = PNG.sync.write(png);
|
|
|
|
assert(pngbuffer.length > 500); // make sure PNG is big enough
|
|
|
|
try { fs.mkdirSync("./test"); } catch(e) { }
|
|
|
|
try { fs.mkdirSync("./test/output"); } catch(e) { }
|
|
|
|
try {
|
|
|
|
fs.writeFileSync("./test/output/"+platid+"-"+romname+".png", pngbuffer);
|
|
|
|
} catch (e) { console.log(e) }
|
|
|
|
}
|
2018-08-23 20:02:13 +00:00
|
|
|
return platform;
|
2018-08-21 22:32:07 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 20:02:13 +00:00
|
|
|
describe('Platform Replay', () => {
|
2018-08-23 22:27:07 +00:00
|
|
|
|
2018-08-23 20:02:13 +00:00
|
|
|
it('Should run apple2', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('apple2', 'cosmic.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-12-09 15:11:14 +00:00
|
|
|
keycallback(32, 32, 128); // space bar
|
2018-08-23 22:27:07 +00:00
|
|
|
}
|
|
|
|
});
|
2019-08-23 14:37:30 +00:00
|
|
|
assert.equal(platform.saveState().kbdlatch, 0x20); // strobe cleared
|
2018-08-23 22:27:07 +00:00
|
|
|
});
|
|
|
|
|
2018-08-25 02:55:16 +00:00
|
|
|
it('Should run > 120 secs', () => {
|
|
|
|
var platform = testPlatform('apple2', 'mandel.c.rom', 122*60, (platform, frameno) => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-08-23 22:27:07 +00:00
|
|
|
it('Should run vcs', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('vcs', 'brickgame.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 20:02:13 +00:00
|
|
|
var cstate = platform.saveControlsState();
|
2018-08-23 22:27:07 +00:00
|
|
|
cstate.SA = 0xff ^ 0x40; // stick left
|
2018-08-23 20:02:13 +00:00
|
|
|
platform.loadControlsState(cstate);
|
|
|
|
}
|
|
|
|
});
|
2018-08-23 22:27:07 +00:00
|
|
|
assert.equal(platform.saveState().p.SA, 0xff ^ 0x40);
|
2018-08-23 23:45:36 +00:00
|
|
|
assert.equal(60, platform.readAddress(0x80)); // player x pos
|
2018-08-23 20:02:13 +00:00
|
|
|
});
|
2018-08-23 22:27:07 +00:00
|
|
|
|
2018-08-23 22:52:56 +00:00
|
|
|
it('Should run nes', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('nes', 'shoot2.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 23:45:36 +00:00
|
|
|
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
assert.equal(120-10, platform.readAddress(0x41d)); // player x pos
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Should run vicdual', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('vicdual', 'snake1.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 23:45:36 +00:00
|
|
|
keycallback(Keys.VK_DOWN.c, Keys.VK_DOWN.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Should run mw8080bw', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('mw8080bw', 'game2.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 23:45:36 +00:00
|
|
|
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
assert.equal(96-9*2, platform.readAddress(0x2006)); // player x pos
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Should run galaxian', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('galaxian-scramble', 'shoot2.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 23:45:36 +00:00
|
|
|
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
assert.equal(112-10, platform.readAddress(0x4074)); // player x pos
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Should run vector', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('vector-z80color', 'game.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 23:45:36 +00:00
|
|
|
keycallback(Keys.VK_UP.c, Keys.VK_UP.c, 1);
|
2018-08-23 22:52:56 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-08-25 20:20:12 +00:00
|
|
|
/*
|
2019-08-11 14:23:56 +00:00
|
|
|
it('Should run williams 6809', () => {
|
|
|
|
var platform = testPlatform('williams', 'vidfill.asm.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
|
|
|
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-08-25 20:20:12 +00:00
|
|
|
*/
|
2019-08-11 14:23:56 +00:00
|
|
|
it('Should run williams-z80', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('williams-z80', 'game1.c.rom', 72, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
2018-08-23 23:45:36 +00:00
|
|
|
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('Should run sound_williams', () => {
|
2018-08-25 02:55:16 +00:00
|
|
|
var platform = testPlatform('sound_williams-z80', 'swave.c.rom', 72, (platform, frameno) => {
|
2018-08-23 23:45:36 +00:00
|
|
|
if (frameno == 60) {
|
|
|
|
keycallback(Keys.VK_2.c, Keys.VK_2.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2018-09-14 13:10:41 +00:00
|
|
|
|
|
|
|
it('Should run astrocade', () => {
|
|
|
|
var platform = testPlatform('astrocade', 'cosmic.c.rom', 92, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
|
|
|
keycallback(Keys.VK_SPACE.c, Keys.VK_SPACE.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2018-11-19 16:48:56 +00:00
|
|
|
it('Should run coleco', () => {
|
|
|
|
var platform = testPlatform('coleco', 'shoot.c.rom', 92, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
|
|
|
keycallback(Keys.VK_SPACE.c, Keys.VK_SPACE.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2018-11-30 17:37:00 +00:00
|
|
|
it('Should run sms-sg1000-libcv', () => {
|
|
|
|
var platform = testPlatform('sms-sg1000-libcv', 'shoot.c.rom', 92, (platform, frameno) => {
|
|
|
|
if (frameno == 62) {
|
|
|
|
keycallback(Keys.VK_SPACE.c, Keys.VK_SPACE.c, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-08-13 19:43:41 +00:00
|
|
|
it('Should run atari7800', () => {
|
|
|
|
var platform = testPlatform('atari7800', 'sprites.dasm.rom', 92, (platform, frameno) => {
|
2018-09-18 18:09:51 +00:00
|
|
|
if (frameno == 62) {
|
2019-08-13 19:43:41 +00:00
|
|
|
keycallback(Keys.VK_DOWN.c, Keys.VK_DOWN.c, 1);
|
2018-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
});
|
2019-08-23 19:05:12 +00:00
|
|
|
assert.equal(0x1800, platform.saveState().maria.dll);
|
|
|
|
assert.equal(39, platform.readAddress(0x81)); // player y pos
|
2018-09-18 18:09:51 +00:00
|
|
|
});
|
2018-08-21 22:32:07 +00:00
|
|
|
});
|