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 }