2017-01-03 15:43:40 +00:00
|
|
|
"use strict";
|
2016-12-31 16:05:22 +00:00
|
|
|
|
2017-01-03 15:43:40 +00:00
|
|
|
var VCS_PRESETS = [
|
2016-12-31 16:05:22 +00:00
|
|
|
{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/playfield', chapter:6, name:'Playfield Graphics'},
|
|
|
|
{id:'examples/sprite', chapter:7, name:'Players and Sprites'},
|
|
|
|
{id:'examples/timing2', chapter:9, name:'Fine Positioning', title:'Fine Position'},
|
|
|
|
{id:'examples/missiles', chapter:10, name:'Player/Missile Graphics', title:'Player/Missile'},
|
|
|
|
{id:'examples/complexscene', chapter:15, name:'Complex Scene I'},
|
|
|
|
{id:'examples/complexscene2', chapter:16, name:'Complex Scene II'},
|
|
|
|
{id:'examples/scoreboard', chapter:18, name:'Scoreboard'},
|
|
|
|
{id:'examples/collisions', chapter:19, name:'Collisions'},
|
|
|
|
{id:'examples/bitmap', chapter:20, name:'Async Playfield: Bitmap', title:'Async PF Bitmap'},
|
|
|
|
{id:'examples/brickgame', chapter:21, name:'Async Playfield: Bricks', title:'Async PF Bricks'},
|
|
|
|
// {id:'examples/multisprite1', chapter:8, name:'Sprite Kernel'},
|
|
|
|
{id:'examples/bigsprite', chapter:22, name:'A Big 48-Pixel Sprite', title:'48-Pixel Sprite'},
|
|
|
|
{id:'examples/tinyfonts2', chapter:23, name:'Tiny Text'},
|
|
|
|
{id:'examples/score6', chapter:24, name:'6-Digit Score'},
|
|
|
|
{id:'examples/retrigger', chapter:26, name:'Sprite Formations'},
|
|
|
|
// {id:'examples/tinyfonts', chapter:23, name:'Tiny Fonts, Slow'},
|
|
|
|
{id:'examples/multisprite3', chapter:28, name:'Multisprites'},
|
|
|
|
{id:'examples/procgen1', chapter:30, name:'Procedural Generation'},
|
|
|
|
{id:'examples/lines', chapter:31, name:'Drawing Lines'},
|
|
|
|
// {id:'examples/piatable', name:'Timer Table'},
|
|
|
|
{id:'examples/musicplayer', chapter:32, name:'Music Player'},
|
|
|
|
{id:'examples/road', chapter:33, name:'Pseudo 3D Road'},
|
|
|
|
{id:'examples/bankswitching', chapter:35, name:'Bankswitching'},
|
|
|
|
{id:'examples/wavetable', chapter:36, name:'Wavetable Sound'},
|
2017-05-25 19:49:30 +00:00
|
|
|
{id:'examples/fracpitch', name:'Fractional Pitch'},
|
2017-04-09 13:33:38 +00:00
|
|
|
// {id:'examples/music2', name:'Pitch-Accurate Music'},
|
2016-12-31 16:05:22 +00:00
|
|
|
// {id:'examples/fullgame', name:'Thru Hike: The Game', title:'Thru Hike'},
|
|
|
|
];
|
|
|
|
|
2017-01-03 01:42:15 +00:00
|
|
|
Javatari.AUTO_START = false;
|
2016-12-31 16:05:22 +00:00
|
|
|
Javatari.SHOW_ERRORS = false;
|
|
|
|
Javatari.CARTRIDGE_CHANGE_DISABLED = true;
|
|
|
|
Javatari.DEBUG_SCANLINE_OVERFLOW = false; // TODO: make a switch
|
|
|
|
Javatari.AUDIO_BUFFER_SIZE = 256;
|
|
|
|
|
2017-01-03 15:43:40 +00:00
|
|
|
var VCSPlatform = function() {
|
2016-12-31 16:05:22 +00:00
|
|
|
var self = this;
|
|
|
|
|
2017-01-03 15:43:40 +00:00
|
|
|
this.getPresets = function() { return VCS_PRESETS; }
|
|
|
|
|
2017-01-03 01:42:15 +00:00
|
|
|
this.start = function() {
|
2018-03-24 22:13:27 +00:00
|
|
|
$("#javatari-div").show();
|
2017-01-03 01:42:15 +00:00
|
|
|
Javatari.start();
|
|
|
|
}
|
|
|
|
|
2016-12-31 16:05:22 +00:00
|
|
|
this.loadROM = function(title, data) {
|
|
|
|
Javatari.loadROM(title, data);
|
|
|
|
this.current_output = data; // TODO: use bus
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getOpcodeMetadata = function(opcode, offset) {
|
|
|
|
return Javatari.getOpcodeMetadata(opcode, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getRasterPosition = function() {
|
|
|
|
var clkfs = Javatari.room.console.getClocksFromFrameStart() - 1;
|
|
|
|
var row = Math.floor(clkfs/76);
|
|
|
|
var col = clkfs - row*76;
|
|
|
|
var xpos = col*3-68;
|
|
|
|
var ypos = row-39;
|
|
|
|
return {x:xpos, y:ypos};
|
|
|
|
}
|
|
|
|
|
2017-04-19 01:18:53 +00:00
|
|
|
this.isRunning = function() { return Javatari.room && Javatari.room.console.isRunning(); }
|
2018-08-06 18:22:06 +00:00
|
|
|
this.pause = function() { Javatari.room.console.pause(); Javatari.room.speaker.mute(); }
|
|
|
|
this.resume = function() { Javatari.room.console.go(); Javatari.room.speaker.play(); }
|
2016-12-31 16:05:22 +00:00
|
|
|
this.step = function() { Javatari.room.console.debugSingleStepCPUClock(); }
|
2017-01-12 03:28:29 +00:00
|
|
|
this.stepBack = function() { Javatari.room.console.debugStepBackInstruction(); }
|
2017-01-06 16:57:28 +00:00
|
|
|
this.runEval = function(evalfunc) { Javatari.room.console.debugEval(evalfunc); }
|
2016-12-31 16:05:22 +00:00
|
|
|
|
|
|
|
this.setupDebug = function(callback) {
|
|
|
|
Javatari.room.console.onBreakpointHit = callback;
|
2018-08-06 18:22:06 +00:00
|
|
|
Javatari.room.speaker.mute();
|
2016-12-31 16:05:22 +00:00
|
|
|
}
|
|
|
|
this.clearDebug = function() {
|
|
|
|
Javatari.room.console.disableDebug();
|
|
|
|
Javatari.room.console.onBreakpointHit = null;
|
2018-08-06 18:22:06 +00:00
|
|
|
if (this.isRunning()) Javatari.room.speaker.play();
|
2016-12-31 16:05:22 +00:00
|
|
|
}
|
|
|
|
this.reset = function() {
|
|
|
|
Javatari.room.console.powerOff();
|
|
|
|
Javatari.room.console.resetDebug();
|
|
|
|
Javatari.room.console.powerOn();
|
2018-08-06 18:22:06 +00:00
|
|
|
Javatari.room.speaker.play();
|
2016-12-31 16:05:22 +00:00
|
|
|
}
|
|
|
|
this.getOriginPC = function() {
|
2017-01-03 01:42:15 +00:00
|
|
|
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
2016-12-31 16:05:22 +00:00
|
|
|
}
|
2017-01-22 14:35:04 +00:00
|
|
|
/*
|
|
|
|
this.saveState = function() {
|
|
|
|
return Javatari.room.console.saveState(); // TODO
|
|
|
|
}
|
|
|
|
this.loadState = function(state) {
|
|
|
|
return Javatari.room.console.loadState(state); // TODO
|
|
|
|
}
|
|
|
|
*/
|
2016-12-31 16:05:22 +00:00
|
|
|
this.readAddress = function(addr) {
|
2017-01-14 02:31:04 +00:00
|
|
|
return current_output[addr & 0xfff]; // TODO: use bus to read
|
|
|
|
}
|
|
|
|
this.runUntilReturn = function() {
|
|
|
|
var depth = 1;
|
|
|
|
self.runEval(function(c) {
|
|
|
|
if (depth <= 0 && c.T == 0)
|
|
|
|
return true;
|
|
|
|
if (c.o == 0x20)
|
|
|
|
depth++;
|
|
|
|
else if (c.o == 0x60 || c.o == 0x40)
|
|
|
|
--depth;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
this.cpuStateToLongString = function(c) {
|
|
|
|
return cpuStateToLongString_6502(c);
|
2016-12-31 16:05:22 +00:00
|
|
|
}
|
2017-01-03 01:42:15 +00:00
|
|
|
this.getRAMForState = function(state) {
|
|
|
|
return jt.Util.byteStringToUInt8Array(atob(state.r.b));
|
|
|
|
}
|
2017-01-14 02:31:04 +00:00
|
|
|
this.ramStateToLongString = function(state) {
|
|
|
|
var ram = self.getRAMForState(state);
|
|
|
|
return "\n" + dumpRAM(ram, 0x80, 0x80);
|
|
|
|
}
|
2017-01-15 03:46:12 +00:00
|
|
|
this.getToolForFilename = function(fn) {
|
|
|
|
return "dasm";
|
|
|
|
}
|
2017-04-20 00:55:13 +00:00
|
|
|
this.getDefaultExtension = function() { return ".a"; };
|
2018-07-29 20:26:05 +00:00
|
|
|
|
|
|
|
this.getDebugCategories = function() {
|
2018-08-06 17:47:55 +00:00
|
|
|
return ['CPU','PIA','TIA'];
|
2018-07-29 20:26:05 +00:00
|
|
|
}
|
|
|
|
this.getDebugInfo = function(category, state) {
|
|
|
|
switch (category) {
|
|
|
|
case 'CPU': return this.cpuStateToLongString(state.c);
|
2018-08-06 17:47:55 +00:00
|
|
|
case 'PIA': return this.ramStateToLongString(state) + "\n" + this.piaStateToLongString(state.p);
|
2018-07-29 20:26:05 +00:00
|
|
|
case 'TIA': return this.tiaStateToLongString(state.t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.piaStateToLongString = function(p) {
|
|
|
|
return "Timer " + p.t + "/" + p.c + "\n";
|
|
|
|
}
|
|
|
|
this.tiaStateToLongString = function(t) {
|
|
|
|
var pos = this.getRasterPosition();
|
|
|
|
var s = '';
|
2018-08-06 17:47:55 +00:00
|
|
|
s += "H" + lpad(pos.x,5) + " V" + lpad(pos.y,5) + " ";
|
2018-07-29 20:26:05 +00:00
|
|
|
s += (t.vs?"VSYNC ":"- ") + (t.vb?"VBLANK ":"- ") + "\n";
|
2018-08-06 17:47:55 +00:00
|
|
|
s += "\n";
|
2018-07-29 20:26:05 +00:00
|
|
|
s += "Playfield " + t.f + "\n";
|
2018-08-06 17:47:55 +00:00
|
|
|
s += " " + (t.fr?"REFLECT ":"- ") + (t.fs?"SCOREMODE ":"- ") + (t.ft?"PRIORITY ":"- ") + "\n";
|
|
|
|
for (var j=0; j<2; j++) {
|
|
|
|
var i = "p"+j;
|
|
|
|
s += "Player"+j+ lpad(tobin(t[i]),11) + lpad(tobin(t[i+'d']),11) + "\n";
|
|
|
|
}
|
|
|
|
s += "\n";
|
2018-07-29 20:26:05 +00:00
|
|
|
// TODO? s += " Color {color:0x" + hex(t.fc) + "} {color:0x" + hex(t.fb) + "}\n";
|
2018-08-06 17:47:55 +00:00
|
|
|
s += " Count Scan Speed\n";
|
2018-07-29 20:26:05 +00:00
|
|
|
for (var j=0; j<2; j++) {
|
|
|
|
var i = "p"+j;
|
2018-08-06 17:47:55 +00:00
|
|
|
s += "Player"+j+ lpad(t[i+'co'],8) + lpad(nonegstr(t[i+'sc']),5) + lpad(t[i+'ss'],6);
|
|
|
|
s += " " + (t[i+'rr']?"RESET":"") + " " + (t[i+'v']?"DELAY":"") + " " + (t[i+'cc']?"CLOSECOPY":"") + " " + (t[i+'mc']?"MEDCOPY":"") + " " + (t[i+'wc']?"WIDECOPY":"") + " " + (t[i+'r']?"REFLECT":"") + "\n";
|
2018-07-29 20:26:05 +00:00
|
|
|
}
|
|
|
|
for (var j=0; j<2; j++) {
|
|
|
|
var i = "m"+j;
|
2018-08-06 17:47:55 +00:00
|
|
|
s += "Missile"+j+ lpad(t[i+'co'],7) + lpad(nonegstr(t[i+'sc']),5) + lpad(t[i+'ss'],6);
|
|
|
|
s += " " + (t[i+'rr']?"RESET":"") + " " + (t[i+'r']?"RESET2PLAYER":"") + "\n";
|
2018-07-29 20:26:05 +00:00
|
|
|
}
|
2018-08-06 17:47:55 +00:00
|
|
|
s += "Ball"+ lpad(t['bco'],11) + lpad(nonegstr(t['bsc']),5) + lpad(t['bss'],6) + "\n";
|
2018-07-29 20:26:05 +00:00
|
|
|
return s;
|
|
|
|
}
|
2016-12-31 16:05:22 +00:00
|
|
|
};
|
2017-01-14 05:47:26 +00:00
|
|
|
|
2018-08-06 17:47:55 +00:00
|
|
|
function nonegstr(n) {
|
|
|
|
return n < 0 ? "-" : n.toString();
|
|
|
|
}
|
|
|
|
|
2017-04-21 19:19:22 +00:00
|
|
|
/// VCS TIMING ANALYSIS
|
|
|
|
|
|
|
|
var pc2minclocks = {};
|
|
|
|
var pc2maxclocks = {};
|
|
|
|
var jsrresult = {};
|
|
|
|
var MAX_CLOCKS = 76*2;
|
|
|
|
|
2018-06-27 02:32:34 +00:00
|
|
|
// [taken, not taken]
|
|
|
|
var BRANCH_CONSTRAINTS = [
|
|
|
|
[{N:0},{N:1}],
|
|
|
|
[{N:1},{N:0}],
|
|
|
|
[{V:0},{V:1}],
|
|
|
|
[{V:1},{V:0}],
|
|
|
|
[{C:0},{C:1}],
|
|
|
|
[{C:1},{C:0}],
|
|
|
|
[{Z:0},{Z:1}],
|
|
|
|
[{Z:1},{Z:0}]
|
|
|
|
];
|
|
|
|
|
|
|
|
function constraintEquals(a,b) {
|
|
|
|
if (a == null || b == null)
|
|
|
|
return null;
|
|
|
|
for (var n in a) {
|
|
|
|
if (b[n] !== 'undefined')
|
|
|
|
return a[n] == b[n];
|
|
|
|
}
|
|
|
|
for (var n in b) {
|
|
|
|
if (a[n] !== 'undefined')
|
|
|
|
return a[n] == b[n];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getClockCountsAtPC(pc) {
|
|
|
|
var opcode = platform.readAddress(pc);
|
|
|
|
var meta = platform.getOpcodeMetadata(opcode, pc);
|
|
|
|
return meta; // minCycles, maxCycles
|
|
|
|
}
|
|
|
|
|
2017-04-21 19:19:22 +00:00
|
|
|
function _traceInstructions(pc, minclocks, maxclocks, subaddr, constraints) {
|
|
|
|
//console.log("trace", hex(pc), minclocks, maxclocks);
|
|
|
|
if (!minclocks) minclocks = 0;
|
|
|
|
if (!maxclocks) maxclocks = 0;
|
|
|
|
if (!constraints) constraints = {};
|
|
|
|
var modified = true;
|
|
|
|
var abort = false;
|
|
|
|
for (var i=0; i<1000 && modified && !abort; i++) {
|
|
|
|
modified = false;
|
|
|
|
var meta = getClockCountsAtPC(pc);
|
|
|
|
var lob = platform.readAddress(pc+1);
|
|
|
|
var hib = platform.readAddress(pc+2);
|
|
|
|
var addr = lob + (hib << 8);
|
|
|
|
var pc0 = pc;
|
|
|
|
if (!pc2minclocks[pc0] || minclocks < pc2minclocks[pc0]) {
|
|
|
|
pc2minclocks[pc0] = minclocks;
|
|
|
|
modified = true;
|
|
|
|
}
|
|
|
|
if (!pc2maxclocks[pc0] || maxclocks > pc2maxclocks[pc0]) {
|
|
|
|
pc2maxclocks[pc0] = maxclocks;
|
|
|
|
modified = true;
|
|
|
|
}
|
|
|
|
//console.log(hex(pc),minclocks,maxclocks,meta);
|
|
|
|
if (!meta.insnlength) {
|
|
|
|
console.log("Illegal instruction!", hex(pc), hex(meta.opcode), meta);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pc += meta.insnlength;
|
|
|
|
var oldconstraints = constraints;
|
|
|
|
constraints = null;
|
|
|
|
// TODO: if jump to zero-page, maybe assume RTS?
|
|
|
|
switch (meta.opcode) {
|
|
|
|
/*
|
|
|
|
case 0xb9: // TODO: hack for zero page,y
|
|
|
|
if (addr < 0x100)
|
|
|
|
meta.maxCycles -= 1;
|
|
|
|
break;
|
|
|
|
*/
|
|
|
|
case 0x85:
|
|
|
|
if (lob == 0x2) { // STA WSYNC
|
|
|
|
minclocks = maxclocks = 0;
|
|
|
|
meta.minCycles = meta.maxCycles = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x20: // JSR
|
|
|
|
_traceInstructions(addr, minclocks, maxclocks, addr, constraints);
|
|
|
|
var result = jsrresult[addr];
|
|
|
|
if (result) {
|
|
|
|
minclocks = result.minclocks;
|
|
|
|
maxclocks = result.maxclocks;
|
|
|
|
} else {
|
|
|
|
console.log("No JSR result!", hex(pc), hex(addr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x4c: // JMP
|
|
|
|
pc = addr; // TODO: make sure in ROM space
|
|
|
|
break;
|
|
|
|
case 0x60: // RTS
|
|
|
|
if (subaddr) {
|
|
|
|
// TODO: combine with previous result
|
|
|
|
var result = jsrresult[subaddr];
|
|
|
|
if (!result) {
|
|
|
|
result = {minclocks:minclocks, maxclocks:maxclocks};
|
|
|
|
} else {
|
|
|
|
result = {
|
|
|
|
minclocks:Math.min(minclocks,result.minclocks),
|
|
|
|
maxclocks:Math.max(maxclocks,result.maxclocks)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
jsrresult[subaddr] = result;
|
|
|
|
console.log("RTS", hex(pc), hex(subaddr), jsrresult[subaddr]);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case 0x10: case 0x30: // branch
|
|
|
|
case 0x50: case 0x70:
|
|
|
|
case 0x90: case 0xB0:
|
|
|
|
case 0xD0: case 0xF0:
|
|
|
|
var newpc = pc + byte2signed(lob);
|
|
|
|
var crosspage = (pc>>8) != (newpc>>8);
|
|
|
|
if (!crosspage) meta.maxCycles--;
|
|
|
|
// TODO: other instructions might modify flags too
|
|
|
|
var cons = BRANCH_CONSTRAINTS[Math.floor((meta.opcode-0x10)/0x20)];
|
|
|
|
var cons0 = constraintEquals(oldconstraints, cons[0]);
|
|
|
|
var cons1 = constraintEquals(oldconstraints, cons[1]);
|
|
|
|
if (cons0 !== false) {
|
|
|
|
_traceInstructions(newpc, minclocks+meta.maxCycles, maxclocks+meta.maxCycles, subaddr, cons[0]);
|
|
|
|
}
|
|
|
|
if (cons1 === false) {
|
|
|
|
console.log("abort", hex(pc), oldconstraints, cons[1]);
|
|
|
|
abort = true;
|
|
|
|
}
|
|
|
|
constraints = cons[1]; // not taken
|
|
|
|
meta.maxCycles = meta.minCycles; // branch not taken, no extra clock(s)
|
|
|
|
break;
|
|
|
|
case 0x6c:
|
|
|
|
console.log("Instruction not supported!", hex(pc), hex(meta.opcode), meta); // TODO
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// TODO: wraparound?
|
|
|
|
minclocks = Math.min(MAX_CLOCKS, minclocks + meta.minCycles);
|
|
|
|
maxclocks = Math.min(MAX_CLOCKS, maxclocks + meta.maxCycles);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-04 15:36:32 +00:00
|
|
|
function showLoopTimingForPC(pc, sourcefile, ed) {
|
2017-04-21 19:19:22 +00:00
|
|
|
pc2minclocks = {};
|
|
|
|
pc2maxclocks = {};
|
|
|
|
jsrresult = {};
|
|
|
|
// recurse through all traces
|
|
|
|
_traceInstructions(pc | platform.getOriginPC(), MAX_CLOCKS, MAX_CLOCKS);
|
2018-08-07 14:25:32 +00:00
|
|
|
ed.editor.clearGutter("gutter-bytes");
|
2017-04-21 19:19:22 +00:00
|
|
|
// show the lines
|
|
|
|
for (var line in sourcefile.line2offset) {
|
|
|
|
var pc = sourcefile.line2offset[line];
|
|
|
|
var minclocks = pc2minclocks[pc];
|
|
|
|
var maxclocks = pc2maxclocks[pc];
|
|
|
|
if (minclocks>=0 && maxclocks>=0) {
|
|
|
|
var s;
|
|
|
|
if (maxclocks == minclocks)
|
|
|
|
s = minclocks + "";
|
|
|
|
else
|
|
|
|
s = minclocks + "-" + maxclocks;
|
|
|
|
if (maxclocks == MAX_CLOCKS)
|
|
|
|
s += "+";
|
2018-07-04 15:36:32 +00:00
|
|
|
ed.setGutterBytes(line, s);
|
2017-04-21 19:19:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-01 15:30:47 +00:00
|
|
|
///////////////
|
|
|
|
|
|
|
|
var VCSMAMEPlatform = function(mainElement) {
|
|
|
|
var self = this;
|
|
|
|
this.__proto__ = new BaseMAMEPlatform();
|
|
|
|
|
|
|
|
// MCFG_SCREEN_RAW_PARAMS( MASTER_CLOCK_NTSC, 228, 26, 26 + 160 + 16, 262, 24 , 24 + 192 + 31 )
|
|
|
|
this.start = function() {
|
|
|
|
self.startModule(mainElement, {
|
|
|
|
jsfile:'mamea2600.js',
|
|
|
|
driver:'a2600',
|
|
|
|
width:176*2,
|
|
|
|
height:223,
|
|
|
|
romfn:'/emulator/cart.rom',
|
|
|
|
romsize:0x1000,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.loadROM = function(title, data) {
|
2017-05-18 02:33:56 +00:00
|
|
|
this.loadROMFile(data);
|
2017-05-01 15:30:47 +00:00
|
|
|
this.loadRegion(":cartslot:cart:rom", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getPresets = function() { return VCS_PRESETS; }
|
|
|
|
|
|
|
|
this.getToolForFilename = function(fn) {
|
|
|
|
return "dasm";
|
|
|
|
}
|
|
|
|
this.getDefaultExtension = function() { return ".a"; };
|
2017-05-13 12:08:36 +00:00
|
|
|
|
|
|
|
this.getOriginPC = function() {
|
|
|
|
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
this.getOpcodeMetadata = function(opcode, offset) {
|
|
|
|
return Javatari.getOpcodeMetadata(opcode, offset);
|
|
|
|
}
|
|
|
|
*/
|
2017-05-01 15:30:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////
|
|
|
|
|
|
|
|
PLATFORMS['vcs'] = VCSPlatform;
|
|
|
|
PLATFORMS['vcs-mame'] = VCSMAMEPlatform;
|