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