rubyboy 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubyboy/sdl'
4
+
5
+ module Rubyboy
6
+ class Audio
7
+ SAMPLE_RATE = 48000
8
+ SAMPLES = 512
9
+
10
+ def initialize
11
+ SDL.InitSubSystem(SDL::INIT_AUDIO)
12
+
13
+ desired = SDL::AudioSpec.new
14
+ desired[:freq] = SAMPLE_RATE
15
+ desired[:format] = SDL::AUDIO_F32SYS
16
+ desired[:channels] = 2
17
+ desired[:samples] = SAMPLES * 2
18
+
19
+ @device = SDL.OpenAudioDevice(nil, 0, desired, nil, 0)
20
+
21
+ SDL.PauseAudioDevice(@device, 0)
22
+ end
23
+
24
+ def queue(buffer)
25
+ sleep(0.001) while SDL.GetQueuedAudioSize(@device) > 8192
26
+
27
+ buf_ptr = FFI::MemoryPointer.new(:float, buffer.size)
28
+ buf_ptr.put_array_of_float(0, buffer)
29
+
30
+ SDL.QueueAudio(@device, buf_ptr, buffer.size * buf_ptr.type_size)
31
+ end
32
+ end
33
+ end
data/lib/rubyboy/bus.rb CHANGED
@@ -2,137 +2,83 @@
2
2
 
3
3
  module Rubyboy
4
4
  class Bus
5
- def initialize(ppu, rom, ram, mbc, timer, interrupt, joypad)
5
+ def initialize(ppu, rom, ram, mbc, timer, interrupt, joypad, apu)
6
6
  @ppu = ppu
7
7
  @rom = rom
8
8
  @ram = ram
9
9
  @mbc = mbc
10
10
  @joypad = joypad
11
+ @apu = apu
11
12
  @interrupt = interrupt
12
13
  @timer = timer
13
14
 
14
- @tmp = {}
15
+ @read_methods = Array.new(0x10000)
16
+ @write_methods = Array.new(0x10000)
17
+
18
+ set_methods
15
19
  end
16
20
 
17
- def read_byte(addr)
18
- case addr
19
- when 0x0000..0x7fff
20
- @mbc.read_byte(addr)
21
- when 0x8000..0x9fff
22
- @ppu.read_byte(addr)
23
- when 0xa000..0xbfff
24
- @mbc.read_byte(addr)
25
- when 0xc000..0xcfff
26
- @ram.wram1[addr - 0xc000]
27
- when 0xd000..0xdfff
28
- @ram.wram2[addr - 0xd000]
29
- when 0xe000..0xfdff
30
- # echo ram
31
- when 0xfe00..0xfe9f
32
- @ppu.read_byte(addr)
33
- when 0xfea0..0xfeff
34
- # unused
35
- 0xff
36
- when 0xff00
37
- @joypad.read_byte(addr)
38
- when 0xff01..0xff02
39
- # serial
40
- @tmp[addr] ||= 0
41
- when 0xff04..0xff07
42
- @timer.read_byte(addr)
43
- when 0xff0f
44
- @interrupt.read_byte(addr)
45
- when 0xff10..0xff26
46
- # sound
47
- @tmp[addr] ||= 0
48
- when 0xff30..0xff3f
49
- # wave pattern ram
50
- @tmp[addr] ||= 0
51
- when 0xff40..0xff4b
52
- @ppu.read_byte(addr)
53
- when 0xff4f
54
- # vbk
55
- @tmp[addr] ||= 0
56
- when 0xff50
57
- # boot rom
58
- @tmp[addr] ||= 0
59
- when 0xff51..0xff55
60
- # hdma
61
- @tmp[addr] ||= 0
62
- when 0xff68..0xff6b
63
- # bgp
64
- @tmp[addr] ||= 0
65
- when 0xff70
66
- # svbk
67
- @tmp[addr] ||= 0
68
- when 0xff80..0xfffe
69
- @ram.hram[addr - 0xff80]
70
- when 0xffff
71
- @interrupt.read_byte(addr)
72
- else
73
- 0xff
21
+ def set_methods
22
+ 0x10000.times do |addr|
23
+ case addr
24
+ when 0x0000..0x7fff
25
+ @read_methods[addr] = -> { @mbc.read_byte(addr) }
26
+ @write_methods[addr] = ->(value) { @mbc.write_byte(addr, value) }
27
+ when 0x8000..0x9fff
28
+ @read_methods[addr] = -> { @ppu.read_byte(addr) }
29
+ @write_methods[addr] = ->(value) { @ppu.write_byte(addr, value) }
30
+ when 0xa000..0xbfff
31
+ @read_methods[addr] = -> { @mbc.read_byte(addr) }
32
+ @write_methods[addr] = ->(value) { @mbc.write_byte(addr, value) }
33
+ when 0xc000..0xcfff
34
+ @read_methods[addr] = -> { @ram.wram1[addr - 0xc000] }
35
+ @write_methods[addr] = ->(value) { @ram.wram1[addr - 0xc000] = value }
36
+ when 0xd000..0xdfff
37
+ @read_methods[addr] = -> { @ram.wram2[addr - 0xd000] }
38
+ @write_methods[addr] = ->(value) { @ram.wram2[addr - 0xd000] = value }
39
+ when 0xfe00..0xfe9f
40
+ @read_methods[addr] = -> { @ppu.read_byte(addr) }
41
+ @write_methods[addr] = ->(value) { @ppu.write_byte(addr, value) }
42
+ when 0xff00
43
+ @read_methods[addr] = -> { @joypad.read_byte(addr) }
44
+ @write_methods[addr] = ->(value) { @joypad.write_byte(addr, value) }
45
+ when 0xff04..0xff07
46
+ @read_methods[addr] = -> { @timer.read_byte(addr) }
47
+ @write_methods[addr] = ->(value) { @timer.write_byte(addr, value) }
48
+ when 0xff0f
49
+ @read_methods[addr] = -> { @interrupt.read_byte(addr) }
50
+ @write_methods[addr] = ->(value) { @interrupt.write_byte(addr, value) }
51
+ when 0xff10..0xff26
52
+ @read_methods[addr] = -> { @apu.read_byte(addr) }
53
+ @write_methods[addr] = ->(value) { @apu.write_byte(addr, value) }
54
+ when 0xff30..0xff3f
55
+ @read_methods[addr] = -> { @apu.read_byte(addr) }
56
+ @write_methods[addr] = ->(value) { @apu.write_byte(addr, value) }
57
+ when 0xff46
58
+ @read_methods[addr] = -> { @ppu.read_byte(addr) }
59
+ @write_methods[addr] = ->(value) { 0xa0.times { |i| write_byte(0xfe00 + i, read_byte((value << 8) + i)) } }
60
+ when 0xff40..0xff4b
61
+ @read_methods[addr] = -> { @ppu.read_byte(addr) }
62
+ @write_methods[addr] = ->(value) { @ppu.write_byte(addr, value) }
63
+ when 0xff80..0xfffe
64
+ @read_methods[addr] = -> { @ram.hram[addr - 0xff80] }
65
+ @write_methods[addr] = ->(value) { @ram.hram[addr - 0xff80] = value }
66
+ when 0xffff
67
+ @read_methods[addr] = -> { @interrupt.read_byte(addr) }
68
+ @write_methods[addr] = ->(value) { @interrupt.write_byte(addr, value) }
69
+ else
70
+ @read_methods[addr] = -> { 0xff }
71
+ @write_methods[addr] = ->(_value) {}
72
+ end
74
73
  end
75
74
  end
76
75
 
76
+ def read_byte(addr)
77
+ @read_methods[addr].call
78
+ end
79
+
77
80
  def write_byte(addr, value)
78
- case addr
79
- when 0x0000..0x7fff
80
- @mbc.write_byte(addr, value)
81
- when 0x8000..0x9fff
82
- @ppu.write_byte(addr, value)
83
- when 0xa000..0xbfff
84
- @mbc.write_byte(addr, value)
85
- when 0xc000..0xcfff
86
- @ram.wram1[addr - 0xc000] = value
87
- when 0xd000..0xdfff
88
- @ram.wram2[addr - 0xd000] = value
89
- when 0xe000..0xfdff
90
- # echo ram
91
- when 0xfe00..0xfe9f
92
- @ppu.write_byte(addr, value)
93
- when 0xfea0..0xfeff
94
- # unused
95
- when 0xff00
96
- @joypad.write_byte(addr, value)
97
- when 0xff01..0xff02
98
- # serial
99
- @tmp[addr] = value
100
- when 0xff04..0xff07
101
- @timer.write_byte(addr, value)
102
- when 0xff0f
103
- @interrupt.write_byte(addr, value)
104
- when 0xff10..0xff26
105
- # sound
106
- @tmp[addr] = value
107
- when 0xff30..0xff3f
108
- # wave pattern ram
109
- @tmp[addr] = value
110
- when 0xff46
111
- 0xa0.times do |i|
112
- write_byte(0xfe00 + i, read_byte((value << 8) + i))
113
- end
114
- when 0xff40..0xff4b
115
- @ppu.write_byte(addr, value)
116
- when 0xff4f
117
- # vbk
118
- @tmp[addr] = value
119
- when 0xff50
120
- # boot rom
121
- @tmp[addr] = value
122
- when 0xff51..0xff55
123
- # hdma
124
- @tmp[addr] = value
125
- when 0xff68..0xff6b
126
- # bgp
127
- @tmp[addr] = value
128
- when 0xff70
129
- # svbk
130
- @tmp[addr] = value
131
- when 0xff80..0xfffe
132
- @ram.hram[addr - 0xff80] = value
133
- when 0xffff
134
- @interrupt.write_byte(addr, value)
135
- end
81
+ @write_methods[addr].call(value)
136
82
  end
137
83
 
138
84
  def read_word(addr)
@@ -15,7 +15,7 @@ module Rubyboy
15
15
  when 0x08..0x09
16
16
  Nombc.new(rom)
17
17
  else
18
- raise "Unsupported cartridge type: #{cartridge_type}"
18
+ raise "Unsupported cartridge type: #{rom.cartridge_type}"
19
19
  end
20
20
  end
21
21
  end
@@ -10,50 +10,66 @@ module Rubyboy
10
10
  @ram_bank = 0
11
11
  @ram_enable = false
12
12
  @ram_banking_mode = false
13
+
14
+ @read_methods = Array.new(0xc000)
15
+ @write_methods = Array.new(0xc000)
16
+
17
+ set_methods
13
18
  end
14
19
 
15
- def read_byte(addr)
16
- case addr
17
- when 0x0000..0x3fff
18
- @rom.data[addr]
19
- when 0x4000..0x7fff
20
- @rom.data[addr + (@rom_bank - 1) * 0x4000]
21
- when 0xa000..0xbfff
22
- if @ram_enable
23
- if @ram_banking_mode
24
- @ram.eram[addr - 0xa000 + @ram_bank * 0x800]
25
- else
26
- @ram.eram[addr - 0xa000]
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
27
38
  end
28
- else
29
- 0xff
30
- end
31
- else
32
- raise "not implemented: read_byte #{addr}"
33
39
  end
34
- end
35
40
 
36
- def write_byte(addr, value)
37
- case addr
38
- when 0x0000..0x1fff
39
- @ram_enable = value & 0x0f == 0x0a
40
- when 0x2000..0x3fff
41
- @rom_bank = value & 0x1f
42
- @rom_bank = 1 if @rom_bank == 0
43
- when 0x4000..0x5fff
44
- @ram_bank = value & 0x03
45
- when 0x6000..0x7fff
46
- @ram_banking_mode = value & 0x01 == 0x01
47
- when 0xa000..0xbfff
48
- if @ram_enable
49
- if @ram_banking_mode
50
- @ram.eram[addr - 0xa000 + @ram_bank * 0x800] = value
51
- else
52
- @ram.eram[addr - 0xa000] = value
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
53
62
  end
54
- end
55
63
  end
56
64
  end
65
+
66
+ def read_byte(addr)
67
+ @read_methods[addr].call
68
+ end
69
+
70
+ def write_byte(addr, value)
71
+ @write_methods[addr].call(value)
72
+ end
57
73
  end
58
74
  end
59
75
  end