1 // SPDX-License-Identifier: MIT
3 #include "platforms/platforms.h"
10 #define M68K_CPU_TYPES M68K_CPU_TYPE_SCC68070
12 const char *cpu_types[M68K_CPU_TYPES] = {
25 const char *map_type_names[MAPTYPE_NUM] = {
33 const char *config_item_names[CONFITEM_NUM] = {
45 const char *mapcmd_names[MAPCMD_NUM] = {
58 int get_config_item_type(char *cmd) {
59 for (int i = 0; i < CONFITEM_NUM; i++) {
60 if (strcmp(cmd, config_item_names[i]) == 0) {
68 unsigned int get_m68k_cpu_type(char *name) {
69 for (int i = 0; i < M68K_CPU_TYPES; i++) {
70 if (strcmp(name, cpu_types[i]) == 0) {
71 printf("[CFG] Set CPU type to %s.\n", cpu_types[i]);
76 printf("[CFG] Invalid CPU type %s specified, defaulting to 68000.\n", name);
77 return M68K_CPU_TYPE_68000;
80 unsigned int get_map_cmd(char *name) {
81 for (int i = 1; i < MAPCMD_NUM; i++) {
82 if (strcmp(name, mapcmd_names[i]) == 0) {
87 return MAPCMD_UNKNOWN;
90 unsigned int get_map_type(char *name) {
91 for (int i = 1; i < MAPTYPE_NUM; i++) {
92 if (strcmp(name, map_type_names[i]) == 0) {
100 void trim_whitespace(char *str) {
101 while (strlen(str) != 0 && (str[strlen(str) - 1] == ' ' || str[strlen(str) - 1] == '\t' || str[strlen(str) - 1] == 0x0A || str[strlen(str) - 1] == 0x0D)) {
102 str[strlen(str) - 1] = '\0';
106 unsigned int get_int(char *str) {
107 if (strlen(str) == 0)
112 if (strlen(str) > 2 && str[0] == '0' && str[1] == 'x') {
113 for (int i = 2; i < (int)strlen(str); i++) {
114 if (str[i] >= '0' && str[i] <= '9') {
115 ret_int = (str[i] - '0') | (ret_int << 4);
119 case 'A': ret_int = 0xA | (ret_int << 4); break;
120 case 'B': ret_int = 0xB | (ret_int << 4); break;
121 case 'C': ret_int = 0xC | (ret_int << 4); break;
122 case 'D': ret_int = 0xD | (ret_int << 4); break;
123 case 'E': ret_int = 0xE | (ret_int << 4); break;
124 case 'F': ret_int = 0xF | (ret_int << 4); break;
125 case 'K': ret_int = ret_int * SIZE_KILO; break;
126 case 'M': ret_int = ret_int * SIZE_MEGA; break;
127 case 'G': ret_int = ret_int * SIZE_GIGA; break;
129 printf("[CFG] Unknown character %c in hex value.\n", str[i]);
138 if (str[strlen(str) - 1] == 'K')
139 ret_int = ret_int * SIZE_KILO;
140 else if (str[strlen(str) - 1] == 'M')
141 ret_int = ret_int * SIZE_MEGA;
142 else if (str[strlen(str) - 1] == 'G')
143 ret_int = ret_int * SIZE_GIGA;
149 void get_next_string(char *str, char *str_out, int *strpos, char separator) {
150 int str_pos = 0, out_pos = 0, startquote = 0, endstring = 0;
158 while ((str[str_pos] == ' ' || str[str_pos] == '\t') && str_pos < (int)strlen(str)) {
162 if (str[str_pos] == '\"') {
168 for (int i = str_pos; i < (int)strlen(str); i++) {
169 str_out[out_pos] = str[i];
175 if ((separator == ' ' && (str[i] == ' ' || str[i] == '\t')) || str[i] == separator) {
181 str_out[out_pos] = '\0';
189 if (i + 1 == (int)strlen(str) && strpos) {
191 str_out[out_pos] = '\0';
196 void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int addr, unsigned int size, int mirr_addr, char *filename, char *map_id, unsigned int autodump) {
197 unsigned int index = 0, file_size = 0;
200 while (index < MAX_NUM_MAPPED_ITEMS) {
201 if (cfg->map_type[index] == MAPTYPE_NONE)
205 if (index == MAX_NUM_MAPPED_ITEMS) {
206 printf("[CFG] Unable to map item, only %d items can be mapped with current binary.\n", MAX_NUM_MAPPED_ITEMS);
210 cfg->map_type[index] = type;
211 cfg->map_offset[index] = addr;
212 cfg->map_size[index] = size;
213 cfg->map_high[index] = addr + size;
214 cfg->map_mirror[index] = mirr_addr;
215 if (strlen(map_id)) {
216 cfg->map_id[index] = (char *)malloc(strlen(map_id) + 1);
217 strcpy(cfg->map_id[index], map_id);
221 case MAPTYPE_RAM_NOALLOC:
222 printf("[CFG] Adding %d byte (%d MB) RAM mapping %s...\n", size, size / 1024 / 1024, map_id);
223 cfg->map_data[index] = (unsigned char *)filename;
226 printf("[CFG] Allocating %d bytes for RAM mapping (%d MB)...\n", size, size / 1024 / 1024);
227 cfg->map_data[index] = (unsigned char *)malloc(size);
228 if (!cfg->map_data[index]) {
229 printf("[CFG] ERROR: Unable to allocate memory for mapped RAM!\n");
232 memset(cfg->map_data[index], 0x00, size);
235 in = fopen(filename, "rb");
238 printf("[CFG] Failed to open file %s for ROM mapping. Using onboard ROM instead, if available.\n", filename);
240 } else if (autodump == MAPCMD_AUTODUMP_FILE) {
241 printf("[CFG] Could not open file %s for ROM mapping. Autodump flag is set, dumping to file.\n", filename);
242 dump_range_to_file(cfg->map_offset[index], cfg->map_size[index], filename);
243 in = fopen(filename, "rb");
245 printf("[CFG] Could not open dumped file for reading. Using onboard ROM instead, if available.\n");
248 } else if (autodump == MAPCMD_AUTODUMP_MEM) {
249 printf("[CFG] Could not open file %s for ROM mapping. Autodump flag is set, dumping to memory.\n", filename);
250 cfg->map_data[index] = dump_range_to_memory(cfg->map_offset[index], cfg->map_size[index]);
251 cfg->rom_size[index] = cfg->map_size[index];
252 if (cfg->map_data[index] == NULL) {
253 printf("[CFG] Could not dump range to memory. Using onboard ROM instead, if available.\n");
259 fseek(in, 0, SEEK_END);
260 file_size = (int)ftell(in);
262 cfg->map_size[index] = file_size;
263 cfg->map_high[index] = addr + cfg->map_size[index];
265 fseek(in, 0, SEEK_SET);
266 cfg->map_data[index] = (unsigned char *)calloc(1, cfg->map_size[index]);
267 cfg->rom_size[index] = (cfg->map_size[index] <= file_size) ? cfg->map_size[index] : file_size;
268 if (!cfg->map_data[index]) {
269 printf("[CFG] ERROR: Unable to allocate memory for mapped ROM!\n");
272 memset(cfg->map_data[index], 0x00, cfg->map_size[index]);
273 fread(cfg->map_data[index], cfg->rom_size[index], 1, in);
277 displayRomInfo(cfg->map_data[index], cfg->rom_size[index]);
278 if (cfg->map_size[index] == cfg->rom_size[index])
279 m68k_add_rom_range(cfg->map_offset[index], cfg->map_high[index], cfg->map_data[index]);
281 case MAPTYPE_REGISTER:
286 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");
291 cfg->map_type[index] = MAPTYPE_NONE;
296 void free_config_file(struct emulator_config *cfg) {
298 printf("[CFG] Tried to free NULL config, aborting.\n");
302 cfg->platform->shutdown(cfg);
304 cfg->platform = NULL;
307 for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
308 if (cfg->map_data[i]) {
309 if (cfg->map_type[i] != MAPTYPE_RAM_NOALLOC) {
310 free(cfg->map_data[i]);
312 cfg->map_data[i] = NULL;
314 if (cfg->map_id[i]) {
315 free(cfg->map_id[i]);
316 cfg->map_id[i] = NULL;
320 if (cfg->mouse_file) {
321 free(cfg->mouse_file);
322 cfg->mouse_file = NULL;
324 if (cfg->keyboard_file) {
325 free(cfg->keyboard_file);
326 cfg->keyboard_file = NULL;
331 printf("[CFG] Config file freed. Maybe.\n");
334 struct emulator_config *load_config_file(char *filename) {
335 FILE *in = fopen(filename, "rb");
337 printf("[CFG] Failed to open config file %s for reading.\n", filename);
341 char *parse_line = NULL;
343 struct emulator_config *cfg = NULL;
346 parse_line = (char *)calloc(1, 512);
348 printf("[CFG] Failed to allocate memory for config file line buffer.\n");
351 cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
353 printf("[CFG] Failed to allocate memory for temporary emulator config.\n");
357 memset(cfg, 0x00, sizeof(struct emulator_config));
358 cfg->cpu_type = M68K_CPU_TYPE_68000;
362 memset(parse_line, 0x00, 512);
363 fgets(parse_line, 512, in);
365 if (strlen(parse_line) <= 2 || parse_line[0] == '#' || parse_line[0] == '/')
368 trim_whitespace(parse_line);
370 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
372 switch (get_config_item_type(cur_cmd)) {
373 case CONFITEM_CPUTYPE:
374 cfg->cpu_type = get_m68k_cpu_type(parse_line + str_pos);
377 unsigned int maptype = 0, mapsize = 0, mapaddr = 0, autodump = 0;
378 unsigned int mirraddr = ((unsigned int)-1);
379 char mapfile[128], mapid[128];
380 memset(mapfile, 0x00, 128);
381 memset(mapid, 0x00, 128);
383 while (str_pos < (int)strlen(parse_line)) {
384 get_next_string(parse_line, cur_cmd, &str_pos, '=');
385 switch(get_map_cmd(cur_cmd)) {
387 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
388 maptype = get_map_type(cur_cmd);
389 //printf("Type! %s\n", map_type_names[maptype]);
392 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
393 mapaddr = get_int(cur_cmd);
394 //printf("Address! %.8X\n", mapaddr);
397 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
398 mapsize = get_int(cur_cmd);
399 //printf("Size! %.8X\n", mapsize);
402 get_next_string(parse_line, cur_cmd, &str_pos, '-');
403 mapaddr = get_int(cur_cmd);
404 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
405 mapsize = get_int(cur_cmd) - 1 - mapaddr;
406 //printf("Range! %d-%d\n", mapaddr, mapaddr + mapsize);
408 case MAPCMD_FILENAME:
409 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
410 strcpy(mapfile, cur_cmd);
411 //printf("File! %s\n", mapfile);
414 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
415 strcpy(mapid, cur_cmd);
416 //printf("File! %s\n", mapfile);
418 case MAPCMD_OVL_REMAP:
419 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
420 mirraddr = get_int(cur_cmd);
422 case MAPCMD_AUTODUMP_FILE:
423 case MAPCMD_AUTODUMP_MEM:
424 autodump = get_map_cmd(cur_cmd);
427 printf("[CFG] Unknown/unhandled map argument %s on line %d.\n", cur_cmd, cur_line);
431 add_mapping(cfg, maptype, mapaddr, mapsize, mirraddr, mapfile, mapid, autodump);
435 case CONFITEM_LOOPCYCLES:
436 cfg->loop_cycles = get_int(parse_line + str_pos);
437 printf("[CFG] Set CPU loop cycles to %d.\n", cfg->loop_cycles);
440 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
441 cfg->mouse_file = (char *)calloc(1, strlen(cur_cmd) + 1);
442 strcpy(cfg->mouse_file, cur_cmd);
443 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
444 cfg->mouse_toggle_key = cur_cmd[0];
445 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
446 cfg->mouse_autoconnect = (strcmp(cur_cmd, "autoconnect") == 0) ? 1 : 0;
447 cfg->mouse_enabled = 1;
448 printf("[CFG] Enabled mouse event forwarding from file %s, toggle key %c.\n", cfg->mouse_file, cfg->mouse_toggle_key);
450 case CONFITEM_KEYBOARD:
451 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
452 cfg->keyboard_toggle_key = cur_cmd[0];
453 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
454 cfg->keyboard_grab = (strcmp(cur_cmd, "grab") == 0) ? 1 : 0;
455 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
456 cfg->keyboard_autoconnect = (strcmp(cur_cmd, "autoconnect") == 0) ? 1 : 0;
457 printf("[CFG] Enabled keyboard event forwarding, toggle key %c", cfg->keyboard_toggle_key);
458 if (cfg->keyboard_grab)
459 printf(", locking from host when connected");
460 if (cfg->keyboard_autoconnect)
461 printf(", connected to guest at startup");
464 case CONFITEM_KBFILE:
465 get_next_string(parse_line, cur_cmd, &str_pos, ' ');
466 cfg->keyboard_file = (char *)calloc(1, strlen(cur_cmd) + 1);
467 strcpy(cfg->keyboard_file, cur_cmd);
468 printf("[CFG] Set keyboard event source file to %s.\n", cfg->keyboard_file);
470 case CONFITEM_PLATFORM: {
471 char platform_name[128], platform_sub[128];
472 memset(platform_name, 0x00, 128);
473 memset(platform_sub, 0x00, 128);
474 get_next_string(parse_line, platform_name, &str_pos, ' ');
475 printf("[CFG] Setting platform to %s", platform_name);
476 get_next_string(parse_line, platform_sub, &str_pos, ' ');
477 if (strlen(platform_sub))
478 printf(" (sub: %s)", platform_sub);
480 cfg->platform = make_platform_config(platform_name, platform_sub);
483 case CONFITEM_SETVAR: {
484 if (!cfg->platform) {
485 printf("[CFG] Warning: setvar used in config file with no platform specified.\n");
489 char var_name[128], var_value[128];
490 memset(var_name, 0x00, 128);
491 memset(var_value, 0x00, 128);
492 get_next_string(parse_line, var_name, &str_pos, ' ');
493 get_next_string(parse_line, var_value, &str_pos, ' ');
494 cfg->platform->setvar(cfg, var_name, var_value);
500 printf("[CFG] Unknown config item %s on line %d.\n", cur_cmd, cur_line);
507 goto load_successful;
511 for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
512 if (cfg->map_data[i])
513 free(cfg->map_data[i]);
514 cfg->map_data[i] = NULL;
526 int get_named_mapped_item(struct emulator_config *cfg, char *name) {
527 if (strlen(name) == 0)
530 for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
531 if (cfg->map_type[i] == MAPTYPE_NONE || !cfg->map_id[i])
533 if (strcmp(name, cfg->map_id[i]) == 0)
540 int get_mapped_item_by_address(struct emulator_config *cfg, uint32_t address) {
541 for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
542 if (cfg->map_type[i] == MAPTYPE_NONE || !cfg->map_data[i])
544 else if (address >= cfg->map_offset[i] && address < cfg->map_high[i]) {
545 if (cfg->map_type[i] == MAPTYPE_RAM || cfg->map_type[i] == MAPTYPE_RAM_NOALLOC || cfg->map_type[i] == MAPTYPE_ROM)
553 uint8_t *get_mapped_data_pointer_by_address(struct emulator_config *cfg, uint32_t address) {
554 for (int i = 0; i < MAX_NUM_MAPPED_ITEMS; i++) {
555 if (cfg->map_type[i] == MAPTYPE_NONE || !cfg->map_data[i])
557 else if (address >= cfg->map_offset[i] && address < cfg->map_high[i]) {
558 if (cfg->map_type[i] == MAPTYPE_RAM || cfg->map_type[i] == MAPTYPE_RAM_NOALLOC || cfg->map_type[i] == MAPTYPE_ROM)
559 return cfg->map_data[i] + (address - cfg->map_offset[i]);