Add hard disk and m3u support to retro core

This commit is contained in:
Craig Carnell authored and Thomas Huth committed 2026-10-24 08:26:01 +02:00
1 parent 7dd6a196cd
commit 56524ef6a5
7 files changed
+328 -14

No files matched your search

+2 -2
View File
@@ -1,7 +1,7 @@
include_directories(. ../.. ../includes ../debug ../falcon)
add_library(UiRetro OBJECT audio.c disk_control.c joy_ui.c gui_event.c keymap.c main_retro.c
microphone.c options.c screen.c statusbar.c timing.c)
add_library(UiRetro OBJECT audio.c disk_control.c harddisk.c joy_ui.c gui_event.c keymap.c
main_retro.c microphone.c options.c screen.c statusbar.c timing.c)
target_include_directories(UiRetro PRIVATE ${LIBRETRO_INCLUDE_DIR})
set_target_properties(UiRetro PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
+129
View File
@@ -72,6 +72,115 @@ static void DiskControl_UpdateLabel(unsigned int idx)
DiskImages[idx].label[sizeof(DiskImages[idx].label) - 1] = '\0';
}
/**
* Return true if 'p' looks like an absolute path.
*/
static bool DiskControl_PathIsAbsolute(const char *p)
{
if (!p || !p[0])
return false;
if (p[0] == '/' || p[0] == '\\')
return true;
#if defined(_WIN32) || defined(WIN32)
if (p[1] == ':')
return true;
#endif
return false;
}
/**
* Parse a .m3u file
*/
static unsigned int DiskControl_ParseM3U(const char *m3u_path)
{
uint8_t *raw;
long size = 0;
char *text, *p;
char dir[FILENAME_MAX], name[FILENAME_MAX], ext[FILENAME_MAX];
DiskImagesCount = 0;
raw = File_ReadAsIs(m3u_path, &size);
if (!raw || size <= 0)
{
Log_Printf(LOG_ERROR, "DiskControl: could not read m3u file '%s'\n", m3u_path);
free(raw);
return 0;
}
text = malloc((size_t)size + 1);
if (!text)
{
free(raw);
return 0;
}
memcpy(text, raw, (size_t)size);
text[size] = '\0';
free(raw);
File_SplitPath(m3u_path, dir, name, ext);
p = text;
while (*p)
{
char *line, *eol;
char full[FILENAME_MAX];
while (*p == '\r' || *p == '\n')
p++;
if (!*p)
break;
line = p;
eol = strpbrk(p, "\r\n");
if (eol)
{
*eol = '\0';
p = eol + 1;
}
else
{
p += strlen(p);
}
while (*line == ' ' || *line == '\t')
line++;
if (!*line || *line == '#')
continue;
if (DiskControl_PathIsAbsolute(line))
{
strncpy(full, line, sizeof(full) - 1);
full[sizeof(full) - 1] = '\0';
}
else
{
char *built = File_MakePath(dir, line, NULL);
if (!built)
continue;
strncpy(full, built, sizeof(full) - 1);
full[sizeof(full) - 1] = '\0';
free(built);
}
if (!DiskControl_EnsureCapacity(DiskImagesCount + 1))
break;
strncpy(DiskImages[DiskImagesCount].path, full,
sizeof(DiskImages[DiskImagesCount].path) - 1);
DiskImages[DiskImagesCount].path[sizeof(DiskImages[DiskImagesCount].path) - 1] = '\0';
DiskControl_UpdateLabel(DiskImagesCount);
DiskImagesCount++;
}
free(text);
Log_Printf(LOG_INFO, "DiskControl: m3u '%s' parsed, %u file(s) found.\n",
m3u_path, DiskImagesCount);
return DiskImagesCount;
}
/**
* (Re-)insert the image at CurrentImageIndex into floppy drive A
*/
@@ -253,6 +362,26 @@ void DiskControl_NewGame(const char *path)
}
}
void DiskControl_NewGameM3U(const char *m3u_path)
{
unsigned int n;
bTrayEjected = false;
n = DiskControl_ParseM3U(m3u_path);
if (n == 0)
{
DiskImagesCount = 0;
CurrentImageIndex = 0;
Floppy_SetDiskFileNameNone(0);
Floppy_EjectDiskFromDrive(0);
return;
}
CurrentImageIndex = 0;
DiskControl_ApplyCurrentImage();
}
void DiskControl_UnInit(void)
{
free(DiskImages);
+1
View File
@@ -9,6 +9,7 @@
void DiskControl_Init(void);
void DiskControl_NewGame(const char *path);
void DiskControl_NewGameM3U(const char *m3u_path);
void DiskControl_UnInit(void);
#endif /* HATARI_RETRO_DISK_CONTROL_H */
+130
View File
@@ -0,0 +1,130 @@
/*
Hatari - harddisk.c
This file is distributed under the GNU General Public License, version 2
or at your option any later version. Read the file gpl.txt for details.
*/
#include <string.h>
#include <stdio.h>
#include <libretro.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#include "main.h"
#include "main_retro.h"
#include "harddisk.h"
#include "configuration.h"
#include "file.h"
#include "floppy.h"
#include "gemdos.h"
#include "hdc.h"
#include "ide.h"
#include "log.h"
#include "ncr5380.h"
#include "reset.h"
/**
* Insert a raw HD image into the IDE master slot and reboot so TOS
* picks it up.
*/
void HardDisk_InsertIde(const char *path)
{
Ide_UnInit();
ConfigureParams.Ide[0].bUseDevice = true;
ConfigureParams.Ide[0].nByteSwap = BYTESWAP_AUTO;
ConfigureParams.Ide[0].nBlockSize = 512;
strncpy(ConfigureParams.Ide[0].sDeviceFile, path,
sizeof(ConfigureParams.Ide[0].sDeviceFile) - 1);
ConfigureParams.Ide[0].sDeviceFile[sizeof(ConfigureParams.Ide[0].sDeviceFile) - 1] = '\0';
File_MakeAbsoluteName(ConfigureParams.Ide[0].sDeviceFile);
Ide_Init();
Log_Printf(LOG_INFO, "HardDisk (%s) inserted into IDE master slot.\n", path);
Reset_Cold();
}
/**
* Insert a raw HD image into ACSI slot 0 and reboot so TOS picks it up.
*/
void HardDisk_InsertAcsi(const char *path)
{
HDC_UnInit();
Ncr5380_UnInit();
ConfigureParams.Acsi[0].bUseDevice = true;
ConfigureParams.Acsi[0].nBlockSize = 512;
ConfigureParams.Acsi[0].nScsiVersion = 1;
strncpy(ConfigureParams.Acsi[0].sDeviceFile, path,
sizeof(ConfigureParams.Acsi[0].sDeviceFile) - 1);
ConfigureParams.Acsi[0].sDeviceFile[sizeof(ConfigureParams.Acsi[0].sDeviceFile) - 1] = '\0';
File_MakeAbsoluteName(ConfigureParams.Acsi[0].sDeviceFile);
HDC_Init();
Ncr5380_Init();
Log_Printf(LOG_INFO, "HardDisk (%s) inserted into ACSI slot 0.\n", path);
Reset_Cold();
}
/**
* Enable GEMDOS HD directory emulation
*/
void HardDisk_SetGemdosDrive(const char *path)
{
char dir[FILENAME_MAX];
size_t len = strlen(path);
if (len >= 4 && strcasecmp(path + len - 4, ".gem") == 0)
len -= 4;
if (len >= sizeof(dir))
len = sizeof(dir) - 1;
memcpy(dir, path, len);
dir[len] = '\0';
GemDOS_UnInitDrives();
strncpy(ConfigureParams.HardDisk.szHardDiskDirectories[0], dir,
sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]) - 1);
ConfigureParams.HardDisk.szHardDiskDirectories[0][sizeof(ConfigureParams.HardDisk.szHardDiskDirectories[0]) - 1] = '\0';
File_CleanFileName(ConfigureParams.HardDisk.szHardDiskDirectories[0]);
File_MakeAbsoluteName(ConfigureParams.HardDisk.szHardDiskDirectories[0]);
ConfigureParams.HardDisk.bUseHardDiskDirectories = true;
ConfigureParams.HardDisk.bBootFromHardDisk = true;
GemDOS_InitDrives();
Log_Printf(LOG_INFO, "GEMDOS HDD emulation set to '%s'.\n",
ConfigureParams.HardDisk.szHardDiskDirectories[0]);
if (retro_system_directory && retro_system_directory[0])
{
char boot_path[FILENAME_MAX];
snprintf(boot_path, sizeof(boot_path), "%s%chatari%cBOOT.ST",
retro_system_directory, PATHSEP, PATHSEP);
if (File_Exists(boot_path))
{
Floppy_SetDiskFileName(0, boot_path, NULL);
Floppy_InsertDiskIntoDrive(0);
}
else
{
Log_Printf(LOG_WARN, "GEMDOS HDD boot floppy '%s' not found, "
"content may not autoboot.\n", boot_path);
}
}
else
{
Log_Printf(LOG_WARN, "GEMDOS HDD: no system directory available, "
"cannot look for BOOT.ST helper floppy.\n");
}
Reset_Cold();
}
+14
View File
@@ -0,0 +1,14 @@
/*
Hatari - harddisk.h
This file is distributed under the GNU General Public License, version 2
or at your option any later version. Read the file gpl.txt for details.
*/
#ifndef HATARI_RETRO_HARDDISK_H
#define HATARI_RETRO_HARDDISK_H
void HardDisk_InsertIde(const char *path);
void HardDisk_InsertAcsi(const char *path);
void HardDisk_SetGemdosDrive(const char *path);
#endif /* HATARI_RETRO_HARDDISK_H */
+51 -11
View File
@@ -1,4 +1,5 @@
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -12,6 +13,7 @@
#include "disk_control.h"
#include "file.h"
#include "floppy.h"
#include "harddisk.h"
#include "memorySnapShot.h"
#include "m68000.h"
#include "options.h"
@@ -153,7 +155,7 @@ RETRO_API void retro_get_system_info(struct retro_system_info *info)
info->library_name = "hatari";
info->library_version = HATARI_VERSION;
info->need_fullpath = true;
info->valid_extensions = "st|msa|dim|stx";
info->valid_extensions = "st|msa|dim|stx|ipf|m3u|ide|vhd|gem";
}
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
@@ -294,18 +296,56 @@ RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
RETRO_API bool retro_load_game(const struct retro_game_info *game)
{
if (game)
Floppy_SetDiskFileName(0, game->path, NULL);
if (game && game->path)
{
const char *path = game->path;
if (File_DoesFileExtensionMatch(path, ".m3u"))
{
DiskControl_NewGameM3U(path);
}
else if (File_DoesFileExtensionMatch(path, ".ide"))
{
Floppy_SetDiskFileNameNone(0);
DiskControl_NewGame(NULL);
HardDisk_InsertIde(path);
}
else if (File_DoesFileExtensionMatch(path, ".vhd"))
{
Floppy_SetDiskFileNameNone(0);
DiskControl_NewGame(NULL);
HardDisk_InsertAcsi(path);
}
else if (File_DoesFileExtensionMatch(path, ".gem"))
{
DiskControl_NewGame(NULL);
HardDisk_SetGemdosDrive(path);
}
else
{
#ifndef HAVE_CAPSIMAGE
if (File_DoesFileExtensionMatch(path, ".ipf"))
{
Log_Printf(LOG_WARN, "IPF image '%s' requested, but this build "
"was compiled without CAPSImage support.\n",
path);
}
#endif
Floppy_SetDiskFileName(0, path, NULL);
Floppy_InsertDiskIntoDrive(0);
/* insert disk B also */
if (ConfigureParams.DiskImage.szDiskFileName[1][0])
Floppy_InsertDiskIntoDrive(1);
DiskControl_NewGame(path);
}
}
else
{
Floppy_SetDiskFileNameNone(0);
Floppy_InsertDiskIntoDrive(0);
// insert disk B also
if (ConfigureParams.DiskImage.szDiskFileName[1][0])
Floppy_InsertDiskIntoDrive(1);
DiskControl_NewGame(game ? game->path : NULL);
DiskControl_NewGame(NULL);
}
Retro_SetInputDescriptors();
+1 -1
View File
@@ -6,7 +6,7 @@
*/
extern bool has_cpu_config_changed;
extern const char *retro_system_directory;
extern retro_environment_t environment_cb;
extern retro_video_refresh_t video_refresh_cb;
extern retro_input_state_t input_state_cb;