nesemul 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 857b40d37a4f1e744285b7f92eaf7354ae4d35c0
4
+ data.tar.gz: 50591ad3372d5ee471158dd24f752ca726c7431c
5
+ SHA512:
6
+ metadata.gz: 40aec0bf7505fdc6ac8f574ca724de21021fd5229975bfe1022543e42fa6c82c3285e7fb9663cc1d08e0f8c465b59d48a15ab0d10fd726f4e75fb0d4f6a2b67c
7
+ data.tar.gz: e44c0848ce985ccbd57e947cf0e5a6feec2c6e22f2c19af37ae3dbe6a558f9aa9f2c0d13e8fbd1a884d4c36e352d98179cb4e20f2eb9e2c561dc1797fa52f1ed
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ #NesEmul
2
+
3
+ *Requires* : ruby/sdl
4
+
5
+ *Install Nesemul*
6
+
7
+ ~~~
8
+ $ gem install nesemul
9
+ ~~~
10
+
11
+ ~~~
12
+ $ nesemul <Your file>
13
+ ~~~
data/bin/nesemul ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path("../..", __FILE__)
4
+ require "sdl"
5
+ require 'json'
6
+ require "#{root}/lib/ppu.rb"
7
+ require "#{root}/lib/cpu.rb"
8
+ require '#{root}/lib/opcodes.rb'
9
+ require '#{root}/lib/bitwise.rb'
10
+ #require '#{root}/OAM.rb'
11
+
12
+
13
+ rom = File.open(ARGV[0]).read.bytes.to_a
14
+
15
+ $compteur_cycles = 0
16
+ $cpu = Cpu.new(rom)
17
+ $ppu = $cpu.ppu
18
+ $cpu.reset_rom
19
+
20
+
21
+ def ppu_exec(cycles)
22
+ (3*cycles).times do
23
+ $ppu.draw_screen
24
+ case $compteur_cycles
25
+ when 0 then $ppu.clear_vblank
26
+ when 61800
27
+ $ppu.set_vblank
28
+ $ppu.screen.flip
29
+ $cpu.nmi_interrupt if $ppu.registers[0x2000].bit?(7)==1
30
+ $compteur_cycles = 0
31
+ end
32
+ $compteur_cycles += 1
33
+ end
34
+ end
35
+
36
+ while true
37
+ nb_args = OPCODES[$cpu.ram[$cpu.cpu[:compteur]]][:len].to_i
38
+ $cpu.cpu[:compteur_new] += nb_args
39
+ #puts $cpu.ram.count(nil) if $cpu.ram.count(nil) !=0
40
+ $cpu.send OPCODES[$cpu.ram[$cpu.cpu[:compteur]]][:opcodes].downcase,
41
+ $cpu.ram[$cpu.cpu[:compteur]], $cpu.ram[$cpu.cpu[:compteur]+1], $cpu.ram[$cpu.cpu[:compteur]+2]
42
+ ppu_exec(OPCODES[$cpu.ram[$cpu.cpu[:compteur]]][:tim].to_i)
43
+ #puts "#{$cpu.ram[$cpu.cpu[:compteur]+1]}, #{$cpu.ram[$cpu.cpu[:compteur]+2]}"
44
+ #puts "Nom de l'instruct : #{OPCODES[$cpu.ram[$cpu.cpu[:compteur]]][:opcodes]}"
45
+ #puts "Etat du cpu apres l'instruction #{$cpu.cpu}"
46
+ #puts "___________________________________________________________________________________________\n"
47
+ #puts "#{$cpu.cpu[:A]},#{$cpu.ram[52692]},#{$cpu.ram[52692+1]}"
48
+ $cpu.cpu[:compteur] = $cpu.cpu[:compteur_new]
49
+ end
50
+
data/lib/bitwise.rb ADDED
@@ -0,0 +1,82 @@
1
+ class Integer
2
+ def int8_plus(integer)
3
+ ((self+integer).abs)%256
4
+ end
5
+
6
+ def int8_minus(integer)
7
+ if (self-integer)<0
8
+ (self-integer)+256
9
+ else
10
+ (self-integer)
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+
17
+
18
+
19
+ class Fixnum
20
+ def bit?(bit)
21
+ if bit == 7
22
+ value = 0 if self & 128 == 0
23
+ value = 1 if self & 128 != 0
24
+ elsif bit == 6
25
+ value = 0 if self & 64 == 0
26
+ value = 1 if self & 64 != 0
27
+ elsif bit == 5
28
+ value = 0 if self & 32 == 0
29
+ value = 1 if self & 32 != 0
30
+ elsif bit == 4
31
+ value = 0 if self & 16 == 0
32
+ value = 1 if self & 16 != 0
33
+ elsif bit == 3
34
+ value = 0 if self & 8 == 0
35
+ value = 1 if self & 8 != 0
36
+ elsif bit == 2
37
+ value = 0 if self & 4 == 0
38
+ value = 1 if self & 4 != 0
39
+ elsif bit == 1
40
+ value = 0 if self & 2 == 0
41
+ value = 1 if self & 2 != 0
42
+ elsif bit == 0
43
+ value = 0 if self & 1 == 0
44
+ value = 1 if self & 1 != 0
45
+ end
46
+
47
+ return value
48
+ end
49
+
50
+ def set_bit(bit)
51
+ self | case bit
52
+ when 7 then 128
53
+ when 6 then 64
54
+ when 5 then 32
55
+ when 4 then 16
56
+ when 3 then 8
57
+ when 2 then 4
58
+ when 1 then 2
59
+ when 0 then 1
60
+ end
61
+ end
62
+
63
+ def clear_bit(bit)
64
+ self & case bit
65
+ when 7 then 127
66
+ when 6 then 191
67
+ when 5 then 223
68
+ when 4 then 239
69
+ when 3 then 247
70
+ when 2 then 251
71
+ when 1 then 253
72
+ when 0 then 254
73
+ end
74
+ end
75
+ end
76
+
77
+
78
+ def signed(int)
79
+ table_conversion = Array(0..128) + Array(-127..-1)
80
+ return table_conversion[int]
81
+ end
82
+
data/lib/cpu.rb ADDED
@@ -0,0 +1,710 @@
1
+ class Cpu
2
+ attr_accessor :ram
3
+ attr_accessor :cpu
4
+ attr_accessor :ppu
5
+
6
+ def initialize(rom)
7
+ @ram = [0]*100000
8
+ @ppu = Ppu.new
9
+ #@oam = Oam.new
10
+ prg_start_index = map_rom(rom)
11
+ @cpu = {:Y=>0,:X=>0,:A=>0,:S=>255,:P=>0,:compteur=>prg_start_index,:compteur_new=>prg_start_index}
12
+ end
13
+
14
+ def map_rom(rom)
15
+ header = rom.shift(16)
16
+ if header[4] == 1
17
+ prg_start_index = 0xC000 #Index de mappage de la PRG (- de 16Ko de PRG)
18
+ else
19
+ prg_start_index = 0x8000 #Index de mappage de la PRG (+ de 16Ko de PRG)
20
+ end
21
+ if header[6].bit?(2) == 1
22
+ trainer = rom.shift(512)
23
+ @ram[0x7000,trainer.length] = trainer # Mapping du trainer dans la RAM
24
+ end
25
+ prg_rom = rom.shift(header[4]*16384)
26
+ chr_rom = rom.shift(header[5]*8192)
27
+ @ppu.ppu[0,chr_rom.length] = chr_rom
28
+ @ram[prg_start_index,prg_rom.length] = prg_rom # Mapping de la PRG dans la RAM
29
+ return prg_start_index
30
+ end
31
+
32
+
33
+ def nmi_interrupt()
34
+ bytefort = @cpu[:compteur_new] >> 8
35
+ bytefaible = @cpu[:compteur_new] & 0x00FF
36
+ @ram[@cpu[:S]+0x100] = bytefort # octet de poids fort
37
+ @cpu[:S] -= 1 #decrementation pour la prochaine valeur
38
+ @ram[@cpu[:S]+0x100] = bytefaible #octet de poids faible
39
+ @cpu[:S] -= 1
40
+ @ram[@cpu[:S]+0x100] = @cpu[:P] #status
41
+ @cpu[:S] -= 1
42
+ @cpu[:compteur_new] = read(0xFFFA)+(read(0xFFFB)*256)
43
+ @cpu[:P] = @cpu[:P].set_bit(2)
44
+ end
45
+
46
+
47
+
48
+ def reset_rom()
49
+ reset_address = @ram[0xFFFC]+(@ram[0xFFFD]*256)
50
+ @cpu[:compteur] = @cpu[:compteur_new] = reset_address
51
+ end
52
+
53
+
54
+ def cmp(zone,arg1,arg2)
55
+ opcode = zone.to_s(16).upcase
56
+ sign_zero_carry @cpu[:A].int8_minus signed case opcode
57
+ when "C9" then arg1
58
+ when "C5" then read(arg1)
59
+ when "D5" then read(arg1+@cpu[:X])
60
+ when "CD" then read(arg1+(arg2*256))
61
+ when "DD" then read(arg1+(arg2*256)+@cpu[:X])
62
+ when "D9" then read(arg1+(arg2*256)+@cpu[:Y])
63
+ when "C1" then read(read(arg1+@cpu[:X]) + (read(arg1+@cpu[:X]+1)*256))
64
+ when "D1" then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y])
65
+ end
66
+ end
67
+
68
+ def asl(zone,arg1,arg2)
69
+ opcode = zone.to_s(16).upcase
70
+ sign_zero_set_switch case zone
71
+ when 0x0A then @cpu[:A] << 1
72
+ when 0x06 then write(arg1,read(arg1) << 1)
73
+ when 0x16 then write(arg1+@cpu[:X], read(arg1+@cpu[:X]) << 1)
74
+ when 0x0E then write(arg1+(arg2*256),read(arg1+(arg2*256)) << 1)
75
+ when 0x1E then write(arg1+(arg2*256)+@cpu[:X],read(arg1+(arg2*256)+@cpu[:X]) << 1)
76
+ end
77
+ end
78
+
79
+ def rol(zone,arg1,arg2)
80
+ opcode = zone.to_s(16).upcase
81
+ sign_zero_set case opcode
82
+ when "2A" then @cpu[:A] = rotate_left(@cpu[:A])
83
+ when "26" then write(arg1,rotate_left(read(arg1)))
84
+ when "36" then write(arg1+@cpu[:X], rotate_left(read(arg1+@cpu[:X])))
85
+ when "2E" then write(arg1+(arg2*256), rotate_left(read(arg1+(arg2*256))))
86
+ when "3E" then write(arg1+(arg2*256)+@cpu[:X], rotate_left(read(arg1+(arg2*256)+@cpu[:X])))
87
+ end
88
+
89
+ end
90
+
91
+ def ror(zone,arg1,arg2)
92
+ opcode = zone.to_s(16).upcase
93
+ sign_zero_set case opcode
94
+ when "6A" then @cpu[:A] = rotate_right(@cpu[:A])
95
+ when "66" then write(arg1,rotate_right(read(arg1)))
96
+ when "76" then write(arg1+@cpu[:X], rotate_right(read(arg1+@cpu[:X])))
97
+ when "6E" then write(arg1+(arg2*256), rotate_right(read(arg1+(arg2*256))))
98
+ when "7E" then write(arg1+(arg2*256)+@cpu[:X], rotate_right(read(arg1+(arg2*256)+@cpu[:X])))
99
+ end
100
+
101
+ end
102
+
103
+ def rotate_left(byte)
104
+ byte.bit?(7) == 1 ? @cpu[:P] = @cpu[:P].set_bit(0) : @cpu[:P] = @cpu[:P].clear_bit(0)
105
+ @cpu[:P].bit?(0) == 1 ? byte = ((byte << 1)&0xFF)| 1 : byte = ((byte << 1)&0xFF)| 0
106
+ @cpu[:P] = @cpu[:P].clear_bit(0) if byte.bit?(7) == 0 #clear carry
107
+ @cpu[:P] = @cpu[:P].set_bit(0) if byte.bit?(7) == 1 #set carry
108
+ return byte
109
+ end
110
+
111
+ def rotate_right(byte)
112
+ byte.bit?(0) == 1 ? @cpu[:P] = @cpu[:P].set_bit(0) : @cpu[:P] = @cpu[:P].clear_bit(0)
113
+ @cpu[:P].bit?(0) ==1 ? byte = (byte >> 1)| 128 : byte = (byte >> 1)| 0
114
+ @cpu[:P] = @cpu[:P].clear_bit(0) if byte.bit?(0) == 0 #clear carry
115
+ @cpu[:P] = @cpu[:P].set_bit(0) if byte.bit?(0)==1 #set carry
116
+ return byte
117
+ end
118
+
119
+
120
+
121
+ def lsr(zone,arg1,arg2)
122
+ opcode = zone.to_s(16).upcase
123
+ sign_zero_set_switch case opcode
124
+ when "4A" then @cpu[:A] = @cpu[:A] >> 1
125
+ when "46" then write(arg1,read(arg1) >> 1)
126
+ when "56" then write(arg1+@cpu[:X], read(arg1+@cpu[:X]) >> 1)
127
+ when "4E" then write(arg1+(arg2*256),read(arg1+(arg2*256)) >> 1)
128
+ when "5E" then write(arg1+(arg2*256)+@cpu[:X], read(arg1+(arg2*256)+@cpu[:X]) >> 1)
129
+ end
130
+ end
131
+
132
+
133
+
134
+
135
+ def cpx(zone,arg1,arg2)
136
+ opcode = zone.to_s(16).upcase
137
+ sign_zero_carry @cpu[:X].int8_minus signed case opcode
138
+ when "E0" then arg1
139
+ when "E4" then read(arg1)
140
+ when "EC" then read(arg1+(arg2*256))
141
+ end
142
+ end
143
+
144
+ def cpy(zone,arg1,arg2)
145
+ opcode = zone.to_s(16).upcase
146
+ sign_zero_carry @cpu[:Y].int8_minus signed case opcode
147
+ when "C0" then arg1
148
+ when "C4" then read(arg1)
149
+ when "CC" then read(arg1+(arg2*256))
150
+ end
151
+
152
+ end
153
+
154
+
155
+ def and(zone,arg1,arg2)
156
+ opcode = zone.to_s(16).upcase
157
+ @cpu[:A] = @cpu[:A] & case opcode
158
+ when "29" then arg1
159
+ when "25" then read(arg1)
160
+ when "35" then read(arg1+@cpu[:X])
161
+ when "2D" then read(arg1+(arg2*256))
162
+ when "3D" then read(arg1+(arg2*256)+@cpu[:X])
163
+ when "39" then read(arg1+(arg2*256)+@cpu[:Y])
164
+ when "21" then read(read(arg1+@cpu[:X]) + read(arg1+@cpu[:X]+1)*256)
165
+ when "31" then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y])
166
+ end
167
+ sign_zero_set(@cpu[:A])
168
+ end
169
+
170
+ def eor(zone,arg1,arg2)
171
+ opcode = zone.to_s(16).upcase
172
+ @cpu[:A] = @cpu[:A] ^ case opcode
173
+ when "49" then arg1
174
+ when "45" then read(arg1)
175
+ when "55" then read(arg1+@cpu[:X])
176
+ when "4D" then read(arg1+(arg2*256))
177
+ when "5D" then read(arg1+(arg2*256)+@cpu[:X])
178
+ when "59" then read(arg1+(arg2*256)+@cpu[:Y])
179
+ when "41" then read(read(arg1+@cpu[:X]) + read(arg1+@cpu[:X]+1)*256)
180
+ when "51" then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y])
181
+ end
182
+ sign_zero_set(@cpu[:A])
183
+ end
184
+
185
+
186
+ def ora(zone,arg1,arg2)
187
+ @cpu[:A] |= case zone
188
+ when 0x09 then arg1
189
+ when 0x05 then read(arg1)
190
+ when 0x15 then read(arg1+@cpu[:X])
191
+ when 0x0D then read(arg1+(arg2*256))
192
+ when 0x1D then read(arg1+(arg2*256)+@cpu[:X])
193
+ when 0x19 then read(arg1+(arg2*256)+@cpu[:Y])
194
+ when 0x01 then read(read(arg1+@cpu[:X]) + read(arg1+@cpu[:X]+1)*256)
195
+ when 0x11 then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y])
196
+ end
197
+ sign_zero_set(@cpu[:A])
198
+ end
199
+
200
+
201
+ def clc(x,y,z)
202
+ @cpu[:P] = @cpu[:P].clear_bit(0)
203
+ end
204
+
205
+ def sec(x,y,z)
206
+ @cpu[:P] = @cpu[:P].set_bit(0)
207
+ end
208
+
209
+ def cli(x,y,z)
210
+ @cpu[:P] = @cpu[:P].clear_bit(2)
211
+ end
212
+
213
+ def sei(x,y,z)
214
+ @cpu[:P] = @cpu[:P].set_bit(2)
215
+ end
216
+
217
+ def clv(x,y,z)
218
+ @cpu[:P] = @cpu[:P].clear_bit(6)
219
+ end
220
+
221
+ def cld(x,y,z)
222
+ @cpu[:P] = @cpu[:P].clear_bit(3)
223
+ end
224
+
225
+ def sed(x,y,z)
226
+ @cpu[:P] = @cpu[:P].set_bit(3)
227
+ end
228
+
229
+ def nop(x,y,z)
230
+ end
231
+
232
+ def bit(zone,arg1,arg2)
233
+ opcode = zone.to_s(16).upcase
234
+ case opcode
235
+ when "24"
236
+ valeur = read(arg1)
237
+ if valeur.bit?(7) == 0
238
+ @cpu[:P] = @cpu[:P].clear_bit(7) #clear
239
+ else
240
+ @cpu[:P] = @cpu[:P].set_bit(7) #set
241
+ end
242
+ if valeur.bit?(6) == 0
243
+ @cpu[:P] = @cpu[:P].clear_bit(6) #clear
244
+ else
245
+ @cpu[:P] = @cpu[:P].set_bit(6) #set
246
+ end
247
+ if valeur & @cpu[:A] == 0
248
+ @cpu[:P] = @cpu[:P].set_bit(1) #set
249
+ else
250
+ @cpu[:P] = @cpu[:P].clear_bit(1) #clear
251
+ end
252
+ when "2C"
253
+ valeur = read(arg1+(arg2*256))
254
+ if valeur.bit?(7) == 0
255
+ @cpu[:P] = @cpu[:P].clear_bit(7) #clear
256
+ else
257
+ @cpu[:P] = @cpu[:P].set_bit(7) #set
258
+ end
259
+ if valeur.bit?(6) == 0
260
+ @cpu[:P] = @cpu[:P].clear_bit(6) #clear
261
+ else
262
+ @cpu[:P] = @cpu[:P].set_bit(6) #set
263
+ end
264
+ if valeur & @cpu[:A] == 0
265
+ @cpu[:P] = @cpu[:P].set_bit(1) #set
266
+ else
267
+ @cpu[:P] = @cpu[:P].clear_bit(1) #clear
268
+ end
269
+ end
270
+ end
271
+
272
+
273
+ ###Rappel : dans 0xC0E1 , C0 est l'octet de poids fort et E1 celui de poids faible
274
+
275
+ def jsr(zone,arg1,arg2)
276
+ adresse = @cpu[:compteur_new] -1
277
+ bytefort = adresse >> 8 #byte fort
278
+ bytefaible = adresse & 0x00FF #byte faible
279
+ @ram[@cpu[:S]+0x100] = bytefort # adresse actuelle
280
+ @cpu[:S] -= 1 #decrementation pour la prochaine valeur
281
+ @ram[@cpu[:S]+0x100] = bytefaible
282
+ @cpu[:S] -= 1
283
+ @cpu[:compteur_new] = arg1+(arg2*256)
284
+ end
285
+
286
+ def rts(zone,arg1,arg2)
287
+ bytefaible = @ram[@cpu[:S]+1+0x100]
288
+ bytefort = @ram[@cpu[:S]+2+0x100]
289
+ @cpu[:compteur_new] = bytefaible+(bytefort*256) +1
290
+ @cpu[:S]+=2 # pour ecraser l'adresse précédente sur 2x8bits
291
+ end
292
+
293
+ def rti(zone,arg1,arg2)
294
+ bytefort = @ram[@cpu[:S]+3+0x100]
295
+ bytefaible = @ram[@cpu[:S]+2+0x100]
296
+ status = @ram[@cpu[:S]+1+0x100]
297
+ @cpu[:compteur_new] = bytefaible+(bytefort*256)
298
+ @cpu[:P] = status #récup du status
299
+ @cpu[:S]+=3 # pour ecraser l'adresse précédente sur 3x8bits
300
+ end
301
+
302
+ def brk(x,y,z)
303
+ #Interruption push d'abord l'octet de poids fort ensuite octet de pds faible ensuite le status
304
+ bytefort = @cpu[:compteur_new] >> 8
305
+ bytefaible = @cpu[:compteur_new] & 0x00FF
306
+ @ram[@cpu[:S]+0x100] = bytefort # octet de poids fort
307
+ @cpu[:S] -= 1 #decrementation pour la prochaine valeur
308
+ @ram[@cpu[:S]+0x100] = bytefaible #octet de poids faible
309
+ @cpu[:S] -= 1
310
+ @ram[@cpu[:S]+0x100] = @cpu[:P] #status
311
+ @cpu[:S] -= 1
312
+ @cpu[:compteur_new] = read(0xFFFE)+(read(0xFFFF)*256)
313
+ @cpu[:P] = @cpu[:P].set_bit(4)
314
+ end
315
+
316
+ def php(x,y,z)
317
+ end
318
+
319
+ def jmp(zone,arg1,arg2)
320
+ opcode = zone.to_s(16).upcase
321
+ @cpu[:compteur_new] = case opcode
322
+ when "4C" then arg1+(arg2*256)
323
+ when "6C" then read(arg1+(arg2*256))+(read(arg1+(arg2*256)+1)*256)
324
+ end
325
+ end
326
+
327
+ def adc(zone,arg1,arg2)
328
+ opcode = zone.to_s(16).upcase
329
+ accumulator_temp = @cpu[:A]
330
+ @cpu[:P].bit?(0) == 1 ? valeur_carry = 1 : valeur_carry = 0
331
+ @cpu[:A] = @cpu[:A].int8_plus case opcode
332
+ when "69" then arg1.int8_plus(valeur_carry)
333
+ when "65" then read(arg1).int8_plus(valeur_carry)
334
+ when "75" then read(arg1+@cpu[:X]).int8_plus(valeur_carry)
335
+ when "6D" then read(arg1+(arg2*256)).int8_plus(valeur_carry)
336
+ when "7D" then read(arg1+(arg2*256)+@cpu[:X]).int8_plus(valeur_carry)
337
+ when "79" then read(arg1+(arg2*256)+@cpu[:Y]).int8_plus(valeur_carry)
338
+ when "61" then read(read(arg1+@cpu[:X]) + (read(arg1+@cpu[:X]+1)*256)).int8_plus(valeur_carry)
339
+ when "71" then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y]).int8_plus(valeur_carry)
340
+ end
341
+ @cpu[:P] = @cpu[:P].clear_bit(0) #clear the carry
342
+ set_overflow(accumulator_temp)
343
+ sign_zero_clear_or_set(@cpu[:A])
344
+ end
345
+
346
+ def sbc(zone,arg1,arg2)
347
+ opcode = zone.to_s(16).upcase
348
+ accumulator_temp = @cpu[:A]
349
+ @cpu[:P].bit?(0) == 1 ? valeur_carry = 1 : valeur_carry = 0
350
+ @cpu[:A] = @cpu[:A].int8_minus case opcode
351
+ when "E9" then arg1.int8_minus(valeur_carry)
352
+ when "E5" then read(arg1).int8_minus(valeur_carry)
353
+ when "F5" then read(arg1+@cpu[:X]).int8_minus(valeur_carry)
354
+ when "ED" then read(arg1+(arg2*256)).int8_minus(valeur_carry)
355
+ when "FD" then read(arg1+(arg2*256)+@cpu[:X]).int8_minus(valeur_carry)
356
+ when "F9" then read(arg1+(arg2*256)+@cpu[:Y]).int8_minus(valeur_carry)
357
+ when "E1" then read(read(arg1+@cpu[:X]) + (read(arg1+@cpu[:X]+1)*256)).int8_minus(valeur_carry)
358
+ when "F1" then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y]).int8_minus(valeur_carry)
359
+ end
360
+ @cpu[:P] = @cpu[:P].set_bit(0) #set the carry
361
+ set_overflow(accumulator_temp)
362
+ sign_zero_clear_or_set(@cpu[:A])
363
+ end
364
+
365
+ def dec(zone,arg1,arg2)
366
+ opcode = zone.to_s(16).upcase
367
+ sign_zero_clear_or_set case opcode
368
+ when "C6" then write(arg1,read(arg1).int8_minus(1))
369
+ when "D6" then write(arg1+@cpu[:X],read(arg1+@cpu[:X]).int8_minus(1))
370
+ when "CE" then write(arg1+(arg2*256),read(arg1+(arg2*256)).int8_minus(1))
371
+ when "DE" then write(arg1+(arg2*256)+@cpu[:X],read(arg1+(arg2*256)+@cpu[:X]).int8_minus(1))
372
+ end
373
+ end
374
+
375
+ def inc(zone,arg1,arg2)
376
+ opcode = zone.to_s(16).upcase
377
+ sign_zero_clear_or_set case opcode
378
+ when "E6" then write(arg1,read(arg1).int8_plus(1))
379
+ when "F6" then write(arg1+@cpu[:X],read(arg1+@cpu[:X]).int8_plus(1))
380
+ when "EE" then write(arg1+(arg2*256),read(arg1+(arg2*256)).int8_plus(1))
381
+ when "FE" then write(arg1+(arg2*256)+@cpu[:X],read(arg1+(arg2*256)+@cpu[:X]).int8_plus(1))
382
+ end
383
+ end
384
+
385
+ def lda(zone,arg1,arg2)
386
+ opcode = zone.to_s(16).upcase
387
+ @cpu[:A] = case opcode
388
+ when "A9" then arg1
389
+ when "A5" then read(arg1)
390
+ when "B5" then read(arg1+@cpu[:X])
391
+ when "AD" then read(arg1+(arg2*256))
392
+ when "BD" then read(arg1+(arg2*256)+@cpu[:X])
393
+ when "B9" then read(arg1+(arg2*256)+@cpu[:Y])
394
+ when "A1" then read(read(arg1+@cpu[:X]) + (read(arg1+@cpu[:X]+1)*256))
395
+ when "B1" then read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y])
396
+ end
397
+ sign_zero_set(@cpu[:A])
398
+ end
399
+
400
+ def ldx(zone,arg1,arg2)
401
+ opcode = zone.to_s(16).upcase
402
+ @cpu[:X] = case opcode
403
+ when "A2" then arg1
404
+ when "A6" then read(arg1)
405
+ when "B6" then read(arg1+@cpu[:Y])
406
+ when "AE" then read(arg1+(arg2*256))
407
+ when "BE" then read(arg1+(arg2*256)+@cpu[:Y])
408
+ end
409
+ sign_zero_set(@cpu[:X])
410
+ end
411
+
412
+ def ldy(zone,arg1,arg2)
413
+ opcode = zone.to_s(16).upcase
414
+ @cpu[:Y] = case opcode
415
+ when "A0" then arg1
416
+ when "A4" then read(arg1)
417
+ when "B4" then read(arg1+@cpu[:X])
418
+ when "AC" then read(arg1+(arg2*256))
419
+ when "BC" then read(arg1+(arg2*256)+@cpu[:X])
420
+ end
421
+ sign_zero_set(@cpu[:Y])
422
+ end
423
+
424
+
425
+ def sta(zone,arg1,arg2)
426
+ opcode = zone.to_s(16).upcase
427
+ case opcode
428
+ when "85" then write(arg1,@cpu[:A])
429
+ when "95" then write(arg1+@cpu[:X],@cpu[:A])
430
+ when "8D" then write(arg1+(arg2*256),@cpu[:A])
431
+ when "9D" then write(arg1+(arg2*256)+@cpu[:X], @cpu[:A])
432
+ when "99" then write(arg1+(arg2*256)+@cpu[:Y], @cpu[:A])
433
+ when "81" then write(read(read(arg1+@cpu[:X]) + (read(arg1+@cpu[:X]+1)*256)),@cpu[:A])
434
+ when "91" then write(read(read(arg1)+(read(arg1+1)*256)+@cpu[:Y]), @cpu[:A])
435
+ end
436
+ sign_zero_set(@cpu[:A])
437
+ end
438
+
439
+ def stx(zone,arg1,arg2)
440
+ opcode = zone.to_s(16).upcase
441
+ case opcode
442
+ when "86" then write(arg1, @cpu[:X])
443
+ when "96" then write(arg1+@cpu[:Y], @cpu[:X])
444
+ when "8E" then write(arg1+(arg2*256),@cpu[:X])
445
+ end
446
+ sign_zero_set(@cpu[:X])
447
+ end
448
+
449
+ def sty(zone,arg1,arg2)
450
+ opcode = zone.to_s(16).upcase
451
+ case opcode
452
+ when "84" then write(arg1, @cpu[:Y])
453
+ when "94" then write(arg1+@cpu[:X], @cpu[:Y])
454
+ when "8C" then write(arg1+(arg2*256),@cpu[:Y])
455
+ end
456
+ sign_zero_set(@cpu[:Y])
457
+ end
458
+
459
+
460
+
461
+ def tax(x,y,z)
462
+ @cpu[:X] = @cpu[:A]
463
+ sign_zero_set(@cpu[:X])
464
+ end
465
+
466
+ def txa(x,y,z)
467
+ @cpu[:A] = @cpu[:X]
468
+ sign_zero_set(@cpu[:A])
469
+ end
470
+
471
+ def dex(x,y,z)
472
+ @cpu[:X] = @cpu[:X].int8_minus(1)
473
+ sign_zero_clear_or_set(@cpu[:X])
474
+ end
475
+
476
+ def inx(x,y,z)
477
+ @cpu[:X] = @cpu[:X].int8_plus(1)
478
+ sign_zero_clear_or_set(@cpu[:X])
479
+ end
480
+
481
+ def tay(x,y,z)
482
+ @cpu[:Y] = @cpu[:A]
483
+ sign_zero_set(@cpu[:Y])
484
+ end
485
+
486
+ def tya(x,y,z)
487
+ @cpu[:A] = @cpu[:Y]
488
+ sign_zero_set(@cpu[:A])
489
+ end
490
+
491
+ def dey(x,y,z)
492
+ @cpu[:Y] = @cpu[:Y].int8_minus(1)
493
+ sign_zero_clear_or_set(@cpu[:Y])
494
+ end
495
+
496
+ def iny(x,y,z)
497
+ @cpu[:Y] = @cpu[:Y].int8_plus(1)
498
+ sign_zero_clear_or_set(@cpu[:Y])
499
+ end
500
+
501
+ def txs(x,y,z)
502
+ @cpu[:S] = @cpu[:X]
503
+ end
504
+
505
+ def tsx(x,y,z)
506
+ @cpu[:X] = @cpu[:S]
507
+ end
508
+
509
+ def pha(x,y,z)
510
+ @ram[@cpu[:S]+0x100] = @cpu[:A]
511
+ @cpu[:S] -= 1
512
+ end
513
+
514
+ def pla(x,y,z)
515
+ @cpu[:A] = @ram[@cpu[:S]+1+0x100] #dernier elem
516
+ @cpu[:S] += 1
517
+ end
518
+
519
+ def php(x,y,z)
520
+ @ram[@cpu[:S]+0x100] = @cpu[:P]
521
+ @cpu[:S] -= 1
522
+ end
523
+
524
+ def plp(x,y,z)
525
+ @cpu[:A] = @ram[@cpu[:S]+1+0x100]
526
+ @cpu[:S] += 1
527
+
528
+ end
529
+
530
+ def bcc(zone,arg1,arg2)
531
+ if @cpu[:P].bit?(0) == 0
532
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
533
+ end
534
+ end
535
+
536
+ def bcs(zone,arg1,arg2)
537
+ if @cpu[:P].bit?(0) == 1
538
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
539
+ end
540
+ end
541
+
542
+ def bvc(zone,arg1,arg2)
543
+ if @cpu[:P].bit?(6) == 0
544
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
545
+ end
546
+ end
547
+
548
+ def bvs(zone,arg1,arg2)
549
+ if @cpu[:P].bit?(6) == 1
550
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
551
+ end
552
+ end
553
+
554
+ def bpl(zone,arg1,arg2)
555
+ if @cpu[:P].bit?(7) == 0
556
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
557
+ end
558
+ end
559
+
560
+ def bmi(zone,arg1,arg2)
561
+ if @cpu[:P].bit?(7) == 1
562
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
563
+ end
564
+ end
565
+
566
+ def bne(zone,arg1,arg2)
567
+ if @cpu[:P].bit?(1) == 0
568
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
569
+ end
570
+ end
571
+
572
+ def beq(zone,arg1,arg2)
573
+ if @cpu[:P].bit?(1) == 1
574
+ @cpu[:compteur_new] = @cpu[:compteur_new]+signed(arg1)
575
+ end
576
+ end
577
+
578
+
579
+ def set_overflow(byte)
580
+ if @cpu[:A].bit?(6) != byte.bit?(6)
581
+ @cpu[:P] = @cpu[:P].set_bit(6)
582
+ end
583
+ end
584
+
585
+
586
+ def sign_zero_carry(byte)
587
+ if byte & 0x80 == 0
588
+ @cpu[:P] = @cpu[:P].set_bit(0)
589
+ @cpu[:P] = @cpu[:P].clear_bit(7)
590
+ @cpu[:P] = @cpu[:P].clear_bit(1)
591
+ elsif byte == 0
592
+ @cpu[:P] = @cpu[:P].set_bit(0)
593
+ @cpu[:P] = @cpu[:P].clear_bit(7)
594
+ @cpu[:P] = @cpu[:P].set_bit(1)
595
+ elsif byte & 0x80 != 0
596
+ @cpu[:P] = @cpu[:P].clear_bit(0)
597
+ @cpu[:P] = @cpu[:P].set_bit(7)
598
+ @cpu[:P] = @cpu[:P].clear_bit(1)
599
+ end
600
+ end
601
+
602
+ def sign_zero_clear_or_set(byte) #Clears or sets flag
603
+ if byte==0
604
+ @cpu[:P] = @cpu[:P].set_bit(1)
605
+ else
606
+ @cpu[:P] = @cpu[:P].clear_bit(1)
607
+ end
608
+
609
+ if byte & 0x80 == 0
610
+ @cpu[:P] = @cpu[:P].clear_bit(7)
611
+ else
612
+ @cpu[:P] = @cpu[:P].set_bit(7)
613
+ end
614
+ end
615
+
616
+ def sign_zero_set(byte) #Only sets flag ( in case of load or store instruction )
617
+ if byte==0
618
+ @cpu[:P] = @cpu[:P].set_bit(1)
619
+ else
620
+ @cpu[:P] = @cpu[:P].clear_bit(1)
621
+ end
622
+
623
+ if byte & 0x80 != 0
624
+ @cpu[:P] = @cpu[:P].set_bit(7)
625
+ end
626
+ end
627
+
628
+ def sign_zero_set_switch(byte) # S_z_set, mais avec le petit bonus "Carry" pour les opcodes de switch !
629
+ if byte==0
630
+ @cpu[:P] = @cpu[:P].set_bit(1)
631
+ end
632
+ if byte & 0x80 != 0
633
+ @cpu[:P] = @cpu[:P].set_bit(7)
634
+ @cpu[:P] = @cpu[:P].set_bit(0) #set carry
635
+ end
636
+ @cpu[:P] = @cpu[:P].clear_bit(0) if byte & 0x80 == 0 #clear carry
637
+ end
638
+
639
+
640
+
641
+
642
+
643
+
644
+
645
+ def read(adresse)
646
+
647
+ case adresse
648
+ when 0x2007
649
+ @ppu.registers[0x2000].bit?(2) ==1 ? @pointeur_2006+=32 : @pointeur_2006+=1
650
+
651
+
652
+ when 0x2004
653
+ @ppu.registers[0x2003] = @ppu.registers[0x2003].int8_plus(1)
654
+ end
655
+
656
+ if Registers.include?(adresse)
657
+ return @ppu.registers[adresse]
658
+ else
659
+ return @ram[adresse]
660
+ end
661
+ end
662
+
663
+
664
+
665
+ def write(adresse,value)
666
+
667
+ case adresse
668
+ when 0x2007
669
+ print value
670
+ @ppu.ppu[@pointeur_2006] = value
671
+
672
+ @ppu.registers[0x2000].bit?(2) ==1 ? @pointeur_2006+=32 : @pointeur_2006+=1
673
+
674
+ when 0x2006
675
+ if @pointeur_2006==nil
676
+ @pointeur_2006 = value
677
+ elsif @pointeur_2006 <= 0xFF
678
+ @pointeur_2006 = value + (@pointeur_2006 *256) ###CA VIENDRAIT DE Là
679
+ elsif @pointeur_2006 > 0xFF
680
+ @pointeur_2006 = value
681
+ end
682
+ until @pointeur_2006.between?(0,0x3FFF)
683
+ @pointeur_2006 -= 0x4000
684
+ end
685
+
686
+
687
+ when 0x2004
688
+ @OAM[@ppu.registers[0x2003]] = value
689
+ @ppu.registers[0x2003] = @ppu.registers[0x2003].int8_plus(1)
690
+
691
+ when 0x4014
692
+ @OAM = @ram[value*0x100..(value*0x100)+0xFF]
693
+ end
694
+
695
+ if Registers.include?(adresse)
696
+ @ppu.registers[adresse] = value
697
+ return @ppu.registers[adresse]
698
+ else
699
+ @ram[adresse] = value
700
+ return @ram[adresse]
701
+ end
702
+
703
+ end
704
+
705
+
706
+ end
707
+
708
+
709
+
710
+ #attr_accessor #googler ça
data/lib/opcodes.rb ADDED
@@ -0,0 +1 @@
1
+ OPCODES =[{:hex=>"00", :opcodes=>"BRK", :mode=>"", :len=>"1", :tim=>"7"}, {:hex=>"01", :opcodes=>"ORA", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"02", :opcodes=>"", :mode=>""}, {:hex=>"03", :opcodes=>"", :mode=>""}, {:hex=>"04", :opcodes=>"", :mode=>""}, {:hex=>"05", :opcodes=>"ORA", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"06", :opcodes=>"ASL", :mode=>"Zero Page", :len=>"2", :tim=>"5"}, {:hex=>"07", :opcodes=>"", :mode=>""}, {:hex=>"08", :len=>"1", :opcodes=>"PHP", :mode=>"", :tim=>"3"}, {:hex=>"09", :opcodes=>"ORA", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"0A", :opcodes=>"ASL", :mode=>"Accumulator", :len=>"1", :tim=>"2"}, {:hex=>"0B", :opcodes=>"", :mode=>""}, {:hex=>"0C", :opcodes=>"", :mode=>""}, {:hex=>"0D", :opcodes=>"ORA", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"0E", :opcodes=>"ASL", :mode=>"Absolute", :len=>"3", :tim=>"6"}, {:hex=>"0F", :opcodes=>"", :mode=>""}, {:hex=>"10", :opcodes=>"BPL", :len=>"2", :mode=>"", :tim=>"2"}, {:hex=>"11", :opcodes=>"ORA", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"12", :opcodes=>"", :mode=>""}, {:hex=>"13", :opcodes=>"", :mode=>""}, {:hex=>"14", :opcodes=>"", :mode=>""}, {:hex=>"15", :opcodes=>"ORA", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"16", :opcodes=>"ASL", :mode=>"Zero Page, X", :len=>"2", :tim=>"6"}, {:hex=>"17", :opcodes=>"", :mode=>""}, {:hex=>"18", :opcodes=>"CLC", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"19", :opcodes=>"ORA", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"1A", :opcodes=>"", :mode=>""}, {:hex=>"1B", :opcodes=>"", :mode=>""}, {:hex=>"1C", :opcodes=>"", :mode=>""}, {:hex=>"1D", :opcodes=>"ORA", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"1E", :opcodes=>"ASL", :mode=>"Absolute, X", :len=>"3", :tim=>"7"}, {:hex=>"1F", :opcodes=>"", :mode=>""}, {:hex=>"20", :opcodes=>"JSR", :mode=>"", :len=>"3", :tim=>"6"}, {:hex=>"21", :opcodes=>"AND", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"22", :opcodes=>"", :mode=>""}, {:hex=>"23", :opcodes=>"", :mode=>""}, {:hex=>"24", :opcodes=>"BIT", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"25", :opcodes=>"AND", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"26", :opcodes=>"ROL", :mode=>"Zero Page", :len=>"2", :tim=>"5"}, {:hex=>"27", :opcodes=>"", :mode=>""}, {:hex=>"28", :len=>"1", :opcodes=>"PLP", :mode=>"", :tim=>"4"}, {:hex=>"29", :opcodes=>"AND", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"2A", :opcodes=>"ROL", :mode=>"Accumulator", :len=>"1", :tim=>"2"}, {:hex=>"2B", :opcodes=>"", :mode=>""}, {:hex=>"2C", :opcodes=>"BIT", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"2D", :opcodes=>"AND", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"2E", :opcodes=>"ROL", :mode=>"Absolute", :len=>"3", :tim=>"6"}, {:hex=>"2F", :opcodes=>"", :mode=>""}, {:hex=>"30", :opcodes=>"BMI", :len=>"2", :mode=>"", :tim=>"2"}, {:hex=>"31", :opcodes=>"AND", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"32", :opcodes=>"", :mode=>""}, {:hex=>"33", :opcodes=>"", :mode=>""}, {:hex=>"34", :opcodes=>"", :mode=>""}, {:hex=>"35", :opcodes=>"AND", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"36", :opcodes=>"ROL", :mode=>"Zero Page, X", :len=>"2", :tim=>"6"}, {:hex=>"37", :opcodes=>"", :mode=>""}, {:hex=>"38", :opcodes=>"SEC", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"39", :opcodes=>"AND", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"3A", :opcodes=>"", :mode=>""}, {:hex=>"3B", :opcodes=>"", :mode=>""}, {:hex=>"3C", :opcodes=>"", :mode=>""}, {:hex=>"3D", :opcodes=>"AND", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"3E", :opcodes=>"ROL", :mode=>"Absolute, X", :len=>"3", :tim=>"7"}, {:hex=>"3F", :opcodes=>"", :mode=>""}, {:hex=>"40", :opcodes=>"RTI", :mode=>"", :len=>"1", :tim=>"6"}, {:hex=>"41", :opcodes=>"EOR", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"42", :opcodes=>"", :mode=>""}, {:hex=>"43", :opcodes=>"", :mode=>""}, {:hex=>"44", :opcodes=>"", :mode=>""}, {:hex=>"45", :opcodes=>"EOR", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"46", :opcodes=>"LSR", :mode=>"Zero Page", :len=>"2", :tim=>"5"}, {:hex=>"47", :opcodes=>"", :mode=>""}, {:hex=>"48", :len=>"1", :opcodes=>"PHA", :mode=>"", :tim=>"3"}, {:hex=>"49", :opcodes=>"EOR", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"4A", :opcodes=>"LSR", :mode=>"Accumulator", :len=>"1", :tim=>"2"}, {:hex=>"4B", :opcodes=>"", :mode=>""}, {:hex=>"4C", :opcodes=>"JMP", :mode=>"Absolute", :len=>"3", :tim=>"3"}, {:hex=>"4D", :opcodes=>"EOR", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"4E", :opcodes=>"LSR", :mode=>"Absolute", :len=>"3", :tim=>"6"}, {:hex=>"4F", :opcodes=>"", :mode=>""}, {:hex=>"50",:len=>"2", :opcodes=>"BVC", :mode=>"", :tim=>"2"}, {:hex=>"51", :opcodes=>"EOR", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"52", :opcodes=>"", :mode=>""}, {:hex=>"53", :opcodes=>"", :mode=>""}, {:hex=>"54", :opcodes=>"", :mode=>""}, {:hex=>"55", :opcodes=>"EOR", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"56", :opcodes=>"LSR", :mode=>"Zero Page, X", :len=>"2", :tim=>"6"}, {:hex=>"57", :opcodes=>"", :mode=>""}, {:hex=>"58", :opcodes=>"CLI", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"59", :opcodes=>"EOR", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"5A", :opcodes=>"", :mode=>""}, {:hex=>"5B", :opcodes=>"", :mode=>""}, {:hex=>"5C", :opcodes=>"", :mode=>""}, {:hex=>"5D", :opcodes=>"EOR", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"5E", :opcodes=>"LSR", :mode=>"Absolute, X", :len=>"3", :tim=>"7"}, {:hex=>"5F", :opcodes=>"", :mode=>""}, {:hex=>"60", :opcodes=>"RTS", :mode=>"", :len=>"1", :tim=>"6"}, {:hex=>"61", :opcodes=>"ADC", :len=>"2", :tim=>"6", :mode=>"(Indirect, X)"}, {:hex=>"62", :opcodes=>"", :mode=>""}, {:hex=>"63", :opcodes=>"", :mode=>""}, {:hex=>"64", :opcodes=>"", :mode=>""}, {:hex=>"65", :opcodes=>"ADC", :tim=>"3", :len=>"2", :mode=>"Zero Page"}, {:hex=>"66", :opcodes=>"ROR", :mode=>"Zero Page", :len=>"2", :tim=>"5"}, {:hex=>"67", :opcodes=>"", :mode=>""}, {:hex=>"68", :len=>"1", :opcodes=>"PLA", :mode=>"", :tim=>"4"}, {:hex=>"69", :opcodes=>"ADC", :tim=>"2", :len=>"2", :mode=>"Immediate"}, {:hex=>"6A", :opcodes=>"ROR", :mode=>"Accumulator", :len=>"1", :tim=>"2"}, {:hex=>"6B", :opcodes=>"", :mode=>""}, {:hex=>"6C", :opcodes=>"JMP", :mode=>"Indirect", :len=>"3", :tim=>"5"}, {:hex=>"6D", :opcodes=>"ADC", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"6E", :opcodes=>"ROR", :mode=>"Absolute", :len=>"3", :tim=>"6"}, {:hex=>"6F", :opcodes=>"", :mode=>""}, {:hex=>"70", :len=>"2", :opcodes=>"BVS", :mode=>"", :tim=>"2"}, {:hex=>"71", :opcodes=>"ADC", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"72", :opcodes=>"", :mode=>""}, {:hex=>"73", :opcodes=>"", :mode=>""}, {:hex=>"74", :opcodes=>"", :mode=>""}, {:hex=>"75", :opcodes=>"ADC", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"76", :opcodes=>"ROR", :mode=>"Zero Page, X", :len=>"2", :tim=>"6"}, {:hex=>"77", :opcodes=>"", :mode=>""}, {:hex=>"78", :opcodes=>"SEI", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"79", :opcodes=>"ADC", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"7A", :opcodes=>"", :mode=>""}, {:hex=>"7B", :opcodes=>"", :mode=>""}, {:hex=>"7C", :opcodes=>"", :mode=>""}, {:hex=>"7D", :opcodes=>"ADC", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"7E", :opcodes=>"ROR", :mode=>"Absolute, X", :len=>"3", :tim=>"7"}, {:hex=>"7F", :opcodes=>"", :mode=>""}, {:hex=>"80", :opcodes=>"", :mode=>""}, {:hex=>"81", :opcodes=>"STA", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"82", :opcodes=>"", :mode=>""}, {:hex=>"83", :opcodes=>"", :mode=>""}, {:hex=>"84", :opcodes=>"STY", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"85", :opcodes=>"STA", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"86", :opcodes=>"STX", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"87", :opcodes=>"", :mode=>""}, {:hex=>"88", :len=>"1", :opcodes=>"DEY", :mode=>"", :tim=>"2"}, {:hex=>"89", :opcodes=>"", :mode=>""}, {:hex=>"8A", :opcodes=>"TXA", :mode=>"", :len=>"1", :tim=>"2"}, {:hex=>"8B", :opcodes=>"", :mode=>""}, {:hex=>"8C", :opcodes=>"STY", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"8D", :opcodes=>"STA", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"8E", :opcodes=>"STX", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"8F", :opcodes=>"", :mode=>""}, {:hex=>"90", :len=>"2", :opcodes=>"BCC", :mode=>"", :tim=>"2"}, {:hex=>"91", :opcodes=>"STA", :mode=>"(Indirect), Y", :len=>"2", :tim=>"6"}, {:hex=>"92", :opcodes=>"", :mode=>""}, {:hex=>"93", :opcodes=>"", :mode=>""}, {:hex=>"94", :opcodes=>"STY", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"95", :opcodes=>"STA", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"96", :opcodes=>"STX", :mode=>"Zero Page, Y", :len=>"2", :tim=>"4"}, {:hex=>"97", :opcodes=>"", :mode=>""}, {:hex=>"98", :len=>"1", :opcodes=>"TYA", :mode=>"", :tim=>"2"}, {:hex=>"99", :opcodes=>"STA", :mode=>"Absolute, Y", :len=>"3", :tim=>"5"}, {:hex=>"9A", :len=>"1", :opcodes=>"TXS", :mode=>"", :tim=>"2"}, {:hex=>"9B", :opcodes=>"", :mode=>""}, {:hex=>"9C", :opcodes=>"", :mode=>""}, {:hex=>"9D", :opcodes=>"STA", :mode=>"Absolute, X", :len=>"3", :tim=>"5"}, {:hex=>"9E", :opcodes=>"", :mode=>""}, {:hex=>"9F", :opcodes=>"", :mode=>""}, {:hex=>"A0", :opcodes=>"LDY", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"A1", :opcodes=>"LDA", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"A2", :opcodes=>"LDX", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"A3", :opcodes=>"", :mode=>""}, {:hex=>"A4", :opcodes=>"LDY", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"A5", :opcodes=>"LDA", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"A6", :opcodes=>"LDX", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"A7", :opcodes=>"", :mode=>""}, {:hex=>"A8", :len=>"1", :opcodes=>"TAY", :mode=>"", :tim=>"2"}, {:hex=>"A9", :opcodes=>"LDA", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"AA", :len=>"1", :opcodes=>"TAX", :mode=>"", :tim=>"2"}, {:hex=>"AB", :opcodes=>"", :mode=>""}, {:hex=>"AC", :opcodes=>"LDY", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"AD", :opcodes=>"LDA", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"AE", :opcodes=>"LDX", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"AF", :opcodes=>"", :mode=>""}, {:hex=>"B0", :len=>"2", :opcodes=>"BCS", :mode=>"", :tim=>"2"}, {:hex=>"B1", :opcodes=>"LDA", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"B2", :opcodes=>"", :mode=>""}, {:hex=>"B3", :opcodes=>"", :mode=>""}, {:hex=>"B4", :opcodes=>"LDY", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"B5", :opcodes=>"LDA", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"B6", :opcodes=>"LDX", :mode=>"Zero Page, Y", :len=>"2", :tim=>"4"}, {:hex=>"B7", :opcodes=>"", :mode=>""}, {:hex=>"B8", :opcodes=>"CLV", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"B9", :opcodes=>"LDA", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"BA", :len=>"1", :opcodes=>"TSX", :mode=>"", :tim=>"2"}, {:hex=>"BB", :opcodes=>"", :mode=>""}, {:hex=>"BC", :opcodes=>"LDY", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"BD", :opcodes=>"LDA", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"BE", :opcodes=>"LDX", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"BF", :opcodes=>"", :mode=>""}, {:hex=>"C0", :opcodes=>"CPY", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"C1", :opcodes=>"CMP", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"C2", :opcodes=>"", :mode=>""}, {:hex=>"C3", :opcodes=>"", :mode=>""}, {:hex=>"C4", :opcodes=>"CPY", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"C5", :opcodes=>"CMP", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"C6", :opcodes=>"DEC", :mode=>"Zero Page", :len=>"2", :tim=>"5"}, {:hex=>"C7", :opcodes=>"", :mode=>""}, {:hex=>"C8", :len=>"1", :opcodes=>"INY", :mode=>"", :tim=>"2"}, {:hex=>"C9", :opcodes=>"CMP", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"CA", :opcodes=>"DEX", :len=>"1", :mode=>"", :tim=>"2"}, {:hex=>"CB", :opcodes=>"", :mode=>""}, {:hex=>"CC", :opcodes=>"CPY", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"CD", :opcodes=>"CMP", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"CE", :opcodes=>"DEC", :mode=>"Absolute", :len=>"3", :tim=>"6"}, {:hex=>"CF", :opcodes=>"", :mode=>""}, {:hex=>"D0", :len=>"2", :opcodes=>"BNE", :mode=>"", :tim=>"2"}, {:hex=>"D1", :opcodes=>"CMP", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"D2", :opcodes=>"", :mode=>""}, {:hex=>"D3", :opcodes=>"", :mode=>""}, {:hex=>"D4", :opcodes=>"", :mode=>""}, {:hex=>"D5", :opcodes=>"CMP", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"D6", :opcodes=>"DEC", :mode=>"Zero Page, X", :len=>"2", :tim=>"6"}, {:hex=>"D7", :opcodes=>"", :mode=>""}, {:hex=>"D8", :opcodes=>"CLD", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"D9", :opcodes=>"CMP", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"DA", :opcodes=>"", :mode=>""}, {:hex=>"DB", :opcodes=>"", :mode=>""}, {:hex=>"DC", :opcodes=>"", :mode=>""}, {:hex=>"DD", :opcodes=>"CMP", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"DE", :opcodes=>"DEC", :mode=>"Absolute, X", :len=>"3", :tim=>"7"}, {:hex=>"DF", :opcodes=>"", :mode=>""}, {:hex=>"E0", :opcodes=>"CPX", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"E1", :opcodes=>"SBC", :mode=>"(Indirect, X)", :len=>"2", :tim=>"6"}, {:hex=>"E2", :opcodes=>"", :mode=>""}, {:hex=>"E3", :opcodes=>"", :mode=>""}, {:hex=>"E4", :opcodes=>"CPX", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"E5", :opcodes=>"SBC", :mode=>"Zero Page", :len=>"2", :tim=>"3"}, {:hex=>"E6", :opcodes=>"INC", :mode=>"Zero Page", :len=>"2", :tim=>"5"}, {:hex=>"E7", :opcodes=>"", :mode=>""}, {:hex=>"E8", :opcodes=>"INX", :len=>"1", :mode=>"", :tim=>"2"}, {:hex=>"E9", :opcodes=>"SBC", :mode=>"Immediate", :len=>"2", :tim=>"2"}, {:hex=>"EA", :opcodes=>"NOP", :mode=>"", :len=>"1", :tim=>"2"}, {:hex=>"EB", :opcodes=>"", :mode=>""}, {:hex=>"EC", :opcodes=>"CPX", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"ED", :opcodes=>"SBC", :mode=>"Absolute", :len=>"3", :tim=>"4"}, {:hex=>"EE", :opcodes=>"INC", :mode=>"Absolute", :len=>"3", :tim=>"6"}, {:hex=>"EF", :opcodes=>"", :mode=>""}, {:hex=>"F0", :len=>"2", :opcodes=>"BEQ", :mode=>"", :tim=>"2"}, {:hex=>"F1", :opcodes=>"SBC", :mode=>"(Indirect), Y", :len=>"2", :tim=>"5+"}, {:hex=>"F2", :opcodes=>"", :mode=>""}, {:hex=>"F3", :opcodes=>"", :mode=>""}, {:hex=>"F4", :opcodes=>"", :mode=>""}, {:hex=>"F5", :opcodes=>"SBC", :mode=>"Zero Page, X", :len=>"2", :tim=>"4"}, {:hex=>"F6", :opcodes=>"INC", :mode=>"Zero Page, X", :len=>"2", :tim=>"6"}, {:hex=>"F7", :opcodes=>"", :mode=>""}, {:hex=>"F8", :opcodes=>"SED", :len =>"1", :tim =>"2", :mode=>""}, {:hex=>"F9", :opcodes=>"SBC", :mode=>"Absolute, Y", :len=>"3", :tim=>"4+"}, {:hex=>"FA", :opcodes=>"", :mode=>""}, {:hex=>"FB", :opcodes=>"", :mode=>""}, {:hex=>"FC", :opcodes=>"", :mode=>""}, {:hex=>"FD", :opcodes=>"SBC", :mode=>"Absolute, X", :len=>"3", :tim=>"4+"}, {:hex=>"FE", :opcodes=>"INC", :mode=>"Absolute, X", :len=>"3", :tim=>"7"}, {:hex=>"FF", :opcodes=>"", :mode=>""}]
data/lib/ppu.rb ADDED
@@ -0,0 +1,95 @@
1
+ Registers = [0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,0x4014]
2
+
3
+ class Ppu
4
+ attr_accessor :ppu
5
+ attr_accessor :registers
6
+ attr_accessor :screen
7
+
8
+
9
+ def initialize()
10
+ @ppu = [0]*0x4000
11
+ @registers = {}
12
+ Registers.each {|adresse| @registers[adresse] = 0}
13
+ init_affichage
14
+ end
15
+
16
+
17
+ def init_affichage()
18
+ SDL.init SDL::INIT_VIDEO
19
+ @screen = SDL::set_video_mode 256, 240, 32, SDL::SWSURFACE
20
+ reset_pixel
21
+ end
22
+
23
+
24
+ def reset_pixel()
25
+ @x = @y = 0
26
+ end
27
+
28
+
29
+ def get_bit(liste_octets,ligne,bit)
30
+ return (liste_octets[ligne].bit?(7-bit) | liste_octets[ligne+8].bit?(7-bit) << 1)
31
+ end
32
+
33
+ def get_pixel(x,y)
34
+ set_tables
35
+ pos_tile = (y/8)*32+(x/8)
36
+ index = @table_nommage_screen[pos_tile] * 16
37
+ pixel = get_bit(@screen_pattern_table[index..index+15],y%8,x%8)
38
+ return pixel
39
+
40
+ end
41
+
42
+ def color?(color)
43
+ rgb = case color
44
+ when 0 then [124,124,124]
45
+ when 1 then [0,0,22]
46
+ when 2 then [0,0,18]
47
+ when 3 then [64,40,188]
48
+ end
49
+ return rgb
50
+ end
51
+
52
+ def set_tables()
53
+ @sprite_pattern_table = case @registers[0x2000].bit?(3)
54
+ when 0 then @ppu[0x0..0x0FFF]
55
+ when 1 then @ppu[0x1000..0x1FFF]
56
+ end
57
+
58
+ @screen_pattern_table = case @registers[0x2000].bit?(4)
59
+ when 0 then @ppu[0x0..0x0FFF]
60
+ when 1 then @ppu[0x1000..0x1FFF]
61
+ end
62
+
63
+ @sprite_size = @registers[0x2000].bit?(5)
64
+
65
+ @table_nommage_screen = @ppu[0x2000..0x23C0] if @registers[0x2000].bit?(1) == 0 and @registers[0x2000].bit?(0) == 0
66
+ @table_nommage_screen = @ppu[0x2400..0x27C0] if @registers[0x2000].bit?(1) == 0 and @registers[0x2000].bit?(0) == 1
67
+ @table_nommage_screen = @ppu[0x2800..0x2BC0] if @registers[0x2000].bit?(1) == 1 and @registers[0x2000].bit?(0) == 0
68
+ @table_nommage_screen = @ppu[0x2C00..0x2FC0] if @registers[0x2000].bit?(1) == 1 and @registers[0x2000].bit?(0) == 1
69
+
70
+
71
+ end
72
+
73
+
74
+ def set_vblank()
75
+ @registers[0x2002] = @registers[0x2002].set_bit(7) #Set du Vblank
76
+ end
77
+
78
+ def clear_vblank()
79
+ @registers[0x2002] = @registers[0x2002].clear_bit(7) #Clear du Vblank
80
+ end
81
+
82
+
83
+ def draw_screen()
84
+ @screen.putPixel(@x,@y,color?(get_pixel(@x,@y)))
85
+ @x+=1
86
+ if @x>255
87
+ @x = 0
88
+ @y+=1
89
+ elsif @y>239
90
+ reset_pixel
91
+ end
92
+
93
+ end
94
+
95
+ end
data/nesemul.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'nesemul'
3
+ s.version = '0.0.1'
4
+ s.date = '2013-12-02'
5
+ s.summary = "NesEmul"
6
+ s.description = "Nes Emulator"
7
+ s.authors = ["Galaad Gauthier"]
8
+ s.email = 'coontail7@gmail.com'
9
+ s.files = Dir['**/*']
10
+ s.executables = ["nesemul"]
11
+ s.require_path = 'lib'
12
+ s.homepage =
13
+ 'https://github.com/Galaad-Gauthier/NesEmul'
14
+ s.license = 'MIT'
15
+ s.add_dependency "json"
16
+ s.add_dependency "sdl"
17
+ end
data/roms/mario.nes ADDED
Binary file
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nesemul
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Galaad Gauthier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sdl
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Nes Emulator
42
+ email: coontail7@gmail.com
43
+ executables:
44
+ - nesemul
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/bitwise.rb
49
+ - lib/opcodes.rb
50
+ - lib/cpu.rb
51
+ - lib/ppu.rb
52
+ - roms/mario.nes
53
+ - nesemul.gemspec
54
+ - bin/nesemul
55
+ - README.md
56
+ homepage: https://github.com/Galaad-Gauthier/NesEmul
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.0.14
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: NesEmul
80
+ test_files: []