diff --git a/core/main.cpp b/core/main.cpp index 919d4d1..76ad555 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -26,7 +26,6 @@ virtual keyboard core options v2 https://github.com/libretro/libretro-common/tree/master/samples/core_options check and include libretro common detailed type detection from content name -m3u (or, rather, name-based autodetect) multi-disk, multi-tape interface support (cpc 3 guerra) locale support ep, cpc rom config for clkoff+hfont @@ -42,6 +41,7 @@ EP Mouse support achievement support test mp3 support with sndfile 1.1 - cmake won't find lame / mpeg123 when compiling libsndfile led driver for tape / disk loading - see comments inside +name-based autodetect for multi-disk, multi-tape interface support (cpc 3 guerra) */ @@ -104,15 +104,25 @@ retro_usec_t prev_frame_time = 0; float waitPeriod = 0.001; bool useSwFb = false; bool useHalfFrame = false; -bool enableDiskControl = false; -bool needsDiskControl = false; int borderSize = 0; bool soundHq = true; -unsigned maxUsers; -bool maxUsersSupported = true; bool canSkipFrames = false; bool enhancedRom = false; +unsigned maxUsers; +bool maxUsersSupported = true; + +unsigned diskIndex = 0; +unsigned diskCount = 1; +#define MAX_DISK_COUNT 6 +std::string diskPaths[MAX_DISK_COUNT]; +std::string diskNames[MAX_DISK_COUNT]; +bool diskEjected = false; + +bool tapeContent = false; +bool diskContent = false; +bool fileContent = false; + Ep128Emu::VMThread *vmThread = (Ep128Emu::VMThread *) 0; Ep128Emu::EmulatorConfiguration *config = (Ep128Emu::EmulatorConfiguration *) 0; Ep128Emu::LibretroCore *core = (Ep128Emu::LibretroCore *) 0; @@ -293,6 +303,117 @@ static void check_variables(void) if(vmThread) vmThread->resetKeyboard(); } +/* If ejected is true, "ejects" the virtual disk tray. + */ +static bool set_eject_state_cb(bool ejected) { + log_cb(RETRO_LOG_DEBUG, "Disk control: eject (%d)\n",ejected?1:0); + diskEjected = ejected; + return true; +} + +/* Gets current eject state. The initial state is 'not ejected'. */ +static bool get_eject_state_cb(void) { +// log_cb(RETRO_LOG_DEBUG, "Disk control: get eject status (%d)\n",diskEjected?1:0); + return diskEjected; +} + +/* Gets current disk index. First disk is index 0. + * If return value is >= get_num_images(), no disk is currently inserted. + */ +static unsigned get_image_index_cb(void) { +// log_cb(RETRO_LOG_DEBUG, "Disk control: get image index (%d)\n",diskIndex); + if (diskEjected) return diskCount + 1; + return diskIndex; +} + +/* Sets image index. Can only be called when disk is ejected. + */ +static bool set_image_index_cb(unsigned index) { + log_cb(RETRO_LOG_DEBUG, "Disk control: change image to (%d)\n",index); + if (index>=diskCount) { + diskIndex = diskCount + 1; + } else { + diskIndex = index; + if (core) { + config = core->config; + if(diskContent) { + config->floppy.a.imageFile = diskPaths[index]; + config->floppyAChanged = true; + log_cb(RETRO_LOG_DEBUG, "Disk control: new disk is %s\n",diskPaths[index].c_str()); + } else if(tapeContent) { + config->tape.imageFile = diskPaths[index]; + config->tapeFileChanged = true; + log_cb(RETRO_LOG_DEBUG, "Disk control: new tape is %s\n",diskPaths[index].c_str()); + } + config->applySettings(); + } + } + return true; +} + +/* Gets total number of images which are available to use. */ +static unsigned get_num_images_cb(void) {return diskCount;} + +/* Replaces the disk image associated with index. + * Arguments to pass in info have same requirements as retro_load_game(). + */ +static bool replace_image_index_cb(unsigned index, + const struct retro_game_info *info) { + + log_cb(RETRO_LOG_DEBUG, "Disk control: replace image index (%d) to %s\n",index,info->path); + if (index >= diskCount) return false; + diskPaths[index] = info->path; + std::string contentPath; + Ep128Emu::splitPath(diskPaths[index],contentPath,diskNames[index]); + return true; +} + +/* Adds a new valid index (get_num_images()) to the internal disk list. + * This will increment subsequent return values from get_num_images() by 1. + * This image index cannot be used until a disk image has been set + * with replace_image_index. */ +static bool add_image_index_cb(void) { + log_cb(RETRO_LOG_DEBUG, "Disk control: add image index (current %d)\n",diskCount); + if (diskCount >= MAX_DISK_COUNT) return false; + diskCount++; + return true; +} + +/* Sets initial image to insert in drive when calling + * core_load_game(). + * Returns 'false' if index or 'path' are invalid, or core + * does not support this functionality + */ +static bool set_initial_image_cb(unsigned index, const char *path) {return false;} + +/* Fetches the path of the specified disk image file. + * Returns 'false' if index is invalid (index >= get_num_images()) + * or path is otherwise unavailable. + */ +static bool get_image_path_cb(unsigned index, char *path, size_t len) { + if (index >= diskCount) return false; + if(diskPaths[index].length() > 0) + path=(char*)diskPaths[index].c_str(); + len=diskPaths[index].length(); + log_cb(RETRO_LOG_DEBUG, "Disk control: get image path (%d) %s\n",index,path); + return true; +} + +/* Fetches a core-provided 'label' for the specified disk + * image file. In the simplest case this may be a file name + * Returns 'false' if index is invalid (index >= get_num_images()) + * or label is otherwise unavailable. + */ +static bool get_image_label_cb(unsigned index, char *label, size_t len) { + if(index >= diskCount) return false; + if(diskNames[index].length() > 0) + label=(char*)diskNames[index].c_str(); + len=diskNames[index].length(); + //log_cb(RETRO_LOG_DEBUG, "Disk control: get image label (%d) %s\n",index,label); + return true; +} + + void retro_init(void) { struct retro_log_callback log; @@ -303,12 +424,42 @@ void retro_init(void) else log_cb = fallback_log; - // actually it is the advanced disk control... + struct retro_disk_control_callback dccb = + { + set_eject_state_cb, + get_eject_state_cb, + + get_image_index_cb, + set_image_index_cb, + get_num_images_cb, + + replace_image_index_cb, + add_image_index_cb + }; + + struct retro_disk_control_ext_callback dccb_ext = + { + set_eject_state_cb, + get_eject_state_cb, + + get_image_index_cb, + set_image_index_cb, + get_num_images_cb, + + replace_image_index_cb, + add_image_index_cb, + set_initial_image_cb, + + get_image_path_cb, + get_image_label_cb + }; + unsigned dci; - if (environ_cb(RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION, &dci)) - enableDiskControl = true; - else - enableDiskControl = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION, &dci)) { + environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE, &dccb_ext); + } else { + environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &dccb); + } /* struct retro_led_interface led_interface; if(environ_cb(RETRO_ENVIRONMENT_GET_LED_INTERFACE, &led_interface)) { @@ -366,7 +517,7 @@ void retro_init(void) sizeof(retro_system_save_directory) - 1 ); - log_cb(RETRO_LOG_INFO, "Retro ROM DIRECTORY %s\n", retro_system_bios_directory); + log_cb(RETRO_LOG_DEBUG, "Retro ROM DIRECTORY %s\n", retro_system_bios_directory); log_cb(RETRO_LOG_DEBUG, "Retro SAVE_DIRECTORY %s\n", retro_system_save_directory); log_cb(RETRO_LOG_DEBUG, "Retro CONTENT_DIRECTORY %s\n", retro_content_directory); @@ -421,7 +572,7 @@ void retro_get_system_info(struct retro_system_info *info) { memset(info, 0, sizeof(*info)); info->library_name = "ep128emu"; - info->library_version = "v1.2.0"; + info->library_version = "v1.2.1"; info->need_fullpath = true; info->valid_extensions = "img|dsk|tap|dtf|com|trn|128|bas|cas|cdt|tzx|wav|tvcwav|."; } @@ -642,6 +793,8 @@ bool retro_load_game(const struct retro_game_info *info) log_cb(RETRO_LOG_DEBUG, "Content extension: %s \n",contentExt.c_str()); Ep128Emu::splitPath(filename,contentPath,contentFile); contentBasename = contentFile; + diskPaths[0] = filename; + diskNames[0] = contentBasename; Ep128Emu::stringToLowerCase(contentBasename); int contentLocale = Ep128Emu::LOCALE_UK; @@ -720,9 +873,9 @@ bool retro_load_game(const struct retro_game_info *info) // - 0xfe as " // - 0xfd as F1 (START) const char* startupSequence = ""; - bool tapeContent = false; - bool diskContent = false; - bool fileContent = false; + tapeContent = false; + diskContent = false; + fileContent = false; int detectedMachineDetailedType = Ep128Emu::VM_config.at("VM_CONFIG_UNKNOWN"); // start with longer magic strings - less chance of mis-detection diff --git a/ep128emu_core_libretro.info b/ep128emu_core_libretro.info index 3a01737..22e0794 100644 --- a/ep128emu_core_libretro.info +++ b/ep128emu_core_libretro.info @@ -23,7 +23,7 @@ license = "GPLv2" permissions = "" # Version of the core: -display_version = "v1.2.0" +display_version = "v1.2.1" # Hardware Information - Information about the hardware the core supports (when applicable) # Name of the manufacturer who produced the emulated system: @@ -48,91 +48,91 @@ firmware_count = 22 # firmware0_opt = "true/false" firmware0_desc = "exos21.rom (Enterprise 128 Expandible OS 2.1)" -firmware0_path = "ep128emu/roms/exos21.rom"; +firmware0_path = "ep128emu/roms/exos21.rom" firmware0_opt = "true" firmware1_desc = "basic21.rom (Enterprise 128 BASIC Interpreter v2.1)" -firmware1_path = "ep128emu/roms/basic21.rom"; +firmware1_path = "ep128emu/roms/basic21.rom" firmware1_opt = "true" firmware2_desc = "exdos13.rom (Enterprise 128 Disk Controller v1.3)" -firmware2_path = "ep128emu/roms/exdos13.rom"; +firmware2_path = "ep128emu/roms/exdos13.rom" firmware2_opt = "true" firmware3_desc = "exos20.rom (Enterprise 64 Expandible OS 2.0)" -firmware3_path = "ep128emu/roms/exos20.rom"; +firmware3_path = "ep128emu/roms/exos20.rom" firmware3_opt = "true" firmware4_desc = "basic20.rom (Enterprise 64 BASIC Interpreter v2.0)" -firmware4_path = "ep128emu/roms/basic20.rom"; +firmware4_path = "ep128emu/roms/basic20.rom" firmware4_opt = "true" firmware5_desc = "epfileio.rom (Enterprise 128 Direct File I/O)" -firmware5_path = "ep128emu/roms/epfileio.rom"; +firmware5_path = "ep128emu/roms/epfileio.rom" firmware5_opt = "true" firmware6_desc = "exos24uk.rom (Enterprise 128 Expandible OS 2.4)" -firmware6_path = "ep128emu/roms/exos24uk.rom"; +firmware6_path = "ep128emu/roms/exos24uk.rom" firmware6_opt = "true" firmware7_desc = "hun.rom (Enterprise 128 Hungarian language extension)" -firmware7_path = "ep128emu/roms/hun.rom"; +firmware7_path = "ep128emu/roms/hun.rom" firmware7_opt = "true" firmware8_desc = "epd19hft.rom (Enterprise 128 EP-DOS with Hungarian language extension)" -firmware8_path = "ep128emu/roms/epd19hft.rom"; +firmware8_path = "ep128emu/roms/epd19hft.rom" firmware8_opt = "true" firmware9_desc = "zt19hfnt.rom (Enterprise 128 ZozoTools with Hungarian language extension 1.9)" -firmware9_path = "ep128emu/roms/zt19hfnt.rom"; +firmware9_path = "ep128emu/roms/zt19hfnt.rom" firmware9_opt = "true" firmware10_desc = "brd.rom (Enterprise 128 German language extension)" -firmware10_path = "ep128emu/roms/brd.rom"; +firmware10_path = "ep128emu/roms/brd.rom" firmware10_opt = "true" firmware11_desc = "zt19uk.rom (Enterprise 128 ZozoTools extension)" -firmware11_path = "ep128emu/roms/zt19uk.rom"; +firmware11_path = "ep128emu/roms/zt19uk.rom" firmware11_opt = "true" firmware12_desc = "tvc22_sys.rom (Videoton TVC system BIOS)" -firmware12_path = "ep128emu/roms/tvc22_sys.rom"; +firmware12_path = "ep128emu/roms/tvc22_sys.rom" firmware12_opt = "true" firmware13_desc = "tvc22_ext.rom (Videoton TVC extension BIOS)" -firmware13_path = "ep128emu/roms/tvc22_ext.rom"; +firmware13_path = "ep128emu/roms/tvc22_ext.rom" firmware13_opt = "true" firmware14_desc = "tvcfileio.rom (Videoton TVC Direct File I/O)" -firmware14_path = "ep128emu/roms/tvcfileio.rom"; +firmware14_path = "ep128emu/roms/tvcfileio.rom" firmware14_opt = "true" firmware15_desc = "tvc_dos12d.rom (Videoton TVC disk BIOS)" -firmware15_path = "ep128emu/roms/tvc_dos12d.rom"; +firmware15_path = "ep128emu/roms/tvc_dos12d.rom" firmware15_opt = "true" firmware16_desc = "cpc464.rom (Amstrad CPC 464 BIOS)" -firmware16_path = "ep128emu/roms/cpc464.rom"; +firmware16_path = "ep128emu/roms/cpc464.rom" firmware16_opt = "true" firmware17_desc = "cpc664.rom (Amstrad CPC 664 BIOS)" -firmware17_path = "ep128emu/roms/cpc664.rom"; +firmware17_path = "ep128emu/roms/cpc664.rom" firmware17_opt = "true" firmware18_desc = "cpc6128.rom (Amstrad CPC 6128 BIOS)" -firmware18_path = "ep128emu/roms/cpc6128.rom"; +firmware18_path = "ep128emu/roms/cpc6128.rom" firmware18_opt = "true" firmware19_desc = "cpc_amsdos.rom (Amstrad CPC AMSDOS BIOS)" -firmware19_path = "ep128emu/roms/cpc_amsdos.rom"; +firmware19_path = "ep128emu/roms/cpc_amsdos.rom" firmware19_opt = "true" firmware20_desc = "zx128.rom (ZX Spectrum 128 BIOS)" -firmware20_path = "ep128emu/roms/zx128.rom"; +firmware20_path = "ep128emu/roms/zx128.rom" firmware20_opt = "true" firmware21_desc = "zx48.rom (ZX Spectrum 48 BIOS)" -firmware21_path = "ep128emu/roms/zx48.rom"; +firmware21_path = "ep128emu/roms/zx48.rom" firmware21_opt = "true" # Additional notes: @@ -145,11 +145,11 @@ savestate = "true" # If true, how complete is the savestate support? basic, serialized (rewind), deterministic (netplay/runahead) savestate_features = "serialized" # Does the core support the libretro cheat interface? -cheats = "false" +cheats = "true" # Does the core support libretro input descriptors input_descriptors = "true" # Does the core support memory descriptors commonly used for achievements -memory_descriptors = "false" +memory_descriptors = "true" # Does the core use the libretro save interface or does it do its own thing (like with shared memory cards)? libretro_saves = "true" # Does the core support the core options interface? @@ -171,7 +171,7 @@ hw_render = "false" # Does the core require ongoing access to the file after loading? Mostly used for softpatching and streaming of data needs_fullpath = "true" # Does the core support the libretro disk control interface for swapping disks on the fly? -disk_control = "false" +disk_control = "true" # Is the core currently suitable for general use? That is, will regular users find it useful or is it for development/testing only (subject to change over time)? is_experimental = "false"