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