changeset 2342:9f0c67e5c50a

Implement CD-ROM data sector scrambling/descrambling
author Michael Pavone <pavone@retrodev.com>
date Sun, 01 Oct 2023 23:39:48 -0700
parents e81c6a44274c
children 49bd818ec9d8
files cdimage.c cdimage.h lc8951.c lc8951.h system.h
diffstat 5 files changed, 39 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/cdimage.c	Sun Sep 17 23:03:28 2023 -0700
+++ b/cdimage.c	Sun Oct 01 23:39:48 2023 -0700
@@ -6,6 +6,16 @@
 #include "util.h"
 #include "wave.h"
 
+uint8_t cdrom_scramble(uint16_t *lsfr, uint8_t data)
+{
+	data ^= *lsfr;
+	uint16_t new_bit = *lsfr;
+	*lsfr >>= 1;
+	new_bit = (new_bit ^ *lsfr) & 1;
+	*lsfr |= new_bit << 14;
+	return data;
+}
+
 static char* cmd_start(char *cur)
 {
 	while (*cur && isblank(*cur))
@@ -127,6 +137,9 @@
 				fseek(media->tracks[track].f, media->tracks[track].file_offset + lba * media->tracks[track].sector_bytes, SEEK_SET);
 			}
 		}
+		if (media->tracks[track].type == TRACK_DATA) {
+			media->cdrom_scramble_lsfr = 1;
+		}
 	}
 	return track;
 }
@@ -154,32 +167,38 @@
 
 static uint8_t bin_read(system_media *media, uint32_t offset)
 {
+	uint8_t retval;
 	if (media->in_fake_pregap == FAKE_DATA) {
-		return fake_read(media->cur_sector, offset);
+		retval = fake_read(media->cur_sector, offset);
 	} else if (media->in_fake_pregap == FAKE_AUDIO) {
-		return 0;
+		retval = 0;
 	} else if ((media->tracks[media->cur_track].sector_bytes < 2352 && offset < 16) || offset > (media->tracks[media->cur_track].sector_bytes + 16)) {
-		return fake_read(media->cur_sector, offset);
+		retval = fake_read(media->cur_sector, offset);
 	} else if (media->tracks[media->cur_track].flac) {
 		if (offset & 3) {
-			return media->byte_storage[(offset & 3) - 1];
+			retval = media->byte_storage[(offset & 3) - 1];
 		} else {
 			int16_t samples[2];
 			flac_get_sample(media->tracks[media->cur_track].flac, samples, 2);
 			media->byte_storage[0] = samples[0] >> 8;
 			media->byte_storage[1] = samples[1];
 			media->byte_storage[2] = samples[1] >> 8;
-			return samples[0];
+			retval = samples[0];
 		}
 	} else {
 		if (media->tracks[media->cur_track].need_swap) {
 			if (offset & 1) {
-				return media->byte_storage[0];
+				retval = media->byte_storage[0];
 			}
 			media->byte_storage[0] = fgetc(media->tracks[media->cur_track].f);
+		} else {
+			retval = fgetc(media->tracks[media->cur_track].f);
 		}
-		return fgetc(media->tracks[media->cur_track].f);
 	}
+	if (offset >= 12 && media->tracks[media->cur_track].type == TRACK_DATA) {
+		retval = cdrom_scramble(&media->cdrom_scramble_lsfr, retval);
+	}
+	return retval;
 }
 
 static uint8_t bin_subcode_read(system_media *media, uint32_t offset)
--- a/cdimage.h	Sun Sep 17 23:03:28 2023 -0700
+++ b/cdimage.h	Sun Oct 01 23:39:48 2023 -0700
@@ -6,5 +6,6 @@
 uint32_t make_iso_media(system_media *media, const char *filename);
 void cdimage_serialize(system_media *media, serialize_buffer *buf);
 void cdimage_deserialize(deserialize_buffer *buf, void *vmedia);
+uint8_t cdrom_scramble(uint16_t *lsfr, uint8_t data);
 
 #endif //CUE_H_
--- a/lc8951.c	Sun Sep 17 23:03:28 2023 -0700
+++ b/lc8951.c	Sun Oct 01 23:39:48 2023 -0700
@@ -1,5 +1,6 @@
 #include "lc8951.h"
 #include "backend.h"
+#include "cdimage.h"
 
 enum {
 	COMIN,
@@ -62,6 +63,7 @@
 //CTRL1
 #define BIT_SYIEN  0x80
 #define BIT_SYDEN  0x40
+#define BIT_DSCREN 0x20
 
 //STAT0
 #define BIT_CRCOK  0x80
@@ -315,11 +317,7 @@
 
 	uint8_t sync_detected = 0, sync_ignored = 0;
 	if (byte == 0) {
-		// HACK!: The (sector_offset < 0x10) check is not correct, but without it Thunderhawk gets stuck
-		// It has a sector that contains the sync pattern in the main data area
-		// From the LC8951 datasheet, I would expect tohis to trigger a short block, but either
-		// it's sync detection is fancier than I thought or I have a bug that is confusing the BIOS
-		if (context->sync_counter == 11 && ((sector_offset & 3) == 3) && (sector_offset < 0x10)) {
+		if (context->sync_counter == 11) {
 			if (context->ctrl1 & BIT_SYDEN) {
 				sync_detected = 1;
 			} else {
@@ -335,6 +333,11 @@
 		context->sync_counter = 0;
 	}
 
+	//TODO: figure out if chip tries to avoid descrambling sync signal
+	if (context->ctrl1 & BIT_DSCREN) {
+		byte = cdrom_scramble(&context->scrambler_lsfr, byte);
+	}
+
 	uint8_t sync_inserted = 0;
 	if (context->ctrl1 & BIT_SYIEN && context->sector_counter == 2351) {
 		sync_inserted = 1;
@@ -359,6 +362,7 @@
 			context->regs[STAT0] |= BIT_ILSYNC;
 		}
 		context->sector_counter = 0;
+		context->scrambler_lsfr = 1;
 
 		//header/status regs no longer considered "valid"
 		context->regs[STAT3] |= BIT_VALST;
@@ -373,7 +377,7 @@
 				context->regs[PTL] = block_start;
 				context->regs[PTH] = block_start >> 8;
 			}
-			printf("Decoding block starting at %X (WRRQ: %d)\n", context->regs[PTL] | (context->regs[PTH] << 8), !!(context->ctrl0 & BIT_WRRQ));
+			printf("Decoding block starting at %X (WRRQ: %d, sector_offset: %X)\n", context->regs[PTL] | (context->regs[PTH] << 8), !!(context->ctrl0 & BIT_WRRQ), sector_offset);
 			//Based on measurements of a Wondermega M1 (LC8951) with SYDEN, SYIEN and DECEN only
 			context->decode_end = context->cycle + 22030 * context->clock_step;
 		}
--- a/lc8951.h	Sun Sep 17 23:03:28 2023 -0700
+++ b/lc8951.h	Sun Oct 01 23:39:48 2023 -0700
@@ -23,6 +23,7 @@
 	uint8_t  comin[8];
 
 	uint16_t dac;
+	uint16_t scrambler_lsfr;
 	uint8_t  comin_write;
 	uint8_t  comin_count;
 	uint8_t  ifctrl;
--- a/system.h	Sun Sep 17 23:03:28 2023 -0700
+++ b/system.h	Sun Oct 01 23:39:48 2023 -0700
@@ -142,6 +142,7 @@
 	uint32_t     cur_track;
 	uint32_t     size;
 	uint32_t     cur_sector;
+	uint16_t     cdrom_scramble_lsfr;
 	media_type   type;
 	uint8_t      in_fake_pregap;
 	uint8_t      byte_storage[3];