From 4c77eb84f6ce1862bf4c54292d3a516f1a1a9626 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sat, 21 Oct 2023 23:18:46 +0100 Subject: [PATCH 01/11] config: more robust parsing of config file values. --- src/config.c | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/config.c b/src/config.c index 3c9f1dfe..c61537c9 100644 --- a/src/config.c +++ b/src/config.c @@ -35,28 +35,45 @@ ALLEGRO_CONFIG *bem_cfg; int get_config_int(const char *sect, const char *key, int ival) { const char *str = al_get_config_value(bem_cfg, sect, key); - if (str) - ival = atoi(str); - else if (sect && (str = al_get_config_value(bem_cfg, NULL, key))) { - ival = atoi(str); - al_remove_config_key(bem_cfg, "", key); + if (!str && sect) { + if ((str = al_get_config_value(bem_cfg, NULL, key))) + al_remove_config_key(bem_cfg, "", key); + } + if (str) { + char *end; + long nval = strtol(str, &end, 0); + if (end > str && !end[0]) + ival = nval; + else if (sect) + log_warn("config: section '%s', key '%s': invalid integer %s", sect, key, str); + else + log_warn("config: global section, key '%s': invalid integer %s", key, str); } return ival; } -static bool parse_bool(const char *value) -{ - return strcasecmp(value, "true") == 0 || strcasecmp(value, "yes") == 0 || atoi(value) > 0; -} - bool get_config_bool(const char *sect, const char *key, bool bval) { const char *str = al_get_config_value(bem_cfg, sect, key); - if (str) - bval = parse_bool(str); - else if (sect && (str = al_get_config_value(bem_cfg, NULL, key))) { - bval = parse_bool(str); - al_remove_config_key(bem_cfg, "", key); + if (!str && sect) { + if ((str = al_get_config_value(bem_cfg, NULL, key))) + al_remove_config_key(bem_cfg, "", key); + } + if (str) { + if (strcasecmp(str, "true") == 0 || strcasecmp(str, "yes") == 0) + bval = true; + else if (strcasecmp(str, "false") == 0 || strcasecmp(str, "no") == 0) + bval = false; + else { + char *end; + long nval = strtol(str, &end, 0); + if (end > str && !end[0]) + bval = (nval > 0); + else if (sect) + log_warn("config: section '%s', key '%s': invalid boolean %s", sect, key, str); + else + log_warn("config: global section, key '%s': invalid boolean %s", key, str); + } } return bval; } From c1f68db571302faf0f95e3657fed21d0ccaf09f7 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sat, 21 Oct 2023 23:53:50 +0100 Subject: [PATCH 02/11] logging: make 'append' a proper boolean. --- src/logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging.c b/src/logging.c index bfab6918..4f5bcb56 100644 --- a/src/logging.c +++ b/src/logging.c @@ -290,7 +290,7 @@ static void log_open_file(void) { log_warn("log_open: unable to find suitable destination for log file"); } if (log_fn) { - append = get_config_int(log_section, "append", 1); + append = get_config_bool(log_section, "append", 1); if ((log_fp = fopen(log_fn, append ? "at" : "wt")) == NULL) log_warn("log_open: unable to open log %s: %s", log_fn, strerror(errno)); } From 82c93863a33a3b9527e9b8d07ef8bc2f5bb8f0e1 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 00:19:55 +0100 Subject: [PATCH 03/11] model: split tubes into model/CPU with model in the config file. Formally a "tube" was a combination of a CPU with other details like the boot ROM to be loaded and was hard-coded as an array in model.c This commit splits this so a tube CPU is still defined in a hard-coded array as it has to refer to functions within the emulator itself but the definition of a tube model is moved to the config file. There can now be more than one model using the same tube CPU with basic differences including the name, clock speed and boot ROM. --- src/config.c | 8 +++ src/config.h | 1 + src/debugger.c | 4 +- src/gui-allegro.c | 14 ++-- src/main.c | 4 +- src/model.c | 161 ++++++++++++++++++++++++++++++++++++---------- src/model.h | 21 +++--- src/tube.c | 2 +- 8 files changed, 159 insertions(+), 56 deletions(-) diff --git a/src/config.c b/src/config.c index c61537c9..dda49a84 100644 --- a/src/config.c +++ b/src/config.c @@ -260,6 +260,14 @@ void set_config_int(const char *sect, const char *key, int value) al_set_config_value(bem_cfg, sect, key, buf); } +void set_config_hex(const char *sect, const char *key, unsigned value) +{ + char buf[11]; + + snprintf(buf, sizeof buf, "0x%x", value); + al_set_config_value(bem_cfg, sect, key, buf); +} + void set_config_bool(const char *sect, const char *key, bool value) { al_set_config_value(bem_cfg, sect, key, value ? "true" : "false"); diff --git a/src/config.h b/src/config.h index e1348032..d52b63c6 100644 --- a/src/config.h +++ b/src/config.h @@ -11,6 +11,7 @@ bool get_config_bool(const char *sect, const char *key, bool bdefault); const char *get_config_string(const char *sect, const char *key, const char *sdefault); ALLEGRO_COLOR get_config_colour(const char *sect, const char *key, ALLEGRO_COLOR cdefault); void set_config_int(const char *sect, const char *key, int value); +void set_config_hex(const char *sect, const char *key, unsigned value); void set_config_bool(const char *sect, const char *key, bool value); void set_config_string(const char *sect, const char *key, const char *value); diff --git a/src/debugger.c b/src/debugger.c index b0bf102f..a92cf9bf 100644 --- a/src/debugger.c +++ b/src/debugger.c @@ -296,7 +296,7 @@ static void enable_tube_debug(void) debug_step = 1; debug_tube = 1; log_info("debugger: debugging of tube CPU enabled"); - tubes[curtube].debug->debug_enable(1); + tubes[curtube].cpu->debug->debug_enable(1); } } @@ -313,7 +313,7 @@ static void disable_tube_debug(void) { if (curtube != -1) { - tubes[curtube].debug->debug_enable(0); + tubes[curtube].cpu->debug->debug_enable(0); log_info("debugger: debugging of tube CPU disabled"); debug_tube = 0; debug_cons_close(); diff --git a/src/gui-allegro.c b/src/gui-allegro.c index 8974dfdd..f9e3fbb0 100644 --- a/src/gui-allegro.c +++ b/src/gui-allegro.c @@ -305,15 +305,17 @@ static ALLEGRO_MENU *create_tube_menu(void) { ALLEGRO_MENU *menu = al_create_menu(); ALLEGRO_MENU *sub = al_create_menu(); - menu_map_t map[NUM_TUBES]; - int i; - - for (i = 0; i < NUM_TUBES; i++) { + menu_map_t *map = malloc(num_tubes * sizeof(menu_map_t)); + if (!map) { + log_error("gui: unable to allocate tube menu"); + return NULL; + } + for (int i = 0; i < num_tubes; ++i) { map[i].label = tubes[i].name; map[i].itemno = i; } - add_sorted_set(menu, map, NUM_TUBES, IDM_TUBE, curtube); - for (i = 0; i < NUM_TUBE_SPEEDS; i++) + add_sorted_set(menu, map, num_tubes, IDM_TUBE, curtube); + for (int i = 0; i < NUM_TUBE_SPEEDS; i++) add_radio_item(sub, tube_speeds[i].name, IDM_TUBE_SPEED, i, tube_speed_num); al_append_menu_item(menu, "Tube speed", 0, 0, NULL, sub); return menu; diff --git a/src/main.c b/src/main.c index 190c828c..118dd7c9 100644 --- a/src/main.c +++ b/src/main.c @@ -123,7 +123,7 @@ void main_reset() music5000_reset(); paula_reset(); sn_init(); - if (curtube != -1) tubes[curtube].reset(); + if (curtube != -1) tubes[curtube].cpu->reset(); else tube_exec = NULL; tube_reset(); } @@ -412,7 +412,7 @@ void main_key_break(void) paula_reset(); if (curtube != -1) - tubes[curtube].reset(); + tubes[curtube].cpu->reset(); tube_reset(); } diff --git a/src/model.c b/src/model.c index 444e2298..0d8b42ed 100644 --- a/src/model.c +++ b/src/model.c @@ -1,3 +1,4 @@ +#define _DEBUG #include "b-em.h" #include "main.h" @@ -52,32 +53,61 @@ static rom_setup_t rom_setups[NUM_ROM_SETUP] = { "weramrom", mem_romsetup_weramrom } }; +extern cpu_debug_t n32016_cpu_debug; + +#define NUM_TUBE_CPUS 12 + +static const TUBE_CPU tube_cpus[NUM_TUBE_CPUS] = +{ + {"6502", tube_6502_init, tube_6502_reset, &tube6502_cpu_debug }, + {"ARM", arm_init, arm_reset, &tubearm_cpu_debug }, + {"Z80", z80_init, z80_reset, &tubez80_cpu_debug }, + {"80186", x86_init, x86_reset, &tubex86_cpu_debug }, + {"65816", w65816_init_recoco, w65816_reset, &tube65816_cpu_debug }, + {"32016", tube_32016_init, n32016_reset, &n32016_cpu_debug }, + {"6809", tube_6809_init, mc6809nc_reset, &mc6809nc_cpu_debug }, + {"PDP11", tube_pdp11_init, copro_pdp11_rst, &pdp11_cpu_debug }, + {"6502 Turbo", tube_6502_iturb, tube_6502_reset, &tube6502_cpu_debug }, + {"68000", tube_68000_init, tube_68000_rst, &mc68000_cpu_debug }, + {"65816Dossy", w65816_init_dossy, w65816_reset, &tube65816_cpu_debug }, + {"Sprow ARM", sprow_init, sprow_reset, &tubesprow_cpu_debug } +}; + +TUBE_MODEL *tubes; +int num_tubes; + /* * The number of tube cycles to run for each core 6502 processor cycle * is calculated by mutliplying the multiplier in this table with the * one in the general tube speed table and dividing by two. */ -extern cpu_debug_t n32016_cpu_debug; +typedef struct +{ + char name[32]; + char cpu[32]; + uint_least32_t rom_size; + char bootrom[16]; + int speed_multiplier; +} TUBE_DEFAULT; -TUBE tubes[NUM_TUBES]= +#define NUM_DFLT_TUBE 13 + +static const TUBE_DEFAULT tube_defaults[] = { - {"6502 Internal", tube_6502_init, tube_6502_reset, &tube6502_cpu_debug, 0x0800, "6502Intern", 4 }, - {"ARM", arm_init, arm_reset, &tubearm_cpu_debug, 0x4000, "ARMeval_100", 4 }, - {"Z80", z80_init, z80_reset, &tubez80_cpu_debug, 0x1000, "Z80_121", 6 }, - {"80186", x86_init, x86_reset, &tubex86_cpu_debug, 0x4000, "BIOS", 8 }, - {"65816", w65816_init_recoco, w65816_reset, &tube65816_cpu_debug, 0x8000, "ReCo6502ROM_816", 16 }, - {"32016", tube_32016_init, n32016_reset, &n32016_cpu_debug, 0x0000, "", 8 }, - {"6502 External", tube_6502_init, tube_6502_reset, &tube6502_cpu_debug, 0x0800, "6502Tube", 3 }, - {"6809", tube_6809_init, mc6809nc_reset, &mc6809nc_cpu_debug, 0x0800, "6809Tube", 3 }, - {"Z80 ROM 2.00", z80_init, z80_reset, &tubez80_cpu_debug, 0x1000, "Z80_200", 6 }, - {"PDP11", tube_pdp11_init, copro_pdp11_rst, &pdp11_cpu_debug, 0x0800, "PDP11Tube", 2 }, - {"6502 Turbo", tube_6502_iturb, tube_6502_reset, &tube6502_cpu_debug, 0x0800, "6502Turbo", 4 }, -#ifdef M68K - {"68000", tube_68000_init, tube_68000_rst, &mc68000_cpu_debug, 0x8000, "CiscOS", 4 }, -#endif - {"65816Dossy", w65816_init_dossy, w65816_reset, &tube65816_cpu_debug, 0x8000, "Dossy_816", 16 }, - {"Sprow ARM", sprow_init, sprow_reset, &tubesprow_cpu_debug, 0x80000, "Sprow_ARM", 4 } + {"6502 Internal", "6502", 0x0800, "6502Intern", 4 }, + {"ARM", "ARM", 0x4000, "ARMeval_100", 4 }, + {"Z80 ROM 1.21", "Z80", 0x1000, "Z80_121", 6 }, + {"80186", "80186", 0x4000, "BIOS", 8 }, + {"65816", "65816", 0x8000, "ReCo6502ROM_816", 16 }, + {"32016", "32016", 0x0000, "", 8 }, + {"6502 External", "6502", 0x0800, "6502Tube", 3 }, + {"6809", "6809", 0x0800, "6809Tube", 3 }, + {"Z80 ROM 2.00", "Z80", 0x1000, "Z80_200", 6 }, + {"PDP11", "PDP11", 0x0800, "PDP11Tube", 2 }, + {"6502 Turbo", "6502 Turbo", 0x0800, "6502Turbo", 4 }, + {"65816Dossy", "65816Dossy", 0x8000, "Dossy_816", 16 }, + {"Sprow ARM", "Sprow ARM", 0x80000, "Sprow_ARM", 4 } }; static fdc_type_t model_find_fdc(const char *name, const char *model) @@ -100,10 +130,19 @@ static rom_setup_t *model_find_romsetup(const char *name, const char *model) return rom_setups; } +static const TUBE_CPU *model_find_tcpu(const char *name, const char *cpu) +{ + for (int i = 0; i < NUM_TUBE_CPUS; ++i) + if (strcmp(tube_cpus[i].name, cpu) == 0) + return &tube_cpus[i]; + log_warn("model: invalid tube CPU name '%s' in tube '%s'", name, cpu); + return NULL; +} + static int model_find_tube(const char *name, const char *model) { if (strcmp(name, "none")) { - for (int i = 0; i < NUM_TUBES; i++) + for (int i = 0; i < num_tubes; i++) if (strcmp(tubes[i].name, name) == 0) return i; log_warn("model: invalid tube name '%s' in model '%s', no tube will be used", name, model); @@ -114,31 +153,78 @@ static int model_find_tube(const char *name, const char *model) void model_loadcfg(void) { ALLEGRO_CONFIG_SECTION *siter; - const char *sect; - int num, max = -1; - MODEL *ptr; + int max_model = -1; + int max_tube = -1; - for (sect = al_get_first_config_section(bem_cfg, &siter); sect; sect = al_get_next_config_section(&siter)) { + for (const char *sect = al_get_first_config_section(bem_cfg, &siter); sect; sect = al_get_next_config_section(&siter)) { if (strncmp(sect, "model_", 6) == 0) { - num = atoi(sect+6); + int num = atoi(sect+6); log_debug("model: pass1, found model#%02d", num); - if (num > max) - max = num; + if (num > max_model) + max_model = num; + } + else if (strncmp(sect, "tube_", 5) == 0) { + int num = atoi(sect+5); + log_debug("model: pass1, found tube#%02d", num); + if (num > max_tube) + max_tube = num; } } - if (max < 0) { + log_debug("model: pass1, max_model=%d, max_tube=%d", max_model, max_tube); + if (max_model < 0) { log_fatal("model: no models defined in config file"); exit(1); } - if (!(models = malloc(++max * sizeof(MODEL)))) { + if (max_tube < 0) { + tubes = malloc(NUM_DFLT_TUBE * sizeof(TUBE_MODEL)); + if (!tubes) { + log_fatal("model: out of memory allocating tubes"); + exit(1); + } + num_tubes = NUM_DFLT_TUBE; + for (int i = 0; i < NUM_DFLT_TUBE; ++i) { + char sect[CFG_SECT_LEN]; + tubes[i].name = tube_defaults[i].name; + tubes[i].cpu = model_find_tcpu(tube_defaults[i].name, tube_defaults[i].cpu); + tubes[i].rom_size = tube_defaults[i].rom_size; + tubes[i].bootrom = tube_defaults[i].bootrom; + tubes[i].speed_multiplier = tube_defaults[i].speed_multiplier; + snprintf(sect, sizeof(sect), "tube_%02d", i); + set_config_string(sect, "name", tube_defaults[i].name); + set_config_string(sect, "cpu", tube_defaults[i].cpu); + if (tube_defaults[i].rom_size) + set_config_hex(sect, "romsize", tube_defaults[i].rom_size); + if (tube_defaults[i].bootrom[0]) + set_config_string(sect, "bootrom", tube_defaults[i].bootrom); + set_config_int(sect, "speed", tube_defaults[i].speed_multiplier); + } + } + else { + tubes = malloc(++max_tube * sizeof(TUBE_MODEL)); + if (!tubes) { + log_fatal("model: out of memory allocating tubes"); + exit(1); + } + num_tubes = max_tube; + for (int i = 0; i < max_tube; ++i) { + char sect[16]; + snprintf(sect, sizeof(sect), "tube_%d", i); + tubes[i].name = get_config_string(sect, "name", NULL); + tubes[i].cpu = model_find_tcpu(tubes[i].name, get_config_string(sect, "cpu", "none")); + tubes[i].rom_size = get_config_int(sect, "romsize", 0); + tubes[i].bootrom = get_config_string(sect, "bootrom", NULL); + tubes[i].speed_multiplier = get_config_int(sect, "speed", 1); + } + } + if (!(models = malloc(++max_model * sizeof(MODEL)))) { log_fatal("model: out of memory allocating models"); exit(1); } - for (sect = al_get_first_config_section(bem_cfg, &siter); sect; sect = al_get_next_config_section(&siter)) { + for (const char *sect = al_get_first_config_section(bem_cfg, &siter); sect; sect = al_get_next_config_section(&siter)) { if (strncmp(sect, "model_", 6) == 0) { - num = atoi(sect+6); + int num = atoi(sect+6); log_debug("model: pass2, found model#%02d", num); - ptr = models + num; + MODEL *ptr = models + num; ptr->cfgsect = sect; ptr->name = get_config_string(sect, "name", sect); ptr->fdc_type = model_find_fdc(get_config_string(sect, "fdc", "none"), ptr->name); @@ -156,7 +242,7 @@ void model_loadcfg(void) ptr->boot_logo = get_config_int(sect, "boot_logo", 255); } } - model_count = max; + model_count = max_model; } void model_check(void) { @@ -170,7 +256,7 @@ void model_check(void) { curtube = models[curmodel].tube; else curtube = selecttube; - if (curtube < -1 || curtube >= NUM_TUBES) { + if (curtube < -1 || curtube >= num_tubes) { log_warn("No tube #%d, running with no tube instead", curtube); curtube = -1; } @@ -186,7 +272,7 @@ static void tube_init(void) if (curtube!=-1) { if (!tubes[curtube].bootrom[0]) { // no boot ROM needed - tubes[curtube].init(NULL); + tubes[curtube].cpu->init(NULL); tube_updatespeed(); tube_reset(); } @@ -197,6 +283,11 @@ static void tube_init(void) cpath = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); if ((romf = fopen(cpath, "rb"))) { int rom_size = tubes[curtube].rom_size; + if (rom_size == 0) { + fseek(romf, 0, SEEK_END); + rom_size = ftell(romf); + fseek(romf, 0, SEEK_SET); + } log_debug("model: rom_size=%X", rom_size); if (tuberom) free(tuberom); @@ -204,7 +295,7 @@ static void tube_init(void) log_debug("model: tuberom=%p, romf=%p", tuberom, romf); if (fread(tuberom, rom_size, 1, romf) == 1) { fclose(romf); - if (tubes[curtube].init(tuberom)) { + if (tubes[curtube].cpu->init(tuberom)) { tube_updatespeed(); tube_reset(); return; diff --git a/src/model.h b/src/model.h index 24b4fa14..2d559410 100644 --- a/src/model.h +++ b/src/model.h @@ -50,18 +50,19 @@ typedef struct bool (*init)(void *rom); void (*reset)(void); cpu_debug_t *debug; - int rom_size; - char bootrom[16]; - int speed_multiplier; -} TUBE; +} TUBE_CPU; -#ifdef M68K -# define NUM_TUBES 14 -#else -# define NUM_TUBES 13 -#endif +typedef struct +{ + const char *name; + const TUBE_CPU *cpu; + uint_least32_t rom_size; + const char *bootrom; + int speed_multiplier; +} TUBE_MODEL; -extern TUBE tubes[NUM_TUBES]; +extern TUBE_MODEL *tubes; +extern int num_tubes; extern int curmodel, curtube, oldmodel, selecttube; extern fdc_type_t fdc_type; diff --git a/src/tube.c b/src/tube.c index 32bc79ca..9fa24236 100644 --- a/src/tube.c +++ b/src/tube.c @@ -177,7 +177,7 @@ void tube_host_write(uint16_t addr, uint8_t val) else if (tubeula.r1stat & 0x20) { tube_reset(); if (curtube != -1) - tubes[curtube].reset(); + tubes[curtube].cpu->reset(); } else tubeula.r1stat &= ~(val&0x3F); From 0afc7ec0a75ba481382acf28760369bb0eb5dd52 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 01:50:37 +0100 Subject: [PATCH 04/11] model: record config file section in tube model structure. By recording the name of the config section that defined a particular tube model, code, including that in the CPU implementation, can check for extra values in the config section according to their own requirements. --- src/model.c | 63 +++++++++++++++++++++++++++++++---------------------- src/model.h | 3 ++- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/model.c b/src/model.c index 0d8b42ed..b5808ea4 100644 --- a/src/model.c +++ b/src/model.c @@ -176,20 +176,23 @@ void model_loadcfg(void) exit(1); } if (max_tube < 0) { - tubes = malloc(NUM_DFLT_TUBE * sizeof(TUBE_MODEL)); - if (!tubes) { + size_t tubes_size = NUM_DFLT_TUBE * sizeof(TUBE_MODEL); + size_t sects_size = NUM_DFLT_TUBE * CFG_SECT_LEN; + void *data = malloc(tubes_size + sects_size); + if (!data) { log_fatal("model: out of memory allocating tubes"); exit(1); } - num_tubes = NUM_DFLT_TUBE; + tubes = data; + char *sect = (char *)data + tubes_size; for (int i = 0; i < NUM_DFLT_TUBE; ++i) { - char sect[CFG_SECT_LEN]; - tubes[i].name = tube_defaults[i].name; tubes[i].cpu = model_find_tcpu(tube_defaults[i].name, tube_defaults[i].cpu); + snprintf(sect, CFG_SECT_LEN, "tube_%02d", i); + tubes[i].cfgsect = sect; + tubes[i].name = tube_defaults[i].name; tubes[i].rom_size = tube_defaults[i].rom_size; tubes[i].bootrom = tube_defaults[i].bootrom; tubes[i].speed_multiplier = tube_defaults[i].speed_multiplier; - snprintf(sect, sizeof(sect), "tube_%02d", i); set_config_string(sect, "name", tube_defaults[i].name); set_config_string(sect, "cpu", tube_defaults[i].cpu); if (tube_defaults[i].rom_size) @@ -197,26 +200,32 @@ void model_loadcfg(void) if (tube_defaults[i].bootrom[0]) set_config_string(sect, "bootrom", tube_defaults[i].bootrom); set_config_int(sect, "speed", tube_defaults[i].speed_multiplier); + sect += CFG_SECT_LEN; } + num_tubes = NUM_DFLT_TUBE; } else { - tubes = malloc(++max_tube * sizeof(TUBE_MODEL)); + tubes = calloc(++max_tube, sizeof(TUBE_MODEL)); if (!tubes) { log_fatal("model: out of memory allocating tubes"); exit(1); } num_tubes = max_tube; - for (int i = 0; i < max_tube; ++i) { - char sect[16]; - snprintf(sect, sizeof(sect), "tube_%d", i); - tubes[i].name = get_config_string(sect, "name", NULL); - tubes[i].cpu = model_find_tcpu(tubes[i].name, get_config_string(sect, "cpu", "none")); - tubes[i].rom_size = get_config_int(sect, "romsize", 0); - tubes[i].bootrom = get_config_string(sect, "bootrom", NULL); - tubes[i].speed_multiplier = get_config_int(sect, "speed", 1); + for (const char *sect = al_get_first_config_section(bem_cfg, &siter); sect; sect = al_get_next_config_section(&siter)) { + if (strncmp(sect, "tube_", 5) == 0) { + int num = atoi(sect+5); + TUBE_MODEL *ptr = tubes + num; + log_debug("model: pass2, found tube#%02d", num); + ptr->cpu = model_find_tcpu(ptr->name, get_config_string(sect, "cpu", "none")); + ptr->cfgsect = sect; + ptr->name = get_config_string(sect, "name", NULL); + ptr->rom_size = get_config_int(sect, "romsize", 0); + ptr->bootrom = get_config_string(sect, "bootrom", NULL); + ptr->speed_multiplier = get_config_int(sect, "speed", 1); + } } } - if (!(models = malloc(++max_model * sizeof(MODEL)))) { + if (!(models = calloc(++max_model, sizeof(MODEL)))) { log_fatal("model: out of memory allocating models"); exit(1); } @@ -271,48 +280,50 @@ static void tube_init(void) FILE *romf; if (curtube!=-1) { - if (!tubes[curtube].bootrom[0]) { // no boot ROM needed - tubes[curtube].cpu->init(NULL); + TUBE_MODEL *tube = &tubes[curtube]; + if (!tube->bootrom[0]) { // no boot ROM needed + tube->cpu->init(NULL); tube_updatespeed(); tube_reset(); } else { if (!tube_dir) tube_dir = al_create_path_for_directory("roms/tube"); - if ((path = find_dat_file(tube_dir, tubes[curtube].bootrom, ".rom"))) { + if ((path = find_dat_file(tube_dir, tube->bootrom, ".rom"))) { cpath = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); if ((romf = fopen(cpath, "rb"))) { - int rom_size = tubes[curtube].rom_size; + int rom_size = tube->rom_size; + log_debug("model: rom_size=%X", rom_size); if (rom_size == 0) { fseek(romf, 0, SEEK_END); rom_size = ftell(romf); + log_debug("model: rom_size from file=%X", rom_size); fseek(romf, 0, SEEK_SET); } - log_debug("model: rom_size=%X", rom_size); if (tuberom) free(tuberom); if ((tuberom = malloc(rom_size))) { log_debug("model: tuberom=%p, romf=%p", tuberom, romf); if (fread(tuberom, rom_size, 1, romf) == 1) { fclose(romf); - if (tubes[curtube].cpu->init(tuberom)) { + if (tube->cpu->init(tuberom)) { tube_updatespeed(); tube_reset(); return; } } else { - log_error("model: error reading boot rom %s for tube %s: %s", cpath, tubes[curtube].name, strerror(errno)); + log_error("model: error reading boot rom %s for tube %s: %s", cpath, tube->name, strerror(errno)); fclose(romf); } } else - log_error("model: no space for ROM for tube %s", tubes[curtube].name); + log_error("model: no space for ROM for tube %s", tube->name); } else - log_error("model: unable to open boot rom %s for tube %s: %s", cpath, tubes[curtube].name, strerror(errno)); + log_error("model: unable to open boot rom %s for tube %s: %s", cpath, tube->name, strerror(errno)); al_destroy_path(path); } else - log_error("model: boot rom %s for tube %s not found", tubes[curtube].bootrom, tubes[curtube].name); + log_error("model: boot rom %s for tube %s not found", tube->bootrom, tube->name); curtube = -1; } } diff --git a/src/model.h b/src/model.h index 2d559410..46a7154d 100644 --- a/src/model.h +++ b/src/model.h @@ -54,8 +54,9 @@ typedef struct typedef struct { - const char *name; const TUBE_CPU *cpu; + const char *cfgsect; + const char *name; uint_least32_t rom_size; const char *bootrom; int speed_multiplier; From 8585c54ebc34ba4c594d88429c69946528062bc1 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 01:52:17 +0100 Subject: [PATCH 05/11] 68000: make the memory size configurable. --- src/mc68000tube.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/mc68000tube.c b/src/mc68000tube.c index e8d14021..a9d78611 100644 --- a/src/mc68000tube.c +++ b/src/mc68000tube.c @@ -1,10 +1,13 @@ - +#define _DEBUG #include "b-em.h" #include "cpu_debug.h" #include "tube.h" +#include "config.h" +#include "model.h" #include "mc68000tube.h" #include "musahi/m68k.h" +static uint_least32_t mc68000_ram_size; static uint8_t *mc68000_ram, *mc68000_rom; static bool mc68000_debug_enabled = false; static bool rom_low; @@ -35,7 +38,7 @@ static uint8_t readmem(uint32_t addr) } else { - uint8_t data = mc68000_ram[addr % MC68000_RAM_SIZE]; + uint8_t data = mc68000_ram[addr % mc68000_ram_size]; log_debug("mc68000: read %08X as RAM -> %02X", addr, data); return data; } @@ -96,7 +99,7 @@ static void writemem(uint32_t addr, uint8_t data) else { log_debug("mc68000: write %08X as RAM <- %02X", addr, data); - mc68000_ram[addr % MC68000_RAM_SIZE] = data; + mc68000_ram[addr % mc68000_ram_size] = data; } } @@ -145,7 +148,7 @@ static void mc68000_savestate(ZFILE *zfp) m68k_get_context(buf); savestate_zwrite(zfp, buf, bytes); free(buf); - savestate_zwrite(zfp, mc68000_ram, MC68000_RAM_SIZE); + savestate_zwrite(zfp, mc68000_ram, mc68000_ram_size); savestate_zwrite(zfp, mc68000_rom, MC68000_ROM_SIZE); } else @@ -160,7 +163,7 @@ static void mc68000_loadstate(ZFILE *zfp) savestate_zread(zfp, buf, bytes); m68k_set_context(buf); free(buf); - savestate_zread(zfp, mc68000_ram, MC68000_RAM_SIZE); + savestate_zread(zfp, mc68000_ram, mc68000_ram_size); savestate_zread(zfp, mc68000_rom, MC68000_ROM_SIZE); } else @@ -171,7 +174,9 @@ bool tube_68000_init(void *rom) { log_debug("mc68000: init"); if (!mc68000_ram) { - mc68000_ram = malloc(MC68000_RAM_SIZE); + const char *sect = tubes[curtube].cfgsect; + mc68000_ram_size = get_config_int(sect, "ramsize", MC68000_RAM_SIZE); + mc68000_ram = malloc(mc68000_ram_size); if (!mc68000_ram) { log_error("mc68000: unable to allocate RAM: %s", strerror(errno)); return false; From 156f0995e05984b13188c810dda3f0a064373ff0 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 02:03:02 +0100 Subject: [PATCH 06/11] Remove #define _DEBUG left in by mistake. --- src/mc68000tube.c | 1 - src/model.c | 1 - src/savestate.c | 1 - src/sdf-acc.c | 1 - 4 files changed, 4 deletions(-) diff --git a/src/mc68000tube.c b/src/mc68000tube.c index a9d78611..f40e032c 100644 --- a/src/mc68000tube.c +++ b/src/mc68000tube.c @@ -1,4 +1,3 @@ -#define _DEBUG #include "b-em.h" #include "cpu_debug.h" #include "tube.h" diff --git a/src/model.c b/src/model.c index b5808ea4..c265dd8b 100644 --- a/src/model.c +++ b/src/model.c @@ -1,4 +1,3 @@ -#define _DEBUG #include "b-em.h" #include "main.h" diff --git a/src/savestate.c b/src/savestate.c index 255247cd..2f60854a 100644 --- a/src/savestate.c +++ b/src/savestate.c @@ -1,4 +1,3 @@ -#define _DEBUG /*B-em v2.2 by Tom Walker Savestate handling*/ #include "b-em.h" diff --git a/src/sdf-acc.c b/src/sdf-acc.c index ece2f1ad..5827dcc2 100644 --- a/src/sdf-acc.c +++ b/src/sdf-acc.c @@ -1,4 +1,3 @@ -#define _DEBUG /* * B-EM SDF - Simple Disk Formats - Access * From 22fe5063ac83025b87d1817dd5ae4529295c48d3 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 17:57:53 +0100 Subject: [PATCH 07/11] m68k: remove conditional compilation. --- src/tube.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tube.c b/src/tube.c index 9fa24236..01c4dc16 100644 --- a/src/tube.c +++ b/src/tube.c @@ -68,10 +68,8 @@ void tube_updateints() if (((m_pdp11->PS >> 5) & 7) < 6) pdp11_interrupt(0x84, 6); } -#ifdef M68K else if (tube_type == TUBE68000) m68k_set_virq(2, 1); -#endif else if (tube_type == TUBESPROW) sprow_interrupt(1); } From 8558375e4b98307bffd560165d1929ae48a0a025 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 21:46:20 +0100 Subject: [PATCH 08/11] model: fix memory leak in tube initialisation. --- src/model.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/model.c b/src/model.c index c265dd8b..959ef9b2 100644 --- a/src/model.c +++ b/src/model.c @@ -308,6 +308,7 @@ static void tube_init(void) if (tube->cpu->init(tuberom)) { tube_updatespeed(); tube_reset(); + al_destroy_path(path); return; } } From 8eff1dd649ff10935ea08cb95448bc0166e1705c Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 22 Oct 2023 21:52:59 +0100 Subject: [PATCH 09/11] model: allow tube ROM to be an absolute path. This makes the specification of the tube client ROM in a tube entry in the config file rather like a normal sideways ROM in that an absolute path will be loaded directly whereas a relative path will be searched for the roms/tube directory. --- src/model.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/model.c b/src/model.c index 959ef9b2..4c108f3a 100644 --- a/src/model.c +++ b/src/model.c @@ -274,10 +274,6 @@ static void *tuberom = NULL; static void tube_init(void) { - ALLEGRO_PATH *path; - const char *cpath; - FILE *romf; - if (curtube!=-1) { TUBE_MODEL *tube = &tubes[curtube]; if (!tube->bootrom[0]) { // no boot ROM needed @@ -286,11 +282,27 @@ static void tube_init(void) tube_reset(); } else { - if (!tube_dir) - tube_dir = al_create_path_for_directory("roms/tube"); - if ((path = find_dat_file(tube_dir, tube->bootrom, ".rom"))) { - cpath = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); - if ((romf = fopen(cpath, "rb"))) { + ALLEGRO_PATH *path = NULL; + const char *cpath; + if (is_relative_filename(tube->bootrom)) { + if (!tube_dir) + tube_dir = al_create_path_for_directory("roms/tube"); + if ((path = find_dat_file(tube_dir, tube->bootrom, ".rom"))) { + cpath = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); + log_debug("model: will load searched tube ROM %s", cpath); + } + else { + log_error("model: boot rom %s for tube %s not found", tube->bootrom, tube->name); + cpath = NULL; + } + } + else { + cpath = tube->bootrom; + log_debug("model: will load absolute path tube ROM %s", cpath); + } + if (cpath) { + FILE *romf = fopen(cpath, "rb"); + if (romf) { int rom_size = tube->rom_size; log_debug("model: rom_size=%X", rom_size); if (rom_size == 0) { @@ -305,10 +317,13 @@ static void tube_init(void) log_debug("model: tuberom=%p, romf=%p", tuberom, romf); if (fread(tuberom, rom_size, 1, romf) == 1) { fclose(romf); + if (path) + al_destroy_path(path); if (tube->cpu->init(tuberom)) { tube_updatespeed(); tube_reset(); - al_destroy_path(path); + if (path) + al_destroy_path(path); return; } } @@ -317,13 +332,16 @@ static void tube_init(void) fclose(romf); } } - else + else { log_error("model: no space for ROM for tube %s", tube->name); - } else + fclose(romf); + } + } + else log_error("model: unable to open boot rom %s for tube %s: %s", cpath, tube->name, strerror(errno)); + } + if (path) al_destroy_path(path); - } else - log_error("model: boot rom %s for tube %s not found", tube->bootrom, tube->name); curtube = -1; } } From ad8c316f70624dccf4888761d072a74ca47fbfd9 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 29 Oct 2023 18:53:52 +0000 Subject: [PATCH 10/11] m68k: remove more conditional compilation --- src/tube.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tube.c b/src/tube.c index 01c4dc16..620f2804 100644 --- a/src/tube.c +++ b/src/tube.c @@ -75,11 +75,9 @@ void tube_updateints() } } else if (tube_irq & 1) { -#ifdef M68K log_debug("tube: parasite IRQ de-asserted"); if (tube_type == TUBE68000) m68k_set_virq(2, 0); -#endif } if (tubeula.r1stat & 8 && (tubeula.ph3pos == 0 || tubeula.hp3pos > (tubeula.r1stat & 16) ? 1 : 0)) { From 02e367622453f1e0989935bd27f23b011a077575 Mon Sep 17 00:00:00 2001 From: Steve Fosdick Date: Sun, 29 Oct 2023 18:54:46 +0000 Subject: [PATCH 11/11] tube: fix double-free. See: https://github.com/stardot/b-em/issues/212#issuecomment-1784190372 --- src/model.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/model.c b/src/model.c index 4c108f3a..d893bc21 100644 --- a/src/model.c +++ b/src/model.c @@ -317,8 +317,6 @@ static void tube_init(void) log_debug("model: tuberom=%p, romf=%p", tuberom, romf); if (fread(tuberom, rom_size, 1, romf) == 1) { fclose(romf); - if (path) - al_destroy_path(path); if (tube->cpu->init(tuberom)) { tube_updatespeed(); tube_reset();