diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f11fd25
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,18 @@
+Copyright (c) 2012 John McCann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..ae20e63
--- /dev/null
+++ b/index.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javascript/assembler.js b/javascript/assembler.js
new file mode 100644
index 0000000..395e9e8
--- /dev/null
+++ b/javascript/assembler.js
@@ -0,0 +1,81 @@
+
+Tokenizer = {
+
+ tokens: [
+ { pattern: /^(;.*)/, type: "comment" },
+ { pattern: /^\b(0x[0-9ABCDEF]+)\b/i, type: "hexidecimal" },
+ { pattern: /^\b([0-9]+)\b/, type: "decimal" },
+ { pattern: /^(\".*\")/, type: "string" },
+ { pattern: /^(:[0-9A-Za-z_]+)/, type: "label_def" },
+ { pattern: /^\b(POP|PUSH|PEEK|DAT)\b/i, type: "reserved_word" },
+ { pattern: /^\b(SET|ADD|SUB|MUL|MLI|DIV|DVI|JSR)\b/i,
+ type: "command" },
+ { pattern: /^\b([ABCXYZIJ]|SP|PC|EX)\b/i, type: "register" },
+ { pattern: /^\b([0-9A-Za-z_]+)\b/, type: "label_ref" },
+ { pattern: /^(\[)/, type: "open_bracket" },
+ { pattern: /^(\])/, type: "close_bracket" },
+ { pattern: /^(,)/, type: "comma" },
+ { pattern: /^(\+|\-|\*)/, type: "operator" },
+ { pattern: /^([\s]+)/, type: "space" },
+ ],
+
+ tokenize: function(input) {
+
+ var lines = input.split("\n");
+ var tokenizedLines = [];
+ for(var i = 0; i < lines.length; i++) {
+ var line = lines[i];
+ var tokenizedLine = [];
+
+ while(line != null && line.length > 0) {
+
+ //console.log("tokenizing ", line);
+
+ var lexeme = null;
+ var match = null;
+ var token = null;
+
+ for(var p = 0; p < this.tokens.length; p++) {
+ token = this.tokens[p];
+ match = token.pattern.exec(line);
+ if(match) break;
+ }
+
+ if(match && match[1].length > 0) {
+ //console.log("token", match);
+
+ lexeme = match[1];
+ tokenizedLine.push( { lexeme: lexeme, type: token.type } );
+
+ line = line.substr(lexeme.length)
+ }
+ else {
+ throw ("Invlid token '" + line + "' on line " + (i+1));
+ line = null;
+ }
+ }
+ if(tokenizedLine.length > 0)
+ tokenizedLines.push(tokenizedLine);
+ }
+ return tokenizedLines;
+ },
+
+ htmlFormatTokens: function(tokenizedLines) {
+ var html = "";
+ for(var i = 0; i < tokenizedLines.length; i++) {
+ var tokenizedLine = tokenizedLines[i];
+ for(var j = 0; j < tokenizedLine.length; j++) {
+ var token = tokenizedLine[j];
+ html += this.formatToken(token);
+ }
+ html += " ";
+ }
+ return html;
+ },
+
+ formatToken: function(token) {
+ var str = token.lexeme.replace(/ /g, " ");
+ return "" + str + " ";
+ }
+
+}
\ No newline at end of file
diff --git a/javascript/emulator.js b/javascript/emulator.js
new file mode 100644
index 0000000..29b7fc2
--- /dev/null
+++ b/javascript/emulator.js
@@ -0,0 +1,842 @@
+
+// http://pastebin.com/raw.php?i=Q4JvQvnM
+// https://github.com/gibbed/0x10c-Notes
+
+function Register(_name, _value, _emulator) {
+ this.name = _name;
+ this.value = _value;
+ this.emulator = _emulator;
+ this.contents = 0;
+}
+Register.prototype.get = function() { return this.contents; }
+Register.prototype.set = function(val) { this.contents = val; }
+
+function RegisterValue(_register) {
+ this.register = _register;
+ this.emulator = _register.emulator;
+}
+RegisterValue.prototype.get = function() {
+ return this.emulator.RAM[this.register.get()];
+}
+RegisterValue.prototype.set = function(val) {
+ this.emulator.RAM[this.register.get()] = val;
+}
+
+function RegisterPlusNextWord(_register) {
+ this.register = _register;
+ this.emulator = _register.emulator;
+}
+RegisterPlusNextWord.prototype.get = function() {
+ return this.emulator.RAM[this.register.get() + this.emulator.nextWord()];
+}
+RegisterPlusNextWord.prototype.set = function(val) {
+ this.emulator.RAM[this.register.get() + this.emulator.nextWord()] = val;
+}
+
+
+function StackPointerValue(_emulator) {
+ this.emulator = _emulator
+}
+StackPointerValue.prototype.get = function() {
+ return this.emulator.Registers.SP.pop();
+}
+StackPointerValue.prototype.set = function(val) {
+ this.emulator.Registers.SP.push(val);
+}
+
+function Literal(_value) {
+ this.value = _value;
+}
+Literal.prototype.get = function() { return this.value; }
+Literal.prototype.set = function(val) { }
+Literals = { };
+
+function Op(_emulator, _name, _value, _cycles, __exec, _set) {
+ this.emulator = _emulator;
+ this.name = _name;
+ this.value = _value;
+ this.cycles = _cycles;
+ this._exec = __exec;
+ _set = _set || this.emulator.OpSet;
+ _set[this.value] = this;
+}
+Op.prototype.exec = function(a, b) {
+ var valA = this.emulator.Values[new String(a)];
+ var valB = this.emulator.Values[new String(b)];
+
+ if(!valA) throw new Error("Invalid 'a' value " + a);
+ if(!valB) throw new Error("Invalid 'b' value " + b);
+
+ this._exec(valA, valB);
+ this.emulator.CPU_CYCLE += this.cycles;
+};
+
+// literals
+for(var i = 0x20, literalVal = -1; i < 0x40; i++, literalVal++) {
+ Literals["L_" + literalVal] = i;
+}
+
+// convenience constants
+Values = { };
+Values.REGISTER_VALUE_OFFSET = 0x08;
+Values.REGISTER_NEXT_WORD_OFFSET = 0x10;
+Values.SP_OFFSET = 0x18;
+Values.NEXT_WORD_VALUE = 0x1e;
+Values.NEXT_WORD_LITERAL = 0x1f;
+Values.SP = 0x1b;
+Values.PC = 0x1c;
+Values.EX = 0x1d;
+
+REGISTER_A = 0x00;
+REGISTER_B = 0x01;
+REGISTER_C = 0x02;
+REGISTER_X = 0x03;
+REGISTER_Y = 0x04;
+REGISTER_Z = 0x05;
+REGISTER_I = 0x06;
+REGISTER_J = 0x07;
+REGISTER_SP = 0x1b;
+REGISTER_PC = 0x1c;
+REGISTER_EX = 0x1d;
+
+OPERATION_SET = 0x01;
+OPERATION_ADD = 0x02;
+OPERATION_SUB = 0x03;
+OPERATION_MUL = 0x04;
+OPERATION_MLI = 0x05;
+OPERATION_DIV = 0x06;
+OPERATION_DVI = 0x07;
+OPERATION_MOD = 0x08;
+OPERATION_MDI = 0x09;
+OPERATION_AND = 0x0a;
+OPERATION_BOR = 0x0b;
+OPERATION_XOR = 0x0c;
+OPERATION_SHR = 0x0d;
+OPERATION_ASR = 0x0e;
+OPERATION_SHL = 0x0f;
+
+OPERATION_IFB = 0x10;
+OPERATION_IFC = 0x11;
+OPERATION_IFE = 0x12;
+OPERATION_IFN = 0x13;
+OPERATION_IFG = 0x14;
+OPERATION_IFA = 0x15;
+OPERATION_IFL = 0x16;
+OPERATION_IFU = 0x17;
+
+OPERATION_ADX = 0x1a;
+OPERATION_SBX = 0x1b;
+
+OPERATION_STI = 0x1e;
+OPERATION_STD = 0x1f;
+
+OPERATION_JSR = 0x01;
+OPERATION_INT = 0x08;
+OPERATION_IAG = 0x09;
+OPERATION_IAS = 0x0a;
+OPERATION_RFI = 0x0b;
+OPERATION_IAQ = 0x0c;
+
+OPERATION_HWN = 0x10;
+OPERATION_HWQ = 0x11;
+OPERATION_HWI = 0x12;
+
+
+
+Utils = {
+ to32BitSigned: function(val) {
+ if((val & 0x8000) > 0) {
+ return (((~val) + 1) & 0xffff) * -1; // two's complement
+ }
+ return val;
+ },
+
+ to16BitSigned: function(val) {
+ if(val < 0) {
+ //return ((~val) + 1) & 0xffff; // two's complement
+ return ((val & 0x7fff) | 0x8000);
+ }
+ return val & 0xffff;
+ },
+
+ roundTowardsZero: function(val) {
+ if(val < 0)
+ val = Math.ceil(val);
+ else
+ val = Math.floor(val);
+ return val;
+ },
+
+ makeInstruction: function(opcode, a, b) {
+ var instruction = opcode;
+ instruction |= (b << 5);
+ instruction |= (a << 10);
+ return instruction;
+ },
+
+ makeSpecialInstruction: function(opcode, a) {
+ var instruction = 0;
+ instruction |= (a << 10);
+ instruction |= (opcode << 5);
+ return instruction;
+ },
+
+ parseInstruction: function(instruction) {
+ return {
+ opcode: instruction & 0x001f,
+ b: (instruction & 0x03e0) >> 5,
+ a: (instruction & 0xfc00) >> 10
+ }
+ },
+
+ parseSpecialInstruction: function(instruction) {
+ return {
+ a: (instruction & 0xfc00) >> 10,
+ opcode: (instruction & 0x03e0) >> 5,
+ b: 0
+ }
+ },
+
+ hex: function(num) {
+ return "0x" + num.toString(16);
+ },
+
+ makeVideoCell: function(glyph, blink, bg, fg) {
+ var result = glyph & 0x7f;
+ result |= (blink & 0x1) << 7;
+ result |= (bg & 0xf) << 8;
+ result |= (fg & 0xf) << 12;
+ return result;
+ },
+
+ makeColor: function(d) {
+ var hex = Number(d).toString(16);
+ hex = "000000".substr(0, 6 - hex.length) + hex;
+ return "#" + hex;
+ }
+
+};
+
+
+function Emulator() {
+
+ this.async = false;
+
+ this.CPU_CYCLE = 0;
+ this.RAM = [];
+
+ this.OpSet = { };
+ this.SpecialOpSet = { };
+ this.Registers = {
+ A: new Register("A", REGISTER_A, this),
+ B: new Register("B", REGISTER_B, this),
+ C: new Register("C", REGISTER_C, this),
+ X: new Register("X", REGISTER_X, this),
+ Y: new Register("Y", REGISTER_Y, this),
+ Z: new Register("Z", REGISTER_Z, this),
+ I: new Register("I", REGISTER_I, this),
+ J: new Register("J", REGISTER_J, this),
+ SP: new Register("SP", REGISTER_SP, this),
+ PC: new Register("PC", REGISTER_PC, this),
+ EX: new Register("EX", REGISTER_EX, this),
+ IA: new Register("IA", 0xffff, this),
+ };
+
+
+ this.Registers.PC.inc = function() {
+ var v = this.get();
+ this.set(v+1);
+ return v;
+ };
+ this.PC = this.Registers.PC;
+
+ this.Registers.SP.push = function(val) {
+ this.emulator.RAM[--this.contents] = val;
+ };
+ this.Registers.SP.pop = function() {
+ return this.emulator.RAM[this.contents++];
+ };
+
+
+ this.Values = { }
+ this.Values[0x00] = this.Registers.A;
+ this.Values[0x01] = this.Registers.B;
+ this.Values[0x02] = this.Registers.C;
+ this.Values[0x03] = this.Registers.X;
+ this.Values[0x04] = this.Registers.Y;
+ this.Values[0x05] = this.Registers.Z;
+ this.Values[0x06] = this.Registers.I;
+ this.Values[0x07] = this.Registers.J;
+ this.Values[0x08] = new RegisterValue(this.Registers.A);
+ this.Values[0x09] = new RegisterValue(this.Registers.B);
+ this.Values[0x0a] = new RegisterValue(this.Registers.C);
+ this.Values[0x0b] = new RegisterValue(this.Registers.X);
+ this.Values[0x0c] = new RegisterValue(this.Registers.Y);
+ this.Values[0x0d] = new RegisterValue(this.Registers.Z);
+ this.Values[0x0e] = new RegisterValue(this.Registers.I);
+ this.Values[0x0f] = new RegisterValue(this.Registers.J);
+ this.Values[0x10] = new RegisterPlusNextWord(this.Registers.A);
+ this.Values[0x11] = new RegisterPlusNextWord(this.Registers.B);
+ this.Values[0x12] = new RegisterPlusNextWord(this.Registers.C);
+ this.Values[0x13] = new RegisterPlusNextWord(this.Registers.X);
+ this.Values[0x14] = new RegisterPlusNextWord(this.Registers.Y);
+ this.Values[0x15] = new RegisterPlusNextWord(this.Registers.Z);
+ this.Values[0x16] = new RegisterPlusNextWord(this.Registers.I);
+ this.Values[0x17] = new RegisterPlusNextWord(this.Registers.J);
+ this.Values[0x18] = new StackPointerValue(this);
+ this.Values[0x19] = new RegisterValue(this.Registers.SP);
+ this.Values[0x1a] = new RegisterPlusNextWord(this.Registers.SP);
+ this.Values[0x1b] = this.Registers.SP;
+ this.Values[0x1c] = this.Registers.PC;
+ this.Values[0x1d] = this.Registers.EX;
+ this.Values[0x1e] = { // next word value
+ emulator: this,
+ get: function() { return this.emulator.RAM[this.emulator.nextWord()]; },
+ set: function(val) { this.emulator.RAM[this.emulator.nextWord()] = val; }
+ };
+ this.Values[0x1f] = { // next word literal
+ emulator: this,
+ get: function() { return this.emulator.nextWord(); },
+ set: function(val) { }
+ };
+
+ for(var i = 0x20, literalVal = -1; i < 0x40; i++, literalVal++) {
+ this.Values[i] = new Literal(literalVal);
+ }
+
+
+ this.BasicOperations = {
+ SET: new Op(this, "SET", OPERATION_SET, 1, function(a, b) {
+ b.set(a.get());
+ }),
+
+ ADD: new Op(this, "ADD", OPERATION_ADD, 2, function(a, b) {
+ var res = a.get() + b.get();
+ b.set(res & 0xffff);
+ if((res & 0xffff0000) > 0)
+ this.emulator.Registers.EX.set(0x0001);
+ else
+ this.emulator.Registers.EX.set(0);
+ }),
+
+ SUB: new Op(this, "SUB", OPERATION_SUB, 2, function(a, b) {
+ var aVal = a.get();
+ var res = b.get() - aVal;
+ b.set(res & 0xffff);
+ if((res) < 0)
+ this.emulator.Registers.EX.set(0xffff);
+ else
+ this.emulator.Registers.EX.set(0);
+
+ }),
+
+ MUL: new Op(this, "MUL", OPERATION_MUL, 2, function(a, b) {
+ var res = a.get() * b.get();
+ b.set(res & 0xffff);
+ this.emulator.Registers.EX.set((res >> 16) & 0xffff);
+ }),
+
+ MLI: new Op(this, "MLI", OPERATION_MLI, 2, function(a, b) {
+ var aVal = Utils.to32BitSigned(a.get()), bVal = Utils.to32BitSigned(b.get());
+ var res = bVal * aVal;
+ b.set(Utils.to16BitSigned(res));
+ this.emulator.Registers.EX.set((res >> 16) & 0xffff);
+ }),
+
+ DIV: new Op(this, "DIV", OPERATION_DIV, 3, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if(aVal === 0) {
+ b.set(0);
+ this.emulator.Registers.EX.set(0);
+ }
+ else {
+ var res = Math.floor(bVal / aVal);
+ b.set(res & 0xffff);
+ this.emulator.Registers.EX.set(Math.floor(((bVal << 16) / aVal)) & 0xffff);
+ }
+ }),
+
+ DVI: new Op(this, "DVI", OPERATION_DVI, 3, function(a, b) {
+ var aVal = Utils.to32BitSigned(a.get()), bVal = Utils.to32BitSigned(b.get());
+ if(aVal === 0) {
+ b.set(0);
+ this.emulator.Registers.EX.set(0);
+ }
+ else {
+ var res = Utils.roundTowardsZero(bVal / aVal);
+ b.set(Utils.to16BitSigned(res));
+ this.emulator.Registers.EX.set(Utils.roundTowardsZero(((bVal << 16) / aVal)) & 0xffff);
+ }
+ }),
+
+ MOD: new Op(this, "MOD", OPERATION_MOD, 3, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if(aVal === 0)
+ b.set(0);
+ else
+ b.set(bVal % aVal);
+ }),
+
+ MDI: new Op(this, "MDI", OPERATION_MDI, 3, function(a, b) {
+ var aVal = Utils.to32BitSigned(a.get()), bVal = Utils.to32BitSigned(b.get());
+ if(aVal === 0)
+ b.set(0);
+ else
+ b.set(Utils.to16BitSigned(bVal % aVal));
+ }),
+
+ AND: new Op(this, "AND", OPERATION_AND, 1, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set(bVal & aVal);
+ }),
+
+ BOR: new Op(this, "BND", OPERATION_BOR, 1, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set(bVal | aVal);
+ }),
+
+ XOR: new Op(this, "XOR", OPERATION_XOR, 1, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set(bVal ^ aVal);
+ }),
+
+ SHR: new Op(this, "SHR", OPERATION_SHR, 1, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set(bVal >>> aVal);
+ this.emulator.Registers.EX.set(((bVal << 16 ) >> aVal) & 0xffff);
+ }),
+
+ ASR: new Op(this, "ASR", OPERATION_ASR, 1, function(a, b) {
+ var aVal = a.get(), bVal = Utils.to32BitSigned(b.get());
+ b.set((bVal >> aVal) & 0xffff);
+ this.emulator.Registers.EX.set(((bVal << 16) >>> aVal) & 0xffff);
+ }),
+
+ SHL: new Op(this, "SHL", OPERATION_SHL, 1, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set((bVal << aVal) & 0xffff);
+ this.emulator.Registers.EX.set(((bVal << aVal) >> 16) & 0xffff);
+ }),
+
+ IFB: new Op(this, "IFB", OPERATION_IFB, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if((bVal & aVal) != 0) { }
+ else this.emulator.skipInstruction();
+
+ }),
+
+ IFC: new Op(this, "IFC", OPERATION_IFC, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if((bVal & aVal) === 0) { }
+ else this.emulator.skipInstruction();
+
+ }),
+
+ IFE: new Op(this, "IFE", OPERATION_IFE, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if(bVal === aVal) { }
+ else this.emulator.skipInstruction();
+ }),
+
+ IFN: new Op(this, "IFN", OPERATION_IFN, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if(bVal !== aVal) { }
+ else this.emulator.skipInstruction();
+ }),
+
+ IFG: new Op(this, "IFG", OPERATION_IFG, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if(bVal > aVal) { }
+ else this.emulator.skipInstruction();
+ }),
+
+ IFA: new Op(this, "IFA", OPERATION_IFA, 2, function(a, b) {
+ var aVal = Utils.to32BitSigned(a.get()), bVal = Utils.to32BitSigned(b.get());
+ if(bVal > aVal) { }
+ else this.emulator.skipInstruction();
+ }),
+
+ IFL: new Op(this, "IFL", OPERATION_IFL, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ if(bVal < aVal) { }
+ else this.emulator.skipInstruction();
+ }),
+
+ IFU: new Op(this, "IFU", OPERATION_IFU, 2, function(a, b) {
+ var aVal = Utils.to32BitSigned(a.get()), bVal = Utils.to32BitSigned(b.get());
+ if(bVal < aVal) { }
+ else this.emulator.skipInstruction();
+ }),
+
+
+ ADX: new Op(this, "ADX", OPERATION_ADX, 3, function(a, b) {
+ var res = a.get() + b.get() + this.emulator.Registers.EX.get();
+ b.set(res & 0xffff);
+ this.emulator.Registers.EX.set(res > 0xffff ? 1 : 0);
+ }),
+
+ SBX: new Op(this, "SBX", OPERATION_SBX, 3, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ var res = bVal - aVal + this.emulator.Registers.EX.get();
+ b.set(res & 0xffff);
+ this.emulator.Registers.EX.set(res < 0 ? 0xffff : 0);
+ }),
+
+ STI: new Op(this, "STI", OPERATION_STI, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set(aVal);
+ a.set(bVal);
+ this.emulator.Registers.I.set((this.emulator.Registers.I.get() + 1) & 0xffff);
+ this.emulator.Registers.J.set((this.emulator.Registers.J.get() + 1) & 0xffff);
+ }),
+
+ STD: new Op(this, "STD", OPERATION_STD, 2, function(a, b) {
+ var aVal = a.get(), bVal = b.get();
+ b.set(aVal);
+ a.set(bVal);
+ this.emulator.Registers.I.set((this.emulator.Registers.I.get() - 1) & 0xffff);
+ this.emulator.Registers.J.set((this.emulator.Registers.J.get() - 1) & 0xffff);
+ }),
+
+ JSR: new Op(this, "JSR", OPERATION_JSR, 3, function(a) {
+ var aVal = a.get();
+ this.emulator.Registers.SP.push(this.emulator.Registers.PC.get());
+ this.emulator.Registers.PC.set(aVal);
+ }, this.SpecialOpSet),
+
+ INT: new Op(this, "INT", OPERATION_INT, 4, function(a) {
+ var aVal = a.get();
+ this.emulator.interruptQueue.push(aVal);
+ }, this.SpecialOpSet),
+
+ IAG: new Op(this, "IAG", OPERATION_IAG, 1, function(a) {
+ a.set(this.emulator.Registers.IA.get());
+ }, this.SpecialOpSet),
+
+ IAS: new Op(this, "IAS", OPERATION_IAS, 1, function(a) {
+ this.emulator.Registers.IA.set(a.get());
+ }, this.SpecialOpSet),
+
+ RFI: new Op(this, "RFI", OPERATION_RFI, 3, function(a) {
+ this.emulator.interruptQueueingEnabled = false;
+ this.emulator.Registers.A.set(this.emulator.Registers.SP.pop());
+ this.emulator.Registers.PC.set(this.emulator.Registers.SP.pop());
+
+ }, this.SpecialOpSet),
+
+ IAQ: new Op(this, "IAQ", OPERATION_IAQ, 2, function(a) {
+ if(a === 0)
+ this.emulator.interruptQueueingEnabled = false;
+ else
+ this.emulator.interruptQueueingEnabled = true;
+ }, this.SpecialOpSet),
+
+ HWN: new Op(this, "HWN", OPERATION_HWN, 2, function(a) {
+ a.set(this.emulator.devices.length);
+ }, this.SpecialOpSet),
+
+ HWQ: new Op(this, "HWQ", OPERATION_HWQ, 4, function(a) {
+ var dev = this.emulator.devices[a.get()];
+ if(dev) {
+ this.emulator.Registers.A.set(dev.id & 0xffff);
+ this.emulator.Registers.B.set((dev.id >> 16) & 0xffff);
+ this.emulator.Registers.C.set(dev.version & 0xffff);
+ this.emulator.Registers.X.set(dev.manufacturer & 0xffff);
+ this.emulator.Registers.Y.set((dev.manufacturer >> 16) & 0xffff);
+ }
+
+ }, this.SpecialOpSet),
+
+ HWI: new Op(this, "HWI", OPERATION_HWI, 4, function(a) {
+ var dev = this.emulator.devices[a.get()];
+ if(dev)
+ dev.interrupt();
+ }, this.SpecialOpSet),
+ };
+
+
+ this.boot= function() {
+ console.log("--- DCPU-16 Emulator ---");
+
+ this.PC.set(0);
+ this.CPU_CYCLE = 0;
+ this.RAM = new Array(0x10000);
+
+ for(var r in this.Registers) {
+ this.Registers[r].set(0);
+ }
+ this.Registers.SP.set(0xffff);
+ };
+
+ this.reboot= function() { this.boot(); };
+
+ this.run = function(_program) {
+ this.program = _program;
+
+ console.log("Running program (" + this.program.length + " words)" );
+
+ if(!this.async) {
+ while(this.step()) { }
+ this.exit();
+ }
+ else
+ this.stepAsync();
+
+ };
+
+ this.step = function() {
+ if(this.PC.get() < this.program.length) {
+ this.nextInstruction();
+
+ // process one interrupt if we have one
+ if(this.interruptQueueingEnabled == false && this.interruptQueue.length > 0) {
+ this.processInterrupt(this.interruptQueue.pop());
+ }
+
+ return true;
+ }
+ else return false;
+ };
+
+ var _this = this;
+ this.asyncSteps = 1;
+ this.stepAsync = function() {
+
+ if(Math.floor(_this.CPU_CYCLE / 1000) > _this.asyncSteps) {
+ _this.asyncSteps++;
+ setTimeout(_this.stepAsync, 1);
+ }
+ else {
+ if(_this.step()) {
+ _this.stepAsync();
+ }
+ else
+ _this.exit();
+ }
+ };
+
+ this.nextInstruction = function() {
+ var data = this.program[this.PC.inc()];
+ var instruction = Utils.parseInstruction(data);
+ var op;
+ if(instruction.opcode === 0) {
+ instruction = Utils.parseSpecialInstruction(data);
+ op = this.SpecialOpSet[instruction.opcode];
+ }
+ else
+ op = this.OpSet[instruction.opcode];
+
+
+
+ if(!op) {
+ var err = "Invalid opcode " + instruction.opcode;
+ console.warn(err);
+ throw err;
+ }
+
+// console.log(
+// Utils.hex(this.Registers.PC.get()) + "\t" +
+// op.name + "\t(" +
+// Utils.hex(instruction.a) + ",\t" +
+// Utils.hex(instruction.b) + ")"
+// );
+ op.exec(instruction.a, instruction.b);
+
+ };
+
+ this.nextWord = function() {
+ this.CPU_CYCLE++;
+ return this.program[this.Registers.PC.inc()];
+ };
+
+ this.skipInstruction = function() {
+ var instruction = Utils.parseInstruction(this.program[this.PC.inc()]);
+ this.CPU_CYCLE++;
+
+ if(instruction.opcode >= OPERATION_IFB && instruction.opcode <= OPERATION_IFU) {
+ // skip additional instruction at cost of an additional cycle
+ instruction = Utils.parseInstruction(this.program[this.PC.inc()]);
+ this.CPU_CYCLE++;
+ }
+
+ };
+
+ this.interruptQueueingEnabled = false;
+ this.interruptQueue = [];
+
+ this.processInterrupt = function(message) {
+ if(this.Registers.IA.get() != 0) {
+ this.interruptQueueingEnabled = true;
+ this.Registers.SP.push(this.Registers.PC.get()); // push PC onto the stack
+ this.Registers.SP.push(this.Registers.A.get()); // followed by pusing A to the stack
+ this.Registers.PC.set(this.Registers.IA.get()); // set PC to IA
+ this.Registers.A.set(message); // set A to the interrupt message
+ }
+ else {
+ }
+ };
+
+ this.interrupt = function(message) {
+ interruptQueue.push(message);
+
+ if(interruptQueue.length > 256) {
+ // catch fire?
+ console.warn("DCUP-16 is on fire");
+ throw "Too many interrupts";
+ }
+ };
+
+ this.exit = function() {
+ console.log("Program completed in " + this.CPU_CYCLE + " cycles");
+ };
+
+ this.devices = [];
+
+ this.boot();
+};
+
+// generic device used for unit tests
+function Device(_id, _version, _manufacturer, _emulator) {
+ this.id = _id;
+ this.version = _version;
+ this.manufacturer = _manufacturer;
+ this.emulator = _emulator;
+};
+Device.prototype.interrupt = function() { };
+
+
+// https://raw.github.com/gibbed/0x10c-Notes/master/hardware/clock.txt
+function Clock(_emulator) {
+ this.id = 0x12d0b402;
+ this.version = 1;
+ this.manufacturer = 0x90099009;
+ this.emulator = _emulator;
+
+ this.interruptsOn = false;
+ this.elapsed = 0;
+ this.interval = 0;
+ this.interruptMessage = 0;
+};
+
+Clock.prototype.interrupt = function() {
+ var aVal = this.emulator.Registers.A.get();
+ var bVal = this.emulator.Registers.B.get();
+ switch(aVal) {
+ case 0:
+ if(bVal != 0)
+ this.start(Math.round(bVal / 60 * 1000));
+ else
+ this.stop();
+ break;
+
+ case 1:
+ this.emulator.Registers.C.set(this.elapsed);
+ break;
+
+ case 2:
+ if(bVal != 0) {
+ this.interruptsOn = true;
+ this.interruptMessage = bVal;
+ }
+ else {
+ this.interruptsOn = false;
+ }
+ break;
+ }
+
+};
+
+Clock.prototype.start = function(duration) {
+ this.stop();
+ this.elapsed = 0;
+ this.interval = setInterval(this.tick, duration);
+}
+
+Clock.prototype.stop = function() {
+ if(this.interval != 0) {
+ clearInterval(this.interval);
+ this.interval = 0;
+ }
+}
+
+Clock.prototype.tick = function() {
+ this.elapsed = (this.elapsed + 1) & 0xffff;
+
+ if(this.interruptsOn)
+ this.emulator.interrupt(this.interruptMessage);
+}
+
+// https://raw.github.com/gibbed/0x10c-Notes/master/hardware/keyboard.txt
+function Keyboard(_emulator) {
+ this.id = 0x30cf7406;
+ this.version = 1;
+ this.manufacturer = 0x90099009;
+ this.emulator = _emulator;
+
+ this.interruptsOn = false;
+ this.interruptMessage = 0;
+ this.keys = [];
+ this.downKeys = {};
+
+ var _this = this;
+ document.body.onkeydown = function(event) { _this.keyDown(event); }
+ document.body.onkeyup = function(event) { _this.keyUp(event); }
+}
+
+Keyboard.prototype.keyDown = function(event) {
+ var code = this.convert(event.keyCode);
+ this.downKeys[""+code] = true;
+
+ this.keys.push(code);
+
+ if(this.interruptsOn)
+ this.emulator.interrupt(this.interruptMessage);
+}
+
+Keyboard.prototype.keyUp = function(event) {
+ var code = this.convert(event.keyCode);
+ this.downKeys[""+code] = false;
+}
+
+Keyboard.prototype.convert = function(code) {
+ // TODO: convert key codes
+ return code;
+}
+
+Keyboard.prototype.interrupt = function() {
+ var aVal = this.emulator.Registers.A.get();
+ switch(aVal) {
+ case 0:
+ this.keys = [];
+ break;
+
+ case 1:
+ var val = 0;
+ if(this.keys.length > 0)
+ val = this.keys.pop();
+ this.emulator.Registers.C.set(val);
+ break;
+
+ case 2:
+ if(this.downKeys[""+bVal])
+ this.emulator.Registers.C.set(1);
+ else
+ this.emulator.Registers.C.set(0);
+ break;
+
+ case 3:
+ if(bVal != 0) {
+ this.interruptsOn = true;
+ this.interruptMessage = bVal;
+ }
+ else {
+ this.interruptsOn = false;
+ }
+ break;
+ }
+
+};
+
+
+
+
diff --git a/javascript/lem1820.js b/javascript/lem1820.js
new file mode 100644
index 0000000..435d02b
--- /dev/null
+++ b/javascript/lem1820.js
@@ -0,0 +1,128 @@
+function Monitor(_emulator) {
+ this.id = 0x7349f615;
+ this.version = 0x1802;
+ this.manufacturer = 0x1c6c8b36;
+ this.emulator = _emulator;
+
+
+
+ this.font = [
+ 0xB79E, 0x388E, 0x722C, 0x75F4, 0x19BB, 0x7F8F, 0x85F9, 0xB158, 0x242E, 0x2400, 0x082A, 0x0800, 0x0008, 0x0000, 0x0808, 0x0808,
+ 0x00FF, 0x0000, 0x00F8, 0x0808, 0x08F8, 0x0000, 0x080F, 0x0000, 0x000F, 0x0808, 0x00FF, 0x0808, 0x08F8, 0x0808, 0x08FF, 0x0000,
+ 0x080F, 0x0808, 0x08FF, 0x0808, 0x6633, 0x99CC, 0x9933, 0x66CC, 0xFEF8, 0xE080, 0x7F1F, 0x0701, 0x0107, 0x1F7F, 0x80E0, 0xF8FE,
+ 0x5500, 0xAA00, 0x55AA, 0x55AA, 0xFFAA, 0xFF55, 0x0F0F, 0x0F0F, 0xF0F0, 0xF0F0, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF,
+ 0x0000, 0x0000, 0x005F, 0x0000, 0x0300, 0x0300, 0x3E14, 0x3E00, 0x266B, 0x3200, 0x611C, 0x4300, 0x3629, 0x7650, 0x0002, 0x0100,
+ 0x1C22, 0x4100, 0x4122, 0x1C00, 0x1408, 0x1400, 0x081C, 0x0800, 0x4020, 0x0000, 0x0808, 0x0800, 0x0040, 0x0000, 0x601C, 0x0300,
+ 0x3E49, 0x3E00, 0x427F, 0x4000, 0x6259, 0x4600, 0x2249, 0x3600, 0x0F08, 0x7F00, 0x2745, 0x3900, 0x3E49, 0x3200, 0x6119, 0x0700,
+ 0x3649, 0x3600, 0x2649, 0x3E00, 0x0024, 0x0000, 0x4024, 0x0000, 0x0814, 0x2200, 0x1414, 0x1400, 0x2214, 0x0800, 0x0259, 0x0600,
+ 0x3E59, 0x5E00, 0x7E09, 0x7E00, 0x7F49, 0x3600, 0x3E41, 0x2200, 0x7F41, 0x3E00, 0x7F49, 0x4100, 0x7F09, 0x0100, 0x3E41, 0x7A00,
+ 0x7F08, 0x7F00, 0x417F, 0x4100, 0x2040, 0x3F00, 0x7F08, 0x7700, 0x7F40, 0x4000, 0x7F06, 0x7F00, 0x7F01, 0x7E00, 0x3E41, 0x3E00,
+ 0x7F09, 0x0600, 0x3E61, 0x7E00, 0x7F09, 0x7600, 0x2649, 0x3200, 0x017F, 0x0100, 0x3F40, 0x7F00, 0x1F60, 0x1F00, 0x7F30, 0x7F00,
+ 0x7708, 0x7700, 0x0778, 0x0700, 0x7149, 0x4700, 0x007F, 0x4100, 0x031C, 0x6000, 0x417F, 0x0000, 0x0201, 0x0200, 0x8080, 0x8000,
+ 0x0001, 0x0200, 0x2454, 0x7800, 0x7F44, 0x3800, 0x3844, 0x2800, 0x3844, 0x7F00, 0x3854, 0x5800, 0x087E, 0x0900, 0x4854, 0x3C00,
+ 0x7F04, 0x7800, 0x047D, 0x0000, 0x2040, 0x3D00, 0x7F10, 0x6C00, 0x017F, 0x0000, 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, 0x0205, 0x0200]
+
+ this.palette = [
+ 0x000000, 0x0000aa, 0x00aa00, 0x00aaaa, 0xaa0000, 0xaa00aa, 0xaa5500, 0xaaaaaa,
+ 0x555555, 0x5555ff, 0x55ff55, 0x55ffff, 0xff5555, 0xff55ff, 0xffff55, 0xffffff
+ ];
+
+ this.borderColor = 8;
+
+ this.zoom = 2;
+
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = this.zoom * 128;
+ this.canvas.height = this.zoom * 96;
+ this.canvas.style.backgroundColor = "#777777";
+ this.canvas.className = "lem1820";
+ this.setBorderColor(this.borderColor);
+ document.body.appendChild(this.canvas);
+ this.context = this.canvas.getContext('2d');
+}
+
+Monitor.prototype.interrupt = function() {
+ var aVal = this.emulator.Registers.A.get();
+ var bVal = this.emulator.Registers.B.get();
+ switch(aVal) {
+ case 0:
+ if(bVal === 0)
+ this.disconnect();
+ else
+ this.memMapScreen(bVal);
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ this.setBorderColor(bVal & 0xf);
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+ }
+}
+
+Monitor.prototype.memMapScreen = function(offset) {
+ for(var y = 0; y < 12; y++) {
+ for(var x = 0; x < 32; x++) {
+ this.drawCell(x, y, this.emulator.RAM[offset + x + y*32]);
+ }
+ }
+}
+
+Monitor.prototype.drawCell = function(x, y, word) {
+ var glyph = word & 0x7f;
+ var blink = (word & 0x80) >> 7;
+ var bg = (word & 0xf00) >> 8;
+ var fg = (word & 0xf000) >> 12;
+ this.drawGlyph(x, y, glyph, this.palette[fg], this.palette[bg], blink);
+}
+
+Monitor.prototype.drawGlyph = function(x, y, glyph, fg, bg, blink) {
+ this.context.fillStyle = Utils.makeColor(bg);
+ this.context.fillRect(x * 4 * this.zoom, y * 8 * this.zoom, 4 * this.zoom, 8 * this.zoom);
+
+ this.context.fillStyle = Utils.makeColor(fg);
+
+ var cols = [];
+ glyph *= 2;
+ cols[0] = this.font[glyph] >> 8;
+ cols[1] = this.font[glyph] & 0xff;
+ cols[2] = this.font[glyph+1] >> 8;
+ cols[3] = this.font[glyph+1] & 0xff;
+
+ for(var row = 0; row < 8; row++) {
+ for(var col = 0; col < 4; col++) {
+ var bit = (cols[col] >> row) & 0x01;
+ if(bit == 1)
+ this.context.fillRect((x*4 + col) * this.zoom, (y*8 + row) * this.zoom, this.zoom, this.zoom);
+ }
+ }
+
+}
+
+Monitor.prototype.disconnect = function() {
+ this.context.fillStyle = "#777777";
+ this.context.fillRect(0, 0, 128, 96);
+}
+
+Monitor.prototype.setBorderColor = function(color) {
+ this.borderColor = this.palette[color & 0xf];
+ this.canvas.style.border = (4+this.zoom) + "px solid " + Utils.makeColor(this.borderColor);
+}
+
+Monitor.prototype.getDOMElement = function() {
+ return this.canvas;
+}
+
+
diff --git a/stylesheets/styles.css b/stylesheets/styles.css
new file mode 100644
index 0000000..278f7f1
--- /dev/null
+++ b/stylesheets/styles.css
@@ -0,0 +1,50 @@
+body {
+ font-family: courier, 'courier new', 'fixed-width';
+ font-size: 12px;
+}
+.assembly {
+ background: #111111;
+ padding: 6px;
+ border: 1px dashed #cccccc;
+}
+.comment {
+ color: #777777;
+}
+.hexidecimal {
+ color: #007777;
+}
+.decimal {
+ color: #0077ff;
+}
+.string {
+ color: #007700
+}
+.label_def {
+ color: #6666ff
+}
+.label_ref {
+ color: #aaaaff
+}
+.command {
+ color: #ffffff;
+ font-weight: bold;
+}
+.reserved_word {
+ color: #aaaa00;
+}
+.open_bracket {
+ color: #dddddd;
+}
+.close_bracket {
+ color: #dddddd;
+}
+.comma {
+ color: #dddddd;
+}
+.operator {
+ color: #dddddd;
+}
+.register {
+ color: #aa33aa;
+}
+.space { }
\ No newline at end of file
diff --git a/test/units.html b/test/units.html
new file mode 100644
index 0000000..229e008
--- /dev/null
+++ b/test/units.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test markup, will be hidden
+
+
\ No newline at end of file
diff --git a/test/units.js b/test/units.js
new file mode 100644
index 0000000..fb047e6
--- /dev/null
+++ b/test/units.js
@@ -0,0 +1,638 @@
+function units() {
+
+ module("opcodes Module");
+
+ test("SET Bad Programs", function() {
+ var e = new Emulator();
+
+ raises(function() {
+ e.run([ 0x18 ]);
+ }, "Test bad op code");
+
+ });
+
+ test("SET Test", function() {
+ //expect(8);
+
+ var program = [
+ // register tests
+ Utils.makeInstruction(OPERATION_SET, Literals.L_2, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_10, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, REGISTER_B, REGISTER_C),
+
+ // register + RAM tests
+ Utils.makeInstruction(OPERATION_SET, Literals.L_3, REGISTER_B + Values.REGISTER_VALUE_OFFSET),
+ Utils.makeInstruction(OPERATION_SET, REGISTER_B + Values.REGISTER_VALUE_OFFSET, REGISTER_I),
+
+ // register + RAM + next word tests
+ Utils.makeInstruction(OPERATION_SET, Literals.L_4, REGISTER_A + Values.REGISTER_NEXT_WORD_OFFSET), 0x03,
+ Utils.makeInstruction(OPERATION_SET, REGISTER_A + Values.REGISTER_NEXT_WORD_OFFSET, REGISTER_J), 0x03,
+
+ // next word tests
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x2222,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_VALUE, REGISTER_Y), 0x0a,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, Values.NEXT_WORD_VALUE), 0x3333, 0x0b
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.A.get(), 2, "Register A set correctly");
+ equal(e.Registers.B.get(), 10, "Register B set correctly");
+ equal(e.Registers.C.get(), 10, "Register C set to value of B");
+
+ equal(e.RAM[0x0a], 3, "RAM at location 10 set to value of 3");
+ equal(e.Registers.I.get(), e.RAM[0x0a], "Register I set to RAM at location 10");
+
+ equal(e.RAM[0x05], 4, "RAM at location 5 set to value of 4");
+ equal(e.Registers.J.get(), e.RAM[0x05], "Register J set to RAM at location 5");
+
+ equal(e.Registers.X.get(), 0x2222, "Register X set to NEXT_WORD_LITERAL");
+ equal(e.Registers.Y.get(), 3, "Register Y set to NEXT_WORD_VALUE");
+ equal(e.RAM[0x0b], 0x3333, "RAM at NEXT_WORD_VALUE set to NEXT_WORD_LITERAL");
+
+ });
+
+ test("SP Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Literals.L_5, Values.SP_OFFSET), // push 5
+ Utils.makeInstruction(OPERATION_SET, Literals.L_4, Values.SP_OFFSET), // push 4
+ Utils.makeInstruction(OPERATION_SET, Literals.L_3, Values.SP_OFFSET), // push 3
+ Utils.makeInstruction(OPERATION_SET, Literals.L_2, Values.SP_OFFSET), // push 2
+ Utils.makeInstruction(OPERATION_SET, Literals.L_1, Values.SP_OFFSET), // push 1
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, Values.SP_OFFSET), // push 0
+ Utils.makeInstruction(OPERATION_SET, Literals["L_-1"], Values.SP_OFFSET), // push -1
+
+ Utils.makeInstruction(OPERATION_SET, Values.SP_OFFSET, REGISTER_A), // pop -1
+ Utils.makeInstruction(OPERATION_SET, Values.SP_OFFSET+1, REGISTER_B), // peak 0
+ Utils.makeInstruction(OPERATION_SET, Values.SP_OFFSET+2, REGISTER_C), 0x3,// pick 3
+ Utils.makeInstruction(OPERATION_SET, Values.SP_OFFSET, REGISTER_I), // pop 0
+ Utils.makeInstruction(OPERATION_SET, Values.SP_OFFSET, REGISTER_J), // pop 1
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.A.get(), -1, "Register A is -1");
+ equal(e.Registers.B.get(), 0, "Register B is 0");
+ equal(e.Registers.C.get(), 3, "Register C is 3");
+ equal(e.Registers.I.get(), 0, "Register I is 0");
+ equal(e.Registers.J.get(), 1, "Register J is 1");
+ equal(e.Registers.SP.get(), 0xfffb, "Register SP is 0xfffb");
+ });
+
+
+
+ test("ADD Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Literals.L_2, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_4, REGISTER_B),
+ Utils.makeInstruction(OPERATION_ADD, REGISTER_A, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x8800,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0x8801,
+ Utils.makeInstruction(OPERATION_ADD, REGISTER_X, REGISTER_Y)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 6, "Register B is sum of A and B");
+ equal(e.Registers.Y.get(), 0x1001, "Register Y is sum of 0x8800 and 0x8801");
+ equal(e.Registers.EX.get(), 1, "Register EX shows overflow");
+ });
+
+
+ test("SUB Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Literals.L_2, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_4, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SUB, REGISTER_A, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x8801,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0x4800,
+ Utils.makeInstruction(OPERATION_SUB, REGISTER_X, REGISTER_Y)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 2, "Register B is difference of B and A");
+ equal(e.Registers.Y.get(), 0xbfff, "Register Y is difference of 0x4800 and 0x8801");
+ equal(e.Registers.EX.get(), 0xffff, "Register EX shows overflow");
+ });
+
+ test("MUL Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Literals.L_2, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_4, REGISTER_B),
+ Utils.makeInstruction(OPERATION_MUL, REGISTER_A, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x1010,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0x0408,
+ Utils.makeInstruction(OPERATION_MUL, REGISTER_X, REGISTER_Y)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 8, "Register B is product of B and A");
+ equal(e.Registers.Y.get(), 0xc080, "Register Y is product of 0x1010 and 0x0400");
+ equal(e.Registers.EX.get(), 0x0040, "Register EX shows overflow");
+ });
+
+ test("MLI Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0xFFFB, // -5
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x02,
+ Utils.makeInstruction(OPERATION_MLI, REGISTER_A, REGISTER_B), // B = -10
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0xD8F0, // -10,000
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0xEB20, // -5,344
+ Utils.makeInstruction(OPERATION_MLI, REGISTER_X, REGISTER_Y) // X = 0x6E00, EX=0x32F
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xFFF6, "Register B is product of B and A");
+ equal(e.Registers.Y.get(), 0x6E00, "Register Y is product of 0xD8F0 and 0xEB20");
+ equal(e.Registers.EX.get(), 0x32F, "Register EX shows overflow");
+ });
+
+ test("DIV Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x03,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x2c, // 44
+ Utils.makeInstruction(OPERATION_DIV, REGISTER_A, REGISTER_B), // B = 14
+ Utils.makeInstruction(OPERATION_SET, REGISTER_EX, REGISTER_I),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x0332,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0xF445, //
+ Utils.makeInstruction(OPERATION_DIV, REGISTER_X, REGISTER_Y) // X = 0x4c, EX=0x723a
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x0e, "Register B is quotient of B and A");
+ equal(e.Registers.I.get(), 0xAAAA, "Register I shows overflow from first operation");
+ equal(e.Registers.Y.get(), 0x4c, "Register Y is quotient of 0xD8F0 and 0xEB20");
+ //equal(e.Registers.EX.get(), 0x723a, "Register EX shows overflow");
+ });
+
+ test("DVI Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0xFFFD, // -3
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x2c, // 44
+ Utils.makeInstruction(OPERATION_DVI, REGISTER_A, REGISTER_B), // B = -14
+ Utils.makeInstruction(OPERATION_SET, REGISTER_EX, REGISTER_I),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x0332,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0xF445, //
+ Utils.makeInstruction(OPERATION_DVI, REGISTER_X, REGISTER_Y) // X = 0x4c, EX=0x723a
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xFFF2, "Register B is quotient of B and A");
+ equal(e.Registers.I.get(), 0x5556, "Register I shows overflow from first operation");
+ equal(e.Registers.Y.get(), 0xFFFD, "Register Y is quotient of 0xD8F0 and 0xEB20");
+ //equal(e.Registers.EX.get(), 0x723a, "Register EX shows overflow");
+ });
+
+ test("MOD Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x0f, // 15
+ Utils.makeInstruction(OPERATION_MOD, REGISTER_A, REGISTER_B), // B = 3
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0x13, //
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0x3452, //
+ Utils.makeInstruction(OPERATION_MOD, REGISTER_X, REGISTER_Y) // X = 0x12
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 3, "Register B is result of B % A");
+ equal(e.Registers.Y.get(), 0x12, "Register Y 0x3452 % 0x13");
+ });
+
+ test("MDI Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x10, // -7
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xFFF9, // 16
+ Utils.makeInstruction(OPERATION_MDI, REGISTER_A, REGISTER_B), // B = -7
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xFFF9, "Register B is result of B % A");
+ });
+
+ test("AND Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0xff44,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x44ff,
+ Utils.makeInstruction(OPERATION_AND, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x4444, "Register B is result of B & A");
+ });
+
+ test("BOR Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x4444,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x3333,
+ Utils.makeInstruction(OPERATION_BOR, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x7777, "Register B is result of B | A");
+ });
+
+ test("XOR Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x3434,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x1111,
+ Utils.makeInstruction(OPERATION_XOR, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x2525, "Register B is result of B ^ A");
+ });
+
+ test("SHR Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xFF11,
+ Utils.makeInstruction(OPERATION_SHR, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x0FF1, "Register B is result of B >>> A");
+ equal(e.Registers.EX.get(), 0x1000, "Register EX shows overflow");
+ });
+
+ test("ASR Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xFF11,
+ Utils.makeInstruction(OPERATION_ASR, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xFFF1, "Register B is result of B >> A");
+ equal(e.Registers.EX.get(), 0x1000, "Register EX shows overflow");
+ });
+
+ test("SHL Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xFF11,
+ Utils.makeInstruction(OPERATION_SHL, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xF110, "Register B is result of B << A");
+ equal(e.Registers.EX.get(), 0x0f, "Register EX shows overflow");
+ });
+
+ // branching operations
+ test("IFB Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xffee,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x01,
+ Utils.makeInstruction(OPERATION_IFB, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B)
+
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xffee, "B is 0xffee, instruction was skipped");
+ });
+
+ test("IFC Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xffee,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_IFC, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B)
+
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xffee, "B is 0xffee, instruction was skipped");
+ });
+
+ test("IFE Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xffee,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_X),
+ Utils.makeInstruction(OPERATION_IFE, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_1, REGISTER_I),
+ Utils.makeInstruction(OPERATION_IFE, Literals.L_4, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_2, REGISTER_J),
+ Utils.makeInstruction(OPERATION_IFE, Literals.L_5, REGISTER_A),
+ Utils.makeInstruction(OPERATION_IFE, Literals.L_6, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_7, REGISTER_X)
+
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xffee, "B is 0xffee, instruction was skipped");
+ equal(e.Registers.I.get(), 1, "I is 1, instruction was not skipped");
+ equal(e.Registers.J.get(), 2, "J is 2, instruction was not skipped");
+ equal(e.Registers.X.get(), 0, "X is 0, instruction was skipped");
+ });
+
+ test("IFN Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xffee,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0xffee,
+ Utils.makeInstruction(OPERATION_IFN, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B),
+ Utils.makeInstruction(OPERATION_IFN, Literals.L_5, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_7, REGISTER_J)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xffee, "B is 0xffee, instruction was skipped");
+ equal(e.Registers.J.get(), 7, "J is 7, instruction was not skipped");
+ });
+
+ test("IFG Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xffee,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_IFG, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0xffee, "B is 0xffee, instruction was skipped");
+ });
+
+ test("IFA Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0xffee,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_IFA, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0, "B is 0, instruction was not skipped");
+ });
+
+ test("IFL Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x03,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_IFL, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x03, "B is 0x03, instruction was skipped");
+ });
+
+ test("IFU Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0xff43,
+ Utils.makeInstruction(OPERATION_IFU, REGISTER_B, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_B)
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0, "B is 0, instruction was not skipped");
+ });
+
+ test("ADX Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x05,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_EX), 0x06,
+ Utils.makeInstruction(OPERATION_ADX, REGISTER_A, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0xee55,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0xff44,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_EX), 0x06,
+ Utils.makeInstruction(OPERATION_ADX, REGISTER_X, REGISTER_Y),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x0f, "Register B is result of A + B + EX");
+ equal(e.Registers.Y.get(), 0xED9F, "Register Y is result of X + Y + EX");
+ equal(e.Registers.EX.get(), 0x01, "Register EX shows overflow");
+ });
+
+ test("SBX Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x05,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_EX), 0x06,
+ Utils.makeInstruction(OPERATION_SBX, REGISTER_A, REGISTER_B),
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_X), 0xff44,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_Y), 0xee55,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_EX), 0x06,
+ Utils.makeInstruction(OPERATION_SBX, REGISTER_X, REGISTER_Y),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.B.get(), 0x07, "Register B is result of B - A + EX");
+ equal(e.Registers.Y.get(), 0xEF17, "Register Y is result of Y - X + EX");
+ equal(e.Registers.EX.get(), 0xffff, "Register EX shows underflow");
+ });
+
+ test("STI Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x05,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_I), 0x06,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_J), 0x07,
+ Utils.makeInstruction(OPERATION_STI, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.A.get(), 0x05, "Register A is set to B");
+ equal(e.Registers.B.get(), 0x04, "Register B is set to A");
+ equal(e.Registers.I.get(), 0x07, "Register I has been incremented");
+ equal(e.Registers.J.get(), 0x08, "Register J has been incremented");
+ });
+
+ test("STD Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x05,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_I), 0x06,
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_J), 0x00,
+ Utils.makeInstruction(OPERATION_STD, REGISTER_A, REGISTER_B),
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.A.get(), 0x05, "Register A is set to B");
+ equal(e.Registers.B.get(), 0x04, "Register B is set to A");
+ equal(e.Registers.I.get(), 0x05, "Register I has been decremented");
+ equal(e.Registers.J.get(), 0xffff, "Register J has been decremented");
+ });
+
+ test("JSR Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x04,
+ Utils.makeSpecialInstruction(OPERATION_JSR, Values.NEXT_WORD_LITERAL), 0x08, // jump to 0x8
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x05,
+ Utils.makeInstruction(OPERATION_IFE, Literals.L_5, REGISTER_A),
+ Utils.makeInstruction(OPERATION_SET, Literals.L_16, REGISTER_PC), // exit
+
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_A), 0x03, // 0x8
+ Utils.makeInstruction(OPERATION_SET, Values.SP_OFFSET, REGISTER_PC) // return
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.A.get(), 0x05, "Register A is set to 5");
+ });
+
+ test("Interrupt Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeInstruction(OPERATION_SET, Values.NEXT_WORD_LITERAL, REGISTER_B), 0x06,
+ Utils.makeSpecialInstruction(OPERATION_IAS, REGISTER_B),
+ Utils.makeSpecialInstruction(OPERATION_INT, Values.NEXT_WORD_LITERAL), 0x08,
+ Utils.makeInstruction(OPERATION_SET, Literals.L_16, REGISTER_PC), // exit
+ Utils.makeInstruction(OPERATION_SET, Literals.L_0, REGISTER_C), // 0x06
+ Utils.makeSpecialInstruction(OPERATION_IAG, REGISTER_Y), // Y = 6
+ Utils.makeSpecialInstruction(OPERATION_IAS, REGISTER_C), // IA = 0
+ Utils.makeInstruction(OPERATION_SET, REGISTER_A, REGISTER_X), // X = 8 (INT message)
+ Utils.makeSpecialInstruction(OPERATION_RFI, Literals.L_0), // return
+
+ ];
+
+ var e = new Emulator();
+ e.run(program);
+
+ equal(e.Registers.IA.get(), 0x00, "Register IA is set to 0");
+ equal(e.Registers.X.get(), 0x08, "Register X is set to 8");
+ equal(e.Registers.Y.get(), 0x06, "Register Y is set to 6");
+ });
+
+ test("Hardware Test", function() {
+ //expect(1);
+
+ var program = [
+ Utils.makeSpecialInstruction(OPERATION_HWN, REGISTER_I),
+ Utils.makeSpecialInstruction(OPERATION_HWQ, Literals.L_0),
+ Utils.makeSpecialInstruction(OPERATION_HWI, Literals.L_0),
+ ];
+
+ var e = new Emulator();
+ e.devices.push(new Device(0xdeadbeef, 0x21, 0xfeeddeee));
+ e.run(program);
+
+ equal(e.Registers.I.get(), 1, "Register I is set to 1");
+ equal(e.Registers.A.get(), 0xbeef, "Register A is set to 0xbeef");
+ equal(e.Registers.B.get(), 0xdead, "Register B is set to 0xdead");
+ equal(e.Registers.C.get(), 0x21, "Register C is set to 0x21");
+ equal(e.Registers.X.get(), 0xdeee, "Register X is set to 0xdeee");
+ equal(e.Registers.Y.get(), 0xfeed, "Register Y is set to 0xfeed");
+
+ });
+
+
+};
+
+
diff --git a/tokenizer.html b/tokenizer.html
new file mode 100644
index 0000000..cbb0d16
--- /dev/null
+++ b/tokenizer.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file