diff options
| author | vin <git@vineetk.net> | 2024-05-24 12:20:04 +0530 |
|---|---|---|
| committer | vin <git@vineetk.net> | 2024-05-24 12:20:04 +0530 |
| commit | 8493837ef921880196c29f0b766bebe9d2bf33ad (patch) | |
| tree | 9bc00785935d12b85518a0533ec741a293758042 /cpu.c | |
| parent | 24ca08a83d8b420d337d29c87d672b624890b5bf (diff) | |
implement tax and inx and print status each time
Diffstat (limited to 'cpu.c')
| -rw-r--r-- | cpu.c | 114 |
1 files changed, 97 insertions, 17 deletions
| @@ -1,4 +1,10 @@ | |||
| 1 | #include <stdint.h> | 1 | #include <stdint.h> |
| 2 | #include <stdio.h> | ||
| 3 | |||
| 4 | #define STATUS_UPDATE_ZERO(r) \ | ||
| 5 | (regs.status.zero = r == 0) | ||
| 6 | #define STATUS_UPDATE_NEGATIVE(r) \ | ||
| 7 | (regs.status.negative = ((r & (1 << 7)) > 0)) | ||
| 2 | 8 | ||
| 3 | struct cpu_flags { | 9 | struct cpu_flags { |
| 4 | uint8_t carry : 1; | 10 | uint8_t carry : 1; |
| @@ -12,7 +18,7 @@ struct cpu_flags { | |||
| 12 | }; | 18 | }; |
| 13 | 19 | ||
| 14 | struct registers { | 20 | struct registers { |
| 15 | uint8_t acc, x, y, sp; | 21 | uint8_t a, x, y, sp; |
| 16 | struct cpu_flags status; | 22 | struct cpu_flags status; |
| 17 | uint16_t pc; | 23 | uint16_t pc; |
| 18 | }; | 24 | }; |
| @@ -40,28 +46,64 @@ uint8_t addrbus[0x10000]; | |||
| 40 | /* example program taken from https://bugzmanov.github.io/nes_ebook/chapter_3_1.html */ | 46 | /* example program taken from https://bugzmanov.github.io/nes_ebook/chapter_3_1.html */ |
| 41 | uint8_t program[] = { 0xa9, 0xc0, 0xaa, 0xe8, 0x00 }; | 47 | uint8_t program[] = { 0xa9, 0xc0, 0xaa, 0xe8, 0x00 }; |
| 42 | 48 | ||
| 43 | void brk(void) | 49 | void |
| 50 | brk(void) | ||
| 44 | { | 51 | { |
| 52 | /* $00 */ | ||
| 45 | /* TODO: push regs.pc and regs.status to stack and load IRQ vector */ | 53 | /* TODO: push regs.pc and regs.status to stack and load IRQ vector */ |
| 46 | regs.status.brk = 1; | 54 | regs.status.brk = 1; |
| 47 | return; | 55 | return; |
| 48 | } | 56 | } |
| 49 | 57 | ||
| 50 | void lda(enum addressing_mode mode) | 58 | void |
| 59 | tax(void) | ||
| 60 | { | ||
| 61 | /* $AA */ | ||
| 62 | regs.x = regs.a; | ||
| 63 | |||
| 64 | STATUS_UPDATE_ZERO(regs.x); | ||
| 65 | STATUS_UPDATE_NEGATIVE(regs.x); | ||
| 66 | } | ||
| 67 | |||
| 68 | void | ||
| 69 | inx(void) | ||
| 70 | { | ||
| 71 | /* $E8 */ | ||
| 72 | regs.x++; | ||
| 73 | |||
| 74 | STATUS_UPDATE_ZERO(regs.x); | ||
| 75 | STATUS_UPDATE_NEGATIVE(regs.x); | ||
| 76 | } | ||
| 77 | |||
| 78 | void | ||
| 79 | lda(enum addressing_mode mode) | ||
| 51 | { | 80 | { |
| 52 | uint8_t val; | 81 | uint8_t val; |
| 53 | 82 | ||
| 54 | switch (mode) { | 83 | switch (mode) { |
| 55 | case AM_IMMEDIATE: /* $A9 */ | 84 | case AM_IMMEDIATE: /* $A9 */ |
| 56 | val = program[regs.pc++]; | 85 | val = program[regs.pc++]; |
| 57 | regs.acc = val; | 86 | printf("arg1 $%02X\n", val); |
| 87 | regs.a = val; | ||
| 58 | break; | 88 | break; |
| 59 | case AM_ZERO_PAGE: /* $A5 */ | 89 | case AM_ZERO_PAGE: /* $A5 */ |
| 90 | /* TODO */ | ||
| 91 | break; | ||
| 60 | case AM_ZERO_PAGE_X: /* $B5 */ | 92 | case AM_ZERO_PAGE_X: /* $B5 */ |
| 93 | /* TODO */ | ||
| 94 | break; | ||
| 61 | case AM_ABSOLUTE: /* $AD */ | 95 | case AM_ABSOLUTE: /* $AD */ |
| 96 | /* TODO */ | ||
| 97 | break; | ||
| 62 | case AM_ABSOLUTE_X: /* $BD */ | 98 | case AM_ABSOLUTE_X: /* $BD */ |
| 99 | /* TODO */ | ||
| 100 | break; | ||
| 63 | case AM_ABSOLUTE_Y: /* $B9 */ | 101 | case AM_ABSOLUTE_Y: /* $B9 */ |
| 102 | /* TODO */ | ||
| 103 | break; | ||
| 64 | case AM_INDIRECT_X: /* $A1 */ | 104 | case AM_INDIRECT_X: /* $A1 */ |
| 105 | /* TODO */ | ||
| 106 | break; | ||
| 65 | case AM_INDIRECT_Y: /* $B1 */ | 107 | case AM_INDIRECT_Y: /* $B1 */ |
| 66 | /* TODO */ | 108 | /* TODO */ |
| 67 | break; | 109 | break; |
| @@ -69,48 +111,86 @@ void lda(enum addressing_mode mode) | |||
| 69 | return; | 111 | return; |
| 70 | } | 112 | } |
| 71 | 113 | ||
| 72 | regs.status.zero = regs.acc == 0; | 114 | STATUS_UPDATE_ZERO(regs.a); |
| 73 | regs.status.negative = (regs.acc & (1 << 7)) != 0; | 115 | STATUS_UPDATE_NEGATIVE(regs.a); |
| 74 | } | 116 | } |
| 75 | 117 | ||
| 76 | void interpret(void) | 118 | void |
| 119 | interpret(void) | ||
| 77 | { | 120 | { |
| 78 | uint8_t opcode; | 121 | uint8_t opcode; |
| 79 | regs.pc = 0; | 122 | regs.pc = 0; |
| 123 | regs.status.unused = 1; | ||
| 124 | |||
| 125 | printf("Initial State:\n"); | ||
| 126 | printf("status: %i%i%i%i%i%i%i%i\n", regs.status.carry, | ||
| 127 | regs.status.zero, regs.status.interrupt_disable, | ||
| 128 | regs.status.decimal_mode, regs.status.brk, | ||
| 129 | regs.status.unused, regs.status.overflow, | ||
| 130 | regs.status.negative); | ||
| 131 | printf("A: $%02X, X: $%02X, Y: $%02X, SP: $%02X, PC: $%02X\n", | ||
| 132 | regs.a, regs.x, regs.y, regs.sp, regs.pc); | ||
| 133 | |||
| 134 | putchar('\n'); | ||
| 80 | 135 | ||
| 81 | for (;;) { | 136 | for (;;) { |
| 82 | opcode = program[regs.pc++]; | 137 | opcode = program[regs.pc++]; |
| 83 | 138 | ||
| 139 | printf("opcode: $%02X\n", opcode); | ||
| 140 | |||
| 84 | switch (opcode) { | 141 | switch (opcode) { |
| 85 | case 0x00: | 142 | case 0x00: |
| 86 | brk(); | 143 | brk(); |
| 87 | return; | 144 | return; |
| 88 | case 0xa9: | 145 | case 0xa1: |
| 89 | lda(AM_IMMEDIATE); | 146 | lda(AM_INDIRECT_X); |
| 90 | break; | 147 | break; |
| 91 | case 0xa5: | 148 | case 0xa5: |
| 92 | lda(AM_ZERO_PAGE); | 149 | lda(AM_ZERO_PAGE); |
| 93 | break; | 150 | break; |
| 94 | case 0xb5: | 151 | case 0xa9: |
| 95 | lda(AM_ZERO_PAGE_X); | 152 | lda(AM_IMMEDIATE); |
| 153 | break; | ||
| 154 | case 0xaa: | ||
| 155 | tax(); | ||
| 96 | break; | 156 | break; |
| 97 | case 0xad: | 157 | case 0xad: |
| 98 | lda(AM_ABSOLUTE); | 158 | lda(AM_ABSOLUTE); |
| 99 | break; | 159 | break; |
| 100 | case 0xbd: | 160 | case 0xb1: |
| 101 | lda(AM_ABSOLUTE_X); | 161 | lda(AM_INDIRECT_Y); |
| 162 | break; | ||
| 163 | case 0xb5: | ||
| 164 | lda(AM_ZERO_PAGE_X); | ||
| 102 | break; | 165 | break; |
| 103 | case 0xb9: | 166 | case 0xb9: |
| 104 | lda(AM_ABSOLUTE_Y); | 167 | lda(AM_ABSOLUTE_Y); |
| 105 | break; | 168 | break; |
| 106 | case 0xa1: | 169 | case 0xbd: |
| 107 | lda(AM_INDIRECT_X); | 170 | lda(AM_ABSOLUTE_X); |
| 108 | break; | 171 | break; |
| 109 | case 0xb1: | 172 | case 0xe8: |
| 110 | lda(AM_INDIRECT_Y); | 173 | inx(); |
| 111 | break; | 174 | break; |
| 112 | default: | 175 | default: |
| 176 | printf("opcode $%02X not implemented\n", opcode); | ||
| 113 | break; | 177 | break; |
| 114 | } | 178 | } |
| 179 | |||
| 180 | printf("status: %i%i%i%i%i%i%i%i\n", regs.status.carry, | ||
| 181 | regs.status.zero, regs.status.interrupt_disable, | ||
| 182 | regs.status.decimal_mode, regs.status.brk, | ||
| 183 | regs.status.unused, regs.status.overflow, | ||
| 184 | regs.status.negative); | ||
| 185 | printf("A: $%02X, X: $%02X, Y: $%02X, SP: $%02X, PC: $%02X\n", | ||
| 186 | regs.a, regs.x, regs.y, regs.sp, regs.pc); | ||
| 115 | } | 187 | } |
| 116 | } | 188 | } |
| 189 | |||
| 190 | int | ||
| 191 | main(void) | ||
| 192 | { | ||
| 193 | interpret(); | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
