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