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
15 #include <dirent.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <time.h>
21 #include "crc32.h"
22 #include "audio.h"
23 #include "vmachine.h"
24 #include "config.h"
25 #include "vdc.h"
26 #include "cpu.h"
27 #include "debug.h"
28 #include "keyboard.h"
29 #include "voice.h"
30 #include "allegro.h"
31 #ifdef ALLEGRO_WINDOWS
32 #include "winalleg.h"
33 #endif
34
35
36 #define MAXC 1024
37
38
39 static char bios[MAXC], scshot[MAXC], xrom[MAXC], xbios[MAXC], arkivo[MAXC][MAXC], biossux[MAXC],
40 romssux[MAXC], odyssey2[MAXC], g7400[MAXC], c52[MAXC], jopac[MAXC];
41 char name_f, rom_f;
42 char pathx;
43 int file_name(char *pathx);
44 int suck_bios();
45 int suck_roms();
46 int contax;
47 unsigned long crcx = ~0;
48
49
50 static long filesize(FILE *stream);
51 static void load_bios(const char *biosname);
52 static void load_cart(char *file);
53 int parse_option(char *attr, char *val);
54 void read_default_config(void);
55
56
main(int argc,char * argv[])57 int main(int argc, char *argv[]){
58 int i;
59 static char file[MAXC], attr[MAXC], val[MAXC], *p, *binver;
60
61 #if defined(ALLEGRO_WINDOWS)
62 binver = "Windows binary";
63 #elif defined(ALLEGRO_DOS)
64 binver = "DOS binary";
65 #elif defined(ALLEGRO_LINUX)
66 binver = "Linux binary";
67 #elif defined(ALLEGRO_BEOS)
68 binver = "BEOS binary";
69 #elif defined(ALLEGRO_QNX)
70 binver = "QNX binary";
71 #elif defined(ALLEGRO_UNIX)
72 binver = "UNIX binary";
73 #elif defined(ALLEGRO_MPW)
74 binver = "MacOS binary";
75 #else
76 binver = "Unknown binary";
77 #endif
78
79 printf("%s %s\n","\nO2EM v" O2EM_VERSION " " RELEASE_DATE " - ", binver);
80 printf("Free Odyssey2 / Videopac+ Emulator - http://o2em.sourceforge.net\n");
81 printf("Developed by Andre de la Rocha and Arlindo M. de Oliveira\n");
82 printf("Created by Daniel Boris (c)1996/1998\n");
83 printf("\n");
84
85 if (argc < 2) {
86 printf("Use: o2em <file> [options]\n");
87 printf("<file> = file to load\n");
88 #ifndef ALLEGRO_DOS
89 printf("-wsize=n Window size (1-4)\n");
90 printf("-fullscreen Full screen mode\n");
91 #endif
92 printf("-scanlines Enable scanlines\n");
93 printf("-nosound Turn off sound emulation\n");
94 printf("-novoice Turn off voice emulation\n");
95 printf("-svolume=n Set sound volume (0-100)\n");
96 printf("-vvolume=n Set voice volume (0-100)\n");
97 printf("-filter Enable low-pass audio filter\n");
98 printf("-debug Start the emulator in debug mode\n");
99 printf("-speed=n Relative speed (100 = original)\n");
100 printf("-nolimit Turn off speed limiter\n");
101 printf("-bios=file Set the O2 bios file name/dir (default=o2rom.bin)\n");
102 printf("-scshot=file Set the screenshot file name/template\n");
103 printf("-euro Use European timing / 50Hz mode\n");
104 printf("-exrom Use special 3K program/1K data ROM mode\n");
105 printf("-3k Use 3K rom mapping mode\n");
106 printf("-s<n>=mode/keys Define stick n mode/keys (n=1-2)\n");
107 printf("-c52 Start the emulator with french Odyssey 2 BIOS\n");
108 printf("-g7400 Start the emulator with VP+ BIOS\n");
109 printf("-jopac Start the emulator with french VP+ bios\n");
110
111 printf("\nPress Enter...");
112 fflush(stdout);
113 getchar();
114 exit(EXIT_SUCCESS);
115 }
116
117 app_data.debug = 0;
118 app_data.stick[0] = app_data.stick[1] = 1;
119 set_defjoykeys(0,0);
120 set_defjoykeys(1,1);
121 app_data.bank = 0;
122 app_data.limit = 1;
123 app_data.sound_en = 1;
124 app_data.speed = 100;
125 app_data.wsize = 2;
126 #ifdef ALLEGRO_DOS
127 app_data.fullscreen = 1;
128 #else
129 app_data.fullscreen = 0;
130 #endif
131 app_data.scanlines = 0;
132 app_data.voice = 1;
133 app_data.window_title = "O2EM v" O2EM_VERSION;
134 app_data.svolume = 100;
135 app_data.vvolume = 100;
136 app_data.filter = 0;
137 app_data.exrom = 0;
138 app_data.three_k = 0;
139 app_data.crc = 0;
140 app_data.scshot = scshot;
141 app_data.euro = 0;
142 app_data.openb = 0;
143 app_data.vpp = 0;
144
145 strcpy(file,"");
146 strcpy(bios,"");
147 strcpy(scshot,"");
148 strcpy(xrom,"");
149 read_default_config();
150
151 for(i=1; i<argc; i++) {
152 if (argv[i][0] != '-') {
153 strncat(file,argv[i],MAXC-1);
154 file[MAXC-1]=0;
155 } else {
156 p=strtok(argv[i],"=");
157 if (p){
158 strncpy(attr,p+1,MAXC-1);
159 attr[MAXC-1]=0;
160 } else
161 strcpy(attr,"");
162 p=strtok(NULL,"=");
163 if (p){
164 strncpy(val,p,MAXC-1);
165 val[MAXC-1]=0;
166 } else
167 strcpy(val,"");
168 strlwr(attr);
169
170 if (!parse_option(attr, val)) exit(EXIT_FAILURE);
171
172 }
173
174 }
175
176 if (strlen(file)==0) {
177 fprintf(stderr,"Error: file name missing\n");
178 exit(EXIT_FAILURE);
179 }
180
181 printf("Starting emulation ...\n");
182
183 allegro_init();
184 install_timer();
185 init_audio();
186 printf("Using Allegro %s\n",allegro_id);
187
188 app_data.crc = crc32_file(file);
189 crcx = app_data.crc;
190
191 strcpy (xbios, PREFIX);
192 strcat (xbios, "/o2em/bios/");
193 file_name(xbios);
194 suck_bios();
195
196 if (contax < 3)
197 {
198 printf("\nBIOS directory empty!\n");
199 exit(EXIT_FAILURE);
200 }
201
202
203 if ((rom_f!=1)&& (strcmp(bios,"jopac"))) strcpy(bios,g7400);
204
205 if (!strcmp(bios,"g7400")) strcpy(bios,g7400);
206 if (!strcmp(bios,"c52")) strcpy(bios,c52);
207 if (!strcmp(bios,"jopac")) strcpy(bios,jopac);
208 if ((!strcmp(bios,"")) || (!strcmp(bios,"o2rom"))){
209 strcpy(bios, PREFIX);
210 strcat(bios,"/o2em/bios/o2rom.bin");
211 }
212
213
214
215 load_bios(bios);
216 load_cart(file);
217
218 if (app_data.voice) load_voice_samples();
219
220 init_display();
221 init_cpu();
222 init_system();
223 if (app_data.debug) key_debug=1;
224 #ifndef _DEBUG
225 #ifdef ALLEGRO_WINDOWS
226 FreeConsole();
227 #endif
228 #endif
229 run();
230 exit(EXIT_SUCCESS);
231 }
232
233 END_OF_MAIN();
234
235
parse_option(char * attr,char * val)236 int parse_option(char *attr, char *val){
237 int t;
238
239 if (!strcmp(attr,"nolimit")) {
240 app_data.limit = !(val[0]!='0');
241 } else if (!strcmp(attr,"nosound")) {
242 app_data.sound_en = !(val[0]!='0');
243 } else if (!strcmp(attr,"novoice")) {
244 app_data.voice = !(val[0]!='0');
245 } else if (!strcmp(attr,"filter")) {
246 app_data.filter = (val[0]!='0');
247 } else if (!strcmp(attr,"debug")) {
248 app_data.debug = (val[0]!='0');
249 } else if ((!strcmp(attr,"s1")) || (!strcmp(attr,"s2"))) {
250 int sn;
251 sn = (!strcmp(attr,"s1"))? 0 : 1;
252 if (strlen(val)<2){
253 t = -1;
254 sscanf(val,"%d",&t);
255 if ((t>=0) && (t<=3)) {
256 if ((t==1)||(t==2)){
257 app_data.stick[sn] = 1;
258 set_defjoykeys(sn,t-1);
259 } else {
260 app_data.stick[sn] = (t==0) ? 0 : 2;
261 set_joykeys(sn,0,0,0,0,0);
262 }
263 } else {
264 fprintf(stderr,"Invalid value for option %s\n",attr);
265 return 0;
266 }
267 } else {
268 char *p,*s;
269 int i,k,code,nk,codes[5];
270 strupr(val);
271 nk = 0;
272 p = strtok(val,",");
273 while (p) {
274 i = code = 0;
275 k = keybtab[i].keybcode;
276 s = keybtab[i].keybname;
277 while (k && (code==0)) {
278 if (strcmp(s,p)==0) code = k;
279 i++;
280 k = keybtab[i].keybcode;
281 s = keybtab[i].keybname;
282 }
283 if (!code) {
284 fprintf(stderr,"Invalid value for option %s : key %s unknown\n",attr,p);
285 return 0;
286 }
287 codes[nk] = code;
288 p = strtok(NULL,",");
289 nk++;
290 if (nk>5) {
291 fprintf(stderr,"Invalid value for option %s : invalid number of keys\n",attr);
292 return 0;
293 }
294 }
295 if (nk != 5) {
296 fprintf(stderr,"Invalid value for option %s : invalid number of keys\n",attr);
297 return 0;
298 }
299 app_data.stick[sn] = 1;
300 set_joykeys(sn,codes[0],codes[1],codes[2],codes[3],codes[4]);
301 }
302 } else if (!strcmp(attr,"speed")) {
303 t = -1;
304 sscanf(val,"%d",&t);
305 if ((t>0) && (t<=10000))
306 app_data.speed = t;
307 else {
308 fprintf(stderr,"Invalid value for option %s\n",attr);
309 return 0;
310 }
311 } else if (!strcmp(attr,"svolume")) {
312 t = -1;
313 sscanf(val,"%d",&t);
314 if ((t>=0) && (t<=100))
315 app_data.svolume = t;
316 else {
317 fprintf(stderr,"Invalid value for option %s\n",attr);
318 return 0;
319 }
320 if (t==0) app_data.sound_en=0;
321 } else if (!strcmp(attr,"vvolume")) {
322 t = -1;
323 sscanf(val,"%d",&t);
324 if ((t>=0) && (t<=100))
325 app_data.vvolume = t;
326 else {
327 fprintf(stderr,"Invalid value for option %s\n",attr);
328 return 0;
329 }
330 if (t==0) app_data.voice=0;
331 } else if (!strcmp(attr,"wsize")) {
332 t = -1;
333 sscanf(val,"%d",&t);
334 if ((t>0) && (t<5)) {
335 app_data.wsize = t;
336 app_data.fullscreen = 0;
337 } else {
338 fprintf(stderr,"Invalid value for option %s\n",attr);
339 return 0;
340 }
341 } else if (!strcmp(attr,"fullscreen")) {
342 app_data.fullscreen = (val[0]!='0');
343 } else if (!strcmp(attr,"scanlines")) {
344 app_data.scanlines = (val[0]!='0');
345 } else if (!strcmp(attr,"scshot")) {
346 strcpy(scshot,val);
347 } else if (!strcmp(attr,"euro")) {
348 app_data.euro = (val[0]!='0');
349 } else if (!strcmp(attr,"exrom")) {
350 app_data.exrom = (val[0]!='0');
351 } else if (!strcmp(attr,"3k")) {
352 app_data.three_k = (val[0]!='0');
353 } else if (!strcmp(attr,"g7400")){
354 strcpy(bios,"g7400");
355 }else if (!strcmp(attr,"c52")) {
356 strcpy(bios,"c52");
357 }else if (!strcmp(attr,"jopac")) {
358 strcpy(bios,"jopac");
359 }else if (!strcmp(attr,"o2rom")) {
360 strcpy(bios,"o2rom");
361 } else if (!strcmp(attr,"bios")) {
362 strcpy(bios,val);
363 } else {
364 fprintf(stderr,"Invalid option : %s\n",attr);
365 return 0;
366 }
367 return 1;
368 }
369
370
read_default_config(void)371 void read_default_config(void){
372 FILE *f;
373 static char attr[MAXC], val[MAXC], s[MAXC];
374 char *p, *fn;
375 int i,l;
376
377 fn = "o2em_def.cfg";
378 f = fopen(fn,"r");
379 if (!f) {
380 fn = "O2EM_DEF.CFG";
381 f = fopen(fn,"r");
382 }
383 if (!f) return;
384
385 l=0;
386 while (fgets(s,MAXC-1,f)){
387 l++;
388 p=s;
389 while (*p && (isspace(*p))) p++;
390 if (*p && (*p != '#')) {
391 i=0;
392 while (*p && (!isspace(*p)) && (*p != '=')) attr[i++] = *p++;
393 attr[i]=0;
394 while (*p && (isspace(*p))) p++;
395 i=0;
396 if (*p == '='){
397 p++;
398 while (*p && (isspace(*p))) p++;
399 if (*p == '"'){
400 p++;
401 while (*p && (*p != '"') && (*p != '\n') && (*p != '\r')) val[i++] = *p++;
402 } else {
403 while (*p && (!isspace(*p))) val[i++] = *p++;
404 }
405 }
406 val[i]=0;
407 if (strlen(attr)>0) {
408 strlwr(attr);
409 if (!parse_option(attr,val)) {
410 printf("Error in the %s file at line number %d !\n\n",fn,l);
411 }
412 }
413 }
414 }
415 fclose(f);
416 }
417
418
filesize(FILE * stream)419 static long filesize(FILE *stream){
420 long curpos, length;
421
422 curpos = ftell(stream);
423 fseek(stream, 0L, SEEK_END);
424 length = ftell(stream);
425 fseek(stream, curpos, SEEK_SET);
426 return length;
427 }
428
429 /****************************************************************/
430
load_bios(const char * biosname)431 static void load_bios(const char *biosname){
432 FILE *fn;
433 static char s[MAXC+10];
434 unsigned long crc;
435 int i;
436
437 if (!strcmp(biosname,"g7400"))
438 {
439 if ((!biosname) || (strlen(biosname)==0)) {
440 strcpy(s,"o2rom.bin");
441 fn = fopen("o2rom.bin","rb");
442 if (!fn) fn = fopen("O2ROM.BIN","rb");
443 } else if ((biosname[strlen(biosname)-1]=='/') || (biosname[strlen(biosname)-1]=='\\') || (biosname[strlen(biosname)-1]==':')) {
444 strcpy(s,biosname);
445 strcat(s,"O2ROM.BIN");
446 fn = fopen(s,"rb");
447 if (!fn) {
448 strcpy(s,biosname);
449 strcat(s,"o2rom.bin");
450 fn = fopen(s,"rb");
451 }
452 } else {
453 strcpy(s,biosname);
454 fn = fopen(biosname,"rb");
455 }
456
457 if (!fn) {
458 fprintf(stderr,"Error loading bios ROM (%s)\n",s);
459 exit(EXIT_FAILURE);
460 }
461
462 if (fread(rom_table[0],1024,1,fn) != 1) {
463 fprintf(stderr,"Error loading bios ROM o2rom.bin\n");
464 exit(EXIT_FAILURE);
465 }
466 }
467 strcpy(s,biosname);
468 fn = fopen(biosname,"rb");
469
470 if (!fn) {
471 fprintf(stderr,"Error loading bios ROM (%s)\n",s);
472 exit(EXIT_FAILURE);
473 }
474
475 if (fread(rom_table[0],1024,1,fn) != 1) {
476 fprintf(stderr,"Error loading bios ROM o2rom.bin\n");
477 exit(EXIT_FAILURE);
478 }
479
480 fclose(fn);
481
482 for (i=1; i<8; i++) memcpy(rom_table[i],rom_table[0],1024);
483
484 crc = crc32_buf(rom_table[0],1024);
485
486 if (crc==0x8016A315) {
487 printf("Odyssey2 bios ROM loaded\n");
488 app_data.vpp = 0;
489 } else if (crc==0xE20A9F41) {
490 printf("Videopac+ G7400 bios ROM loaded\n");
491 app_data.vpp = 1;
492 } else if (crc==0xA318E8D6) {
493 printf("C52 bios ROM loaded\n");
494 app_data.vpp = 0;
495 } else if (crc==0x11647CA5) {
496 printf("Jopac bios ROM loaded\n");
497 app_data.vpp = 1;
498 } else {
499 printf("Bios ROM loaded (unknown version)\n");
500 app_data.vpp = 0;
501 }
502 }
503
504
load_cart(char * file)505 static void load_cart(char *file){
506 FILE *fn;
507 long l;
508 int i, nb;
509
510 app_data.crc = crc32_file(file);
511
512 if (app_data.crc == 0xAFB23F89) app_data.exrom = 1; /* Musician */
513
514 if (app_data.crc == 0x3BFEF56B) app_data.exrom = 1; /* Four in 1 Row! */
515 if (app_data.crc == 0x9B5E9356) app_data.exrom = 1; /* Four in 1 Row! (french) */
516
517 if ((app_data.crc == 0x4E2CC6D3) || (app_data.crc == 0xBCF1EFC9)) app_data.three_k = 1; /* Kill the Attacking Aliens */
518
519 if (((app_data.crc == 0x975AB8DA) || (app_data.crc == 0xE246A812)) && (!app_data.debug)) {
520 fprintf(stderr,"Error: file %s is an incomplete ROM dump\n",file);
521 exit(EXIT_FAILURE);
522 }
523
524 fn=fopen(file,"rb");
525 if (!fn) {
526 fprintf(stderr,"Error loading %s\n",file);
527 exit(EXIT_FAILURE);
528 }
529 printf("Loading: \"%s\" Size: ",file);
530 l = filesize(fn);
531
532 if ((l % 1024) != 0) {
533 fprintf(stderr,"Error: file %s is an invalid ROM dump\n",file);
534 exit(EXIT_FAILURE);
535 }
536
537 if (((l % 3072) == 0) && app_data.three_k) {
538
539 nb = l/3072;
540
541 for (i=nb-1; i>=0; i--) {
542 if (fread(&rom_table[i][1024],3072,1,fn) != 1) {
543 fprintf(stderr,"Error loading %s\n",file);
544 exit(EXIT_FAILURE);
545 }
546 }
547 printf("%dK",nb*2);
548
549 } else {
550
551 nb = l/2048;
552
553 if ((nb == 2) && (app_data.exrom)) {
554
555 if (fread(&extROM[0], 1024,1,fn) != 1) {
556 fprintf(stderr,"Error loading %s\n",file);
557 exit(EXIT_FAILURE);
558 }
559 if (fread(&rom_table[0][1024],3072,1,fn) != 1) {
560 fprintf(stderr,"Error loading %s\n",file);
561 exit(EXIT_FAILURE);
562 }
563 printf("3K EXROM");
564
565 } else {
566
567 for (i=nb-1; i>=0; i--) {
568 if (fread(&rom_table[i][1024],2048,1,fn) != 1) {
569 fprintf(stderr,"Error loading %s\n",file);
570 exit(EXIT_FAILURE);
571 }
572 memcpy(&rom_table[i][3072],&rom_table[i][2048],1024); /* simulate missing A10 */
573 }
574 printf("%dK",nb*2);
575
576 }
577 }
578 fclose(fn);
579
580 rom = rom_table[0];
581
582 if (nb==1)
583 app_data.bank = 1;
584 else if (nb==2)
585 app_data.bank = app_data.exrom ? 1 : 2;
586 else if (nb==4)
587 app_data.bank = 3;
588 else
589 app_data.bank = 4;
590
591 if ((rom_table[nb-1][1024+12]=='O') && (rom_table[nb-1][1024+13]=='P') && (rom_table[nb-1][1024+14]=='N') && (rom_table[nb-1][1024+15]=='B')) app_data.openb=1;
592
593 printf(" CRC: %08lX\n",app_data.crc);
594
595 }
596
597 /************************************[Open the directory `pathx�]****/
598
file_name(char * pathx)599 int file_name(char *pathx)
600 {
601
602 DIR *dir_p;
603 struct dirent *dir_entry_p;
604 contax=0;
605
606 dir_p = opendir(pathx);
607
608 while(0 != (dir_entry_p = readdir(dir_p)))
609
610 {
611
612 strcpy(arkivo[contax], dir_entry_p->d_name);
613 contax++;
614 }
615
616 closedir(dir_p);
617 return(0);
618
619 }
620
suck_bios()621 int suck_bios()
622 {
623 int i;
624 for (i=0; i<contax; ++i)
625 {
626 strcpy(biossux, PREFIX);
627 strcat(biossux,"/o2em/bios/");
628 strcat(biossux,arkivo[i]);
629
630 app_data.crc = crc32_file(biossux);
631 if (app_data.crc == 0x8016A315) strcpy(odyssey2, biossux);
632 if (app_data.crc == 0xE20A9F41) strcpy(g7400, biossux);
633 if (app_data.crc == 0xA318E8D6) strcpy(c52, biossux);
634 if (app_data.crc == 0x11647CA5) strcpy(jopac, biossux);
635 }
636 return(0);
637
638 }
639
640
suck_roms()641 int suck_roms()
642 {
643 int i;
644 rom_f = 1;
645
646 for (i=0; i<contax; ++i)
647 {
648
649 strcpy(romssux,"roms/");
650 strcat(romssux,arkivo[i]);
651 app_data.crc = crc32_file(romssux);
652 if (app_data.crc == crcx)
653 {
654 if ((app_data.crc == 0xD7089068)||(app_data.crc == 0xB0A7D723)||
655 (app_data.crc == 0x0CA26992)||(app_data.crc == 0x0B6EB25B)||
656 (app_data.crc == 0x06861A9C)||(app_data.crc == 0xB2F0F0B4)||
657 (app_data.crc == 0x68560DC7)||(app_data.crc == 0x0D2D721D)||
658 (app_data.crc == 0xC4134DF8)||(app_data.crc == 0xA75C42F8))
659 rom_f = 0;
660 }
661
662 }
663 return(0);
664 }
665