update for spec 1.5 #19

Merged
merged 13 commits into from Apr 27, 2012
View
168 dcpu.htm
@@ -2,6 +2,7 @@
<head>
<title>DCPU-16 emulator</title>
<script type="text/javascript" src="js/assembler.js?v=1"></script>
+ <script type="text/javascript" src="js/disassembler.js?v=1"></script>
<script type="text/javascript" src="js/dcpu.js?v=1"></script>
<script type="text/javascript" src="js/screen.js?v=1"></script>
<style>
@@ -379,14 +380,10 @@ <h4>Memory dump:</h4>
var memToLine = {};
var lineToMem = {};
var breaks = {};
- // Not final yet! Will most probably change after clarifications from Notch
- var keymap = {0x0d: 0x0a, 0x25: 0x01, 0x27: 0x02, 0x26: 0x03, 0x28: 0x04};
- var keypointer = 0;
+
document.onkeydown = function(event) {
- var e = event || window.event;
- var key = e.keyCode;
- if (keymap[key]) key = keymap[key];
- switch (key) {
+ var code = window.event ? event.keyCode : event.which;
+ switch (code) {
case 116: { // F5
run(ge("button_run"));
return false;
@@ -396,19 +393,22 @@ <h4>Memory dump:</h4>
return false;
}
default: { // pass it to program
- if (!runningTimer) {
- return true;
- }
- if (!memory[keypointer + 0x9000]) {
- memory[keypointer + 0x9000] = key;
- keypointer = (keypointer + 1) % 0x10;
- updateMemoryView();
- }
- return false;
+ if (!runningTimer) return true;
+ return Keyboard.onkeydown(event);
}
}
- return true;
- }
+ };
+ document.onkeypress = function(event) {
+ if (!runningTimer) return true;
+ if (event.which == 8) { return false; }
+
+ Keyboard.onkeypress(event);
+ };
+ document.onkeyup = function(event) {
+ if (!runningTimer) return true;
+ Keyboard.onkeyup(event);
+ };
+
function toggleTab(index) {
for (var i = 0; i < 2; i++) {
ge("tab" + i + "_wrapper").style.display = (index == i) ? "block" : "none";
@@ -505,7 +505,7 @@ <h4>Memory dump:</h4>
function step() {
ge('loading_overlay').style.display = 'none';
- var rv = DCPU.step(memory, registers, [Screen]);
+ var rv = DCPU.step(memory, registers, [ Screen, Keyboard ]);
if (rv > 0) {
cycles += rv;
}
@@ -524,7 +524,7 @@ <h4>Memory dump:</h4>
runningTimer = setInterval(function() {
var was_cycles = cycles;
for (var i = 0; i < 10000; i++) {
- var rv = DCPU.step(memory, registers, [Screen]);
+ var rv = DCPU.step(memory, registers, [ Screen, Keyboard ]);
if (rv < 0) { // break
if (runningTimer) run(button);
return;
@@ -616,102 +616,70 @@ <h4>Memory dump:</h4>
}
function disassemble() {
- lastInput = ge("da_input").value;
- var input = lastInput + " ";
- var linenum = lastInput.split("\n").length;
- var data = [];
- var s = "";
- for (var i = 0; i < input.length; i++) {
- if ("0123456789abcdefABCDEF".indexOf(input.charAt(i)) > -1) {
- s += input.charAt(i);
- if (s.length == 4) {
- data.push(parseInt(s, 16));
- s = "";
- }
+ var lines = ge("code").value.split("\n");
+ var logger = function(line, address, pos, message, fatal) { };
+ var buffer = [ ];
+ var rv = Assembler.compile(lines, buffer, logger);
+ if (!rv) return;
+
+ // figure out where code is being compiled
+ var code_blocks = [ ];
+ var pc_start = -1;
+ var pc_current = -1;
+ for (var i = 0; i < rv.infos.length; i++) {
+ var info = rv.infos[i];
+ if (info === undefined) continue;
+ if (info.pc != pc_current) {
+ if (pc_current != -1 && pc_current > pc_start) code_blocks.push({ start: pc_start, end: pc_current });
+ pc_start = info.pc;
+ pc_current = info.pc;
}
+ pc_current += (info.size || 0);
}
+ if (pc_current != -1 && pc_current > pc_start) code_blocks.push({ start: pc_start, end: pc_current });
- var log = [];
- var aborted = false;
- var logger = function(offset, msg, fatal) {
- log.push("<span class='line'>" + pad(offset, 4) + ":</span> " + (fatal ? "(<span class='fatal'>Fatal</span>) " : "") + msg);
- if (fatal) aborted = true;
- };
+ var targets = [ ];
+ for (var i = 0; i < code_blocks.length; i++) {
+ var t = Disassembler.findTargets(buffer, code_blocks[i].start, code_blocks[i].end);
+ targets = targets.concat(t);
+ }
+ targets.sort();
+ var labels = { };
+ for (var i = 0; i < targets.length; i++) {
+ labels[targets[i]] = "label" + i;
+ }
- var used = {};
- var code = {};
- var stack = [];
+ var lines = [];
+ var output = [];
var conditional = false;
- if (data.length > 0) {
- stack.push(0);
- }
- var labels = {last: 0};
- while (stack.length > 0) {
- var pc = stack.pop();
- if (used[pc]) {
- continue;
- }
+ for (var i = 0; i < code_blocks.length; i++) {
+ var pc = code_blocks[i].start;
+ var end = code_blocks[i].end;
do {
- var info = DCPU.disassemble(data, pc, labels, logger);
- if (info.branch !== undefined) {
- stack.push(info.branch);
- }
- for (var i = pc; i < pc + info.size; i++) {
- used[i] = true;
+ var info = Disassembler.disassemble(buffer, pc, labels, function(type, str) {
+ return "<span class='" + type + "'>" + str + "</span>";
+ });
+ if (labels[pc]) {
+ lines.push("");
+ output.push(":" + wrapAs(labels[pc], "lbl"));
}
if (info.code !== undefined) {
- code[pc] = (conditional ? "&nbsp;&nbsp;" : "") + info.code;
+ lines.push(pad(pc.toString(16), 4) + ":");
+ output.push("&nbsp;&nbsp;" + (conditional ? "&nbsp;&nbsp;" : "") + info.code);
}
pc += info.size;
- if (conditional) {
- info.terminal = false;
- }
conditional = info.conditional;
- } while (pc < data.length && !info.terminal);
- }
-
- var lines = [];
- var output = [];
- for (var i = 0; i < data.length; i++) {
- if (labels[i]) {
- lines.push("");
- output.push("");
- lines.push("");
- output.push(":" + wrapAs(labels[i], "lbl"));
- }
- if (code[i] !== undefined) {
- lines.push(pad(i.toString(16), 4) + ":");
- output.push("&nbsp;&nbsp;" + code[i]);
- } else if (!used[i]) {
- var words = [];
- var all_zeros = true;
- var old_i = i;
- while (i < data.length && !used[i]) {
- words.push(wrapAs("0x" + pad(data[i].toString(16), 4), "lit"));
- if (data[i]) all_zeros = false;
- i++;
- }
- if (all_zeros) {
- if (i < data.length) {
- lines.push("");
- lines.push("");
- output.push("");
- output.push(wrapAs("ORG", "op") + " " + wrapAs("0x" + pad(i.toString(16), 4), "lit"));
- }
- } else {
- lines.push(pad(old_i.toString(16), 4) + ":");
- output.push("&nbsp;&nbsp;" + wrapAs("DAT", "op") + " " + words.join(", "));
- }
- i--;
- }
+ } while (pc < end);
+ lines.push("");
+ output.push("");
}
// update UI
ge("da_lines").innerHTML = lines.join("<br/>");
ge("da_code").innerHTML = output.join("<br/>");
- ge("log").innerHTML = log.join("<br/>");
- ge("da_input").style.height = Math.max(560, ((linenum + 1) * 19 + 9)) + "px";
+ ge("da_input").style.height = Math.max(560, ((lines.length + 1) * 19 + 9)) + "px";
}
+
function disassembleDump() {
var dump = "";
var end = 0x7ffe;
@@ -726,10 +694,12 @@ <h4>Memory dump:</h4>
}
Screen.init();
+ Keyboard.init();
disassemble();
reset();
var lastCode = ge("code").value;
var lastInput = ge("da_input").value;
+
setInterval(function() {
Screen.blink = !Screen.blink;
Screen.update(memory);
View
@@ -5,8 +5,7 @@
var Assembler = {
DIRECTIVES: [ "macro", "define" ],
- REGISTERS: {
- "a": 0, "b": 1, "c": 2, "x": 3, "y": 4, "z": 5, "i": 6, "j": 7 },
+ REGISTERS: { "a": 0, "b": 1, "c": 2, "x": 3, "y": 4, "z": 5, "i": 6, "j": 7 },
SPECIALS: {
"push": 0x18,
"pop": 0x18,
@@ -28,13 +27,13 @@ var Assembler = {
"div": 0x06,
"dvi": 0x07,
"mod": 0x08,
- "and": 0x09,
- "bor": 0x0a,
- "xor": 0x0b,
- "shr": 0x0c,
- "asr": 0x0d,
- "shl": 0x0e,
- "mvi": 0x0f,
+ "mdi": 0x09,
+ "and": 0x0a,
+ "bor": 0x0b,
+ "xor": 0x0c,
+ "shr": 0x0d,
+ "asr": 0x0e,
+ "shl": 0x0f,
"ifb": 0x10,
"ifc": 0x11,
"ife": 0x12,
@@ -45,24 +44,31 @@ var Assembler = {
"ifu": 0x17,
// ...
"adx": 0x1a,
- "sux": 0x1b
+ "sbx": 0x1b,
+ // ...
+ "sti": 0x1e,
+ "std": 0x1f,
},
OP_SPECIAL: {
"jsr": 0x01,
// ...
+ "hcf": 0x07,
"int": 0x08,
"iag": 0x09,
"ias": 0x0a,
+ "iap": 0x0b,
+ "iaq": 0x0c,
// ...
"hwn": 0x10,
"hwq": 0x11,
- "hwi": 0x12
+ "hwi": 0x12,
},
OP_RESERVED: [ "set", "add", "sub", "mul", "mli", "div", "dvi", "mod",
- "and", "bor", "xor", "shr", "asr", "shl", "mvi",
+ "mdi", "and", "bor", "xor", "shr", "asr", "shl",
"ifb", "ifc", "ife", "ifn", "ifg", "ifa", "ifl", "ifu",
- "adx", "sux",
- "jsr", "int", "iag", "ias", "hwn", "hwq", "hwi",
+ "adx", "sbx", "sti", "std",
+ "jsr", "hcf", "int", "iag", "ias", "iap", "iaq",
+ "hwn", "hwq", "hwi",
"jmp", "brk", "ret", "bra", "dat", "org" ],
SPACE: { ' ': true, '\n': true, '\r': true, '\t': true }, // to replace charAt(pos).match(/\s/), using regexps is very slow
@@ -112,10 +118,10 @@ var Assembler = {
return false;
}
operand = operand[0].toLowerCase();
+ pos += operand.length;
if (subst[operand]) {
operand = subst[operand];
}
- pos += operand.length;
if (operand.match(/^[0-9]+$/g)) {
atom.literal = parseInt(operand, 10);
} else if (operand.match(/^0x[0-9a-fA-F]+$/g)) {
@@ -271,7 +277,7 @@ var Assembler = {
* Returns true if this line did contain some constant definition (even if it was an error),
* meaning you shouldn't bother compiling this line.
*/
- parseConstant: function(text, labels, logger) {
+ parseConstant: function(text, labels, subst, logger) {
var match = text.match(/^\s*([A-Za-z_.][A-Za-z0-9_.]*)\s*=\s*(\S+)/);
if (!match) return false;
var name = match[1].toLowerCase();
@@ -284,7 +290,7 @@ var Assembler = {
// manually find position of expression, for displaying nice error messages.
var pos = text.indexOf('=') + 1;
while (this.SPACE[text.charAt(pos)]) pos++;
- var state = { text: text, pos: pos, end: text.length, logger: logger };
+ var state = { text: text, pos: pos, end: text.length, subst: subst, logger: logger };
var expr = this.parseExpression(state, 0);
if (expr) {
var value = this.evalConstant(expr, labels, true);
@@ -482,6 +488,7 @@ var Assembler = {
case 'n': { rv += "\n"; break; }
case 'r': { rv += "\r"; break; }
case 't': { rv += "\t"; break; }
+ case 'z': { rv += "\x00"; break; }
case 'x': {
if (i < s.length - 2) {
rv += String.fromCharCode(parseInt(s.substr(i + 1, 2), 16));
@@ -515,6 +522,26 @@ var Assembler = {
info.size++;
info.dump.push(arg.charCodeAt(j));
}
+ } else if (arg.charAt(0) == 'p' && arg.charAt(1) == '"') {
+ // packed string
+ arg = this.unquoteString(arg.substr(2, arg.length - 3));
+ var word = 0, in_word = false;
+ for (var j = 0; j < arg.length; j++) {
+ var c = arg.charCodeAt(j);
+ if (in_word) {
+ word |= c;
+ info.size++;
+ info.dump.push(word);
+ in_word = false;
+ } else {
+ word = c << 8;
+ in_word = true;
+ }
+ }
+ if (in_word) {
+ info.size++;
+ info.dump.push(word);
+ }
} else {
var expr = this.parseExpression(this.stateFromArg(true, line, i, subst, logger), 0);
if (!expr) return false;
@@ -876,14 +903,12 @@ var Assembler = {
if (fatal) aborted = true;
};
labels["."] = pc;
- if (!this.parseConstant(lines[i], labels, l_logger)) {
- var info = this.compileLine(lines[i], pc, labels, macros, {}, l_logger);
+ if (!this.parseConstant(lines[i], labels, { }, l_logger)) {
+ var info = this.compileLine(lines[i], pc, labels, macros, { }, l_logger);
if (!info) break;
if (pc + info.size > 0xffff) {
l_logger(0, "Code is too big (exceeds 128 KB) &mdash; not enough memory", true);
break;
- } else if (pc + info.size > 0x8000) {
- l_logger(0, "Code is too big (exceeds 64 KB) &mdash; overlaps video memory");
}
if (info.org !== undefined) {
pc = info.org;
Oops, something went wrong.