ARMCoreArm = function (cpu) { this.cpu = cpu; this.addressingMode23Immediate = [ // 000x0 function(rn, offset, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn]; if (!condOp || condOp()) { gprs[rn] -= offset; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, // 000xW null, null, null, // 00Ux0 function(rn, offset, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn]; if (!condOp || condOp()) { gprs[rn] += offset; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, // 00UxW null, null, null, // 0P0x0 function(rn, offset, condOp) { var gprs = cpu.gprs; var address = function() { return addr = gprs[rn] - offset; }; address.writesPC = false; return address; }, // 0P0xW function(rn, offset, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn] - offset; if (!condOp || condOp()) { gprs[rn] = addr; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, null, null, // 0PUx0 function(rn, offset, condOp) { var gprs = cpu.gprs; var address = function() { return addr = gprs[rn] + offset; }; address.writesPC = false; return address; }, // 0PUxW function(rn, offset, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn] + offset; if (!condOp || condOp()) { gprs[rn] = addr; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, null, null, ]; this.addressingMode23Register = [ // I00x0 function(rn, rm, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn]; if (!condOp || condOp()) { gprs[rn] -= gprs[rm]; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, // I00xW null, null, null, // I0Ux0 function(rn, rm, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn]; if (!condOp || condOp()) { gprs[rn] += gprs[rm]; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, // I0UxW null, null, null, // IP0x0 function(rn, rm, condOp) { var gprs = cpu.gprs; var address = function() { return gprs[rn] - gprs[rm]; }; address.writesPC = false; return address; }, // IP0xW function(rn, rm, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn] - gprs[rm]; if (!condOp || condOp()) { gprs[rn] = addr; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, null, null, // IPUx0 function(rn, rm, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn] + gprs[rm]; return addr; }; address.writesPC = false; return address; }, // IPUxW function(rn, rm, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn] + gprs[rm]; if (!condOp || condOp()) { gprs[rn] = addr; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, null, null ]; this.addressingMode2RegisterShifted = [ // I00x0 function(rn, shiftOp, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn]; if (!condOp || condOp()) { shiftOp(); gprs[rn] -= cpu.shifterOperand; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, // I00xW null, null, null, // I0Ux0 function(rn, shiftOp, condOp) { var gprs = cpu.gprs; var address = function() { var addr = gprs[rn]; if (!condOp || condOp()) { shiftOp(); gprs[rn] += cpu.shifterOperand; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, // I0UxW null, null, null, // IP0x0 function(rn, shiftOp, condOp) { var gprs = cpu.gprs; var address = function() { shiftOp(); return gprs[rn] - cpu.shifterOperand; }; address.writesPC = false; return address; }, // IP0xW function(rn, shiftOp, condOp) { var gprs = cpu.gprs; var address = function() { shiftOp(); var addr = gprs[rn] - cpu.shifterOperand; if (!condOp || condOp()) { gprs[rn] = addr; } return addr; }; address.writesPC = rn == cpu.PC; return address; }, null, null, // IPUx0 function(rn, shiftOp, condOp) { var gprs = cpu.gprs; var address = function() { shiftOp(); return gprs[rn] + cpu.shifterOperand; }; address.writesPC = false; return address; }, // IPUxW function(rn, shiftOp, condOp) { var gprs = cpu.gprs; var address = function() { shiftOp(); var addr = gprs[rn] + cpu.shifterOperand; if (!condOp || condOp()) { gprs[rn] = addr; } return addr; }; address.writePC = rn == cpu.PC; return address; }, null, null, ]; } ARMCoreArm.prototype.constructAddressingMode1ASR = function(rs, rm) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { ++cpu.cycles; var shift = gprs[rs]; if (rs == cpu.PC) { shift += 4; } shift &= 0xFF; var shiftVal = gprs[rm]; if (rm == cpu.PC) { shiftVal += 4; } if (shift == 0) { cpu.shifterOperand = shiftVal; cpu.shifterCarryOut = cpu.cpsrC; } else if (shift < 32) { cpu.shifterOperand = shiftVal >> shift; cpu.shifterCarryOut = shiftVal & (1 << (shift - 1)); } else if (gprs[rm] >> 31) { cpu.shifterOperand = 0xFFFFFFFF; cpu.shifterCarryOut = 0x80000000; } else { cpu.shifterOperand = 0; cpu.shifterCarryOut = 0; } }; }; ARMCoreArm.prototype.constructAddressingMode1Immediate = function(immediate) { var cpu = this.cpu; return function() { cpu.shifterOperand = immediate; cpu.shifterCarryOut = cpu.cpsrC; }; }; ARMCoreArm.prototype.constructAddressingMode1ImmediateRotate = function(immediate, rotate) { var cpu = this.cpu; return function() { cpu.shifterOperand = (immediate >>> rotate) | (immediate << (32 - rotate)); cpu.shifterCarryOut = cpu.shifterOperand >> 31; } }; ARMCoreArm.prototype.constructAddressingMode1LSL = function(rs, rm) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { ++cpu.cycles; var shift = gprs[rs]; if (rs == cpu.PC) { shift += 4; } shift &= 0xFF; var shiftVal = gprs[rm]; if (rm == cpu.PC) { shiftVal += 4; } if (shift == 0) { cpu.shifterOperand = shiftVal; cpu.shifterCarryOut = cpu.cpsrC; } else if (shift < 32) { cpu.shifterOperand = shiftVal << shift; cpu.shifterCarryOut = shiftVal & (1 << (32 - shift)); } else if (shift == 32) { cpu.shifterOperand = 0; cpu.shifterCarryOut = shiftVal & 1; } else { cpu.shifterOperand = 0; cpu.shifterCarryOut = 0; } }; }; ARMCoreArm.prototype.constructAddressingMode1LSR = function(rs, rm) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { ++cpu.cycles; var shift = gprs[rs]; if (rs == cpu.PC) { shift += 4; } shift &= 0xFF; var shiftVal = gprs[rm]; if (rm == cpu.PC) { shiftVal += 4; } if (shift == 0) { cpu.shifterOperand = shiftVal; cpu.shifterCarryOut = cpu.cpsrC; } else if (shift < 32) { cpu.shifterOperand = shiftVal >>> shift; cpu.shifterCarryOut = shiftVal & (1 << (shift - 1)); } else if (shift == 32) { cpu.shifterOperand = 0; cpu.shifterCarryOut = shiftVal >> 31; } else { cpu.shifterOperand = 0; cpu.shifterCarryOut = 0; } }; }; ARMCoreArm.prototype.constructAddressingMode1ROR = function(rs, rm) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { ++cpu.cycles; var shift = gprs[rs]; if (rs == cpu.PC) { shift += 4; } shift &= 0xFF; var shiftVal = gprs[rm]; if (rm == cpu.PC) { shiftVal += 4; } var rotate = shift & 0x1F; if (shift == 0) { cpu.shifterOperand = shiftVal; cpu.shifterCarryOut = cpu.cpsrC; } else if (rotate) { cpu.shifterOperand = (gprs[rm] >>> rotate) | (gprs[rm] << (32 - rotate)); cpu.shifterCarryOut = shiftVal & (1 << (rotate - 1)); } else { cpu.shifterOperand = shiftVal; cpu.shifterCarryOut = shiftVal >> 31; } }; }; ARMCoreArm.prototype.constructAddressingMode23Immediate = function(instruction, immediate, condOp) { var rn = (instruction & 0x000F0000) >> 16; return this.addressingMode23Immediate[(instruction & 0x01A00000) >> 21](rn, immediate, condOp); }; ARMCoreArm.prototype.constructAddressingMode23Register = function(instruction, rm, condOp) { var rn = (instruction & 0x000F0000) >> 16; return this.addressingMode23Register[(instruction & 0x01A00000) >> 21](rn, rm, condOp); }; ARMCoreArm.prototype.constructAddressingMode2RegisterShifted = function(instruction, shiftOp, condOp) { var rn = (instruction & 0x000F0000) >> 16; return this.addressingMode2RegisterShifted[(instruction & 0x01A00000) >> 21](rn, shiftOp, condOp); }; ARMCoreArm.prototype.constructAddressingMode4 = function(immediate, rn) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { var addr = gprs[rn] + immediate; return addr; } }; ARMCoreArm.prototype.constructAddressingMode4Writeback = function(immediate, offset, rn, overlap) { var cpu = this.cpu; var gprs = cpu.gprs; return function(writeInitial) { var addr = gprs[rn] + immediate; if (writeInitial && overlap) { cpu.mmu.store32(gprs[rn] + immediate - 4, gprs[rn]); } gprs[rn] += offset; return addr; } }; ARMCoreArm.prototype.constructADC = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var shifterOperand = (cpu.shifterOperand >>> 0) + !!cpu.cpsrC; gprs[rd] = (gprs[rn] >>> 0) + shifterOperand; }; }; ARMCoreArm.prototype.constructADCS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var shifterOperand = (cpu.shifterOperand >>> 0) + !!cpu.cpsrC; var d = (gprs[rn] >>> 0) + shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = d >> 31; cpu.cpsrZ = !(d & 0xFFFFFFFF); cpu.cpsrC = d > 0xFFFFFFFF; cpu.cpsrV = (gprs[rn] >> 31) == (shifterOperand >> 31) && (gprs[rn] >> 31) != (d >> 31) && (shifterOperand >> 31) != (d >> 31); } gprs[rd] = d; }; }; ARMCoreArm.prototype.constructADD = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = (gprs[rn] >>> 0) + (cpu.shifterOperand >>> 0); }; }; ARMCoreArm.prototype.constructADDS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var d = (gprs[rn] >>> 0) + (cpu.shifterOperand >>> 0); if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = d >> 31; cpu.cpsrZ = !(d & 0xFFFFFFFF); cpu.cpsrC = d > 0xFFFFFFFF; cpu.cpsrV = (gprs[rn] >> 31) == (cpu.shifterOperand >> 31) && (gprs[rn] >> 31) != (d >> 31) && (cpu.shifterOperand >> 31) != (d >> 31); } gprs[rd] = d; }; }; ARMCoreArm.prototype.constructAND = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] & cpu.shifterOperand; }; }; ARMCoreArm.prototype.constructANDS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] & cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; } }; }; ARMCoreArm.prototype.constructB = function(immediate, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } cpu.mmu.waitPrefetch32(gprs[cpu.PC]); gprs[cpu.PC] += immediate; }; }; ARMCoreArm.prototype.constructBIC = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] & ~cpu.shifterOperand; }; }; ARMCoreArm.prototype.constructBICS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] & ~cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; } }; }; ARMCoreArm.prototype.constructBL = function(immediate, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } cpu.mmu.waitPrefetch32(gprs[cpu.PC]); gprs[cpu.LR] = gprs[cpu.PC] - 4; gprs[cpu.PC] += immediate; }; }; ARMCoreArm.prototype.constructBX = function(rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } cpu.mmu.waitPrefetch32(gprs[cpu.PC]); cpu.switchExecMode(gprs[rm] & 0x00000001); gprs[cpu.PC] = gprs[rm] & 0xFFFFFFFE; }; }; ARMCoreArm.prototype.constructCMN = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var aluOut = (gprs[rn] >>> 0) + (cpu.shifterOperand >>> 0); cpu.cpsrN = aluOut >> 31; cpu.cpsrZ = !(aluOut & 0xFFFFFFFF); cpu.cpsrC = aluOut > 0xFFFFFFFF; cpu.cpsrV = (gprs[rn] >> 31) == (cpu.shifterOperand >> 31) && (gprs[rn] >> 31) != (aluOut >> 31) && (cpu.shifterOperand >> 31) != (aluOut >> 31); }; }; ARMCoreArm.prototype.constructCMP = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var aluOut = gprs[rn] - cpu.shifterOperand; cpu.cpsrN = aluOut >> 31; cpu.cpsrZ = !(aluOut & 0xFFFFFFFF); cpu.cpsrC = (gprs[rn] >>> 0) >= (cpu.shifterOperand >>> 0); cpu.cpsrV = (gprs[rn] >> 31) != (cpu.shifterOperand >> 31) && (gprs[rn] >> 31) != (aluOut >> 31); }; }; ARMCoreArm.prototype.constructEOR = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] ^ cpu.shifterOperand; }; }; ARMCoreArm.prototype.constructEORS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] ^ cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; } }; }; ARMCoreArm.prototype.constructLDM = function(rs, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; var mmu = cpu.mmu; return function() { mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(false); var total = 0; var m, i; for (m = rs, i = 0; m; m >>= 1, ++i) { if (m & 1) { gprs[i] = mmu.load32(addr & 0xFFFFFFFC); addr += 4; ++total; } } mmu.waitMulti32(addr, total); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructLDMS = function(rs, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; var mmu = cpu.mmu; return function() { mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(false); var total = 0; var mode = cpu.mode; cpu.switchMode(cpu.MODE_SYSTEM); var m, i; for (m = rs, i = 0; m; m >>= 1, ++i) { if (m & 1) { gprs[i] = mmu.load32(addr & 0xFFFFFFFC); addr += 4; ++total; } } cpu.switchMode(mode); mmu.waitMulti32(addr, total); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructLDR = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(); gprs[rd] = cpu.mmu.load32(addr); cpu.mmu.wait32(addr); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructLDRB = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(); gprs[rd] = cpu.mmu.loadU8(addr); cpu.mmu.wait(addr); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructLDRH = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(); gprs[rd] = cpu.mmu.loadU16(addr); cpu.mmu.wait(addr); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructLDRSB = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(); gprs[rd] = cpu.mmu.load8(addr); cpu.mmu.wait(addr); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructLDRSH = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var addr = address(); gprs[rd] = cpu.mmu.load16(addr); cpu.mmu.wait(addr); ++cpu.cycles; }; }; ARMCoreArm.prototype.constructMLA = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } ++cpu.cycles; cpu.mmu.waitMul(rs); if ((gprs[rm] & 0xFFFF0000) && (gprs[rs] & 0xFFFF0000)) { // Our data type is a double--we'll lose bits if we do it all at once! var hi = ((gprs[rm] & 0xFFFF0000) * gprs[rs]) & 0xFFFFFFFF; var lo = ((gprs[rm] & 0x0000FFFF) * gprs[rs]) & 0xFFFFFFFF; gprs[rd] = (hi + lo + gprs[rn]) & 0xFFFFFFFF; } else { gprs[rd] = gprs[rm] * gprs[rs] + gprs[rn]; } }; }; ARMCoreArm.prototype.constructMLAS = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } ++cpu.cycles; cpu.mmu.waitMul(rs); if ((gprs[rm] & 0xFFFF0000) && (gprs[rs] & 0xFFFF0000)) { // Our data type is a double--we'll lose bits if we do it all at once! var hi = ((gprs[rm] & 0xFFFF0000) * gprs[rs]) & 0xFFFFFFFF; var lo = ((gprs[rm] & 0x0000FFFF) * gprs[rs]) & 0xFFFFFFFF; gprs[rd] = (hi + lo + gprs[rn]) & 0xFFFFFFFF; } else { gprs[rd] = gprs[rm] * gprs[rs] + gprs[rn]; } cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); }; }; ARMCoreArm.prototype.constructMOV = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = cpu.shifterOperand; }; }; ARMCoreArm.prototype.constructMOVS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; } }; }; ARMCoreArm.prototype.constructMRS = function(rd, r, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } if (r) { gprs[rd] = cpu.spsr; } else { gprs[rd] = cpu.packCPSR(); } }; }; ARMCoreArm.prototype.constructMSR = function(rm, r, instruction, immediate, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; var c = instruction & 0x00010000; //var x = instruction & 0x00020000; //var s = instruction & 0x00040000; var f = instruction & 0x00080000; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } var operand; if (instruction & 0x02000000) { operand = immediate; } else { operand = gprs[rm]; } var mask = (c ? 0x000000FF : 0x00000000) | //(x ? 0x0000FF00 : 0x00000000) | // Irrelevant on ARMv4T //(s ? 0x00FF0000 : 0x00000000) | // Irrelevant on ARMv4T (f ? 0xFF000000 : 0x00000000); if (r) { mask &= cpu.USER_MASK | cpu.PRIV_MASK | cpu.STATE_MASK; cpu.spsr = (cpu.spsr & ~mask) | (operand & mask); } else { if (mask & cpu.USER_MASK) { cpu.cpsrN = operand >> 31; cpu.cpsrZ = operand & 0x40000000; cpu.cpsrC = operand & 0x20000000; cpu.cpsrV = operand & 0x10000000; } if (cpu.mode != cpu.MODE_USER && (mask & cpu.PRIV_MASK)) { cpu.switchMode((operand & 0x0000000F) | 0x00000010); cpu.cpsrI = operand & 0x00000080; cpu.cpsrF = operand & 0x00000040; } } }; }; ARMCoreArm.prototype.constructMUL = function(rd, rs, rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.mmu.waitMul(gprs[rs]); if ((gprs[rm] & 0xFFFF0000) && (gprs[rs] & 0xFFFF0000)) { // Our data type is a double--we'll lose bits if we do it all at once! var hi = ((gprs[rm] & 0xFFFF0000) * gprs[rs]) | 0; var lo = ((gprs[rm] & 0x0000FFFF) * gprs[rs]) | 0; gprs[rd] = hi + lo; } else { gprs[rd] = gprs[rm] * gprs[rs]; } }; }; ARMCoreArm.prototype.constructMULS = function(rd, rs, rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.mmu.waitMul(gprs[rs]); if ((gprs[rm] & 0xFFFF0000) && (gprs[rs] & 0xFFFF0000)) { // Our data type is a double--we'll lose bits if we do it all at once! var hi = ((gprs[rm] & 0xFFFF0000) * gprs[rs]) | 0; var lo = ((gprs[rm] & 0x0000FFFF) * gprs[rs]) | 0; gprs[rd] = hi + lo; } else { gprs[rd] = gprs[rm] * gprs[rs]; } cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); }; }; ARMCoreArm.prototype.constructMVN = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = ~cpu.shifterOperand; }; }; ARMCoreArm.prototype.constructMVNS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = ~cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; } }; }; ARMCoreArm.prototype.constructORR = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] | cpu.shifterOperand; } }; ARMCoreArm.prototype.constructORRS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] | cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !(gprs[rd] & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; } }; }; ARMCoreArm.prototype.constructRSB = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = cpu.shifterOperand - gprs[rn]; }; }; ARMCoreArm.prototype.constructRSBS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var d = cpu.shifterOperand - gprs[rn]; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = d >> 31; cpu.cpsrZ = !(d & 0xFFFFFFFF); cpu.cpsrC = (cpu.shifterOperand >>> 0) >= (gprs[rn] >>> 0); cpu.cpsrV = (cpu.shifterOperand >> 31) != (gprs[rn] >> 31) && (cpu.shifterOperand >> 31) != (d >> 31); } gprs[rd] = d; }; }; ARMCoreArm.prototype.constructRSC = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var n = (gprs[rn] >>> 0) + !cpu.cpsrC; gprs[rd] = (cpu.shifterOperand >>> 0) - n; }; }; ARMCoreArm.prototype.constructRSCS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var n = (gprs[rn] >>> 0) + !cpu.cpsrC; var d = (cpu.shifterOperand >>> 0) - n; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = d >> 31; cpu.cpsrZ = !(d & 0xFFFFFFFF); cpu.cpsrC = (cpu.shifterOperand >>> 0) >= (d >>> 0); cpu.cpsrV = (cpu.shifterOperand >> 31) != (n >> 31) && (cpu.shifterOperand >> 31) != (d >> 31); } gprs[rd] = d; }; }; ARMCoreArm.prototype.constructSBC = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var shifterOperand = (cpu.shifterOperand >>> 0) + !cpu.cpsrC; gprs[rd] = (gprs[rn] >>> 0) - shifterOperand; }; }; ARMCoreArm.prototype.constructSBCS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var shifterOperand = (cpu.shifterOperand >>> 0) + !cpu.cpsrC; var d = (gprs[rn] >>> 0) - shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = d >> 31; cpu.cpsrZ = !(d & 0xFFFFFFFF); cpu.cpsrC = (gprs[rn] >>> 0) >= (d >>> 0); cpu.cpsrV = (gprs[rn] >> 31) != (shifterOperand >> 31) && (gprs[rn] >> 31) != (d >> 31); } gprs[rd] = d; }; }; ARMCoreArm.prototype.constructSMLAL = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.cycles += 2; cpu.mmu.waitMul(rs); var hi = (gprs[rm] & 0xFFFF0000) * gprs[rs]; var lo = (gprs[rm] & 0x0000FFFF) * gprs[rs]; var carry = (gprs[rn] >>> 0) + hi + lo; gprs[rn] = carry; gprs[rd] += Math.floor(carry * SHIFT_32); }; }; ARMCoreArm.prototype.constructSMLALS = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.cycles += 2; cpu.mmu.waitMul(rs); var hi = (gprs[rm] & 0xFFFF0000) * gprs[rs]; var lo = (gprs[rm] & 0x0000FFFF) * gprs[rs]; var carry = (gprs[rn] >>> 0) + hi + lo; gprs[rn] = carry; gprs[rd] += Math.floor(carry * SHIFT_32); cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !((gprs[rd] & 0xFFFFFFFF) || (gprs[rn] & 0xFFFFFFFF)); }; }; ARMCoreArm.prototype.constructSMULL = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } ++cpu.cycles; cpu.mmu.waitMul(gprs[rs]); var hi = ((gprs[rm] & 0xFFFF0000) >> 0) * (gprs[rs] >> 0); var lo = ((gprs[rm] & 0x0000FFFF) >> 0) * (gprs[rs] >> 0); gprs[rn] = ((hi & 0xFFFFFFFF) + (lo & 0xFFFFFFFF)) & 0xFFFFFFFF; gprs[rd] = Math.floor(hi * SHIFT_32 + lo * SHIFT_32); }; }; ARMCoreArm.prototype.constructSMULLS = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } ++cpu.cycles; cpu.mmu.waitMul(gprs[rs]); var hi = ((gprs[rm] & 0xFFFF0000) >> 0) * (gprs[rs] >> 0); var lo = ((gprs[rm] & 0x0000FFFF) >> 0) * (gprs[rs] >> 0); gprs[rn] = ((hi & 0xFFFFFFFF) + (lo & 0xFFFFFFFF)) & 0xFFFFFFFF; gprs[rd] = Math.floor(hi * SHIFT_32 + lo * SHIFT_32); cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !((gprs[rd] & 0xFFFFFFFF) || (gprs[rn] & 0xFFFFFFFF)); }; }; ARMCoreArm.prototype.constructSTM = function(rs, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; var mmu = cpu.mmu; return function() { if (condOp && !condOp()) { mmu.waitPrefetch32(gprs[cpu.PC]); return; } mmu.wait32(gprs[cpu.PC]); var addr = address(true); var total = 0; var m, i; for (m = rs, i = 0; m; m >>= 1, ++i) { if (m & 1) { mmu.store32(addr, gprs[i]); addr += 4; ++total; } } mmu.waitMulti32(addr, total); }; }; ARMCoreArm.prototype.constructSTMS = function(rs, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; var mmu = cpu.mmu; return function() { if (condOp && !condOp()) { mmu.waitPrefetch32(gprs[cpu.PC]); return; } mmu.wait32(gprs[cpu.PC]); var mode = cpu.mode; var addr = address(true); var total = 0; var m, i; cpu.switchMode(cpu.MODE_SYSTEM); for (m = rs, i = 0; m; m >>= 1, ++i) { if (m & 1) { mmu.store32(addr, gprs[i]); addr += 4; ++total; } } cpu.switchMode(mode); mmu.waitMulti32(addr, total); }; }; ARMCoreArm.prototype.constructSTR = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } var addr = address(); cpu.mmu.store32(addr, gprs[rd]); cpu.mmu.wait32(addr); cpu.mmu.wait32(gprs[cpu.PC]); }; }; ARMCoreArm.prototype.constructSTRB = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } var addr = address(); cpu.mmu.store8(addr, gprs[rd]); cpu.mmu.wait(addr); cpu.mmu.wait32(gprs[cpu.PC]); }; }; ARMCoreArm.prototype.constructSTRH = function(rd, address, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } var addr = address(); cpu.mmu.store16(addr, gprs[rd]); cpu.mmu.wait(addr); cpu.mmu.wait32(gprs[cpu.PC]); }; }; ARMCoreArm.prototype.constructSUB = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); gprs[rd] = gprs[rn] - cpu.shifterOperand; }; }; ARMCoreArm.prototype.constructSUBS = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var d = gprs[rn] - cpu.shifterOperand; if (rd == cpu.PC && cpu.hasSPSR()) { cpu.unpackCPSR(cpu.spsr); } else { cpu.cpsrN = d >> 31; cpu.cpsrZ = !(d & 0xFFFFFFFF); cpu.cpsrC = (gprs[rn] >>> 0) >= (cpu.shifterOperand >>> 0); cpu.cpsrV = (gprs[rn] >> 31) != (cpu.shifterOperand >> 31) && (gprs[rn] >> 31) != (d >> 31); } gprs[rd] = d; }; }; ARMCoreArm.prototype.constructSWI = function(immediate, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { if (condOp && !condOp()) { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); return; } cpu.irq.swi32(immediate); cpu.mmu.waitPrefetch32(gprs[cpu.PC]); }; }; ARMCoreArm.prototype.constructSWP = function(rd, rn, rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.mmu.wait32(gprs[rn]); cpu.mmu.wait32(gprs[rn]); var d = cpu.mmu.load32(gprs[rn]); cpu.mmu.store32(gprs[rn], gprs[rm]); gprs[rd] = d; ++cpu.cycles; } }; ARMCoreArm.prototype.constructSWPB = function(rd, rn, rm, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.mmu.wait(gprs[rn]); cpu.mmu.wait(gprs[rn]); var d = cpu.mmu.load8(gprs[rn]); cpu.mmu.store8(gprs[rn], gprs[rm]); gprs[rd] = d; ++cpu.cycles; } }; ARMCoreArm.prototype.constructTEQ = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var aluOut = gprs[rn] ^ cpu.shifterOperand; cpu.cpsrN = aluOut >> 31; cpu.cpsrZ = !(aluOut & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; }; }; ARMCoreArm.prototype.constructTST = function(rd, rn, shiftOp, condOp) { var cpu = this.cpu; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } shiftOp(); var aluOut = gprs[rn] & cpu.shifterOperand; cpu.cpsrN = aluOut >> 31; cpu.cpsrZ = !(aluOut & 0xFFFFFFFF); cpu.cpsrC = cpu.shifterCarryOut; }; }; ARMCoreArm.prototype.constructUMLAL = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.cycles += 2; cpu.mmu.waitMul(rs); var hi = ((gprs[rm] & 0xFFFF0000) >>> 0) * (gprs[rs] >>> 0); var lo = (gprs[rm] & 0x0000FFFF) * (gprs[rs] >>> 0); var carry = (gprs[rn] >>> 0) + hi + lo; gprs[rn] = carry; gprs[rd] += carry * SHIFT_32; }; }; ARMCoreArm.prototype.constructUMLALS = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } cpu.cycles += 2; cpu.mmu.waitMul(rs); var hi = ((gprs[rm] & 0xFFFF0000) >>> 0) * (gprs[rs] >>> 0); var lo = (gprs[rm] & 0x0000FFFF) * (gprs[rs] >>> 0); var carry = (gprs[rn] >>> 0) + hi + lo; gprs[rn] = carry; gprs[rd] += carry * SHIFT_32; cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !((gprs[rd] & 0xFFFFFFFF) || (gprs[rn] & 0xFFFFFFFF)); }; }; ARMCoreArm.prototype.constructUMULL = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } ++cpu.cycles; cpu.mmu.waitMul(gprs[rs]); var hi = ((gprs[rm] & 0xFFFF0000) >>> 0) * (gprs[rs] >>> 0); var lo = ((gprs[rm] & 0x0000FFFF) >>> 0) * (gprs[rs] >>> 0); gprs[rn] = ((hi & 0xFFFFFFFF) + (lo & 0xFFFFFFFF)) & 0xFFFFFFFF; gprs[rd] = (hi * SHIFT_32 + lo * SHIFT_32) >>> 0; }; }; ARMCoreArm.prototype.constructUMULLS = function(rd, rn, rs, rm, condOp) { var cpu = this.cpu; var SHIFT_32 = 1/0x100000000; var gprs = cpu.gprs; return function() { cpu.mmu.waitPrefetch32(gprs[cpu.PC]); if (condOp && !condOp()) { return; } ++cpu.cycles; cpu.mmu.waitMul(gprs[rs]); var hi = ((gprs[rm] & 0xFFFF0000) >>> 0) * (gprs[rs] >>> 0); var lo = ((gprs[rm] & 0x0000FFFF) >>> 0) * (gprs[rs] >>> 0); gprs[rn] = ((hi & 0xFFFFFFFF) + (lo & 0xFFFFFFFF)) & 0xFFFFFFFF; gprs[rd] = (hi * SHIFT_32 + lo * SHIFT_32) >>> 0; cpu.cpsrN = gprs[rd] >> 31; cpu.cpsrZ = !((gprs[rd] & 0xFFFFFFFF) || (gprs[rn] & 0xFFFFFFFF)); }; };