rubyboy 1.4.1 → 1.5.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: f029df58812310dc308546c77d25e75496e0e7b0aff605a5d0826deba85d9014
4
- data.tar.gz: c2fffa4e8f4535ae4fad4bdf3c5742f569443fffc925ee02fa06f6b268f5e2c4
3
+ metadata.gz: f906ad2a5676ad89d614d3898dee887cf2b1b0a76c2b5ae906a7f234e806e779
4
+ data.tar.gz: d5c133d3ba340a570febc3bd4e4d67245e14a5fef408af6d0aba711a7738c503
5
5
  SHA512:
6
- metadata.gz: c7f5d75b7ae8ec29488242943aca521b013875c896c8b368622f02408f52803b01e94b548b720fb4bad1ffca30d4223cfbf15ab2e8bd04b89799dc2a41bcf164
7
- data.tar.gz: b21b63a6c19263c3a72aa9b592505358dc55f450b0fd9fd3c8fb8b907d2057c07b2dae41dc9c0fa1be2fcd4e77010d4dcaf8ca7eafab908f27f7b5d903596a69
6
+ metadata.gz: 66db379a951b75f717339c4030e201dbfcf79d85fec15deb2a4c0d03e6513262122411eb4149b00533eae5f18c5ed44ab23d57b0ffb2ed2c7b64076c06f1fb77
7
+ data.tar.gz: 648a015c3aeceab1b53b1ae3d20023c573c24a0fd91f3fde2c9da66ad0dd8caddfa6a2013374f96f7ab8dd7b70d510c32437cdd48cc46327f431f8ed06b00440
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
- ## [Unreleased]
1
+ ## [1.5.0] - 2025-02-09
2
+
3
+ - Add EmulatorHeadless and use it for bench
4
+ - Bump ruby.wasm version to 2.7.1
5
+
6
+ ## [1.4.2] - 2025-01-11
7
+
8
+ - Use DefaultRubyVM
9
+ - Bump ruby.wasm version to 2.7.0
2
10
 
3
11
  ## [1.4.1] - 2024-12-25
4
12
 
data/docs/worker.js CHANGED
@@ -1,5 +1,5 @@
1
- import { RubyVM } from 'https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.6.2/+esm';
2
- import { Directory, File, OpenDirectory, OpenFile, PreopenDirectory, WASI } from 'https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/+esm';
1
+ import { DefaultRubyVM } from 'https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm';
2
+ import { File } from 'https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/+esm';
3
3
 
4
4
  const DIRECTION_KEY_MASKS = {
5
5
  'KeyD': 0b0001, // Right
@@ -19,20 +19,6 @@ class Rubyboy {
19
19
  constructor() {
20
20
  this.wasmUrl = 'https://proxy.sacckey.dev/rubyboy.wasm';
21
21
 
22
- const rootContents = new Map();
23
- rootContents.set('RUBYBOY_TMP', new Directory(new Map()));
24
- this.rootFs = rootContents;
25
-
26
- const args = ['ruby.wasm', '-e_=0'];
27
- this.wasi = new WASI(args, [], [
28
- new OpenFile(new File([])), // stdin
29
- new OpenFile(new File([])), // stdout
30
- new OpenFile(new File([])), // stderr
31
- new PreopenDirectory('/', rootContents)
32
- ], {
33
- debug: false
34
- });
35
-
36
22
  this.directionKey = 0b1111;
37
23
  this.actionKey = 0b1111;
38
24
  }
@@ -43,18 +29,8 @@ class Rubyboy {
43
29
  response = await fetch(this.wasmUrl);
44
30
  }
45
31
 
46
- const buffer = await response.arrayBuffer();
47
- const imports = {
48
- wasi_snapshot_preview1: this.wasi.wasiImport,
49
- };
50
- const vm = new RubyVM();
51
- vm.addToImports(imports);
52
-
53
- const { instance } = await WebAssembly.instantiate(buffer, imports);
54
- await vm.setInstance(instance);
55
- this.wasi.initialize(instance);
56
- vm.initialize();
57
-
32
+ const module = await WebAssembly.compileStreaming(response)
33
+ const { vm, wasi } = await DefaultRubyVM(module);
58
34
  vm.eval(`
59
35
  require 'js'
60
36
  require_relative 'lib/executor'
@@ -63,15 +39,13 @@ class Rubyboy {
63
39
  `);
64
40
 
65
41
  this.vm = vm;
42
+ this.rootDir = wasi.fds[3].dir
66
43
  }
67
44
 
68
45
  sendPixelData() {
69
46
  this.vm.eval(`$executor.exec(${this.directionKey}, ${this.actionKey})`);
70
47
 
71
- const tmpDir = this.rootFs.get('RUBYBOY_TMP');
72
- const op = new OpenDirectory(tmpDir);
73
- const result = op.path_lookup('video.data', 0);
74
- const file = result.inode_obj;
48
+ const file = this.rootDir.contents.get('video.data');
75
49
  const bytes = file.data;
76
50
 
77
51
  postMessage({ type: 'pixelData', data: bytes.buffer }, [bytes.buffer]);
@@ -127,8 +101,7 @@ self.addEventListener('message', async (event) => {
127
101
 
128
102
  if (event.data.type === 'loadROM') {
129
103
  const romFile = new File(new Uint8Array(event.data.data));
130
- const tmpDir = rubyboy.rootFs.get('RUBYBOY_TMP');
131
- tmpDir.contents.set('rom.data', romFile);
104
+ rubyboy.rootDir.contents.set('rom.data', romFile);
132
105
  rubyboy.vm.eval(`
133
106
  $executor.read_rom_from_virtual_fs
134
107
  `);
data/exe/rubyboy-bench CHANGED
@@ -40,4 +40,4 @@ else
40
40
  puts 'YJIT is not available in this environment.'
41
41
  end
42
42
 
43
- Rubyboy::Bench.new.bench(**options)
43
+ Rubyboy::Bench.new.run(**options)
data/exe/rubyboy-wasm CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  case ARGV[0]
5
5
  when 'build'
6
- command = %w[build --ruby-version 3.3 -o ./docs/ruby-js.wasm]
6
+ command = %w[build --ruby-version 3.4 -o ./docs/ruby-js.wasm]
7
7
  when 'pack'
8
8
  command = %w[pack ./docs/ruby-js.wasm --dir ./lib::/lib -o ./docs/rubyboy.wasm]
9
9
  else
data/lib/bench.rb CHANGED
@@ -1,22 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'stackprof'
4
- require_relative 'rubyboy'
3
+ require_relative 'rubyboy/emulator_headless'
5
4
 
6
5
  module Rubyboy
7
6
  class Bench
8
- def stackprof
9
- StackProf.run(mode: :cpu, out: 'stackprof-cpu-myapp.dump', raw: true) do
10
- Rubyboy::Emulator.new('lib/roms/tobu.gb').bench
11
- end
12
- end
13
-
14
- def bench(count: 3, frames: 1500, rom_path: 'lib/roms/tobu.gb')
7
+ def run(count: 3, frames: 1500, rom_path: 'lib/roms/tobu.gb')
15
8
  time_sum = 0
9
+
16
10
  count.times do |i|
17
- time = Rubyboy::Emulator.new(rom_path).bench(frames)
18
- time_sum += time
11
+ emulator = Rubyboy::EmulatorHeadless.new(rom_path)
12
+ frame_count = 0
13
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
14
+ while frame_count < frames
15
+ emulator.step
16
+ frame_count += 1
17
+ end
18
+ time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond) - start_time
19
19
  puts "#{i + 1}: #{time / 1_000_000_000.0} sec"
20
+
21
+ time_sum += time
20
22
  end
21
23
 
22
24
  puts "FPS: #{frames * count * 1_000_000_000.0 / time_sum}"
data/lib/executor.rb CHANGED
@@ -15,11 +15,11 @@ class Executor
15
15
 
16
16
  def exec(direction_key = 0b1111, action_key = 0b1111)
17
17
  bin = @emulator.step(direction_key, action_key).pack('V*')
18
- File.binwrite(File.join('/RUBYBOY_TMP', 'video.data'), bin)
18
+ File.binwrite('/video.data', bin)
19
19
  end
20
20
 
21
21
  def read_rom_from_virtual_fs
22
- rom_path = '/RUBYBOY_TMP/rom.data'
22
+ rom_path = '/rom.data'
23
23
  raise "ROM file not found in virtual filesystem at #{rom_path}" unless File.exist?(rom_path)
24
24
 
25
25
  rom_data = File.open(rom_path, 'rb') { |file| file.read.bytes }
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'apu'
4
+ require_relative 'bus'
5
+ require_relative 'cpu'
6
+ require_relative 'ppu'
7
+ require_relative 'rom'
8
+ require_relative 'ram'
9
+ require_relative 'timer'
10
+ require_relative 'joypad'
11
+ require_relative 'interrupt'
12
+ require_relative 'cartridge/factory'
13
+
14
+ module Rubyboy
15
+ class EmulatorHeadless
16
+ def initialize(rom_path)
17
+ rom_data = File.open(rom_path, 'r') { _1.read.bytes }
18
+ rom = Rom.new(rom_data)
19
+ ram = Ram.new
20
+ mbc = Cartridge::Factory.create(rom, ram)
21
+ interrupt = Interrupt.new
22
+ @ppu = Ppu.new(interrupt)
23
+ @timer = Timer.new(interrupt)
24
+ joypad = Joypad.new(interrupt)
25
+ @apu = Apu.new
26
+ bus = Bus.new(@ppu, rom, ram, mbc, @timer, interrupt, joypad, @apu)
27
+ @cpu = Cpu.new(bus, interrupt)
28
+ end
29
+
30
+ def step
31
+ loop do
32
+ cycles = @cpu.exec
33
+ @timer.step(cycles)
34
+ @apu.step(cycles)
35
+ break if @ppu.step(cycles)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubyboy
4
- VERSION = '1.4.1'
4
+ VERSION = '1.5.0'
5
5
  end
data/lib/stackprof.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackprof'
4
+ require_relative 'rubyboy/emulator'
5
+
6
+ module Rubyboy
7
+ class Stackprof
8
+ def run
9
+ StackProf.run(mode: :cpu, out: 'stackprof-cpu-myapp.dump', raw: true) do
10
+ Rubyboy::Emulator.new('lib/roms/tobu.gb').bench
11
+ end
12
+ end
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyboy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sacckey
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-12-25 00:00:00.000000000 Z
10
+ date: 2025-02-09 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: ffi
@@ -30,8 +29,6 @@ dependencies:
30
29
  - - ">="
31
30
  - !ruby/object:Gem::Version
32
31
  version: 1.16.3
33
- description:
34
- email:
35
32
  executables:
36
33
  - rubyboy
37
34
  - rubyboy-bench
@@ -91,6 +88,7 @@ files:
91
88
  - lib/rubyboy/cartridge/nombc.rb
92
89
  - lib/rubyboy/cpu.rb
93
90
  - lib/rubyboy/emulator.rb
91
+ - lib/rubyboy/emulator_headless.rb
94
92
  - lib/rubyboy/emulator_wasm.rb
95
93
  - lib/rubyboy/interrupt.rb
96
94
  - lib/rubyboy/joypad.rb
@@ -105,6 +103,7 @@ files:
105
103
  - lib/rubyboy/sdl.rb
106
104
  - lib/rubyboy/timer.rb
107
105
  - lib/rubyboy/version.rb
106
+ - lib/stackprof.rb
108
107
  - resource/logo/logo.png
109
108
  - resource/logo/logo.svg
110
109
  - resource/logo/rubyboy.png
@@ -120,7 +119,6 @@ metadata:
120
119
  source_code_uri: https://github.com/sacckey/rubyboy
121
120
  changelog_uri: https://github.com/sacckey/rubyboy/blob/main/CHANGELOG.md
122
121
  rubygems_mfa_required: 'true'
123
- post_install_message:
124
122
  rdoc_options: []
125
123
  require_paths:
126
124
  - lib
@@ -135,8 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
133
  - !ruby/object:Gem::Version
136
134
  version: '0'
137
135
  requirements: []
138
- rubygems_version: 3.5.3
139
- signing_key:
136
+ rubygems_version: 3.6.2
140
137
  specification_version: 4
141
138
  summary: A Game Boy emulator written in Ruby
142
139
  test_files: []