diff --git a/ASCII b/ASCII new file mode 100644 index 0000000..f4df85f --- /dev/null +++ b/ASCII @@ -0,0 +1,133 @@ + +ASCII Table ( 0 - 127 ) + + Decimal Octal Hex Binary Character + ------- ----- --- -------- --------- + 000 000 00 00000000 NUL (Null char.) + 001 001 01 00000001 SOH (Start of Header) + 002 002 02 00000010 STX (Start of Text) + 003 003 03 00000011 ETX (End of Text) + 004 004 04 00000100 EOT (End of Transmission) + 005 005 05 00000101 ENQ (Enquiry) + 006 006 06 00000110 ACK (Acknowledgment) + 007 007 07 00000111 BEL (Bell) + 008 010 08 00001000 BS (Backspace) + 009 011 09 00001001 HT (Horizontal Tab) + 010 012 0A 00001010 LF (Line Feed) + 011 013 0B 00001011 VT (Vertical Tab) + 012 014 0C 00001100 FF (Form Feed) + 013 015 0D 00001101 CR (Carriage Return) + 014 016 0E 00001110 SO (Shift Out) + 015 017 0F 00001111 SI (Shift In) + 016 020 10 00010000 DLE (Data Link Escape) + 017 021 11 00010001 DC1 (XON)(Device Control 1) + 018 022 12 00010010 DC2 (Device Control 2) + 019 023 13 00010011 DC3 (XOFF)(Device Control 3) + 020 024 14 00010100 DC4 (Device Control 4) + 021 025 15 00010101 NAK (Negative Acknowledgement) + 022 026 16 00010110 SYN (Synchronous Idle) + 023 027 17 00010111 ETB (End of Trans. Block) + 024 030 18 00011000 CAN (Cancel) + 025 031 19 00011001 EM (End of Medium) + 026 032 1A 00011010 SUB (Substitute) + 027 033 1B 00011011 ESC (Escape) + 028 034 1C 00011100 FS (File Separator) + 029 035 1D 00011101 GS (Group Separator) + 030 036 1E 00011110 RS (Request to Send)(Record Separator) + 031 037 1F 00011111 US (Unit Separator) + 032 040 20 00100000 SP (Space) + 033 041 21 00100001 ! (exclamation mark) + 034 042 22 00100010 " (double quote) + 035 043 23 00100011 # (number sign) + 036 044 24 00100100 $ (dollar sign) + 037 045 25 00100101 % (percent) + 038 046 26 00100110 & (ampersand) + 039 047 27 00100111 ' (single quote) + 040 050 28 00101000 ( (left opening parenthesis) + 041 051 29 00101001 ) (right closing parenthesis) + 042 052 2A 00101010 * (asterisk) + 043 053 2B 00101011 + (plus) + 044 054 2C 00101100 , (comma) + 045 055 2D 00101101 - (minus or dash) + 046 056 2E 00101110 . (dot) + 047 057 2F 00101111 / (forward slash) + 048 060 30 00110000 0 + 049 061 31 00110001 1 + 050 062 32 00110010 2 + 051 063 33 00110011 3 + 052 064 34 00110100 4 + 053 065 35 00110101 5 + 054 066 36 00110110 6 + 055 067 37 00110111 7 + 056 070 38 00111000 8 + 057 071 39 00111001 9 + 058 072 3A 00111010 : (colon) + 059 073 3B 00111011 ; (semi-colon) + 060 074 3C 00111100 < (less than sign) + 061 075 3D 00111101 = (equal sign) + 062 076 3E 00111110 > (greater than sign) + 063 077 3F 00111111 ? (question mark) + 064 100 40 01000000 @ (AT symbol) + 065 101 41 01000001 A + 066 102 42 01000010 B + 067 103 43 01000011 C + 068 104 44 01000100 D + 069 105 45 01000101 E + 070 106 46 01000110 F + 071 107 47 01000111 G + 072 110 48 01001000 H + 073 111 49 01001001 I + 074 112 4A 01001010 J + 075 113 4B 01001011 K + 076 114 4C 01001100 L + 077 115 4D 01001101 M + 078 116 4E 01001110 N + 079 117 4F 01001111 O + 080 120 50 01010000 P + 081 121 51 01010001 Q + 082 122 52 01010010 R + 083 123 53 01010011 S + 084 124 54 01010100 T + 085 125 55 01010101 U + 086 126 56 01010110 V + 087 127 57 01010111 W + 088 130 58 01011000 X + 089 131 59 01011001 Y + 090 132 5A 01011010 Z + 091 133 5B 01011011 [ (left opening bracket) + 092 134 5C 01011100 \ (back slash) + 093 135 5D 01011101 ] (right closing bracket) + 094 136 5E 01011110 ^ (caret cirumflex) + 095 137 5F 01011111 _ (underscore) + 096 140 60 01100000 ` + 097 141 61 01100001 a + 098 142 62 01100010 b + 099 143 63 01100011 c + 100 144 64 01100100 d + 101 145 65 01100101 e + 102 146 66 01100110 f + 103 147 67 01100111 g + 104 150 68 01101000 h + 105 151 69 01101001 i + 106 152 6A 01101010 j + 107 153 6B 01101011 k + 108 154 6C 01101100 l + 109 155 6D 01101101 m + 110 156 6E 01101110 n + 111 157 6F 01101111 o + 112 160 70 01110000 p + 113 161 71 01110001 q + 114 162 72 01110010 r + 115 163 73 01110011 s + 116 164 74 01110100 t + 117 165 75 01110101 u + 118 166 76 01110110 v + 119 167 77 01110111 w + 120 170 78 01111000 x + 121 171 79 01111001 y + 122 172 7A 01111010 z + 123 173 7B 01111011 { (left opening brace) + 124 174 7C 01111100 | (vertical bar) + 125 175 7D 01111101 } (right closing brace) + 126 176 7E 01111110 ~ (tilde) + 127 177 7F 01111111 DEL (delete) diff --git a/assets/asmsimulator.js b/assets/asmsimulator.js index 4d04f8c..9526ef0 100644 --- a/assets/asmsimulator.js +++ b/assets/asmsimulator.js @@ -248,6 +248,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'ADD': p1 = getValue(match[op1_group]); p2 = getValue(match[op2_group]); @@ -265,6 +266,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'SUB': p1 = getValue(match[op1_group]); p2 = getValue(match[op2_group]); @@ -282,6 +284,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'INC': p1 = getValue(match[op1_group]); checkNoExtraArg('INC', match[op2_group]); @@ -294,6 +297,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'DEC': p1 = getValue(match[op1_group]); checkNoExtraArg('DEC', match[op2_group]); @@ -306,6 +310,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'CMP': p1 = getValue(match[op1_group]); p2 = getValue(match[op2_group]); @@ -323,6 +328,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'JMP': p1 = getValue(match[op1_group]); checkNoExtraArg('JMP', match[op2_group]); @@ -336,6 +342,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'JC': case 'JB': case 'JNAE': @@ -351,6 +358,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'JNC': case 'JNB': case 'JAE': @@ -366,6 +374,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'JZ': case 'JE': p1 = getValue(match[op1_group]); @@ -380,6 +389,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'JNZ': case 'JNE': p1 = getValue(match[op1_group]); @@ -394,6 +404,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'JA': case 'JNBE': p1 = getValue(match[op1_group]); @@ -408,6 +419,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'JNA': case 'JBE': p1 = getValue(match[op1_group]); @@ -422,6 +434,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'PUSH': p1 = getValue(match[op1_group]); checkNoExtraArg(instr, match[op2_group]); @@ -439,6 +452,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'POP': p1 = getValue(match[op1_group]); checkNoExtraArg(instr, match[op2_group]); @@ -450,6 +464,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'CALL': p1 = getValue(match[op1_group]); checkNoExtraArg(instr, match[op2_group]); @@ -463,6 +478,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'RET': checkNoExtraArg(instr, match[op1_group]); @@ -488,6 +504,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'DIV': p1 = getValue(match[op1_group]); checkNoExtraArg(instr, match[op2_group]); @@ -505,6 +522,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'AND': p1 = getValue(match[op1_group]); p2 = getValue(match[op2_group]); @@ -522,6 +540,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'OR': p1 = getValue(match[op1_group]); p2 = getValue(match[op2_group]); @@ -539,6 +558,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'XOR': p1 = getValue(match[op1_group]); p2 = getValue(match[op2_group]); @@ -556,6 +576,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'NOT': p1 = getValue(match[op1_group]); checkNoExtraArg(instr, match[op2_group]); @@ -567,6 +588,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value); break; + case 'SHL': case 'SAL': p1 = getValue(match[op1_group]); @@ -585,6 +607,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + case 'SHR': case 'SAR': p1 = getValue(match[op1_group]); @@ -603,6 +626,7 @@ var app = angular.module('ASMSimulator', []); code.push(opCode, p1.value, p2.value); break; + default: throw "Invalid instruction: " + match[2]; } @@ -766,144 +790,169 @@ var app = angular.module('ASMSimulator', []); switch(instr) { case opcodes.NONE: return false; // Abort step + case opcodes.MOV_REG_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = checkGPR_SP(memory.load(++self.ip)); setGPR_SP(regTo,getGPR_SP(regFrom)); self.ip++; break; + case opcodes.MOV_ADDRESS_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); memFrom = memory.load(++self.ip); setGPR_SP(regTo,memory.load(memFrom)); self.ip++; break; + case opcodes.MOV_REGADDRESS_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = memory.load(++self.ip); setGPR_SP(regTo,memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.MOV_REG_TO_ADDRESS: memTo = memory.load(++self.ip); regFrom = checkGPR_SP(memory.load(++self.ip)); memory.store(memTo, getGPR_SP(regFrom)); self.ip++; break; + case opcodes.MOV_REG_TO_REGADDRESS: regTo = memory.load(++self.ip); regFrom = checkGPR_SP(memory.load(++self.ip)); memory.store(indirectRegisterAddress(regTo), getGPR_SP(regFrom)); self.ip++; break; + case opcodes.MOV_NUMBER_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); number = memory.load(++self.ip); setGPR_SP(regTo,number); self.ip++; break; + case opcodes.MOV_NUMBER_TO_ADDRESS: memTo = memory.load(++self.ip); number = memory.load(++self.ip); memory.store(memTo, number); self.ip++; break; + case opcodes.MOV_NUMBER_TO_REGADDRESS: regTo = memory.load(++self.ip); number = memory.load(++self.ip); memory.store(indirectRegisterAddress(regTo), number); self.ip++; break; + case opcodes.ADD_REG_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = checkGPR_SP(memory.load(++self.ip)); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + getGPR_SP(regFrom))); self.ip++; break; + case opcodes.ADD_REGADDRESS_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = memory.load(++self.ip); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + memory.load(indirectRegisterAddress(regFrom)))); self.ip++; break; + case opcodes.ADD_ADDRESS_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); memFrom = memory.load(++self.ip); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + memory.load(memFrom))); self.ip++; break; + case opcodes.ADD_NUMBER_TO_REG: regTo = checkGPR_SP(memory.load(++self.ip)); number = memory.load(++self.ip); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + number)); self.ip++; break; + case opcodes.SUB_REG_FROM_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = checkGPR_SP(memory.load(++self.ip)); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - self.gpr[regFrom])); self.ip++; break; + case opcodes.SUB_REGADDRESS_FROM_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = memory.load(++self.ip); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - memory.load(indirectRegisterAddress(regFrom)))); self.ip++; break; + case opcodes.SUB_ADDRESS_FROM_REG: regTo = checkGPR_SP(memory.load(++self.ip)); memFrom = memory.load(++self.ip); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - memory.load(memFrom))); self.ip++; break; + case opcodes.SUB_NUMBER_FROM_REG: regTo = checkGPR_SP(memory.load(++self.ip)); number = memory.load(++self.ip); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - number)); self.ip++; break; + case opcodes.INC_REG: regTo = checkGPR_SP(memory.load(++self.ip)); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + 1)); self.ip++; break; + case opcodes.DEC_REG: regTo = checkGPR_SP(memory.load(++self.ip)); setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - 1)); self.ip++; break; + case opcodes.CMP_REG_WITH_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = checkGPR_SP(memory.load(++self.ip)); checkOperation(getGPR_SP(regTo) - getGPR_SP(regFrom)); self.ip++; break; + case opcodes.CMP_REGADDRESS_WITH_REG: regTo = checkGPR_SP(memory.load(++self.ip)); regFrom = memory.load(++self.ip); checkOperation(getGPR_SP(regTo) - memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.CMP_ADDRESS_WITH_REG: regTo = checkGPR_SP(memory.load(++self.ip)); memFrom = memory.load(++self.ip); checkOperation(getGPR_SP(regTo) - memory.load(memFrom)); self.ip++; break; + case opcodes.CMP_NUMBER_WITH_REG: regTo = checkGPR_SP(memory.load(++self.ip)); number = memory.load(++self.ip); checkOperation(getGPR_SP(regTo) - number); self.ip++; break; + case opcodes.JMP_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); jump(self.gpr[regTo]); break; + case opcodes.JMP_ADDRESS: number = memory.load(++self.ip); jump(number); break; + case opcodes.JC_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); if (self.carry) { @@ -912,6 +961,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JC_ADDRESS: number = memory.load(++self.ip); if (self.carry) { @@ -920,6 +970,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JNC_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); if (!self.carry) { @@ -928,6 +979,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JNC_ADDRESS: number = memory.load(++self.ip); if (!self.carry) { @@ -936,6 +988,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JZ_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); if (self.zero) { @@ -944,6 +997,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JZ_ADDRESS: number = memory.load(++self.ip); if (self.zero) { @@ -952,6 +1006,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JNZ_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); if (!self.zero) { @@ -960,6 +1015,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JNZ_ADDRESS: number = memory.load(++self.ip); if (!self.zero) { @@ -968,6 +1024,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JA_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); if (!self.zero && !self.carry) { @@ -976,6 +1033,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JA_ADDRESS: number = memory.load(++self.ip); if (!self.zero && !self.carry) { @@ -984,6 +1042,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JNA_REGADDRESS: // JNA REG regTo = checkGPR(memory.load(++self.ip)); if (self.zero || self.carry) { @@ -992,6 +1051,7 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.JNA_ADDRESS: number = memory.load(++self.ip); if (self.zero || self.carry) { @@ -1000,209 +1060,247 @@ var app = angular.module('ASMSimulator', []); self.ip++; } break; + case opcodes.PUSH_REG: regFrom = checkGPR(memory.load(++self.ip)); push(self.gpr[regFrom]); self.ip++; break; + case opcodes.PUSH_REGADDRESS: regFrom = memory.load(++self.ip); push(memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.PUSH_ADDRESS: memFrom = memory.load(++self.ip); push(memory.load(memFrom)); self.ip++; break; + case opcodes.PUSH_NUMBER: number = memory.load(++self.ip); push(number); self.ip++; break; + case opcodes.POP_REG: regTo = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = pop(); self.ip++; break; + case opcodes.CALL_REGADDRESS: regTo = checkGPR(memory.load(++self.ip)); push(self.ip+1); jump(self.gpr[regTo]); break; + case opcodes.CALL_ADDRESS: number = memory.load(++self.ip); push(self.ip+1); jump(number); break; + case opcodes.RET: jump(pop()); break; + case opcodes.MUL_REG: // A = A * REG regFrom = checkGPR(memory.load(++self.ip)); self.gpr[0] = checkOperation(self.gpr[0] * self.gpr[regFrom]); self.ip++; break; + case opcodes.MUL_REGADDRESS: // A = A * [REG] regFrom = memory.load(++self.ip); self.gpr[0] = checkOperation(self.gpr[0] * memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.MUL_ADDRESS: // A = A * [NUMBER] memFrom = memory.load(++self.ip); self.gpr[0] = checkOperation(self.gpr[0] * memory.load(memFrom)); self.ip++; break; + case opcodes.MUL_NUMBER: // A = A * NUMBER number = memory.load(++self.ip); self.gpr[0] = checkOperation(self.gpr[0] * number); self.ip++; break; + case opcodes.DIV_REG: // A = A / REG regFrom = checkGPR(memory.load(++self.ip)); self.gpr[0] = checkOperation(division(self.gpr[regFrom])); self.ip++; break; + case opcodes.DIV_REGADDRESS: // A = A / [REG] regFrom = memory.load(++self.ip); self.gpr[0] = checkOperation(division(memory.load(indirectRegisterAddress(regFrom)))); self.ip++; break; + case opcodes.DIV_ADDRESS: // A = A / [NUMBER] memFrom = memory.load(++self.ip); self.gpr[0] = checkOperation(division(memory.load(memFrom))); self.ip++; break; + case opcodes.DIV_NUMBER: // A = A / NUMBER number = memory.load(++self.ip); self.gpr[0] = checkOperation(division(number)); self.ip++; break; + case opcodes.AND_REG_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = checkOperation(self.gpr[regTo] & self.gpr[regFrom]); self.ip++; break; + case opcodes.AND_REGADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] & memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.AND_ADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); memFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] & memory.load(memFrom)); self.ip++; break; + case opcodes.AND_NUMBER_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); number = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] & number); self.ip++; break; + case opcodes.OR_REG_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = checkOperation(self.gpr[regTo] | self.gpr[regFrom]); self.ip++; break; + case opcodes.OR_REGADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] | memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.OR_ADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); memFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] | memory.load(memFrom)); self.ip++; break; + case opcodes.OR_NUMBER_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); number = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] | number); self.ip++; break; + case opcodes.XOR_REG_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ self.gpr[regFrom]); self.ip++; break; + case opcodes.XOR_REGADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.XOR_ADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); memFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ memory.load(memFrom)); self.ip++; break; + case opcodes.XOR_NUMBER_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); number = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ number); self.ip++; break; + case opcodes.NOT_REG: regTo = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = checkOperation(~self.gpr[regTo]); self.ip++; break; + case opcodes.SHL_REG_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = checkOperation(self.gpr[regTo] << self.gpr[regFrom]); self.ip++; break; + case opcodes.SHL_REGADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] << memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.SHL_ADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); memFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] << memory.load(memFrom)); self.ip++; break; + case opcodes.SHL_NUMBER_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); number = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] << number); self.ip++; break; + case opcodes.SHR_REG_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = checkGPR(memory.load(++self.ip)); self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> self.gpr[regFrom]); self.ip++; break; + case opcodes.SHR_REGADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); regFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> memory.load(indirectRegisterAddress(regFrom))); self.ip++; break; + case opcodes.SHR_ADDRESS_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); memFrom = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> memory.load(memFrom)); self.ip++; break; + case opcodes.SHR_NUMBER_WITH_REG: regTo = checkGPR(memory.load(++self.ip)); number = memory.load(++self.ip); self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> number); self.ip++; break; + default: throw "Invalid op code: " + instr; } @@ -1257,7 +1355,8 @@ var app = angular.module('ASMSimulator', []); reset: function () { var self = this; - self.lastAccess = -1; + self.lastAccess = -1; + for (var i = 0, l = self.data.length; i < l; i++) { self.data[i] = 0; } @@ -1348,12 +1447,11 @@ var app = angular.module('ASMSimulator', []); return opcodes; }]); ;app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'assembler', function ($document, $scope, $timeout, cpu, memory, assembler) { + $scope.displayInstr = false; $scope.memory = memory; $scope.cpu = cpu; $scope.error = ''; - $scope.isRunning = false; $scope.displayHex = true; - $scope.displayInstr = true; $scope.displayA = false; $scope.displayB = false; $scope.displayC = false; @@ -1367,7 +1465,14 @@ var app = angular.module('ASMSimulator', []); $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 () { + $timeout.cancel(runner); + $scope.isRunning = false; + $scope.labels = null; + + $scope.displayInstr = false; + delete $scope.mapping; + cpu.reset(); memory.reset(); $scope.error = ''; @@ -1438,7 +1543,8 @@ var app = angular.module('ASMSimulator', []); $scope.assemble = function () { try { - $scope.reset(); + $scope.reset(); + $scope.displayInstr = true; var assembly = assembler.go($scope.code); $scope.mapping = assembly.mapping; @@ -1485,7 +1591,7 @@ var app = angular.module('ASMSimulator', []); } }; - $scope.getMemoryInnerCellCss = function (index) { + $scope.getMemoryInnerCellCss = function (index) { if (index === cpu.ip) { return 'marker marker-ip'; } else if (index === cpu.sp) { @@ -1505,7 +1611,15 @@ var app = angular.module('ASMSimulator', []); }]); ;app.filter('flag', function() { return function(input) { - return input.toString().toUpperCase(); + // convert flag to uppercase + var str = input.toString().toUpperCase(); + + // pad with unicode nbsp to stop the flag value from change length + var l = str.length; + if(l < 5){ + for(i=0;i<5-l;i++) str += '\u00A0'; + } + return str; }; }); ;app.filter('number', function() { diff --git a/assets/asmsimulator.min.js b/assets/asmsimulator.min.js deleted file mode 100644 index 303ccd0..0000000 --- a/assets/asmsimulator.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! asmsimulator 19-07-2015 */ -var app=angular.module("ASMSimulator",[]);app.service("assembler",["opcodes",function(a){return{go:function(b){for(var c=/^[\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*))?)?)?/,d=3,e=7,f=/^[-+]?[0-9]+$/,g=/^[.A-Za-z]\w*$/,h=[],i={},j={},k={},l=b.split("\n"),m=function(a){if("0x"===a.slice(0,2))return parseInt(a.slice(2),16);if("0o"===a.slice(0,2))return parseInt(a.slice(2),8);if("b"===a.slice(a.length-1))return parseInt(a.slice(0,a.length-1),2);if("d"===a.slice(a.length-1))return parseInt(a.slice(0,a.length-1),10);if(f.exec(a))return parseInt(a,10);throw"Invalid number format"},n=function(a){return a=a.toUpperCase(),"A"===a?0:"B"===a?1:"C"===a?2:"D"===a?3:"SP"===a?4:void 0},o=function(a){a=a.toUpperCase();var b=0,c=0;if("A"===a[0])c=0;else if("B"===a[0])c=1;else if("C"===a[0])c=2;else if("D"===a[0])c=3;else{if("SP"!==a.slice(0,2))return void 0;c=4}var d=1;if(4===c&&(d=2),"-"===a[d])b=-1;else{if("+"!==a[d])return void 0;b=1}var e=b*parseInt(a.slice(d+1),10);if(-16>e||e>15)throw"offset must be a value between -16...+15";return 0>e&&(e=32+e),8*e+c},p=function(a,b,c){var d=n(a);if(void 0!==d)return{type:b,value:d};var e=q(a);if(void 0!==e)return{type:c,value:e};if("regaddress"===b&&(d=o(a),void 0!==d))return{type:b,value:d};var f=m(a);if(isNaN(f))throw"Not a "+c+": "+f;if(0>f||f>255)throw c+" must have a value between 0-255";return{type:c,value:f}},q=function(a){return g.exec(a)?a:void 0},r=function(a){switch(a.slice(0,1)){case"[":var b=a.slice(1,a.length-1);return p(b,"regaddress","address");case'"':for(var c=a.slice(1,a.length-1),d=[],e=0,f=c.length;f>e;e++)d.push(c.charCodeAt(e));return{type:"numbers",value:d};case"'":var g=a.slice(1,a.length-1);if(g.length>1)throw"Only one character is allowed. Use String instead";return{type:"number",value:g.charCodeAt(0)};default:return p(a,"register","number")}},s=(function(a){var b=a.toUpperCase();if(b in k)throw"Duplicate label: "+a;if("A"===b||"B"===b||"C"===b||"D"===b)throw"Label contains keyword: "+b;j[a]=h.length}),t=function(a,b){if(void 0!==b)throw a+": too many arguments"},u=0,v=l.length;v>u;u++)try{var w=c.exec(l[u]);if(void 0!==w[1]||void 0!==w[2]){if(void 0!==w[1]&&s(w[1]),void 0!==w[2]){var x,y,z,A=w[2].toUpperCase();switch("DB"!==A&&(i[h.length]=u),A){case"DB":if(x=r(w[d]),"number"===x.type)h.push(x.value);else{if("numbers"!==x.type)throw"DB does not support this operand";for(var B=0,C=x.value.length;C>B;B++)h.push(x.value[B])}break;case"HLT":t("HLT",w[d]),z=a.NONE,h.push(z);break;case"MOV":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.MOV_REG_TO_REG;else if("register"===x.type&&"address"===y.type)z=a.MOV_ADDRESS_TO_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.MOV_REGADDRESS_TO_REG;else if("address"===x.type&&"register"===y.type)z=a.MOV_REG_TO_ADDRESS;else if("regaddress"===x.type&&"register"===y.type)z=a.MOV_REG_TO_REGADDRESS;else if("register"===x.type&&"number"===y.type)z=a.MOV_NUMBER_TO_REG;else if("address"===x.type&&"number"===y.type)z=a.MOV_NUMBER_TO_ADDRESS;else{if("regaddress"!==x.type||"number"!==y.type)throw"MOV does not support this operands";z=a.MOV_NUMBER_TO_REGADDRESS}h.push(z,x.value,y.value);break;case"ADD":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.ADD_REG_TO_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.ADD_REGADDRESS_TO_REG;else if("register"===x.type&&"address"===y.type)z=a.ADD_ADDRESS_TO_REG;else{if("register"!==x.type||"number"!==y.type)throw"ADD does not support this operands";z=a.ADD_NUMBER_TO_REG}h.push(z,x.value,y.value);break;case"SUB":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.SUB_REG_FROM_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.SUB_REGADDRESS_FROM_REG;else if("register"===x.type&&"address"===y.type)z=a.SUB_ADDRESS_FROM_REG;else{if("register"!==x.type||"number"!==y.type)throw"SUB does not support this operands";z=a.SUB_NUMBER_FROM_REG}h.push(z,x.value,y.value);break;case"INC":if(x=r(w[d]),t("INC",w[e]),"register"!==x.type)throw"INC does not support this operand";z=a.INC_REG,h.push(z,x.value);break;case"DEC":if(x=r(w[d]),t("DEC",w[e]),"register"!==x.type)throw"DEC does not support this operand";z=a.DEC_REG,h.push(z,x.value);break;case"CMP":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.CMP_REG_WITH_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.CMP_REGADDRESS_WITH_REG;else if("register"===x.type&&"address"===y.type)z=a.CMP_ADDRESS_WITH_REG;else{if("register"!==x.type||"number"!==y.type)throw"CMP does not support this operands";z=a.CMP_NUMBER_WITH_REG}h.push(z,x.value,y.value);break;case"JMP":if(x=r(w[d]),t("JMP",w[e]),"register"===x.type)z=a.JMP_REGADDRESS;else{if("number"!==x.type)throw"JMP does not support this operands";z=a.JMP_ADDRESS}h.push(z,x.value);break;case"JC":case"JB":case"JNAE":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.JC_REGADDRESS;else{if("number"!==x.type)throw A+" does not support this operand";z=a.JC_ADDRESS}h.push(z,x.value);break;case"JNC":case"JNB":case"JAE":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.JNC_REGADDRESS;else{if("number"!==x.type)throw A+"does not support this operand";z=a.JNC_ADDRESS}h.push(z,x.value);break;case"JZ":case"JE":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.JZ_REGADDRESS;else{if("number"!==x.type)throw A+" does not support this operand";z=a.JZ_ADDRESS}h.push(z,x.value);break;case"JNZ":case"JNE":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.JNZ_REGADDRESS;else{if("number"!==x.type)throw A+" does not support this operand";z=a.JNZ_ADDRESS}h.push(z,x.value);break;case"JA":case"JNBE":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.JA_REGADDRESS;else{if("number"!==x.type)throw A+" does not support this operand";z=a.JA_ADDRESS}h.push(z,x.value);break;case"JNA":case"JBE":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.JNA_REGADDRESS;else{if("number"!==x.type)throw A+" does not support this operand";z=a.JNA_ADDRESS}h.push(z,x.value);break;case"PUSH":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.PUSH_REG;else if("regaddress"===x.type)z=a.PUSH_REGADDRESS;else if("address"===x.type)z=a.PUSH_ADDRESS;else{if("number"!==x.type)throw"PUSH does not support this operand";z=a.PUSH_NUMBER}h.push(z,x.value);break;case"POP":if(x=r(w[d]),t(A,w[e]),"register"!==x.type)throw"PUSH does not support this operand";z=a.POP_REG,h.push(z,x.value);break;case"CALL":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.CALL_REGADDRESS;else{if("number"!==x.type)throw"CALL does not support this operand";z=a.CALL_ADDRESS}h.push(z,x.value);break;case"RET":t(A,w[d]),z=a.RET,h.push(z);break;case"MUL":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.MUL_REG;else if("regaddress"===x.type)z=a.MUL_REGADDRESS;else if("address"===x.type)z=a.MUL_ADDRESS;else{if("number"!==x.type)throw"MULL does not support this operand";z=a.MUL_NUMBER}h.push(z,x.value);break;case"DIV":if(x=r(w[d]),t(A,w[e]),"register"===x.type)z=a.DIV_REG;else if("regaddress"===x.type)z=a.DIV_REGADDRESS;else if("address"===x.type)z=a.DIV_ADDRESS;else{if("number"!==x.type)throw"DIV does not support this operand";z=a.DIV_NUMBER}h.push(z,x.value);break;case"AND":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.AND_REG_WITH_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.AND_REGADDRESS_WITH_REG;else if("register"===x.type&&"address"===y.type)z=a.AND_ADDRESS_WITH_REG;else{if("register"!==x.type||"number"!==y.type)throw"AND does not support this operands";z=a.AND_NUMBER_WITH_REG}h.push(z,x.value,y.value);break;case"OR":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.OR_REG_WITH_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.OR_REGADDRESS_WITH_REG;else if("register"===x.type&&"address"===y.type)z=a.OR_ADDRESS_WITH_REG;else{if("register"!==x.type||"number"!==y.type)throw"OR does not support this operands";z=a.OR_NUMBER_WITH_REG}h.push(z,x.value,y.value);break;case"XOR":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.XOR_REG_WITH_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.XOR_REGADDRESS_WITH_REG;else if("register"===x.type&&"address"===y.type)z=a.XOR_ADDRESS_WITH_REG;else{if("register"!==x.type||"number"!==y.type)throw"XOR does not support this operands";z=a.XOR_NUMBER_WITH_REG}h.push(z,x.value,y.value);break;case"NOT":if(x=r(w[d]),t(A,w[e]),"register"!==x.type)throw"NOT does not support this operand";z=a.NOT_REG,h.push(z,x.value);break;case"SHL":case"SAL":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.SHL_REG_WITH_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.SHL_REGADDRESS_WITH_REG;else if("register"===x.type&&"address"===y.type)z=a.SHL_ADDRESS_WITH_REG;else{if("register"!==x.type||"number"!==y.type)throw A+" does not support this operands";z=a.SHL_NUMBER_WITH_REG}h.push(z,x.value,y.value);break;case"SHR":case"SAR":if(x=r(w[d]),y=r(w[e]),"register"===x.type&&"register"===y.type)z=a.SHR_REG_WITH_REG;else if("register"===x.type&&"regaddress"===y.type)z=a.SHR_REGADDRESS_WITH_REG;else if("register"===x.type&&"address"===y.type)z=a.SHR_ADDRESS_WITH_REG;else{if("register"!==x.type||"number"!==y.type)throw A+" does not support this operands";z=a.SHR_NUMBER_WITH_REG}h.push(z,x.value,y.value);break;default:throw"Invalid instruction: "+w[2]}}}else{var D=l[u].trim();if(""!==D&&";"!==D.slice(0,1))throw"Syntax error"}}catch(E){throw{error:E,line:u}}for(u=0,v=h.length;v>u;u++)if(!angular.isNumber(h[u])){if(!(h[u]in j))throw{error:"Undefined label: "+h[u]};h[u]=j[h[u]]}return{code:h,mapping:i,labels:j}}}}]),app.service("cpu",["opcodes","memory",function(a,b){var c={step:function(){var c=this;if(c.fault===!0)throw"FAULT. Reset to continue.";try{var d=function(a){if(0>a||a>=c.gpr.length)throw"Invalid register: "+a;return a},e=function(a){if(0>a||a>=1+c.gpr.length)throw"Invalid register: "+a;return a},f=function(a,b){if(a>=0&&ac.maxSP)throw"Stack underflow"}},g=function(a){if(a>=0&&a15&&(e-=32),b+e},i=function(a){return c.zero=!1,c.carry=!1,a>=256?(c.carry=!0,a%=256):0===a?c.zero=!0:0>a&&(c.carry=!0,a=256- -a%256),a},j=function(a){if(0>a||a>=b.data.length)throw"IP outside memory";c.ip=a},k=function(a){if(b.store(c.sp--,a),c.spc.maxSP)throw"Stack underflow";return a},m=function(a){if(0===a)throw"Division by 0";return Math.floor(c.gpr[0]/a)};if(c.ip<0||c.ip>=b.data.length)throw"Instruction pointer is outside of memory";var n,o,p,q,r,s=b.load(c.ip);switch(s){case a.NONE:return!1;case a.MOV_REG_TO_REG:n=e(b.load(++c.ip)),o=e(b.load(++c.ip)),f(n,g(o)),c.ip++;break;case a.MOV_ADDRESS_TO_REG:n=e(b.load(++c.ip)),p=b.load(++c.ip),f(n,b.load(p)),c.ip++;break;case a.MOV_REGADDRESS_TO_REG:n=e(b.load(++c.ip)),o=b.load(++c.ip),f(n,b.load(h(o))),c.ip++;break;case a.MOV_REG_TO_ADDRESS:q=b.load(++c.ip),o=e(b.load(++c.ip)),b.store(q,g(o)),c.ip++;break;case a.MOV_REG_TO_REGADDRESS:n=b.load(++c.ip),o=e(b.load(++c.ip)),b.store(h(n),g(o)),c.ip++;break;case a.MOV_NUMBER_TO_REG:n=e(b.load(++c.ip)),r=b.load(++c.ip),f(n,r),c.ip++;break;case a.MOV_NUMBER_TO_ADDRESS:q=b.load(++c.ip),r=b.load(++c.ip),b.store(q,r),c.ip++;break;case a.MOV_NUMBER_TO_REGADDRESS:n=b.load(++c.ip),r=b.load(++c.ip),b.store(h(n),r),c.ip++;break;case a.ADD_REG_TO_REG:n=e(b.load(++c.ip)),o=e(b.load(++c.ip)),f(n,i(g(n)+g(o))),c.ip++;break;case a.ADD_REGADDRESS_TO_REG:n=e(b.load(++c.ip)),o=b.load(++c.ip),f(n,i(g(n)+b.load(h(o)))),c.ip++;break;case a.ADD_ADDRESS_TO_REG:n=e(b.load(++c.ip)),p=b.load(++c.ip),f(n,i(g(n)+b.load(p))),c.ip++;break;case a.ADD_NUMBER_TO_REG:n=e(b.load(++c.ip)),r=b.load(++c.ip),f(n,i(g(n)+r)),c.ip++;break;case a.SUB_REG_FROM_REG:n=e(b.load(++c.ip)),o=e(b.load(++c.ip)),f(n,i(g(n)-c.gpr[o])),c.ip++;break;case a.SUB_REGADDRESS_FROM_REG:n=e(b.load(++c.ip)),o=b.load(++c.ip),f(n,i(g(n)-b.load(h(o)))),c.ip++;break;case a.SUB_ADDRESS_FROM_REG:n=e(b.load(++c.ip)),p=b.load(++c.ip),f(n,i(g(n)-b.load(p))),c.ip++;break;case a.SUB_NUMBER_FROM_REG:n=e(b.load(++c.ip)),r=b.load(++c.ip),f(n,i(g(n)-r)),c.ip++;break;case a.INC_REG:n=e(b.load(++c.ip)),f(n,i(g(n)+1)),c.ip++;break;case a.DEC_REG:n=e(b.load(++c.ip)),f(n,i(g(n)-1)),c.ip++;break;case a.CMP_REG_WITH_REG:n=e(b.load(++c.ip)),o=e(b.load(++c.ip)),i(g(n)-g(o)),c.ip++;break;case a.CMP_REGADDRESS_WITH_REG:n=e(b.load(++c.ip)),o=b.load(++c.ip),i(g(n)-b.load(h(o))),c.ip++;break;case a.CMP_ADDRESS_WITH_REG:n=e(b.load(++c.ip)),p=b.load(++c.ip),i(g(n)-b.load(p)),c.ip++;break;case a.CMP_NUMBER_WITH_REG:n=e(b.load(++c.ip)),r=b.load(++c.ip),i(g(n)-r),c.ip++;break;case a.JMP_REGADDRESS:n=d(b.load(++c.ip)),j(c.gpr[n]);break;case a.JMP_ADDRESS:r=b.load(++c.ip),j(r);break;case a.JC_REGADDRESS:n=d(b.load(++c.ip)),c.carry?j(c.gpr[n]):c.ip++;break;case a.JC_ADDRESS:r=b.load(++c.ip),c.carry?j(r):c.ip++;break;case a.JNC_REGADDRESS:n=d(b.load(++c.ip)),c.carry?c.ip++:j(c.gpr[n]);break;case a.JNC_ADDRESS:r=b.load(++c.ip),c.carry?c.ip++:j(r);break;case a.JZ_REGADDRESS:n=d(b.load(++c.ip)),c.zero?j(c.gpr[n]):c.ip++;break;case a.JZ_ADDRESS:r=b.load(++c.ip),c.zero?j(r):c.ip++;break;case a.JNZ_REGADDRESS:n=d(b.load(++c.ip)),c.zero?c.ip++:j(c.gpr[n]);break;case a.JNZ_ADDRESS:r=b.load(++c.ip),c.zero?c.ip++:j(r);break;case a.JA_REGADDRESS:n=d(b.load(++c.ip)),c.zero||c.carry?c.ip++:j(c.gpr[n]);break;case a.JA_ADDRESS:r=b.load(++c.ip),c.zero||c.carry?c.ip++:j(r);break;case a.JNA_REGADDRESS:n=d(b.load(++c.ip)),c.zero||c.carry?j(c.gpr[n]):c.ip++;break;case a.JNA_ADDRESS:r=b.load(++c.ip),c.zero||c.carry?j(r):c.ip++;break;case a.PUSH_REG:o=d(b.load(++c.ip)),k(c.gpr[o]),c.ip++;break;case a.PUSH_REGADDRESS:o=b.load(++c.ip),k(b.load(h(o))),c.ip++;break;case a.PUSH_ADDRESS:p=b.load(++c.ip),k(b.load(p)),c.ip++;break;case a.PUSH_NUMBER:r=b.load(++c.ip),k(r),c.ip++;break;case a.POP_REG:n=d(b.load(++c.ip)),c.gpr[n]=l(),c.ip++;break;case a.CALL_REGADDRESS:n=d(b.load(++c.ip)),k(c.ip+1),j(c.gpr[n]);break;case a.CALL_ADDRESS:r=b.load(++c.ip),k(c.ip+1),j(r);break;case a.RET:j(l());break;case a.MUL_REG:o=d(b.load(++c.ip)),c.gpr[0]=i(c.gpr[0]*c.gpr[o]),c.ip++;break;case a.MUL_REGADDRESS:o=b.load(++c.ip),c.gpr[0]=i(c.gpr[0]*b.load(h(o))),c.ip++;break;case a.MUL_ADDRESS:p=b.load(++c.ip),c.gpr[0]=i(c.gpr[0]*b.load(p)),c.ip++;break;case a.MUL_NUMBER:r=b.load(++c.ip),c.gpr[0]=i(c.gpr[0]*r),c.ip++;break;case a.DIV_REG:o=d(b.load(++c.ip)),c.gpr[0]=i(m(c.gpr[o])),c.ip++;break;case a.DIV_REGADDRESS:o=b.load(++c.ip),c.gpr[0]=i(m(b.load(h(o)))),c.ip++;break;case a.DIV_ADDRESS:p=b.load(++c.ip),c.gpr[0]=i(m(b.load(p))),c.ip++;break;case a.DIV_NUMBER:r=b.load(++c.ip),c.gpr[0]=i(m(r)),c.ip++;break;case a.AND_REG_WITH_REG:n=d(b.load(++c.ip)),o=d(b.load(++c.ip)),c.gpr[n]=i(c.gpr[n]&c.gpr[o]),c.ip++;break;case a.AND_REGADDRESS_WITH_REG:n=d(b.load(++c.ip)),o=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]&b.load(h(o))),c.ip++;break;case a.AND_ADDRESS_WITH_REG:n=d(b.load(++c.ip)),p=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]&b.load(p)),c.ip++;break;case a.AND_NUMBER_WITH_REG:n=d(b.load(++c.ip)),r=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]&r),c.ip++;break;case a.OR_REG_WITH_REG:n=d(b.load(++c.ip)),o=d(b.load(++c.ip)),c.gpr[n]=i(c.gpr[n]|c.gpr[o]),c.ip++;break;case a.OR_REGADDRESS_WITH_REG:n=d(b.load(++c.ip)),o=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]|b.load(h(o))),c.ip++;break;case a.OR_ADDRESS_WITH_REG:n=d(b.load(++c.ip)),p=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]|b.load(p)),c.ip++;break;case a.OR_NUMBER_WITH_REG:n=d(b.load(++c.ip)),r=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]|r),c.ip++;break;case a.XOR_REG_WITH_REG:n=d(b.load(++c.ip)),o=d(b.load(++c.ip)),c.gpr[n]=i(c.gpr[n]^c.gpr[o]),c.ip++;break;case a.XOR_REGADDRESS_WITH_REG:n=d(b.load(++c.ip)),o=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]^b.load(h(o))),c.ip++;break;case a.XOR_ADDRESS_WITH_REG:n=d(b.load(++c.ip)),p=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]^b.load(p)),c.ip++;break;case a.XOR_NUMBER_WITH_REG:n=d(b.load(++c.ip)),r=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]^r),c.ip++;break;case a.NOT_REG:n=d(b.load(++c.ip)),c.gpr[n]=i(~c.gpr[n]),c.ip++;break;case a.SHL_REG_WITH_REG:n=d(b.load(++c.ip)),o=d(b.load(++c.ip)),c.gpr[n]=i(c.gpr[n]<>>c.gpr[o]),c.ip++;break;case a.SHR_REGADDRESS_WITH_REG:n=d(b.load(++c.ip)),o=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]>>>b.load(h(o))),c.ip++;break;case a.SHR_ADDRESS_WITH_REG:n=d(b.load(++c.ip)),p=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]>>>b.load(p)),c.ip++;break;case a.SHR_NUMBER_WITH_REG:n=d(b.load(++c.ip)),r=b.load(++c.ip),c.gpr[n]=i(c.gpr[n]>>>r),c.ip++;break;default:throw"Invalid op code: "+s}return!0}catch(t){throw c.fault=!0,t}},reset:function(){var a=this;a.maxSP=231,a.minSP=0,a.gpr=[0,0,0,0],a.sp=a.maxSP,a.ip=0,a.zero=!1,a.carry=!1,a.fault=!1}};return c.reset(),c}]),app.service("memory",[function(){var a={data:Array(256),lastAccess:-1,load:function(a){var b=this;if(0>a||a>=b.data.length)throw"Memory access violation at "+a;return b.lastAccess=a,b.data[a]},store:function(a,b){var c=this;if(0>a||a>=c.data.length)throw"Memory access violation at "+a;c.lastAccess=a,c.data[a]=b},reset:function(){var a=this;a.lastAccess=-1;for(var b=0,c=a.data.length;c>b;b++)a.data[b]=0}};return a.reset(),a}]),app.service("opcodes",[function(){var a={NONE:0,MOV_REG_TO_REG:1,MOV_ADDRESS_TO_REG:2,MOV_REGADDRESS_TO_REG:3,MOV_REG_TO_ADDRESS:4,MOV_REG_TO_REGADDRESS:5,MOV_NUMBER_TO_REG:6,MOV_NUMBER_TO_ADDRESS:7,MOV_NUMBER_TO_REGADDRESS:8,ADD_REG_TO_REG:10,ADD_REGADDRESS_TO_REG:11,ADD_ADDRESS_TO_REG:12,ADD_NUMBER_TO_REG:13,SUB_REG_FROM_REG:14,SUB_REGADDRESS_FROM_REG:15,SUB_ADDRESS_FROM_REG:16,SUB_NUMBER_FROM_REG:17,INC_REG:18,DEC_REG:19,CMP_REG_WITH_REG:20,CMP_REGADDRESS_WITH_REG:21,CMP_ADDRESS_WITH_REG:22,CMP_NUMBER_WITH_REG:23,JMP_REGADDRESS:30,JMP_ADDRESS:31,JC_REGADDRESS:32,JC_ADDRESS:33,JNC_REGADDRESS:34,JNC_ADDRESS:35,JZ_REGADDRESS:36,JZ_ADDRESS:37,JNZ_REGADDRESS:38,JNZ_ADDRESS:39,JA_REGADDRESS:40,JA_ADDRESS:41,JNA_REGADDRESS:42,JNA_ADDRESS:43,PUSH_REG:50,PUSH_REGADDRESS:51,PUSH_ADDRESS:52,PUSH_NUMBER:53,POP_REG:54,CALL_REGADDRESS:55,CALL_ADDRESS:56,RET:57,MUL_REG:60,MUL_REGADDRESS:61,MUL_ADDRESS:62,MUL_NUMBER:63,DIV_REG:64,DIV_REGADDRESS:65,DIV_ADDRESS:66,DIV_NUMBER:67,AND_REG_WITH_REG:70,AND_REGADDRESS_WITH_REG:71,AND_ADDRESS_WITH_REG:72,AND_NUMBER_WITH_REG:73,OR_REG_WITH_REG:74,OR_REGADDRESS_WITH_REG:75,OR_ADDRESS_WITH_REG:76,OR_NUMBER_WITH_REG:77,XOR_REG_WITH_REG:78,XOR_REGADDRESS_WITH_REG:79,XOR_ADDRESS_WITH_REG:80,XOR_NUMBER_WITH_REG:81,NOT_REG:82,SHL_REG_WITH_REG:90,SHL_REGADDRESS_WITH_REG:91,SHL_ADDRESS_WITH_REG:92,SHL_NUMBER_WITH_REG:93,SHR_REG_WITH_REG:94,SHR_REGADDRESS_WITH_REG:95,SHR_ADDRESS_WITH_REG:96,SHR_NUMBER_WITH_REG:97};return a}]),app.controller("Ctrl",["$document","$scope","$timeout","cpu","memory","assembler",function(a,b,c,d,e,f){b.memory=e,b.cpu=d,b.error="",b.isRunning=!1,b.displayHex=!0,b.displayInstr=!0,b.displayA=!1,b.displayB=!1,b.displayC=!1,b.displayD=!1,b.speeds=[{speed:1,desc:"1 HZ"},{speed:4,desc:"4 HZ"},{speed:8,desc:"8 HZ"},{speed:16,desc:"16 HZ"}],b.speed=4,b.outputStartIndex=232,b.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',b.reset=function(){d.reset(),e.reset(),b.error="",b.selectedLine=-1},b.executeStep=function(){b.checkPrgrmLoaded()||b.assemble();try{var a=d.step();return d.ip in b.mapping&&(b.selectedLine=b.mapping[d.ip]),a}catch(c){return b.error=c,!1}};var g;b.run=function(){b.checkPrgrmLoaded()||b.assemble(),b.isRunning=!0,g=c(function(){b.executeStep()===!0?b.run():b.isRunning=!1},1e3/b.speed)},b.stop=function(){c.cancel(g),b.isRunning=!1},b.checkPrgrmLoaded=function(){for(var a=0,b=e.data.length;b>a;a++)if(0!==e.data[a])return!0;return!1},b.getChar=function(a){var b=String.fromCharCode(a);return""===b.trim()?"  ":b},b.assemble=function(){try{b.reset();var a=f.go(b.code);b.mapping=a.mapping;var c=a.code;if(b.labels=a.labels,c.length>e.data.length)throw"Binary code does not fit into the memory. Max "+e.data.length+" bytes are allowed";for(var d=0,g=c.length;g>d;d++)e.data[d]=c[d]}catch(h){void 0!==h.line?(b.error=h.line+" | "+h.error,b.selectedLine=h.line):b.error=h.error}},b.jumpToLine=function(c){a[0].getElementById("sourceCode").scrollIntoView(),b.selectedLine=b.mapping[c]},b.isInstruction=function(a){return void 0!==b.mapping&&void 0!==b.mapping[a]&&b.displayInstr},b.getMemoryCellCss=function(a){return a>=b.outputStartIndex?"output-bg":b.isInstruction(a)?"instr-bg":a>d.sp&&a<=d.maxSP?"stack-bg":""},b.getMemoryInnerCellCss=function(a){return a===d.ip?"marker marker-ip":a===d.sp?"marker marker-sp":a===d.gpr[0]&&b.displayA?"marker marker-a":a===d.gpr[1]&&b.displayB?"marker marker-b":a===d.gpr[2]&&b.displayC?"marker marker-c":a===d.gpr[3]&&b.displayD?"marker marker-d":""}}]),app.filter("flag",function(){return function(a){return a.toString().toUpperCase()}}),app.filter("number",function(){return function(a,b){if(b){var c=a.toString(16).toUpperCase();return 1==c.length?"0"+c:c}return a.toString(10)}}),app.directive("selectLine",[function(){return{restrict:"A",link:function(a,b,c,d){a.$watch("selectedLine",function(){if(a.selectedLine>=0){for(var c=b[0].value.split("\n"),d=0,e=0;eCPU & Memory Clock speed: Instructions: - Show - Hide + Show + Show + Hide View: Hex Decimal diff --git a/src/app.js b/src/app.js deleted file mode 100644 index 65ee481..0000000 --- a/src/app.js +++ /dev/null @@ -1 +0,0 @@ -var app = angular.module('ASMSimulator', []); diff --git a/src/assembler/asm.js b/src/assembler/asm.js deleted file mode 100644 index c12ffd5..0000000 --- a/src/assembler/asm.js +++ /dev/null @@ -1,636 +0,0 @@ -app.service('assembler', ['opcodes', function (opcodes) { - return { - 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*))?)?)?/; - - // Regex group indexes for operands - var op1_group = 3; - 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 - var mapping = {}; - // Hash map of label used to replace the labels after the assembler generated the code - var labels = {}; - // Hash of uppercase labels used to detect duplicates - var normalizedLabels = {}; - - // 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") { - return parseInt(input.slice(2), 16); - } 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 (regexNum.exec(input)) { - return parseInt(input, 10); - } else { - throw "Invalid number format"; - } - }; - - // Allowed registers: A, B, C, D, SP - var parseRegister = function (input) { - input = input.toUpperCase(); - - if (input === 'A') { - return 0; - } else if (input === 'B') { - return 1; - } else if (input === 'C') { - return 2; - } else if (input === 'D') { - return 3; - } else if (input === 'SP') { - 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 - }; - - // Allowed: Register, Label or Number; SP+/-Number is allowed for 'regaddress' type - var parseRegOrNumber = function (input, typeReg, typeNumber) { - var register = parseRegister(input); - - if (register !== undefined) { - return {type: typeReg, value: register}; - } else { - var label = parseLabel(input); - if (label !== undefined) { - return {type: typeNumber, value: label}; - } else { - if (typeReg === "regaddress") { - - register = parseOffsetAddressing(input); - - if (register !== undefined) { - return {type: typeReg, value: register}; - } - } - - var value = parseNumber(input); - - if (isNaN(value)) { - throw "Not a " + typeNumber + ": " + value; - } - else if (value < 0 || value > 255) - throw typeNumber + " must have a value between 0-255"; - - return {type: typeNumber, value: value}; - } - } - }; - - var parseLabel = function (input) { - return regexLabel.exec(input) ? input : undefined; - }; - - var getValue = function (input) { - switch (input.slice(0, 1)) { - case '[': // [number] or [register] - var address = input.slice(1, input.length - 1); - return parseRegOrNumber(address, "regaddress", "address"); - case '"': // "String" - 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}; - case "'": // 'C' - 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)}; - default: // REGISTER, NUMBER or LABEL - return parseRegOrNumber(input, "register", "number"); - } - }; - - var addLabel = function (label) { - var upperLabel = label.toUpperCase(); - if (upperLabel in normalizedLabels) - throw "Duplicate label: " + label; - - if (upperLabel === "A" || upperLabel === "B" || upperLabel === "C" || upperLabel === "D") - throw "Label contains keyword: " + upperLabel; - - 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++) { - try { - var match = regex.exec(lines[i]); - if (match[1] !== undefined || match[2] !== undefined) { - if (match[1] !== undefined) { - addLabel(match[1]); - } - - if (match[2] !== undefined) { - var instr = match[2].toUpperCase(); - var p1, p2, opCode; - - // Add mapping instr pos to line number - // Don't do it for DB as this is not a real instruction - if (instr !== 'DB') { - mapping[code.length] = i; - } - - switch (instr) { - case 'DB': - p1 = getValue(match[op1_group]); - - if (p1.type === "number") - code.push(p1.value); - else if (p1.type === "numbers") - for (var j = 0, k = p1.value.length; j < k; j++) { - code.push(p1.value[j]); - } - else - throw "DB does not support this operand"; - - 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") - opCode = opcodes.MOV_ADDRESS_TO_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.MOV_REGADDRESS_TO_REG; - else if (p1.type === "address" && p2.type === "register") - opCode = opcodes.MOV_REG_TO_ADDRESS; - else if (p1.type === "regaddress" && p2.type === "register") - opCode = opcodes.MOV_REG_TO_REGADDRESS; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.MOV_NUMBER_TO_REG; - else if (p1.type === "address" && p2.type === "number") - opCode = opcodes.MOV_NUMBER_TO_ADDRESS; - else if (p1.type === "regaddress" && p2.type === "number") - opCode = opcodes.MOV_NUMBER_TO_REGADDRESS; - else - throw "MOV does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'ADD': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.ADD_REG_TO_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.ADD_REGADDRESS_TO_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.ADD_ADDRESS_TO_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.ADD_NUMBER_TO_REG; - else - throw "ADD does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'SUB': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.SUB_REG_FROM_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.SUB_REGADDRESS_FROM_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.SUB_ADDRESS_FROM_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.SUB_NUMBER_FROM_REG; - else - throw "SUB does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'INC': - p1 = getValue(match[op1_group]); - checkNoExtraArg('INC', match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.INC_REG; - else - throw "INC does not support this operand"; - - code.push(opCode, p1.value); - - break; - case 'DEC': - p1 = getValue(match[op1_group]); - checkNoExtraArg('DEC', match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.DEC_REG; - else - throw "DEC does not support this operand"; - - code.push(opCode, p1.value); - - break; - case 'CMP': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.CMP_REG_WITH_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.CMP_REGADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.CMP_ADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.CMP_NUMBER_WITH_REG; - else - throw "CMP does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'JMP': - p1 = getValue(match[op1_group]); - checkNoExtraArg('JMP', match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JMP_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JMP_ADDRESS; - else - throw "JMP does not support this operands"; - - code.push(opCode, p1.value); - break; - case 'JC': - case 'JB': - case 'JNAE': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JC_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JC_ADDRESS; - else - throw instr + " does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'JNC': - case 'JNB': - case 'JAE': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JNC_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JNC_ADDRESS; - else - throw instr + "does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'JZ': - case 'JE': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JZ_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JZ_ADDRESS; - else - throw instr + " does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'JNZ': - case 'JNE': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JNZ_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JNZ_ADDRESS; - else - throw instr + " does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'JA': - case 'JNBE': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JA_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JA_ADDRESS; - else - throw instr + " does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'JNA': - case 'JBE': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.JNA_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.JNA_ADDRESS; - else - throw instr + " does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'PUSH': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.PUSH_REG; - else if (p1.type === "regaddress") - opCode = opcodes.PUSH_REGADDRESS; - else if (p1.type === "address") - opCode = opcodes.PUSH_ADDRESS; - else if (p1.type === "number") - opCode = opcodes.PUSH_NUMBER; - else - throw "PUSH does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'POP': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.POP_REG; - else - throw "PUSH does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'CALL': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.CALL_REGADDRESS; - else if (p1.type === "number") - opCode = opcodes.CALL_ADDRESS; - else - throw "CALL does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'RET': - checkNoExtraArg(instr, match[op1_group]); - - opCode = opcodes.RET; - - code.push(opCode); - break; - - case 'MUL': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.MUL_REG; - else if (p1.type === "regaddress") - opCode = opcodes.MUL_REGADDRESS; - else if (p1.type === "address") - opCode = opcodes.MUL_ADDRESS; - else if (p1.type === "number") - opCode = opcodes.MUL_NUMBER; - else - throw "MULL does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'DIV': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.DIV_REG; - else if (p1.type === "regaddress") - opCode = opcodes.DIV_REGADDRESS; - else if (p1.type === "address") - opCode = opcodes.DIV_ADDRESS; - else if (p1.type === "number") - opCode = opcodes.DIV_NUMBER; - else - throw "DIV does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'AND': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.AND_REG_WITH_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.AND_REGADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.AND_ADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.AND_NUMBER_WITH_REG; - else - throw "AND does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'OR': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.OR_REG_WITH_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.OR_REGADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.OR_ADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.OR_NUMBER_WITH_REG; - else - throw "OR does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'XOR': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.XOR_REG_WITH_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.XOR_REGADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.XOR_ADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.XOR_NUMBER_WITH_REG; - else - throw "XOR does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'NOT': - p1 = getValue(match[op1_group]); - checkNoExtraArg(instr, match[op2_group]); - - if (p1.type === "register") - opCode = opcodes.NOT_REG; - else - throw "NOT does not support this operand"; - - code.push(opCode, p1.value); - break; - case 'SHL': - case 'SAL': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.SHL_REG_WITH_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.SHL_REGADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.SHL_ADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.SHL_NUMBER_WITH_REG; - else - throw instr + " does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - case 'SHR': - case 'SAR': - p1 = getValue(match[op1_group]); - p2 = getValue(match[op2_group]); - - if (p1.type === "register" && p2.type === "register") - opCode = opcodes.SHR_REG_WITH_REG; - else if (p1.type === "register" && p2.type === "regaddress") - opCode = opcodes.SHR_REGADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "address") - opCode = opcodes.SHR_ADDRESS_WITH_REG; - else if (p1.type === "register" && p2.type === "number") - opCode = opcodes.SHR_NUMBER_WITH_REG; - else - throw instr + " does not support this operands"; - - code.push(opCode, p1.value, p2.value); - break; - default: - throw "Invalid instruction: " + match[2]; - } - } - } 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) !== ";") { - throw "Syntax error"; - } - } - } catch (e) { - throw {error: e, line: i}; - } - } - - // Replace label - 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]}; - } - } - } - - return {code: code, mapping: mapping, labels: labels}; - } - }; -}]); diff --git a/src/emulator/cpu.js b/src/emulator/cpu.js deleted file mode 100644 index f4522eb..0000000 --- a/src/emulator/cpu.js +++ /dev/null @@ -1,595 +0,0 @@ -app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) { - var cpu = { - step: function() { - var self = this; - - if (self.fault === true) { - throw "FAULT. Reset to continue."; - } - - try { - var checkGPR = function(reg) { - if (reg < 0 || reg >= self.gpr.length) { - throw "Invalid register: " + reg; - } else { - return reg; - } - }; - - var checkGPR_SP = function(reg) { - 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) { - self.gpr[reg] = value; - } else if(reg == self.gpr.length) { - 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"; - } - } else { - throw "Invalid register: " + reg; - } - }; - - var getGPR_SP = function(reg) - { - if(reg >= 0 && reg < self.gpr.length) { - return self.gpr[reg]; - } else if(reg == self.gpr.length) { - return self.sp; - } else { - throw "Invalid register: " + reg; - } - }; - - var indirectRegisterAddress = function(value) { - var reg = value % 8; - - var base; - if (reg < self.gpr.length) { - base = self.gpr[reg]; - } else { - base = self.sp; - } - - var offset = Math.floor(value / 8); - if ( offset > 15 ) { - offset = offset - 32; - } - - return base+offset; - }; - - var checkOperation = function(value) { - self.zero = false; - self.carry = false; - - if (value >= 256) { - self.carry = true; - value = value % 256; - } else if (value === 0) { - self.zero = true; - } else if (value < 0) { - self.carry = true; - value = 256 - (-value) % 256; - } - - return value; - }; - - var jump = function(newIP) { - if (newIP < 0 || newIP >= memory.data.length) { - throw "IP outside memory"; - } else { - 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) { - throw "Stack underflow"; - } - - return value; - }; - - var division = function(divisor) { - if (divisor === 0) { - throw "Division by 0"; - } - - return Math.floor(self.gpr[0] / divisor); - }; - - if (self.ip < 0 || self.ip >= memory.data.length) { - throw "Instruction pointer is outside of memory"; - } - - var regTo, regFrom, memFrom, memTo, number; - var instr = memory.load(self.ip); - switch(instr) { - case opcodes.NONE: - return false; // Abort step - case opcodes.MOV_REG_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = checkGPR_SP(memory.load(++self.ip)); - setGPR_SP(regTo,getGPR_SP(regFrom)); - self.ip++; - break; - case opcodes.MOV_ADDRESS_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - setGPR_SP(regTo,memory.load(memFrom)); - self.ip++; - break; - case opcodes.MOV_REGADDRESS_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - setGPR_SP(regTo,memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.MOV_REG_TO_ADDRESS: - memTo = memory.load(++self.ip); - regFrom = checkGPR_SP(memory.load(++self.ip)); - memory.store(memTo, getGPR_SP(regFrom)); - self.ip++; - break; - case opcodes.MOV_REG_TO_REGADDRESS: - regTo = memory.load(++self.ip); - regFrom = checkGPR_SP(memory.load(++self.ip)); - memory.store(indirectRegisterAddress(regTo), getGPR_SP(regFrom)); - self.ip++; - break; - case opcodes.MOV_NUMBER_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - number = memory.load(++self.ip); - setGPR_SP(regTo,number); - self.ip++; - break; - case opcodes.MOV_NUMBER_TO_ADDRESS: - memTo = memory.load(++self.ip); - number = memory.load(++self.ip); - memory.store(memTo, number); - self.ip++; - break; - case opcodes.MOV_NUMBER_TO_REGADDRESS: - regTo = memory.load(++self.ip); - number = memory.load(++self.ip); - memory.store(indirectRegisterAddress(regTo), number); - self.ip++; - break; - case opcodes.ADD_REG_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = checkGPR_SP(memory.load(++self.ip)); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + getGPR_SP(regFrom))); - self.ip++; - break; - case opcodes.ADD_REGADDRESS_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + memory.load(indirectRegisterAddress(regFrom)))); - self.ip++; - break; - case opcodes.ADD_ADDRESS_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + memory.load(memFrom))); - self.ip++; - break; - case opcodes.ADD_NUMBER_TO_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - number = memory.load(++self.ip); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + number)); - self.ip++; - break; - case opcodes.SUB_REG_FROM_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = checkGPR_SP(memory.load(++self.ip)); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - self.gpr[regFrom])); - self.ip++; - break; - case opcodes.SUB_REGADDRESS_FROM_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - memory.load(indirectRegisterAddress(regFrom)))); - self.ip++; - break; - case opcodes.SUB_ADDRESS_FROM_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - memory.load(memFrom))); - self.ip++; - break; - case opcodes.SUB_NUMBER_FROM_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - number = memory.load(++self.ip); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - number)); - self.ip++; - break; - case opcodes.INC_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) + 1)); - self.ip++; - break; - case opcodes.DEC_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - setGPR_SP(regTo,checkOperation(getGPR_SP(regTo) - 1)); - self.ip++; - break; - case opcodes.CMP_REG_WITH_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = checkGPR_SP(memory.load(++self.ip)); - checkOperation(getGPR_SP(regTo) - getGPR_SP(regFrom)); - self.ip++; - break; - case opcodes.CMP_REGADDRESS_WITH_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - checkOperation(getGPR_SP(regTo) - memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.CMP_ADDRESS_WITH_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - checkOperation(getGPR_SP(regTo) - memory.load(memFrom)); - self.ip++; - break; - case opcodes.CMP_NUMBER_WITH_REG: - regTo = checkGPR_SP(memory.load(++self.ip)); - number = memory.load(++self.ip); - checkOperation(getGPR_SP(regTo) - number); - self.ip++; - break; - case opcodes.JMP_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - jump(self.gpr[regTo]); - break; - case opcodes.JMP_ADDRESS: - number = memory.load(++self.ip); - jump(number); - break; - case opcodes.JC_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - if (self.carry) { - jump(self.gpr[regTo]); - } else { - self.ip++; - } - break; - case opcodes.JC_ADDRESS: - number = memory.load(++self.ip); - if (self.carry) { - jump(number); - } else { - self.ip++; - } - break; - case opcodes.JNC_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - if (!self.carry) { - jump(self.gpr[regTo]); - } else { - self.ip++; - } - break; - case opcodes.JNC_ADDRESS: - number = memory.load(++self.ip); - if (!self.carry) { - jump(number); - } else { - self.ip++; - } - break; - case opcodes.JZ_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - if (self.zero) { - jump(self.gpr[regTo]); - } else { - self.ip++; - } - break; - case opcodes.JZ_ADDRESS: - number = memory.load(++self.ip); - if (self.zero) { - jump(number); - } else { - self.ip++; - } - break; - case opcodes.JNZ_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - if (!self.zero) { - jump(self.gpr[regTo]); - } else { - self.ip++; - } - break; - case opcodes.JNZ_ADDRESS: - number = memory.load(++self.ip); - if (!self.zero) { - jump(number); - } else { - self.ip++; - } - break; - case opcodes.JA_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - if (!self.zero && !self.carry) { - jump(self.gpr[regTo]); - } else { - self.ip++; - } - break; - case opcodes.JA_ADDRESS: - number = memory.load(++self.ip); - if (!self.zero && !self.carry) { - jump(number); - } else { - self.ip++; - } - break; - case opcodes.JNA_REGADDRESS: // JNA REG - regTo = checkGPR(memory.load(++self.ip)); - if (self.zero || self.carry) { - jump(self.gpr[regTo]); - } else { - self.ip++; - } - break; - case opcodes.JNA_ADDRESS: - number = memory.load(++self.ip); - if (self.zero || self.carry) { - jump(number); - } else { - self.ip++; - } - break; - case opcodes.PUSH_REG: - regFrom = checkGPR(memory.load(++self.ip)); - push(self.gpr[regFrom]); - self.ip++; - break; - case opcodes.PUSH_REGADDRESS: - regFrom = memory.load(++self.ip); - push(memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.PUSH_ADDRESS: - memFrom = memory.load(++self.ip); - push(memory.load(memFrom)); - self.ip++; - break; - case opcodes.PUSH_NUMBER: - number = memory.load(++self.ip); - push(number); - self.ip++; - break; - case opcodes.POP_REG: - regTo = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = pop(); - self.ip++; - break; - case opcodes.CALL_REGADDRESS: - regTo = checkGPR(memory.load(++self.ip)); - push(self.ip+1); - jump(self.gpr[regTo]); - break; - case opcodes.CALL_ADDRESS: - number = memory.load(++self.ip); - push(self.ip+1); - jump(number); - break; - case opcodes.RET: - jump(pop()); - break; - case opcodes.MUL_REG: // A = A * REG - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[0] = checkOperation(self.gpr[0] * self.gpr[regFrom]); - self.ip++; - break; - case opcodes.MUL_REGADDRESS: // A = A * [REG] - regFrom = memory.load(++self.ip); - self.gpr[0] = checkOperation(self.gpr[0] * memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.MUL_ADDRESS: // A = A * [NUMBER] - memFrom = memory.load(++self.ip); - self.gpr[0] = checkOperation(self.gpr[0] * memory.load(memFrom)); - self.ip++; - break; - case opcodes.MUL_NUMBER: // A = A * NUMBER - number = memory.load(++self.ip); - self.gpr[0] = checkOperation(self.gpr[0] * number); - self.ip++; - break; - case opcodes.DIV_REG: // A = A / REG - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[0] = checkOperation(division(self.gpr[regFrom])); - self.ip++; - break; - case opcodes.DIV_REGADDRESS: // A = A / [REG] - regFrom = memory.load(++self.ip); - self.gpr[0] = checkOperation(division(memory.load(indirectRegisterAddress(regFrom)))); - self.ip++; - break; - case opcodes.DIV_ADDRESS: // A = A / [NUMBER] - memFrom = memory.load(++self.ip); - self.gpr[0] = checkOperation(division(memory.load(memFrom))); - self.ip++; - break; - case opcodes.DIV_NUMBER: // A = A / NUMBER - number = memory.load(++self.ip); - self.gpr[0] = checkOperation(division(number)); - self.ip++; - break; - case opcodes.AND_REG_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = checkOperation(self.gpr[regTo] & self.gpr[regFrom]); - self.ip++; - break; - case opcodes.AND_REGADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] & memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.AND_ADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] & memory.load(memFrom)); - self.ip++; - break; - case opcodes.AND_NUMBER_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - number = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] & number); - self.ip++; - break; - case opcodes.OR_REG_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = checkOperation(self.gpr[regTo] | self.gpr[regFrom]); - self.ip++; - break; - case opcodes.OR_REGADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] | memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.OR_ADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] | memory.load(memFrom)); - self.ip++; - break; - case opcodes.OR_NUMBER_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - number = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] | number); - self.ip++; - break; - case opcodes.XOR_REG_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ self.gpr[regFrom]); - self.ip++; - break; - case opcodes.XOR_REGADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.XOR_ADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ memory.load(memFrom)); - self.ip++; - break; - case opcodes.XOR_NUMBER_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - number = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] ^ number); - self.ip++; - break; - case opcodes.NOT_REG: - regTo = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = checkOperation(~self.gpr[regTo]); - self.ip++; - break; - case opcodes.SHL_REG_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = checkOperation(self.gpr[regTo] << self.gpr[regFrom]); - self.ip++; - break; - case opcodes.SHL_REGADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] << memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.SHL_ADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] << memory.load(memFrom)); - self.ip++; - break; - case opcodes.SHL_NUMBER_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - number = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] << number); - self.ip++; - break; - case opcodes.SHR_REG_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = checkGPR(memory.load(++self.ip)); - self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> self.gpr[regFrom]); - self.ip++; - break; - case opcodes.SHR_REGADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - regFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> memory.load(indirectRegisterAddress(regFrom))); - self.ip++; - break; - case opcodes.SHR_ADDRESS_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - memFrom = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> memory.load(memFrom)); - self.ip++; - break; - case opcodes.SHR_NUMBER_WITH_REG: - regTo = checkGPR(memory.load(++self.ip)); - number = memory.load(++self.ip); - self.gpr[regTo] = checkOperation(self.gpr[regTo] >>> number); - self.ip++; - break; - default: - throw "Invalid op code: " + instr; - } - - return true; - } catch(e) { - self.fault = true; - throw e; - } - }, - reset: function() { - var self = this; - self.maxSP = 231; - self.minSP = 0; - - self.gpr = [0, 0, 0, 0]; - self.sp = self.maxSP; - self.ip = 0; - self.zero = false; - self.carry = false; - self.fault = false; - } - }; - - cpu.reset(); - return cpu; -}]); diff --git a/src/emulator/memory.js b/src/emulator/memory.js deleted file mode 100644 index 8fe2b7a..0000000 --- a/src/emulator/memory.js +++ /dev/null @@ -1,37 +0,0 @@ -app.service('memory', [function () { - var memory = { - data: Array(256), - lastAccess: -1, - load: function (address) { - var self = this; - - if (address < 0 || address >= self.data.length) { - throw "Memory access violation at " + address; - } - - self.lastAccess = address; - return self.data[address]; - }, - store: function (address, value) { - var self = this; - - if (address < 0 || address >= self.data.length) { - throw "Memory access violation at " + address; - } - - self.lastAccess = address; - self.data[address] = value; - }, - reset: function () { - var self = this; - - self.lastAccess = -1; - for (var i = 0, l = self.data.length; i < l; i++) { - self.data[i] = 0; - } - } - }; - - memory.reset(); - return memory; -}]); diff --git a/src/emulator/opcodes.js b/src/emulator/opcodes.js deleted file mode 100644 index 1a94a13..0000000 --- a/src/emulator/opcodes.js +++ /dev/null @@ -1,80 +0,0 @@ -app.service('opcodes', [function() { - var opcodes = { - NONE: 0, - MOV_REG_TO_REG: 1, - MOV_ADDRESS_TO_REG: 2, - MOV_REGADDRESS_TO_REG: 3, - MOV_REG_TO_ADDRESS: 4, - MOV_REG_TO_REGADDRESS: 5, - MOV_NUMBER_TO_REG: 6, - MOV_NUMBER_TO_ADDRESS: 7, - MOV_NUMBER_TO_REGADDRESS: 8, - ADD_REG_TO_REG: 10, - ADD_REGADDRESS_TO_REG: 11, - ADD_ADDRESS_TO_REG: 12, - ADD_NUMBER_TO_REG: 13, - SUB_REG_FROM_REG: 14, - SUB_REGADDRESS_FROM_REG: 15, - SUB_ADDRESS_FROM_REG: 16, - SUB_NUMBER_FROM_REG: 17, - INC_REG: 18, - DEC_REG: 19, - CMP_REG_WITH_REG: 20, - CMP_REGADDRESS_WITH_REG: 21, - CMP_ADDRESS_WITH_REG: 22, - CMP_NUMBER_WITH_REG: 23, - JMP_REGADDRESS: 30, - JMP_ADDRESS: 31, - JC_REGADDRESS: 32, - JC_ADDRESS: 33, - JNC_REGADDRESS: 34, - JNC_ADDRESS: 35, - JZ_REGADDRESS: 36, - JZ_ADDRESS: 37, - JNZ_REGADDRESS: 38, - JNZ_ADDRESS: 39, - JA_REGADDRESS: 40, - JA_ADDRESS: 41, - JNA_REGADDRESS: 42, - JNA_ADDRESS: 43, - PUSH_REG: 50, - PUSH_REGADDRESS: 51, - PUSH_ADDRESS: 52, - PUSH_NUMBER: 53, - POP_REG: 54, - CALL_REGADDRESS: 55, - CALL_ADDRESS: 56, - RET: 57, - MUL_REG: 60, - MUL_REGADDRESS: 61, - MUL_ADDRESS: 62, - MUL_NUMBER: 63, - DIV_REG: 64, - DIV_REGADDRESS: 65, - DIV_ADDRESS: 66, - DIV_NUMBER: 67, - AND_REG_WITH_REG: 70, - AND_REGADDRESS_WITH_REG: 71, - AND_ADDRESS_WITH_REG: 72, - AND_NUMBER_WITH_REG: 73, - OR_REG_WITH_REG: 74, - OR_REGADDRESS_WITH_REG: 75, - OR_ADDRESS_WITH_REG: 76, - OR_NUMBER_WITH_REG: 77, - XOR_REG_WITH_REG: 78, - XOR_REGADDRESS_WITH_REG: 79, - XOR_ADDRESS_WITH_REG: 80, - XOR_NUMBER_WITH_REG: 81, - NOT_REG: 82, - SHL_REG_WITH_REG: 90, - SHL_REGADDRESS_WITH_REG: 91, - SHL_ADDRESS_WITH_REG: 92, - SHL_NUMBER_WITH_REG: 93, - SHR_REG_WITH_REG: 94, - SHR_REGADDRESS_WITH_REG: 95, - SHR_ADDRESS_WITH_REG: 96, - SHR_NUMBER_WITH_REG: 97 - }; - - return opcodes; -}]); diff --git a/src/ui/controller.js b/src/ui/controller.js deleted file mode 100644 index 256d870..0000000 --- a/src/ui/controller.js +++ /dev/null @@ -1,156 +0,0 @@ -app.controller('Ctrl', ['$document', '$scope', '$timeout', 'cpu', 'memory', 'assembler', function ($document, $scope, $timeout, cpu, memory, assembler) { - $scope.memory = memory; - $scope.cpu = cpu; - $scope.error = ''; - $scope.isRunning = false; - $scope.displayHex = true; - $scope.displayInstr = true; - $scope.displayA = false; - $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.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 () { - cpu.reset(); - memory.reset(); - $scope.error = ''; - $scope.selectedLine = -1; - }; - - $scope.executeStep = function () { - if (!$scope.checkPrgrmLoaded()) { - $scope.assemble(); - } - - try { - // Execute - var res = cpu.step(); - - // Mark in code - if (cpu.ip in $scope.mapping) { - $scope.selectedLine = $scope.mapping[cpu.ip]; - } - - return res; - } catch (e) { - $scope.error = e; - return false; - } - }; - - var runner; - $scope.run = function () { - if (!$scope.checkPrgrmLoaded()) { - $scope.assemble(); - } - - $scope.isRunning = true; - runner = $timeout(function () { - if ($scope.executeStep() === true) { - $scope.run(); - } else { - $scope.isRunning = false; - } - }, 1000 / $scope.speed); - }; - - $scope.stop = function () { - $timeout.cancel(runner); - $scope.isRunning = false; - }; - - $scope.checkPrgrmLoaded = function () { - for (var i = 0, l = memory.data.length; i < l; i++) { - if (memory.data[i] !== 0) { - return true; - } - } - - return false; - }; - - $scope.getChar = function (value) { - var text = String.fromCharCode(value); - - if (text.trim() === '') { - return '\u00A0\u00A0'; - } else { - return text; - } - }; - - $scope.assemble = function () { - try { - $scope.reset(); - - var assembly = assembler.go($scope.code); - $scope.mapping = assembly.mapping; - var binary = assembly.code; - $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"; - - for (var i = 0, l = binary.length; i < l; i++) { - memory.data[i] = binary[i]; - } - } catch (e) { - if (e.line !== undefined) { - $scope.error = e.line + " | " + e.error; - $scope.selectedLine = e.line; - } else { - $scope.error = e.error; - } - } - }; - - $scope.jumpToLine = function (index) { - $document[0].getElementById('sourceCode').scrollIntoView(); - $scope.selectedLine = $scope.mapping[index]; - }; - - - $scope.isInstruction = function (index) { - return $scope.mapping !== undefined && - $scope.mapping[index] !== undefined && - $scope.displayInstr; - }; - - $scope.getMemoryCellCss = function (index) { - if (index >= $scope.outputStartIndex) { - return 'output-bg'; - } else if ($scope.isInstruction(index)) { - return 'instr-bg'; - } else if (index > cpu.sp && index <= cpu.maxSP) { - return 'stack-bg'; - } else { - return ''; - } - }; - - $scope.getMemoryInnerCellCss = function (index) { - if (index === cpu.ip) { - return 'marker marker-ip'; - } else if (index === cpu.sp) { - return 'marker marker-sp'; - } else if (index === cpu.gpr[0] && $scope.displayA) { - return 'marker marker-a'; - } else if (index === cpu.gpr[1] && $scope.displayB) { - return 'marker marker-b'; - } else if (index === cpu.gpr[2] && $scope.displayC) { - return 'marker marker-c'; - } else if (index === cpu.gpr[3] && $scope.displayD) { - return 'marker marker-d'; - } else { - return ''; - } - }; -}]); diff --git a/src/ui/flag.filter.js b/src/ui/flag.filter.js deleted file mode 100644 index 086297c..0000000 --- a/src/ui/flag.filter.js +++ /dev/null @@ -1,5 +0,0 @@ -app.filter('flag', function() { - return function(input) { - return input.toString().toUpperCase(); - }; -}); diff --git a/src/ui/number.filter.js b/src/ui/number.filter.js deleted file mode 100644 index c1e36a7..0000000 --- a/src/ui/number.filter.js +++ /dev/null @@ -1,10 +0,0 @@ -app.filter('number', function() { - return function(input, isHex) { - if (isHex) { - var hex = input.toString(16).toUpperCase(); - return hex.length == 1 ? "0" + hex: hex; - } else { - return input.toString(10); - } - }; -}); diff --git a/src/ui/select-line.directive.js b/src/ui/select-line.directive.js deleted file mode 100644 index 85767cb..0000000 --- a/src/ui/select-line.directive.js +++ /dev/null @@ -1,42 +0,0 @@ -// 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 () { - 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) { - break; - } - startPos += (lines[x].length + 1); - } - - var endPos = lines[scope.selectedLine].length + startPos; - - // Chrome / Firefox - if (typeof(element[0].selectionStart) != "undefined") { - element[0].focus(); - element[0].selectionStart = startPos; - element[0].selectionEnd = endPos; - } - - // IE - if (document.selection && document.selection.createRange) { - element[0].focus(); - element[0].select(); - var range = document.selection.createRange(); - range.collapse(true); - range.moveEnd("character", endPos); - range.moveStart("character", startPos); - range.select(); - } - } - }); - } - }; -}]); diff --git a/src/ui/start.filter.js b/src/ui/start.filter.js deleted file mode 100644 index f22afc8..0000000 --- a/src/ui/start.filter.js +++ /dev/null @@ -1,6 +0,0 @@ -app.filter('startFrom', function() { - return function(input, start) { - start = +start; //parse to int - return input.slice(start); - }; -}); diff --git a/src/ui/tab-support.directive.js b/src/ui/tab-support.directive.js deleted file mode 100644 index 5f4498a..0000000 --- a/src/ui/tab-support.directive.js +++ /dev/null @@ -1,20 +0,0 @@ -app.directive('tabSupport', [function () { - return { - restrict: 'A', - link: function (scope, element, attrs, controller) { - element.bind("keydown", function (e) { - if (e.keyCode === 9) { - var val = this.value; - var start = this.selectionStart; - var end = this.selectionEnd; - - this.value = val.substring(0, start) + '\t' + val.substring(end); - this.selectionStart = this.selectionEnd = start + 1; - - e.preventDefault(); - return false; - } - }); - } - }; -}]);