GBRb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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