Create a simple assembler
This commit is contained in:
parent
62fd07fcaa
commit
74c7f3a657
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Usage: `node assembler_sketch.js assembly.asm`
|
||||||
|
|
||||||
|
// Syntax:
|
||||||
|
// ADD $01 ; comments follow a `;`
|
||||||
|
// ADD $FF ; this is direct addressing
|
||||||
|
// ADD ($CC) ; this is indirect addressing
|
||||||
|
// END ; END, CFC, and CHP don't require arguments
|
||||||
|
// ; (a default value of 0 will be used as their operand)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const filename = process.argv[2];
|
||||||
|
|
||||||
|
const mnemonicsWithOptionalArgs = ['end', 'cfc', 'chp'];
|
||||||
|
const mnemonics2opcodes = {
|
||||||
|
end: { direct: 0, indirect: 0 },
|
||||||
|
sto: { direct: 1, indirect: 2 },
|
||||||
|
lda: { direct: 3, indirect: 4 },
|
||||||
|
add: { direct: 5, indirect: 6 },
|
||||||
|
sub: { direct: 7, indirect: 8 },
|
||||||
|
hop: { direct: 9, indirect: 10 },
|
||||||
|
jmp: { direct: 11, indirect: 12 },
|
||||||
|
cfc: { direct: 13, indirect: 13 },
|
||||||
|
chp: { direct: 14, indirect: 14 },
|
||||||
|
};
|
||||||
|
|
||||||
|
function decodeMultipleInstructions(str) {
|
||||||
|
let lines = str.split(/\n/); // returns an array of lines
|
||||||
|
let output = [];
|
||||||
|
lines.forEach( (l) => {
|
||||||
|
let stripped = stripWhitespaceFromEnds(stripComments(l));
|
||||||
|
let decoded = decodeInstruction(stripped);
|
||||||
|
output.push(decoded.op);
|
||||||
|
output.push(decoded.arg);
|
||||||
|
});
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeInstruction(line) {
|
||||||
|
let addressingMode = "direct"; // Must be "direct" or "indirect"
|
||||||
|
op_arg_array = line.split(" ");
|
||||||
|
let opName = op_arg_array[0].toLowerCase();
|
||||||
|
|
||||||
|
// Handle mnemonics without arguments (eg END)
|
||||||
|
if (op_arg_array.length < 2) { // No argument
|
||||||
|
if (mnemonicsWithOptionalArgs.indexOf(opName) < 0) {
|
||||||
|
throw error("Missing opcode");
|
||||||
|
}
|
||||||
|
let machineOp = mnemonics2opcodes[opName][addressingMode];
|
||||||
|
return { op: machineOp, arg: 0 };
|
||||||
|
}
|
||||||
|
// Handle mnemonics with arguments (eg ADD $FF)
|
||||||
|
let arg_str = op_arg_array[1];
|
||||||
|
if (arg_str.startsWith("(")) {
|
||||||
|
addressingMode = "indirect";
|
||||||
|
arg_str = arg_str.replace("(", "");
|
||||||
|
arg_str = arg_str.replace(")", "");
|
||||||
|
}
|
||||||
|
if (arg_str.startsWith("$")) {
|
||||||
|
arg_str = arg_str.replace("$", "");
|
||||||
|
arg_num = hex2num(arg_str);
|
||||||
|
} else {
|
||||||
|
arg_num = parseInt(arg_str);
|
||||||
|
}
|
||||||
|
let machineOp = mnemonics2opcodes[opName][addressingMode];
|
||||||
|
return { op: machineOp, arg: arg_num };
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripComments(line) {
|
||||||
|
return line.replace(/;.+/,"");
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripWhitespaceFromEnds(line) {
|
||||||
|
line = line.replace(/^\s+/,"");
|
||||||
|
line = line.replace(/\s+$/,"");
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hex2num(hex) { return parseInt(hex, 16) };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// RUN IT
|
||||||
|
|
||||||
|
try {
|
||||||
|
// console.log(`Reading ${filename}`);
|
||||||
|
const inputFile_str = fs.readFileSync(filename, 'utf8');
|
||||||
|
console.log(decodeMultipleInstructions(inputFile_str));
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue