/[VRac]/M6502/src/M6502.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /M6502/src/M6502.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 81 - (show annotations)
Wed Aug 1 15:53:54 2007 UTC (16 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 11472 byte(s)
cleanup build process
1 /** M6502: portable 6502 emulator ****************************/
2 /** **/
3 /** M6502.c **/
4 /** **/
5 /** This file contains implementation for 6502 CPU. Don't **/
6 /** forget to provide Rd6502(), Wr6502(), Loop6502(), and **/
7 /** possibly Op6502() functions to accomodate the emulated **/
8 /** machine's architecture. **/
9 /** **/
10 /** Copyright (C) Marat Fayzullin 1996-2007 **/
11 /** Alex Krasivsky 1996 **/
12 /** You are not allowed to distribute this software **/
13 /** commercially. Please, notify me, if you make any **/
14 /** changes to this file. **/
15 /*************************************************************/
16
17 #include "M6502.h"
18 #include "Tables.h"
19 #include <stdio.h>
20
21 /** INLINE ***************************************************/
22 /** C99 standard has "inline", but older compilers used **/
23 /** __inline for the same purpose. **/
24 /*************************************************************/
25 #ifdef __C99__
26 #define INLINE static inline
27 #else
28 #define INLINE static __inline
29 #endif
30
31 /** System-Dependent Stuff ***********************************/
32 /** This is system-dependent code put here to speed things **/
33 /** up. It has to stay inlined to be fast. **/
34 /*************************************************************/
35 #ifdef INES
36 #define FAST_RDOP
37 extern byte *Page[];
38 INLINE byte Op6502(register word A)
39 {
40 #ifndef S60
41 return(Page[A>>13][A&0x1FFF]);
42 #else
43 asm
44 (
45 "and r2,%1,#0xE000\t\n"
46 "ldr r2,[%2,r2,lsr #11]\t\n"
47 "mov %0,%1,lsl #19\t\n"
48 "ldrb %0,[r2,%0,lsr #19]\t\n"
49 : "=r"(A)
50 : "0"(A),"r"(Page)
51 : "r2"
52 );
53 return(A);
54 #endif /* S60 */
55 }
56 #endif /* INES */
57
58 /** FAST_RDOP ************************************************/
59 /** With this #define not present, Rd6502() should perform **/
60 /** the functions of Rd6502(). **/
61 /*************************************************************/
62 #ifndef FAST_RDOP
63 #define Op6502(A) Rd6502(A)
64 #endif
65
66 /** Addressing Methods ***************************************/
67 /** These macros calculate and return effective addresses. **/
68 /*************************************************************/
69 #define MC_Ab(Rg) M_LDWORD(Rg)
70 #define MC_Zp(Rg) Rg.W=Op6502(R->PC.W++)
71 #define MC_Zx(Rg) Rg.W=(byte)(Op6502(R->PC.W++)+R->X)
72 #define MC_Zy(Rg) Rg.W=(byte)(Op6502(R->PC.W++)+R->Y)
73 #define MC_Ax(Rg) M_LDWORD(Rg);Rg.W+=R->X
74 #define MC_Ay(Rg) M_LDWORD(Rg);Rg.W+=R->Y
75 #define MC_Ix(Rg) K.W=(byte)(Op6502(R->PC.W++)+R->X); \
76 Rg.B.l=Op6502(K.W++);Rg.B.h=Op6502(K.W)
77 #define MC_Iy(Rg) K.W=Op6502(R->PC.W++); \
78 Rg.B.l=Op6502(K.W++);Rg.B.h=Op6502(K.W); \
79 Rg.W+=R->Y
80
81 /** Reading From Memory **************************************/
82 /** These macros calculate address and read from it. **/
83 /*************************************************************/
84 #define MR_Ab(Rg) MC_Ab(J);Rg=Rd6502(J.W)
85 #define MR_Im(Rg) Rg=Op6502(R->PC.W++)
86 #define MR_Zp(Rg) MC_Zp(J);Rg=Rd6502(J.W)
87 #define MR_Zx(Rg) MC_Zx(J);Rg=Rd6502(J.W)
88 #define MR_Zy(Rg) MC_Zy(J);Rg=Rd6502(J.W)
89 #define MR_Ax(Rg) MC_Ax(J);Rg=Rd6502(J.W)
90 #define MR_Ay(Rg) MC_Ay(J);Rg=Rd6502(J.W)
91 #define MR_Ix(Rg) MC_Ix(J);Rg=Rd6502(J.W)
92 #define MR_Iy(Rg) MC_Iy(J);Rg=Rd6502(J.W)
93
94 /** Writing To Memory ****************************************/
95 /** These macros calculate address and write to it. **/
96 /*************************************************************/
97 #define MW_Ab(Rg) MC_Ab(J);Wr6502(J.W,Rg)
98 #define MW_Zp(Rg) MC_Zp(J);Wr6502(J.W,Rg)
99 #define MW_Zx(Rg) MC_Zx(J);Wr6502(J.W,Rg)
100 #define MW_Zy(Rg) MC_Zy(J);Wr6502(J.W,Rg)
101 #define MW_Ax(Rg) MC_Ax(J);Wr6502(J.W,Rg)
102 #define MW_Ay(Rg) MC_Ay(J);Wr6502(J.W,Rg)
103 #define MW_Ix(Rg) MC_Ix(J);Wr6502(J.W,Rg)
104 #define MW_Iy(Rg) MC_Iy(J);Wr6502(J.W,Rg)
105
106 /** Modifying Memory *****************************************/
107 /** These macros calculate address and modify it. **/
108 /*************************************************************/
109 #define MM_Ab(Cmd) MC_Ab(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
110 #define MM_Zp(Cmd) MC_Zp(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
111 #define MM_Zx(Cmd) MC_Zx(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
112 #define MM_Ax(Cmd) MC_Ax(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
113
114 /** Other Macros *********************************************/
115 /** Calculating flags, stack, jumps, arithmetics, etc. **/
116 /*************************************************************/
117 #define M_FL(Rg) R->P=(R->P&~(Z_FLAG|N_FLAG))|ZNTable[Rg]
118 #define M_LDWORD(Rg) Rg.B.l=Op6502(R->PC.W++);Rg.B.h=Op6502(R->PC.W++)
119
120 #define M_PUSH(Rg) Wr6502(0x0100|R->S,Rg);R->S--
121 #define M_POP(Rg) R->S++;Rg=Op6502(0x0100|R->S)
122 #define M_JR R->PC.W+=(offset)Op6502(R->PC.W)+1;R->ICount--
123
124 #ifdef NO_DECIMAL
125
126 #define M_ADC(Rg) \
127 K.W=R->A+Rg+(R->P&C_FLAG); \
128 R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
129 R->P|=(~(R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
130 (K.B.h? C_FLAG:0)|ZNTable[K.B.l]; \
131 R->A=K.B.l
132
133 /* Warning! C_FLAG is inverted before SBC and after it */
134 #define M_SBC(Rg) \
135 K.W=R->A-Rg-(~R->P&C_FLAG); \
136 R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
137 R->P|=((R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
138 (K.B.h? 0:C_FLAG)|ZNTable[K.B.l]; \
139 R->A=K.B.l
140
141 #else /* NO_DECIMAL */
142
143 #define M_ADC(Rg) \
144 if(R->P&D_FLAG) \
145 { \
146 K.B.l=(R->A&0x0F)+(Rg&0x0F)+(R->P&C_FLAG); \
147 if(K.B.l>9) K.B.l+=6; \
148 K.B.h=(R->A>>4)+(Rg>>4)+(K.B.l>15? 1:0); \
149 R->A=(K.B.l&0x0F)|(K.B.h<<4); \
150 R->P=(R->P&~C_FLAG)|(K.B.h>15? C_FLAG:0); \
151 } \
152 else \
153 { \
154 K.W=R->A+Rg+(R->P&C_FLAG); \
155 R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
156 R->P|=(~(R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
157 (K.B.h? C_FLAG:0)|ZNTable[K.B.l]; \
158 R->A=K.B.l; \
159 }
160
161 /* Warning! C_FLAG is inverted before SBC and after it */
162 #define M_SBC(Rg) \
163 if(R->P&D_FLAG) \
164 { \
165 K.B.l=(R->A&0x0F)-(Rg&0x0F)-(~R->P&C_FLAG); \
166 if(K.B.l&0x10) K.B.l-=6; \
167 K.B.h=(R->A>>4)-(Rg>>4)-((K.B.l&0x10)>>4); \
168 if(K.B.h&0x10) K.B.h-=6; \
169 R->A=(K.B.l&0x0F)|(K.B.h<<4); \
170 R->P=(R->P&~C_FLAG)|(K.B.h>15? 0:C_FLAG); \
171 } \
172 else \
173 { \
174 K.W=R->A-Rg-(~R->P&C_FLAG); \
175 R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
176 R->P|=((R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
177 (K.B.h? 0:C_FLAG)|ZNTable[K.B.l]; \
178 R->A=K.B.l; \
179 }
180
181 #endif /* NO_DECIMAL */
182
183 #define M_CMP(Rg1,Rg2) \
184 K.W=Rg1-Rg2; \
185 R->P&=~(N_FLAG|Z_FLAG|C_FLAG); \
186 R->P|=ZNTable[K.B.l]|(K.B.h? 0:C_FLAG)
187 #define M_BIT(Rg) \
188 R->P&=~(N_FLAG|V_FLAG|Z_FLAG); \
189 R->P|=(Rg&(N_FLAG|V_FLAG))|(Rg&R->A? 0:Z_FLAG)
190
191 #define M_AND(Rg) R->A&=Rg;M_FL(R->A)
192 #define M_ORA(Rg) R->A|=Rg;M_FL(R->A)
193 #define M_EOR(Rg) R->A^=Rg;M_FL(R->A)
194 #define M_INC(Rg) Rg++;M_FL(Rg)
195 #define M_DEC(Rg) Rg--;M_FL(Rg)
196
197 #define M_ASL(Rg) R->P&=~C_FLAG;R->P|=Rg>>7;Rg<<=1;M_FL(Rg)
198 #define M_LSR(Rg) R->P&=~C_FLAG;R->P|=Rg&C_FLAG;Rg>>=1;M_FL(Rg)
199 #define M_ROL(Rg) K.B.l=(Rg<<1)|(R->P&C_FLAG); \
200 R->P&=~C_FLAG;R->P|=Rg>>7;Rg=K.B.l; \
201 M_FL(Rg)
202 #define M_ROR(Rg) K.B.l=(Rg>>1)|(R->P<<7); \
203 R->P&=~C_FLAG;R->P|=Rg&C_FLAG;Rg=K.B.l; \
204 M_FL(Rg)
205
206 /** Reset6502() **********************************************/
207 /** This function can be used to reset the registers before **/
208 /** starting execution with Run6502(). It sets registers to **/
209 /** their initial values. **/
210 /*************************************************************/
211 void Reset6502(M6502 *R)
212 {
213 R->A=R->X=R->Y=0x00;
214 R->P=Z_FLAG|R_FLAG;
215 R->S=0xFF;
216 R->PC.B.l=Rd6502(0xFFFC);
217 R->PC.B.h=Rd6502(0xFFFD);
218 R->ICount=R->IPeriod;
219 R->IRequest=INT_NONE;
220 R->AfterCLI=0;
221 #if DEBUG
222 Debug6502(R);
223 #endif
224 }
225
226 /** Exec6502() ***********************************************/
227 /** This function will execute a single 6502 opcode. It **/
228 /** will then return next PC, and current register values **/
229 /** in R. **/
230 /*************************************************************/
231 #ifdef EXEC6502
232 int Exec6502(M6502 *R,int RunCycles)
233 {
234 register pair J,K;
235 register byte I;
236
237 /* Execute requested number of cycles */
238 while(RunCycles>0)
239 {
240 #ifdef DEBUG
241 /* Turn tracing on when reached trap address */
242 if(R->PC.W==R->Trap) R->Trace=1;
243 /* Call single-step debugger, exit if requested */
244 if(R->Trace)
245 if(!Debug6502(R)) return(RunCycles);
246 #endif
247
248 I=Op6502(R->PC.W++);
249 RunCycles-=Cycles[I];
250 switch(I)
251 {
252 #include "Codes.h"
253 }
254 }
255
256 /* Return number of cycles left (<=0) */
257 return(RunCycles);
258 }
259 #endif /* EXEC6502 */
260
261 /** Int6502() ************************************************/
262 /** This function will generate interrupt of a given type. **/
263 /** INT_NMI will cause a non-maskable interrupt. INT_IRQ **/
264 /** will cause a normal interrupt, unless I_FLAG set in R. **/
265 /*************************************************************/
266 void Int6502(M6502 *R,byte Type)
267 {
268 register pair J;
269
270 if((Type==INT_NMI)||((Type==INT_IRQ)&&!(R->P&I_FLAG)))
271 {
272 R->ICount-=7;
273 M_PUSH(R->PC.B.h);
274 M_PUSH(R->PC.B.l);
275 M_PUSH(R->P&~B_FLAG);
276 R->P&=~D_FLAG;
277 if(R->IAutoReset&&(Type==R->IRequest)) R->IRequest=INT_NONE;
278 if(Type==INT_NMI) J.W=0xFFFA; else { R->P|=I_FLAG;J.W=0xFFFE; }
279 R->PC.B.l=Rd6502(J.W++);
280 R->PC.B.h=Rd6502(J.W);
281 }
282 }
283
284 /** Run6502() ************************************************/
285 /** This function will run 6502 code until Loop6502() call **/
286 /** returns INT_QUIT. It will return the PC at which **/
287 /** emulation stopped, and current register values in R. **/
288 /*************************************************************/
289 #ifndef EXEC6502
290 word Run6502(M6502 *R)
291 {
292 register pair J,K;
293 register byte I;
294
295 for(;;)
296 {
297 #ifdef DEBUG
298 /* Turn tracing on when reached trap address */
299 if(R->PC.W==R->Trap) R->Trace=1;
300 /* Call single-step debugger, exit if requested */
301 if(R->Trace)
302 if(!Debug6502(R)) return(R->PC.W);
303 #endif
304
305 I=Op6502(R->PC.W++);
306 R->ICount-=Cycles[I];
307 switch(I)
308 {
309 #include "Codes.h"
310 }
311
312 /* If cycle counter expired... */
313 if(R->ICount<=0)
314 {
315 /* If we have come after CLI, get INT_? from IRequest */
316 /* Otherwise, get it from the loop handler */
317 if(R->AfterCLI)
318 {
319 I=R->IRequest; /* Get pending interrupt */
320 R->ICount+=R->IBackup-1; /* Restore the ICount */
321 R->AfterCLI=0; /* Done with AfterCLI state */
322 }
323 else
324 {
325 I=Loop6502(R); /* Call the periodic handler */
326 R->ICount+=R->IPeriod; /* Reset the cycle counter */
327 if(!I) I=R->IRequest; /* Realize pending interrupt */
328 }
329
330 if(I==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */
331 if(I) Int6502(R,I); /* Interrupt if needed */
332 }
333 }
334
335 /* Execution stopped */
336 return(R->PC.W);
337 }
338 #endif /* !EXEC6502 */

  ViewVC Help
Powered by ViewVC 1.1.26