13 Commits

45 changed files with 1217 additions and 489 deletions
+173 -64
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 alloc] init];
_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,20 +151,20 @@ 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];
if (!load_rom((char *)path.fileSystemRepresentation))
return NO;
if([[self systemIdentifier] isEqualToString:@"openemu.system.sg"] || [[self systemIdentifier] isEqualToString:@"openemu.system.scd"] || [[self systemIdentifier] isEqualToString:@"openemu.system.sms"])
if([self.systemIdentifier isEqualToString:@"openemu.system.sg"] || [self.systemIdentifier isEqualToString:@"openemu.system.scd"] || [self.systemIdentifier isEqualToString:@"openemu.system.sms"])
{
// Force system region to Japan if user locale is Japan and the cart appears to be world/multi-region
if((strstr((const char*)rominfo.country, "EJ") ||
@@ -163,11 +172,11 @@ static __weak GenPlusGameCore *_current;
strstr((const char*)rominfo.country, "JU") ||
strstr((const char*)rominfo.country, "UJ") ||
strstr(rominfo.country, "SMS Export") != NULL)
&& [[self systemRegion] isEqualToString: @"Japan"])
&& [self.systemRegion isEqualToString: @"Japan"])
{
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,23 +190,23 @@ 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"])
if([self.systemIdentifier isEqualToString:@"openemu.system.sg"] || [self.systemIdentifier isEqualToString:@"openemu.system.scd"])
{
// Set initial viewport size because the system briefly outputs 256x192 when it boots
bitmap.viewport.w = 320;
bitmap.viewport.w = 292;
bitmap.viewport.h = 224;
}
@@ -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;
@@ -285,7 +294,7 @@ static __weak GenPlusGameCore *_current;
- (OEIntRect)screenRect
{
if([[self systemIdentifier] isEqualToString:@"openemu.system.gg"])
if([self.systemIdentifier isEqualToString:@"openemu.system.gg"])
{
return OEIntRectMake(0, 0, 160, 144);
}
@@ -302,17 +311,19 @@ static __weak GenPlusGameCore *_current;
- (OEIntSize)aspectSize
{
if([[self systemIdentifier] isEqualToString:@"openemu.system.gg"])
if([self.systemIdentifier isEqualToString:@"openemu.system.gg"])
{
return OEIntSizeMake(160, 144);
}
else if([[self systemIdentifier] isEqualToString:@"openemu.system.sms"] || [[self systemIdentifier] isEqualToString:@"openemu.system.sg100"])
else if([self.systemIdentifier isEqualToString:@"openemu.system.sms"] || [self.systemIdentifier isEqualToString:@"openemu.system.sg1000"])
{
return OEIntSizeMake(256 * (8.0/7.0), 192);
}
else
{
return OEIntSizeMake(4, 3); // TODO: Correct PAR.
// H32 mode (256px * 8:7 PAR)
// H40 mode (320px * 32:35 PAR)
return OEIntSizeMake(292, 224);
}
}
@@ -345,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",
@@ -373,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",
@@ -416,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],
}];
}
@@ -572,11 +583,11 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
if (bitmap.viewport.w == 320)
{
input.analog[4][0] = aPoint.x;
input.analog[4][1] = aPoint.y * 0.933333;
input.analog[4][1] = aPoint.y * 0.912500;
}
else // w == 256
{
input.analog[4][0] = aPoint.x * 0.857143;
input.analog[4][0] = aPoint.x * 0.876712;
input.analog[4][1] = aPoint.y;
}
}
@@ -642,27 +653,27 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled
{
// Sanitize
code = [code stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
code = [code stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
// Genesis Plus GX expects cheats UPPERCASE
code = [code uppercaseString];
code = code.uppercaseString;
// Remove any spaces
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
if (enabled)
[cheatList setValue:@YES forKey:code];
_cheatList[code] = @YES;
else
[cheatList removeObjectForKey:code];
[_cheatList removeObjectForKey:code];
[self resetCheats];
NSArray *multipleCodes = [[NSArray alloc] init];
NSArray<NSString *> *multipleCodes = [NSArray array];
// Apply enabled cheats found in dictionary
for (id key in cheatList)
for (NSString *key in _cheatList)
{
if ([[cheatList valueForKey:key] isEqual:@YES])
if ([_cheatList[key] boolValue])
{
// Handle multi-line cheats
multipleCodes = [key componentsSeparatedByString:@"+"];
@@ -674,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
@@ -682,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++;
@@ -708,15 +797,18 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
config.hq_fm = 1; /* high-quality FM resampling (slower) */
config.hq_psg = 1; /* high-quality PSG resampling (slower) */
config.filter = 0; /* no filter */
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.lp_range = 0x7fff; /* 0.5 in 0.16 fixed point */
config.low_freq = 880;
config.high_freq = 5000;
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.dac_bits = 14; /* MAX DEPTH */
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* AUTO */
config.mono = 0; /* STEREO output */
#ifdef HAVE_YM3438_CORE
config.ym3438 = 0;
#endif
/* system options */
config.system = 0; /* AUTO */
@@ -732,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 */
@@ -740,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
@@ -748,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)
@@ -783,9 +887,11 @@ 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)
@"952e40844509c5739f1e84ea7f9dfd90" : @(TeamPlayerPort1), // Barkley Shut Up and Jam 2 (USA)
@"76aab0e8bc8e670a347676aaf0a0aea3" : @(TeamPlayerPort1), // College Football's National Championship (USA)
@@ -807,6 +913,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
@"234bf02f7f7b6fdad65890424d3a8a8f" : @(TeamPlayerPort1), // NBA Jam (USA, Europe) (v1.1)
@"338b8ed45e02d96f1ed31eaab59eaf43" : @(TeamPlayerPort1), // NBA Jam (USA, Europe)
@"edeb01f0aa8aed3868db1179670db22f" : @(TeamPlayerPort1), // NBA Jam - Tournament Edition (World)
//@"b465081da2e268a1c045c1b0615bed75" : @(TeamPlayerPort1), // NBA Pro Basketball '94 (Japan)
@"3d3c4c2dcc8631373b73cf11170dd4d7" : @(TeamPlayerPort1), // NCAA Final Four Basketball (USA)
@"6e38acfb80ed7e0b1343fa4ffdc6477d" : @(TeamPlayerPort1), // NCAA Football (USA)
@"035283320f792caa2b55129db21f0265" : @(TeamPlayerPort1), // NFL '95 (USA, Europe)
@@ -815,6 +922,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
@"15a8114b96afcabcb2bd08acbc7a11c0" : @(TeamPlayerPort1), // Prime Time NFL Starring Deion Sanders (USA)
@"a0003ccd281f9cc74aa2ef97fe23c2fc" : @(TeamPlayerPort1), // Puzzle & Action - Ichidanto-R (Japan)
@"16b0f48a07baf1fa0df27453b7f008d4" : @(TeamPlayerPort1), // Puzzle & Action - Tanto-R (Japan)
//@"4abb0405b270695261494720a2af0783" : @(TeamPlayerPort1), // Shi Jie Zhi Bang Zheng Ba Zhan - World Pro Baseball 94 (Taiwan) (Unl)
@"abddd42b2548e9b708991f689d726c9a" : @(TeamPlayerPort1), // Tiny Toon Adventures - Acme All-Stars (Europe)
@"1def1d7dbe4ab6b9e1fc90093292de6a" : @(TeamPlayerPort1), // Tiny Toon Adventures - Acme All-Stars (USA, Korea)
@"f314fe624d288b4e1228ae759bae1d86" : @(TeamPlayerPort1), // Unnecessary Roughness '95 (USA)
@@ -830,6 +938,7 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
@"723db55d679ef169b8210764a5f76c4d" : @(GamepadPort1TeamPlayerPort2), // ATP Tour Championship Tennis (USA)
@"5481f0cbab22ca071dad31dd3ca4f884" : @(GamepadPort1TeamPlayerPort2), // College Slam (USA)
@"6a492e2983b2bc306eec905411ee24a8" : @(GamepadPort1TeamPlayerPort2), // Dino Dini's Soccer (Europe)
@"dea9dd7a01d774ccdfe68c835fe55a8a" : @(GamepadPort1TeamPlayerPort2), // J. League Pro Striker (Japan)
@"f5f52249a5dc851864254935e185ea72" : @(GamepadPort1TeamPlayerPort2), // J. League Pro Striker (Japan) (v1.3)
@"ada241db25d7832866b1e58af2038bc6" : @(GamepadPort1TeamPlayerPort2), // J. League Pro Striker 2 (Japan)
@"a7046120d2a4b40949994c71177aec3c" : @(GamepadPort1TeamPlayerPort2), // J. League Pro Striker Perfect (Japan)
@@ -908,15 +1017,15 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
// Set six button controller override if needed
uint8_t pad;
if([pad6Buttons containsObject:[[self ROMMD5] lowercaseString]])
if([pad6Buttons containsObject:self.ROMMD5.lowercaseString])
pad = DEVICE_PAD6B; // Force six button controller
else
pad = DEVICE_PAD2B | DEVICE_PAD3B | DEVICE_PAD6B; // Auto-detects by presence of '6' byte in the cart header (rominfo.peripherals & 2)
// Set multitap type configuration if detected
if (multiTapGames[[[self ROMMD5] lowercaseString]])
if (multiTapGames[self.ROMMD5.lowercaseString])
{
_multiTapType = [[multiTapGames objectForKey:[[self ROMMD5] lowercaseString]] integerValue];
_multiTapType = [multiTapGames[self.ROMMD5.lowercaseString] integerValue];
// 1-4 players: TeamPlayer in Port 1
if (_multiTapType == TeamPlayerPort1)
@@ -1553,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)
{
+1
View File
@@ -578,6 +578,7 @@
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
en,
);
mainGroup = 089C166AFE841209C02AAC07 /* GenesisPlus */;
+3 -1
View File
@@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.7.4.7</string>
<string>1.7.4.11</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>
+38 -13
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Mega Drive cartridge hardware support
*
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Many cartridge protections were initially documented by Haze
* (http://haze.mameworld.info/)
@@ -376,17 +376,37 @@ void md_cart_init(void)
sram_init();
eeprom_i2c_init();
/* external SRAM */
/* memory-mapped SRAM */
if (sram.on && !sram.custom)
{
/* initialize default memory mapping for SRAM */
m68k.memory_map[sram.start >> 16].base = sram.sram;
m68k.memory_map[sram.start >> 16].read8 = sram_read_byte;
m68k.memory_map[sram.start >> 16].read16 = sram_read_word;
m68k.memory_map[sram.start >> 16].write8 = sram_write_byte;
m68k.memory_map[sram.start >> 16].write16 = sram_write_word;
zbank_memory_map[sram.start >> 16].read = sram_read_byte;
zbank_memory_map[sram.start >> 16].write = sram_write_byte;
/* SRAM is mapped by default unless it overlaps with ROM area (Phantasy Star 4, Beyond Oasis/Legend of Thor, World Series Baseball 9x, Duke Nukem 3D,...) */
if (sram.start >= cart.romsize)
{
m68k.memory_map[sram.start >> 16].base = sram.sram;
m68k.memory_map[sram.start >> 16].read8 = sram_read_byte;
m68k.memory_map[sram.start >> 16].read16 = sram_read_word;
m68k.memory_map[sram.start >> 16].write8 = sram_write_byte;
m68k.memory_map[sram.start >> 16].write16 = sram_write_word;
zbank_memory_map[sram.start >> 16].read = sram_read_byte;
zbank_memory_map[sram.start >> 16].write = sram_write_byte;
}
/* support for Triple Play 96 & Triple Play - Gold Edition (available ROM dumps include dumped SRAM data) */
else if ((strstr(rominfo.product,"T-172026") != NULL) || (strstr(rominfo.product,"T-172116") != NULL))
{
/* $000000-$1fffff and $300000-$3fffff: cartridge ROM (2MB + 1MB) */
/* $200000-$2fffff: SRAM (32 KB mirrored) */
for (i=0x20; i<0x30; i++)
{
m68k.memory_map[i].base = sram.sram;
m68k.memory_map[i].read8 = sram_read_byte;
m68k.memory_map[i].read16 = sram_read_word;
m68k.memory_map[i].write8 = sram_write_byte;
m68k.memory_map[i].write16 = sram_write_word;
zbank_memory_map[i].read = sram_read_byte;
zbank_memory_map[i].write = sram_write_byte;
}
}
}
/**********************************************
@@ -760,9 +780,14 @@ int md_cart_context_save(uint8 *state)
/* SRAM */
state[bufferptr++] = 0xff;
}
else if (base == boot_rom)
{
/* Boot ROM */
state[bufferptr++] = 0xfe;
}
else
{
/* ROM */
/* Cartridge ROM */
state[bufferptr++] = ((base - cart.rom) >> 16) & 0xff;
}
}
@@ -819,7 +844,7 @@ int md_cart_context_load(uint8 *state)
}
/* ROM */
m68k.memory_map[i].base = cart.rom + (offset << 16);
m68k.memory_map[i].base = (offset == 0xfe) ? boot_rom : (cart.rom + (offset << 16));
}
}
@@ -908,7 +933,7 @@ static void mapper_512k_w(uint32 address, uint32 data)
uint32 i;
/* 512K ROM paging */
uint8 *src = cart.rom + (data << 19);
uint8 *src = cart.rom + ((data << 19) & cart.mask);
/* cartridge area ($000000-$3FFFFF) is divided into 8 x 512K banks */
address = (address << 2) & 0x38;
+1 -1
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Mega Drive cartridge hardware support
*
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Most cartridge protections were initially documented by Haze
* (http://haze.mameworld.info/)
+66 -9
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* SG-1000, Master System & Game Gear cartridge hardware support
*
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -243,6 +243,7 @@ static const rominfo_t game_list[] =
/* games requiring 3-D Glasses & Sega Light Phaser */
{0xFBE5CFBB, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D */
{0xE79BB689, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D [BIOS] */
{0x43DEF05D, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D [Proto] */
/* games requiring Sega Light Phaser */
{0x861B6E79, 0, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Assault City [Light Phaser] */
@@ -609,9 +610,6 @@ void sms_cart_reset(void)
}
}
/* reset Memory Control register (RAM & I/O are enabled, either BIOS or Cartridge ROM are enabled) */
io_reg[0x0E] = bios_rom.pages ? 0xE0 : 0xA8;
/* reset Z80 memory map */
mapper_reset();
@@ -718,10 +716,21 @@ int sms_cart_region_detect(void)
while(i--);
/* Mark-III hardware */
if (system_hw == SYSTEM_MARKIII)
if (config.system == SYSTEM_MARKIII)
{
/* Japan */
return REGION_JAPAN_NTSC;
/* Japan only */
region_code = REGION_JAPAN_NTSC;
}
/* Master System / Game Gear ROM file */
if (system_hw >= SYSTEM_SMS)
{
/* missing header or valid header with Japan region code */
if (!rominfo.country[0] || !memcmp(rominfo.country,"SMS Japan",9) || !memcmp(rominfo.country,"GG Japan",8))
{
/* assume Japan region (fixes BIOS support) */
return REGION_JAPAN_NTSC;
}
}
/* default region */
@@ -731,14 +740,62 @@ int sms_cart_region_detect(void)
int sms_cart_context_save(uint8 *state)
{
int bufferptr = 0;
save_param(slot.fcr, 4);
/* check if cartridge ROM is disabled */
if (io_reg[0x0E] & 0x40)
{
/* save Boot ROM mapper settings */
save_param(bios_rom.fcr, 4);
}
else
{
/* save cartridge mapper settings */
save_param(cart_rom.fcr, 4);
}
/* support for SG-1000 games with extra RAM */
if ((cart_rom.mapper == MAPPER_RAM_8K) || (cart_rom.mapper == MAPPER_RAM_8K_EXT1))
{
/* 8KB extra RAM */
save_param(work_ram + 0x2000, 0x2000);
}
else if (cart_rom.mapper == MAPPER_RAM_2K)
{
/* 2KB extra RAM */
save_param(work_ram + 0x2000, 0x800);
}
return bufferptr;
}
int sms_cart_context_load(uint8 *state)
{
int bufferptr = 0;
load_param(slot.fcr, 4);
/* check if cartridge ROM is disabled */
if (io_reg[0x0E] & 0x40)
{
/* load Boot ROM mapper settings */
load_param(bios_rom.fcr, 4);
}
else
{
/* load cartridge mapper settings */
load_param(cart_rom.fcr, 4);
}
/* support for SG-1000 games with extra RAM */
if ((cart_rom.mapper == MAPPER_RAM_8K) || (cart_rom.mapper == MAPPER_RAM_8K_EXT1))
{
/* 8KB extra RAM */
load_param(work_ram + 0x2000, 0x2000);
}
else if (cart_rom.mapper == MAPPER_RAM_2K)
{
/* 2KB extra RAM */
load_param(work_ram + 0x2000, 0x800);
}
return bufferptr;
}
+1 -1
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* SG-1000, Master System & Game Gear cartridge hardware support
*
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+1 -4
View File
@@ -555,11 +555,8 @@ static u32 pm_io(int reg, int write, u32 d)
elprintf(EL_SVP, "ssp ROM r [%06x] %04x", CADDR,
((unsigned short *)cart.rom)[addr|((mode&0xf)<<16)]);
#endif
/*if ((signed int)ssp->pmac_read[reg] >> 16 == -1) ssp->pmac_read[reg]++;
ssp->pmac_read[reg] += 1<<16;*/
if ((signed int)(ssp->pmac[0][reg] & 0xffff) == -1) ssp->pmac[0][reg] += 1<<16;
ssp->pmac[0][reg] ++;
d = ((unsigned short *)cart.rom)[addr|((mode&0xf)<<16)];
}
else if ((mode & 0x47ff) == 0x0018) /* DRAM */
+43 -33
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* CD drive processor & CD-DA fader
*
* Copyright (C) 2012-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -198,23 +198,20 @@ void cdd_init(int samplerate)
void cdd_reset(void)
{
/* reset cycle counter */
cdd.cycles = 0;
/* reset drive access latency */
cdd.latency = 0;
/* reset track index */
cdd.index = 0;
/* reset logical block address */
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 +226,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 +252,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 */
@@ -1148,7 +1145,7 @@ int cdd_load(char *filename, char *header)
}
/* Automatically try to open associated subcode data file */
strncpy(&fname[strlen(fname) - 4], ".sub", 4);
memcpy(&fname[strlen(fname) - 4], ".sub", 4);
cdd.toc.sub = cdStreamOpen(fname);
/* return 1 if loaded file is CD image file */
@@ -1169,7 +1166,6 @@ void cdd_unload(void)
chd_close(cdd.chd.file);
if (cdd.chd.hunk)
free(cdd.chd.hunk);
memset(&cdd.chd, 0x00, sizeof(cdd.chd));
#endif
/* close CD tracks */
@@ -1209,7 +1205,12 @@ void cdd_unload(void)
/* reset TOC */
memset(&cdd.toc, 0x00, sizeof(cdd.toc));
#if defined(USE_LIBCHDR)
/* reset CHD data */
memset(&cdd.chd, 0x00, sizeof(cdd.chd));
#endif
/* no CD-ROM track */
cdd.sectorSize = 0;
}
@@ -1283,10 +1284,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)
@@ -1472,7 +1473,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;
@@ -1774,7 +1775,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;
@@ -1796,21 +1797,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) */
@@ -1882,10 +1883,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;
}
@@ -1908,9 +1919,9 @@ void cdd_process(void)
{
/* Fixes a few games hanging because they expect data to be read with some delay */
/* Radical Rex needs at least one interrupt delay */
/* Wolf Team games (Anet Futatabi, Cobra Command, Earnest Evans, Road Avenger & Time Gal) need at least 10 interrupts delay */
/* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 10 is OK) */
cdd.latency = 10;
/* Wolf Team games (Anet Futatabi, Aisle Lord, Cobra Command, Earnest Evans, Road Avenger & Time Gal) need at least 11 interrupts delay */
/* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 11 is OK) */
cdd.latency = 11;
}
/* CD drive seek time */
@@ -2153,7 +2164,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) */
@@ -2175,14 +2185,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
@@ -2210,8 +2220,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;
+23 -11
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* CD drive processor & CD-DA fader
*
* Copyright (C) 2012-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -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;
@@ -53,7 +53,7 @@
#define fseeko _fseeki64
#define ftello _ftelli64
#else /* MinGW */
#if !defined(HAVE_FSEEKO)
#if !defined(HAVE_FSEEKO) && !defined(__MINGW64_VERSION_MAJOR)
#define fseeko fseeko64
#define ftello ftello64
#endif
+66 -11
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-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -255,7 +255,7 @@ static void word_ram_z80_write_byte(unsigned int address, unsigned int data)
}
else
{
WRITE_BYTE(m68k.memory_map[offset].base, address & 0xffff, data);
*(uint16 *)(m68k.memory_map[offset].base + (address & 0xfffe)) = data | (data << 8);
}
}
@@ -293,7 +293,7 @@ static void word_ram_m68k_write_byte(unsigned int address, unsigned int data)
}
else
{
WRITE_BYTE(m68k.memory_map[offset].base, address & 0xffff, data);
*(uint16 *)(m68k.memory_map[offset].base + (address & 0xfffe)) = data | (data << 8);
}
}
@@ -345,7 +345,7 @@ static void word_ram_s68k_write_byte(unsigned int address, unsigned int data)
}
else
{
WRITE_BYTE(s68k.memory_map[offset].base, address & 0xffff, data);
*(uint16 *)(s68k.memory_map[offset].base + (address & 0xfffe)) = data | (data << 8);
}
}
@@ -445,10 +445,16 @@ static void s68k_poll_sync(unsigned int reg_mask)
/* relative MAIN-CPU cycle counter */
unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE;
/* sync MAIN-CPU with SUB-CPU */
if (!m68k.stopped)
{
/* save current MAIN-CPU end cycle count (recursive execution is possible) */
int end_cycle = m68k.cycle_end;
/* sync MAIN-CPU with SUB-CPU */
m68k_run(cycles);
/* restore MAIN-CPU end cycle count */
m68k.cycle_end = end_cycle;
}
/* MAIN-CPU idle on register polling ? */
@@ -669,8 +675,14 @@ static unsigned int scd_read_word(unsigned int address)
/* relative MAIN-CPU cycle counter */
unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE;
/* save current MAIN-CPU end cycle count (recursive execution is possible) */
int end_cycle = m68k.cycle_end;
/* sync MAIN-CPU with SUB-CPU (Mighty Morphin Power Rangers) */
m68k_run(cycles);
/* restore MAIN-CPU end cycle count */
m68k.cycle_end = end_cycle;
}
s68k_poll_detect(3 << (address & 0x1e));
@@ -781,7 +793,7 @@ static void scd_write_byte(unsigned int address, unsigned int data)
case 0x01: /* RESET status */
{
/* RESET bit cleared ? */
/* RESET bit cleared ? */
if (!(data & 0x01))
{
/* reset CD hardware */
@@ -1059,7 +1071,7 @@ static void scd_write_word(unsigned int address, unsigned int data)
/* only update LED status (register $00 is reserved for MAIN-CPU, use $06 instead) */
scd.regs[0x06>>1].byte.h = data >> 8;
/* RESET bit cleared ? */
/* RESET bit cleared ? */
if (!(data & 0x01))
{
/* reset CD hardware */
@@ -1281,6 +1293,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;
@@ -1574,6 +1626,9 @@ void scd_reset(int hard)
s68k.cycles = 0;
s68k_pulse_reset();
s68k_pulse_halt();
/* Reset frame cycle counter */
scd.cycles = 0;
}
else
{
@@ -1597,10 +1652,7 @@ void scd_reset(int hard)
/* Reset Timer & Stopwatch counters */
scd.timer = 0;
scd.stopwatch = 0;
/* Reset frame cycle counter */
scd.cycles = 0;
scd.stopwatch = s68k.cycles;
/* Clear pending interrupts */
scd.pending = 0;
@@ -1609,6 +1661,9 @@ void scd_reset(int hard)
memset(&m68k.poll, 0, sizeof(m68k.poll));
memset(&s68k.poll, 0, sizeof(s68k.poll));
/* reset CDD cycle counter */
cdd.cycles = (scd.cycles - s68k.cycles) * 3;
/* Reset CD hardware */
cdd_reset();
cdc_reset();
+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-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+53
View File
@@ -0,0 +1,53 @@
/***************************************************************************************
* Genesis Plus GX
* CPU hooking support
*
* HOOK_CPU should be defined in a makefile or MSVC project to enable this functionality
*
* Copyright feos (2019)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifdef HOOK_CPU
#include <stdio.h>
#include "cpuhook.h"
void(*cpu_hook)(hook_type_t type, int width, unsigned int address, unsigned int value) = NULL;
void set_cpu_hook(void(*hook)(hook_type_t type, int width, unsigned int address, unsigned int value))
{
cpu_hook = hook;
}
#endif /* HOOK_CPU */
+91
View File
@@ -0,0 +1,91 @@
/***************************************************************************************
* Genesis Plus GX
* CPU hooking support
*
* HOOK_CPU should be defined in a makefile or MSVC project to enable this functionality
*
* Copyright DrMefistO (2018-2019)
*
* Copyright feos (2019)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _CPUHOOK_H_
#define _CPUHOOK_H_
typedef enum {
HOOK_ANY = (0 << 0),
// M68K
HOOK_M68K_E = (1 << 0),
HOOK_M68K_R = (1 << 1),
HOOK_M68K_W = (1 << 2),
HOOK_M68K_RW = HOOK_M68K_R | HOOK_M68K_W,
// VDP
HOOK_VRAM_R = (1 << 3),
HOOK_VRAM_W = (1 << 4),
HOOK_VRAM_RW = HOOK_VRAM_R | HOOK_VRAM_W,
HOOK_CRAM_R = (1 << 5),
HOOK_CRAM_W = (1 << 6),
HOOK_CRAM_RW = HOOK_CRAM_R | HOOK_CRAM_W,
HOOK_VSRAM_R = (1 << 7),
HOOK_VSRAM_W = (1 << 8),
HOOK_VSRAM_RW = HOOK_VSRAM_R | HOOK_VSRAM_W,
// Z80
HOOK_Z80_E = (1 << 9),
HOOK_Z80_R = (1 << 10),
HOOK_Z80_W = (1 << 11),
HOOK_Z80_RW = HOOK_Z80_R | HOOK_Z80_W,
// REGS
HOOK_VDP_REG = (1 << 12),
HOOK_M68K_REG = (1 << 13),
} hook_type_t;
/* CPU hook is called on read, write, and execute.
*/
void (*cpu_hook)(hook_type_t type, int width, unsigned int address, unsigned int value);
/* Use set_cpu_hook() to assign a callback that can process the data provided
* by cpu_hook().
*/
void set_cpu_hook(void(*hook)(hook_type_t type, int width, unsigned int address, unsigned int value));
#endif /* _CPUHOOK_H_ */
+5 -5
View File
@@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
@@ -474,8 +474,8 @@ void gen_zbusreq_w(unsigned int data, unsigned int cycles)
/* check if Z80 is going to be restarted */
if (zstate == 3)
{
/* resynchronize with 68k */
Z80.cycles = cycles;
/* resynchronize with 68k (Z80 cycles should remain a multiple of 15 MClocks) */
Z80.cycles = ((cycles + 14) / 15) * 15;
/* disable 68k access to Z80 bus */
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
@@ -496,8 +496,8 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
/* check if Z80 is going to be restarted */
if (zstate == 0)
{
/* resynchronize with 68k */
Z80.cycles = cycles;
/* resynchronize with 68k (Z80 cycles should remain a multiple of 15 MClocks) */
Z80.cycles = ((cycles + 14) / 15) * 15;
/* reset Z80 & YM2612 */
z80_reset();
+1 -1
View File
@@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
+28 -32
View File
@@ -3,7 +3,7 @@
* 2-Buttons, 3-Buttons & 6-Buttons controller support
* with support for J-Cart, 4-Way Play & Master Tap adapters
*
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -122,37 +122,25 @@ INLINE unsigned char gamepad_read(int port)
/* D-PAD or extra buttons status is returned on D3-D0 (active low) */
switch (step)
{
case 1: /*** First High ***/
case 3: /*** Second High ***/
case 5: /*** Third High ***/
{
/* TH = 1 : ?1CBRLDU */
data &= ~(pad & 0x3F);
break;
}
/* From gen_hw.txt (*):
case 0: /*** 3-button only ***/
case 2: /*** First Low ***/
case 4: /*** Second Low ***/
{
/* TH = 0 : ?0SA00DU */
data &= ~((pad & 0x03) | ((pad >> 2) & 0x30) | 0x0C);
break;
}
A 6-button gamepad allows the extra buttons to be read based on how
many times TH is switched from 0 to 1. Observe the following sequence:
/* A 6-button gamepad allows the extra buttons to be read based on how */
/* many times TH is switched from 1 to 0. Observe the following sequence */
/*
TH = 1 : ?1CBRLDU 3-button pad return value
TH = 0 : ?0SA00DU 3-button pad return value
TH = 1 : ?1CBRLDU 3-button pad return value
TH = 0 : ?0SA00DU 3-button pad return value
TH = 1 : ?1CBRLDU 3-button pad return value (*)
TH = 0 : ?0SA00DU 3-button pad return value (*)
TH = 1 : ?1CBRLDU 3-button pad return value
TH = 0 : ?0SA0000 D3-D0 are forced to '0'
TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0
TH = 0 : ?0SA1111 D3-D0 are forced to '1'
From this point on, the standard 3-button pad values will be returned if any further TH transitions are done.
(*) additional High-to-Low transition is necessary to access extra buttons according to official MK-1653-50 specification
*/
case 6: /*** Third Low ***/
case 4: /*** Third Low ***/
{
/* TH = 0 : ?0SA0000 D3-D0 forced to '0' */
data &= ~(((pad >> 2) & 0x30) | 0x0F);
@@ -166,18 +154,26 @@ INLINE unsigned char gamepad_read(int port)
break;
}
default: /*** D3-D0 forced to '1' ***/
case 6: /*** Fourth Low ***/
{
if (data & 0x40)
/* TH = 0 : ?0SA1111 D3-D0 forced to '1' */
data &= ~((pad >> 2) & 0x30);
break;
}
default: /*** 3-button mode ***/
{
if (step & 1)
{
/* TH = 1 : ?0CB1111 */
data &= ~(pad & 0x30);
/* TH = 1 : ?1CBRLDU */
data &= ~(pad & 0x3F);
}
else
{
/* TH = 0 : ?0SA1111 */
data &= ~((pad >> 2) & 0x30);
/* TH = 0 : ?0SA00DU */
data &= ~((pad & 0x03) | ((pad >> 2) & 0x30) | 0x0C);
}
break;
}
}
@@ -196,10 +192,10 @@ INLINE void gamepad_write(int port, unsigned char data, unsigned char mask)
gamepad[port].Latency = 0;
/* 6-Buttons controller specific */
if (input.dev[port] == DEVICE_PAD6B)
if ((input.dev[port] == DEVICE_PAD6B) && (gamepad[port].Counter < 8))
{
/* TH 1->0 transition */
if (!data && gamepad[port].State)
/* TH 0->1 transition */
if (data && !gamepad[port].State)
{
gamepad[port].Counter += 2;
gamepad[port].Timeout = 0;
+1 -1
View File
@@ -3,7 +3,7 @@
* 2-Buttons, 3-Buttons & 6-Buttons controller support
* with support for J-Cart, 4-Way Play & Master Tap adapters
*
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+60 -7
View File
@@ -5,7 +5,7 @@
* Support for Master System (315-5216, 315-5237 & 315-5297), Game Gear & Mega Drive I/O chips
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -321,13 +321,27 @@ void io_reset(void)
io_reg[0x0D] |= IO_CONT1_HI;
}
/* Control registers */
io_reg[0x0E] = 0x00;
io_reg[0x0F] = 0xFF;
/* on SG-1000 & Mark-III, TH is not connected (always return 1) */
if (system_hw < SYSTEM_SMS)
/* Memory Control register (Master System and Game Gear hardware only) */
if ((system_hw & SYSTEM_SMS) || (system_hw & SYSTEM_GG))
{
/* RAM, I/O and either BIOS or Cartridge ROM are enabled */
io_reg[0x0E] = (z80_readmap[0] == cart.rom + 0x400000) ? 0xE0 : 0xA8;
}
else
{
/* default value (no Memory Control register) */
io_reg[0x0E] = 0x00;
}
/* I/O control register (Master System, Mega Drive and Game Gear hardware only) */
if (system_hw >= SYSTEM_SMS)
{
/* on power-on, TR and TH are configured as inputs */
io_reg[0x0F] = 0xFF;
}
else
{
/* on SG-1000 & Mark-III, TR is always an input and TH is not connected (always return 1) */
io_reg[0x0F] = 0xF5;
}
}
@@ -350,6 +364,16 @@ void io_68k_write(unsigned int offset, unsigned int data)
case 0x02: /* Port B Data */
case 0x03: /* Port C Data */
{
/*
D7 : Unused. This bit will return any value written to it
D6 : TH pin output level (1=high, 0=low)
D5 : TR pin output level (1=high, 0=low)
D4 : TL pin output level (1=high, 0=low)
D3 : D3 pin output level (1=high, 0=low)
D2 : D2 pin output level (1=high, 0=low)
D1 : D1 pin output level (1=high, 0=low)
D0 : D0 pin output level (1=high, 0=low)
*/
io_reg[offset] = data;
port[offset-1].data_w(data, io_reg[offset + 3]);
return;
@@ -359,6 +383,16 @@ void io_68k_write(unsigned int offset, unsigned int data)
case 0x05: /* Port B Ctrl */
case 0x06: /* Port C Ctrl */
{
/*
D7 : /HL output control (1=TH input level, 0=forced high)
D6 : TH pin is 1=output, 0=input
D5 : TR pin is 1=output, 0=input
D4 : TL pin is 1=output, 0=input
D3 : D3 pin is 1=output, 0=input
D2 : D2 pin is 1=output, 0=input
D1 : D1 pin is 1=output, 0=input
D0 : D0 pin is 1=output, 0=input
*/
if (data != io_reg[offset])
{
io_reg[offset] = data;
@@ -379,6 +413,15 @@ void io_68k_write(unsigned int offset, unsigned int data)
case 0x0C: /* Port B S-Ctrl */
case 0x0F: /* Port C S-Ctrl */
{
/*
D7-D6 : Serial baud rate (00= 4800 bps, 01= 2400 bps, 10= 1200 bps, 11= 300 bps)
D5 : TR pin functions as 1= serial input pin, 0= normal
D4 : TL pin functions as 1= serial output pin, 0= normal
D3 : 1= Make I/O chip strobe /HL low when a byte has been received, 0= Do nothing
D2 : read-only (on read, 1= Error receiving current byte, 0= No error)
D1 : read-only (on read, 1= Rxd buffer is ready to read, 0= Rxd buffer isn't ready)
D0 : read-only (on read, 1= Txd buffer is full, 0= Can write to Txd buffer)
*/
io_reg[offset] = data & 0xF8;
return;
}
@@ -398,6 +441,16 @@ unsigned int io_68k_read(unsigned int offset)
case 0x02: /* Port B Data */
case 0x03: /* Port C Data */
{
/*
D7 : Unused. This bit will return any value written to it
D6 : TH pin input level (1=high, 0=low)
D5 : TR pin input level (1=high, 0=low)
D4 : TL pin input level (1=high, 0=low)
D3 : D3 pin input level (1=high, 0=low)
D2 : D2 pin input level (1=high, 0=low)
D1 : D1 pin input level (1=high, 0=low)
D0 : D0 pin input level (1=high, 0=low)
*/
unsigned int mask = 0x80 | io_reg[offset + 3];
unsigned int data = port[offset-1].data_r();
return (io_reg[offset] & mask) | (data & ~mask);
+1 -1
View File
@@ -5,7 +5,7 @@
* Support for Master System (315-5216, 315-5237 & 315-5297), Game Gear & Mega Drive I/O chips
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+19 -2
View File
@@ -3,7 +3,7 @@
* ROM Loading Support
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
@@ -311,7 +311,7 @@ void getrominfo(char *romheader)
}
/* if found, get infos from header */
if (offset)
if ((offset > 0) && (offset < cart.romsize))
{
/* checksum */
rominfo.checksum = romheader[offset + 0x0a] | (romheader[offset + 0x0b] << 8);
@@ -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;
+1 -1
View File
@@ -3,7 +3,7 @@
* ROM Loading Support
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
+3
View File
@@ -43,6 +43,9 @@
#include <setjmp.h>
#include "macros.h"
#ifdef HOOK_CPU
#include "cpuhook.h"
#endif
/* ======================================================================== */
/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
+6
View File
@@ -289,6 +289,12 @@ void m68k_run(unsigned int cycles)
/* Set the address space for reads */
m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */
#ifdef HOOK_CPU
/* Trigger execution hook */
if (cpu_hook)
cpu_hook(HOOK_M68K_E, 0, REG_PC, 0);
#endif
/* Decode next instruction */
REG_IR = m68ki_read_imm_16();
+46 -7
View File
@@ -849,36 +849,60 @@ INLINE uint m68ki_read_imm_32(void)
*/
INLINE uint m68ki_read_8(uint address)
{
cpu_memory_map *temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];;
cpu_memory_map *temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
uint val;
m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */
if (temp->read8) return (*temp->read8)(ADDRESS_68K(address));
else return READ_BYTE(temp->base, (address) & 0xffff);
if (temp->read8) val = (*temp->read8)(ADDRESS_68K(address));
else val = READ_BYTE(temp->base, (address) & 0xffff);
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_M68K_R, 1, address, val);
#endif
return val;
}
INLINE uint m68ki_read_16(uint address)
{
cpu_memory_map *temp;
uint val;
m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_READ, FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->read16) return (*temp->read16)(ADDRESS_68K(address));
else return *(uint16 *)(temp->base + ((address) & 0xffff));
if (temp->read16) val = (*temp->read16)(ADDRESS_68K(address));
else val = *(uint16 *)(temp->base + ((address) & 0xffff));
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_M68K_R, 2, address, val);
#endif
return val;
}
INLINE uint m68ki_read_32(uint address)
{
cpu_memory_map *temp;
uint val;
m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_READ, FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->read16) return ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2)));
else return m68k_read_immediate_32(address);
if (temp->read16) val = ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2)));
else val = m68k_read_immediate_32(address);
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_M68K_R, 4, address, val);
#endif
return val;
}
INLINE void m68ki_write_8(uint address, uint value)
@@ -887,6 +911,11 @@ INLINE void m68ki_write_8(uint address, uint value)
m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_M68K_W, 1, address, value);
#endif
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->write8) (*temp->write8)(ADDRESS_68K(address),value);
else WRITE_BYTE(temp->base, (address) & 0xffff, value);
@@ -899,6 +928,11 @@ INLINE void m68ki_write_16(uint address, uint value)
m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_WRITE, FLAG_S | FUNCTION_CODE_USER_DATA); /* auto-disable (see m68kcpu.h) */
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_M68K_W, 2, address, value);
#endif
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value);
else *(uint16 *)(temp->base + ((address) & 0xffff)) = value;
@@ -911,6 +945,11 @@ INLINE void m68ki_write_32(uint address, uint value)
m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_WRITE, FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_M68K_W, 4, address, value);
#endif
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value>>16);
else *(uint16 *)(temp->base + ((address) & 0xffff)) = value >> 16;
+8 -8
View File
@@ -19,7 +19,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -51,7 +51,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -83,7 +83,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -115,7 +115,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -147,7 +147,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -179,7 +179,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -211,7 +211,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
@@ -243,7 +243,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 6*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7,
10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 10*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 8*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 12*7, 16*7, 12*7, 14*7, 10*7, 0*7, 0*7, 0*7,
8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7,
12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7, 12*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
+5 -2
View File
@@ -20967,7 +20967,10 @@ static void m68k_op_stop(void)
uint new_sr = OPER_I_16();
CPU_STOPPED |= STOP_LEVEL_STOP;
m68ki_set_sr(new_sr);
SET_CYCLES(m68ki_cpu.cycle_end - 4*MUL);
if (CPU_STOPPED)
{
SET_CYCLES(m68ki_cpu.cycle_end - 4*MUL);
}
return;
}
m68ki_exception_privilege_violation();
@@ -24235,7 +24238,7 @@ static const opcode_handler_struct m68k_opcode_handler_table[] =
{m68k_op_btst_8_r_al , 0xf1ff, 0x0139, 16},
{m68k_op_btst_8_r_pcdi , 0xf1ff, 0x013a, 12},
{m68k_op_btst_8_r_pcix , 0xf1ff, 0x013b, 14},
{m68k_op_btst_8_r_i , 0xf1ff, 0x013c, 8},
{m68k_op_btst_8_r_i , 0xf1ff, 0x013c, 10},
{m68k_op_bchg_8_r_pi7 , 0xf1ff, 0x015f, 12},
{m68k_op_bchg_8_r_pd7 , 0xf1ff, 0x0167, 14},
{m68k_op_bchg_8_r_aw , 0xf1ff, 0x0178, 16},
+8 -8
View File
@@ -19,7 +19,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -51,7 +51,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -83,7 +83,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -115,7 +115,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -147,7 +147,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -179,7 +179,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -211,7 +211,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 10*4, 0*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
@@ -243,7 +243,7 @@ static const unsigned char m68ki_cycles[0x10000] =
6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 6*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4,
10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 10*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 12*4, 16*4, 12*4, 14*4, 8*4, 10*4, 0*4, 0*4,
8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4,
12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4, 12*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
+26 -2
View File
@@ -3,7 +3,7 @@
* Main 68k bus handlers
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -268,10 +268,16 @@ static void m68k_poll_sync(unsigned int reg_mask)
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* sync SUB-CPU with MAIN-CPU */
if (!s68k.stopped)
{
/* save current SUB-CPU end cycle count (recursive execution is possible) */
int end_cycle = s68k.cycle_end;
/* sync SUB-CPU with MAIN-CPU */
s68k_run(cycles);
/* restore SUB-CPU end cycle count */
s68k.cycle_end = end_cycle;
}
/* SUB-CPU idle on register polling ? */
@@ -354,8 +360,14 @@ unsigned int ctrl_io_read_byte(unsigned int address)
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* save current SUB-CPU end cycle count (recursive execution is possible) */
int end_cycle = s68k.cycle_end;
/* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 Boot ROM) */
s68k_run(cycles);
/* restore SUB-CPU end cycle count */
s68k.cycle_end = end_cycle;
}
m68k_poll_detect(1<<0x0f);
@@ -527,8 +539,14 @@ unsigned int ctrl_io_read_word(unsigned int address)
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* save current SUB-CPU end cycle count (recursive execution is possible) */
int end_cycle = s68k.cycle_end;
/* sync SUB-CPU with MAIN-CPU (Soul Star) */
s68k_run(cycles);
/* restore SUB-CPU end cycle count */
s68k.cycle_end = end_cycle;
}
m68k_poll_detect(3 << (index - 0x10));
@@ -646,8 +664,14 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* save current SUB-CPU end cycle count (recursive execution is possible) */
int end_cycle = s68k.cycle_end;
/* sync SUB-CPU with MAIN-CPU (Earnest Evans, Fhey Area) */
s68k_run(cycles);
/* restore SUB-CPU end cycle count */
s68k.cycle_end = end_cycle;
}
/* set IFL2 flag */
+1 -1
View File
@@ -3,7 +3,7 @@
* Main 68k bus handlers
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+211 -135
View File
@@ -3,7 +3,7 @@
* Sound Hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
@@ -40,6 +40,9 @@
#include "shared.h"
#include "blip_buf.h"
/* YM2612 internal clock = input clock / 6 = (master clock / 7) / 6 */
#define YM2612_CLOCK_RATIO (7*6)
/* FM output buffer (large enough to hold a whole frame at original chips rate) */
#ifdef HAVE_YM3438_CORE
static int fm_buffer[1080 * 2 * 24];
@@ -51,28 +54,121 @@ static int fm_last[2];
static int *fm_ptr;
/* Cycle-accurate FM samples */
static uint32 fm_cycles_ratio;
static uint32 fm_cycles_start;
static uint32 fm_cycles_count;
static int fm_cycles_ratio;
static int fm_cycles_start;
static int fm_cycles_count;
static int fm_cycles_busy;
/* YM chip function pointers */
static void (*YM_Reset)(void);
static void (*YM_Update)(int *buffer, int length);
static void (*YM_Write)(unsigned int a, unsigned int v);
static unsigned int (*YM_Read)(unsigned int a);
void (*fm_reset)(unsigned int cycles);
void (*fm_write)(unsigned int cycles, unsigned int address, unsigned int data);
unsigned int (*fm_read)(unsigned int cycles, unsigned int address);
#ifdef HAVE_YM3438_CORE
static ym3438_t ym3438;
static int ym3438_accm[24][2];
static short ym3438_accm[24][2];
static int ym3438_sample[2];
static unsigned int ym3438_cycles;
static int ym3438_cycles;
#endif
void YM3438_Reset(void)
/* Run FM chip until required M-cycles */
INLINE void fm_update(int cycles)
{
OPN2_Reset(&ym3438);
if (cycles > fm_cycles_count)
{
/* number of samples to run */
int samples = (cycles - fm_cycles_count + fm_cycles_ratio - 1) / fm_cycles_ratio;
/* run FM chip to sample buffer */
YM_Update(fm_ptr, samples);
/* update FM buffer pointer */
fm_ptr += (samples * 2);
/* update FM cycle counter */
fm_cycles_count += (samples * fm_cycles_ratio);
}
}
void YM3438_Update(int *buffer, int length)
static void YM2612_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
YM2612ResetChip();
fm_cycles_busy = 0;
}
static void YM2612_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
/* detect DATA port write */
if (a & 1)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* set FM BUSY end cycle (discrete or ASIC-integrated YM2612 chip only) */
if (config.ym2612 < YM2612_ENHANCED)
{
fm_cycles_busy = (((cycles + YM2612_CLOCK_RATIO - 1) / YM2612_CLOCK_RATIO) + 32) * YM2612_CLOCK_RATIO;
}
}
/* write FM register */
YM2612Write(a, v);
}
static unsigned int YM2612_Read(unsigned int cycles, unsigned int a)
{
/* FM status can only be read from (A0,A1)=(0,0) on discrete YM2612 */
if ((a == 0) || (config.ym2612 > YM2612_DISCRETE))
{
/* synchronize FM chip with CPU */
fm_update(cycles - fm_cycles_ratio + 1);
/* read FM status */
if (cycles >= fm_cycles_busy)
{
/* BUSY flag cleared */
return YM2612Read();
}
else
{
/* BUSY flag set */
return YM2612Read() | 0x80;
}
}
/* invalid FM status address */
return 0x00;
}
static void YM2413_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
YM2413ResetChip();
}
static void YM2413_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
/* detect DATA port write */
if (a & 1)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
}
/* write FM register */
YM2413Write(a, v);
}
#ifdef HAVE_YM3438_CORE
static void YM3438_Update(int *buffer, int length)
{
int i, j;
for (i = 0; i < length; i++)
@@ -94,36 +190,34 @@ void YM3438_Update(int *buffer, int length)
}
}
void YM3438_Write(unsigned int a, unsigned int v)
static void YM3438_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
OPN2_Reset(&ym3438);
}
static void YM3438_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* write FM register */
OPN2_Write(&ym3438, a, v);
}
unsigned int YM3438_Read(unsigned int a)
static unsigned int YM3438_Read(unsigned int cycles, unsigned int a)
{
/* synchronize FM chip with CPU */
fm_update(cycles - fm_cycles_ratio + 1);
/* read FM status */
return OPN2_Read(&ym3438, a);
}
#endif
/* Run FM chip until required M-cycles */
INLINE void fm_update(unsigned int cycles)
{
if (cycles > fm_cycles_count)
{
/* number of samples to run */
unsigned int samples = (cycles - fm_cycles_count + fm_cycles_ratio - 1) / fm_cycles_ratio;
/* run FM chip to sample buffer */
YM_Update(fm_ptr, samples);
/* update FM buffer pointer */
fm_ptr += (samples << 1);
/* update FM cycle counter */
fm_cycles_count += samples * fm_cycles_ratio;
}
}
void sound_init( void )
{
/* Initialize FM chip */
@@ -137,37 +231,37 @@ void sound_init( void )
memset(&ym3438, 0, sizeof(ym3438));
memset(&ym3438_sample, 0, sizeof(ym3438_sample));
memset(&ym3438_accm, 0, sizeof(ym3438_accm));
YM_Reset = YM3438_Reset;
YM_Update = YM3438_Update;
YM_Write = YM3438_Write;
YM_Read = YM3438_Read;
fm_reset = YM3438_Reset;
fm_write = YM3438_Write;
fm_read = YM3438_Read;
/* chip is running at VCLK / 6 = MCLK / 7 / 6 */
fm_cycles_ratio = 6 * 7;
/* chip is running at internal clock */
fm_cycles_ratio = YM2612_CLOCK_RATIO;
}
else
#endif
{
/* MAME */
/* MAME OPN2*/
YM2612Init();
YM2612Config(config.dac_bits);
YM_Reset = YM2612ResetChip;
YM2612Config(config.ym2612);
YM_Update = YM2612Update;
YM_Write = YM2612Write;
YM_Read = YM2612Read;
fm_reset = YM2612_Reset;
fm_write = YM2612_Write;
fm_read = YM2612_Read;
/* chip is running at VCLK / 144 = MCLK / 7 / 144 */
fm_cycles_ratio = 144 * 7;
/* chip is running at sample clock */
fm_cycles_ratio = YM2612_CLOCK_RATIO * 24;
}
}
else
{
/* YM2413 */
YM2413Init();
YM_Reset = YM2413ResetChip;
YM_Update = YM2413Update;
YM_Write = YM2413Write;
YM_Read = NULL;
YM_Update = (config.ym2413 & 1) ? YM2413Update : NULL;
fm_reset = YM2413_Reset;
fm_write = YM2413_Write;
fm_read = NULL;
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
fm_cycles_ratio = 72 * 15;
@@ -180,7 +274,7 @@ void sound_init( void )
void sound_reset(void)
{
/* reset sound chips */
YM_Reset();
fm_reset(0);
psg_reset();
psg_config(0, config.psg_preamp, 0xff);
@@ -196,73 +290,85 @@ void sound_reset(void)
int sound_update(unsigned int cycles)
{
int prev_l, prev_r, preamp, time, l, r, *ptr;
/* Run PSG chip until end of frame */
psg_end_frame(cycles);
/* Run FM chip until end of frame */
fm_update(cycles);
/* FM output pre-amplification */
preamp = config.fm_preamp;
/* FM frame initial timestamp */
time = fm_cycles_start;
/* Restore last FM outputs from previous frame */
prev_l = fm_last[0];
prev_r = fm_last[1];
/* FM buffer start pointer */
ptr = fm_buffer;
/* flush FM samples */
if (config.hq_fm)
/* FM chip is enabled ? */
if (YM_Update)
{
/* high-quality Band-Limited synthesis */
do
int prev_l, prev_r, preamp, time, l, r, *ptr;
/* Run FM chip until end of frame */
fm_update(cycles);
/* FM output pre-amplification */
preamp = config.fm_preamp;
/* FM frame initial timestamp */
time = fm_cycles_start;
/* Restore last FM outputs from previous frame */
prev_l = fm_last[0];
prev_r = fm_last[1];
/* FM buffer start pointer */
ptr = fm_buffer;
/* flush FM samples */
if (config.hq_fm)
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* high-quality Band-Limited synthesis */
do
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* increment time counter */
time += fm_cycles_ratio;
/* increment time counter */
time += fm_cycles_ratio;
}
while (time < cycles);
}
while (time < cycles);
}
else
{
/* faster Linear Interpolation */
do
else
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta_fast(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* faster Linear Interpolation */
do
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta_fast(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* increment time counter */
time += fm_cycles_ratio;
/* increment time counter */
time += fm_cycles_ratio;
}
while (time < cycles);
}
/* reset FM buffer pointer */
fm_ptr = fm_buffer;
/* save last FM output for next frame */
fm_last[0] = prev_l;
fm_last[1] = prev_r;
/* adjust FM cycle counters for next frame */
fm_cycles_count = fm_cycles_start = time - cycles;
if (fm_cycles_busy > cycles)
{
fm_cycles_busy -= cycles;
}
else
{
fm_cycles_busy = 0;
}
while (time < cycles);
}
/* reset FM buffer pointer */
fm_ptr = fm_buffer;
/* save last FM output for next frame */
fm_last[0] = prev_l;
fm_last[1] = prev_r;
/* adjust FM cycle counters for next frame */
fm_cycles_count = fm_cycles_start = time - cycles;
/* end of blip buffer time frame */
blip_end_frame(snd.blips[0], cycles);
@@ -288,7 +394,6 @@ int sound_context_save(uint8 *state)
else
{
bufferptr += YM2612SaveContext(state + sizeof(config.ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612SaveContext(state);
@@ -325,11 +430,9 @@ int sound_context_load(uint8 *state)
else
{
bufferptr += YM2612LoadContext(state + sizeof(config_ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612LoadContext(state);
YM2612Config(config.dac_bits);
#endif
}
else
@@ -344,30 +447,3 @@ int sound_context_load(uint8 *state)
return bufferptr;
}
void fm_reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
YM_Reset();
}
void fm_write(unsigned int cycles, unsigned int address, unsigned int data)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* write FM register */
YM_Write(address, data);
}
unsigned int fm_read(unsigned int cycles, unsigned int address)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* read FM status (YM2612 only) */
return YM_Read(address);
}
+4 -4
View File
@@ -3,7 +3,7 @@
* Sound Hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
@@ -46,8 +46,8 @@ extern void sound_reset(void);
extern int sound_context_save(uint8 *state);
extern int sound_context_load(uint8 *state);
extern int sound_update(unsigned int cycles);
extern void fm_reset(unsigned int cycles);
extern void fm_write(unsigned int cycles, unsigned int address, unsigned int data);
extern unsigned int fm_read(unsigned int cycles, unsigned int address);
extern void (*fm_reset)(unsigned int cycles);
extern void (*fm_write)(unsigned int cycles, unsigned int address, unsigned int data);
extern unsigned int (*fm_read)(unsigned int cycles, unsigned int address);
#endif /* _SOUND_H_ */
+111 -47
View File
@@ -15,15 +15,16 @@
** Additional info from YM2612 die shot analysis by Sauraen
** See http://gendev.spritesmind.net/forum/viewtopic.php?t=386
**
** TODO:
** - better documentation
** - BUSY flag emulation
** - accurate DAC output
*/
/*
** CHANGELOG:
**
** 03-12-2017 Eke-Eke (Genesis Plus GX):
** - improved 9-bit DAC emulation accuracy
** - added discrete YM2612 DAC distortion emulation ("ladder effect")
** - replaced configurable DAC depth with configurable chip types (discrete, integrated or enhanced)
**
** 26-09-2017 Eke-Eke (Genesis Plus GX):
** - fixed EG counter loopback behavior (verified on YM3438 die)
** - reverted changes to EG rates 2-7 increment values
@@ -626,8 +627,11 @@ static YM2612 ym2612;
/* current chip state */
static INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
static INT32 mem; /* one sample delay memory */
static INT32 out_fm[8]; /* outputs of working channels */
static UINT32 bitmask; /* working channels output bitmasking (DAC quantization) */
static INT32 out_fm[6]; /* outputs of working channels */
/* chip type */
static UINT32 op_mask[8][4]; /* operator output bitmasking (DAC quantization) */
static int chip_type = YM2612_DISCRETE;
INLINE void FM_KEYON(FM_CH *CH , int s )
@@ -1408,22 +1412,22 @@ INLINE void refresh_fc_eg_chan(FM_CH *CH )
#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
INLINE signed int op_calc(UINT32 phase, unsigned int env, unsigned int pm)
INLINE signed int op_calc(UINT32 phase, unsigned int env, unsigned int pm, unsigned int opmask)
{
UINT32 p = (env<<3) + sin_tab[ ( (phase >> SIN_BITS) + (pm >> 1) ) & SIN_MASK ];
if (p >= TL_TAB_LEN)
return 0;
return tl_tab[p];
return (tl_tab[p] & opmask);
}
INLINE signed int op_calc1(UINT32 phase, unsigned int env, unsigned int pm)
INLINE signed int op_calc1(UINT32 phase, unsigned int env, unsigned int pm, unsigned int opmask)
{
UINT32 p = (env<<3) + sin_tab[ ( ( phase >> SIN_BITS ) + pm ) & SIN_MASK ];
if (p >= TL_TAB_LEN)
return 0;
return tl_tab[p];
return (tl_tab[p] & opmask);
}
INLINE void chan_calc(FM_CH *CH, int num)
@@ -1433,6 +1437,7 @@ INLINE void chan_calc(FM_CH *CH, int num)
INT32 out = 0;
UINT32 AM = ym2612.OPN.LFO_AM >> CH->ams;
unsigned int eg_out = volume_calc(&CH->SLOT[SLOT1]);
UINT32 *mask = op_mask[CH->ALGO];
m2 = c1 = c2 = mem = 0;
@@ -1443,7 +1448,7 @@ INLINE void chan_calc(FM_CH *CH, int num)
if (CH->FB < SIN_BITS)
out = (CH->op1_out[0] + CH->op1_out[1]) >> CH->FB;
out = op_calc1(CH->SLOT[SLOT1].phase, eg_out, out );
out = op_calc1(CH->SLOT[SLOT1].phase, eg_out, out, mask[0]);
}
CH->op1_out[0] = CH->op1_out[1];
@@ -1459,22 +1464,21 @@ INLINE void chan_calc(FM_CH *CH, int num)
eg_out = volume_calc(&CH->SLOT[SLOT3]);
if( eg_out < ENV_QUIET ) /* SLOT 3 */
*CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2);
*CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2, mask[2]);
eg_out = volume_calc(&CH->SLOT[SLOT2]);
if( eg_out < ENV_QUIET ) /* SLOT 2 */
*CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1);
*CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1, mask[1]);
eg_out = volume_calc(&CH->SLOT[SLOT4]);
if( eg_out < ENV_QUIET ) /* SLOT 4 */
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2);
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2, mask[3]);
/* store current MEM */
CH->mem_value = mem;
/* update phase counters AFTER output calculations */
if(CH->pms)
if (CH->pms)
{
/* 3-slot mode */
if ((ym2612.OPN.ST.mode & 0xC0) && (CH == &ym2612.CH[2]))
@@ -1515,7 +1519,7 @@ INLINE void OPNWriteMode(int r, int v)
case 0x21: /* Test */
break;
case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/ym2612) */
case 0x22: /* LFO FREQ */
if (v&8) /* LFO enabled ? */
{
ym2612.OPN.lfo_timer_overflow = lfo_samples_per_step[v&7];
@@ -1550,7 +1554,6 @@ INLINE void OPNWriteMode(int r, int v)
if( c == 3 ) break;
if (v&0x04) c+=3; /* CH 4-6 */
CH = &ym2612.CH[c];
if (v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
if (v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
if (v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
@@ -1686,8 +1689,6 @@ INLINE void OPNWriteReg(int r, int v)
That is not necessary, but then EG will be generating Attack phase.
*/
break;
case 0xa0:
@@ -1722,7 +1723,7 @@ INLINE void OPNWriteReg(int r, int v)
ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn;
ym2612.CH[2].SLOT[SLOT1].Incr=-1;
}
break;
break;
case 3: /* 0xac-0xae : 3CH FNUM2,BLK */
if(r < 0x100)
ym2612.OPN.SL3.fn_h = v&0x3f;
@@ -1737,7 +1738,7 @@ INLINE void OPNWriteReg(int r, int v)
CH->ALGO = v&7;
CH->FB = SIN_BITS - ((v>>3)&7);
setup_connection( CH, c );
break;
break;
}
case 1: /* 0xb4-0xb6 : L , R , AMS , PMS */
/* b0-2 PMS */
@@ -1747,8 +1748,8 @@ INLINE void OPNWriteReg(int r, int v)
CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03];
/* PAN : b7 = L, b6 = R */
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? bitmask : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? bitmask : 0;
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? 0xffffffff : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? 0xffffffff : 0;
break;
}
break;
@@ -1884,6 +1885,15 @@ static void init_tables(void)
}
}
/* build default OP mask table */
for (i = 0;i < 8;i++)
{
for (d = 0;d < 4;d++)
{
op_mask[i][d] = 0xffffffff;
}
}
}
@@ -1984,9 +1994,9 @@ void YM2612Write(unsigned int a, unsigned int v)
}
}
unsigned int YM2612Read(unsigned int a)
unsigned int YM2612Read(void)
{
return ym2612.OPN.ST.status & 0xff;
return ym2612.OPN.ST.status;
}
/* Generate samples for ym2612 */
@@ -2020,7 +2030,7 @@ void YM2612Update(int *buffer, int length)
refresh_fc_eg_chan(&ym2612.CH[5]);
/* buffering */
for(i=0; i<length ; i++)
for(i=0; i<length; i++)
{
/* clear outputs */
out_fm[0] = 0;
@@ -2066,21 +2076,21 @@ void YM2612Update(int *buffer, int length)
advance_eg_channels(&ym2612.CH[0], ym2612.OPN.eg_cnt);
}
/* 14-bit accumulator channels outputs (range is -8192;+8192) */
if (out_fm[0] > 8192) out_fm[0] = 8192;
/* channels accumulator output clipping (14-bit max) */
if (out_fm[0] > 8191) out_fm[0] = 8191;
else if (out_fm[0] < -8192) out_fm[0] = -8192;
if (out_fm[1] > 8192) out_fm[1] = 8192;
if (out_fm[1] > 8191) out_fm[1] = 8191;
else if (out_fm[1] < -8192) out_fm[1] = -8192;
if (out_fm[2] > 8192) out_fm[2] = 8192;
if (out_fm[2] > 8191) out_fm[2] = 8191;
else if (out_fm[2] < -8192) out_fm[2] = -8192;
if (out_fm[3] > 8192) out_fm[3] = 8192;
if (out_fm[3] > 8191) out_fm[3] = 8191;
else if (out_fm[3] < -8192) out_fm[3] = -8192;
if (out_fm[4] > 8192) out_fm[4] = 8192;
if (out_fm[4] > 8191) out_fm[4] = 8191;
else if (out_fm[4] < -8192) out_fm[4] = -8192;
if (out_fm[5] > 8192) out_fm[5] = 8192;
if (out_fm[5] > 8191) out_fm[5] = 8191;
else if (out_fm[5] < -8192) out_fm[5] = -8192;
/* stereo DAC channels outputs mixing */
/* stereo DAC output panning & mixing */
lt = ((out_fm[0]) & ym2612.OPN.pan[0]);
rt = ((out_fm[0]) & ym2612.OPN.pan[1]);
lt += ((out_fm[1]) & ym2612.OPN.pan[2]);
@@ -2094,11 +2104,34 @@ void YM2612Update(int *buffer, int length)
lt += ((out_fm[5]) & ym2612.OPN.pan[10]);
rt += ((out_fm[5]) & ym2612.OPN.pan[11]);
/* discrete YM2612 DAC */
if (chip_type == YM2612_DISCRETE)
{
int i;
/* DAC 'ladder effect' */
for (i=0; i<6; i++)
{
if (out_fm[i] < 0)
{
/* -4 offset (-3 when not muted) on negative channel output (9-bit) */
lt -= ((4 - (ym2612.OPN.pan[(2*i)+0] & 1)) << 5);
rt -= ((4 - (ym2612.OPN.pan[(2*i)+1] & 1)) << 5);
}
else
{
/* +4 offset (when muted or not) on positive channel output (9-bit) */
lt += (4 << 5);
rt += (4 << 5);
}
}
}
/* buffering */
*buffer++ = lt;
*buffer++ = rt;
/* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */
/* CSM mode: if CSM Key ON has occurred, CSM Key OFF need to be sent */
/* only if Timer A does not overflow again (i.e CSM Key ON not set again) */
ym2612.OPN.SL3.key_csm <<= 1;
@@ -2121,20 +2154,51 @@ void YM2612Update(int *buffer, int length)
INTERNAL_TIMER_B(length);
}
void YM2612Config(unsigned char dac_bits)
void YM2612Config(int type)
{
int i;
/* YM2612 chip type */
chip_type = type;
/* DAC precision (normally 9-bit on real hardware, implemented through simple 14-bit channel output bitmasking) */
bitmask = ~((1 << (TL_BITS - dac_bits)) - 1);
/* update L/R panning bitmasks */
for (i=0; i<2*6; i++)
/* carrier operator outputs bitmask */
if (chip_type < YM2612_ENHANCED)
{
if (ym2612.OPN.pan[i])
{
ym2612.OPN.pan[i] = bitmask;
}
/* 9-bit DAC */
op_mask[0][3] = 0xffffffe0;
op_mask[1][3] = 0xffffffe0;
op_mask[2][3] = 0xffffffe0;
op_mask[3][3] = 0xffffffe0;
op_mask[4][1] = 0xffffffe0;
op_mask[4][3] = 0xffffffe0;
op_mask[5][1] = 0xffffffe0;
op_mask[5][2] = 0xffffffe0;
op_mask[5][3] = 0xffffffe0;
op_mask[6][1] = 0xffffffe0;
op_mask[6][2] = 0xffffffe0;
op_mask[6][3] = 0xffffffe0;
op_mask[7][0] = 0xffffffe0;
op_mask[7][1] = 0xffffffe0;
op_mask[7][2] = 0xffffffe0;
op_mask[7][3] = 0xffffffe0;
}
else
{
/* 14-bit DAC */
op_mask[0][3] = 0xffffffff;
op_mask[1][3] = 0xffffffff;
op_mask[2][3] = 0xffffffff;
op_mask[3][3] = 0xffffffff;
op_mask[4][1] = 0xffffffff;
op_mask[4][3] = 0xffffffff;
op_mask[5][1] = 0xffffffff;
op_mask[5][2] = 0xffffffff;
op_mask[5][3] = 0xffffffff;
op_mask[6][1] = 0xffffffff;
op_mask[6][2] = 0xffffffff;
op_mask[6][3] = 0xffffffff;
op_mask[7][0] = 0xffffffff;
op_mask[7][1] = 0xffffffff;
op_mask[7][2] = 0xffffffff;
op_mask[7][3] = 0xffffffff;
}
}
+8 -2
View File
@@ -16,12 +16,18 @@
#ifndef _H_YM2612_
#define _H_YM2612_
enum {
YM2612_DISCRETE = 0,
YM2612_INTEGRATED,
YM2612_ENHANCED
};
extern void YM2612Init(void);
extern void YM2612Config(unsigned char dac_bits);
extern void YM2612Config(int type);
extern void YM2612ResetChip(void);
extern void YM2612Update(int *buffer, int length);
extern void YM2612Write(unsigned int a, unsigned int v);
extern unsigned int YM2612Read(unsigned int a);
extern unsigned int YM2612Read(void);
extern int YM2612LoadContext(unsigned char *state);
extern int YM2612SaveContext(unsigned char *state);
+23 -13
View File
@@ -40,7 +40,7 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.7
* version: 1.0.8
*/
#include <string.h>
@@ -233,7 +233,7 @@ static const Bit32u fm_algorithm[4][6][8] = {
}
};
static Bit32u chip_type = ym3438_type_discrete;
static Bit32u chip_type = ym3438_mode_readmode;
void OPN2_DoIO(ym3438_t *chip)
{
@@ -995,7 +995,7 @@ void OPN2_ChOutput(ym3438_t *chip)
chip->mol = 0;
chip->mor = 0;
if (chip_type == ym3438_type_ym2612)
if (chip_type & ym3438_mode_ym2612)
{
out_en = ((cycles & 3) == 3) || test_dac;
/* YM2612 DAC emulation(not verified) */
@@ -1028,11 +1028,6 @@ void OPN2_ChOutput(ym3438_t *chip)
else
{
out_en = ((cycles & 3) != 0) || test_dac;
/* Discrete YM3438 seems has the ladder effect too */
if (out >= 0 && chip_type == ym3438_type_discrete)
{
out++;
}
if (chip->ch_lock_l && out_en)
{
chip->mol = out;
@@ -1223,7 +1218,7 @@ void OPN2_SetChipType(Bit32u type)
chip_type = type;
}
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
{
chip->lfo_inc = chip->mode_test_21[1];
chip->pg_read >>= 1;
@@ -1355,6 +1350,9 @@ void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
buffer[0] = chip->mol;
buffer[1] = chip->mor;
if (chip->status_time)
chip->status_time--;
}
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data)
@@ -1394,7 +1392,7 @@ Bit32u OPN2_ReadIRQPin(ym3438_t *chip)
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
{
if ((port & 3) == 0 || chip_type == ym3438_type_asic)
if ((port & 3) == 0 || (chip_type & ym3438_mode_readmode))
{
if (chip->mode_test_21[6])
{
@@ -1411,18 +1409,30 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
}
if (chip->mode_test_21[7])
{
return testdata & 0xff;
chip->status = testdata & 0xff;
}
else
{
return testdata >> 8;
chip->status = testdata >> 8;
}
}
else
{
return (chip->busy << 7) | (chip->timer_b_overflow_flag << 1)
chip->status = (chip->busy << 7) | (chip->timer_b_overflow_flag << 1)
| chip->timer_a_overflow_flag;
}
if (chip_type & ym3438_mode_ym2612)
{
chip->status_time = 300000;
}
else
{
chip->status_time = 40000000;
}
}
if (chip->status_time)
{
return chip->status;
}
return 0;
}
+6 -5
View File
@@ -39,16 +39,15 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.7
* version: 1.0.8
*/
#ifndef YM3438_H
#define YM3438_H
enum {
ym3438_type_discrete = 0, /* Discrete YM3438 (Teradrive) */
ym3438_type_asic = 1, /* ASIC YM3438 (MD1 VA7, MD2, MD3, etc) */
ym3438_type_ym2612 = 2 /* YM2612 (MD1, MD2 VA2) */
ym3438_mode_ym2612 = 0x01, /* Enables YM2612 emulation (MD1, MD2 VA2) */
ym3438_mode_readmode = 0x02, /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */
};
#include <stdint.h>
@@ -205,11 +204,13 @@ typedef struct
Bit8u pan_l[6], pan_r[6];
Bit8u ams[6];
Bit8u pms[6];
Bit8u status;
Bit32u status_time;
} ym3438_t;
void OPN2_Reset(ym3438_t *chip);
void OPN2_SetChipType(Bit32u type);
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer);
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer);
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data);
void OPN2_SetTestPin(ym3438_t *chip, Bit32u value);
Bit32u OPN2_ReadTestPin(ym3438_t *chip);
+4 -4
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -197,7 +197,7 @@ int state_save(unsigned char *state)
/* version string */
char version[16];
strncpy(version,STATE_VERSION,16);
memcpy(version,STATE_VERSION,16);
save_param(version, 16);
/* GENESIS */
@@ -260,8 +260,8 @@ int state_save(unsigned char *state)
if (system_hw == SYSTEM_MCD)
{
/* CD hardware ID flag */
char id[5];
strncpy(id,"SCD!",4);
char id[4];
memcpy(id,"SCD!",4);
save_param(id, 4);
/* CD hardware */
+1 -1
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+1 -41
View File
@@ -5,7 +5,7 @@
* Support for 16-bit & 8-bit hardware modes
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
@@ -467,10 +467,6 @@ void system_frame_gen(int do_skip)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* set VINT flag */
status |= 0x80;
@@ -493,10 +489,6 @@ void system_frame_gen(int do_skip)
{
z80_run(MCYCLES_PER_LINE);
}
else
{
Z80.cycles = MCYCLES_PER_LINE;
}
/* Z80 interrupt is cleared at the end of the line */
Z80.irq_state = CLEAR_LINE;
@@ -538,10 +530,6 @@ void system_frame_gen(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
@@ -590,10 +578,6 @@ void system_frame_gen(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
@@ -654,10 +638,6 @@ void system_frame_gen(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
@@ -826,10 +806,6 @@ void system_frame_scd(int do_skip)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* set VINT flag */
status |= 0x80;
@@ -854,10 +830,6 @@ void system_frame_scd(int do_skip)
{
z80_run(MCYCLES_PER_LINE);
}
else
{
Z80.cycles = MCYCLES_PER_LINE;
}
/* Z80 interrupt is cleared at the end of the line */
Z80.irq_state = CLEAR_LINE;
@@ -895,10 +867,6 @@ void system_frame_scd(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update VDP cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
@@ -943,10 +911,6 @@ void system_frame_scd(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update VDP cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
@@ -1003,10 +967,6 @@ void system_frame_scd(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update VDP cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
+1 -1
View File
@@ -5,7 +5,7 @@
* Support for 16-bit & 8-bit hardware modes
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-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:
+6
View File
@@ -1,3 +1,7 @@
#ifndef _TYPES_H_
#define _TYPES_H_
#undef uint8
#undef uint16
#undef uint32
@@ -27,3 +31,5 @@ typedef union
} byte;
} reg16_t;
#endif /* _TYPES_H_ */
+37
View File
@@ -2167,6 +2167,11 @@ static void vdp_bus_w(unsigned int data)
MARK_BG_DIRTY (index);
}
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_VRAM_W, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@@ -2210,6 +2215,12 @@ static void vdp_bus_w(unsigned int data)
remap_line(v_counter);
}
}
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_CRAM_W, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@@ -2230,6 +2241,12 @@ static void vdp_bus_w(unsigned int data)
render_line(v_counter);
}
}
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_VSRAM_W, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@@ -2434,6 +2451,11 @@ static unsigned int vdp_68k_data_r_m5(void)
/* read two bytes from VRAM */
data = *(uint16 *)&vram[addr & 0xFFFE];
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_VRAM_R, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@@ -2458,6 +2480,11 @@ static unsigned int vdp_68k_data_r_m5(void)
/* Unused bits are set using data from next available FIFO entry */
data |= (fifo[fifo_idx] & ~0x7FF);
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_VSRAM_R, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@@ -2475,6 +2502,11 @@ static unsigned int vdp_68k_data_r_m5(void)
/* Unused bits are set using data from next available FIFO entry */
data |= (fifo[fifo_idx] & ~0xEEE);
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_CRAM_R, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@@ -2489,6 +2521,11 @@ static unsigned int vdp_68k_data_r_m5(void)
/* Unused bits are set using data from next available FIFO entry */
data |= (fifo[fifo_idx] & ~0xFF);
#ifdef HOOK_CPU
if (cpu_hook)
cpu_hook(HOOK_VRAM_R, 2, addr, data);
#endif
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
+19 -7
View File
@@ -38,6 +38,7 @@
* - Implemented cycle-accurate INI/IND (needed by SMS emulation)
* - Fixed Z80 reset
* - Made SZHVC_add & SZHVC_sub tables statically allocated
* - Fixed compiler warning when BIG_SWITCH is defined
* Changes in 3.9:
* - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow]
* - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap]
@@ -428,7 +429,9 @@ typedef void (*funcptr)(void);
INLINE void prefix##_f0(void); INLINE void prefix##_f1(void); INLINE void prefix##_f2(void); INLINE void prefix##_f3(void); \
INLINE void prefix##_f4(void); INLINE void prefix##_f5(void); INLINE void prefix##_f6(void); INLINE void prefix##_f7(void); \
INLINE void prefix##_f8(void); INLINE void prefix##_f9(void); INLINE void prefix##_fa(void); INLINE void prefix##_fb(void); \
INLINE void prefix##_fc(void); INLINE void prefix##_fd(void); INLINE void prefix##_fe(void); INLINE void prefix##_ff(void); \
INLINE void prefix##_fc(void); INLINE void prefix##_fd(void); INLINE void prefix##_fe(void); INLINE void prefix##_ff(void);
#define FUNCTABLE(tablename,prefix) \
static const funcptr tablename[0x100] = { \
prefix##_00,prefix##_01,prefix##_02,prefix##_03,prefix##_04,prefix##_05,prefix##_06,prefix##_07, \
prefix##_08,prefix##_09,prefix##_0a,prefix##_0b,prefix##_0c,prefix##_0d,prefix##_0e,prefix##_0f, \
@@ -464,12 +467,21 @@ static const funcptr tablename[0x100] = { \
prefix##_f8,prefix##_f9,prefix##_fa,prefix##_fb,prefix##_fc,prefix##_fd,prefix##_fe,prefix##_ff \
}
PROTOTYPES(Z80op,op);
PROTOTYPES(Z80cb,cb);
PROTOTYPES(Z80dd,dd);
PROTOTYPES(Z80ed,ed);
PROTOTYPES(Z80fd,fd);
PROTOTYPES(Z80xycb,xycb);
PROTOTYPES(Z80op,op)
PROTOTYPES(Z80cb,cb)
PROTOTYPES(Z80dd,dd)
PROTOTYPES(Z80ed,ed)
PROTOTYPES(Z80fd,fd)
PROTOTYPES(Z80xycb,xycb)
#ifndef BIG_SWITCH
FUNCTABLE(Z80op,op);
#endif
FUNCTABLE(Z80cb,cb);
FUNCTABLE(Z80dd,dd);
FUNCTABLE(Z80ed,ed);
FUNCTABLE(Z80fd,fd);
FUNCTABLE(Z80xycb,xycb);
/****************************************************************************/
/* Burn an odd amount of cycles, that is instructions taking something */
+4 -1
View File
@@ -34,8 +34,11 @@ struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
#ifdef HAVE_YM3438_CORE
uint8 ym3438;
#endif
uint8 mono;
int16 psg_preamp;
int16 fm_preamp;