mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-16 17:30:27 +00:00
Z80 Space Invaders starting to work; deferred worker module load
This commit is contained in:
parent
bd551f7311
commit
7fce763f64
17
index.html
17
index.html
@ -165,6 +165,14 @@ a.dropdown-toggle {
|
||||
-moz-border-radius:6px 0 6px 6px;
|
||||
border-radius:6px 0 6px 6px;
|
||||
}
|
||||
canvas {
|
||||
image-rendering: optimizeSpeed; /* Older versions of FF */
|
||||
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
|
||||
image-rendering: -webkit-optimize-contrast; /* Safari */
|
||||
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
|
||||
image-rendering: pixelated; /* Awesome future-browsers */
|
||||
-ms-interpolation-mode: nearest-neighbor; /* IE */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -177,14 +185,14 @@ a.dropdown-toggle {
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<li><a class="dropdown-item" href="#" id="item_new_file">New File...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_share_file">Share File...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_reset_file">Reset to Original...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_reset_file">Revert to Original...</a></li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Platform</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=vcs" id="item_platform_vcs">Atari VCS</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=apple2" id="item_platform_apple2">Apple ][</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=atarivec" id="item_platform_atarivec">Asteroids</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=exidy" id="item_platform_exidy">Exidy</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=spaceinv" id="item_platform_spaceinv">Space Invaders</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
@ -202,9 +210,9 @@ a.dropdown-toggle {
|
||||
<button id="dbg_go" type="button" title="Run"><img src="images/play.png"></button>
|
||||
<button id="dbg_step" type="submit" title="Step"><img src="images/singlestep.png"></button>
|
||||
<button id="dbg_toline" type="submit" title="Run To Line"><img src="images/runtoline.png"></button>
|
||||
<button id="dbg_reset" type="submit" title="Reset and Run To Line"><img src="images/resetandrun.png"></button>
|
||||
<button id="dbg_stepout" type="submit" title="Step Out of Subroutine">RTS</button>
|
||||
<button id="dbg_stepback" type="submit" title="Step Backwards"><<</button>
|
||||
<button id="dbg_reset" type="submit" title="Reset and Break"><img src="images/resetandrun.png"></button>
|
||||
<button id="dbg_timing" type="submit" title="See Timing" style="display:none"><img src="images/timing.png"></button>
|
||||
<button id="dbg_disasm" type="submit" title="Toggle Disassembly">#</button>
|
||||
</span>
|
||||
@ -261,13 +269,14 @@ a.dropdown-toggle {
|
||||
<link rel="stylesheet" href="codemirror/addon/dialog/dialog.css">
|
||||
|
||||
<script src="javatari.js/release/javatari/javatari.js"></script>
|
||||
<script src="src/cpu/z80.js"></script>
|
||||
<script src="src/emu.js"></script>
|
||||
<script src="src/util.js"></script>
|
||||
<script src="src/disasm.js"></script>
|
||||
<script src="src/platform/vcs.js"></script>
|
||||
<script src="src/platform/apple2.js"></script>
|
||||
<script src="src/platform/atarivec.js"></script>
|
||||
<script src="src/platform/exidy.js"></script>
|
||||
<script src="src/platform/spaceinv.js"></script>
|
||||
<script src="src/ui.js"></script>
|
||||
|
||||
</body>
|
||||
|
2661
src/cpu/z80.coffee
Normal file
2661
src/cpu/z80.coffee
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
195
src/emu.js
195
src/emu.js
@ -2,6 +2,10 @@
|
||||
|
||||
// Emulator classes
|
||||
|
||||
function noise() {
|
||||
return (Math.random() * 256) & 0xff;
|
||||
}
|
||||
|
||||
function _metakeyflags(e) {
|
||||
return (e.shiftKey?2:0) | (e.ctrlKey?4:0) | (e.altKey?8:0) | (e.metaKey?16:0);
|
||||
}
|
||||
@ -11,6 +15,8 @@ function __createCanvas(mainElement, width, height) {
|
||||
var fsElement = document.createElement('div');
|
||||
fsElement.style.position = "relative";
|
||||
fsElement.style.padding = "20px";
|
||||
if (height > width)
|
||||
fsElement.style.margin = "20%"; // TODO
|
||||
fsElement.style.overflow = "hidden";
|
||||
fsElement.style.background = "black";
|
||||
|
||||
@ -31,8 +37,11 @@ var RasterVideo = function(mainElement, width, height, options) {
|
||||
var canvas, ctx;
|
||||
var imageData, buf8, datau32;
|
||||
|
||||
this.start = function() {
|
||||
this.create = function() {
|
||||
canvas = __createCanvas(mainElement, width, height);
|
||||
if (options.rotate) {
|
||||
canvas.style.transform = "rotate("+options.rotate+"deg)";
|
||||
}
|
||||
ctx = canvas.getContext('2d');
|
||||
imageData = ctx.createImageData(width, height);
|
||||
var buf = new ArrayBuffer(imageData.data.length);
|
||||
@ -303,6 +312,23 @@ var SampleAudio = function(clockfreq) {
|
||||
}
|
||||
}
|
||||
|
||||
function cpuStateToLongString_6502(c) {
|
||||
function decodeFlags(c, flags) {
|
||||
var s = "";
|
||||
s += c.N ? " N" : " -";
|
||||
s += c.V ? " V" : " -";
|
||||
s += c.D ? " D" : " -";
|
||||
s += c.Z ? " Z" : " -";
|
||||
s += c.C ? " C" : " -";
|
||||
// s += c.I ? " I" : " -";
|
||||
return s;
|
||||
}
|
||||
return "PC " + hex(c.PC,4) + " " + decodeFlags(c) + " " + getTIAPosString() + "\n"
|
||||
+ " A " + hex(c.A) + " " + (c.R ? "" : "BUSY") + "\n"
|
||||
+ " X " + hex(c.X) + "\n"
|
||||
+ " Y " + hex(c.Y) + " " + "SP " + hex(c.SP) + "\n";
|
||||
}
|
||||
|
||||
var Base6502Platform = function() {
|
||||
|
||||
this.getOpcodeMetadata = function(opcode, offset) {
|
||||
@ -345,6 +371,7 @@ var Base6502Platform = function() {
|
||||
}
|
||||
this.clearDebug = function() {
|
||||
debugSavedState = null;
|
||||
debugBreakState = null;
|
||||
debugTargetClock = 0;
|
||||
debugClock = 0;
|
||||
onBreakpointHit = null;
|
||||
@ -416,4 +443,170 @@ var Base6502Platform = function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
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.disassemble = function(mem, start, end, pcvisits) {
|
||||
return new Disassembler6502().disassemble(mem, start, end, pcvisits);
|
||||
}
|
||||
this.cpuStateToLongString = function(c) {
|
||||
return cpuStateToLongString_6502(c);
|
||||
}
|
||||
}
|
||||
|
||||
function dumpRAM(ram, ramofs, ramlen) {
|
||||
var s = "";
|
||||
// TODO: show scrollable RAM for other platforms
|
||||
for (var ofs=0; ofs<ramlen; ofs+=0x10) {
|
||||
s += '$' + hex(ofs+ramofs) + ':';
|
||||
for (var i=0; i<0x10; i++) {
|
||||
if (ofs+i < ram.length) {
|
||||
if (i == 8) s += " ";
|
||||
s += " " + hex(ram[ofs+i]);
|
||||
}
|
||||
}
|
||||
s += "\n";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function cpuStateToLongString_Z80(c) {
|
||||
function decodeFlags(flags) {
|
||||
var flagspec = "SZ-H-VNC";
|
||||
var s = "";
|
||||
for (var i=0; i<8; i++)
|
||||
s += (flags & (128>>i)) ? flagspec.slice(i,i+1) : "-";
|
||||
return s; // TODO
|
||||
}
|
||||
return "PC " + hex(c.PC,4) + " " + decodeFlags(c.AF) + " " + getTIAPosString() + "\n"
|
||||
+ "SP " + hex(c.SP,4) + " IR " + hex(c.IR,4) + "\n"
|
||||
+ "IX " + hex(c.IX,4) + " IY " + hex(c.IY,4) + "\n"
|
||||
+ "AF " + hex(c.AF,4) + " BC " + hex(c.BC,4) + "\n"
|
||||
+ "DE " + hex(c.DE,4) + " HL " + hex(c.HL,4) + "\n"
|
||||
;
|
||||
}
|
||||
|
||||
var BaseZ80Platform = function() {
|
||||
|
||||
var onBreakpointHit;
|
||||
var debugCondition;
|
||||
var debugSavedState = null;
|
||||
var debugBreakState = null;
|
||||
var debugTargetClock = 0;
|
||||
|
||||
this.setDebugCondition = function(debugCond) {
|
||||
if (debugSavedState) {
|
||||
this.loadState(debugSavedState);
|
||||
} else {
|
||||
debugSavedState = this.saveState();
|
||||
}
|
||||
debugCondition = debugCond;
|
||||
this.resume();
|
||||
}
|
||||
/*
|
||||
this.restartDebugState = function() {
|
||||
if (debugCondition && !debugBreakState) {
|
||||
debugTargetClock -= cpu.getTstates();
|
||||
cpu.setTstates(0);
|
||||
debugSavedState = this.saveState();
|
||||
}
|
||||
}
|
||||
*/
|
||||
this.getDebugCallback = function() {
|
||||
return debugCondition;
|
||||
}
|
||||
this.setupDebug = function(callback) {
|
||||
onBreakpointHit = callback;
|
||||
}
|
||||
this.clearDebug = function() {
|
||||
debugSavedState = null;
|
||||
debugBreakState = null;
|
||||
debugTargetClock = 0;
|
||||
onBreakpointHit = null;
|
||||
debugCondition = null;
|
||||
}
|
||||
this.breakpointHit = function() {
|
||||
debugBreakState = this.saveState();
|
||||
//debugBreakState.c.PC = (debugBreakState.c.PC-1) & 0xffff;
|
||||
console.log("Breakpoint at clk", debugBreakState.c.tstates, "PC", debugBreakState.c.PC.toString(16));
|
||||
this.pause();
|
||||
if (onBreakpointHit) {
|
||||
onBreakpointHit(debugBreakState);
|
||||
}
|
||||
}
|
||||
// TODO: lower bound of clock value
|
||||
this.step = function() {
|
||||
var self = this;
|
||||
this.setDebugCondition(function() {
|
||||
var cpuState = self.getCPUState();
|
||||
if (cpuState.tstates > debugTargetClock) {
|
||||
debugTargetClock = cpuState.tstates;
|
||||
self.breakpointHit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this.stepBack = function() {
|
||||
var self = this;
|
||||
var prevState;
|
||||
var prevClock;
|
||||
this.setDebugCondition(function() {
|
||||
var cpuState = self.getCPUState();
|
||||
var debugClock = cpuState.tstates;
|
||||
if (debugClock >= debugTargetClock && prevState) {
|
||||
self.loadState(prevState);
|
||||
debugTargetClock = prevClock;
|
||||
self.breakpointHit();
|
||||
return true;
|
||||
} else if (debugClock > debugTargetClock-20 && debugClock < debugTargetClock) {
|
||||
prevState = self.saveState();
|
||||
prevClock = debugClock;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this.runEval = function(evalfunc) {
|
||||
var self = this;
|
||||
this.setDebugCondition(function() {
|
||||
var cpuState = self.getCPUState();
|
||||
if (cpuState.tstates > debugTargetClock) {
|
||||
if (evalfunc(cpuState)) {
|
||||
debugTargetClock = cpuState.tstates;
|
||||
self.breakpointHit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this.runUntilReturn = function() {
|
||||
var self = this;
|
||||
var depth = 1;
|
||||
self.runEval(function(c) {
|
||||
if (depth <= 0)
|
||||
return true;
|
||||
var op = self.readAddress(c.PC);
|
||||
if (op == 0xcd) // CALL
|
||||
depth++;
|
||||
else if (op == 0xc0 || op == 0xc8 || op == 0xc9 || op == 0xd0) // RET (TODO?)
|
||||
--depth;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this.disassemble = function(mem, start, end, pcvisits) {
|
||||
return new Disassembler6502().disassemble(mem, start, end, pcvisits);
|
||||
}
|
||||
this.cpuStateToLongString = function(c) {
|
||||
return cpuStateToLongString_Z80(c);
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,6 @@ var Apple2Platform = function(mainElement) {
|
||||
return APPLE2_PRESETS;
|
||||
}
|
||||
|
||||
function noise() {
|
||||
return (Math.random() * 256) & 0xff;
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
cpu = new jt.M6502();
|
||||
ram = new RAM(0x13000); // 64K + 16K LC RAM - 4K hardware
|
||||
@ -138,8 +134,7 @@ var Apple2Platform = function(mainElement) {
|
||||
// create video/audio
|
||||
video = new RasterVideo(mainElement,280,192);
|
||||
audio = new SampleAudio(cpuFrequency);
|
||||
video.start();
|
||||
audio.start();
|
||||
video.create();
|
||||
video.setKeyboardEvents(function(key,code,flags) {
|
||||
// since we're an Apple II+, we don't do lowercase
|
||||
if (flags & 1) {
|
||||
@ -158,8 +153,6 @@ var Apple2Platform = function(mainElement) {
|
||||
var colors = [0xffff0000, 0xff00ff00];
|
||||
timer = new AnimationTimer(60, function() {
|
||||
// 262.5 scanlines per frame
|
||||
var iaddr = 0x2000;
|
||||
var iofs = 0;
|
||||
var clock = 0;
|
||||
var debugCond = self.getDebugCallback();
|
||||
for (var sl=0; sl<262; sl++) {
|
||||
@ -254,10 +247,6 @@ var Apple2Platform = function(mainElement) {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
this.getRasterPosition = function() {
|
||||
return {x:0, y:0};
|
||||
}
|
||||
|
||||
this.isRunning = function() {
|
||||
return timer.isRunning();
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ var AtariVectorPlatform = function(mainElement) {
|
||||
video = new VectorVideo(mainElement,1024,1024);
|
||||
dvg = new DVGStateMachine(bus, video);
|
||||
audio = new SampleAudio(cpuFrequency);
|
||||
video.start();
|
||||
video.create();
|
||||
timer = new AnimationTimer(60, function() {
|
||||
video.clear();
|
||||
// 262.5 scanlines per frame
|
||||
|
@ -47,9 +47,8 @@ var ExidyPlatform = function(mainElement) {
|
||||
cpu.connectBus(bus);
|
||||
// create video/audio
|
||||
video = new RasterVideo(mainElement,256,256);
|
||||
video.start();
|
||||
video.create();
|
||||
audio = new SampleAudio(cpuFrequency); // TODO
|
||||
audio.start();
|
||||
var idata = video.getFrameData();
|
||||
timer = new AnimationTimer(60, function() {
|
||||
var clock = 0;
|
||||
|
224
src/platform/spaceinv.js
Normal file
224
src/platform/spaceinv.js
Normal file
@ -0,0 +1,224 @@
|
||||
"use strict";
|
||||
|
||||
// http://www.computerarcheology.com/Arcade/SpaceInvaders/Hardware.html
|
||||
|
||||
var SPACEINV_PRESETS = [
|
||||
];
|
||||
|
||||
// TODO: global???
|
||||
window.buildZ80({
|
||||
applyContention: false
|
||||
});
|
||||
|
||||
var SpaceInvadersPlatform = function(mainElement) {
|
||||
var self = this;
|
||||
this.__proto__ = new BaseZ80Platform();
|
||||
|
||||
var cpu, ram, membus, iobus, rom;
|
||||
var video, audio, timer, pixels;
|
||||
var inputs = [0xe,0x8,0x0];
|
||||
var bitshift_offset = 0;
|
||||
var bitshift_register = 0;
|
||||
var watchdog_counter;
|
||||
var cpuFrequency = 1996800;
|
||||
var cpuCyclesPerLine = Math.round(cpuFrequency/(60*224)); // TODO
|
||||
var INITIAL_WATCHDOG = 256;
|
||||
var PIXEL_ON = 0xffeeeeee;
|
||||
var PIXEL_OFF = 0xff000000;
|
||||
|
||||
var KEYCODE_MAP = {
|
||||
32:{i:1,b:4}, // space bar (P1)
|
||||
37:{i:1,b:5}, // left arrow (P1)
|
||||
39:{i:1,b:6}, // right arrow (P1)
|
||||
0x53:{i:2,b:4}, // S (P2)
|
||||
0x41:{i:2,b:5}, // A (P2)
|
||||
0x44:{i:2,b:6}, // D (P2)
|
||||
53:{i:1,b:0}, // 5
|
||||
49:{i:1,b:2}, // 1
|
||||
50:{i:1,b:1}, // 2
|
||||
}
|
||||
|
||||
this.getOpcodeMetadata = function() {
|
||||
return {
|
||||
opcode:0,
|
||||
mnenomic:'?',
|
||||
minCycles:0,
|
||||
maxCycles:0,
|
||||
insnlength:1
|
||||
};
|
||||
}
|
||||
|
||||
this.getPresets = function() {
|
||||
return SPACEINV_PRESETS;
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
ram = new RAM(0x2000);
|
||||
membus = {
|
||||
read: function(address) {
|
||||
if (address < 0x2000) {
|
||||
return rom ? rom[address] : 0;
|
||||
} else {
|
||||
address &= 0x1fff;
|
||||
return ram.mem[address];
|
||||
}
|
||||
},
|
||||
write: function(address, value) {
|
||||
//console.log("write", hex(address,4), hex(value,2));
|
||||
if (address >= 0x2000) {
|
||||
address &= 0x1fff;
|
||||
value &= 0xff;
|
||||
ram.mem[address] = value;
|
||||
if (address >= 0x400) {
|
||||
// TODO: dirty flags
|
||||
var ofs = (address - 0x400)*8;
|
||||
for (var i=0; i<8; i++)
|
||||
pixels[ofs+i] = (value & (1<<i)) ? PIXEL_ON : PIXEL_OFF;
|
||||
}
|
||||
}
|
||||
},
|
||||
isContended: function() { return false; },
|
||||
};
|
||||
iobus = {
|
||||
read: function(addr) {
|
||||
addr &= 0x3;
|
||||
//console.log('IO read', hex(addr,4));
|
||||
switch (addr) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return inputs[addr];
|
||||
case 3:
|
||||
return (bitshift_register << bitshift_offset) & 0xff;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
write: function(addr, val) {
|
||||
addr &= 0x7;
|
||||
val &= 0xff;
|
||||
//console.log('IO write', hex(addr,4), hex(val,2));
|
||||
switch (addr) {
|
||||
case 2:
|
||||
bitshift_offset = val & 0x7;
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
// TODO: sound
|
||||
break;
|
||||
case 4:
|
||||
bitshift_register = (bitshift_register >> 8) | (val << 8);
|
||||
break;
|
||||
case 6:
|
||||
watchdog_counter = INITIAL_WATCHDOG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
cpu = window.Z80({
|
||||
display: {},
|
||||
memory: membus,
|
||||
ioBus: iobus
|
||||
});
|
||||
video = new RasterVideo(mainElement,256,224,{rotate:-90});
|
||||
audio = new SampleAudio(cpuFrequency);
|
||||
video.create();
|
||||
var idata = video.getFrameData();
|
||||
video.setKeyboardEvents(function(key,code,flags) {
|
||||
var o = KEYCODE_MAP[key];
|
||||
if (o) {
|
||||
if (flags & 1) {
|
||||
inputs[o.i] |= (1<<o.b);
|
||||
} else {
|
||||
inputs[o.i] &= ~(1<<o.b);
|
||||
}
|
||||
}
|
||||
});
|
||||
pixels = video.getFrameData();
|
||||
timer = new AnimationTimer(60, function() {
|
||||
if (!self.isRunning())
|
||||
return;
|
||||
cpu.setTstates(0);
|
||||
var debugCond = self.getDebugCallback();
|
||||
for (var sl=0; sl<224; sl++) {
|
||||
var targetTstates = cpu.getTstates() + cpuCyclesPerLine;
|
||||
if (debugCond) {
|
||||
while (cpu.getTstates() < targetTstates) {
|
||||
if (debugCond && debugCond()) { debugCond = null; }
|
||||
cpu.runFrame(cpu.getTstates() + 1);
|
||||
}
|
||||
} else {
|
||||
cpu.runFrame(targetTstates);
|
||||
}
|
||||
if (sl == 95)
|
||||
cpu.requestInterrupt(0x8); // RST $8
|
||||
else if (sl == 223)
|
||||
cpu.requestInterrupt(0x10); // RST $10
|
||||
}
|
||||
video.updateFrame();
|
||||
if (watchdog_counter-- <= 0) {
|
||||
console.log("WATCHDOG FIRED"); // TODO: alert on video
|
||||
self.reset();
|
||||
}
|
||||
//self.restartDebugState();
|
||||
});
|
||||
}
|
||||
|
||||
this.loadROM = function(title, data) {
|
||||
rom = data;
|
||||
self.reset();
|
||||
}
|
||||
|
||||
this.loadState = function(state) {
|
||||
cpu.loadState(state.c);
|
||||
ram.mem.set(state.b);
|
||||
bitshift_register = state.bsr;
|
||||
bitshift_offset = state.bso;
|
||||
watchdog_counter = state.wdc;
|
||||
inputs[0] = state.in0;
|
||||
inputs[1] = state.in1;
|
||||
inputs[2] = state.in2;
|
||||
}
|
||||
this.saveState = function() {
|
||||
return {
|
||||
c:self.getCPUState(),
|
||||
b:ram.mem.slice(0),
|
||||
bsr:bitshift_register,
|
||||
bso:bitshift_offset,
|
||||
wdc:watchdog_counter,
|
||||
in0:inputs[0],
|
||||
in1:inputs[1],
|
||||
in2:inputs[2],
|
||||
};
|
||||
}
|
||||
this.getRAMForState = function(state) {
|
||||
return ram.mem;
|
||||
}
|
||||
this.getCPUState = function() {
|
||||
return cpu.saveState();
|
||||
}
|
||||
|
||||
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();
|
||||
cpu.setTstates(0);
|
||||
watchdog_counter = INITIAL_WATCHDOG;
|
||||
}
|
||||
this.readAddress = function(addr) {
|
||||
return membus.read(addr);
|
||||
}
|
||||
|
||||
this.ramStateToLongString = function(state) {
|
||||
var stack = state.b.slice(state.c.SP & 0x1fff, 0x400);
|
||||
return "\n" + dumpRAM(stack, state.c.SP, stack.length);
|
||||
}
|
||||
}
|
@ -88,9 +88,29 @@ var VCSPlatform = function() {
|
||||
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
||||
}
|
||||
this.readAddress = function(addr) {
|
||||
return current_output[addr - 0xf000]; // TODO: use bus to read
|
||||
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);
|
||||
}
|
||||
this.getRAMForState = function(state) {
|
||||
return jt.Util.byteStringToUInt8Array(atob(state.r.b));
|
||||
}
|
||||
this.ramStateToLongString = function(state) {
|
||||
// TODO: customize RAM dump per-platform
|
||||
var ram = self.getRAMForState(state);
|
||||
return "\n" + dumpRAM(ram, 0x80, 0x80);
|
||||
}
|
||||
};
|
||||
|
208
src/ui.js
208
src/ui.js
@ -1,5 +1,21 @@
|
||||
"use strict";
|
||||
|
||||
// catch errors
|
||||
if (typeof window.onerror == "object") {
|
||||
window.onerror = function (msgevent, url, line, col, error) {
|
||||
console.log(msgevent, url, line, col);
|
||||
console.log(error);
|
||||
//$("#editor").hide();
|
||||
if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||
ga('send', 'exception', {
|
||||
'exDescription': msgevent + " " + url + " " + " " + line + ":" + col + ", " + error,
|
||||
'exFatal': true
|
||||
});
|
||||
}
|
||||
alert(msgevent+"");
|
||||
};
|
||||
}
|
||||
|
||||
// 8bitworkshop IDE user interface
|
||||
|
||||
var PRESETS; // presets array
|
||||
@ -260,6 +276,7 @@ function getToolForFilename(fn) {
|
||||
if (fn.endsWith(".pla")) return "plasm";
|
||||
if (fn.endsWith(".c")) return "cc65";
|
||||
if (fn.endsWith(".s")) return "ca65";
|
||||
if (fn.endsWith(".asm")) return "z80asm";
|
||||
return "dasm";
|
||||
}
|
||||
|
||||
@ -323,8 +340,8 @@ worker.onmessage = function(e) {
|
||||
offset2line = {};
|
||||
line2offset = {};
|
||||
for (var info of e.data.listing.lines) {
|
||||
if (info.offset) {
|
||||
var textel = document.createTextNode(info.offset.toString(16));
|
||||
if (info.offset >= 0) {
|
||||
var textel = document.createTextNode(hex(info.offset,4));
|
||||
editor.setGutterMarker(info.line-1, "gutter-offset", textel);
|
||||
offset2line[info.offset] = info.line;
|
||||
line2offset[info.line] = info.offset;
|
||||
@ -354,7 +371,7 @@ function findLineForOffset(PC) {
|
||||
if (offset2line) {
|
||||
for (var i=0; i<256; i++) {
|
||||
var line = offset2line[PC];
|
||||
if (line) {
|
||||
if (line >= 0) {
|
||||
return line;
|
||||
}
|
||||
PC--;
|
||||
@ -367,36 +384,11 @@ function setCurrentLine(line) {
|
||||
editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true});
|
||||
}
|
||||
|
||||
function hex(v, nd) {
|
||||
try {
|
||||
if (!nd) nd = 2;
|
||||
var s = v.toString(16).toUpperCase();
|
||||
while (s.length < nd)
|
||||
s = "0" + s;
|
||||
return s;
|
||||
} catch (e) {
|
||||
return v+"";
|
||||
}
|
||||
}
|
||||
function decodeFlags(c, flags) {
|
||||
var s = "";
|
||||
s += c.N ? " N" : " -";
|
||||
s += c.V ? " V" : " -";
|
||||
s += c.D ? " D" : " -";
|
||||
s += c.Z ? " Z" : " -";
|
||||
s += c.C ? " C" : " -";
|
||||
// s += c.I ? " I" : " -";
|
||||
return s;
|
||||
}
|
||||
function cpuStateToLongString(c) {
|
||||
return "PC " + hex(c.PC,4) + " " + decodeFlags(c) + " " + getTIAPosString() + "\n"
|
||||
+ " A " + hex(c.A) + " " + (c.R ? "" : "BUSY") + "\n"
|
||||
+ " X " + hex(c.X) + "\n"
|
||||
+ " Y " + hex(c.Y) + " " + "SP " + hex(c.SP) + "\n";
|
||||
}
|
||||
function getTIAPosString() {
|
||||
var pos = platform.getRasterPosition();
|
||||
return "V" + pos.y + " H" + pos.x;
|
||||
if (platform.getRasterPosition) {
|
||||
var pos = platform.getRasterPosition();
|
||||
return "V" + pos.y + " H" + pos.x;
|
||||
} else return "";
|
||||
}
|
||||
|
||||
var lastDebugInfo;
|
||||
@ -431,19 +423,9 @@ function highlightDifferences(s1, s2) {
|
||||
function showMemory(state) {
|
||||
var s = "";
|
||||
if (state) {
|
||||
s = cpuStateToLongString(state.c);
|
||||
s += "\n";
|
||||
var ram = platform.getRAMForState(state);
|
||||
var ramlen = ram.length <= 128 ? 128 : 256; // TODO
|
||||
var ramofs = ram.length == 128 ? 0x80 : 0;
|
||||
// TODO: show scrollable RAM for other platforms
|
||||
for (var ofs=0; ofs<ramlen; ofs+=0x10) {
|
||||
s += '$' + hex(ofs+ramofs) + ':';
|
||||
for (var i=0; i<0x10; i++) {
|
||||
if (i == 8) s += " ";
|
||||
s += " " + hex(ram[ofs+i]);
|
||||
}
|
||||
s += "\n";
|
||||
s = platform.cpuStateToLongString(state.c);
|
||||
if (platform.ramStateToLongString) {
|
||||
s += platform.ramStateToLongString(state);
|
||||
}
|
||||
var hs = lastDebugInfo ? highlightDifferences(lastDebugInfo, s) : s;
|
||||
$("#mem_info").show().html(hs);
|
||||
@ -460,9 +442,12 @@ function setupBreakpoint() {
|
||||
lastDebugState = state;
|
||||
var PC = state.c.PC;
|
||||
var line = findLineForOffset(PC);
|
||||
if (line) {
|
||||
if (line >= 0) {
|
||||
console.log("BREAKPOINT", hex(PC), line);
|
||||
setCurrentLine(line);
|
||||
} else {
|
||||
console.log("BREAKPOINT", hex(PC));
|
||||
// TODO: switch to disasm
|
||||
}
|
||||
pcvisits[PC] = pcvisits[PC] ? pcvisits[PC]+1 : 1;
|
||||
showMemory(state);
|
||||
@ -498,7 +483,7 @@ function runToCursor() {
|
||||
setupBreakpoint();
|
||||
var line = getCurrentLine();
|
||||
var pc = line2offset[line];
|
||||
if (pc) {
|
||||
if (pc >= 0) {
|
||||
console.log("Run to", line, pc.toString(16));
|
||||
platform.runEval(function(c) {
|
||||
return c.PC == pc;
|
||||
@ -508,16 +493,7 @@ function runToCursor() {
|
||||
|
||||
function runUntilReturn() {
|
||||
setupBreakpoint();
|
||||
var depth = 1;
|
||||
platform.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;
|
||||
});
|
||||
platform.runUntilReturn();
|
||||
}
|
||||
|
||||
function runStepBackwards() {
|
||||
@ -735,7 +711,8 @@ function updateDisassembly() {
|
||||
function disassemble(start, end) {
|
||||
if (start < 0) start = 0;
|
||||
if (end > mem.length) end = mem.length;
|
||||
var disasm = new Disassembler6502().disassemble(mem, start, end, pcvisits);
|
||||
// TODO: use platform.readMemory()
|
||||
var disasm = platform.disassemble(mem, start, end, pcvisits);
|
||||
var s = "";
|
||||
for (a in disasm) {
|
||||
var srclinenum = offset2line[a];
|
||||
@ -777,11 +754,11 @@ function toggleDisassembly() {
|
||||
function resetAndDebug() {
|
||||
clearBreakpoint();
|
||||
platform.reset();
|
||||
runToCursor();
|
||||
platform.breakpointHit();
|
||||
}
|
||||
|
||||
function _breakExpression() {
|
||||
var exprs = window.prompt("Enter break expression", "c.PC == 0x6000");
|
||||
var exprs = window.prompt("Enter break expression", "c.PC == 0x6000"); // TODO
|
||||
if (exprs) {
|
||||
var fn = new Function('c', 'return (' + exprs + ');');
|
||||
setupBreakpoint();
|
||||
@ -798,7 +775,10 @@ function setupDebugControls(){
|
||||
$("#dbg_stepout").click(runUntilReturn);
|
||||
$("#dbg_stepback").click(runStepBackwards);
|
||||
$("#dbg_timing").click(traceTiming);
|
||||
$("#dbg_disasm").click(toggleDisassembly);
|
||||
if (platform.disassemble)
|
||||
$("#dbg_disasm").click(toggleDisassembly);
|
||||
else
|
||||
$("#dbg_disasm").hide();
|
||||
$("#disassembly").hide();
|
||||
$(".dropdown-menu").collapse({toggle: false});
|
||||
$("#item_new_file").click(_createNewFile);
|
||||
@ -865,61 +845,59 @@ var qs = (function (a) {
|
||||
})(window.location.search.substr(1).split('&'));
|
||||
|
||||
// start
|
||||
setupDebugControls();
|
||||
showWelcomeMessage();
|
||||
// parse query string
|
||||
try {
|
||||
// is this a share URL?
|
||||
if (qs['sharekey']) {
|
||||
var sharekey = qs['sharekey'];
|
||||
console.log("Loading shared file ", sharekey);
|
||||
$.getJSON( ".storage/" + sharekey, function( result ) {
|
||||
console.log(result);
|
||||
var newid = 'shared/' + result['filename'];
|
||||
updatePreset(newid, result['text']);
|
||||
qs['file'] = newid;
|
||||
delete qs['sharekey'];
|
||||
window.location = "?" + $.param(qs);
|
||||
}, 'text');
|
||||
} else {
|
||||
// add default platform?
|
||||
platform_id = qs['platform'] || localStorage.getItem("__lastplatform");
|
||||
if (!platform_id) {
|
||||
platform_id = qs['platform'] = "vcs";
|
||||
}
|
||||
// load and start platform object
|
||||
// TODO: self-register platforms
|
||||
if (platform_id == 'vcs') {
|
||||
platform = new VCSPlatform();
|
||||
$("#booklink_vcs").show();
|
||||
} else if (platform_id == 'apple2') {
|
||||
platform = new Apple2Platform($("#emulator")[0]);
|
||||
} else if (platform_id == 'atarivec') {
|
||||
platform = new AtariVectorPlatform($("#emulator")[0]);
|
||||
} else if (platform_id == 'exidy') {
|
||||
platform = new ExidyPlatform($("#emulator")[0]);
|
||||
} else {
|
||||
alert("Platform " + platform_id + " not recognized");
|
||||
}
|
||||
store = new FileStore(localStorage, platform_id + '/');
|
||||
PRESETS = platform.getPresets();
|
||||
platform.start();
|
||||
// reset file?
|
||||
if (qs['file'] && qs['reset']) {
|
||||
store.deleteFile(qs['file']);
|
||||
qs['reset'] = '';
|
||||
window.location = "?" + $.param(qs);
|
||||
} else if (qs['file']) {
|
||||
// load file
|
||||
loadPreset(qs['file']);
|
||||
updateSelector();
|
||||
} else {
|
||||
// try to load last file
|
||||
var lastid = localStorage.getItem("__lastid_"+platform_id) || localStorage.getItem("__lastid");
|
||||
localStorage.removeItem("__lastid");
|
||||
gotoPresetNamed(lastid || PRESETS[0].id);
|
||||
}
|
||||
// is this a share URL?
|
||||
if (qs['sharekey']) {
|
||||
var sharekey = qs['sharekey'];
|
||||
console.log("Loading shared file ", sharekey);
|
||||
$.getJSON( ".storage/" + sharekey, function( result ) {
|
||||
console.log(result);
|
||||
var newid = 'shared/' + result['filename'];
|
||||
updatePreset(newid, result['text']);
|
||||
qs['file'] = newid;
|
||||
delete qs['sharekey'];
|
||||
window.location = "?" + $.param(qs);
|
||||
}, 'text');
|
||||
} else {
|
||||
// add default platform?
|
||||
platform_id = qs['platform'] || localStorage.getItem("__lastplatform");
|
||||
if (!platform_id) {
|
||||
platform_id = qs['platform'] = "vcs";
|
||||
}
|
||||
// load and start platform object
|
||||
// TODO: self-register platforms
|
||||
if (platform_id == 'vcs') {
|
||||
platform = new VCSPlatform();
|
||||
$("#booklink_vcs").show();
|
||||
} else if (platform_id == 'apple2') {
|
||||
platform = new Apple2Platform($("#emulator")[0]);
|
||||
} else if (platform_id == 'atarivec') {
|
||||
platform = new AtariVectorPlatform($("#emulator")[0]);
|
||||
} else if (platform_id == 'exidy') {
|
||||
platform = new ExidyPlatform($("#emulator")[0]);
|
||||
} else if (platform_id == 'spaceinv') {
|
||||
platform = new SpaceInvadersPlatform($("#emulator")[0]);
|
||||
} else {
|
||||
alert("Platform " + platform_id + " not recognized");
|
||||
}
|
||||
store = new FileStore(localStorage, platform_id + '/');
|
||||
PRESETS = platform.getPresets();
|
||||
setupDebugControls();
|
||||
platform.start();
|
||||
// reset file?
|
||||
if (qs['file'] && qs['reset']) {
|
||||
store.deleteFile(qs['file']);
|
||||
qs['reset'] = '';
|
||||
window.location = "?" + $.param(qs);
|
||||
} else if (qs['file']) {
|
||||
// load file
|
||||
loadPreset(qs['file']);
|
||||
updateSelector();
|
||||
} else {
|
||||
// try to load last file
|
||||
var lastid = localStorage.getItem("__lastid_"+platform_id) || localStorage.getItem("__lastid");
|
||||
localStorage.removeItem("__lastid");
|
||||
gotoPresetNamed(lastid || PRESETS[0].id);
|
||||
}
|
||||
} catch (e) {
|
||||
alert(e+""); // TODO?
|
||||
}
|
||||
|
12
src/util.js
12
src/util.js
@ -1,4 +1,16 @@
|
||||
|
||||
function hex(v, nd) {
|
||||
try {
|
||||
if (!nd) nd = 2;
|
||||
var s = v.toString(16).toUpperCase();
|
||||
while (s.length < nd)
|
||||
s = "0" + s;
|
||||
return s;
|
||||
} catch (e) {
|
||||
return v+"";
|
||||
}
|
||||
}
|
||||
|
||||
function lzgmini() {
|
||||
|
||||
// Constants
|
||||
|
@ -1,15 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
// set up require.js for worker
|
||||
importScripts("dasm.js");
|
||||
importScripts("acme.js");
|
||||
importScripts("plasm.js");
|
||||
importScripts("cc65.js");
|
||||
importScripts("ca65.js");
|
||||
importScripts("ld65.js");
|
||||
importScripts("z80asm.js");
|
||||
importScripts("sdcc.js");
|
||||
|
||||
var loaded = {}
|
||||
function load(modulename) {
|
||||
if (!loaded[modulename]) {
|
||||
importScripts(modulename+".js");
|
||||
loaded[modulename] = 1;
|
||||
}
|
||||
}
|
||||
// shim out window and document objects for security
|
||||
// https://github.com/mbostock/d3/issues/1053
|
||||
var noop = function() { return new Function(); };
|
||||
@ -49,6 +46,20 @@ function setupFS(FS) {
|
||||
}, '/share');
|
||||
}
|
||||
|
||||
function extractErrors(strings, regex) {
|
||||
var errors = [];
|
||||
for (var i=0; i<strings.length; i++) {
|
||||
var m = regex.exec(strings[i]);
|
||||
if (m) {
|
||||
errors.push({
|
||||
line: m[1],
|
||||
msg: m[2]
|
||||
});
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
// main worker start
|
||||
|
||||
var DASM_MAIN_FILENAME = "main.a";
|
||||
@ -69,13 +80,36 @@ function match_msvc(s) {
|
||||
console.log(s, matches);
|
||||
if (matches) {
|
||||
errline = parseInt(matches[1]);
|
||||
errors.push({
|
||||
msvc_errors.push({
|
||||
line:errline,
|
||||
msg:matches[2]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function parseListing(code, lineMatch) {
|
||||
var lines = [];
|
||||
for (var line of code.split(/\r?\n/)) {
|
||||
var linem = lineMatch.exec(line);
|
||||
if (linem && linem[1]) {
|
||||
var linenum = parseInt(linem[1]);
|
||||
var filename = linem[2];
|
||||
var offset = parseInt(linem[3], 16);
|
||||
var insns = linem[4];
|
||||
var restline = linem[5];
|
||||
if (insns) {
|
||||
lines.push({
|
||||
line:linenum,
|
||||
offset:offset,
|
||||
insns:insns,
|
||||
iscode:restline[0] != '.'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function parseDASMListing(code, unresolved) {
|
||||
var errorMatch = /main.a [(](\d+)[)]: error: (.+)/;
|
||||
// 4 08ee a9 00 start lda #01workermain.js:23:5
|
||||
@ -137,6 +171,7 @@ function parseDASMListing(code, unresolved) {
|
||||
}
|
||||
|
||||
function assembleDASM(code) {
|
||||
load("dasm");
|
||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
||||
var unresolved = {};
|
||||
function match_fn(s) {
|
||||
@ -165,6 +200,7 @@ function assembleDASM(code) {
|
||||
|
||||
// TODO: not quite done
|
||||
function assembleACME(code) {
|
||||
load("acme");
|
||||
// stderr
|
||||
var re_err2 = /(Error|Warning) - File (.+?), line (\d+) ([^:]+) (.*)/;
|
||||
var errors = [];
|
||||
@ -210,6 +246,7 @@ function setupStdin(fs, code) {
|
||||
}
|
||||
|
||||
function compilePLASMA(code) {
|
||||
load("plasm");
|
||||
// stdout
|
||||
var outstr = "";
|
||||
function out_fn(s) { outstr += s; outstr += "\n"; }
|
||||
@ -278,6 +315,8 @@ function parseCA65Listing(code, mapfile) {
|
||||
}
|
||||
|
||||
function assemblelinkCA65(code, platform, warnings) {
|
||||
load("ca65");
|
||||
load("ld65");
|
||||
if (!platform)
|
||||
platform = 'apple2'; // TODO
|
||||
var objout, lstout;
|
||||
@ -321,6 +360,7 @@ function assemblelinkCA65(code, platform, warnings) {
|
||||
}
|
||||
|
||||
function compileCC65(code, platform) {
|
||||
load("cc65");
|
||||
if (!platform)
|
||||
platform = 'apple2'; // TODO
|
||||
// stderr
|
||||
@ -357,6 +397,7 @@ function compileCC65(code, platform) {
|
||||
}
|
||||
|
||||
function assembleZ80ASM(code, platform) {
|
||||
load("z80asm");
|
||||
if (!platform)
|
||||
platform = 'apple2'; // TODO
|
||||
var Module = z80asm({
|
||||
@ -364,6 +405,7 @@ function assembleZ80ASM(code, platform) {
|
||||
//logReadFiles:true,
|
||||
print:print_fn,
|
||||
printErr:print_fn,
|
||||
TOTAL_MEMORY:64*1024*1024,
|
||||
//locateFile: function(s) { return "" + s; },
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
@ -377,7 +419,9 @@ function assembleZ80ASM(code, platform) {
|
||||
Module.callMain(["-b", "-s", "-l", "-m", "main.asm"]);
|
||||
try {
|
||||
var aerr = FS.readFile("main.err", {'encoding':'utf8'}); // TODO
|
||||
console.log("ERRORS", aerr); // TODO
|
||||
if (aerr.length) {
|
||||
return {listing:{errors:extractErrors(aerr.split("\n"), /.+? line (\d+): (.+)/)}};
|
||||
}
|
||||
// Warning at file 'test.asm' line 9: 'XREF' is deprecated, use 'EXTERN' instead
|
||||
} catch (e) {
|
||||
}
|
||||
@ -396,15 +440,19 @@ l_main00101 = 0003, L: test
|
||||
return {
|
||||
exitstatus:Module.EXITSTATUS,
|
||||
output:aout,
|
||||
listing:listing,
|
||||
listing:{
|
||||
errors:[],
|
||||
lines:parseListing(alst, /(\d+)(\s+)([0-9A-F]+)\s+([0-9A-F][0-9A-F ]*[0-9A-F])\s+([A-Z_.].+)/i)
|
||||
},
|
||||
intermediate:{listing:alst, mapfile:amap},
|
||||
};
|
||||
} catch (e) {
|
||||
throw Error(e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
|
||||
function compileSDCC(code, platform) {
|
||||
load("sdcc");
|
||||
var SDCC = sdcc({
|
||||
noInitialRun:true,
|
||||
noFSInit:true,
|
||||
|
@ -59,12 +59,16 @@ global.postMessage = null;
|
||||
|
||||
includeInThisContext("src/worker/workermain.js");
|
||||
|
||||
function compile(tool, code, callback, outlen) {
|
||||
function compile(tool, code, callback, outlen, nlines, nerrors) {
|
||||
global.postMessage = function(msg) {
|
||||
if (msg.listing.errors.length) console.log(msg.listing.errors);
|
||||
assert.ok(msg.listing.lines);
|
||||
assert.equal(msg.listing.errors.length, msg.listing.errors);
|
||||
assert.equal(msg.output.length, outlen);
|
||||
if (msg.listing.errors && msg.listing.errors.length) {
|
||||
console.log(msg.listing.errors);
|
||||
assert.equal(nerrors, msg.listing.errors.length, "errors");
|
||||
} else {
|
||||
assert.equal(nerrors||0, 0, "errors");
|
||||
assert.equal(msg.output.length, outlen, "output binary");
|
||||
assert.equal(msg.listing.lines.length, nlines, "listing lines");
|
||||
}
|
||||
callback(null, msg);
|
||||
};
|
||||
global.onmessage({
|
||||
@ -74,18 +78,21 @@ function compile(tool, code, callback, outlen) {
|
||||
|
||||
describe('Worker', function() {
|
||||
it('should assemble DASM', function(done) {
|
||||
compile('dasm', '\tprocessor 6502\n\torg $f000\nfoo lda #0\n', done, 2);
|
||||
compile('dasm', '\tprocessor 6502\n\torg $f000\nfoo lda #0\n', done, 2, 1);
|
||||
});
|
||||
it('should compile PLASMA', function(done) {
|
||||
compile('plasm', 'word x = 0', done, 5);
|
||||
compile('plasm', 'word x = 0', done, 5, 0);
|
||||
});
|
||||
it('should compile CC65', function(done) {
|
||||
compile('cc65', '#include <stdio.h>\nint main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', done, 2947);
|
||||
compile('cc65', '#include <stdio.h>\nint main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', done, 2947, 4);
|
||||
});
|
||||
it('should NOT assemble Z80ASM', function(done) {
|
||||
compile('z80asm', 'ddwiuweq', done, 0, 0, 1);
|
||||
});
|
||||
it('should assemble Z80ASM', function(done) {
|
||||
compile('z80asm', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', done, 4);
|
||||
compile('z80asm', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', done, 4, 2, 0);
|
||||
});
|
||||
it('should compile SDCC', function(done) {
|
||||
compile('sdcc', 'int main(int argc) {\nint x=1; int y=2;\nreturn x+y+argc;\n}', done, 16);
|
||||
compile('sdcc', 'int main(int argc) {\nint x=1; int y=2;\nreturn x+y+argc;\n}', done, 16, 8, 0);
|
||||
});
|
||||
});
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
require('../../src/cpu/z80.js');
|
||||
|
||||
global.buildZ80({
|
||||
var _global = window;
|
||||
|
||||
_global.buildZ80({
|
||||
applyContention: true
|
||||
});
|
||||
|
||||
@ -92,7 +94,7 @@ function runTest(input, expected) {
|
||||
|
||||
var memory = Memory(dump);
|
||||
var ioBus = IOBus();
|
||||
var z80 = global.Z80({
|
||||
var z80 = _global.Z80({
|
||||
display: {},
|
||||
memory: memory,
|
||||
ioBus: ioBus
|
||||
|
Loading…
x
Reference in New Issue
Block a user