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,16 @@
1
+ require_relative 'instruction_set/instruction'
2
+ require_relative 'instruction_set/ld'
3
+ require_relative 'instruction_set/bitwise'
4
+ require_relative 'instruction_set/rotate'
5
+ require_relative 'instruction_set/stack'
6
+ require_relative 'instruction_set/boolean'
7
+ require_relative 'instruction_set/arithmetic'
8
+ require_relative 'instruction_set/special'
9
+ require_relative 'instruction_set/carry'
10
+ require_relative 'instruction_set/call'
11
+ require_relative 'instruction_set/return'
12
+ require_relative 'instruction_set/jump'
13
+ require_relative 'instruction_set/swap'
14
+ require_relative 'instruction_set/cpl'
15
+ require_relative 'instruction_set/rst'
16
+ require_relative 'instruction_set/daa'
@@ -0,0 +1,238 @@
1
+ require_relative 'instruction'
2
+
3
+ module GBRb::InstructionSet
4
+ class Arithmetic < Instruction
5
+ def initialize target, m, t, indirect, immediates=0
6
+ super m, t, immediates
7
+ @target = target
8
+ @indirect = indirect
9
+ end
10
+
11
+ def carry? left, right, mask
12
+ (mask-1 & left).public_send(@op, mask-1 & right) & mask == mask
13
+ end
14
+
15
+ def call r, mem, right_value
16
+ right_value ||= r.public_send(@target.to_sym).read
17
+ right_value = mem.read_byte(right_value) if @indirect
18
+ a_value = r.a.read
19
+ if carry? a_value, right_value, r.a.half_mask
20
+ r.set_half_carry_flag
21
+ else
22
+ r.clear_half_carry_flag
23
+ end
24
+ if carry? a_value, right_value, r.a.mask
25
+ r.set_carry_flag
26
+ else
27
+ r.clear_carry_flag
28
+ end
29
+ a_value = a_value.public_send(@op, right_value) & 0xff
30
+ r.a.store a_value unless @skip_store
31
+ a_value == 0x00 ? r.set_zero_flag : r.clear_zero_flag
32
+ end
33
+ end
34
+
35
+ class Add < Arithmetic
36
+ def initialize target, m=1, t=4, indirect=false, immediates=0
37
+ super
38
+ @op = :+
39
+ end
40
+
41
+ def call r, mem, right_value=nil
42
+ super
43
+ r.clear_add_sub_flag
44
+ end
45
+ end
46
+
47
+ class AddHl < Instruction
48
+ def initialize target, m=2, t=8
49
+ super m, t
50
+ @target = target.to_sym
51
+ @op = :+
52
+ end
53
+
54
+ def call r, mem
55
+ left = r.hl.read
56
+ right = r.public_send(@target).read
57
+ r.hl.store left + right
58
+ if r.hl.read < left + right
59
+ r.set_carry_flag
60
+ else
61
+ r.clear_carry_flag
62
+ end
63
+ if carry? left, right, r.hl.half_mask
64
+ r.set_half_carry_flag
65
+ else
66
+ r.clear_half_carry_flag
67
+ end
68
+ r.clear_add_sub_flag
69
+ end
70
+ end
71
+
72
+ class AddSpR8 < Instruction
73
+ def initialize m=4, t=16, immediates=1
74
+ super
75
+ end
76
+
77
+ def call r, mem, offset
78
+ v = r.sp.read
79
+ if offset > 127
80
+ v -= ((offset ^ 0xff) + 1) & 0xff
81
+ else
82
+ v += offset
83
+ end
84
+ r.clear_zero_flag
85
+ r.clear_add_sub_flag
86
+ check = r.sp.read ^ offset ^ ((r.sp.read + offset)& 0xffff)
87
+ r.sp.store v
88
+ if check & 0x100 == 0x100
89
+ r.set_carry_flag
90
+ else
91
+ r.clear_carry_flag
92
+ end
93
+ if check & 0x10 == 0x10
94
+ r.set_half_carry_flag
95
+ else
96
+ r.clear_half_carry_flag
97
+ end
98
+ end
99
+ end
100
+
101
+ class Sub < Arithmetic
102
+ def initialize target, m=1, t=4, indirect=false, immediates=0
103
+ super
104
+ @op = :-
105
+ end
106
+
107
+ def call r, mem, right_value=nil
108
+ super
109
+ r.set_add_sub_flag
110
+ end
111
+ end
112
+
113
+ class Cp < Sub
114
+ def initialize *args
115
+ super
116
+ @skip_store = true
117
+ end
118
+ end
119
+
120
+ class Adc < Add
121
+ def call r, mem, right_value=nil
122
+ carry = r.carry_flag? ? 1 : 0
123
+ if right_value
124
+ left_value = r.a.read
125
+ super r, mem, right_value + carry
126
+ ((left_value & 0xf) + (right_value & 0xf) + carry) > 0xf ? r.set_half_carry_flag : r.clear_half_carry_flag
127
+ ((left_value & 0xff) + (right_value & 0xff) + carry) > 0xff ? r.set_carry_flag : r.clear_carry_flag
128
+ else
129
+ right_value = r.public_send(@target.to_sym).read
130
+ right_value = mem.read_byte(right_value) if @indirect
131
+ left_value = r.a.read
132
+ r.clear_add_sub_flag
133
+ ((left_value & 0xf) + (right_value & 0xf) + carry) > 0xf ? r.set_half_carry_flag : r.clear_half_carry_flag
134
+ ((left_value & 0xff) + (right_value & 0xff) + carry) > 0xff ? r.set_carry_flag : r.clear_carry_flag
135
+ r.a.store left_value + right_value + carry
136
+ r.a.zero? ? r.set_zero_flag : r.clear_zero_flag
137
+ end
138
+ end
139
+ end
140
+
141
+ class Sbc < Sub
142
+ def call r, mem, right_value=nil
143
+ carry = r.carry_flag? ? 1 : 0
144
+ right_value = r.public_send(@target.to_sym).read unless right_value
145
+ right_value = mem.read_byte(right_value) if @indirect
146
+ un = right_value & 0xff
147
+ tmpa = r.a.read
148
+ ua = r.a.read
149
+ ua -= un
150
+ ua -= 1 if r.carry_flag?
151
+ r.set_add_sub_flag
152
+ ua < 0 ? r.set_carry_flag : r.clear_carry_flag
153
+ (ua ^ un ^ tmpa) & 0x10 == 0x10 ? r.set_half_carry_flag : r.clear_half_carry_flag
154
+ r.a.store ua
155
+ r.a.zero? ? r.set_zero_flag : r.clear_zero_flag
156
+ end
157
+ end
158
+
159
+ class Inc < Instruction
160
+ def initialize register, m=1, t=4, flags=true, indirect=false
161
+ super m, t
162
+
163
+ @register = register
164
+ @flags = flags
165
+ @op = :+
166
+ @indirect = indirect
167
+ end
168
+
169
+ def call r, mem
170
+ reg = r.public_send(@register.to_sym)
171
+ tmp = reg.read
172
+ if @indirect
173
+ v = mem.read_byte(tmp) + 1
174
+ mem.write_byte(tmp, v)
175
+ tmp = v
176
+ reg = r.h
177
+ else
178
+ reg.store tmp + 1
179
+ end
180
+ if @flags
181
+ r.clear_add_sub_flag
182
+ if @indirect
183
+ (tmp & 0xff == 0x00) ? r.set_zero_flag : r.clear_zero_flag
184
+ if carry? tmp - 1, 0x01, r.h.half_mask
185
+ r.set_half_carry_flag
186
+ else
187
+ r.clear_half_carry_flag
188
+ end
189
+ else
190
+ reg.zero? ? r.set_zero_flag : r.clear_zero_flag
191
+ if carry? tmp, 0x01, reg.half_mask
192
+ r.set_half_carry_flag
193
+ else
194
+ r.clear_half_carry_flag
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ class Dec < Instruction
202
+ def initialize register, m=1, t=4, flags=true, indirect=false
203
+ super m, t
204
+
205
+ @register = register
206
+ @flags = flags
207
+ @op = :-
208
+ @indirect = indirect
209
+ end
210
+
211
+ def call r, mem
212
+ reg = r.public_send(@register.to_sym)
213
+ tmp = reg.read
214
+ if @indirect
215
+ v = mem.read_byte(tmp)
216
+ mem.write_byte(tmp, v - 1)
217
+ tmp = v
218
+ half_mask = r.a.half_mask
219
+ else
220
+ reg.store tmp - 0x01
221
+ half_mask = reg.half_mask
222
+ end
223
+ if @flags
224
+ r.set_add_sub_flag
225
+ if (tmp - 0x01) == 0x00
226
+ r.set_zero_flag
227
+ else
228
+ r.clear_zero_flag
229
+ end
230
+ if carry? tmp, 0x01, half_mask
231
+ r.set_half_carry_flag
232
+ else
233
+ r.clear_half_carry_flag
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,64 @@
1
+ require_relative '../cpu'
2
+ require_relative 'instruction'
3
+
4
+ module GBRb::InstructionSet
5
+ class Res < Instruction
6
+ def initialize bit, target, indirect=false, m=2, t=16
7
+ super m, t
8
+ @bit = bit
9
+ @mask = 0xff - 0b10 ** bit
10
+ @target = target.to_sym
11
+ @indirect = indirect
12
+ end
13
+
14
+ def call r, mem
15
+ if @indirect
16
+ addr = r.public_send(@target).read
17
+ mem.write_byte(addr, mem.read_byte(addr) & @mask)
18
+ else
19
+ r.public_send(@target).store r.public_send(@target).read & @mask
20
+ end
21
+ end
22
+ end
23
+
24
+ class Set < Instruction
25
+ def initialize bit, target, indirect=false, m=2, t=16
26
+ super m, t
27
+ @bit = bit
28
+ @mask = 0b10 ** bit
29
+ @target = target.to_sym
30
+ @indirect = indirect
31
+ end
32
+
33
+ def call r, mem
34
+ if @indirect
35
+ addr = r.public_send(@target).read
36
+ mem.write_byte(addr, mem.read_byte(addr) | @mask)
37
+ else
38
+ r.public_send(@target).store r.public_send(@target).read | @mask
39
+ end
40
+ end
41
+ end
42
+
43
+ class Bit < Instruction
44
+ def initialize bit, target, indirect=false, m=2, t=8
45
+ super m,t
46
+ @target = target
47
+ @bit = bit
48
+ @indirect = indirect
49
+ @mask = 1 << @bit
50
+ end
51
+
52
+ def call r, mem
53
+ if @indirect
54
+ v = mem.read_byte r.public_send(@target).read
55
+ else
56
+ v = r.public_send(@target).read
57
+ end
58
+
59
+ v & @mask != @mask ? r.set_zero_flag : r.clear_zero_flag
60
+ r.set_half_carry_flag
61
+ r.clear_add_sub_flag
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,61 @@
1
+ require_relative '../cpu'
2
+ require_relative 'instruction'
3
+
4
+ module GBRb::InstructionSet
5
+ class Boolean < Instruction
6
+ def initialize target, m, t, indirect, immediates=0
7
+ @target = target
8
+ @indirect = indirect
9
+ super m, t, immediates
10
+ end
11
+
12
+ def call r, mem, v=nil
13
+ if v
14
+ value = v
15
+ else
16
+ value = r.public_send(@target.to_sym).read
17
+ value = mem.read_byte value if @indirect
18
+ end
19
+ r.a.store r.a.read.public_send(@op, value)
20
+ r.a.zero? ? r.set_zero_flag : r.clear_zero_flag
21
+ r.clear_carry_flag
22
+ r.clear_add_sub_flag
23
+ end
24
+ end
25
+
26
+ class And < Boolean
27
+ def initialize target, m=1, t=4, indirect=false, immediates=0
28
+ @op = :&
29
+ super
30
+ end
31
+
32
+ def call r, mem, v=nil
33
+ super
34
+ r.set_half_carry_flag
35
+ end
36
+ end
37
+
38
+ class Or < Boolean
39
+ def initialize target, m=1, t=4, indirect=false, immediates=0
40
+ @op = :|
41
+ super
42
+ end
43
+
44
+ def call r, mem, right_value=nil
45
+ super
46
+ r.clear_half_carry_flag
47
+ end
48
+ end
49
+
50
+ class Xor < Boolean
51
+ def initialize target, m=1, t=4, indirect=false, immediates=0
52
+ @op = :^
53
+ super
54
+ end
55
+
56
+ def call r, mem, right_value=nil
57
+ super
58
+ r.clear_half_carry_flag
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'instruction'
2
+
3
+ module GBRb::InstructionSet
4
+ class Call < Instruction
5
+ def initialize condition, m=3, t_high=24, t_low=12, immediates=2
6
+ @condition = condition
7
+ @t_high = t_high
8
+ @t_low = t_low
9
+ @m_low = m
10
+ super m, t_low, immediates
11
+ end
12
+
13
+ def call r, mem, addr
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
+ r.sp.store r.sp.read - 2
30
+ mem.write_word(r.sp.read, r.pc.read)
31
+ r.pc.store addr
32
+ @t = @t_high
33
+ @m = @t_high / 4
34
+ else
35
+ @t = @t_low
36
+ @m = @m_low
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'instruction'
2
+
3
+ module GBRb::InstructionSet
4
+ class Ccf < Instruction
5
+ def call r, mem
6
+ if r.carry_flag?
7
+ r.clear_carry_flag
8
+ else
9
+ r.set_carry_flag
10
+ end
11
+ r.clear_add_sub_flag
12
+ r.clear_half_carry_flag
13
+ end
14
+ end
15
+
16
+ class Scf < Instruction
17
+ def call r, mem
18
+ r.clear_half_carry_flag
19
+ r.clear_add_sub_flag
20
+ r.set_carry_flag
21
+ end
22
+ end
23
+ end