Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 78 additions & 59 deletions lib/rubyboy/bus.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,74 +11,93 @@ def initialize(ppu, rom, ram, mbc, timer, interrupt, joypad, apu)
@apu = apu
@interrupt = interrupt
@timer = timer
end

def read_byte(addr)
case addr >> 12
when 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb
return @mbc.read_byte(addr)
when 0x8, 0x9
return @ppu.read_byte(addr)
when 0xc
return @ram.wram1[addr - 0xc000]
when 0xd
return @ram.wram2[addr - 0xd000]
when 0xf
case addr >> 8
when 0xfe
return @ppu.read_byte(addr) if addr <= 0xfe9f
when 0xff
last_byte = addr & 0xFF

@read_methods = Array.new(0x10000)
@write_methods = Array.new(0x10000)
case last_byte
when 0x00
return @joypad.read_byte(addr)
when 0x04, 0x05, 0x06, 0x07
return @timer.read_byte(addr)
when 0x0f
return @interrupt.read_byte(addr)
when 0x46
return @ppu.read_byte(addr)
when 0xff
return @interrupt.read_byte(addr)
end

set_methods
end
return @apu.read_byte(addr) if last_byte <= 0x26 && last_byte >= 0x10
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor detail, but since it was originally written as when 0xff10..0xff26, it might be more readable to write it starting with the smaller value, like if last_byte >= 0x10 && last_byte <= 0x26.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was done this way for performance reasons. Almost all values are >= 0x10 few <= 0x26, so it avoid a comparison in most cases.

If Ruby had a very advanced optimizing compiler that wouldn't be needed, but it's not the case yet.

But if you fell very strongly about it, I can change that.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, got it!

I don't have a strong opinion, so it's fine as is.


def set_methods
0x10000.times do |addr|
case addr
when 0x0000..0x7fff
@read_methods[addr] = -> { @mbc.read_byte(addr) }
@write_methods[addr] = ->(value) { @mbc.write_byte(addr, value) }
when 0x8000..0x9fff
@read_methods[addr] = -> { @ppu.read_byte(addr) }
@write_methods[addr] = ->(value) { @ppu.write_byte(addr, value) }
when 0xa000..0xbfff
@read_methods[addr] = -> { @mbc.read_byte(addr) }
@write_methods[addr] = ->(value) { @mbc.write_byte(addr, value) }
when 0xc000..0xcfff
@read_methods[addr] = -> { @ram.wram1[addr - 0xc000] }
@write_methods[addr] = ->(value) { @ram.wram1[addr - 0xc000] = value }
when 0xd000..0xdfff
@read_methods[addr] = -> { @ram.wram2[addr - 0xd000] }
@write_methods[addr] = ->(value) { @ram.wram2[addr - 0xd000] = value }
when 0xfe00..0xfe9f
@read_methods[addr] = -> { @ppu.read_byte(addr) }
@write_methods[addr] = ->(value) { @ppu.write_byte(addr, value) }
when 0xff00
@read_methods[addr] = -> { @joypad.read_byte(addr) }
@write_methods[addr] = ->(value) { @joypad.write_byte(addr, value) }
when 0xff04..0xff07
@read_methods[addr] = -> { @timer.read_byte(addr) }
@write_methods[addr] = ->(value) { @timer.write_byte(addr, value) }
when 0xff0f
@read_methods[addr] = -> { @interrupt.read_byte(addr) }
@write_methods[addr] = ->(value) { @interrupt.write_byte(addr, value) }
when 0xff10..0xff26
@read_methods[addr] = -> { @apu.read_byte(addr) }
@write_methods[addr] = ->(value) { @apu.write_byte(addr, value) }
when 0xff30..0xff3f
@read_methods[addr] = -> { @apu.read_byte(addr) }
@write_methods[addr] = ->(value) { @apu.write_byte(addr, value) }
when 0xff46
@read_methods[addr] = -> { @ppu.read_byte(addr) }
@write_methods[addr] = ->(value) { 0xa0.times { |i| write_byte(0xfe00 + i, read_byte((value << 8) + i)) } }
when 0xff40..0xff4b
@read_methods[addr] = -> { @ppu.read_byte(addr) }
@write_methods[addr] = ->(value) { @ppu.write_byte(addr, value) }
when 0xff80..0xfffe
@read_methods[addr] = -> { @ram.hram[addr - 0xff80] }
@write_methods[addr] = ->(value) { @ram.hram[addr - 0xff80] = value }
when 0xffff
@read_methods[addr] = -> { @interrupt.read_byte(addr) }
@write_methods[addr] = ->(value) { @interrupt.write_byte(addr, value) }
else
@read_methods[addr] = -> { 0xff }
@write_methods[addr] = ->(_value) {}
return @apu.read_byte(addr) if last_byte <= 0x3f && last_byte >= 0x30

return @ppu.read_byte(addr) if last_byte <= 0x4b && last_byte >= 0x40

return @ram.hram[addr - 0xff80] if last_byte <= 0xfe && last_byte >= 0x80
end
end
end

def read_byte(addr)
@read_methods[addr].call
0xff
end

def write_byte(addr, value)
@write_methods[addr].call(value)
case addr >> 12
when 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb
return @mbc.write_byte(addr, value)
when 0x8, 0x9
return @ppu.write_byte(addr, value)
when 0xc
return @ram.wram1[addr - 0xc000] = value
when 0xd
return @ram.wram2[addr - 0xd000] = value
when 0xf
case addr >> 8
when 0xfe
return @ppu.write_byte(addr, value) if addr <= 0xfe9f
when 0xff
last_byte = addr & 0xFF

case last_byte
when 0x00
return @joypad.write_byte(addr, value)
when 0x04, 0x05, 0x06, 0x07
return @timer.write_byte(addr, value)
when 0x0f
return @interrupt.write_byte(addr, value)
when 0x46
0xa0.times { |i| write_byte(0xfe00 + i, read_byte((value << 8) + i)) }
return
when 0xff
return @interrupt.write_byte(addr, value)
end

return @apu.write_byte(addr, value) if last_byte <= 0x26 && last_byte >= 0x10

return @apu.write_byte(addr, value) if last_byte <= 0x3f && last_byte >= 0x30

return @ppu.write_byte(addr, value) if last_byte <= 0x4b && last_byte >= 0x40

return @ram.hram[addr - 0xff80] = value if last_byte <= 0xfe && last_byte >= 0x80
end
end

nil
end

def read_word(addr)
Expand Down
Loading