diff --git a/cpu/cpu.go b/cpu/cpu.go index 702582f..90d739c 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -156,8 +156,20 @@ func (c *Cpu) memoryAddress(in Instruction) uint16 { return uint16(in.Op8 + c.X) case zeropageY: return uint16(in.Op8 + c.Y) + + // 65C02-only modes + case zpindirect: + return c.Bus.Read16(uint16(in.Op8)) + case indirect: + return c.Bus.Read16(uint16(in.Op16)) + + // This is like indirectX but uses a full 16-bit absolute address. + case indirectX16: + return c.Bus.Read16(in.Op16 + uint16(c.X)) + default: - panic("unhandled addressing") + panic(fmt.Sprintf("unhandled addressing mode: %v", + addressingNames[in.addressing])) } } @@ -226,6 +238,10 @@ func (c *Cpu) execute(in Instruction) { c.BNE(in) case bpl: c.BPL(in) + case bvs: + c.BVS(in) + case bvc: + c.BVC(in) case brk: c.BRK(in) case clc: @@ -270,6 +286,10 @@ func (c *Cpu) execute(in Instruction) { c.NOP(in) case ora: c.ORA(in) + case php: + c.PHP(in) + case plp: + c.PLP(in) case pha: c.PHA(in) case pla: @@ -282,6 +302,8 @@ func (c *Cpu) execute(in Instruction) { c.RTS(in) case sbc: c.SBC(in) + case sed: + c.SED(in) case sec: c.SEC(in) case sei: @@ -304,6 +326,24 @@ func (c *Cpu) execute(in Instruction) { c.TXS(in) case tya: c.TYA(in) + + // 65C02 only + case phx: + c.PHX(in) + case phy: + c.PHY(in) + case plx: + c.PLX(in) + case ply: + c.PLY(in) + case stz: + c.STZ(in) + case bra: + c.BRA(in) + case trb: + c.TRB(in) + case tsb: + c.TSB(in) case _end: c._END(in) default: @@ -356,6 +396,20 @@ func (c *Cpu) BCS(in Instruction) { } } +// BVC: Branch if overflow clear. +func (c *Cpu) BVC(in Instruction) { + if !c.getStatus(sOverflow) { + c.branch(in) + } +} + +// BVS: Branch if overflow set. +func (c *Cpu) BVS(in Instruction) { + if c.getStatus(sOverflow) { + c.branch(in) + } +} + // BEQ: Branch if equal (z=1). func (c *Cpu) BEQ(in Instruction) { if c.getStatus(sZero) { @@ -371,6 +425,22 @@ func (c *Cpu) BIT(in Instruction) { c.setStatus(sNegative, value&(1<<7) != 0) } +// TRB: Test and Reset bits +func (c *Cpu) TRB(in Instruction) { + value := c.resolveOperand(in) + c.setStatus(sZero, value&c.AC == 0) + // note: the bits which are *set* in AC are *cleared* in value + c.Bus.Write(c.memoryAddress(in), value&(c.AC^0xFF)) +} + +// TSB: Test and Set bits +func (c *Cpu) TSB(in Instruction) { + value := c.resolveOperand(in) + c.setStatus(sZero, value&c.AC == 0) + // note: the bits which are *set* in AC are *set* in value + c.Bus.Write(c.memoryAddress(in), value|c.AC) +} + // BMI: Branch if negative. func (c *Cpu) BMI(in Instruction) { if c.getStatus(sNegative) { @@ -392,6 +462,11 @@ func (c *Cpu) BPL(in Instruction) { } } +// BRA: Unconditional branch +func (c *Cpu) BRA(in Instruction) { + c.branch(in) +} + // BRK: software interrupt func (c *Cpu) BRK(in Instruction) { // temporarily used to dump status @@ -410,7 +485,7 @@ func (c *Cpu) CLD(in Instruction) { // CLI: Clear interrupt-disable flag. func (c *Cpu) CLI(in Instruction) { - c.setStatus(sInterrupt, true) + c.setStatus(sInterrupt, false) } // CMP: Compare accumulator with memory. @@ -436,10 +511,17 @@ func (c *Cpu) CPY(in Instruction) { // DEC: Decrement. func (c *Cpu) DEC(in Instruction) { - address := c.memoryAddress(in) - value := c.Bus.Read(address) - 1 - c.Bus.Write(address, value) - c.updateStatus(value) + switch in.addressing { + case implied: + // 65C02 only: decrement accumulator + c.AC-- + c.updateStatus(c.AC) + default: + address := c.memoryAddress(in) + value := c.Bus.Read(address) - 1 + c.Bus.Write(address, value) + c.updateStatus(value) + } } // DEX: Decrement index register X. @@ -463,10 +545,17 @@ func (c *Cpu) EOR(in Instruction) { // INC: Increment. func (c *Cpu) INC(in Instruction) { - address := c.memoryAddress(in) - value := c.Bus.Read(address) + 1 - c.Bus.Write(address, value) - c.updateStatus(value) + switch in.addressing { + case implied: + // 65C02 only: increment accumulator + c.AC++ + c.updateStatus(c.AC) + default: + address := c.memoryAddress(in) + value := c.Bus.Read(address) + 1 + c.Bus.Write(address, value) + c.updateStatus(value) + } } // INX: Increment index register X. @@ -538,6 +627,18 @@ func (c *Cpu) ORA(in Instruction) { c.updateStatus(c.AC) } +// PHP: Push status onto stack. +func (c *Cpu) PHP(in Instruction) { + c.Bus.Write(0x0100+uint16(c.SP), c.SR) + c.SP-- +} + +// PLP: Pull status from stack. +func (c *Cpu) PLP(in Instruction) { + c.SP++ + c.SR = c.Bus.Read(0x0100 + uint16(c.SP)) +} + // PHA: Push accumulator onto stack. func (c *Cpu) PHA(in Instruction) { c.Bus.Write(0x0100+uint16(c.SP), c.AC) @@ -548,6 +649,33 @@ func (c *Cpu) PHA(in Instruction) { func (c *Cpu) PLA(in Instruction) { c.SP++ c.AC = c.Bus.Read(0x0100 + uint16(c.SP)) + c.updateStatus(c.AC) +} + +// PHX: Push X onto stack. +func (c *Cpu) PHX(in Instruction) { + c.Bus.Write(0x0100+uint16(c.SP), c.X) + c.SP-- +} + +// PLX: Pull X from stack. +func (c *Cpu) PLX(in Instruction) { + c.SP++ + c.X = c.Bus.Read(0x0100 + uint16(c.SP)) + c.updateStatus(c.X) +} + +// PHY: Push Y onto stack. +func (c *Cpu) PHY(in Instruction) { + c.Bus.Write(0x0100+uint16(c.SP), c.Y) + c.SP-- +} + +// PLY: Pull Y from stack. +func (c *Cpu) PLY(in Instruction) { + c.SP++ + c.Y = c.Bus.Read(0x0100 + uint16(c.SP)) + c.updateStatus(c.Y) } // ROL: Rotate memory or accumulator left one bit. @@ -617,9 +745,14 @@ func (c *Cpu) SEC(in Instruction) { c.setStatus(sCarry, true) } +// SED: Set decimal mode flag. +func (c *Cpu) SED(in Instruction) { + c.setStatus(sDecimal, true) +} + // SEI: Set interrupt-disable flag. func (c *Cpu) SEI(in Instruction) { - c.setStatus(sInterrupt, false) + c.setStatus(sInterrupt, true) } // STA: Store accumulator to memory. @@ -637,6 +770,11 @@ func (c *Cpu) STY(in Instruction) { c.Bus.Write(c.memoryAddress(in), c.Y) } +// STZ: Store zero to memory. +func (c *Cpu) STZ(in Instruction) { + c.Bus.Write(c.memoryAddress(in), 0) +} + // TAX: Transfer accumulator to index register X. func (c *Cpu) TAX(in Instruction) { c.X = c.AC diff --git a/cpu/op_type.go b/cpu/op_type.go index 03e547b..8879727 100644 --- a/cpu/op_type.go +++ b/cpu/op_type.go @@ -18,6 +18,10 @@ const ( zeropage zeropageX zeropageY + + // 65C02 only + zpindirect + indirectX16 ) var addressingNames = [...]string{ @@ -35,6 +39,8 @@ var addressingNames = [...]string{ "zeropage", "zeropageX", "zeropageY", + "(zeropage)", + "(absolute,X)", } // adc..tya represent the 6502 instruction set mnemonics. Each mnemonic maps to @@ -97,6 +103,17 @@ const ( txa txs tya + + // 65{S}C02-only + bra + phx + phy + plx + ply + stz + trb + tsb + _end ) @@ -158,6 +175,17 @@ var instructionNames = [...]string{ "TXA", "TXS", "TYA", + + // 65{S}C02-only + "BRA", + "PHX", + "PHY", + "PLX", + "PLY", + "STZ", + "TRB", + "TSB", + "_END", } @@ -308,7 +336,7 @@ var optypes = map[uint8]OpType{ 0x48: OpType{0x48, pha, implied, 1, 3}, 0x08: OpType{0x08, php, implied, 1, 3}, 0x68: OpType{0x68, pla, implied, 1, 4}, - 0x28: OpType{0x28, php, implied, 1, 4}, + 0x28: OpType{0x28, plp, implied, 1, 4}, 0x2A: OpType{0x2A, rol, accumulator, 1, 2}, 0x26: OpType{0x26, rol, zeropage, 2, 5}, 0x36: OpType{0x36, rol, zeropageX, 2, 6}, @@ -351,5 +379,39 @@ var optypes = map[uint8]OpType{ 0x8A: OpType{0x8A, txa, implied, 1, 2}, 0x9A: OpType{0x9A, txs, implied, 1, 2}, 0x98: OpType{0x98, tya, implied, 1, 2}, + + // 65C02 only + + // Additional addressing modes + 0x12: OpType{0x12, ora, zpindirect, 2, 5}, + 0x32: OpType{0x32, and, zpindirect, 2, 5}, + 0x52: OpType{0x52, eor, zpindirect, 2, 5}, + 0x72: OpType{0x72, adc, zpindirect, 2, 5}, + 0x92: OpType{0x92, sta, zpindirect, 2, 5}, + 0xB2: OpType{0xB2, lda, zpindirect, 2, 5}, + 0xD2: OpType{0xD2, cmp, zpindirect, 2, 5}, + 0xF2: OpType{0xF2, sbc, zpindirect, 2, 5}, + 0x89: OpType{0x89, bit, immediate, 2, 2}, + 0x34: OpType{0x34, bit, zeropageX, 2, 4}, + 0x3C: OpType{0x3C, bit, absoluteX, 3, 4}, + 0x3A: OpType{0x3A, dec, implied, 1, 2}, + 0x1A: OpType{0x1A, inc, implied, 1, 2}, + 0x7C: OpType{0x7C, jmp, indirectX16, 3, 6}, + + // New instructions + 0x80: OpType{0x80, bra, relative, 2, 3}, + 0xDA: OpType{0xDA, phx, implied, 1, 3}, + 0x5A: OpType{0x5A, phy, implied, 1, 3}, + 0xFA: OpType{0xFA, plx, implied, 1, 4}, + 0x7A: OpType{0x7A, ply, implied, 1, 4}, + 0x64: OpType{0x64, stz, zeropage, 2, 3}, + 0x74: OpType{0x74, stz, zeropageX, 2, 4}, + 0x9C: OpType{0x9C, stz, absolute, 3, 4}, + 0x9E: OpType{0x9E, stz, absoluteX, 3, 5}, + 0x14: OpType{0x14, trb, zeropage, 2, 5}, + 0x1C: OpType{0x1C, trb, absolute, 3, 6}, + 0x04: OpType{0x04, tsb, zeropage, 2, 5}, + 0x0C: OpType{0x0C, tsb, absolute, 3, 5}, + 0xFF: OpType{0xFF, _end, implied, 1, 1}, }