blob: af9ad273c3fe5ddf5faafefe08421f29dc11fd6e [file] [log] [blame]
swissChili6c61a792020-07-28 16:29:20 -07001#include "cpu.h"
2#include "instructions.h"
3
4#include <endian.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9#define die(m, ...) \
10 printf("\033[31mError: " m "\033[0m\n", ##__VA_ARGS__); \
11 exit(1);
12
13cpu_t new_cpu()
14{
15 cpu_t cpu = { 0 };
16 cpu.regs[SR] = UNUSED; // unused flag always set
17 cpu.regs[SP] = 0xFD; // stack at is 0x100 + SP
18 cpu.pc = 0; // arbitrary program counter start
19 cpu.mem = malloc(0xFFFF);
20 memset(cpu.mem, 0, 0xFFFF);
21
22 if (!cpu.mem)
23 {
24 die("Could not allocate memory for CPU");
25 }
26
27 return cpu;
28}
29
30void free_cpu(cpu_t *cpu)
31{
32 free(cpu->mem);
33}
34
swissChili710d18d2020-07-29 19:43:20 -070035void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t addr)
swissChili6c61a792020-07-28 16:29:20 -070036{
swissChili710d18d2020-07-29 19:43:20 -070037 switch (op) {
38
39 }
swissChili6c61a792020-07-28 16:29:20 -070040}
41
42uint16_t le_to_native(uint8_t a, uint8_t b)
43{
44#ifdef LITTLE_ENDIAN
45 return a << 8 | b;
46#else
47 return b << 8 | a;
48#endif
49}
50
51uint16_t fetch_le(cpu_t *cpu)
52{
53 uint8_t a = cpu->mem[cpu->pc++];
54 uint8_t b = cpu->mem[cpu->pc++];
55 return le_to_native(a, b);
56}
57
swissChili710d18d2020-07-29 19:43:20 -070058arg_t arg_imm(uint16_t a)
59{
60 return (arg_t){ a, a };
61}
62
63arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
64{
65 if (flags & FETCH_NO_INDIRECTION)
66 return arg_imm(p);
67
68 return (arg_t){ c->mem[p], p };
69}
70
71arg_t arg(uint16_t v, uint16_t a)
72{
73 return (arg_t){ v, a };
74}
75
76arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
swissChili6c61a792020-07-28 16:29:20 -070077{
78 switch (am)
79 {
80 case AM_ACC:
81 case AM_IMP:
swissChili710d18d2020-07-29 19:43:20 -070082 return arg_imm(0);
swissChili6c61a792020-07-28 16:29:20 -070083
84 // In both cases return immediate 8 bit value
85 case AM_IMM:
86 case AM_ZP:
swissChili710d18d2020-07-29 19:43:20 -070087 return arg_imm(cpu->mem[cpu->pc++]);
swissChili6c61a792020-07-28 16:29:20 -070088
89 case AM_ABS:
swissChili710d18d2020-07-29 19:43:20 -070090 return arg_ptr(cpu, f, fetch_le(cpu));
swissChili6c61a792020-07-28 16:29:20 -070091
92 case AM_REL:
93 {
94 // PC should point to the opcode
95 // braces needed to avoid c stupidity
96 uint16_t pc = cpu->pc - 1;
swissChili710d18d2020-07-29 19:43:20 -070097 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + pc);
swissChili6c61a792020-07-28 16:29:20 -070098 }
99
100 case AM_IND:
101 {
102 uint16_t addr = fetch_le(cpu);
103 uint8_t low = cpu->mem[addr],
104 high = cpu->mem[addr + 1];
105
swissChili710d18d2020-07-29 19:43:20 -0700106 return arg_ptr(cpu, f, le_to_native(low, high));
swissChili6c61a792020-07-28 16:29:20 -0700107 }
108
109 case AM_AX:
swissChili710d18d2020-07-29 19:43:20 -0700110 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700111
112 case AM_AY:
swissChili710d18d2020-07-29 19:43:20 -0700113 return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700114
115 case AM_ZPX:
swissChili710d18d2020-07-29 19:43:20 -0700116 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
swissChili6c61a792020-07-28 16:29:20 -0700117
118 case AM_ZPY:
swissChili710d18d2020-07-29 19:43:20 -0700119 return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700120
121 case AM_ZIX:
122 {
123 uint8_t zp = cpu->mem[cpu->pc++];
swissChili710d18d2020-07-29 19:43:20 -0700124 uint16_t addr = zp + cpu->regs[X];
125 uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[addr + 1]);
126 return arg_ptr(cpu, f, indirect);
swissChili6c61a792020-07-28 16:29:20 -0700127 }
128
129 case AM_ZIY:
130 {
131 uint8_t zp = cpu->mem[cpu->pc++];
132 uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[zp + 1]);
swissChili710d18d2020-07-29 19:43:20 -0700133 return arg_ptr(cpu, f, base + cpu->regs[Y]);
swissChili6c61a792020-07-28 16:29:20 -0700134 }
135
136 default:
137 die("Unknown address mode %x", am);
swissChili710d18d2020-07-29 19:43:20 -0700138 __builtin_unreachable();
swissChili6c61a792020-07-28 16:29:20 -0700139 }
140}
141
142void step(cpu_t *cpu)
143{
144 switch (cpu->mem[cpu->pc++])
145 {
146#define INST(mn, am, op) \
147 case op: \
swissChili710d18d2020-07-29 19:43:20 -0700148 execute(cpu, #mn, mn, fetch_addr(cpu, am, 0)); \
swissChili6c61a792020-07-28 16:29:20 -0700149 break;
150
151 INSTRUCTIONS
152
153#undef INST
154
155 default:
156 die("Undefined opcode");
157 }
158}
159
160void dump_inst(cpu_t *cpu, const char *mn, uint16_t addr, uint8_t am)
161{
162 printf("\t%s\t", mn);
163
164 switch (am)
165 {
166 case AM_IMM:
167 printf("#");
168 case AM_REL:
169 case AM_ABS:
170 case AM_ZP:
171 printf("$%x", addr);
172 break;
173
174 case AM_IND:
175 printf("($%x)", addr);
176 break;
177
178 case AM_AX:
179 case AM_ZPX:
180 printf("$%x, X", addr);
181 break;
182
183 case AM_AY:
184 case AM_ZPY:
185 printf("$%x, Y", addr);
186 break;
187
188 case AM_ZIX:
189 printf("($%x, X)", addr);
190 break;
191
192 case AM_ZIY:
193 printf("($%x), Y", addr);
194 break;
195 }
196
197 printf("\n");
198}
199
200void disas_step(cpu_t *cpu)
201{
202 printf("%x", cpu->pc);
203 uint8_t op = cpu->mem[cpu->pc++];
204 switch (op)
205 {
206#define INST(mn, am, op) \
207 case op: \
swissChili710d18d2020-07-29 19:43:20 -0700208 dump_inst(cpu, #mn, \
209 fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
swissChili6c61a792020-07-28 16:29:20 -0700210 break;
211
212 INSTRUCTIONS
213
214#undef INST
215
216 default:
217 die("Undefined opcode %x", op);
218 }
219}
220
221void disas(cpu_t *cpu)
222{
223 while (cpu->pc < 0xFFFF)
224 {
225 disas_step(cpu);
226 }
227}