UNPKG

gbasm

Version:
223 lines (190 loc) 6.51 kB
// Dependencies --------------------------------------------------------------- // ---------------------------------------------------------------------------- var Token = require('../parser/Lexer').Token; // Assembly Instruction Optimizer --------------------------------------------- // ---------------------------------------------------------------------------- function Optimizer(instr, unsafe, next, nextTwo, nextThree) { var opCode = instr.raw[0]; switch(opCode) { // ld a,0 -> xor a // // -> save 1 byte and 3 T-states case 0x3E: if (instr.resolvedArg === 0x00) { instr.rewrite('xor', 4, [0x07 + 0xA8]); return 1; } break; // cp 0 -> or a // // save 1 byte and 3 T-states case 0xFE: if (instr.resolvedArg === 0x00) { instr.rewrite('or', 4, [0x07 + 0xB0]); } break; // ld a,[someLabel] -> ldh a,$XX case 0xFA: // Transform memory loads into high loads if argument is // in the range of 0xff00-0xffff if (instr.resolvedArg >= 0xff00 && instr.resolvedArg <= 0xffff) { instr.rewrite( 'ldh', 12, [0xF0], new Token('NUMBER', instr.resolvedArg & 0xff, instr.index), true ); return 1; } break; // ld [someLabel],a -> ldh $XX,a case 0xEA: // Transform memory loads into high loads if argument is // in the range of 0xff00-0xffff if (instr.resolvedArg >= 0xff00 && instr.resolvedArg <= 0xffff) { instr.rewrite( 'ldh', 12, [0xE0], new Token('NUMBER', instr.resolvedArg & 0xff, instr.index), true ); return 1; } break; // jp c,label -> jr c,label // jp nc,label -> jr nc,label // jp z,label -> jr z,label // jp nz,label -> jr nz,label // jp label -> jr label case 0xDA: case 0xD2: case 0xCA: case 0xC2: case 0xC3: // Transform jp instructions into jrs if the target is in range // of one signed byte var offset = instr.resolvedArg - instr.offset; if (offset >= -127 && offset <= 128) { // Without flags if (opCode === 0xC3) { // We need to check for padding here in case the JP is // used in a jump table, otherwise we'll screw up the // alignment causing all kinds of havoc // Only replace if the next instruction is NOT a nop if (unsafe && (!next || next.raw[0] !== 0x00)) { instr.rewrite('jr', 12, [0x18], instr.arg, true, true); return 1; } // With flags } else { instr.rewrite('jr', 12, [opCode - 0xA2], instr.arg, true, true); return 1; } } break; // call LABEL // ret // -> // jp LABEL // // save 1 byte and 17 T-states case 0xCD: // Transform call instructions which are directly followed by a ret // into a simple jp if (next && next.raw[0] === 0xC9 && next.label === null) { instr.rewrite('jp', 16, [0xC3], instr.arg); return 2; } break; // ld b,$XX // ld c,$XX // -> // ld bc,$XXXX // // -> save 1 byte and 4 T-states case 0x06: if (next && next.raw[0] === 0x0E && next.label === null) { instr.rewrite( 'ld', 12, [0x01], new Token( 'NUMBER', (instr.resolvedArg << 8) | next.resolvedArg, instr.index ) ); return 2; } break; // ld d,$XX // ld e,$XX // -> // ld de,$XXXX // // -> save 1 byte and 4 T-states case 0x16: if (next && next.raw[0] === 0x1E && next.label === null) { instr.rewrite( 'ld', 12, [0x11], new Token( 'NUMBER', (instr.resolvedArg << 8) | next.resolvedArg, instr.index ) ); return 2; } break; // ld h,$XX // ld l,$XX // -> // ld hl,$XXXX // // -> save 1 byte and 4 T-states case 0x26: if (next && next.raw[0] === 0x2E && next.label === null) { instr.rewrite( 'ld', 12, [0x21], new Token( 'NUMBER', (instr.resolvedArg << 8) | next.resolvedArg, instr.index ) ); return 2; } break; // srl a // srl a // srl a // -> // rrca // rrca // rrca // and %00011111 // // save 1 byte and 5 T-states case 0xCB: if (next && nextTwo && instr.raw[1] === 0x38 + 0x07) { if (next.raw[0] === 0xCB && next.raw[1] === 0x38 + 0x07 && next.label === null && nextTwo.raw[0] === 0xCB && nextTwo.raw[1] === 0x38 + 0x07 && nextTwo.label === null) { instr.rewrite( 'rrca,rrca,rrca,and 0x1F', 4 * 3 + 8, [ 0x0F, 0x0F, 0x0F, 0xE6, 0x1F ] ); return 3; } } break; } return 0; } // Exports -------------------------------------------------------------------- module.exports = Optimizer;