Skip to content

Commit efb9e42

Browse files
committed
Optimize Cartridge::Mbc1
Closes: sacckey#23 Having to call a proc for every memory access isn't ideal, that quite a bit of overhead. If instead we use a `case` statement with only immediate values and a few bitwise operations we can let YJIT generate very efficient code. two runs on main with ruby 3.4.1 / YJIT: ``` Ruby: 3.4.1 YJIT: true 1: 4.051815 sec 2: 3.989457 sec 3: 3.963555 sec FPS: 374.849216902501 Ruby: 3.4.1 YJIT: true 1: 3.872855 sec 2: 3.943231 sec 3: 4.024268 sec FPS: 380.05620440064547 ``` On this branch: ``` Ruby: 3.4.1 YJIT: true 1: 3.625805 sec 2: 3.615032 sec 3: 3.572852 sec FPS: 416.1392102177157 Ruby: 3.4.1 YJIT: true 1: 3.543953 sec 2: 3.520738 sec 3: 3.506004 sec FPS: 425.70521616601366 ```
1 parent 7587f86 commit efb9e42

1 file changed

Lines changed: 34 additions & 52 deletions

File tree

lib/rubyboy/cartridge/mbc1.rb

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,65 +10,47 @@ def initialize(rom, ram)
1010
@ram_bank = 0
1111
@ram_enable = false
1212
@ram_banking_mode = false
13-
14-
@read_methods = Array.new(0xc000)
15-
@write_methods = Array.new(0xc000)
16-
17-
set_methods
1813
end
1914

20-
def set_methods
21-
0xc000.times do |addr|
22-
@read_methods[addr] =
23-
case addr
24-
when 0x0000..0x3fff then -> { @rom.data[addr] }
25-
when 0x4000..0x7fff then -> { @rom.data[addr + (@rom_bank - 1) * 0x4000] }
26-
when 0xa000..0xbfff
27-
lambda do
28-
if @ram_enable
29-
if @ram_banking_mode
30-
@ram.eram[addr - 0xa000 + @ram_bank * 0x800]
31-
else
32-
@ram.eram[addr - 0xa000]
33-
end
34-
else
35-
0xff
36-
end
37-
end
38-
end
39-
end
40-
41-
0xc000.times do |addr|
42-
@write_methods[addr] =
43-
case addr
44-
when 0x0000..0x1fff then ->(value) { @ram_enable = value & 0x0f == 0x0a }
45-
when 0x2000..0x3fff
46-
lambda do |value|
47-
@rom_bank = value & 0x1f
48-
@rom_bank = 1 if @rom_bank == 0
49-
end
50-
when 0x4000..0x5fff then ->(value) { @ram_bank = value & 0x03 }
51-
when 0x6000..0x7fff then ->(value) { @ram_banking_mode = value & 0x01 == 0x01 }
52-
when 0xa000..0xbfff
53-
lambda do |value|
54-
if @ram_enable
55-
if @ram_banking_mode
56-
@ram.eram[addr - 0xa000 + @ram_bank * 0x800] = value
57-
else
58-
@ram.eram[addr - 0xa000] = value
59-
end
60-
end
61-
end
15+
def read_byte(addr)
16+
case (addr >> 12)
17+
when 0x0, 0x1, 0x2, 0x3
18+
@rom.data[addr]
19+
when 0x4, 0x5, 0x6, 0x7
20+
@rom.data[addr + ((@rom_bank - 1) << 14)]
21+
when 0xa, 0xb
22+
if @ram_enable
23+
if @ram_banking_mode
24+
@ram.eram[addr - 0xa000 + (@ram_bank << 11)]
25+
else
26+
@ram.eram[addr - 0xa000]
6227
end
28+
else
29+
0xff
30+
end
6331
end
6432
end
6533

66-
def read_byte(addr)
67-
@read_methods[addr].call
68-
end
69-
7034
def write_byte(addr, value)
71-
@write_methods[addr].call(value)
35+
case addr >> 12
36+
when 0x0, 0x1
37+
@ram_enable = value & 0x0f == 0x0a
38+
when 0x2, 0x3
39+
@rom_bank = value & 0x1f
40+
@rom_bank = 1 if @rom_bank == 0
41+
when 0x4, 0x5
42+
@ram_bank = value & 0x03
43+
when 0x6, 0x7
44+
@ram_banking_mode = value & 0x01 == 0x01
45+
when 0xa, 0xb
46+
if @ram_enable
47+
if @ram_banking_mode
48+
@ram.eram[addr - 0xa000 + @ram_bank * 0x800] = value
49+
else
50+
@ram.eram[addr - 0xa000] = value
51+
end
52+
end
53+
end
7254
end
7355
end
7456
end

0 commit comments

Comments
 (0)