rubyboy 0.1.0 → 0.2.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/.rubocop.yml +34 -8
- data/CHANGELOG.md +11 -0
- data/Rakefile +3 -3
- data/lib/opcodes.json +11657 -0
- data/lib/roms/cpu_instrs/cpu_instrs.gb +0 -0
- data/lib/roms/{hello.gb → cpu_instrs/individual/01-special.gb} +0 -0
- data/lib/roms/cpu_instrs/individual/02-interrupts.gb +0 -0
- data/lib/roms/cpu_instrs/individual/03-op sp,hl.gb +0 -0
- data/lib/roms/cpu_instrs/individual/04-op r,imm.gb +0 -0
- data/lib/roms/cpu_instrs/individual/05-op rp.gb +0 -0
- data/lib/roms/cpu_instrs/individual/06-ld r,r.gb +0 -0
- data/lib/roms/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb +0 -0
- data/lib/roms/cpu_instrs/individual/08-misc instrs.gb +0 -0
- data/lib/roms/cpu_instrs/individual/09-op r,r.gb +0 -0
- data/lib/roms/cpu_instrs/individual/10-bit ops.gb +0 -0
- data/lib/roms/cpu_instrs/individual/11-op a,(hl).gb +0 -0
- data/lib/roms/cpu_instrs/readme.txt +119 -0
- data/lib/roms/instr_timing/instr_timing.gb +0 -0
- data/lib/roms/instr_timing/readme.txt +139 -0
- data/lib/rubyboy/bus.rb +150 -11
- data/lib/rubyboy/cartridge/factory.rb +21 -0
- data/lib/rubyboy/cartridge/mbc1.rb +71 -0
- data/lib/rubyboy/cartridge/nombc.rb +19 -0
- data/lib/rubyboy/cpu.rb +1663 -110
- data/lib/rubyboy/interrupt.rb +22 -0
- data/lib/rubyboy/ppu.rb +15 -15
- data/lib/rubyboy/ram.rb +14 -0
- data/lib/rubyboy/register.rb +26 -0
- data/lib/rubyboy/rom.rb +1 -1
- data/lib/rubyboy/timer.rb +68 -0
- data/lib/rubyboy/version.rb +1 -1
- data/lib/rubyboy.rb +14 -12
- metadata +27 -4
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Rubyboy
|
|
6
|
+
class Interrupt
|
|
7
|
+
attr_accessor :ie, :if
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@ie = 0
|
|
11
|
+
@if = 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def interrupts
|
|
15
|
+
@if & @ie & 0x1f
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def request(interrupt)
|
|
19
|
+
@if |= interrupt
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/rubyboy/ppu.rb
CHANGED
|
@@ -17,15 +17,15 @@ module Rubyboy
|
|
|
17
17
|
|
|
18
18
|
def step(cycles)
|
|
19
19
|
@cycles += cycles
|
|
20
|
-
if @cycles
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
return if @cycles < 456
|
|
21
|
+
|
|
22
|
+
@cycles -= 456
|
|
23
|
+
@ly = (@ly + 1) % 154
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def draw_bg
|
|
27
|
-
tile_map_addr = @lcdc[3]
|
|
28
|
-
tile_data_addr = @lcdc[4]
|
|
27
|
+
tile_map_addr = @lcdc[3].zero? ? 0x9800 : 0x9c00
|
|
28
|
+
tile_data_addr = @lcdc[4].zero? ? 0x9000 : 0x8000
|
|
29
29
|
|
|
30
30
|
bg = Array.new(256) { Array.new(256, 0x00) }
|
|
31
31
|
|
|
@@ -38,12 +38,12 @@ module Rubyboy
|
|
|
38
38
|
tile = @vram[tile_data_addr - 0x8000 + tile_index * 16, 16]
|
|
39
39
|
|
|
40
40
|
8.times do |i|
|
|
41
|
-
pixelsa = tile[i*2]
|
|
42
|
-
pixelsb = tile[i*2+1]
|
|
41
|
+
pixelsa = tile[i * 2]
|
|
42
|
+
pixelsb = tile[i * 2 + 1]
|
|
43
43
|
|
|
44
44
|
8.times do |j|
|
|
45
|
-
c = (pixelsb[7-j] << 1) + pixelsa[7-j]
|
|
46
|
-
bg[y*8+i][x*8+j] = get_color(c)
|
|
45
|
+
c = (pixelsb[7 - j] << 1) + pixelsa[7 - j]
|
|
46
|
+
bg[y * 8 + i][x * 8 + j] = get_color(c)
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
end
|
|
@@ -52,7 +52,7 @@ module Rubyboy
|
|
|
52
52
|
|
|
53
53
|
144.times do |y|
|
|
54
54
|
160.times do |x|
|
|
55
|
-
view_port[y][x] = bg[(y
|
|
55
|
+
view_port[y][x] = bg[(y + @scy) % 144][(x + @scx) % 160]
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
view_port
|
|
@@ -63,13 +63,13 @@ module Rubyboy
|
|
|
63
63
|
def get_color(color_num)
|
|
64
64
|
case color_num
|
|
65
65
|
when 0
|
|
66
|
-
[0xff, 0xff, 0xff]
|
|
66
|
+
[0xff, 0xff, 0xff, 0xff]
|
|
67
67
|
when 1
|
|
68
|
-
[0xcc, 0xcc, 0xcc]
|
|
68
|
+
[0xcc, 0xcc, 0xcc, 0xff]
|
|
69
69
|
when 2
|
|
70
|
-
[0x77, 0x77, 0x77]
|
|
70
|
+
[0x77, 0x77, 0x77, 0xff]
|
|
71
71
|
when 3
|
|
72
|
-
[0x00, 0x00, 0x00]
|
|
72
|
+
[0x00, 0x00, 0x00, 0xff]
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
end
|
data/lib/rubyboy/ram.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyboy
|
|
4
|
+
class Ram
|
|
5
|
+
attr_accessor :eram, :wram1, :wram2, :hram
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@eram = Array.new(0x2000, 0)
|
|
9
|
+
@wram1 = Array.new(0x1000, 0)
|
|
10
|
+
@wram2 = Array.new(0x1000, 0)
|
|
11
|
+
@hram = Array.new(0x80, 0)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Rubyboy
|
|
6
|
+
class Register
|
|
7
|
+
attr_reader :value
|
|
8
|
+
|
|
9
|
+
def initialize(name:, value:)
|
|
10
|
+
@name = name
|
|
11
|
+
@value = value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def value=(v)
|
|
15
|
+
@value = v & 0xff
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def increment
|
|
19
|
+
@value = (@value + 1) & 0xff
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def decrement
|
|
23
|
+
@value = (@value - 1) & 0xff
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/rubyboy/rom.rb
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Rubyboy
|
|
6
|
+
class Timer
|
|
7
|
+
def initialize(interrupt)
|
|
8
|
+
@div = 0
|
|
9
|
+
@tima = 0
|
|
10
|
+
@tma = 0
|
|
11
|
+
@tac = 0
|
|
12
|
+
@cycles = 0
|
|
13
|
+
@interrupt = interrupt
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def step(cycles)
|
|
17
|
+
before_cycles = @cycles
|
|
18
|
+
after_cycles = @cycles + cycles
|
|
19
|
+
@cycles = after_cycles & 0xffff
|
|
20
|
+
|
|
21
|
+
@div += after_cycles / 256 - before_cycles / 256
|
|
22
|
+
@div &= 0xffff
|
|
23
|
+
|
|
24
|
+
return if @tac[2].zero?
|
|
25
|
+
|
|
26
|
+
divider = case @tac & 0b11
|
|
27
|
+
when 0b00 then 1024
|
|
28
|
+
when 0b01 then 16
|
|
29
|
+
when 0b10 then 64
|
|
30
|
+
when 0b11 then 256
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
tima_diff = (after_cycles / divider - before_cycles / divider)
|
|
34
|
+
@tima += tima_diff
|
|
35
|
+
|
|
36
|
+
return if @tima < 256
|
|
37
|
+
|
|
38
|
+
@tima &= 0xff
|
|
39
|
+
@interrupt.request(0b0000_0100)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def read_byte(byte)
|
|
43
|
+
case byte
|
|
44
|
+
when 0xff04
|
|
45
|
+
@div >> 8
|
|
46
|
+
when 0xff05
|
|
47
|
+
@tima
|
|
48
|
+
when 0xff06
|
|
49
|
+
@tma
|
|
50
|
+
when 0xff07
|
|
51
|
+
@tac | 0b1111_1000
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write_byte(byte, value)
|
|
56
|
+
case byte
|
|
57
|
+
when 0xff04
|
|
58
|
+
@div = 0
|
|
59
|
+
when 0xff05
|
|
60
|
+
@tima = value
|
|
61
|
+
when 0xff06
|
|
62
|
+
@tma = value
|
|
63
|
+
when 0xff07
|
|
64
|
+
@tac = value & 0b111
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/rubyboy/version.rb
CHANGED
data/lib/rubyboy.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'gosu'
|
|
4
|
-
|
|
4
|
+
require 'benchmark'
|
|
5
|
+
require_relative 'rubyboy/version'
|
|
5
6
|
require_relative 'rubyboy/bus'
|
|
6
7
|
require_relative 'rubyboy/cpu'
|
|
7
8
|
require_relative 'rubyboy/ppu'
|
|
8
9
|
require_relative 'rubyboy/rom'
|
|
10
|
+
require_relative 'rubyboy/timer'
|
|
9
11
|
|
|
10
12
|
module Rubyboy
|
|
11
13
|
class Console < Gosu::Window
|
|
@@ -18,8 +20,10 @@ module Rubyboy
|
|
|
18
20
|
@total_cycles = 0
|
|
19
21
|
|
|
20
22
|
rom = Rom.new(rom_data)
|
|
23
|
+
interrupt = Interrupt.new
|
|
21
24
|
@ppu = Ppu.new
|
|
22
|
-
@
|
|
25
|
+
@timer = Timer.new(interrupt)
|
|
26
|
+
@bus = Bus.new(@ppu, rom, @timer, interrupt)
|
|
23
27
|
@cpu = Cpu.new(@bus)
|
|
24
28
|
end
|
|
25
29
|
|
|
@@ -27,21 +31,19 @@ module Rubyboy
|
|
|
27
31
|
while @total_cycles < 70224
|
|
28
32
|
cycles = @cpu.exec
|
|
29
33
|
@total_cycles += cycles
|
|
34
|
+
@timer.step(cycles)
|
|
30
35
|
@ppu.step(cycles)
|
|
31
36
|
end
|
|
32
37
|
@total_cycles -= 70224
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
p e.to_s[0, 100]
|
|
40
|
+
raise e
|
|
36
41
|
end
|
|
37
42
|
|
|
38
43
|
def draw
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
draw_pixel(j, i, c)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
44
|
+
pixel_data = @ppu.draw_bg.flatten.pack('C*')
|
|
45
|
+
@image = Gosu::Image.from_blob(160, 144, pixel_data)
|
|
46
|
+
@image.draw(0, 0, 0, SCALE, SCALE)
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
def draw_pixel(x, y, color)
|
|
@@ -53,5 +55,5 @@ module Rubyboy
|
|
|
53
55
|
end
|
|
54
56
|
end
|
|
55
57
|
|
|
56
|
-
rom_data = File.open(File.expand_path('roms/
|
|
58
|
+
rom_data = File.open(File.expand_path('roms/cpu_instrs/cpu_instrs.gb', __dir__), 'r') { _1.read.bytes }
|
|
57
59
|
Rubyboy::Console.new(rom_data).show
|
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.
|
|
4
|
+
version: 0.2.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
|
+
date: 2023-11-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: gosu
|
|
@@ -37,14 +37,36 @@ files:
|
|
|
37
37
|
- LICENSE.txt
|
|
38
38
|
- README.md
|
|
39
39
|
- Rakefile
|
|
40
|
+
- lib/opcodes.json
|
|
41
|
+
- lib/roms/cpu_instrs/cpu_instrs.gb
|
|
42
|
+
- lib/roms/cpu_instrs/individual/01-special.gb
|
|
43
|
+
- lib/roms/cpu_instrs/individual/02-interrupts.gb
|
|
44
|
+
- lib/roms/cpu_instrs/individual/03-op sp,hl.gb
|
|
45
|
+
- lib/roms/cpu_instrs/individual/04-op r,imm.gb
|
|
46
|
+
- lib/roms/cpu_instrs/individual/05-op rp.gb
|
|
47
|
+
- lib/roms/cpu_instrs/individual/06-ld r,r.gb
|
|
48
|
+
- lib/roms/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb
|
|
49
|
+
- lib/roms/cpu_instrs/individual/08-misc instrs.gb
|
|
50
|
+
- lib/roms/cpu_instrs/individual/09-op r,r.gb
|
|
51
|
+
- lib/roms/cpu_instrs/individual/10-bit ops.gb
|
|
52
|
+
- lib/roms/cpu_instrs/individual/11-op a,(hl).gb
|
|
53
|
+
- lib/roms/cpu_instrs/readme.txt
|
|
40
54
|
- lib/roms/hello-world.gb
|
|
41
|
-
- lib/roms/
|
|
55
|
+
- lib/roms/instr_timing/instr_timing.gb
|
|
56
|
+
- lib/roms/instr_timing/readme.txt
|
|
42
57
|
- lib/roms/tobu.gb
|
|
43
58
|
- lib/rubyboy.rb
|
|
44
59
|
- lib/rubyboy/bus.rb
|
|
60
|
+
- lib/rubyboy/cartridge/factory.rb
|
|
61
|
+
- lib/rubyboy/cartridge/mbc1.rb
|
|
62
|
+
- lib/rubyboy/cartridge/nombc.rb
|
|
45
63
|
- lib/rubyboy/cpu.rb
|
|
64
|
+
- lib/rubyboy/interrupt.rb
|
|
46
65
|
- lib/rubyboy/ppu.rb
|
|
66
|
+
- lib/rubyboy/ram.rb
|
|
67
|
+
- lib/rubyboy/register.rb
|
|
47
68
|
- lib/rubyboy/rom.rb
|
|
69
|
+
- lib/rubyboy/timer.rb
|
|
48
70
|
- lib/rubyboy/version.rb
|
|
49
71
|
- sig/rubyboy.rbs
|
|
50
72
|
homepage: https://github.com/sacckey/rubyboy
|
|
@@ -55,6 +77,7 @@ metadata:
|
|
|
55
77
|
homepage_uri: https://github.com/sacckey/rubyboy
|
|
56
78
|
source_code_uri: https://github.com/sacckey/rubyboy
|
|
57
79
|
changelog_uri: https://github.com/sacckey/rubyboy/blob/main/CHANGELOG.md
|
|
80
|
+
rubygems_mfa_required: 'true'
|
|
58
81
|
post_install_message:
|
|
59
82
|
rdoc_options: []
|
|
60
83
|
require_paths:
|
|
@@ -63,7 +86,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
63
86
|
requirements:
|
|
64
87
|
- - ">="
|
|
65
88
|
- !ruby/object:Gem::Version
|
|
66
|
-
version: 2.
|
|
89
|
+
version: 3.2.0
|
|
67
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
91
|
requirements:
|
|
69
92
|
- - ">="
|