Browse Source

Fleshing out the 6502 Assembler.

master
Bryan Miller 5 years ago
parent
commit
5a94e35213
1 changed files with 243 additions and 3 deletions
  1. +243
    -3
      src/MOS6502.js

+ 243
- 3
src/MOS6502.js View File

@@ -71,6 +71,29 @@ function toHexString(v, l){
return r;
}

function tokenize(l){
var m = l.match(/([^()]+)|([()])/g);
var ip = false;
t = [];
m.forEach((mi)=>{
if (mi === "("){
ip = true;
} else {
if (ip){
mi.split(/[\s,]+/).forEach((i)=>{
if (i !== "")
t.push("+" + i);
});
} else {
mi.split(/[\s,]+/).forEach((i)=>{
if (i !== "")
t.push(i);
});
}
}
});
}

class Assembler{
constructor(initpc){
// Labels that hold variable values.
@@ -82,31 +105,159 @@ class Assembler{
this.__PC = (initpc >= 0) ? initpc : 0;
}

function __AddrModeVal(tA, tB){
var mode = "";
var v = Number.NaN;
if (tA[0] === '#'){
mode = "i"; // Immediate
if (tA[1] === '$'){
v = parseInt(tA.substr(2), 16);
} else if (tA[1] === 'b'){
v = parseInt(tA.substr(2), 2);
} else {
v = parseInt(tA.substr(1));
if (isNaN(v)){
let lbl = tA.substr(1);
if (lbl in this.__varlabels){
if (this.__varlabels[lbl] < 256)
v = this.__varlabels[lbl]
}
}
}
} else if (tA[0] === '$'){
v = parseInt(tA.substr(1), 16);
if (tA.length === 3){
// Zero Page
if (tB !== null){
if (tB === "X")
mode = "zX";
} else {
mode = "z";
}
} else if (tA.length === 5){
// Absolute
if (tB !== null){
if (tB === "X"){
mode = "aX";
} else if (tB === "Y"){
mode = "aY";
}
} else {
mode = "a";
}
}
} else if (tA.startsWith("+")){
if (tB !== null){
if (tB === "+X"){ // The plus exists due to how tokenize() works.
mode = "nX";
} else if (tB === "Y"){
mode = "nY";
}

if (mode !== ""){
if (tA.startsWith("+$")){
v = parseInt(tA.substr(2));
} else {
let lbl = tA.substr(1);
if (lbl in this.__varlabels){
if (this.__varlabels[lbl] < 256)
v = vlb[lbl];
}
}
}
}
} else {
// We've been given a variable name. Need to look it up.
// if the var is 1 byte, assume "Zero Page". If var 2 bytes, assume "Absolute"
if (tA in this.__varlabel){
v = this.__varlabel[tA];
if (v < 256){
if (tB !== null){
if (tB === "X")
mode = "zX";
} else {
mode = "z";
}
} else {
if (tB !== null){
if (tB === "X"){
mode = "aX";
} else if (tB === "Y"){
mode = "aY";
}
} else {
mode = "a";
}
}
}
}

if (mode !== "" && ! isNaN(v))
return [mode, v];
throw new Error("Malformed op-code or value on program address " + toHexString(this.__PC));
}

compile(src){
var op = [];
src.split("\n").forEach((line)=>{
line = line.trim();
if (line[0] !== ";"){ // Skip comment lines.
line = line.split(";")[0].trim(); // Take out any trailing comments.
var tokens = line.split(/\s+/);
var tokens = tokenize(line);

if (tokens[0] === 'define'){
// Variable label!!
} else if (tokens[0][tokens[0].length - 1] === ':'){
// Jump label!!
} else if (tokens[0].length === 3){
} else if (tokens[0].length === 3){
let procFailed = false;
let mv = null;
// Possible op code.
switch(tokens[0].toLowerCase()){
// --- ADC
case 'adc':
break;
if (tokens.length >= 2 && tokens.length <= 3){
mv = addrModeVal(tokens[1]);
this.__PC += 2;
switch(mv[0]){
case "i":
op.push(0x69);
op.push(mv[1]);
break;
case "z":
case "zX":
op.push((mv[0] === "z") ? 0x65 : 0x75);
op.push(mv[1]);
break;
case "a":
case "aX":
case "aY":
op.push((mv[0] === "a") ? 0x6D : ((mv[0] === "aX") ? 0x7D : 0x79));
op.push(mv[1] & 0x000000FF);
op.push((mv[1] & 0x0000FF00) >> 8);
this.__PC += 1;
break;
case "nX":
case "nY":
op.push((mv[0] === "nX") ? 0x61 : 0x71);
op.push(mv[1]);
break;
}
} else { procFailed = true; }
break;
// --- AND
case 'and':
break;
// --- ASL
case 'asl':
break;
// --- BCC
case 'bcc':
break;
// --- BCS
case 'bcs':
break;
// --- BEQ
case 'beq':
break;
case 'bit':
@@ -117,19 +268,44 @@ class Assembler{
break;
case 'bpl':
break;
// --- BRK
case 'brk':
if (tokens.length === 1){
op.push(0x00);
this.__PC += 1;
} else { procFailed = true; }
break;
case 'bvc':
break;
case 'bvs':
break;
// --- CLC
case 'clc':
if (tokens.length === 1){
op.push(0x18);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- CLD
case 'cld':
if (tokens.length === 1){
op.push(0xD8);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- CLI
case 'cli':
if (tokens.length === 1){
op.push(0x58);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- CLV
case 'clv':
if (tokens.length === 1){
op.push(0xB8);
this.__PC += 1;
} else { procFailed = true; }
break;
case 'cmp':
break;
@@ -139,17 +315,37 @@ class Assembler{
break;
case 'dec':
break;
// --- DEX
case 'dex':
if (tokens.length === 1){
op.push(0xCA);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- DEY
case 'dey':
if (tokens.length === 1){
op.push(0x88);
this.__PC += 1;
} else { procFailed = true; }
break;
case 'eor':
break;
case 'inc':
break;
// --- INX
case 'inx':
if (tokens.length === 1){
op.push(0xE8);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- INY
case 'iny':
if (tokens.length === 1){
op.push(0xC8);
this.__PC += 1
} else { procFailed = true; }
break;
case 'jmp':
break;
@@ -163,7 +359,12 @@ class Assembler{
break;
case 'lsr':
break;
// --- NOP
case 'nop':
if (tokens.length === 1){
op.push(0xEA);
this.__PC += 1;
} else { procFailed = true; }
break;
case 'ora':
break;
@@ -185,11 +386,24 @@ class Assembler{
break;
case 'sbc':
break;
// --- SEC
case 'sec':
if (tokens.length === 1){
op.push(0x38);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- SED
case 'sed':
if (tokens.length === 1){
op.push(0xF8);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- SEI
case 'sei':
op.push(0x78);
this.__PC += 1;
break;
case 'sta':
break;
@@ -197,21 +411,47 @@ class Assembler{
break;
case 'sty':
break;
// --- TAX
case 'tax':
if (tokens.length === 1){
op.push(0xAA);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- TAY
case 'tay':
if (tokens.length === 1){
op.push(0xA8);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- TSX
case 'tsx':
break;
// --- TXA
case 'txa':
if (tokens.length === 1){
op.push(0x8A);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- TXS
case 'txs':
break;
// --- TYA
case 'tya':
if (tokens.length === 1){
op.push(0x98);
this.__PC += 1;
} else { procFailed = true; }
break;
// --- ---
default:
throw new Error("Unknown op-code '" + tokens[0].toUpperCase() + "' at program address " + toHexString(this.__PC));
}

if (procFailed)
throw new Error("Malformed op-code on program address " + toHexString(this.__PC));
} else {
throw new Error("Failed to compile line '" + line + "' at program address " + toHexString(this.__PC));
}

Loading…
Cancel
Save