diff options
| author | vin <git@vineetk.net> | 2024-06-08 17:41:06 +0530 |
|---|---|---|
| committer | vin <git@vineetk.net> | 2024-06-08 17:41:17 +0530 |
| commit | 1ac30a026b7877ca6b295c661d91b20eaddb01c9 (patch) | |
| tree | 22b23ab204390641e84ce42581ee5408444dd993 /cpu.c | |
| parent | bd85b80ba7a7919a80ce6fd742b37d3e183f2e3a (diff) | |
add adc and actually fix peek/16
Diffstat (limited to 'cpu.c')
| -rw-r--r-- | cpu.c | 84 |
1 files changed, 82 insertions, 2 deletions
| @@ -1,7 +1,10 @@ | |||
| 1 | #include <stdint.h> | 1 | #include <stdint.h> |
| 2 | #include <stdio.h> | 2 | #include <stdio.h> |
| 3 | #include <stdlib.h> | ||
| 3 | #include <string.h> | 4 | #include <string.h> |
| 4 | 5 | ||
| 6 | #define MAX(a, b) ((a > b) ? a : b) | ||
| 7 | |||
| 5 | #define STATUS_UPDATE_ZERO(r) \ | 8 | #define STATUS_UPDATE_ZERO(r) \ |
| 6 | (regs.status.zero = r == 0) | 9 | (regs.status.zero = r == 0) |
| 7 | #define STATUS_UPDATE_NEGATIVE(r) \ | 10 | #define STATUS_UPDATE_NEGATIVE(r) \ |
| @@ -47,12 +50,12 @@ uint8_t memory[0x16000]; | |||
| 47 | uint8_t program[] = { 0xa9, 0xc0, 0xaa, 0xe8, 0x00 }; | 50 | uint8_t program[] = { 0xa9, 0xc0, 0xaa, 0xe8, 0x00 }; |
| 48 | 51 | ||
| 49 | uint8_t | 52 | uint8_t |
| 50 | peek(uint8_t addr) | 53 | peek(uint16_t addr) |
| 51 | { | 54 | { |
| 52 | return memory[addr]; | 55 | return memory[addr]; |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | uint8_t | 58 | uint16_t |
| 56 | peek16(uint16_t addr) | 59 | peek16(uint16_t addr) |
| 57 | { | 60 | { |
| 58 | /* bytes are stored in little-endian (low then high) */ | 61 | /* bytes are stored in little-endian (low then high) */ |
| @@ -60,6 +63,58 @@ peek16(uint16_t addr) | |||
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | void | 65 | void |
| 66 | adc(enum addressing_mode mode) | ||
| 67 | { | ||
| 68 | uint8_t arg, val; | ||
| 69 | uint16_t sum; // 16-bit sum makes it easier to determine carry flag | ||
| 70 | |||
| 71 | if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) | ||
| 72 | arg = peek(regs.pc++); | ||
| 73 | else | ||
| 74 | arg = peek16(regs.pc++); | ||
| 75 | |||
| 76 | switch (mode) { | ||
| 77 | case AM_IMM: /* $69 */ | ||
| 78 | val = arg; | ||
| 79 | break; | ||
| 80 | case AM_ZP: /* $65 */ | ||
| 81 | val = peek(arg % 256); | ||
| 82 | break; | ||
| 83 | case AM_ABS: /* $6D */ | ||
| 84 | val = peek16(arg); | ||
| 85 | break; | ||
| 86 | case AM_ZP_X: /* $75 */ | ||
| 87 | val = peek((arg + regs.x) % 256); | ||
| 88 | break; | ||
| 89 | case AM_ABS_X: /* $7D */ | ||
| 90 | val = peek16(arg + regs.x); | ||
| 91 | break; | ||
| 92 | case AM_ABS_Y: /* $79 */ | ||
| 93 | val = peek16(arg + regs.y); | ||
| 94 | break; | ||
| 95 | case AM_IND_X: /* $61 */ | ||
| 96 | val = peek(peek((arg + regs.x) % 256) + peek((arg + regs.x + 1) % 256) * 256); | ||
| 97 | break; | ||
| 98 | case AM_IND_Y: /* $71 */ | ||
| 99 | val = peek(peek(arg) + peek((arg + 1) % 256) * 256 + regs.y); | ||
| 100 | break; | ||
| 101 | default: | ||
| 102 | fprintf(stderr, "INVALID ADC ADDRESSING MODE\n"); | ||
| 103 | abort(); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | |||
| 107 | sum = regs.a + val + regs.status.carry; | ||
| 108 | regs.a = sum & 0xFF; | ||
| 109 | |||
| 110 | regs.status.carry = sum > 0xFF; | ||
| 111 | /* overflow flag formula: https://stackoverflow.com/a/29224684 */ | ||
| 112 | regs.status.overflow = ~(regs.a ^ arg) & (regs.a ^ sum) & 0x80; | ||
| 113 | STATUS_UPDATE_ZERO(regs.a); | ||
| 114 | STATUS_UPDATE_NEGATIVE(regs.a); | ||
| 115 | } | ||
| 116 | |||
| 117 | void | ||
| 63 | brk(void) | 118 | brk(void) |
| 64 | { | 119 | { |
| 65 | /* $00 */ | 120 | /* $00 */ |
| @@ -150,6 +205,30 @@ interpret(void) | |||
| 150 | case 0x00: | 205 | case 0x00: |
| 151 | brk(); | 206 | brk(); |
| 152 | return; | 207 | return; |
| 208 | case 0x61: | ||
| 209 | adc(AM_IND_X); | ||
| 210 | break; | ||
| 211 | case 0x65: | ||
| 212 | adc(AM_ZP); | ||
| 213 | break; | ||
| 214 | case 0x69: | ||
| 215 | adc(AM_IMM); | ||
| 216 | break; | ||
| 217 | case 0x6D: | ||
| 218 | adc(AM_ABS); | ||
| 219 | break; | ||
| 220 | case 0x71: | ||
| 221 | adc(AM_IND_Y); | ||
| 222 | break; | ||
| 223 | case 0x75: | ||
| 224 | adc(AM_ZP_X); | ||
| 225 | break; | ||
| 226 | case 0x79: | ||
| 227 | adc(AM_ABS_Y); | ||
| 228 | break; | ||
| 229 | case 0x7D: | ||
| 230 | adc(AM_ABS_X); | ||
| 231 | break; | ||
| 153 | case 0xa1: | 232 | case 0xa1: |
| 154 | lda(AM_IND_X); | 233 | lda(AM_IND_X); |
| 155 | break; | 234 | break; |
| @@ -216,6 +295,7 @@ main(void) | |||
| 216 | fprintf(stderr, "program is too big for memory\n"); | 295 | fprintf(stderr, "program is too big for memory\n"); |
| 217 | return 1; | 296 | return 1; |
| 218 | } | 297 | } |
| 298 | |||
| 219 | memcpy(memory + 0x8000, program, sizeof(program)); | 299 | memcpy(memory + 0x8000, program, sizeof(program)); |
| 220 | regs.pc = 0x8000; | 300 | regs.pc = 0x8000; |
| 221 | 301 | ||
