Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: robey/carrot16
base: 785e928e8c
...
head fork: robey/carrot16
compare: ba0b8efc98
  • 2 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
4 index.html
View
@@ -45,6 +45,10 @@
</li>
<li class="divider"></li>
<li>
+ <a id="menu-disassemble">Disassemble<span class="pull-right">&#x25c6;D</span></a>
+ </li>
+ <li class="divider"></li>
+ <li>
<a id="menu-close">Close tab<span class="pull-right">&#x25c6;W</span></a>
</li>
</ul>
363 js/lib/d16asm.js
View
@@ -1,7 +1,7 @@
var exports = {};
// Generated by CoffeeScript 1.3.3
(function() {
- var Assembler, AssemblerError, AssemblerOutput, BuiltinMacros, DataLine, Dcpu, Expression, Line, Macro, Operand, ParsedLine, Parser, PrettyPrinter, Span, hex, padding, pp, prettyPrinter, x,
+ var Assembler, AssemblerError, AssemblerOutput, BuiltinMacros, DataLine, Dcpu, Disassembler, Expression, Instruction, Line, Macro, Operand, ParsedLine, Parser, PrettyPrinter, Span, hex, k, padding, pp, prettyPrinter, v, x, _ref, _ref1,
__slice = [].slice;
@@ -609,8 +609,285 @@ var exports = {};
return _results;
})()).concat(["jmp", "hlt", "ret", "bra", "dat", "org", "equ"]);
+ Dcpu.BinaryOpNames = {};
+
+ _ref = Dcpu.BinaryOp;
+ for (k in _ref) {
+ v = _ref[k];
+ Dcpu.BinaryOpNames[v] = k;
+ }
+
+ Dcpu.SpecialOpNames = {};
+
+ _ref1 = Dcpu.SpecialOp;
+ for (k in _ref1) {
+ v = _ref1[k];
+ Dcpu.SpecialOpNames[v] = k;
+ }
+
exports.Dcpu = Dcpu;
+
+
+
+ Instruction = (function() {
+
+ function Instruction(pc, words, opname, a, b, aArgument, bArgument) {
+ this.pc = pc;
+ this.words = words;
+ this.opname = opname;
+ this.a = a;
+ this.b = b;
+ this.aArgument = aArgument;
+ this.bArgument = bArgument;
+ }
+
+ Instruction.prototype.resolve = function(labels) {
+ if ((this.aArgument != null) && (labels[this.aArgument] != null)) {
+ this.aArgument = labels[this.aArgument];
+ }
+ if ((this.bArgument != null) && (labels[this.bArgument] != null)) {
+ this.bArgument = labels[this.bArgument];
+ }
+ return this;
+ };
+
+ Instruction.prototype.stringify = function(x) {
+ if (typeof x === "number") {
+ if (x < 32) {
+ return x.toString();
+ } else {
+ return "0x" + (x.toString(16));
+ }
+ } else {
+ return x.toString();
+ }
+ };
+
+ Instruction.prototype.decodeOperand = function(op, argument, dest) {
+ if (dest == null) {
+ dest = false;
+ }
+ if (op >= Operand.Register && op < Operand.Register + 8) {
+ return Dcpu.RegisterNames[op];
+ } else if (op >= Operand.RegisterDereference && op < Operand.RegisterDereference + 8) {
+ return "[" + Dcpu.RegisterNames[op - Operand.RegisterDereference] + "]";
+ } else if (op >= Operand.RegisterIndex && op < Operand.RegisterIndex + 8) {
+ return "[" + Dcpu.RegisterNames[op - Operand.RegisterIndex] + " + " + (this.stringify(argument)) + "]";
+ } else if (op === Dcpu.Specials["pop"]) {
+ if (dest) {
+ return "PUSH";
+ } else {
+ return "POP";
+ }
+ } else if (op === Dcpu.Specials["peek"]) {
+ return "PEEK";
+ } else if (op === Dcpu.Specials["pick"]) {
+ return "PICK " + (this.stringify(argument));
+ } else if (op === Dcpu.Specials["sp"]) {
+ return "SP";
+ } else if (op === Dcpu.Specials["pc"]) {
+ return "PC";
+ } else if (op === Dcpu.Specials["ex"]) {
+ return "EX";
+ } else if (op === Operand.ImmediateDereference) {
+ return "[" + (this.stringify(argument)) + "]";
+ } else if (op === Operand.Immediate) {
+ return this.stringify(argument);
+ } else {
+ return "wut";
+ }
+ };
+
+ Instruction.prototype.toString = function(labels) {
+ var aString, bString, comment, target;
+ bString = this.b != null ? "" + (this.decodeOperand(this.b, this.bArgument, true)) + ", " : "";
+ aString = this.decodeOperand(this.a, this.aArgument);
+ target = this.target();
+ if (target) {
+ target = (labels != null) && (labels[target] != null) ? labels[target] : this.stringify(target);
+ }
+ comment = (target != null) && target !== aString ? " ; " + target : "";
+ return "" + (this.opname.toUpperCase()) + " " + bString + aString + comment;
+ };
+
+ Instruction.prototype.target = function() {
+ var _ref2, _ref3;
+ if (((_ref2 = this.opname) === "jsr" || _ref2 === "ias") && this.a === Operand.Immediate) {
+ return this.aArgument;
+ } else if (((_ref3 = this.opname) === "set" || _ref3 === "add" || _ref3 === "sub" || _ref3 === "xor") && this.b === Dcpu.Specials["pc"] && this.a === Operand.Immediate) {
+ switch (this.opname) {
+ case "set":
+ return this.aArgument;
+ case "add":
+ return ((this.pc + this.words) + this.aArgument) & 0xffff;
+ case "sub":
+ return ((this.pc + this.words) - this.aArgument) & 0xffff;
+ case "xor":
+ return ((this.pc + this.words) ^ this.aArgument) & 0xffff;
+ default:
+ return null;
+ }
+ } else {
+ return null;
+ }
+ };
+
+ Instruction.prototype.terminal = function() {
+ var _ref2;
+ return this.opname === "rfi" || (((_ref2 = this.opname) === "set" || _ref2 === "add" || _ref2 === "sub" || _ref2 === "xor" || _ref2 === "adx" || _ref2 === "sbx" || _ref2 === "sti" || _ref2 === "std") && this.b === Dcpu.Specials["pc"]);
+ };
+
+ Instruction.prototype.conditional = function() {
+ return this.opname.slice(0, 2) === "if";
+ };
+
+ return Instruction;
+
+ })();
+
+ Disassembler = (function() {
+
+ Disassembler.prototype.hasImmediate = {
+ 0x10: true,
+ 0x11: true,
+ 0x12: true,
+ 0x13: true,
+ 0x14: true,
+ 0x15: true,
+ 0x16: true,
+ 0x17: true,
+ 0x1a: true,
+ 0x1e: true,
+ 0x1f: true
+ };
+
+ function Disassembler(memory) {
+ this.memory = memory;
+ this.address = 0;
+ }
+
+ Disassembler.prototype.nextWord = function() {
+ var word;
+ word = this.memory[this.address] || 0;
+ this.address = (this.address + 1) % 0x10000;
+ return word;
+ };
+
+ Disassembler.prototype.nextInstruction = function() {
+ var a, aArgument, b, bArgument, instruction, opcode, opname, pc, word;
+ pc = this.address;
+ word = this.nextWord();
+ if (word === 0) {
+ return null;
+ }
+ opcode = word & 0x1f;
+ a = (word >> 10) & 0x3f;
+ b = (word >> 5) & 0x1f;
+ aArgument = null;
+ bArgument = null;
+ if (opcode === 0) {
+ opcode = b;
+ b = null;
+ opname = Dcpu.SpecialOpNames[opcode];
+ } else {
+ opname = Dcpu.BinaryOpNames[opcode];
+ if (opname != null) {
+ bArgument = this.hasImmediate[b] ? this.nextWord() : void 0;
+ } else {
+ null;
+ }
+ }
+ if (opname != null) {
+ aArgument = this.hasImmediate[a] ? this.nextWord() : null;
+ if (a >= 0x20) {
+ aArgument = (a - 0x21) & 0xffff;
+ a = Operand.Immediate;
+ }
+ } else {
+ opname = "DAT";
+ aArgument = word;
+ a = Operand.Immediate;
+ b = null;
+ }
+ return instruction = new Instruction(pc, this.address - pc, opname, a, b, aArgument, bArgument);
+ };
+
+ Disassembler.prototype.disassemble = function() {
+ var address, end, i, indent, instructions, labeled, labels, name, out, start, t, target, targets, _i, _j, _k, _l, _len, _len1, _len2, _len3;
+ out = [];
+ instructions = [];
+ while ((this.memory[this.address] || 0) === 0 && this.address < 0x10000) {
+ this.address += 1;
+ }
+ if (this.address >= 0x10000) {
+ return [];
+ }
+ end = 0x10000;
+ while ((this.memory[end - 1] || 0) === 0) {
+ end -= 1;
+ }
+ while (this.address < end) {
+ x = this.nextInstruction();
+ if (x != null) {
+ instructions.push(x);
+ }
+ }
+ targets = [];
+ labels = {};
+ for (_i = 0, _len = instructions.length; _i < _len; _i++) {
+ x = instructions[_i];
+ target = x.target();
+ if (target != null) {
+ targets.push(target);
+ }
+ }
+ targets.sort();
+ for (i = _j = 0, _len1 = targets.length; _j < _len1; i = ++_j) {
+ t = targets[i];
+ labels[t] = "t" + (i + 1);
+ }
+ for (_k = 0, _len2 = instructions.length; _k < _len2; _k++) {
+ x = instructions[_k];
+ x.resolve(labels);
+ }
+ start = 0;
+ indent = " ";
+ labeled = {};
+ for (_l = 0, _len3 = instructions.length; _l < _len3; _l++) {
+ x = instructions[_l];
+ if (x.pc !== start) {
+ if (labels[start] != null) {
+ out.push(":" + labels[start]);
+ labeled[start] = true;
+ }
+ out.push("");
+ out.push(".ORG 0x" + (x.pc.toString(16)));
+ indent = " ";
+ }
+ if (labels[x.pc] != null) {
+ out.push(":" + labels[x.pc]);
+ labeled[x.pc] = true;
+ }
+ out.push(indent + x.toString(labels));
+ indent = x.conditional() ? indent + " " : " ";
+ start = x.pc + x.words;
+ }
+ for (address in labels) {
+ name = labels[address];
+ if (!labeled[address]) {
+ out.unshift(".DEFINE " + name + " 0x" + (parseInt(address).toString(16)));
+ }
+ }
+ return out;
+ };
+
+ return Disassembler;
+
+ })();
+
+ exports.Disassembler = Disassembler;
+
AssemblerError = (function() {
function AssemblerError(text, pos, reason) {
@@ -624,9 +901,9 @@ var exports = {};
AssemblerError.prototype.format = function(reason) {
var i, spacer;
spacer = this.pos === 0 ? "" : ((function() {
- var _i, _ref, _results;
+ var _i, _ref2, _results;
_results = [];
- for (i = _i = 0, _ref = this.pos; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ for (i = _i = 0, _ref2 = this.pos; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
_results.push(" ");
}
return _results;
@@ -914,12 +1191,12 @@ var exports = {};
};
Line.prototype.toHtml = function() {
- var rv, span, _i, _len, _ref;
+ var rv, span, _i, _len, _ref2;
x = 0;
rv = "";
- _ref = this.spans;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- span = _ref[_i];
+ _ref2 = this.spans;
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
+ span = _ref2[_i];
if (x < span.start) {
rv += this.htmlEscape(this.text.slice(x, span.start));
}
@@ -933,12 +1210,12 @@ var exports = {};
};
Line.prototype.toDebug = function() {
- var rv, span, _i, _len, _ref;
+ var rv, span, _i, _len, _ref2;
x = 0;
rv = "";
- _ref = this.spans;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- span = _ref[_i];
+ _ref2 = this.spans;
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
+ span = _ref2[_i];
if (x < span.start) {
rv += this.text.slice(x, span.start);
}
@@ -1116,12 +1393,12 @@ var exports = {};
};
Line.prototype.parseMacroArg = function() {
- var ch, inChar, inString, rv, start, _ref;
+ var ch, inChar, inString, rv, start, _ref2;
inString = false;
inChar = false;
rv = "";
while (!this.finished()) {
- if (((_ref = this.text[this.pos]) === ';' || _ref === ')' || _ref === ',') && !inString && !inChar) {
+ if (((_ref2 = this.text[this.pos]) === ';' || _ref2 === ')' || _ref2 === ',') && !inString && !inChar) {
return rv;
}
start = this.pos;
@@ -1280,12 +1557,12 @@ var exports = {};
AssemblerOutput = (function() {
function AssemblerOutput(errors, lines, symtab) {
- var i, line, size, _i, _ref;
+ var i, line, size, _i, _ref2;
this.errors = errors;
this.lines = lines;
this.symtab = symtab;
this.lineMap = [];
- for (i = _i = 0, _ref = this.lines.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ for (i = _i = 0, _ref2 = this.lines.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
line = this.lines[i];
if (!(line != null)) {
continue;
@@ -1398,7 +1675,7 @@ var exports = {};
};
AssemblerOutput.prototype.createImage = function(memory) {
- var block, j, _i, _j, _len, _ref, _ref1, _ref2;
+ var block, j, _i, _j, _len, _ref2, _ref3, _ref4;
if (memory == null) {
memory = null;
}
@@ -1408,10 +1685,10 @@ var exports = {};
memory[j] = 0;
}
}
- _ref = this.pack();
- for (_j = 0, _len = _ref.length; _j < _len; _j++) {
- block = _ref[_j];
- [].splice.apply(memory, [(_ref1 = block.address), (block.address + block.data.length) - _ref1].concat(_ref2 = block.data)), _ref2;
+ _ref2 = this.pack();
+ for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
+ block = _ref2[_j];
+ [].splice.apply(memory, [(_ref3 = block.address), (block.address + block.data.length) - _ref3].concat(_ref4 = block.data)), _ref4;
}
return memory;
};
@@ -1489,11 +1766,11 @@ var exports = {};
};
ParsedLine.prototype.foldConstants = function(symtab) {
- var _i, _len, _ref,
+ var _i, _len, _ref2,
_this = this;
- _ref = this.operands;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- x = _ref[_i];
+ _ref2 = this.operands;
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
+ x = _ref2[_i];
x.foldConstants(symtab);
}
return this.data = this.data.map(function(x) {
@@ -1523,17 +1800,17 @@ var exports = {};
}
Macro.prototype.invoke = function(parser, pline, args) {
- var argOffset, argOffsets, expanded, i, newTextLines, plines, text, _i, _j, _k, _len, _len1, _len2, _ref;
+ var argOffset, argOffsets, expanded, i, newTextLines, plines, text, _i, _j, _k, _len, _len1, _len2, _ref2;
parser.debug(" macro expansion of ", this.fullname, ":");
newTextLines = (function() {
- var _i, _j, _len, _ref, _ref1, _results,
+ var _i, _j, _len, _ref2, _ref3, _results,
_this = this;
- _ref = this.textLines;
+ _ref2 = this.textLines;
_results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- text = _ref[_i];
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
+ text = _ref2[_i];
argOffsets = [];
- for (i = _j = 0, _ref1 = args.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
+ for (i = _j = 0, _ref3 = args.length; 0 <= _ref3 ? _j < _ref3 : _j > _ref3; i = 0 <= _ref3 ? ++_j : --_j) {
text = text.replace(this.parameterMatchers[i], function(original, offset) {
argOffsets.push({
left: offset,
@@ -1553,7 +1830,7 @@ var exports = {};
plines = [];
try {
for (_i = 0, _len = newTextLines.length; _i < _len; _i++) {
- _ref = newTextLines[_i], text = _ref[0], argOffsets = _ref[1];
+ _ref2 = newTextLines[_i], text = _ref2[0], argOffsets = _ref2[1];
try {
pline = parser.parseLine(text);
} catch (e) {
@@ -1700,8 +1977,8 @@ var exports = {};
};
Parser.prototype.clearLabelPrefix = function() {
- var _ref;
- return _ref = this.labelStack.pop(), this.lastLabel = _ref[0], this.labelPrefix = _ref[1], _ref;
+ var _ref2;
+ return _ref2 = this.labelStack.pop(), this.lastLabel = _ref2[0], this.labelPrefix = _ref2[1], _ref2;
};
Parser.prototype.parseLine = function(text, lineNumber, options) {
@@ -1986,7 +2263,7 @@ var exports = {};
};
Parser.prototype.parseData = function(line, pline) {
- var ch, i, inWord, m, rom, s, word, _i, _j, _ref, _ref1, _results;
+ var ch, i, inWord, m, rom, s, word, _i, _j, _ref2, _ref3, _results;
delete pline.op;
pline.data = [];
line.skipWhitespace();
@@ -1995,7 +2272,7 @@ var exports = {};
m = line.mark();
if (line.scanAhead('"')) {
s = line.parseString();
- for (i = _i = 0, _ref = s.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ for (i = _i = 0, _ref2 = s.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
pline.data.push(Expression.prototype.Literal(line.text, m.pos, s.charCodeAt(i)));
}
} else if (line.scanAhead('p"') || line.scanAhead('r"')) {
@@ -2007,7 +2284,7 @@ var exports = {};
s = line.parseString();
word = 0;
inWord = false;
- for (i = _j = 0, _ref1 = s.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
+ for (i = _j = 0, _ref3 = s.length; 0 <= _ref3 ? _j < _ref3 : _j > _ref3; i = 0 <= _ref3 ? ++_j : --_j) {
ch = s.charCodeAt(i);
if (rom && i === s.length - 1) {
ch |= 0x80;
@@ -2036,11 +2313,11 @@ var exports = {};
};
Parser.prototype.parseDirective = function(line, pline) {
- var m, _ref;
+ var m, _ref2;
m = line.mark();
pline.directive = line.parseDirective("Directive");
line.skipWhitespace();
- if ((_ref = pline.directive) === "if" || _ref === "else" || _ref === "endif") {
+ if ((_ref2 = pline.directive) === "if" || _ref2 === "else" || _ref2 === "endif") {
if (this.inMacro) {
return false;
}
@@ -2145,7 +2422,7 @@ var exports = {};
};
Parser.prototype.parseMacroCall = function(line, pline) {
- var argIndexes, args, m, name, _ref,
+ var argIndexes, args, m, name, _ref2,
_this = this;
m = line.mark();
name = line.parseMacroName("Macro name");
@@ -2153,7 +2430,7 @@ var exports = {};
if (line.scan("(", Span.Operator)) {
line.skipWhitespace();
}
- _ref = this.parseMacroArgs(line), args = _ref[0], argIndexes = _ref[1];
+ _ref2 = this.parseMacroArgs(line), args = _ref2[0], argIndexes = _ref2[1];
pline.macroArgIndexes = argIndexes;
args = args.map(function(x) {
if (x[0] === ".") {
@@ -2318,7 +2595,7 @@ var exports = {};
};
PrettyPrinter.prototype.dumpObject = function(obj, colorIndex) {
- var first, k, out, v;
+ var first, out;
first = true;
out = this.inColor("{", colorIndex);
for (k in obj) {
@@ -2335,9 +2612,9 @@ var exports = {};
};
PrettyPrinter.prototype.dumpString = function(s) {
- var ch, i, out, _i, _ref;
+ var ch, i, out, _i, _ref2;
out = "";
- for (i = _i = 0, _ref = s.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ for (i = _i = 0, _ref2 = s.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
ch = s.charCodeAt(i);
if (ch < 32 || ch > 127) {
hex = ch.toString(16);
1  src/carrot16/ui.coffee
View
@@ -154,6 +154,7 @@ $(document).ready =>
$(document).bind "keydown", "alt+r", => (webui.Project.rename(); false)
$(document).bind "keydown", "alt+s", => (webui.Project.save(); false)
$(document).bind "keydown", "alt+w", => (webui.Project.closeTab(); webui.Project.saveSession(); false)
+ $(document).bind "keydown", "alt+d", => (webui.Project.disassemble(); false)
$(document).bind "keydown", "f1", => (reset(); false)
$(document).bind "keydown", "f2", => (run(); false)
4 src/carrot16/webui/codeview.coffee
View
@@ -275,6 +275,10 @@ CodeViewSet =
remove: (view) ->
@views = @views.filter (x) -> x isnt view
+ findByName: (name) ->
+ for v in @views then if v.getName() == name then return v
+ null
+
exports.CodeView = CodeView
exports.CodeViewSet = CodeViewSet
11 src/carrot16/webui/project.coffee
View
@@ -7,6 +7,7 @@ Project =
$("#menu-save").click => @save()
$("#menu-close").click => (@closeTab(); @saveSession())
$("#menu-rename").click => @rename()
+ $("#menu-disassemble").click => @disassemble()
# thread "load" clicks through to the real file loader. (the web sucks.)
$("#load_input").bind("change", Project.finishLoading)
@@ -68,5 +69,15 @@ Project =
localStorage.setItem("c16:current-project", @projectId)
webui.Tabs.saveSession(@projectId)
+ disassemble: ->
+ d = new d16bunny.Disassembler(emulator.memory.memory)
+ lines = d.disassemble()
+ # get rid of any old tab
+ webui.Tabs.closeByName("(disassembled)")
+ view = new webui.CodeView()
+ view.setName("(disassembled)")
+ view.setCode(lines.join("\n"))
+ view.activate()
+
exports.Project = Project
17 src/carrot16/webui/tabs.coffee
View
@@ -57,18 +57,25 @@ Tabs =
view.activate()
view
- closeCurrent: ->
- if not @activePane? then return
- if not webui.CodeViewSet.visible() then return
- pane = @activePane
+ close: (pane) ->
tab = pane.data("tab")
- @next()
+ if tab is @activeTab() then @next()
@tablist = @tablist.filter (x) -> x isnt tab
tab.remove()
webui.CodeViewSet.remove(pane.data("codeview"))
pane.remove()
webui.CodeViewSet.assemble()
+ closeCurrent: ->
+ if not @activePane? then return
+ if not webui.CodeViewSet.visible() then return
+ @close(@activePane)
+
+ closeByName: (name) ->
+ view = webui.CodeViewSet.findByName(name)
+ if not view? then return
+ @close(view.pane)
+
closeAll: ->
for tab in @tablist
if tab.data("pane")?.data("codeview")?

No commit comments for this range

Something went wrong with that request. Please try again.