GBRb 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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/README.md +9 -1
  4. data/bin/gbrb +3 -3
  5. data/doc/images/blargg_cpu.png +0 -0
  6. data/doc/images/cpu_01.png +0 -0
  7. data/doc/images/cpu_03.png +0 -0
  8. data/doc/images/cpu_04.png +0 -0
  9. data/doc/images/cpu_05.png +0 -0
  10. data/doc/images/cpu_06.png +0 -0
  11. data/doc/images/cpu_07.png +0 -0
  12. data/doc/images/cpu_08.png +0 -0
  13. data/doc/images/cpu_09.png +0 -0
  14. data/doc/images/cpu_10.png +0 -0
  15. data/doc/images/cpu_11.png +0 -0
  16. data/doc/images/nintendo_logo.png +0 -0
  17. data/doc/images/opus5.png +0 -0
  18. data/doc/images/test.gb.png +0 -0
  19. data/doc/images/ttt.png +0 -0
  20. data/lib/gbrb.rb +7 -0
  21. data/lib/gbrb/cartridge.rb +21 -8
  22. data/lib/gbrb/cartridge/cartridge.rb +187 -0
  23. data/lib/gbrb/cpu/concatenated_register.rb +1 -1
  24. data/lib/gbrb/cpu/z80.rb +575 -498
  25. data/lib/gbrb/gb.rb +102 -32
  26. data/lib/gbrb/graphics.rb +1 -1
  27. data/lib/gbrb/graphics/gpu.rb +38 -30
  28. data/lib/gbrb/graphics/mode_clock.rb +31 -30
  29. data/lib/gbrb/graphics/screen_client.rb +3 -2
  30. data/lib/gbrb/instruction_set.rb +16 -0
  31. data/lib/gbrb/instruction_set/arithmetic.rb +238 -0
  32. data/lib/gbrb/instruction_set/bitwise.rb +64 -0
  33. data/lib/gbrb/instruction_set/boolean.rb +61 -0
  34. data/lib/gbrb/instruction_set/call.rb +40 -0
  35. data/lib/gbrb/instruction_set/carry.rb +23 -0
  36. data/lib/gbrb/instruction_set/cpl.rb +12 -0
  37. data/lib/gbrb/instruction_set/daa.rb +33 -0
  38. data/lib/gbrb/instruction_set/instruction.rb +23 -0
  39. data/lib/gbrb/instruction_set/jump.rb +47 -0
  40. data/lib/gbrb/instruction_set/ld.rb +241 -0
  41. data/lib/gbrb/instruction_set/return.rb +43 -0
  42. data/lib/gbrb/instruction_set/rotate.rb +178 -0
  43. data/lib/gbrb/instruction_set/rst.rb +16 -0
  44. data/lib/gbrb/instruction_set/special.rb +37 -0
  45. data/lib/gbrb/instruction_set/stack.rb +34 -0
  46. data/lib/gbrb/instruction_set/swap.rb +32 -0
  47. data/lib/gbrb/mmu.rb +60 -35
  48. data/lib/gbrb/options.rb +54 -0
  49. data/lib/gbrb/timer.rb +114 -0
  50. data/lib/gbrb/version.rb +1 -1
  51. data/misc/dump_diff +133 -0
  52. data/perf/cpu_perf_spec.rb +2 -2
  53. data/spec/gbrb/cartridge/cartridge_spec.rb +19 -0
  54. data/spec/gbrb/cartridge/mbc1_spec.rb +83 -0
  55. data/spec/gbrb/cpu/z80_spec.rb +92 -2
  56. data/spec/gbrb/{cpu/instruction_spec.rb → instruction_set/arithmetic_spec.rb} +21 -100
  57. data/spec/gbrb/instruction_set/boolean_spec.rb +50 -0
  58. data/spec/gbrb/instruction_set/instruction_spec.rb +22 -0
  59. data/spec/gbrb/instruction_set/ld_spec.rb +21 -0
  60. data/spec/gbrb/instruction_set/special_spec.rb +22 -0
  61. data/spec/gbrb/mmu_spec.rb +1 -1
  62. data/spec/gbrb/timer_spec.rb +26 -0
  63. metadata +53 -9
  64. data/lib/gbrb/cpu/instruction.rb +0 -648
  65. data/spec/gbrb/cartridge_spec.rb +0 -19
  66. data/spec/gbrb/graphics/mode_clock_spec.rb +0 -82
@@ -0,0 +1,12 @@
1
+ require_relative '../cpu'
2
+ require_relative 'instruction'
3
+
4
+ module GBRb::InstructionSet
5
+ class Cpl < Instruction
6
+ def call r, mem
7
+ r.set_add_sub_flag
8
+ r.set_half_carry_flag
9
+ r.a.store r.a.read ^ 0xff
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../cpu'
2
+ require_relative 'instruction'
3
+
4
+ module GBRb::InstructionSet
5
+ class Daa < Instruction
6
+ def initialize m=1, t=4
7
+ super
8
+ end
9
+
10
+ def call r, *misc
11
+ a = r.a.read
12
+
13
+ if r.add_sub_flag?
14
+ a = (a - 0x06) & 0xff if r.half_carry_flag?
15
+ a -= 0x60 if r.carry_flag?
16
+ else
17
+ if r.half_carry_flag? || a&0x0f > 9
18
+ a += 0x06
19
+ end
20
+ if r.carry_flag? || a > 0x9f
21
+ a += 0x60
22
+ end
23
+ end
24
+
25
+ r.clear_half_carry_flag
26
+
27
+ r.set_carry_flag if a & 0x100 == 0x100
28
+
29
+ r.a.store a
30
+ r.a.zero? ? r.set_zero_flag : r.clear_zero_flag
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ module GBRb::InstructionSet
2
+ class Instruction
3
+ attr_accessor :i, :m, :t
4
+
5
+ def initialize m=1, t=4, immediates=0, *extra
6
+ @m = m
7
+ @t = t
8
+ @immediates = immediates
9
+ end
10
+
11
+ def immediate_count
12
+ @immediates
13
+ end
14
+
15
+ def call r, mem
16
+ nil
17
+ end
18
+
19
+ def carry? left, right, mask
20
+ (mask-1 & left).public_send(@op, mask-1 & right) & mask == mask
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'instruction'
2
+
3
+ module GBRb::InstructionSet
4
+ class Jump < Instruction
5
+ def initialize condition, m=2, t_high=12, t_low=8, immediates=1
6
+ super m, t_low, immediates
7
+ @m_low = m
8
+ @t_high = t_high
9
+ @t_low = t_low
10
+ @condition = condition.downcase.to_sym
11
+ end
12
+
13
+ def call r, mem, offset=0x00
14
+ do_it = case @condition
15
+ when :c
16
+ r.carry_flag?
17
+ when :none
18
+ true
19
+ when :nc
20
+ not r.carry_flag?
21
+ when :nz
22
+ not r.zero_flag?
23
+ when :z
24
+ r.zero_flag?
25
+ else
26
+ false
27
+ end
28
+
29
+ if do_it
30
+ @t = @t_high
31
+ @m = @t_high / 4
32
+ if @immediates == 0
33
+ r.pc.store r.hl.read
34
+ elsif @immediates == 1
35
+ sign = (offset >> 7 == 1) ? :- : :+
36
+ offset = ((offset ^ 0xff) + 1) & 0xff if sign == :-
37
+ r.pc.store r.pc.read.public_send(sign, offset)
38
+ else
39
+ r.pc.store offset
40
+ end
41
+ else
42
+ @t = @t_low
43
+ @m = @m_low
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,241 @@
1
+ require_relative '../cpu'
2
+ require_relative 'instruction'
3
+
4
+
5
+ module GBRb::InstructionSet
6
+ class Ld < Instruction
7
+ def initialize destination, target, m=1, t=4
8
+ super m, t
9
+ @destination = destination.to_sym
10
+ @target = target.to_sym
11
+ end
12
+
13
+ def call r, mem
14
+ v = r.public_send(@target).read
15
+ r.public_send(@destination).store v
16
+ end
17
+ end
18
+
19
+ class Ldnhl < Instruction
20
+ def initialize destination, m=2, t=8
21
+ super m, t
22
+ @destination = destination.to_sym
23
+ end
24
+
25
+ def call r, mem
26
+ r.public_send(@destination).store mem.read_byte(r.hl.read)
27
+ end
28
+ end
29
+
30
+ class Ldhln < Instruction
31
+ def initialize target, m=2, t=8
32
+ super m, t
33
+ @target = target.to_sym
34
+ end
35
+
36
+ def call r, mem
37
+ mem.write_byte r.hl.read, r.public_send(@target).read
38
+ end
39
+ end
40
+
41
+ class LdD8 < Instruction
42
+ def initialize destination, m=2, t=8
43
+ super m, t, 1
44
+ @destination = destination
45
+ end
46
+
47
+ def call r, mem, v
48
+ r.public_send(@destination).store v
49
+ end
50
+ end
51
+
52
+ class LdhlD8 < Instruction
53
+ def initialize m=3, t=12
54
+ super m, t, 1
55
+ end
56
+
57
+ def call r, mem, v
58
+ mem.write_byte r.hl.read, v
59
+ end
60
+ end
61
+
62
+ class LdD16 < Instruction
63
+ def initialize destination, m=3, t=12
64
+ super m, t, 2
65
+ @destination = destination
66
+ end
67
+
68
+ def call r, mem, v
69
+ r.public_send(@destination).store v
70
+ end
71
+ end
72
+
73
+ class Ldahli < Instruction
74
+ def initialize m=2, t=8
75
+ super
76
+ end
77
+
78
+ def call r, mem
79
+ r.a.store mem.read_byte r.hl.read
80
+ r.hl.store r.hl.read + 1
81
+ end
82
+ end
83
+
84
+ class Ldhlia < Instruction
85
+ def initialize m=2, t=8
86
+ super
87
+ end
88
+
89
+ def call r, mem
90
+ mem.write_byte r.hl.read, r.a.read
91
+ r.hl.store r.hl.read + 1
92
+ end
93
+ end
94
+
95
+ class Ldahld < Instruction
96
+ def initialize m=2, t=8
97
+ super
98
+ end
99
+
100
+ def call r, mem
101
+ r.a.store mem.read_byte r.hl.read
102
+ r.hl.store r.hl.read - 1
103
+ end
104
+ end
105
+
106
+ class Ldhlda < Instruction
107
+ def initialize m=2, t=8
108
+ super
109
+ end
110
+
111
+ def call r, mem
112
+ mem.write_byte r.hl.read, r.a.read
113
+ r.hl.store r.hl.read - 1
114
+ end
115
+ end
116
+
117
+
118
+ class Ldann < Instruction
119
+ def initialize target, m=2, t=8
120
+ super m, t
121
+ @target = target
122
+ end
123
+
124
+ def call r, mem
125
+ r.a.store mem.read_byte r.public_send(@target).read
126
+ end
127
+ end
128
+
129
+ class Ldnna < Instruction
130
+ def initialize destination, m=2, t=8
131
+ super m, t
132
+ @destination = destination
133
+ end
134
+
135
+ def call r, mem
136
+ mem.write_byte r.public_send(@destination).read, r.a.read
137
+ end
138
+ end
139
+
140
+ class Ldca < Instruction
141
+ def initialize m=2, t=8
142
+ super m, t
143
+ end
144
+
145
+ def call r, mem
146
+ mem.write_byte r.c.read + 0xff00, r.a.read
147
+ end
148
+ end
149
+
150
+
151
+ class Ldac < Instruction
152
+ def initialize m=2, t=8
153
+ super m,t
154
+ end
155
+
156
+ def call r, mem
157
+ r.a.store mem.read_byte(r.c.read + 0xff00)
158
+ end
159
+ end
160
+
161
+ class Lda16a < Instruction
162
+ def initialize m=4, t=16, immediates=2
163
+ super
164
+ end
165
+
166
+ def call r, mem, v
167
+ mem.write_byte v, r.a.read
168
+ end
169
+ end
170
+
171
+ class Ldaa16 < Instruction
172
+ def initialize m=4, t=16, immediates=2
173
+ super
174
+ end
175
+
176
+ def call r, mem, v
177
+ r.a.store mem.read_byte v
178
+ end
179
+ end
180
+
181
+ class Lda16sp < Instruction
182
+ def initialize m=5, t=20, immediates=2
183
+ super
184
+ end
185
+
186
+ def call r, mem, v
187
+ mem.write_word v, r.sp.read
188
+ end
189
+ end
190
+
191
+ class Ldsphl < Instruction
192
+ def initialize m=2, t=8
193
+ super m, t
194
+ end
195
+
196
+ def call r, mem
197
+ r.sp.store r.hl.read
198
+ end
199
+ end
200
+
201
+ class Ldh < Instruction
202
+ def initialize destination, target, indirect_dest, indirect_target, m=3, t=12, immediates=1
203
+ super m, t, immediates
204
+
205
+ @destination = destination
206
+ @target = target
207
+ @indirect_dest = indirect_dest
208
+ @indirect_target = indirect_target
209
+ @offset = 0xff00
210
+ end
211
+
212
+ def call r, mem, address
213
+ if @indirect_dest
214
+ value = r.public_send(@target.to_sym).read
215
+ mem.write_byte address + @offset, value
216
+ elsif @indirect_target
217
+ value = mem.read_byte address + @offset
218
+ r.public_send(@destination.to_sym).store value
219
+ end
220
+ end
221
+ end
222
+
223
+ class Ldhlsp < Instruction
224
+ def initialize m=3, t=12, immediates=1
225
+ super
226
+ @op = :+
227
+ end
228
+
229
+ def call r, mem, offset
230
+ check = (r.sp.read ^ offset ^ ((r.sp.read + offset) & 0xffff))
231
+ sign = (offset >> 7 == 1) ? :- : :+
232
+ offset = ((offset ^ 0xff) + 1) & 0xff if sign == :-
233
+ value = r.sp.read.public_send(sign, offset)
234
+ r.hl.store value
235
+ r.clear_zero_flag
236
+ r.clear_add_sub_flag
237
+ check & 0x100 == 0x100 ? r.set_carry_flag : r.clear_carry_flag
238
+ check & 0x10 == 0x10 ? r.set_half_carry_flag : r.clear_half_carry_flag
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,43 @@
1
+ require_relative 'instruction'
2
+
3
+ module GBRb::InstructionSet
4
+ class Ret < Instruction
5
+ def initialize condition, m=2, t_high=20, t=8
6
+ @condition = condition
7
+ @t_high = t_high
8
+ @t_low = t
9
+ @m_low = m
10
+ super m, t, 0
11
+ end
12
+
13
+ def call r, mem
14
+ condition_met = case @condition
15
+ when :c
16
+ r.carry_flag?
17
+ when :nc
18
+ not r.carry_flag?
19
+ when :nz
20
+ not r.zero_flag?
21
+ when :z
22
+ r.zero_flag?
23
+ when :none
24
+ true
25
+ else
26
+ false
27
+ end
28
+ if condition_met
29
+ @t = @t_high
30
+ @m = @t_high / 4
31
+ low = mem.read_byte(r.sp.read)
32
+ r.sp.store r.sp.read + 1
33
+ high = mem.read_byte(r.sp.read)
34
+ r.sp.store r.sp.read + 1
35
+
36
+ r.pc.store (high << 8) + low
37
+ else
38
+ @t = @t_low
39
+ @m = @m_low
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,178 @@
1
+ require_relative '../cpu'
2
+ require_relative 'instruction'
3
+
4
+ module GBRb::InstructionSet
5
+ class Rl < Instruction
6
+ def initialize target, carry=false, indirect=false, m=1, t=4, zero=true
7
+ super m, t
8
+ @target = target.to_sym
9
+ @carry = carry
10
+ @indirect = indirect
11
+ @zero_check = zero
12
+ end
13
+
14
+ def call r, mem
15
+ if @indirect
16
+ address = r.public_send(@target).read
17
+ v = mem.read_byte(address) << 1
18
+ else
19
+ v = r.public_send(@target).read << 1
20
+ end
21
+
22
+ carry_in = if @carry
23
+ v & 0x100 == 0x100 ? 1 : 0
24
+ else
25
+ r.carry_flag? ? 1 : 0
26
+ end
27
+
28
+ v += carry_in
29
+
30
+ if @indirect
31
+ mem.write_byte(address, v)
32
+ else
33
+ r.public_send(@target).store v
34
+ end
35
+
36
+ r.clear_add_sub_flag
37
+ r.clear_half_carry_flag
38
+ if @zero_check
39
+ v & 0xff == 0 ? r.set_zero_flag : r.clear_zero_flag
40
+ else
41
+ r.clear_zero_flag
42
+ end
43
+ carry_out = v >> 8
44
+ carry_out == 1 ? r.set_carry_flag : r.clear_carry_flag
45
+ end
46
+ end
47
+
48
+ class Rr < Instruction
49
+ def initialize target, carry=false, indirect=false, m=1, t=4, check_for_zero=true
50
+ super m, t
51
+ @target = target.to_sym
52
+ @carry = carry
53
+ @indirect = indirect
54
+ @check_for_zero = check_for_zero
55
+ end
56
+
57
+ def call r, mem
58
+ if @indirect
59
+ address = r.public_send(@target).read
60
+ v = mem.read_byte(address)
61
+ else
62
+ v = r.public_send(@target).read
63
+ end
64
+
65
+ carry_out = v & 0x01
66
+
67
+ carry_in = if @carry
68
+ carry_out
69
+ else
70
+ r.carry_flag? ? 1 : 0
71
+ end
72
+
73
+ v >>= 1
74
+
75
+ v += carry_in << 7
76
+
77
+ if @indirect
78
+ original = mem.read_byte address
79
+ mem.write_byte(address, v)
80
+ else
81
+ r.public_send(@target).store v
82
+ end
83
+
84
+ r.clear_add_sub_flag
85
+ r.clear_half_carry_flag
86
+ if @check_for_zero
87
+ v & 0xff == 0 ? r.set_zero_flag : r.clear_zero_flag
88
+ else
89
+ r.clear_zero_flag
90
+ end
91
+ carry_out == 1 ? r.set_carry_flag : r.clear_carry_flag
92
+ end
93
+ end
94
+
95
+ class Srl < Instruction
96
+ def initialize target, indirect=false, m=1, t=4
97
+ super m, t
98
+ @target = target
99
+ @indirect = indirect
100
+ end
101
+
102
+ def call r, mem
103
+ if @indirect
104
+ v = mem.read_byte r.public_send(@target).read
105
+ else
106
+ v = r.public_send(@target).read
107
+ end
108
+
109
+ v & 0b1 == 0 ? r.clear_carry_flag : r.set_carry_flag
110
+ v >>= 1
111
+ v == 0 ? r.set_zero_flag : r.clear_zero_flag
112
+ r.clear_add_sub_flag
113
+ r.clear_half_carry_flag
114
+
115
+ if @indirect
116
+ mem.write_byte(r.public_send(@target).read, v)
117
+ else
118
+ r.public_send(@target).store v
119
+ end
120
+ end
121
+ end
122
+
123
+ class Sla < Instruction
124
+ def initialize target, indirect=false, m=1, t=4
125
+ super m, t
126
+ @target = target
127
+ @indirect = indirect
128
+ end
129
+
130
+ def call r, mem
131
+ if @indirect
132
+ v = mem.read_byte r.public_send(@target).read
133
+ else
134
+ v = r.public_send(@target).read
135
+ end
136
+
137
+ v & 0b10000000 == 0b10000000 ? r.set_carry_flag : r.clear_carry_flag
138
+ v = (v << 1) & 0xff
139
+ v == 0 ? r.set_zero_flag : r.clear_zero_flag
140
+ r.clear_add_sub_flag
141
+ r.clear_half_carry_flag
142
+
143
+ if @indirect
144
+ mem.write_byte(r.public_send(@target).read, v)
145
+ else
146
+ r.public_send(@target).store v
147
+ end
148
+ end
149
+ end
150
+
151
+ class Sra < Instruction
152
+ def initialize target, indirect=false, m=1, t=4
153
+ super m, t
154
+ @target = target
155
+ @indirect = indirect
156
+ end
157
+
158
+ def call r, mem
159
+ if @indirect
160
+ v = mem.read_byte r.public_send(@target).read
161
+ else
162
+ v = r.public_send(@target).read
163
+ end
164
+
165
+ v & 0b01 == 0b01 ? r.set_carry_flag : r.clear_carry_flag
166
+ v = ((v >> 1) | (v & 0x80)) & 0xff
167
+ v == 0 ? r.set_zero_flag : r.clear_zero_flag
168
+ r.clear_add_sub_flag
169
+ r.clear_half_carry_flag
170
+
171
+ if @indirect
172
+ mem.write_byte(r.public_send(@target).read, v)
173
+ else
174
+ r.public_send(@target).store v
175
+ end
176
+ end
177
+ end
178
+ end