ruby6502 0.1.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 +7 -0
- data/ext/ruby6502/extconf.rb +5 -0
- data/ext/ruby6502/fake6502.c +1055 -0
- data/ext/ruby6502/fake6502.h +20 -0
- data/ext/ruby6502/ruby6502.c +253 -0
- data/lib/ruby6502/version.rb +5 -0
- data/lib/ruby6502.rb +96 -0
- metadata +119 -0
@@ -0,0 +1,1055 @@
|
|
1
|
+
/* Fake6502 CPU emulator core v1.1 *******************
|
2
|
+
* (c)2011 Mike Chambers (miker00lz@gmail.com) *
|
3
|
+
*****************************************************
|
4
|
+
* v1.1 - Small bugfix in BIT opcode, but it was the *
|
5
|
+
* difference between a few games in my NES *
|
6
|
+
* emulator working and being broken! *
|
7
|
+
* I went through the rest carefully again *
|
8
|
+
* after fixing it just to make sure I didn't *
|
9
|
+
* have any other typos! (Dec. 17, 2011) *
|
10
|
+
* *
|
11
|
+
* v1.0 - First release (Nov. 24, 2011) *
|
12
|
+
*****************************************************
|
13
|
+
* LICENSE: This source code is released into the *
|
14
|
+
* public domain, but if you use it please do give *
|
15
|
+
* credit. I put a lot of effort into writing this! *
|
16
|
+
* *
|
17
|
+
*****************************************************
|
18
|
+
* Fake6502 is a MOS Technology 6502 CPU emulation *
|
19
|
+
* engine in C. It was written as part of a Nintendo *
|
20
|
+
* Entertainment System emulator I've been writing. *
|
21
|
+
* *
|
22
|
+
* A couple important things to know about are two *
|
23
|
+
* defines in the code. One is "UNDOCUMENTED" which, *
|
24
|
+
* when defined, allows Fake6502 to compile with *
|
25
|
+
* full support for the more predictable *
|
26
|
+
* undocumented instructions of the 6502. If it is *
|
27
|
+
* undefined, undocumented opcodes just act as NOPs. *
|
28
|
+
* *
|
29
|
+
* The other define is "NES_CPU", which causes the *
|
30
|
+
* code to compile without support for binary-coded *
|
31
|
+
* decimal (BCD) support for the ADC and SBC *
|
32
|
+
* opcodes. The Ricoh 2A03 CPU in the NES does not *
|
33
|
+
* support BCD, but is otherwise identical to the *
|
34
|
+
* standard MOS 6502. (Note that this define is *
|
35
|
+
* enabled in this file if you haven't changed it *
|
36
|
+
* yourself. If you're not emulating a NES, you *
|
37
|
+
* should comment it out.) *
|
38
|
+
* *
|
39
|
+
* If you do discover an error in timing accuracy, *
|
40
|
+
* or operation in general please e-mail me at the *
|
41
|
+
* address above so that I can fix it. Thank you! *
|
42
|
+
* *
|
43
|
+
*****************************************************
|
44
|
+
* Usage: *
|
45
|
+
* *
|
46
|
+
* Fake6502 requires you to provide two external *
|
47
|
+
* functions: *
|
48
|
+
* *
|
49
|
+
* uint8_t read6502(uint16_t address) *
|
50
|
+
* void write6502(uint16_t address, uint8_t value) *
|
51
|
+
* *
|
52
|
+
* You may optionally pass Fake6502 the pointer to a *
|
53
|
+
* function which you want to be called after every *
|
54
|
+
* emulated instruction. This function should be a *
|
55
|
+
* void with no parameters expected to be passed to *
|
56
|
+
* it. *
|
57
|
+
* *
|
58
|
+
* This can be very useful. For example, in a NES *
|
59
|
+
* emulator, you check the number of clock ticks *
|
60
|
+
* that have passed so you can know when to handle *
|
61
|
+
* APU events. *
|
62
|
+
* *
|
63
|
+
* To pass Fake6502 this pointer, use the *
|
64
|
+
* hookexternal(void *funcptr) function provided. *
|
65
|
+
* *
|
66
|
+
* To disable the hook later, pass NULL to it. *
|
67
|
+
*****************************************************
|
68
|
+
* Useful functions in this emulator: *
|
69
|
+
* *
|
70
|
+
* void reset6502() *
|
71
|
+
* - Call this once before you begin execution. *
|
72
|
+
* *
|
73
|
+
* void exec6502(uint32_t tickcount) *
|
74
|
+
* - Execute 6502 code up to the next specified *
|
75
|
+
* count of clock ticks. *
|
76
|
+
* *
|
77
|
+
* void step6502() *
|
78
|
+
* - Execute a single instrution. *
|
79
|
+
* *
|
80
|
+
* void irq6502() *
|
81
|
+
* - Trigger a hardware IRQ in the 6502 core. *
|
82
|
+
* *
|
83
|
+
* void nmi6502() *
|
84
|
+
* - Trigger an NMI in the 6502 core. *
|
85
|
+
* *
|
86
|
+
* void hookexternal(void *funcptr) *
|
87
|
+
* - Pass a pointer to a void function taking no *
|
88
|
+
* parameters. This will cause Fake6502 to call *
|
89
|
+
* that function once after each emulated *
|
90
|
+
* instruction. *
|
91
|
+
* *
|
92
|
+
*****************************************************
|
93
|
+
* Useful variables in this emulator: *
|
94
|
+
* *
|
95
|
+
* uint32_t clockticks6502 *
|
96
|
+
* - A running total of the emulated cycle count. *
|
97
|
+
* *
|
98
|
+
* uint32_t instructions *
|
99
|
+
* - A running total of the total emulated *
|
100
|
+
* instruction count. This is not related to *
|
101
|
+
* clock cycle timing. *
|
102
|
+
* *
|
103
|
+
*****************************************************/
|
104
|
+
|
105
|
+
#include <stdio.h>
|
106
|
+
#include <stdint.h>
|
107
|
+
#include "fake6502.h"
|
108
|
+
|
109
|
+
//6502 defines
|
110
|
+
//#define UNDOCUMENTED //when this is defined, undocumented opcodes are handled.
|
111
|
+
//otherwise, they're simply treated as NOPs.
|
112
|
+
|
113
|
+
//#define NES_CPU //when this is defined, the binary-coded decimal (BCD)
|
114
|
+
//status flag is not honored by ADC and SBC. the 2A03
|
115
|
+
//CPU in the Nintendo Entertainment System does not
|
116
|
+
//support BCD operation.
|
117
|
+
|
118
|
+
#define FLAG_CARRY 0x01
|
119
|
+
#define FLAG_ZERO 0x02
|
120
|
+
#define FLAG_INTERRUPT 0x04
|
121
|
+
#define FLAG_DECIMAL 0x08
|
122
|
+
#define FLAG_BREAK 0x10
|
123
|
+
#define FLAG_CONSTANT 0x20
|
124
|
+
#define FLAG_OVERFLOW 0x40
|
125
|
+
#define FLAG_SIGN 0x80
|
126
|
+
|
127
|
+
#define BASE_STACK 0x100
|
128
|
+
|
129
|
+
#define saveaccum(n) a = (uint8_t)((n) & 0x00FF)
|
130
|
+
|
131
|
+
|
132
|
+
//flag modifier macros
|
133
|
+
#define setcarry() status |= FLAG_CARRY
|
134
|
+
#define clearcarry() status &= (~FLAG_CARRY)
|
135
|
+
#define setzero() status |= FLAG_ZERO
|
136
|
+
#define clearzero() status &= (~FLAG_ZERO)
|
137
|
+
#define setinterrupt() status |= FLAG_INTERRUPT
|
138
|
+
#define clearinterrupt() status &= (~FLAG_INTERRUPT)
|
139
|
+
#define setdecimal() status |= FLAG_DECIMAL
|
140
|
+
#define cleardecimal() status &= (~FLAG_DECIMAL)
|
141
|
+
#define setoverflow() status |= FLAG_OVERFLOW
|
142
|
+
#define clearoverflow() status &= (~FLAG_OVERFLOW)
|
143
|
+
#define setsign() status |= FLAG_SIGN
|
144
|
+
#define clearsign() status &= (~FLAG_SIGN)
|
145
|
+
|
146
|
+
|
147
|
+
//flag calculation macros
|
148
|
+
#define zerocalc(n) {\
|
149
|
+
if ((n) & 0x00FF) clearzero();\
|
150
|
+
else setzero();\
|
151
|
+
}
|
152
|
+
|
153
|
+
#define signcalc(n) {\
|
154
|
+
if ((n) & 0x0080) setsign();\
|
155
|
+
else clearsign();\
|
156
|
+
}
|
157
|
+
|
158
|
+
#define carrycalc(n) {\
|
159
|
+
if ((n) & 0xFF00) setcarry();\
|
160
|
+
else clearcarry();\
|
161
|
+
}
|
162
|
+
|
163
|
+
#define overflowcalc(n, m, o) { /* n = result, m = accumulator, o = memory */ \
|
164
|
+
if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) setoverflow();\
|
165
|
+
else clearoverflow();\
|
166
|
+
}
|
167
|
+
|
168
|
+
|
169
|
+
//6502 CPU registers
|
170
|
+
uint16_t pc;
|
171
|
+
uint8_t sp, a, x, y, status;
|
172
|
+
|
173
|
+
|
174
|
+
//helper variables
|
175
|
+
uint64_t instructions = 0; //keep track of total instructions executed
|
176
|
+
uint64_t clockticks6502 = 0, clockgoal6502 = 0;
|
177
|
+
uint16_t oldpc, ea, reladdr, value, result;
|
178
|
+
uint8_t opcode, oldstatus;
|
179
|
+
|
180
|
+
//externally supplied functions
|
181
|
+
extern uint8_t read6502(uint16_t address);
|
182
|
+
extern void write6502(uint16_t address, uint8_t value);
|
183
|
+
|
184
|
+
//a few general functions used by various other functions
|
185
|
+
void push16(uint16_t pushval) {
|
186
|
+
write6502(BASE_STACK + sp, (pushval >> 8) & 0xFF);
|
187
|
+
write6502(BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF);
|
188
|
+
sp -= 2;
|
189
|
+
}
|
190
|
+
|
191
|
+
void push8(uint8_t pushval) {
|
192
|
+
write6502(BASE_STACK + sp--, pushval);
|
193
|
+
}
|
194
|
+
|
195
|
+
uint16_t pull16() {
|
196
|
+
uint16_t temp16;
|
197
|
+
temp16 = read6502(BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t)read6502(BASE_STACK + ((sp + 2) & 0xFF)) << 8);
|
198
|
+
sp += 2;
|
199
|
+
return(temp16);
|
200
|
+
}
|
201
|
+
|
202
|
+
uint8_t pull8() {
|
203
|
+
return (read6502(BASE_STACK + ++sp));
|
204
|
+
}
|
205
|
+
|
206
|
+
void reset6502() {
|
207
|
+
pc = (uint16_t)read6502(0xFFFC) | ((uint16_t)read6502(0xFFFD) << 8);
|
208
|
+
a = 0;
|
209
|
+
x = 0;
|
210
|
+
y = 0;
|
211
|
+
sp = 0xFD;
|
212
|
+
status = FLAG_CONSTANT;
|
213
|
+
instructions = 0;
|
214
|
+
clockticks6502 = 0;
|
215
|
+
clockgoal6502 = 0;
|
216
|
+
}
|
217
|
+
|
218
|
+
|
219
|
+
static void (*addrtable[256])();
|
220
|
+
static void (*optable[256])();
|
221
|
+
uint8_t penaltyop, penaltyaddr;
|
222
|
+
|
223
|
+
//addressing mode functions, calculates effective addresses
|
224
|
+
static void imp() { //implied
|
225
|
+
}
|
226
|
+
|
227
|
+
static void acc() { //accumulator
|
228
|
+
}
|
229
|
+
|
230
|
+
static void imm() { //immediate
|
231
|
+
ea = pc++;
|
232
|
+
}
|
233
|
+
|
234
|
+
static void zp() { //zero-page
|
235
|
+
ea = (uint16_t)read6502((uint16_t)pc++);
|
236
|
+
}
|
237
|
+
|
238
|
+
static void zpx() { //zero-page,X
|
239
|
+
ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)x) & 0xFF; //zero-page wraparound
|
240
|
+
}
|
241
|
+
|
242
|
+
static void zpy() { //zero-page,Y
|
243
|
+
ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)y) & 0xFF; //zero-page wraparound
|
244
|
+
}
|
245
|
+
|
246
|
+
static void rel() { //relative for branch ops (8-bit immediate value, sign-extended)
|
247
|
+
reladdr = (uint16_t)read6502(pc++);
|
248
|
+
if (reladdr & 0x80) reladdr |= 0xFF00;
|
249
|
+
}
|
250
|
+
|
251
|
+
static void abso() { //absolute
|
252
|
+
ea = (uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8);
|
253
|
+
pc += 2;
|
254
|
+
}
|
255
|
+
|
256
|
+
static void absx() { //absolute,X
|
257
|
+
uint16_t startpage;
|
258
|
+
ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8));
|
259
|
+
startpage = ea & 0xFF00;
|
260
|
+
ea += (uint16_t)x;
|
261
|
+
|
262
|
+
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
|
263
|
+
penaltyaddr = 1;
|
264
|
+
}
|
265
|
+
|
266
|
+
pc += 2;
|
267
|
+
}
|
268
|
+
|
269
|
+
static void absy() { //absolute,Y
|
270
|
+
uint16_t startpage;
|
271
|
+
ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8));
|
272
|
+
startpage = ea & 0xFF00;
|
273
|
+
ea += (uint16_t)y;
|
274
|
+
|
275
|
+
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
|
276
|
+
penaltyaddr = 1;
|
277
|
+
}
|
278
|
+
|
279
|
+
pc += 2;
|
280
|
+
}
|
281
|
+
|
282
|
+
static void ind() { //indirect
|
283
|
+
uint16_t eahelp, eahelp2;
|
284
|
+
eahelp = (uint16_t)read6502(pc) | (uint16_t)((uint16_t)read6502(pc+1) << 8);
|
285
|
+
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug
|
286
|
+
ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8);
|
287
|
+
pc += 2;
|
288
|
+
}
|
289
|
+
|
290
|
+
static void indx() { // (indirect,X)
|
291
|
+
uint16_t eahelp;
|
292
|
+
eahelp = (uint16_t)(((uint16_t)read6502(pc++) + (uint16_t)x) & 0xFF); //zero-page wraparound for table pointer
|
293
|
+
ea = (uint16_t)read6502(eahelp & 0x00FF) | ((uint16_t)read6502((eahelp+1) & 0x00FF) << 8);
|
294
|
+
}
|
295
|
+
|
296
|
+
static void indy() { // (indirect),Y
|
297
|
+
uint16_t eahelp, eahelp2, startpage;
|
298
|
+
eahelp = (uint16_t)read6502(pc++);
|
299
|
+
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //zero-page wraparound
|
300
|
+
ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8);
|
301
|
+
startpage = ea & 0xFF00;
|
302
|
+
ea += (uint16_t)y;
|
303
|
+
|
304
|
+
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
|
305
|
+
penaltyaddr = 1;
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
static uint16_t getvalue() {
|
310
|
+
if (addrtable[opcode] == acc) return((uint16_t)a);
|
311
|
+
else return((uint16_t)read6502(ea));
|
312
|
+
}
|
313
|
+
|
314
|
+
static uint16_t getvalue16() {
|
315
|
+
return((uint16_t)read6502(ea) | ((uint16_t)read6502(ea+1) << 8));
|
316
|
+
}
|
317
|
+
|
318
|
+
static void putvalue(uint16_t saveval) {
|
319
|
+
if (addrtable[opcode] == acc) a = (uint8_t)(saveval & 0x00FF);
|
320
|
+
else write6502(ea, (saveval & 0x00FF));
|
321
|
+
}
|
322
|
+
|
323
|
+
|
324
|
+
//instruction handler functions
|
325
|
+
|
326
|
+
// Original adc which does not handle BCD mode
|
327
|
+
// static void adc() {
|
328
|
+
// penaltyop = 1;
|
329
|
+
// value = getvalue();
|
330
|
+
// result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
|
331
|
+
|
332
|
+
// carrycalc(result);
|
333
|
+
// zerocalc(result);
|
334
|
+
// overflowcalc(result, a, value);
|
335
|
+
// signcalc(result);
|
336
|
+
|
337
|
+
// #ifndef NES_CPU
|
338
|
+
// if (status & FLAG_DECIMAL) {
|
339
|
+
// clearcarry();
|
340
|
+
|
341
|
+
// if ((a & 0x0F) > 0x09) {
|
342
|
+
// a += 0x06;
|
343
|
+
// }
|
344
|
+
// if ((a & 0xF0) > 0x90) {
|
345
|
+
// a += 0x60;
|
346
|
+
// setcarry();
|
347
|
+
// }
|
348
|
+
|
349
|
+
// clockticks6502++;
|
350
|
+
// }
|
351
|
+
// #endif
|
352
|
+
|
353
|
+
// saveaccum(result);
|
354
|
+
// }
|
355
|
+
// from http://forum.6502.org/viewtopic.php?f=2&t=2052#p37758
|
356
|
+
static void adc() {
|
357
|
+
penaltyop = 1;
|
358
|
+
value = getvalue();
|
359
|
+
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
|
360
|
+
|
361
|
+
zerocalc(result);
|
362
|
+
overflowcalc(result, a, value);
|
363
|
+
signcalc(result);
|
364
|
+
|
365
|
+
#ifndef NES_CPU
|
366
|
+
if (status & FLAG_DECIMAL) /* detect and apply BCD nybble carries */
|
367
|
+
result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
|
368
|
+
#endif
|
369
|
+
|
370
|
+
carrycalc(result);
|
371
|
+
saveaccum(result);
|
372
|
+
}
|
373
|
+
|
374
|
+
static void and() {
|
375
|
+
penaltyop = 1;
|
376
|
+
value = getvalue();
|
377
|
+
result = (uint16_t)a & value;
|
378
|
+
|
379
|
+
zerocalc(result);
|
380
|
+
signcalc(result);
|
381
|
+
|
382
|
+
saveaccum(result);
|
383
|
+
}
|
384
|
+
|
385
|
+
static void asl() {
|
386
|
+
value = getvalue();
|
387
|
+
result = value << 1;
|
388
|
+
|
389
|
+
carrycalc(result);
|
390
|
+
zerocalc(result);
|
391
|
+
signcalc(result);
|
392
|
+
|
393
|
+
putvalue(result);
|
394
|
+
}
|
395
|
+
|
396
|
+
static void bcc() {
|
397
|
+
if ((status & FLAG_CARRY) == 0) {
|
398
|
+
oldpc = pc;
|
399
|
+
pc += reladdr;
|
400
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
401
|
+
else clockticks6502++;
|
402
|
+
}
|
403
|
+
}
|
404
|
+
|
405
|
+
static void bcs() {
|
406
|
+
if ((status & FLAG_CARRY) == FLAG_CARRY) {
|
407
|
+
oldpc = pc;
|
408
|
+
pc += reladdr;
|
409
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
410
|
+
else clockticks6502++;
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
static void beq() {
|
415
|
+
if ((status & FLAG_ZERO) == FLAG_ZERO) {
|
416
|
+
oldpc = pc;
|
417
|
+
pc += reladdr;
|
418
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
419
|
+
else clockticks6502++;
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
static void bit() {
|
424
|
+
value = getvalue();
|
425
|
+
result = (uint16_t)a & value;
|
426
|
+
|
427
|
+
zerocalc(result);
|
428
|
+
status = (status & 0x3F) | (uint8_t)(value & 0xC0);
|
429
|
+
}
|
430
|
+
|
431
|
+
static void bmi() {
|
432
|
+
if ((status & FLAG_SIGN) == FLAG_SIGN) {
|
433
|
+
oldpc = pc;
|
434
|
+
pc += reladdr;
|
435
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
436
|
+
else clockticks6502++;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
static void bne() {
|
441
|
+
if ((status & FLAG_ZERO) == 0) {
|
442
|
+
oldpc = pc;
|
443
|
+
pc += reladdr;
|
444
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
445
|
+
else clockticks6502++;
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
449
|
+
static void bpl() {
|
450
|
+
if ((status & FLAG_SIGN) == 0) {
|
451
|
+
oldpc = pc;
|
452
|
+
pc += reladdr;
|
453
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
454
|
+
else clockticks6502++;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
static void brk() {
|
459
|
+
pc++;
|
460
|
+
push16(pc); //push next instruction address onto stack
|
461
|
+
push8(status | FLAG_BREAK); //push CPU status to stack
|
462
|
+
setinterrupt(); //set interrupt flag
|
463
|
+
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
|
464
|
+
}
|
465
|
+
|
466
|
+
static void bvc() {
|
467
|
+
if ((status & FLAG_OVERFLOW) == 0) {
|
468
|
+
oldpc = pc;
|
469
|
+
pc += reladdr;
|
470
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
471
|
+
else clockticks6502++;
|
472
|
+
}
|
473
|
+
}
|
474
|
+
|
475
|
+
static void bvs() {
|
476
|
+
if ((status & FLAG_OVERFLOW) == FLAG_OVERFLOW) {
|
477
|
+
oldpc = pc;
|
478
|
+
pc += reladdr;
|
479
|
+
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
480
|
+
else clockticks6502++;
|
481
|
+
}
|
482
|
+
}
|
483
|
+
|
484
|
+
static void clc() {
|
485
|
+
clearcarry();
|
486
|
+
}
|
487
|
+
|
488
|
+
static void cld() {
|
489
|
+
cleardecimal();
|
490
|
+
}
|
491
|
+
|
492
|
+
static void cli() {
|
493
|
+
clearinterrupt();
|
494
|
+
}
|
495
|
+
|
496
|
+
static void clv() {
|
497
|
+
clearoverflow();
|
498
|
+
}
|
499
|
+
|
500
|
+
static void cmp() {
|
501
|
+
penaltyop = 1;
|
502
|
+
value = getvalue();
|
503
|
+
result = (uint16_t)a - value;
|
504
|
+
|
505
|
+
if (a >= (uint8_t)(value & 0x00FF)) setcarry();
|
506
|
+
else clearcarry();
|
507
|
+
if (a == (uint8_t)(value & 0x00FF)) setzero();
|
508
|
+
else clearzero();
|
509
|
+
signcalc(result);
|
510
|
+
}
|
511
|
+
|
512
|
+
static void cpx() {
|
513
|
+
value = getvalue();
|
514
|
+
result = (uint16_t)x - value;
|
515
|
+
|
516
|
+
if (x >= (uint8_t)(value & 0x00FF)) setcarry();
|
517
|
+
else clearcarry();
|
518
|
+
if (x == (uint8_t)(value & 0x00FF)) setzero();
|
519
|
+
else clearzero();
|
520
|
+
signcalc(result);
|
521
|
+
}
|
522
|
+
|
523
|
+
static void cpy() {
|
524
|
+
value = getvalue();
|
525
|
+
result = (uint16_t)y - value;
|
526
|
+
|
527
|
+
if (y >= (uint8_t)(value & 0x00FF)) setcarry();
|
528
|
+
else clearcarry();
|
529
|
+
if (y == (uint8_t)(value & 0x00FF)) setzero();
|
530
|
+
else clearzero();
|
531
|
+
signcalc(result);
|
532
|
+
}
|
533
|
+
|
534
|
+
static void dec() {
|
535
|
+
value = getvalue();
|
536
|
+
result = value - 1;
|
537
|
+
|
538
|
+
zerocalc(result);
|
539
|
+
signcalc(result);
|
540
|
+
|
541
|
+
putvalue(result);
|
542
|
+
}
|
543
|
+
|
544
|
+
static void dex() {
|
545
|
+
x--;
|
546
|
+
|
547
|
+
zerocalc(x);
|
548
|
+
signcalc(x);
|
549
|
+
}
|
550
|
+
|
551
|
+
static void dey() {
|
552
|
+
y--;
|
553
|
+
|
554
|
+
zerocalc(y);
|
555
|
+
signcalc(y);
|
556
|
+
}
|
557
|
+
|
558
|
+
static void eor() {
|
559
|
+
penaltyop = 1;
|
560
|
+
value = getvalue();
|
561
|
+
result = (uint16_t)a ^ value;
|
562
|
+
|
563
|
+
zerocalc(result);
|
564
|
+
signcalc(result);
|
565
|
+
|
566
|
+
saveaccum(result);
|
567
|
+
}
|
568
|
+
|
569
|
+
static void inc() {
|
570
|
+
value = getvalue();
|
571
|
+
result = value + 1;
|
572
|
+
|
573
|
+
zerocalc(result);
|
574
|
+
signcalc(result);
|
575
|
+
|
576
|
+
putvalue(result);
|
577
|
+
}
|
578
|
+
|
579
|
+
static void inx() {
|
580
|
+
x++;
|
581
|
+
|
582
|
+
zerocalc(x);
|
583
|
+
signcalc(x);
|
584
|
+
}
|
585
|
+
|
586
|
+
static void iny() {
|
587
|
+
y++;
|
588
|
+
|
589
|
+
zerocalc(y);
|
590
|
+
signcalc(y);
|
591
|
+
}
|
592
|
+
|
593
|
+
static void jmp() {
|
594
|
+
pc = ea;
|
595
|
+
}
|
596
|
+
|
597
|
+
static void jsr() {
|
598
|
+
push16(pc - 1);
|
599
|
+
pc = ea;
|
600
|
+
}
|
601
|
+
|
602
|
+
static void lda() {
|
603
|
+
penaltyop = 1;
|
604
|
+
value = getvalue();
|
605
|
+
a = (uint8_t)(value & 0x00FF);
|
606
|
+
|
607
|
+
zerocalc(a);
|
608
|
+
signcalc(a);
|
609
|
+
}
|
610
|
+
|
611
|
+
static void ldx() {
|
612
|
+
penaltyop = 1;
|
613
|
+
value = getvalue();
|
614
|
+
x = (uint8_t)(value & 0x00FF);
|
615
|
+
|
616
|
+
zerocalc(x);
|
617
|
+
signcalc(x);
|
618
|
+
}
|
619
|
+
|
620
|
+
static void ldy() {
|
621
|
+
penaltyop = 1;
|
622
|
+
value = getvalue();
|
623
|
+
y = (uint8_t)(value & 0x00FF);
|
624
|
+
|
625
|
+
zerocalc(y);
|
626
|
+
signcalc(y);
|
627
|
+
}
|
628
|
+
|
629
|
+
static void lsr() {
|
630
|
+
value = getvalue();
|
631
|
+
result = value >> 1;
|
632
|
+
|
633
|
+
if (value & 1) setcarry();
|
634
|
+
else clearcarry();
|
635
|
+
zerocalc(result);
|
636
|
+
signcalc(result);
|
637
|
+
|
638
|
+
putvalue(result);
|
639
|
+
}
|
640
|
+
|
641
|
+
static void nop() {
|
642
|
+
switch (opcode) {
|
643
|
+
case 0x1C:
|
644
|
+
case 0x3C:
|
645
|
+
case 0x5C:
|
646
|
+
case 0x7C:
|
647
|
+
case 0xDC:
|
648
|
+
case 0xFC:
|
649
|
+
penaltyop = 1;
|
650
|
+
break;
|
651
|
+
}
|
652
|
+
}
|
653
|
+
|
654
|
+
static void ora() {
|
655
|
+
penaltyop = 1;
|
656
|
+
value = getvalue();
|
657
|
+
result = (uint16_t)a | value;
|
658
|
+
|
659
|
+
zerocalc(result);
|
660
|
+
signcalc(result);
|
661
|
+
|
662
|
+
saveaccum(result);
|
663
|
+
}
|
664
|
+
|
665
|
+
static void pha() {
|
666
|
+
push8(a);
|
667
|
+
}
|
668
|
+
|
669
|
+
static void php() {
|
670
|
+
push8(status | FLAG_BREAK);
|
671
|
+
}
|
672
|
+
|
673
|
+
static void pla() {
|
674
|
+
a = pull8();
|
675
|
+
|
676
|
+
zerocalc(a);
|
677
|
+
signcalc(a);
|
678
|
+
}
|
679
|
+
|
680
|
+
static void plp() {
|
681
|
+
status = pull8() | FLAG_CONSTANT;
|
682
|
+
}
|
683
|
+
|
684
|
+
static void rol() {
|
685
|
+
value = getvalue();
|
686
|
+
result = (value << 1) | (status & FLAG_CARRY);
|
687
|
+
|
688
|
+
carrycalc(result);
|
689
|
+
zerocalc(result);
|
690
|
+
signcalc(result);
|
691
|
+
|
692
|
+
putvalue(result);
|
693
|
+
}
|
694
|
+
|
695
|
+
static void ror() {
|
696
|
+
value = getvalue();
|
697
|
+
result = (value >> 1) | ((status & FLAG_CARRY) << 7);
|
698
|
+
|
699
|
+
if (value & 1) setcarry();
|
700
|
+
else clearcarry();
|
701
|
+
zerocalc(result);
|
702
|
+
signcalc(result);
|
703
|
+
|
704
|
+
putvalue(result);
|
705
|
+
}
|
706
|
+
|
707
|
+
static void rti() {
|
708
|
+
status = pull8();
|
709
|
+
value = pull16();
|
710
|
+
pc = value;
|
711
|
+
}
|
712
|
+
|
713
|
+
static void rts() {
|
714
|
+
value = pull16();
|
715
|
+
pc = value + 1;
|
716
|
+
}
|
717
|
+
|
718
|
+
// Original adc which does not handle BCD mode
|
719
|
+
// static void sbc() {
|
720
|
+
// penaltyop = 1;
|
721
|
+
// value = getvalue() ^ 0x00FF;
|
722
|
+
// result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
|
723
|
+
|
724
|
+
// carrycalc(result);
|
725
|
+
// zerocalc(result);
|
726
|
+
// overflowcalc(result, a, value);
|
727
|
+
// signcalc(result);
|
728
|
+
|
729
|
+
// #ifndef NES_CPU
|
730
|
+
// if (status & FLAG_DECIMAL) {
|
731
|
+
// clearcarry();
|
732
|
+
|
733
|
+
// a -= 0x66;
|
734
|
+
// if ((a & 0x0F) > 0x09) {
|
735
|
+
// a += 0x06;
|
736
|
+
// }
|
737
|
+
// if ((a & 0xF0) > 0x90) {
|
738
|
+
// a += 0x60;
|
739
|
+
// setcarry();
|
740
|
+
// }
|
741
|
+
|
742
|
+
// clockticks6502++;
|
743
|
+
// }
|
744
|
+
// #endif
|
745
|
+
|
746
|
+
// saveaccum(result);
|
747
|
+
// }
|
748
|
+
// from http://forum.6502.org/viewtopic.php?f=2&t=2052#p37758
|
749
|
+
static void sbc() {
|
750
|
+
penaltyop = 1;
|
751
|
+
value = getvalue() ^ 0x00FF; /* ones complement */
|
752
|
+
|
753
|
+
#ifndef NES_CPU
|
754
|
+
if (status & FLAG_DECIMAL) /* use nines complement for BCD */
|
755
|
+
value -= 0x0066;
|
756
|
+
#endif
|
757
|
+
|
758
|
+
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
|
759
|
+
|
760
|
+
zerocalc(result);
|
761
|
+
overflowcalc(result, a, value);
|
762
|
+
signcalc(result);
|
763
|
+
|
764
|
+
#ifndef NES_CPU
|
765
|
+
if (status & FLAG_DECIMAL) /* detect and apply BCD nybble carries */
|
766
|
+
result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
|
767
|
+
#endif
|
768
|
+
|
769
|
+
carrycalc(result);
|
770
|
+
saveaccum(result);
|
771
|
+
}
|
772
|
+
|
773
|
+
static void sec() {
|
774
|
+
setcarry();
|
775
|
+
}
|
776
|
+
|
777
|
+
static void sed() {
|
778
|
+
setdecimal();
|
779
|
+
}
|
780
|
+
|
781
|
+
static void sei() {
|
782
|
+
setinterrupt();
|
783
|
+
}
|
784
|
+
|
785
|
+
static void sta() {
|
786
|
+
putvalue(a);
|
787
|
+
}
|
788
|
+
|
789
|
+
static void stx() {
|
790
|
+
putvalue(x);
|
791
|
+
}
|
792
|
+
|
793
|
+
static void sty() {
|
794
|
+
putvalue(y);
|
795
|
+
}
|
796
|
+
|
797
|
+
static void tax() {
|
798
|
+
x = a;
|
799
|
+
|
800
|
+
zerocalc(x);
|
801
|
+
signcalc(x);
|
802
|
+
}
|
803
|
+
|
804
|
+
static void tay() {
|
805
|
+
y = a;
|
806
|
+
|
807
|
+
zerocalc(y);
|
808
|
+
signcalc(y);
|
809
|
+
}
|
810
|
+
|
811
|
+
static void tsx() {
|
812
|
+
x = sp;
|
813
|
+
|
814
|
+
zerocalc(x);
|
815
|
+
signcalc(x);
|
816
|
+
}
|
817
|
+
|
818
|
+
static void txa() {
|
819
|
+
a = x;
|
820
|
+
|
821
|
+
zerocalc(a);
|
822
|
+
signcalc(a);
|
823
|
+
}
|
824
|
+
|
825
|
+
static void txs() {
|
826
|
+
sp = x;
|
827
|
+
}
|
828
|
+
|
829
|
+
static void tya() {
|
830
|
+
a = y;
|
831
|
+
|
832
|
+
zerocalc(a);
|
833
|
+
signcalc(a);
|
834
|
+
}
|
835
|
+
|
836
|
+
//undocumented instructions
|
837
|
+
#ifdef UNDOCUMENTED
|
838
|
+
static void lax() {
|
839
|
+
lda();
|
840
|
+
ldx();
|
841
|
+
}
|
842
|
+
|
843
|
+
static void sax() {
|
844
|
+
sta();
|
845
|
+
stx();
|
846
|
+
putvalue(a & x);
|
847
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
848
|
+
}
|
849
|
+
|
850
|
+
static void dcp() {
|
851
|
+
dec();
|
852
|
+
cmp();
|
853
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
854
|
+
}
|
855
|
+
|
856
|
+
static void isb() {
|
857
|
+
inc();
|
858
|
+
sbc();
|
859
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
860
|
+
}
|
861
|
+
|
862
|
+
static void slo() {
|
863
|
+
asl();
|
864
|
+
ora();
|
865
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
866
|
+
}
|
867
|
+
|
868
|
+
static void rla() {
|
869
|
+
rol();
|
870
|
+
and();
|
871
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
872
|
+
}
|
873
|
+
|
874
|
+
static void sre() {
|
875
|
+
lsr();
|
876
|
+
eor();
|
877
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
878
|
+
}
|
879
|
+
|
880
|
+
static void rra() {
|
881
|
+
ror();
|
882
|
+
adc();
|
883
|
+
if (penaltyop && penaltyaddr) clockticks6502--;
|
884
|
+
}
|
885
|
+
#else
|
886
|
+
#define lax nop
|
887
|
+
#define sax nop
|
888
|
+
#define dcp nop
|
889
|
+
#define isb nop
|
890
|
+
#define slo nop
|
891
|
+
#define rla nop
|
892
|
+
#define sre nop
|
893
|
+
#define rra nop
|
894
|
+
#endif
|
895
|
+
|
896
|
+
|
897
|
+
static void (*addrtable[256])() = {
|
898
|
+
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
899
|
+
/* 0 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 0 */
|
900
|
+
/* 1 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 1 */
|
901
|
+
/* 2 */ abso, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 2 */
|
902
|
+
/* 3 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 3 */
|
903
|
+
/* 4 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 4 */
|
904
|
+
/* 5 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 5 */
|
905
|
+
/* 6 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, ind, abso, abso, abso, /* 6 */
|
906
|
+
/* 7 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 7 */
|
907
|
+
/* 8 */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* 8 */
|
908
|
+
/* 9 */ rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* 9 */
|
909
|
+
/* A */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* A */
|
910
|
+
/* B */ rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* B */
|
911
|
+
/* C */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* C */
|
912
|
+
/* D */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* D */
|
913
|
+
/* E */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* E */
|
914
|
+
/* F */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx /* F */
|
915
|
+
};
|
916
|
+
|
917
|
+
static void (*optable[256])() = {
|
918
|
+
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
919
|
+
/* 0 */ brk, ora, nop, slo, nop, ora, asl, slo, php, ora, asl, nop, nop, ora, asl, slo, /* 0 */
|
920
|
+
/* 1 */ bpl, ora, nop, slo, nop, ora, asl, slo, clc, ora, nop, slo, nop, ora, asl, slo, /* 1 */
|
921
|
+
/* 2 */ jsr, and, nop, rla, bit, and, rol, rla, plp, and, rol, nop, bit, and, rol, rla, /* 2 */
|
922
|
+
/* 3 */ bmi, and, nop, rla, nop, and, rol, rla, sec, and, nop, rla, nop, and, rol, rla, /* 3 */
|
923
|
+
/* 4 */ rti, eor, nop, sre, nop, eor, lsr, sre, pha, eor, lsr, nop, jmp, eor, lsr, sre, /* 4 */
|
924
|
+
/* 5 */ bvc, eor, nop, sre, nop, eor, lsr, sre, cli, eor, nop, sre, nop, eor, lsr, sre, /* 5 */
|
925
|
+
/* 6 */ rts, adc, nop, rra, nop, adc, ror, rra, pla, adc, ror, nop, jmp, adc, ror, rra, /* 6 */
|
926
|
+
/* 7 */ bvs, adc, nop, rra, nop, adc, ror, rra, sei, adc, nop, rra, nop, adc, ror, rra, /* 7 */
|
927
|
+
/* 8 */ nop, sta, nop, sax, sty, sta, stx, sax, dey, nop, txa, nop, sty, sta, stx, sax, /* 8 */
|
928
|
+
/* 9 */ bcc, sta, nop, nop, sty, sta, stx, sax, tya, sta, txs, nop, nop, sta, nop, nop, /* 9 */
|
929
|
+
/* A */ ldy, lda, ldx, lax, ldy, lda, ldx, lax, tay, lda, tax, nop, ldy, lda, ldx, lax, /* A */
|
930
|
+
/* B */ bcs, lda, nop, lax, ldy, lda, ldx, lax, clv, lda, tsx, lax, ldy, lda, ldx, lax, /* B */
|
931
|
+
/* C */ cpy, cmp, nop, dcp, cpy, cmp, dec, dcp, iny, cmp, dex, nop, cpy, cmp, dec, dcp, /* C */
|
932
|
+
/* D */ bne, cmp, nop, dcp, nop, cmp, dec, dcp, cld, cmp, nop, dcp, nop, cmp, dec, dcp, /* D */
|
933
|
+
/* E */ cpx, sbc, nop, isb, cpx, sbc, inc, isb, inx, sbc, nop, sbc, cpx, sbc, inc, isb, /* E */
|
934
|
+
/* F */ beq, sbc, nop, isb, nop, sbc, inc, isb, sed, sbc, nop, isb, nop, sbc, inc, isb /* F */
|
935
|
+
};
|
936
|
+
|
937
|
+
static const uint32_t ticktable[256] = {
|
938
|
+
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
939
|
+
/* 0 */ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0 */
|
940
|
+
/* 1 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1 */
|
941
|
+
/* 2 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2 */
|
942
|
+
/* 3 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3 */
|
943
|
+
/* 4 */ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4 */
|
944
|
+
/* 5 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5 */
|
945
|
+
/* 6 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6 */
|
946
|
+
/* 7 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7 */
|
947
|
+
/* 8 */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8 */
|
948
|
+
/* 9 */ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9 */
|
949
|
+
/* A */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* A */
|
950
|
+
/* B */ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* B */
|
951
|
+
/* C */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* C */
|
952
|
+
/* D */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* D */
|
953
|
+
/* E */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* E */
|
954
|
+
/* F */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* F */
|
955
|
+
};
|
956
|
+
|
957
|
+
|
958
|
+
void nmi6502() {
|
959
|
+
push16(pc);
|
960
|
+
push8(status);
|
961
|
+
status |= FLAG_INTERRUPT;
|
962
|
+
pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8);
|
963
|
+
}
|
964
|
+
|
965
|
+
void irq6502() {
|
966
|
+
if (! (status & FLAG_INTERRUPT) ) {
|
967
|
+
push16(pc);
|
968
|
+
push8(status);
|
969
|
+
status |= FLAG_INTERRUPT;
|
970
|
+
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
|
971
|
+
}
|
972
|
+
}
|
973
|
+
|
974
|
+
uint8_t callexternal = 0;
|
975
|
+
void (*loopexternal)();
|
976
|
+
|
977
|
+
void exec6502(uint32_t tickcount) {
|
978
|
+
clockgoal6502 += tickcount;
|
979
|
+
|
980
|
+
while (clockticks6502 < clockgoal6502) {
|
981
|
+
opcode = read6502(pc++);
|
982
|
+
status |= FLAG_CONSTANT;
|
983
|
+
|
984
|
+
penaltyop = 0;
|
985
|
+
penaltyaddr = 0;
|
986
|
+
|
987
|
+
(*addrtable[opcode])();
|
988
|
+
(*optable[opcode])();
|
989
|
+
clockticks6502 += ticktable[opcode];
|
990
|
+
if (penaltyop && penaltyaddr) clockticks6502++;
|
991
|
+
|
992
|
+
instructions++;
|
993
|
+
|
994
|
+
if (callexternal) (*loopexternal)();
|
995
|
+
}
|
996
|
+
|
997
|
+
}
|
998
|
+
|
999
|
+
void step6502() {
|
1000
|
+
opcode = read6502(pc++);
|
1001
|
+
status |= FLAG_CONSTANT;
|
1002
|
+
|
1003
|
+
penaltyop = 0;
|
1004
|
+
penaltyaddr = 0;
|
1005
|
+
|
1006
|
+
(*addrtable[opcode])();
|
1007
|
+
(*optable[opcode])();
|
1008
|
+
clockticks6502 += ticktable[opcode];
|
1009
|
+
if (penaltyop && penaltyaddr) clockticks6502++;
|
1010
|
+
clockgoal6502 = clockticks6502;
|
1011
|
+
|
1012
|
+
instructions++;
|
1013
|
+
|
1014
|
+
if (callexternal) (*loopexternal)();
|
1015
|
+
}
|
1016
|
+
|
1017
|
+
void hookexternal(void *funcptr) {
|
1018
|
+
if (funcptr != (void *)NULL) {
|
1019
|
+
loopexternal = funcptr;
|
1020
|
+
callexternal = 1;
|
1021
|
+
} else callexternal = 0;
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
// functions added by infiton<kbt.tate@gmail.com> to expose 6502 internals
|
1025
|
+
uint16_t getPC() {
|
1026
|
+
return pc;
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
uint8_t getSP() {
|
1030
|
+
return sp;
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
uint8_t getA() {
|
1034
|
+
return a;
|
1035
|
+
}
|
1036
|
+
|
1037
|
+
uint8_t getX() {
|
1038
|
+
return x;
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
uint8_t getY() {
|
1042
|
+
return y;
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
uint8_t getStatus() {
|
1046
|
+
return status;
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
uint32_t getInstructions() {
|
1050
|
+
return instructions;
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
uint64_t getTicks() {
|
1054
|
+
return clockticks6502;
|
1055
|
+
}
|