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