diff options
Diffstat (limited to 'cpu/instructions.go')
| -rw-r--r-- | cpu/instructions.go | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/cpu/instructions.go b/cpu/instructions.go new file mode 100644 index 0000000..b390f5c --- /dev/null +++ b/cpu/instructions.go @@ -0,0 +1,223 @@ +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) +} |