Sfoglia il codice sorgente

Started work on a new assembler for the 6502 cpu. Something cleaner!

master
Bryan Miller 5 anni fa
parent
commit
198ef7d18d
2 ha cambiato i file con 288 aggiunte e 0 eliminazioni
  1. +96
    -0
      src/MOS/6502/assembler/op.js
  2. +192
    -0
      src/MOS/6502/assembler/tokenizer.js

+ 96
- 0
src/MOS/6502/assembler/op.js Vedi File

@@ -0,0 +1,96 @@


// Each array orders op codes as...
// [<immediate>, <zero page>, <zero page X/Y>, <absolute>, <absolute X>, <absolute Y>, <Indirect X>, <Indirect Y>, <Indirect>, <accumulator>]
// If an opcode does not support a particular format, null will be in that space.
// NOTE: Opcode that do not have arguments will store their opcode value directly (no array).
const CODES = {
"ADC":[0x69, 0x65, 0x75, 0x6D, 0x7D, 0x79, 0x61, 0x71, null, null],
"AND":[0x29, 0x25, 0x35, 0x2D, 0x3D, 0x39, 0x21, 0x31, null, null],
"ASL":[null, 0x06, 0x16, 0x0E, 0x1E, null, null, null, null, 0x0A],
"BCC":0x90,
"BCS":0xB0,
"BEQ":0xF0,
"BIT":[null, 0x24, null, 0x2C, null, null, null, null, null, null],
"BMI":0x30,
"BNE":0xD0,
"BPL":0x10,
"BRK":0x00,
"BVC":0x50,
"BVS":0x70,
"CLC":0x18,
"CLD":0xD8,
"CLI":0x58,
"CLV":0xB8,
"CMP":[0xC9, 0xC5, 0xD5, 0xCD, 0xDD, 0xD9, 0xC1, 0xD1, null, null],
"CPX":[0xE0, 0xE4, null, 0xEC, null, null, null, null, null, null],
"CPY":[0xC0, 0xC4, null, 0xCC, null, null, null, null, null, null],
"DEC":[null, 0xC6, 0xD6, 0xCE, 0xDE, null, null, null, null, null],
"DEX":0xCA,
"DEY":0x88,
"EOR":[0x49, 0x45, 0x55, 0x4D, 0x5D, 0x59, 0x41, 0x51, null, null],
"INC":[null, 0xE6, 0xF6, 0xEE, 0xFE, null, null, null, null, null],
"INX":0xE8,
"INY":0xC8,
"JMP":[null, null, null, 0x4C, null, null, null, null, 0x6C, null],
"JSR":[null, null, null, 0x20, null, null, null, null, null, null],
"LDA":[0xA9, 0xA5, 0xB5, 0xAD, 0xBD, 0xB9, 0xA1, 0xB1, null, null],
"LDX":[0xA2, 0xA6, 0xB6, 0xAE, 0xBE, null, null, null, null, null],
"LDY":[0xA0, 0xA4, 0xB4, 0xAC, 0xBC, null, null, null, null, null],
"LSR":[null, 0x46, 0x56, 0x4E, 0x5E, null, null, null, null, 0x4A],
"NOP":0xEA,
"ORA":[0x09, 0x05, 0x15, 0x0D, 0x1D, 0x19, 0x01, 0x11, null, null],
"PHA":0x48,
"PHP":0x08,
"PLA":0x68,
"PLP":0x28,
"ROL":[null, 0x26, 0x36, 0x2E, 0x3E, null, null, null, null, 0x2A],
"ROR":[null, 0x66, 0x76, 0x6E, 0x7E, null, null, null, null, 0x6A],
"RTI":0x40,
"RTS":0x60,
"SBC":[0xE9, 0xE5, 0xF5, 0xED, 0xFD, 0xF9, 0xE1, 0xF1, null, null],
"SEC":0x38,
"SED":0xF8,
"SEI":0x78,
"STA":[null, 0x85, 0x95, 0x8D, 0x9D, 0x99, 0x81, 0x91, null, null],
"STX":[null, 0x86, 0x96, 0x8E, null, null, null, null, null, null],
"STY":[null, 0x84, 0x94, 0x8C, null, null, null, null, null, null],
"TAX":0xAA,
"TAY":0xA8,
"TSX":0xBA,
"TXA":0x8A,
"TXS":0x9A,
"TYA":0x98
};
var NAMES = Object.keys(CODES);



module.exports = Object.freeze({
MODES:{
IMMEDIATE: 0,
ZEROPAGE: 1,
ZEROPAGEXY: 2,
ABSOLUTE: 3,
ABSOLUTEX: 4,
ABSOLUTEY: 5,
INDIRECTX: 6,
INDIRECTY: 7,
INDIRECT: 8,
ACCUMULATOR: 9
},
CODES: CODES,
NAMES: NAMES,
isCode:function(op){return (NAMES.indexOf(op) >= 0);},
getCode:function(op, mode){
if (NAMES.indexOf(op) >= 0){
if (typeof(CODES[op]) === 'number')
return CODES[op];
return (!(mode >= 0 && mode <= 9)) ? CODES[op][mode] : null;
}
return null;
}
});




+ 192
- 0
src/MOS/6502/assembler/tokenizer.js Vedi File

@@ -0,0 +1,192 @@


function GetTextStream(input){
var pos = 0;
var line = 0;
var col = 0;

function peek(){
return input.getChar(pos);
}

function next(){
let c = input.charAt(pos);
pos += 1;
if (c === "\n"){
line += 1;
col = 0;
} else {col += 1;}
return c;
}

function eof(){
return (input.charAt(pos) === "");
}

function die(msg){
throw new Error(msg + " Line: " + line + ", Col: " + col);
}

return {
peek: peek,
get: next,
eof: eof
};
}

// ----------------------------------------------
// VALIDATORS
// ----------------------------------------------

function isWhiteSpace(c){
return ("\t\n ".indexOf(c) >= 0);
}

function isStringStart(c){
return (c === "\"" || c === "'");
}

function isNumType(c){
return ("$%".indexOf(c) >= 0 || isDigit(c));
}

function isDigit(c){
return /[0-9]/i.test(c);
}

function isHex(c){
return /[0-9a-fA-F]/i.test(c);
}

function isBinary(c){
return ("01".indexOf(c) >= 0);
}

function isLabelStart(c){
return /[a-fA-F_]/i.test(c);
}

function isLabel(c){
return (isLabelStart(c) || isDigit(c));
}

function isPunctuation(c){
return (",()".indexOf(c) >= 0);
}

function isOp(c){
return ("=+-/*".indexOf(c) >= 0);
}


// ----------------------------------------------
// Read Operations
// ----------------------------------------------

function skipComment(stream){
readWhile(stream, (c)=>{return c != "\n";});
stream.next();
}

function readHex(stream){
stream.next();
var str = readWhile(stream, isHex);
return {type:'number', val: parseInt(str, 16)};
}

function readBinary(stream){
stream.next();
var str = readWhile(stream, isBinary);
return {type:'number', val: parseInt(str, 2)};
}

function readNumber(stream){
let c = stream.peek();
if (c === "$")
return readHex(stream);
if (c === "%")
return readBinary(stream);

var dot = false;
var str = readWhile(stream, (c)=>{
if (c === "."){
if (dot){return false;}
dot = true;
return true;
}
return isDigit(c);
});
return {type:'number', val:parseFloat(str)};
}


function readString(stream, end){
var str = "";
var escaped = false;
stream.next();
while (!stream.eof()){
let c = stream.next();
if (escaped){
str += c;
escaped = false;
} else if (c === "\\"){
escaped = true;
} else if (c === end){
break;
} else {
str += c;
}
}
return {type: "string", val: str};
}

function readLabel(stream){
str = readWhile(stream, isLabel);
return {type:"label", val: str};
}

function readWhile(stream, validator){
var str = "";
while (!stream.eof() && validator(stream.peek()))
str += stream.next();
return str;
}

function nextToken(stream){
readWhile(stream, isWhiteSpace);
if (stream.eof()){return null;}
let c = stream.peek();
if (c === ";"){
skipComment(stream);
return nextToken(stream);
} else if (isStringStart(c)){
return readString(stream, c);
} else if (isNumType(c)){
return readNumber(stream);
} else if (isLabelStart(c)){
return readLabel(stream);
} else if (isPunctuation(c)){
return {type:"punctuation", val:stream.next()};
} else if (isMathOp(c)){
return {type:"op", val:stream.next()};
}
stream.die("Unable to process character '" + c + "'.");
}


function tokenize(input){
var stream = GetTextStream(input);
var tokens = [];
var t = nextToken(stream);
while (t !== null){
tokens.push(t);
t = nextToken(stream);
}
return tokens;
}


module.exports = tokenize;




Loading…
Annulla
Salva