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 +4 -4
- data/CHANGELOG.md +9 -1
- data/docs/worker.js +7 -34
- data/exe/rubyboy-bench +1 -1
- data/exe/rubyboy-wasm +1 -1
- data/lib/bench.rb +13 -11
- data/lib/executor.rb +2 -2
- data/lib/rubyboy/emulator_headless.rb +39 -0
- data/lib/rubyboy/version.rb +1 -1
- data/lib/stackprof.rb +14 -0
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f906ad2a5676ad89d614d3898dee887cf2b1b0a76c2b5ae906a7f234e806e779
|
4
|
+
data.tar.gz: d5c133d3ba340a570febc3bd4e4d67245e14a5fef408af6d0aba711a7738c503
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66db379a951b75f717339c4030e201dbfcf79d85fec15deb2a4c0d03e6513262122411eb4149b00533eae5f18c5ed44ab23d57b0ffb2ed2c7b64076c06f1fb77
|
7
|
+
data.tar.gz: 648a015c3aeceab1b53b1ae3d20023c573c24a0fd91f3fde2c9da66ad0dd8caddfa6a2013374f96f7ab8dd7b70d510c32437cdd48cc46327f431f8ed06b00440
|
data/CHANGELOG.md
CHANGED
data/docs/worker.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
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
|
47
|
-
const
|
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
|
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
|
-
|
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
data/exe/rubyboy-wasm
CHANGED
data/lib/bench.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative 'rubyboy'
|
3
|
+
require_relative 'rubyboy/emulator_headless'
|
5
4
|
|
6
5
|
module Rubyboy
|
7
6
|
class Bench
|
8
|
-
def
|
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
|
-
|
18
|
-
|
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(
|
18
|
+
File.binwrite('/video.data', bin)
|
19
19
|
end
|
20
20
|
|
21
21
|
def read_rom_from_virtual_fs
|
22
|
-
rom_path = '/
|
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
|
data/lib/rubyboy/version.rb
CHANGED
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
|
+
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:
|
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.
|
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: []
|