// 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 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 new Uint8Array(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 exports.assemble = (str) => { return decodeMultipleInstructions(str); }