diff --git a/sketches/assembler_sketch.js b/sketches/assembler_sketch.js new file mode 100644 index 0000000..d5af2b8 --- /dev/null +++ b/sketches/assembler_sketch.js @@ -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); +} \ No newline at end of file