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 <stdlib.h>
19 #include <stdio.h>
20 #include <time.h>
21 #include "audio.h"
22 #include "types.h"
23 #include "cpu.h"
24 #include "keyboard.h"
25 #include "config.h"
26 #include "debug.h"
27 #include "vdc.h"
28 #include "vpp.h"
29 #include "timefunc.h"
30 #include "voice.h"
31 #include "vmachine.h"
32 #include "allegro.h"
33 
34 
35 
36 static Byte x_latch,y_latch;
37 static int romlatch=0;
38 static Byte line_count;
39 static int fps=FPS_NTSC;
40 
41 static Byte snapedlines[MAXLINES+2*MAXSNAP][256][2];
42 
43 int evblclk=EVBLCLK_NTSC;
44 
45 struct resource app_data;
46 int frame=0;
47 Byte dbstick1,dbstick2;
48 
49 int int_clk; 	/* counter for length of /INT pulses */
50 int master_clk;	/* Master clock */
51 int h_clk;   /* horizontal clock */
52 unsigned long clk_counter;
53 int last_line;
54 int key2vcnt=0;
55 int mstate;
56 
57 int pendirq=0;
58 int enahirq=1;
59 int useforen=0;
60 long regionoff=0xffff;
61 int mxsnap=2;
62 int sproff=0;
63 int tweakedaudio=0;
64 
65 Byte rom_table[8][4096];
66 
67 Byte intRAM[64];
68 Byte extRAM[256];
69 Byte extROM[1024];
70 Byte VDCwrite[256];
71 Byte ColorVector[MAXLINES];
72 Byte AudioVector[MAXLINES];
73 Byte *rom;
74 
75 int key2[128];
76 
77 
78 static unsigned int key_map[6][8]= {
79 	{KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7},
80 	{KEY_8,KEY_9,0,0,KEY_SPACE,KEY_SLASH,KEY_L,KEY_P},
81 	{KEY_PLUS_PAD,KEY_W,KEY_E,KEY_R,KEY_T,KEY_U,KEY_I,KEY_O},
82 	{KEY_Q,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K},
83 	{KEY_A,KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_M,KEY_STOP},
84 	{KEY_MINUS,KEY_ASTERISK,KEY_SLASH_PAD,KEY_EQUALS,KEY_Y,KEY_N,KEY_DEL,KEY_ENTER}
85 };
86 
87 
88 static void do_kluges(void);
89 static void setvideomode(int t);
90 
run(void)91 void run(void){
92 	while(!key_done) {
93 
94 		if (key_debug) {
95 			app_data.debug=1;
96 			set_textmode();
97 			mute_audio();
98 			mute_voice();
99 			debug();
100 			grmode();
101 			app_data.debug=0;
102 			init_keyboard();
103 			init_sound_stream();
104 		}
105 
106 		cpu_exec();
107 
108 	}
109 	close_audio();
110 	close_voice();
111 	close_display();
112 }
113 
114 
handle_vbl(void)115 void handle_vbl(void){
116 	if (!app_data.debug) {
117 		handle_key();
118 		update_audio();
119 		update_voice();
120 	}
121 	draw_region();
122 	ext_IRQ();
123 	mstate = 1;
124 }
125 
126 
handle_evbl(void)127 void handle_evbl(void){
128 	static long last=0;
129 	static int rest_cnt=0;
130 	int i;
131 
132 	#ifndef ALLEGRO_DOS
133 	yield_timeslice();
134 	#endif
135 	i = (15*app_data.speed/100);
136 	rest_cnt = (rest_cnt+1)%(i<5?5:i);
137 	#ifdef ALLEGRO_WINDOWS
138 	if (rest_cnt==0) rest(1);
139 	#endif
140 	last_line=0;
141 	master_clk -= evblclk;
142 	frame++;
143 	if (!app_data.debug) {
144 		finish_display();
145 	}
146 
147     if (app_data.crc == 0xA7344D1F)
148                       {for (i=0; i<140; i++)
149                            {
150 		                   ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80);
151 		                   AudioVector[i] = VDCwrite[0xAA];
152                            }
153                       }/*Atlantis*/
154                       else
155                       for (i=0; i<MAXLINES; i++)  {
156                       ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80);
157 	                  AudioVector[i] = VDCwrite[0xAA];
158                       }
159 
160 
161     if (key2vcnt++ > 10) {
162 		key2vcnt=0;
163 		for (i=0; i<128; i++) key2[i] = 0;
164 		dbstick1 = dbstick2 = 0;
165 	}
166 	if (app_data.limit) {
167 		long d,f;
168 		d = (TICKSPERSEC*100)/(app_data.speed*fps);
169 		f = ((d-gettimeticks()+last)*1000)/TICKSPERSEC;
170 		if (f>0) {
171 			#ifdef ALLEGRO_WINDOWS
172 				f = f-(f%10);
173 				if (f>5) rest(f-5);
174 			#else
175 				#ifndef ALLEGRO_DOS
176 					yield_timeslice();
177 				#endif
178 			#endif
179 		}
180 		while (gettimeticks() - last < d);
181 		last = gettimeticks();
182 	}
183 	mstate=0;
184 
185 }
186 
handle_evbll(void)187 void handle_evbll(void){
188 	static long last=0;
189 	static int rest_cnt=0;
190 	int i;
191 
192 	#ifndef ALLEGRO_DOS
193 	yield_timeslice();
194 	#endif
195 	i = (15*app_data.speed/100);
196 	rest_cnt = (rest_cnt+1)%(i<5?5:i);
197 	#ifdef ALLEGRO_WINDOWS
198 	if (rest_cnt==0) rest(1);
199 	#endif
200 
201 /******************* 150 */
202 
203     for (i=150; i<MAXLINES; i++)  {
204 		ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80);
205 		AudioVector[i] = VDCwrite[0xAA];
206 	}
207 
208 	if (key2vcnt++ > 10) {
209 		key2vcnt=0;
210 		for (i=0; i<128; i++) key2[i] = 0;
211 		dbstick1 = dbstick2 = 0;
212 	}
213 	if (app_data.limit) {
214 		long d,f;
215 		d = (TICKSPERSEC*100)/(app_data.speed*fps);
216 		f = ((d-gettimeticks()+last)*1000)/TICKSPERSEC;
217 		if (f>0) {
218 			#ifdef ALLEGRO_WINDOWS
219 				f = f-(f%10);
220 				if (f>5) rest(f-5);
221 			#else
222 				#ifndef ALLEGRO_DOS
223 					yield_timeslice();
224 				#endif
225 			#endif
226 		}
227 		while (gettimeticks() - last < d);
228 		last = gettimeticks();
229 	}
230 	mstate=0;
231 }
232 
init_system(void)233 void init_system(void){
234 	int i,j,k;
235 
236 	last_line=0;
237 	dbstick1=0x00;
238 	dbstick2=0x00;
239 	mstate=0;
240 	master_clk=0;
241 	h_clk=0;
242 	line_count=0;
243 	itimer=0;
244 	clk_counter=0;
245 	init_roms();
246 	for(i=0; i<256; i++) {
247 		VDCwrite[i]=0;
248 		extRAM[i]=0;
249 	}
250 	for(i=0; i<64; i++) {
251 		intRAM[i]=0;
252 	}
253 	for (i=0; i<MAXLINES; i++) AudioVector[i] = ColorVector[i] = 0;
254 
255 	for (i=0; i<MAXLINES+2*MAXSNAP; i++)
256 		for (j=0; j<256; j++)
257 			for (k=0; k<2; k++)
258 				snapedlines[i][j][k]=0;
259 
260 	if (app_data.stick[0] == 2 || app_data.stick[1] == 2) {
261 		i = install_joystick(JOY_TYPE_AUTODETECT);
262 		if (i || (num_joysticks<1)) {
263 			fprintf(stderr,"Error: no joystick detected\n");
264 			exit(EXIT_FAILURE);
265 		}
266 	}
267 	for (i=0; i<128; i++) key2[i] = 0;
268 	key2vcnt=0;
269 	if (app_data.euro)
270 		setvideomode(1);
271 	else
272 		setvideomode(0);
273 	do_kluges();
274 	init_vpp();
275 	clear_collision();
276 }
277 
278 
init_roms(void)279 void init_roms(void){
280 	rom=rom_table[0];
281 	romlatch=0;
282 }
283 
284 
read_t1(void)285 Byte read_t1(void){
286 	if ((h_clk > 17) || (master_clk > VBLCLK))
287 		return 1;
288 	else
289 		return 0;
290 }
291 
292 
write_p1(Byte d)293 void write_p1(Byte d){
294 	if ((d & 0x80) != (p1 & 0x80)) {
295 		int i,l;
296 		l = snapline((int)((float)master_clk/22.0+0.1), VDCwrite[0xA3], 1);
297 		for (i=l; i<MAXLINES; i++) ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (d & 0x80);
298 	}
299 	p1 = d;
300 	if (app_data.bank == 2) {
301 		rom=rom_table[~p1 & 0x01];
302 	} else if (app_data.bank == 3) {
303 		rom=rom_table[~p1 & 0x03];
304 	} else if (app_data.bank == 4) {
305 		rom=rom_table[(p1 & 1)?0:romlatch];
306 	}
307 }
308 
309 
read_P2(void)310 Byte read_P2(void){
311 	int i,si,so,km;
312 
313 	if (NeedsPoll) poll_keyboard();
314 
315 	if (!(p1 & 0x04)) {
316 		si = (p2 & 7);
317 		so=0xff;
318 		if (si<6) {
319 			for (i=0; i<8; i++) {
320 				km = key_map[si][i];
321 				if ((key[km] && ((!joykeystab[km]) || (key_shifts & KB_CAPSLOCK_FLAG))) || (key2[km])) {
322 					so = i ^ 0x07;
323 				}
324 			}
325 		}
326 		if (so != 0xff) {
327 			p2 = p2 & 0x0F;
328 			p2 = p2 | (so << 5);
329 		} else {
330 			p2 = p2 | 0xF0;
331 		}
332 	 } else {
333 		p2 = p2 | 0xF0;
334 	 }
335 	 return(p2);
336 
337 }
338 
339 
ext_read(ADDRESS adr)340 Byte ext_read(ADDRESS adr){
341 	Byte d;
342 	Byte si;
343 	Byte m;
344 	int i;
345 
346 	if (!(p1 & 0x08) && !(p1 & 0x40)) {
347 		/* Handle VDC Read */
348 		switch(adr) {
349 			case 0xA1:
350 				d = VDCwrite[0xA0] & 0x02;
351 				if (master_clk > VBLCLK) d = d | 0x08;
352 				if (h_clk < (LINECNT-7)) d = d | 0x01;
353 				if (sound_IRQ) d = d | 0x04;
354 				sound_IRQ=0;
355 				return d;
356 			case 0xA2:
357 				si = VDCwrite[0xA2];
358 				m=0x01;
359 				d=0;
360 				for(i=0; i<8; i++) {
361 					if (si & m) {
362 						if (coltab[1] & m) d = d | (coltab[1] & (m ^ 0xFF));
363 						if (coltab[2] & m) d = d | (coltab[2] & (m ^ 0xFF));
364 						if (coltab[4] & m) d = d | (coltab[4] & (m ^ 0xFF));
365 						if (coltab[8] & m) d = d | (coltab[8] & (m ^ 0xFF));
366 						if (coltab[0x10] & m) d = d | (coltab[0x10] & (m ^ 0xFF));
367 						if (coltab[0x20] & m) d = d | (coltab[0x20] & (m ^ 0xFF));
368 						if (coltab[0x80] & m) d = d | (coltab[0x80] & (m ^ 0xFF));
369 					}
370 					m = m << 1;
371 				}
372 				clear_collision();
373 				return d;
374 			case 0xA5:
375 				if (!(VDCwrite[0xA0] & 0x02)) {
376 					return x_latch;
377 				}
378 				else {
379 					x_latch = h_clk * 12;
380 					return x_latch;
381 				}
382 			case 0xA4:
383 				if (!(VDCwrite[0xA0] & 0x02)) {
384 					return y_latch;
385 				}
386 				else {
387 					y_latch = master_clk/22;
388 					if (y_latch > 241) y_latch=0xFF;
389 					return y_latch;
390 				}
391 			default:
392 				return VDCwrite[adr];
393 		}
394 	} else if (!(p1 & 0x10)) {
395 		/* Handle ext RAM Read */
396 		 return extRAM[adr & 0xFF];
397 	} else if (!(p1 & 0x20)) {
398 		/* Read a Videopac+ register */
399 		return vpp_read(adr);
400 	} else if (app_data.exrom && (p1 & 0x02)) {
401 		/* Handle read from exrom */
402 		return extROM[(p2 << 8) | (adr & 0xFF)];
403 	}
404 
405 	return 0;
406 }
407 
408 
in_bus(void)409 Byte in_bus(void){
410 	Byte si=0,d=0,mode=0,jn=0;
411 
412 	if ((p1 & 0x08) && (p1 & 0x10)) {
413 		/* Handle joystick read */
414 		if (!(p1 & 0x04)) {
415 			si = (p2 & 7);
416 		}
417 		d=0xFF;
418 		if (si == 1) {
419 			mode = app_data.stick[0];
420 			jn = 0;
421 		} else {
422 			mode = app_data.stick[1];
423 			jn = 1;
424 		}
425 		switch(mode) {
426 			case 1:
427 				d = keyjoy(jn);
428 				break;
429 			case 2:
430 				poll_joystick();
431 				if (joy_up) d &= 0xFE;
432 				if (joy_right) d &= 0xFD;
433 				if (joy_down) d &= 0xFB;
434 				if (joy_left) d &= 0xF7;
435 				if (joy_b1) d &= 0xEF;
436 				break;
437 		}
438 		if (si == 1) {
439 			if (dbstick1) d = dbstick1;
440 		} else {
441 			if (dbstick2) d = dbstick2;
442 		}
443    }
444    return d;
445 }
446 
447 
ext_write(Byte dat,ADDRESS adr)448 void ext_write(Byte dat, ADDRESS adr){
449 	int i;
450 
451 	if (!(p1 & 0x08)) {
452 		/* Handle VDC Write */
453 		if (adr == 0xA0){
454 			if ((VDCwrite[0xA0] & 0x02) && !(dat & 0x02)) {
455 				y_latch = master_clk/22;
456 				x_latch = h_clk * 12;
457 				if (y_latch > 241) y_latch=0xFF;
458 			}
459 			if ((master_clk <= VBLCLK) && (VDCwrite[0xA0] != dat)) {
460 				draw_region();
461 			}
462 		} else if (adr == 0xA3){
463 			int l;
464 			l = snapline((int)((float)master_clk/22.0+0.5), dat, 1);
465 			for (i=l; i<MAXLINES; i++) ColorVector[i] = (dat & 0x7f) | (p1 & 0x80);
466 		} else if (adr == 0xAA) {
467 			for (i=master_clk/22; i<MAXLINES; i++) AudioVector[i]=dat;
468 		}
469 		VDCwrite[adr]=dat;
470 	} else if (!(p1 & 0x10) && !(p1 & 0x40)) {
471 		adr = adr & 0xFF;
472 		if (adr < 0x80) {
473 			/* Handle ext RAM Write */
474 			extRAM[adr] = dat;
475 		} else {
476 
477 			if (app_data.bank == 4) {
478 				romlatch = (~dat) & 7;
479 				rom=rom_table[(p1 & 1)?0:romlatch];
480 			}
481 
482 			/* Handle The Voice */
483 			if (!(dat & 0x20))
484 				reset_voice();
485 			else {
486 				if (adr == 0xE4)
487 					set_voice_bank(0);
488 				else if ((adr >= 0xE8) && (adr <= 0xEF))
489 					set_voice_bank(adr-0xE7);
490 				else if (((adr >= 0x80) && (adr <= 0xDF)) || ((adr >= 0xF0) && (adr <= 0xFF)))
491 					trigger_voice(adr);
492 			}
493 		}
494 	} else if (!(p1 & 0x20)) {
495 		/* Write to a Videopac+ register */
496 		vpp_write(dat,adr);
497 	}
498 }
499 
500 
do_kluges(void)501 static void do_kluges(void){
502 	if (app_data.crc == 0xA7344D1F) pendirq=1;				/* Atlantis */
503 
504 	if (app_data.crc == 0xFB83171E) pendirq=1;				/* Blockout */
505 	if (app_data.crc == 0xD38153F6) pendirq=1;				/* Blockout (french) */
506 	if (app_data.crc == 0x881CEAE4) pendirq=1;				/* Wall Street */
507 
508 	if (app_data.crc == 0x9E42E766) useforen=1;				/* Turtles */
509 	if (app_data.crc == 0x1C750349) useforen=1;				/* Turtles (European version) */
510 	if (app_data.crc == 0x202F2749) useforen=1;				/* Q*bert */
511 	if (app_data.crc == 0x06861A9C) useforen=1;				/* Flashpoint 5 (Videopac adaption) */
512 
513 	if (app_data.crc == 0xFB83171E) enahirq=0;				/* Blockout*/
514 	if (app_data.crc == 0xD38153F6) enahirq=0;				/* Blockout (french) */
515 
516 	if (app_data.crc == 0xFB83171E) regionoff=1;			/* Blockout*/
517 	if (app_data.crc == 0xD38153F6) regionoff=1;			/* Blockout (french) */
518 	if (app_data.crc == 0x202F2749) regionoff=0;			/* Q*bert */
519 	if (app_data.crc == 0x5216771A) regionoff=1;			/* Popeye */
520 	if (app_data.crc == 0x0C2E4811) regionoff=11;			/* Out of this World! / Helicopter Rescue! */
521 	if (app_data.crc == 0x67069924) regionoff=11;			/* Smithereens! */
522 	if (app_data.crc == 0x44D1A8A5) regionoff=11;			/* Smithereens! (European version) */
523 	if (app_data.crc == 0x2391C2FB) regionoff=11;			/* Smithereens! + */
524 	if (app_data.crc == 0xBB4AD548) regionoff=11;			/* Smithereens! modified 1 */
525 	if (app_data.crc == 0x25057C11) regionoff=11;			/* Smithereens! modified 2 */
526 	if (app_data.crc == 0xB936BD78) regionoff=12;			/* Type & Tell */
527 	if (app_data.crc == 0xAD8B9AE0) regionoff=2;			/* Type & Tell modified 1 */
528 	if (app_data.crc == 0x5C02BEE6) regionoff=2;			/* Type & Tell modified 2 */
529 	if (app_data.crc == 0xDC30AD3D) regionoff=10;			/* Dynasty! */
530 	if (app_data.crc == 0x7810BAD5) regionoff=8;			/* Dynasty! (European) */
531 	if (app_data.crc == 0xA7344D1F) regionoff=0;			/* Atlantis */
532 
533 	if (app_data.crc == 0xD0BC4EE6) regionoff=12;			/* Frogger */
534 
535 	if (app_data.crc == 0xA57D84F3) regionoff=8;			/* Frogger BR */
536 	if (app_data.crc == 0x825976A9) regionoff=0;			/* Mousing Cat 8kb */
537 	if (app_data.crc == 0xF390BFEC) regionoff=0;			/* Mousing Cat 4kb */
538 	if (app_data.crc == 0x61A350E6) regionoff=0;			/* Mousing Cat (french) */
539 	if (app_data.crc == 0x3BFEF56B) regionoff=1;			/* Four in 1 Row! */
540 	if (app_data.crc == 0x7C747245) regionoff=1;			/* Four in 1 Row! modified */
541 	if (app_data.crc == 0x9B5E9356) regionoff=1;			/* Four in 1 Row! (french) */
542 
543 	if (app_data.crc == 0x6CEBAB74) regionoff=12;			/* P.T. Barnum's Acrobats! (European version) */
544 	if (app_data.crc == 0xE7B26A56) regionoff=12;			/* P.T. Barnum's Acrobats! (European version - Extra keys) */
545 
546 	if (app_data.crc == 0xFB83171E) mxsnap=3;				/* Blockout*/
547 	if (app_data.crc == 0xD38153F6) mxsnap=3;				/* Blockout (french) */
548 	if (app_data.crc == 0xA57E1724) mxsnap=12;				/* Catch the Ball / Noughts and Crosses */
549 	if (app_data.crc == 0xBE4FF48E) mxsnap=12;				/* Catch the Ball / Noughts and Crosses modified */
550 	if (app_data.crc == 0xFD179F6D) mxsnap=3;				/* Clay Pigeon! */
551 	if (app_data.crc == 0x9C9DDDF9) mxsnap=3;				/* Verkehr */
552 	if (app_data.crc == 0x95936B07) mxsnap=3;				/* Super Cobra */
553 	if (app_data.crc == 0x881CEAE4) mxsnap=3;				/* Wall Street */
554 	if (app_data.crc == 0x9E42E766) mxsnap=0;				/* Turtles */
555 	if (app_data.crc == 0x1C750349) mxsnap=0;				/* Turtles (European version) */
556 
557 	if (app_data.crc == 0xD0BC4EE6) mxsnap=3;				/* Frogger */
558 
559 	if (app_data.crc == 0xA57D84F3) mxsnap=3;				/* Frogger BR */
560 	if (app_data.crc == 0x3BFEF56B) mxsnap=6;				/* Four in 1 Row! */
561 	if (app_data.crc == 0x9B5E9356) mxsnap=6;				/* Four in 1 Row! (french) */
562 	if (app_data.crc == 0x7C747245) mxsnap=6;				/* Four in 1 Row! modified */
563 
564 	if (app_data.crc == 0xA7344D1F) setvideomode(1);		/* Atlantis */
565 	if (app_data.crc == 0x39E31BF0) setvideomode(1);		/* Jake */
566 	if (app_data.crc == 0x92D0177B) setvideomode(1);		/* Jake (hack) */
567 	if (app_data.crc == 0x3351FEDA) setvideomode(1);		/* Power Lords */
568 	if (app_data.crc == 0x40AE062D) setvideomode(1);		/* Power Lords (alternate) */
569 	if (app_data.crc == 0xD158EEBA) setvideomode(1);		/* Labirinth */
570 	if (app_data.crc == 0x26B0FF5B) setvideomode(1);		/* Nightmare */
571 	if (app_data.crc == 0xDF36683F) setvideomode(1);		/* Shark Hunter */
572 	if (app_data.crc == 0xAF307559) setvideomode(1);		/* Super Bee 8Kb */
573 	if (app_data.crc == 0x9585D511) setvideomode(1);		/* Super Bee 4Kb */
574 	if (app_data.crc == 0x58FA6766) setvideomode(1);		/* War of the Nerves */
575 	if (app_data.crc == 0x58FA6766) setvideomode(1);		/* War of the Nerves */
576 	if (app_data.crc == 0x39989464) setvideomode(1);		/* Hockey! / Soccer! */
577 	if (app_data.crc == 0x3BFEF56B) setvideomode(1);		/* Four in 1 Row! */
578 	if (app_data.crc == 0x9B5E9356) setvideomode(1);		/* Four in 1 Row! (french) */
579 	if (app_data.crc == 0x7C747245) setvideomode(1);		/* Four in 1 Row! modified */
580 	if (app_data.crc == 0x68560DC7) setvideomode(1);		/* Jopac Moto Crash */
581 	if (app_data.crc == 0x020FCA15) setvideomode(1);		/* Jopac Moto Crash modified (non VP+) */
582 	if (app_data.crc == 0xC4134DF8) setvideomode(1);		/* Helicopter Rescue + */
583 	if (app_data.crc == 0x0D2D721D) setvideomode(1);		/* Trans American Rally + */
584 	if (app_data.crc == 0x9D72D4E9) setvideomode(1);		/* Blobbers */
585 	if (app_data.crc == 0xB2F0F0B4) setvideomode(1);		/* Le Tresor Englouti + */
586 	if (app_data.crc == 0x0B2DEB61) setvideomode(1);		/* Tutankham */
587 	if (app_data.crc == 0x313547EB) setvideomode(1);		/* VP53 */
588 	if (app_data.crc == 0x06861A9C) setvideomode(1);		/* Flashpoint 5 (Videopac adaption) */
589 	if (app_data.crc == 0xA57E1724) setvideomode(0);		/* Catch the Ball / Noughts and Crosses */
590 	if (app_data.crc == 0xBE4FF48E) setvideomode(0);		/* Catch the Ball / Noughts and Crosses modified */
591 	if (app_data.crc == 0xFB83171E) setvideomode(0);		/* Blockout*/
592 	if (app_data.crc == 0xD38153F6) setvideomode(0);		/* Blockout (french) */
593 	if (app_data.crc == 0x9BFC3E01) setvideomode(0);		/* Demon Attack */
594 	if (app_data.crc == 0x50AF9D45) setvideomode(0);		/* Demon Attack + */
595 	if (app_data.crc == 0x9884EF36) setvideomode(0);		/* Demon Attack + modified */
596 	if (app_data.crc == 0x4A578DFE) setvideomode(0);		/* Restaurant ntsc */
597 	if (app_data.crc == 0x863D5E2D) setvideomode(0);		/* Shark Hunter ntsc */
598 
599 	if (app_data.crc == 0xD62814A3) evblclk=12000;			/* Pick Axe Pete */
600 	if (app_data.crc == 0xB2FFB353) evblclk=12000;			/* Pick Axe Pete + */
601 	if (app_data.crc == 0x81C20196) evblclk=12000;			/* Pick Axe Pete + (modified) */
602 
603 	if ((app_data.crc == 0xF390BFEC) || (app_data.crc == 0x825976A9) || (app_data.crc ==  0x61A350E6)){	/* Mousing Cat */
604 		setvideomode(1);
605 		evblclk=7642;
606 	}
607 
608 	if (app_data.crc == 0xD0BC4EE6) {					    /* Frogger */
609 		setvideomode(1);
610 		evblclk=7642;
611 
612 	}
613     if (app_data.crc == 0x26517E77) {						/* Commando Noturno */
614 		setvideomode(1);
615 		evblclk=6100;
616 		regionoff=12;
617 	}
618     if (app_data.crc == 0xA57E1724) {						/* Catch the ball*/
619 		regionoff=5;
620 		sproff=1;
621 
622     }
623 
624     if ((app_data.crc == 0x2DCB77F0) || (app_data.crc == 0xF6882734)) {	/* Depth Charge / Marksman */
625 		setvideomode(1);
626 		evblclk=8000;
627 	}
628 	if (app_data.crc == 0x881CEAE4) {						/* Wall Street */
629 		setvideomode(1);
630 		evblclk=6100;
631 	}
632 	if (app_data.crc == 0xD0BC4EE6) tweakedaudio=1;			/* Frogger */
633 	if (app_data.crc == 0xA57D84F3) tweakedaudio=1;			/* Frogger BR */
634 	if (app_data.crc == 0x5216771A) tweakedaudio=1;			/* Popeye */
635 	if (app_data.crc == 0xAFB23F89) tweakedaudio=1;			/* Musician */
636 	if (app_data.crc == 0xC4134DF8) tweakedaudio=1;			/* Helicopter Rescue + */
637 	if (app_data.crc == 0x0D2D721D) tweakedaudio=1;			/* Trans American Rally + */
638 
639 	if (app_data.crc == 0xD3B09FEC) sproff=1;				/* Volleyball! */
640 	if (app_data.crc == 0x551E38A2) sproff=1;				/* Volleyball! (french) */
641 
642 }
643 
644 
snapline(int pos,Byte reg,int t)645 int snapline(int pos, Byte reg, int t){
646 	int i;
647 	if (pos<MAXLINES+MAXSNAP+MAXSNAP) {
648 		for (i=0; i<mxsnap; i++){
649 			if (snapedlines[pos+MAXSNAP-i][reg][t]) return pos-i;
650 			if (snapedlines[pos+MAXSNAP+i][reg][t]) return pos+i;
651 		}
652 		snapedlines[pos+MAXSNAP][reg][t]=1;
653 	}
654 	return pos;
655 }
656 
657 
setvideomode(int t)658 static void setvideomode(int t){
659 	if (t) {
660 		evblclk = EVBLCLK_PAL;
661 		fps = FPS_PAL;
662 	} else {
663 		evblclk = EVBLCLK_NTSC;
664 		fps = FPS_NTSC;
665 	}
666 }
667