package m65go2
import (
"time"
)
// Represents a clock signal for an IC. Once a Clock is started, it
// maintains a 'ticks' counters which is incremented at a specific
// interval.
type Clock struct {
rate time.Duration
ticks uint64
ticker *time.Ticker
stopChan chan int
waiting map[uint64][]chan int
}
// Returns a pointer to a new Clock which increments its ticker at
// intervals of 'rate'. The returned Clock has not been started and
// its ticks counter is zero.
func NewClock(rate time.Duration) *Clock {
return &Clock{
rate: rate,
ticks: 0,
ticker: nil,
stopChan: make(chan int),
waiting: make(map[uint64][]chan int),
}
}
func (clock *Clock) maintainTime() {
for {
select {
case <-clock.stopChan:
clock.ticker = nil
return
case _ = <-clock.ticker.C:
clock.ticks++
if Ca, ok := clock.waiting[clock.ticks]; ok {
for _, C := range Ca {
C <- 1
}
delete(clock.waiting, clock.ticks)
}
}
}
}
// Returns the current value of the Clock's ticks counter.
func (clock *Clock) Ticks() uint64 {
return clock.ticks
}
// Starts the Clock
func (clock *Clock) Start() (ticks uint64) {
ticks = clock.ticks
if clock.ticker == nil {
clock.ticker = time.NewTicker(clock.rate)
clock.maintainTime()
}
return
}
// Stops the clock
func (clock *Clock) Stop() {
if clock.ticker != nil {
clock.stopChan <- 1
}
}
// Blocks the calling thread until the given tick has arrived.
// Returns immediately if the clock has already passed the given tick.
func (clock *Clock) Await(tick uint64) uint64 {
if clock.ticks < tick {
C := make(chan int, 1)
clock.waiting[tick] = append(clock.waiting[tick], C)
<-C
}
return clock.ticks
}
// Package m65go2 simulates the MOS 6502 CPU
package m65go2
import (
"fmt"
"os"
)
// Flags used by P (Status) register
type Status uint8
const (
C Status = 1 << iota // carry flag
Z // zero flag
I // interrupt disable
D // decimal mode
B // break command
_ // -UNUSED-
V // overflow flag
N // negative flag
)
// The 6502's registers, all registers are 8-bit values except for PC
// which is 16-bits.
type Registers struct {
A uint8 // accumulator
X uint8 // index register X
Y uint8 // index register Y
P Status // processor status
SP uint8 // stack pointer
PC uint16 // program counter
}
// Creates a new set of Registers. All registers are initialized to
// 0.
func NewRegisters() Registers {
return Registers{}
}
// Resets all registers. Register P is initialized with only the I
// bit set, SP is initialized to 0xfd, PC is initialized to 0xfffc
// (the RESET vector) and all other registers are initialized to 0.
func (reg *Registers) Reset() {
reg.A = 0
reg.X = 0
reg.Y = 0
reg.P = I
reg.SP = 0xfd
reg.PC = 0xfffc
}
// Prints the values of each register to os.Stderr.
func (reg *Registers) String() {
fmt.Fprintf(os.Stderr, "A: %#02x (%03dd) (%08bb)\n", reg.A, reg.A, reg.A)
fmt.Fprintf(os.Stderr, "X: %#02x (%03dd) (%08bb)\n", reg.X, reg.X, reg.X)
fmt.Fprintf(os.Stderr, "Y: %#02x (%03dd) (%08bb)\n", reg.Y, reg.Y, reg.Y)
fmt.Fprintf(os.Stderr, "SP: %#02x (%03dd) (%08bb)\n", reg.SP, reg.SP, reg.SP)
f := ""
getFlag := func(flag Status, set string) string {
if reg.P&flag != 0 {
return set
}
return "-"
}
f += getFlag(N, "N")
f += getFlag(V, "V")
f += "-" // -UNUSED-
f += getFlag(B, "B")
f += getFlag(D, "D")
f += getFlag(I, "I")
f += getFlag(Z, "Z")
f += getFlag(C, "C")
fmt.Fprintf(os.Stderr, "P: %08bb (%s)\n", reg.P, f)
fmt.Fprintf(os.Stderr, "PC: %#04x (%05dd) (%016bb)\n", reg.PC, reg.PC, reg.PC)
}
// Represents the 6502 CPU.
type CPU struct {
decode bool
divisor uint16
clock *Clock
Registers Registers
Memory Memory
Instructions InstructionTable
}
// Returns a pointer to a new CPU with the given Memory, clock divisor
// and clock.
func NewCPU(mem Memory, divisor uint16, clock *Clock) *CPU {
instructions := NewInstructionTable()
instructions.InitInstructions()
return &CPU{decode: false, divisor: divisor, clock: clock, Registers: NewRegisters(), Memory: mem, Instructions: instructions}
}
// Resets the CPU by resetting both the registers and memory.
func (cpu *CPU) Reset() {
cpu.Registers.Reset()
cpu.Memory.Reset()
}
// Error type used to indicate that the CPU attempted to execute an
// invalid opcode
type BadOpCodeError OpCode
func (b BadOpCodeError) Error() string {
return fmt.Sprintf("No such opcode %#02x", b)
}
// Executes the instruction pointed to by the PC register in the
// number of clock cycles as returned by the instruction's Exec
// function. Returns the number of cycles executed and any error
// (such as BadOpCodeError).
func (cpu *CPU) Execute() (cycles uint16, error error) {
ticks := cpu.clock.ticks
// fetch
opcode := OpCode(cpu.Memory.Fetch(cpu.Registers.PC))
inst, ok := cpu.Instructions[opcode]
if !ok {
return 0, BadOpCodeError(opcode)
}
// execute
cpu.Registers.PC++
cycles = inst.Exec(cpu)
// count cycles
cpu.clock.Await(ticks + uint64(cycles*cpu.divisor))
return cycles, nil
}
// Executes instruction until Execute() returns an error.
func (cpu *CPU) Run() (error error) {
for {
if _, error := cpu.Execute(); error != nil {
return error
}
}
return nil
}
func (cpu *CPU) setZFlag(value uint8) uint8 {
if value == 0 {
cpu.Registers.P |= Z
} else {
cpu.Registers.P &= ^Z
}
return value
}
func (cpu *CPU) setNFlag(value uint8) uint8 {
cpu.Registers.P = (cpu.Registers.P & ^N) | Status(value&uint8(N))
return value
}
func (cpu *CPU) setZNFlags(value uint8) uint8 {
cpu.setZFlag(value)
cpu.setNFlag(value)
return value
}
func (cpu *CPU) setCFlagAddition(value uint16) uint16 {
cpu.Registers.P = (cpu.Registers.P & ^C) | Status(value>>8&uint16(C))
return value
}
func (cpu *CPU) setVFlagAddition(term1 uint16, term2 uint16, result uint16) uint16 {
cpu.Registers.P = (cpu.Registers.P & ^V) | Status((^(term1^term2)&(term1^result)&uint16(N))>>1)
return result
}
func (cpu *CPU) load(address uint16, register *uint8) {
*register = cpu.setZNFlags(cpu.Memory.Fetch(address))
}
func (cpu *CPU) immediateAddress() (result uint16) {
result = cpu.Registers.PC
cpu.Registers.PC++
return
}
func (cpu *CPU) zeroPageAddress() (result uint16) {
result = uint16(cpu.Memory.Fetch(cpu.Registers.PC))
cpu.Registers.PC++
return
}
func (cpu *CPU) zeroPageIndexedAddress(index uint8) (result uint16) {
result = uint16(cpu.Memory.Fetch(cpu.Registers.PC) + index)
cpu.Registers.PC++
return
}
func (cpu *CPU) relativeAddress() (result uint16) {
value := uint16(cpu.Memory.Fetch(cpu.Registers.PC))
cpu.Registers.PC++
if value > 0x7f {
result = cpu.Registers.PC - (0x0100 - value)
} else {
result = cpu.Registers.PC + value
}
return
}
func (cpu *CPU) absoluteAddress() (result uint16) {
low := cpu.Memory.Fetch(cpu.Registers.PC)
high := cpu.Memory.Fetch(cpu.Registers.PC + 1)
cpu.Registers.PC += 2
result = (uint16(high) << 8) | uint16(low)
return
}
func (cpu *CPU) indirectAddress() (result uint16) {
low := cpu.Memory.Fetch(cpu.Registers.PC)
high := cpu.Memory.Fetch(cpu.Registers.PC + 1)
cpu.Registers.PC += 2
// XXX: The 6502 had a bug in which it incremented only the
// high byte instead of the whole 16-bit address when
// computing the address.
//
// See http://www.obelisk.demon.co.uk/6502/reference.html#JMP
// and http://www.6502.org/tutorials/6502opcodes.html#JMP for
// details
aHigh := (uint16(high) << 8) | uint16(low+1)
aLow := (uint16(high) << 8) | uint16(low)
low = cpu.Memory.Fetch(aLow)
high = cpu.Memory.Fetch(aHigh)
result = (uint16(high) << 8) | uint16(low)
return
}
func (cpu *CPU) absoluteIndexedAddress(index uint8, cycles *uint16) (result uint16) {
low := cpu.Memory.Fetch(cpu.Registers.PC)
high := cpu.Memory.Fetch(cpu.Registers.PC + 1)
cpu.Registers.PC += 2
address := (uint16(high) << 8) | uint16(low)
result = address + uint16(index)
if cycles != nil && !SamePage(address, result) {
*cycles++
}
return
}
func (cpu *CPU) indexedIndirectAddress() (result uint16) {
address := uint16(cpu.Memory.Fetch(cpu.Registers.PC) + cpu.Registers.X)
cpu.Registers.PC++
low := cpu.Memory.Fetch(address)
high := cpu.Memory.Fetch(address + 1)
result = (uint16(high) << 8) | uint16(low)
return
}
func (cpu *CPU) indirectIndexedAddress(cycles *uint16) (result uint16) {
address := uint16(cpu.Memory.Fetch(cpu.Registers.PC))
cpu.Registers.PC++
low := cpu.Memory.Fetch(address)
high := cpu.Memory.Fetch(address + 1)
address = (uint16(high) << 8) | uint16(low)
result = address + uint16(cpu.Registers.Y)
if cycles != nil && !SamePage(address, result) {
*cycles++
}
return
}
// Loads a byte of memory into the accumulator setting the zero and
// negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of A is set
func (cpu *CPU) Lda(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: LDA $%04x\n", cpu.Registers.PC, address)
}
cpu.load(address, &cpu.Registers.A)
}
// Loads a byte of memory into the X register setting the zero and
// negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if X = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of X is set
func (cpu *CPU) Ldx(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: LDX $%04x\n", cpu.Registers.PC, address)
}
cpu.load(address, &cpu.Registers.X)
}
// Loads a byte of memory into the Y register setting the zero and
// negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if Y = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of Y is set
func (cpu *CPU) Ldy(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: LDY $%04x\n", cpu.Registers.PC, address)
}
cpu.load(address, &cpu.Registers.Y)
}
func (cpu *CPU) store(address uint16, value uint8) {
cpu.Memory.Store(address, value)
}
// Stores the contents of the accumulator into memory.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Sta(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: STA $%04x\n", cpu.Registers.PC, address)
}
cpu.store(address, cpu.Registers.A)
}
// Stores the contents of the X register into memory.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Stx(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: STX $%04x\n", cpu.Registers.PC, address)
}
cpu.store(address, cpu.Registers.X)
}
// Stores the contents of the Y register into memory.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Sty(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: STY $%04x\n", cpu.Registers.PC, address)
}
cpu.store(address, cpu.Registers.Y)
}
func (cpu *CPU) transfer(from uint8, to *uint8) {
*to = cpu.setZNFlags(from)
}
// Copies the current contents of the accumulator into the X register
// and sets the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if X = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of X is set
func (cpu *CPU) Tax() {
if cpu.decode {
fmt.Printf(" %04x: TAX\n", cpu.Registers.PC)
}
cpu.transfer(cpu.Registers.A, &cpu.Registers.X)
}
// Copies the current contents of the accumulator into the Y register
// and sets the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if Y = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of Y is set
func (cpu *CPU) Tay() {
if cpu.decode {
fmt.Printf(" %04x: TAY\n", cpu.Registers.PC)
}
cpu.transfer(cpu.Registers.A, &cpu.Registers.Y)
}
// Copies the current contents of the X register into the accumulator
// and sets the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of A is set
func (cpu *CPU) Txa() {
if cpu.decode {
fmt.Printf(" %04x: TXA\n", cpu.Registers.PC)
}
cpu.transfer(cpu.Registers.X, &cpu.Registers.A)
}
// Copies the current contents of the Y register into the accumulator
// and sets the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of A is set
func (cpu *CPU) Tya() {
if cpu.decode {
fmt.Printf(" %04x: TYA\n", cpu.Registers.PC)
}
cpu.transfer(cpu.Registers.Y, &cpu.Registers.A)
}
// Copies the current contents of the stack register into the X
// register and sets the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if X = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of X is set
func (cpu *CPU) Tsx() {
if cpu.decode {
fmt.Printf(" %04x: TSX\n", cpu.Registers.PC)
}
cpu.transfer(cpu.Registers.SP, &cpu.Registers.X)
}
// Copies the current contents of the X register into the stack
// register.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Txs() {
if cpu.decode {
fmt.Printf(" %04x: TXS\n", cpu.Registers.PC)
}
cpu.transfer(cpu.Registers.X, &cpu.Registers.SP)
}
func (cpu *CPU) push(value uint8) {
cpu.Memory.Store(0x0100|uint16(cpu.Registers.SP), value)
cpu.Registers.SP--
}
func (cpu *CPU) push16(value uint16) {
cpu.push(uint8(value >> 8))
cpu.push(uint8(value))
}
func (cpu *CPU) pull() (value uint8) {
cpu.Registers.SP++
value = cpu.Memory.Fetch(0x0100 | uint16(cpu.Registers.SP))
return
}
func (cpu *CPU) pull16() (value uint16) {
low := cpu.pull()
high := cpu.pull()
value = (uint16(high) << 8) | uint16(low)
return
}
// Pushes a copy of the accumulator on to the stack.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Pha() {
if cpu.decode {
fmt.Printf(" %04x: PHA\n", cpu.Registers.PC)
}
cpu.push(cpu.Registers.A)
}
// Pushes a copy of the status flags on to the stack.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Php() {
if cpu.decode {
fmt.Printf(" %04x: PHP\n", cpu.Registers.PC)
}
cpu.push(uint8(cpu.Registers.P | B))
}
// Pulls an 8 bit value from the stack and into the accumulator. The
// zero and negative flags are set as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of A is set
func (cpu *CPU) Pla() {
if cpu.decode {
fmt.Printf(" %04x: PLA\n", cpu.Registers.PC)
}
cpu.Registers.A = cpu.setZNFlags(cpu.pull())
}
// Pulls an 8 bit value from the stack and into the processor
// flags. The flags will take on new states as determined by the value
// pulled.
//
// C Carry Flag Set from stack
// Z Zero Flag Set from stack
// I Interrupt Disable Set from stack
// D Decimal Mode Flag Set from stack
// B Break Command Set from stack
// V Overflow Flag Set from stack
// N Negative Flag Set from stack
func (cpu *CPU) Plp() {
if cpu.decode {
fmt.Printf(" %04x: PLP\n", cpu.Registers.PC)
}
cpu.Registers.P = Status(cpu.pull())
}
// A logical AND is performed, bit by bit, on the accumulator contents
// using the contents of a byte of memory.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 set
func (cpu *CPU) And(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: AND $%04x\n", cpu.Registers.PC, address)
}
cpu.Registers.A = cpu.setZNFlags(cpu.Registers.A & cpu.Memory.Fetch(address))
}
// An exclusive OR is performed, bit by bit, on the accumulator
// contents using the contents of a byte of memory.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 set
func (cpu *CPU) Eor(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: EOR $%04x\n", cpu.Registers.PC, address)
}
cpu.Registers.A = cpu.setZNFlags(cpu.Registers.A ^ cpu.Memory.Fetch(address))
}
// An inclusive OR is performed, bit by bit, on the accumulator
// contents using the contents of a byte of memory.
//
// C Carry Flag Not affected
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 set
func (cpu *CPU) Ora(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: ORA $%04x\n", cpu.Registers.PC, address)
}
cpu.Registers.A = cpu.setZNFlags(cpu.Registers.A | cpu.Memory.Fetch(address))
}
// This instructions is used to test if one or more bits are set in a
// target memory location. The mask pattern in A is ANDed with the
// value in memory to set or clear the zero flag, but the result is
// not kept. Bits 7 and 6 of the value from memory are copied into the
// N and V flags.
//
// C Carry Flag Not affected
// Z Zero Flag Set if the result if the AND is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Set to bit 6 of the memory value
// N Negative Flag Set to bit 7 of the memory value
func (cpu *CPU) Bit(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: BIT $%04x\n", cpu.Registers.PC, address)
}
value := cpu.Memory.Fetch(address)
cpu.setZFlag(value & cpu.Registers.A)
cpu.Registers.P = Status(uint8(cpu.Registers.P) | (value & 0xc0))
}
func (cpu *CPU) addition(value uint16) {
orig := uint16(cpu.Registers.A)
if cpu.Registers.P&D == 0 {
result := cpu.setCFlagAddition(orig + value + uint16(cpu.Registers.P&C))
cpu.Registers.A = cpu.setZNFlags(uint8(cpu.setVFlagAddition(orig, value, result)))
} else {
low := uint16(orig&0x000f) + uint16(value&0x000f) + uint16(cpu.Registers.P&C)
high := uint16(orig&0x00f0) + uint16(value&0x00f0)
if low >= 0x000a {
low -= 0x000a
high += 0x0010
}
if high >= 0x00a0 {
high -= 0x00a0
}
result := cpu.setCFlagAddition(high | (low & 0x000f))
cpu.Registers.A = cpu.setZNFlags(uint8(cpu.setVFlagAddition(orig, value, result)))
}
}
// This instruction adds the contents of a memory location to the
// accumulator together with the carry bit. If overflow occurs the
// carry bit is set, this enables multiple byte addition to be
// performed.
//
// C Carry Flag Set if overflow in bit 7
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Set if sign bit is incorrect
// N Negative Flag Set if bit 7 set
func (cpu *CPU) Adc(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: ADC $%04x\n", cpu.Registers.PC, address)
}
value := uint16(cpu.Memory.Fetch(address))
cpu.addition(value)
}
// This instruction subtracts the contents of a memory location to the
// accumulator together with the not of the carry bit. If overflow
// occurs the carry bit is clear, this enables multiple byte
// subtraction to be performed.
//
// C Carry Flag Clear if overflow in bit 7
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Set if sign bit is incorrect
// N Negative Flag Set if bit 7 set
func (cpu *CPU) Sbc(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: SBC $%04x\n", cpu.Registers.PC, address)
}
value := uint16(cpu.Memory.Fetch(address))
if cpu.Registers.P&D == 0 {
value ^= 0xff
} else {
value = 0x99 - value
}
cpu.addition(value)
}
func (cpu *CPU) compare(address uint16, register uint8) {
value := uint16(cpu.Memory.Fetch(address)) ^ 0xff + 1
cpu.setZNFlags(uint8(cpu.setCFlagAddition(uint16(register) + value)))
}
// This instruction compares the contents of the accumulator with
// another memory held value and sets the zero and carry flags as
// appropriate.
//
// C Carry Flag Set if A >= M
// Z Zero Flag Set if A = M
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Cmp(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: CMP $%04x\n", cpu.Registers.PC, address)
}
cpu.compare(address, cpu.Registers.A)
}
// This instruction compares the contents of the X register with
// another memory held value and sets the zero and carry flags as
// appropriate.
//
// C Carry Flag Set if X >= M
// Z Zero Flag Set if X = M
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Cpx(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: CPX $%04x\n", cpu.Registers.PC, address)
}
cpu.compare(address, cpu.Registers.X)
}
// This instruction compares the contents of the Y register with
// another memory held value and sets the zero and carry flags as
// appropriate.
//
// C Carry Flag Set if Y >= M
// Z Zero Flag Set if Y = M
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Cpy(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: CPY $%04x\n", cpu.Registers.PC, address)
}
cpu.compare(address, cpu.Registers.Y)
}
// Adds one to the value held at a specified memory location setting
// the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if result is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Inc(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: INC $%04x\n", cpu.Registers.PC, address)
}
cpu.Memory.Store(address, cpu.setZNFlags(cpu.Memory.Fetch(address)+1))
}
func (cpu *CPU) increment(register *uint8) {
*register = cpu.setZNFlags(*register + 1)
}
// Adds one to the X register setting the zero and negative flags as
// appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if X is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of X is set
func (cpu *CPU) Inx() {
if cpu.decode {
fmt.Printf(" %04x: INX\n", cpu.Registers.PC)
}
cpu.increment(&cpu.Registers.X)
}
// Adds one to the Y register setting the zero and negative flags as
// appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if Y is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of Y is set
func (cpu *CPU) Iny() {
if cpu.decode {
fmt.Printf(" %04x: INY\n", cpu.Registers.PC)
}
cpu.increment(&cpu.Registers.Y)
}
// Subtracts one from the value held at a specified memory location
// setting the zero and negative flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if result is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Dec(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: DEC $%04x\n", cpu.Registers.PC, address)
}
cpu.Memory.Store(address, cpu.setZNFlags(cpu.Memory.Fetch(address)-1))
}
func (cpu *CPU) decrement(register *uint8) {
*register = cpu.setZNFlags(*register - 1)
}
// Subtracts one from the X register setting the zero and negative
// flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if X is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of X is set
func (cpu *CPU) Dex() {
if cpu.decode {
fmt.Printf(" %04x: DEX\n", cpu.Registers.PC)
}
cpu.decrement(&cpu.Registers.X)
}
// Subtracts one from the Y register setting the zero and negative
// flags as appropriate.
//
// C Carry Flag Not affected
// Z Zero Flag Set if Y is zero
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of Y is set
func (cpu *CPU) Dey() {
if cpu.decode {
fmt.Printf(" %04x: DEY\n", cpu.Registers.PC)
}
cpu.decrement(&cpu.Registers.Y)
}
type direction int
const (
left direction = iota
right
)
func (cpu *CPU) shift(direction direction, value uint8, store func(uint8)) {
c := Status(0)
switch direction {
case left:
c = Status((value & uint8(N)) >> 7)
value <<= 1
case right:
c = Status(value & uint8(C))
value >>= 1
}
cpu.Registers.P &= ^C
cpu.Registers.P |= c
store(cpu.setZNFlags(value))
}
// This operation shifts all the bits of the accumulator one bit
// left. Bit 0 is set to 0 and bit 7 is placed in the carry flag. The
// effect of this operation is to multiply the memory contents by 2
// (ignoring 2's complement considerations), setting the carry if the
// result will not fit in 8 bits.
//
// C Carry Flag Set to contents of old bit 7
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) AslA() {
if cpu.decode {
fmt.Printf(" %04x: ASL A\n", cpu.Registers.PC)
}
cpu.shift(left, cpu.Registers.A, func(value uint8) { cpu.Registers.A = value })
}
// This operation shifts all the bits of the memory contents one bit
// left. Bit 0 is set to 0 and bit 7 is placed in the carry flag. The
// effect of this operation is to multiply the memory contents by 2
// (ignoring 2's complement considerations), setting the carry if the
// result will not fit in 8 bits.
//
// C Carry Flag Set to contents of old bit 7
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Asl(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: ASL $%04x\n", cpu.Registers.PC, address)
}
cpu.shift(left, cpu.Memory.Fetch(address), func(value uint8) { cpu.Memory.Store(address, value) })
}
// Each of the bits in A is shift one place to the right. The bit that
// was in bit 0 is shifted into the carry flag. Bit 7 is set to zero.
//
// C Carry Flag Set to contents of old bit 0
// Z Zero Flag Set if result = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) LsrA() {
if cpu.decode {
fmt.Printf(" %04x: LSR A\n", cpu.Registers.PC)
}
cpu.shift(right, cpu.Registers.A, func(value uint8) { cpu.Registers.A = value })
}
// Each of the bits in M is shift one place to the right. The bit that
// was in bit 0 is shifted into the carry flag. Bit 7 is set to zero.
//
// C Carry Flag Set to contents of old bit 0
// Z Zero Flag Set if result = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Lsr(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: LSR $%04x\n", cpu.Registers.PC, address)
}
cpu.shift(right, cpu.Memory.Fetch(address), func(value uint8) { cpu.Memory.Store(address, value) })
}
func (cpu *CPU) rotate(direction direction, value uint8, store func(uint8)) {
c := Status(0)
switch direction {
case left:
c = Status(value & uint8(N) >> 7)
value = ((value << 1) & uint8(^C)) | uint8(cpu.Registers.P&C)
case right:
c = Status(value & uint8(C))
value = ((value >> 1) & uint8(^N)) | uint8((cpu.Registers.P&C)<<7)
}
cpu.Registers.P &= ^C
cpu.Registers.P |= c
store(cpu.setZNFlags(value))
}
// Move each of the bits in A one place to the left. Bit 0 is filled
// with the current value of the carry flag whilst the old bit 7
// becomes the new carry flag value.
//
// C Carry Flag Set to contents of old bit 7
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) RolA() {
if cpu.decode {
fmt.Printf(" %04x: ROL A\n", cpu.Registers.PC)
}
cpu.rotate(left, cpu.Registers.A, func(value uint8) { cpu.Registers.A = value })
}
// Move each of the bits in A one place to the left. Bit 0 is filled
// with the current value of the carry flag whilst the old bit 7
// becomes the new carry flag value.
//
// C Carry Flag Set to contents of old bit 7
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Rol(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: ROL $%04x\n", cpu.Registers.PC, address)
}
cpu.rotate(left, cpu.Memory.Fetch(address), func(value uint8) { cpu.Memory.Store(address, value) })
}
// Move each of the bits in A one place to the right. Bit 7 is filled
// with the current value of the carry flag whilst the old bit 0
// becomes the new carry flag value.
//
// C Carry Flag Set to contents of old bit 0
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) RorA() {
if cpu.decode {
fmt.Printf(" %04x: ROR A\n", cpu.Registers.PC)
}
cpu.rotate(right, cpu.Registers.A, func(value uint8) { cpu.Registers.A = value })
}
// Move each of the bits in M one place to the right. Bit 7 is filled
// with the current value of the carry flag whilst the old bit 0
// becomes the new carry flag value.
//
// C Carry Flag Set to contents of old bit 0
// Z Zero Flag Set if A = 0
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Set if bit 7 of the result is set
func (cpu *CPU) Ror(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: ROR $%04x\n", cpu.Registers.PC, address)
}
cpu.rotate(right, cpu.Memory.Fetch(address), func(value uint8) { cpu.Memory.Store(address, value) })
}
// Sets the program counter to the address specified by the operand.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Jmp(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: JMP $%04x\n", cpu.Registers.PC, address)
}
cpu.Registers.PC = address
}
// The JSR instruction pushes the address (minus one) of the return
// point on to the stack and then sets the program counter to the
// target memory address.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Jsr(address uint16) {
if cpu.decode {
fmt.Printf(" %04x: JSR $%04x\n", cpu.Registers.PC, address)
}
value := cpu.Registers.PC - 1
cpu.push16(value)
cpu.Registers.PC = address
}
// The RTS instruction is used at the end of a subroutine to return to
// the calling routine. It pulls the program counter (minus one) from
// the stack.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Rts() {
if cpu.decode {
fmt.Printf(" %04x: RTS\n", cpu.Registers.PC)
}
cpu.Registers.PC = cpu.pull16() + 1
}
func (cpu *CPU) branch(address uint16, condition func() bool, cycles *uint16) {
if condition() {
*cycles++
if !SamePage(cpu.Registers.PC, address) {
*cycles++
}
cpu.Registers.PC = address
}
}
// If the carry flag is clear then add the relative displacement to
// the program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bcc(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BCC $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&C == 0 }, cycles)
}
// If the carry flag is set then add the relative displacement to the
// program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bcs(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BCS $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&C != 0 }, cycles)
}
// If the zero flag is set then add the relative displacement to the
// program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Beq(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BEQ $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&Z != 0 }, cycles)
}
// If the negative flag is set then add the relative displacement to
// the program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bmi(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BMI $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&N != 0 }, cycles)
}
// If the zero flag is clear then add the relative displacement to the
// program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bne(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BNE $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&Z == 0 }, cycles)
}
// If the negative flag is clear then add the relative displacement to
// the program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bpl(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BPL $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&N == 0 }, cycles)
}
// If the overflow flag is clear then add the relative displacement to
// the program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bvc(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BVC $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&V == 0 }, cycles)
}
// If the overflow flag is set then add the relative displacement to
// the program counter to cause a branch to a new location.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Bvs(address uint16, cycles *uint16) {
if cpu.decode {
fmt.Printf(" %04x: BVS $%04x\n", cpu.Registers.PC, address)
}
cpu.branch(address, func() bool { return cpu.Registers.P&V != 0 }, cycles)
}
// Set the carry flag to zero.
//
// C Carry Flag Set to 0
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Clc() {
if cpu.decode {
fmt.Printf(" %04x: CLC\n", cpu.Registers.PC)
}
cpu.Registers.P &^= C
}
// Set the decimal mode flag to zero.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Set to 0
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Cld() {
if cpu.decode {
fmt.Printf(" %04x: CLD\n", cpu.Registers.PC)
}
cpu.Registers.P &^= D
}
// Clears the interrupt disable flag allowing normal interrupt
// requests to be serviced.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Set to 0
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Cli() {
if cpu.decode {
fmt.Printf(" %04x: CLI\n", cpu.Registers.PC)
}
cpu.Registers.P &^= I
}
// Clears the interrupt disable flag allowing normal interrupt
// requests to be serviced.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Set to 0
// N Negative Flag Not affected
func (cpu *CPU) Clv() {
if cpu.decode {
fmt.Printf(" %04x: CLV\n", cpu.Registers.PC)
}
cpu.Registers.P &^= V
}
// Set the carry flag to one.
//
// C Carry Flag Set to 1
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Sec() {
if cpu.decode {
fmt.Printf(" %04x: SEC\n", cpu.Registers.PC)
}
cpu.Registers.P |= C
}
// Set the decimal mode flag to one.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Set to 1
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Sed() {
if cpu.decode {
fmt.Printf(" %04x: SED\n", cpu.Registers.PC)
}
cpu.Registers.P |= D
}
// Set the interrupt disable flag to one.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Set to 1
// D Decimal Mode Flag Not affected
// B Break Command Not affected
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Sei() {
if cpu.decode {
fmt.Printf(" %04x: SEI\n", cpu.Registers.PC)
}
cpu.Registers.P |= I
}
// The BRK instruction forces the generation of an interrupt
// request. The program counter and processor status are pushed on the
// stack then the IRQ interrupt vector at $FFFE/F is loaded into the
// PC and the break flag in the status set to one.
//
// C Carry Flag Not affected
// Z Zero Flag Not affected
// I Interrupt Disable Not affected
// D Decimal Mode Flag Not affected
// B Break Command Set to 1
// V Overflow Flag Not affected
// N Negative Flag Not affected
func (cpu *CPU) Brk() {
if cpu.decode {
fmt.Printf(" %04x: BRK\n", cpu.Registers.PC)
}
cpu.Registers.PC++
cpu.push16(cpu.Registers.PC)
cpu.push(uint8(cpu.Registers.P | B))
cpu.Registers.P |= I
low := cpu.Memory.Fetch(0xfffe)
high := cpu.Memory.Fetch(0xffff)
cpu.Registers.PC = (uint16(high) << 8) | uint16(low)
}
// The RTI instruction is used at the end of an interrupt processing
// routine. It pulls the processor flags from the stack followed by
// the program counter.
//
// C Carry Flag Set from stack
// Z Zero Flag Set from stack
// I Interrupt Disable Set from stack
// D Decimal Mode Flag Set from stack
// B Break Command Set from stack
// V Overflow Flag Set from stack
// N Negative Flag Set from stack
func (cpu *CPU) Rti() {
if cpu.decode {
fmt.Printf(" %04x: RTI\n", cpu.Registers.PC)
}
cpu.Registers.P = Status(cpu.pull())
cpu.Registers.PC = cpu.pull16()
}
package m65go2
// Represents opcodes for the 6502 CPU
type OpCode uint8
// Represents an instruction for the 6502 CPU. The Exec field
// implements the instruction and returns the total clock cycles to be
// consumed by the instruction.
type Instruction struct {
OpCode OpCode
Exec func(*CPU) (cycles uint16)
}
// Stores instructions understood by the 6502 CPU, indexed by opcode.
type InstructionTable map[OpCode]Instruction
// Returns a new, empty InstructionTable
func NewInstructionTable() InstructionTable {
instructions := make(map[OpCode]Instruction)
return instructions
}
// Adds an instruction to the InstructionTable
func (instructions InstructionTable) AddInstruction(inst Instruction) {
instructions[inst.OpCode] = inst
}
// Removes any instruction with the given opcode
func (instructions InstructionTable) RemoveInstruction(opcode OpCode) {
delete(instructions, opcode)
}
// Adds the 6502 CPU's instruction set to the InstructionTable.
func (instructions InstructionTable) InitInstructions() {
// LDA
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xa9,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Lda(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xa5,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Lda(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0xb5,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Lda(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xad,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Lda(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0xbd,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Lda(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0xb9,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Lda(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0xa1,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Lda(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0xb1,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Lda(cpu.indirectIndexedAddress(&cycles))
return
}})
// LDX
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xa2,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Ldx(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xa6,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Ldx(cpu.zeroPageAddress())
return
}})
// Zero Page,Y
instructions.AddInstruction(Instruction{
OpCode: 0xb6,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ldx(cpu.zeroPageIndexedAddress(cpu.Registers.Y))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xae,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ldx(cpu.absoluteAddress())
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0xbe,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ldx(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// LDY
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xa0,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Ldy(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xa4,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Ldy(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0xb4,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ldy(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xac,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ldy(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0xbc,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ldy(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// STA
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x85,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Sta(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x95,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sta(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x8d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sta(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x9d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Sta(cpu.absoluteIndexedAddress(cpu.Registers.X, nil))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0x99,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Sta(cpu.absoluteIndexedAddress(cpu.Registers.Y, nil))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0x81,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Sta(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0x91,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Sta(cpu.indirectIndexedAddress(&cycles))
cycles = 6
return
}})
// STX
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x86,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Stx(cpu.zeroPageAddress())
return
}})
// Zero Page,Y
instructions.AddInstruction(Instruction{
OpCode: 0x96,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Stx(cpu.zeroPageIndexedAddress(cpu.Registers.Y))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x8e,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Stx(cpu.absoluteAddress())
return
}})
// STY
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x84,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Sty(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x94,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sty(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x8c,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sty(cpu.absoluteAddress())
return
}})
// TAX
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xaa,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Tax()
return
}})
// TAY
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xa8,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Tay()
return
}})
// TXA
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x8a,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Txa()
return
}})
// TYA
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x98,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Tya()
return
}})
// TSX
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xba,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Tsx()
return
}})
// TXS
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x9a,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Txs()
return
}})
// PHA
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x48,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Pha()
return
}})
// PHP
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x08,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Php()
return
}})
// PLA
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x68,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Pla()
return
}})
// PLP
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x28,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Plp()
return
}})
// AND
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0x29,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.And(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x25,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.And(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x35,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.And(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x2d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.And(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x3d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.And(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0x39,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.And(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0x21,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.And(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0x31,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.And(cpu.indirectIndexedAddress(&cycles))
return
}})
// EOR
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0x49,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Eor(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x45,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Eor(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x55,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Eor(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x4d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Eor(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x5d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Eor(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0x59,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Eor(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0x41,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Eor(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0x51,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Eor(cpu.indirectIndexedAddress(&cycles))
return
}})
// ORA
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0x09,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Ora(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x05,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Ora(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x15,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ora(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x0d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ora(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x1d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ora(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0x19,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Ora(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0x01,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Ora(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0x11,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Ora(cpu.indirectIndexedAddress(&cycles))
return
}})
// BIT
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x24,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Bit(cpu.zeroPageAddress())
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x2c,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Bit(cpu.absoluteAddress())
return
}})
// ADC
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0x69,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Adc(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x65,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Adc(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x75,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Adc(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x6d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Adc(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x7d,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Adc(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0x79,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Adc(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0x61,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Adc(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0x71,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Adc(cpu.indirectIndexedAddress(&cycles))
return
}})
// SBC
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xe9,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Sbc(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xe5,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Sbc(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0xf5,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sbc(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xed,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sbc(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0xfd,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sbc(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0xf9,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Sbc(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0xe1,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Sbc(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0xf1,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Sbc(cpu.indirectIndexedAddress(&cycles))
return
}})
// CMP
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xc9,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Cmp(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xc5,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Cmp(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0xd5,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Cmp(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xcd,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Cmp(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0xdd,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Cmp(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
return
}})
// Absolute,Y
instructions.AddInstruction(Instruction{
OpCode: 0xd9,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Cmp(cpu.absoluteIndexedAddress(cpu.Registers.Y, &cycles))
return
}})
// (Indirect,X)
instructions.AddInstruction(Instruction{
OpCode: 0xc1,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Cmp(cpu.indexedIndirectAddress())
return
}})
// (Indirect),Y
instructions.AddInstruction(Instruction{
OpCode: 0xd1,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Cmp(cpu.indirectIndexedAddress(&cycles))
return
}})
// CPX
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xe0,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Cpx(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xe4,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Cpx(cpu.zeroPageAddress())
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xec,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Cpx(cpu.absoluteAddress())
return
}})
// CPY
// Immediate
instructions.AddInstruction(Instruction{
OpCode: 0xc0,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Cpy(cpu.immediateAddress())
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xc4,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Cpy(cpu.zeroPageAddress())
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xcc,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 4
cpu.Cpy(cpu.absoluteAddress())
return
}})
// INC
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xe6,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Inc(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0xf6,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Inc(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xee,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Inc(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0xfe,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Inc(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
cycles = 7
return
}})
// INX
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xe8,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Inx()
return
}})
// INY
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xc8,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Iny()
return
}})
// DEC
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0xc6,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Dec(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0xd6,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Dec(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0xce,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Dec(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0xde,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Dec(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
cycles = 7
return
}})
// DEX
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xca,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Dex()
return
}})
// DEY
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x88,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Dey()
return
}})
// ASL
// Accumulator
instructions.AddInstruction(Instruction{
OpCode: 0x0a,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.AslA()
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x06,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Asl(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x16,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Asl(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x0e,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Asl(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x1e,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Asl(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
cycles = 7
return
}})
// LSR
// Accumulator
instructions.AddInstruction(Instruction{
OpCode: 0x4a,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.LsrA()
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x46,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Lsr(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x56,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Lsr(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x4e,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Lsr(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x5e,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Lsr(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
cycles = 7
return
}})
// ROL
// Accumulator
instructions.AddInstruction(Instruction{
OpCode: 0x2a,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.RolA()
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x26,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Rol(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x36,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Rol(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x2e,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Rol(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x3e,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Rol(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
cycles = 7
return
}})
// ROR
// Accumulator
instructions.AddInstruction(Instruction{
OpCode: 0x6a,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.RorA()
return
}})
// Zero Page
instructions.AddInstruction(Instruction{
OpCode: 0x66,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Ror(cpu.zeroPageAddress())
return
}})
// Zero Page,X
instructions.AddInstruction(Instruction{
OpCode: 0x76,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Ror(cpu.zeroPageIndexedAddress(cpu.Registers.X))
return
}})
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x6e,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Ror(cpu.absoluteAddress())
return
}})
// Absolute,X
instructions.AddInstruction(Instruction{
OpCode: 0x7e,
Exec: func(cpu *CPU) (cycles uint16) {
cpu.Ror(cpu.absoluteIndexedAddress(cpu.Registers.X, &cycles))
cycles = 7
return
}})
// JMP
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x4c,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 3
cpu.Jmp(cpu.absoluteAddress())
return
}})
// Indirect
instructions.AddInstruction(Instruction{
OpCode: 0x6c,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 5
cpu.Jmp(cpu.indirectAddress())
return
}})
// JSR
// Absolute
instructions.AddInstruction(Instruction{
OpCode: 0x20,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Jsr(cpu.absoluteAddress())
return
}})
// RTS
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x60,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Rts()
return
}})
// BCC
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0x90,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bcc(cpu.relativeAddress(), &cycles)
return
}})
// BCS
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0xb0,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bcs(cpu.relativeAddress(), &cycles)
return
}})
// BEQ
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0xf0,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Beq(cpu.relativeAddress(), &cycles)
return
}})
// BMI
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0x30,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bmi(cpu.relativeAddress(), &cycles)
return
}})
// BNE
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0xd0,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bne(cpu.relativeAddress(), &cycles)
return
}})
// BPL
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0x10,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bpl(cpu.relativeAddress(), &cycles)
return
}})
// BVC
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0x50,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bvc(cpu.relativeAddress(), &cycles)
return
}})
// BVS
// Relative
instructions.AddInstruction(Instruction{
OpCode: 0x70,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Bvs(cpu.relativeAddress(), &cycles)
return
}})
// CLC
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x18,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Clc()
return
}})
// CLD
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xd8,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Cld()
return
}})
// CLI
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x58,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Cli()
return
}})
// CLV
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xb8,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Clv()
return
}})
// SEC
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x38,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Sec()
return
}})
// SED
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xf8,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Sed()
return
}})
// SEI
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x78,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
cpu.Sei()
return
}})
// BRK
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x00,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 7
cpu.Brk()
return
}})
// NOP
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0xea,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 2
return
}})
// RTI
// Implied
instructions.AddInstruction(Instruction{
OpCode: 0x40,
Exec: func(cpu *CPU) (cycles uint16) {
cycles = 6
cpu.Rti()
return
}})
}
package m65go2
import (
"io"
"os"
)
// Represents the RAM memory available to the 6502 CPU. Stores 8-bit
// values using a 16-bit address for a total of 65,536 possible 8-bit
// values.
type Memory interface {
Reset() // Sets all memory locations to zero
Fetch(address uint16) (value uint8) // Returns the value stored at the given memory address
Store(address uint16, value uint8) (oldValue uint8) // Stores the value at the given memory address
}
// Represents the 6502 CPU's memory using a static array of uint8's.
type BasicMemory [65536]uint8
// Returns a pointer to a new BasicMemory with all memory initialized
// to zero.
func NewBasicMemory() *BasicMemory {
return &BasicMemory{}
}
// Resets all memory locations to zero
func (mem *BasicMemory) Reset() {
for i := range mem {
mem[i] = 0
}
}
// Returns the value stored at the given memory address
func (mem *BasicMemory) Fetch(address uint16) (value uint8) {
value = mem[address]
return
}
// Stores the value at the given memory address
func (mem *BasicMemory) Store(address uint16, value uint8) (oldValue uint8) {
oldValue = mem[address]
mem[address] = value
return
}
func (mem *BasicMemory) load(path string) {
fi, err := os.Open(path)
if err != nil {
panic(err)
}
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
total := 0
buf := make([]byte, 65536)
for {
n, err := fi.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
total++
}
for i, b := range buf {
if i+1 == total {
break
}
mem[i] = b
}
return
}
// Returns true iff the two addresses are located in the same page in
// memory. Two addresses are on the same page if their high bytes are
// both the same, i.e. 0x0101 and 0x0103 are on the same page but
// 0x0101 and 0203 are not.
func SamePage(addr1 uint16, addr2 uint16) bool {
return (addr1^addr2)>>8 == 0
}