emulator/gba3/js/arm.js
2019-06-14 09:33:19 +08:00

1570 lines
36 KiB
JavaScript

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));
};
};