diff --git a/lib/waterfoul/cpu.rb b/lib/waterfoul/cpu.rb index 06c32cf..749f88e 100644 --- a/lib/waterfoul/cpu.rb +++ b/lib/waterfoul/cpu.rb @@ -65,6 +65,7 @@ module Waterfoul @a = @b = @c = @d = @e = @f = @h = @l = @f = 0x00 @m = 0 @timer = Timer.new + @ime = false end # This method emulates the CPU cycle process. Each instruction is @@ -72,13 +73,9 @@ module Waterfoul # This processes repeats infinitly until the process is closed def step reset_tick - if halted? - halt_step - else - serve_interrupt if @ime - instruction_byte = fetch_instruction - perform_instruction instruction_byte - end + serve_interrupt if @ime + instruction_byte = fetch_instruction + perform_instruction instruction_byte @timer.tick @m end @@ -107,7 +104,7 @@ module Waterfoul raise 'instruction not found' if operation.nil? # perform the instruction self.public_send operation - @m = instruction_cycle_time instruction + @m = instruction_cycle_time(instruction) * 4 end # fetch the next byte to be executed from memory and increment the program @@ -123,7 +120,9 @@ module Waterfoul # 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 @prefix_cb + CB_OPCODE_TIMINGS[@prefix_cb] + elsif @branched OPCODE_CONDITIONAL_TIMINGS[instruction] else OPCODE_TIMINGS[instruction] @@ -137,24 +136,30 @@ module Waterfoul # master disable interrupts @ime = false push_onto_stack @pc - @m = 20 - # point to instruction which handles appropiate interrupt + if_reg = $mmu.read_byte 0xFF0F case interrupt when Interrupt::INTERRUPT_VBLANK @pc = 0x40 + $mmu.write_byte(0xFF0F, if_reg & 0xFE) when Interrupt::INTERRUPT_LCDSTAT @pc = 0x48 + $mmu.write_byte(0xFF0F, if_reg & 0xFD) when Interrupt::INTERRUPT_TIMER @pc = 0x50 + $mmu.write_byte(0xFF0F, if_reg & 0xFB) when Interrupt::INTERRUPT_SERIAL @pc = 0x58 + $mmu.write_byte(0xFF0F, if_reg & 0xF7) when Interrupt::INTERRUPT_JOYPAD @pc = 0x60 + $mmu.write_byte(0xFF0F, if_reg & 0xEF) end + @m = 20 end # reset variables that are set on every instruction def reset_tick + @prefix_cb = false @branched = false @m = 0 end diff --git a/lib/waterfoul/instructions/misc.rb b/lib/waterfoul/instructions/misc.rb index 29f8264..8143d02 100644 --- a/lib/waterfoul/instructions/misc.rb +++ b/lib/waterfoul/instructions/misc.rb @@ -34,10 +34,10 @@ module Waterfoul # @flags - - - - def prefix_cb ins = $mmu.read_byte @pc + @prefix_cb = ins @pc += 1 opcode = Waterfoul::CPU::CB_OPCODE[ins] - #p "cb opcode: #{opcode}" self.public_send opcode end diff --git a/lib/waterfoul/timer.rb b/lib/waterfoul/timer.rb index 6540d6e..dff3ab9 100644 --- a/lib/waterfoul/timer.rb +++ b/lib/waterfoul/timer.rb @@ -1,6 +1,6 @@ module Waterfoul class Timer - DIV_INC_TIME = 255 # cycles + DIV_INC_TIME = 256 # cycles def initialize @div_cycles = 0 @@ -9,8 +9,6 @@ module Waterfoul end def tick(cycles = 0) - # increment TIMA and DIV register - @tima_cycles += cycles @div_cycles += cycles # incremnt DIV register if its time to inc_div_register if @div_cycles >= DIV_INC_TIME @@ -18,6 +16,8 @@ module Waterfoul @tima.update # dont bother if TIMA is not running if @tima.running? + # increment TIMA and DIV register + @tima_cycles += cycles frequency = @tima.frequency if @tima_cycles >= frequency inc_tima_register @@ -32,7 +32,7 @@ module Waterfoul tima = $mmu.read_byte 0xFF06 Interrupt.request_interrupt(Interrupt::INTERRUPT_TIMER) else - tima = (tima + 1) & 0xFF + tima += 1 end $mmu.write_byte 0xFF05, tima, hardware_operation: true