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