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, &reg_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(&reg_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(&reg_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(&reg_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