PancakeNESEmu
A homebrewed NES Emulator written in C
Loading...
Searching...
No Matches
unit_tests.c
Go to the documentation of this file.
1#include "core/cpu.h"
2#include "core/mem.h"
3#include "macros.h"
4#include "rom_reader/reader.h"
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9
10void print_cpu_state(CPU* processor) {
11
12 printf("|======== Registers State ========|\n");
13 printf("Accumulator: %i\n", processor->accumulator);
14 printf("X Register: %i\n", processor->register_x);
15 printf("Y Register: %i\n", processor->register_y);
16 printf("Program Counter: %#04x\n", processor->program_counter);
17 printf("Stack Pointer: %#02x\n", processor->stack_pointer);
18 printf("Flags: %#02x\n", processor->flags);
19
20 printf("\n");
21
22 printf("|======== Flags State ========|\n");
23 printf("Negative Flag (N): %i\n", (GET_N_FLAG(processor) >> 7));
24 printf("Overflow Flag (V): %i\n", (GET_V_FLAG(processor) >> 6));
25 printf("Pause Flag (P): %i\n", (GET_P_FLAG(processor) >> 5));
26 printf("Break Flag (B): %i\n", (GET_B_FLAG(processor) >> 4));
27 printf("Decimal Flag (D): %i\n", (GET_D_FLAG(processor) >> 3));
28 printf("Interrupt Flag (I): %i\n", (GET_I_FLAG(processor) >> 2));
29 printf("Zero Flag (Z): %i\n", (GET_Z_FLAG(processor) >> 1));
30 printf("Carry Flag (C): %i\n", GET_C_FLAG(processor));
31
32 printf("\n");
33}
34
35void print_cpu_expected(data acc, data x, data y, data flags, address pc, data sp) {
36 printf("|======== EXPECTED: Registers State ========|\n");
37 printf("Accumulator: %i\n", acc);
38 printf("X Register: %i\n", x);
39 printf("Y Register: %i\n", y);
40 printf("Program Counter: %#04x\n", pc);
41 printf("Stack Pointer: %#02x\n", sp);
42 printf("Flags: %#02x\n", flags);
43
44 printf("\n");
45
46 printf("|======== EXPECTED: Flags State ========|\n");
47 printf("Negative Flag (N): %i\n", ((flags & BIT_7_MASK) >> 7));
48 printf("Overflow Flag (V): %i\n", ((flags & BIT_6_MASK) >> 6));
49 printf("Pause Flag (P): %i\n", ((flags & BIT_5_MASK) >> 5));
50 printf("Break Flag (B): %i\n", ((flags & BIT_4_MASK) >> 4));
51 printf("Decimal Flag (D): %i\n", ((flags & BIT_3_MASK) >> 3));
52 printf("Interrupt Flag (I): %i\n", ((flags & BIT_2_MASK) >> 2));
53 printf("Zero Flag (Z): %i\n", ((flags & BIT_1_MASK) >> 1));
54 printf("Carry Flag (C): %i\n", (flags & BIT_0_MASK));
55
56 printf("\n");
57}
58
60
61 printf("<====== Stack State =====>\n");
62 printf("Stack pointer: %#02x\n", cpu->stack_pointer);
63
64 if (cpu->stack_pointer == 0xFF) {
65 printf("\n");
66 return;
67 }
68
69 printf("sp: | int |\t | hex |\n\n");
70
71 for (uint8_t sp = cpu->stack_pointer + 1; sp < 0xFF; ++sp) {
72 printf("%#02x: | %i |", sp, cpu->mem[STACK_END | sp]);
73 printf("\t | %#02x |\n", cpu->mem[STACK_END | sp]);
74 }
75
76 printf("%#02x: | %i |", 0xFF, cpu->mem[STACK_START]);
77 printf("\t | %#02x |\n", cpu->mem[STACK_START]);
78
79 printf("\n");
80}
81
82void print_stack_expected(memory stack, data start) {
83 printf("<===== EXPECTED: Stack State =====>\n");
84 printf("Stack pointer: %#02x\n", start);
85
86 if (start == 0xFF) {
87 printf("\n");
88 return;
89 }
90
91 printf("sp: | int |\t | hex |\n\n");
92
93 for (data sp = start + 1; sp < 0xFF; ++sp) {
94 printf("%#02x: | %i |", sp, stack[sp]);
95 printf("\t | %#02x |\n", stack[sp]);
96 }
97
98 printf("%#02x: | %i |", 0xFF, stack[0xFF]);
99 printf("\t | %#02x |\n", stack[0xFF]);
100
101 printf("\n");
102}
103
104int main(int argc, char** argv) {
105
106 int opt;
107 rom* my_rom = NULL;
108
109 while ((opt = getopt(argc, argv, ":i:")) != -1) {
110 switch (opt) {
111 case 'i':
112 printf("Filepath: %s\n", optarg);
113 my_rom = open_rom(optarg);
114 if (my_rom != NULL) {
115 display_rom(my_rom);
116 free_rom(my_rom);
117 }
118 return EXIT_SUCCESS;
119 break;
120 default:
121 break;
122 }
123 }
124
125 CPU* cpu = (CPU*)malloc(sizeof(CPU));
126 data stack_test[256];
127
128 memory mem = init_memory();
129 init_cpu(cpu, mem);
130 reset_memory(cpu->mem);
131
132 for (unsigned int i = 0; i < 50; ++i) {
133 cpu->mem[i] = i;
134 }
135
136 printf("##### Load Tests #####\n\n");
137
138 LD_immediate_ACC(cpu, 5);
139 LD_immediate_X(cpu, 5);
140 LD_immediate_Y(cpu, 5);
141
142 print_cpu_expected(5, 5, 5, 0x00, 0xFFFC, 0xFF);
143 print_cpu_state(cpu);
144
145 LD_offset_ACC(cpu, 0, 0);
146 LD_offset_X(cpu, 0, 1);
147 LD_offset_Y(cpu, 0, 2);
148
149 print_cpu_expected(0, 1, 2, 0x00, 0xFFFC, 0xFF);
150 print_cpu_state(cpu);
151
152 LD_absolute_ACC(cpu, 3);
153 LD_absolute_X(cpu, 4);
154 LD_absolute_Y(cpu, 5);
155
156 print_cpu_expected(3, 4, 5, 0x00, 0xFFFC, 0xFF);
157 print_cpu_state(cpu);
158
159 cpu->mem[0 | 1 << 8] = 121;
160 cpu->mem[1 | 2 << 8] = 122;
161 cpu->mem[2 | 3 << 8] = 123;
162
163 LD_indirect_ACC(cpu, 0); // Expected: 121
164 LD_indirect_X(cpu, 1); // Expected: 122
165 LD_indirect_Y(cpu, 2); // Expected: 123
166
167 print_cpu_expected(121, 122, 123, 0x00, 0xFFFC, 0xFF);
168 print_cpu_state(cpu);
169
170 LD_immediate_X(cpu, 0);
171 LD_immediate_Y(cpu, 0);
172
173 printf("##### INC/DEC Tests #####\n\n");
174
175 INC_X(cpu);
176 INC_Y(cpu);
177
178 print_cpu_expected(121, 1, 1, 0x00, 0xFFFC, 0xFF);
179 print_cpu_state(cpu);
180
181 DEC_X(cpu);
182 DEC_Y(cpu);
183
184 print_cpu_expected(121, 0, 0, 0b00000010, 0xFFFC, 0xFF);
185 print_cpu_state(cpu);
186
187 printf("##### Indirections test #####\n\n");
188
189 cpu->mem[(5) | (6) << 8] = 150;
190
191 LD_immediate_X(cpu, 5);
193
194 print_cpu_expected(150, 5, 0, 0b10000000, 0xFFFC, 0xFF);
195 print_cpu_state(cpu);
196
197 cpu->mem[0] = 1;
198 cpu->mem[1] = 1;
199
200 cpu->mem[((1) | (1) << 8) + 2] = 5;
201
202 LD_immediate_Y(cpu, 2);
203
205
206 print_cpu_expected(5, 5, 2, 0x00, 0xFFFC, 0xFF);
207 print_cpu_state(cpu);
208
209 stack_test[0xFF] = 5;
210
211 printf("##### PUSH/PULL tests #####\n\n");
212
213 LD_immediate_ACC(cpu, 5);
214 PUSH_ACC(cpu);
215
216 print_stack_expected(stack_test, 0xFE);
218
219 LD_immediate_ACC(cpu, 0);
220 LD_immediate_X(cpu, 0);
221 LD_immediate_Y(cpu, 0);
222
223 PULL_ACC(cpu);
224
225 print_cpu_expected(5, 0, 0, 0x00, 0xFFFC, 0xFF);
226 print_cpu_state(cpu);
227
228 print_stack_expected(stack_test, 0xFF);
230
231 PUSH_PC(cpu);
232
233 stack_test[0xFF] = 0xFC;
234 stack_test[0xFE] = 0xFF;
235
236 print_stack_expected(stack_test, 0xFD);
238
239 stack_test[0xFF] = 0x0C;
240 stack_test[0xFE] = 0x81;
241
242 cpu->mem[STACK_END | 0xFF] = 0x0C;
243 cpu->mem[STACK_END | 0xFE] = 0x81;
244
245 print_stack_expected(stack_test, 0xFD);
247
248 PULL_PC(cpu);
249
250 print_cpu_expected(5, 0, 0, 0x00, 0x810C, 0xFF);
251 print_cpu_state(cpu);
252
253 cpu->flags = 0x9c;
254
255 PUSH_FLAGS(cpu);
256
257 stack_test[0xFF] = 0x9c;
258
259 print_cpu_expected(5, 0, 0, 0x9c, 0x810C, 0xFE);
260 print_cpu_state(cpu);
261
262 print_stack_expected(stack_test, 0xFE);
264
265 CLEAR_ALL_FLAGS(cpu);
266
267 cpu->mem[STACK_END | 0xFF] = 0x69;
268
269 PULL_FLAGS(cpu);
270
271 print_stack_expected(stack_test, 0xFF);
273
274 print_cpu_expected(5, 0, 0, 0x69, 0x810C, 0xFF);
275 print_cpu_state(cpu);
276
277 printf("##### ADD Tests #####\n\n");
278
279 CLEAR_ALL_FLAGS(cpu);
280
281 LD_immediate_ACC(cpu, 0);
282 ADD_immediate(cpu, 1);
283
284 print_cpu_expected(1, 0, 0, 0x00, 0x810C, 0xFF);
285 print_cpu_state(cpu);
286
287 LD_immediate_ACC(cpu, 0);
288 ADD_immediate(cpu, 0);
289
290 print_cpu_expected(0, 0, 0, 0b00000010, 0x810C, 0xFF);
291 print_cpu_state(cpu);
292
293 LD_immediate_ACC(cpu, 255);
294 ADD_immediate(cpu, 1);
295
296 print_cpu_expected(0, 0, 0, 0b01000011, 0x810C, 0xFF);
297 print_cpu_state(cpu);
298
299 LD_immediate_ACC(cpu, 0);
300 cpu->mem[20] = 5;
301 ADD_offset(cpu, 15, 5);
302
303 print_cpu_expected(5, 0, 0, 0x00, 0x810C, 0xFF);
304 print_cpu_state(cpu);
305
306 CLEAR_ALL_FLAGS(cpu);
307 LD_immediate_ACC(cpu, 0);
308
309 cpu->mem[0] = 0x11;
310 cpu->mem[1] = 0x11;
311 cpu->mem[0x1111] = 20;
312
313 ADD_indirect_indexed(cpu, 0, 0);
314
315 print_cpu_expected(20, 0, 0, 0x00, 0x810C, 0xFF);
316 print_cpu_state(cpu);
317
318 CLEAR_ALL_FLAGS(cpu);
319 LD_immediate_ACC(cpu, 0);
320
321 ADD_indexed_indirect(cpu, 0, 0);
322
323 print_cpu_expected(20, 0, 0, 0x00, 0x810C, 0xFF);
324 print_cpu_state(cpu);
325
326 CLEAR_ALL_FLAGS(cpu);
327 LD_immediate_ACC(cpu, 255);
328
329 ADD_immediate(cpu, 1);
330
331 print_cpu_expected(0, 0, 0, 0b01000010, 0x810c, 0xff);
332 print_cpu_state(cpu);
333
334 CLEAR_ALL_FLAGS(cpu);
335 LD_immediate_ACC(cpu, 0b11001001);
336
337 printf("##### And Tests #####\n\n");
338
339 AND_immediate(cpu, 0b00000001);
340
341 print_cpu_expected(1, 0, 0, 0x00, 0x810c, 0xff);
342 print_cpu_state(cpu);
343
344 cpu->mem[0x5040] = 0xf1;
345
346 AND_absolute(cpu, 0x5040);
347
348 print_cpu_expected(1, 0, 0, 0x00, 0x810c, 0xff);
349 print_cpu_state(cpu);
350
351 LD_immediate_ACC(cpu, 0b10000001);
352 cpu->mem[1] = 0xff;
353
354 AND_offset(cpu, 0x00, 1);
355
356 print_cpu_expected(0b10000001, 0, 0, BIT_7_MASK, 0x810c, 0xff);
357 print_cpu_state(cpu);
358
359 cpu->mem[0] = 0x11;
360 cpu->mem[1] = 0x11;
361 cpu->mem[0x1111] = 0x00;
362
363 AND_indirect_indexed(cpu, 0x00, 0);
364
365 print_cpu_expected(0, 0, 0, BIT_1_MASK, 0x810c, 0xff);
366 print_cpu_state(cpu);
367
368 LD_immediate_ACC(cpu, 128);
369
370 AND_indexed_indirect(cpu, 0, 0);
371
372 print_cpu_expected(0, 0, 0, 0b000000010, 0x810c, 0xff);
373 print_cpu_state(cpu);
374
375 printf("##### Or Tests #####\n\n");
376
377 OR_immediate(cpu, 0b00000001);
378
379 print_cpu_expected(0b00000001, 0, 0, 0, 0x810c, 0xff);
380 print_cpu_state(cpu);
381
382 cpu->mem[0] = 0b00000010;
383
384 OR_absolute(cpu, 0);
385
386 print_cpu_expected(0b00000011, 0, 0, 0, 0x810c, 0xff);
387 print_cpu_state(cpu);
388
389 cpu->mem[1] = 0b00000100;
390
391 OR_offset(cpu, 0, 1);
392
393 print_cpu_expected(0b00000111, 0, 0, 0, 0x810c, 0xff);
394 print_cpu_state(cpu);
395
396 cpu->mem[2] = 0x11;
397 cpu->mem[3] = 0x11;
398 cpu->mem[0x1111] = 0b00001000;
399
400 OR_indirect_indexed(cpu, 2, 0);
401
402 print_cpu_expected(0b00001111, 0, 0, 0, 0x810c, 0xff);
403 print_cpu_state(cpu);
404
405 cpu->mem[0x1111] = 0b00010000;
406
407 OR_indexed_indirect(cpu, 2, 0);
408
409 print_cpu_expected(0b00011111, 0, 0, 0, 0x810c, 0xff);
410 print_cpu_state(cpu);
411
412 printf("##### Xor Tests #####\n\n");
413
414 LD_immediate_ACC(cpu, 0b11111100);
415 XOR_immediate(cpu, 0b00111111);
416
417 print_cpu_expected(0b11000011, 0, 0, 0b10000000, 0x810c, 0xff);
418 print_cpu_state(cpu);
419
420 cpu->mem[0] = 0b11000011;
421
422 XOR_absolute(cpu, 0);
423
424 print_cpu_expected(0, 0, 0, 0b00000010, 0x810c, 0xff);
425 print_cpu_state(cpu);
426
427 cpu->mem[1] = 0b10101010;
428 XOR_offset(cpu, 0, 1);
429
430 print_cpu_expected(0b10101010, 0, 0, 0b10000000, 0x810c, 0xff);
431 print_cpu_state(cpu);
432
433 cpu->mem[0] = 0x55;
434 cpu->mem[1] = 0x55;
435
436 cpu->mem[0x5555] = 0b01010101;
437
438 XOR_indirect_indexed(cpu, 0, 0);
439
440 print_cpu_expected(0xff, 0, 0, 0b10000000, 0x810c, 0xff);
441 print_cpu_state(cpu);
442
443 cpu->mem[0x5555] = 0xff;
444
445 XOR_indexed_indirect(cpu, 0, 0);
446
447 print_cpu_expected(0, 0, 0, 2, 0x810c, 0xff);
448 print_cpu_state(cpu);
449
450 printf("##### Sbc Tests #####\n\n");
451
452 SBC_immediate(cpu, 1);
453
454 print_cpu_expected(0xff, 0, 0, 0b11000000, 0x810c, 0xff);
455 print_cpu_state(cpu);
456
457 CLEAR_ALL_FLAGS(cpu);
458 LD_immediate_ACC(cpu, 80);
459
460 cpu->mem[0] = 0x01;
461
462 SBC_absolute(cpu, 0x00);
463
464 print_cpu_expected(79, 0, 0, 0, 0x810c, 0xff);
465 print_cpu_state(cpu);
466
467 cpu->mem[1] = 0x02;
468
469 SBC_offset(cpu, 0, 1);
470
471 print_cpu_expected(77, 0, 0, 0, 0x810c, 0xff);
472 print_cpu_state(cpu);
473
474 cpu->mem[0] = 0x11;
475 cpu->mem[1] = 0x11;
476
477 cpu->mem[0x1111] = 10;
478
479 SBC_indirect_indexed(cpu, 0, 0);
480
481 print_cpu_expected(67, 0, 0, 0, 0x810c, 0xff);
482 print_cpu_state(cpu);
483
484 SBC_indexed_indirect(cpu, 0, 0);
485
486 print_cpu_expected(57, 0, 0, 0, 0x810c, 0xff);
487 print_cpu_state(cpu);
488
489 printf("##### TR Tests #####\n\n");
490
491 CLEAR_ALL_FLAGS(cpu);
492 LD_immediate_ACC(cpu, 10);
493 TR_ACC_X(cpu);
494
495 print_cpu_expected(10, 10, 0, 0, 0x810c, 0xff);
496 print_cpu_state(cpu);
497
498 TR_ACC_Y(cpu);
499
500 print_cpu_expected(10, 10, 10, 0, 0x810c, 0xff);
501 print_cpu_state(cpu);
502
503 LD_immediate_X(cpu, 50);
504 TR_X_ACC(cpu);
505
506 print_cpu_expected(50, 50, 10, 0, 0x810c, 0xff);
507 print_cpu_state(cpu);
508
509 TR_Y_ACC(cpu);
510
511 print_cpu_expected(10, 50, 10, 0, 0x810c, 0xff);
512 print_cpu_state(cpu);
513
514 TR_SP_X(cpu);
515
516 print_cpu_expected(10, 0xff, 10, 0b10000000, 0x810c, 0xff);
517 print_cpu_state(cpu);
518
519 LD_immediate_X(cpu, 0xfe);
520 TR_X_SP(cpu);
521
522 print_cpu_expected(10, 0xfe, 10, 0b10000000, 0x810c, 0xfe);
523 print_cpu_state(cpu);
524
525 cpu->stack_pointer = 0xff;
526 cpu->register_x = 10;
527 CLEAR_ALL_FLAGS(cpu);
528
529 printf("##### STR Tests #####\n\n");
530
531 STR_absolute_ACC(cpu, 0x1100);
532 printf("\nExpected: 10 | %i\n", cpu->mem[0x1100]);
533
534 STR_absolute_X(cpu, 0x1101);
535 printf("\nExpected: 10 | %i\n", cpu->mem[0x1101]);
536
537 STR_absolute_Y(cpu, 0x1102);
538 printf("\nExpected: 10 | %i\n", cpu->mem[0x1102]);
539
540 LD_immediate_ACC(cpu, 15);
541 LD_immediate_X(cpu, 16);
542 LD_immediate_Y(cpu, 17);
543
544 STR_offset_ACC(cpu, 0x00, 5);
545 printf("\nExpected: 15 | %i\n", cpu->mem[0x05]);
546
547 STR_offset_X(cpu, 0x00, 6);
548 printf("\nExpected: 16 | %i\n", cpu->mem[0x06]);
549
550 STR_offset_Y(cpu, 0x00, 7);
551 printf("\nExpected: 17 | %i\n", cpu->mem[0x07]);
552
553 STR_indirect_indexed_ACC(cpu, 0x10, 5);
554 printf("\nExpected: 15 | %i\n", indirect_indexed(cpu, 0x10, 5));
555
556 STR_indexed_indirect_ACC(cpu, 0x10, 5);
557 printf("\nExpected: 15 | %i\n", indexed_indirect(cpu, 0x10, 5));
558
559 printf("##### BIT Tests #####\n\n");
560
561 cpu->mem[0x00] = 0xFF;
562 cpu->mem[0x01] = 0b00110011;
563 cpu->mem[0x02] = 0x00;
564 CLEAR_ALL_FLAGS(cpu);
565 LD_immediate_ACC(cpu, 15);
566 LD_immediate_X(cpu, 1);
567 LD_immediate_Y(cpu, 1);
568
569 BIT_TEST(cpu, 0x02);
570
571 print_cpu_expected(15, 1, 1, 2, 0x810c, 0xff);
572 print_cpu_state(cpu);
573
574 BIT_TEST(cpu, 0x01);
575 print_cpu_expected(15, 1, 1, 0, 0x810c, 0xff);
576 print_cpu_state(cpu);
577
578 LD_immediate_ACC(cpu, 0b01111111);
579
580 BIT_TEST(cpu, 0x00);
581 print_cpu_expected(127, 1, 1, 0b01000000, 0x810c, 0xff);
582 print_cpu_state(cpu);
583
584 cpu->accumulator = 0xff;
585
586 BIT_TEST(cpu, 0x00);
587 print_cpu_expected(0xff, 1, 1, 0b11000000, 0x810c, 0xff);
588 print_cpu_state(cpu);
589
590 printf("##### Branch Tests #####\n\n");
591
592 CLEAR_ALL_FLAGS(cpu);
593 LD_immediate_ACC(cpu, 1);
594 BRANCH_If_Positive(cpu, 0b10000000);
595
596 print_cpu_expected(1, 1, 1, 0, 0x808c, 0xff);
597 print_cpu_state(cpu);
598
599 LD_immediate_ACC(cpu, 0b10000000);
600 BRANCH_If_Minus(cpu, 0b01111111);
601
602 print_cpu_expected(0b10000000, 1, 1, 0b10000000, 0x810b, 0xff);
603 print_cpu_state(cpu);
604
605 LD_immediate_ACC(cpu, 0);
606 BRANCH_Equal(cpu, 1);
607
608 print_cpu_expected(0, 1, 1, 0b00000010, 0x810c, 0xff);
609 print_cpu_state(cpu);
610
611 LD_immediate_ACC(cpu, 1);
612 BRANCH_Not_Equal(cpu, 0b10000000);
613
614 print_cpu_expected(1, 1, 1, 0, 0x808c, 0xff);
615 print_cpu_state(cpu);
616
617 BRANCH_Overflow_C(cpu, 0b01111111);
618
619 print_cpu_expected(1, 1, 1, 0, 0x810b, 0xff);
620 print_cpu_state(cpu);
621
622 BRANCH_Carry_C(cpu, 1);
623
624 print_cpu_expected(1, 1, 1, 0, 0x810c, 0xff);
625 print_cpu_state(cpu);
626
627 SET_V_FLAG(cpu);
628 SET_C_FLAG(cpu);
629
630 BRANCH_Carry_S(cpu, 0xff);
631
632 print_cpu_expected(1, 1, 1, 0b01000001, 0x810b, 0xff);
633 print_cpu_state(cpu);
634
635 BRANCH_Overflow_S(cpu, 1);
636
637 print_cpu_expected(1, 1, 1, 0b01000001, 0x810c, 0xff);
638 print_cpu_state(cpu);
639
640 printf("##### Shifts Tests #####\n\n");
641
642 LD_immediate_ACC(cpu, 0b10000001);
643 CLEAR_ALL_FLAGS(cpu);
644
645 SHIFT_LEFT_ACC(cpu);
646
647 print_cpu_expected(2, 1, 1, 0b00000001, 0x810c, 0xff);
648 print_cpu_state(cpu);
649
650 SHIFT_LEFT_ACC(cpu);
651
652 print_cpu_expected(4, 1, 1, 0, 0x810c, 0xff);
653 print_cpu_state(cpu);
654
655 for (int i = 0; i < 3; ++i) {
656 SHIFT_RIGHT_ACC(cpu);
657 }
658
659 print_cpu_expected(0, 1, 1, 0b00000011, 0x810c, 0xff);
660 print_cpu_state(cpu);
661
662 CLEAR_Z_FLAG(cpu);
663 cpu->mem[10] = 0b10000001;
664
665 SHIFT_LEFT_absolute(cpu, 10);
666
667 print_cpu_expected(0, 1, 1, 0b00000001, 0x810c, 0xff);
668 print_cpu_state(cpu);
669
670 printf("\nExpected: 2 | %i\n\n", cpu->mem[10]);
671
672 SHIFT_LEFT_offset(cpu, 5, 5);
673
674 print_cpu_expected(0, 1, 1, 0, 0x810c, 0xff);
675 print_cpu_state(cpu);
676
677 printf("\nExpected: 4 | %i\n\n", cpu->mem[10]);
678
679 SHIFT_RIGHT_absolute(cpu, 10);
680
681 print_cpu_expected(0, 1, 1, 0, 0x810c, 0xff);
682 print_cpu_state(cpu);
683
684 printf("\nExpected: 2 | %i\n\n", cpu->mem[10]);
685
686 SHIFT_RIGHT_offset(cpu, 5, 5);
687 SHIFT_RIGHT_offset(cpu, 8, 2);
688
689 print_cpu_expected(0, 1, 1, 0b00000011, 0x810c, 0xff);
690 print_cpu_state(cpu);
691
692 printf("\nExpected: 0 | %i\n\n", cpu->mem[10]);
693
694 printf("##### Rotations Tests #####\n\n");
695
696 LD_immediate_ACC(cpu, 0b00000110);
697 CLEAR_ALL_FLAGS(cpu);
698
701
702 print_cpu_expected(1, 1, 1, 1, 0x810c, 0xff);
703 print_cpu_state(cpu);
704
707
708 print_cpu_expected(0b11000000, 1, 1, 0b10000000, 0x810c, 0xff);
709 print_cpu_state(cpu);
710
713
714 CLEAR_N_FLAG(cpu);
715
716 print_cpu_expected(1, 1, 1, 1, 0x810c, 0xff);
717 print_cpu_state(cpu);
718
721
722 print_cpu_expected(0b00000110, 1, 1, 0, 0x810c, 0xff);
723 print_cpu_state(cpu);
724
725 LD_immediate_ACC(cpu, 1);
726 CLEAR_ALL_FLAGS(cpu);
727
728 cpu->mem[10] = 0b00000110;
731
732 print_cpu_expected(1, 1, 1, 1, 0x810c, 0xff);
733 print_cpu_state(cpu);
734
735 printf("\nExpected: 1 | %i\n\n", cpu->mem[10]);
736
737 ROTATION_RIGHT_offset(cpu, 5, 5);
738 ROTATION_RIGHT_offset(cpu, 2, 8);
739
740 print_cpu_expected(1, 1, 1, 0b10000000, 0x810c, 0xff);
741 print_cpu_state(cpu);
742
743 printf("\nExpected: %i | %i\n\n", 0b11000000, cpu->mem[10]);
744
745 ROTATION_LEFT_absolute(cpu, 10);
746 ROTATION_LEFT_absolute(cpu, 10);
747
748 CLEAR_N_FLAG(cpu);
749
750 print_cpu_expected(1, 1, 1, 1, 0x810c, 0xff);
751 print_cpu_state(cpu);
752
753 printf("\nExpected: 1 | %i\n\n", cpu->mem[10]);
754
755 ROTATION_LEFT_offset(cpu, 1, 9);
756 ROTATION_LEFT_offset(cpu, 6, 4);
757
758 print_cpu_expected(1, 1, 1, 0, 0x810c, 0xff);
759 print_cpu_state(cpu);
760
761 printf("\nExpected: 6 | %i\n\n", cpu->mem[10]);
762
763 printf("##### Jump Tests #####\n\n");
764
765 JUMP_absolute(cpu, 0x1000);
766
767 print_cpu_expected(1, 1, 1, 0, 0x1000, 0xff);
768 print_cpu_state(cpu);
769
770 cpu->mem[0x00ff] = 0x0c;
771 cpu->mem[0x0100] = 0x81;
772
773 JUMP_indirect(cpu, 0x00ff);
774
775 print_cpu_expected(1, 1, 1, 0, 0x810c, 0xff);
776 print_cpu_state(cpu);
777
778 printf("##### Break Test #####\n\n");
779
780 cpu->mem[0xfffe] = 0xaa;
781 cpu->mem[0xffff] = 0xff;
782
783 stack_test[0xff] = 0x81;
784 stack_test[0xfe] = 0x0c;
785 stack_test[0xfd] = 0;
786
787 BREAK(cpu);
788
789 print_stack_expected(stack_test, 0xfc);
791
792 print_cpu_expected(1, 1, 1, 0b00010000, 0xffaa, 0xfc);
793 print_cpu_state(cpu);
794
795 printf("##### RTI, RTS, JSR Test #####\n\n");
796
797 RETURN_Interrupt(cpu);
798
799 print_cpu_expected(1, 1, 1, 0, 0x810c, 0xff);
800 print_cpu_state(cpu);
801
802 JUMP_Subroutine(cpu, 0xb00b);
803
804 stack_test[0xff] = 0x81;
805 stack_test[0xfe] = 0x0e;
806
807 print_stack_expected(stack_test, 0xfd);
809
810 print_cpu_expected(1, 1, 1, 0, 0xb00b, 0xfd);
811 print_cpu_state(cpu);
812
814
815 print_cpu_expected(1, 1, 1, 0, 0x810f, 0xff);
816 print_cpu_state(cpu);
817
818 free_cpu(cpu);
819
820 if (my_rom != NULL) {
821 free_rom(my_rom);
822 }
823
824 return EXIT_SUCCESS;
825}
#define ADD_indexed_indirect(processor, addr, offset)
Procedure that perform a ADD with the carry flag (A,Z,C,N=A+M+C) with indexed indirect addressing mod...
Definition cpu.h:710
#define STR_absolute_X(processor, addr)
Procedure that store the X register value to a memory address.
Definition cpu.h:464
#define GET_V_FLAG(x)
Definition cpu.h:125
#define TR_ACC_X(processor)
Procedure that store the value in the accumulator in the X register.
Definition cpu.h:545
#define OR_indexed_indirect(processor, addr, offset)
Procedure that perform a OR with the carry flag (A,Z,C,N=A+M+C) with indexed indirect addressing mode...
Definition cpu.h:817
#define PULL_FLAGS(processor)
Procedure that pop the top value of the stack and return it to the flags register.
Definition cpu.h:642
#define OR_absolute(processor, addr)
Procedure that performs a bitwise logic OR (A,Z,N = A&M) using absolute addressing mode.
Definition cpu.h:800
#define BRANCH_If_Minus(processor, offset)
Procedure that performs a BMI (branch if positive, if the N flag is clear)
Definition cpu.h:1025
#define AND_indirect_indexed(processor, addr, offset)
Procedure that perform a AND with the carry flag (A,Z,C,N=A+M+C) with indirect indexed.
Definition cpu.h:781
#define TR_ACC_Y(processor)
Procedure that store the value in accumulator in the Y register.
Definition cpu.h:551
#define ROTATION_RIGHT_absolute(processor, addr)
Procedure that performs a bit shift with rotation to the right (ROR operation) at the memory address ...
Definition cpu.h:1176
#define ROTATION_RIGHT_offset(processor, addr, offset)
Procedure that performs a bit shift with rotation to the right (ROR operation) at the memory address ...
Definition cpu.h:1198
#define LD_indirect_ACC(processor, addr)
Procedure that lods a value from memory at the address contained in addr|addr+1. (indirection)
Definition cpu.h:333
#define GET_C_FLAG(x)
Definition cpu.h:119
#define ADD_immediate(processor, data)
Procedure that perform a ADD with the carry flag (A,Z,C,N=A+data+C) with an immediate.
Definition cpu.h:662
#define SHIFT_RIGHT_absolute(processor, addr)
Procedure that performs a bitshift to the right (LSR operation) at the address addr and place the 0th...
Definition cpu.h:1098
#define ROTATION_RIGHT_ACC(processor)
Procedure that performs a bit shift with rotation to the right (ROR operation) on the accumulator....
Definition cpu.h:1157
#define TR_X_SP(processor)
Procedure that store the value in the X register in the stack pointer.
Definition cpu.h:575
#define STR_offset_ACC(processor, addr, offset)
Procedure that store the accumulator value to a memory address + offset.
Definition cpu.h:488
#define XOR_immediate(processor, data)
Procedure that performs a bitwise logic XOR (A,Z,N = A & data)
Definition cpu.h:834
#define DEC_Y(processor)
Procedure that decrements the Y register.
Definition cpu.h:424
#define XOR_indexed_indirect(processor, addr, offset)
Procedure that perform a XOR with the carry flag (A,Z,C,N=A+M+C) with indexed indirect addressing mod...
Definition cpu.h:862
void init_cpu(CPU *cpu, memory mem)
Procedure that initialize the CPU to its boot/reset state.
Definition cpu.c:9
#define STR_offset_X(processor, addr, offset)
Procedure that store the X register value to a memory address + offset.
Definition cpu.h:497
#define PULL_PC(processor)
Procedure that pop the top value of the stack and return it to the program counter.
Definition cpu.h:648
#define STR_absolute_ACC(processor, addr)
Procedure that store the accumulator value to a memory address.
Definition cpu.h:457
#define LD_indirect_indexed_ACC(processor, addr, offset)
Procedure that loads to the accmulator using Inderect Indexed.
Definition cpu.h:441
#define GET_N_FLAG(x)
Definition cpu.h:126
#define OR_immediate(processor, data)
Procedure that performs a bitwise logic OR (A,Z,N = A & data)
Definition cpu.h:789
#define LD_indirect_X(processor, addr)
Procedure that lods a value from memory at the address contained in addr|addr+1. (indirection)
Definition cpu.h:341
#define ADD_indirect_indexed(processor, addr, offset)
Procedure that perform a ADD with the carry flag (A,Z,C,N=A+M+C) with indirect indexed.
Definition cpu.h:719
#define AND_absolute(processor, addr)
Procedure that performs a bitwise logic AND (A,Z,N = A&M) using absolute addressing mode.
Definition cpu.h:755
#define BRANCH_Carry_S(processor, offset)
Procedure that performs a BCS (branch if positive, if the N flag is clear)
Definition cpu.h:1046
#define AND_indexed_indirect(processor, addr, offset)
Procedure that perform a AND with the carry flag (A,Z,C,N=A+M+C) with indexed indirect addressing mod...
Definition cpu.h:772
#define SET_C_FLAG(x)
Definition cpu.h:128
#define LD_indirect_Y(processor, addr)
Procedure that lods a value from memory at the address contained in addr|addr+1. (indirection)
Definition cpu.h:349
#define BRANCH_Not_Equal(processor, offset)
Procedure that performs a BNE (if the Z flag is clear)
Definition cpu.h:1011
#define CLEAR_N_FLAG(x)
Definition cpu.h:146
#define BRANCH_If_Positive(processor, offset)
Procedure that performs a BPL (branch if positive, if the N flag is clear)
Definition cpu.h:997
#define STR_indirect_indexed_ACC(processor, addr, offset)
Procedure that store the accumulator value to a memory address using indirect indexed addressing mode...
Definition cpu.h:516
#define CLEAR_Z_FLAG(x)
Definition cpu.h:140
#define SET_V_FLAG(x)
Definition cpu.h:134
#define STR_offset_Y(processor, addr, offset)
Procedure that store the Y register value to a memory address + offset.
Definition cpu.h:506
#define DEC_X(processor)
Procedure that decrements the X register.
Definition cpu.h:418
#define BREAK(processor)
Procedure that performs a break instruction (forces an interrupt).
Definition cpu.h:1232
#define RETURN_Subroutine(processor)
Procedure that performs a return from subroutine (RTS instruction) by pulling the top two elements of...
Definition cpu.h:1287
#define LD_absolute_X(processor, addr)
Procedure that loads a value from memory at the address addr to the X register.
Definition cpu.h:310
#define LD_immediate_ACC(processor, d)
Procedure that loads an immediate (const value) in the accumulator.
Definition cpu.h:237
#define LD_immediate_X(processor, d)
Procedure that loads an immediate (const value) in the X register.
Definition cpu.h:244
#define SHIFT_LEFT_ACC(processor)
Procedure that performs a bitshift to the left (ASL operation) on the accumulator and place the 7th b...
Definition cpu.h:1076
#define BIT_TEST(processor, addr)
Procedure that performs a BIT test (A & M, N = M7, V = M6)
Definition cpu.h:951
#define ADD_offset(processor, addr, offset)
Procedure that perform a ADD with the carry flag (A,Z,C,N=A+M+C) with absolute+offset addressing addr...
Definition cpu.h:701
#define PUSH_ACC(processor)
Procedure that push the accumulator value to the top of the stack.
Definition cpu.h:603
#define SHIFT_LEFT_absolute(processor, addr)
Procedure that performs a bitshift to the left (ASL operation) at the address addr and place the 7th ...
Definition cpu.h:1091
#define SBC_indexed_indirect(processor, addr, offset)
Procedure that perform a SBC with the carry flag (A,Z,C,N=A-M-C) with indexed indirect addressing mod...
Definition cpu.h:928
#define INC_Y(processor)
Procedure that increments the Y register.
Definition cpu.h:412
#define XOR_absolute(processor, addr)
Procedure that performs a bitwise logic XOR (A,Z,N = A&M) using absolute addressing mode.
Definition cpu.h:845
#define LD_absolute_Y(processor, addr)
Procedure that loads a value from memory at the address addr to the Y register.
Definition cpu.h:317
#define JUMP_absolute(processor, addr)
Procedure that sets the program counter to a certain address (JMP instruction)
Definition cpu.h:1206
#define PULL_ACC(processor)
Procedure that pop the top value of the stack and return it to the accumulator.
Definition cpu.h:636
#define GET_P_FLAG(x)
Definition cpu.h:124
#define SBC_offset(processor, addr, offset)
Procedure that perform a SBC with the carry flag (A,Z,C,N=A-M-C) with offset addressing mode.
Definition cpu.h:919
#define GET_B_FLAG(x)
Definition cpu.h:123
#define SBC_absolute(processor, addr)
Procedure that perform a SBC with the carry flag (A,Z,C,N=A-M-C) with absolute addressing mode.
Definition cpu.h:910
#define OR_offset(processor, addr, offset)
Procedure that performs a bitwise logic OR (A,Z,N = A&M) using offset addressing mode.
Definition cpu.h:808
#define SBC_immediate(processor, data)
Procedure that perform a substract with the carry flag (A,Z,C,N=A-data-C) with an immediate.
Definition cpu.h:880
#define BRANCH_Equal(processor, offset)
Procedure that performs a BEQ (branch if positive, if the N flag is clear)
Definition cpu.h:1039
#define TR_SP_X(processor)
Procedure that store the stack pointer in the X register.
Definition cpu.h:569
#define LD_indexed_indirect_ACC(processor, addr, offset)
Procedure that loads to the accumulator using Indexed Indirect.
Definition cpu.h:432
#define LD_offset_ACC(processor, addr, offset)
Procedure that loads a value from memory at address addr+offset to the X register.
Definition cpu.h:269
#define RETURN_Interrupt(processor)
Procedure that performs a return from interrupt (RTI instruction) by pulling the flags from the top o...
Definition cpu.h:1298
#define LD_absolute_ACC(processor, addr)
Procedure that loads a value from memory at the address addr to the accumulator.
Definition cpu.h:303
#define GET_Z_FLAG(x)
Definition cpu.h:120
#define indirect_indexed(cpu, addr, offset)
Macro to access memory by indirect indexed addressing mode.
Definition cpu.h:165
#define CLEAR_ALL_FLAGS(x)
Definition cpu.h:148
#define XOR_offset(processor, addr, offset)
Procedure that performs a bitwise logic XOR (A,Z,N = A&M) using offset addressing mode.
Definition cpu.h:853
#define PUSH_PC(processor)
Procedure that push the program_counter to the top of the stack.
Definition cpu.h:615
#define AND_offset(processor, addr, offset)
Procedure that performs a bitwise logic AND (A,Z,N = A&M) using offset addressing mode.
Definition cpu.h:763
#define TR_X_ACC(processor)
Procedure that store the value in the X register in the accumulator.
Definition cpu.h:557
#define indexed_indirect(cpu, addr, offset)
Macro to access memory by indexed indirect addressing mode.
Definition cpu.h:156
#define SHIFT_RIGHT_ACC(processor)
Procedure that performs a bitshift to the right (LSR operation) on the accumulator and place the 0th ...
Definition cpu.h:1083
#define OR_indirect_indexed(processor, addr, offset)
Procedure that perform a OR with the carry flag (A,Z,C,N=A+M+C) with indirect indexed.
Definition cpu.h:826
#define XOR_indirect_indexed(processor, addr, offset)
Procedure that perform a XOR with the carry flag (A,Z,C,N=A+M+C) with indirect indexed.
Definition cpu.h:871
#define ROTATION_LEFT_offset(processor, addr, offset)
Procedure that performs a bit shift with rotation to the left (ROL operation) at the memory address (...
Definition cpu.h:1187
#define GET_I_FLAG(x)
Definition cpu.h:121
#define TR_Y_ACC(processor)
Procedure that store the value in the Y register in the accumulator.
Definition cpu.h:563
#define SBC_indirect_indexed(processor, addr, offset)
Procedure that perform a SBC with the carry flag (A,Z,C,N=A-M-C) with indirect indexed addressing mod...
Definition cpu.h:938
#define JUMP_Subroutine(processor, addr)
Procedure that performs a Jump to a subroutine (JSR instruction) located at the address addr.
Definition cpu.h:1275
#define SHIFT_RIGHT_offset(processor, addr, offset)
Procedure that performs a bitshift to the right (LSR operation) at the address (addr + offset) and pl...
Definition cpu.h:1116
#define LD_immediate_Y(processor, d)
Procedure that loads an immediate (const value) in the Y register.
Definition cpu.h:251
#define JUMP_indirect(processor, addr)
Procedure that sets the program counter to a certain indirect address (JMP instruction)
Definition cpu.h:1213
#define INC_X(processor)
Procedure that increments the X register.
Definition cpu.h:406
#define BRANCH_Overflow_S(processor, offset)
Procedure that performs a BVS (branch if positive, if the N flag is clear)
Definition cpu.h:1032
#define BRANCH_Overflow_C(processor, offset)
Procedure that performs a BVC (branch if overflow clear, if the V flag is clear)
Definition cpu.h:1004
#define ROTATION_LEFT_absolute(processor, addr)
Procedure that performs a bit shift with rotation to the left (ROL operation) at the memory address a...
Definition cpu.h:1166
#define GET_D_FLAG(x)
Definition cpu.h:122
#define PUSH_FLAGS(processor)
Procedure that push the processor flags to the top of the stack.
Definition cpu.h:609
#define LD_offset_X(processor, addr, offset)
Procedure that loads a value from memory at address addr+offset to the X register.
Definition cpu.h:278
#define AND_immediate(processor, data)
Procedure that performs a bitwise logic AND (A,Z,N = A & data)
Definition cpu.h:744
#define BRANCH_Carry_C(processor, offset)
Procedure that performs a BCC (if the C flag is clear)
Definition cpu.h:1018
void free_cpu(CPU *cpu)
Procedure that free the memory used by the CPU and the memory array.
Definition cpu.c:21
#define STR_absolute_Y(processor, addr)
Procedure that store the Y register value to a memory address.
Definition cpu.h:471
#define ROTATION_LEFT_ACC(processor)
Procedure that performs a bit shift with rotation to the left (ROL operation) on the accumulator....
Definition cpu.h:1149
#define SHIFT_LEFT_offset(processor, addr, offset)
Procedure that performs a bitshift to the left (ASL operation) at the address (addr + offset) and pla...
Definition cpu.h:1107
#define STR_indexed_indirect_ACC(processor, addr, offset)
Procedure that store the accumulator value to a memory address using indexes indirect addressing mode...
Definition cpu.h:526
#define LD_offset_Y(processor, addr, offset)
Procedure that loads a value from memory at address addr+offset to the Y register.
Definition cpu.h:287
#define STACK_END
Definition macros.h:46
#define STACK_START
Definition macros.h:45
#define BIT_7_MASK
Definition macros.h:20
#define BIT_3_MASK
Definition macros.h:24
#define BIT_6_MASK
Definition macros.h:21
#define BIT_0_MASK
Definition macros.h:27
#define EXIT_SUCCESS
Definition macros.h:5
#define BIT_5_MASK
Definition macros.h:22
#define BIT_4_MASK
Definition macros.h:23
#define BIT_1_MASK
Definition macros.h:26
#define BIT_2_MASK
Definition macros.h:25
data * memory
Definition mem.h:6
void reset_memory(memory mem)
This procedure set the entire memory to 0.
Definition mem.c:19
memory init_memory()
This function allocate on the heap a memory of exactly TOTAL_MEMORY_SIZE.
Definition mem.c:7
void free_rom(rom *r)
Frees the rom struct.
Definition reader.c:75
void display_rom(rom *r)
Procedure that displays the content of the rom in hexadecimal.
Definition reader.c:59
rom * open_rom(char *filepath)
A function that open the NES rom at a specified path.
Definition reader.c:7
This structure will be used to represent the state of the Central Processing Unit (CPU) of our emulat...
Definition cpu.h:27
data accumulator
A 8 bit register used to perform operations.
Definition cpu.h:31
data register_y
A 8 bit register. Commonly used to hold offset and counters.
Definition cpu.h:33
data flags
NVPBDIZC.
Definition cpu.h:35
address program_counter
An address pointing to the next instruction to be executed.
Definition cpu.h:28
data stack_pointer
A register that holds the 8 lower bytes of the address 0x11??.
Definition cpu.h:29
memory mem
A direct access to the Emulator Memory.
Definition cpu.h:39
data register_x
A 8 bit register. Commonly used to hold offset and counters.
Definition cpu.h:32
Definition reader.h:8
two_bytes_word address
Definition of the address format used by the CPU.
Definition types.h:12
byte data
Definition of the data format used by the CPU.
Definition types.h:11
void print_stack_expected(memory stack, data start)
Procedure that display the expected state of the stack.
Definition unit_tests.c:82
int main(int argc, char **argv)
Definition unit_tests.c:104
void print_cpu_state(CPU *processor)
Procedure that displays the current state of the CPU.
Definition unit_tests.c:10
void print_cpu_expected(data acc, data x, data y, data flags, address pc, data sp)
Procedure that display the expected state of the CPU.
Definition unit_tests.c:35
void print_stack_state(CPU *cpu)
Procedure that display the current state of the stack.
Definition unit_tests.c:59