| @@ -105,7 +105,40 @@ class Assembler{ | |||
| this.__PC = (initpc >= 0) ? initpc : 0; | |||
| } | |||
| function __AddrModeVal(tA, tB){ | |||
| __StoreVarLabel(lbl, val){ | |||
| if (lbl in this.__varlabels) | |||
| throw new Error("Variable label '" + lbl + "' defined more than once."); | |||
| if (lbl in this.__jmplabels) | |||
| throw new Error("Variable label '" + lbl + "' matches already existing jump label."); | |||
| let v = Number.NaN; | |||
| if (val[0] === "$"){ | |||
| if (val.length >= 2 && val.length <= 5) | |||
| v = parseInt(val.substr(1), 16); | |||
| } else if (val[0] === "#"){ | |||
| if (val.startsWith("#b")){ | |||
| v = parseInt(val.substr(2), 2); | |||
| } else { | |||
| v = parseInt(val); | |||
| } | |||
| } | |||
| if (!isNaN(v)){ | |||
| if (v < 0 || v > 65535) | |||
| throw new Error("Variable '" + lbl + "' value is out of bounds for this processor."); | |||
| this.__varlabels[lbl] = v; | |||
| } else { | |||
| throw new Error("Variable '" + lbl + "' value malformed."); | |||
| } | |||
| } | |||
| __StoreJmpLabel(lbl){ | |||
| if (lbl in this.__jmplabels) | |||
| throw new Error("Jump label '" + lbl + "' defined more than once at program address " + toHexString(this.__PC)); | |||
| if (lbl in this.__varlabels) | |||
| throw new Error("Jump label '" + lbl + "' matches already existing variable name at program address " + toHexString(this.__PC)); | |||
| this.__jmplabels[lbl] = this.__PC; | |||
| } | |||
| __AddrModeVal(tA, tB){ | |||
| var mode = ""; | |||
| var v = Number.NaN; | |||
| if (tA[0] === '#'){ | |||
| @@ -207,15 +240,10 @@ class Assembler{ | |||
| if (tokens[0] === 'define'){ | |||
| // Variable label!! | |||
| this.__StoreVarLabel(tokens[1], tokens[2]); | |||
| } else if (tokens[0][tokens[0].length - 1] === ':'){ | |||
| // Jump labels! | |||
| // TODO: Finish me!! | |||
| let lbl = tokens[0].substr(0, tokens[0].length - 1); | |||
| if (lbl in this.__jmplabels) | |||
| throw new Error("Jump label '" + lbl + "' defined more than once at program address " + toHexString(this.__PC)); | |||
| if (lbl in this.__varlabels) | |||
| throw new Error("Jump label '" + lbl + "' matches already existing variable name at program address " + toHexString(this.__PC)); | |||
| this.__jmplabels[lbl] = this.__PC; | |||
| this.__StoreJmpLabel(tokens[0].substr(0, tokens[0].length - 1);); | |||
| } else if (tokens[0].length === 3){ | |||
| let StoreSingleOp = (code)=>{ | |||
| @@ -228,12 +256,19 @@ class Assembler{ | |||
| }; | |||
| let StoreBranchOp = (code) => { | |||
| // TODO: If value is not valid, test to see if it's a jump or variable value. | |||
| if (tokens.length === 2){ | |||
| if (token[1][0] === '$' && (tokens[1].length === 3 || tokens[1].length === 5)){ | |||
| let v = parseInt(token[1].substr(1), 16); | |||
| if (isNaN(v)) | |||
| return false; | |||
| let v = Number.NaN; | |||
| if (token[1][0] === '$'){ | |||
| if (tokens[1].length === 3 || tokens[1].length === 5){ | |||
| v = parseInt(token[1].substr(1), 16); | |||
| } | |||
| } else { | |||
| if (tokens[1] in this.__jmplabels){ | |||
| v = this.__jmplabels[tokens[1]]; | |||
| } | |||
| } | |||
| if (!isNaN(v)){ | |||
| if (v < this.__PC - 127 || v > this.__PC + 128) | |||
| throw new Error("Branch exceeds maximum number of bytes on program address " + toHexString(this.__PC)); | |||
| v = v - this.__PC; | |||
| @@ -444,46 +479,49 @@ class Assembler{ | |||
| procFailed = StoreSingleOp(0xC8); break; | |||
| // --- JMP | |||
| case 'jmp': | |||
| // TODO: Update value results to test for jump names if value not a number. | |||
| if (tokens.length === 2){ | |||
| if (tokens[1].startsWith("$") && tokens[1].length === 5){ | |||
| let v = parseInt(tokens[1].substr(1), 16); | |||
| if (!isNaN(v)){ | |||
| op.push(0x4C); | |||
| op.push(v & 0x000000FF); | |||
| op.push((v & 0x0000FF00) >> 8); | |||
| this.__PC += 3; | |||
| } else { | |||
| throw new Error("Malformed op-code or value on program address " + toHexString(this.__PC)); | |||
| } | |||
| } else if (tokens[1].startsWith("+$") && tokens[1].length === 6){ | |||
| let v = parseInt(tokens[1].substr(2), 16); | |||
| if (!isNaN(v)){ | |||
| op.push(0x6C); | |||
| op.push(v & 0x000000FF); | |||
| op.push((v & 0x0000FF00) >> 8); | |||
| this.__PC += 3; | |||
| } else { | |||
| throw new Error("Malformed op-code or value on program address " + toHexString(this.__PC)); | |||
| } | |||
| } else { procFailed = true; } | |||
| let v = Number.NaN; | |||
| let code = (tokens[1].startsWith("+")) ? 0x6C : 0x4C; | |||
| if (tokens[1].startsWith("$")){ | |||
| if (tokens[1].length === 5) | |||
| v = parseInt(tokens[1].substr(1), 16); | |||
| } else if (tokens[1].startsWith("+$")){ | |||
| if (tokens[1].length === 6) | |||
| v = parseInt(tokens[1].substr(2), 16); | |||
| } else { | |||
| let lbl = (tokens[1].startsWith("+")) ? tokens[1].substr(1) : tokens[1]; | |||
| if (lbl in this.__jmplabels) | |||
| v = this.__jmplabels[lbl]; | |||
| } | |||
| if (!isNaN(v)){ | |||
| op.push(code); | |||
| op.push(v & 0x000000FF); | |||
| op.push((v & 0x0000FF00) >> 8); | |||
| this.__PC += 3; | |||
| } else { | |||
| throw new Error("Malformed op-code or value on program address " + toHexString(this.__PC)); | |||
| } | |||
| } else { procFailed = true; } | |||
| break; | |||
| // --- JSR | |||
| case 'jsr': | |||
| // TODO: Update value results to test for jump names if value not a number. | |||
| if (tokens.length === 2){ | |||
| if (tokens[1].startsWith("$") && tokens[1].length === 5){ | |||
| let v = parseInt(tokens[1].substr(1), 16); | |||
| if (!isNaN(v)){ | |||
| op.push(0x20); | |||
| op.push(v & 0x000000FF); | |||
| op.push((v & 0x0000FF00) >> 8); | |||
| this.__PC += 3; | |||
| } else { | |||
| throw new Error("Malformed op-code or value on program address " + toHexString(this.__PC)); | |||
| } | |||
| } else { procFailed = true; } | |||
| let v = Number.NaN; | |||
| if (tokens[1].startsWith("$")){ | |||
| if (tokens[1].length === 5) | |||
| v = parseInt(tokens[1].substr(1), 16); | |||
| } else { | |||
| if (tokens[1] in this.__jmplabels) | |||
| v = this.__jmplabels[tokens[1]]; | |||
| } | |||
| if (!isNaN(v)){ | |||
| op.push(0x20); | |||
| op.push(v & 0x000000FF); | |||
| op.push((v & 0x0000FF00) >> 8); | |||
| this.__PC += 3; | |||
| } else { | |||
| throw new Error("Malformed op-code or value on program address " + toHexString(this.__PC)); | |||
| } | |||
| } else { | |||
| procFailed = true; | |||
| } | |||