]> git.sesse.net Git - pistorm/blob - config_file/config_file.c
Map some ROMs directly to Musashi as well?
[pistorm] / config_file / config_file.c
1 #include "../platforms/platforms.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #define M68K_CPU_TYPES M68K_CPU_TYPE_SCC68070
7
8 const char *cpu_types[M68K_CPU_TYPES] = {
9   "68000",
10   "68010",
11   "68EC020",
12   "68020",
13   "68EC030",
14   "68030",
15   "68EC040",
16   "68LC040",
17   "68040",
18   "SCC68070",
19 };
20
21 const char *map_type_names[MAPTYPE_NUM] = {
22   "NONE",
23   "rom",
24   "ram",
25   "register",
26 };
27
28 const char *config_item_names[CONFITEM_NUM] = {
29   "NONE",
30   "cpu",
31   "map",
32   "loopcycles",
33   "mouse",
34   "keyboard",
35   "platform",
36   "setvar",
37 };
38
39 const char *mapcmd_names[MAPCMD_NUM] = {
40   "NONE",
41   "type",
42   "address",
43   "size",
44   "range",
45   "file",
46   "ovl",
47   "id",
48 };
49
50 int get_config_item_type(char *cmd) {
51   for (int i = 0; i < CONFITEM_NUM; i++) {
52     if (strcmp(cmd, config_item_names[i]) == 0) {
53       return i;
54     }
55   }
56
57   return CONFITEM_NONE;
58 }
59
60 unsigned int get_m68k_cpu_type(char *name) {
61   for (int i = 0; i < M68K_CPU_TYPES; i++) {
62     if (strcmp(name, cpu_types[i]) == 0) {
63       printf("Set CPU type to %s.\n", cpu_types[i]);
64       return i + 1;
65     }
66   }
67
68   printf ("Invalid CPU type %s specified, defaulting to 68000.\n", name);
69   return M68K_CPU_TYPE_68000;
70 }
71
72 unsigned int get_map_cmd(char *name) {
73   for (int i = 1; i < MAPCMD_NUM; i++) {
74     if (strcmp(name, mapcmd_names[i]) == 0) {
75       return i;
76     }
77   }
78
79   return MAPCMD_UNKNOWN;
80 }
81
82 unsigned int get_map_type(char *name) {
83   for (int i = 1; i < MAPTYPE_NUM; i++) {
84     if (strcmp(name, map_type_names[i]) == 0) {
85       return i;
86     }
87   }
88
89   return MAPTYPE_NONE;
90 }
91
92 void trim_whitespace(char *str) {
93   while (strlen(str) != 0 && (str[strlen(str) - 1] == ' ' || str[strlen(str) - 1] == '\t' || str[strlen(str) - 1] == 0x0A || str[strlen(str) - 1] == 0x0D)) {
94     str[strlen(str) - 1] = '\0';
95   }
96 }
97
98 unsigned int get_int(char *str) {
99   if (strlen(str) == 0)
100     return -1;
101
102   int ret_int = 0;
103
104   if (strlen(str) > 2 && str[0] == '0' && str[1] == 'x') {
105     for (int i = 2; i < (int)strlen(str); i++) {
106       if (str[i] >= '0' && str[i] <= '9') {
107         ret_int = (str[i] - '0') | (ret_int << 4);
108       }
109       else {
110         switch(str[i]) {
111           case 'A': ret_int = 0xA | (ret_int << 4); break;
112           case 'B': ret_int = 0xB | (ret_int << 4); break;
113           case 'C': ret_int = 0xC | (ret_int << 4); break;
114           case 'D': ret_int = 0xD | (ret_int << 4); break;
115           case 'E': ret_int = 0xE | (ret_int << 4); break;
116           case 'F': ret_int = 0xF | (ret_int << 4); break;
117           case 'K': ret_int = ret_int * SIZE_KILO; break;
118           case 'M': ret_int = ret_int * SIZE_MEGA; break;
119           case 'G': ret_int = ret_int * SIZE_GIGA; break;
120           default:
121             printf("Unknown character %c in hex value.\n", str[i]);
122             break;
123         }
124       }
125     }
126     return ret_int;
127   }
128   else {
129     ret_int = atoi(str);
130     if (str[strlen(str) - 1] == 'K')
131       ret_int = ret_int * SIZE_KILO;
132     else if (str[strlen(str) - 1] == 'M')
133       ret_int = ret_int * SIZE_MEGA;
134     else if (str[strlen(str) - 1] == 'G')
135       ret_int = ret_int * SIZE_GIGA;
136
137     return ret_int;
138   }
139 }
140
141 void get_next_string(char *str, char *str_out, int *strpos, char separator) {
142   int str_pos = 0, out_pos = 0;
143
144   if (!str_out)
145     return;
146
147   if (strpos)
148     str_pos = *strpos;
149
150   while (str[str_pos] == ' ' && str[str_pos] == '\t' && str_pos < (int)strlen(str)) {
151     str_pos++;
152   }
153
154   for (int i = str_pos; i < (int)strlen(str); i++) {
155     str_out[out_pos] = str[i];
156     if ((separator == ' ' && (str[i] == ' ' || str[i] == '\t')) || str[i] == separator) {
157       str_out[out_pos] = '\0';
158       if (strpos) {
159         *strpos = i + 1;
160       }
161       break;
162     }
163     out_pos++;
164     if (i + 1 == (int)strlen(str) && strpos) {
165       *strpos = i + 1;
166       str_out[out_pos] = '\0';
167     }
168   }
169 }
170
171 void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int addr, unsigned int size, int mirr_addr, char *filename, char *map_id) {
172   unsigned int index = 0, file_size = 0;
173   FILE *in = NULL;
174
175   while (index < MAX_NUM_MAPPED_ITEMS) {
176     if (cfg->map_type[index] == MAPTYPE_NONE)
177       break;
178     index++;
179   }
180   if (index == MAX_NUM_MAPPED_ITEMS) {
181     printf("Unable to map item, only %d items can be mapped with current binary.\n", MAX_NUM_MAPPED_ITEMS);
182     return;
183   }
184
185   cfg->map_type[index] = type;
186   cfg->map_offset[index] = addr;
187   cfg->map_size[index] = size;
188   cfg->map_high[index] = addr + size;
189   cfg->map_mirror[index] = mirr_addr;
190   if (strlen(map_id)) {
191     cfg->map_id[index] = (char *)malloc(strlen(map_id) + 1);
192     strcpy(cfg->map_id[index], map_id);
193   }
194
195   switch(type) {
196     case MAPTYPE_RAM:
197       printf("Allocating %d bytes for RAM mapping (%d MB)...\n", size, size / 1024 / 1024);
198       cfg->map_data[index] = (unsigned char *)malloc(size);
199       if (!cfg->map_data[index]) {
200         printf("ERROR: Unable to allocate memory for mapped RAM!\n");
201         goto mapping_failed;
202       }
203       memset(cfg->map_data[index], 0x00, size);
204       break;
205     case MAPTYPE_ROM:
206       in = fopen(filename, "rb");
207       if (!in) {
208         printf("Failed to open file %s for ROM mapping.\n", filename);
209         goto mapping_failed;
210       }
211       fseek(in, 0, SEEK_END);
212       file_size = (int)ftell(in);
213       if (size == 0) {
214         cfg->map_size[index] = file_size;
215       }
216       fseek(in, 0, SEEK_SET);
217       cfg->map_data[index] = (unsigned char *)calloc(1, cfg->map_size[index]);
218       cfg->rom_size[index] = (cfg->map_size[index] <= file_size) ? cfg->map_size[index] : file_size;
219       if (!cfg->map_data[index]) {
220         printf("ERROR: Unable to allocate memory for mapped ROM!\n");
221         goto mapping_failed;
222       }
223       memset(cfg->map_data[index], 0x00, cfg->map_size[index]);
224       fread(cfg->map_data[index], cfg->rom_size[index], 1, in);
225       fclose(in);
226       break;
227     case MAPTYPE_REGISTER:
228     default:
229       break;
230       break;
231   }
232
233   printf("[MAP %d] Added %s mapping for range %.8lX-%.8lX ID: %s\n", index, map_type_names[type], cfg->map_offset[index], cfg->map_offset[index] + cfg->map_size[index] - 1, cfg->map_id[index] ? cfg->map_id[index] : "None");
234   if (cfg->map_size[index] == cfg->rom_size[index])
235     m68k_add_rom_range(cfg->map_offset[index], cfg->map_high[index], cfg->map_data[index]);
236
237   return;
238
239   mapping_failed:;
240   cfg->map_type[index] = MAPTYPE_NONE;
241   if (in)
242     fclose(in);
243 }
244
245 struct emulator_config *load_config_file(char *filename) {
246   FILE *in = fopen(filename, "rb");
247   if (in == NULL) {
248     printf("Failed to open config file %s for reading.\n", filename);
249     return NULL;
250   }
251
252   char *parse_line = NULL;
253   char cur_cmd[128];
254   struct emulator_config *cfg = NULL;
255   int cur_line = 1;
256
257   parse_line = (char *)calloc(1, 512);
258   if (!parse_line) {
259     printf("Failed to allocate memory for config file line buffer.\n");
260     return NULL;
261   }
262   cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
263   if (!cfg) {
264     printf("Failed to allocate memory for temporary emulator config.\n");
265     goto load_failed;
266   }
267
268   memset(cfg, 0x00, sizeof(struct emulator_config));
269   cfg->cpu_type = M68K_CPU_TYPE_68000;
270
271   while (!feof(in)) {
272     int str_pos = 0;
273     memset(parse_line, 0x00, 512);
274     fgets(parse_line, 512, in);
275
276     if (strlen(parse_line) <= 2 || parse_line[0] == '#' || parse_line[0] == '/')
277       goto skip_line;
278
279     trim_whitespace(parse_line);
280     
281     get_next_string(parse_line, cur_cmd, &str_pos, ' ');
282
283     switch (get_config_item_type(cur_cmd)) {
284       case CONFITEM_CPUTYPE:
285         cfg->cpu_type = get_m68k_cpu_type(parse_line + str_pos);
286         break;
287       case CONFITEM_MAP: {
288         unsigned int maptype = 0, mapsize = 0, mapaddr = 0;
289         int mirraddr = -1;
290         char mapfile[128], mapid[128];
291         memset(mapfile, 0x00, 128);
292         memset(mapid, 0x00, 128);
293
294         while (str_pos < (int)strlen(parse_line)) {
295           get_next_string(parse_line, cur_cmd, &str_pos, '=');
296           switch(get_map_cmd(cur_cmd)) {
297             case MAPCMD_TYPE:
298               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
299               maptype = get_map_type(cur_cmd);
300               //printf("Type! %s\n", map_type_names[maptype]);
301               break;
302             case MAPCMD_ADDRESS:
303               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
304               mapaddr = get_int(cur_cmd);
305               //printf("Address! %.8X\n", mapaddr);
306               break;
307             case MAPCMD_SIZE:
308               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
309               mapsize = get_int(cur_cmd);
310               //printf("Size! %.8X\n", mapsize);
311               break;
312             case MAPCMD_RANGE:
313               get_next_string(parse_line, cur_cmd, &str_pos, '-');
314               mapaddr = get_int(cur_cmd);
315               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
316               mapsize = get_int(cur_cmd) - 1 - mapaddr;
317               //printf("Range! %d-%d\n", mapaddr, mapaddr + mapsize);
318               break;
319             case MAPCMD_FILENAME:
320               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
321               strcpy(mapfile, cur_cmd);
322               //printf("File! %s\n", mapfile);
323               break;
324             case MAPCMD_MAP_ID:
325               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
326               strcpy(mapid, cur_cmd);
327               //printf("File! %s\n", mapfile);
328               break;
329             case MAPCMD_OVL_REMAP:
330               get_next_string(parse_line, cur_cmd, &str_pos, ' ');
331               mirraddr = get_int(cur_cmd);
332               break;
333             default:
334               printf("Unknown/unhandled map argument %s on line %d.\n", cur_cmd, cur_line);
335               break;
336           }
337         }
338         add_mapping(cfg, maptype, mapaddr, mapsize, mirraddr, mapfile, mapid);
339
340         break;
341       }
342       case CONFITEM_LOOPCYCLES:
343         cfg->loop_cycles = get_int(parse_line + str_pos);
344         printf("Set CPU loop cycles to %d.\n", cfg->loop_cycles);
345         break;
346       case CONFITEM_MOUSE:
347         get_next_string(parse_line, cur_cmd, &str_pos, ' ');
348         cfg->mouse_file = (char *)calloc(1, strlen(cur_cmd) + 1);
349         strcpy(cfg->mouse_file, cur_cmd);
350         get_next_string(parse_line, cur_cmd, &str_pos, ' ');
351         cfg->mouse_toggle_key = cur_cmd[0];
352         cfg->mouse_enabled = 1;
353         printf("Enabled mouse event forwarding from file %s, toggle key %c.\n", cfg->mouse_file, cfg->mouse_toggle_key);
354         break;
355       case CONFITEM_KEYBOARD:
356         get_next_string(parse_line, cur_cmd, &str_pos, ' ');
357         cfg->keyboard_toggle_key = cur_cmd[0];
358         printf("Enabled keyboard event forwarding, toggle key %c.\n", cfg->keyboard_toggle_key);
359         break;
360       case CONFITEM_PLATFORM: {
361         char platform_name[128], platform_sub[128];
362         memset(platform_name, 0x00, 128);
363         memset(platform_sub, 0x00, 128);
364         get_next_string(parse_line, platform_name, &str_pos, ' ');
365         printf("Setting platform to %s", platform_name);
366         get_next_string(parse_line, platform_sub, &str_pos, ' ');
367         if (strlen(platform_sub))
368           printf(" (sub: %s)", platform_sub);
369         printf("\n");
370         cfg->platform = make_platform_config(platform_name, platform_sub);
371         break;
372       }
373       case CONFITEM_SETVAR: {
374         if (!cfg->platform) {
375           printf("Warning: esetvar used in config file with no platform specified.\n");
376           break;
377         }
378
379         char var_name[128], var_value[128];
380         memset(var_name, 0x00, 128);
381         memset(var_value, 0x00, 128);
382         get_next_string(parse_line, var_name, &str_pos, ' ');
383         get_next_string(parse_line, var_value, &str_pos, ' ');
384         cfg->platform->setvar(var_name, var_value);
385
386         break;
387       }
388       case CONFITEM_NONE:
389       default:
390         printf("Unknown config item %s on line %d.\n", cur_cmd, cur_line);
391         break;
392     }
393     
394     skip_line:;
395     cur_line++;
396   }
397   goto load_successful;
398
399   load_failed:;
400   if (cfg) {
401     for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
402       if (cfg->map_data[i])
403         free(cfg->map_data[i]);
404       cfg->map_data[i] = NULL;
405     }
406     free(cfg);
407     cfg = NULL;
408   }
409   load_successful:;
410   if (parse_line)
411     free(parse_line);
412
413   return cfg;
414 }
415
416 int get_named_mapped_item(struct emulator_config *cfg, char *name) {
417   if (strlen(name) == 0)
418     return -1;
419
420   for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
421     if (cfg->map_type[i] == MAPTYPE_NONE || !cfg->map_id[i])
422       continue;
423     if (strcmp(name, cfg->map_id[i]) == 0)
424       return i;
425   }
426
427   return -1;
428 }