From d3134aa9e67625bf83d6538d4cb1e7c42f383238 Mon Sep 17 00:00:00 2001 From: n loewen Date: Thu, 3 Aug 2023 15:50:37 +0100 Subject: [PATCH] Add constants to assembler --- assembler.js | 59 +++++++++++++++++++++++++++++-------- readme.md | 13 ++++++-- test-programs/constants.asm | 7 +++++ 3 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 test-programs/constants.asm diff --git a/assembler.js b/assembler.js index bf82b0f..bccf98d 100644 --- a/assembler.js +++ b/assembler.js @@ -34,9 +34,10 @@ function decodeInstructions(str) { machineCode[0] = POINTER_TO_START_OF_DISPLAY_MEM; let labels = {}; + let constants = {}; let IP = INITIAL_IP_ADDRESS; for (let i = 0; i < lines.length; i++) { - dbg(1, ''); + dbg(2, ''); dbgGroup(1, `Input line ${i}, IP ${num2hex(IP)}`); dbg(3, `> ${lines[i]}`); let line = stripWhitespaceFromEnds(stripComments(lines[i])); @@ -49,11 +50,14 @@ function decodeInstructions(str) { continue; } - // Handle labels -- anchors + + // HANDLE OPS + + // Handle label definitions if (line.startsWith('@')) { // TODO: validate label // validateLabel(line); - label = line.substring(1); // strip '@' + let label = line.substring(1); // strip '@' if (label in labels) { labels[label].pointsToByte = IP; @@ -72,21 +76,36 @@ function decodeInstructions(str) { let op_arg_array = line.split(" "); // split line into an array of [op, arg] let opName = op_arg_array[0].toLowerCase(); - let addressingMode = 'direct'; // Must be "direct" or "indirect" let arg_str = op_arg_array[1]; let arg_num = null; + let addressingMode = 'direct'; // Must be "direct" or "indirect" + // Handle constant definitions + if (opName.startsWith('=')) { + // TODO: validate constant + let constantName = opName.substring(1); // strip '>' + let constantValue = arg_str; + constants[constantName] = constantValue; + dbg(2, `constants:`); + dbg(2, constants); + continue; + } + + // Handle mnemonics without arguments (eg END) ... if (typeof arg_str === 'undefined') { - // Handle mnemonics without arguments (eg END) ... if (mnemonicsWithOptionalArgs.indexOf(opName) < 0) { console.error(`Missing opcode: ${line}`); throw new Error("Missing opcode"); } arg_num = 0; + + + // HANDLE ARGUMENTS + + // Handle references to labels } else if (arg_str.startsWith('@')) { - // Handle mnemonics with pointers to labels // TODO: validate label // validateLabel(line); - label = arg_str.substring(1); // strip '@' + let label = arg_str.substring(1); // strip '@' arg_num = 0; if (label in labels) { @@ -100,8 +119,24 @@ function decodeInstructions(str) { } dbg(2, `pointsToByte: ${labels[label].pointsToByte}`); dbg(2, `bytesToReplace: ${labels[label].bytesToReplace}`); + + // Handle references to constants + } else if (arg_str.startsWith('=')) { + arg_str = arg_str.substring(1) // strip '>' + dbg(2, `argument references '${arg_str}'`); + arg_str = constants[arg_str]; + dbg(2, `arg_str from '${arg_str}`); + + // Handle references to constants in indirect mode + } else if (arg_str.startsWith("(=")) { + addressingMode = "indirect"; + arg_str = arg_str.replace("(=", ""); + arg_str = arg_str.replace(")", ""); + dbg(2, `INDY - argument references '${arg_str}'`); + arg_str = constants[arg_str]; + + // Handle indirect expressions } else if (arg_str.startsWith("(")) { - // Handle indirect expressions addressingMode = "indirect"; arg_str = arg_str.replace("(", ""); arg_str = arg_str.replace(")", ""); @@ -119,7 +154,7 @@ function decodeInstructions(str) { } } - // Decode! + // DECODE! op = mnemonics2opcodes[opName][addressingMode]; machineCode.push(op); @@ -130,11 +165,11 @@ function decodeInstructions(str) { }; dbg(1, ''); - dbgGroup(1, 'Memory before filling in label pointers'); + dbgGroup(1, 'Memory before filling in label constants'); dbgExec(1, () => logMemory(machineCode)); - dbgGroupEnd(1, 'Memory before filling in label pointers'); + dbgGroupEnd(1, 'Memory before filling in label constants'); - // Backfill label pointers + // Backfill label references for (let k of Object.keys(labels)) { dbgGroup(2, `@${k}`); let label = labels[k]; diff --git a/readme.md b/readme.md index e84bd81..bc286bd 100644 --- a/readme.md +++ b/readme.md @@ -10,12 +10,14 @@ ### Features -- [ ] Make $0F a NOP +- [ ] Assembler: pad to 256 bytes, OR, to start, always add an END +- [x] Add constants to assembler +- [ ] Keypad +- [ ] Add single-stepping +- [x] Make $0F a NOP - [ ] In assembler.js: validateLabel() - [ ] In assemble.js: print better output to stdout - [ ] Add a function for logging just a specific range of memory -- [ ] Add single-stepping -- [ ] Add variables to assembler ### Under-the-hood improvements @@ -104,5 +106,10 @@ Assemble and run, with debug output: ; the label will be replaced with ; the address of the label + =foo $FF ; define a constant + ; (must be defined before it is referenced) + + ADD =foo ; use a constant as an operand + - Hexadecimal numbers are preceded by a `$` - Whitespace is ignored \ No newline at end of file diff --git a/test-programs/constants.asm b/test-programs/constants.asm new file mode 100644 index 0000000..ddc5ed6 --- /dev/null +++ b/test-programs/constants.asm @@ -0,0 +1,7 @@ +;; Test constants +=foo $01 +=bar $02 +ADD =foo +STO =bar +STO (=bar) +END \ No newline at end of file