1 /*
2 * cpu6502.c
3 *
4 * CAL interface and non-generated code for the cpu6502 core
5 */
6
7 /* $Id: cpu6502.c,v 1.5 2001/03/05 00:04:22 nyef Exp $ */
8
9 #include "cpu6502.h"
10
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include "cal.h"
14 #include "tool.h"
15 #include "ui.h"
16
17 #include "cpu6502int.h"
18
cpu6502_create(void)19 struct cpu6502_context *cpu6502_create(void)
20 {
21 return calloc(1, sizeof(struct cpu6502_context));
22 }
23
cpu6502_setuserdata(struct cpu6502_context * context,void * userdata)24 void cpu6502_setuserdata(struct cpu6502_context *context, void *userdata)
25 {
26 context->cpu = userdata;
27 }
28
cpu6502_setmemhandlers(struct cpu6502_context * context,memread8_t readfunc,memwrite8_t writefunc)29 void cpu6502_setmemhandlers(struct cpu6502_context *context, memread8_t readfunc, memwrite8_t writefunc)
30 {
31 context->readfunc = readfunc;
32 context->writefunc = writefunc;
33 }
34
cpu6502_setzpage(struct cpu6502_context * context,void * page0)35 void cpu6502_setzpage(struct cpu6502_context *context, void *page0)
36 {
37 context->zpage = page0;
38 }
39
cpu6502_reset(struct cpu6502_context * context)40 void cpu6502_reset(struct cpu6502_context *context)
41 {
42 context->reg_a = 0x00;
43 context->reg_x = 0x00;
44 context->reg_y = 0x00;
45 context->reg_s = 0xff;
46
47 SET_FLAGS(context, 0x00); /* FIXME: wrong */
48
49 context->pc = context->readfunc(context->cpu, VECTOR_RESET_LO);
50 context->pc |= context->readfunc(context->cpu, VECTOR_RESET_HI) << 8;
51 }
52
cpu6502_step(struct cpu6502_context * context)53 void cpu6502_step(struct cpu6502_context *context)
54 {
55 u8 opcode;
56
57 opcode = OPFETCH(context);
58 cpu6502_decode[opcode](context);
59 }
60
cpu6502_run(struct cpu6502_context * context)61 void cpu6502_run(struct cpu6502_context *context)
62 {
63 while (context->cycles_left > 0) {
64 cpu6502_step(context);
65
66 if (system_flags & F_UNIMPL) {
67 return;
68 }
69 }
70 }
71
cpu6502_runfor(struct cpu6502_context * context,int cycles)72 void cpu6502_runfor(struct cpu6502_context *context, int cycles)
73 {
74 context->cycles_left += cycles;
75 }
76
cpu6502_event_delay_callback(void * context,int cycles)77 void cpu6502_event_delay_callback(void *context, int cycles)
78 {
79 cpu6502_runfor(context, cycles);
80 cpu6502_run(context);
81 }
82
cpu6502_irq(struct cpu6502_context * context)83 void cpu6502_irq(struct cpu6502_context *context)
84 {
85 if (context->flags & FLAG_I) {
86 return; /* interrupts disabled */
87 }
88
89 PUSH_BYTE(context, context->pc >> 8);
90 PUSH_BYTE(context, context->pc & 0xff);
91 PUSH_BYTE(context, (GET_FLAGS(context)) & ~FLAG_B);
92
93 context->flags |= FLAG_I;
94 context->flags &= ~FLAG_D;
95
96 context->pc = context->readfunc(context->cpu, VECTOR_IRQ_LO);
97 context->pc |= context->readfunc(context->cpu, VECTOR_IRQ_HI) << 8;
98
99 context->cycles_left -= 7;
100 }
101
cpu6502_nmi(struct cpu6502_context * context)102 void cpu6502_nmi(struct cpu6502_context *context)
103 {
104 PUSH_BYTE(context, context->pc >> 8);
105 PUSH_BYTE(context, context->pc & 0xff);
106 PUSH_BYTE(context, (GET_FLAGS(context)) & ~FLAG_B);
107
108 context->pc = context->readfunc(context->cpu, VECTOR_NMI_LO);
109 context->pc |= context->readfunc(context->cpu, VECTOR_NMI_HI) << 8;
110
111 context->cycles_left -= 7;
112 }
113
114 #ifdef LAZY_FLAG_EVALUATION
cpu6502_get_flags(struct cpu6502_context * context)115 u8 cpu6502_get_flags(struct cpu6502_context *context)
116 {
117 u8 retval;
118
119 retval = context->flags;
120 retval &= ~(FLAG_N | FLAG_Z | FLAG_V | FLAG_C);
121 retval |= context->flag_n & FLAG_N;
122 retval |= (!context->flag_z) << 1;
123 retval |= context->flag_c;
124 retval |= context->flag_v >> 1;
125
126 return retval;
127 }
128
cpu6502_set_flags(struct cpu6502_context * context,u8 flags)129 void cpu6502_set_flags(struct cpu6502_context *context, u8 flags)
130 {
131 context->flags = flags & ~(FLAG_N | FLAG_Z | FLAG_V | FLAG_C);
132 context->flag_n = flags;
133 context->flag_z = !(flags & FLAG_Z);
134 context->flag_c = flags & FLAG_C;
135 context->flag_v = (flags & FLAG_V) << 1;
136 }
137 #endif
138
cpu6502_op_0(struct cpu6502_context * context)139 void cpu6502_op_0(struct cpu6502_context *context)
140 {
141 context->pc -= 1;
142 deb_printf("unimplemented opcode 0x%02x.\n", OPFETCH(context));
143 system_flags |= F_UNIMPL;
144 }
145
146 /* CAL interface code */
147
148 void cal_cpu6502_reset(cal_cpu cpu);
149 void cal_cpu6502_run(cal_cpu cpu);
150 void cal_cpu6502_runfor(cal_cpu cpu, int cycles);
151 void cal_cpu6502_irq(cal_cpu cpu, int irqno);
152 void cal_cpu6502_nmi(cal_cpu cpu);
153 void cal_cpu6502_setzpage(cal_cpu cpu, void *page0);
154 int cal_cpu6502_timeleft(cal_cpu cpu);
155 void cal_cpu6502_setmmu8(cal_cpu cpu, int shift, int mask, memread8_t *rtbl, memwrite8_t *wtbl);
156
cal_cpu6502_init(cal_cpu * cpu)157 void cal_cpu6502_init(cal_cpu *cpu)
158 {
159 (*cpu)->data.d_cpu6502 = calloc(1, sizeof(struct cpu6502_context));
160 if (!(*cpu)->data.d_cpu6502) {
161 printf("Insufficient memory to create CPU.\n");
162 free(*cpu);
163 *cpu = NULL;
164 return;
165 }
166 (*cpu)->reset = cal_cpu6502_reset;
167 (*cpu)->run = cal_cpu6502_run;
168 (*cpu)->runfor = cal_cpu6502_runfor;
169 (*cpu)->irq = cal_cpu6502_irq;
170 (*cpu)->nmi = cal_cpu6502_nmi;
171 (*cpu)->setzpage = cal_cpu6502_setzpage;
172 (*cpu)->timeleft = cal_cpu6502_timeleft;
173 (*cpu)->setmmu8 = cal_cpu6502_setmmu8;
174 (*cpu)->data.d_cpu6502->cpu = *cpu;
175 }
176
cal_cpu6502_reset(cal_cpu cpu)177 void cal_cpu6502_reset(cal_cpu cpu)
178 {
179 cpu6502_reset(cpu->data.d_cpu6502);
180 }
181
cal_cpu6502_run(cal_cpu cpu)182 void cal_cpu6502_run(cal_cpu cpu)
183 {
184 cpu6502_run(cpu->data.d_cpu6502);
185 }
186
cal_cpu6502_runfor(cal_cpu cpu,int cycles)187 void cal_cpu6502_runfor(cal_cpu cpu, int cycles)
188 {
189 cpu6502_runfor(cpu->data.d_cpu6502, cycles);
190 }
191
cal_cpu6502_irq(cal_cpu cpu,int irqno)192 void cal_cpu6502_irq(cal_cpu cpu, int irqno)
193 {
194 cpu6502_irq(cpu->data.d_cpu6502);
195 }
196
cal_cpu6502_nmi(cal_cpu cpu)197 void cal_cpu6502_nmi(cal_cpu cpu)
198 {
199 cpu6502_nmi(cpu->data.d_cpu6502);
200 }
201
cal_cpu6502_setzpage(cal_cpu cpu,void * page0)202 void cal_cpu6502_setzpage(cal_cpu cpu, void *page0)
203 {
204 cpu6502_setzpage(cpu->data.d_cpu6502, page0);
205 }
206
cal_cpu6502_timeleft(cal_cpu cpu)207 int cal_cpu6502_timeleft(cal_cpu cpu)
208 {
209 return cpu->data.d_cpu6502->cycles_left;
210 }
211
cal_cpu6502_setmmu8(cal_cpu cpu,int shift,int mask,memread8_t * rtbl,memwrite8_t * wtbl)212 void cal_cpu6502_setmmu8(cal_cpu cpu, int shift, int mask, memread8_t *rtbl, memwrite8_t *wtbl)
213 {
214 cpu6502_setmemhandlers(cpu->data.d_cpu6502, *rtbl, *wtbl);
215 }
216
217
218 /*
219 * $Log: cpu6502.c,v $
220 * Revision 1.5 2001/03/05 00:04:22 nyef
221 * added inclusion of new cpu6502.h
222 *
223 * Revision 1.4 2001/03/04 23:22:26 nyef
224 * reduced cal interface code to wrappers around cpu6502_*() functions
225 *
226 * Revision 1.3 2000/09/26 06:30:36 nyef
227 * added cycle timings for IRQ and NMI
228 *
229 * Revision 1.2 2000/07/15 22:18:49 nyef
230 * converted to use lazy flag evaluation
231 *
232 * Revision 1.1 2000/05/01 00:35:33 nyef
233 * Initial revision
234 *
235 */
236