-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlmc.js
192 lines (176 loc) · 5.25 KB
/
lmc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//Requiring correct modules.
var fs = require('fs');
//Setting version.
var currentver = 1;
var outer = this;
//Creating all memory slots.
var mem = [];
for (var i=0; i<100; i++) {
mem.push(000);
}
//Creating ACC, PC, IR, and AR.
var acc = 0;
var pc = 0;
var ir = 0;
var ar = 0;
//Reading from file.
if (process.argv.length<3) {
console.log("LMC E00: Usage is "+process.argv[1]+" [filename].lms");
process.exit(1);
} else {
//Checking file extension validity.
var filename = process.argv[2];
var validfile = false;
var fileext = filename.substring(filename.length-4);
if (fileext!=".lms") {
console.log("LMC E01: Invalid file extension '"+fileext+"'.");
process.exit(1);
} else {
//EXT Valid, sending to memory loader.
memload(filename);
}
}
function memload(filename) {
//Attempting to read file.
try {
fs.readFile(filename, 'utf8', function(err, data) {
if (err) throw err;
console.log("OK: Loaded LMC file.");
//Splitting data into separate lines.
data = data.split("\r\n");
//Splitting split data into addresses and commands.
for (i in data) {
data[i] = data[i].split(" ");
}
//Saving instructions in file to addresses.
for (i in data) {
//Removing header.
if (i!=0) {
//Verifying they're valid addresses.
try {
dint = parseInt(data[i][0]);
}
catch (err) {
console.log("LMC EO3: Invalid address at line "+(i+1)+".");
process.exit(1);
}
//Checking address is within range.#
if (dint>99 || dint<0) {
console.log("LMC EO4: Address out of range at line "+(i+1)+".");
process.exit(1);
} else {
//Checking operations are 3 long.
console.log(data[i]);
if (data[i][1].length==3) {
//Valid, loading to memory.
mem[dint] = data[i][1];
} else {
//Invalid length.
console.log("LMC EO5: Invalid opcode length, address "+i+".");
process.exit(1);
}
}
} else {
//Loading filename, versions.
outer.fname = data[0][2].replace("_", " ");
outer.version = data[0][3];
outer.compiledate = data[0][1];
}
}
//All memory saved, checking version is not future.
if (outer.version>currentver) {
console.log("LMC EO8: File version ahead of interpreter, download latest source.");
process.exit(1);
}
//File valid, interpreting.
interpreter(0);
});
}
catch (err) {
console.log("LMC E02: Failure loading LMC file.");
process.exit(1);
}
}
//Interpreter function, processes opcodes and provides function.
//Takes a starting address.
function interpreter(s) {
//Printing header.
console.log(" ");
console.log(outer.fname+ " | "+outer.compiledate+" | LMCv"+outer.version);
console.log("--------------------");
//Looping through memory, checking for start address.
for (i in mem) {
//Check for optype from start address onward.
if (i>=s) {
var opcode = parseInt(mem[i].substring(0,1));
var opadd = parseInt(mem[i].substring(1));
var op = mem[i];
if (opcode==5 && op.length==3) {
//LOAD
//Set accumulator to value.
acc = mem[opadd];
//Sanitizing.
acc = parseInt(acc);
console.log("Loaded VAL "+acc+" from location "+opadd+".");
} else if (opcode==3 && op.length==3) {
//STORE
//Set address value to ACC.
mem[opadd] = acc;
console.log("Saved VAL "+acc+" to location "+opadd+".");
} else if (opcode==1 && op.length==3) {
//ADD
//Add accumulator value to address.
acc+=parseInt(mem[opadd]);
if (acc>999) {
console.log("LMC EO7: Accumulator overflow, val>999.");
process.exit(1);
}
console.log("Added VAL "+mem[opadd]+" to ACC.");
} else if (opcode==2 && op.length==3) {
//SUB
//Take address value from ACC.
acc-=parseInt(mem[opadd]);
console.log("Took VAL "+mem[opadd]+" from ACC.");
} else if (opcode==7 && op.length==3) {
//BIZ
//Branch if Zero
if (acc==0) {
i=parseInt(mem[opadd]);
console.log("PC set to VAL "+mem[opadd]+".");
} else {
console.log("BIZ failed, ACC not zero.");
}
} else if (opcode==8 && op.length==3) {
//BIZOP
//Branch if Zero or Positive
if (acc==0 || acc>=0 && op.length==3) {
i=parseInt(mem[opadd]);
console.log("PC set to VAL "+mem[opadd]+".");
} else {
console.log("BIZOP failed, ACC not zero or positive.");
}
} else if (opcode==6 && op.length==3) {
//BRA
//Branch Always
i=parseInt(mem[opadd]);
console.log("PC set to VAL "+mem[opadd]+".");
} else if (op==901 && op.length==3) {
//INP
//Taking input from user using prompt.
} else if (op==902 && op.length==3) {
//OUT
//Outputting to console.
console.log("OUTPUT: "+acc);
} else if (op==000) {
//HLT
//Terminating for loop.
console.log("EOF, halting...");
break;
} else {
//No command found, invalid injected code or before halt.
console.log("LMC EO6: Invalid operation at address "+i+", operation "+op+". Have you placed data before a halt?");
process.exit(1);
}
}
}
}