/[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 208 - (show annotations)
Mon Apr 14 19:40:02 2008 UTC (16 years ago) by dpavlin
File size: 7922 byte(s)
added mem_peek_region to get chunk of memory as single scalar
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 0x10000
15 byte memory[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 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 memory[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 memory[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 memory[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) {
199 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( memory, 0xff, CACHE_SIZE );
208 }
209 memset( perlCallBack, ( CALLBACK_READ_ALWAYS | CALLBACK_WRITE_ALWAYS ), CACHE_SIZE );
210 Reset6502(R);
211 debugf(("Reset6502 over"));
212 update_perl_R();
213 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 void mem_poke(int Addr, int byte) {
262 memory[Addr] = byte;
263 }
264
265 int mem_peek(int Addr) {
266 return memory[Addr];
267 }
268
269
270 MODULE = M6502 PACKAGE = M6502
271
272 PROTOTYPES: DISABLE
273
274 int set_debug(int state)
275
276 int get_debug()
277
278 int reset()
279
280 void update_C_R()
281
282 void update_perl_R()
283
284 int exec(int cycles)
285
286 void set_read_callback(int Addr)
287
288 void set_write_callback(int Addr)
289
290 int set_all_callbacks(int mode)
291
292 int get_callback(int Addr)
293
294 void mem_poke(int Addr, int byte)
295
296 int mem_peek(int Addr)
297
298 SV*
299 mem_peek_region(int from, int to)
300 CODE:
301 RETVAL = newSVpvn(memory+from,to-from+1);
302 OUTPUT:
303 RETVAL
304

  ViewVC Help
Powered by ViewVC 1.1.26