| | function ARMCore() { |
| | this.inherit(); |
| | this.SP = 13; |
| | this.LR = 14; |
| | this.PC = 15; |
| |
|
| | this.MODE_ARM = 0; |
| | this.MODE_THUMB = 1; |
| |
|
| | this.MODE_USER = 0x10; |
| | this.MODE_FIQ = 0x11; |
| | this.MODE_IRQ = 0x12; |
| | this.MODE_SUPERVISOR = 0x13; |
| | this.MODE_ABORT = 0x17; |
| | this.MODE_UNDEFINED = 0x1B; |
| | this.MODE_SYSTEM = 0x1F; |
| |
|
| | this.BANK_NONE = 0 |
| | this.BANK_FIQ = 1; |
| | this.BANK_IRQ = 2; |
| | this.BANK_SUPERVISOR = 3; |
| | this.BANK_ABORT = 4; |
| | this.BANK_UNDEFINED = 5; |
| |
|
| | this.UNALLOC_MASK = 0x0FFFFF00; |
| | this.USER_MASK = 0xF0000000; |
| | this.PRIV_MASK = 0x000000CF; |
| | this.STATE_MASK = 0x00000020; |
| |
|
| | this.WORD_SIZE_ARM = 4; |
| | this.WORD_SIZE_THUMB = 2; |
| |
|
| | this.BASE_RESET = 0x00000000; |
| | this.BASE_UNDEF = 0x00000004; |
| | this.BASE_SWI = 0x00000008; |
| | this.BASE_PABT = 0x0000000C; |
| | this.BASE_DABT = 0x00000010; |
| | this.BASE_IRQ = 0x00000018; |
| | this.BASE_FIQ = 0x0000001C; |
| |
|
| | this.armCompiler = new ARMCoreArm(this); |
| | this.thumbCompiler = new ARMCoreThumb(this); |
| | this.generateConds(); |
| |
|
| | this.gprs = new Int32Array(16); |
| | }; |
| |
|
| | ARMCore.prototype.resetCPU = function(startOffset) { |
| | for (var i = 0; i < this.PC; ++i) { |
| | this.gprs[i] = 0; |
| | } |
| | this.gprs[this.PC] = startOffset + this.WORD_SIZE_ARM; |
| |
|
| | this.loadInstruction = this.loadInstructionArm; |
| | this.execMode = this.MODE_ARM; |
| | this.instructionWidth = this.WORD_SIZE_ARM; |
| |
|
| | this.mode = this.MODE_SYSTEM; |
| |
|
| | this.cpsrI = false; |
| | this.cpsrF = false; |
| |
|
| | this.cpsrV = false; |
| | this.cpsrC = false; |
| | this.cpsrZ = false; |
| | this.cpsrN = false; |
| |
|
| | this.bankedRegisters = [ |
| | new Int32Array(7), |
| | new Int32Array(7), |
| | new Int32Array(2), |
| | new Int32Array(2), |
| | new Int32Array(2), |
| | new Int32Array(2) |
| | ]; |
| | this.spsr = 0; |
| | this.bankedSPSRs = new Int32Array(6); |
| |
|
| | this.cycles = 0; |
| |
|
| | this.shifterOperand = 0; |
| | this.shifterCarryOut = 0; |
| |
|
| | this.page = null; |
| | this.pageId = 0; |
| | this.pageRegion = -1; |
| |
|
| | this.instruction = null; |
| |
|
| | this.irq.clear(); |
| |
|
| | var gprs = this.gprs; |
| | var mmu = this.mmu; |
| | this.step = function() { |
| | var instruction = this.instruction || (this.instruction = this.loadInstruction(gprs[this.PC] - this.instructionWidth)); |
| | gprs[this.PC] += this.instructionWidth; |
| | this.conditionPassed = true; |
| | instruction(); |
| |
|
| | if (!instruction.writesPC) { |
| | if (this.instruction != null) { |
| | if (instruction.next == null || instruction.next.page.invalid) { |
| | instruction.next = this.loadInstruction(gprs[this.PC] - this.instructionWidth); |
| | } |
| | this.instruction = instruction.next; |
| | } |
| | } else { |
| | if (this.conditionPassed) { |
| | var pc = gprs[this.PC] &= 0xFFFFFFFE; |
| | if (this.execMode == this.MODE_ARM) { |
| | mmu.wait32(pc); |
| | mmu.waitPrefetch32(pc); |
| | } else { |
| | mmu.wait(pc); |
| | mmu.waitPrefetch(pc); |
| | } |
| | gprs[this.PC] += this.instructionWidth; |
| | if (!instruction.fixedJump) { |
| | this.instruction = null; |
| | } else if (this.instruction != null) { |
| | if (instruction.next == null || instruction.next.page.invalid) { |
| | instruction.next = this.loadInstruction(gprs[this.PC] - this.instructionWidth); |
| | } |
| | this.instruction = instruction.next; |
| | } |
| | } else { |
| | this.instruction = null; |
| | } |
| | } |
| | this.irq.updateTimers(); |
| | }; |
| | }; |
| |
|
| | ARMCore.prototype.freeze = function() { |
| | return { |
| | 'gprs': [ |
| | this.gprs[0], |
| | this.gprs[1], |
| | this.gprs[2], |
| | this.gprs[3], |
| | this.gprs[4], |
| | this.gprs[5], |
| | this.gprs[6], |
| | this.gprs[7], |
| | this.gprs[8], |
| | this.gprs[9], |
| | this.gprs[10], |
| | this.gprs[11], |
| | this.gprs[12], |
| | this.gprs[13], |
| | this.gprs[14], |
| | this.gprs[15], |
| | ], |
| | 'mode': this.mode, |
| | 'cpsrI': this.cpsrI, |
| | 'cpsrF': this.cpsrF, |
| | 'cpsrV': this.cpsrV, |
| | 'cpsrC': this.cpsrC, |
| | 'cpsrZ': this.cpsrZ, |
| | 'cpsrN': this.cpsrN, |
| | 'bankedRegisters': [ |
| | [ |
| | this.bankedRegisters[0][0], |
| | this.bankedRegisters[0][1], |
| | this.bankedRegisters[0][2], |
| | this.bankedRegisters[0][3], |
| | this.bankedRegisters[0][4], |
| | this.bankedRegisters[0][5], |
| | this.bankedRegisters[0][6] |
| | ], |
| | [ |
| | this.bankedRegisters[1][0], |
| | this.bankedRegisters[1][1], |
| | this.bankedRegisters[1][2], |
| | this.bankedRegisters[1][3], |
| | this.bankedRegisters[1][4], |
| | this.bankedRegisters[1][5], |
| | this.bankedRegisters[1][6] |
| | ], |
| | [ |
| | this.bankedRegisters[2][0], |
| | this.bankedRegisters[2][1] |
| | ], |
| | [ |
| | this.bankedRegisters[3][0], |
| | this.bankedRegisters[3][1] |
| | ], |
| | [ |
| | this.bankedRegisters[4][0], |
| | this.bankedRegisters[4][1] |
| | ], |
| | [ |
| | this.bankedRegisters[5][0], |
| | this.bankedRegisters[5][1] |
| | ] |
| | ], |
| | 'spsr': this.spsr, |
| | 'bankedSPSRs': [ |
| | this.bankedSPSRs[0], |
| | this.bankedSPSRs[1], |
| | this.bankedSPSRs[2], |
| | this.bankedSPSRs[3], |
| | this.bankedSPSRs[4], |
| | this.bankedSPSRs[5] |
| | ], |
| | 'cycles': this.cycles |
| | }; |
| | }; |
| |
|
| | ARMCore.prototype.defrost = function(frost) { |
| | this.instruction = null; |
| |
|
| | this.page = null; |
| | this.pageId = 0; |
| | this.pageRegion = -1; |
| |
|
| | this.gprs[0] = frost.gprs[0]; |
| | this.gprs[1] = frost.gprs[1]; |
| | this.gprs[2] = frost.gprs[2]; |
| | this.gprs[3] = frost.gprs[3]; |
| | this.gprs[4] = frost.gprs[4]; |
| | this.gprs[5] = frost.gprs[5]; |
| | this.gprs[6] = frost.gprs[6]; |
| | this.gprs[7] = frost.gprs[7]; |
| | this.gprs[8] = frost.gprs[8]; |
| | this.gprs[9] = frost.gprs[9]; |
| | this.gprs[10] = frost.gprs[10]; |
| | this.gprs[11] = frost.gprs[11]; |
| | this.gprs[12] = frost.gprs[12]; |
| | this.gprs[13] = frost.gprs[13]; |
| | this.gprs[14] = frost.gprs[14]; |
| | this.gprs[15] = frost.gprs[15]; |
| |
|
| | this.mode = frost.mode; |
| | this.cpsrI = frost.cpsrI; |
| | this.cpsrF = frost.cpsrF; |
| | this.cpsrV = frost.cpsrV; |
| | this.cpsrC = frost.cpsrC; |
| | this.cpsrZ = frost.cpsrZ; |
| | this.cpsrN = frost.cpsrN; |
| |
|
| | this.bankedRegisters[0][0] = frost.bankedRegisters[0][0]; |
| | this.bankedRegisters[0][1] = frost.bankedRegisters[0][1]; |
| | this.bankedRegisters[0][2] = frost.bankedRegisters[0][2]; |
| | this.bankedRegisters[0][3] = frost.bankedRegisters[0][3]; |
| | this.bankedRegisters[0][4] = frost.bankedRegisters[0][4]; |
| | this.bankedRegisters[0][5] = frost.bankedRegisters[0][5]; |
| | this.bankedRegisters[0][6] = frost.bankedRegisters[0][6]; |
| |
|
| | this.bankedRegisters[1][0] = frost.bankedRegisters[1][0]; |
| | this.bankedRegisters[1][1] = frost.bankedRegisters[1][1]; |
| | this.bankedRegisters[1][2] = frost.bankedRegisters[1][2]; |
| | this.bankedRegisters[1][3] = frost.bankedRegisters[1][3]; |
| | this.bankedRegisters[1][4] = frost.bankedRegisters[1][4]; |
| | this.bankedRegisters[1][5] = frost.bankedRegisters[1][5]; |
| | this.bankedRegisters[1][6] = frost.bankedRegisters[1][6]; |
| |
|
| | this.bankedRegisters[2][0] = frost.bankedRegisters[2][0]; |
| | this.bankedRegisters[2][1] = frost.bankedRegisters[2][1]; |
| |
|
| | this.bankedRegisters[3][0] = frost.bankedRegisters[3][0]; |
| | this.bankedRegisters[3][1] = frost.bankedRegisters[3][1]; |
| |
|
| | this.bankedRegisters[4][0] = frost.bankedRegisters[4][0]; |
| | this.bankedRegisters[4][1] = frost.bankedRegisters[4][1]; |
| |
|
| | this.bankedRegisters[5][0] = frost.bankedRegisters[5][0]; |
| | this.bankedRegisters[5][1] = frost.bankedRegisters[5][1]; |
| |
|
| | this.spsr = frost.spsr; |
| | this.bankedSPSRs[0] = frost.bankedSPSRs[0]; |
| | this.bankedSPSRs[1] = frost.bankedSPSRs[1]; |
| | this.bankedSPSRs[2] = frost.bankedSPSRs[2]; |
| | this.bankedSPSRs[3] = frost.bankedSPSRs[3]; |
| | this.bankedSPSRs[4] = frost.bankedSPSRs[4]; |
| | this.bankedSPSRs[5] = frost.bankedSPSRs[5]; |
| |
|
| | this.cycles = frost.cycles; |
| | }; |
| |
|
| | ARMCore.prototype.fetchPage = function(address) { |
| | var region = address >> this.mmu.BASE_OFFSET; |
| | var pageId = this.mmu.addressToPage(region, address & this.mmu.OFFSET_MASK); |
| | if (region == this.pageRegion) { |
| | if (pageId == this.pageId && !this.page.invalid) { |
| | return; |
| | } |
| | this.pageId = pageId; |
| | } else { |
| | this.pageMask = this.mmu.memory[region].PAGE_MASK; |
| | this.pageRegion = region; |
| | this.pageId = pageId; |
| | } |
| |
|
| | this.page = this.mmu.accessPage(region, pageId); |
| | }; |
| |
|
| | ARMCore.prototype.loadInstructionArm = function(address) { |
| | var next = null; |
| | this.fetchPage(address); |
| | var offset = (address & this.pageMask) >> 2; |
| | next = this.page.arm[offset]; |
| | if (next) { |
| | return next; |
| | } |
| | var instruction = this.mmu.load32(address) >>> 0; |
| | next = this.compileArm(instruction); |
| | next.next = null; |
| | next.page = this.page; |
| | next.address = address; |
| | next.opcode = instruction; |
| | this.page.arm[offset] = next; |
| | return next; |
| | }; |
| |
|
| | ARMCore.prototype.loadInstructionThumb = function(address) { |
| | var next = null; |
| | this.fetchPage(address); |
| | var offset = (address & this.pageMask) >> 1; |
| | next = this.page.thumb[offset]; |
| | if (next) { |
| | return next; |
| | } |
| | var instruction = this.mmu.load16(address); |
| | next = this.compileThumb(instruction); |
| | next.next = null; |
| | next.page = this.page; |
| | next.address = address; |
| | next.opcode = instruction; |
| | this.page.thumb[offset] = next; |
| | return next; |
| | }; |
| |
|
| | ARMCore.prototype.selectBank = function(mode) { |
| | switch (mode) { |
| | case this.MODE_USER: |
| | case this.MODE_SYSTEM: |
| | |
| | return this.BANK_NONE; |
| | case this.MODE_FIQ: |
| | return this.BANK_FIQ; |
| | case this.MODE_IRQ: |
| | return this.BANK_IRQ; |
| | case this.MODE_SUPERVISOR: |
| | return this.BANK_SUPERVISOR; |
| | case this.MODE_ABORT: |
| | return this.BANK_ABORT; |
| | case this.MODE_UNDEFINED: |
| | return this.BANK_UNDEFINED; |
| | default: |
| | throw "Invalid user mode passed to selectBank"; |
| | } |
| | }; |
| |
|
| | ARMCore.prototype.switchExecMode = function(newMode) { |
| | if (this.execMode != newMode) { |
| | this.execMode = newMode; |
| | if (newMode == this.MODE_ARM) { |
| | this.instructionWidth = this.WORD_SIZE_ARM; |
| | this.loadInstruction = this.loadInstructionArm; |
| | } else { |
| | this.instructionWidth = this.WORD_SIZE_THUMB; |
| | this.loadInstruction = this.loadInstructionThumb; |
| | } |
| | } |
| | |
| | }; |
| |
|
| | ARMCore.prototype.switchMode = function(newMode) { |
| | if (newMode == this.mode) { |
| | |
| | return; |
| | } |
| | if (newMode != this.MODE_USER || newMode != this.MODE_SYSTEM) { |
| | |
| | var newBank = this.selectBank(newMode); |
| | var oldBank = this.selectBank(this.mode); |
| | if (newBank != oldBank) { |
| | |
| | if (newMode == this.MODE_FIQ || this.mode == this.MODE_FIQ) { |
| | var oldFiqBank = (oldBank == this.BANK_FIQ) + 0; |
| | var newFiqBank = (newBank == this.BANK_FIQ) + 0; |
| | this.bankedRegisters[oldFiqBank][2] = this.gprs[8]; |
| | this.bankedRegisters[oldFiqBank][3] = this.gprs[9]; |
| | this.bankedRegisters[oldFiqBank][4] = this.gprs[10]; |
| | this.bankedRegisters[oldFiqBank][5] = this.gprs[11]; |
| | this.bankedRegisters[oldFiqBank][6] = this.gprs[12]; |
| | this.gprs[8] = this.bankedRegisters[newFiqBank][2]; |
| | this.gprs[9] = this.bankedRegisters[newFiqBank][3]; |
| | this.gprs[10] = this.bankedRegisters[newFiqBank][4]; |
| | this.gprs[11] = this.bankedRegisters[newFiqBank][5]; |
| | this.gprs[12] = this.bankedRegisters[newFiqBank][6]; |
| | } |
| | this.bankedRegisters[oldBank][0] = this.gprs[this.SP]; |
| | this.bankedRegisters[oldBank][1] = this.gprs[this.LR]; |
| | this.gprs[this.SP] = this.bankedRegisters[newBank][0]; |
| | this.gprs[this.LR] = this.bankedRegisters[newBank][1]; |
| |
|
| | this.bankedSPSRs[oldBank] = this.spsr; |
| | this.spsr = this.bankedSPSRs[newBank]; |
| | } |
| | } |
| | this.mode = newMode; |
| | }; |
| |
|
| | ARMCore.prototype.packCPSR = function() { |
| | return this.mode | (!!this.execMode << 5) | (!!this.cpsrF << 6) | (!!this.cpsrI << 7) | |
| | (!!this.cpsrN << 31) | (!!this.cpsrZ << 30) | (!!this.cpsrC << 29) | (!!this.cpsrV << 28); |
| | }; |
| |
|
| | ARMCore.prototype.unpackCPSR = function(spsr) { |
| | this.switchMode(spsr & 0x0000001F); |
| | this.switchExecMode(!!(spsr & 0x00000020)); |
| | this.cpsrF = spsr & 0x00000040; |
| | this.cpsrI = spsr & 0x00000080; |
| | this.cpsrN = spsr & 0x80000000; |
| | this.cpsrZ = spsr & 0x40000000; |
| | this.cpsrC = spsr & 0x20000000; |
| | this.cpsrV = spsr & 0x10000000; |
| |
|
| | this.irq.testIRQ(); |
| | }; |
| |
|
| | ARMCore.prototype.hasSPSR = function() { |
| | return this.mode != this.MODE_SYSTEM && this.mode != this.MODE_USER; |
| | }; |
| |
|
| | ARMCore.prototype.raiseIRQ = function() { |
| | if (this.cpsrI) { |
| | return; |
| | } |
| | var cpsr = this.packCPSR(); |
| | var instructionWidth = this.instructionWidth; |
| | this.switchMode(this.MODE_IRQ); |
| | this.spsr = cpsr; |
| | this.gprs[this.LR] = this.gprs[this.PC] - instructionWidth + 4; |
| | this.gprs[this.PC] = this.BASE_IRQ + this.WORD_SIZE_ARM; |
| | this.instruction = null; |
| | this.switchExecMode(this.MODE_ARM); |
| | this.cpsrI = true; |
| | }; |
| |
|
| | ARMCore.prototype.raiseTrap = function() { |
| | var cpsr = this.packCPSR(); |
| | var instructionWidth = this.instructionWidth; |
| | this.switchMode(this.MODE_SUPERVISOR); |
| | this.spsr = cpsr; |
| | this.gprs[this.LR] = this.gprs[this.PC] - instructionWidth; |
| | this.gprs[this.PC] = this.BASE_SWI + this.WORD_SIZE_ARM; |
| | this.instruction = null; |
| | this.switchExecMode(this.MODE_ARM); |
| | this.cpsrI = true; |
| | }; |
| |
|
| | ARMCore.prototype.badOp = function(instruction) { |
| | var func = function() { |
| | throw "Illegal instruction: 0x" + instruction.toString(16); |
| | }; |
| | func.writesPC = true; |
| | func.fixedJump = false; |
| | return func; |
| | }; |
| |
|
| | ARMCore.prototype.generateConds = function() { |
| | var cpu = this; |
| | this.conds = [ |
| | |
| | function() { |
| | return cpu.conditionPassed = cpu.cpsrZ; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = !cpu.cpsrZ; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = cpu.cpsrC; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = !cpu.cpsrC; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = cpu.cpsrN; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = !cpu.cpsrN; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = cpu.cpsrV; |
| | }, |
| | |
| | function() { |
| | return cpu.conditionPassed = !cpu.cpsrV; |
| | }, |
| | |
| | function () { |
| | return cpu.conditionPassed = cpu.cpsrC && !cpu.cpsrZ; |
| | }, |
| | |
| | function () { |
| | return cpu.conditionPassed = !cpu.cpsrC || cpu.cpsrZ; |
| | }, |
| | |
| | function () { |
| | return cpu.conditionPassed = !cpu.cpsrN == !cpu.cpsrV; |
| | }, |
| | |
| | function () { |
| | return cpu.conditionPassed = !cpu.cpsrN != !cpu.cpsrV; |
| | }, |
| | |
| | function () { |
| | return cpu.conditionPassed = !cpu.cpsrZ && !cpu.cpsrN == !cpu.cpsrV; |
| | }, |
| | |
| | function () { |
| | return cpu.conditionPassed = cpu.cpsrZ || !cpu.cpsrN != !cpu.cpsrV; |
| | }, |
| | |
| | null, |
| | null |
| | ] |
| | } |
| |
|
| | ARMCore.prototype.barrelShiftImmediate = function(shiftType, immediate, rm) { |
| | var cpu = this; |
| | var gprs = this.gprs; |
| | var shiftOp = this.badOp; |
| | switch (shiftType) { |
| | case 0x00000000: |
| | |
| | if (immediate) { |
| | shiftOp = function() { |
| | cpu.shifterOperand = gprs[rm] << immediate; |
| | cpu.shifterCarryOut = gprs[rm] & (1 << (32 - immediate)); |
| | }; |
| | } else { |
| | |
| | shiftOp = function() { |
| | cpu.shifterOperand = gprs[rm]; |
| | cpu.shifterCarryOut = cpu.cpsrC; |
| | }; |
| | } |
| | break; |
| | case 0x00000020: |
| | |
| | if (immediate) { |
| | shiftOp = function() { |
| | cpu.shifterOperand = gprs[rm] >>> immediate; |
| | cpu.shifterCarryOut = gprs[rm] & (1 << (immediate - 1)); |
| | }; |
| | } else { |
| | shiftOp = function() { |
| | cpu.shifterOperand = 0; |
| | cpu.shifterCarryOut = gprs[rm] & 0x80000000; |
| | }; |
| | } |
| | break; |
| | case 0x00000040: |
| | |
| | if (immediate) { |
| | shiftOp = function() { |
| | cpu.shifterOperand = gprs[rm] >> immediate; |
| | cpu.shifterCarryOut = gprs[rm] & (1 << (immediate - 1)); |
| | }; |
| | } else { |
| | shiftOp = function() { |
| | cpu.shifterCarryOut = gprs[rm] & 0x80000000; |
| | if (cpu.shifterCarryOut) { |
| | cpu.shifterOperand = 0xFFFFFFFF; |
| | } else { |
| | cpu.shifterOperand = 0; |
| | } |
| | }; |
| | } |
| | break; |
| | case 0x00000060: |
| | |
| | if (immediate) { |
| | shiftOp = function() { |
| | cpu.shifterOperand = (gprs[rm] >>> immediate) | (gprs[rm] << (32 - immediate)); |
| | cpu.shifterCarryOut = gprs[rm] & (1 << (immediate - 1)); |
| | }; |
| | } else { |
| | |
| | shiftOp = function() { |
| | cpu.shifterOperand = (!!cpu.cpsrC << 31) | (gprs[rm] >>> 1); |
| | cpu.shifterCarryOut = gprs[rm] & 0x00000001; |
| | }; |
| | } |
| | break; |
| | } |
| | return shiftOp; |
| | } |
| |
|
| | ARMCore.prototype.compileArm = function(instruction) { |
| | var op = this.badOp(instruction); |
| | var i = instruction & 0x0E000000; |
| | var cpu = this; |
| | var gprs = this.gprs; |
| |
|
| | var condOp = this.conds[(instruction & 0xF0000000) >>> 28]; |
| | if ((instruction & 0x0FFFFFF0) == 0x012FFF10) { |
| | |
| | var rm = instruction & 0xF; |
| | op = this.armCompiler.constructBX(rm, condOp); |
| | op.writesPC = true; |
| | op.fixedJump = false; |
| | } else if (!(instruction & 0x0C000000) && (i == 0x02000000 || (instruction & 0x00000090) != 0x00000090)) { |
| | var opcode = instruction & 0x01E00000; |
| | var s = instruction & 0x00100000; |
| | var shiftsRs = false; |
| | if ((opcode & 0x01800000) == 0x01000000 && !s) { |
| | var r = instruction & 0x00400000; |
| | if ((instruction & 0x00B0F000) == 0x0020F000) { |
| | |
| | var rm = instruction & 0x0000000F; |
| | var immediate = instruction & 0x000000FF; |
| | var rotateImm = (instruction & 0x00000F00) >> 7; |
| | immediate = (immediate >>> rotateImm) | (immediate << (32 - rotateImm)); |
| | op = this.armCompiler.constructMSR(rm, r, instruction, immediate, condOp); |
| | op.writesPC = false; |
| | } else if ((instruction & 0x00BF0000) == 0x000F0000) { |
| | |
| | var rd = (instruction & 0x0000F000) >> 12; |
| | op = this.armCompiler.constructMRS(rd, r, condOp); |
| | op.writesPC = rd == this.PC; |
| | } |
| | } else { |
| | |
| | var rn = (instruction & 0x000F0000) >> 16; |
| | var rd = (instruction & 0x0000F000) >> 12; |
| |
|
| | |
| | var shiftType = instruction & 0x00000060; |
| | var rm = instruction & 0x0000000F; |
| | var shiftOp = function() { |
| | throw 'BUG: invalid barrel shifter'; |
| | }; |
| | if (instruction & 0x02000000) { |
| | var immediate = instruction & 0x000000FF; |
| | var rotate = (instruction & 0x00000F00) >> 7; |
| | if (!rotate) { |
| | shiftOp = this.armCompiler.constructAddressingMode1Immediate(immediate); |
| | } else { |
| | shiftOp = this.armCompiler.constructAddressingMode1ImmediateRotate(immediate, rotate); |
| | } |
| | } else if (instruction & 0x00000010) { |
| | var rs = (instruction & 0x00000F00) >> 8; |
| | shiftsRs = true; |
| | switch (shiftType) { |
| | case 0x00000000: |
| | |
| | shiftOp = this.armCompiler.constructAddressingMode1LSL(rs, rm); |
| | break; |
| | case 0x00000020: |
| | |
| | shiftOp = this.armCompiler.constructAddressingMode1LSR(rs, rm); |
| | break; |
| | case 0x00000040: |
| | |
| | shiftOp = this.armCompiler.constructAddressingMode1ASR(rs, rm); |
| | break; |
| | case 0x00000060: |
| | |
| | shiftOp = this.armCompiler.constructAddressingMode1ROR(rs, rm); |
| | break; |
| | } |
| | } else { |
| | var immediate = (instruction & 0x00000F80) >> 7; |
| | shiftOp = this.barrelShiftImmediate(shiftType, immediate, rm); |
| | } |
| |
|
| | switch (opcode) { |
| | case 0x00000000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructANDS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructAND(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00200000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructEORS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructEOR(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00400000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructSUBS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructSUB(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00600000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructRSBS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructRSB(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00800000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructADDS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructADD(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00A00000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructADCS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructADC(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00C00000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructSBCS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructSBC(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x00E00000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructRSCS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructRSC(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x01000000: |
| | |
| | op = this.armCompiler.constructTST(rd, rn, shiftOp, condOp); |
| | break; |
| | case 0x01200000: |
| | |
| | op = this.armCompiler.constructTEQ(rd, rn, shiftOp, condOp); |
| | break; |
| | case 0x01400000: |
| | |
| | op = this.armCompiler.constructCMP(rd, rn, shiftOp, condOp); |
| | break; |
| | case 0x01600000: |
| | |
| | op = this.armCompiler.constructCMN(rd, rn, shiftOp, condOp); |
| | break; |
| | case 0x01800000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructORRS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructORR(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x01A00000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructMOVS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructMOV(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x01C00000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructBICS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructBIC(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | case 0x01E00000: |
| | |
| | if (s) { |
| | op = this.armCompiler.constructMVNS(rd, rn, shiftOp, condOp); |
| | } else { |
| | op = this.armCompiler.constructMVN(rd, rn, shiftOp, condOp); |
| | } |
| | break; |
| | } |
| | op.writesPC = rd == this.PC; |
| | } |
| | } else if ((instruction & 0x0FB00FF0) == 0x01000090) { |
| | |
| | var rm = instruction & 0x0000000F; |
| | var rd = (instruction >> 12) & 0x0000000F; |
| | var rn = (instruction >> 16) & 0x0000000F; |
| | if (instruction & 0x00400000) { |
| | op = this.armCompiler.constructSWPB(rd, rn, rm, condOp); |
| | } else { |
| | op = this.armCompiler.constructSWP(rd, rn, rm, condOp); |
| | } |
| | op.writesPC = rd == this.PC; |
| | } else { |
| | switch (i) { |
| | case 0x00000000: |
| | if ((instruction & 0x010000F0) == 0x00000090) { |
| | |
| | var rd = (instruction & 0x000F0000) >> 16; |
| | var rn = (instruction & 0x0000F000) >> 12; |
| | var rs = (instruction & 0x00000F00) >> 8; |
| | var rm = instruction & 0x0000000F; |
| | switch (instruction & 0x00F00000) { |
| | case 0x00000000: |
| | |
| | op = this.armCompiler.constructMUL(rd, rs, rm, condOp); |
| | break; |
| | case 0x00100000: |
| | |
| | op = this.armCompiler.constructMULS(rd, rs, rm, condOp); |
| | break; |
| | case 0x00200000: |
| | |
| | op = this.armCompiler.constructMLA(rd, rn, rs, rm, condOp); |
| | break |
| | case 0x00300000: |
| | |
| | op = this.armCompiler.constructMLAS(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00800000: |
| | |
| | op = this.armCompiler.constructUMULL(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00900000: |
| | |
| | op = this.armCompiler.constructUMULLS(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00A00000: |
| | |
| | op = this.armCompiler.constructUMLAL(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00B00000: |
| | |
| | op = this.armCompiler.constructUMLALS(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00C00000: |
| | |
| | op = this.armCompiler.constructSMULL(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00D00000: |
| | |
| | op = this.armCompiler.constructSMULLS(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00E00000: |
| | |
| | op = this.armCompiler.constructSMLAL(rd, rn, rs, rm, condOp); |
| | break; |
| | case 0x00F00000: |
| | |
| | op = this.armCompiler.constructSMLALS(rd, rn, rs, rm, condOp); |
| | break; |
| | } |
| | op.writesPC = rd == this.PC; |
| | } else { |
| | |
| | var load = instruction & 0x00100000; |
| | var rd = (instruction & 0x0000F000) >> 12; |
| | var hiOffset = (instruction & 0x00000F00) >> 4; |
| | var loOffset = rm = instruction & 0x0000000F; |
| | var h = instruction & 0x00000020; |
| | var s = instruction & 0x00000040; |
| | var w = instruction & 0x00200000; |
| | var i = instruction & 0x00400000; |
| |
|
| | var address; |
| | if (i) { |
| | var immediate = loOffset | hiOffset; |
| | address = this.armCompiler.constructAddressingMode23Immediate(instruction, immediate, condOp); |
| | } else { |
| | address = this.armCompiler.constructAddressingMode23Register(instruction, rm, condOp); |
| | } |
| | address.writesPC = !!w && rn == this.PC; |
| |
|
| | if ((instruction & 0x00000090) == 0x00000090) { |
| | if (load) { |
| | |
| | if (h) { |
| | if (s) { |
| | |
| | op = this.armCompiler.constructLDRSH(rd, address, condOp); |
| | } else { |
| | |
| | op = this.armCompiler.constructLDRH(rd, address, condOp); |
| | } |
| | } else { |
| | if (s) { |
| | |
| | op = this.armCompiler.constructLDRSB(rd, address, condOp); |
| | } |
| | } |
| | } else if (!s && h) { |
| | |
| | op = this.armCompiler.constructSTRH(rd, address, condOp); |
| | } |
| | } |
| | op.writesPC = rd == this.PC || address.writesPC; |
| | } |
| | break; |
| | case 0x04000000: |
| | case 0x06000000: |
| | |
| | var rd = (instruction & 0x0000F000) >> 12; |
| | var load = instruction & 0x00100000; |
| | var b = instruction & 0x00400000; |
| | var i = instruction & 0x02000000; |
| |
|
| | var address = function() { |
| | throw "Unimplemented memory access: 0x" + instruction.toString(16); |
| | }; |
| | if (~instruction & 0x01000000) { |
| | |
| | instruction &= 0xFFDFFFFF; |
| | } |
| | if (i) { |
| | |
| | var rm = instruction & 0x0000000F; |
| | var shiftType = instruction & 0x00000060; |
| | var shiftImmediate = (instruction & 0x00000F80) >> 7; |
| | |
| | if (shiftType || shiftImmediate) { |
| | var shiftOp = this.barrelShiftImmediate(shiftType, shiftImmediate, rm); |
| | address = this.armCompiler.constructAddressingMode2RegisterShifted(instruction, shiftOp, condOp); |
| | } else { |
| | address = this.armCompiler.constructAddressingMode23Register(instruction, rm, condOp); |
| | } |
| | } else { |
| | |
| | var offset = instruction & 0x00000FFF; |
| | address = this.armCompiler.constructAddressingMode23Immediate(instruction, offset, condOp); |
| | } |
| | if (load) { |
| | if (b) { |
| | |
| | op = this.armCompiler.constructLDRB(rd, address, condOp); |
| | } else { |
| | |
| | op = this.armCompiler.constructLDR(rd, address, condOp); |
| | } |
| | } else { |
| | if (b) { |
| | |
| | op = this.armCompiler.constructSTRB(rd, address, condOp); |
| | } else { |
| | |
| | op = this.armCompiler.constructSTR(rd, address, condOp); |
| | } |
| | } |
| | op.writesPC = rd == this.PC || address.writesPC; |
| | break; |
| | case 0x08000000: |
| | |
| | var load = instruction & 0x00100000; |
| | var w = instruction & 0x00200000; |
| | var user = instruction & 0x00400000; |
| | var u = instruction & 0x00800000; |
| | var p = instruction & 0x01000000; |
| | var rs = instruction & 0x0000FFFF; |
| | var rn = (instruction & 0x000F0000) >> 16; |
| |
|
| | var address; |
| | var immediate = 0; |
| | var offset = 0; |
| | var overlap = false; |
| | if (u) { |
| | if (p) { |
| | immediate = 4; |
| | } |
| | for (var m = 0x01, i = 0; i < 16; m <<= 1, ++i) { |
| | if (rs & m) { |
| | if (w && i == rn && !offset) { |
| | rs &= ~m; |
| | immediate += 4; |
| | overlap = true; |
| | } |
| | offset += 4; |
| | } |
| | } |
| | } else { |
| | if (!p) { |
| | immediate = 4; |
| | } |
| | for (var m = 0x01, i = 0; i < 16; m <<= 1, ++i) { |
| | if (rs & m) { |
| | if (w && i == rn && !offset) { |
| | rs &= ~m; |
| | immediate += 4; |
| | overlap = true; |
| | } |
| | immediate -= 4; |
| | offset -= 4; |
| | } |
| | } |
| | } |
| | if (w) { |
| | address = this.armCompiler.constructAddressingMode4Writeback(immediate, offset, rn, overlap); |
| | } else { |
| | address = this.armCompiler.constructAddressingMode4(immediate, rn); |
| | } |
| | if (load) { |
| | |
| | if (user) { |
| | op = this.armCompiler.constructLDMS(rs, address, condOp); |
| | } else { |
| | op = this.armCompiler.constructLDM(rs, address, condOp); |
| | } |
| | op.writesPC = !!(rs & (1 << 15)); |
| | } else { |
| | |
| | if (user) { |
| | op = this.armCompiler.constructSTMS(rs, address, condOp); |
| | } else { |
| | op = this.armCompiler.constructSTM(rs, address, condOp); |
| | } |
| | op.writesPC = false; |
| | } |
| | break; |
| | case 0x0A000000: |
| | |
| | var immediate = instruction & 0x00FFFFFF; |
| | if (immediate & 0x00800000) { |
| | immediate |= 0xFF000000; |
| | } |
| | immediate <<= 2; |
| | var link = instruction & 0x01000000; |
| | if (link) { |
| | op = this.armCompiler.constructBL(immediate, condOp); |
| | } else { |
| | op = this.armCompiler.constructB(immediate, condOp); |
| | } |
| | op.writesPC = true; |
| | op.fixedJump = true; |
| | break; |
| | case 0x0C000000: |
| | |
| | break; |
| | case 0x0E000000: |
| | |
| | if ((instruction & 0x0F000000) == 0x0F000000) { |
| | |
| | var immediate = (instruction & 0x00FFFFFF); |
| | op = this.armCompiler.constructSWI(immediate, condOp); |
| | op.writesPC = false; |
| | } |
| | break; |
| | default: |
| | throw 'Bad opcode: 0x' + instruction.toString(16); |
| | } |
| | } |
| |
|
| | op.execMode = this.MODE_ARM; |
| | op.fixedJump = op.fixedJump || false; |
| | return op; |
| | }; |
| |
|
| | ARMCore.prototype.compileThumb = function(instruction) { |
| | var op = this.badOp(instruction & 0xFFFF); |
| | var cpu = this; |
| | var gprs = this.gprs; |
| | if ((instruction & 0xFC00) == 0x4000) { |
| | |
| | var rm = (instruction & 0x0038) >> 3; |
| | var rd = instruction & 0x0007; |
| | switch (instruction & 0x03C0) { |
| | case 0x0000: |
| | |
| | op = this.thumbCompiler.constructAND(rd, rm); |
| | break; |
| | case 0x0040: |
| | |
| | op = this.thumbCompiler.constructEOR(rd, rm); |
| | break; |
| | case 0x0080: |
| | |
| | op = this.thumbCompiler.constructLSL2(rd, rm); |
| | break; |
| | case 0x00C0: |
| | |
| | op = this.thumbCompiler.constructLSR2(rd, rm); |
| | break; |
| | case 0x0100: |
| | |
| | op = this.thumbCompiler.constructASR2(rd, rm); |
| | break; |
| | case 0x0140: |
| | |
| | op = this.thumbCompiler.constructADC(rd, rm); |
| | break; |
| | case 0x0180: |
| | |
| | op = this.thumbCompiler.constructSBC(rd, rm); |
| | break; |
| | case 0x01C0: |
| | |
| | op = this.thumbCompiler.constructROR(rd, rm); |
| | break; |
| | case 0x0200: |
| | |
| | op = this.thumbCompiler.constructTST(rd, rm); |
| | break; |
| | case 0x0240: |
| | |
| | op = this.thumbCompiler.constructNEG(rd, rm); |
| | break; |
| | case 0x0280: |
| | |
| | op = this.thumbCompiler.constructCMP2(rd, rm); |
| | break; |
| | case 0x02C0: |
| | |
| | op = this.thumbCompiler.constructCMN(rd, rm); |
| | break; |
| | case 0x0300: |
| | |
| | op = this.thumbCompiler.constructORR(rd, rm); |
| | break; |
| | case 0x0340: |
| | |
| | op = this.thumbCompiler.constructMUL(rd, rm); |
| | break; |
| | case 0x0380: |
| | |
| | op = this.thumbCompiler.constructBIC(rd, rm); |
| | break; |
| | case 0x03C0: |
| | |
| | op = this.thumbCompiler.constructMVN(rd, rm); |
| | break; |
| | } |
| | op.writesPC = false; |
| | } else if ((instruction & 0xFC00) == 0x4400) { |
| | |
| | var rm = (instruction & 0x0078) >> 3; |
| | var rn = instruction & 0x0007; |
| | var h1 = instruction & 0x0080; |
| | var rd = rn | (h1 >> 4); |
| | switch (instruction & 0x0300) { |
| | case 0x0000: |
| | |
| | op = this.thumbCompiler.constructADD4(rd, rm) |
| | op.writesPC = rd == this.PC; |
| | break; |
| | case 0x0100: |
| | |
| | op = this.thumbCompiler.constructCMP3(rd, rm); |
| | op.writesPC = false; |
| | break; |
| | case 0x0200: |
| | |
| | op = this.thumbCompiler.constructMOV3(rd, rm); |
| | op.writesPC = rd == this.PC; |
| | break; |
| | case 0x0300: |
| | |
| | op = this.thumbCompiler.constructBX(rd, rm); |
| | op.writesPC = true; |
| | op.fixedJump = false; |
| | break; |
| | } |
| | } else if ((instruction & 0xF800) == 0x1800) { |
| | |
| | var rm = (instruction & 0x01C0) >> 6; |
| | var rn = (instruction & 0x0038) >> 3; |
| | var rd = instruction & 0x0007; |
| | switch (instruction & 0x0600) { |
| | case 0x0000: |
| | |
| | op = this.thumbCompiler.constructADD3(rd, rn, rm); |
| | break; |
| | case 0x0200: |
| | |
| | op = this.thumbCompiler.constructSUB3(rd, rn, rm); |
| | break; |
| | case 0x0400: |
| | var immediate = (instruction & 0x01C0) >> 6; |
| | if (immediate) { |
| | |
| | op = this.thumbCompiler.constructADD1(rd, rn, immediate); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructMOV2(rd, rn, rm); |
| | } |
| | break; |
| | case 0x0600: |
| | |
| | var immediate = (instruction & 0x01C0) >> 6; |
| | op = this.thumbCompiler.constructSUB1(rd, rn, immediate); |
| | break; |
| | } |
| | op.writesPC = false; |
| | } else if (!(instruction & 0xE000)) { |
| | |
| | var rd = instruction & 0x0007; |
| | var rm = (instruction & 0x0038) >> 3; |
| | var immediate = (instruction & 0x07C0) >> 6; |
| | switch (instruction & 0x1800) { |
| | case 0x0000: |
| | |
| | op = this.thumbCompiler.constructLSL1(rd, rm, immediate); |
| | break; |
| | case 0x0800: |
| | |
| | op = this.thumbCompiler.constructLSR1(rd, rm, immediate); |
| | break; |
| | case 0x1000: |
| | |
| | op = this.thumbCompiler.constructASR1(rd, rm, immediate); |
| | break; |
| | case 0x1800: |
| | break; |
| | } |
| | op.writesPC = false; |
| | } else if ((instruction & 0xE000) == 0x2000) { |
| | |
| | var immediate = instruction & 0x00FF; |
| | var rn = (instruction & 0x0700) >> 8; |
| | switch (instruction & 0x1800) { |
| | case 0x0000: |
| | |
| | op = this.thumbCompiler.constructMOV1(rn, immediate); |
| | break; |
| | case 0x0800: |
| | |
| | op = this.thumbCompiler.constructCMP1(rn, immediate); |
| | break; |
| | case 0x1000: |
| | |
| | op = this.thumbCompiler.constructADD2(rn, immediate); |
| | break; |
| | case 0x1800: |
| | |
| | op = this.thumbCompiler.constructSUB2(rn, immediate); |
| | break; |
| | } |
| | op.writesPC = false; |
| | } else if ((instruction & 0xF800) == 0x4800) { |
| | |
| | var rd = (instruction & 0x0700) >> 8; |
| | var immediate = (instruction & 0x00FF) << 2; |
| | op = this.thumbCompiler.constructLDR3(rd, immediate); |
| | op.writesPC = false; |
| | } else if ((instruction & 0xF000) == 0x5000) { |
| | |
| | var rd = instruction & 0x0007; |
| | var rn = (instruction & 0x0038) >> 3; |
| | var rm = (instruction & 0x01C0) >> 6; |
| | var opcode = instruction & 0x0E00; |
| | switch (opcode) { |
| | case 0x0000: |
| | |
| | op = this.thumbCompiler.constructSTR2(rd, rn, rm); |
| | break; |
| | case 0x0200: |
| | |
| | op = this.thumbCompiler.constructSTRH2(rd, rn, rm); |
| | break; |
| | case 0x0400: |
| | |
| | op = this.thumbCompiler.constructSTRB2(rd, rn, rm); |
| | break; |
| | case 0x0600: |
| | |
| | op = this.thumbCompiler.constructLDRSB(rd, rn, rm); |
| | break; |
| | case 0x0800: |
| | |
| | op = this.thumbCompiler.constructLDR2(rd, rn, rm); |
| | break; |
| | case 0x0A00: |
| | |
| | op = this.thumbCompiler.constructLDRH2(rd, rn, rm); |
| | break; |
| | case 0x0C00: |
| | |
| | op = this.thumbCompiler.constructLDRB2(rd, rn, rm); |
| | break; |
| | case 0x0E00: |
| | |
| | op = this.thumbCompiler.constructLDRSH(rd, rn, rm); |
| | break; |
| | } |
| | op.writesPC = false; |
| | } else if ((instruction & 0xE000) == 0x6000) { |
| | |
| | var rd = instruction & 0x0007; |
| | var rn = (instruction & 0x0038) >> 3; |
| | var immediate = (instruction & 0x07C0) >> 4; |
| | var b = instruction & 0x1000; |
| | if (b) { |
| | immediate >>= 2; |
| | } |
| | var load = instruction & 0x0800; |
| | if (load) { |
| | if (b) { |
| | |
| | op = this.thumbCompiler.constructLDRB1(rd, rn, immediate); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructLDR1(rd, rn, immediate); |
| | } |
| | } else { |
| | if (b) { |
| | |
| | op = this.thumbCompiler.constructSTRB1(rd, rn, immediate); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructSTR1(rd, rn, immediate); |
| | } |
| | } |
| | op.writesPC = false; |
| | } else if ((instruction & 0xF600) == 0xB400) { |
| | |
| | var r = !!(instruction & 0x0100); |
| | var rs = instruction & 0x00FF; |
| | if (instruction & 0x0800) { |
| | |
| | op = this.thumbCompiler.constructPOP(rs, r); |
| | op.writesPC = r; |
| | op.fixedJump = false; |
| | } else { |
| | |
| | op = this.thumbCompiler.constructPUSH(rs, r); |
| | op.writesPC = false; |
| | } |
| | } else if (instruction & 0x8000) { |
| | switch (instruction & 0x7000) { |
| | case 0x0000: |
| | |
| | var rd = instruction & 0x0007; |
| | var rn = (instruction & 0x0038) >> 3; |
| | var immediate = (instruction & 0x07C0) >> 5; |
| | if (instruction & 0x0800) { |
| | |
| | op = this.thumbCompiler.constructLDRH1(rd, rn, immediate); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructSTRH1(rd, rn, immediate); |
| | } |
| | op.writesPC = false; |
| | break; |
| | case 0x1000: |
| | |
| | var rd = (instruction & 0x0700) >> 8; |
| | var immediate = (instruction & 0x00FF) << 2; |
| | var load = instruction & 0x0800; |
| | if (load) { |
| | |
| | op = this.thumbCompiler.constructLDR4(rd, immediate); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructSTR3(rd, immediate); |
| | } |
| | op.writesPC = false; |
| | break; |
| | case 0x2000: |
| | |
| | var rd = (instruction & 0x0700) >> 8; |
| | var immediate = (instruction & 0x00FF) << 2; |
| | if (instruction & 0x0800) { |
| | |
| | op = this.thumbCompiler.constructADD6(rd, immediate); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructADD5(rd, immediate); |
| | } |
| | op.writesPC = false; |
| | break; |
| | case 0x3000: |
| | |
| | if (!(instruction & 0x0F00)) { |
| | |
| | |
| | var b = instruction & 0x0080; |
| | var immediate = (instruction & 0x7F) << 2; |
| | if (b) { |
| | immediate = -immediate; |
| | } |
| | op = this.thumbCompiler.constructADD7(immediate) |
| | op.writesPC = false; |
| | } |
| | break; |
| | case 0x4000: |
| | |
| | var rn = (instruction & 0x0700) >> 8; |
| | var rs = instruction & 0x00FF; |
| | if (instruction & 0x0800) { |
| | |
| | op = this.thumbCompiler.constructLDMIA(rn, rs); |
| | } else { |
| | |
| | op = this.thumbCompiler.constructSTMIA(rn, rs); |
| | } |
| | op.writesPC = false; |
| | break; |
| | case 0x5000: |
| | |
| | var cond = (instruction & 0x0F00) >> 8; |
| | var immediate = (instruction & 0x00FF); |
| | if (cond == 0xF) { |
| | |
| | op = this.thumbCompiler.constructSWI(immediate); |
| | op.writesPC = false; |
| | } else { |
| | |
| | if (instruction & 0x0080) { |
| | immediate |= 0xFFFFFF00; |
| | } |
| | immediate <<= 1; |
| | var condOp = this.conds[cond]; |
| | op = this.thumbCompiler.constructB1(immediate, condOp); |
| | op.writesPC = true; |
| | op.fixedJump = true; |
| | } |
| | break; |
| | case 0x6000: |
| | case 0x7000: |
| | |
| | var immediate = instruction & 0x07FF; |
| | var h = instruction & 0x1800; |
| | switch (h) { |
| | case 0x0000: |
| | |
| | if (immediate & 0x0400) { |
| | immediate |= 0xFFFFF800; |
| | } |
| | immediate <<= 1; |
| | op = this.thumbCompiler.constructB2(immediate); |
| | op.writesPC = true; |
| | op.fixedJump = true; |
| | break; |
| | case 0x0800: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | break; |
| | case 0x1000: |
| | |
| | if (immediate & 0x0400) { |
| | immediate |= 0xFFFFFC00; |
| | } |
| | immediate <<= 12; |
| | op = this.thumbCompiler.constructBL1(immediate); |
| | op.writesPC = false; |
| | break; |
| | case 0x1800: |
| | |
| | op = this.thumbCompiler.constructBL2(immediate); |
| | op.writesPC = true; |
| | op.fixedJump = false; |
| | break; |
| | } |
| | break; |
| | default: |
| | this.WARN("Undefined instruction: 0x" + instruction.toString(16)); |
| | } |
| | } else { |
| | throw 'Bad opcode: 0x' + instruction.toString(16); |
| | } |
| |
|
| | op.execMode = this.MODE_THUMB; |
| | op.fixedJump = op.fixedJump || false; |
| | return op; |
| | }; |
| |
|