new buttons; better DASM listing; fixed dbg btns; removed menu
@ -366,7 +366,7 @@ span.CodeMirror-selectedtext { background: none; }
|
||||
|
||||
.cm-s-mbo span.cm-comment { color: #95958a; }
|
||||
.cm-s-mbo span.cm-atom { color: #00a8c6; }
|
||||
.cm-s-mbo span.cm-number { color: #00a8c6; }
|
||||
.cm-s-mbo span.cm-number { color: #33aadd; }
|
||||
|
||||
.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute { color: #9ddfe9; }
|
||||
.cm-s-mbo span.cm-keyword { color: #ffb928; }
|
||||
@ -376,7 +376,7 @@ span.CodeMirror-selectedtext { background: none; }
|
||||
.cm-s-mbo span.cm-variable { color: #ffffec; }
|
||||
.cm-s-mbo span.cm-variable-2 { color: #00a8c6; }
|
||||
.cm-s-mbo span.cm-variable-3 { color: #ffb928; }
|
||||
.cm-s-mbo span.cm-def { color: #ffff88; }
|
||||
.cm-s-mbo span.cm-def { color: #88eeff; }
|
||||
.cm-s-mbo span.cm-bracket { color: #fffffc; font-weight: bold; }
|
||||
.cm-s-mbo span.cm-tag { color: #9ddfe9; }
|
||||
.cm-s-mbo span.cm-link { color: #f54b07; }
|
||||
@ -414,3 +414,7 @@ span.CodeMirror-selectedtext { background: none; }
|
||||
|
||||
.cm-s-cobalt .CodeMirror-activeline-background { background: #003399; }
|
||||
.cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }
|
||||
|
||||
/*** FIXES FOR BOOTSTRAP ***/
|
||||
|
||||
.CodeMirror-dialog > button { background-color: #333 !important; }
|
||||
|
BIN
images/pause.png
Before Width: | Height: | Size: 95 B |
BIN
images/play.png
Before Width: | Height: | Size: 123 B |
Before Width: | Height: | Size: 143 B |
Before Width: | Height: | Size: 128 B |
BIN
images/share.png
Before Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 160 B |
Before Width: | Height: | Size: 165 B |
20
index.html
@ -186,6 +186,7 @@ canvas.pixelated {
|
||||
<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">Revert to Original...</a></li>
|
||||
<!--
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Platform</a>
|
||||
<ul class="dropdown-menu">
|
||||
@ -195,6 +196,7 @@ canvas.pixelated {
|
||||
<li><a class="dropdown-item" href="?platform=spaceinv" id="item_platform_spaceinv">Space Invaders</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
-->
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Debug</a>
|
||||
<ul class="dropdown-menu">
|
||||
@ -206,15 +208,15 @@ canvas.pixelated {
|
||||
<select id="preset_select" name="">
|
||||
</select>
|
||||
<span id="debug_bar">
|
||||
<button id="dbg_pause" type="button" title="Pause"><img src="images/pause.png"></button>
|
||||
<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_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>
|
||||
<button id="dbg_reset" type="submit" title="Reset and Break"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
|
||||
<button id="dbg_pause" type="button" title="Pause"><span class="glyphicon glyphicon-pause" aria-hidden="true"></span></button>
|
||||
<button id="dbg_go" type="button" title="Run"><span class="glyphicon glyphicon-play" aria-hidden="true"></span></button>
|
||||
<button id="dbg_step" type="submit" title="Step"><span class="glyphicon glyphicon-step-forward" aria-hidden="true"></span></button>
|
||||
<button id="dbg_toline" type="submit" title="Run To Line"><span class="glyphicon glyphicon-save" aria-hidden="true"></span></button>
|
||||
<button id="dbg_stepout" type="submit" title="Step Out of Subroutine"><span class="glyphicon glyphicon-hand-left" aria-hidden="true"></span></button>
|
||||
<button id="dbg_stepback" type="submit" title="Step Backwards"><span class="glyphicon glyphicon-step-backward" aria-hidden="true"></span></button>
|
||||
<button id="dbg_timing" type="submit" title="See Timing" style="display:none"><span class="glyphicon glyphicon-time" aria-hidden="true"></span></button>
|
||||
<button id="dbg_disasm" type="submit" title="Toggle Disassembly" style="display:none"><span class="glyphicon glyphicon-list" aria-hidden="true"></span></button>
|
||||
</span>
|
||||
<span class="dbg_info" id="dbg_info"></span>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "8bitworkshop",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"author": "Steven Hugg",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
@ -630,6 +630,8 @@ var BaseZ80Platform = function() {
|
||||
if (fn.endsWith(".s")) return "sdasz80";
|
||||
return "z80asm";
|
||||
}
|
||||
// TODO
|
||||
//this.getOpcodeMetadata = function() { }
|
||||
}
|
||||
|
||||
function padBytes(data, len) {
|
||||
|
@ -15,7 +15,7 @@ var SpaceInvadersPlatform = function(mainElement) {
|
||||
this.__proto__ = new BaseZ80Platform();
|
||||
|
||||
var cpu, ram, membus, iobus, rom;
|
||||
var video, audio, timer, pixels, displayPCs;
|
||||
var video, timer, pixels, displayPCs;
|
||||
var inputs = [0xe,0x8,0x0];
|
||||
var bitshift_offset = 0;
|
||||
var bitshift_register = 0;
|
||||
@ -38,16 +38,6 @@ var SpaceInvadersPlatform = function(mainElement) {
|
||||
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;
|
||||
}
|
||||
@ -58,10 +48,10 @@ var SpaceInvadersPlatform = function(mainElement) {
|
||||
membus = {
|
||||
read: function(address) {
|
||||
if (address < 0x2000) {
|
||||
return rom ? rom[address] : 0;
|
||||
return (rom ? rom[address] : 0) & 0xff;
|
||||
} else {
|
||||
address &= 0x1fff;
|
||||
return ram.mem[address];
|
||||
return ram.mem[address] & 0xff;
|
||||
}
|
||||
},
|
||||
write: function(address, value) {
|
||||
@ -122,7 +112,6 @@ var SpaceInvadersPlatform = function(mainElement) {
|
||||
ioBus: iobus
|
||||
});
|
||||
video = new RasterVideo(mainElement,256,224,{rotate:-90});
|
||||
audio = new SampleAudio(cpuFrequency);
|
||||
video.create();
|
||||
$(video.canvas).click(function(e) {
|
||||
var x = Math.floor(e.offsetX * video.canvas.width / $(video.canvas).width());
|
||||
@ -215,11 +204,9 @@ var SpaceInvadersPlatform = function(mainElement) {
|
||||
}
|
||||
this.pause = function() {
|
||||
timer.stop();
|
||||
audio.stop();
|
||||
}
|
||||
this.resume = function() {
|
||||
timer.start();
|
||||
audio.start();
|
||||
}
|
||||
this.reset = function() {
|
||||
cpu.reset();
|
||||
|
@ -42,8 +42,6 @@ var VCSPlatform = function() {
|
||||
this.getPresets = function() { return VCS_PRESETS; }
|
||||
|
||||
this.start = function() {
|
||||
$("#dbg_timing").show();
|
||||
$("#dbg_disasm").show();
|
||||
Javatari.start();
|
||||
}
|
||||
|
||||
|
72
src/ui.js
@ -74,7 +74,7 @@ var SourceFile = function(lines, text) {
|
||||
}
|
||||
this.findLineForOffset = function(PC) {
|
||||
if (this.offset2line) {
|
||||
for (var i=0; i<256; i++) {
|
||||
for (var i=0; i<16; i++) {
|
||||
var line = this.offset2line[PC];
|
||||
if (line >= 0) {
|
||||
return line;
|
||||
@ -200,17 +200,9 @@ function gotoPresetAt(index) {
|
||||
}
|
||||
|
||||
function gotoPresetNamed(id) {
|
||||
if (id.startsWith("_")) {
|
||||
var result = eval(id+"()");
|
||||
console.log(id, result);
|
||||
if (!result) {
|
||||
updateSelector();
|
||||
}
|
||||
} else {
|
||||
qs['platform'] = platform_id;
|
||||
qs['file'] = id;
|
||||
window.location = "?" + $.param(qs);
|
||||
}
|
||||
qs['platform'] = platform_id;
|
||||
qs['file'] = id;
|
||||
window.location = "?" + $.param(qs);
|
||||
}
|
||||
|
||||
function _createNewFile(e) {
|
||||
@ -263,7 +255,7 @@ function _resetPreset(e) {
|
||||
}
|
||||
|
||||
function populateExamples(sel) {
|
||||
sel.append($("<option />").text("--------- Chapters ---------"));
|
||||
sel.append($("<option />").text("--------- Chapters ---------").attr('disabled',true));
|
||||
for (var i=0; i<PRESETS.length; i++) {
|
||||
var preset = PRESETS[i];
|
||||
var name = preset.chapter + ". " + preset.name;
|
||||
@ -272,7 +264,7 @@ function populateExamples(sel) {
|
||||
}
|
||||
|
||||
function populateLocalFiles(sel) {
|
||||
sel.append($("<option />").text("------- Local Files -------"));
|
||||
sel.append($("<option />").text("------- Local Files -------").attr('disabled',true));
|
||||
var filenames = store.getFiles("local/");
|
||||
for (var i = 0; i < filenames.length; i++) {
|
||||
var name = filenames[i];
|
||||
@ -282,7 +274,7 @@ function populateLocalFiles(sel) {
|
||||
}
|
||||
|
||||
function populateSharedFiles(sel) {
|
||||
sel.append($("<option />").text("--------- Shared ---------"));
|
||||
sel.append($("<option />").text("--------- Shared ---------").attr('disabled',true));
|
||||
var filenames = store.getFiles("shared/");
|
||||
for (var i = 0; i < filenames.length; i++) {
|
||||
var name = filenames[i];
|
||||
@ -354,13 +346,15 @@ worker.onmessage = function(e) {
|
||||
var rom_changed = rom && !arrayCompare(rom, current_output);
|
||||
if (rom_changed) {
|
||||
try {
|
||||
resume();
|
||||
//console.log("Loading ROM length", rom.length);
|
||||
platform.loadROM(getCurrentPresetTitle(), rom);
|
||||
resume();
|
||||
// TODO: what if loadROM fails?
|
||||
current_output = rom;
|
||||
pcvisits = {};
|
||||
} catch (e) {
|
||||
console.log(e); // TODO
|
||||
console.log(e); // TODO: show error
|
||||
alert("Could not load ROM: " + e);
|
||||
current_output = null;
|
||||
}
|
||||
}
|
||||
@ -381,10 +375,12 @@ worker.onmessage = function(e) {
|
||||
editor.setGutterMarker(info.line-1, "gutter-bytes", textel);
|
||||
if (info.iscode) {
|
||||
var opcode = parseInt(info.insns.split()[0], 16);
|
||||
var meta = platform.getOpcodeMetadata(opcode, info.offset);
|
||||
var clockstr = meta.minCycles+"";
|
||||
var textel = document.createTextNode(clockstr);
|
||||
editor.setGutterMarker(info.line-1, "gutter-clock", textel);
|
||||
if (platform.getOpcodeMetadata) {
|
||||
var meta = platform.getOpcodeMetadata(opcode, info.offset);
|
||||
var clockstr = meta.minCycles+"";
|
||||
var textel = document.createTextNode(clockstr);
|
||||
editor.setGutterMarker(info.line-1, "gutter-clock", textel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -497,8 +493,8 @@ function getCurrentLine() {
|
||||
|
||||
function runToCursor() {
|
||||
setupBreakpoint();
|
||||
var line = sourcefile.getCurrentLine();
|
||||
var pc = line2offset[line];
|
||||
var line = getCurrentLine();
|
||||
var pc = sourcefile.line2offset[line];
|
||||
if (pc >= 0) {
|
||||
console.log("Run to", line, pc.toString(16));
|
||||
platform.runEval(function(c) {
|
||||
@ -678,8 +674,8 @@ function showLoopTimingForPC(pc) {
|
||||
// recurse through all traces
|
||||
_traceInstructions(pc | platform.getOriginPC(), MAX_CLOCKS, MAX_CLOCKS);
|
||||
// show the lines
|
||||
for (var line in line2offset) {
|
||||
var pc = line2offset[line];
|
||||
for (var line in sourcefile.line2offset) {
|
||||
var pc = sourcefile.line2offset[line];
|
||||
var minclocks = pc2minclocks[pc];
|
||||
var maxclocks = pc2maxclocks[pc];
|
||||
if (minclocks>=0 && maxclocks>=0) {
|
||||
@ -774,8 +770,10 @@ function toggleDisassembly() {
|
||||
|
||||
function resetAndDebug() {
|
||||
clearBreakpoint();
|
||||
platform.resume();
|
||||
platform.reset();
|
||||
platform.breakpointHit();
|
||||
setupBreakpoint();
|
||||
platform.runEval(function(c) { return true; });
|
||||
}
|
||||
|
||||
function _breakExpression() {
|
||||
@ -795,11 +793,13 @@ function setupDebugControls(){
|
||||
$("#dbg_toline").click(runToCursor);
|
||||
$("#dbg_stepout").click(runUntilReturn);
|
||||
$("#dbg_stepback").click(runStepBackwards);
|
||||
$("#dbg_timing").click(traceTiming);
|
||||
if (platform.disassemble)
|
||||
$("#dbg_disasm").click(toggleDisassembly);
|
||||
else
|
||||
$("#dbg_disasm").hide();
|
||||
// TODO: vcs platform seems to show them regardless
|
||||
if (platform_id == 'vcs') {
|
||||
$("#dbg_timing").click(traceTiming).show();
|
||||
}
|
||||
if (platform.disassemble) {
|
||||
$("#dbg_disasm").click(toggleDisassembly).show();
|
||||
}
|
||||
$("#disassembly").hide();
|
||||
$(".dropdown-menu").collapse({toggle: false});
|
||||
$("#item_new_file").click(_createNewFile);
|
||||
@ -869,17 +869,19 @@ function startPlatform() {
|
||||
platform = new PLATFORMS[platform_id]($("#emulator")[0]);
|
||||
store = new FileStore(localStorage, platform_id + '/');
|
||||
PRESETS = platform.getPresets();
|
||||
setupDebugControls();
|
||||
platform.start();
|
||||
if (qs['file']) {
|
||||
// load file
|
||||
// start platform and load file
|
||||
setupDebugControls();
|
||||
platform.start();
|
||||
loadPreset(qs['file']);
|
||||
updateSelector();
|
||||
return true;
|
||||
} else {
|
||||
// try to load last file
|
||||
// try to load last file (redirect)
|
||||
var lastid = localStorage.getItem("__lastid_"+platform_id) || localStorage.getItem("__lastid");
|
||||
localStorage.removeItem("__lastid");
|
||||
gotoPresetNamed(lastid || PRESETS[0].id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,17 +71,18 @@ var print_fn = function(s) {
|
||||
}
|
||||
|
||||
// test.c(6) : warning 85: in function main unreferenced local variable : 'x'
|
||||
var re_msvc = /(.*?)[(](\d+)[)]\s*:\s*(\w+)\s*(\d+):\s*(.*)/;
|
||||
var re_msvc2 = /\s*at\s+(\d+)\s*:\s*(.*)/;
|
||||
// main.a (4): error: Unknown Mnemonic 'xxx'.
|
||||
var re_msvc = /([^(]+)\s*[(](\d+)[)]\s*:\s*(.+?):\s*(.*)/;
|
||||
var re_msvc2 = /\s*(at)\s+(\d+)\s*(:)\s*(.*)/;
|
||||
var msvc_errors;
|
||||
|
||||
function match_msvc(s) {
|
||||
var matches = re_msvc.exec(s) || re_msvc2.exec(s);
|
||||
if (matches) {
|
||||
var errline = parseInt(matches[1]);
|
||||
var errline = parseInt(matches[2]);
|
||||
msvc_errors.push({
|
||||
line:errline,
|
||||
msg:matches[2]
|
||||
msg:matches[4]
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -129,9 +130,8 @@ function parseSourceLines(code, lineMatch, offsetMatch) {
|
||||
}
|
||||
|
||||
function parseDASMListing(code, unresolved) {
|
||||
var errorMatch = /main.a [(](\d+)[)]: error: (.+)/;
|
||||
// 4 08ee a9 00 start lda #01workermain.js:23:5
|
||||
var lineMatch = /\s*(\d+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f][0-9a-f ]+)\s+(.+)/;
|
||||
var lineMatch = /\s*(\d+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f][0-9a-f ]+)?\s+(.+)?/;
|
||||
var equMatch = /\bequ\b/;
|
||||
var errors = [];
|
||||
var lines = [];
|
||||
@ -157,7 +157,7 @@ function parseDASMListing(code, unresolved) {
|
||||
lastline = linenum;
|
||||
} else {
|
||||
// inside of macro or include file
|
||||
if (linenum == -DASM_PREAMBLE_LINES) { // start of macro?
|
||||
if (insns && linem[3] && lastline>0) {
|
||||
lines.push({
|
||||
line:lastline+1,
|
||||
offset:offset,
|
||||
@ -177,11 +177,11 @@ function parseDASMListing(code, unresolved) {
|
||||
}
|
||||
}
|
||||
}
|
||||
var errm = errorMatch.exec(line);
|
||||
var errm = re_msvc.exec(line);
|
||||
if (errm) {
|
||||
errors.push({
|
||||
line:parseInt(errm[1]),
|
||||
msg:errm[2]
|
||||
line:parseInt(errm[2]),
|
||||
msg:errm[4]
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -204,9 +204,10 @@ function assembleDASM(code) {
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
FS.writeFile(DASM_MAIN_FILENAME, DASM_PREAMBLE + code);
|
||||
Module.callMain([DASM_MAIN_FILENAME, "-v3", "-la.lst"]);
|
||||
Module.callMain([DASM_MAIN_FILENAME, "-la.lst"/*, "-v3", "-sa.sym"*/]);
|
||||
var aout = FS.readFile("a.out");
|
||||
var alst = FS.readFile("a.lst", {'encoding':'utf8'});
|
||||
//var asym = FS.readFile("a.sym", {'encoding':'utf8'});
|
||||
var listing = parseDASMListing(alst, unresolved);
|
||||
return {
|
||||
output:aout.slice(2),
|
||||
|
@ -80,28 +80,43 @@ describe('Worker', function() {
|
||||
it('should assemble DASM', function(done) {
|
||||
compile('dasm', '\tprocessor 6502\n\torg $f000\nfoo lda #0\n', 'vcs', done, 2, 1);
|
||||
});
|
||||
it('should NOT assemble DASM', function(done) {
|
||||
compile('dasm', '\tprocessor 6502\n\torg $f000\nfoo xxx #0\n', 'vcs', done, 0, 0, 1);
|
||||
});
|
||||
it('should assemble ACME', function(done) {
|
||||
compile('acme', 'foo: lda #0\n', 'vcs', done, 2, 0); // TODO
|
||||
});
|
||||
it('should NOT assemble ACME', function(done) {
|
||||
compile('acme', 'foo: xxx #0\n', 'vcs', done, 0, 0, 2); // TODO
|
||||
});
|
||||
it('should compile PLASMA', function(done) {
|
||||
compile('plasm', 'word x = 0', 'apple2', done, 5, 0);
|
||||
});
|
||||
it('should NOT compile PLASMA', function(done) {
|
||||
compile('plasm', 'word x = ', 'apple2', done, 0, 0, 1);
|
||||
});
|
||||
it('should compile CC65', function(done) {
|
||||
compile('cc65', '#include <stdio.h>\nint main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', 'apple2', done, 2947, 4);
|
||||
});
|
||||
it('should NOT assemble Z80ASM', function(done) {
|
||||
compile('z80asm', 'ddwiuweq', 'none', done, 0, 0, 1);
|
||||
it('should NOT compile CC65', function(done) {
|
||||
compile('cc65', 'int main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', 'apple2', done, 0, 0, 1);
|
||||
});
|
||||
it('should assemble Z80ASM', function(done) {
|
||||
compile('z80asm', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', 'spaceinv', done, 4, 2, 0);
|
||||
});
|
||||
it('should NOT compile SDCC', function(done) {
|
||||
compile('sdcc', 'foobar', 'spaceinv', done, 0, 0, 1);
|
||||
it('should NOT assemble Z80ASM', function(done) {
|
||||
compile('z80asm', 'ddwiuweq', 'none', done, 0, 0, 1);
|
||||
});
|
||||
it('should assemble SDASZ80', function(done) {
|
||||
compile('sdcc', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', 'spaceinv', done, 8192, 2, 1);
|
||||
compile('sdasz80', '\tld hl,#0\n\tret\n', 'spaceinv', done, 8192, 2);
|
||||
});
|
||||
it('should NOT assemble SDASZ80', function(done) {
|
||||
compile('sdasz80', '\txxx hl,#0\n\tret\n', 'spaceinv', done, 0, 0, 1);
|
||||
});
|
||||
it('should compile SDCC', function(done) {
|
||||
compile('sdcc', 'int foo=0;\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'spaceinv', done, 8192, 3, 0);
|
||||
});
|
||||
it('should NOT compile SDCC', function(done) {
|
||||
compile('sdcc', 'foobar', 'spaceinv', done, 0, 0, 1);
|
||||
});
|
||||
});
|