/[VRac]/M6502/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

Annotation of /M6502/M6502.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Mon Jul 30 10:49:26 2007 UTC (16 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 11436 byte(s)
import upstream M6502-010807.zip from http://fms.komkon.org/EMUL8/
1 dpavlin 23 /** 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     }
222    
223     /** Exec6502() ***********************************************/
224     /** This function will execute a single 6502 opcode. It **/
225     /** will then return next PC, and current register values **/
226     /** in R. **/
227     /*************************************************************/
228     #ifdef EXEC6502
229     int Exec6502(M6502 *R,int RunCycles)
230     {
231     register pair J,K;
232     register byte I;
233    
234     /* Execute requested number of cycles */
235     while(RunCycles>0)
236     {
237     #ifdef DEBUG
238     /* Turn tracing on when reached trap address */
239     if(R->PC.W==R->Trap) R->Trace=1;
240     /* Call single-step debugger, exit if requested */
241     if(R->Trace)
242     if(!Debug6502(R)) return(RunCycles);
243     #endif
244    
245     I=Op6502(R->PC.W++);
246     RunCycles-=Cycles[I];
247     switch(I)
248     {
249     #include "Codes.h"
250     }
251     }
252    
253     /* Return number of cycles left (<=0) */
254     return(RunCycles);
255     }
256     #endif /* EXEC6502 */
257    
258     /** Int6502() ************************************************/
259     /** This function will generate interrupt of a given type. **/
260     /** INT_NMI will cause a non-maskable interrupt. INT_IRQ **/
261     /** will cause a normal interrupt, unless I_FLAG set in R. **/
262     /*************************************************************/
263     void Int6502(M6502 *R,byte Type)
264     {
265     register pair J;
266    
267     if((Type==INT_NMI)||((Type==INT_IRQ)&&!(R->P&I_FLAG)))
268     {
269     R->ICount-=7;
270     M_PUSH(R->PC.B.h);
271     M_PUSH(R->PC.B.l);
272     M_PUSH(R->P&~B_FLAG);
273     R->P&=~D_FLAG;
274     if(R->IAutoReset&&(Type==R->IRequest)) R->IRequest=INT_NONE;
275     if(Type==INT_NMI) J.W=0xFFFA; else { R->P|=I_FLAG;J.W=0xFFFE; }
276     R->PC.B.l=Rd6502(J.W++);
277     R->PC.B.h=Rd6502(J.W);
278     }
279     }
280    
281     /** Run6502() ************************************************/
282     /** This function will run 6502 code until Loop6502() call **/
283     /** returns INT_QUIT. It will return the PC at which **/
284     /** emulation stopped, and current register values in R. **/
285     /*************************************************************/
286     #ifndef EXEC6502
287     word Run6502(M6502 *R)
288     {
289     register pair J,K;
290     register byte I;
291    
292     for(;;)
293     {
294     #ifdef DEBUG
295     /* Turn tracing on when reached trap address */
296     if(R->PC.W==R->Trap) R->Trace=1;
297     /* Call single-step debugger, exit if requested */
298     if(R->Trace)
299     if(!Debug6502(R)) return(R->PC.W);
300     #endif
301    
302     I=Op6502(R->PC.W++);
303     R->ICount-=Cycles[I];
304     switch(I)
305     {
306     #include "Codes.h"
307     }
308    
309     /* If cycle counter expired... */
310     if(R->ICount<=0)
311     {
312     /* If we have come after CLI, get INT_? from IRequest */
313     /* Otherwise, get it from the loop handler */
314     if(R->AfterCLI)
315     {
316     I=R->IRequest; /* Get pending interrupt */
317     R->ICount+=R->IBackup-1; /* Restore the ICount */
318     R->AfterCLI=0; /* Done with AfterCLI state */
319     }
320     else
321     {
322     I=Loop6502(R); /* Call the periodic handler */
323     R->ICount+=R->IPeriod; /* Reset the cycle counter */
324     if(!I) I=R->IRequest; /* Realize pending interrupt */
325     }
326    
327     if(I==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */
328     if(I) Int6502(R,I); /* Interrupt if needed */
329     }
330     }
331    
332     /* Execution stopped */
333     return(R->PC.W);
334     }
335     #endif /* !EXEC6502 */

  ViewVC Help
Powered by ViewVC 1.1.26