4 Commits

Author SHA1 Message Date
clobber 02499a735b Bump version for sparkle updater 2018-11-26 23:18:38 -06:00
clobber 2875815a60 GG: Add display mode change support 2018-11-26 23:17:54 -06:00
clobber f1828430d3 Cleanup 2018-11-26 21:10:10 -06:00
clobber 682625653b Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/2ab02c8122d5127fe4a884ed8b65a3c767c90fb9 2018-11-26 18:54:25 -06:00
7 changed files with 260 additions and 81 deletions
+146 -47
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2015, OpenEmu Team
Copyright (c) 2018, OpenEmu Team
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -36,6 +36,14 @@
#include "shared.h"
#include "scrc32.h"
#define OptionDefault(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @YES, }
#define Option(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, }
#define OptionIndented(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeIndentationLevelKey : @(1), }
#define OptionToggleable(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, }
#define OptionToggleableNoSave(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, OEGameCoreDisplayModeDisallowPrefSaveKey : @YES, }
#define Label(_NAME_) @{ OEGameCoreDisplayModeLabelKey : _NAME_, }
#define SeparatorItem() @{ OEGameCoreDisplayModeSeparatorItemKey : @"",}
static const double pal_fps = 53203424.0 / (3420.0 * 313.0);
static const double ntsc_fps = 53693175.0 / (3420.0 * 262.0);
@@ -99,9 +107,10 @@ typedef NS_ENUM(NSInteger, MultiTapType)
@interface GenPlusGameCore () <OEGenesisSystemResponderClient, OESegaCDSystemResponderClient>
{
uint8_t *videoBuffer;
int16_t *soundBuffer;
NSMutableDictionary *cheatList;
uint8_t *_videoBuffer;
int16_t *_soundBuffer;
NSMutableDictionary<NSString *, NSNumber *> *_cheatList;
NSMutableArray <NSMutableDictionary <NSString *, id> *> *_availableDisplayModes;
NSURL *_romFile;
MultiTapType _multiTapType;
}
@@ -119,9 +128,9 @@ static __weak GenPlusGameCore *_current;
{
if((self = [super init]))
{
videoBuffer = (uint8_t*)malloc(720 * 576 * 4);
soundBuffer = (int16_t *)malloc(2048 * 2 * 2);
cheatList = [NSMutableDictionary dictionary];
_videoBuffer = (uint8_t *)malloc(720 * 576 * sizeof(uint32_t));
_soundBuffer = (int16_t *)malloc(2048 * 2 * sizeof(int16_t));
_cheatList = [NSMutableDictionary dictionary];
}
_current = self;
@@ -131,8 +140,8 @@ static __weak GenPlusGameCore *_current;
- (void)dealloc
{
free(videoBuffer);
free(soundBuffer);
free(_videoBuffer);
free(_soundBuffer);
}
# pragma mark - Execution
@@ -142,13 +151,13 @@ static __weak GenPlusGameCore *_current;
_romFile = [NSURL fileURLWithPath:path];
// Set CD BIOS and BRAM/RAM Cart paths
snprintf(CD_BIOS_EU, sizeof(CD_BIOS_EU), "%s%sbios_CD_E.bin", [[self biosDirectoryPath] fileSystemRepresentation], "/");
snprintf(CD_BIOS_US, sizeof(CD_BIOS_US), "%s%sbios_CD_U.bin", [[self biosDirectoryPath] fileSystemRepresentation], "/");
snprintf(CD_BIOS_JP, sizeof(CD_BIOS_JP), "%s%sbios_CD_J.bin", [[self biosDirectoryPath] fileSystemRepresentation], "/");
snprintf(CD_BRAM_EU, sizeof(CD_BRAM_EU), "%s%sscd_E.brm", [[self batterySavesDirectoryPath] fileSystemRepresentation], "/");
snprintf(CD_BRAM_US, sizeof(CD_BRAM_US), "%s%sscd_U.brm", [[self batterySavesDirectoryPath] fileSystemRepresentation], "/");
snprintf(CD_BRAM_JP, sizeof(CD_BRAM_JP), "%s%sscd_J.brm", [[self batterySavesDirectoryPath] fileSystemRepresentation], "/");
snprintf(CART_BRAM, sizeof(CART_BRAM), "%s%scart.brm", [[self batterySavesDirectoryPath] fileSystemRepresentation], "/");
snprintf(CD_BIOS_EU, sizeof(CD_BIOS_EU), "%s%sbios_CD_E.bin", self.biosDirectoryPath.fileSystemRepresentation, "/");
snprintf(CD_BIOS_US, sizeof(CD_BIOS_US), "%s%sbios_CD_U.bin", self.biosDirectoryPath.fileSystemRepresentation, "/");
snprintf(CD_BIOS_JP, sizeof(CD_BIOS_JP), "%s%sbios_CD_J.bin", self.biosDirectoryPath.fileSystemRepresentation, "/");
snprintf(CD_BRAM_EU, sizeof(CD_BRAM_EU), "%s%sscd_E.brm", self.batterySavesDirectoryPath.fileSystemRepresentation, "/");
snprintf(CD_BRAM_US, sizeof(CD_BRAM_US), "%s%sscd_U.brm", self.batterySavesDirectoryPath.fileSystemRepresentation, "/");
snprintf(CD_BRAM_JP, sizeof(CD_BRAM_JP), "%s%sscd_J.brm", self.batterySavesDirectoryPath.fileSystemRepresentation, "/");
snprintf(CART_BRAM, sizeof(CART_BRAM), "%s%scart.brm", self.batterySavesDirectoryPath.fileSystemRepresentation, "/");
[self configureOptions];
@@ -167,7 +176,7 @@ static __weak GenPlusGameCore *_current;
{
config.region_detect = 3;
region_code = REGION_JAPAN_NTSC;
NSLog(@"Genesis Plus GX: Forcing region to Japan for multi-region cart");
NSLog(@"[Genesis Plus GX] Forcing region to Japan for multi-region cart");
}
}
@@ -181,17 +190,17 @@ static __weak GenPlusGameCore *_current;
bram_load();
// Set battery saves dir and load sram
NSString *extensionlessFilename = [[_romFile lastPathComponent] stringByDeletingPathExtension];
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
[[NSFileManager defaultManager] createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
NSString *extensionlessFilename = _romFile.lastPathComponent.stringByDeletingPathExtension;
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
[NSFileManager.defaultManager createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
NSURL *saveFile = [batterySavesDirectory URLByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
if ([saveFile checkResourceIsReachableAndReturnError:nil])
{
NSData *saveData = [NSData dataWithContentsOfURL:saveFile];
memcpy(sram.sram, [saveData bytes], 0x10000);
memcpy(sram.sram, saveData.bytes, 0x10000);
sram.crc = crc32(0, sram.sram, 0x10000);
NSLog(@"GenesisPlusGX: Loaded sram");
NSLog(@"[Genesis Plus GX] Loaded sram");
}
if([self.systemIdentifier isEqualToString:@"openemu.system.sg"] || [self.systemIdentifier isEqualToString:@"openemu.system.scd"])
@@ -213,8 +222,8 @@ static __weak GenPlusGameCore *_current;
else
system_frame_sms(0);
int samples = audio_update(soundBuffer);
[[self ringBufferAtIndex:0] write:soundBuffer maxLength:samples << 2];
int samples = audio_update(_soundBuffer);
[[self ringBufferAtIndex:0] write:_soundBuffer maxLength:samples << 2];
}
- (void)resetEmulation
@@ -241,8 +250,8 @@ static __weak GenPlusGameCore *_current;
if ((filesize != 0) || (crc32(0, &sram.sram[0], 0x10000) != sram.crc))
{
NSError *error = nil;
NSString *extensionlessFilename = [[_romFile lastPathComponent] stringByDeletingPathExtension];
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
NSString *extensionlessFilename = _romFile.lastPathComponent.stringByDeletingPathExtension;
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
NSURL *saveFile = [batterySavesDirectory URLByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
// copy SRAM data
@@ -253,9 +262,9 @@ static __weak GenPlusGameCore *_current;
sram.crc = crc32(0, sram.sram, 0x10000);
if (error)
NSLog(@"GenesisPlusGX: Error writing sram file: %@", error);
NSLog(@"[Genesis Plus GX] Error writing sram file: %@", error);
else
NSLog(@"GenesisPlusGX: Saved sram file: %@", saveFile);
NSLog(@"[Genesis Plus GX] Saved sram file: %@", saveFile);
}
}
@@ -277,7 +286,7 @@ static __weak GenPlusGameCore *_current;
- (const void *)getVideoBufferWithHint:(void *)hint
{
if (!hint) {
hint = videoBuffer;
hint = _videoBuffer;
}
return bitmap.data = (uint8_t*)hint;
@@ -347,7 +356,7 @@ static __weak GenPlusGameCore *_current;
int serial_size = STATE_SIZE;
NSMutableData *stateData = [NSMutableData dataWithLength:serial_size];
if(!state_save([stateData mutableBytes]))
if(!state_save(stateData.mutableBytes))
{
NSError *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotSaveStateError userInfo:@{
NSLocalizedDescriptionKey : @"Save state data could not be written",
@@ -375,17 +384,17 @@ static __weak GenPlusGameCore *_current;
}
int serial_size = STATE_SIZE;
if(serial_size != [data length])
if(serial_size != data.length)
{
NSError *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreStateHasWrongSizeError userInfo:@{
NSLocalizedDescriptionKey : @"Save state has wrong file size.",
NSLocalizedRecoverySuggestionErrorKey : [NSString stringWithFormat:@"The size of the file %@ does not have the right size, %d expected, got: %ld.", fileName, serial_size, [data length]],
NSLocalizedRecoverySuggestionErrorKey : [NSString stringWithFormat:@"The size of the file %@ does not have the right size, %d expected, got: %ld.", fileName, serial_size, data.length],
}];
block(NO, error);
return;
}
if(!state_load((uint8_t *)[data bytes]))
if(!state_load((uint8_t *)data.bytes))
{
NSError *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:@{
NSLocalizedDescriptionKey : @"The save state data could not be read",
@@ -418,15 +427,15 @@ static __weak GenPlusGameCore *_current;
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError
{
const void *bytes = [state bytes];
size_t length = [state length];
const void *bytes = state.bytes;
size_t length = state.length;
size_t serialSize = STATE_SIZE;
if(serialSize != length) {
if (outError) {
*outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreStateHasWrongSizeError userInfo:@{
NSLocalizedDescriptionKey : @"Save state has wrong file size.",
NSLocalizedRecoverySuggestionErrorKey : [NSString stringWithFormat:@"The size of the save state does not have the right size, %lu expected, got: %ld.", serialSize, [state length]],
NSLocalizedRecoverySuggestionErrorKey : [NSString stringWithFormat:@"The size of the save state does not have the right size, %lu expected, got: %ld.", serialSize, state.length],
}];
}
@@ -653,18 +662,18 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
if (enabled)
cheatList[code] = @YES;
_cheatList[code] = @YES;
else
[cheatList removeObjectForKey:code];
[_cheatList removeObjectForKey:code];
[self resetCheats];
NSArray *multipleCodes = [NSArray array];
NSArray<NSString *> *multipleCodes = [NSArray array];
// Apply enabled cheats found in dictionary
for (id key in cheatList)
for (NSString *key in _cheatList)
{
if ([cheatList[key] isEqual:@YES])
if ([_cheatList[key] boolValue])
{
// Handle multi-line cheats
multipleCodes = [key componentsSeparatedByString:@"+"];
@@ -676,6 +685,84 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
}
}
# pragma mark - Display Mode
- (NSArray <NSDictionary <NSString *, id> *> *)displayModes
{
if (![self.systemIdentifier isEqualToString:@"openemu.system.gg"])
return nil;
if (_availableDisplayModes.count == 0)
{
_availableDisplayModes = [NSMutableArray array];
NSArray <NSDictionary <NSString *, id> *> *availableModesWithDefault =
@[
Label(@"Screen"),
OptionToggleable(@"LCD Ghosting", @"ggLCDFilter"),
];
// Deep mutable copy
_availableDisplayModes = (NSMutableArray *)CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)availableModesWithDefault, kCFPropertyListMutableContainers));
}
return [_availableDisplayModes copy];
}
- (void)changeDisplayWithMode:(NSString *)displayMode
{
if (_availableDisplayModes.count == 0)
[self displayModes];
// First check if 'displayMode' is valid
BOOL isDisplayModeToggleable = NO;
BOOL isValidDisplayMode = NO;
BOOL displayModeState = NO;
NSString *displayModePrefKey;
for (NSDictionary *modeDict in _availableDisplayModes) {
if ([modeDict[OEGameCoreDisplayModeNameKey] isEqualToString:displayMode]) {
displayModeState = [modeDict[OEGameCoreDisplayModeStateKey] boolValue];
displayModePrefKey = modeDict[OEGameCoreDisplayModePrefKeyNameKey];
isDisplayModeToggleable = [modeDict[OEGameCoreDisplayModeAllowsToggleKey] boolValue];
isValidDisplayMode = YES;
break;
}
}
// Disallow a 'displayMode' not found in _availableDisplayModes
if (!isValidDisplayMode)
return;
// Handle option state changes
for (NSMutableDictionary *optionDict in _availableDisplayModes) {
NSString *modeName = optionDict[OEGameCoreDisplayModeNameKey];
NSString *prefKey = optionDict[OEGameCoreDisplayModePrefKeyNameKey];
if (!modeName)
continue;
// Mutually exclusive option state change
else if ([modeName isEqualToString:displayMode] && !isDisplayModeToggleable)
optionDict[OEGameCoreDisplayModeStateKey] = @YES;
// Reset mutually exclusive options that are the same prefs group as 'displayMode'
else if (!isDisplayModeToggleable && [prefKey isEqualToString:displayModePrefKey])
optionDict[OEGameCoreDisplayModeStateKey] = @NO;
// Toggleable option state change
else if ([modeName isEqualToString:displayMode] && isDisplayModeToggleable)
optionDict[OEGameCoreDisplayModeStateKey] = @(!displayModeState);
}
// Game Gear: LCD ghosting / motion blur
// Required for proper display of some effects in a few games (James Pond 3, Power Drift, Super Monaco GP II)
if ([displayMode isEqualToString:@"LCD Ghosting"])
{
if (!displayModeState)
config.lcd = (uint8)(0.80 * 256);
else
config.lcd = 0;
}
}
# pragma mark - Misc Helper Methods
- (void)applyCheat:(NSString *)code
@@ -684,7 +771,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
clear_cheats();
/* interpret code and give it an index */
decode_cheat((char *)[code UTF8String], maxcheats);
decode_cheat((char *)code.UTF8String, maxcheats);
/* increment cheat count */
maxcheats++;
@@ -737,7 +824,19 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
config.overscan = 0; /* 3 == FULL */
config.gg_extra = 0; /* 1 = show extended Game Gear screen (256x192) */
config.ntsc = 0;
config.lcd = 0;
// Only temporary, so core doesn't crash on an older OpenEmu version
if ([self respondsToSelector:@selector(displayModeInfo)]) {
BOOL isLCDFilterEnabled = [self.displayModeInfo[@"ggLCDFilter"] boolValue];
if (isLCDFilterEnabled)
[self changeDisplayWithMode:@"LCD Ghosting"];
else
config.lcd = 0;
}
else
config.lcd = 0;
config.render = 0;
/* initialize bitmap */
@@ -745,7 +844,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
bitmap.width = 720;
bitmap.height = 576;
bitmap.pitch = bitmap.width * sizeof(uint32_t);
bitmap.data = (uint8_t *)videoBuffer;
bitmap.data = (uint8_t *)_videoBuffer;
}
- (void)configureInput
@@ -753,7 +852,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
_multiTapType = MultiTapTypeNone;
// Overrides: Six button controller-supported games missing '6' byte in cart header, so they cannot be auto-detected
NSArray *pad6Buttons = @[
NSArray<NSString *> *pad6Buttons = @[
@"b04c06df1009c60182df902a4ec7c959", // Batman Forever (World)
@"7b144947f6e8842dd4419d5166cddff6", // Boogerman - A Pick and Flick Adventure (Europe)
@"265a10bf2ea2d1ee30e6cde631d54474", // Boogerman - A Pick and Flick Adventure (USA)
@@ -790,7 +889,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
// Different port configurations and multitap devices are used depending on the game
// NOTE: J-Cart games are automatically handled.
// TODO: Identify supported Sega CD games by rominfo.domestic/rominfo.international?
NSDictionary *multiTapGames =
NSDictionary<NSString *, NSNumber *> *multiTapGames =
@{
//@"3cc6df243e714097f1599cf618f94d0b" : @(TeamPlayerPort1), // Aq Renkan Awa (Taiwan) (Unl)
@"2b27a61cdae4492044bd273c5807de75" : @(TeamPlayerPort1), // Barkley Shut Up and Jam! (USA, Europe)
@@ -1563,7 +1662,7 @@ void RAMCheatUpdate(void)
/* apply RAM patch */
//if (cheatlist[index].data & 0xFF00)
//if (cheatlist[index].data & 0x00FF) // For LSB?
BOOL isSega8bit = [[_current systemIdentifier] isEqualToString:@"openemu.system.gg"] || [[_current systemIdentifier] isEqualToString:@"openemu.system.sms"] || [[_current systemIdentifier] isEqualToString:@"openemu.system.sg1000"];
BOOL isSega8bit = [_current.systemIdentifier isEqualToString:@"openemu.system.gg"] || [_current.systemIdentifier isEqualToString:@"openemu.system.sms"] || [_current.systemIdentifier isEqualToString:@"openemu.system.sg1000"];
// TODO: Figure out why this is. Some PAR cheats for Genesis don't work otherwise.
if (isSega8bit ? cheatlist[index].data & 0xFF00 : cheatlist[index].data & 0x00FF)
{
+3 -1
View File
@@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.7.4.9</string>
<string>1.7.4.10</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
@@ -34,6 +34,8 @@
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsDisplayModeChange</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
</dict>
+30 -21
View File
@@ -211,10 +211,10 @@ void cdd_reset(void)
cdd.lba = 0;
/* reset status */
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
cdd.status = cdd.loaded ? CD_TOC : NO_DISC;
/* reset CD-DA fader (full volume) */
cdd.volume = 0x400;
cdd.fader[0] = cdd.fader[1] = 0x400;
/* clear CD-DA output */
cdd.audio[0] = cdd.audio[1] = 0;
@@ -229,7 +229,7 @@ int cdd_context_save(uint8 *state)
save_param(&cdd.index, sizeof(cdd.index));
save_param(&cdd.lba, sizeof(cdd.lba));
save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
save_param(&cdd.volume, sizeof(cdd.volume));
save_param(&cdd.fader, sizeof(cdd.fader));
save_param(&cdd.status, sizeof(cdd.status));
return bufferptr;
@@ -255,7 +255,7 @@ int cdd_context_load(uint8 *state)
load_param(&cdd.index, sizeof(cdd.index));
load_param(&cdd.lba, sizeof(cdd.lba));
load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
load_param(&cdd.volume, sizeof(cdd.volume));
load_param(&cdd.fader, sizeof(cdd.fader));
load_param(&cdd.status, sizeof(cdd.status));
/* adjust current LBA within track limit */
@@ -1287,10 +1287,10 @@ void cdd_read_audio(unsigned int samples)
int i, mul, l, r;
/* current CD-DA fader volume */
int curVol = cdd.volume;
int curVol = cdd.fader[0];
/* CD-DA fader volume setup (0-1024) */
int endVol = scd.regs[0x34>>1].w >> 4;
int endVol = cdd.fader[1];
/* read samples from current block */
#if defined(USE_LIBCHDR)
@@ -1476,7 +1476,7 @@ void cdd_read_audio(unsigned int samples)
}
/* save current CD-DA fader volume */
cdd.volume = curVol;
cdd.fader[0] = curVol;
/* save last audio output for next frame */
cdd.audio[0] = prev_l;
@@ -1778,7 +1778,7 @@ void cdd_process(void)
/* Process CDD command */
switch (scd.regs[0x42>>1].byte.h & 0x0f)
{
case 0x00: /* Drive Status */
case 0x00: /* Report Drive Status */
{
/* RS1-RS8 normally unchanged */
scd.regs[0x38>>1].byte.h = cdd.status;
@@ -1800,21 +1800,21 @@ void cdd_process(void)
case 0x01: /* Stop Drive */
{
/* update status */
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
cdd.status = cdd.loaded ? CD_TOC : NO_DISC;
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
/* RS1-RS8 ignored, expects 0x0 (drive busy ?) in RS0 once */
scd.regs[0x38>>1].w = CD_BUSY << 8;
/* RS1-RS8 ignored, expects 0x0 (CD_STOP) in RS0 once */
scd.regs[0x38>>1].w = CD_STOP << 8;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~CD_BUSY & 0x0f;
scd.regs[0x40>>1].w = ~CD_STOP & 0x0f;
return;
}
case 0x02: /* Read TOC */
case 0x02: /* Report TOC infos */
{
/* Infos automatically retrieved by CDD processor from Q-Channel */
/* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
@@ -1886,10 +1886,20 @@ void cdd_process(void)
break;
}
case 0x06: /* Latest Error Information */
{
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x06;
scd.regs[0x3a>>1].w = 0x0000; /* no error */
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
default:
{
#ifdef LOG_ERROR
error("Unknown CDD Command %02X (%X)\n", scd.regs[0x44>>1].byte.l, s68k.pc);
error("Invalid CDD request code %02X (%X)\n", scd.regs[0x44>>1].byte.l, s68k.pc);
#endif
return;
}
@@ -2157,7 +2167,6 @@ void cdd_process(void)
break;
}
case 0x0a: /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
{
/* TC3 corresponds to seek direction (00=forward, FF=reverse) */
@@ -2179,14 +2188,14 @@ void cdd_process(void)
scd.regs[0x36>>1].byte.h = 0x01;
/* update status */
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
cdd.status = cdd.loaded ? CD_TOC : NO_DISC;
/* RS1-RS8 ignored, expects 0x0 (drive busy ?) in RS0 once */
scd.regs[0x38>>1].w = CD_BUSY << 8;
/* RS1-RS8 ignored, expects CD_STOP in RS0 once */
scd.regs[0x38>>1].w = CD_STOP << 8;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~CD_BUSY & 0x0f;
scd.regs[0x40>>1].w = ~CD_STOP & 0x0f;
#ifdef CD_TRAY_CALLBACK
CD_TRAY_CALLBACK
@@ -2214,8 +2223,8 @@ void cdd_process(void)
}
default: /* Unknown command */
#ifdef LOG_CDD
error("Unknown CDD Command !!!\n");
#ifdef LOG_ERROR
error("Unsupported CDD command %02X (%X)\n", scd.regs[0x42>>1].byte.h & 0x0f, s68k.pc);
#endif
scd.regs[0x38>>1].byte.h = cdd.status;
break;
+22 -10
View File
@@ -54,15 +54,26 @@
#define cdd scd.cdd_hw
/* CDD status */
#define CD_BUSY 0x00
#define CD_PLAY 0x01
#define CD_SEEK 0x02
#define CD_SCAN 0x03
#define CD_PAUSE 0x04
#define CD_OPEN 0x05
#define CD_STOP 0x09
#define NO_DISC 0x0B
#define CD_END 0x0C
#define CD_STOP 0x00
#define CD_PLAY 0x01
#define CD_SEEK 0x02
#define CD_SCAN 0x03
#define CD_PAUSE 0x04
#define CD_OPEN 0x05
#define NO_VALID_CHK 0x06 /* unused */
#define NO_VALID_CMD 0x07 /* unused */
#define CD_ERROR 0x08 /* unused */
#define CD_TOC 0x09
#define CD_TRACK_MOVE 0x0A /* unused */
#define NO_DISC 0x0B
#define CD_END 0x0C
#define CD_TRAY 0x0E /* unused */
#define CD_TEST 0x0F /* unusec */
/* CD-DA digital filter types */
#define CD_TYPE_DEFAULT 0x00
#define CD_TYPE_WONDERMEGA 0x01
#define CD_TYPE_WONDERMEGA_M2 0x02
/* CD track */
typedef struct
@@ -103,11 +114,12 @@ typedef struct
{
uint32 cycles;
uint32 latency;
int type;
int loaded;
int index;
int lba;
int scanOffset;
int volume;
uint16 fader[2];
uint8 status;
uint16 sectorSize;
toc_t toc;
+41 -1
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Mega CD / Sega CD hardware
*
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -1281,6 +1281,46 @@ static void scd_write_word(unsigned int address, unsigned int data)
return;
}
case 0x34: /* CD Fader */
{
/* Wondermega hardware (CXD2554M digital filter) */
if (cdd.type == CD_TYPE_WONDERMEGA)
{
/* only MSB is latched by CXD2554M chip, LSB is ignored (8-bit digital filter) */
/* attenuator data is 7-bit only (bits 0-7) */
data = (data >> 8) & 0x7f;
/* scale CXD2554M volume (0-127) to full (LC7883KM compatible) volume range (0-1024) */
cdd.fader[1] = (1024 * data) / 127 ;
}
/* Wondermega M2 / X'Eye hardware (SM5841A digital filter) */
else if (cdd.type == CD_TYPE_WONDERMEGA_M2)
{
/* only MSB is latched by SM5841A chip, LSB is ignored (8-bit digital filter) */
data = data >> 8;
/* attenuator data is set only when command bit (bit 0) is cleared (other commands are ignored) */
if (data & 0x01) return;
/* attenuator data is 7-bit only (bits 8-1) and reverted (bit 1 = msb) */
/* bit reversing formula taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
data = (((((data * 0x0802) & 0x22110) | ((data * 0x8020) & 0x88440)) * 0x10101) >> 16) & 0x7f;
/* convert & scale SM5841A attenuation (127-0) to full (LC7883KM compatible) volume range (0-1024) */
cdd.fader[1] = (1024 * (127 - data)) / 127 ;
}
/* default CD hardware (LC7883KM digital filter) */
else
{
/* get LC7883KM volume data (12-bit) */
cdd.fader[1] = data >> 4 ;
}
return;
}
case 0x4a: /* CDD command 9 (controlled by BIOS, word access only ?) */
{
scd.regs[0x4a>>1].w = 0;
+1 -1
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Mega CD / Sega CD hardware
*
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+17
View File
@@ -417,6 +417,23 @@ int load_bios(int system)
/* CD BOOTROM loaded ? */
if (size > 0)
{
/* auto-detect CD hardware model */
if (!memcmp (&scd.bootrom[0x120], "WONDER-MEGA BOOT", 16))
{
/* Wondermega CD hardware */
cdd.type = CD_TYPE_WONDERMEGA;
}
else if (!memcmp (&scd.bootrom[0x120], "WONDERMEGA2 BOOT", 16))
{
/* Wondermega M2 / X'Eye CD hardware */
cdd.type = CD_TYPE_WONDERMEGA_M2;
}
else
{
/* default CD hardware */
cdd.type = CD_TYPE_DEFAULT;
}
#ifdef LSB_FIRST
/* Byteswap ROM to optimize 16-bit access */
int i;