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