Add constants to assembler
This commit is contained in:
parent
297daafc89
commit
d3134aa9e6
59
assembler.js
59
assembler.js
|
|
@ -34,9 +34,10 @@ function decodeInstructions(str) {
|
||||||
machineCode[0] = POINTER_TO_START_OF_DISPLAY_MEM;
|
machineCode[0] = POINTER_TO_START_OF_DISPLAY_MEM;
|
||||||
|
|
||||||
let labels = {};
|
let labels = {};
|
||||||
|
let constants = {};
|
||||||
let IP = INITIAL_IP_ADDRESS;
|
let IP = INITIAL_IP_ADDRESS;
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
dbg(1, '');
|
dbg(2, '');
|
||||||
dbgGroup(1, `Input line ${i}, IP ${num2hex(IP)}`);
|
dbgGroup(1, `Input line ${i}, IP ${num2hex(IP)}`);
|
||||||
dbg(3, `> ${lines[i]}`);
|
dbg(3, `> ${lines[i]}`);
|
||||||
let line = stripWhitespaceFromEnds(stripComments(lines[i]));
|
let line = stripWhitespaceFromEnds(stripComments(lines[i]));
|
||||||
|
|
@ -49,11 +50,14 @@ function decodeInstructions(str) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle labels -- anchors
|
|
||||||
|
// HANDLE OPS
|
||||||
|
|
||||||
|
// Handle label definitions
|
||||||
if (line.startsWith('@')) {
|
if (line.startsWith('@')) {
|
||||||
// TODO: validate label
|
// TODO: validate label
|
||||||
// validateLabel(line);
|
// validateLabel(line);
|
||||||
label = line.substring(1); // strip '@'
|
let label = line.substring(1); // strip '@'
|
||||||
|
|
||||||
if (label in labels) {
|
if (label in labels) {
|
||||||
labels[label].pointsToByte = IP;
|
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 op_arg_array = line.split(" "); // split line into an array of [op, arg]
|
||||||
let opName = op_arg_array[0].toLowerCase();
|
let opName = op_arg_array[0].toLowerCase();
|
||||||
let addressingMode = 'direct'; // Must be "direct" or "indirect"
|
|
||||||
let arg_str = op_arg_array[1];
|
let arg_str = op_arg_array[1];
|
||||||
let arg_num = null;
|
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') {
|
if (typeof arg_str === 'undefined') {
|
||||||
// Handle mnemonics without arguments (eg END) ...
|
|
||||||
if (mnemonicsWithOptionalArgs.indexOf(opName) < 0) {
|
if (mnemonicsWithOptionalArgs.indexOf(opName) < 0) {
|
||||||
console.error(`Missing opcode: ${line}`);
|
console.error(`Missing opcode: ${line}`);
|
||||||
throw new Error("Missing opcode");
|
throw new Error("Missing opcode");
|
||||||
}
|
}
|
||||||
arg_num = 0;
|
arg_num = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// HANDLE ARGUMENTS
|
||||||
|
|
||||||
|
// Handle references to labels
|
||||||
} else if (arg_str.startsWith('@')) {
|
} else if (arg_str.startsWith('@')) {
|
||||||
// Handle mnemonics with pointers to labels
|
|
||||||
// TODO: validate label // validateLabel(line);
|
// TODO: validate label // validateLabel(line);
|
||||||
label = arg_str.substring(1); // strip '@'
|
let label = arg_str.substring(1); // strip '@'
|
||||||
arg_num = 0;
|
arg_num = 0;
|
||||||
|
|
||||||
if (label in labels) {
|
if (label in labels) {
|
||||||
|
|
@ -100,8 +119,24 @@ function decodeInstructions(str) {
|
||||||
}
|
}
|
||||||
dbg(2, `pointsToByte: ${labels[label].pointsToByte}`);
|
dbg(2, `pointsToByte: ${labels[label].pointsToByte}`);
|
||||||
dbg(2, `bytesToReplace: ${labels[label].bytesToReplace}`);
|
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("(")) {
|
} else if (arg_str.startsWith("(")) {
|
||||||
// Handle indirect expressions
|
|
||||||
addressingMode = "indirect";
|
addressingMode = "indirect";
|
||||||
arg_str = arg_str.replace("(", "");
|
arg_str = arg_str.replace("(", "");
|
||||||
arg_str = arg_str.replace(")", "");
|
arg_str = arg_str.replace(")", "");
|
||||||
|
|
@ -119,7 +154,7 @@ function decodeInstructions(str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode!
|
// DECODE!
|
||||||
op = mnemonics2opcodes[opName][addressingMode];
|
op = mnemonics2opcodes[opName][addressingMode];
|
||||||
|
|
||||||
machineCode.push(op);
|
machineCode.push(op);
|
||||||
|
|
@ -130,11 +165,11 @@ function decodeInstructions(str) {
|
||||||
};
|
};
|
||||||
|
|
||||||
dbg(1, '');
|
dbg(1, '');
|
||||||
dbgGroup(1, 'Memory before filling in label pointers');
|
dbgGroup(1, 'Memory before filling in label constants');
|
||||||
dbgExec(1, () => logMemory(machineCode));
|
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)) {
|
for (let k of Object.keys(labels)) {
|
||||||
dbgGroup(2, `@${k}`);
|
dbgGroup(2, `@${k}`);
|
||||||
let label = labels[k];
|
let label = labels[k];
|
||||||
|
|
|
||||||
13
readme.md
13
readme.md
|
|
@ -10,12 +10,14 @@
|
||||||
|
|
||||||
### Features
|
### 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 assembler.js: validateLabel()
|
||||||
- [ ] In assemble.js: print better output to stdout
|
- [ ] In assemble.js: print better output to stdout
|
||||||
- [ ] Add a function for logging just a specific range of memory
|
- [ ] Add a function for logging just a specific range of memory
|
||||||
- [ ] Add single-stepping
|
|
||||||
- [ ] Add variables to assembler
|
|
||||||
|
|
||||||
### Under-the-hood improvements
|
### Under-the-hood improvements
|
||||||
|
|
||||||
|
|
@ -104,5 +106,10 @@ Assemble and run, with debug output:
|
||||||
; the label will be replaced with
|
; the label will be replaced with
|
||||||
; the address of the label
|
; 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 `$`
|
- Hexadecimal numbers are preceded by a `$`
|
||||||
- Whitespace is ignored
|
- Whitespace is ignored
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
;; Test constants
|
||||||
|
=foo $01
|
||||||
|
=bar $02
|
||||||
|
ADD =foo
|
||||||
|
STO =bar
|
||||||
|
STO (=bar)
|
||||||
|
END
|
||||||
Loading…
Reference in New Issue