/[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 195 - (show annotations)
Sun Apr 13 00:32:39 2008 UTC (16 years, 1 month ago) by dpavlin
File size: 7037 byte(s)
a try at implementing selectable callbacks to perl for read/write operations
as opposed to whole memory
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 opCache[Addr] = Value;
133 if ( perlCallBack[Addr] & CALLBACK_WRITE_MASK == CALLBACK_WRITE_SKIP ) return;
134 if ( perlCallBack[Addr] & CALLBACK_WRITE_MASK == CALLBACK_WRITE_ONCE )
135 perlCallBack[Addr] = perlCallBack[Addr] & CALLBACK_READ_MASK | CALLBACK_WRITE_SKIP;
136 dSP;
137 ENTER;
138 SAVETMPS;
139 PUSHMARK(SP);
140 XPUSHs( sv_2mortal( newSViv( Addr ) ) );
141 XPUSHs( sv_2mortal( newSViv( Value ) ) );
142 PUTBACK;
143 call_pv("M6502::_write", G_DISCARD );
144 FREETMPS;
145 LEAVE;
146 }
147
148 byte Op6502(register word Addr) {
149 byte Op;
150 Op = mem(Addr);
151 debugf(("Op6502(%04x,%02x) PC:%04x", Addr, Op, R->PC.W));
152 return Op;
153 }
154
155 /** Loop6502() ***********************************************/
156 /** 6502 emulation calls this function periodically to **/
157 /** check if the system hardware requires any interrupts. **/
158 /** This function must return one of following values: **/
159 /** INT_NONE, INT_IRQ, INT_NMI, or INT_QUIT to exit the **/
160 /** emulation loop. **/
161 /************************************ TO BE WRITTEN BY USER **/
162
163 int hw_int = INT_NONE;
164
165 byte Loop6502(register M6502 *R) {
166 debugf(("Loop6502"));
167 dump_R;
168 return hw_int;
169 }
170
171 /** Patch6502() **********************************************/
172 /** Emulation calls this function when it encounters an **/
173 /** unknown opcode. This can be used to patch the code to **/
174 /** emulate BIOS calls, such as disk and tape access. The **/
175 /** function should return 1 if the exception was handled, **/
176 /** or 0 if the opcode was truly illegal. **/
177 /************************************ TO BE WRITTEN BY USER **/
178 byte Patch6502(register byte Op,register M6502 *R) {
179 debugf(("Patch6502(%02x)", Op));
180 dump_R;
181 hw_int = INT_QUIT;
182 return 0;
183 }
184
185 /*************************************************************/
186
187 int
188 reset (void) {
189 debugf(("M6502::reset called"));
190 if ( ! R ) {
191 debugf(("allocating space for R"));
192 R = malloc(sizeof(M6502));
193 if (!R) {
194 PerlIO_stdoutf("can't alloc %d bytes for M6502", sizeof(M6502));
195 exit(1);
196 }
197 memset( opCache, 0, CACHE_SIZE );
198 memset( perlCallBack, CALLBACK_READ_ALWAYS | CALLBACK_WRITE_ALWAYS, CACHE_SIZE );
199 }
200 Reset6502(R);
201 debugf(("Reset6502 over"));
202 update_perl_R();
203 dump_R;
204 return 1;
205 }
206
207 int exec(int cycles) {
208 int left;
209 debugf(("exec for %d cycles", cycles));
210
211 if (!R) reset();
212
213 update_C_R();
214 left = Exec6502(R, cycles);
215 update_perl_R();
216 debugf(("end of %d cycles CPU run\n", cycles));
217 return left;
218 }
219
220 int set_debug(int state) {
221 debug = state;
222 return debug;
223 }
224
225 int get_debug(void) {
226 return debug;
227 }
228
229 /* FIXME somehow check if Addr will fit in int on current platform */
230 void set_read_callback(int Addr) {
231 perlCallBack[Addr] == perlCallBack[Addr] & CALLBACK_WRITE_MASK | CALLBACK_READ_ALWAYS;
232 }
233
234 void set_write_callback(int Addr) {
235 perlCallBack[Addr] == perlCallBack[Addr] & CALLBACK_READ_MASK | CALLBACK_WRITE_ALWAYS;
236 }
237
238 /* we fake here, since we will need to call perl at least once to get initial value... */
239 int disable_all_callbacks(void) {
240 memset( perlCallBack, CALLBACK_READ_ONCE | CALLBACK_WRITE_ONCE, CACHE_SIZE );
241 return perlCallBack[0];
242 }
243
244
245 MODULE = M6502 PACKAGE = M6502
246
247 PROTOTYPES: DISABLE
248
249 int
250 set_debug(int state)
251
252 int
253 get_debug()
254
255 int
256 reset()
257
258 void
259 update_C_R()
260
261 void
262 update_perl_R()
263
264 int
265 exec(int cycles)
266
267 void
268 set_read_callback(int Addr)
269
270 void
271 set_write_callback(int Addr)
272
273 int
274 disable_all_callbacks()
275

  ViewVC Help
Powered by ViewVC 1.1.26