changeset 2076:3f29e2726522

Added basic support for ISO images for games that only have a data track
author Michael Pavone <pavone@retrodev.com>
date Mon, 31 Jan 2022 22:07:18 -0800
parents 983f57d08eff
children c3241eff3c3a
files blastem.c cdd_mcu.c cue.c cue.h system.h
diffstat 5 files changed, 124 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/blastem.c	Mon Jan 31 19:05:54 2022 -0800
+++ b/blastem.c	Mon Jan 31 22:07:18 2022 -0800
@@ -188,11 +188,18 @@
 		free(ext);
 		return load_media_zip(filename, dst);
 	}
+	if (ext && !strcasecmp(ext, "iso")) {
+		if (stype) {
+			*stype = SYSTEM_SEGACD;
+		}
+		return make_iso_media(dst, filename);
+	}
 	free(ext);
 	ROMFILE f = romopen(filename, "rb");
 	if (!f) {
 		return 0;
 	}
+
 	if (sizeof(header) != romread(header, 1, sizeof(header), f)) {
 		fatal_error("Error reading from %s\n", filename);
 	}
@@ -248,15 +255,8 @@
 	return ret;
 }
 
-
-
 int break_on_sync = 0;
 char *save_state_path;
-
-
-
-
-
 char * save_filename;
 system_header *current_system;
 system_header *menu_system;
--- a/cdd_mcu.c	Mon Jan 31 19:05:54 2022 -0800
+++ b/cdd_mcu.c	Mon Jan 31 22:07:18 2022 -0800
@@ -39,10 +39,12 @@
 	context->next_int_cycle = CYCLE_NEVER;
 	context->last_subcode_cycle = CYCLE_NEVER;
 	context->last_nibble_cycle = CYCLE_NEVER;
+	context->last_byte_cycle = CYCLE_NEVER;
 	context->requested_format = SF_NOTREADY;
 	context->media = media;
 	context->current_status_nibble = -1;
 	context->current_cmd_nibble = -1;
+	context->current_sector_byte = -1;
 }
 
 enum {
@@ -111,24 +113,7 @@
 		handle_seek(context);
 		if (!context->seeking) {
 			context->head_pba++;
-			uint32_t lba = context->head_pba - LEADIN_SECTORS;
-			for (uint32_t i = 0; i < context->media->num_tracks; i++)
-			{
-				if (lba < context->media->tracks[i].fake_pregap) {
-					context->in_fake_pregap = 1;
-					break;
-				}
-				lba -= context->media->tracks[i].fake_pregap;
-				if (lba < context->media->tracks[i].start_lba) {
-					context->in_fake_pregap = 1;
-					break;
-				}
-				if (lba < context->media->tracks[i].end_lba) {
-					fseek(context->media->f, lba * 2352, SEEK_SET);
-					context->in_fake_pregap = 0;
-					break;
-				}
-			}
+			context->media->seek(context->media, context->head_pba - LEADIN_SECTORS);
 		}
 		break;
 	case DS_PAUSE:
@@ -523,28 +508,7 @@
 			}
 		}
 		if (context->cycle >= next_byte) {
-			uint8_t byte;
-			if (context->in_fake_pregap) {
-				if (!context->current_sector_byte || (context->current_sector_byte >= 16)) {
-					byte = 0;
-					//TODO: error detection and correction bytes
-				} else if (context->current_sector_byte < 12) {
-					byte = 0xFF;
-				} else if (context->current_sector_byte == 12) {
-					uint32_t minute = ((context->head_pba - LEADIN_SECTORS) / 75) / 60;
-					byte = (minute % 10) | ((minute / 10 ) << 4);
-				} else if (context->current_sector_byte == 13) {
-					uint32_t seconds = ((context->head_pba - LEADIN_SECTORS) / 75) % 60;
-					byte = (seconds % 10) | ((seconds / 10 ) << 4);
-				} else if (context->current_sector_byte == 14) {
-					uint32_t frames = (context->head_pba - LEADIN_SECTORS) % 75;
-					byte = (frames % 10) | ((frames / 10 ) << 4);
-				} else {
-					byte = 1;
-				}
-			} else {
-				byte = fgetc(context->media->f);
-			}
+			uint8_t byte = context->media->read(context->media, context->current_sector_byte);
 			lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), context->current_sector_byte++, byte);
 			context->last_byte_cycle = context->cycle;
 			if (context->current_sector_byte == 2352) {
--- a/cue.c	Mon Jan 31 19:05:54 2022 -0800
+++ b/cue.c	Mon Jan 31 22:07:18 2022 -0800
@@ -43,6 +43,81 @@
 
 }
 
+static void bin_seek(system_media *media, uint32_t sector)
+{
+	media->cur_sector = sector;
+	uint32_t lba = sector;
+	for (uint32_t i = 0; i < media->num_tracks; i++)
+	{
+		if (lba < media->tracks[i].fake_pregap) {
+			media->in_fake_pregap = 1;
+			break;
+		}
+		lba -= media->tracks[i].fake_pregap;
+		if (lba < media->tracks[i].start_lba) {
+			media->in_fake_pregap = 1;
+			break;
+		}
+		if (lba < media->tracks[i].end_lba) {
+			media->in_fake_pregap = 0;
+			break;
+		}
+	}
+	if (!media->in_fake_pregap) {
+		fseek(media->f, lba * 2352, SEEK_SET);
+	}
+}
+
+static uint8_t fake_read(uint32_t sector, uint32_t offset)
+{
+	if (!offset || (offset >= 16)) {
+		return 0;
+		//TODO: error detection and correction bytes
+	} else if (offset < 12) {
+		return 0xFF;
+	} else if (offset == 12) {
+		uint32_t minute = (sector / 75) / 60;
+		return (minute % 10) | ((minute / 10 ) << 4);
+	} else if (offset == 13) {
+		uint32_t seconds = (sector / 75) % 60;
+		return (seconds % 10) | ((seconds / 10 ) << 4);
+	} else if (offset == 14) {
+		uint32_t frames = sector % 75;
+		return (frames % 10) | ((frames / 10 ) << 4);
+	} else {
+		return 1;
+	}
+}
+
+static uint8_t bin_read(system_media *media, uint32_t offset)
+{
+	if (media->in_fake_pregap) {
+		return fake_read(media->cur_sector, offset);
+	} else {
+		return fgetc(media->f);
+	}
+}
+
+static void iso_seek(system_media *media, uint32_t sector)
+{
+	media->cur_sector = sector;
+	if (sector < (2 * 75)) {
+		media->in_fake_pregap = 1;
+	} else {
+		media->in_fake_pregap = 0;
+		fseek(media->f, (sector -  2 * 75) * 2048, SEEK_SET);
+	}
+}
+
+static uint8_t iso_read(system_media *media, uint32_t offset)
+{
+	if (media->in_fake_pregap || offset < 16 || offset > (2048 + 16)) {
+		return fake_read(media->cur_sector, offset);
+	} else {
+		return fgetc(media->f);
+	}
+}
+
 uint8_t parse_cue(system_media *media)
 {
 	char *line = media->buffer;
@@ -153,8 +228,38 @@
 
 		fseek(media->f, 16, SEEK_SET);
 		media->size = fread(media->buffer, 1, 2048, media->f);
+		media->seek = bin_seek;
+		media->read = bin_read;
 	}
 	uint8_t valid = tracks > 0 && media->f != NULL;
 	media->type = valid ? MEDIA_CDROM : MEDIA_CART;
 	return valid;
 }
+
+uint32_t make_iso_media(system_media *media, const char *filename)
+{
+	media->f = fopen(filename, "rb");
+	if (!media->f) {
+		return 0;
+	}
+	media->buffer = calloc(2048, 1);
+	media->size = fread(media->buffer, 1, 2048, media->f);
+	media->num_tracks = 2;
+	media->tracks = calloc(sizeof(track_info), 2);
+	media->tracks[0] = (track_info){
+		.fake_pregap = 2 * 75,
+		.start_lba = 0,
+		.end_lba = file_size(media->f),
+		.type = TRACK_DATA
+	};
+	media->tracks[1] = (track_info){
+		.fake_pregap = 2 * 75,
+		.start_lba = media->tracks[0].end_lba,
+		.end_lba = media->tracks[0].end_lba + 2 * 75,
+		.type = TRACK_DATA
+	};
+	media->type = MEDIA_CDROM;
+	media->seek = iso_seek;
+	media->read = iso_read;
+	return media->size;
+}
--- a/cue.h	Mon Jan 31 19:05:54 2022 -0800
+++ b/cue.h	Mon Jan 31 22:07:18 2022 -0800
@@ -2,5 +2,6 @@
 #define CUE_H_
 
 uint8_t parse_cue(system_media *media);
+uint32_t make_iso_media(system_media *media, const char *filename);
 
 #endif //CUE_H_
--- a/system.h	Mon Jan 31 19:05:54 2022 -0800
+++ b/system.h	Mon Jan 31 22:07:18 2022 -0800
@@ -98,6 +98,9 @@
 	track_type type;
 } track_info;
 
+typedef void (*seek_fun)(system_media *media, uint32_t sector);
+typedef uint8_t (*read_fun)(system_media *media, uint32_t offset);
+
 struct system_media {
 	void         *buffer;
 	char         *dir;
@@ -106,9 +109,13 @@
 	system_media *chain;
 	track_info   *tracks;
 	FILE         *f;
+	seek_fun     seek;
+	read_fun     read;
 	uint32_t     num_tracks;
 	uint32_t     size;
+	uint32_t     cur_sector;
 	media_type   type;
+	uint8_t      in_fake_pregap;
 };
 
 #define OPT_ADDRESS_LOG (1U << 31U)