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