some code cleanup and documentation

This commit is contained in:
Colby 2016-07-05 19:03:49 +10:00
parent 9a1f2456ae
commit 932159d05f
2 changed files with 48 additions and 47 deletions

View file

@ -58,10 +58,7 @@ module Waterfoul
# other cpu flags # other cpu flags
attr_reader :ime, :stop attr_reader :ime, :stop
## # init CPU registers to 0
# Set the CPU to its initial state, the boot rom will then initialize
# the memory and registers to the approiate values before control is
# handed to the game cartridge
def initialize(options = {}) def initialize(options = {})
@pc = 0x0000 @pc = 0x0000
@sp = 0x0000 @sp = 0x0000
@ -69,49 +66,21 @@ module Waterfoul
@m = 0 @m = 0
end end
##
# This method emulates the CPU cycle process. Each instruction is # This method emulates the CPU cycle process. Each instruction is
# fetched from memory (pointed by the program counter). The value in memory is then # fetched from memory (pointed by the program counter) and executed.
# matched against an instruction from the set of opcodes. # This processes repeats infinitly until the process is closed
# (see instructions/opcode.rb) and executed. This processes repeats infinitly
# until the process is closed.
def step def step
if halt? reset_tick
if halted?
halt_step halt_step
end else
if !halt?
reset_switches
serve_interrupt if @ime serve_interrupt if @ime
instruction_byte = fetch_instruction instruction_byte = fetch_instruction
perform_instruction instruction_byte perform_instruction instruction_byte
end end
end end
def serve_interrupt def halted?
interrupt = Interrupt.serve_interrupt
if interrupt > 0
@ime = false
push_onto_stack @pc
@m = 10
end
case interrupt
when Interrupt::INTERRUPT_VBLANK
@pc = 0x40
when Interrupt::INTERRUPT_LCDSTAT
@pc = 0x48
when Interrupt::INTERRUPT_TIMER
@pc = 0x50
when Interrupt::INTERRUPT_SERIAL
@pc = 0x58
when Interrupt::INTERRUPT_JOYPAD
@pc = 0x60
end
end
def halt?
@halt == true @halt == true
end end
@ -130,28 +99,60 @@ module Waterfoul
@m = 2 @m = 2
end end
# Execute the instruction and
def perform_instruction(instruction) def perform_instruction(instruction)
operation = OPCODE[instruction] operation = OPCODE[instruction]
raise 'instruction not found' if operation.nil?
# perform the instruction # perform the instruction
self.public_send operation self.public_send operation
set_instruction_timing instruction @m = instruction_cycle_time instruction
end end
def fetch_instruction # fetch the next byte to be executed from memory and increment the program
# counter (except under particular circumstances, see interrupts)
def fetch_instruction(increment_pc = false)
instruction_byte = $mmu.read_byte @pc instruction_byte = $mmu.read_byte @pc
@pc = (@pc + 1) & 0xFFFF @pc = (@pc + 1) & 0xFFFF unless increment_pc
instruction_byte instruction_byte
end end
def set_instruction_timing(instruction) private
# get the number of cycles a instruction takes to execute. The times
# can be found in the instruction opcode table
def instruction_cycle_time(instruction)
if @branched if @branched
@m = OPCODE_CONDITIONAL_TIMINGS[instruction] OPCODE_CONDITIONAL_TIMINGS[instruction]
else else
@m = OPCODE_TIMINGS[instruction] OPCODE_TIMINGS[instruction]
end end
end end
def reset_switches def serve_interrupt
interrupt = Interrupt.serve_interrupt
# skip if there is no interrupt to serve
return if interrupt == Interrupt::INTERRUPT_NONE
# master disable interrupts
@ime = false
push_onto_stack @pc
@m = 10
# point to instruction which handles appropiate interrupt
case interrupt
when Interrupt::INTERRUPT_VBLANK
@pc = 0x40
when Interrupt::INTERRUPT_LCDSTAT
@pc = 0x48
when Interrupt::INTERRUPT_TIMER
@pc = 0x50
when Interrupt::INTERRUPT_SERIAL
@pc = 0x58
when Interrupt::INTERRUPT_JOYPAD
@pc = 0x60
end
end
# reset variables that are set on every instruction
def reset_tick
@branched = false @branched = false
@m = 0 @m = 0
end end

View file

@ -1,6 +1,6 @@
module Waterfoul module Waterfoul
# set the state of the emulator to the same state it is in after the boot rom is executed. # Set the state of the emulator after it has finished running the bootloader and ready to execute
# This helps us run the game program without needing to execute the boot rom every time # the game program. This lets us run the game program without needing to execute the boot rom every time
# the emulator is started. # the emulator is started.
class SkipBoot class SkipBoot
def self.set_state(cpu) def self.set_state(cpu)