|
|
@@ -209,15 +209,116 @@ class Assembler{ |
|
|
|
// 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 StoreSingleOp = (code)=>{ |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(code); |
|
|
|
this.__PC += 1; |
|
|
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
let StoreBranchOp = (code) => { |
|
|
|
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; |
|
|
|
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; |
|
|
|
op.push(code); |
|
|
|
op.push((v >= 0) ? v : v + 255); |
|
|
|
this.__PC += 2; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
let StoreOp = (codes, mint, maxt) => { |
|
|
|
if (tokens.length >= mint && tokens.length <= maxt){ |
|
|
|
let mv = addrModeVal(tokens[1], (tokens.length === 3) ? tokens[2].toUpperCase(), null); |
|
|
|
let modea = true; |
|
|
|
switch(mv[0]){ |
|
|
|
case "i": |
|
|
|
modea = codes[0] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[0]); |
|
|
|
op.push(mv[1]); |
|
|
|
this.__PC += 2; |
|
|
|
} break; |
|
|
|
case "z": |
|
|
|
modea = codes[1] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[1]); |
|
|
|
op.push(mv[1]); |
|
|
|
this.__PC += 2; |
|
|
|
} break; |
|
|
|
case "zX": |
|
|
|
modea = codes[2] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[2]); |
|
|
|
op.push(mv[1]); |
|
|
|
this.__PC += 2; |
|
|
|
} break; |
|
|
|
case "a": |
|
|
|
modea = codes[3] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[3]); |
|
|
|
op.push(mv[1] & 0x000000FF); |
|
|
|
op.push((mv[1] & 0x0000FF00) >> 8); |
|
|
|
this.__PC += 3; |
|
|
|
} break; |
|
|
|
case "aX": |
|
|
|
modea = codes[4] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[4]); |
|
|
|
op.push(mv[1] & 0x000000FF); |
|
|
|
op.push((mv[1] & 0x0000FF00) >> 8); |
|
|
|
this.__PC += 3; |
|
|
|
} break; |
|
|
|
case "aY": |
|
|
|
modea = codes[5] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[5]); |
|
|
|
op.push(mv[1] & 0x000000FF); |
|
|
|
op.push((mv[1] & 0x0000FF00) >> 8); |
|
|
|
this.__PC += 3; |
|
|
|
} break; |
|
|
|
case "nX": |
|
|
|
modea = codes[6] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[6]); |
|
|
|
op.push(mv[1]); |
|
|
|
this.__PC += 2; |
|
|
|
} break; |
|
|
|
case "nY": |
|
|
|
modea = codes[7] !== null; |
|
|
|
if (modea){ |
|
|
|
op.push(codes[7]); |
|
|
|
op.push(mv[1]); |
|
|
|
this.__PC += 2; |
|
|
|
} break; |
|
|
|
} |
|
|
|
if (modea === false) |
|
|
|
throw new Error("Op-code does not support implied mode on program address " + toHexString(this.__PC)); |
|
|
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
let procFailed = false; |
|
|
|
let mv = null; |
|
|
|
// Possible op code. |
|
|
|
switch(tokens[0].toLowerCase()){ |
|
|
|
// --- ADC |
|
|
|
case 'adc': |
|
|
|
procFailed = StoreOp([0x69, 0x65, 0x75, 0x6D, 0x7D, 0x79, 0x61, 0x71], 2, 3); |
|
|
|
/* |
|
|
|
if (tokens.length >= 2 && tokens.length <= 3){ |
|
|
|
mv = addrModeVal(tokens[1]); |
|
|
|
mv = addrModeVal(tokens[1], (tokens.length === 3) ? tokens[2].toUpperCase(), null); |
|
|
|
this.__PC += 2; |
|
|
|
switch(mv[0]){ |
|
|
|
case "i": |
|
|
@@ -244,207 +345,183 @@ class Assembler{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} else { procFailed = true; } |
|
|
|
*/ |
|
|
|
break; |
|
|
|
// --- AND |
|
|
|
case 'and': |
|
|
|
procFailed = StoreOp([0x29, 0x25, 0x35, 0x2D, 0x3D, 0x39, 0x21, 0x31], 2, 3); |
|
|
|
break; |
|
|
|
// --- ASL |
|
|
|
case 'asl': |
|
|
|
if (tokens.length === 2){ |
|
|
|
if (tokens[1].toUpperCase() === 'A'){ |
|
|
|
op.push(0x0A); |
|
|
|
this.__PC += 1; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
procFailed = StoreOp([null, 0x06, 0x16, 0x0E, 0x1E, null, null, null], 2, 3); |
|
|
|
break; |
|
|
|
// --- BCC |
|
|
|
case 'bcc': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0x90); break; |
|
|
|
// --- BCS |
|
|
|
case 'bcs': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0xB0); break; |
|
|
|
// --- BEQ |
|
|
|
case 'beq': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0xF0); break; |
|
|
|
// --- BIT |
|
|
|
case 'bit': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([null, 0x24, null, 0x2C, null, null, null, null], 2, 2); break; |
|
|
|
// --- BMI |
|
|
|
case 'bmi': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0x30); break; |
|
|
|
// --- BNE |
|
|
|
case 'bne': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0xD0); break; |
|
|
|
// --- BPL |
|
|
|
case 'bpl': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0x10); break; |
|
|
|
// --- BRK |
|
|
|
case 'brk': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x00); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x00); break; |
|
|
|
// --- BVC |
|
|
|
case 'bvc': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0x50); break; |
|
|
|
// --- BVS |
|
|
|
case 'bvs': |
|
|
|
break; |
|
|
|
procFailed = StoreBranchOp(0x70); break; |
|
|
|
// --- CLC |
|
|
|
case 'clc': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x18); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x18); break; |
|
|
|
// --- CLD |
|
|
|
case 'cld': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xD8); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xD8); break; |
|
|
|
// --- CLI |
|
|
|
case 'cli': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x58); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x58); break; |
|
|
|
// --- CLV |
|
|
|
case 'clv': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xB8); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xB8); break; |
|
|
|
// --- CMP |
|
|
|
case 'cmp': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([0xC9, 0xC5, 0xD5, 0xCD, 0xDD, 0xD9, 0xC1, 0xD1], 2, 3); break; |
|
|
|
// --- CPX |
|
|
|
case 'cpx': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([0xE0, 0xE4, null, 0xEC, null, null, null, null], 2, 2); break; |
|
|
|
// --- CPY |
|
|
|
case 'cpy': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([0xC0, 0xC4, null, 0xCC, null, null, null, null], 2, 2); break; |
|
|
|
// --- DEC |
|
|
|
case 'dec': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([null, 0xC6, 0xD6, 0xCE, 0xDE, null, null, null], 2, 3); break; |
|
|
|
// --- DEX |
|
|
|
case 'dex': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xCA); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xCA); break; |
|
|
|
// --- DEY |
|
|
|
case 'dey': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x88); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x88); break; |
|
|
|
// --- EOR |
|
|
|
case 'eor': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([0x49, 0x45, 0x55, 0x4D, 0x5D, 0x59, 0x41, 0x51], 2, 3); break; |
|
|
|
// --- INC |
|
|
|
case 'inc': |
|
|
|
break; |
|
|
|
procFailed = StoreOp([null, 0xE6, 0xF6, 0xEE, 0xFE, null, null, null], 2, 3); break; |
|
|
|
// --- INX |
|
|
|
case 'inx': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xE8); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xE8); break; |
|
|
|
// --- INY |
|
|
|
case 'iny': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xC8); |
|
|
|
this.__PC += 1 |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xC8); break; |
|
|
|
// --- JMP |
|
|
|
case 'jmp': |
|
|
|
break; |
|
|
|
// --- JSR |
|
|
|
case 'jsr': |
|
|
|
break; |
|
|
|
// --- LDA |
|
|
|
case 'lda': |
|
|
|
break; |
|
|
|
// --- LDX |
|
|
|
case 'ldx': |
|
|
|
break; |
|
|
|
// --- LDY |
|
|
|
case 'ldy': |
|
|
|
break; |
|
|
|
// --- LSR |
|
|
|
case 'lsr': |
|
|
|
break; |
|
|
|
// --- NOP |
|
|
|
case 'nop': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xEA); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xEA); break; |
|
|
|
// --- ORA |
|
|
|
case 'ora': |
|
|
|
break; |
|
|
|
// --- PHA |
|
|
|
case 'pha': |
|
|
|
break; |
|
|
|
// --- PHP |
|
|
|
case 'php': |
|
|
|
break; |
|
|
|
// --- PLA |
|
|
|
case 'pla': |
|
|
|
break; |
|
|
|
// --- PLP |
|
|
|
case 'plp': |
|
|
|
break; |
|
|
|
// --- ROL |
|
|
|
case 'rol': |
|
|
|
break; |
|
|
|
// --- ROR |
|
|
|
case 'ror': |
|
|
|
break; |
|
|
|
// --- RTI |
|
|
|
case 'rti': |
|
|
|
break; |
|
|
|
// --- RTS |
|
|
|
case 'rts': |
|
|
|
break; |
|
|
|
// --- SBC |
|
|
|
case 'sbc': |
|
|
|
break; |
|
|
|
// --- SEC |
|
|
|
case 'sec': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x38); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x38); break; |
|
|
|
// --- SED |
|
|
|
case 'sed': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xF8); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xF8); break; |
|
|
|
// --- SEI |
|
|
|
case 'sei': |
|
|
|
op.push(0x78); |
|
|
|
this.__PC += 1; |
|
|
|
procFailed = StoreSingleOp(0x78); break; |
|
|
|
break; |
|
|
|
// --- STA |
|
|
|
case 'sta': |
|
|
|
break; |
|
|
|
// --- STX |
|
|
|
case 'stx': |
|
|
|
break; |
|
|
|
// --- STY |
|
|
|
case 'sty': |
|
|
|
break; |
|
|
|
// --- TAX |
|
|
|
case 'tax': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xAA); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xAA); break; |
|
|
|
// --- TAY |
|
|
|
case 'tay': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0xA8); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0xA8); break; |
|
|
|
// --- TSX |
|
|
|
case 'tsx': |
|
|
|
break; |
|
|
|
// --- TXA |
|
|
|
case 'txa': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x8A); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x8A); break; |
|
|
|
// --- TXS |
|
|
|
case 'txs': |
|
|
|
break; |
|
|
|
// --- TYA |
|
|
|
case 'tya': |
|
|
|
if (tokens.length === 1){ |
|
|
|
op.push(0x98); |
|
|
|
this.__PC += 1; |
|
|
|
} else { procFailed = true; } |
|
|
|
break; |
|
|
|
procFailed = StoreSingleOp(0x98); break; |
|
|
|
// --- --- |
|
|
|
default: |
|
|
|
throw new Error("Unknown op-code '" + tokens[0].toUpperCase() + "' at program address " + toHexString(this.__PC)); |