This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.CPU = function(nes) { | |
this.nes = nes; | |
// Keep Chrome happy | |
this.mem = null; | |
this.REG_ACC = null; | |
this.REG_X = null; | |
this.REG_Y = null; | |
this.REG_SP = null; | |
this.REG_PC = null; | |
this.REG_PC_NEW = null; | |
this.REG_STATUS = null; | |
this.F_CARRY = null; | |
this.F_DECIMAL = null; | |
this.F_INTERRUPT = null; | |
this.F_INTERRUPT_NEW = null; | |
this.F_OVERFLOW = null; | |
this.F_SIGN = null; | |
this.F_ZERO = null; | |
this.F_NOTUSED = null; | |
this.F_NOTUSED_NEW = null; | |
this.F_BRK = null; | |
this.F_BRK_NEW = null; | |
this.opdata = null; | |
this.cyclesToHalt = null; | |
this.crash = null; | |
this.irqRequested = null; | |
this.irqType = null; | |
this.reset(); | |
}; | |
JSNES.CPU.prototype = { | |
// IRQ Types | |
IRQ_NORMAL: 0, | |
IRQ_NMI: 1, | |
IRQ_RESET: 2, | |
reset: function() { | |
// Main memory | |
this.mem = new Array(0x10000); | |
for (var i=0; i < 0x2000; i++) { | |
this.mem[i] = 0xFF; | |
} | |
for (var p=0; p < 4; p++) { | |
var i = p*0x800; | |
this.mem[i+0x008] = 0xF7; | |
this.mem[i+0x009] = 0xEF; | |
this.mem[i+0x00A] = 0xDF; | |
this.mem[i+0x00F] = 0xBF; | |
} | |
for (var i=0x2001; i < this.mem.length; i++) { | |
this.mem[i] = 0; | |
} | |
// CPU Registers: | |
this.REG_ACC = 0; | |
this.REG_X = 0; | |
this.REG_Y = 0; | |
// Reset Stack pointer: | |
this.REG_SP = 0x01FF; | |
// Reset Program counter: | |
this.REG_PC = 0x8000-1; | |
this.REG_PC_NEW = 0x8000-1; | |
// Reset Status register: | |
this.REG_STATUS = 0x28; | |
this.setStatus(0x28); | |
// Set flags: | |
this.F_CARRY = 0; | |
this.F_DECIMAL = 0; | |
this.F_INTERRUPT = 1; | |
this.F_INTERRUPT_NEW = 1; | |
this.F_OVERFLOW = 0; | |
this.F_SIGN = 0; | |
this.F_ZERO = 1; | |
this.F_NOTUSED = 1; | |
this.F_NOTUSED_NEW = 1; | |
this.F_BRK = 1; | |
this.F_BRK_NEW = 1; | |
this.opdata = new JSNES.CPU.OpData().opdata; | |
this.cyclesToHalt = 0; | |
// Reset crash flag: | |
this.crash = false; | |
// Interrupt notification: | |
this.irqRequested = false; | |
this.irqType = null; | |
}, | |
// Emulates a single CPU instruction, returns the number of cycles | |
emulate: function() { | |
var temp; | |
var add; | |
// Check interrupts: | |
if(this.irqRequested){ | |
temp = | |
(this.F_CARRY)| | |
((this.F_ZERO===0?1:0)<<1)| | |
(this.F_INTERRUPT<<2)| | |
(this.F_DECIMAL<<3)| | |
(this.F_BRK<<4)| | |
(this.F_NOTUSED<<5)| | |
(this.F_OVERFLOW<<6)| | |
(this.F_SIGN<<7); | |
this.REG_PC_NEW = this.REG_PC; | |
this.F_INTERRUPT_NEW = this.F_INTERRUPT; | |
switch(this.irqType){ | |
case 0: { | |
// Normal IRQ: | |
if(this.F_INTERRUPT!=0){ | |
////System.out.println("Interrupt was masked."); | |
break; | |
} | |
this.doIrq(temp); | |
////System.out.println("Did normal IRQ. I="+this.F_INTERRUPT); | |
break; | |
}case 1:{ | |
// NMI: | |
this.doNonMaskableInterrupt(temp); | |
break; | |
}case 2:{ | |
// Reset: | |
this.doResetInterrupt(); | |
break; | |
} | |
} | |
this.REG_PC = this.REG_PC_NEW; | |
this.F_INTERRUPT = this.F_INTERRUPT_NEW; | |
this.F_BRK = this.F_BRK_NEW; | |
this.irqRequested = false; | |
} | |
var opinf = this.opdata[this.nes.mmap.load(this.REG_PC+1)]; | |
var cycleCount = (opinf>>24); | |
var cycleAdd = 0; | |
// Find address mode: | |
var addrMode = (opinf >> 8) & 0xFF; | |
// Increment PC by number of op bytes: | |
var opaddr = this.REG_PC; | |
this.REG_PC += ((opinf >> 16) & 0xFF); | |
var addr = 0; | |
switch(addrMode){ | |
case 0:{ | |
// Zero Page mode. Use the address given after the opcode, | |
// but without high byte. | |
addr = this.load(opaddr+2); | |
break; | |
}case 1:{ | |
// Relative mode. | |
addr = this.load(opaddr+2); | |
if(addr<0x80){ | |
addr += this.REG_PC; | |
}else{ | |
addr += this.REG_PC-256; | |
} | |
break; | |
}case 2:{ | |
// Ignore. Address is implied in instruction. | |
break; | |
}case 3:{ | |
// Absolute mode. Use the two bytes following the opcode as | |
// an address. | |
addr = this.load16bit(opaddr+2); | |
break; | |
}case 4:{ | |
// Accumulator mode. The address is in the accumulator | |
// register. | |
addr = this.REG_ACC; | |
break; | |
}case 5:{ | |
// Immediate mode. The value is given after the opcode. | |
addr = this.REG_PC; | |
break; | |
}case 6:{ | |
// Zero Page Indexed mode, X as index. Use the address given | |
// after the opcode, then add the | |
// X register to it to get the final address. | |
addr = (this.load(opaddr+2)+this.REG_X)&0xFF; | |
break; | |
}case 7:{ | |
// Zero Page Indexed mode, Y as index. Use the address given | |
// after the opcode, then add the | |
// Y register to it to get the final address. | |
addr = (this.load(opaddr+2)+this.REG_Y)&0xFF; | |
break; | |
}case 8:{ | |
// Absolute Indexed Mode, X as index. Same as zero page | |
// indexed, but with the high byte. | |
addr = this.load16bit(opaddr+2); | |
if((addr&0xFF00)!=((addr+this.REG_X)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_X; | |
break; | |
}case 9:{ | |
// Absolute Indexed Mode, Y as index. Same as zero page | |
// indexed, but with the high byte. | |
addr = this.load16bit(opaddr+2); | |
if((addr&0xFF00)!=((addr+this.REG_Y)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_Y; | |
break; | |
}case 10:{ | |
// Pre-indexed Indirect mode. Find the 16-bit address | |
// starting at the given location plus | |
// the current X register. The value is the contents of that | |
// address. | |
addr = this.load(opaddr+2); | |
if((addr&0xFF00)!=((addr+this.REG_X)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_X; | |
addr&=0xFF; | |
addr = this.load16bit(addr); | |
break; | |
}case 11:{ | |
// Post-indexed Indirect mode. Find the 16-bit address | |
// contained in the given location | |
// (and the one following). Add to that address the contents | |
// of the Y register. Fetch the value | |
// stored at that adress. | |
addr = this.load16bit(this.load(opaddr+2)); | |
if((addr&0xFF00)!=((addr+this.REG_Y)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_Y; | |
break; | |
}case 12:{ | |
// Indirect Absolute mode. Find the 16-bit address contained | |
// at the given location. | |
addr = this.load16bit(opaddr+2);// Find op | |
if(addr < 0x1FFF) { | |
addr = this.mem[addr] + (this.mem[(addr & 0xFF00) | (((addr & 0xFF) + 1) & 0xFF)] << 8);// Read from address given in op | |
} | |
else{ | |
addr = this.nes.mmap.load(addr) + (this.nes.mmap.load((addr & 0xFF00) | (((addr & 0xFF) + 1) & 0xFF)) << 8); | |
} | |
break; | |
} | |
} | |
// Wrap around for addresses above 0xFFFF: | |
addr&=0xFFFF; | |
// ---------------------------------------------------------------------------------------------------- | |
// Decode & execute instruction: | |
// ---------------------------------------------------------------------------------------------------- | |
// This should be compiled to a jump table. | |
switch(opinf&0xFF){ | |
case 0:{ | |
// ******* | |
// * ADC * | |
// ******* | |
// Add with carry. | |
temp = this.REG_ACC + this.load(addr) + this.F_CARRY; | |
this.F_OVERFLOW = ((!(((this.REG_ACC ^ this.load(addr)) & 0x80)!=0) && (((this.REG_ACC ^ temp) & 0x80))!=0)?1:0); | |
this.F_CARRY = (temp>255?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
this.REG_ACC = (temp&255); | |
cycleCount+=cycleAdd; | |
break; | |
}case 1:{ | |
// ******* | |
// * AND * | |
// ******* | |
// AND memory with accumulator. | |
this.REG_ACC = this.REG_ACC & this.load(addr); | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
//this.REG_ACC = temp; | |
if(addrMode!=11)cycleCount+=cycleAdd; // PostIdxInd = 11 | |
break; | |
}case 2:{ | |
// ******* | |
// * ASL * | |
// ******* | |
// Shift left one bit | |
if(addrMode == 4){ // ADDR_ACC = 4 | |
this.F_CARRY = (this.REG_ACC>>7)&1; | |
this.REG_ACC = (this.REG_ACC<<1)&255; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
}else{ | |
temp = this.load(addr); | |
this.F_CARRY = (temp>>7)&1; | |
temp = (temp<<1)&255; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.write(addr, temp); | |
} | |
break; | |
}case 3:{ | |
// ******* | |
// * BCC * | |
// ******* | |
// Branch on carry clear | |
if(this.F_CARRY == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 4:{ | |
// ******* | |
// * BCS * | |
// ******* | |
// Branch on carry set | |
if(this.F_CARRY == 1){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 5:{ | |
// ******* | |
// * BEQ * | |
// ******* | |
// Branch on zero | |
if(this.F_ZERO == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 6:{ | |
// ******* | |
// * BIT * | |
// ******* | |
temp = this.load(addr); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_OVERFLOW = (temp>>6)&1; | |
temp &= this.REG_ACC; | |
this.F_ZERO = temp; | |
break; | |
}case 7:{ | |
// ******* | |
// * BMI * | |
// ******* | |
// Branch on negative result | |
if(this.F_SIGN == 1){ | |
cycleCount++; | |
this.REG_PC = addr; | |
} | |
break; | |
}case 8:{ | |
// ******* | |
// * BNE * | |
// ******* | |
// Branch on not zero | |
if(this.F_ZERO != 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 9:{ | |
// ******* | |
// * BPL * | |
// ******* | |
// Branch on positive result | |
if(this.F_SIGN == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 10:{ | |
// ******* | |
// * BRK * | |
// ******* | |
this.REG_PC+=2; | |
this.push((this.REG_PC>>8)&255); | |
this.push(this.REG_PC&255); | |
this.F_BRK = 1; | |
this.push( | |
(this.F_CARRY)| | |
((this.F_ZERO==0?1:0)<<1)| | |
(this.F_INTERRUPT<<2)| | |
(this.F_DECIMAL<<3)| | |
(this.F_BRK<<4)| | |
(this.F_NOTUSED<<5)| | |
(this.F_OVERFLOW<<6)| | |
(this.F_SIGN<<7) | |
); | |
this.F_INTERRUPT = 1; | |
//this.REG_PC = load(0xFFFE) | (load(0xFFFF) << 8); | |
this.REG_PC = this.load16bit(0xFFFE); | |
this.REG_PC--; | |
break; | |
}case 11:{ | |
// ******* | |
// * BVC * | |
// ******* | |
// Branch on overflow clear | |
if(this.F_OVERFLOW == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 12:{ | |
// ******* | |
// * BVS * | |
// ******* | |
// Branch on overflow set | |
if(this.F_OVERFLOW == 1){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 13:{ | |
// ******* | |
// * CLC * | |
// ******* | |
// Clear carry flag | |
this.F_CARRY = 0; | |
break; | |
}case 14:{ | |
// ******* | |
// * CLD * | |
// ******* | |
// Clear decimal flag | |
this.F_DECIMAL = 0; | |
break; | |
}case 15:{ | |
// ******* | |
// * CLI * | |
// ******* | |
// Clear interrupt flag | |
this.F_INTERRUPT = 0; | |
break; | |
}case 16:{ | |
// ******* | |
// * CLV * | |
// ******* | |
// Clear overflow flag | |
this.F_OVERFLOW = 0; | |
break; | |
}case 17:{ | |
// ******* | |
// * CMP * | |
// ******* | |
// Compare memory and accumulator: | |
temp = this.REG_ACC - this.load(addr); | |
this.F_CARRY = (temp>=0?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
cycleCount+=cycleAdd; | |
break; | |
}case 18:{ | |
// ******* | |
// * CPX * | |
// ******* | |
// Compare memory and index X: | |
temp = this.REG_X - this.load(addr); | |
this.F_CARRY = (temp>=0?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
break; | |
}case 19:{ | |
// ******* | |
// * CPY * | |
// ******* | |
// Compare memory and index Y: | |
temp = this.REG_Y - this.load(addr); | |
this.F_CARRY = (temp>=0?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
break; | |
}case 20:{ | |
// ******* | |
// * DEC * | |
// ******* | |
// Decrement memory by one: | |
temp = (this.load(addr)-1)&0xFF; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.write(addr, temp); | |
break; | |
}case 21:{ | |
// ******* | |
// * DEX * | |
// ******* | |
// Decrement index X by one: | |
this.REG_X = (this.REG_X-1)&0xFF; | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 22:{ | |
// ******* | |
// * DEY * | |
// ******* | |
// Decrement index Y by one: | |
this.REG_Y = (this.REG_Y-1)&0xFF; | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
break; | |
}case 23:{ | |
// ******* | |
// * EOR * | |
// ******* | |
// XOR Memory with accumulator, store in accumulator: | |
this.REG_ACC = (this.load(addr)^this.REG_ACC)&0xFF; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
cycleCount+=cycleAdd; | |
break; | |
}case 24:{ | |
// ******* | |
// * INC * | |
// ******* | |
// Increment memory by one: | |
temp = (this.load(addr)+1)&0xFF; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.write(addr, temp&0xFF); | |
break; | |
}case 25:{ | |
// ******* | |
// * INX * | |
// ******* | |
// Increment index X by one: | |
this.REG_X = (this.REG_X+1)&0xFF; | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 26:{ | |
// ******* | |
// * INY * | |
// ******* | |
// Increment index Y by one: | |
this.REG_Y++; | |
this.REG_Y &= 0xFF; | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
break; | |
}case 27:{ | |
// ******* | |
// * JMP * | |
// ******* | |
// Jump to new location: | |
this.REG_PC = addr-1; | |
break; | |
}case 28:{ | |
// ******* | |
// * JSR * | |
// ******* | |
// Jump to new location, saving return address. | |
// Push return address on stack: | |
this.push((this.REG_PC>>8)&255); | |
this.push(this.REG_PC&255); | |
this.REG_PC = addr-1; | |
break; | |
}case 29:{ | |
// ******* | |
// * LDA * | |
// ******* | |
// Load accumulator with memory: | |
this.REG_ACC = this.load(addr); | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
cycleCount+=cycleAdd; | |
break; | |
}case 30:{ | |
// ******* | |
// * LDX * | |
// ******* | |
// Load index X with memory: | |
this.REG_X = this.load(addr); | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
cycleCount+=cycleAdd; | |
break; | |
}case 31:{ | |
// ******* | |
// * LDY * | |
// ******* | |
// Load index Y with memory: | |
this.REG_Y = this.load(addr); | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
cycleCount+=cycleAdd; | |
break; | |
}case 32:{ | |
// ******* | |
// * LSR * | |
// ******* | |
// Shift right one bit: | |
if(addrMode == 4){ // ADDR_ACC | |
temp = (this.REG_ACC & 0xFF); | |
this.F_CARRY = temp&1; | |
temp >>= 1; | |
this.REG_ACC = temp; | |
}else{ | |
temp = this.load(addr) & 0xFF; | |
this.F_CARRY = temp&1; | |
temp >>= 1; | |
this.write(addr, temp); | |
} | |
this.F_SIGN = 0; | |
this.F_ZERO = temp; | |
break; | |
}case 33:{ | |
// ******* | |
// * NOP * | |
// ******* | |
// No OPeration. | |
// Ignore. | |
break; | |
}case 34:{ | |
// ******* | |
// * ORA * | |
// ******* | |
// OR memory with accumulator, store in accumulator. | |
temp = (this.load(addr)|this.REG_ACC)&255; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.REG_ACC = temp; | |
if(addrMode!=11)cycleCount+=cycleAdd; // PostIdxInd = 11 | |
break; | |
}case 35:{ | |
// ******* | |
// * PHA * | |
// ******* | |
// Push accumulator on stack | |
this.push(this.REG_ACC); | |
break; | |
}case 36:{ | |
// ******* | |
// * PHP * | |
// ******* | |
// Push processor status on stack | |
this.F_BRK = 1; | |
this.push( | |
(this.F_CARRY)| | |
((this.F_ZERO==0?1:0)<<1)| | |
(this.F_INTERRUPT<<2)| | |
(this.F_DECIMAL<<3)| | |
(this.F_BRK<<4)| | |
(this.F_NOTUSED<<5)| | |
(this.F_OVERFLOW<<6)| | |
(this.F_SIGN<<7) | |
); | |
break; | |
}case 37:{ | |
// ******* | |
// * PLA * | |
// ******* | |
// Pull accumulator from stack | |
this.REG_ACC = this.pull(); | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
break; | |
}case 38:{ | |
// ******* | |
// * PLP * | |
// ******* | |
// Pull processor status from stack | |
temp = this.pull(); | |
this.F_CARRY = (temp )&1; | |
this.F_ZERO = (((temp>>1)&1)==1)?0:1; | |
this.F_INTERRUPT = (temp>>2)&1; | |
this.F_DECIMAL = (temp>>3)&1; | |
this.F_BRK = (temp>>4)&1; | |
this.F_NOTUSED = (temp>>5)&1; | |
this.F_OVERFLOW = (temp>>6)&1; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_NOTUSED = 1; | |
break; | |
}case 39:{ | |
// ******* | |
// * ROL * | |
// ******* | |
// Rotate one bit left | |
if(addrMode == 4){ // ADDR_ACC = 4 | |
temp = this.REG_ACC; | |
add = this.F_CARRY; | |
this.F_CARRY = (temp>>7)&1; | |
temp = ((temp<<1)&0xFF)+add; | |
this.REG_ACC = temp; | |
}else{ | |
temp = this.load(addr); | |
add = this.F_CARRY; | |
this.F_CARRY = (temp>>7)&1; | |
temp = ((temp<<1)&0xFF)+add; | |
this.write(addr, temp); | |
} | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
break; | |
}case 40:{ | |
// ******* | |
// * ROR * | |
// ******* | |
// Rotate one bit right | |
if(addrMode == 4){ // ADDR_ACC = 4 | |
add = this.F_CARRY<<7; | |
this.F_CARRY = this.REG_ACC&1; | |
temp = (this.REG_ACC>>1)+add; | |
this.REG_ACC = temp; | |
}else{ | |
temp = this.load(addr); | |
add = this.F_CARRY<<7; | |
this.F_CARRY = temp&1; | |
temp = (temp>>1)+add; | |
this.write(addr, temp); | |
} | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
break; | |
}case 41:{ | |
// ******* | |
// * RTI * | |
// ******* | |
// Return from interrupt. Pull status and PC from stack. | |
temp = this.pull(); | |
this.F_CARRY = (temp )&1; | |
this.F_ZERO = ((temp>>1)&1)==0?1:0; | |
this.F_INTERRUPT = (temp>>2)&1; | |
this.F_DECIMAL = (temp>>3)&1; | |
this.F_BRK = (temp>>4)&1; | |
this.F_NOTUSED = (temp>>5)&1; | |
this.F_OVERFLOW = (temp>>6)&1; | |
this.F_SIGN = (temp>>7)&1; | |
this.REG_PC = this.pull(); | |
this.REG_PC += (this.pull()<<8); | |
if(this.REG_PC==0xFFFF){ | |
return; | |
} | |
this.REG_PC--; | |
this.F_NOTUSED = 1; | |
break; | |
}case 42:{ | |
// ******* | |
// * RTS * | |
// ******* | |
// Return from subroutine. Pull PC from stack. | |
this.REG_PC = this.pull(); | |
this.REG_PC += (this.pull()<<8); | |
if(this.REG_PC==0xFFFF){ | |
return; // return from NSF play routine: | |
} | |
break; | |
}case 43:{ | |
// ******* | |
// * SBC * | |
// ******* | |
temp = this.REG_ACC-this.load(addr)-(1-this.F_CARRY); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
this.F_OVERFLOW = ((((this.REG_ACC^temp)&0x80)!=0 && ((this.REG_ACC^this.load(addr))&0x80)!=0)?1:0); | |
this.F_CARRY = (temp<0?0:1); | |
this.REG_ACC = (temp&0xFF); | |
if(addrMode!=11)cycleCount+=cycleAdd; // PostIdxInd = 11 | |
break; | |
}case 44:{ | |
// ******* | |
// * SEC * | |
// ******* | |
// Set carry flag | |
this.F_CARRY = 1; | |
break; | |
}case 45:{ | |
// ******* | |
// * SED * | |
// ******* | |
// Set decimal mode | |
this.F_DECIMAL = 1; | |
break; | |
}case 46:{ | |
// ******* | |
// * SEI * | |
// ******* | |
// Set interrupt disable status | |
this.F_INTERRUPT = 1; | |
break; | |
}case 47:{ | |
// ******* | |
// * STA * | |
// ******* | |
// Store accumulator in memory | |
this.write(addr, this.REG_ACC); | |
break; | |
}case 48:{ | |
// ******* | |
// * STX * | |
// ******* | |
// Store index X in memory | |
this.write(addr, this.REG_X); | |
break; | |
}case 49:{ | |
// ******* | |
// * STY * | |
// ******* | |
// Store index Y in memory: | |
this.write(addr, this.REG_Y); | |
break; | |
}case 50:{ | |
// ******* | |
// * TAX * | |
// ******* | |
// Transfer accumulator to index X: | |
this.REG_X = this.REG_ACC; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
break; | |
}case 51:{ | |
// ******* | |
// * TAY * | |
// ******* | |
// Transfer accumulator to index Y: | |
this.REG_Y = this.REG_ACC; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
break; | |
}case 52:{ | |
// ******* | |
// * TSX * | |
// ******* | |
// Transfer stack pointer to index X: | |
this.REG_X = (this.REG_SP-0x0100); | |
this.F_SIGN = (this.REG_SP>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 53:{ | |
// ******* | |
// * TXA * | |
// ******* | |
// Transfer index X to accumulator: | |
this.REG_ACC = this.REG_X; | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 54:{ | |
// ******* | |
// * TXS * | |
// ******* | |
// Transfer index X to stack pointer: | |
this.REG_SP = (this.REG_X+0x0100); | |
this.stackWrap(); | |
break; | |
}case 55:{ | |
// ******* | |
// * TYA * | |
// ******* | |
// Transfer index Y to accumulator: | |
this.REG_ACC = this.REG_Y; | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
break; | |
}default:{ | |
// ******* | |
// * ??? * | |
// ******* | |
this.nes.stop(); | |
this.nes.crashMessage = "Game crashed, invalid opcode at address $"+opaddr.toString(16); | |
break; | |
} | |
}// end of switch | |
return cycleCount; | |
}, | |
load: function(addr){ | |
if (addr < 0x2000) { | |
return this.mem[addr & 0x7FF]; | |
} | |
else { | |
return this.nes.mmap.load(addr); | |
} | |
}, | |
load16bit: function(addr){ | |
if (addr < 0x1FFF) { | |
return this.mem[addr&0x7FF] | |
| (this.mem[(addr+1)&0x7FF]<<8); | |
} | |
else { | |
return this.nes.mmap.load(addr) | (this.nes.mmap.load(addr+1) << 8); | |
} | |
}, | |
write: function(addr, val){ | |
if(addr < 0x2000) { | |
this.mem[addr&0x7FF] = val; | |
} | |
else { | |
this.nes.mmap.write(addr,val); | |
} | |
}, | |
requestIrq: function(type){ | |
if(this.irqRequested){ | |
if(type == this.IRQ_NORMAL){ | |
return; | |
} | |
////System.out.println("too fast irqs. type="+type); | |
} | |
this.irqRequested = true; | |
this.irqType = type; | |
}, | |
push: function(value){ | |
this.nes.mmap.write(this.REG_SP, value); | |
this.REG_SP--; | |
this.REG_SP = 0x0100 | (this.REG_SP&0xFF); | |
}, | |
stackWrap: function(){ | |
this.REG_SP = 0x0100 | (this.REG_SP&0xFF); | |
}, | |
pull: function(){ | |
this.REG_SP++; | |
this.REG_SP = 0x0100 | (this.REG_SP&0xFF); | |
return this.nes.mmap.load(this.REG_SP); | |
}, | |
pageCrossed: function(addr1, addr2){ | |
return ((addr1&0xFF00) != (addr2&0xFF00)); | |
}, | |
haltCycles: function(cycles){ | |
this.cyclesToHalt += cycles; | |
}, | |
doNonMaskableInterrupt: function(status){ | |
if((this.nes.mmap.load(0x2000) & 128) != 0) { // Check whether VBlank Interrupts are enabled | |
this.REG_PC_NEW++; | |
this.push((this.REG_PC_NEW>>8)&0xFF); | |
this.push(this.REG_PC_NEW&0xFF); | |
//this.F_INTERRUPT_NEW = 1; | |
this.push(status); | |
this.REG_PC_NEW = this.nes.mmap.load(0xFFFA) | (this.nes.mmap.load(0xFFFB) << 8); | |
this.REG_PC_NEW--; | |
} | |
}, | |
doResetInterrupt: function(){ | |
this.REG_PC_NEW = this.nes.mmap.load(0xFFFC) | (this.nes.mmap.load(0xFFFD) << 8); | |
this.REG_PC_NEW--; | |
}, | |
doIrq: function(status){ | |
this.REG_PC_NEW++; | |
this.push((this.REG_PC_NEW>>8)&0xFF); | |
this.push(this.REG_PC_NEW&0xFF); | |
this.push(status); | |
this.F_INTERRUPT_NEW = 1; | |
this.F_BRK_NEW = 0; | |
this.REG_PC_NEW = this.nes.mmap.load(0xFFFE) | (this.nes.mmap.load(0xFFFF) << 8); | |
this.REG_PC_NEW--; | |
}, | |
getStatus: function(){ | |
return (this.F_CARRY) | |
|(this.F_ZERO<<1) | |
|(this.F_INTERRUPT<<2) | |
|(this.F_DECIMAL<<3) | |
|(this.F_BRK<<4) | |
|(this.F_NOTUSED<<5) | |
|(this.F_OVERFLOW<<6) | |
|(this.F_SIGN<<7); | |
}, | |
setStatus: function(st){ | |
this.F_CARRY = (st )&1; | |
this.F_ZERO = (st>>1)&1; | |
this.F_INTERRUPT = (st>>2)&1; | |
this.F_DECIMAL = (st>>3)&1; | |
this.F_BRK = (st>>4)&1; | |
this.F_NOTUSED = (st>>5)&1; | |
this.F_OVERFLOW = (st>>6)&1; | |
this.F_SIGN = (st>>7)&1; | |
}, | |
JSON_PROPERTIES: [ | |
'mem', 'cyclesToHalt', 'irqRequested', 'irqType', | |
// Registers | |
'REG_ACC', 'REG_X', 'REG_Y', 'REG_SP', 'REG_PC', 'REG_PC_NEW', | |
'REG_STATUS', | |
// Status | |
'F_CARRY', 'F_DECIMAL', 'F_INTERRUPT', 'F_INTERRUPT_NEW', 'F_OVERFLOW', | |
'F_SIGN', 'F_ZERO', 'F_NOTUSED', 'F_NOTUSED_NEW', 'F_BRK', 'F_BRK_NEW' | |
], | |
toJSON: function() { | |
return JSNES.Utils.toJSON(this); | |
}, | |
fromJSON: function(s) { | |
JSNES.Utils.fromJSON(this, s); | |
} | |
} | |
// Generates and provides an array of details about instructions | |
JSNES.CPU.OpData = function() { | |
this.opdata = new Array(256); | |
// Set all to invalid instruction (to detect crashes): | |
for(var i=0;i<256;i++) this.opdata[i]=0xFF; | |
// Now fill in all valid opcodes: | |
// ADC: | |
this.setOp(this.INS_ADC,0x69,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_ADC,0x65,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_ADC,0x75,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_ADC,0x6D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_ADC,0x7D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_ADC,0x79,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_ADC,0x61,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_ADC,0x71,this.ADDR_POSTIDXIND,2,5); | |
// AND: | |
this.setOp(this.INS_AND,0x29,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_AND,0x25,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_AND,0x35,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_AND,0x2D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_AND,0x3D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_AND,0x39,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_AND,0x21,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_AND,0x31,this.ADDR_POSTIDXIND,2,5); | |
// ASL: | |
this.setOp(this.INS_ASL,0x0A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_ASL,0x06,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_ASL,0x16,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_ASL,0x0E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_ASL,0x1E,this.ADDR_ABSX,3,7); | |
// BCC: | |
this.setOp(this.INS_BCC,0x90,this.ADDR_REL,2,2); | |
// BCS: | |
this.setOp(this.INS_BCS,0xB0,this.ADDR_REL,2,2); | |
// BEQ: | |
this.setOp(this.INS_BEQ,0xF0,this.ADDR_REL,2,2); | |
// BIT: | |
this.setOp(this.INS_BIT,0x24,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_BIT,0x2C,this.ADDR_ABS,3,4); | |
// BMI: | |
this.setOp(this.INS_BMI,0x30,this.ADDR_REL,2,2); | |
// BNE: | |
this.setOp(this.INS_BNE,0xD0,this.ADDR_REL,2,2); | |
// BPL: | |
this.setOp(this.INS_BPL,0x10,this.ADDR_REL,2,2); | |
// BRK: | |
this.setOp(this.INS_BRK,0x00,this.ADDR_IMP,1,7); | |
// BVC: | |
this.setOp(this.INS_BVC,0x50,this.ADDR_REL,2,2); | |
// BVS: | |
this.setOp(this.INS_BVS,0x70,this.ADDR_REL,2,2); | |
// CLC: | |
this.setOp(this.INS_CLC,0x18,this.ADDR_IMP,1,2); | |
// CLD: | |
this.setOp(this.INS_CLD,0xD8,this.ADDR_IMP,1,2); | |
// CLI: | |
this.setOp(this.INS_CLI,0x58,this.ADDR_IMP,1,2); | |
// CLV: | |
this.setOp(this.INS_CLV,0xB8,this.ADDR_IMP,1,2); | |
// CMP: | |
this.setOp(this.INS_CMP,0xC9,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_CMP,0xC5,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_CMP,0xD5,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_CMP,0xCD,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_CMP,0xDD,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_CMP,0xD9,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_CMP,0xC1,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_CMP,0xD1,this.ADDR_POSTIDXIND,2,5); | |
// CPX: | |
this.setOp(this.INS_CPX,0xE0,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_CPX,0xE4,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_CPX,0xEC,this.ADDR_ABS,3,4); | |
// CPY: | |
this.setOp(this.INS_CPY,0xC0,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_CPY,0xC4,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_CPY,0xCC,this.ADDR_ABS,3,4); | |
// DEC: | |
this.setOp(this.INS_DEC,0xC6,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_DEC,0xD6,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_DEC,0xCE,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_DEC,0xDE,this.ADDR_ABSX,3,7); | |
// DEX: | |
this.setOp(this.INS_DEX,0xCA,this.ADDR_IMP,1,2); | |
// DEY: | |
this.setOp(this.INS_DEY,0x88,this.ADDR_IMP,1,2); | |
// EOR: | |
this.setOp(this.INS_EOR,0x49,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_EOR,0x45,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_EOR,0x55,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_EOR,0x4D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_EOR,0x5D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_EOR,0x59,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_EOR,0x41,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_EOR,0x51,this.ADDR_POSTIDXIND,2,5); | |
// INC: | |
this.setOp(this.INS_INC,0xE6,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_INC,0xF6,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_INC,0xEE,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_INC,0xFE,this.ADDR_ABSX,3,7); | |
// INX: | |
this.setOp(this.INS_INX,0xE8,this.ADDR_IMP,1,2); | |
// INY: | |
this.setOp(this.INS_INY,0xC8,this.ADDR_IMP,1,2); | |
// JMP: | |
this.setOp(this.INS_JMP,0x4C,this.ADDR_ABS,3,3); | |
this.setOp(this.INS_JMP,0x6C,this.ADDR_INDABS,3,5); | |
// JSR: | |
this.setOp(this.INS_JSR,0x20,this.ADDR_ABS,3,6); | |
// LDA: | |
this.setOp(this.INS_LDA,0xA9,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_LDA,0xA5,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_LDA,0xB5,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_LDA,0xAD,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_LDA,0xBD,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_LDA,0xB9,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_LDA,0xA1,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_LDA,0xB1,this.ADDR_POSTIDXIND,2,5); | |
// LDX: | |
this.setOp(this.INS_LDX,0xA2,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_LDX,0xA6,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_LDX,0xB6,this.ADDR_ZPY,2,4); | |
this.setOp(this.INS_LDX,0xAE,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_LDX,0xBE,this.ADDR_ABSY,3,4); | |
// LDY: | |
this.setOp(this.INS_LDY,0xA0,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_LDY,0xA4,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_LDY,0xB4,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_LDY,0xAC,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_LDY,0xBC,this.ADDR_ABSX,3,4); | |
// LSR: | |
this.setOp(this.INS_LSR,0x4A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_LSR,0x46,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_LSR,0x56,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_LSR,0x4E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_LSR,0x5E,this.ADDR_ABSX,3,7); | |
// NOP: | |
this.setOp(this.INS_NOP,0xEA,this.ADDR_IMP,1,2); | |
// ORA: | |
this.setOp(this.INS_ORA,0x09,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_ORA,0x05,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_ORA,0x15,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_ORA,0x0D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_ORA,0x1D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_ORA,0x19,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_ORA,0x01,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_ORA,0x11,this.ADDR_POSTIDXIND,2,5); | |
// PHA: | |
this.setOp(this.INS_PHA,0x48,this.ADDR_IMP,1,3); | |
// PHP: | |
this.setOp(this.INS_PHP,0x08,this.ADDR_IMP,1,3); | |
// PLA: | |
this.setOp(this.INS_PLA,0x68,this.ADDR_IMP,1,4); | |
// PLP: | |
this.setOp(this.INS_PLP,0x28,this.ADDR_IMP,1,4); | |
// ROL: | |
this.setOp(this.INS_ROL,0x2A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_ROL,0x26,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_ROL,0x36,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_ROL,0x2E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_ROL,0x3E,this.ADDR_ABSX,3,7); | |
// ROR: | |
this.setOp(this.INS_ROR,0x6A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_ROR,0x66,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_ROR,0x76,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_ROR,0x6E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_ROR,0x7E,this.ADDR_ABSX,3,7); | |
// RTI: | |
this.setOp(this.INS_RTI,0x40,this.ADDR_IMP,1,6); | |
// RTS: | |
this.setOp(this.INS_RTS,0x60,this.ADDR_IMP,1,6); | |
// SBC: | |
this.setOp(this.INS_SBC,0xE9,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_SBC,0xE5,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_SBC,0xF5,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_SBC,0xED,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_SBC,0xFD,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_SBC,0xF9,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_SBC,0xE1,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_SBC,0xF1,this.ADDR_POSTIDXIND,2,5); | |
// SEC: | |
this.setOp(this.INS_SEC,0x38,this.ADDR_IMP,1,2); | |
// SED: | |
this.setOp(this.INS_SED,0xF8,this.ADDR_IMP,1,2); | |
// SEI: | |
this.setOp(this.INS_SEI,0x78,this.ADDR_IMP,1,2); | |
// STA: | |
this.setOp(this.INS_STA,0x85,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_STA,0x95,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_STA,0x8D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_STA,0x9D,this.ADDR_ABSX,3,5); | |
this.setOp(this.INS_STA,0x99,this.ADDR_ABSY,3,5); | |
this.setOp(this.INS_STA,0x81,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_STA,0x91,this.ADDR_POSTIDXIND,2,6); | |
// STX: | |
this.setOp(this.INS_STX,0x86,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_STX,0x96,this.ADDR_ZPY,2,4); | |
this.setOp(this.INS_STX,0x8E,this.ADDR_ABS,3,4); | |
// STY: | |
this.setOp(this.INS_STY,0x84,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_STY,0x94,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_STY,0x8C,this.ADDR_ABS,3,4); | |
// TAX: | |
this.setOp(this.INS_TAX,0xAA,this.ADDR_IMP,1,2); | |
// TAY: | |
this.setOp(this.INS_TAY,0xA8,this.ADDR_IMP,1,2); | |
// TSX: | |
this.setOp(this.INS_TSX,0xBA,this.ADDR_IMP,1,2); | |
// TXA: | |
this.setOp(this.INS_TXA,0x8A,this.ADDR_IMP,1,2); | |
// TXS: | |
this.setOp(this.INS_TXS,0x9A,this.ADDR_IMP,1,2); | |
// TYA: | |
this.setOp(this.INS_TYA,0x98,this.ADDR_IMP,1,2); | |
this.cycTable = new Array( | |
/*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6, | |
/*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6, | |
/*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6, | |
/*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6, | |
/*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, | |
/*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5, | |
/*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, | |
/*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4, | |
/*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, | |
/*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6, | |
/*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 | |
); | |
this.instname = new Array(56); | |
// Instruction Names: | |
this.instname[ 0] = "ADC"; | |
this.instname[ 1] = "AND"; | |
this.instname[ 2] = "ASL"; | |
this.instname[ 3] = "BCC"; | |
this.instname[ 4] = "BCS"; | |
this.instname[ 5] = "BEQ"; | |
this.instname[ 6] = "BIT"; | |
this.instname[ 7] = "BMI"; | |
this.instname[ 8] = "BNE"; | |
this.instname[ 9] = "BPL"; | |
this.instname[10] = "BRK"; | |
this.instname[11] = "BVC"; | |
this.instname[12] = "BVS"; | |
this.instname[13] = "CLC"; | |
this.instname[14] = "CLD"; | |
this.instname[15] = "CLI"; | |
this.instname[16] = "CLV"; | |
this.instname[17] = "CMP"; | |
this.instname[18] = "CPX"; | |
this.instname[19] = "CPY"; | |
this.instname[20] = "DEC"; | |
this.instname[21] = "DEX"; | |
this.instname[22] = "DEY"; | |
this.instname[23] = "EOR"; | |
this.instname[24] = "INC"; | |
this.instname[25] = "INX"; | |
this.instname[26] = "INY"; | |
this.instname[27] = "JMP"; | |
this.instname[28] = "JSR"; | |
this.instname[29] = "LDA"; | |
this.instname[30] = "LDX"; | |
this.instname[31] = "LDY"; | |
this.instname[32] = "LSR"; | |
this.instname[33] = "NOP"; | |
this.instname[34] = "ORA"; | |
this.instname[35] = "PHA"; | |
this.instname[36] = "PHP"; | |
this.instname[37] = "PLA"; | |
this.instname[38] = "PLP"; | |
this.instname[39] = "ROL"; | |
this.instname[40] = "ROR"; | |
this.instname[41] = "RTI"; | |
this.instname[42] = "RTS"; | |
this.instname[43] = "SBC"; | |
this.instname[44] = "SEC"; | |
this.instname[45] = "SED"; | |
this.instname[46] = "SEI"; | |
this.instname[47] = "STA"; | |
this.instname[48] = "STX"; | |
this.instname[49] = "STY"; | |
this.instname[50] = "TAX"; | |
this.instname[51] = "TAY"; | |
this.instname[52] = "TSX"; | |
this.instname[53] = "TXA"; | |
this.instname[54] = "TXS"; | |
this.instname[55] = "TYA"; | |
this.addrDesc = new Array( | |
"Zero Page ", | |
"Relative ", | |
"Implied ", | |
"Absolute ", | |
"Accumulator ", | |
"Immediate ", | |
"Zero Page,X ", | |
"Zero Page,Y ", | |
"Absolute,X ", | |
"Absolute,Y ", | |
"Preindexed Indirect ", | |
"Postindexed Indirect", | |
"Indirect Absolute " | |
); | |
} | |
JSNES.CPU.OpData.prototype = { | |
INS_ADC: 0, | |
INS_AND: 1, | |
INS_ASL: 2, | |
INS_BCC: 3, | |
INS_BCS: 4, | |
INS_BEQ: 5, | |
INS_BIT: 6, | |
INS_BMI: 7, | |
INS_BNE: 8, | |
INS_BPL: 9, | |
INS_BRK: 10, | |
INS_BVC: 11, | |
INS_BVS: 12, | |
INS_CLC: 13, | |
INS_CLD: 14, | |
INS_CLI: 15, | |
INS_CLV: 16, | |
INS_CMP: 17, | |
INS_CPX: 18, | |
INS_CPY: 19, | |
INS_DEC: 20, | |
INS_DEX: 21, | |
INS_DEY: 22, | |
INS_EOR: 23, | |
INS_INC: 24, | |
INS_INX: 25, | |
INS_INY: 26, | |
INS_JMP: 27, | |
INS_JSR: 28, | |
INS_LDA: 29, | |
INS_LDX: 30, | |
INS_LDY: 31, | |
INS_LSR: 32, | |
INS_NOP: 33, | |
INS_ORA: 34, | |
INS_PHA: 35, | |
INS_PHP: 36, | |
INS_PLA: 37, | |
INS_PLP: 38, | |
INS_ROL: 39, | |
INS_ROR: 40, | |
INS_RTI: 41, | |
INS_RTS: 42, | |
INS_SBC: 43, | |
INS_SEC: 44, | |
INS_SED: 45, | |
INS_SEI: 46, | |
INS_STA: 47, | |
INS_STX: 48, | |
INS_STY: 49, | |
INS_TAX: 50, | |
INS_TAY: 51, | |
INS_TSX: 52, | |
INS_TXA: 53, | |
INS_TXS: 54, | |
INS_TYA: 55, | |
INS_DUMMY: 56, // dummy instruction used for 'halting' the processor some cycles | |
// -------------------------------- // | |
// Addressing modes: | |
ADDR_ZP : 0, | |
ADDR_REL : 1, | |
ADDR_IMP : 2, | |
ADDR_ABS : 3, | |
ADDR_ACC : 4, | |
ADDR_IMM : 5, | |
ADDR_ZPX : 6, | |
ADDR_ZPY : 7, | |
ADDR_ABSX : 8, | |
ADDR_ABSY : 9, | |
ADDR_PREIDXIND : 10, | |
ADDR_POSTIDXIND: 11, | |
ADDR_INDABS : 12, | |
setOp: function(inst, op, addr, size, cycles){ | |
this.opdata[op] = | |
((inst &0xFF) )| | |
((addr &0xFF)<< 8)| | |
((size &0xFF)<<16)| | |
((cycles&0xFF)<<24); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var swfobject=function(){var m="undefined",t="object",W="Shockwave Flash",bh="ShockwaveFlash.ShockwaveFlash",F="application/x-shockwave-flash",X="SWFObjectExprInst",Y="onreadystatechange",r=window,i=document,w=navigator,Z=false,G=[bi],x=[],H=[],B=[],D,I,O,ba,z=false,J=false,u,P,bb=true,f=function(){var a=typeof i.getElementById!=m&&typeof i.getElementsByTagName!=m&&typeof i.createElement!=m,c=w.userAgent.toLowerCase(),b=w.platform.toLowerCase(),d=b?/win/.test(b):/win/.test(c),g=b?/mac/.test(b):/mac/.test(c),j=/webkit/.test(c)?parseFloat(c.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,h=!+"\v1",o=[0,0,0],l=null;if(typeof w.plugins!=m&&typeof w.plugins[W]==t){l=w.plugins[W].description;if(l&&!(typeof w.mimeTypes!=m&&w.mimeTypes[F]&&!w.mimeTypes[F].enabledPlugin)){Z=true;h=false;l=l.replace(/^.*\s+(\S+\s+\S+$)/,"$1");o[0]=parseInt(l.replace(/^(.*)\..*$/,"$1"),10);o[1]=parseInt(l.replace(/^.*\.(.*)\s.*$/,"$1"),10);o[2]=/[a-zA-Z]/.test(l)?parseInt(l.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else if(typeof r.ActiveXObject!=m){try{var q=new ActiveXObject(bh);if(q){l=q.GetVariable("$version");if(l){h=true;l=l.split(" ")[1].split(",");o=[parseInt(l[0],10),parseInt(l[1],10),parseInt(l[2],10)]}}}catch(e){}}return{w3:a,pv:o,wk:j,ie:h,win:d,mac:g}}(),bo=function(){if(!f.w3){return}if((typeof i.readyState!=m&&i.readyState=="complete")||(typeof i.readyState==m&&(i.getElementsByTagName("body")[0]||i.body))){C()}if(!z){if(typeof i.addEventListener!=m){i.addEventListener("DOMContentLoaded",C,false)}if(f.ie&&f.win){i.attachEvent(Y,function(){if(i.readyState=="complete"){i.detachEvent(Y,arguments.callee);C()}});if(r==top){(function(){if(z){return}try{i.documentElement.doScroll("left")}catch(e){setTimeout(arguments.callee,0);return}C()})()}}if(f.wk){(function(){if(z){return}if(!/loaded|complete/.test(i.readyState)){setTimeout(arguments.callee,0);return}C()})()}bc(C)}}();function C(){if(z){return}try{var a=i.getElementsByTagName("body")[0].appendChild(y("span"));a.parentNode.removeChild(a)}catch(e){return}z=true;var c=G.length;for(var b=0;b<c;b++){G[b]()}}function bd(a){if(z){a()}else{G[G.length]=a}}function bc(a){if(typeof r.addEventListener!=m){r.addEventListener("load",a,false)}else if(typeof i.addEventListener!=m){i.addEventListener("load",a,false)}else if(typeof r.attachEvent!=m){bj(r,"onload",a)}else if(typeof r.onload=="function"){var c=r.onload;r.onload=function(){c();a()}}else{r.onload=a}}function bi(){if(Z){bk()}else{Q()}}function bk(){var c=i.getElementsByTagName("body")[0];var b=y(t);b.setAttribute("type",F);var d=c.appendChild(b);if(d){var g=0;(function(){if(typeof d.GetVariable!=m){var a=d.GetVariable("$version");if(a){a=a.split(" ")[1].split(",");f.pv=[parseInt(a[0],10),parseInt(a[1],10),parseInt(a[2],10)]}}else if(g<10){g++;setTimeout(arguments.callee,10);return}c.removeChild(b);d=null;Q()})()}else{Q()}}function Q(){var a=x.length;if(a>0){for(var c=0;c<a;c++){var b=x[c].id;var d=x[c].callbackFn;var g={success:false,id:b};if(f.pv[0]>0){var j=s(b);if(j){if(K(x[c].swfVersion)&&!(f.wk&&f.wk<312)){A(b,true);if(d){g.success=true;g.ref=R(b);d(g)}}else if(x[c].expressInstall&&S()){var h={};h.data=x[c].expressInstall;h.width=j.getAttribute("width")||"0";h.height=j.getAttribute("height")||"0";if(j.getAttribute("class")){h.styleclass=j.getAttribute("class")}if(j.getAttribute("align")){h.align=j.getAttribute("align")}var o={};var l=j.getElementsByTagName("param");var q=l.length;for(var p=0;p<q;p++){if(l[p].getAttribute("name").toLowerCase()!="movie"){o[l[p].getAttribute("name")]=l[p].getAttribute("value")}}T(h,o,b,d)}else{bl(j);if(d){d(g)}}}}else{A(b,true);if(d){var v=R(b);if(v&&typeof v.SetVariable!=m){g.success=true;g.ref=v}d(g)}}}}}function R(a){var c=null;var b=s(a);if(b&&b.nodeName=="OBJECT"){if(typeof b.SetVariable!=m){c=b}else{var d=b.getElementsByTagName(t)[0];if(d){c=d}}}return c}function S(){return!J&&K("6.0.65")&&(f.win||f.mac)&&!(f.wk&&f.wk<312)}function T(a,c,b,d){J=true;O=d||null;ba={success:false,id:b};var g=s(b);if(g){if(g.nodeName=="OBJECT"){D=U(g);I=null}else{D=g;I=b}a.id=X;if(typeof a.width==m||(!/%$/.test(a.width)&&parseInt(a.width,10)<310)){a.width="310"}if(typeof a.height==m||(!/%$/.test(a.height)&&parseInt(a.height,10)<137)){a.height="137"}i.title=i.title.slice(0,47)+" - Flash Player Installation";var j=f.ie&&f.win?"ActiveX":"PlugIn",h="MMredirectURL="+r.location.toString().replace(/&/g,"%26")+"&MMplayerType="+j+"&MMdoctitle="+i.title;if(typeof c.flashvars!=m){c.flashvars+="&"+h}else{c.flashvars=h}if(f.ie&&f.win&&g.readyState!=4){var o=y("div");b+="SWFObjectNew";o.setAttribute("id",b);g.parentNode.insertBefore(o,g);g.style.display="none";(function(){if(g.readyState==4){g.parentNode.removeChild(g)}else{setTimeout(arguments.callee,10)}})()}V(a,c,b)}}function bl(a){if(f.ie&&f.win&&a.readyState!=4){var c=y("div");a.parentNode.insertBefore(c,a);c.parentNode.replaceChild(U(a),c);a.style.display="none";(function(){if(a.readyState==4){a.parentNode.removeChild(a)}else{setTimeout(arguments.callee,10)}})()}else{a.parentNode.replaceChild(U(a),a)}}function U(a){var c=y("div");if(f.win&&f.ie){c.innerHTML=a.innerHTML}else{var b=a.getElementsByTagName(t)[0];if(b){var d=b.childNodes;if(d){var g=d.length;for(var j=0;j<g;j++){if(!(d[j].nodeType==1&&d[j].nodeName=="PARAM")&&!(d[j].nodeType==8)){c.appendChild(d[j].cloneNode(true))}}}}}return c}function V(a,c,b){var d,g=s(b);if(f.wk&&f.wk<312){return d}if(g){if(typeof a.id==m){a.id=b}if(f.ie&&f.win){var j="";for(var h in a){if(a[h]!=Object.prototype[h]){if(h.toLowerCase()=="data"){c.movie=a[h]}else if(h.toLowerCase()=="styleclass"){j+=' class="'+a[h]+'"'}else if(h.toLowerCase()!="classid"){j+=' '+h+'="'+a[h]+'"'}}}var o="";for(var l in c){if(c[l]!=Object.prototype[l]){o+='<param name="'+l+'" value="'+c[l]+'" />'}}g.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+j+'>'+o+'</object>';H[H.length]=a.id;d=s(a.id)}else{var q=y(t);q.setAttribute("type",F);for(var p in a){if(a[p]!=Object.prototype[p]){if(p.toLowerCase()=="styleclass"){q.setAttribute("class",a[p])}else if(p.toLowerCase()!="classid"){q.setAttribute(p,a[p])}}}for(var n in c){if(c[n]!=Object.prototype[n]&&n.toLowerCase()!="movie"){bm(q,n,c[n])}}g.parentNode.replaceChild(q,g);d=q}}return d}function bm(a,c,b){var d=y("param");d.setAttribute("name",c);d.setAttribute("value",b);a.appendChild(d)}function be(a){var c=s(a);if(c&&c.nodeName=="OBJECT"){if(f.ie&&f.win){c.style.display="none";(function(){if(c.readyState==4){bn(a)}else{setTimeout(arguments.callee,10)}})()}else{c.parentNode.removeChild(c)}}}function bn(a){var c=s(a);if(c){for(var b in c){if(typeof c[b]=="function"){c[b]=null}}c.parentNode.removeChild(c)}}function s(a){var c=null;try{c=i.getElementById(a)}catch(e){}return c}function y(a){return i.createElement(a)}function bj(a,c,b){a.attachEvent(c,b);B[B.length]=[a,c,b]}function K(a){var c=f.pv,b=a.split(".");b[0]=parseInt(b[0],10);b[1]=parseInt(b[1],10)||0;b[2]=parseInt(b[2],10)||0;return(c[0]>b[0]||(c[0]==b[0]&&c[1]>b[1])||(c[0]==b[0]&&c[1]==b[1]&&c[2]>=b[2]))?true:false}function bf(a,c,b,d){if(f.ie&&f.mac){return}var g=i.getElementsByTagName("head")[0];if(!g){return}var j=(b&&typeof b=="string")?b:"screen";if(d){u=null;P=null}if(!u||P!=j){var h=y("style");h.setAttribute("type","text/css");h.setAttribute("media",j);u=g.appendChild(h);if(f.ie&&f.win&&typeof i.styleSheets!=m&&i.styleSheets.length>0){u=i.styleSheets[i.styleSheets.length-1]}P=j}if(f.ie&&f.win){if(u&&typeof u.addRule==t){u.addRule(a,c)}}else{if(u&&typeof i.createTextNode!=m){u.appendChild(i.createTextNode(a+" {"+c+"}"))}}}function A(a,c){if(!bb){return}var b=c?"visible":"hidden";if(z&&s(a)){s(a).style.visibility=b}else{bf("#"+a,"visibility:"+b)}}function bg(a){var c=/[\\\"<>\.;]/;var b=c.exec(a)!=null;return b&&typeof encodeURIComponent!=m?encodeURIComponent(a):a}var bp=function(){if(f.ie&&f.win){window.attachEvent("onunload",function(){var a=B.length;for(var c=0;c<a;c++){B[c][0].detachEvent(B[c][1],B[c][2])}var b=H.length;for(var d=0;d<b;d++){be(H[d])}for(var g in f){f[g]=null}f=null;for(var j in swfobject){swfobject[j]=null}swfobject=null})}}();return{registerObject:function(a,c,b,d){if(f.w3&&a&&c){var g={};g.id=a;g.swfVersion=c;g.expressInstall=b;g.callbackFn=d;x[x.length]=g;A(a,false)}else if(d){d({success:false,id:a})}},getObjectById:function(a){if(f.w3){return R(a)}},embedSWF:function(j,h,o,l,q,p,v,L,M,E){var N={success:false,id:h};if(f.w3&&!(f.wk&&f.wk<312)&&j&&h&&o&&l&&q){A(h,false);bd(function(){o+="";l+="";var a={};if(M&&typeof M===t){for(var c in M){a[c]=M[c]}}a.data=j;a.width=o;a.height=l;var b={};if(L&&typeof L===t){for(var d in L){b[d]=L[d]}}if(v&&typeof v===t){for(var k in v){if(typeof b.flashvars!=m){b.flashvars+="&"+k+"="+v[k]}else{b.flashvars=k+"="+v[k]}}}if(K(q)){var g=V(a,b,h);if(a.id==h){A(h,true)}N.success=true;N.ref=g}else if(p&&S()){a.data=p;T(a,b,h,E);return}else{A(h,true)}if(E){E(N)}})}else if(E){E(N)}},switchOffAutoHideShow:function(){bb=false},ua:f,getFlashPlayerVersion:function(){return{major:f.pv[0],minor:f.pv[1],release:f.pv[2]}},hasFlashPlayerVersion:K,createSWF:function(a,c,b){if(f.w3){return V(a,c,b)}else{return undefined}},showExpressInstall:function(a,c,b,d){if(f.w3&&S()){T(a,c,b,d)}},removeSWF:function(a){if(f.w3){be(a)}},createCSS:function(a,c,b,d){if(f.w3){bf(a,c,b,d)}},addDomLoadEvent:bd,addLoadEvent:bc,getQueryParamValue:function(a){var c=i.location.search||i.location.hash;if(c){if(/\?/.test(c)){c=c.split("?")[1]}if(a==null){return bg(c)}var b=c.split("&");for(var d=0;d<b.length;d++){if(b[d].substring(0,b[d].indexOf("="))==a){return bg(b[d].substring((b[d].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(J){var a=s(X);if(a&&D){a.parentNode.replaceChild(D,a);if(I){A(I,true);if(f.ie&&f.win){D.style.display="block"}}if(O){O(ba)}}J=false}}}}();function DynamicAudio(a){if(this instanceof arguments.callee){if(typeof this.init=="function"){this.init.apply(this,(a&&a.callee)?a:arguments)}}else{return new arguments.callee(arguments)}}DynamicAudio.nextId=1;DynamicAudio.prototype={nextId:null,swf:'dynamicaudio.swf',audioElement:null,flashWrapper:null,flashElement:null,init:function(c){var b=this;b.id=DynamicAudio.nextId++;if(c&&typeof c['swf']!='undefined'){b.swf=c['swf']}if(typeof Audio!='undefined'){b.audioElement=new Audio();if(b.audioElement.mozSetup){b.audioElement.mozSetup(2,44100,1);return}}b.audioElement=null;b.flashWrapper=document.createElement('div');b.flashWrapper.id='dynamicaudio-flashwrapper-'+b.id;var d=b.flashWrapper.style;d['position']='fixed';d['width']=d['height']='8px';d['bottom']=d['left']='0px';d['overflow']='hidden';b.flashElement=document.createElement('div');b.flashElement.id='dynamicaudio-flashelement-'+b.id;b.flashWrapper.appendChild(b.flashElement);document.body.appendChild(b.flashWrapper);swfobject.embedSWF(b.swf,b.flashElement.id,"8","8","9.0.0",null,null,{'allowScriptAccess':'always'},null,function(a){b.flashElement=a.ref})},write:function(a){if(this.audioElement!=null){this.audioElement.mozWriteAudio(a.length,a)}else if(this.flashElement!=null){var c=new Array(a.length);for(var b=a.length-1;b!=0;b--){c[b]=Math.floor(a[b]*32768)}this.flashElement.write(c.join(' '))}},writeInt:function(a){if(this.audioElement!=null){var c=new Array(a.length);for(var b=a.length-1;b!=0;b--){c[b]=Math.floor(a[b]/32768)}this.audioElement.mozWriteAudio(c.length,c)}else if(this.flashElement!=null){this.flashElement.write(a.join(' '))}}}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<title>JSNES for Google Glass: A JavaScript NES emulator running on Google Glass via Wearscript</title> | |
</head> | |
<body bgcolor="#000000"> | |
<div style="background-color:black;height:380px;width:640px;"> | |
<div align="center" id="emulator"></div> | |
</div> | |
<script src="jquery-1.4.2.min.js" type="text/javascript" charset="utf-8"></script> | |
<script src="dynamicaudio-min.js" type="text/javascript" charset="utf-8"></script> | |
<script src="nes.js" type="text/javascript" charset="utf-8"></script> | |
<script src="utils.js" type="text/javascript" charset="utf-8"></script> | |
<script src="cpu.js" type="text/javascript" charset="utf-8"></script> | |
<script src="keyboard.js" type="text/javascript" charset="utf-8"></script> | |
<script src="mappers.js" type="text/javascript" charset="utf-8"></script> | |
<script src="papu.js" type="text/javascript" charset="utf-8"></script> | |
<script src="ppu.js" type="text/javascript" charset="utf-8"></script> | |
<script src="rom.js" type="text/javascript" charset="utf-8"></script> | |
<script src="ui.js" type="text/javascript" charset="utf-8"></script> | |
<script type="text/javascript" charset="utf-8"> | |
var nes; | |
$(function() { | |
nes = new JSNES({ | |
'ui': $('#emulator').JSNESUI({ | |
"Homebrew": [ | |
['Super Mario Bros', 'smb.nes'], | |
], | |
}) | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* jQuery JavaScript Library v1.4.2 | |
* http://jquery.com/ | |
* | |
* Copyright 2010, John Resig | |
* Dual licensed under the MIT or GPL Version 2 licenses. | |
* http://jquery.org/license | |
* | |
* Includes Sizzle.js | |
* http://sizzlejs.com/ | |
* Copyright 2010, The Dojo Foundation | |
* Released under the MIT, BSD, and GPL Licenses. | |
* | |
* Date: Sat Feb 13 22:33:48 2010 -0500 | |
*/ | |
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i? | |
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r= | |
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g, | |
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e= | |
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, | |
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& | |
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, | |
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== | |
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, | |
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)|| | |
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded", | |
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype, | |
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+ | |
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f], | |
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]=== | |
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&& | |
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari= | |
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>"; | |
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, | |
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= | |
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= | |
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, | |
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; | |
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, | |
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== | |
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, | |
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ", | |
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ", | |
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className= | |
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i= | |
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= | |
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); | |
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, | |
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); | |
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[] |