fixes for IME instructions and time

This commit is contained in:
Colby 2016-07-23 23:09:31 +10:00
parent c0780010a5
commit db5044effa
3 changed files with 21 additions and 16 deletions

View file

@ -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

View file

@ -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

View file

@ -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