package cpu func ldaExec(c *CPU, op operand) { c.A = c.operandValue(op); c.setZN(c.A) } func ldxExec(c *CPU, op operand) { c.X = c.operandValue(op); c.setZN(c.X) } func ldyExec(c *CPU, op operand) { c.Y = c.operandValue(op); c.setZN(c.Y) } func staExec(c *CPU, op operand) { c.write(op.addr, c.A) } func stxExec(c *CPU, op operand) { c.write(op.addr, c.X) } func styExec(c *CPU, op operand) { c.write(op.addr, c.Y) } func taxExec(c *CPU, op operand) { c.X = c.A; c.setZN(c.X) } func txaExec(c *CPU, op operand) { c.A = c.X; c.setZN(c.A) } func tayExec(c *CPU, op operand) { c.Y = c.A; c.setZN(c.Y) } func tyaExec(c *CPU, op operand) { c.A = c.Y; c.setZN(c.A) } func tsxExec(c *CPU, op operand) { c.X = c.SP; c.setZN(c.X) } func txsExec(c *CPU, op operand) { c.SP = c.X } // no flags affected func phaExec(c *CPU, op operand) { c.push(c.A) } func plaExec(c *CPU, op operand) { c.A = c.pop(); c.setZN(c.A) } func phpExec(c *CPU, op operand) { c.push(c.Status | FlagB | FlagU) } func plpExec(c *CPU, op operand) { pulled := c.pop() c.Status = (pulled &^ FlagB) | FlagU } func (c *CPU) addWithCarry(v uint8) { var carryIn uint16 if c.flag(FlagC) { carryIn = 1 } sum := uint16(c.A) + uint16(v) + carryIn result := uint8(sum) c.setFlag(FlagC, sum > 0xFF) c.setFlag(FlagV, (c.A^v)&0x80 == 0 && (c.A^result)&0x80 != 0) c.A = result c.setZN(c.A) } func adcExec(c *CPU, op operand) { c.addWithCarry(c.operandValue(op)) } func sbcExec(c *CPU, op operand) { c.addWithCarry(^c.operandValue(op)) } func andExec(c *CPU, op operand) { c.A &= c.operandValue(op); c.setZN(c.A) } func oraExec(c *CPU, op operand) { c.A |= c.operandValue(op); c.setZN(c.A) } func eorExec(c *CPU, op operand) { c.A ^= c.operandValue(op); c.setZN(c.A) } func bitExec(c *CPU, op operand) { v := c.operandValue(op) c.setFlag(FlagZ, c.A&v == 0) c.setFlag(FlagV, v&0x40 != 0) c.setFlag(FlagN, v&0x80 != 0) } func aslExec(c *CPU, op operand) { v := c.operandValue(op) c.setFlag(FlagC, v&0x80 != 0) result := v << 1 c.writeOperand(op, result) c.setZN(result) } func lsrExec(c *CPU, op operand) { v := c.operandValue(op) c.setFlag(FlagC, v&0x01 != 0) result := v >> 1 c.writeOperand(op, result) c.setZN(result) } func rolExec(c *CPU, op operand) { v := c.operandValue(op) var carryIn uint8 if c.flag(FlagC) { carryIn = 1 } c.setFlag(FlagC, v&0x80 != 0) result := v<<1 | carryIn c.writeOperand(op, result) c.setZN(result) } func rorExec(c *CPU, op operand) { v := c.operandValue(op) var carryIn uint8 if c.flag(FlagC) { carryIn = 0x80 } c.setFlag(FlagC, v&0x01 != 0) result := v>>1 | carryIn c.writeOperand(op, result) c.setZN(result) } func incExec(c *CPU, op operand) { v := c.operandValue(op) + 1; c.writeOperand(op, v); c.setZN(v) } func decExec(c *CPU, op operand) { v := c.operandValue(op) - 1; c.writeOperand(op, v); c.setZN(v) } func inxExec(c *CPU, op operand) { c.X++; c.setZN(c.X) } func dexExec(c *CPU, op operand) { c.X--; c.setZN(c.X) } func inyExec(c *CPU, op operand) { c.Y++; c.setZN(c.Y) } func deyExec(c *CPU, op operand) { c.Y--; c.setZN(c.Y) } func (c *CPU) compare(reg, v uint8) { result := reg - v c.setFlag(FlagC, reg >= v) c.setZN(result) } func cmpExec(c *CPU, op operand) { c.compare(c.A, c.operandValue(op)) } func cpxExec(c *CPU, op operand) { c.compare(c.X, c.operandValue(op)) } func cpyExec(c *CPU, op operand) { c.compare(c.Y, c.operandValue(op)) } func (c *CPU) branch(op operand, cond bool) { if !cond { return } c.extraCycles++ if !samePage(c.PC, op.addr) { c.extraCycles++ } c.PC = op.addr } func bccExec(c *CPU, op operand) { c.branch(op, !c.flag(FlagC)) } func bcsExec(c *CPU, op operand) { c.branch(op, c.flag(FlagC)) } func bneExec(c *CPU, op operand) { c.branch(op, !c.flag(FlagZ)) } func beqExec(c *CPU, op operand) { c.branch(op, c.flag(FlagZ)) } func bplExec(c *CPU, op operand) { c.branch(op, !c.flag(FlagN)) } func bmiExec(c *CPU, op operand) { c.branch(op, c.flag(FlagN)) } func bvcExec(c *CPU, op operand) { c.branch(op, !c.flag(FlagV)) } func bvsExec(c *CPU, op operand) { c.branch(op, c.flag(FlagV)) } func jmpExec(c *CPU, op operand) { c.PC = op.addr } func jsrExec(c *CPU, op operand) { c.push16(c.PC - 1) // address of the last byte of the jsr instruction c.PC = op.addr } func rtsExec(c *CPU, op operand) { c.PC = c.pop16() + 1 } func rtiExec(c *CPU, op operand) { pulled := c.pop() c.Status = (pulled &^ FlagB) | FlagU c.PC = c.pop16() } func clcExec(c *CPU, op operand) { c.setFlag(FlagC, false) } func secExec(c *CPU, op operand) { c.setFlag(FlagC, true) } func cliExec(c *CPU, op operand) { c.setFlag(FlagI, false) } func seiExec(c *CPU, op operand) { c.setFlag(FlagI, true) } func cldExec(c *CPU, op operand) { c.setFlag(FlagD, false) } func sedExec(c *CPU, op operand) { c.setFlag(FlagD, true) } func clvExec(c *CPU, op operand) { c.setFlag(FlagV, false) } func nopExec(c *CPU, op operand) {} func brkExec(c *CPU, op operand) { c.PC++ // brk is logically 2 bytes: the byte after the opcode is skipped c.interrupt(vectorIRQ, true) } func laxExec(c *CPU, op operand) { v := c.operandValue(op) c.A, c.X = v, v c.setZN(v) } func saxExec(c *CPU, op operand) { c.write(op.addr, c.A&c.X) } func dcpExec(c *CPU, op operand) { v := c.operandValue(op) - 1 c.writeOperand(op, v) c.compare(c.A, v) } func sloExec(c *CPU, op operand) { v := c.operandValue(op) c.setFlag(FlagC, v&0x80 != 0) result := v << 1 c.writeOperand(op, result) c.A |= result c.setZN(c.A) } func rlaExec(c *CPU, op operand) { v := c.operandValue(op) var carryIn uint8 if c.flag(FlagC) { carryIn = 1 } c.setFlag(FlagC, v&0x80 != 0) result := v<<1 | carryIn c.writeOperand(op, result) c.A &= result c.setZN(c.A) } func sreExec(c *CPU, op operand) { v := c.operandValue(op) c.setFlag(FlagC, v&0x01 != 0) result := v >> 1 c.writeOperand(op, result) c.A ^= result c.setZN(c.A) } func rraExec(c *CPU, op operand) { v := c.operandValue(op) var carryIn uint8 if c.flag(FlagC) { carryIn = 0x80 } c.setFlag(FlagC, v&0x01 != 0) result := v>>1 | carryIn c.writeOperand(op, result) c.addWithCarry(result) } func iscExec(c *CPU, op operand) { v := c.operandValue(op) + 1 c.writeOperand(op, v) c.addWithCarry(^v) } func jamExec(c *CPU, op operand) { c.Jammed = true c.PC-- } // and with immediate, then carry takes the sign bit func ancExec(c *CPU, op operand) { c.A &= c.operandValue(op) c.setZN(c.A) c.setFlag(FlagC, c.A&0x80 != 0) } // and with immediate, then lsr a func alrExec(c *CPU, op operand) { v := c.A & c.operandValue(op) c.setFlag(FlagC, v&0x01 != 0) c.A = v >> 1 c.setZN(c.A) } // and with immediate, then ror a, but C and V come from bits 6 and 5 of the // result (binary mode only, the 2A03 has no decimal mode) func arrExec(c *CPU, op operand) { v := c.A & c.operandValue(op) var carryIn uint8 if c.flag(FlagC) { carryIn = 0x80 } c.A = v>>1 | carryIn c.setZN(c.A) c.setFlag(FlagC, c.A&0x40 != 0) c.setFlag(FlagV, (c.A>>6^c.A>>5)&0x01 != 0) } // x = (a & x) - immediate, like cmp: no borrow in, V untouched func axsExec(c *CPU, op operand) { v := c.A & c.X imm := c.operandValue(op) c.setFlag(FlagC, v >= imm) c.X = v - imm c.setZN(c.X) } // memory & sp goes into a, x and sp func lasExec(c *CPU, op operand) { v := c.operandValue(op) & c.SP c.A, c.X, c.SP = v, v, v c.setZN(v) } const unstableMagic uint8 = 0xEE func aneExec(c *CPU, op operand) { c.A = (c.A | unstableMagic) & c.X & c.operandValue(op) c.setZN(c.A) } func lxaExec(c *CPU, op operand) { c.A = (c.A | unstableMagic) & c.operandValue(op) c.X = c.A c.setZN(c.A) } func (c *CPU) storeHighAnd(op operand, v uint8) { baseHi := uint8(op.addr >> 8) if op.pageCrossed { baseHi-- } v &= baseHi + 1 addr := op.addr if op.pageCrossed { addr = uint16(v)<<8 | addr&0x00FF } c.write(addr, v) } func ahxExec(c *CPU, op operand) { c.storeHighAnd(op, c.A&c.X) } func shxExec(c *CPU, op operand) { c.storeHighAnd(op, c.X) } func shyExec(c *CPU, op operand) { c.storeHighAnd(op, c.Y) } func tasExec(c *CPU, op operand) { c.SP = c.A & c.X c.storeHighAnd(op, c.SP) }