mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-25 15:29:34 +00:00
made some platforms classy
This commit is contained in:
parent
86823c2c21
commit
0dd741f446
|
@ -55,6 +55,7 @@ TODO:
|
||||||
- state buffer/replay
|
- state buffer/replay
|
||||||
- intro/help text for each platform
|
- intro/help text for each platform
|
||||||
- make sure controls work with replay feature (we'll have to save control state every frame)
|
- make sure controls work with replay feature (we'll have to save control state every frame)
|
||||||
|
- vscode/atom extension?
|
||||||
|
|
||||||
FYI: Image links for the books on http://8bitworkshop.com/ are broken
|
FYI: Image links for the books on http://8bitworkshop.com/ are broken
|
||||||
On the website the additional grey spacing next to the program line numbers is not dynamically resized when the web browser window size is changed. Intentional?
|
On the website the additional grey spacing next to the program line numbers is not dynamically resized when the web browser window size is changed. Intentional?
|
||||||
|
|
|
@ -569,71 +569,75 @@ export abstract class Base6809Platform extends BaseZ80Platform {
|
||||||
declare var FS, ENV, Module; // mame emscripten
|
declare var FS, ENV, Module; // mame emscripten
|
||||||
|
|
||||||
// TODO: make class
|
// TODO: make class
|
||||||
export function BaseMAMEPlatform() {
|
export abstract class BaseMAMEPlatform {
|
||||||
|
|
||||||
var self = this;
|
loaded = false;
|
||||||
|
preinitted = false;
|
||||||
|
romfn;
|
||||||
|
romdata;
|
||||||
|
video;
|
||||||
|
preload_files;
|
||||||
|
running = false;
|
||||||
|
console_vars : {[varname:string]:string[]} = {};
|
||||||
|
console_varname;
|
||||||
|
initluavars = false;
|
||||||
|
luadebugscript;
|
||||||
|
js_lua_string;
|
||||||
|
onBreakpointHit;
|
||||||
|
mainElement;
|
||||||
|
|
||||||
var loaded = false;
|
constructor(mainElement) {
|
||||||
var preinitted = false;
|
this.mainElement = mainElement;
|
||||||
var romfn;
|
}
|
||||||
var romdata;
|
|
||||||
var video;
|
|
||||||
var preload_files;
|
|
||||||
var running = false;
|
|
||||||
var console_vars : {[varname:string]:string[]} = {};
|
|
||||||
var console_varname;
|
|
||||||
var initluavars = false;
|
|
||||||
var luadebugscript;
|
|
||||||
var js_lua_string;
|
|
||||||
|
|
||||||
this.luareset = function() {
|
luareset() {
|
||||||
console_vars = {};
|
this.console_vars = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://docs.mamedev.org/techspecs/luaengine.html
|
// http://docs.mamedev.org/techspecs/luaengine.html
|
||||||
this.luacall = function(s) {
|
luacall(s) {
|
||||||
console_varname = null;
|
this.console_varname = null;
|
||||||
//Module.ccall('_Z13js_lua_stringPKc', 'void', ['string'], [s+""]);
|
//Module.ccall('_Z13js_lua_stringPKc', 'void', ['string'], [s+""]);
|
||||||
if (!js_lua_string) js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'void', ['string']);
|
if (!this.js_lua_string) this.js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'void', ['string']);
|
||||||
js_lua_string(s || "");
|
this.js_lua_string(s || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pause = function() {
|
pause() {
|
||||||
if (loaded && running) {
|
if (this.loaded && this.running) {
|
||||||
this.luacall('emu.pause()');
|
this.luacall('emu.pause()');
|
||||||
running = false;
|
this.running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resume = function() {
|
resume() {
|
||||||
if (loaded && !running) { // TODO
|
if (this.loaded && !this.running) { // TODO
|
||||||
this.luacall('emu.unpause()');
|
this.luacall('emu.unpause()');
|
||||||
running = true;
|
this.running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reset = function() {
|
reset() {
|
||||||
this.luacall('manager:machine():soft_reset()');
|
this.luacall('manager:machine():soft_reset()');
|
||||||
running = true;
|
this.running = true;
|
||||||
initluavars = false;
|
this.initluavars = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
isRunning() {
|
||||||
return running;
|
return this.running;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bufferConsoleOutput(s) {
|
bufferConsoleOutput(s) {
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
if (s.startsWith(">>>")) {
|
if (s.startsWith(">>>")) {
|
||||||
console_varname = s.length > 3 ? s.slice(3) : null;
|
this.console_varname = s.length > 3 ? s.slice(3) : null;
|
||||||
if (console_varname) console_vars[console_varname] = [];
|
if (this.console_varname) this.console_vars[this.console_varname] = [];
|
||||||
} else if (console_varname) {
|
} else if (this.console_varname) {
|
||||||
console_vars[console_varname].push(s);
|
this.console_vars[this.console_varname].push(s);
|
||||||
if (console_varname == 'debug_stopped') {
|
if (this.console_varname == 'debug_stopped') {
|
||||||
var debugSaveState = self.preserveState();
|
var debugSaveState = this.preserveState();
|
||||||
self.pause();
|
this.pause();
|
||||||
if (onBreakpointHit) {
|
if (this.onBreakpointHit) {
|
||||||
onBreakpointHit(debugSaveState);
|
this.onBreakpointHit(debugSaveState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -641,12 +645,11 @@ export function BaseMAMEPlatform() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.startModule = function(mainElement, opts) {
|
startModule(mainElement, opts) {
|
||||||
romfn = opts.romfn;
|
var romfn = this.romfn = this.romfn || opts.romfn;
|
||||||
if (opts.romdata) romdata = opts.romdata;
|
var romdata = this.romdata = this.romdata || opts.romdata || new RAM(opts.romsize).mem;
|
||||||
if (!romdata) romdata = new RAM(opts.romsize).mem;
|
|
||||||
// create canvas
|
// create canvas
|
||||||
video = new RasterVideo(mainElement, opts.width, opts.height);
|
var video = this.video = new RasterVideo(this.mainElement, opts.width, opts.height);
|
||||||
video.create();
|
video.create();
|
||||||
$(video.canvas).attr('id','canvas');
|
$(video.canvas).attr('id','canvas');
|
||||||
// load asm.js module
|
// load asm.js module
|
||||||
|
@ -662,11 +665,11 @@ export function BaseMAMEPlatform() {
|
||||||
window['Module'] = {
|
window['Module'] = {
|
||||||
arguments: modargs,
|
arguments: modargs,
|
||||||
screenIsReadOnly: true,
|
screenIsReadOnly: true,
|
||||||
print: bufferConsoleOutput,
|
print: this.bufferConsoleOutput,
|
||||||
canvas:video.canvas,
|
canvas:video.canvas,
|
||||||
doNotCaptureKeyboard:true,
|
doNotCaptureKeyboard:true,
|
||||||
keyboardListeningElement:video.canvas,
|
keyboardListeningElement:video.canvas,
|
||||||
preInit: function () {
|
preInit: () => {
|
||||||
console.log("loading FS");
|
console.log("loading FS");
|
||||||
ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = 'canvas';
|
ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = 'canvas';
|
||||||
if (opts.cfgfile) {
|
if (opts.cfgfile) {
|
||||||
|
@ -685,14 +688,14 @@ export function BaseMAMEPlatform() {
|
||||||
if (opts.preInit) {
|
if (opts.preInit) {
|
||||||
opts.preInit(self);
|
opts.preInit(self);
|
||||||
}
|
}
|
||||||
preinitted = true;
|
this.preinitted = true;
|
||||||
},
|
},
|
||||||
preRun: [
|
preRun: [
|
||||||
function() {
|
() => {
|
||||||
$(video.canvas).click(function(e) {
|
$(video.canvas).click((e) =>{
|
||||||
video.canvas.focus();
|
video.canvas.focus();
|
||||||
});
|
});
|
||||||
loaded = true;
|
this.loaded = true;
|
||||||
console.log("about to run...");
|
console.log("about to run...");
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -704,7 +707,7 @@ export function BaseMAMEPlatform() {
|
||||||
var fetch_wasm = $.Deferred();
|
var fetch_wasm = $.Deferred();
|
||||||
// fetch config file
|
// fetch config file
|
||||||
if (opts.cfgfile) {
|
if (opts.cfgfile) {
|
||||||
fetch_cfg = $.get('mame/cfg/' + opts.cfgfile, function(data) {
|
fetch_cfg = $.get('mame/cfg/' + opts.cfgfile, (data) => {
|
||||||
opts.cfgdata = data;
|
opts.cfgdata = data;
|
||||||
console.log("loaded " + opts.cfgfile);
|
console.log("loaded " + opts.cfgfile);
|
||||||
}, 'text');
|
}, 'text');
|
||||||
|
@ -714,7 +717,7 @@ export function BaseMAMEPlatform() {
|
||||||
var oReq1 = new XMLHttpRequest();
|
var oReq1 = new XMLHttpRequest();
|
||||||
oReq1.open("GET", 'mame/roms/' + opts.biosfile, true);
|
oReq1.open("GET", 'mame/roms/' + opts.biosfile, true);
|
||||||
oReq1.responseType = "arraybuffer";
|
oReq1.responseType = "arraybuffer";
|
||||||
oReq1.onload = function(oEvent) {
|
oReq1.onload = (oEvent) => {
|
||||||
opts.biosdata = new Uint8Array(oReq1.response);
|
opts.biosdata = new Uint8Array(oReq1.response);
|
||||||
console.log("loaded " + opts.biosfile); // + " (" + oEvent.total + " bytes)");
|
console.log("loaded " + opts.biosfile); // + " (" + oEvent.total + " bytes)");
|
||||||
fetch_bios.resolve();
|
fetch_bios.resolve();
|
||||||
|
@ -724,8 +727,8 @@ export function BaseMAMEPlatform() {
|
||||||
fetch_bios.resolve();
|
fetch_bios.resolve();
|
||||||
}
|
}
|
||||||
// load debugger Lua script
|
// load debugger Lua script
|
||||||
fetch_lua = $.get('mame/debugger.lua', function(data) {
|
fetch_lua = $.get('mame/debugger.lua', (data) => {
|
||||||
luadebugscript = data;
|
this.luadebugscript = data;
|
||||||
console.log("loaded debugger.lua");
|
console.log("loaded debugger.lua");
|
||||||
}, 'text');
|
}, 'text');
|
||||||
// load WASM
|
// load WASM
|
||||||
|
@ -733,7 +736,7 @@ export function BaseMAMEPlatform() {
|
||||||
var oReq2 = new XMLHttpRequest();
|
var oReq2 = new XMLHttpRequest();
|
||||||
oReq2.open("GET", 'mame/' + opts.jsfile.replace('.js','.wasm'), true);
|
oReq2.open("GET", 'mame/' + opts.jsfile.replace('.js','.wasm'), true);
|
||||||
oReq2.responseType = "arraybuffer";
|
oReq2.responseType = "arraybuffer";
|
||||||
oReq2.onload = function(oEvent) {
|
oReq2.onload = (oEvent) => {
|
||||||
console.log("loaded WASM file");
|
console.log("loaded WASM file");
|
||||||
window['Module'].wasmBinary = new Uint8Array(oReq2.response);
|
window['Module'].wasmBinary = new Uint8Array(oReq2.response);
|
||||||
fetch_wasm.resolve();
|
fetch_wasm.resolve();
|
||||||
|
@ -741,7 +744,7 @@ export function BaseMAMEPlatform() {
|
||||||
oReq2.send();
|
oReq2.send();
|
||||||
}
|
}
|
||||||
// start loading script
|
// start loading script
|
||||||
$.when(fetch_lua, fetch_cfg, fetch_bios, fetch_wasm).done(function() {
|
$.when(fetch_lua, fetch_cfg, fetch_bios, fetch_wasm).done( () => {
|
||||||
var script = document.createElement('script');
|
var script = document.createElement('script');
|
||||||
script.src = 'mame/' + opts.jsfile;
|
script.src = 'mame/' + opts.jsfile;
|
||||||
document.getElementsByTagName('head')[0].appendChild(script);
|
document.getElementsByTagName('head')[0].appendChild(script);
|
||||||
|
@ -749,32 +752,32 @@ export function BaseMAMEPlatform() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROMFile = function(data) {
|
loadROMFile(data) {
|
||||||
romdata = data;
|
this.romdata = data;
|
||||||
if (preinitted && romfn) {
|
if (this.preinitted && this.romfn) {
|
||||||
FS.writeFile(romfn, data, {encoding:'binary'});
|
FS.writeFile(this.romfn, data, {encoding:'binary'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadRegion = function(region, data) {
|
loadRegion(region, data) {
|
||||||
if (loaded) {
|
if (this.loaded) {
|
||||||
//self.luacall('cart=manager:machine().images["cart"]\nprint(cart:filename())\ncart:load("' + romfn + '")\n');
|
//this.luacall('cart=manager:machine().images["cart"]\nprint(cart:filename())\ncart:load("' + romfn + '")\n');
|
||||||
var s = 'rgn = manager:machine():memory().regions["' + region + '"]\n';
|
var s = 'rgn = manager:machine():memory().regions["' + region + '"]\n';
|
||||||
//s += 'print(rgn.size)\n';
|
//s += 'print(rgn.size)\n';
|
||||||
for (var i=0; i<data.length; i+=4) {
|
for (var i=0; i<data.length; i+=4) {
|
||||||
var v = data[i] + (data[i+1]<<8) + (data[i+2]<<16) + (data[i+3]<<24);
|
var v = data[i] + (data[i+1]<<8) + (data[i+2]<<16) + (data[i+3]<<24);
|
||||||
s += 'rgn:write_u32(' + i + ',' + v + ')\n'; // TODO: endian?
|
s += 'rgn:write_u32(' + i + ',' + v + ')\n'; // TODO: endian?
|
||||||
}
|
}
|
||||||
self.luacall(s);
|
this.luacall(s);
|
||||||
self.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.preserveState = function() {
|
preserveState() {
|
||||||
var state = {c:{}};
|
var state = {c:{}};
|
||||||
for (var k in console_vars) {
|
for (var k in this.console_vars) {
|
||||||
if (k.startsWith("cpu_")) {
|
if (k.startsWith("cpu_")) {
|
||||||
var v = parseInt(console_vars[k][0]);
|
var v = parseInt(this.console_vars[k][0]);
|
||||||
state.c[k.slice(4)] = v;
|
state.c[k.slice(4)] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,59 +785,57 @@ export function BaseMAMEPlatform() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.saveState = function() {
|
saveState() {
|
||||||
this.luareset();
|
this.luareset();
|
||||||
this.luacall('mamedbg.printstate()');
|
this.luacall('mamedbg.printstate()');
|
||||||
return self.preserveState();
|
return this.preserveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initlua = function() {
|
initlua() {
|
||||||
if (!initluavars) {
|
if (!this.initluavars) {
|
||||||
self.luacall(luadebugscript);
|
this.luacall(this.luadebugscript);
|
||||||
self.luacall('mamedbg.init()')
|
this.luacall('mamedbg.init()')
|
||||||
initluavars = true;
|
this.initluavars = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.readAddress = function(a) {
|
readAddress(a) {
|
||||||
self.initlua();
|
this.initlua();
|
||||||
self.luacall('print(">>>v"); print(mem:read_u8(' + a + '))');
|
this.luacall('print(">>>v"); print(mem:read_u8(' + a + '))');
|
||||||
return parseInt(console_vars.v[0]);
|
return parseInt(this.console_vars.v[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUGGING SUPPORT
|
// DEBUGGING SUPPORT
|
||||||
|
|
||||||
var onBreakpointHit;
|
clearDebug() {
|
||||||
|
this.onBreakpointHit = null;
|
||||||
this.clearDebug = function() {
|
|
||||||
onBreakpointHit = null;
|
|
||||||
}
|
}
|
||||||
this.getDebugCallback = function() {
|
getDebugCallback() {
|
||||||
return onBreakpointHit;// TODO?
|
return this.onBreakpointHit;// TODO?
|
||||||
}
|
}
|
||||||
this.setupDebug = function(callback) {
|
setupDebug(callback) {
|
||||||
self.initlua();
|
this.initlua();
|
||||||
self.luareset();
|
this.luareset();
|
||||||
onBreakpointHit = callback;
|
this.onBreakpointHit = callback;
|
||||||
}
|
}
|
||||||
this.runToPC = function(pc) {
|
runToPC(pc) {
|
||||||
self.luacall('mamedbg.runTo(' + pc + ')');
|
this.luacall('mamedbg.runTo(' + pc + ')');
|
||||||
self.resume();
|
this.resume();
|
||||||
}
|
}
|
||||||
this.runToVsync = function() {
|
runToVsync() {
|
||||||
self.luacall('mamedbg.runToVsync()');
|
this.luacall('mamedbg.runToVsync()');
|
||||||
self.resume();
|
this.resume();
|
||||||
}
|
}
|
||||||
this.runUntilReturn = function() {
|
runUntilReturn() {
|
||||||
self.luacall('mamedbg.runUntilReturn()');
|
this.luacall('mamedbg.runUntilReturn()');
|
||||||
self.resume();
|
this.resume();
|
||||||
}
|
}
|
||||||
this.step = function() {
|
step() {
|
||||||
self.luacall('mamedbg.step()');
|
this.luacall('mamedbg.step()');
|
||||||
self.resume();
|
this.resume();
|
||||||
}
|
}
|
||||||
// TODO: other than z80
|
// TODO: other than z80
|
||||||
this.cpuStateToLongString = function(c) {
|
cpuStateToLongString(c) {
|
||||||
if (c.HL)
|
if (c.HL)
|
||||||
return cpuStateToLongString_Z80(c);
|
return cpuStateToLongString_Z80(c);
|
||||||
else
|
else
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { SampleAudio } from "../audio";
|
||||||
|
|
||||||
declare var jt; // 6502
|
declare var jt; // 6502
|
||||||
|
|
||||||
var APPLE2_PRESETS = [
|
const APPLE2_PRESETS = [
|
||||||
{id:'sieve.c', name:'Sieve'},
|
{id:'sieve.c', name:'Sieve'},
|
||||||
{id:'mandel.c', name:'Mandelbrot'},
|
{id:'mandel.c', name:'Mandelbrot'},
|
||||||
{id:'tgidemo.c', name:'TGI Graphics Demo'},
|
{id:'tgidemo.c', name:'TGI Graphics Demo'},
|
||||||
|
@ -19,15 +19,12 @@ var APPLE2_PRESETS = [
|
||||||
// {id:'tb_6502.s', name:'Tom Bombem (assembler game)'},
|
// {id:'tb_6502.s', name:'Tom Bombem (assembler game)'},
|
||||||
];
|
];
|
||||||
|
|
||||||
var GR_TXMODE = 1;
|
const GR_TXMODE = 1;
|
||||||
var GR_MIXMODE = 2;
|
const GR_MIXMODE = 2;
|
||||||
var GR_PAGE1 = 4;
|
const GR_PAGE1 = 4;
|
||||||
var GR_HIRES = 8;
|
const GR_HIRES = 8;
|
||||||
|
|
||||||
var Apple2Platform = function(mainElement) {
|
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new (Base6502Platform as any)();
|
|
||||||
|
|
||||||
|
const _Apple2Platform = function(mainElement) {
|
||||||
var cpuFrequency = 1023000;
|
var cpuFrequency = 1023000;
|
||||||
var cpuCyclesPerLine = 65;
|
var cpuCyclesPerLine = 65;
|
||||||
var cpu, ram, bus;
|
var cpu, ram, bus;
|
||||||
|
@ -50,11 +47,12 @@ var Apple2Platform = function(mainElement) {
|
||||||
var bank2rdoffset=0, bank2wroffset=0;
|
var bank2rdoffset=0, bank2wroffset=0;
|
||||||
var grparams;
|
var grparams;
|
||||||
|
|
||||||
this.getPresets = function() {
|
class Apple2Platform extends Base6502Platform {
|
||||||
|
|
||||||
|
getPresets() {
|
||||||
return APPLE2_PRESETS;
|
return APPLE2_PRESETS;
|
||||||
}
|
}
|
||||||
|
start() {
|
||||||
this.start = function() {
|
|
||||||
cpu = new jt.M6502();
|
cpu = new jt.M6502();
|
||||||
ram = new RAM(0x13000); // 64K + 16K LC RAM - 4K hardware
|
ram = new RAM(0x13000); // 64K + 16K LC RAM - 4K hardware
|
||||||
// ROM
|
// ROM
|
||||||
|
@ -183,7 +181,7 @@ var Apple2Platform = function(mainElement) {
|
||||||
timer = new AnimationTimer(60, this.advance.bind(this));
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.advance = function(novideo : boolean) {
|
advance(novideo : boolean) {
|
||||||
// 262.5 scanlines per frame
|
// 262.5 scanlines per frame
|
||||||
var clock = 0;
|
var clock = 0;
|
||||||
var debugCond = this.getDebugCallback();
|
var debugCond = this.getDebugCallback();
|
||||||
|
@ -214,6 +212,70 @@ var Apple2Platform = function(mainElement) {
|
||||||
this.restartDebugState(); // reset debug start state
|
this.restartDebugState(); // reset debug start state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadROM(title, data) {
|
||||||
|
pgmbin = data;
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
isRunning() {
|
||||||
|
return timer.isRunning();
|
||||||
|
}
|
||||||
|
pause() {
|
||||||
|
timer.stop();
|
||||||
|
audio.stop();
|
||||||
|
}
|
||||||
|
resume() {
|
||||||
|
timer.start();
|
||||||
|
audio.start();
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
cpu.reset();
|
||||||
|
// execute until $c600 boot
|
||||||
|
for (var i=0; i<2000000; i++) {
|
||||||
|
cpu.clockPulse();
|
||||||
|
if (this.getCPUState().PC == 0xc602) {
|
||||||
|
cpu.clockPulse();
|
||||||
|
cpu.clockPulse();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readAddress(addr) {
|
||||||
|
return bus.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadState(state) {
|
||||||
|
cpu.loadState(state.c);
|
||||||
|
ram.mem.set(state.b);
|
||||||
|
kbdlatch = state.kbd;
|
||||||
|
grswitch = state.gr;
|
||||||
|
auxRAMselected = state.lc.s;
|
||||||
|
auxRAMbank = state.lc.b;
|
||||||
|
writeinhibit = state.lc.w;
|
||||||
|
setupLanguageCardConstants();
|
||||||
|
}
|
||||||
|
saveState() {
|
||||||
|
return {
|
||||||
|
c:cpu.saveState(),
|
||||||
|
b:ram.mem.slice(0),
|
||||||
|
kbd:kbdlatch,
|
||||||
|
gr:grswitch,
|
||||||
|
lc:{s:auxRAMselected,b:auxRAMbank,w:writeinhibit},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
loadControlsState(state) {
|
||||||
|
kbdlatch = state.kbd;
|
||||||
|
}
|
||||||
|
saveControlsState() {
|
||||||
|
return {
|
||||||
|
kbd:kbdlatch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getCPUState() {
|
||||||
|
return cpu.saveState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function doLanguageCardIO(address, value)
|
function doLanguageCardIO(address, value)
|
||||||
{
|
{
|
||||||
switch (address & 0x0f) {
|
switch (address & 0x0f) {
|
||||||
|
@ -284,68 +346,7 @@ var Apple2Platform = function(mainElement) {
|
||||||
bank2wroffset = 0x3000; // map 0xd000-0xdfff -> 0x10000-0x10fff
|
bank2wroffset = 0x3000; // map 0xd000-0xdfff -> 0x10000-0x10fff
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
return new Apple2Platform(); // return inner class from constructor
|
||||||
pgmbin = data;
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isRunning = function() {
|
|
||||||
return timer.isRunning();
|
|
||||||
}
|
|
||||||
this.pause = function() {
|
|
||||||
timer.stop();
|
|
||||||
audio.stop();
|
|
||||||
}
|
|
||||||
this.resume = function() {
|
|
||||||
timer.start();
|
|
||||||
audio.start();
|
|
||||||
}
|
|
||||||
this.reset = function() {
|
|
||||||
cpu.reset();
|
|
||||||
// execute until $c600 boot
|
|
||||||
for (var i=0; i<2000000; i++) {
|
|
||||||
cpu.clockPulse();
|
|
||||||
if (this.getCPUState().PC == 0xc602) {
|
|
||||||
cpu.clockPulse();
|
|
||||||
cpu.clockPulse();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.readAddress = function(addr) {
|
|
||||||
return bus.read(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadState = function(state) {
|
|
||||||
cpu.loadState(state.c);
|
|
||||||
ram.mem.set(state.b);
|
|
||||||
kbdlatch = state.kbd;
|
|
||||||
grswitch = state.gr;
|
|
||||||
auxRAMselected = state.lc.s;
|
|
||||||
auxRAMbank = state.lc.b;
|
|
||||||
writeinhibit = state.lc.w;
|
|
||||||
setupLanguageCardConstants();
|
|
||||||
}
|
|
||||||
this.saveState = function() {
|
|
||||||
return {
|
|
||||||
c:cpu.saveState(),
|
|
||||||
b:ram.mem.slice(0),
|
|
||||||
kbd:kbdlatch,
|
|
||||||
gr:grswitch,
|
|
||||||
lc:{s:auxRAMselected,b:auxRAMbank,w:writeinhibit},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this.loadControlsState = function(state) {
|
|
||||||
kbdlatch = state.kbd;
|
|
||||||
}
|
|
||||||
this.saveControlsState = function() {
|
|
||||||
return {
|
|
||||||
kbd:kbdlatch,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this.getCPUState = function() {
|
|
||||||
return cpu.saveState();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var Apple2Display = function(pixels, apple) {
|
var Apple2Display = function(pixels, apple) {
|
||||||
|
@ -1015,12 +1016,10 @@ var APPLEIIGO_LZG = [
|
||||||
|
|
||||||
/// MAME support
|
/// MAME support
|
||||||
|
|
||||||
var Apple2MAMEPlatform = function(mainElement) {
|
class Apple2MAMEPlatform extends BaseMAMEPlatform {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new BaseMAMEPlatform();
|
|
||||||
|
|
||||||
this.start = function() {
|
start () {
|
||||||
self.startModule(mainElement, {
|
this.startModule(this.mainElement, {
|
||||||
jsfile:'mameapple2e.js',
|
jsfile:'mameapple2e.js',
|
||||||
biosfile:['apple2e.zip'],
|
biosfile:['apple2e.zip'],
|
||||||
//cfgfile:'nes.cfg',
|
//cfgfile:'nes.cfg',
|
||||||
|
@ -1035,16 +1034,16 @@ var Apple2MAMEPlatform = function(mainElement) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getOpcodeMetadata = getOpcodeMetadata_6502;
|
getOpcodeMetadata = getOpcodeMetadata_6502;
|
||||||
this.getDefaultExtension = function() { return ".c"; };
|
getDefaultExtension () { return ".c"; };
|
||||||
|
|
||||||
this.getPresets = function() { return APPLE2_PRESETS; }
|
getPresets () { return APPLE2_PRESETS; }
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM (title, data) {
|
||||||
this.loadROMFile(data);
|
this.loadROMFile(data);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PLATFORMS['apple2'] = Apple2Platform;
|
PLATFORMS['apple2'] = _Apple2Platform;
|
||||||
PLATFORMS['apple2-e'] = Apple2MAMEPlatform;
|
PLATFORMS['apple2-e'] = Apple2MAMEPlatform;
|
||||||
|
|
|
@ -12,7 +12,7 @@ var Atari8_PRESETS = [
|
||||||
|
|
||||||
var Atari8MAMEPlatform = function(mainElement) {
|
var Atari8MAMEPlatform = function(mainElement) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.__proto__ = new BaseMAMEPlatform();
|
this.__proto__ = new (BaseMAMEPlatform as any)();
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
this.loadROM = function(title, data) {
|
||||||
this.loadROMFile(data);
|
this.loadROMFile(data);
|
||||||
|
@ -47,7 +47,7 @@ var Atari800Platform = function(mainElement) {
|
||||||
|
|
||||||
var Atari5200Platform = function(mainElement) {
|
var Atari5200Platform = function(mainElement) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.__proto__ = new Atari8MAMEPlatform(mainElement);
|
this.__proto__ = new (Atari8MAMEPlatform as any)(mainElement);
|
||||||
|
|
||||||
this.start = function() {
|
this.start = function() {
|
||||||
self.startModule(mainElement, {
|
self.startModule(mainElement, {
|
||||||
|
|
|
@ -33,13 +33,10 @@ var ColecoVision_PRESETS = [
|
||||||
|
|
||||||
/// MAME support
|
/// MAME support
|
||||||
|
|
||||||
var ColecoVisionMAMEPlatform = function(mainElement) {
|
class ColecoVisionMAMEPlatform extends BaseMAMEPlatform {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new BaseMAMEPlatform();
|
|
||||||
|
|
||||||
//
|
start() {
|
||||||
this.start = function() {
|
this.startModule(this.mainElement, {
|
||||||
self.startModule(mainElement, {
|
|
||||||
jsfile:'mamecoleco.js',
|
jsfile:'mamecoleco.js',
|
||||||
cfgfile:'coleco.cfg',
|
cfgfile:'coleco.cfg',
|
||||||
biosfile:'coleco/313 10031-4005 73108a.u2',
|
biosfile:'coleco/313 10031-4005 73108a.u2',
|
||||||
|
@ -53,15 +50,15 @@ var ColecoVisionMAMEPlatform = function(mainElement) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM(title, data) {
|
||||||
this.loadROMFile(data);
|
this.loadROMFile(data);
|
||||||
this.loadRegion(":coleco_cart:rom", data);
|
this.loadRegion(":coleco_cart:rom", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getPresets = function() { return ColecoVision_PRESETS; }
|
getPresets() { return ColecoVision_PRESETS; }
|
||||||
|
|
||||||
this.getToolForFilename = getToolForFilename_z80;
|
getToolForFilename = getToolForFilename_z80;
|
||||||
this.getDefaultExtension = function() { return ".c"; };
|
getDefaultExtension() { return ".c"; };
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
|
@ -5,12 +5,12 @@ import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap,
|
||||||
import { hex } from "../util";
|
import { hex } from "../util";
|
||||||
import { MasterAudio, AY38910_Audio } from "../audio";
|
import { MasterAudio, AY38910_Audio } from "../audio";
|
||||||
|
|
||||||
var GALAXIAN_PRESETS = [
|
const GALAXIAN_PRESETS = [
|
||||||
{id:'gfxtest.c', name:'Graphics Test'},
|
{id:'gfxtest.c', name:'Graphics Test'},
|
||||||
{id:'shoot2.c', name:'Solarian Game'},
|
{id:'shoot2.c', name:'Solarian Game'},
|
||||||
];
|
];
|
||||||
|
|
||||||
var GALAXIAN_KEYCODE_MAP = makeKeycodeMap([
|
const GALAXIAN_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_SPACE, 0, 0x10], // P1
|
[Keys.VK_SPACE, 0, 0x10], // P1
|
||||||
[Keys.VK_LEFT, 0, 0x4],
|
[Keys.VK_LEFT, 0, 0x4],
|
||||||
[Keys.VK_RIGHT, 0, 0x8],
|
[Keys.VK_RIGHT, 0, 0x8],
|
||||||
|
@ -22,7 +22,7 @@ var GALAXIAN_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_2, 1, 0x2],
|
[Keys.VK_2, 1, 0x2],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var SCRAMBLE_KEYCODE_MAP = makeKeycodeMap([
|
const SCRAMBLE_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_UP, 0, -0x1], // P1
|
[Keys.VK_UP, 0, -0x1], // P1
|
||||||
[Keys.VK_SHIFT, 0, -0x2], // fire
|
[Keys.VK_SHIFT, 0, -0x2], // fire
|
||||||
[Keys.VK_7, 0, -0x4], // credit
|
[Keys.VK_7, 0, -0x4], // credit
|
||||||
|
@ -38,10 +38,7 @@ var SCRAMBLE_KEYCODE_MAP = makeKeycodeMap([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
var GalaxianPlatform = function(mainElement, options) {
|
const _GalaxianPlatform = function(mainElement, options) {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new (BaseZ80Platform as any)();
|
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var romSize = options.romSize || 0x4000;
|
var romSize = options.romSize || 0x4000;
|
||||||
var gfxBase = options.gfxBase || 0x2800;
|
var gfxBase = options.gfxBase || 0x2800;
|
||||||
|
@ -169,10 +166,6 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getPresets = function() {
|
|
||||||
return GALAXIAN_PRESETS;
|
|
||||||
}
|
|
||||||
|
|
||||||
var m_protection_state = 0;
|
var m_protection_state = 0;
|
||||||
var m_protection_result = 0;
|
var m_protection_result = 0;
|
||||||
function scramble_protection_w(addr,data) {
|
function scramble_protection_w(addr,data) {
|
||||||
|
@ -201,7 +194,19 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
return (bit << 5) | ((bit^1) << 7);
|
return (bit << 5) | ((bit^1) << 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.start = function() {
|
const bitcolors = [
|
||||||
|
0x000021, 0x000047, 0x000097, // red
|
||||||
|
0x002100, 0x004700, 0x009700, // green
|
||||||
|
0x510000, 0xae0000 // blue
|
||||||
|
];
|
||||||
|
|
||||||
|
class GalaxianPlatform extends BaseZ80Platform {
|
||||||
|
|
||||||
|
getPresets() {
|
||||||
|
return GALAXIAN_PRESETS;
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
ram = new RAM(0x800);
|
ram = new RAM(0x800);
|
||||||
vram = new RAM(0x400);
|
vram = new RAM(0x400);
|
||||||
oram = new RAM(0x100);
|
oram = new RAM(0x100);
|
||||||
|
@ -271,9 +276,6 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
isContended: function() { return false; },
|
isContended: function() { return false; },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.readAddress = function(a) {
|
|
||||||
return (a == 0x7000 || a == 0x7800) ? null : membus.read(a); // ignore watchdog
|
|
||||||
};
|
|
||||||
audio = new MasterAudio();
|
audio = new MasterAudio();
|
||||||
psg1 = new AY38910_Audio(audio);
|
psg1 = new AY38910_Audio(audio);
|
||||||
psg2 = new AY38910_Audio(audio);
|
psg2 = new AY38910_Audio(audio);
|
||||||
|
@ -288,7 +290,7 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
if (addr & 0x8) { psg2.setData(val); };
|
if (addr & 0x8) { psg2.setData(val); };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cpu = self.newCPU(membus, iobus);
|
cpu = this.newCPU(membus, iobus);
|
||||||
video = new RasterVideo(mainElement,264,264,{rotate:90});
|
video = new RasterVideo(mainElement,264,264,{rotate:90});
|
||||||
video.create();
|
video.create();
|
||||||
var idata = video.getFrameData();
|
var idata = video.getFrameData();
|
||||||
|
@ -297,7 +299,11 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
timer = new AnimationTimer(60, this.advance.bind(this));
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.advance = function(novideo : boolean) {
|
readAddress(a) {
|
||||||
|
return (a == 0x7000 || a == 0x7800) ? null : membus.read(a); // ignore watchdog
|
||||||
|
}
|
||||||
|
|
||||||
|
advance(novideo : boolean) {
|
||||||
var debugCond = this.getDebugCallback();
|
var debugCond = this.getDebugCallback();
|
||||||
var targetTstates = cpu.getTstates();
|
var targetTstates = cpu.getTstates();
|
||||||
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
||||||
|
@ -326,13 +332,7 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
this.restartDebugState(); // TODO: after interrupt?
|
this.restartDebugState(); // TODO: after interrupt?
|
||||||
}
|
}
|
||||||
|
|
||||||
var bitcolors = [
|
loadROM(title, data) {
|
||||||
0x000021, 0x000047, 0x000097, // red
|
|
||||||
0x002100, 0x004700, 0x009700, // green
|
|
||||||
0x510000, 0xae0000 // blue
|
|
||||||
];
|
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
|
||||||
rom = padBytes(data, romSize);
|
rom = padBytes(data, romSize);
|
||||||
|
|
||||||
palette = new Uint32Array(new ArrayBuffer(32*4));
|
palette = new Uint32Array(new ArrayBuffer(32*4));
|
||||||
|
@ -343,10 +343,10 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
if (((1<<j) & b))
|
if (((1<<j) & b))
|
||||||
palette[i] += bitcolors[j];
|
palette[i] += bitcolors[j];
|
||||||
}
|
}
|
||||||
self.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadState = function(state) {
|
loadState(state) {
|
||||||
cpu.loadState(state.c);
|
cpu.loadState(state.c);
|
||||||
ram.mem.set(state.b);
|
ram.mem.set(state.b);
|
||||||
vram.mem.set(state.bv);
|
vram.mem.set(state.bv);
|
||||||
|
@ -359,9 +359,9 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
inputs[1] = state.in1;
|
inputs[1] = state.in1;
|
||||||
inputs[2] = state.in2;
|
inputs[2] = state.in2;
|
||||||
}
|
}
|
||||||
this.saveState = function() {
|
saveState() {
|
||||||
return {
|
return {
|
||||||
c:self.getCPUState(),
|
c:this.getCPUState(),
|
||||||
b:ram.mem.slice(0),
|
b:ram.mem.slice(0),
|
||||||
bv:vram.mem.slice(0),
|
bv:vram.mem.slice(0),
|
||||||
bo:oram.mem.slice(0),
|
bo:oram.mem.slice(0),
|
||||||
|
@ -374,31 +374,46 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
in2:inputs[2],
|
in2:inputs[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.getCPUState = function() {
|
loadControlsState(state) {
|
||||||
|
inputs[0] = state.in0;
|
||||||
|
inputs[1] = state.in1;
|
||||||
|
inputs[2] = state.in2;
|
||||||
|
}
|
||||||
|
saveControlsState() {
|
||||||
|
return {
|
||||||
|
in0:inputs[0],
|
||||||
|
in1:inputs[1],
|
||||||
|
in2:inputs[2],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getCPUState() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
isRunning() {
|
||||||
return timer && timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
pause() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
audio.stop();
|
audio.stop();
|
||||||
}
|
}
|
||||||
this.resume = function() {
|
resume() {
|
||||||
timer.start();
|
timer.start();
|
||||||
audio.start();
|
audio.start();
|
||||||
}
|
}
|
||||||
this.reset = function() {
|
reset() {
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
//audio.reset();
|
//audio.reset();
|
||||||
if (!this.getDebugCallback()) cpu.setTstates(0); // TODO?
|
if (!this.getDebugCallback()) cpu.setTstates(0); // TODO?
|
||||||
watchdog_counter = INITIAL_WATCHDOG;
|
watchdog_counter = INITIAL_WATCHDOG;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GalaxianPlatform();
|
||||||
}
|
}
|
||||||
|
|
||||||
var GalaxianScramblePlatform = function(mainElement) {
|
const _GalaxianScramblePlatform = function(mainElement) {
|
||||||
this.__proto__ = new GalaxianPlatform(mainElement, {
|
return _GalaxianPlatform(mainElement, {
|
||||||
romSize: 0x5020,
|
romSize: 0x5020,
|
||||||
gfxBase: 0x4000,
|
gfxBase: 0x4000,
|
||||||
palBase: 0x5000,
|
palBase: 0x5000,
|
||||||
|
@ -409,5 +424,5 @@ var GalaxianScramblePlatform = function(mainElement) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PLATFORMS['galaxian'] = GalaxianPlatform;
|
PLATFORMS['galaxian'] = _GalaxianPlatform;
|
||||||
PLATFORMS['galaxian-scramble'] = GalaxianScramblePlatform;
|
PLATFORMS['galaxian-scramble'] = _GalaxianScramblePlatform;
|
||||||
|
|
|
@ -6,15 +6,13 @@ import { hex } from "../util";
|
||||||
|
|
||||||
// http://www.computerarcheology.com/Arcade/
|
// http://www.computerarcheology.com/Arcade/
|
||||||
|
|
||||||
var MW8080BW_PRESETS = [
|
const MW8080BW_PRESETS = [
|
||||||
{id:'gfxtest.c', name:'Graphics Test'},
|
{id:'gfxtest.c', name:'Graphics Test'},
|
||||||
{id:'shifter.c', name:'Sprite w/ Bit Shifter'},
|
{id:'shifter.c', name:'Sprite w/ Bit Shifter'},
|
||||||
{id:'game2.c', name:'Cosmic Impalas'},
|
{id:'game2.c', name:'Cosmic Impalas'},
|
||||||
];
|
];
|
||||||
|
|
||||||
var Midway8080BWPlatform = function(mainElement) {
|
const _Midway8080BWPlatform = function(mainElement) {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new (BaseZ80Platform as any)();
|
|
||||||
|
|
||||||
var cpu, ram, membus, iobus, rom;
|
var cpu, ram, membus, iobus, rom;
|
||||||
var probe;
|
var probe;
|
||||||
|
@ -23,13 +21,13 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
var bitshift_offset = 0;
|
var bitshift_offset = 0;
|
||||||
var bitshift_register = 0;
|
var bitshift_register = 0;
|
||||||
var watchdog_counter;
|
var watchdog_counter;
|
||||||
var cpuFrequency = 1996800;
|
const cpuFrequency = 1996800;
|
||||||
var cpuCyclesPerLine = cpuFrequency/(60*224); // TODO
|
const cpuCyclesPerLine = cpuFrequency/(60*224); // TODO
|
||||||
var INITIAL_WATCHDOG = 256;
|
const INITIAL_WATCHDOG = 256;
|
||||||
var PIXEL_ON = 0xffeeeeee;
|
const PIXEL_ON = 0xffeeeeee;
|
||||||
var PIXEL_OFF = 0xff000000;
|
const PIXEL_OFF = 0xff000000;
|
||||||
|
|
||||||
var SPACEINV_KEYCODE_MAP = makeKeycodeMap([
|
const SPACEINV_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_SPACE, 1, 0x10], // P1
|
[Keys.VK_SPACE, 1, 0x10], // P1
|
||||||
[Keys.VK_LEFT, 1, 0x20],
|
[Keys.VK_LEFT, 1, 0x20],
|
||||||
[Keys.VK_RIGHT, 1, 0x40],
|
[Keys.VK_RIGHT, 1, 0x40],
|
||||||
|
@ -41,11 +39,13 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
[Keys.VK_2, 1, 0x2],
|
[Keys.VK_2, 1, 0x2],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.getPresets = function() {
|
class Midway8080BWPlatform extends BaseZ80Platform {
|
||||||
|
|
||||||
|
getPresets() {
|
||||||
return MW8080BW_PRESETS;
|
return MW8080BW_PRESETS;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.start = function() {
|
start = function() {
|
||||||
ram = new RAM(0x2000);
|
ram = new RAM(0x2000);
|
||||||
//displayPCs = new Uint16Array(new ArrayBuffer(0x2000*2));
|
//displayPCs = new Uint16Array(new ArrayBuffer(0x2000*2));
|
||||||
membus = {
|
membus = {
|
||||||
|
@ -65,7 +65,6 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
]),
|
]),
|
||||||
isContended: function() { return false; },
|
isContended: function() { return false; },
|
||||||
};
|
};
|
||||||
this.readAddress = membus.read;
|
|
||||||
iobus = {
|
iobus = {
|
||||||
read: function(addr) {
|
read: function(addr) {
|
||||||
addr &= 0x3;
|
addr &= 0x3;
|
||||||
|
@ -116,7 +115,11 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
timer = new AnimationTimer(60, this.advance.bind(this));
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.advance = function(novideo : boolean) {
|
readAddress(addr) {
|
||||||
|
return membus.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
advance(novideo : boolean) {
|
||||||
var debugCond = this.getDebugCallback();
|
var debugCond = this.getDebugCallback();
|
||||||
var targetTstates = cpu.getTstates();
|
var targetTstates = cpu.getTstates();
|
||||||
for (var sl=0; sl<224; sl++) {
|
for (var sl=0; sl<224; sl++) {
|
||||||
|
@ -149,12 +152,12 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
this.restartDebugState();
|
this.restartDebugState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM(title, data) {
|
||||||
rom = padBytes(data, 0x2000);
|
rom = padBytes(data, 0x2000);
|
||||||
self.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadState = function(state) {
|
loadState(state) {
|
||||||
cpu.loadState(state.c);
|
cpu.loadState(state.c);
|
||||||
ram.mem.set(state.b);
|
ram.mem.set(state.b);
|
||||||
bitshift_register = state.bsr;
|
bitshift_register = state.bsr;
|
||||||
|
@ -164,9 +167,9 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
inputs[1] = state.in1;
|
inputs[1] = state.in1;
|
||||||
inputs[2] = state.in2;
|
inputs[2] = state.in2;
|
||||||
}
|
}
|
||||||
this.saveState = function() {
|
saveState() {
|
||||||
return {
|
return {
|
||||||
c:self.getCPUState(),
|
c:this.getCPUState(),
|
||||||
b:ram.mem.slice(0),
|
b:ram.mem.slice(0),
|
||||||
bsr:bitshift_register,
|
bsr:bitshift_register,
|
||||||
bso:bitshift_offset,
|
bso:bitshift_offset,
|
||||||
|
@ -176,24 +179,38 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
in2:inputs[2],
|
in2:inputs[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.getCPUState = function() {
|
loadControlsState(state) {
|
||||||
|
inputs[0] = state.in0;
|
||||||
|
inputs[1] = state.in1;
|
||||||
|
inputs[2] = state.in2;
|
||||||
|
}
|
||||||
|
saveControlsState() {
|
||||||
|
return {
|
||||||
|
in0:inputs[0],
|
||||||
|
in1:inputs[1],
|
||||||
|
in2:inputs[2],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getCPUState() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
isRunning() {
|
||||||
return timer && timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
pause() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
}
|
}
|
||||||
this.resume = function() {
|
resume() {
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
this.reset = function() {
|
reset() {
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
cpu.setTstates(0);
|
cpu.setTstates(0);
|
||||||
watchdog_counter = INITIAL_WATCHDOG;
|
watchdog_counter = INITIAL_WATCHDOG;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return new Midway8080BWPlatform();
|
||||||
}
|
}
|
||||||
|
|
||||||
PLATFORMS['mw8080bw'] = Midway8080BWPlatform;
|
PLATFORMS['mw8080bw'] = _Midway8080BWPlatform;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { SampleAudio } from "../audio";
|
||||||
|
|
||||||
declare var jsnes : any;
|
declare var jsnes : any;
|
||||||
|
|
||||||
var JSNES_PRESETS = [
|
const JSNES_PRESETS = [
|
||||||
{id:'ex0.asm', name:'Initialization (ASM)'},
|
{id:'ex0.asm', name:'Initialization (ASM)'},
|
||||||
{id:'ex1.asm', name:'Scrolling Demo (ASM)'},
|
{id:'ex1.asm', name:'Scrolling Demo (ASM)'},
|
||||||
{id:'ex2.asm', name:'Sprite Demo (ASM)'},
|
{id:'ex2.asm', name:'Sprite Demo (ASM)'},
|
||||||
|
@ -25,7 +25,7 @@ var JSNES_PRESETS = [
|
||||||
{id:'musicdemo.asm', name:'Famitone Demo (ASM)'},
|
{id:'musicdemo.asm', name:'Famitone Demo (ASM)'},
|
||||||
];
|
];
|
||||||
|
|
||||||
var NES_NESLIB_PRESETS = [
|
const NES_NESLIB_PRESETS = [
|
||||||
{id:'neslib1.c', name:'Text'},
|
{id:'neslib1.c', name:'Text'},
|
||||||
{id:'neslib2.c', name:'Sprites'},
|
{id:'neslib2.c', name:'Sprites'},
|
||||||
{id:'neslib3.c', name:'Cursor'},
|
{id:'neslib3.c', name:'Cursor'},
|
||||||
|
@ -33,7 +33,7 @@ var NES_NESLIB_PRESETS = [
|
||||||
{id:'chase/game.c', name:'Chase (example game)'},
|
{id:'chase/game.c', name:'Chase (example game)'},
|
||||||
];
|
];
|
||||||
|
|
||||||
var NES_CONIO_PRESETS = [
|
const NES_CONIO_PRESETS = [
|
||||||
{id:'ex0.asm', name:'ASM: Initialization'},
|
{id:'ex0.asm', name:'ASM: Initialization'},
|
||||||
{id:'ex1.asm', name:'ASM: Scrolling Demo'},
|
{id:'ex1.asm', name:'ASM: Scrolling Demo'},
|
||||||
{id:'hello.c', name:'C: Hello PPU'},
|
{id:'hello.c', name:'C: Hello PPU'},
|
||||||
|
@ -43,7 +43,7 @@ var NES_CONIO_PRESETS = [
|
||||||
|
|
||||||
/// JSNES
|
/// JSNES
|
||||||
|
|
||||||
var JSNES_KEYCODE_MAP = makeKeycodeMap([
|
const JSNES_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_Z, 0, 0],
|
[Keys.VK_Z, 0, 0],
|
||||||
[Keys.VK_X, 0, 1],
|
[Keys.VK_X, 0, 1],
|
||||||
[Keys.VK_2, 0, 2],
|
[Keys.VK_2, 0, 2],
|
||||||
|
@ -62,21 +62,22 @@ var JSNES_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_D, 1, 7],
|
[Keys.VK_D, 1, 7],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var JSNESPlatform = function(mainElement) {
|
const _JSNESPlatform = function(mainElement) {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new (Base6502Platform as any)();
|
|
||||||
this.debugPCDelta = 1;
|
|
||||||
|
|
||||||
var nes;
|
var nes;
|
||||||
var rom;
|
var rom;
|
||||||
var video, audio, timer;
|
var video, audio, timer;
|
||||||
var audioFrequency = 44030; //44100
|
const audioFrequency = 44030; //44100
|
||||||
var frameindex = 0;
|
var frameindex = 0;
|
||||||
var nsamples = 0;
|
var nsamples = 0;
|
||||||
|
|
||||||
this.getPresets = function() { return JSNES_PRESETS; }
|
class JSNESPlatform extends Base6502Platform {
|
||||||
|
debugPCDelta = 1;
|
||||||
|
|
||||||
this.start = function() {
|
getPresets() { return JSNES_PRESETS; }
|
||||||
|
|
||||||
|
start() {
|
||||||
|
var self = this;
|
||||||
video = new RasterVideo(mainElement,256,224);
|
video = new RasterVideo(mainElement,256,224);
|
||||||
audio = new SampleAudio(audioFrequency);
|
audio = new SampleAudio(audioFrequency);
|
||||||
video.create();
|
video.create();
|
||||||
|
@ -128,52 +129,51 @@ var JSNESPlatform = function(mainElement) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.advance = function(novideo : boolean) {
|
advance(novideo : boolean) {
|
||||||
nes.frame();
|
nes.frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM(title, data) {
|
||||||
var romstr = String.fromCharCode.apply(null, data);
|
var romstr = String.fromCharCode.apply(null, data);
|
||||||
nes.loadROM(romstr);
|
nes.loadROM(romstr);
|
||||||
frameindex = 0;
|
frameindex = 0;
|
||||||
}
|
}
|
||||||
this.newCodeAnalyzer = function() {
|
newCodeAnalyzer() {
|
||||||
return new CodeAnalyzer_nes(this);
|
return new CodeAnalyzer_nes(this);
|
||||||
}
|
}
|
||||||
this.getOriginPC = function() { // TODO: is actually NMI
|
getOriginPC() { // TODO: is actually NMI
|
||||||
return (this.readAddress(0xfffa) | (this.readAddress(0xfffb) << 8)) & 0xffff;
|
return (this.readAddress(0xfffa) | (this.readAddress(0xfffb) << 8)) & 0xffff;
|
||||||
}
|
}
|
||||||
this.getOpcodeMetadata = getOpcodeMetadata_6502;
|
getDefaultExtension() { return ".c"; };
|
||||||
this.getDefaultExtension = function() { return ".c"; };
|
|
||||||
|
|
||||||
this.reset = function() {
|
reset() {
|
||||||
//nes.cpu.reset(); // doesn't work right, crashes
|
//nes.cpu.reset(); // doesn't work right, crashes
|
||||||
nes.cpu.requestIrq(nes.cpu.IRQ_RESET);
|
nes.cpu.requestIrq(nes.cpu.IRQ_RESET);
|
||||||
}
|
}
|
||||||
this.isRunning = function() {
|
isRunning() {
|
||||||
return timer.isRunning();
|
return timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
pause() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
audio.stop();
|
audio.stop();
|
||||||
}
|
}
|
||||||
this.resume = function() {
|
resume() {
|
||||||
timer.start();
|
timer.start();
|
||||||
audio.start();
|
audio.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.runToVsync = function() {
|
runToVsync() {
|
||||||
var frame0 = frameindex;
|
var frame0 = frameindex;
|
||||||
this.runEval(function(c) { return frameindex>frame0; });
|
this.runEval(function(c) { return frameindex>frame0; });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getCPUState = function() {
|
getCPUState() {
|
||||||
var c = nes.cpu.toJSON();
|
var c = nes.cpu.toJSON();
|
||||||
this.copy6502REGvars(c);
|
this.copy6502REGvars(c);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
// TODO don't need to save ROM?
|
// TODO don't need to save ROM?
|
||||||
this.saveState = function() {
|
saveState() {
|
||||||
//var s = $.extend(true, {}, nes);
|
//var s = $.extend(true, {}, nes);
|
||||||
var s = nes.toJSON();
|
var s = nes.toJSON();
|
||||||
s.c = s.cpu;
|
s.c = s.cpu;
|
||||||
|
@ -181,9 +181,10 @@ var JSNESPlatform = function(mainElement) {
|
||||||
s.b = s.cpu.mem = s.cpu.mem.slice(0);
|
s.b = s.cpu.mem = s.cpu.mem.slice(0);
|
||||||
s.ppu.vramMem = s.ppu.vramMem.slice(0);
|
s.ppu.vramMem = s.ppu.vramMem.slice(0);
|
||||||
s.ppu.spriteMem = s.ppu.spriteMem.slice(0);
|
s.ppu.spriteMem = s.ppu.spriteMem.slice(0);
|
||||||
|
s.ctrl = this.saveControlsState();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
this.loadState = function(state) {
|
loadState(state) {
|
||||||
nes.fromJSON(state);
|
nes.fromJSON(state);
|
||||||
//nes.cpu.fromJSON(state.cpu);
|
//nes.cpu.fromJSON(state.cpu);
|
||||||
//nes.mmap.fromJSON(state.mmap);
|
//nes.mmap.fromJSON(state.mmap);
|
||||||
|
@ -191,12 +192,23 @@ var JSNESPlatform = function(mainElement) {
|
||||||
nes.cpu.mem = state.cpu.mem.slice(0);
|
nes.cpu.mem = state.cpu.mem.slice(0);
|
||||||
nes.ppu.vramMem = state.ppu.vramMem.slice(0);
|
nes.ppu.vramMem = state.ppu.vramMem.slice(0);
|
||||||
nes.ppu.spriteMem = state.ppu.spriteMem.slice(0);
|
nes.ppu.spriteMem = state.ppu.spriteMem.slice(0);
|
||||||
|
this.loadControlsState(state.ctrl);
|
||||||
//$.extend(nes, state);
|
//$.extend(nes, state);
|
||||||
}
|
}
|
||||||
this.readAddress = function(addr) {
|
saveControlsState() {
|
||||||
|
return {
|
||||||
|
c1: nes.controllers[1].state.slice(0),
|
||||||
|
c2: nes.controllers[2].state.slice(0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
loadControlsState(state) {
|
||||||
|
nes.controllers[1].state = state.c1;
|
||||||
|
nes.controllers[2].state = state.c2;
|
||||||
|
}
|
||||||
|
readAddress(addr) {
|
||||||
return nes.cpu.mem[addr] & 0xff;
|
return nes.cpu.mem[addr] & 0xff;
|
||||||
}
|
}
|
||||||
this.copy6502REGvars = function(c) {
|
copy6502REGvars(c) {
|
||||||
c.T = 0;
|
c.T = 0;
|
||||||
c.PC = c.REG_PC;
|
c.PC = c.REG_PC;
|
||||||
c.A = c.REG_ACC;
|
c.A = c.REG_ACC;
|
||||||
|
@ -214,10 +226,10 @@ var JSNESPlatform = function(mainElement) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getDebugCategories = function() {
|
getDebugCategories() {
|
||||||
return ['CPU','ZPRAM','Stack','PPU'];
|
return ['CPU','ZPRAM','Stack','PPU'];
|
||||||
}
|
}
|
||||||
this.getDebugInfo = function(category, state) {
|
getDebugInfo(category, state) {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case 'CPU': return cpuStateToLongString_6502(state.c);
|
case 'CPU': return cpuStateToLongString_6502(state.c);
|
||||||
case 'ZPRAM': return dumpRAM(state.b, 0x0, 0x100);
|
case 'ZPRAM': return dumpRAM(state.b, 0x0, 0x100);
|
||||||
|
@ -225,7 +237,7 @@ var JSNESPlatform = function(mainElement) {
|
||||||
case 'PPU': return this.ppuStateToLongString(state.ppu, state.b);
|
case 'PPU': return this.ppuStateToLongString(state.ppu, state.b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.ppuStateToLongString = function(ppu, mem) {
|
ppuStateToLongString(ppu, mem) {
|
||||||
var s = '';
|
var s = '';
|
||||||
var PPUFLAGS = [
|
var PPUFLAGS = [
|
||||||
["f_nmiOnVblank","NMI_ON_VBLANK"],
|
["f_nmiOnVblank","NMI_ON_VBLANK"],
|
||||||
|
@ -283,54 +295,57 @@ var JSNESPlatform = function(mainElement) {
|
||||||
*/
|
*/
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return new JSNESPlatform();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MAME support
|
/// MAME support
|
||||||
|
|
||||||
var NESMAMEPlatform = function(mainElement, lzgRom, romSize) {
|
class NESMAMEPlatform extends BaseMAMEPlatform {
|
||||||
var self = this;
|
// = function(mainElement, lzgRom, romSize) {
|
||||||
this.__proto__ = new BaseMAMEPlatform();
|
lzgRom;
|
||||||
|
romSize;
|
||||||
|
|
||||||
//
|
start() {
|
||||||
this.start = function() {
|
this.startModule(this.mainElement, {
|
||||||
self.startModule(mainElement, {
|
|
||||||
jsfile:'mamenes.js',
|
jsfile:'mamenes.js',
|
||||||
//cfgfile:'nes.cfg',
|
//cfgfile:'nes.cfg',
|
||||||
driver:'nes',
|
driver:'nes',
|
||||||
width:256*2,
|
width:256*2,
|
||||||
height:240*2,
|
height:240*2,
|
||||||
romfn:'/emulator/cart.nes',
|
romfn:'/emulator/cart.nes',
|
||||||
romsize:romSize,
|
romsize:this.romSize,
|
||||||
romdata:new Uint8Array(new lzgmini().decode(lzgRom).slice(0, romSize)),
|
romdata:new Uint8Array(new lzgmini().decode(this.lzgRom).slice(0, this.romSize)),
|
||||||
preInit:function(_self) {
|
preInit:function(_self) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getOpcodeMetadata = getOpcodeMetadata_6502;
|
getOpcodeMetadata = getOpcodeMetadata_6502;
|
||||||
this.getToolForFilename = getToolForFilename_6502;
|
getToolForFilename = getToolForFilename_6502;
|
||||||
this.getDefaultExtension = function() { return ".c"; };
|
getDefaultExtension() { return ".c"; };
|
||||||
}
|
}
|
||||||
|
|
||||||
var NESConIOPlatform = function(mainElement) {
|
class NESConIOPlatform extends NESMAMEPlatform {
|
||||||
var self = this;
|
lzgRom = NES_CONIO_ROM_LZG;
|
||||||
this.__proto__ = new NESMAMEPlatform(mainElement, NES_CONIO_ROM_LZG, 0xa010);
|
romSize = 0xa010;
|
||||||
|
|
||||||
this.getPresets = function() { return NES_CONIO_PRESETS; }
|
getPresets() { return NES_CONIO_PRESETS; }
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM(title, data) {
|
||||||
this.loadROMFile(data);
|
this.loadROMFile(data);
|
||||||
this.loadRegion(":nes_slot:cart:prg_rom", data.slice(0x10, 0x8010));
|
this.loadRegion(":nes_slot:cart:prg_rom", data.slice(0x10, 0x8010));
|
||||||
this.loadRegion(":nes_slot:cart:chr_rom", data.slice(0x8010, 0xa010));
|
this.loadRegion(":nes_slot:cart:chr_rom", data.slice(0x8010, 0xa010));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var NESLibPlatform = function(mainElement) {
|
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new NESMAMEPlatform(mainElement, NES_NESLIB_ROM_LZG, 0x8010);
|
|
||||||
|
|
||||||
this.getPresets = function() { return NES_NESLIB_PRESETS; }
|
class NESLibPlatform extends NESMAMEPlatform {
|
||||||
|
lzgRom = NES_NESLIB_ROM_LZG;
|
||||||
|
romSize = 0x8010;
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
getPresets() { return NES_NESLIB_PRESETS; }
|
||||||
|
|
||||||
|
loadROM(title, data) {
|
||||||
this.loadROMFile(data);
|
this.loadROMFile(data);
|
||||||
this.loadRegion(":nes_slot:cart:prg_rom", data.slice(0x10, 0x8010));
|
this.loadRegion(":nes_slot:cart:prg_rom", data.slice(0x10, 0x8010));
|
||||||
}
|
}
|
||||||
|
@ -338,7 +353,7 @@ var NESLibPlatform = function(mainElement) {
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
||||||
PLATFORMS['nes'] = JSNESPlatform;
|
PLATFORMS['nes'] = _JSNESPlatform;
|
||||||
PLATFORMS['nes-lib'] = NESLibPlatform;
|
PLATFORMS['nes-lib'] = NESLibPlatform;
|
||||||
PLATFORMS['nes-conio'] = NESConIOPlatform;
|
PLATFORMS['nes-conio'] = NESConIOPlatform;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ declare var platform : Platform; // global platform object
|
||||||
declare var Javatari : any;
|
declare var Javatari : any;
|
||||||
declare var jt : any; // 6502
|
declare var jt : any; // 6502
|
||||||
|
|
||||||
var VCS_PRESETS = [
|
const VCS_PRESETS = [
|
||||||
{id:'examples/hello', chapter:4, name:'Hello 6502 and TIA'},
|
{id:'examples/hello', chapter:4, name:'Hello 6502 and TIA'},
|
||||||
{id:'examples/vsync', chapter:5, name:'Painting on the CRT', title:'Color Bars'},
|
{id:'examples/vsync', chapter:5, name:'Painting on the CRT', title:'Color Bars'},
|
||||||
{id:'examples/playfield', chapter:6, name:'Playfield Graphics'},
|
{id:'examples/playfield', chapter:6, name:'Playfield Graphics'},
|
||||||
|
@ -47,13 +47,16 @@ Javatari.CARTRIDGE_CHANGE_DISABLED = true;
|
||||||
Javatari.DEBUG_SCANLINE_OVERFLOW = false; // TODO: make a switch
|
Javatari.DEBUG_SCANLINE_OVERFLOW = false; // TODO: make a switch
|
||||||
Javatari.AUDIO_BUFFER_SIZE = 256;
|
Javatari.AUDIO_BUFFER_SIZE = 256;
|
||||||
|
|
||||||
var VCSPlatform = function() {
|
class VCSPlatform {
|
||||||
var self = this;
|
|
||||||
this.paused = true;
|
|
||||||
|
|
||||||
this.getPresets = function() { return VCS_PRESETS; }
|
current_output;
|
||||||
|
recorder : EmuRecorder;
|
||||||
|
paused : boolean = true;
|
||||||
|
|
||||||
this.start = function() {
|
getPresets() { return VCS_PRESETS; }
|
||||||
|
|
||||||
|
start() {
|
||||||
|
var self = this;
|
||||||
$("#javatari-div").show();
|
$("#javatari-div").show();
|
||||||
Javatari.start();
|
Javatari.start();
|
||||||
// intercept clockPulse function
|
// intercept clockPulse function
|
||||||
|
@ -65,16 +68,16 @@ var VCSPlatform = function() {
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM(title, data) {
|
||||||
Javatari.loadROM(title, data);
|
Javatari.loadROM(title, data);
|
||||||
this.current_output = data; // TODO: use bus
|
this.current_output = data; // TODO: use bus
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getOpcodeMetadata = function(opcode, offset) {
|
getOpcodeMetadata(opcode, offset) {
|
||||||
return Javatari.getOpcodeMetadata(opcode, offset);
|
return Javatari.getOpcodeMetadata(opcode, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getRasterPosition = function() {
|
getRasterPosition() {
|
||||||
var clkfs = Javatari.room.console.getClocksFromFrameStart() - 1;
|
var clkfs = Javatari.room.console.getClocksFromFrameStart() - 1;
|
||||||
var row = Math.floor(clkfs/76);
|
var row = Math.floor(clkfs/76);
|
||||||
var col = clkfs - row*76;
|
var col = clkfs - row*76;
|
||||||
|
@ -84,10 +87,10 @@ var VCSPlatform = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Clock changes this on event, so it may not be current
|
// TODO: Clock changes this on event, so it may not be current
|
||||||
this.isRunning = function() {
|
isRunning() {
|
||||||
return Javatari.room && Javatari.room.console.isRunning();
|
return Javatari.room && Javatari.room.console.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
pause() {
|
||||||
//console.log('pause', this.paused, this.isRunning());
|
//console.log('pause', this.paused, this.isRunning());
|
||||||
if (!this.paused) {
|
if (!this.paused) {
|
||||||
this.paused = true;
|
this.paused = true;
|
||||||
|
@ -95,7 +98,7 @@ var VCSPlatform = function() {
|
||||||
Javatari.room.speaker.mute();
|
Javatari.room.speaker.mute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.resume = function() {
|
resume() {
|
||||||
//console.log('resume', this.paused, this.isRunning());
|
//console.log('resume', this.paused, this.isRunning());
|
||||||
if (this.paused) {
|
if (this.paused) {
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
|
@ -103,51 +106,52 @@ var VCSPlatform = function() {
|
||||||
Javatari.room.speaker.play();
|
Javatari.room.speaker.play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.advance = function() {
|
advance() {
|
||||||
Javatari.room.console.clockPulse();
|
Javatari.room.console.clockPulse();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.step = function() { Javatari.room.console.debugSingleStepCPUClock(); }
|
step() { Javatari.room.console.debugSingleStepCPUClock(); }
|
||||||
this.stepBack = function() { Javatari.room.console.debugStepBackInstruction(); }
|
stepBack() { Javatari.room.console.debugStepBackInstruction(); }
|
||||||
this.runEval = function(evalfunc) { Javatari.room.console.debugEval(evalfunc); }
|
runEval(evalfunc) { Javatari.room.console.debugEval(evalfunc); }
|
||||||
|
|
||||||
this.setupDebug = function(callback) {
|
setupDebug(callback) {
|
||||||
Javatari.room.console.onBreakpointHit = function(state) {
|
Javatari.room.console.onBreakpointHit = (state) => {
|
||||||
self.paused = true;
|
this.paused = true;
|
||||||
callback(state);
|
callback(state);
|
||||||
}
|
}
|
||||||
Javatari.room.speaker.mute();
|
Javatari.room.speaker.mute();
|
||||||
}
|
}
|
||||||
this.clearDebug = function() {
|
clearDebug() {
|
||||||
Javatari.room.console.disableDebug();
|
Javatari.room.console.disableDebug();
|
||||||
Javatari.room.console.onBreakpointHit = null;
|
Javatari.room.console.onBreakpointHit = null;
|
||||||
if (this.isRunning()) Javatari.room.speaker.play();
|
if (this.isRunning()) Javatari.room.speaker.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reset = function() {
|
reset() {
|
||||||
Javatari.room.console.powerOff();
|
Javatari.room.console.powerOff();
|
||||||
Javatari.room.console.resetDebug();
|
Javatari.room.console.resetDebug();
|
||||||
Javatari.room.console.powerOn();
|
Javatari.room.console.powerOn();
|
||||||
Javatari.room.speaker.play();
|
Javatari.room.speaker.play();
|
||||||
}
|
}
|
||||||
this.getOriginPC = function() {
|
getOriginPC() {
|
||||||
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
||||||
}
|
}
|
||||||
this.newCodeAnalyzer = function() {
|
newCodeAnalyzer() {
|
||||||
return new CodeAnalyzer_vcs(this);
|
return new CodeAnalyzer_vcs(this);
|
||||||
}
|
}
|
||||||
this.saveState = function() {
|
saveState() {
|
||||||
return Javatari.room.console.saveState();
|
return Javatari.room.console.saveState();
|
||||||
}
|
}
|
||||||
this.loadState = function(state) {
|
loadState(state) {
|
||||||
return Javatari.room.console.loadState(state);
|
return Javatari.room.console.loadState(state);
|
||||||
}
|
}
|
||||||
this.readAddress = function(addr) {
|
// TODO: load/save controls state
|
||||||
|
readAddress(addr) {
|
||||||
return this.current_output[addr & 0xfff]; // TODO: use bus to read
|
return this.current_output[addr & 0xfff]; // TODO: use bus to read
|
||||||
}
|
}
|
||||||
this.runUntilReturn = function() {
|
runUntilReturn() {
|
||||||
var depth = 1;
|
var depth = 1;
|
||||||
self.runEval(function(c) {
|
this.runEval(function(c) {
|
||||||
if (depth <= 0 && c.T == 0)
|
if (depth <= 0 && c.T == 0)
|
||||||
return true;
|
return true;
|
||||||
if (c.o == 0x20)
|
if (c.o == 0x20)
|
||||||
|
@ -157,38 +161,38 @@ var VCSPlatform = function() {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.cpuStateToLongString = function(c) {
|
cpuStateToLongString(c) {
|
||||||
return cpuStateToLongString_6502(c);
|
return cpuStateToLongString_6502(c);
|
||||||
}
|
}
|
||||||
this.getRAMForState = function(state) {
|
getRAMForState(state) {
|
||||||
return jt.Util.byteStringToUInt8Array(atob(state.r.b));
|
return jt.Util.byteStringToUInt8Array(atob(state.r.b));
|
||||||
}
|
}
|
||||||
this.ramStateToLongString = function(state) {
|
ramStateToLongString(state) {
|
||||||
var ram = self.getRAMForState(state);
|
var ram = this.getRAMForState(state);
|
||||||
return "\n" + dumpRAM(ram, 0x80, 0x80);
|
return "\n" + dumpRAM(ram, 0x80, 0x80);
|
||||||
}
|
}
|
||||||
this.getToolForFilename = function(fn) {
|
getToolForFilename(fn) {
|
||||||
return "dasm";
|
return "dasm";
|
||||||
}
|
}
|
||||||
this.getDefaultExtension = function() { return ".a"; };
|
getDefaultExtension() { return ".a"; };
|
||||||
|
|
||||||
this.getDebugCategories = function() {
|
getDebugCategories() {
|
||||||
return ['CPU','PIA','TIA'];
|
return ['CPU','PIA','TIA'];
|
||||||
}
|
}
|
||||||
this.getDebugInfo = function(category, state) {
|
getDebugInfo(category, state) {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case 'CPU': return this.cpuStateToLongString(state.c);
|
case 'CPU': return this.cpuStateToLongString(state.c);
|
||||||
case 'PIA': return this.ramStateToLongString(state) + "\n" + this.piaStateToLongString(state.p);
|
case 'PIA': return this.ramStateToLongString(state) + "\n" + this.piaStateToLongString(state.p);
|
||||||
case 'TIA': return this.tiaStateToLongString(state.t);
|
case 'TIA': return this.tiaStateToLongString(state.t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.piaStateToLongString = function(p) {
|
piaStateToLongString(p) {
|
||||||
return "Timer " + p.t + "/" + p.c + "\n";
|
return "Timer " + p.t + "/" + p.c + "\n";
|
||||||
}
|
}
|
||||||
this.tiaStateToLongString = function(t) {
|
tiaStateToLongString(t) {
|
||||||
var pos = this.getRasterPosition();
|
var pos = this.getRasterPosition();
|
||||||
var s = '';
|
var s = '';
|
||||||
s += "H" + lpad(pos.x,5) + " V" + lpad(pos.y,5) + " ";
|
s += "H" + lpad(pos.x.toString(),5) + " V" + lpad(pos.y.toString(),5) + " ";
|
||||||
s += (t.vs?"VSYNC ":"- ") + (t.vb?"VBLANK ":"- ") + "\n";
|
s += (t.vs?"VSYNC ":"- ") + (t.vb?"VBLANK ":"- ") + "\n";
|
||||||
s += "\n";
|
s += "\n";
|
||||||
s += "Playfield " + t.f + "\n";
|
s += "Playfield " + t.f + "\n";
|
||||||
|
@ -214,13 +218,13 @@ var VCSPlatform = function() {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setRecorder = function(recorder : EmuRecorder) : void {
|
setRecorder(recorder : EmuRecorder) : void {
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
}
|
}
|
||||||
this.updateRecorder = function() {
|
updateRecorder() {
|
||||||
// are we recording and do we need to save a frame?
|
// are we recording and do we need to save a frame?
|
||||||
if (this.recorder && !this.paused && this.isRunning() && this.recorder.frameRequested()) {
|
if (this.recorder && !this.paused && this.isRunning() && this.recorder.frameRequested()) {
|
||||||
this.recorder.recordFrame(this, this.saveState());
|
this.recorder.recordFrame(this.saveState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -231,13 +235,12 @@ function nonegstr(n) {
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
var VCSMAMEPlatform = function(mainElement) {
|
class VCSMAMEPlatform extends BaseMAMEPlatform {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new BaseMAMEPlatform();
|
|
||||||
|
|
||||||
// MCFG_SCREEN_RAW_PARAMS( MASTER_CLOCK_NTSC, 228, 26, 26 + 160 + 16, 262, 24 , 24 + 192 + 31 )
|
// MCFG_SCREEN_RAW_PARAMS( MASTER_CLOCK_NTSC, 228, 26, 26 + 160 + 16, 262, 24 , 24 + 192 + 31 )
|
||||||
this.start = function() {
|
|
||||||
self.startModule(mainElement, {
|
start = function() {
|
||||||
|
this.startModule(this.mainElement, {
|
||||||
jsfile:'mamea2600.js',
|
jsfile:'mamea2600.js',
|
||||||
driver:'a2600',
|
driver:'a2600',
|
||||||
width:176*2,
|
width:176*2,
|
||||||
|
@ -247,27 +250,21 @@ var VCSMAMEPlatform = function(mainElement) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM = function(title, data) {
|
||||||
this.loadROMFile(data);
|
this.loadROMFile(data);
|
||||||
this.loadRegion(":cartslot:cart:rom", data);
|
this.loadRegion(":cartslot:cart:rom", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getPresets = function() { return VCS_PRESETS; }
|
getPresets = function() { return VCS_PRESETS; }
|
||||||
|
|
||||||
this.getToolForFilename = function(fn) {
|
getToolForFilename = function(fn) {
|
||||||
return "dasm";
|
return "dasm";
|
||||||
}
|
}
|
||||||
this.getDefaultExtension = function() { return ".a"; };
|
getDefaultExtension = function() { return ".a"; };
|
||||||
|
|
||||||
this.getOriginPC = function() {
|
getOriginPC = function() {
|
||||||
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
this.getOpcodeMetadata = function(opcode, offset) {
|
|
||||||
return Javatari.getOpcodeMetadata(opcode, offset);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
|
|
|
@ -169,6 +169,14 @@ var AtariVectorPlatform = function(mainElement) {
|
||||||
nmic:nmicount
|
nmic:nmicount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.loadControlsState = function(state) {
|
||||||
|
switches.set(state.sw);
|
||||||
|
}
|
||||||
|
this.saveControlsState = function() {
|
||||||
|
return {
|
||||||
|
sw:switches.slice(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
this.getCPUState = function() {
|
this.getCPUState = function() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
@ -308,6 +316,14 @@ var AtariColorVectorPlatform = function(mainElement) {
|
||||||
nmic:nmicount
|
nmic:nmicount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.loadControlsState = function(state) {
|
||||||
|
switches.set(state.sw);
|
||||||
|
}
|
||||||
|
this.saveControlsState = function() {
|
||||||
|
return {
|
||||||
|
sw:switches.slice(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
this.getCPUState = function() {
|
this.getCPUState = function() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
@ -431,6 +447,14 @@ var Z80ColorVectorPlatform = function(mainElement, proto) {
|
||||||
mr:mathram.slice(0),
|
mr:mathram.slice(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.loadControlsState = function(state) {
|
||||||
|
switches.set(state.sw);
|
||||||
|
}
|
||||||
|
this.saveControlsState = function() {
|
||||||
|
return {
|
||||||
|
sw:switches.slice(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
this.getCPUState = function() {
|
this.getCPUState = function() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap,
|
||||||
import { hex } from "../util";
|
import { hex } from "../util";
|
||||||
import { MasterAudio, AY38910_Audio } from "../audio";
|
import { MasterAudio, AY38910_Audio } from "../audio";
|
||||||
|
|
||||||
var VICDUAL_PRESETS = [
|
const VICDUAL_PRESETS = [
|
||||||
{id:'minimal.c', name:'Minimal Example'},
|
{id:'minimal.c', name:'Minimal Example'},
|
||||||
{id:'hello.c', name:'Hello World'},
|
{id:'hello.c', name:'Hello World'},
|
||||||
{id:'gfxtest.c', name:'Graphics Test'},
|
{id:'gfxtest.c', name:'Graphics Test'},
|
||||||
|
@ -15,31 +15,30 @@ var VICDUAL_PRESETS = [
|
||||||
{id:'music.c', name:'Music Player'},
|
{id:'music.c', name:'Music Player'},
|
||||||
];
|
];
|
||||||
|
|
||||||
var VicDualPlatform = function(mainElement) {
|
const _VicDualPlatform = function(mainElement) {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new (BaseZ80Platform as any)();
|
|
||||||
|
|
||||||
var cpu, ram, membus, iobus, rom;
|
var cpu, ram, membus, iobus, rom;
|
||||||
var video, audio, psg, timer, pixels;
|
var video, audio, psg, timer, pixels;
|
||||||
var inputs = [0xff, 0xff, 0xff, 0xff^0x8]; // most things active low
|
var inputs = [0xff, 0xff, 0xff, 0xff^0x8]; // most things active low
|
||||||
var palbank = 0;
|
var palbank = 0;
|
||||||
|
|
||||||
var XTAL = 15468000.0;
|
const XTAL = 15468000.0;
|
||||||
var scanlinesPerFrame = 0x106;
|
const scanlinesPerFrame = 0x106;
|
||||||
var vblankStart = 0xe0;
|
const vblankStart = 0xe0;
|
||||||
var vsyncStart = 0xec;
|
const vsyncStart = 0xec;
|
||||||
var vsyncEnd = 0xf0;
|
const vsyncEnd = 0xf0;
|
||||||
var cpuFrequency = XTAL/8;
|
const cpuFrequency = XTAL/8;
|
||||||
var hsyncFrequency = XTAL/3/scanlinesPerFrame;
|
const hsyncFrequency = XTAL/3/scanlinesPerFrame;
|
||||||
var vsyncFrequency = hsyncFrequency/0x148;
|
const vsyncFrequency = hsyncFrequency/0x148;
|
||||||
var cpuCyclesPerLine = cpuFrequency/hsyncFrequency;
|
const cpuCyclesPerLine = cpuFrequency/hsyncFrequency;
|
||||||
var timerFrequency = 500; // input 2 bit 0x8
|
const timerFrequency = 500; // input 2 bit 0x8
|
||||||
var cyclesPerTimerTick = cpuFrequency / (2 * timerFrequency);
|
const cyclesPerTimerTick = cpuFrequency / (2 * timerFrequency);
|
||||||
|
|
||||||
var reset_disable = false;
|
var reset_disable = false;
|
||||||
var reset_disable_timer;
|
var reset_disable_timer;
|
||||||
var framestats;
|
var framestats;
|
||||||
|
|
||||||
var palette = [
|
const palette = [
|
||||||
0xff000000, // black
|
0xff000000, // black
|
||||||
0xff0000ff, // red
|
0xff0000ff, // red
|
||||||
0xff00ff00, // green
|
0xff00ff00, // green
|
||||||
|
@ -50,6 +49,7 @@ var VicDualPlatform = function(mainElement) {
|
||||||
0xffffffff // white
|
0xffffffff // white
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// default PROM
|
||||||
var colorprom = [
|
var colorprom = [
|
||||||
0xe0,0x60,0x20,0x60, 0xc0,0x60,0x40,0xc0,
|
0xe0,0x60,0x20,0x60, 0xc0,0x60,0x40,0xc0,
|
||||||
0x20,0x40,0x60,0x80, 0xa0,0xc0,0xe0,0x0e,
|
0x20,0x40,0x60,0x80, 0xa0,0xc0,0xe0,0x0e,
|
||||||
|
@ -85,7 +85,7 @@ var VicDualPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var CARNIVAL_KEYCODE_MAP = makeKeycodeMap([
|
const CARNIVAL_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.VK_SPACE, 2, -0x20],
|
[Keys.VK_SPACE, 2, -0x20],
|
||||||
[Keys.VK_SHIFT, 2, -0x40],
|
[Keys.VK_SHIFT, 2, -0x40],
|
||||||
[Keys.VK_LEFT, 1, -0x10],
|
[Keys.VK_LEFT, 1, -0x10],
|
||||||
|
@ -97,11 +97,13 @@ var VicDualPlatform = function(mainElement) {
|
||||||
[Keys.VK_5, 3, 0x8],
|
[Keys.VK_5, 3, 0x8],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.getPresets = function() {
|
class VicDualPlatform extends BaseZ80Platform {
|
||||||
|
|
||||||
|
getPresets() {
|
||||||
return VICDUAL_PRESETS;
|
return VICDUAL_PRESETS;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.start = function() {
|
start() {
|
||||||
ram = new RAM(0x1000);
|
ram = new RAM(0x1000);
|
||||||
membus = {
|
membus = {
|
||||||
read: newAddressDecoder([
|
read: newAddressDecoder([
|
||||||
|
@ -113,7 +115,6 @@ var VicDualPlatform = function(mainElement) {
|
||||||
]),
|
]),
|
||||||
isContended: function() { return false; },
|
isContended: function() { return false; },
|
||||||
};
|
};
|
||||||
this.readAddress = membus.read;
|
|
||||||
iobus = {
|
iobus = {
|
||||||
read: function(addr) {
|
read: function(addr) {
|
||||||
return inputs[addr&3];
|
return inputs[addr&3];
|
||||||
|
@ -145,7 +146,11 @@ var VicDualPlatform = function(mainElement) {
|
||||||
timer = new AnimationTimer(60, this.advance.bind(this));
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.advance = function(novideo : boolean) {
|
readAddress(addr) {
|
||||||
|
return membus.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
advance(novideo : boolean) {
|
||||||
var targetTstates = cpu.getTstates();
|
var targetTstates = cpu.getTstates();
|
||||||
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
||||||
inputs[2] &= ~0x8;
|
inputs[2] &= ~0x8;
|
||||||
|
@ -162,26 +167,23 @@ var VicDualPlatform = function(mainElement) {
|
||||||
this.restartDebugState();
|
this.restartDebugState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
loadROM(title, data) {
|
||||||
if (data.length >= 0x4020 && (data[0x4000] || data[0x401f])) {
|
if (data.length >= 0x4020 && (data[0x4000] || data[0x401f])) {
|
||||||
colorprom = data.slice(0x4000,0x4020);
|
colorprom = data.slice(0x4000,0x4020);
|
||||||
}
|
}
|
||||||
rom = padBytes(data, 0x4040);
|
rom = padBytes(data, 0x4040);
|
||||||
self.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadState = function(state) {
|
loadState(state) {
|
||||||
cpu.loadState(state.c);
|
cpu.loadState(state.c);
|
||||||
ram.mem.set(state.b);
|
ram.mem.set(state.b);
|
||||||
inputs[0] = state.in0;
|
this.loadControlsState(state);
|
||||||
inputs[1] = state.in1;
|
|
||||||
inputs[2] = state.in2;
|
|
||||||
inputs[3] = state.in3;
|
|
||||||
palbank = state.pb;
|
palbank = state.pb;
|
||||||
}
|
}
|
||||||
this.saveState = function() {
|
saveState() {
|
||||||
return {
|
return {
|
||||||
c:self.getCPUState(),
|
c:this.getCPUState(),
|
||||||
b:ram.mem.slice(0),
|
b:ram.mem.slice(0),
|
||||||
in0:inputs[0],
|
in0:inputs[0],
|
||||||
in1:inputs[1],
|
in1:inputs[1],
|
||||||
|
@ -190,32 +192,48 @@ var VicDualPlatform = function(mainElement) {
|
||||||
pb:palbank,
|
pb:palbank,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.getCPUState = function() {
|
loadControlsState(state) {
|
||||||
|
inputs[0] = state.in0;
|
||||||
|
inputs[1] = state.in1;
|
||||||
|
inputs[2] = state.in2;
|
||||||
|
inputs[3] = state.in3;
|
||||||
|
}
|
||||||
|
saveControlsState() {
|
||||||
|
return {
|
||||||
|
in0:inputs[0],
|
||||||
|
in1:inputs[1],
|
||||||
|
in2:inputs[2],
|
||||||
|
in3:inputs[3]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getCPUState() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
isRunning() {
|
||||||
return timer && timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
pause() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
audio.stop();
|
audio.stop();
|
||||||
}
|
}
|
||||||
this.resume = function() {
|
resume() {
|
||||||
timer.start();
|
timer.start();
|
||||||
audio.start();
|
audio.start();
|
||||||
}
|
}
|
||||||
this.reset = function() {
|
reset() {
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
psg.reset();
|
psg.reset();
|
||||||
if (!this.getDebugCallback()) cpu.setTstates(0); // TODO?
|
if (!this.getDebugCallback()) cpu.setTstates(0); // TODO?
|
||||||
}
|
}
|
||||||
this.setFrameStats = function(on) {
|
setFrameStats(on) {
|
||||||
framestats = on ? {
|
framestats = on ? {
|
||||||
palette: palette,
|
palette: palette,
|
||||||
layers: {width:256, height:224, tiles:[]}
|
layers: {width:256, height:224, tiles:[]}
|
||||||
} : null;
|
} : null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return new VicDualPlatform();
|
||||||
}
|
}
|
||||||
|
|
||||||
PLATFORMS['vicdual'] = VicDualPlatform;
|
PLATFORMS['vicdual'] = _VicDualPlatform;
|
||||||
|
|
|
@ -364,7 +364,7 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||||
cpu.loadState(state.c);
|
cpu.loadState(state.c);
|
||||||
ram.mem.set(state.b);
|
ram.mem.set(state.b);
|
||||||
nvram.mem.set(state.nvram);
|
nvram.mem.set(state.nvram);
|
||||||
//pia6821.set(state.pia);
|
pia6821.set(state.pia);
|
||||||
blitregs.set(state.blt);
|
blitregs.set(state.blt);
|
||||||
watchdog_counter = state.wdc;
|
watchdog_counter = state.wdc;
|
||||||
banksel = state.bs;
|
banksel = state.bs;
|
||||||
|
@ -382,6 +382,14 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||||
ps:portsel,
|
ps:portsel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
this.loadControlsState = function(state) {
|
||||||
|
pia6821.set(state.pia);
|
||||||
|
}
|
||||||
|
this.saveControlsState = function() {
|
||||||
|
return {
|
||||||
|
pia:pia6821.slice(0),
|
||||||
|
};
|
||||||
|
}
|
||||||
this.getCPUState = function() {
|
this.getCPUState = function() {
|
||||||
return cpu.saveState();
|
return cpu.saveState();
|
||||||
}
|
}
|
||||||
|
|
14
src/ui.ts
14
src/ui.ts
|
@ -951,6 +951,13 @@ function loadSharedFile(sharekey : string) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadScript(scriptfn, onload) {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.onload = onload;
|
||||||
|
script.src = scriptfn;
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
// start
|
// start
|
||||||
function startUI(loadplatform : boolean) {
|
function startUI(loadplatform : boolean) {
|
||||||
installErrorHandler();
|
installErrorHandler();
|
||||||
|
@ -975,14 +982,11 @@ function startUI(loadplatform : boolean) {
|
||||||
// load and start platform object
|
// load and start platform object
|
||||||
if (loadplatform) {
|
if (loadplatform) {
|
||||||
var scriptfn = 'gen/platform/' + platform_id.split(/[.-]/)[0] + '.js';
|
var scriptfn = 'gen/platform/' + platform_id.split(/[.-]/)[0] + '.js';
|
||||||
var script = document.createElement('script');
|
loadScript(scriptfn, () => {
|
||||||
script.onload = function() {
|
|
||||||
console.log("loaded platform", platform_id);
|
console.log("loaded platform", platform_id);
|
||||||
startPlatform();
|
startPlatform();
|
||||||
showWelcomeMessage();
|
showWelcomeMessage();
|
||||||
};
|
});
|
||||||
script.src = scriptfn;
|
|
||||||
document.getElementsByTagName('head')[0].appendChild(script);
|
|
||||||
} else {
|
} else {
|
||||||
startPlatform();
|
startPlatform();
|
||||||
showWelcomeMessage();
|
showWelcomeMessage();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user