rubyboy 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75741c0c0044a7a9985e38c81e7756ed155481f39a8ced6620842ad09590a631
4
- data.tar.gz: 6ca44b4cf8b11111eaaae44876b1d303f7d9baf20ee6e2132b61c61bf5d93486
3
+ metadata.gz: a90f9cbc5a0ac4a9f9b971f0c4454421dc83ae9686222c275679f173e7503232
4
+ data.tar.gz: 52833516da6531982602c373acb11a74d292db6221b8ad34d4420a94be7fe017
5
5
  SHA512:
6
- metadata.gz: 0ef6237619ea02791de321e13645a694cdf715bdcd3f958d4116e739e4d6734309d7da66c03d829ffacec3e231310ea5d70ede2daf8c53b2bd93d7d1d483df19
7
- data.tar.gz: ff8fd7354154f5f62b16ce5139a3c689d3e01f4e2dabe95e48350fe8573ddb490dc576a533c06d826974b20f3fcd7e245b5ada766cad2212a513d50ef632b59b
6
+ metadata.gz: ef45830027a11b9827e8660bef2fbb45a5a0fc867486aef58ece8a930acae959eb66ac5709d425e8562d1a546608cbb4cce040efc9e17940b627dfc9095c4a7b
7
+ data.tar.gz: d8564cc7f5c66dbce015fead7ff770527736943e9c1de3858ed813c1cc012c1e9c5b9248010d16ee39a5fa668e720eb9cda93443b2097260b3b24688b9acdd42
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0] - 2023-11-20
4
+
5
+ - Fix interrupt
6
+ - Fix sprite priority
7
+ - Implement joypad
8
+ - Pass bgbtest
9
+
3
10
  ## [0.3.0] - 2023-11-19
4
11
 
5
12
  - Fix bg rendering
data/lib/rubyboy/bus.rb CHANGED
@@ -8,11 +8,12 @@ module Rubyboy
8
8
  class Bus
9
9
  attr_accessor :ppu, :rom, :interrupt
10
10
 
11
- def initialize(ppu, rom, timer, interrupt)
11
+ def initialize(ppu, rom, timer, interrupt, joypad)
12
12
  @ppu = ppu
13
13
  @rom = rom
14
14
  @ram = Ram.new
15
15
  @mbc = Cartridge::Factory.create(rom, @ram)
16
+ @joypad = joypad
16
17
 
17
18
  @interrupt = interrupt
18
19
  @timer = timer
@@ -42,8 +43,7 @@ module Rubyboy
42
43
  # unused
43
44
  0xff
44
45
  when 0xff00
45
- # joypad
46
- @tmp[addr] ||= 0
46
+ @joypad.read_byte(addr)
47
47
  when 0xff01..0xff02
48
48
  # serial
49
49
  @tmp[addr] ||= 0
@@ -102,8 +102,7 @@ module Rubyboy
102
102
  when 0xfea0..0xfeff
103
103
  # unused
104
104
  when 0xff00
105
- # joypad
106
- @tmp[addr] = value
105
+ @joypad.write_byte(addr, value)
107
106
  when 0xff01..0xff02
108
107
  # serial
109
108
  @tmp[addr] = value
data/lib/rubyboy/cpu.rb CHANGED
@@ -85,12 +85,12 @@ module Rubyboy
85
85
 
86
86
  @bus.interrupt.if &= (~(1 << i)) & 0xff
87
87
  @ime = false
88
- @bus.write_word(@sp - 2, @pc)
89
88
  @sp -= 2
89
+ @bus.write_word(@sp, @pc)
90
90
  @pc = pcs[i]
91
- opcode = read_byte(@pc)
92
91
  break
93
92
  end
93
+ return 20
94
94
  end
95
95
 
96
96
  if @ime_delay
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubyboy
4
+ class Joypad
5
+ def initialize(interupt)
6
+ @mode = 0xcf
7
+ @action = 0xff
8
+ @direction = 0xff
9
+ @interupt = interupt
10
+ end
11
+
12
+ def read_byte(addr)
13
+ raise "not implemented: write_byte #{addr}" unless addr == 0xff00
14
+
15
+ res = @mode | 0xcf
16
+ res &= @direction if @mode[4].zero?
17
+ res &= @action if @mode[5].zero?
18
+
19
+ res
20
+ end
21
+
22
+ def write_byte(addr, value)
23
+ raise "not implemented: write_byte #{addr}" unless addr == 0xff00
24
+
25
+ @mode = value & 0x30
26
+ @mode |= 0xc0
27
+ end
28
+
29
+ def direction_button(button)
30
+ @direction = button | 0xf0
31
+
32
+ @interupt.request(0b0001_0000) if button < 0b1111
33
+ end
34
+
35
+ def action_button(button)
36
+ @action = button | 0xf0
37
+
38
+ @interupt.request(0b0001_0000) if button < 0b1111
39
+ end
40
+ end
41
+ end
data/lib/rubyboy/lcd.rb CHANGED
@@ -11,7 +11,6 @@ module Rubyboy
11
11
  SCALE = 4
12
12
 
13
13
  def initialize
14
- load_raylib
15
14
  InitWindow(WIDTH * SCALE, HEIGHT * SCALE, 'RUBY BOY')
16
15
  image = GenImageColor(WIDTH, HEIGHT, BLACK)
17
16
  image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8
@@ -34,24 +33,5 @@ module Rubyboy
34
33
  def close_window
35
34
  CloseWindow()
36
35
  end
37
-
38
- private
39
-
40
- def load_raylib
41
- shared_lib_path = "#{Gem::Specification.find_by_name('raylib-bindings').full_gem_path}/lib/"
42
- case RUBY_PLATFORM
43
- when /mswin|msys|mingw/ # Windows
44
- Raylib.load_lib("#{shared_lib_path}libraylib.dll")
45
- when /darwin/ # macOS
46
- Raylib.load_lib("#{shared_lib_path}libraylib.dylib")
47
- when /linux/ # Ubuntu Linux (x86_64 or aarch64)
48
- arch = RUBY_PLATFORM.split('-')[0]
49
- Raylib.load_lib(shared_lib_path + "libraylib.#{arch}.so")
50
- else
51
- raise "Unknown system: #{RUBY_PLATFORM}"
52
- end
53
-
54
- SetTraceLogLevel(LOG_ERROR)
55
- end
56
36
  end
57
37
  end
data/lib/rubyboy/ppu.rb CHANGED
@@ -38,6 +38,7 @@ module Rubyboy
38
38
  @cycles = 0
39
39
  @interrupt = interrupt
40
40
  @buffer = Array.new(144 * 160, 0x00)
41
+ @bg_pixels = Array.new(LCD_WIDTH, 0x00)
41
42
  end
42
43
 
43
44
  def read_byte(addr)
@@ -169,6 +170,7 @@ module Rubyboy
169
170
  tile_index = get_tile_index(@lcdc[3], x, y)
170
171
  pixel = get_pixel(tile_index, x, y)
171
172
  @buffer[@ly * LCD_WIDTH + i] = get_color(@bgp, pixel)
173
+ @bg_pixels[i] = pixel
172
174
  end
173
175
  end
174
176
 
@@ -185,6 +187,7 @@ module Rubyboy
185
187
  tile_index = get_tile_index(@lcdc[6], x, y)
186
188
  pixel = get_pixel(tile_index, x, y)
187
189
  @buffer[@ly * LCD_WIDTH + i] = get_color(@bgp, pixel)
190
+ @bg_pixels[i] = pixel
188
191
  end
189
192
  @wly += 1 if rendered
190
193
  end
@@ -223,7 +226,7 @@ module Rubyboy
223
226
  i = (sprite[:x] + x) % 256
224
227
 
225
228
  next if pixel.zero? || i >= LCD_WIDTH
226
- next if sprite[:flags][7] == 1 && @buffer[@ly * LCD_WIDTH + i] != 0xff
229
+ next if sprite[:flags][7] == 1 && @bg_pixels[i] != 0
227
230
 
228
231
  @buffer[@ly * LCD_WIDTH + i] = get_color(pallet, pixel)
229
232
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubyboy
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/rubyboy.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'raylib'
3
4
  require 'benchmark'
4
5
  require_relative 'rubyboy/version'
5
6
  require_relative 'rubyboy/bus'
@@ -8,21 +9,27 @@ require_relative 'rubyboy/ppu'
8
9
  require_relative 'rubyboy/rom'
9
10
  require_relative 'rubyboy/timer'
10
11
  require_relative 'rubyboy/lcd'
12
+ require_relative 'rubyboy/joypad'
11
13
 
12
14
  module Rubyboy
13
15
  class Console
16
+ include Raylib
17
+
14
18
  def initialize(rom_data)
19
+ load_raylib
15
20
  rom = Rom.new(rom_data)
16
21
  interrupt = Interrupt.new
17
22
  @ppu = Ppu.new(interrupt)
18
23
  @timer = Timer.new(interrupt)
19
- @bus = Bus.new(@ppu, rom, @timer, interrupt)
24
+ @joypad = Joypad.new(interrupt)
25
+ @bus = Bus.new(@ppu, rom, @timer, interrupt, @joypad)
20
26
  @cpu = Cpu.new(@bus)
21
27
  @lcd = Lcd.new
22
28
  end
23
29
 
24
30
  def start
25
31
  until @lcd.window_should_close?
32
+ key_input_check
26
33
  cycles = @cpu.exec
27
34
  @timer.step(cycles)
28
35
  draw if @ppu.step(cycles)
@@ -33,6 +40,8 @@ module Rubyboy
33
40
  raise e
34
41
  end
35
42
 
43
+ private
44
+
36
45
  def draw
37
46
  pixel_data = buffer_to_pixel_data(@ppu.buffer)
38
47
  @lcd.draw(pixel_data)
@@ -43,8 +52,32 @@ module Rubyboy
43
52
  [row, row, row]
44
53
  end.flatten.pack('C*')
45
54
  end
55
+
56
+ def key_input_check
57
+ direction = (IsKeyUp(KEY_D) && 1 || 0) | ((IsKeyUp(KEY_A) && 1 || 0) << 1) | ((IsKeyUp(KEY_W) && 1 || 0) << 2) | ((IsKeyUp(KEY_S) && 1 || 0) << 3)
58
+ action = (IsKeyUp(KEY_K) && 1 || 0) | ((IsKeyUp(KEY_J) && 1 || 0) << 1) | ((IsKeyUp(KEY_U) && 1 || 0) << 2) | ((IsKeyUp(KEY_I) && 1 || 0) << 3)
59
+ @joypad.direction_button(direction)
60
+ @joypad.action_button(action)
61
+ end
62
+
63
+ def load_raylib
64
+ shared_lib_path = "#{Gem::Specification.find_by_name('raylib-bindings').full_gem_path}/lib/"
65
+ case RUBY_PLATFORM
66
+ when /mswin|msys|mingw/ # Windows
67
+ Raylib.load_lib("#{shared_lib_path}libraylib.dll")
68
+ when /darwin/ # macOS
69
+ Raylib.load_lib("#{shared_lib_path}libraylib.dylib")
70
+ when /linux/ # Ubuntu Linux (x86_64 or aarch64)
71
+ arch = RUBY_PLATFORM.split('-')[0]
72
+ Raylib.load_lib(shared_lib_path + "libraylib.#{arch}.so")
73
+ else
74
+ raise "Unknown system: #{RUBY_PLATFORM}"
75
+ end
76
+
77
+ SetTraceLogLevel(LOG_ERROR)
78
+ end
46
79
  end
47
80
  end
48
81
 
49
- rom_data = File.open(File.expand_path('roms/cpu_instrs/cpu_instrs.gb', __dir__), 'r') { _1.read.bytes }
82
+ rom_data = File.open(File.expand_path('roms/bgbtest.gb', __dir__), 'r') { _1.read.bytes }
50
83
  Rubyboy::Console.new(rom_data).start
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyboy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sacckey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-19 00:00:00.000000000 Z
11
+ date: 2023-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: raylib-bindings
@@ -64,6 +64,7 @@ files:
64
64
  - lib/rubyboy/cartridge/nombc.rb
65
65
  - lib/rubyboy/cpu.rb
66
66
  - lib/rubyboy/interrupt.rb
67
+ - lib/rubyboy/joypad.rb
67
68
  - lib/rubyboy/lcd.rb
68
69
  - lib/rubyboy/ppu.rb
69
70
  - lib/rubyboy/ram.rb