diff options
Diffstat (limited to 'js.2/cpu.js')
-rw-r--r-- | js.2/cpu.js | 1656 |
1 files changed, 1656 insertions, 0 deletions
diff --git a/js.2/cpu.js b/js.2/cpu.js new file mode 100644 index 0000000..bde3f2a --- /dev/null +++ b/js.2/cpu.js @@ -0,0 +1,1656 @@ +NES.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.palCnt = null; + this.opdata = null; + this.cyclesToHalt = null; + this.crash = null; + this.irqRequested = null; + this.irqType = null; + + this.reset(); +} + +NES.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.palCnt = 0; + this.opdata = new NES.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; + } + 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; + } +} + +// Generates and provides an array of details about instructions +NES.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 " + ); +} + +NES.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); + } +} |