class Rnes::Cpu
Constants
- INTERRUPTION_VECTOR_FOR_IRQ_OR_BRK
- INTERRUPTION_VECTOR_FOR_NMI
- INTERRUPTION_VECTOR_FOR_RESET
Attributes
@return [Rnes::CpuBus] bus
@return [Rnes::CpuRegisters]
Public Class Methods
@param [Rnes::CpuBus] bus @param [Rnes::InterruptLine] interrupt_line
# File lib/rnes/cpu.rb, line 22 def initialize(bus:, interrupt_line:) @branched = false @bus = bus @crossed = false @interrupt_line = interrupt_line @registers = ::Rnes::CpuRegisters.new end
Public Instance Methods
@note For logging. @return [Rnes::Operation]
# File lib/rnes/cpu.rb, line 32 def read_operation address = @registers.program_counter operation_code = read(address) ::Rnes::Operation.build(operation_code) end
# File lib/rnes/cpu.rb, line 38 def reset @registers.reset @registers.program_counter = read_word(INTERRUPTION_VECTOR_FOR_RESET) end
@return [Integer]
# File lib/rnes/cpu.rb, line 44 def step handle_interrupts operation = fetch_operation operand = fetch_operand_by(operation.addressing_mode) execute_operation( addressing_mode: operation.addressing_mode, operand: operand, operation_name: operation.name, ) cycles_count = operation.cycle + (@branched ? 1 : 0) + (@crossed ? 1 : 0) @branched = false @crossed = false cycles_count end
Private Instance Methods
@param [Integer] address
# File lib/rnes/cpu.rb, line 62 def branch(address) @branched = true @registers.program_counter = address end
@param [Symbol] addressing_mode @param [Integer, nil] operand @param [Symbol] operation_name @return [Integer]
# File lib/rnes/cpu.rb, line 71 def execute_operation(addressing_mode:, operand:, operation_name:) case operation_name when :ADC if addressing_mode == :immediate execute_operation_adc_for_immediate_addressing(operand) else execute_operation_adc_for_non_immediate_addressing(operand) end when :AND if addressing_mode == :immediate execute_operation_and_for_immediate_addressing(operand) else execute_operation_and_for_non_immediate_addressing(operand) end when :ASL if addressing_mode == :accumulator execute_operation_asl_for_accoumulator(operand) else execute_operation_asl_for_non_accumulator(operand) end when :BCC execute_operation_bcc(operand) when :BCS execute_operation_bcs(operand) when :BEQ execute_operation_beq(operand) when :BIT execute_operation_bit(operand) when :BMI execute_operation_bmi(operand) when :BNE execute_operation_bne(operand) when :BPL execute_operation_bpl(operand) when :BRK execute_operation_brk(operand) when :BVC execute_operation_bvc(operand) when :BVS execute_operation_bvs(operand) when :CLC execute_operation_clc(operand) when :CLD execute_operation_cld(operand) when :CLI execute_operation_cli(operand) when :CLV execute_operation_clv(operand) when :CMP if addressing_mode == :immediate execute_operation_cmp_for_immediate_addressing(operand) else execute_operation_cmp_for_non_immediate_addressing(operand) end when :CPX if addressing_mode == :immediate execute_operation_cpx_for_immediate_addressing(operand) else execute_operation_cpx_for_non_immediate_addressing(operand) end when :CPY if addressing_mode == :immediate execute_operation_cpy_for_immediate_addressing(operand) else execute_operation_cpy_for_non_immediate_addressing(operand) end when :DCP execute_operation_dcp(operand) when :DEC execute_operation_dec(operand) when :DEX execute_operation_dex(operand) when :DEY execute_operation_dey(operand) when :EOR if addressing_mode == :immediate execute_operation_eor_for_immediate_addressing(operand) else execute_operation_eor_for_non_immediate_addressing(operand) end when :INC execute_operation_inc(operand) when :INX execute_operation_inx(operand) when :INY execute_operation_iny(operand) when :ISB execute_operation_isb(operand) when :JMP execute_operation_jmp(operand) when :JSR execute_operation_jsr(operand) when :LAX execute_operation_lax(operand) when :LDA if addressing_mode == :immediate execute_operation_lda_for_immediate_addressing(operand) else execute_operation_lda_for_non_immediate_addressing(operand) end when :LDX if addressing_mode == :immediate execute_operation_ldx_for_immediate_addressing(operand) else execute_operation_ldx_for_non_immediate_addressing(operand) end when :LDY if addressing_mode == :immediate execute_operation_ldy_for_immediate_addressing(operand) else execute_operation_ldy_for_non_immediate_addressing(operand) end when :LSR if addressing_mode == :accumulator execute_operation_lsr_for_accumulator(operand) else execute_operation_lsr_for_non_accumulator(operand) end when :NOP execute_operation_nop(operand) when :NOPD execute_operation_nopd(operand) when :NOPI execute_operation_nopi(operand) when :ORA if addressing_mode == :immediate execute_operation_ora_for_immediate_addressing(operand) else execute_operation_ora_for_non_immediate_addressing(operand) end when :PHA execute_operation_pha(operand) when :PHP execute_operation_php(operand) when :PLA execute_operation_pla(operand) when :PLP execute_operation_plp(operand) when :RLA execute_operation_rla(operand) when :ROL if addressing_mode == :accumulator execute_operation_rol_for_accumulator(operand) else execute_operation_rol_for_non_accumulator(operand) end when :ROR if addressing_mode == :accumulator execute_operation_ror_for_accumulator(operand) else execute_operation_ror_for_non_accumulator(operand) end when :RRA execute_operation_rra(operand) when :RTI execute_operation_rti(operand) when :RTS execute_operation_rts(operand) when :SAX execute_operation_sax(operand) when :SBC if addressing_mode == :immediate execute_operation_sbc_for_immediate_addressing(operand) else execute_operation_sbc_for_non_immediate_addressing(operand) end when :SEC execute_operation_sec(operand) when :SED execute_operation_sed(operand) when :SEI execute_operation_sei(operand) when :SLO execute_operation_slo(operand) when :SRE execute_operation_sre(operand) when :STA execute_operation_sta(operand) when :STX execute_operation_stx(operand) when :STY execute_operation_sty(operand) when :TAX execute_operation_tax(operand) when :TAY execute_operation_tay(operand) when :TSX execute_operation_tsx(operand) when :TXA execute_operation_txa(operand) when :TXS execute_operation_txs(operand) when :TYA execute_operation_tya(operand) else raise ::Rnes::Errors::InvalidOperationError, "Invalid operation: #{operation_name}" end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 271 def execute_operation_adc_for_immediate_addressing(operand) result = operand + @registers.accumulator + @registers.carry_bit @registers.carry = result > 0xFF @registers.negative = result[7] == 1 @registers.overflow = (@registers.accumulator ^ operand)[7].zero? && !(@registers.accumulator ^ result)[7].zero? @registers.zero = (result & 0xFF).zero? @registers.accumulator = result & 0xFF end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 281 def execute_operation_adc_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_adc_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 287 def execute_operation_and_for_immediate_addressing(operand) result = operand & @registers.accumulator @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 295 def execute_operation_and_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_and_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 301 def execute_operation_asl_for_accoumulator(_operand) value = @registers.accumulator result = (value << 1) & 0xFF @registers.carry = value[7] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 311 def execute_operation_asl_for_non_accumulator(operand) value = read(operand) result = (value << 1) & 0xFF @registers.carry = value[7] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 321 def execute_operation_bcc(operand) unless @registers.carry? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 328 def execute_operation_bcs(operand) if @registers.carry? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 335 def execute_operation_beq(operand) if @registers.zero? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 342 def execute_operation_bit(operand) result = read(operand) @registers.overflow = result[6] == 1 @registers.negative = result[7] == 1 @registers.zero = (@registers.accumulator & result).zero? end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 350 def execute_operation_bmi(operand) if @registers.negative? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 357 def execute_operation_bne(operand) unless @registers.zero? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 364 def execute_operation_bpl(operand) unless @registers.negative? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 371 def execute_operation_brk(_operand) @registers.break = true @registers.program_counter += 1 push_word(@registers.program_counter) push(@registers.status) unless @registers.interrupt? @registers.interrupt = true @registers.program_counter = read_word(INTERRUPTION_VECTOR_FOR_IRQ_OR_BRK) end @registers.program_counter -= 1 end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 384 def execute_operation_bvc(operand) unless @registers.overflow? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 391 def execute_operation_bvs(operand) if @registers.overflow? branch(operand) end end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 398 def execute_operation_clc(_operand) @registers.carry = false end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 403 def execute_operation_cld(_operand) @registers.decimal = false end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 408 def execute_operation_cli(_operand) @registers.interrupt = false end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 413 def execute_operation_clv(_operand) @registers.overflow = false end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 418 def execute_operation_cmp_for_immediate_addressing(operand) result = @registers.accumulator - operand @registers.carry = result >= 0 @registers.negative = result[7] == 1 @registers.zero = (result & 0xFF).zero? end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 426 def execute_operation_cmp_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_cmp_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 432 def execute_operation_cpx_for_immediate_addressing(operand) result = @registers.index_x - operand @registers.carry = result >= 0 @registers.negative = result[7] == 1 @registers.zero = (result & 0xFF).zero? end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 440 def execute_operation_cpx_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_cpx_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 446 def execute_operation_cpy_for_immediate_addressing(operand) result = @registers.index_y - operand @registers.carry = result >= 0 @registers.negative = result[7] == 1 @registers.zero = (result & 0xFF).zero? end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 454 def execute_operation_cpy_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_cpy_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 460 def execute_operation_dcp(operand) result = (read(operand) - 1) & 0xFF sub_result = (@registers.accumulator - result) & 0x1FF @registers.negative = sub_result[7] == 1 @registers.zero = sub_result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 469 def execute_operation_dec(operand) result = (read(operand) - 1) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 477 def execute_operation_dex(_operand) result = (@registers.index_x - 1) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_x = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 485 def execute_operation_dey(_operand) result = (@registers.index_y - 1) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_y = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 493 def execute_operation_eor_for_immediate_addressing(operand) result = (operand ^ @registers.accumulator) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 501 def execute_operation_eor_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_eor_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 507 def execute_operation_inc(operand) result = (read(operand) + 1) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 515 def execute_operation_inx(_operand) result = (@registers.index_x + 1) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_x = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 523 def execute_operation_iny(_operand) result = (@registers.index_y + 1) & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_y = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 531 def execute_operation_isb(operand) value = (read(operand) + 1) & 0xFF result = (~value & 0xFF) + @registers.accumulator + @registers.carry_bit @registers.overflow = (@registers.accumulator ^ value)[7].zero? && !(@registers.accumulator ^ result)[7].zero? @registers.carry = result > 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result & 0xFF write(operand, value) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 543 def execute_operation_jmp(operand) @registers.program_counter = operand end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 548 def execute_operation_jsr(operand) push_word(@registers.program_counter - 1) @registers.program_counter = operand end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 554 def execute_operation_lax(operand) result = read(operand) @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result @registers.index_x = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 563 def execute_operation_lda_for_immediate_addressing(operand) @registers.negative = operand[7] == 1 @registers.zero = operand.zero? @registers.accumulator = operand end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 570 def execute_operation_lda_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_lda_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 576 def execute_operation_ldx_for_immediate_addressing(operand) @registers.negative = operand[7] == 1 @registers.zero = operand.zero? @registers.index_x = operand end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 583 def execute_operation_ldx_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_ldx_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 589 def execute_operation_ldy_for_immediate_addressing(operand) @registers.negative = operand[7] == 1 @registers.zero = operand.zero? @registers.index_y = operand end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 596 def execute_operation_ldy_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_ldy_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 602 def execute_operation_lsr_for_accumulator(_operand) value = @registers.accumulator result = value >> 1 @registers.carry = value[0] == 1 @registers.negative = false @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 612 def execute_operation_lsr_for_non_accumulator(operand) value = read(operand) result = value >> 1 @registers.carry = value[0] == 1 @registers.negative = false @registers.zero = result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 622 def execute_operation_nop(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 626 def execute_operation_nopd(_operand) @registers.program_counter += 1 end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 631 def execute_operation_nopi(_operand) @registers.program_counter += 2 end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 636 def execute_operation_ora_for_immediate_addressing(operand) result = @registers.accumulator | operand @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result & 0xFF end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 644 def execute_operation_ora_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_ora_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 650 def execute_operation_pha(_operand) push(@registers.accumulator) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 655 def execute_operation_php(_operand) push(@registers.status | 0x10) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 660 def execute_operation_pla(_operand) result = pop @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 668 def execute_operation_plp(_operand) @registers.status = pop & 0b11101111 @registers.reserved = true end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 674 def execute_operation_rla(operand) value = (read(operand) << 1) + @registers.carry_bit result = (value & @registers.accumulator) & 0xFF @registers.carry = value[8] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result write(operand, value & 0xFF) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 685 def execute_operation_rol_for_accumulator(_operand) value = @registers.accumulator result = ((value << 1) | @registers.carry_bit) & 0xFF @registers.carry = value[7] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 695 def execute_operation_rol_for_non_accumulator(operand) value = read(operand) result = ((value << 1) | @registers.carry_bit) & 0xFF @registers.carry = value[7] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 705 def execute_operation_ror_for_accumulator(_operand) value = @registers.accumulator result = ((value >> 1) | (@registers.carry_bit << 7)) @registers.carry = value[0] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 715 def execute_operation_ror_for_non_accumulator(operand) value = read(operand) result = ((value >> 1) | (@registers.carry_bit << 7)) @registers.carry = value[0] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 725 def execute_operation_rra(operand) read_value = read(operand) value = (read_value >> 1) | (@registers.carry_bit << 7) result = value + @registers.accumulator + read_value[0] @registers.carry = result > 0xFF @registers.overflow = (@registers.accumulator ^ value)[7].zero? && !(@registers.accumulator ^ result)[7].zero? @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result & 0xFF write(operand, value) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 738 def execute_operation_rti(_operand) @registers.status = pop @registers.program_counter = pop_word @registers.reserved = true end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 745 def execute_operation_rts(_operand) @registers.program_counter = pop_word @registers.program_counter += 1 end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 751 def execute_operation_sax(operand) result = @registers.accumulator & @registers.index_x write(operand, result) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 757 def execute_operation_sbc_for_immediate_addressing(operand) result = @registers.accumulator - operand - 1 + @registers.carry_bit @registers.overflow = ((@registers.accumulator ^ result) & 0x80 != 0 && ((@registers.accumulator ^ operand) & 0x80) != 0) @registers.carry = result >= 0 @registers.negative = result[7] == 1 @registers.zero = (result & 0xFF).zero? @registers.accumulator = result & 0xFF end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 767 def execute_operation_sbc_for_non_immediate_addressing(operand) operand = read(operand) execute_operation_sbc_for_immediate_addressing(operand) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 773 def execute_operation_sec(_operand) @registers.carry = true end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 778 def execute_operation_sed(_operand) @registers.decimal = true end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 783 def execute_operation_sei(_operand) @registers.interrupt = true end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 788 def execute_operation_slo(operand) read_value = read(operand) value = (read_value << 1) & 0xFF result = value | @registers.accumulator @registers.carry = read_value[7] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result write(operand, value) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 800 def execute_operation_sre(operand) read_value = read(operand) value = read_value >> 1 result = value ^ @registers.accumulator @registers.carry = read_value[0] == 1 @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result write(operand, value) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 812 def execute_operation_sta(operand) write(operand, @registers.accumulator) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 817 def execute_operation_stx(operand) write(operand, @registers.index_x) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 822 def execute_operation_sty(operand) write(operand, @registers.index_y) end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 827 def execute_operation_tax(_operand) result = @registers.accumulator @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_x = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 835 def execute_operation_tay(_operand) result = @registers.accumulator @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_y = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 843 def execute_operation_tsx(_operand) result = @registers.stack_pointer & 0xFF @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.index_x = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 851 def execute_operation_txa(_operand) result = @registers.index_x @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 859 def execute_operation_txs(_operand) @registers.stack_pointer = @registers.index_x + 0x100 end
@param [Integer] operand
# File lib/rnes/cpu.rb, line 864 def execute_operation_tya(_operand) result = @registers.index_y @registers.negative = result[7] == 1 @registers.zero = result.zero? @registers.accumulator = result end
@return [Integer]
# File lib/rnes/cpu.rb, line 872 def fetch address = @registers.program_counter value = read(address) @registers.program_counter += 1 value end
@param [Symbol] addressing_mode
# File lib/rnes/cpu.rb, line 880 def fetch_operand_by(addressing_mode) case addressing_mode when :absolute fetch_operand_by_absolute_addressing when :absolute_x fetch_operand_by_absolute_x_addressing when :absolute_y fetch_operand_by_absolute_y_addressing when :accumulator fetch_operand_by_accumulator_addressing when :immediate fetch_operand_by_immediate_addressing when :implied fetch_operand_by_implied_addressing when :indirect_absolute fetch_operand_by_indirect_absolute_addressing when :post_indexed_indirect fetch_operand_by_post_indexed_indirect_addressing when :pre_indexed_indirect fetch_operand_by_pre_indexed_indirect_addressing when :relative fetch_operand_by_relative_addressing when :zero_page fetch_operand_by_zero_page_addressing when :zero_page_x fetch_operand_by_zero_page_x_addressing when :zero_page_y fetch_operand_by_zero_page_y_addressing else raise ::Rnes::Errors::InvalidAddressingModeError, "Invalid addressing mode: #{addressing_mode}" end end
@return [Integer]
# File lib/rnes/cpu.rb, line 914 def fetch_operand_by_absolute_addressing fetch_word end
@return [Integer]
# File lib/rnes/cpu.rb, line 919 def fetch_operand_by_absolute_x_addressing base_address = fetch_word @crossed = (base_address & 0xFF00) != ((base_address + @registers.index_x) & 0xFF00) (base_address + @registers.index_x) & 0xFFFF end
@return [Integer]
# File lib/rnes/cpu.rb, line 926 def fetch_operand_by_absolute_y_addressing base_address = fetch_word @crossed = (base_address & 0xFF00) != ((base_address + @registers.index_y) & 0xFF00) (base_address + @registers.index_y) & 0xFFFF end
@return [nil]
# File lib/rnes/cpu.rb, line 933 def fetch_operand_by_accumulator_addressing end
@return [Integer]
# File lib/rnes/cpu.rb, line 937 def fetch_operand_by_immediate_addressing fetch end
@return [nil]
# File lib/rnes/cpu.rb, line 942 def fetch_operand_by_implied_addressing end
@note The address must not overlap a page boundary as a bug in the original 6502 prevents it from being fetched properly. @return [Integer]
# File lib/rnes/cpu.rb, line 947 def fetch_operand_by_indirect_absolute_addressing address = fetch_word low = read(address) high = read((address & 0xFF00) | ((address + 1) & 0xFF)) low + (high << 8) end
@return [Integer]
# File lib/rnes/cpu.rb, line 963 def fetch_operand_by_post_indexed_indirect_addressing base_address = fetch address = (read_word_with_wrap_around(base_address) + @registers.index_y) & 0xFFFF @crossed = (address & 0xFF00) != (base_address & 0xFF00) address end
@return [Integer]
# File lib/rnes/cpu.rb, line 955 def fetch_operand_by_pre_indexed_indirect_addressing base_address = (fetch + @registers.index_x) & 0xFF address = read_word_with_wrap_around(base_address) @crossed = (address & 0xFF00) != (base_address & 0xFF00) address end
@return [Integer]
# File lib/rnes/cpu.rb, line 971 def fetch_operand_by_relative_addressing int8 = fetch offset = int8 >= 0x80 ? int8 - 256 : int8 address = @registers.program_counter + offset @crossed = (address & 0xFF00) != (@registers.program_counter & 0xFF00) address end
@return [Integer]
# File lib/rnes/cpu.rb, line 980 def fetch_operand_by_zero_page_addressing fetch end
@return [Integer]
# File lib/rnes/cpu.rb, line 985 def fetch_operand_by_zero_page_x_addressing (fetch + @registers.index_x) & 0xFF end
@return [Integer]
# File lib/rnes/cpu.rb, line 990 def fetch_operand_by_zero_page_y_addressing (fetch + @registers.index_y) & 0xFF end
@return [Rnes::Operation]
# File lib/rnes/cpu.rb, line 995 def fetch_operation operation_code = fetch ::Rnes::Operation.build(operation_code) end
@return [Integer]
# File lib/rnes/cpu.rb, line 1001 def fetch_word fetch | (fetch << 8) end
# File lib/rnes/cpu.rb, line 1005 def handle_interrupts if @interrupt_line.nmi handle_nmi end if !@registers.interrupt? && @interrupt_line.irq handle_irq end end
# File lib/rnes/cpu.rb, line 1014 def handle_irq @interrupt_line.deassert_irq @registers.break = false push_word(@registers.program_counter) push(@registers.status) @registers.interrupt = true @registers.program_counter = read_word(INTERRUPTION_VECTOR_FOR_IRQ_OR_BRK) end
# File lib/rnes/cpu.rb, line 1023 def handle_nmi @interrupt_line.deassert_nmi @registers.break = false push_word(@registers.program_counter) push(@registers.status) @registers.interrupt = true @registers.program_counter = read_word(INTERRUPTION_VECTOR_FOR_NMI) end
@return [Integer] @raise [Rnes::Errors::StackPointerOverflowError]
# File lib/rnes/cpu.rb, line 1034 def pop if @registers.stack_pointer < 0x1FF @registers.stack_pointer += 1 else @registers.stack_pointer = 0x100 end read(@registers.stack_pointer) end
@return [Integer]
# File lib/rnes/cpu.rb, line 1044 def pop_word pop | pop << 8 end
@param [Integer] value @raise [Rnes::Errors::StackPointerOverflowError]
# File lib/rnes/cpu.rb, line 1050 def push(value) write(@registers.stack_pointer, value) if @registers.stack_pointer > 0x100 @registers.stack_pointer -= 1 else @registers.stack_pointer = 0x1FF end end
@param [Integer] value
# File lib/rnes/cpu.rb, line 1060 def push_word(value) push(value >> 8) push(value & 0xFF) end
@param [Integer] address @return [Integer]
# File lib/rnes/cpu.rb, line 1067 def read(address) @bus.read(address) end
@param [Integer] address @return [Integer]
# File lib/rnes/cpu.rb, line 1073 def read_word(address) read(address) | read((address + 1) & 0xFFFF) << 8 end
@param [Integer] byte Unsigned integer from 0x00 to 0xFF.
# File lib/rnes/cpu.rb, line 1078 def read_word_with_wrap_around(byte) low = read(byte) high = read((byte + 1) & 0xFF) low + (high << 8) end
@param [Integer] address @param [Integer] value
# File lib/rnes/cpu.rb, line 1086 def write(address, value) @bus.write(address, value) end