1
2 /*
3 * O2EM Free Odyssey2 / Videopac+ Emulator
4 *
5 * Created by Daniel Boris <dboris@comcast.net> (c) 1997,1998
6 *
7 * Developed by Andre de la Rocha <adlroc@users.sourceforge.net>
8 * Arlindo M. de Oliveira <dgtec@users.sourceforge.net>
9 *
10 * http://o2em.sourceforge.net
11 *
12 *
13 *
14 * Main O2 machine emulation
15 */
16
17
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <time.h>
22 #include "audio.h"
23 #include "cpu.h"
24 #include "keyboard.h"
25 #include "config.h"
26 #ifdef HAVE_DEBUG
27 #include "debug.h"
28 #endif
29 #include "vdc.h"
30 #include "vpp.h"
31 #include "voice.h"
32 #include "vmachine.h"
33
34 #include "wrapalleg.h"
35 #include "libretro.h"
36 extern unsigned char key[512];
37
38 static uint8_t x_latch,y_latch;
39 static int romlatch=0;
40 static uint8_t line_count;
41 static int fps=FPS_NTSC;
42
43 static uint8_t snapedlines[MAXLINES+2*MAXSNAP][256][2];
44
45 int evblclk=EVBLCLK_NTSC;
46
47 struct resource app_data;
48 int frame=0;
49 uint8_t dbstick1,dbstick2;
50
51 int int_clk; /* counter for length of /INT pulses */
52 int master_clk; /* Master clock */
53 int h_clk; /* horizontal clock */
54 unsigned long clk_counter;
55 int last_line;
56 int key2vcnt=0;
57 int mstate;
58
59 int pendirq=0;
60 int enahirq=1;
61 int useforen=0;
62 long regionoff=0xffff;
63 int mxsnap=2;
64 int sproff=0;
65 int tweakedaudio=0;
66
67 uint8_t rom_table[8][4096];
68
69 uint8_t intRAM[64];
70 uint8_t extRAM[256];
71 uint8_t extROM[1024];
72 uint8_t VDCwrite[256];
73 uint8_t ColorVector[MAXLINES];
74 uint8_t AudioVector[MAXLINES];
75 uint8_t *rom;
76 uint8_t *megarom;
77
78 int key2[128];
79
80
81 static unsigned int key_map[6][8]= {
82 {RETROK_0,RETROK_1,RETROK_2,RETROK_3,RETROK_4,RETROK_5,RETROK_6,RETROK_7},
83 {RETROK_8,RETROK_9,RETROK_LALT/*YES key*/,RETROK_RALT/*NO key*/,RETROK_SPACE,RETROK_QUESTION,RETROK_l,RETROK_p},
84 {RETROK_PLUS,RETROK_w,RETROK_e,RETROK_r,RETROK_t,RETROK_u,RETROK_i,RETROK_o},
85 {RETROK_q,RETROK_s,RETROK_d,RETROK_f,RETROK_g,RETROK_h,RETROK_j,RETROK_k},
86 {RETROK_a,RETROK_z,RETROK_x,RETROK_c,RETROK_v,RETROK_b,RETROK_m,RETROK_PERIOD},
87 {RETROK_MINUS,RETROK_ASTERISK,RETROK_SLASH,RETROK_EQUALS,RETROK_y,RETROK_n,RETROK_END,RETROK_RETURN}
88 };
89
90
91 static void do_kluges(void);
92 static void setvideomode(int t);
93
run(void)94 void run(void){
95 while(!key_done) {
96
97 if (key_debug) {
98 app_data.debug=1;
99 set_textmode();
100 mute_audio();
101 mute_voice();
102 #ifdef HAVE_DEBUG
103 debug();
104 #endif
105 grmode();
106 app_data.debug=0;
107 init_keyboard();
108 init_sound_stream();
109 }
110
111 cpu_exec();
112
113 }
114 close_audio();
115 close_voice();
116 close_display();
117 }
118
119
handle_vbl(void)120 void handle_vbl(void)
121 {
122 if (!app_data.debug)
123 {
124 update_joy();
125 update_audio();
126 update_voice();
127 }
128 draw_region();
129 ext_IRQ();
130 mstate = 1;
131 }
132
133 extern int RLOOP;
134
handle_evbl(void)135 void handle_evbl(void)
136 {
137 static int rest_cnt=0;
138 int i;
139
140 i = (15*app_data.speed/100);
141 rest_cnt = (rest_cnt+1)%(i<5?5:i);
142 last_line=0;
143 master_clk -= evblclk;
144 frame++;
145 if (!app_data.debug) {
146 finish_display();
147 }
148
149 if (app_data.crc == 0xA7344D1F)
150 {for (i=0; i<140; i++)
151 {
152 ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80);
153 AudioVector[i] = VDCwrite[0xAA];
154 }
155 }/*Atlantis*/
156 else
157 for (i=0; i<MAXLINES; i++) {
158 ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80);
159 AudioVector[i] = VDCwrite[0xAA];
160 }
161
162
163 if (key2vcnt++ > 10) {
164 key2vcnt=0;
165 for (i=0; i<128; i++) key2[i] = 0;
166 dbstick1 = dbstick2 = 0;
167 }
168 if (app_data.limit)
169 {
170 RLOOP=0;
171 }
172 mstate=0;
173
174 }
175
handle_evbll(void)176 void handle_evbll(void)
177 {
178 static int rest_cnt=0;
179 int i;
180
181 i = (15*app_data.speed/100);
182 rest_cnt = (rest_cnt+1)%(i<5?5:i);
183
184 /******************* 150 */
185
186 for (i=150; i<MAXLINES; i++)
187 {
188 ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80);
189 AudioVector[i] = VDCwrite[0xAA];
190 }
191
192 if (key2vcnt++ > 10)
193 {
194 key2vcnt=0;
195 for (i=0; i<128; i++) key2[i] = 0;
196 dbstick1 = dbstick2 = 0;
197 }
198
199 if (app_data.limit)
200 RLOOP=0;
201 mstate=0;
202 }
203
init_system(void)204 void init_system(void){
205 int i,j,k;
206
207 last_line=0;
208 dbstick1=0x00;
209 dbstick2=0x00;
210 mstate=0;
211 master_clk=0;
212 h_clk=0;
213 line_count=0;
214 itimer=0;
215 clk_counter=0;
216 init_roms();
217 for(i=0; i<256; i++) {
218 VDCwrite[i]=0;
219 extRAM[i]=0;
220 }
221 for(i=0; i<64; i++) {
222 intRAM[i]=0;
223 }
224 for (i=0; i<MAXLINES; i++) AudioVector[i] = ColorVector[i] = 0;
225
226 for (i=0; i<MAXLINES+2*MAXSNAP; i++)
227 for (j=0; j<256; j++)
228 for (k=0; k<2; k++)
229 snapedlines[i][j][k]=0;
230
231 if (app_data.stick[0] == 2 || app_data.stick[1] == 2) {
232 #ifndef __LIBRETRO__
233 i = install_joystick(JOY_TYPE_AUTODETECT);
234 if (i || (num_joysticks<1)) {
235 fprintf(stderr,"Error: no joystick detected\n");
236 exit(EXIT_FAILURE);
237 }
238 #endif
239
240 }
241
242 for (i=0; i<256*2; i++) key[i] = 0;
243
244 for (i=0; i<128; i++) key2[i] = 0;
245 key2vcnt=0;
246 if (app_data.euro)
247 setvideomode(1);
248 else
249 setvideomode(0);
250
251 do_kluges();
252 init_vpp();
253 clear_collision();
254 }
255
256
init_roms(void)257 void init_roms(void){
258 rom=rom_table[0];
259 romlatch=0;
260 }
261
262
read_t1(void)263 uint8_t read_t1(void){
264 /*17*/
265 if ((h_clk > 16) || (master_clk > VBLCLK))
266 return 1;
267 return 0;
268 }
269
270
write_p1(uint8_t d)271 void write_p1(uint8_t d){
272 if ((d & 0x80) != (p1 & 0x80)) {
273 int i,l;
274 l = snapline((int)((float)master_clk/22.0+0.1), VDCwrite[0xA3], 1);
275 for (i=l; i<MAXLINES; i++) ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (d & 0x80);
276 }
277 p1 = d;
278 if (app_data.bank == 2) {
279 rom=rom_table[~p1 & 0x01];
280 } else if (app_data.bank == 3) {
281 rom=rom_table[~p1 & 0x03];
282 } else if (app_data.bank == 4) {
283 rom=rom_table[(p1 & 1)?0:romlatch];
284 }
285 }
286
read_P2(void)287 uint8_t read_P2(void)
288 {
289 if (NeedsPoll)
290 poll_keyboard();
291
292 if (!(p1 & 0x04))
293 {
294 int si = (p2 & 7);
295 int so = 0xff;
296
297 if (si<6)
298 {
299 int i;
300
301 for (i=0; i<8; i++)
302 {
303 int km = key_map[si][i];
304 #ifndef __LIBRETRO__
305 if ((key[km] && ((!joykeystab[km]) || (key_shifts & KB_CAPSLOCK_FLAG))) || (key2[km]))
306 so = i ^ 0x07;
307 #else
308 //FIXME
309 if ( key[km] && (!joykeystab[km]))
310 so = i ^ 0x07;
311 #endif
312 }
313 }
314 if (so != 0xff)
315 {
316 p2 = p2 & 0x0F;
317 p2 = p2 | (so << 5);
318 }
319 else
320 p2 = p2 | 0xF0;
321 }
322 else
323 p2 = p2 | 0xF0;
324
325 return(p2);
326
327 }
328
329
ext_read(uint16_t adr)330 uint8_t ext_read(uint16_t adr){
331 uint8_t d;
332 uint8_t si;
333 uint8_t m;
334 int i;
335
336 if (!(p1 & 0x08) && !(p1 & 0x40)) {
337 /* Handle VDC Read */
338 switch(adr) {
339 case 0xA1:
340 d = VDCwrite[0xA0] & 0x02;
341 if (master_clk > VBLCLK) d = d | 0x08;
342 if (h_clk < (LINECNT-7)) d = d | 0x01;
343 if (sound_IRQ) d = d | 0x04;
344 sound_IRQ=0;
345 return d;
346 case 0xA2:
347 si = VDCwrite[0xA2];
348 m=0x01;
349 d=0;
350 for(i=0; i<8; i++) {
351 if (si & m) {
352 if (coltab[1] & m) d = d | (coltab[1] & (m ^ 0xFF));
353 if (coltab[2] & m) d = d | (coltab[2] & (m ^ 0xFF));
354 if (coltab[4] & m) d = d | (coltab[4] & (m ^ 0xFF));
355 if (coltab[8] & m) d = d | (coltab[8] & (m ^ 0xFF));
356 if (coltab[0x10] & m) d = d | (coltab[0x10] & (m ^ 0xFF));
357 if (coltab[0x20] & m) d = d | (coltab[0x20] & (m ^ 0xFF));
358 if (coltab[0x80] & m) d = d | (coltab[0x80] & (m ^ 0xFF));
359 }
360 m = m << 1;
361 }
362 clear_collision();
363 return d;
364 case 0xA5:
365 if (!(VDCwrite[0xA0] & 0x02)) {
366 return x_latch;
367 }
368 else {
369 x_latch = h_clk * 12;
370 return x_latch;
371 }
372 case 0xA4:
373 if (!(VDCwrite[0xA0] & 0x02)) {
374 return y_latch;
375 }
376 else {
377 y_latch = master_clk/22;
378 if (y_latch > 241) y_latch=0xFF;
379 return y_latch;
380 }
381 default:
382 return VDCwrite[adr];
383 }
384 } else if (!(p1 & 0x10)) {
385 /* Handle ext RAM Read */
386 if (app_data.megaxrom && (adr >= 0x80)) {
387 /* MegaCART registers are mirrored every 4 bytes */
388 if ((adr & 0x83) == 0x83) {
389 /* TODO: emulate EEPROM data in */
390 return 0xff;
391 } else return extRAM[adr & 0x83];
392 } else return extRAM[adr & 0xFF];
393 } else if (!(p1 & 0x20)) {
394 /* Read a Videopac+ register */
395 return vpp_read(adr);
396 } else if (app_data.exrom && (p1 & 0x02)) {
397 /* Handle read from exrom */
398 return extROM[(p2 << 8) | (adr & 0xFF)];
399 } else if (app_data.megaxrom && !(p1 & 0x02) && !(p1 & 0x40)) {
400 /* Handle data read from MegaCART */
401 return megarom[(extRAM[0x81] << 12) | ((p2 & 0x0f) << 8) | (adr & 0xff)];
402 }
403
404 return 0;
405 }
406
407
in_bus(void)408 uint8_t in_bus(void)
409 {
410 uint8_t si=0,d=0, jn=0,sticknum=0;
411
412 (void)sticknum;
413
414 if ((p1 & 0x08) && (p1 & 0x10))
415 {
416 uint8_t mode = 0;
417
418 /* Handle joystick read */
419 if (!(p1 & 0x04))
420 si = (p2 & 7);
421 d=0xFF;
422 if (si == 1)
423 {
424 mode = app_data.stick[0];
425 jn = 0;
426 sticknum = app_data.sticknumber[0]-1;
427 }
428 else
429 {
430 mode = app_data.stick[1];
431 jn = 1;
432 sticknum = app_data.sticknumber[1]-1;
433 }
434
435 switch(mode)
436 {
437 case 1:
438 d = keyjoy(jn);
439 break;
440 case 2:
441
442 #ifndef __LIBRETRO__
443 poll_joystick();
444 if (joy[sticknum].stick[0].axis[1].d1) d &= 0xFE; // joy_up
445 if (joy[sticknum].stick[0].axis[0].d2) d &= 0xFD; // joy_right
446 if (joy[sticknum].stick[0].axis[1].d2) d &= 0xFB; // joy_down
447 if (joy[sticknum].stick[0].axis[0].d1) d &= 0xF7; // joy_left
448 if (joy[sticknum].button[0].b || joy[jn].button[1].b) d &= 0xEF; // both main-buttons
449 #else
450 //FIXME
451 d = keyjoy(jn);
452 #endif
453
454 break;
455 }
456 if (si == 1)
457 {
458 if (dbstick1)
459 d = dbstick1;
460 }
461 else
462 {
463 if (dbstick2)
464 d = dbstick2;
465 }
466 }
467 return d;
468 }
469
470
ext_write(uint8_t dat,uint16_t adr)471 void ext_write(uint8_t dat, uint16_t adr){
472 int i;
473
474 if (!(p1 & 0x08)) {
475 /* Handle VDC Write */
476 if (adr == 0xA0){
477 if ((VDCwrite[0xA0] & 0x02) && !(dat & 0x02)) {
478 y_latch = master_clk/22;
479 x_latch = h_clk * 12;
480 if (y_latch > 241) y_latch=0xFF;
481 }
482 if ((master_clk <= VBLCLK) && (VDCwrite[0xA0] != dat)) {
483 draw_region();
484 }
485 } else if (adr == 0xA3){
486 int l;
487 l = snapline((int)((float)master_clk/22.0+0.5), dat, 1);
488 for (i=l; i<MAXLINES; i++) ColorVector[i] = (dat & 0x7f) | (p1 & 0x80);
489 } else if (adr == 0xAA) {
490 for (i=master_clk/22; i<MAXLINES; i++) AudioVector[i]=dat;
491 } else if ((adr >= 0x40) && (adr <= 0x7f) && ((adr & 2) == 0)) {
492 /* simulate quad: all 4 sub quad position registers
493 * are mapped to the same internal register */
494 adr = adr & 0x71;
495 /* Another minor thing: the y register always returns
496 * bit 0 as 0 */
497 if ((adr & 1) == 0) dat = dat & 0xfe;
498 VDCwrite[adr] = VDCwrite[adr+4] = VDCwrite[adr+8] = VDCwrite[adr+12] = dat;
499 }
500 VDCwrite[adr]=dat;
501 } else if (!(p1 & 0x10) && !(p1 & 0x40)) {
502 adr = adr & 0xFF;
503
504 if (adr < 0x80) {
505 /* Handle ext RAM Write */
506 extRAM[adr] = dat;
507
508
509 } else {
510 if (app_data.bank == 4) {
511 romlatch = (~dat) & 7;
512 rom=rom_table[(p1 & 1)?0:romlatch];
513 }
514
515 /* Handle The Voice */
516 if (!(dat & 0x20))
517 reset_voice();
518 else {
519 if (adr == 0xE4)
520 set_voice_bank(0);
521 else if ((adr >= 0xE8) && (adr <= 0xEF))
522 set_voice_bank(adr-0xE7);
523 else if (((adr >= 0x80) && (adr <= 0xDF)) || ((adr >= 0xF0) && (adr <= 0xFF)))
524 trigger_voice(adr);
525 }
526 }
527 } else if (!(p1 & 0x20)) {
528 /* Write to a Videopac+ register */
529 vpp_write(dat,adr);
530 }
531 }
532
533
do_kluges(void)534 static void do_kluges(void){
535 if (app_data.crc == 0xA7344D1F) pendirq=1; /* Atlantis */
536 if (app_data.crc == 0xFB83171E) pendirq=1; /* Blockout */
537 if (app_data.crc == 0xD38153F6) pendirq=1; /* Blockout (french) */
538 if (app_data.crc == 0x881CEAE4) pendirq=1; /* Wall Street */
539
540 if (app_data.crc == 0x9E42E766) useforen=1; /* Turtles */
541 if (app_data.crc == 0x1C750349) useforen=1; /* Turtles (European version) */
542 if (app_data.crc == 0x202F2749) useforen=1; /* Q*bert */
543 if (app_data.crc == 0x06861A9C) useforen=1; /* Flashpoint 5 (Videopac adaption) */
544
545 if (app_data.crc == 0xFB83171E) enahirq=0; /* Blockout*/
546 if (app_data.crc == 0xD38153F6) enahirq=0; /* Blockout (french) */
547
548 if (app_data.crc == 0xFB83171E) regionoff=1; /* Blockout*/
549 if (app_data.crc == 0xD38153F6) regionoff=1; /* Blockout (french) */
550 if (app_data.crc == 0x202F2749) regionoff=0; /* Q*bert */
551 if (app_data.crc == 0x5216771A) regionoff=1; /* Popeye */
552 if (app_data.crc == 0x0C2E4811) regionoff=11; /* Out of this World! / Helicopter Rescue! */
553 if (app_data.crc == 0x67069924) regionoff=11; /* Smithereens! */
554 if (app_data.crc == 0x44D1A8A5) regionoff=11; /* Smithereens! (European version) */
555 if (app_data.crc == 0x2391C2FB) regionoff=11; /* Smithereens! + */
556 if (app_data.crc == 0xBB4AD548) regionoff=11; /* Smithereens! modified 1 */
557 if (app_data.crc == 0x25057C11) regionoff=11; /* Smithereens! modified 2 */
558 if (app_data.crc == 0xB936BD78) regionoff=12; /* Type & Tell */
559 if (app_data.crc == 0xAD8B9AE0) regionoff=2; /* Type & Tell modified 1 */
560 if (app_data.crc == 0x5C02BEE6) regionoff=2; /* Type & Tell modified 2 */
561 if (app_data.crc == 0xDC30AD3D) regionoff=10; /* Dynasty! */
562 if (app_data.crc == 0x7810BAD5) regionoff=8; /* Dynasty! (European) */
563 if (app_data.crc == 0xA7344D1F) regionoff=0; /* Atlantis */
564 if (app_data.crc == 0xD0BC4EE6) regionoff=12; /* Frogger */
565 if (app_data.crc == 0xA57D84F3) regionoff=8; /* Frogger BR */
566 if (app_data.crc == 0x825976A9) regionoff=0; /* Mousing Cat 8kb */
567 if (app_data.crc == 0xF390BFEC) regionoff=0; /* Mousing Cat 4kb */
568 if (app_data.crc == 0x61A350E6) regionoff=0; /* Mousing Cat (french) */
569 if (app_data.crc == 0x3BFEF56B) regionoff=1; /* Four in 1 Row! */
570 if (app_data.crc == 0x7C747245) regionoff=1; /* Four in 1 Row! modified */
571 if (app_data.crc == 0x9B5E9356) regionoff=1; /* Four in 1 Row! (french) */
572
573 if (app_data.crc == 0x6CEBAB74) regionoff=12; /* P.T. Barnum's Acrobats! (European version) */
574 if (app_data.crc == 0xE7B26A56) regionoff=12; /* P.T. Barnum's Acrobats! (European version - Extra keys) */
575
576 if (app_data.crc == 0xFB83171E) mxsnap=3; /* Blockout*/
577 if (app_data.crc == 0xD38153F6) mxsnap=3; /* Blockout (french) */
578 if (app_data.crc == 0xA57E1724) mxsnap=12; /* Catch the Ball / Noughts and Crosses */
579 if (app_data.crc == 0xBE4FF48E) mxsnap=12; /* Catch the Ball / Noughts and Crosses modified */
580 if (app_data.crc == 0xFD179F6D) mxsnap=3; /* Clay Pigeon! */
581 if (app_data.crc == 0x9C9DDDF9) mxsnap=3; /* Verkehr */
582 if (app_data.crc == 0x95936B07) mxsnap=3; /* Super Cobra */
583 if (app_data.crc == 0x881CEAE4) mxsnap=3; /* Wall Street */
584 if (app_data.crc == 0x9E42E766) mxsnap=0; /* Turtles */
585 if (app_data.crc == 0x1C750349) mxsnap=0; /* Turtles (European version) */
586 if (app_data.crc == 0xD0BC4EE6) mxsnap=3; /* Frogger */
587 if (app_data.crc == 0xA57D84F3) mxsnap=3; /* Frogger BR */
588 if (app_data.crc == 0x3BFEF56B) mxsnap=6; /* Four in 1 Row! */
589 if (app_data.crc == 0x9B5E9356) mxsnap=6; /* Four in 1 Row! (french) */
590 if (app_data.crc == 0x7C747245) mxsnap=6; /* Four in 1 Row! modified */
591
592 if (app_data.crc == 0xA7344D1F) setvideomode(1); /* Atlantis */
593 if (app_data.crc == 0x39E31BF0) setvideomode(1); /* Jake */
594 if (app_data.crc == 0x92D0177B) setvideomode(1); /* Jake (hack) */
595 if (app_data.crc == 0x3351FEDA) setvideomode(1); /* Power Lords */
596 if (app_data.crc == 0x40AE062D) setvideomode(1); /* Power Lords (alternate) */
597 if (app_data.crc == 0xD158EEBA) setvideomode(1); /* Labirinth */
598 if (app_data.crc == 0x26B0FF5B) setvideomode(1); /* Nightmare */
599 if (app_data.crc == 0xDF36683F) setvideomode(1); /* Shark Hunter */
600 if (app_data.crc == 0xAF307559) setvideomode(1); /* Super Bee 8Kb */
601 if (app_data.crc == 0x9585D511) setvideomode(1); /* Super Bee 4Kb */
602 if (app_data.crc == 0x58FA6766) setvideomode(1); /* War of the Nerves */
603 if (app_data.crc == 0x58FA6766) setvideomode(1); /* War of the Nerves */
604 if (app_data.crc == 0x39989464) setvideomode(1); /* Hockey! / Soccer! */
605 if (app_data.crc == 0x3BFEF56B) setvideomode(1); /* Four in 1 Row! */
606 if (app_data.crc == 0x9B5E9356) setvideomode(1); /* Four in 1 Row! (french) */
607 if (app_data.crc == 0x7C747245) setvideomode(1); /* Four in 1 Row! modified */
608 if (app_data.crc == 0x68560DC7) setvideomode(1); /* Jopac Moto Crash */
609 if (app_data.crc == 0x020FCA15) setvideomode(1); /* Jopac Moto Crash modified (non VP+) */
610 if (app_data.crc == 0xC4134DF8) setvideomode(1); /* Helicopter Rescue + */
611 if (app_data.crc == 0x0D2D721D) setvideomode(1); /* Trans American Rally + */
612 if (app_data.crc == 0x9D72D4E9) setvideomode(1); /* Blobbers */
613 if (app_data.crc == 0xB2F0F0B4) setvideomode(1); /* Le Tresor Englouti + */
614 if (app_data.crc == 0x0B2DEB61) setvideomode(1); /* Tutankham */
615 if (app_data.crc == 0x313547EB) setvideomode(1); /* VP53 */
616 if (app_data.crc == 0x06861A9C) setvideomode(1); /* Flashpoint 5 (Videopac adaption) */
617 if (app_data.crc == 0xA57E1724) setvideomode(0); /* Catch the Ball / Noughts and Crosses */
618 if (app_data.crc == 0xBE4FF48E) setvideomode(0); /* Catch the Ball / Noughts and Crosses modified */
619 if (app_data.crc == 0xFB83171E) setvideomode(0); /* Blockout*/
620 if (app_data.crc == 0xD38153F6) setvideomode(0); /* Blockout (french) */
621 if (app_data.crc == 0x9BFC3E01) setvideomode(0); /* Demon Attack */
622 if (app_data.crc == 0x50AF9D45) setvideomode(0); /* Demon Attack + */
623 if (app_data.crc == 0x9884EF36) setvideomode(0); /* Demon Attack + modified */
624 if (app_data.crc == 0x4A578DFE) setvideomode(0); /* Restaurant ntsc */
625 if (app_data.crc == 0x863D5E2D) setvideomode(0); /* Shark Hunter ntsc */
626
627 if (app_data.crc == 0xD62814A3) evblclk=12000; /* Pick Axe Pete */
628 if (app_data.crc == 0xB2FFB353) evblclk=12000; /* Pick Axe Pete + */
629 if (app_data.crc == 0x81C20196) evblclk=12000; /* Pick Axe Pete + (modified) */
630
631 if ((app_data.crc == 0xF390BFEC) || (app_data.crc == 0x825976A9) || (app_data.crc == 0x61A350E6)){ /* Mousing Cat */
632 setvideomode(1);
633 evblclk=7642;
634 }
635
636 if (app_data.crc == 0xD0BC4EE6) { /* Frogger */
637 setvideomode(1);
638 evblclk=7642;
639
640 }
641 if (app_data.crc == 0x26517E77) { /* Commando Noturno */
642 setvideomode(1);
643 evblclk=6100;
644 regionoff=12;
645 }
646 if (app_data.crc == 0xA57E1724) { /* Catch the ball*/
647 regionoff=5;
648 sproff=1;
649
650 }
651
652 if ((app_data.crc == 0x2DCB77F0) || (app_data.crc == 0xF6882734)) { /* Depth Charge / Marksman */
653 setvideomode(1);
654 evblclk=8000;
655 }
656 if (app_data.crc == 0x881CEAE4) { /* Wall Street */
657 setvideomode(1);
658 evblclk=6100;
659 }
660 if (app_data.crc == 0xD0BC4EE6) tweakedaudio=1; /* Frogger */
661 if (app_data.crc == 0xA57D84F3) tweakedaudio=1; /* Frogger BR */
662 if (app_data.crc == 0x5216771A) tweakedaudio=1; /* Popeye */
663 if (app_data.crc == 0xAFB23F89) tweakedaudio=1; /* Musician */
664 if (app_data.crc == 0xC4134DF8) tweakedaudio=1; /* Helicopter Rescue + */
665 if (app_data.crc == 0x0D2D721D) tweakedaudio=1; /* Trans American Rally + */
666
667 if (app_data.crc == 0xD3B09FEC) sproff=1; /* Volleyball! */
668 if (app_data.crc == 0x551E38A2) sproff=1; /* Volleyball! (french) */
669
670 }
671
672
snapline(int pos,uint8_t reg,int t)673 int snapline(int pos, uint8_t reg, int t)
674 {
675 int i;
676 if (pos<MAXLINES+MAXSNAP+MAXSNAP)
677 {
678 for (i=0; i<mxsnap; i++)
679 {
680 if (snapedlines[pos+MAXSNAP-i][reg][t]) return pos-i;
681 if (snapedlines[pos+MAXSNAP+i][reg][t]) return pos+i;
682 }
683 snapedlines[pos+MAXSNAP][reg][t]=1;
684 }
685 return pos;
686 }
687
688
setvideomode(int t)689 static void setvideomode(int t){
690 if (t) {
691 evblclk = EVBLCLK_PAL;
692 fps = FPS_PAL;
693 } else {
694 evblclk = EVBLCLK_NTSC;
695 fps = FPS_NTSC;
696 }
697 }
698
699
700 #ifdef __LIBRETRO__
701 #include <errno.h>
702 #include <string.h>
703
savestate_to_mem(uint8_t * data)704 void savestate_to_mem(uint8_t *data)
705 {
706 int offset = 0;
707 memcpy(data+offset, &app_data.crc, sizeof(app_data.crc));
708 offset += sizeof(app_data.crc);
709 memcpy(data+offset, &app_data.bios, sizeof(app_data.bios));
710 offset += sizeof(app_data.bios);
711 memcpy(data+offset, VDCwrite, 256);
712 offset += 256;
713 memcpy(data+offset, extRAM, 256);
714 offset += 256;
715 memcpy(data+offset, intRAM, 64);
716 offset += 64;
717 memcpy(data+offset, &pc, sizeof(pc));
718 offset += sizeof(pc);
719 memcpy(data+offset, &sp, sizeof(sp));
720 offset += sizeof(sp);
721 memcpy(data+offset, &bs, sizeof(bs));
722 offset += sizeof(bs);
723 memcpy(data+offset, &p1, sizeof(p1));
724 offset += sizeof(p1);
725 memcpy(data+offset, &p2, sizeof(p2));
726 offset += sizeof(p2);
727 memcpy(data+offset, &ac, sizeof(ac));
728 offset += sizeof(ac);
729 memcpy(data+offset, &cy, sizeof(cy));
730 offset += sizeof(cy);
731 memcpy(data+offset, &f0, sizeof(f0));
732 offset += sizeof(f0);
733 memcpy(data+offset, &A11, sizeof(A11));
734 offset += sizeof(A11);
735 memcpy(data+offset, &A11ff, sizeof(A11ff));
736 offset += sizeof(A11ff);
737 memcpy(data+offset, &timer_on, sizeof(timer_on));
738 offset += sizeof(timer_on);
739 memcpy(data+offset, &count_on, sizeof(count_on));
740 offset += sizeof(count_on);
741 memcpy(data+offset, ®_pnt, sizeof(reg_pnt));
742 offset += sizeof(reg_pnt);
743 memcpy(data+offset, &tirq_en, sizeof(tirq_en));
744 offset += sizeof(tirq_en);
745 memcpy(data+offset, &xirq_en, sizeof(xirq_en));
746 offset += sizeof(xirq_en);
747 memcpy(data+offset, &irq_ex, sizeof(irq_ex));
748 offset += sizeof(irq_ex);
749 memcpy(data+offset, &xirq_pend, sizeof(xirq_pend));
750 offset += sizeof(xirq_pend);
751 memcpy(data+offset, &tirq_pend, sizeof(tirq_pend));
752 }
753
loadstate_from_mem(const uint8_t * data)754 void loadstate_from_mem(const uint8_t *data)
755 {
756 int offset = 0;
757 memcpy(&app_data.crc, data+offset, sizeof(app_data.crc));
758 offset += sizeof(app_data.crc);
759 memcpy(&app_data.bios, data+offset, sizeof(app_data.bios));
760 offset += sizeof(app_data.bios);
761 memcpy(VDCwrite, data+offset, 256);
762 offset += 256;
763 memcpy(extRAM, data+offset, 256);
764 offset += 256;
765 memcpy(intRAM, data+offset, 64);
766 offset += 64;
767 memcpy(&pc, data+offset, sizeof(pc));
768 offset += sizeof(pc);
769 memcpy(&sp, data+offset, sizeof(sp));
770 offset += sizeof(sp);
771 memcpy(&bs, data+offset, sizeof(bs));
772 offset += sizeof(bs);
773 memcpy(&p1, data+offset, sizeof(p1));
774 offset += sizeof(p1);
775 memcpy(&p2, data+offset, sizeof(p2));
776 offset += sizeof(p2);
777 memcpy(&ac, data+offset, sizeof(ac));
778 offset += sizeof(ac);
779 memcpy(&cy, data+offset, sizeof(cy));
780 offset += sizeof(cy);
781 memcpy(&f0, data+offset, sizeof(f0));
782 offset += sizeof(f0);
783 memcpy(&A11, data+offset, sizeof(A11));
784 offset += sizeof(A11);
785 memcpy(&A11ff, data+offset, sizeof(A11ff));
786 offset += sizeof(A11ff);
787 memcpy(&timer_on, data+offset, sizeof(timer_on));
788 offset += sizeof(timer_on);
789 memcpy(&count_on, data+offset, sizeof(count_on));
790 offset += sizeof(count_on);
791 memcpy(®_pnt, data+offset, sizeof(reg_pnt));
792 offset += sizeof(reg_pnt);
793 memcpy(&tirq_en, data+offset, sizeof(tirq_en));
794 offset += sizeof(tirq_en);
795 memcpy(&xirq_en, data+offset, sizeof(xirq_en));
796 offset += sizeof(xirq_en);
797 memcpy(&irq_ex, data+offset, sizeof(irq_ex));
798 offset += sizeof(irq_ex);
799 memcpy(&xirq_pend, data+offset, sizeof(xirq_pend));
800 offset += sizeof(xirq_pend);
801 memcpy(&tirq_pend, data+offset, sizeof(tirq_pend));
802 }
803 #endif
804
savestate(char * filename)805 int savestate(char* filename)
806 {
807 FILE *fn;
808
809 fn = fopen(filename,"wb");
810 if (fn==NULL) {
811 fprintf(stderr,"Error opening state-file %s: %i\n",filename,errno);
812 return(errno);
813 }
814
815 fwrite (&app_data.crc,sizeof(app_data.crc),1,fn);
816 fwrite (&app_data.bios,sizeof(app_data.bios),1,fn);
817
818 fwrite (VDCwrite,256,1,fn);
819 fwrite (extRAM,256,1,fn);
820 fwrite (intRAM,64,1,fn);
821
822 fwrite(&pc, sizeof(pc),1,fn);
823 fwrite(&sp, sizeof(sp),1,fn);
824 fwrite(&bs, sizeof(bs),1,fn);
825 fwrite(&p1, sizeof(p1),1,fn);
826 fwrite(&p2, sizeof(p2),1,fn);
827
828 fwrite(&ac, sizeof(ac),1,fn);
829 fwrite(&cy, sizeof(cy),1,fn);
830 fwrite(&f0, sizeof(f0),1,fn);
831 fwrite(&A11, sizeof(A11),1,fn);
832 fwrite(&A11ff, sizeof(A11ff),1,fn);
833
834 fwrite(&timer_on, sizeof(timer_on),1,fn);
835 fwrite(&count_on, sizeof(count_on),1,fn);
836 fwrite(®_pnt, sizeof(reg_pnt),1,fn);
837
838 fwrite(&tirq_en, sizeof(tirq_en),1,fn);
839 fwrite(&xirq_en, sizeof(xirq_en),1,fn);
840 fwrite(&irq_ex, sizeof(irq_ex),1,fn);
841 fwrite(&xirq_pend, sizeof(xirq_pend),1,fn);
842 fwrite(&tirq_pend, sizeof(tirq_pend),1,fn);
843
844 fclose(fn);
845 return(0);
846
847 }
848
loadstate(char * filename)849 int loadstate(char* filename)
850 {
851 int bios;
852 unsigned long crc;
853 FILE *fn = fopen(filename,"rb");
854 if (fn==NULL) // no savefile yet
855 return(errno);
856
857 fread (&crc,sizeof(crc),1,fn);
858 if (crc!=app_data.crc) // wrong cart
859 {
860 fclose(fn);
861 return(199);
862 }
863
864 fread (&bios,sizeof(bios),1,fn);
865 if (bios!=app_data.bios) // wrong bios
866 {
867 fclose(fn);
868 return(200+bios);
869 }
870
871 fread (VDCwrite,256,1,fn);
872 fread (extRAM,256,1,fn);
873 fread (intRAM,64,1,fn);
874
875 fread(&pc, sizeof(pc),1,fn);
876 fread(&sp, sizeof(sp),1,fn);
877 fread(&bs, sizeof(bs),1,fn);
878 fread(&p1, sizeof(p1),1,fn);
879 fread(&p2, sizeof(p2),1,fn);
880
881 fread(&ac, sizeof(ac),1,fn);
882 fread(&cy, sizeof(cy),1,fn);
883 fread(&f0, sizeof(f0),1,fn);
884 fread(&A11, sizeof(A11),1,fn);
885 fread(&A11ff, sizeof(A11ff),1,fn);
886
887 fread(&timer_on, sizeof(timer_on),1,fn);
888 fread(&count_on, sizeof(count_on),1,fn);
889 fread(®_pnt, sizeof(reg_pnt),1,fn);
890
891 fread(&tirq_en, sizeof(tirq_en),1,fn);
892 fread(&xirq_en, sizeof(xirq_en),1,fn);
893 fread(&irq_ex, sizeof(irq_ex),1,fn);
894 fread(&xirq_pend, sizeof(xirq_pend),1,fn);
895 fread(&tirq_pend, sizeof(tirq_pend),1,fn);
896
897 fclose(fn);
898
899 return(0);
900
901 }
902