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

Diff of /M6502/M6502.xs

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 82 by dpavlin, Wed Aug 1 21:40:17 2007 UTC revision 202 by dpavlin, Sun Apr 13 20:03:57 2008 UTC
# Line 7  Line 7 
7  #include "M6502.h"  #include "M6502.h"
8  #include "config.h"  #include "config.h"
9    
10  M6502 *R;  M6502 *R = NULL;
11    int debug = 0;
12    
13  void  // same as memory size
14  run (void) {  #define CACHE_SIZE 0x10000
15          debugf(("M6502::run"));  byte opCache[CACHE_SIZE];
16          run_forever();  
17    #define CALLBACK_READ_SKIP      0x00
18    #define CALLBACK_READ_ONCE      0x01
19    #define CALLBACK_READ_ALWAYS    0x02
20    #define CALLBACK_READ_MASK      0x0f
21    #define CALLBACK_WRITE_SKIP     0x00
22    #define CALLBACK_WRITE_ONCE     0x10
23    #define CALLBACK_WRITE_ALWAYS   0x20
24    #define CALLBACK_WRITE_MASK     0xf0
25    byte perlCallBack[CACHE_SIZE];
26    
27    void update_C_R(void) {
28            R->A = SvIV( get_sv("M6502::A", FALSE) );
29            R->P = SvIV( get_sv("M6502::P", FALSE) );
30            R->X = SvIV( get_sv("M6502::X", FALSE) );
31            R->Y = SvIV( get_sv("M6502::Y", FALSE) );
32            R->S = SvIV( get_sv("M6502::S", FALSE) );
33            R->PC.W = SvIV( get_sv("M6502::PC", FALSE) );
34            R->IPeriod = SvIV( get_sv("M6502::IPeriod", FALSE) );
35            R->IRequest = SvIV( get_sv("M6502::IRequest", FALSE) );
36            R->IAutoReset = SvIV( get_sv("M6502::IAutoReset", FALSE) );
37            R->TrapBadOps = SvIV( get_sv("M6502::TrapBadOps", FALSE) );
38            R->Trap = SvIV( get_sv("M6502::Trap", FALSE) );
39            R->Trace = SvIV( get_sv("M6502::Trace", FALSE) );
40            debugf(("pull_R finished"));
41            dump_R;
42  }  }
43    
44  void  void update_perl_R(void) {
45            debugf(("update_perl_R"));
46            dSP;
47            ENTER;
48            SAVETMPS;
49            PUSHMARK(SP);
50            XPUSHs( sv_2mortal( newSViv( R->A ) ) );
51            XPUSHs( sv_2mortal( newSViv( R->P ) ) );
52            XPUSHs( sv_2mortal( newSViv( R->X ) ) );
53            XPUSHs( sv_2mortal( newSViv( R->Y ) ) );
54            XPUSHs( sv_2mortal( newSViv( R->S ) ) );
55            XPUSHs( sv_2mortal( newSViv( R->PC.W ) ) );
56            XPUSHs( sv_2mortal( newSViv( R->IPeriod ) ) );
57            XPUSHs( sv_2mortal( newSViv( R->ICount ) ) );
58            XPUSHs( sv_2mortal( newSViv( R->IRequest ) ) );
59            XPUSHs( sv_2mortal( newSViv( R->IAutoReset ) ) );
60            XPUSHs( sv_2mortal( newSViv( R->TrapBadOps ) ) );
61            XPUSHs( sv_2mortal( newSViv( R->Trap ) ) );
62            XPUSHs( sv_2mortal( newSViv( R->Trace ) ) );
63            PUTBACK;
64            call_pv("M6502::_update_perl_R", G_DISCARD );
65            debugf(("_update_perl_R returned to C"));
66            dump_R;
67            FREETMPS;
68            LEAVE;
69    }
70    
71    /** Debug6502() **********************************************/
72    
73    byte Debug6502(M6502 *R) {
74            dump_R;
75            return 1; // continue emulation
76    }
77    
78    /** Rd6502()/Wr6502/Op6502() *********************************/
79    /** These functions are called when access to RAM occurs.   **/
80    /** They allow to control memory access. Op6502 is the same **/
81    /** as Rd6502, but used to read *opcodes* only, when many   **/
82    /** checks can be skipped to make it fast. It is only       **/
83    /** required if there is a #define FAST_RDOP.               **/
84    /************************************ TO BE WRITTEN BY USER **/
85    
86    byte mem(register word Addr) {
87            debugf(("mem(%04x) callback %02x", Addr, perlCallBack[Addr]));
88    
89            debugf(("### SKIP? %02x == %02x", perlCallBack[Addr] & CALLBACK_READ_MASK, CALLBACK_READ_SKIP));
90            if ( ( perlCallBack[Addr] & CALLBACK_READ_MASK ) == CALLBACK_READ_SKIP ) {
91                    debugf(("MEM: read callback skipped"));
92                    return opCache[Addr];
93            }
94            if ( ( perlCallBack[Addr] & CALLBACK_READ_MASK ) == CALLBACK_READ_ONCE ) {
95                    debugf(("MEM: read callback disabled"));
96                    perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_WRITE_MASK | CALLBACK_READ_SKIP;
97            }
98    
99            byte byte;
100            int count;
101            dSP;
102            ENTER;
103            SAVETMPS;
104            PUSHMARK(SP);
105            XPUSHs( sv_2mortal( newSViv( Addr ) ) );
106            PUTBACK;
107            count = call_pv("M6502::_read", G_ARRAY | G_EVAL );
108            debugf(("got %d values", count));
109            SPAGAIN;
110            if (SvTRUE(ERRSV)) {
111                    printf("ERROR: %s", SvPV_nolen( ERRSV ) );
112                    exit(1);
113            }
114            if ( count != 1 ) {
115                    printf("expect 1 return value, got %d", count);
116                    exit(1);
117            }
118            SV *sv;
119            sv = POPs;
120            byte = SvIV(sv);
121            FREETMPS;
122            LEAVE;
123            debugf(("mem(%04x) = %02x", Addr, byte));
124            opCache[Addr] = byte;
125            return byte;
126    }
127    
128    byte Rd6502(register word Addr) {
129            byte Value;
130            Value = mem(Addr);
131            debugf(("Rd6502(%04x) = %02x", Addr, Value));
132            return Value;
133    }
134    
135    void Wr6502(register word Addr,register byte Value) {
136            debugf(("Wr6502(%04x,%02x)", Addr, Value));
137            opCache[Addr] = Value;
138            if ( ( perlCallBack[Addr] & CALLBACK_WRITE_MASK ) == CALLBACK_WRITE_SKIP ) {
139                    debugf(("MEM: write callback skipped"));
140                    return;
141            }
142            if ( ( perlCallBack[Addr] & CALLBACK_WRITE_MASK ) == CALLBACK_WRITE_ONCE ) {
143                    perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_READ_MASK | CALLBACK_WRITE_SKIP;
144                    debugf(("MEM: write callback skipped"));
145            }
146            dSP;
147            ENTER;
148            SAVETMPS;
149            PUSHMARK(SP);
150            XPUSHs( sv_2mortal( newSViv( Addr ) ) );
151            XPUSHs( sv_2mortal( newSViv( Value ) ) );
152            PUTBACK;
153            call_pv("M6502::_write", G_DISCARD );
154            FREETMPS;
155            LEAVE;
156    }
157    
158    byte Op6502(register word Addr) {
159            byte Op;
160            Op = mem(Addr);
161            debugf(("Op6502(%04x,%02x) PC:%04x", Addr, Op, R->PC.W));
162            return Op;
163    }
164    
165    /** Loop6502() ***********************************************/
166    /** 6502 emulation calls this function periodically to      **/
167    /** check if the system hardware requires any interrupts.   **/
168    /** This function must return one of following values:      **/
169    /** INT_NONE, INT_IRQ, INT_NMI, or INT_QUIT to exit the     **/
170    /** emulation loop.                                         **/
171    /************************************ TO BE WRITTEN BY USER **/
172    
173    int hw_int = INT_NONE;
174    
175    byte Loop6502(register M6502 *R) {
176            debugf(("Loop6502"));
177            dump_R;
178            return hw_int;
179    }
180    
181    /** Patch6502() **********************************************/
182    /** Emulation calls this function when it encounters an     **/
183    /** unknown opcode. This can be used to patch the code to   **/
184    /** emulate BIOS calls, such as disk and tape access. The   **/
185    /** function should return 1 if the exception was handled,  **/
186    /** or 0 if the opcode was truly illegal.                   **/
187    /************************************ TO BE WRITTEN BY USER **/
188    byte Patch6502(register byte Op,register M6502 *R) {
189            debugf(("Patch6502(%02x)", Op));
190            dump_R;
191            hw_int = INT_QUIT;
192            return 0;
193    }
194    
195    /*************************************************************/
196    
197    int
198  reset (void) {  reset (void) {
199          debugf(("M6502::reset called"));          debugf(("M6502::reset called"));
200            if ( ! R ) {
201                    debugf(("allocating space for R"));
202                    R = malloc(sizeof(M6502));
203                    if (!R) {
204                            PerlIO_stdoutf("can't alloc %d bytes for M6502", sizeof(M6502));
205                            exit(1);
206                    }
207                    memset( opCache, 0, CACHE_SIZE );
208            }
209            memset( perlCallBack, ( CALLBACK_READ_ALWAYS | CALLBACK_WRITE_ALWAYS ), CACHE_SIZE );
210          Reset6502(R);          Reset6502(R);
211            debugf(("Reset6502 over"));
212            update_perl_R();
213          dump_R;          dump_R;
214            return 1;
215    }
216    
217    int exec(int cycles) {
218            int left;
219            debugf(("exec for %d cycles", cycles));
220    
221            if (!R) reset();
222    
223            update_C_R();
224            left = Exec6502(R, cycles);
225            update_perl_R();
226            debugf(("end of %d cycles CPU run\n", cycles));
227            return left;
228    }
229    
230    int set_debug(int state) {
231            debug = state;
232            return debug;
233    }
234    
235    int get_debug(void) {
236            return debug;
237    }
238    
239    /* FIXME somehow check if Addr will fit in int on current platform */
240    void set_read_callback(int Addr) {
241            perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_WRITE_MASK | CALLBACK_READ_ALWAYS;
242            debugf(("MEM: %04x read callback to %02x\n", Addr, perlCallBack[Addr]));
243    }
244    
245    void set_write_callback(int Addr) {
246            perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_READ_MASK | CALLBACK_WRITE_ALWAYS;
247            debugf(("MEM: %04x write callback to %02x\n", Addr, perlCallBack[Addr]));
248    }
249    
250    /* we fake here, since we will need to call perl at least once to get initial value... */
251    int set_all_callbacks(int mode) {
252            memset( perlCallBack, mode, CACHE_SIZE );
253            debugf(("MEM: all callbacks set to %02x\n", perlCallBack[0]));
254            return perlCallBack[0];
255  }  }
256    
257    int get_callback(int Addr) {
258            return perlCallBack[Addr];
259    }
260    
261    
262  MODULE = M6502          PACKAGE = M6502  MODULE = M6502          PACKAGE = M6502
263    
264  PROTOTYPES: DISABLE  PROTOTYPES: DISABLE
265    
266    int
267    set_debug(int state)
268    
269    int
270    get_debug()
271    
272    int
273    reset()
274    
275  void  void
276  run()  update_C_R()
277    
278  void  void
279  reset()  update_perl_R()
280    
281    int
282    exec(int cycles)
283    
284    void
285    set_read_callback(int Addr)
286    
287    void
288    set_write_callback(int Addr)
289    
290    int
291    set_all_callbacks(int mode)
292    
293    int get_callback(int Addr)

Legend:
Removed from v.82  
changed lines
  Added in v.202

  ViewVC Help
Powered by ViewVC 1.1.26