Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

update for spec 1.5 #19

Merged
merged 13 commits into from

2 participants

@robey

(this is on top of the disassembler branch.)

Robey Pointer added some commits
Robey Pointer break out disassembler into its own file. refactored it a lot. 4be20de
Robey Pointer Merge remote-tracking branch 'denull/master' into disasm
Conflicts:
	dcpu.htm
	js/dcpu.js
15ad7c5
Robey Pointer merge denull's new disasm work into the refactored disasm. 6eef97d
Robey Pointer fix bug in parsing constants. ed6a281
Robey Pointer BRK moved. :) bef5f6f
Robey Pointer add keyboard support. 77ed4f0
Robey Pointer fix imported-font format to match the current spec. ff84e60
Robey Pointer make sure to always disassemble starting from every target. as a bonu…
…s, decode BRA now too.
d8af46a
Robey Pointer allow space to work. 3964a3d
Robey Pointer don't get hardware report negative numbers. 505ceda
Robey Pointer support byte-packed strings as p"…". c83e05f
Robey Pointer update for spec 1.5.
- conditions can be chained now
- a bunch of binary ops moved (doh)
- added: HCF, MDI, STD
- renamed: MVI -> STI, SUX -> SBX
- did not implement the extra interrupt modes yet
e44f240
Robey Pointer fix parameter decoding bug in macros. 0fe981f
@deNULL deNULL merged commit 0fe981f into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 26, 2012
  1. Merge remote-tracking branch 'denull/master' into disasm

    Robey Pointer authored
    Conflicts:
    	dcpu.htm
    	js/dcpu.js
  2. fix bug in parsing constants.

    Robey Pointer authored
  3. BRK moved. :)

    Robey Pointer authored
  4. add keyboard support.

    Robey Pointer authored
  5. fix imported-font format to match the current spec.

    Robey Pointer authored
  6. make sure to always disassemble starting from every target. as a bonu…

    Robey Pointer authored
    …s, decode BRA now too.
Commits on Apr 27, 2012
  1. allow space to work.

    Robey Pointer authored
  2. don't get hardware report negative numbers.

    Robey Pointer authored
  3. support byte-packed strings as p"…".

    Robey Pointer authored
  4. update for spec 1.5.

    Robey Pointer authored
    - conditions can be chained now
    - a bunch of binary ops moved (doh)
    - added: HCF, MDI, STD
    - renamed: MVI -> STI, SUX -> SBX
    - did not implement the extra interrupt modes yet
  5. fix parameter decoding bug in macros.

    Robey Pointer authored
This page is out of date. Refresh to see the latest.
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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
67 js/assembler.js
@@ -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;
View
312 js/dcpu.js
@@ -1,8 +1,7 @@
/*
-* DCPU-16 Assembler & Emulator Library
-* by deNULL (me@denull.ru)
-*
-*/
+ * DCPU-16 Assembler & Emulator Library
+ * by deNULL (me@denull.ru)
+ */
// some common functions, shouldn't actually be here...
String.prototype.trim = function() {
@@ -26,45 +25,6 @@ function ge(e) {
}
var DCPU = {
-bops: {
- 0x01: "SET",
- 0x02: "ADD",
- 0x03: "SUB",
- 0x04: "MUL",
- 0x05: "MLI",
- 0x06: "DIV",
- 0x07: "DVI",
- 0x08: "MOD",
- 0x09: "AND",
- 0x0a: "BOR",
- 0x0b: "XOR",
- 0x0c: "SHR",
- 0x0d: "ASR",
- 0x0e: "SHL",
- 0x0f: "MVI",
- 0x10: "IFB",
- 0x11: "IFC",
- 0x12: "IFE",
- 0x13: "IFN",
- 0x14: "IFG",
- 0x15: "IFA",
- 0x16: "IFL",
- 0x17: "IFU",
- // ...
- 0x1a: "ADX",
- 0x1b: "SUX"
-},
-nbops: {
- 0x01: "JSR",
- // ...
- 0x08: "INT",
- 0x09: "IAG",
- 0x0a: "IAS",
- // ...
- 0x10: "HWN",
- 0x11: "HWQ",
- 0x12: "HWI"
-},
regs: ["A", "B", "C", "X", "Y", "Z", "I", "J"],
cycles: 0,
@@ -181,15 +141,22 @@ setValue: function(code, value, memory, registers) {
* Skips one command, without performing any changes to memory and/or registers
*/
skip: function(memory, registers) {
- var cur = memory[registers.PC] || 0;
- var op = cur & 0x1f;
- var aa = (cur >> 10) & 0x3f;
- var bb = (cur >> 5) & 0x1f;
+ var op;
var cycles = DCPU.cycles;
- registers.PC = (registers.PC + 1) & 0xffff;
- DCPU.getValue(false, bb, memory, registers, true);
- DCPU.getValue(true, aa, memory, registers, true);
+ var skipped = 0;
+ do {
+ var cur = memory[registers.PC] || 0;
+ op = cur & 0x1f;
+ var aa = (cur >> 10) & 0x3f;
+ var bb = (cur >> 5) & 0x1f;
+
+ registers.PC = (registers.PC + 1) & 0xffff;
+ DCPU.getValue(false, bb, memory, registers, true);
+ DCPU.getValue(true, aa, memory, registers, true);
+ skipped++;
+ } while (op >= 0x10 && op <= 0x17);
DCPU.cycles = cycles;
+ return skipped;
},
/*
* Steps over the next command (at [PC])
@@ -206,7 +173,7 @@ step: function(memory, registers, hardware) {
DCPU.cycles = 0;
// check for BRK (SUB PC, 1)
- if (cur == 0x85c3) {
+ if (cur == 0x8b83) {
return -1;
}
switch (op) {
@@ -220,6 +187,10 @@ step: function(memory, registers, hardware) {
return DCPU.cycles + 3;
}
// ...
+ case 0x07: { // HCF
+ // for now, assume = BRK
+ return -1;
+ }
case 0x08: { // INT
var av = DCPU.getValue(true, aa, memory, registers);
if (registers.IA) {
@@ -249,10 +220,10 @@ step: function(memory, registers, hardware) {
}
case 0x11: { // HWQ
var hw = hardware[DCPU.getValue(true, aa, memory, registers)];
- registers.A = (hw.type >> 16);
+ registers.A = (hw.type >> 16) & 0xffff;
registers.B = (hw.type & 0xffff);
registers.C = hw.revision;
- registers.X = (hw.manufacturer >> 16);
+ registers.X = (hw.manufacturer >> 16) & 0xffff;
registers.Y = (hw.manufacturer & 0xffff);
return DCPU.cycles + 4;
}
@@ -328,56 +299,53 @@ step: function(memory, registers, hardware) {
DCPU.setValue(bb, (av == 0) ? 0 : (bv % av), memory, registers);
return DCPU.cycles + 3;
}
- case 0x09: { // AND
+ case 0x09: { // MDI
+ var av = DCPU.getSignedValue(true, aa, memory, registers);
+ var bv = DCPU.getSignedValue(false, bb, memory, registers);
+ DCPU.setValue(bb, (av == 0) ? 0 : (bv % av), memory, registers);
+ return DCPU.cycles + 3;
+ }
+ case 0x0a: { // AND
var v = DCPU.getValue(true, aa, memory, registers) & DCPU.getValue(false, bb, memory, registers);
DCPU.setValue(bb, v & 0xffff, memory, registers);
return DCPU.cycles + 1;
}
- case 0x0a: { // BOR
+ case 0x0b: { // BOR
var v = DCPU.getValue(true, aa, memory, registers) | DCPU.getValue(false, bb, memory, registers);
DCPU.setValue(bb, v & 0xffff, memory, registers);
return DCPU.cycles + 1;
}
- case 0x0b: { // XOR
+ case 0x0c: { // XOR
var v = DCPU.getValue(true, aa, memory, registers) ^ DCPU.getValue(false, bb, memory, registers);
DCPU.setValue(bb, v & 0xffff, memory, registers);
return DCPU.cycles + 1;
}
- case 0x0c: { // SHR
+ case 0x0d: { // SHR
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
DCPU.setValue(bb, (bv >>> av) & 0xffff, memory, registers);
registers.EX = ((bv << 16) >>> av) & 0xffff;
return DCPU.cycles + 2;
}
- case 0x0d: { // ASR
+ case 0x0e: { // ASR
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getSignedValue(true, bb, memory, registers);
DCPU.setValue(bb, (bv >> av) & 0xffff, memory, registers);
registers.EX = ((bv << 16) >> av) & 0xffff;
return DCPU.cycles + 2;
}
- case 0x0e: { // SHL
+ case 0x0f: { // SHL
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
DCPU.setValue(bb, (bv << av) & 0xffff, memory, registers);
registers.EX = ((bv << av) >> 16) & 0xffff;
return DCPU.cycles + 2;
}
- case 0x0f: { // MVI
- var av = DCPU.getValue(true, aa, memory, registers);
- DCPU.getValue(false, bb, memory, registers);
- DCPU.setValue(bb, av, memory, registers);
- registers.I = (registers.I + 1) & 0xffff;
- registers.J = (registers.J + 1) & 0xffff;
- return DCPU.cycles + 2;
- }
case 0x10: { // IFB
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
if ((bv & av) == 0) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -385,8 +353,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
if ((bv & av) != 0) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -394,8 +361,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
if (bv != av) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -403,8 +369,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
if (bv == av) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -412,8 +377,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
if (bv <= av) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -421,8 +385,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getSignedValue(true, aa, memory, registers);
var bv = DCPU.getSignedValue(true, bb, memory, registers);
if (bv <= av) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -430,8 +393,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getValue(true, aa, memory, registers);
var bv = DCPU.getValue(false, bb, memory, registers);
if (bv >= av) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -439,8 +401,7 @@ step: function(memory, registers, hardware) {
var av = DCPU.getSignedValue(true, aa, memory, registers);
var bv = DCPU.getSignedValue(true, bb, memory, registers);
if (bv >= av) {
- DCPU.skip(memory, registers);
- return DCPU.cycles + 3;
+ return DCPU.cycles + 2 + DCPU.skip(memory, registers);
}
return DCPU.cycles + 2;
}
@@ -453,184 +414,29 @@ step: function(memory, registers, hardware) {
registers.EX = (v >> 16) & 0xffff;
return DCPU.cycles + 3;
}
- case 0x1b: { // SUX
+ case 0x1b: { // SBX
var v = -DCPU.getValue(true, aa, memory, registers) + DCPU.getValue(false, bb, memory, registers) + registers.EX;
DCPU.setValue(bb, v & 0xffff, memory, registers);
registers.EX = (v >> 16) & 0xffff;
return DCPU.cycles + 3;
}
- }
-},
-
-
-// -------
-
-disassembleValue: function(is_a, code, memory, offset, logger) {
-
- if (code < 0x8) {
- return {size: 0, str: wrapAs(DCPU.regs[code], "reg")};
- } else
- if (code < 0x10) {
- return {size: 0, str: "[" + wrapAs(DCPU.regs[code - 0x08], "reg") + "]"};
- } else
- if (code < 0x18) {
- if (offset >= memory.length) {
- logger(offset, "Disassembler reached end of the file", true);
- return false;
- }
- var nw = memory[offset];
- return {size: 1, str: "[" + wrapAs(DCPU.regs[code - 0x10], "reg") + "+" + wrapAs("0x" + nw.toString(16), "lit") + "]"};
- } else
- if (code == 0x18) { // POP
- return {size: 0, str: wrapAs(is_a ? "POP" : "PUSH", "kw")};
- } else
- if (code == 0x19) { // PEEK
- return {size: 0, str: wrapAs("PEEK", "kw")};
- } else
- if (code == 0x1a) { // PICK
- if (offset >= memory.length) {
- logger(offset, "Disassembler reached end of the file", true);
- return false;
- }
- var nw = memory[offset];
- return {size: 0, str: wrapAs("PICK", "kw") + " " + wrapAs(nw.toString(10), "lit")};
- } else
- if (code == 0x1b) {
- return {size: 0, str: wrapAs("SP", "kw")};
- } else
- if (code == 0x1c) {
- return {size: 0, str: wrapAs("PC", "kw")};
- } else
- if (code == 0x1d) {
- return {size: 0, str: wrapAs("EX", "kw")};
- } else
- if (code == 0x1e) {
- if (offset >= memory.length) {
- logger(offset, "Disassembler reached end of the file", true);
- return false;
+ case 0x1e: { // STI
+ var av = DCPU.getValue(true, aa, memory, registers);
+ DCPU.getValue(false, bb, memory, registers);
+ DCPU.setValue(bb, av, memory, registers);
+ registers.I = (registers.I + 1) & 0xffff;
+ registers.J = (registers.J + 1) & 0xffff;
+ return DCPU.cycles + 2;
}
- var nw = memory[offset];
- return {size: 1, str: "[" + wrapAs("0x" + pad(nw.toString(16), 4), "lit") + "]"};
- } else
- if (code == 0x1f) {
- if (offset >= memory.length) {
- logger(offset, "Disassembler reached end of the file");
- return false;
+ case 0x1f: { // STD
+ var av = DCPU.getValue(true, aa, memory, registers);
+ DCPU.getValue(false, bb, memory, registers);
+ DCPU.setValue(bb, av, memory, registers);
+ registers.I = (registers.I - 1) & 0xffff;
+ registers.J = (registers.J - 1) & 0xffff;
+ return DCPU.cycles + 2;
}
- var nw = memory[offset];
- return {size: 1, str: wrapAs("0x" + pad(nw.toString(16), 4), "lit"), literal: nw};
- } else {
- return {size: 0, str: wrapAs((code - 0x21).toString(10), "lit"), literal: (code == 0x20) ? 0xffff : (code - 0x21)};
}
},
-/*
-* Disassembles code in memory at specified offset
-*
-* Returns object with fields
-* - code
-* - branch
-* - terminal
-* - size
-*/
-disassemble: function(memory, offset, labels, logger) {
- var res = {size: 1};
- if (offset >= memory.length) {
- logger(offset, "Disassembler reached end of the file");
- return {size: 0, terminal: true};
- }
- var cur = memory[offset];
- var op = cur & 0x1f;
- var aa = (cur >> 10) & 0x3f;
- var bb = (cur >> 5) & 0x1f;
-
- switch (op) {
- case 0x00: {
- switch (bb) {
- case 0x01: // JSR
- case 0x0a: { // IAS
- var va = DCPU.disassembleValue(true, aa, memory, offset + res.size, logger);
- res.size += va.size;
- res.code = wrapAs(DCPU.nbops[bb], "op") + " " + va.str;
- if (va.literal !== undefined) {
- res.branch = va.literal;
- if (!labels[res.branch]) {
- labels.last++;
- labels[res.branch] = (bb == 0x0a ? "int_handler" : "label") + labels.last;
- }
- res.code = wrapAs(DCPU.nbops[bb], "op") + " " + wrapAs(labels[res.branch], "lbl");
- }
- return res;
- }
- default: {
- if (!DCPU.nbops[bb]) {
- logger(offset, "Unknown non-basic instruction: " + aa.toString(16));
- return {size: 0, terminal: true};
- }
-
- var va = DCPU.disassembleValue(true, aa, memory, offset + res.size, logger);
- res.size += va.size;
- res.code = wrapAs(DCPU.nbops[bb], "op") + " " + va.str;
- return res;
- }
- }
- }
- default: {
- if (!DCPU.bops[op]) {
- logger(offset, "Unknown basic instruction: " + op.toString(16));
- return {size: 0, terminal: true};
- }
-
- var vb = DCPU.disassembleValue(false, bb, memory, offset + res.size, logger);
- res.size += vb.size;
- var va = DCPU.disassembleValue(true, aa, memory, offset + res.size, logger);
- res.size += va.size;
-
- res.code = wrapAs(DCPU.bops[op], "op") + " " + vb.str + ", " + va.str;
- if (op >= 0x10 && op <= 0x17) {
- res.conditional = true;
- } else
- if (bb == 0x1c) {
- offset += res.size;
- res.terminal = true;
- if (va.literal === undefined) {
- if (aa != 0x18) // assuming SET PC, POP - RET
- logger(offset, "(Warning) Can't predict the value of PC after " + res.code + ". Some instructions may be not disassembled.");
- } else
- switch (op) {
- case 0x01:
- case 0x0f: {
- res.branch = va.literal;
- if (!labels[res.branch]) {
- labels.last++;
- labels[res.branch] = "label" + labels.last;
- }
- res.code = wrapAs(DCPU.bops[op], "op") + " " + vb.str + ", " + wrapAs(labels[res.branch], "lbl");
- break;
- }
- case 0x02: { res.branch = (offset + va.literal) & 0xffff; break; }
- case 0x03: { res.branch = (offset - va.literal) & 0xffff; break; }
- case 0x04: { res.branch = (offset * va.literal) & 0xffff; break; }
- case 0x05: { res.branch = (DCPU.extendSign(offset) * DCPU.extendSign(va.literal)) & 0xffff; break; }
- case 0x06: { res.branch = parseInt(offset / va.literal) & 0xffff; break; }
- case 0x07: { res.branch = parseInt(DCPU.extendSign(offset) / DCPU.extendSign(va.literal)) & 0xffff; break; }
- case 0x08: { res.branch = (va.literal == 0) ? 0 : (offset % va.literal); break; }
- case 0x09: { res.branch = (offset & va.literal); break; }
- case 0x0a: { res.branch = (offset | va.literal); break; }
- case 0x0b: { res.branch = (offset ^ va.literal); break; }
- case 0x0c: { res.branch = (offset >>> va.literal) & 0xffff; break; }
- case 0x0d: { res.branch = (DCPU.extendSign(offset) >> va.literal) & 0xffff; break; }
- case 0x0e: { res.branch = (offset << va.literal) & 0xffff; break; }
- case 0x1a: { res.branch = (offset + va.literal) & 0xffff; break; }
- case 0x1b: { res.branch = (offset - va.literal) & 0xffff; break; }
- }
- }
-
- return res;
- }
- }
-}
-
-
-
};
View
202 js/disassembler.js
@@ -0,0 +1,202 @@
+/*
+ * DCPU-16 Assembler & Emulator Library
+ * by deNULL (me@denull.ru)
+ */
+
+var Disassembler = {
+ REGISTERS: [ "A", "B", "C", "X", "Y", "Z", "I", "J" ],
+ SPECIALS: {
+ 0x18: "PUSH",
+ 0x19: "PEEK",
+ 0x1a: "PICK",
+ 0x1b: "SP",
+ 0x1c: "PC",
+ 0x1d: "EX"
+ },
+ OP_BINARY: {
+ 0x01: "SET",
+ 0x02: "ADD",
+ 0x03: "SUB",
+ 0x04: "MUL",
+ 0x05: "MLI",
+ 0x06: "DIV",
+ 0x07: "DVI",
+ 0x08: "MOD",
+ 0x09: "MDI",
+ 0x0a: "AND",
+ 0x0b: "BOR",
+ 0x0c: "XOR",
+ 0x0d: "SHR",
+ 0x0e: "ASR",
+ 0x0f: "SHL",
+ 0x10: "IFB",
+ 0x11: "IFC",
+ 0x12: "IFE",
+ 0x13: "IFN",
+ 0x14: "IFG",
+ 0x15: "IFA",
+ 0x16: "IFL",
+ 0x17: "IFU",
+ 0x1A: "ADX",
+ 0x1B: "SBX",
+ // ...
+ 0x1E: "STI",
+ 0x1F: "STD",
+ },
+ OP_SPECIAL: {
+ 0x01: "JSR",
+ // ...
+ 0x07: "HCF",
+ 0x08: "INT",
+ 0x09: "IAG",
+ 0x0a: "IAS",
+ 0x0b: "IAP",
+ 0x0c: "IAQ",
+ // ...
+ 0x10: "HWN",
+ 0x11: "HWQ",
+ 0x12: "HWI",
+ },
+
+ address: function(n, labels) {
+ if (labels[n]) return labels[n];
+ return (n > 15) ? ("0x" + pad(n.toString(16), 4)) : n.toString(10);
+ },
+
+ decodeValue: function(is_a, code, immediate, labels, wrapAs) {
+ if (code < 0x08) {
+ return wrapAs("reg", this.REGISTERS[code]);
+ } else if (code < 0x10) {
+ return "[" + wrapAs("reg", this.REGISTERS[code - 0x08]) + "]";
+ } else if (code < 0x18) {
+ return "[" + wrapAs("reg", this.REGISTERS[code - 0x10]) + "+" +
+ wrapAs("lit", "0x" + pad(immediate.toString(16), 4)) + "]";
+ } else if (code == 0x18) {
+ return wrapAs("kw", is_a ? "PUSH" : "POP");
+ } else if (code == 0x1a) {
+ return wrapAs("kw", "PICK") + " " + wrapAs("lit", immediate.toString(10));
+ } else if (code < 0x1e) {
+ return wrapAs("kw", this.SPECIALS[code]);
+ } else if (code == 0x1e) {
+ return "[" + wrapAs("lit", this.address(immediate, labels)) + "]";
+ } else if (code == 0x1f) {
+ return wrapAs("lit", this.address(immediate, labels));
+ } else { // embedded immediate
+ return wrapAs("lit", this.address(immediate, labels));
+ }
+ },
+
+ hasArg: function(code) {
+ return ((code >= 0x10 && code < 0x18) || code == 0x1a || code == 0x1e || code == 0x1f);
+ },
+
+ nextOp: function(memory, offset) {
+ var start = offset;
+ if (offset >= memory.length) return { op: 0, a: 0, b: 0 };
+ var word = memory[offset++];
+ var op = { opcode: (word & 0x1f), a: (word >> 10 & 0x3f), b: (word >> 5 & 0x1f) };
+ if (this.hasArg(op.b)) {
+ if (offset >= memory.length) return { op: 0, a: 0, b: 0 };
+ op.b_immediate = memory[offset++];
+ }
+ if (this.hasArg(op.a)) {
+ if (offset >= memory.length) return { op: 0, a: 0, b: 0 };
+ op.a_immediate = memory[offset++];
+ }
+ // go ahead and decode embedded immediates.
+ if (op.a >= 0x20) op.a_immediate = (op.a == 0x20 ? 0xffff : (op.a - 0x21));
+ if (op.b >= 0x20) op.b_immediate = (op.b == 0x20 ? 0xffff : (op.b - 0x21));
+ op.size = offset - start;
+ return op;
+ },
+
+ /**
+ * Build a list of memory addresses targeted by JMP/JSR instructions.
+ */
+ findTargets: function(memory, offset, end) {
+ var targets = [ ];
+ var jsr = Assembler.OP_SPECIAL["jsr"];
+ var add = Assembler.OP_BINARY["add"];
+ var sub = Assembler.OP_BINARY["sub"];
+ var set = Assembler.OP_BINARY["set"];
+ var pc = Assembler.SPECIALS["pc"];
+ while (offset < end) {
+ var op = this.nextOp(memory, offset);
+ var a = op.a_immediate;
+ var b = op.a_immediate;
+
+ if (op.opcode == 0 && op.b == jsr && a !== undefined) {
+ targets.push(a);
+ } else if (op.opcode == set && op.b == pc && a !== undefined) {
+ targets.push(a);
+ } else if (op.opcode == add && op.b == pc && a !== undefined) {
+ targets.push(offset + op.size + a);
+ } else if (op.opcode == sub && op.b == pc && a !== undefined) {
+ targets.push(offset + op.size - a);
+ }
+
+ if (op.size > 1 && targets.indexOf(offset + 1) >= 0) {
+ offset++;
+ } else if (op.size > 2 && targets.indexOf(offset + 2) >= 0) {
+ offset += 2;
+ } else {
+ offset += op.size;
+ }
+ }
+ return targets;
+ },
+
+ /**
+ * Disassemble a single operation in memory at the specified offset.
+ * Returns:
+ * - code: string for displaying
+ * - conditional: if this is a conditional op
+ * - size: # of words consumed
+ */
+ disassemble: function(memory, offset, labels, wrapAs) {
+ var res = { };
+ var op = this.nextOp(memory, offset);
+
+ // if this op would stretch into a labeled target, scrap it. it's just data.
+ if ((op.size == 2 && labels[offset + 1]) ||
+ (op.size == 3 && (labels[offset + 1] || labels[offset + 2]))) {
+ res.size = 1;
+ res.code = wrapAs("op", "DAT") + " " + wrapAs("lit", "0x" + pad(memory[offset].toString(16), 4));
+ return res;
+ }
+
+ res.size = op.size;
+
+ // for convenience, decode BRA.
+ var add = Assembler.OP_BINARY["add"];
+ var sub = Assembler.OP_BINARY["sub"];
+ var pc = Assembler.SPECIALS["pc"];
+
+ if (op.opcode == add && op.b == pc && op.a_immediate !== undefined) {
+ res.code = wrapAs("op", "BRA") + " " + this.address(offset + op.size + op.a_immediate, labels);
+ return res;
+ }
+ if (op.opcode == sub && op.b == pc && op.a_immediate !== undefined) {
+ res.code = wrapAs("op", "BRA") + " " + this.address(offset + op.size - op.a_immediate, labels);
+ return res;
+ }
+
+ var va = this.decodeValue(true, op.a, op.a_immediate, labels, wrapAs);
+ var vb = this.decodeValue(false, op.b, op.b_immediate, labels, wrapAs);
+
+ if (op.opcode == 0) {
+ // special
+ var code = this.OP_SPECIAL[op.b];
+ if (code === undefined) code = "???";
+ res.code = wrapAs("op", code) + " " + va;
+ } else {
+ var code = this.OP_BINARY[op.opcode];
+ if (code === undefined) code = "???";
+ res.code = wrapAs("op", code) + " " + vb + ", " + va;
+ if (op.opcode >= 0x10 && op.opcode <= 0x17) {
+ res.conditional = true;
+ }
+ }
+ return res;
+ },
+};
View
141 js/keyboard.js
@@ -0,0 +1,141 @@
+// Generic Keyboard (compatible)
+
+var Keyboard = {
+ type: 0x30cf7406,
+ revision: 1,
+ manufacturer: 0x904b3115,
+
+ CLEAR_BUFFER: 0,
+ GET_KEY: 1,
+ SCAN_KEYBOARD: 2,
+ SET_INT: 3,
+
+ BS: 0x10,
+ ENTER: 0x11,
+ INSERT: 0x12,
+ DELETE: 0x13,
+ UP: 0x80,
+ DOWN: 0x81,
+ LEFT: 0x82,
+ RIGHT: 0x83,
+ SHIFT: 0x90,
+ CONTROL: 0X91,
+
+ JS: {
+ BS: 8,
+ ENTER: 13,
+ SHIFT: 16,
+ CONTROL: 17,
+ SPACE: 32,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+// INSERT: 45,
+ // DELETE: 46,
+ },
+
+ init: function() {
+ this.buffer = [ ];
+ this.shift_down = false;
+ this.control_down = false;
+ this.translate = { };
+ this.translate[this.JS.BS] = this.BS;
+ this.translate[this.JS.ENTER] = this.ENTER;
+ this.translate[this.JS.INSERT] = this.INSERT;
+ this.translate[this.JS.DELETE] = this.DELETE;
+ this.translate[this.JS.UP] = this.UP;
+ this.translate[this.JS.DOWN] = this.DOWN;
+ this.translate[this.JS.LEFT] = this.LEFT;
+ this.translate[this.JS.RIGHT] = this.RIGHT;
+ },
+
+ onkeydown: function(event) {
+ var code = window.event ? event.keyCode : event.which;
+ switch (code) {
+ case this.JS.SHIFT: {
+ this.shift_down = true;
+ return true;
+ }
+ case this.JS.CONTROL: {
+ this.control_down = true;
+ return true;
+ }
+ }
+ // have to intercept BS or chrome will do something weird.
+ if (code == this.JS.BS || code == this.JS.UP || code == this.JS.DOWN ||
+ code == this.JS.LEFT || code == this.JS.RIGHT || code == this.JS.SPACE) {
+ this.onkeypress(event);
+ return false;
+ }
+ return true;
+ },
+
+ onkeypress: function(event) {
+ var code = window.event ? event.keyCode : event.which;
+ if (this.translate[code]) {
+ code = this.translate[code];
+ } else if (code < 0x20 || code > 0x7e) {
+ // ignore
+ return;
+ }
+ this.buffer.push(code);
+ // small 8-character buffer
+ if (this.buffer.length > 8) this.buffer.shift();
+ // keychar = String.fromCharCode(keynum);
+ },
+
+ onkeyup: function(event) {
+ var code = window.event ? event.keyCode : event.which;
+ switch (code) {
+ case this.JS.SHIFT: {
+ this.shift_down = false;
+ break;
+ }
+ case this.JS.CONTROL: {
+ this.control_down = false;
+ break;
+ }
+ }
+ },
+
+ interrupt: function(memory, registers) {
+ switch (registers.A) {
+ case this.CLEAR_BUFFER: {
+ this.buffer = [ ];
+ break;
+ }
+ case this.GET_KEY: {
+ var key = this.buffer.shift();
+ registers.C = (key === undefined) ? 0 : key;
+ break;
+ }
+ case this.SCAN_KEYBOARD: {
+ // FIXME
+ break;
+ }
+ case this.SET_INT: {
+ // FIXME
+ break;
+ }
+ }
+ return 0;
+ },
+};
+
+/*
+Interrupts do different things depending on contents of the A register:
+
+ A | BEHAVIOR
+---+----------------------------------------------------------------------------
+ 0 | Clear keyboard buffer
+ 1 | Store next key typed in C register, or 0 if the buffer is empty
+ 2 | Set C register to 1 if the key specified by the B register is pressed, or
+ | 0 if it's not pressed
+ 3 | If register B is non-zero, turn on interrupts with message B. If B is zero,
+ | disable interrupts
+---+----------------------------------------------------------------------------
+
+When interrupts are enabled, the keyboard will trigger an interrupt when one or
+more keys have been pressed, released, or typed.
+*/
View
48 js/screen.js
@@ -34,8 +34,41 @@ var Screen = {
[0xff, 0xff, 0xff, 0xff]
],
- // not so much of data, we can store it right here
- defaultFont: [0x000f, 0x0808, 0x080f, 0x0808, 0x08f8, 0x0808, 0x00ff, 0x0808, 0x0808, 0x0808, 0x08ff, 0x0808, 0x00ff, 0x1414, 0xff00, 0xff08, 0x1f10, 0x1714, 0xfc04, 0xf414, 0x1710, 0x1714, 0xf404, 0xf414, 0xff00, 0xf714, 0x1414, 0x1414, 0xf700, 0xf714, 0x1417, 0x1414, 0x0f08, 0x0f08, 0x14f4, 0x1414, 0xf808, 0xf808, 0x0f08, 0x0f08, 0x001f, 0x1414, 0x00fc, 0x1414, 0xf808, 0xf808, 0xff08, 0xff08, 0x14ff, 0x1414, 0x080f, 0x0000, 0x00f8, 0x0808, 0xffff, 0xffff, 0xf0f0, 0xf0f0, 0xffff, 0x0000, 0x0000, 0xffff, 0x0f0f, 0x0f0f, 0x0000, 0x0000, 0x005f, 0x0000, 0x0300, 0x0300, 0x3e14, 0x3e00, 0x266b, 0x3200, 0x611c, 0x4300, 0x3629, 0x7650, 0x0002, 0x0100, 0x1c22, 0x4100, 0x4122, 0x1c00, 0x2a1c, 0x2a00, 0x083e, 0x0800, 0x4020, 0x0000, 0x0808, 0x0800, 0x0040, 0x0000, 0x601c, 0x0300, 0x3e41, 0x3e00, 0x427f, 0x4000, 0x6259, 0x4600, 0x2249, 0x3600, 0x0f08, 0x7f00, 0x2745, 0x3900, 0x3e49, 0x3200, 0x6119, 0x0700, 0x3649, 0x3600, 0x2649, 0x3e00, 0x0024, 0x0000, 0x4024, 0x0000, 0x0814, 0x2241, 0x1414, 0x1400, 0x4122, 0x1408, 0x0259, 0x0600, 0x3e59, 0x5e00, 0x7e09, 0x7e00, 0x7f49, 0x3600, 0x3e41, 0x2200, 0x7f41, 0x3e00, 0x7f49, 0x4100, 0x7f09, 0x0100, 0x3e49, 0x3a00, 0x7f08, 0x7f00, 0x417f, 0x4100, 0x2040, 0x3f00, 0x7f0c, 0x7300, 0x7f40, 0x4000, 0x7f06, 0x7f00, 0x7f01, 0x7e00, 0x3e41, 0x3e00, 0x7f09, 0x0600, 0x3e41, 0xbe00, 0x7f09, 0x7600, 0x2649, 0x3200, 0x017f, 0x0100, 0x7f40, 0x7f00, 0x1f60, 0x1f00, 0x7f30, 0x7f00, 0x7708, 0x7700, 0x0778, 0x0700, 0x7149, 0x4700, 0x007f, 0x4100, 0x031c, 0x6000, 0x0041, 0x7f00, 0x0201, 0x0200, 0x8080, 0x8000, 0x0001, 0x0200, 0x2454, 0x7800, 0x7f44, 0x3800, 0x3844, 0x2800, 0x3844, 0x7f00, 0x3854, 0x5800, 0x087e, 0x0900, 0x4854, 0x3c00, 0x7f04, 0x7800, 0x447d, 0x4000, 0x2040, 0x3d00, 0x7f10, 0x6c00, 0x417f, 0x4000, 0x7c18, 0x7c00, 0x7c04, 0x7800, 0x3844, 0x3800, 0x7c14, 0x0800, 0x0814, 0x7c00, 0x7c04, 0x0800, 0x4854, 0x2400, 0x043e, 0x4400, 0x3c40, 0x7c00, 0x1c60, 0x1c00, 0x7c30, 0x7c00, 0x6c10, 0x6c00, 0x4c50, 0x3c00, 0x6454, 0x4c00, 0x0836, 0x4100, 0x0077, 0x0000, 0x4136, 0x0800, 0x0201, 0x0201, 0x704c, 0x7000], // default font by Notch
+ // default font by Notch
+ defaultFont: [
+ 0x000f, 0x0808, 0x080f, 0x0808, 0x08f8, 0x0808, 0x00ff, 0x0808,
+ 0x0808, 0x0808, 0x08ff, 0x0808, 0x00ff, 0x1414, 0xff00, 0xff08,
+ 0x1f10, 0x1714, 0xfc04, 0xf414, 0x1710, 0x1714, 0xf404, 0xf414,
+ 0xff00, 0xf714, 0x1414, 0x1414, 0xf700, 0xf714, 0x1417, 0x1414,
+ 0x0f08, 0x0f08, 0x14f4, 0x1414, 0xf808, 0xf808, 0x0f08, 0x0f08,
+ 0x001f, 0x1414, 0x00fc, 0x1414, 0xf808, 0xf808, 0xff08, 0xff08,
+ 0x14ff, 0x1414, 0x080f, 0x0000, 0x00f8, 0x0808, 0xffff, 0xffff,
+ 0xf0f0, 0xf0f0, 0xffff, 0x0000, 0x0000, 0xffff, 0x0f0f, 0x0f0f,
+ 0x0000, 0x0000, 0x005f, 0x0000, 0x0300, 0x0300, 0x3e14, 0x3e00,
+ 0x266b, 0x3200, 0x611c, 0x4300, 0x3629, 0x7650, 0x0002, 0x0100,
+ 0x1c22, 0x4100, 0x4122, 0x1c00, 0x2a1c, 0x2a00, 0x083e, 0x0800,
+ 0x4020, 0x0000, 0x0808, 0x0800, 0x0040, 0x0000, 0x601c, 0x0300,
+ 0x3e41, 0x3e00, 0x427f, 0x4000, 0x6259, 0x4600, 0x2249, 0x3600,
+ 0x0f08, 0x7f00, 0x2745, 0x3900, 0x3e49, 0x3200, 0x6119, 0x0700,
+ 0x3649, 0x3600, 0x2649, 0x3e00, 0x0024, 0x0000, 0x4024, 0x0000,
+ 0x0814, 0x2241, 0x1414, 0x1400, 0x4122, 0x1408, 0x0259, 0x0600,
+ 0x3e59, 0x5e00, 0x7e09, 0x7e00, 0x7f49, 0x3600, 0x3e41, 0x2200,
+ 0x7f41, 0x3e00, 0x7f49, 0x4100, 0x7f09, 0x0100, 0x3e49, 0x3a00,
+ 0x7f08, 0x7f00, 0x417f, 0x4100, 0x2040, 0x3f00, 0x7f0c, 0x7300,
+ 0x7f40, 0x4000, 0x7f06, 0x7f00, 0x7f01, 0x7e00, 0x3e41, 0x3e00,
+ 0x7f09, 0x0600, 0x3e41, 0xbe00, 0x7f09, 0x7600, 0x2649, 0x3200,
+ 0x017f, 0x0100, 0x7f40, 0x7f00, 0x1f60, 0x1f00, 0x7f30, 0x7f00,
+ 0x7708, 0x7700, 0x0778, 0x0700, 0x7149, 0x4700, 0x007f, 0x4100,
+ 0x031c, 0x6000, 0x0041, 0x7f00, 0x0201, 0x0200, 0x8080, 0x8000,
+ 0x0001, 0x0200, 0x2454, 0x7800, 0x7f44, 0x3800, 0x3844, 0x2800,
+ 0x3844, 0x7f00, 0x3854, 0x5800, 0x087e, 0x0900, 0x4854, 0x3c00,
+ 0x7f04, 0x7800, 0x447d, 0x4000, 0x2040, 0x3d00, 0x7f10, 0x6c00,
+ 0x417f, 0x4000, 0x7c18, 0x7c00, 0x7c04, 0x7800, 0x3844, 0x3800,
+ 0x7c14, 0x0800, 0x0814, 0x7c00, 0x7c04, 0x0800, 0x4854, 0x2400,
+ 0x043e, 0x4400, 0x3c40, 0x7c00, 0x1c60, 0x1c00, 0x7c30, 0x7c00,
+ 0x6c10, 0x6c00, 0x4c50, 0x3c00, 0x6454, 0x4c00, 0x0836, 0x4100,
+ 0x0077, 0x0000, 0x4136, 0x0800, 0x0201, 0x0201, 0x704c, 0x7000
+ ],
init: function() {
this.screen = ge("screen").getContext("2d");
@@ -61,15 +94,14 @@ var Screen = {
for (var j = 0; j < 32; j++) {
var fontData = fontCtx.getImageData(j * charWidth, i * charHeight, charWidth, charHeight), charId = (i * 32) + j;
var glyph = 0;
- for (var y = charHeight - 1; y >= 0; y--) {
- var row = 0;
- for (var x = 0; x < charWidth; x++) {
+ for (var x = 0; x < charWidth; x++) {
+ for (var y = charHeight - 1; y >= 0; y--) {
var pixelId = y * charWidth + x;
- row = (row << 1) | ((fontData.data[pixelId * charWidth + 1] > 128) * 1);
+ glyph = (glyph << 1) | ((fontData.data[pixelId * charWidth + 1] > 128) * 1);
}
- glyph = (glyph << 4) | row;
}
- self.font[i * 32 + j] = glyph;
+ self.defaultFont[(i * 32 + j) * 2] = (glyph >> 16);
+ self.defaultFont[(i * 32 + j) * 2 + 1] = (glyph & 0xffff);
}
}
};
Something went wrong with that request. Please try again.