mirror of https://github.com/chyyuu/v8-cpu.git
style(formatting): Small code format cleanup
This commit is contained in:
parent
6a043667bf
commit
1b549c25dc
|
@ -2,4 +2,4 @@
|
|||
.idea
|
||||
.DS_Store
|
||||
node_modules/*
|
||||
ASMSimulator.iml
|
||||
ASMSimulator.iml
|
||||
|
|
|
@ -45,4 +45,4 @@ module.exports = function(grunt) {
|
|||
|
||||
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
|
||||
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes', function(opcodes) {
|
||||
var app = angular.module('ASMSimulator', []);
|
||||
;app.service('assembler', ['opcodes', function (opcodes) {
|
||||
return {
|
||||
go: function(input) {
|
||||
var self = this;
|
||||
|
||||
go: function (input) {
|
||||
// Use https://www.debuggex.com/
|
||||
// Matches: "label: INSTRUCTION (["')OPERAND1(]"'), (["')OPERAND2(]"')
|
||||
// GROUPS: 1 2 3 7
|
||||
var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,4})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?/;
|
||||
var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,4})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?/;
|
||||
|
||||
// Regex group indexes for operands
|
||||
var op1_group = 3;
|
||||
var op2_group = 7;
|
||||
|
||||
var op1_group=3; // group indexes for operands
|
||||
var op2_group=7;
|
||||
// MATCHES: "(+|-)INTEGER"
|
||||
var regexNum = /^[-+]?[0-9]+$/;
|
||||
// MATCHES: "(.L)abel"
|
||||
var regexLabel = /^[.A-Za-z]\w*$/;
|
||||
|
||||
// Contains the program code & data generated by the assembler
|
||||
var code = [];
|
||||
// Contains the mapping from instructions to assembler line
|
||||
|
@ -24,26 +24,28 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
// Hash of uppercase labels used to detect duplicates
|
||||
var normalizedLabels = {};
|
||||
|
||||
var lines = input.split('\n'); // Split text into code lines
|
||||
// Split text into code lines
|
||||
var lines = input.split('\n');
|
||||
|
||||
// Allowed formats: 200, 200d, 0xA4, 0o48, 101b
|
||||
var parseNumber = function(input) {
|
||||
if (input.slice(0,2) === "0x") {
|
||||
var parseNumber = function (input) {
|
||||
if (input.slice(0, 2) === "0x") {
|
||||
return parseInt(input.slice(2), 16);
|
||||
} else if (input.slice(0,2) === "0o") {
|
||||
} else if (input.slice(0, 2) === "0o") {
|
||||
return parseInt(input.slice(2), 8);
|
||||
} else if (input.slice(input.length-1) === "b") {
|
||||
return parseInt(input.slice(0, input.length-1), 2);
|
||||
} else if (input.slice(input.length-1) === "d") {
|
||||
return parseInt(input.slice(0, input.length-1), 10);
|
||||
} else if (input.slice(input.length - 1) === "b") {
|
||||
return parseInt(input.slice(0, input.length - 1), 2);
|
||||
} else if (input.slice(input.length - 1) === "d") {
|
||||
return parseInt(input.slice(0, input.length - 1), 10);
|
||||
} else if (regexNum.exec(input)) {
|
||||
return parseInt(input, 10);
|
||||
} else {
|
||||
throw "Invalid number format";
|
||||
}
|
||||
};
|
||||
|
||||
// Allowed registers: A, B, C, D, SP
|
||||
var parseRegister = function(input) {
|
||||
var parseRegister = function (input) {
|
||||
input = input.toUpperCase();
|
||||
|
||||
if (input === 'A') {
|
||||
|
@ -55,75 +57,75 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
} else if (input === 'D') {
|
||||
return 3;
|
||||
} else if (input === 'SP') {
|
||||
return 4;
|
||||
} else {
|
||||
return 4;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
var parseOffsetAddressing=function(input) {
|
||||
input = input.toUpperCase();
|
||||
var m = 0;
|
||||
var base = 0;
|
||||
|
||||
if (input[0] === 'A') {
|
||||
base = 0;
|
||||
} else if (input[0] === 'B') {
|
||||
base = 1;
|
||||
} else if (input[0] === 'C') {
|
||||
base = 2;
|
||||
} else if (input[0] === 'D') {
|
||||
base = 3;
|
||||
} else if( input.slice(0,2) === "SP") {
|
||||
base = 4;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
var offset_start = 1;
|
||||
if (base === 4) {
|
||||
offset_start = 2;
|
||||
}
|
||||
|
||||
if (input[offset_start] === '-') {
|
||||
m = -1;
|
||||
} else if (input[offset_start] === '+') {
|
||||
m = 1;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var offset = m*parseInt(input.slice(offset_start+1),10);
|
||||
|
||||
if (offset < -16 || offset > 15)
|
||||
throw "offset must be a value between -16...+15";
|
||||
|
||||
if (offset < 0) {
|
||||
offset=32+offset; // two's complement representation in 5-bit
|
||||
}
|
||||
|
||||
return offset*8+base; // shift offset 3 bits right and add code for register
|
||||
};
|
||||
|
||||
|
||||
var parseOffsetAddressing = function (input) {
|
||||
input = input.toUpperCase();
|
||||
var m = 0;
|
||||
var base = 0;
|
||||
|
||||
if (input[0] === 'A') {
|
||||
base = 0;
|
||||
} else if (input[0] === 'B') {
|
||||
base = 1;
|
||||
} else if (input[0] === 'C') {
|
||||
base = 2;
|
||||
} else if (input[0] === 'D') {
|
||||
base = 3;
|
||||
} else if (input.slice(0, 2) === "SP") {
|
||||
base = 4;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
var offset_start = 1;
|
||||
if (base === 4) {
|
||||
offset_start = 2;
|
||||
}
|
||||
|
||||
if (input[offset_start] === '-') {
|
||||
m = -1;
|
||||
} else if (input[offset_start] === '+') {
|
||||
m = 1;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var offset = m * parseInt(input.slice(offset_start + 1), 10);
|
||||
|
||||
if (offset < -16 || offset > 15)
|
||||
throw "offset must be a value between -16...+15";
|
||||
|
||||
if (offset < 0) {
|
||||
offset = 32 + offset; // two's complement representation in 5-bit
|
||||
}
|
||||
|
||||
return offset * 8 + base; // shift offset 3 bits right and add code for register
|
||||
};
|
||||
|
||||
// Allowed: Register, Label or Number; SP+/-Number is allowed for 'regaddress' type
|
||||
var parseRegOrNumber = function(input, typeReg, typeNumber) {
|
||||
var parseRegOrNumber = function (input, typeReg, typeNumber) {
|
||||
var register = parseRegister(input);
|
||||
|
||||
if (register !== undefined) {
|
||||
return { type: typeReg, value: register};
|
||||
return {type: typeReg, value: register};
|
||||
} else {
|
||||
var label = parseLabel(input);
|
||||
if (label !== undefined) {
|
||||
return { type: typeNumber, value: label};
|
||||
return {type: typeNumber, value: label};
|
||||
} else {
|
||||
if (typeReg === "regaddress") {
|
||||
|
||||
register = parseOffsetAddressing(input);
|
||||
|
||||
if (register !== undefined) {
|
||||
return { type: typeReg, value: register};
|
||||
}
|
||||
}
|
||||
|
||||
if (typeReg === "regaddress") {
|
||||
|
||||
register = parseOffsetAddressing(input);
|
||||
|
||||
if (register !== undefined) {
|
||||
return {type: typeReg, value: register};
|
||||
}
|
||||
}
|
||||
|
||||
var value = parseNumber(input);
|
||||
|
||||
if (isNaN(value)) {
|
||||
|
@ -132,39 +134,41 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
else if (value < 0 || value > 255)
|
||||
throw typeNumber + " must have a value between 0-255";
|
||||
|
||||
return { type: typeNumber, value: value};
|
||||
return {type: typeNumber, value: value};
|
||||
}
|
||||
}
|
||||
};
|
||||
// Allowed: Label
|
||||
var parseLabel = function(input) {
|
||||
|
||||
var parseLabel = function (input) {
|
||||
return regexLabel.exec(input) ? input : undefined;
|
||||
};
|
||||
var getValue = function(input) {
|
||||
switch(input.slice(0,1)) {
|
||||
|
||||
var getValue = function (input) {
|
||||
switch (input.slice(0, 1)) {
|
||||
case '[': // [number] or [register]
|
||||
var address = input.slice(1,input.length-1);
|
||||
var address = input.slice(1, input.length - 1);
|
||||
return parseRegOrNumber(address, "regaddress", "address");
|
||||
case '"': // "String"
|
||||
var text = input.slice(1,input.length-1);
|
||||
var text = input.slice(1, input.length - 1);
|
||||
var chars = [];
|
||||
|
||||
for (var i = 0, l = text.length; i < l; i++) {
|
||||
chars.push(text.charCodeAt(i));
|
||||
}
|
||||
|
||||
return { type: "numbers", value: chars };
|
||||
return {type: "numbers", value: chars};
|
||||
case "'": // 'C'
|
||||
var character = input.slice(1,input.length-1);
|
||||
var character = input.slice(1, input.length - 1);
|
||||
if (character.length > 1)
|
||||
throw "Only one character is allowed. Use String instead";
|
||||
|
||||
return { type: "number", value: character.charCodeAt(0) };
|
||||
return {type: "number", value: character.charCodeAt(0)};
|
||||
default: // REGISTER, NUMBER or LABEL
|
||||
return parseRegOrNumber(input, "register", "number");
|
||||
}
|
||||
};
|
||||
var addLabel = function(label) {
|
||||
|
||||
var addLabel = function (label) {
|
||||
var upperLabel = label.toUpperCase();
|
||||
if (upperLabel in normalizedLabels)
|
||||
throw "Duplicate label: " + label;
|
||||
|
@ -174,14 +178,14 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
labels[label] = code.length;
|
||||
};
|
||||
|
||||
var checkNoExtraArg= function(instr, arg) {
|
||||
if (arg !== undefined) {
|
||||
throw instr+": too many arguments";
|
||||
}
|
||||
};
|
||||
|
||||
for(var i = 0, l = lines.length; i < l; i++) {
|
||||
var checkNoExtraArg = function (instr, arg) {
|
||||
if (arg !== undefined) {
|
||||
throw instr + ": too many arguments";
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0, l = lines.length; i < l; i++) {
|
||||
try {
|
||||
var match = regex.exec(lines[i]);
|
||||
if (match[1] !== undefined || match[2] !== undefined) {
|
||||
|
@ -199,7 +203,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
mapping[code.length] = i;
|
||||
}
|
||||
|
||||
switch(instr) {
|
||||
switch (instr) {
|
||||
case 'DB':
|
||||
p1 = getValue(match[op1_group]);
|
||||
|
||||
|
@ -213,16 +217,16 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
throw "DB does not support this operand";
|
||||
|
||||
break;
|
||||
case 'HLT':
|
||||
checkNoExtraArg('HLT',match[op1_group]);
|
||||
opCode=opcodes.NONE;
|
||||
code.push(opCode);
|
||||
break;
|
||||
|
||||
case 'HLT':
|
||||
checkNoExtraArg('HLT', match[op1_group]);
|
||||
opCode = opcodes.NONE;
|
||||
code.push(opCode);
|
||||
break;
|
||||
|
||||
case 'MOV':
|
||||
p1 = getValue(match[op1_group]);
|
||||
p2 = getValue(match[op2_group]);
|
||||
|
||||
|
||||
if (p1.type === "register" && p2.type === "register")
|
||||
opCode = opcodes.MOV_REG_TO_REG;
|
||||
else if (p1.type === "register" && p2.type === "address")
|
||||
|
@ -280,7 +284,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'INC':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg('INC',match[op2_group]);
|
||||
checkNoExtraArg('INC', match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.INC_REG;
|
||||
|
@ -292,7 +296,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'DEC':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg('DEC',match[op2_group]);
|
||||
checkNoExtraArg('DEC', match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.DEC_REG;
|
||||
|
@ -321,7 +325,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'JMP':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg('JMP',match[op2_group]);
|
||||
checkNoExtraArg('JMP', match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JMP_REGADDRESS;
|
||||
|
@ -332,9 +336,11 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JC':case 'JB':case 'JNAE':
|
||||
case 'JC':
|
||||
case 'JB':
|
||||
case 'JNAE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JC_REGADDRESS;
|
||||
|
@ -345,9 +351,11 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JNC':case 'JNB':case 'JAE':
|
||||
case 'JNC':
|
||||
case 'JNB':
|
||||
case 'JAE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JNC_REGADDRESS;
|
||||
|
@ -358,9 +366,10 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JZ': case 'JE':
|
||||
case 'JZ':
|
||||
case 'JE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JZ_REGADDRESS;
|
||||
|
@ -371,9 +380,10 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JNZ': case 'JNE':
|
||||
case 'JNZ':
|
||||
case 'JNE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JNZ_REGADDRESS;
|
||||
|
@ -384,9 +394,10 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JA': case 'JNBE':
|
||||
case 'JA':
|
||||
case 'JNBE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JA_REGADDRESS;
|
||||
|
@ -397,9 +408,10 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JNA': case 'JBE':
|
||||
case 'JNA':
|
||||
case 'JBE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JNA_REGADDRESS;
|
||||
|
@ -412,7 +424,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'PUSH':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.PUSH_REG;
|
||||
|
@ -429,7 +441,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'POP':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.POP_REG;
|
||||
|
@ -440,7 +452,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'CALL':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.CALL_REGADDRESS;
|
||||
|
@ -452,16 +464,16 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'RET':
|
||||
checkNoExtraArg(instr,match[op1_group]);
|
||||
checkNoExtraArg(instr, match[op1_group]);
|
||||
|
||||
opCode = opcodes.RET;
|
||||
|
||||
code.push(opCode);
|
||||
break;
|
||||
|
||||
case 'MUL':
|
||||
case 'MUL':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.MUL_REG;
|
||||
|
@ -478,7 +490,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'DIV':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.DIV_REG;
|
||||
|
@ -546,7 +558,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
break;
|
||||
case 'NOT':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.NOT_REG;
|
||||
|
@ -555,7 +567,8 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'SHL':case 'SAL':
|
||||
case 'SHL':
|
||||
case 'SAL':
|
||||
p1 = getValue(match[op1_group]);
|
||||
p2 = getValue(match[op2_group]);
|
||||
|
||||
|
@ -572,7 +585,8 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
code.push(opCode, p1.value, p2.value);
|
||||
break;
|
||||
case 'SHR': case 'SAR':
|
||||
case 'SHR':
|
||||
case 'SAR':
|
||||
p1 = getValue(match[op1_group]);
|
||||
p2 = getValue(match[op2_group]);
|
||||
|
||||
|
@ -596,31 +610,32 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
} else {
|
||||
// Check if line starts with a comment otherwise the line contains an error and can not be parsed
|
||||
var line = lines[i].trim();
|
||||
if (line !== "" && line.slice(0,1) !== ";") {
|
||||
if (line !== "" && line.slice(0, 1) !== ";") {
|
||||
throw "Syntax error";
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
throw { error: e, line: i};
|
||||
} catch (e) {
|
||||
throw {error: e, line: i};
|
||||
}
|
||||
}
|
||||
|
||||
// Replace label
|
||||
for(i = 0, l = code.length; i < l; i++) {
|
||||
for (i = 0, l = code.length; i < l; i++) {
|
||||
if (!angular.isNumber(code[i])) {
|
||||
if (code[i] in labels) {
|
||||
code[i] = labels[code[i]];
|
||||
} else {
|
||||
|
||||
throw { error: "Undefined label: " + code[i] };
|
||||
throw {error: "Undefined label: " + code[i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { code: code, mapping: mapping, labels: labels };
|
||||
return {code: code, mapping: mapping, labels: labels};
|
||||
}
|
||||
};
|
||||
}]);;app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
||||
}]);
|
||||
;app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
||||
var cpu = {
|
||||
step: function() {
|
||||
var self = this;
|
||||
|
@ -637,20 +652,24 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
return reg;
|
||||
}
|
||||
};
|
||||
|
||||
var checkGPR_SP = function(reg) {
|
||||
if (reg < 0 || reg >= 1+self.gpr.length) {
|
||||
if (reg < 0 || reg >= 1 + self.gpr.length) {
|
||||
throw "Invalid register: " + reg;
|
||||
} else {
|
||||
return reg;
|
||||
}
|
||||
};
|
||||
|
||||
var setGPR_SP = function(reg,value)
|
||||
{
|
||||
if(reg >= 0 && reg <self.gpr.length) {
|
||||
if(reg >= 0 && reg < self.gpr.length) {
|
||||
self.gpr[reg] = value;
|
||||
} else if(reg == self.gpr.length) {
|
||||
self.sp=value;
|
||||
if (self.sp < self.minSP) { // Not likely to happen, since we always get here after checkOpertion().
|
||||
self.sp = value;
|
||||
|
||||
// Not likely to happen, since we always get here after checkOpertion().
|
||||
if (self.sp < self.minSP) {
|
||||
throw "Stack overflow";
|
||||
} else if (self.sp > self.maxSP) {
|
||||
throw "Stack underflow";
|
||||
|
@ -659,9 +678,10 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
throw "Invalid register: " + reg;
|
||||
}
|
||||
};
|
||||
|
||||
var getGPR_SP = function(reg)
|
||||
{
|
||||
if(reg >= 0 && reg <self.gpr.length) {
|
||||
if(reg >= 0 && reg < self.gpr.length) {
|
||||
return self.gpr[reg];
|
||||
} else if(reg == self.gpr.length) {
|
||||
return self.sp;
|
||||
|
@ -669,7 +689,8 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
throw "Invalid register: " + reg;
|
||||
}
|
||||
};
|
||||
var indirectRegisterAddress=function(value) {
|
||||
|
||||
var indirectRegisterAddress = function(value) {
|
||||
var reg = value % 8;
|
||||
|
||||
var base;
|
||||
|
@ -680,12 +701,13 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
}
|
||||
|
||||
var offset = Math.floor(value / 8);
|
||||
if ( offset>15 ) {
|
||||
if ( offset > 15 ) {
|
||||
offset = offset - 32;
|
||||
}
|
||||
|
||||
return base+offset;
|
||||
};
|
||||
|
||||
var checkOperation = function(value) {
|
||||
self.zero = false;
|
||||
self.carry = false;
|
||||
|
@ -702,6 +724,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
return value;
|
||||
};
|
||||
|
||||
var jump = function(newIP) {
|
||||
if (newIP < 0 || newIP >= memory.data.length) {
|
||||
throw "IP outside memory";
|
||||
|
@ -709,12 +732,14 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
self.ip = newIP;
|
||||
}
|
||||
};
|
||||
|
||||
var push = function(value) {
|
||||
memory.store(self.sp--, value);
|
||||
if (self.sp < self.minSP) {
|
||||
throw "Stack overflow";
|
||||
}
|
||||
};
|
||||
|
||||
var pop = function() {
|
||||
var value = memory.load(++self.sp);
|
||||
if (self.sp > self.maxSP) {
|
||||
|
@ -723,6 +748,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
return value;
|
||||
};
|
||||
|
||||
var division = function(divisor) {
|
||||
if (divisor === 0) {
|
||||
throw "Division by 0";
|
||||
|
@ -1203,11 +1229,12 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
cpu.reset();
|
||||
return cpu;
|
||||
}]);;app.service('memory', [function() {
|
||||
}]);
|
||||
;app.service('memory', [function () {
|
||||
var memory = {
|
||||
data: Array(256),
|
||||
lastAccess: -1,
|
||||
load: function(address) {
|
||||
load: function (address) {
|
||||
var self = this;
|
||||
|
||||
if (address < 0 || address >= self.data.length) {
|
||||
|
@ -1217,7 +1244,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
self.lastAccess = address;
|
||||
return self.data[address];
|
||||
},
|
||||
store: function(address, value) {
|
||||
store: function (address, value) {
|
||||
var self = this;
|
||||
|
||||
if (address < 0 || address >= self.data.length) {
|
||||
|
@ -1227,7 +1254,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
self.lastAccess = address;
|
||||
self.data[address] = value;
|
||||
},
|
||||
reset: function() {
|
||||
reset: function () {
|
||||
var self = this;
|
||||
|
||||
self.lastAccess = -1;
|
||||
|
@ -1239,7 +1266,8 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
|
||||
memory.reset();
|
||||
return memory;
|
||||
}]);;app.service('opcodes', [function() {
|
||||
}]);
|
||||
;app.service('opcodes', [function() {
|
||||
var opcodes = {
|
||||
NONE: 0,
|
||||
MOV_REG_TO_REG: 1,
|
||||
|
@ -1318,7 +1346,8 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
};
|
||||
|
||||
return opcodes;
|
||||
}]);;app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'assembler', function($document, $scope, $timeout, cpu, memory, assembler) {
|
||||
}]);
|
||||
;app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'assembler', function ($document, $scope, $timeout, cpu, memory, assembler) {
|
||||
$scope.memory = memory;
|
||||
$scope.cpu = cpu;
|
||||
$scope.error = '';
|
||||
|
@ -1329,20 +1358,23 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
$scope.displayB = false;
|
||||
$scope.displayC = false;
|
||||
$scope.displayD = false;
|
||||
$scope.speeds = [{speed:1, desc:"1 HZ"}, {speed:4, desc:"4 HZ"}, {speed:8, desc:"8 HZ"}, {speed:16, desc:"16 HZ"}];
|
||||
$scope.speeds = [{speed: 1, desc: "1 HZ"},
|
||||
{speed: 4, desc: "4 HZ"},
|
||||
{speed: 8, desc: "8 HZ"},
|
||||
{speed: 16, desc: "16 HZ"}];
|
||||
$scope.speed = 4;
|
||||
$scope.outputStartIndex = 232;
|
||||
|
||||
$scope.code = "; Simple example\n; Writes Hello World to the output\n\n JMP start\nhello: DB \"Hello World!\" ; Variable\n DB 0 ; String terminator\n\nstart:\n MOV C, hello ; Point to var \n MOV D, 232 ; Point to output\n CALL print\n HLT ; Stop execution\n\nprint: ; print(C:*from, D:*to)\n PUSH A\n PUSH B\n MOV B, 0\n.loop:\n MOV A, [C] ; Get char from var\n MOV [D], A ; Write to output\n INC C\n INC D \n CMP B, [C] ; Check if end\n JNZ .loop ; jump if not\n\n POP B\n POP A\n RET";
|
||||
|
||||
$scope.reset = function() {
|
||||
$scope.reset = function () {
|
||||
cpu.reset();
|
||||
memory.reset();
|
||||
$scope.error = '';
|
||||
$scope.selectedLine = -1;
|
||||
};
|
||||
|
||||
$scope.executeStep = function() {
|
||||
$scope.executeStep = function () {
|
||||
if (!$scope.checkPrgrmLoaded()) {
|
||||
$scope.assemble();
|
||||
}
|
||||
|
@ -1364,13 +1396,13 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
};
|
||||
|
||||
var runner;
|
||||
$scope.run = function() {
|
||||
$scope.run = function () {
|
||||
if (!$scope.checkPrgrmLoaded()) {
|
||||
$scope.assemble();
|
||||
}
|
||||
|
||||
$scope.isRunning = true;
|
||||
runner = $timeout(function() {
|
||||
runner = $timeout(function () {
|
||||
if ($scope.executeStep() === true) {
|
||||
$scope.run();
|
||||
} else {
|
||||
|
@ -1379,12 +1411,12 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
}, 1000 / $scope.speed);
|
||||
};
|
||||
|
||||
$scope.stop = function() {
|
||||
$scope.stop = function () {
|
||||
$timeout.cancel(runner);
|
||||
$scope.isRunning = false;
|
||||
};
|
||||
|
||||
$scope.checkPrgrmLoaded = function() {
|
||||
$scope.checkPrgrmLoaded = function () {
|
||||
for (var i = 0, l = memory.data.length; i < l; i++) {
|
||||
if (memory.data[i] !== 0) {
|
||||
return true;
|
||||
|
@ -1394,7 +1426,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
return false;
|
||||
};
|
||||
|
||||
$scope.getChar = function(value) {
|
||||
$scope.getChar = function (value) {
|
||||
var text = String.fromCharCode(value);
|
||||
|
||||
if (text.trim() === '') {
|
||||
|
@ -1404,14 +1436,14 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
}
|
||||
};
|
||||
|
||||
$scope.assemble = function() {
|
||||
$scope.assemble = function () {
|
||||
try {
|
||||
$scope.reset();
|
||||
|
||||
var assembly = assembler.go($scope.code);
|
||||
$scope.mapping = assembly.mapping;
|
||||
var binary = assembly.code;
|
||||
$scope.labels = assembly.labels;
|
||||
$scope.labels = assembly.labels;
|
||||
|
||||
if (binary.length > memory.data.length)
|
||||
throw "Binary code does not fit into the memory. Max " + memory.data.length + " bytes are allowed";
|
||||
|
@ -1429,19 +1461,19 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
}
|
||||
};
|
||||
|
||||
$scope.jumpToLine = function(index) {
|
||||
$scope.jumpToLine = function (index) {
|
||||
$document[0].getElementById('sourceCode').scrollIntoView();
|
||||
$scope.selectedLine = $scope.mapping[index];
|
||||
};
|
||||
|
||||
|
||||
$scope.isInstruction = function(index) {
|
||||
$scope.isInstruction = function (index) {
|
||||
return $scope.mapping !== undefined &&
|
||||
$scope.mapping[index] !== undefined &&
|
||||
$scope.displayInstr;
|
||||
$scope.mapping[index] !== undefined &&
|
||||
$scope.displayInstr;
|
||||
};
|
||||
|
||||
$scope.getMemoryCellCss = function(index) {
|
||||
$scope.getMemoryCellCss = function (index) {
|
||||
if (index >= $scope.outputStartIndex) {
|
||||
return 'output-bg';
|
||||
} else if ($scope.isInstruction(index)) {
|
||||
|
@ -1453,7 +1485,7 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
}
|
||||
};
|
||||
|
||||
$scope.getMemoryInnerCellCss = function(index) {
|
||||
$scope.getMemoryInnerCellCss = function (index) {
|
||||
if (index === cpu.ip) {
|
||||
return 'marker marker-ip';
|
||||
} else if (index === cpu.sp) {
|
||||
|
@ -1470,11 +1502,13 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
return '';
|
||||
}
|
||||
};
|
||||
}]);;app.filter('flag', function() {
|
||||
}]);
|
||||
;app.filter('flag', function() {
|
||||
return function(input) {
|
||||
return input.toString().toUpperCase();
|
||||
};
|
||||
});;app.filter('number', function() {
|
||||
});
|
||||
;app.filter('number', function() {
|
||||
return function(input, isHex) {
|
||||
if (isHex) {
|
||||
var hex = input.toString(16).toUpperCase();
|
||||
|
@ -1483,28 +1517,29 @@ var app = angular.module('ASMSimulator', []);;app.service('assembler', ['opcodes
|
|||
return input.toString(10);
|
||||
}
|
||||
};
|
||||
});;// Source: http://lostsource.com/2012/11/30/selecting-textarea-line.html
|
||||
app.directive('selectLine', [function() {
|
||||
});
|
||||
;// Source: http://lostsource.com/2012/11/30/selecting-textarea-line.html
|
||||
app.directive('selectLine', [function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs, controller) {
|
||||
scope.$watch('selectedLine', function() {
|
||||
link: function (scope, element, attrs, controller) {
|
||||
scope.$watch('selectedLine', function () {
|
||||
if (scope.selectedLine >= 0) {
|
||||
var lines = element[0].value.split("\n");
|
||||
|
||||
// Calculate start/end
|
||||
var startPos = 0;
|
||||
for(var x = 0; x < lines.length; x++) {
|
||||
if(x == scope.selectedLine) {
|
||||
for (var x = 0; x < lines.length; x++) {
|
||||
if (x == scope.selectedLine) {
|
||||
break;
|
||||
}
|
||||
startPos += (lines[x].length+1);
|
||||
startPos += (lines[x].length + 1);
|
||||
}
|
||||
|
||||
var endPos = lines[scope.selectedLine].length+startPos;
|
||||
var endPos = lines[scope.selectedLine].length + startPos;
|
||||
|
||||
// Chrome / Firefox
|
||||
if(typeof(element[0].selectionStart) != "undefined") {
|
||||
if (typeof(element[0].selectionStart) != "undefined") {
|
||||
element[0].focus();
|
||||
element[0].selectionStart = startPos;
|
||||
element[0].selectionEnd = endPos;
|
||||
|
@ -1524,15 +1559,17 @@ app.directive('selectLine', [function() {
|
|||
});
|
||||
}
|
||||
};
|
||||
}]);;app.filter('startFrom', function() {
|
||||
}]);
|
||||
;app.filter('startFrom', function() {
|
||||
return function(input, start) {
|
||||
start = +start; //parse to int
|
||||
return input.slice(start);
|
||||
};
|
||||
});;app.directive('tabSupport', [function() {
|
||||
});
|
||||
;app.directive('tabSupport', [function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs, controller) {
|
||||
link: function (scope, element, attrs, controller) {
|
||||
element.bind("keydown", function (e) {
|
||||
if (e.keyCode === 9) {
|
||||
var val = this.value;
|
||||
|
@ -1548,4 +1585,4 @@ app.directive('selectLine', [function() {
|
|||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -59,4 +59,4 @@
|
|||
|
||||
.marker-d {
|
||||
background-color: #E81F1F;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,4 +166,4 @@
|
|||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
|
||||
<script src="assets/asmsimulator.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -266,4 +266,4 @@ HLT
|
|||
<p><small>by Marco Schweighauser (2015) | MIT License</small></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -1 +1 @@
|
|||
var app = angular.module('ASMSimulator', []);
|
||||
var app = angular.module('ASMSimulator', []);
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
app.service('assembler', ['opcodes', function(opcodes) {
|
||||
app.service('assembler', ['opcodes', function (opcodes) {
|
||||
return {
|
||||
go: function(input) {
|
||||
var self = this;
|
||||
|
||||
go: function (input) {
|
||||
// Use https://www.debuggex.com/
|
||||
// Matches: "label: INSTRUCTION (["')OPERAND1(]"'), (["')OPERAND2(]"')
|
||||
// GROUPS: 1 2 3 7
|
||||
var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,4})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?/;
|
||||
var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,4})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?/;
|
||||
|
||||
// Regex group indexes for operands
|
||||
var op1_group = 3;
|
||||
var op2_group = 7;
|
||||
|
||||
var op1_group=3; // group indexes for operands
|
||||
var op2_group=7;
|
||||
// MATCHES: "(+|-)INTEGER"
|
||||
var regexNum = /^[-+]?[0-9]+$/;
|
||||
// MATCHES: "(.L)abel"
|
||||
var regexLabel = /^[.A-Za-z]\w*$/;
|
||||
|
||||
// Contains the program code & data generated by the assembler
|
||||
var code = [];
|
||||
// Contains the mapping from instructions to assembler line
|
||||
|
@ -24,26 +23,28 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
// Hash of uppercase labels used to detect duplicates
|
||||
var normalizedLabels = {};
|
||||
|
||||
var lines = input.split('\n'); // Split text into code lines
|
||||
// Split text into code lines
|
||||
var lines = input.split('\n');
|
||||
|
||||
// Allowed formats: 200, 200d, 0xA4, 0o48, 101b
|
||||
var parseNumber = function(input) {
|
||||
if (input.slice(0,2) === "0x") {
|
||||
var parseNumber = function (input) {
|
||||
if (input.slice(0, 2) === "0x") {
|
||||
return parseInt(input.slice(2), 16);
|
||||
} else if (input.slice(0,2) === "0o") {
|
||||
} else if (input.slice(0, 2) === "0o") {
|
||||
return parseInt(input.slice(2), 8);
|
||||
} else if (input.slice(input.length-1) === "b") {
|
||||
return parseInt(input.slice(0, input.length-1), 2);
|
||||
} else if (input.slice(input.length-1) === "d") {
|
||||
return parseInt(input.slice(0, input.length-1), 10);
|
||||
} else if (input.slice(input.length - 1) === "b") {
|
||||
return parseInt(input.slice(0, input.length - 1), 2);
|
||||
} else if (input.slice(input.length - 1) === "d") {
|
||||
return parseInt(input.slice(0, input.length - 1), 10);
|
||||
} else if (regexNum.exec(input)) {
|
||||
return parseInt(input, 10);
|
||||
} else {
|
||||
throw "Invalid number format";
|
||||
}
|
||||
};
|
||||
|
||||
// Allowed registers: A, B, C, D, SP
|
||||
var parseRegister = function(input) {
|
||||
var parseRegister = function (input) {
|
||||
input = input.toUpperCase();
|
||||
|
||||
if (input === 'A') {
|
||||
|
@ -55,75 +56,75 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
} else if (input === 'D') {
|
||||
return 3;
|
||||
} else if (input === 'SP') {
|
||||
return 4;
|
||||
} else {
|
||||
return 4;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
var parseOffsetAddressing=function(input) {
|
||||
input = input.toUpperCase();
|
||||
var m = 0;
|
||||
var base = 0;
|
||||
|
||||
if (input[0] === 'A') {
|
||||
base = 0;
|
||||
} else if (input[0] === 'B') {
|
||||
base = 1;
|
||||
} else if (input[0] === 'C') {
|
||||
base = 2;
|
||||
} else if (input[0] === 'D') {
|
||||
base = 3;
|
||||
} else if( input.slice(0,2) === "SP") {
|
||||
base = 4;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
var offset_start = 1;
|
||||
if (base === 4) {
|
||||
offset_start = 2;
|
||||
}
|
||||
|
||||
if (input[offset_start] === '-') {
|
||||
m = -1;
|
||||
} else if (input[offset_start] === '+') {
|
||||
m = 1;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var offset = m*parseInt(input.slice(offset_start+1),10);
|
||||
|
||||
if (offset < -16 || offset > 15)
|
||||
throw "offset must be a value between -16...+15";
|
||||
|
||||
if (offset < 0) {
|
||||
offset=32+offset; // two's complement representation in 5-bit
|
||||
}
|
||||
|
||||
return offset*8+base; // shift offset 3 bits right and add code for register
|
||||
};
|
||||
|
||||
|
||||
var parseOffsetAddressing = function (input) {
|
||||
input = input.toUpperCase();
|
||||
var m = 0;
|
||||
var base = 0;
|
||||
|
||||
if (input[0] === 'A') {
|
||||
base = 0;
|
||||
} else if (input[0] === 'B') {
|
||||
base = 1;
|
||||
} else if (input[0] === 'C') {
|
||||
base = 2;
|
||||
} else if (input[0] === 'D') {
|
||||
base = 3;
|
||||
} else if (input.slice(0, 2) === "SP") {
|
||||
base = 4;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
var offset_start = 1;
|
||||
if (base === 4) {
|
||||
offset_start = 2;
|
||||
}
|
||||
|
||||
if (input[offset_start] === '-') {
|
||||
m = -1;
|
||||
} else if (input[offset_start] === '+') {
|
||||
m = 1;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var offset = m * parseInt(input.slice(offset_start + 1), 10);
|
||||
|
||||
if (offset < -16 || offset > 15)
|
||||
throw "offset must be a value between -16...+15";
|
||||
|
||||
if (offset < 0) {
|
||||
offset = 32 + offset; // two's complement representation in 5-bit
|
||||
}
|
||||
|
||||
return offset * 8 + base; // shift offset 3 bits right and add code for register
|
||||
};
|
||||
|
||||
// Allowed: Register, Label or Number; SP+/-Number is allowed for 'regaddress' type
|
||||
var parseRegOrNumber = function(input, typeReg, typeNumber) {
|
||||
var parseRegOrNumber = function (input, typeReg, typeNumber) {
|
||||
var register = parseRegister(input);
|
||||
|
||||
if (register !== undefined) {
|
||||
return { type: typeReg, value: register};
|
||||
return {type: typeReg, value: register};
|
||||
} else {
|
||||
var label = parseLabel(input);
|
||||
if (label !== undefined) {
|
||||
return { type: typeNumber, value: label};
|
||||
return {type: typeNumber, value: label};
|
||||
} else {
|
||||
if (typeReg === "regaddress") {
|
||||
|
||||
register = parseOffsetAddressing(input);
|
||||
|
||||
if (register !== undefined) {
|
||||
return { type: typeReg, value: register};
|
||||
}
|
||||
}
|
||||
|
||||
if (typeReg === "regaddress") {
|
||||
|
||||
register = parseOffsetAddressing(input);
|
||||
|
||||
if (register !== undefined) {
|
||||
return {type: typeReg, value: register};
|
||||
}
|
||||
}
|
||||
|
||||
var value = parseNumber(input);
|
||||
|
||||
if (isNaN(value)) {
|
||||
|
@ -132,39 +133,41 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
else if (value < 0 || value > 255)
|
||||
throw typeNumber + " must have a value between 0-255";
|
||||
|
||||
return { type: typeNumber, value: value};
|
||||
return {type: typeNumber, value: value};
|
||||
}
|
||||
}
|
||||
};
|
||||
// Allowed: Label
|
||||
var parseLabel = function(input) {
|
||||
|
||||
var parseLabel = function (input) {
|
||||
return regexLabel.exec(input) ? input : undefined;
|
||||
};
|
||||
var getValue = function(input) {
|
||||
switch(input.slice(0,1)) {
|
||||
|
||||
var getValue = function (input) {
|
||||
switch (input.slice(0, 1)) {
|
||||
case '[': // [number] or [register]
|
||||
var address = input.slice(1,input.length-1);
|
||||
var address = input.slice(1, input.length - 1);
|
||||
return parseRegOrNumber(address, "regaddress", "address");
|
||||
case '"': // "String"
|
||||
var text = input.slice(1,input.length-1);
|
||||
var text = input.slice(1, input.length - 1);
|
||||
var chars = [];
|
||||
|
||||
for (var i = 0, l = text.length; i < l; i++) {
|
||||
chars.push(text.charCodeAt(i));
|
||||
}
|
||||
|
||||
return { type: "numbers", value: chars };
|
||||
return {type: "numbers", value: chars};
|
||||
case "'": // 'C'
|
||||
var character = input.slice(1,input.length-1);
|
||||
var character = input.slice(1, input.length - 1);
|
||||
if (character.length > 1)
|
||||
throw "Only one character is allowed. Use String instead";
|
||||
|
||||
return { type: "number", value: character.charCodeAt(0) };
|
||||
return {type: "number", value: character.charCodeAt(0)};
|
||||
default: // REGISTER, NUMBER or LABEL
|
||||
return parseRegOrNumber(input, "register", "number");
|
||||
}
|
||||
};
|
||||
var addLabel = function(label) {
|
||||
|
||||
var addLabel = function (label) {
|
||||
var upperLabel = label.toUpperCase();
|
||||
if (upperLabel in normalizedLabels)
|
||||
throw "Duplicate label: " + label;
|
||||
|
@ -174,14 +177,14 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
labels[label] = code.length;
|
||||
};
|
||||
|
||||
var checkNoExtraArg= function(instr, arg) {
|
||||
if (arg !== undefined) {
|
||||
throw instr+": too many arguments";
|
||||
}
|
||||
};
|
||||
|
||||
for(var i = 0, l = lines.length; i < l; i++) {
|
||||
var checkNoExtraArg = function (instr, arg) {
|
||||
if (arg !== undefined) {
|
||||
throw instr + ": too many arguments";
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0, l = lines.length; i < l; i++) {
|
||||
try {
|
||||
var match = regex.exec(lines[i]);
|
||||
if (match[1] !== undefined || match[2] !== undefined) {
|
||||
|
@ -199,7 +202,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
mapping[code.length] = i;
|
||||
}
|
||||
|
||||
switch(instr) {
|
||||
switch (instr) {
|
||||
case 'DB':
|
||||
p1 = getValue(match[op1_group]);
|
||||
|
||||
|
@ -213,16 +216,16 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
throw "DB does not support this operand";
|
||||
|
||||
break;
|
||||
case 'HLT':
|
||||
checkNoExtraArg('HLT',match[op1_group]);
|
||||
opCode=opcodes.NONE;
|
||||
code.push(opCode);
|
||||
break;
|
||||
|
||||
case 'HLT':
|
||||
checkNoExtraArg('HLT', match[op1_group]);
|
||||
opCode = opcodes.NONE;
|
||||
code.push(opCode);
|
||||
break;
|
||||
|
||||
case 'MOV':
|
||||
p1 = getValue(match[op1_group]);
|
||||
p2 = getValue(match[op2_group]);
|
||||
|
||||
|
||||
if (p1.type === "register" && p2.type === "register")
|
||||
opCode = opcodes.MOV_REG_TO_REG;
|
||||
else if (p1.type === "register" && p2.type === "address")
|
||||
|
@ -280,7 +283,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'INC':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg('INC',match[op2_group]);
|
||||
checkNoExtraArg('INC', match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.INC_REG;
|
||||
|
@ -292,7 +295,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'DEC':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg('DEC',match[op2_group]);
|
||||
checkNoExtraArg('DEC', match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.DEC_REG;
|
||||
|
@ -321,7 +324,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'JMP':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg('JMP',match[op2_group]);
|
||||
checkNoExtraArg('JMP', match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JMP_REGADDRESS;
|
||||
|
@ -332,9 +335,11 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JC':case 'JB':case 'JNAE':
|
||||
case 'JC':
|
||||
case 'JB':
|
||||
case 'JNAE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JC_REGADDRESS;
|
||||
|
@ -345,9 +350,11 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JNC':case 'JNB':case 'JAE':
|
||||
case 'JNC':
|
||||
case 'JNB':
|
||||
case 'JAE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JNC_REGADDRESS;
|
||||
|
@ -358,9 +365,10 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JZ': case 'JE':
|
||||
case 'JZ':
|
||||
case 'JE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JZ_REGADDRESS;
|
||||
|
@ -371,9 +379,10 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JNZ': case 'JNE':
|
||||
case 'JNZ':
|
||||
case 'JNE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JNZ_REGADDRESS;
|
||||
|
@ -384,9 +393,10 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JA': case 'JNBE':
|
||||
case 'JA':
|
||||
case 'JNBE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JA_REGADDRESS;
|
||||
|
@ -397,9 +407,10 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'JNA': case 'JBE':
|
||||
case 'JNA':
|
||||
case 'JBE':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.JNA_REGADDRESS;
|
||||
|
@ -412,7 +423,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'PUSH':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.PUSH_REG;
|
||||
|
@ -429,7 +440,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'POP':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.POP_REG;
|
||||
|
@ -440,7 +451,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'CALL':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.CALL_REGADDRESS;
|
||||
|
@ -452,16 +463,16 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'RET':
|
||||
checkNoExtraArg(instr,match[op1_group]);
|
||||
checkNoExtraArg(instr, match[op1_group]);
|
||||
|
||||
opCode = opcodes.RET;
|
||||
|
||||
code.push(opCode);
|
||||
break;
|
||||
|
||||
case 'MUL':
|
||||
case 'MUL':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.MUL_REG;
|
||||
|
@ -478,7 +489,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'DIV':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.DIV_REG;
|
||||
|
@ -546,7 +557,7 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
break;
|
||||
case 'NOT':
|
||||
p1 = getValue(match[op1_group]);
|
||||
checkNoExtraArg(instr,match[op2_group]);
|
||||
checkNoExtraArg(instr, match[op2_group]);
|
||||
|
||||
if (p1.type === "register")
|
||||
opCode = opcodes.NOT_REG;
|
||||
|
@ -555,7 +566,8 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value);
|
||||
break;
|
||||
case 'SHL':case 'SAL':
|
||||
case 'SHL':
|
||||
case 'SAL':
|
||||
p1 = getValue(match[op1_group]);
|
||||
p2 = getValue(match[op2_group]);
|
||||
|
||||
|
@ -572,7 +584,8 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
|
||||
code.push(opCode, p1.value, p2.value);
|
||||
break;
|
||||
case 'SHR': case 'SAR':
|
||||
case 'SHR':
|
||||
case 'SAR':
|
||||
p1 = getValue(match[op1_group]);
|
||||
p2 = getValue(match[op2_group]);
|
||||
|
||||
|
@ -596,28 +609,28 @@ app.service('assembler', ['opcodes', function(opcodes) {
|
|||
} else {
|
||||
// Check if line starts with a comment otherwise the line contains an error and can not be parsed
|
||||
var line = lines[i].trim();
|
||||
if (line !== "" && line.slice(0,1) !== ";") {
|
||||
if (line !== "" && line.slice(0, 1) !== ";") {
|
||||
throw "Syntax error";
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
throw { error: e, line: i};
|
||||
} catch (e) {
|
||||
throw {error: e, line: i};
|
||||
}
|
||||
}
|
||||
|
||||
// Replace label
|
||||
for(i = 0, l = code.length; i < l; i++) {
|
||||
for (i = 0, l = code.length; i < l; i++) {
|
||||
if (!angular.isNumber(code[i])) {
|
||||
if (code[i] in labels) {
|
||||
code[i] = labels[code[i]];
|
||||
} else {
|
||||
|
||||
throw { error: "Undefined label: " + code[i] };
|
||||
throw {error: "Undefined label: " + code[i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { code: code, mapping: mapping, labels: labels };
|
||||
return {code: code, mapping: mapping, labels: labels};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
|
|
@ -15,20 +15,24 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
return reg;
|
||||
}
|
||||
};
|
||||
|
||||
var checkGPR_SP = function(reg) {
|
||||
if (reg < 0 || reg >= 1+self.gpr.length) {
|
||||
if (reg < 0 || reg >= 1 + self.gpr.length) {
|
||||
throw "Invalid register: " + reg;
|
||||
} else {
|
||||
return reg;
|
||||
}
|
||||
};
|
||||
|
||||
var setGPR_SP = function(reg,value)
|
||||
{
|
||||
if(reg >= 0 && reg <self.gpr.length) {
|
||||
if(reg >= 0 && reg < self.gpr.length) {
|
||||
self.gpr[reg] = value;
|
||||
} else if(reg == self.gpr.length) {
|
||||
self.sp=value;
|
||||
if (self.sp < self.minSP) { // Not likely to happen, since we always get here after checkOpertion().
|
||||
self.sp = value;
|
||||
|
||||
// Not likely to happen, since we always get here after checkOpertion().
|
||||
if (self.sp < self.minSP) {
|
||||
throw "Stack overflow";
|
||||
} else if (self.sp > self.maxSP) {
|
||||
throw "Stack underflow";
|
||||
|
@ -37,9 +41,10 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
throw "Invalid register: " + reg;
|
||||
}
|
||||
};
|
||||
|
||||
var getGPR_SP = function(reg)
|
||||
{
|
||||
if(reg >= 0 && reg <self.gpr.length) {
|
||||
if(reg >= 0 && reg < self.gpr.length) {
|
||||
return self.gpr[reg];
|
||||
} else if(reg == self.gpr.length) {
|
||||
return self.sp;
|
||||
|
@ -47,7 +52,8 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
throw "Invalid register: " + reg;
|
||||
}
|
||||
};
|
||||
var indirectRegisterAddress=function(value) {
|
||||
|
||||
var indirectRegisterAddress = function(value) {
|
||||
var reg = value % 8;
|
||||
|
||||
var base;
|
||||
|
@ -58,12 +64,13 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
}
|
||||
|
||||
var offset = Math.floor(value / 8);
|
||||
if ( offset>15 ) {
|
||||
if ( offset > 15 ) {
|
||||
offset = offset - 32;
|
||||
}
|
||||
|
||||
return base+offset;
|
||||
};
|
||||
|
||||
var checkOperation = function(value) {
|
||||
self.zero = false;
|
||||
self.carry = false;
|
||||
|
@ -80,6 +87,7 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
|
||||
return value;
|
||||
};
|
||||
|
||||
var jump = function(newIP) {
|
||||
if (newIP < 0 || newIP >= memory.data.length) {
|
||||
throw "IP outside memory";
|
||||
|
@ -87,12 +95,14 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
self.ip = newIP;
|
||||
}
|
||||
};
|
||||
|
||||
var push = function(value) {
|
||||
memory.store(self.sp--, value);
|
||||
if (self.sp < self.minSP) {
|
||||
throw "Stack overflow";
|
||||
}
|
||||
};
|
||||
|
||||
var pop = function() {
|
||||
var value = memory.load(++self.sp);
|
||||
if (self.sp > self.maxSP) {
|
||||
|
@ -101,6 +111,7 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
|
||||
return value;
|
||||
};
|
||||
|
||||
var division = function(divisor) {
|
||||
if (divisor === 0) {
|
||||
throw "Division by 0";
|
||||
|
@ -581,4 +592,4 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
|
||||
cpu.reset();
|
||||
return cpu;
|
||||
}]);
|
||||
}]);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
app.service('memory', [function() {
|
||||
app.service('memory', [function () {
|
||||
var memory = {
|
||||
data: Array(256),
|
||||
lastAccess: -1,
|
||||
load: function(address) {
|
||||
load: function (address) {
|
||||
var self = this;
|
||||
|
||||
if (address < 0 || address >= self.data.length) {
|
||||
|
@ -12,7 +12,7 @@ app.service('memory', [function() {
|
|||
self.lastAccess = address;
|
||||
return self.data[address];
|
||||
},
|
||||
store: function(address, value) {
|
||||
store: function (address, value) {
|
||||
var self = this;
|
||||
|
||||
if (address < 0 || address >= self.data.length) {
|
||||
|
@ -22,7 +22,7 @@ app.service('memory', [function() {
|
|||
self.lastAccess = address;
|
||||
self.data[address] = value;
|
||||
},
|
||||
reset: function() {
|
||||
reset: function () {
|
||||
var self = this;
|
||||
|
||||
self.lastAccess = -1;
|
||||
|
@ -34,4 +34,4 @@ app.service('memory', [function() {
|
|||
|
||||
memory.reset();
|
||||
return memory;
|
||||
}]);
|
||||
}]);
|
||||
|
|
|
@ -77,4 +77,4 @@ app.service('opcodes', [function() {
|
|||
};
|
||||
|
||||
return opcodes;
|
||||
}]);
|
||||
}]);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'assembler', function($document, $scope, $timeout, cpu, memory, assembler) {
|
||||
app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'assembler', function ($document, $scope, $timeout, cpu, memory, assembler) {
|
||||
$scope.memory = memory;
|
||||
$scope.cpu = cpu;
|
||||
$scope.error = '';
|
||||
|
@ -9,20 +9,23 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
$scope.displayB = false;
|
||||
$scope.displayC = false;
|
||||
$scope.displayD = false;
|
||||
$scope.speeds = [{speed:1, desc:"1 HZ"}, {speed:4, desc:"4 HZ"}, {speed:8, desc:"8 HZ"}, {speed:16, desc:"16 HZ"}];
|
||||
$scope.speeds = [{speed: 1, desc: "1 HZ"},
|
||||
{speed: 4, desc: "4 HZ"},
|
||||
{speed: 8, desc: "8 HZ"},
|
||||
{speed: 16, desc: "16 HZ"}];
|
||||
$scope.speed = 4;
|
||||
$scope.outputStartIndex = 232;
|
||||
|
||||
$scope.code = "; Simple example\n; Writes Hello World to the output\n\n JMP start\nhello: DB \"Hello World!\" ; Variable\n DB 0 ; String terminator\n\nstart:\n MOV C, hello ; Point to var \n MOV D, 232 ; Point to output\n CALL print\n HLT ; Stop execution\n\nprint: ; print(C:*from, D:*to)\n PUSH A\n PUSH B\n MOV B, 0\n.loop:\n MOV A, [C] ; Get char from var\n MOV [D], A ; Write to output\n INC C\n INC D \n CMP B, [C] ; Check if end\n JNZ .loop ; jump if not\n\n POP B\n POP A\n RET";
|
||||
|
||||
$scope.reset = function() {
|
||||
$scope.reset = function () {
|
||||
cpu.reset();
|
||||
memory.reset();
|
||||
$scope.error = '';
|
||||
$scope.selectedLine = -1;
|
||||
};
|
||||
|
||||
$scope.executeStep = function() {
|
||||
$scope.executeStep = function () {
|
||||
if (!$scope.checkPrgrmLoaded()) {
|
||||
$scope.assemble();
|
||||
}
|
||||
|
@ -44,13 +47,13 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
};
|
||||
|
||||
var runner;
|
||||
$scope.run = function() {
|
||||
$scope.run = function () {
|
||||
if (!$scope.checkPrgrmLoaded()) {
|
||||
$scope.assemble();
|
||||
}
|
||||
|
||||
$scope.isRunning = true;
|
||||
runner = $timeout(function() {
|
||||
runner = $timeout(function () {
|
||||
if ($scope.executeStep() === true) {
|
||||
$scope.run();
|
||||
} else {
|
||||
|
@ -59,12 +62,12 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
}, 1000 / $scope.speed);
|
||||
};
|
||||
|
||||
$scope.stop = function() {
|
||||
$scope.stop = function () {
|
||||
$timeout.cancel(runner);
|
||||
$scope.isRunning = false;
|
||||
};
|
||||
|
||||
$scope.checkPrgrmLoaded = function() {
|
||||
$scope.checkPrgrmLoaded = function () {
|
||||
for (var i = 0, l = memory.data.length; i < l; i++) {
|
||||
if (memory.data[i] !== 0) {
|
||||
return true;
|
||||
|
@ -74,7 +77,7 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
return false;
|
||||
};
|
||||
|
||||
$scope.getChar = function(value) {
|
||||
$scope.getChar = function (value) {
|
||||
var text = String.fromCharCode(value);
|
||||
|
||||
if (text.trim() === '') {
|
||||
|
@ -84,14 +87,14 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
}
|
||||
};
|
||||
|
||||
$scope.assemble = function() {
|
||||
$scope.assemble = function () {
|
||||
try {
|
||||
$scope.reset();
|
||||
|
||||
var assembly = assembler.go($scope.code);
|
||||
$scope.mapping = assembly.mapping;
|
||||
var binary = assembly.code;
|
||||
$scope.labels = assembly.labels;
|
||||
$scope.labels = assembly.labels;
|
||||
|
||||
if (binary.length > memory.data.length)
|
||||
throw "Binary code does not fit into the memory. Max " + memory.data.length + " bytes are allowed";
|
||||
|
@ -109,19 +112,19 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
}
|
||||
};
|
||||
|
||||
$scope.jumpToLine = function(index) {
|
||||
$scope.jumpToLine = function (index) {
|
||||
$document[0].getElementById('sourceCode').scrollIntoView();
|
||||
$scope.selectedLine = $scope.mapping[index];
|
||||
};
|
||||
|
||||
|
||||
$scope.isInstruction = function(index) {
|
||||
$scope.isInstruction = function (index) {
|
||||
return $scope.mapping !== undefined &&
|
||||
$scope.mapping[index] !== undefined &&
|
||||
$scope.displayInstr;
|
||||
$scope.mapping[index] !== undefined &&
|
||||
$scope.displayInstr;
|
||||
};
|
||||
|
||||
$scope.getMemoryCellCss = function(index) {
|
||||
$scope.getMemoryCellCss = function (index) {
|
||||
if (index >= $scope.outputStartIndex) {
|
||||
return 'output-bg';
|
||||
} else if ($scope.isInstruction(index)) {
|
||||
|
@ -133,7 +136,7 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
}
|
||||
};
|
||||
|
||||
$scope.getMemoryInnerCellCss = function(index) {
|
||||
$scope.getMemoryInnerCellCss = function (index) {
|
||||
if (index === cpu.ip) {
|
||||
return 'marker marker-ip';
|
||||
} else if (index === cpu.sp) {
|
||||
|
@ -150,4 +153,4 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'ass
|
|||
return '';
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
|
|
@ -2,4 +2,4 @@ app.filter('flag', function() {
|
|||
return function(input) {
|
||||
return input.toString().toUpperCase();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,4 +7,4 @@ app.filter('number', function() {
|
|||
return input.toString(10);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
// Source: http://lostsource.com/2012/11/30/selecting-textarea-line.html
|
||||
app.directive('selectLine', [function() {
|
||||
app.directive('selectLine', [function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs, controller) {
|
||||
scope.$watch('selectedLine', function() {
|
||||
link: function (scope, element, attrs, controller) {
|
||||
scope.$watch('selectedLine', function () {
|
||||
if (scope.selectedLine >= 0) {
|
||||
var lines = element[0].value.split("\n");
|
||||
|
||||
// Calculate start/end
|
||||
var startPos = 0;
|
||||
for(var x = 0; x < lines.length; x++) {
|
||||
if(x == scope.selectedLine) {
|
||||
for (var x = 0; x < lines.length; x++) {
|
||||
if (x == scope.selectedLine) {
|
||||
break;
|
||||
}
|
||||
startPos += (lines[x].length+1);
|
||||
startPos += (lines[x].length + 1);
|
||||
}
|
||||
|
||||
var endPos = lines[scope.selectedLine].length+startPos;
|
||||
var endPos = lines[scope.selectedLine].length + startPos;
|
||||
|
||||
// Chrome / Firefox
|
||||
if(typeof(element[0].selectionStart) != "undefined") {
|
||||
if (typeof(element[0].selectionStart) != "undefined") {
|
||||
element[0].focus();
|
||||
element[0].selectionStart = startPos;
|
||||
element[0].selectionEnd = endPos;
|
||||
|
@ -39,4 +39,4 @@ app.directive('selectLine', [function() {
|
|||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
|
|
@ -3,4 +3,4 @@ app.filter('startFrom', function() {
|
|||
start = +start; //parse to int
|
||||
return input.slice(start);
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
app.directive('tabSupport', [function() {
|
||||
app.directive('tabSupport', [function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs, controller) {
|
||||
link: function (scope, element, attrs, controller) {
|
||||
element.bind("keydown", function (e) {
|
||||
if (e.keyCode === 9) {
|
||||
var val = this.value;
|
||||
|
@ -17,4 +17,4 @@ app.directive('tabSupport', [function() {
|
|||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
|
Loading…
Reference in New Issue