/[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

Contents of /M6502/M6502.xs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 198 - (show annotations)
Sun Apr 13 11:05:29 2008 UTC (16 years, 1 month ago) by dpavlin
File size: 7411 byte(s)
callback debugging
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include "ppport.h"
6
7 #include "M6502.h"
8 #include "config.h"
9
10 M6502 *R = NULL;
11 int debug = 0;
12
13 // same as memory size
14 #define CACHE_SIZE 0xffff
15 byte opCache[CACHE_SIZE];
16
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 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
88 if ( perlCallBack[Addr] & CALLBACK_READ_MASK == CALLBACK_READ_SKIP )
89 return opCache[Addr];
90 if ( perlCallBack[Addr] & CALLBACK_READ_MASK == CALLBACK_READ_ONCE )
91 perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_WRITE_MASK | CALLBACK_READ_SKIP;
92
93 byte byte;
94 int count;
95 debugf(("mem(%04x)", Addr));
96 dSP;
97 ENTER;
98 SAVETMPS;
99 PUSHMARK(SP);
100 XPUSHs( sv_2mortal( newSViv( Addr ) ) );
101 PUTBACK;
102 count = call_pv("M6502::_read", G_ARRAY | G_EVAL );
103 debugf(("got %d values", count));
104 SPAGAIN;
105 if (SvTRUE(ERRSV)) {
106 printf("ERROR: %s", SvPV_nolen( ERRSV ) );
107 exit(1);
108 }
109 if ( count != 1 ) {
110 printf("expect 1 return value, got %d", count);
111 exit(1);
112 }
113 SV *sv;
114 sv = POPs;
115 byte = SvIV(sv);
116 FREETMPS;
117 LEAVE;
118 debugf(("mem(%04x) = %02x", Addr, byte));
119 opCache[Addr] = byte;
120 return byte;
121 }
122
123 byte Rd6502(register word Addr) {
124 byte Value;
125 Value = mem(Addr);
126 debugf(("Rd6502(%04x) = %02x", Addr, Value));
127 return Value;
128 }
129
130 void Wr6502(register word Addr,register byte Value) {
131 debugf(("Wr6502(%04x,%02x)", Addr, Value));
132 if ( perlCallBack[Addr] & CALLBACK_WRITE_MASK == CALLBACK_WRITE_SKIP && opCache[Addr] == Value ) {
133 debugf(("skipped perl callback, same value"));
134 return;
135 }
136 opCache[Addr] = Value;
137 if ( perlCallBack[Addr] & CALLBACK_WRITE_MASK == CALLBACK_WRITE_SKIP ) return;
138 if ( perlCallBack[Addr] & CALLBACK_WRITE_MASK == CALLBACK_WRITE_ONCE )
139 perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_READ_MASK | CALLBACK_WRITE_SKIP;
140 dSP;
141 ENTER;
142 SAVETMPS;
143 PUSHMARK(SP);
144 XPUSHs( sv_2mortal( newSViv( Addr ) ) );
145 XPUSHs( sv_2mortal( newSViv( Value ) ) );
146 PUTBACK;
147 call_pv("M6502::_write", G_DISCARD );
148 FREETMPS;
149 LEAVE;
150 }
151
152 byte Op6502(register word Addr) {
153 byte Op;
154 Op = mem(Addr);
155 debugf(("Op6502(%04x,%02x) PC:%04x", Addr, Op, R->PC.W));
156 return Op;
157 }
158
159 /** Loop6502() ***********************************************/
160 /** 6502 emulation calls this function periodically to **/
161 /** check if the system hardware requires any interrupts. **/
162 /** This function must return one of following values: **/
163 /** INT_NONE, INT_IRQ, INT_NMI, or INT_QUIT to exit the **/
164 /** emulation loop. **/
165 /************************************ TO BE WRITTEN BY USER **/
166
167 int hw_int = INT_NONE;
168
169 byte Loop6502(register M6502 *R) {
170 debugf(("Loop6502"));
171 dump_R;
172 return hw_int;
173 }
174
175 /** Patch6502() **********************************************/
176 /** Emulation calls this function when it encounters an **/
177 /** unknown opcode. This can be used to patch the code to **/
178 /** emulate BIOS calls, such as disk and tape access. The **/
179 /** function should return 1 if the exception was handled, **/
180 /** or 0 if the opcode was truly illegal. **/
181 /************************************ TO BE WRITTEN BY USER **/
182 byte Patch6502(register byte Op,register M6502 *R) {
183 debugf(("Patch6502(%02x)", Op));
184 dump_R;
185 hw_int = INT_QUIT;
186 return 0;
187 }
188
189 /*************************************************************/
190
191 int
192 reset (void) {
193 debugf(("M6502::reset called"));
194 if ( ! R ) {
195 debugf(("allocating space for R"));
196 R = malloc(sizeof(M6502));
197 if (!R) {
198 PerlIO_stdoutf("can't alloc %d bytes for M6502", sizeof(M6502));
199 exit(1);
200 }
201 memset( opCache, 0, CACHE_SIZE );
202 memset( perlCallBack, CALLBACK_READ_ALWAYS | CALLBACK_WRITE_ALWAYS, CACHE_SIZE );
203 }
204 Reset6502(R);
205 debugf(("Reset6502 over"));
206 update_perl_R();
207 dump_R;
208 return 1;
209 }
210
211 int exec(int cycles) {
212 int left;
213 debugf(("exec for %d cycles", cycles));
214
215 if (!R) reset();
216
217 update_C_R();
218 left = Exec6502(R, cycles);
219 update_perl_R();
220 debugf(("end of %d cycles CPU run\n", cycles));
221 return left;
222 }
223
224 int set_debug(int state) {
225 debug = state;
226 return debug;
227 }
228
229 int get_debug(void) {
230 return debug;
231 }
232
233 /* FIXME somehow check if Addr will fit in int on current platform */
234 void set_read_callback(int Addr) {
235 perlCallBack[Addr] == perlCallBack[Addr] & CALLBACK_WRITE_MASK | CALLBACK_READ_ALWAYS;
236 debugf(("MEM: %04x read callback\n", Addr));
237 }
238
239 void set_write_callback(int Addr) {
240 perlCallBack[Addr] == perlCallBack[Addr] & CALLBACK_READ_MASK | CALLBACK_WRITE_ALWAYS;
241 debugf(("MEM: %04x write callback\n", Addr));
242 }
243
244 /* we fake here, since we will need to call perl at least once to get initial value... */
245 int set_all_callbacks(int mode) {
246 memset( perlCallBack, mode, CACHE_SIZE );
247 debugf(("MEM: all callbacks set to %02x\n", perlCallBack[0]));
248 return perlCallBack[0];
249 }
250
251 int get_callback(int Addr) {
252 return perlCallBack[Addr];
253 }
254
255
256 MODULE = M6502 PACKAGE = M6502
257
258 PROTOTYPES: DISABLE
259
260 int
261 set_debug(int state)
262
263 int
264 get_debug()
265
266 int
267 reset()
268
269 void
270 update_C_R()
271
272 void
273 update_perl_R()
274
275 int
276 exec(int cycles)
277
278 void
279 set_read_callback(int Addr)
280
281 void
282 set_write_callback(int Addr)
283
284 int
285 set_all_callbacks(int mode)
286
287 int get_callback(int Addr)

  ViewVC Help
Powered by ViewVC 1.1.26