diff --git a/assembler.js b/assembler.js index 7918794..def5161 100644 --- a/assembler.js +++ b/assembler.js @@ -76,13 +76,15 @@ function preparseSourceCode(source) { } return lines.map((line, index) => { - dbg(1, ` ${line}`); + dbg(1, ` in: ${line}`); let info = { number: index + 1, source: line, sanitized: stripWhitespaceFromEnds(stripComments(line)), type: getLineType(line), }; + dbg(1, ` → ${info.number} - ${info.type}: ${info.sanitized}`); + dbg(1, ``); if (info.type === 'code') { const op_arg_array = info.sanitized.split(/\s+/); // split line into an array of [op, arg] @@ -147,6 +149,7 @@ function handleConstantDefinitions(op, arg, IP, constants) { constantValue = IP.toString(); } constants[constantName] = constantValue; + dbg(1, ''); dbg(1, `Constants:`); dbg(1, constants); dbg(1, ''); @@ -208,9 +211,24 @@ function decodeInstructions(source) { // dbg(2, line); if (line.type === 'code') { const op = line.operation; - let arg = null; + + let sourceArgument; // TODO remove null? if (typeof line.argument != 'undefined') { - arg = line.argument; + sourceArgument = line.argument; + } else { + // If this isn't a label definition, + // or one of the ops with optional arguments, + // then it's an error + if (!line.operation.startsWith('@')) { + if (mnemonicsWithOptionalArgs.indexOf(line.operation) < 0) { + console.error(`Missing opcode for line ${line.number}: ${line.source}`); + throw new Error("Missing opcode"); + } else { + // It *is* one of the special optional-arg ops + // So let's fill in the implicit operand with $00 + sourceArgument = '0'; + } + } } @@ -224,13 +242,13 @@ function decodeInstructions(source) { // Opcodes - Handle constant definitions if (op.startsWith(ASM_CONSTANT_PREFIX)) { - constants = handleConstantDefinitions(op, arg, IP, constants); + constants = handleConstantDefinitions(op, sourceArgument, IP, constants); continue; } // Opcodes - Handle setting value of IP if (op.startsWith(ASM_IP_LABEL)) { - IP = parseInt(arg); + IP = parseInt(sourceArgument); continue; } @@ -248,17 +266,8 @@ function decodeInstructions(source) { // Now that it can't be a label or a constant, normalize the opcode line.operation = line.operation.toLowerCase(); - // Opcodes - Handle mnemonics without operands (eg END) - if (arg === null) { - if (mnemonicsWithOptionalArgs.indexOf(line.operation) < 0) { - console.error(`Missing opcode for line ${line.number}: ${line.source}`); - throw new Error("Missing opcode"); - } - decodedArg = 0; - } - // Operands - Handle references to labels - if (arg !== null && arg.startsWith(ASM_LABEL_PREFIX)) { + if (sourceArgument.startsWith(ASM_LABEL_PREFIX)) { let label = line.argument.substring(1); // strip label prefix if (label in labels) { dbg(1, `'${label}' already in labels object`); @@ -276,30 +285,30 @@ function decodeInstructions(source) { } // Operands - Handle references to the Instruction Pointer - if (arg !== null && arg === ASM_IP_LABEL) { + if (sourceArgument === ASM_IP_LABEL) { dbg(1, ` References current IP - ${IP}`); decodedArg = IP; } // Operands - Handle references to constants - if (arg !== null && arg.startsWith(ASM_CONSTANT_PREFIX)) { - dbg(1, `References '${arg}'`); - decodedArg = decodeNumericOp(constants[arg.substring(1)]); // substring(1) strips '>' + if (sourceArgument.startsWith(ASM_CONSTANT_PREFIX)) { + dbg(1, `References '${sourceArgument}'`); + decodedArg = decodeNumericOp(constants[sourceArgument.substring(1)]); // substring(1) strips '>' } // Operands - Handle references to constants in indirect mode - if (arg !== null && arg.startsWith(`(${ASM_CONSTANT_PREFIX}`)) { + if (sourceArgument.startsWith(`(${ASM_CONSTANT_PREFIX}`)) { addressingMode = "indirect"; - dbg(1, `(Indirectly) References '${arg}'`); - let constName = arg.replace(`(${ASM_CONSTANT_PREFIX}`, ""); + dbg(1, `(Indirectly) References '${sourceArgument}'`); + let constName = sourceArgument.replace(`(${ASM_CONSTANT_PREFIX}`, ""); constName = constName.replace(")", ""); decodedArg = decodeNumericOp(constants[constName]); } // Operands - Handle indirect expressions - if (arg !== null && decodedArg === null && arg.startsWith("(")) { + if (decodedArg === null && sourceArgument.startsWith("(")) { addressingMode = "indirect"; - let indyTemp = arg.replace("(", "").replace(")", ""); + let indyTemp = sourceArgument.replace("(", "").replace(")", ""); decodedArg = decodeNumericOp(indyTemp); } @@ -308,13 +317,11 @@ function decodeInstructions(source) { decodedOp = mnemonics2opcodes[line.operation][addressingMode]; } - // Decode regular operands if (decodedArg === null) { decodedArg = decodeNumericOp(line.argument); } - machineCode[IP] = decodedOp; machineCode[IP + 1] = decodedArg; @@ -340,6 +347,7 @@ function decodeInstructions(source) { }; } + dbg(1, ''); dbgGroup(1, 'Memory before filling in label constants'); dbgExec(1, () => logMemory(new Uint8Array(machineCode))); dbgGroupEnd(1);