24 Commits

Author SHA1 Message Date
clobber 3ebf7e57eb Bump version for sparkle updater 2021-09-17 00:27:33 -06:00
clobber 576e14d64c Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/35ed78cc71f6b2c69b1377c9520416d0253b6633 2021-09-17 00:24:44 -06:00
C.W. Betts 95b9099b3e Change crc32 to be/take unsigned int instead of unsigned long.
This'll make crc_table smaller.
2020-10-19 17:05:00 -06:00
C.W. Betts 90c519eb1e Poke the plists: get the development language from Xcode build. 2020-10-01 01:51:37 -06:00
C.W. Betts 779baa7fca Fix locations of the system plugin headers.
Minor Xcode maintenance.
2020-10-01 01:26:41 -06:00
C.W. Betts 4f13fea4e2 Fix Xcode 12 build failure. 2020-09-22 14:13:55 -06:00
clobber 17f423cfbd Bump version for sparkle updater 2020-08-28 15:10:36 -05:00
clobber 975a3e3266 Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/f8a8046948aedc9d96ad81b3894c55d914dbef0f 2020-08-28 15:10:11 -05:00
clobber 17788c3ddd Bump version for sparkle updater 2020-08-19 14:47:23 -05:00
clobber 15af996d79 Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/15722b16ab5a539b14dba024bb008b5c6f22c202 2020-08-19 14:46:59 -05:00
C.W. Betts 2c0279c0ac Update language resources.
This quiets warnings in newer Xcode releases.

Also update framework locations.
2020-01-08 01:15:51 -07:00
clobber 6863200707 Bump version for sparkle updater 2019-10-23 11:44:33 -05:00
clobber 35889724f4 Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/5b1271e4770412f47a6170b8f925905a9f46e5ef 2019-10-23 11:44:03 -05:00
clobber 41577e1fa5 Fix typo. 2019-10-21 11:09:07 -05:00
clobber 02499a735b Bump version for sparkle updater 2018-11-26 23:18:38 -06:00
clobber 2875815a60 GG: Add display mode change support 2018-11-26 23:17:54 -06:00
clobber f1828430d3 Cleanup 2018-11-26 21:10:10 -06:00
clobber 682625653b Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/2ab02c8122d5127fe4a884ed8b65a3c767c90fb9 2018-11-26 18:54:25 -06:00
clobber 38c438243e Bump version for sparkle updater 2018-09-17 16:14:52 -05:00
clobber 25933fefad Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/a4255fafc2f649faca84126ebab1c5cb99fc5df3 2018-09-17 16:13:37 -05:00
clobber 20a3b05782 Cleanup 2018-09-17 16:12:32 -05:00
clobber c5df0565e6 Bump version for sparkle updater 2018-03-18 14:28:39 -05:00
clobber c06e10d458 SG/MD/SCD/MCD: Fix PAR 2018-03-18 14:28:11 -05:00
clobber 0419c81f9e Sync with https://github.com/ekeeke/Genesis-Plus-GX/commit/726b7112d806ae23694b2a1634d8d866c87c4864 2018-03-18 13:43:08 -05:00
71 changed files with 3950 additions and 1287 deletions
Binary file not shown.
+175 -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,9 +36,19 @@
#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);
t_config config;
char GG_ROM[256];
char AR_ROM[256];
char SK_ROM[256];
@@ -99,9 +109,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 +130,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 +142,8 @@ static __weak GenPlusGameCore *_current;
- (void)dealloc
{
free(videoBuffer);
free(soundBuffer);
free(_videoBuffer);
free(_soundBuffer);
}
# pragma mark - Execution
@@ -142,20 +153,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 +174,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 +192,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 +224,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 +252,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 +264,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 +288,7 @@ static __weak GenPlusGameCore *_current;
- (const void *)getVideoBufferWithHint:(void *)hint
{
if (!hint) {
hint = videoBuffer;
hint = _videoBuffer;
}
return bitmap.data = (uint8_t*)hint;
@@ -285,7 +296,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 +313,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 +358,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 +386,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 +429,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 +585,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 +655,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 +687,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 +773,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 +799,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 +826,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 +846,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 +854,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 +889,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 +915,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 +924,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 +940,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 +1019,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 +1664,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)
{
+14 -13
View File
@@ -126,10 +126,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
089C167EFE841241C02AAC07 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
82287C08101E9C2C0072172D /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
82287C33101E9DB40072172D /* GenPlusGameCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenPlusGameCore.h; sourceTree = "<group>"; };
82287C34101E9DB40072172D /* GenPlusGameCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GenPlusGameCore.m; sourceTree = "<group>"; };
@@ -138,9 +138,9 @@
879243AD1C0D044B0064C515 /* xe_1ap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xe_1ap.h; sourceTree = "<group>"; };
879243AF1C0D05120064C515 /* graphic_board.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = graphic_board.c; sourceTree = "<group>"; };
879243B01C0D05120064C515 /* graphic_board.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphic_board.h; sourceTree = "<group>"; };
87D7BFC01F9841EE000B38DE /* OESMSSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESMSSystemResponderClient.h; path = ../OpenEmu/SegaMasterSystem/OESMSSystemResponderClient.h; sourceTree = "<group>"; };
87D7BFC11F9841F8000B38DE /* OEGGSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGGSystemResponderClient.h; path = ../OpenEmu/GameGear/OEGGSystemResponderClient.h; sourceTree = "<group>"; };
87D7BFC21F984206000B38DE /* OESG1000SystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESG1000SystemResponderClient.h; path = "../OpenEmu/SG-1000/OESG1000SystemResponderClient.h"; sourceTree = "<group>"; };
87D7BFC01F9841EE000B38DE /* OESMSSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESMSSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/SegaMasterSystem/OESMSSystemResponderClient.h; sourceTree = "<group>"; };
87D7BFC11F9841F8000B38DE /* OEGGSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGGSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/GameGear/OEGGSystemResponderClient.h; sourceTree = "<group>"; };
87D7BFC21F984206000B38DE /* OESG1000SystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESG1000SystemResponderClient.h; path = "../OpenEmu/SystemPlugins/SG-1000/OESG1000SystemResponderClient.h"; sourceTree = "<group>"; };
87E0514A1B18092700E870E1 /* osd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osd.h; sourceTree = "<group>"; };
87E0514B1B18092700E870E1 /* scrc32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scrc32.c; sourceTree = "<group>"; };
87E0514C1B18092700E870E1 /* scrc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scrc32.h; sourceTree = "<group>"; };
@@ -156,7 +156,7 @@
941FF4F8162A4BAE005A9427 /* eeprom_spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eeprom_spi.h; sourceTree = "<group>"; };
941FF4FC162A4BE1005A9427 /* blip_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blip_buf.c; sourceTree = "<group>"; };
941FF4FD162A4BE1005A9427 /* blip_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blip_buf.h; sourceTree = "<group>"; };
946C18AE17148D5200C64BF9 /* OESegaCDSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESegaCDSystemResponderClient.h; path = "../OpenEmu/Sega CD/OESegaCDSystemResponderClient.h"; sourceTree = "<group>"; };
946C18AE17148D5200C64BF9 /* OESegaCDSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESegaCDSystemResponderClient.h; path = "../OpenEmu/SystemPlugins/Sega CD/OESegaCDSystemResponderClient.h"; sourceTree = "<group>"; };
948DA2A115AB906400C0EA78 /* cd_cart.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cd_cart.c; sourceTree = "<group>"; };
948DA2A215AB906400C0EA78 /* cd_cart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cd_cart.h; sourceTree = "<group>"; };
948DA2A315AB906400C0EA78 /* cdc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cdc.c; sourceTree = "<group>"; };
@@ -256,9 +256,9 @@
94ED8A8514CF933700FF8901 /* osd_cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osd_cpu.h; sourceTree = "<group>"; };
94ED8A8614CF933700FF8901 /* z80.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = z80.c; sourceTree = "<group>"; };
94ED8A8714CF933700FF8901 /* z80.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = z80.h; sourceTree = "<group>"; };
C6B948191365164700A425F0 /* OEGenesisSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGenesisSystemResponderClient.h; path = ../OpenEmu/Genesis/OEGenesisSystemResponderClient.h; sourceTree = "<group>"; };
C6B948191365164700A425F0 /* OEGenesisSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGenesisSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/Genesis/OEGenesisSystemResponderClient.h; sourceTree = "<group>"; };
C6D120F1171130E700E868A8 /* OpenEmuBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OpenEmuBase.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -570,12 +570,11 @@
089C1669FE841209C02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 0700;
};
buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "GenesisPlus" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
en,
@@ -714,7 +713,7 @@
089C167DFE841241C02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
089C167EFE841241C02AAC07 /* English */,
089C167EFE841241C02AAC07 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
@@ -734,6 +733,7 @@
OTHER_CFLAGS = (
"-DLSB_FIRST",
"-DUSE_32BPP_RENDERING",
"-DMAXROMSIZE=33554432",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
PRODUCT_NAME = GenesisPlus;
@@ -754,6 +754,7 @@
OTHER_CFLAGS = (
"-DLSB_FIRST",
"-DUSE_32BPP_RENDERING",
"-DMAXROMSIZE=33554432",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
PRODUCT_NAME = GenesisPlus;
+5 -3
View File
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
@@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.7.4.7</string>
<string>1.7.4.14</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>
@@ -120,7 +122,7 @@
<key>OEGameCorePlayerCount</key>
<string>8</string>
<key>OEProjectURL</key>
<string>http://code.google.com/p/genplus-gx</string>
<string>https://github.com/ekeeke/Genesis-Plus-GX</string>
<key>OESystemIdentifiers</key>
<array>
<string>openemu.system.sg1000</string>
+2
View File
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
+38 -58
View File
@@ -1,8 +1,8 @@
/****************************************************************************
* Genesis Plus
* Action Replay / Pro Action Replay emulation
* Action Replay / Pro Action Replay hardware support
*
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -45,8 +45,7 @@ static struct
{
uint8 enabled;
uint8 status;
uint8 *rom;
uint8 *ram;
uint8 ram[0x10000];
uint16 regs[13];
uint16 old[4];
uint16 data[4];
@@ -54,64 +53,52 @@ static struct
} action_replay;
static void ar_write_regs(uint32 address, uint32 data);
static void ar_write_regs_2(uint32 address, uint32 data);
static void ar2_write_reg(uint32 address, uint32 data);
static void ar_write_ram_8(uint32 address, uint32 data);
void areplay_init(void)
{
int size;
memset(&action_replay,0,sizeof(action_replay));
action_replay.enabled = action_replay.status = 0;
/* store Action replay ROM (max. 128k) & RAM (64k) above cartridge ROM + SRAM area */
if (cart.romsize > 0x810000) return;
action_replay.rom = cart.rom + 0x810000;
action_replay.ram = cart.rom + 0x830000;
/* try to load Action Replay ROM file */
size = load_archive(AR_ROM, action_replay.rom, 0x20000, NULL);
/* detect Action Replay board type */
switch (size)
/* try to load Action Replay ROM file (max. 64KB) */
if (load_archive(AR_ROM, cart.lockrom, 0x10000, NULL) > 0)
{
case 0x8000:
/* detect Action Replay board type */
if (!memcmp(cart.lockrom + 0x120, "ACTION REPLAY ", 16))
{
if (!memcmp(action_replay.rom + 0x120, "ACTION REPLAY ", 16))
{
/* normal Action Replay (32K) */
action_replay.enabled = TYPE_AR;
/* internal registers mapped at $010000-$01ffff */
m68k.memory_map[0x01].write16 = ar_write_regs;
break;
}
}
/* normal Action Replay (32KB ROM) */
action_replay.enabled = TYPE_AR;
case 0x10000:
case 0x20000:
/* $0000-$7fff mirrored into $8000-$ffff */
memcpy(cart.lockrom + 0x8000, cart.lockrom, 0x8000);
/* internal registers mapped at $010000-$01ffff */
m68k.memory_map[0x01].write16 = ar_write_regs;
}
else
{
/* Read stack pointer MSB */
uint8 sp = READ_BYTE(action_replay.rom, 0x01);
uint8 sp = cart.lockrom[0x01];
/* Detect board version */
if ((sp == 0x42) && !memcmp(action_replay.rom + 0x120, "ACTION REPLAY 2 ", 16))
if ((sp == 0x42) && !memcmp(cart.lockrom + 0x120, "ACTION REPLAY 2 ", 16))
{
/* PRO Action Replay 1 (64/128K) */
/* PRO Action Replay (2x32KB ROM) */
action_replay.enabled = TYPE_PRO1;
/* internal registers mapped at $010000-$01ffff */
m68k.memory_map[0x01].write16 = ar_write_regs;
}
else if ((sp == 0x60) && !memcmp(action_replay.rom + 0x3c6, "ACTION REPLAY II", 16))
else if ((sp == 0x60) && !memcmp(cart.lockrom + 0x3c6, "ACTION REPLAY II", 16))
{
/* PRO Action Replay 2 (64K) */
/* PRO Action Replay 2 (2x32KB ROM) */
action_replay.enabled = TYPE_PRO2;
/* internal registers mapped at $100000-$10ffff */
m68k.memory_map[0x10].write16 = ar_write_regs_2;
/* internal register mapped at $100000-$10ffff */
m68k.memory_map[0x10].write16 = ar2_write_reg;
}
/* internal RAM (64k), mapped at $420000-$42ffff or $600000-$60ffff */
/* internal RAM (64KB), mapped at $420000-$42ffff or $600000-$60ffff */
if (action_replay.enabled)
{
m68k.memory_map[sp].base = action_replay.ram;
@@ -120,28 +107,22 @@ void areplay_init(void)
m68k.memory_map[sp].write8 = ar_write_ram_8;
m68k.memory_map[sp].write16 = NULL;
}
break;
}
default:
{
break;
}
}
#ifdef LSB_FIRST
if (action_replay.enabled)
{
int i;
for (i= 0; i<size; i+=2)
if (action_replay.enabled)
{
/* Byteswap ROM */
uint8 temp = action_replay.rom[i];
action_replay.rom[i] = action_replay.rom[i+1];
action_replay.rom[i+1] = temp;
int i;
for (i= 0; i<0x10000; i+=2)
{
/* Byteswap ROM */
uint8 temp = cart.lockrom[i];
cart.lockrom[i] = cart.lockrom[i+1];
cart.lockrom[i+1] = temp;
}
}
}
#endif
}
}
void areplay_shutdown(void)
@@ -166,7 +147,7 @@ void areplay_reset(int hard)
memset(action_replay.addr, 0, sizeof(action_replay.addr));
/* by default, internal ROM is mapped at $000000-$00FFFF */
m68k.memory_map[0].base = action_replay.rom;
m68k.memory_map[0].base = cart.lockrom;
/* reset internal RAM on power-on */
if (hard)
@@ -287,7 +268,7 @@ static void ar_write_regs(uint32 address, uint32 data)
}
}
static void ar_write_regs_2(uint32 address, uint32 data)
static void ar2_write_reg(uint32 address, uint32 data)
{
/* enable Cartridge ROM */
if (((address & 0xff) == 0x78) && (data == 0xffff))
@@ -301,4 +282,3 @@ static void ar_write_ram_8(uint32 address, uint32 data)
/* byte writes are handled as word writes, with LSB duplicated in MSB (/LWR is not used) */
*(uint16 *)(action_replay.ram + (address & 0xfffe)) = (data | (data << 8));
}
+2 -2
View File
@@ -1,8 +1,8 @@
/****************************************************************************
* Genesis Plus
* DATEL Action Replay / Pro Action Replay emulation
* Action Replay / Pro Action Replay hardware support
*
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+12 -17
View File
@@ -1,8 +1,8 @@
/****************************************************************************
* Genesis Plus
* Game Genie Hardware emulation
* Game Genie hardware support
*
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
*
* Based on documentation from Charles McDonald
* (http://cgfm2.emuviews.com/txt/genie.txt)
@@ -44,7 +44,6 @@
static struct
{
uint8 enabled;
uint8 *rom;
uint16 regs[0x20];
uint16 old[6];
uint16 data[6];
@@ -58,29 +57,25 @@ static void ggenie_write_word(unsigned int address, unsigned int data);
static void ggenie_write_regs(unsigned int offset, unsigned int data);
void ggenie_init(void)
{
memset(&ggenie,0,sizeof(ggenie));
{
ggenie.enabled = 0;
/* Store Game Genie ROM (32k) above cartridge ROM + SRAM area */
if (cart.romsize > 0x810000) return;
ggenie.rom = cart.rom + 0x810000;
/* Try to load Game Genie ROM file */
if (load_archive(GG_ROM, ggenie.rom, 0x8000, NULL) > 0)
/* Try to load Game Genie ROM file (32KB) */
if (load_archive(GG_ROM, cart.lockrom, 0x8000, NULL) > 0)
{
#ifdef LSB_FIRST
int i;
for (i=0; i<0x8000; i+=2)
{
/* Byteswap ROM */
uint8 temp = ggenie.rom[i];
ggenie.rom[i] = ggenie.rom[i+1];
ggenie.rom[i+1] = temp;
uint8 temp = cart.lockrom[i];
cart.lockrom[i] = cart.lockrom[i+1];
cart.lockrom[i+1] = temp;
}
#endif
/* $0000-$7fff mirrored into $8000-$ffff */
memcpy(ggenie.rom + 0x8000, ggenie.rom, 0x8000);
memcpy(cart.lockrom + 0x8000, cart.lockrom, 0x8000);
/* Game Genie hardware is enabled */
ggenie.enabled = 1;
@@ -113,7 +108,7 @@ void ggenie_reset(int hard)
}
/* Game Genie ROM is mapped at $000000-$007fff */
m68k.memory_map[0].base = ggenie.rom;
m68k.memory_map[0].base = cart.lockrom;
/* Internal registers are mapped at $000000-$00001f */
m68k.memory_map[0].write8 = ggenie_write_byte;
@@ -214,7 +209,7 @@ static void ggenie_write_regs(unsigned int offset, unsigned int data)
else
{
/* $0000-$7ffff reads mapped to Game Genie ROM */
m68k.memory_map[0].base = ggenie.rom;
m68k.memory_map[0].base = cart.lockrom;
m68k.memory_map[0].read8 = NULL;
m68k.memory_map[0].read16 = NULL;
+2 -2
View File
@@ -1,8 +1,8 @@
/****************************************************************************
* Genesis Plus
* Game Genie Hardware emulation
* Game Genie hardware support
*
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
*
* Based on documentation from Charles McDonald
* (http://cgfm2.emuviews.com/txt/genie.txt)
+388 -105
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-2021 Eke-Eke (Genesis Plus GX)
*
* Many cartridge protections were initially documented by Haze
* (http://haze.mameworld.info/)
@@ -74,7 +74,12 @@ static void mapper_seganet_w(uint32 address, uint32 data);
static void mapper_32k_w(uint32 data);
static void mapper_64k_w(uint32 data);
static void mapper_64k_multi_w(uint32 address);
static uint32 mapper_radica_r(uint32 address);
static uint32 mapper_128k_multi_r(uint32 address);
static void mapper_256k_multi_w(uint32 address, uint32 data);
static void mapper_wd1601_w(uint32 address, uint32 data);
static uint32 mapper_64k_radica_r(uint32 address);
static uint32 mapper_128k_radica_r(uint32 address);
static void mapper_sr16v1_w(uint32 address, uint32 data);
static void default_time_w(uint32 address, uint32 data);
static void default_regs_w(uint32 address, uint32 data);
static uint32 default_regs_r(uint32 address);
@@ -102,13 +107,26 @@ static const md_entry_t rom_database[] =
/* Tom Clown */
{0x0000,0xc0cd,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}},
/* 1800-in-1 */
{0x3296,0x2370,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_128k_multi_r,m68k_unused_8_w,NULL,NULL}},
/* Golden Mega 250-in-1 */
{0xe43c,0x886f,0x08,0x08,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,m68k_unused_8_w,NULL,mapper_256k_multi_w}},
/* RADICA (Volume 1) (bad dump ?) */
{0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_radica_r,NULL,NULL,NULL}},
{0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* RADICA (Volume 1) */
{0x24f4,0xfc84,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}},
{0x24f4,0xfc84,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* RADICA (Volume 2) */
{0x104f,0x32e9,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}},
{0xd951,0x78d0,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* RADICA (Volume 3 - Super Sonic Gold edition) */
{0x0000,0x1f25,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* RADICA (Street Fighter II CE edition) */
{0x1add,0xa838,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* RADICA (Street Fighter II CE edition) (PAL) */
{0x104f,0x32e9,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* RADICA (Sensible Soccer Plus edition) (PAL) */
{0x0000,0x1f7f,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_128k_radica_r,m68k_unused_8_w,NULL,NULL}},
/* Tenchi wo Kurau III: Sangokushi Gaiden - Chinese Fighter */
@@ -210,6 +228,12 @@ static const md_entry_t rom_database[] =
{0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,NULL,default_regs_r,NULL}},
/* Rock Heaven */
{0x6cca,0x2395,0x50,0x50,{{0x50,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x500008,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}},
/* Rock World */
{0x3547,0xa3da,0x50,0x50,{{0x50,0xa0,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x500008,0x500208,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}},
/* Rockman X3 (bootleg version ? two last register returned values are ignored, note that 0xaa/0x18 would work as well) */
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x00,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x400004,0x400006},0,0,default_regs_r,NULL,default_regs_r,NULL}},
@@ -376,101 +400,59 @@ 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 mapping */
else if ((strstr(rominfo.product,"T-172026") != NULL) || (strstr(rominfo.product,"T-172116") != NULL))
{
/* $000000-$1fffff: cartridge ROM (lower 2MB) */
/* $200000-$2fffff: SRAM (32KB mirrored) */
/* NB: existing 4MB ROM dumps include SRAM data at ROM offsets 0x200000-0x2fffff */
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;
}
/* $300000-$3fffff: cartridge ROM (upper 1MB) */
/* NB: only real (3MB) Mask ROM dumps need ROM offsets 0x200000-0x2fffff to be remapped to this area */
if (READ_BYTE(cart.rom, 0x200000) != 0xFF)
{
for (i=0x30; i<0x40; i++)
{
m68k.memory_map[i].base = cart.rom + ((i - 0x10) << 16);
}
}
}
}
/**********************************************
SVP CHIP
***********************************************/
svp = NULL;
if (strstr(rominfo.international,"Virtua Racing"))
if ((READ_BYTE(cart.rom, 0x1c8) == 'S') && (READ_BYTE(cart.rom, 0x1c9) == 'V'))
{
svp_init();
}
/**********************************************
LOCK-ON
***********************************************/
/* clear existing patches */
ggenie_shutdown();
areplay_shutdown();
/* initialize extra hardware */
switch (config.lock_on)
{
case TYPE_GG:
{
ggenie_init();
break;
}
case TYPE_AR:
{
areplay_init();
break;
}
case TYPE_SK:
{
/* store S&K ROM above cartridge ROM (and before backup memory) */
if (cart.romsize > 0x600000) break;
/* try to load Sonic & Knuckles ROM file (2 MB) */
if (load_archive(SK_ROM, cart.rom + 0x600000, 0x200000, NULL) == 0x200000)
{
/* check ROM header */
if (!memcmp(cart.rom + 0x600000 + 0x120, "SONIC & KNUCKLES",16))
{
/* try to load Sonic 2 & Knuckles UPMEM ROM (256 KB) */
if (load_archive(SK_UPMEM, cart.rom + 0x900000, 0x40000, NULL) == 0x40000)
{
/* $000000-$1FFFFF is mapped to S&K ROM */
for (i=0x00; i<0x20; i++)
{
m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16);
}
#ifdef LSB_FIRST
for (i=0; i<0x200000; i+=2)
{
/* Byteswap ROM */
uint8 temp = cart.rom[i + 0x600000];
cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1];
cart.rom[i + 0x600000 + 1] = temp;
}
for (i=0; i<0x40000; i+=2)
{
/* Byteswap ROM */
uint8 temp = cart.rom[i + 0x900000];
cart.rom[i + 0x900000] = cart.rom[i + 0x900000 + 1];
cart.rom[i + 0x900000 + 1] = temp;
}
#endif
cart.special |= HW_LOCK_ON;
}
}
}
break;
}
default:
{
break;
}
}
/**********************************************
CARTRIDGE EXTRA HARDWARE
***********************************************/
@@ -514,16 +496,16 @@ void md_cart_init(void)
/* Realtec mapper */
if (cart.hw.realtec)
{
/* 8k BOOT ROM */
/* copy 8KB Boot ROM after cartridge ROM area */
for (i=0; i<8; i++)
{
memcpy(cart.rom + 0x900000 + i*0x2000, cart.rom + 0x7e000, 0x2000);
memcpy(cart.rom + 0x400000 + i*0x2000, cart.rom + 0x7e000, 0x2000);
}
/* BOOT ROM is mapped to $000000-$3FFFFF */
/* Boot ROM (8KB mirrored) is mapped to $000000-$3FFFFF */
for (i=0x00; i<0x40; i++)
{
m68k.memory_map[i].base = cart.rom + 0x900000;
m68k.memory_map[i].base = cart.rom + 0x400000;
}
}
@@ -637,6 +619,20 @@ void md_cart_init(void)
m68k.memory_map[0x00].write16 = mapper_flashkit_w;
zbank_memory_map[0x00].write = mapper_flashkit_w;
}
else if ((cart.romsize == 0x400000) &&
(READ_BYTE(cart.rom, 0x200150) == 'C') &&
(READ_BYTE(cart.rom, 0x200151) == 'A') &&
(READ_BYTE(cart.rom, 0x200152) == 'N') &&
(READ_BYTE(cart.rom, 0x200153) == 'O') &&
(READ_BYTE(cart.rom, 0x200154) == 'N'))
{
/* Canon - Legend of the new Gods (4MB dump) */
cart.hw.time_w = mapper_wd1601_w;
cart.hw.bankshift = 1;
sram.on = 1;
sram.start = 0x200000;
sram.end = 0x201fff;
}
else if ((*(uint16 *)(cart.rom + 0x08) == 0x6000) && (*(uint16 *)(cart.rom + 0x0a) == 0x01f6) && (rominfo.realchecksum == 0xf894))
{
/* Super Mario World 64 (unlicensed) mapper */
@@ -669,6 +665,11 @@ void md_cart_init(void)
zbank_memory_map[i].write = mapper_smw_64_w;
}
}
else if ((*(uint16 *)(cart.rom + 0x04) == 0x0000) && (*(uint16 *)(cart.rom + 0x06) == 0x0104) && (rominfo.checksum == 0x31fc))
{
/* Micro Machines (USA) custom TMSS bypass logic */
m68k.memory_map[0xa1].write8 = mapper_sr16v1_w;
}
else if (cart.romsize > 0x400000)
{
/* assume linear ROM mapping by default (max. 10MB) */
@@ -686,6 +687,79 @@ void md_cart_init(void)
{
cart.hw.time_w = default_time_w;
}
/**********************************************
LOCK-ON
***********************************************/
/* clear existing patches */
ggenie_shutdown();
areplay_shutdown();
/* initialize extra hardware */
switch (config.lock_on)
{
case TYPE_GG:
{
ggenie_init();
break;
}
case TYPE_AR:
{
areplay_init();
break;
}
case TYPE_SK:
{
/* store Sonic & Knuckles ROM files after cartridge ROM area */
if (cart.romsize > 0x400000) break;
/* try to load Sonic & Knuckles ROM file (2MB) */
if (load_archive(SK_ROM, cart.rom + 0x400000, 0x200000, NULL) == 0x200000)
{
/* check ROM header */
if (!memcmp(cart.rom + 0x400000 + 0x120, "SONIC & KNUCKLES",16))
{
/* try to load Sonic 2 & Knuckles upmem ROM file (256KB) */
if (load_archive(SK_UPMEM, cart.rom + 0x600000, 0x40000, NULL) == 0x40000)
{
/* $000000-$1FFFFF is mapped to S&K ROM */
for (i=0x00; i<0x20; i++)
{
m68k.memory_map[i].base = cart.rom + 0x400000 + (i << 16);
}
#ifdef LSB_FIRST
for (i=0; i<0x200000; i+=2)
{
/* Byteswap ROM */
uint8 temp = cart.rom[i + 0x400000];
cart.rom[i + 0x400000] = cart.rom[i + 0x400000 + 1];
cart.rom[i + 0x400000 + 1] = temp;
}
for (i=0; i<0x40000; i+=2)
{
/* Byteswap ROM */
uint8 temp = cart.rom[i + 0x600000];
cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1];
cart.rom[i + 0x600000 + 1] = temp;
}
#endif
cart.special |= HW_LOCK_ON;
}
}
}
break;
}
default:
{
break;
}
}
}
/* hardware that need to be reseted on power on */
@@ -760,9 +834,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 +898,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));
}
}
@@ -874,12 +953,12 @@ static void mapper_sega_w(uint32 data)
}
/* S&K lock-on chip */
if ((cart.special & HW_LOCK_ON) && (config.lock_on == TYPE_SK))
if (cart.special & HW_LOCK_ON)
{
/* S2K upmem chip mapped to $300000-$3fffff (256K mirrored) */
/* S2K upmem chip mapped to $300000-$3fffff (256KB mirrored) */
for (i=0x30; i<0x40; i++)
{
m68k.memory_map[i].base = (cart.rom + 0x900000) + ((i & 3) << 16);
m68k.memory_map[i].base = (cart.rom + 0x600000) + ((i & 3) << 16);
}
}
}
@@ -908,7 +987,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;
@@ -1621,27 +1700,231 @@ static void mapper_64k_multi_w(uint32 address)
/* 64 x 64k banks */
for (i=0; i<64; i++)
{
m68k.memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16];
m68k.memory_map[i].base = &cart.rom[((address + i) & 0x3f) << 16];
}
}
/*
Custom ROM Bankswitch used in pirate "1800-in-1" cartridge
*/
static uint32 mapper_128k_multi_r(uint32 address)
{
int i;
/* 16 x 128k banks (2MB ROM) */
/* Bank index (B3 B2 B1 B0) is encoded in address lower byte = {0 X B0 B1 X B2 B3 0} */
/* Note: {0 B0 X B1 X B2 B3 0} also works, see below for the 9 unique values being used for all menu entries
read16 00A13000 (0002FBEE) => 0x000000-0x03ffff (2x128KB)
read16 00A13018 (00FF2056) => 0x040000-0x07ffff (2x128KB)
read16 00A13004 (00FF2120) => 0x080000-0x0bffff (2x128KB)
read16 00A1301C (00FF20A6) => 0x0c0000-0x0fffff (2x128KB)
read16 00A1300A (00FF20BA) => 0x100000-0x13ffff (2x128KB)
read16 00A1301A (00FF20CE) => 0x140000-0x17ffff (2x128KB)
read16 00A1300E (00FF20F4) => 0x180000-0x1bffff (2x128KB)
read16 00A1301E (00FF2136) => 0x1c0000-0x1dffff (1x128KB)
read16 00A1307E (00FF2142) => 0x1e0000-0x1fffff (1x128KB)
*/
int bank = ((address & 0x02) << 2) | (address & 0x04) | ((address & 0x10) >> 3) | ((address & 0x20) >> 5);
/* remap cartridge area (64 x 64k banks) */
address = bank << 1;
for (i=0x00; i<0x40; i++)
{
m68k.memory_map[i].base = &cart.rom[((address + i) & 0x3f) << 16];
}
/* returned value changes the menu title and number of entries in the 'game' list (the number of distinct games does not change though) */
/* 0x00 => 9-in-1 */
/* 0x01 => 190-in-1 */
/* 0x02 => 888-in-1 */
/* 0x03 => 1800-in-1 */
/* real cartridge board has switches to select between the four different menus but here we force the largest menu selection (each other menus being a subset of the next larger menu) */
return 0x03;
}
/*
Custom ROM Bankswitch used in pirate "Golden Mega 250-in-1" cartridge
*/
static void mapper_256k_multi_w(uint32 address, uint32 data)
{
int i;
/* 8 x 256k banks (2MB ROM) */
/* Bank index (B2 B1 B0) is encoded in data lower byte = {B1 B0 X X 0 0 0 B2} */
/* Note: {X B0 B1 B2 0 0 0 X}, {B1 B0 X B2 0 0 0 X} or {X B0 B1 X 0 0 0 B2} also work, see below for the 4 unique values being used for all menu entries
write16 00089000 = 0000 (00FF0006) => 0x000000-0x03ffff (1x256KB)
write16 00089000 = 0040 (00FF0006) => 0x040000-0x07ffff (1x256KB)
write16 00089000 = 00A0 (00FF0006) => 0x080000-0x0fffff (2x256KB)
write16 00089000 = 0011 (00FF0006) => 0x100000-0x1fffff (4x256KB)
*/
int bank = ((data & 0x01) << 2) | ((data & 0xc0) >> 6);
/* remap cartridge area (64 x 64k banks) */
address = bank << 2;
for (i=0x00; i<0x40; i++)
{
m68k.memory_map[i].base = &cart.rom[((address + i) & 0x3f) << 16];
}
}
/*
Custom ROM Bankswitch used in "Canon - Legend of the New Gods"
(uses WD1601 QFPL V1.01 board also used in chinese X-in-1 pirates sold by mindkids)
*/
static void mapper_wd1601_w(uint32 address, uint32 data)
{
int i;
/* !TIME write16 0xA13002 = 0x3002 (00FFFE0C) */
/* The board probably allows up to 256MB Flash ROM remapping but this game only has 4MB ROM chip */
if ((address & 0xfe) == 0x02)
{
/* upper 2MB ROM mapped to $000000-$1fffff */
for (i=0; i<0x20; i++)
{
m68k.memory_map[i].base = &cart.rom[(0x20 + i) << 16];
}
/* backup RAM (8KB) mapped to $2000000-$3fffff */
for (i=0x20; i<0x40; 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;
}
}
}
/*
Custom ROM Bankswitch used in RADICA cartridges
+++++++++++++++++++++++++++++++++++++++++++++++
Two different boards seem to exist (one with support for 64KB banks mapping and another one supporting 128KB banks + battery-RAM).
Radica Volume 1 requires 64KB banks mapping as the menu is located at a 64KB boundary.
Sensible Soccer Plus edition requires 128KB banks mapping with only VA6-VA2 being used to select bank index (VA1 is ignored).
Sensible Soccer Plus edition also requires 8KB backup RAM to be mapped in higher 2MB range.
Other games support both 64KB or 128KB mapping so it's not clear what exact board they are using but none require SRAM so we use 64KB mapper by default.
Note that Radica Volume 3 uses similar ROM mapping as Sensible Soccer Plus edition so it might be using same 128KB board, without any SRAM chip connected.
*/
static uint32 mapper_radica_r(uint32 address)
static uint32 mapper_64k_radica_r(uint32 address)
{
int i = 0;
address = (address >> 1);
/* 64 x 64k banks */
for (i = 0; i < 64; i++)
/*
Volume 1
--------
000000h-0fffffh: Kid Chameleon : !TIME read16 0xA13000 (00FF103A)
100000h-1fffffh: Dr Robotnik's Mean Bean Machine : !TIME read16 0xA13020 (00FF101E)
200000h-27ffffh: Sonic The Hedgehog : !TIME read16 0xA13040 (00FF101E)
280000h-2fffffh: Golden Axe : !TIME read16 0xA13050 (00FF101E)
300000h-37ffffh: Altered Beast : !TIME read16 0xA13060 (00FF101E)
380000h-39ffffh: Flicky : !TIME read16 0xA13070 (00FF101E)
3a0000h-3effffh: N/A : N/A
3f0000h-3fffffh: Radica Menu (64 KB) : !TIME read16 0xA1307E (00FF1006)
Volume 2
--------
000000h-0fffffh: Sonic The Hedgehog 2 : !TIME read16 0xA13000 (00FF103A)
100000h-1fffffh: The Ooze : !TIME read16 0xA13020 (00FF101E)
200000h-2fffffh: Ecco The Dolphin : !TIME read16 0xA13040 (00FF101E)
300000h-37ffffh: Gain Ground : !TIME read16 0xA13060 (00FF101E)
380000h-3bffffh: Alex Kidd in Enchanted Castle : !TIME read16 0xA13070 (00FF101E)
3c0000h-3dffffh: Columns : !TIME read16 0xA13078 (00FF101E)
3e0000h-3fffffh: Radica Menu (128 KB) : !TIME read16 0xA1307C (00FF1006)
Volume 3 - Super Sonic Gold edition
-----------------------------------
000000h-01ffffh: Radica Menu (128 KB) : N/A
020000h-07ffffh: N/A : N/A
080000h-0fffffh: Sonic The Hedgehog : !TIME read16 0xA13010 (00FF1012)
100000h-1fffffh: Sonic The Hedgehog 2 : !TIME read16 0xA13020 (00FF1012)
200000h-2fffffh: Sonic Spinball : !TIME read16 0xA13040 (00FF1012)
300000h-3fffffh: Dr Robotnik's Mean Bean Machine : !TIME read16 0xA13060 (00FF1012)
Street Fighter 2 CE edition
---------------------------
000000h-2fffffh: Street Fighter 2 CE : !TIME read16 0xA13000 (00FF103A)
300000h-3bffffh: Ghouls'n Ghosts : !TIME read16 0xA13060 (00FF101E)
3c0000h-3dffffh: Radica Menu (128 KB) : !TIME read16 0xA13078 (00FF1006)
3e0000h-3fffffh: N/A : N/A
*/
int index = (address >> 1) & 0x3F;
/* $000000-$3fffff area is mapped to selected banks (OR gates between VA21-VA16 and selected index) */
for (i = 0x00; i < 0x40; i++)
{
m68k.memory_map[i].base = &cart.rom[((address++)& 0x3f)<< 16];
m68k.memory_map[i].base = &cart.rom[(index | i) << 16];
}
return 0xffff;
}
static uint32 mapper_128k_radica_r(uint32 address)
{
int i = 0;
/* 32 x 128k banks */
/*
Sensible Soccer Plus edition
----------------------------
000000h-01ffffh: Radica Menu (128 KB) : N/A
020000h-07ffffh: N/A : N/A
080000h-0fffffh: Sensible Soccer : !TIME read16 0xA13010 (00FF1012)
100000h-1fffffh: Mega-Lo-Mania : !TIME read16 0xA13022 (00FF1012)
200000h-37ffffh: Cannon Fodder : !TIME read16 0xA13042 (00FF1012)
380000h-3fffffh: N/A : N/A
Note: address bit 1 is ignored for bank selection but might be used to enable/disable SRAM mapping ?
*/
int index = (address >> 1) & 0x3E;
/* $000000-$1fffff area is mapped to selected banks (OR gates between VA20-VA17 and selected index) */
for (i = 0x00; i < 0x20; i++)
{
m68k.memory_map[i].base = &cart.rom[(index | i) << 16];
}
/* $200000-$3fffff area is mapped to 8KB SRAM (mirrored) */
for (i = 0x20; i < 0x40; 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;
}
return 0xffff;
}
/*
Custom logic (ST 16S25HB1 PAL) used in Micro Machines US cartridge (SR16V1.1 board)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/VRES is asserted after write access to 0xA14101 (TMSS bank-shift register)
with D0=1 (cartridge ROM access enabled instead of TMSS Boot ROM) being detected
*/
static void mapper_sr16v1_w(uint32 address, uint32 data)
{
/* 0xA10000-0xA1FFFF address range is mapped to I/O and Control registers */
ctrl_io_write_byte(address, data);
/* cartridge uses /LWR, /AS and VA1-VA18 (only VA8-VA17 required to decode access to TMSS bank-shift register) */
if ((address & 0xff01) == 0x4101)
{
/* cartridge ROM is enabled when D0=1 */
if (data & 0x01)
{
gen_reset(0);
}
}
}
/************************************************************
default !TIME signal handler
@@ -1650,7 +1933,7 @@ static uint32 mapper_radica_r(uint32 address)
static void default_time_w(uint32 address, uint32 data)
{
/* enable multi-game cartridge mapper by default */
if (address < 0xa13040)
if (address < 0xa13060)
{
mapper_64k_multi_w(address);
return;
+3 -3
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-2021 Eke-Eke (Genesis Plus GX)
*
* Most cartridge protections were initially documented by Haze
* (http://haze.mameworld.info/)
@@ -81,10 +81,10 @@ typedef struct
uint32 mask; /* ROM mask */
uint8 special; /* custom external hardware (Lock-On, J-Cart, 3-D glasses, Terebi Oekaki,...) */
cart_hw_t hw; /* cartridge internal hardware */
uint8 rom[MAXROMSIZE]; /* ROM area */
uint8 lockrom[0x10000]; /* Game Genie / (Pro) Action Replay Lock-On ROM area (max 64KB) */
uint8 rom[MAXROMSIZE]; /* cartridge ROM area */
} md_cart_t;
/* Function prototypes */
extern void md_cart_init(void);
extern void md_cart_reset(int hard_reset);
+111 -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-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -39,6 +39,7 @@
#include "shared.h"
#include "eeprom_93c.h"
#include "terebi_oekaki.h"
#include "scrc32.h"
#define MAPPER_NONE (0x00)
#define MAPPER_TEREBI (0x01)
@@ -133,9 +134,12 @@ static const rominfo_t game_list[] =
{0x5E53C7F7, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Ernie Els Golf */
{0xD9A7F170, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Man Overboard! */
{0xF7C524F6, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines [GG] */
{0xC21E6CD0, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines [GG] [Proto] */
{0xDBE8895C, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines 2 - Turbo Tournament */
{0xC1756BEE, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Pete Sampras Tennis */
{0x72981057, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* CJ Elephant Fugitive */
{0x3ACE6335, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* CJ Elephant Fugitive [Proto] */
{0x2306AAF4, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Dinobasher - Starring Bignose the Caveman [GG] [Proto] */
/* games using serial EEPROM */
{0x36EBCD6D, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* Majors Pro Baseball */
@@ -196,6 +200,7 @@ static const rominfo_t game_list[] =
{0xC0E25D62, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* California Games II */
{0x45C50294, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Jogos de Verao II (BR) */
{0xC9DBF936, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Home Alone */
{0xA109A6FE, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Power Strike II */
{0x0047B615, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Predator2 */
{0xF42E145C, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Quest for the Shaven Yak Starring Ren Hoek & Stimpy (BR) */
{0x9F951756, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* RoboCop 3 */
@@ -237,12 +242,15 @@ static const rominfo_t game_list[] =
{0xA3EF13CB, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Zaxxon 3-D */
{0xBBA74147, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Zaxxon 3-D [Proto] */
{0xD6F43DDA, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Out Run 3-D */
{0x4E684EC0, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Out Run 3-D [Proto] */
{0x871562b0, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Maze Walker */
{0x156948f9, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Space Harrier 3-D (J) */
/* 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] */
{0x56DCB2D4, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* 3D Gunner [Proto] */
/* games requiring Sega Light Phaser */
{0x861B6E79, 0, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Assault City [Light Phaser] */
@@ -337,6 +345,8 @@ static const rominfo_t game_list[] =
{0x56BD2455, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Doki Doki Penguin Land - Uchuu-Daibouken [Proto] */
{0xC722FB42, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Fantasy Zone II (J) */
{0x7ABC70E9, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Family Games (Party Games) */
{0x9AFAB511, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game De Check! Koutsuu Anzen [Proto] (JP) */
{0x9E9DEB18, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game De Check! Koutsuu Anzen [Proto] (JP) [T-Eng] */
{0x6586BD1F, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Masters Golf */
{0x4847BC91, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Masters Golf [Proto] */
{0xB9FDF6D9, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Haja no Fuuin */
@@ -349,6 +359,8 @@ static const rominfo_t game_list[] =
{0x5B5F9106, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Nekyuu Kousien */
{0xBEA27D5C, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Opa Opa */
{0x6605D36A, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) */
{0x70E89681, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) [T-Eng v1.02] */
{0xA04CF71A, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) [T-Eng v2.00] */
{0xE1FFF1BB, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Shinobi (J) */
{0x11645549, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Solomon no Kagi - Oujo Rihita no Namida */
{0x7E0EF8CB, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Racing */
@@ -609,9 +621,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 +727,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 +751,96 @@ 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);
/* set default cartridge ROM paging */
switch (cart_rom.mapper)
{
case MAPPER_SEGA:
case MAPPER_SEGA_X:
cart_rom.fcr[0] = 0;
cart_rom.fcr[1] = 0;
cart_rom.fcr[2] = 1;
cart_rom.fcr[3] = 2;
break;
case MAPPER_KOREA_8K:
case MAPPER_MSX:
case MAPPER_MSX_NEMESIS:
cart_rom.fcr[0] = 0;
cart_rom.fcr[1] = 0;
cart_rom.fcr[2] = 0;
cart_rom.fcr[3] = 0;
break;
default:
cart_rom.fcr[0] = 0;
cart_rom.fcr[1] = 0;
cart_rom.fcr[2] = 1;
cart_rom.fcr[3] = 0;
break;
}
}
else
{
/* load cartridge mapper settings */
load_param(cart_rom.fcr, 4);
/* set default BIOS ROM paging (SEGA mapper by default) */
bios_rom.fcr[0] = 0;
bios_rom.fcr[1] = 0;
bios_rom.fcr[2] = 1;
bios_rom.fcr[3] = 2;
}
/* 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-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+13 -11
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Backup RAM support
*
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -37,6 +37,7 @@
****************************************************************************************/
#include "shared.h"
#include "scrc32.h"
T_SRAM sram;
@@ -61,11 +62,8 @@ T_SRAM sram;
****************************************************************************/
void sram_init()
{
memset(&sram, 0, sizeof (T_SRAM));
/* backup RAM data is stored above cartridge ROM area, at $800000-$80FFFF (max. 64K) */
if (cart.romsize > 0x800000) return;
sram.sram = cart.rom + 0x800000;
/* disable Backup RAM by default */
sram.detected = sram.on = sram.custom = sram.start = sram.end = 0;
/* initialize Backup RAM */
if (strstr(rominfo.international,"Sonic 1 Remastered"))
@@ -147,6 +145,13 @@ void sram_init()
sram.start = 0x400001;
sram.end = 0x40ffff;
}
else if ((rominfo.checksum == 0x0000) && (rominfo.realchecksum == 0x1f7f) && (READ_BYTE(cart.rom + 0x80000,0x1b0) == 0x52) && (READ_BYTE(cart.rom + 0x80000,0x1b1) == 0x41))
{
/* Radica - Sensible Soccer Plus edition (use bankswitching) */
sram.on = 1;
sram.start = 0x200001;
sram.end = 0x203fff;
}
else if ((strstr(rominfo.ROMType,"SF") != NULL) && (strstr(rominfo.product,"001") != NULL))
{
/* SF-001 */
@@ -214,8 +219,7 @@ unsigned int sram_read_byte(unsigned int address)
unsigned int sram_read_word(unsigned int address)
{
address &= 0xfffe;
return (sram.sram[address + 1] | (sram.sram[address] << 8));
return READ_WORD(sram.sram, address & 0xfffe);
}
void sram_write_byte(unsigned int address, unsigned int data)
@@ -225,7 +229,5 @@ void sram_write_byte(unsigned int address, unsigned int data)
void sram_write_word(unsigned int address, unsigned int data)
{
address &= 0xfffe;
sram.sram[address] = data >> 8;
sram.sram[address + 1] = data & 0xff;
WRITE_WORD(sram.sram, address & 0xfffe, data);
}
+2 -2
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* Backup RAM support
*
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -47,7 +47,7 @@ typedef struct
uint32 start;
uint32 end;
uint32 crc;
uint8 *sram;
uint8 sram[0x10000];
} T_SRAM;
/* Function prototypes */
+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 */
+1 -2
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* CD compatible ROM/RAM cartridge support
*
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -38,7 +38,6 @@
#include "shared.h"
/*--------------------------------------------------------------------------*/
/* backup RAM cartridge (max. 512KB) */
/*--------------------------------------------------------------------------*/
+3 -2
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* CD compatible ROM/RAM cartridge support
*
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2021 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,7 +40,8 @@
/* CD compatible ROM/RAM cartridge */
typedef struct
{
uint8 area[0x840080]; /* cartridge ROM/RAM area (max. 8MB ROM + 64KB backup memory + Pro Action Replay 128KB ROM / 64KB RAM + cartridge infos) */
uint8 reserved[0x80]; /* reserved for ROM cartridge infos (see md_cart.h) */
uint8 area[0x810000]; /* cartridge ROM/RAM area (max. 8MB ROM + Pro Action Replay 64KB ROM) */
uint8 boot; /* cartridge boot mode (0x00: boot from CD with ROM/RAM cartridge enabled, 0x40: boot from ROM cartridge with CD enabled) */
uint8 id; /* RAM cartridge ID (related to RAM size, 0 if disabled) */
uint8 prot; /* RAM cartridge write protection */
+53 -27
View File
@@ -1,8 +1,8 @@
/***************************************************************************************
* Genesis Plus
* CD data controller (LC89510 compatible)
* CD data controller (LC8951x compatible)
*
* Copyright (C) 2012-2015 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:
@@ -51,7 +51,6 @@
/* CTRL0 register bitmasks */
#define BIT_DECEN 0x80
#define BIT_E01RQ 0x20
#define BIT_AUTORQ 0x10
#define BIT_WRRQ 0x04
@@ -60,7 +59,7 @@
#define BIT_FORMRQ 0x04
#define BIT_SHDREN 0x01
/* CTRL2 register bitmask */
/* STAT3 register bitmask */
#define BIT_VALST 0x80
/* TODO: figure exact DMA transfer rate */
@@ -248,7 +247,7 @@ void cdc_decoder_update(uint32 header)
/* data decoding enabled ? */
if (cdc.ctrl[0] & BIT_DECEN)
{
/* update HEAD registers */
/* update HEADx registers with current block header */
*(uint32 *)(cdc.head[0]) = header;
/* set !VALST */
@@ -285,18 +284,50 @@ void cdc_decoder_update(uint32 header)
/* CDC buffer address */
offset = cdc.pt.w & 0x3fff;
/* write CDD block header (4 bytes) */
/* write current block header to RAM buffer (4 bytes) */
*(uint32 *)(cdc.ram + offset) = header;
offset += 4;
/* write CDD block data (2048 bytes) */
cdd_read_data(cdc.ram + 4 + offset);
/* check decoded block mode */
if (cdc.head[0][3] == 0x01)
{
/* write Mode 1 user data to RAM buffer (2048 bytes) */
cdd_read_data(cdc.ram + offset, NULL);
offset += 2048;
}
else
{
/* check if CD-ROM Mode 2 decoding is enabled */
if (cdc.ctrl[1] & BIT_MODRQ)
{
/* update HEADx registers with current block sub-header & write Mode 2 user data to RAM buffer (max 2328 bytes) */
cdd_read_data(cdc.ram + offset + 8, cdc.head[1]);
/* write current block sub-header to RAM buffer (4 bytes x 2) */
*(uint32 *)(cdc.ram + offset) = *(uint32 *)(cdc.head[1]);
*(uint32 *)(cdc.ram + offset + 4) = *(uint32 *)(cdc.head[1]);
offset += 2336;
}
else
{
/* update HEADx registers with current block sub-header & write Mode 2 user data to RAM buffer (max 2328 bytes) */
/* NB: when Mode 2 decoding is disabled, sub-header is apparently not written to RAM buffer (required by Wonder Library) */
cdd_read_data(cdc.ram + offset, cdc.head[1]);
offset += 2328;
}
/* set STAT2 register FORM bit according to sub-header FORM bit when CTRL0 register AUTORQ bit is set */
if (cdc.ctrl[0] & BIT_AUTORQ)
{
cdc.stat[2] = (cdc.ctrl[1] & BIT_MODRQ) | ((cdc.head[1][2] & 0x20) >> 3);
}
}
/* take care of buffer overrun */
offset = offset + 2048 + 4 - 0x4000;
if (offset > 0)
if (offset > 0x4000)
{
/* data should be written at the start of buffer */
memcpy(cdc.ram, cdc.ram + 0x4000, offset);
memcpy(cdc.ram, cdc.ram + 0x4000, offset - 0x4000);
}
}
}
@@ -484,15 +515,15 @@ void cdc_reg_w(unsigned char data)
/* set CRCOK bit only if decoding is enabled */
cdc.stat[0] = data & BIT_DECEN;
/* update decoding mode */
/* update STAT2 register */
if (data & BIT_AUTORQ)
{
/* set MODE bit according to CTRL1 register & clear FORM bit */
cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ;
/* set MODE bit according to CTRL1 register MODRQ bit & set FORM bit according to sub-header FORM bit*/
cdc.stat[2] = (cdc.ctrl[1] & BIT_MODRQ) | ((cdc.head[1][2] & 0x20) >> 3);
}
else
{
/* set MODE & FORM bits according to CTRL1 register */
/* set MODE & FORM bits according to CTRL1 register MODRQ & FORMRQ bits */
cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
}
@@ -503,15 +534,15 @@ void cdc_reg_w(unsigned char data)
case 0x0b: /* CTRL1 */
{
/* update decoding mode */
/* update STAT2 register */
if (cdc.ctrl[0] & BIT_AUTORQ)
{
/* set MODE bit according to CTRL1 register & clear FORM bit */
cdc.stat[2] = data & BIT_MODRQ;
/* set MODE bit according to CTRL1 register MODRQ bit & set FORM bit according to sub-header FORM bit*/
cdc.stat[2] = (data & BIT_MODRQ) | ((cdc.head[1][2] & 0x20) >> 3);
}
else
{
/* set MODE & FORM bits according to CTRL1 register */
/* set MODE & FORM bits according to CTRL1 register MODRQ & FORMRQ bits */
cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
}
@@ -612,7 +643,7 @@ unsigned char cdc_reg_r(void)
/* clear pending decoder interrupt */
cdc.ifstat |= BIT_DECI;
#if 0
/* no pending data transfer end interrupt */
if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
@@ -639,13 +670,8 @@ unsigned short cdc_host_r(void)
/* check if data is available */
if (scd.regs[0x04>>1].byte.h & 0x40)
{
/* read data word from CDC RAM buffer */
uint16 data = *(uint16 *)(cdc.ram + (cdc.dac.w & 0x3ffe));
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* read 16-bit word from CDC RAM buffer (big-endian format) */
uint16 data = READ_WORD(cdc.ram, cdc.dac.w & 0x3ffe);
#ifdef LOG_CDC
error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, data, cdc.dbc.w, s68k.pc);
+2 -2
View File
@@ -1,8 +1,8 @@
/***************************************************************************************
* Genesis Plus
* CD data controller (LC89510 compatible)
* CD data controller (LC8951x compatible)
*
* Copyright (C) 2012-2015 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:
+265 -202
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-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -47,7 +47,9 @@
#define CD_SCAN_SPEED 30
/* CD tracks type (CD-DA by default) */
#define TYPE_CDROM 0x01
#define TYPE_AUDIO 0x00
#define TYPE_MODE1 0x01
#define TYPE_MODE2 0x02
/* BCD conversion lookup tables */
static const uint8 lut_BCD_8[100] =
@@ -122,14 +124,8 @@ static const uint32 toc_ffightj[29] =
14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
};
/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
static const unsigned char waveHeader[28] =
{
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,
0x02,0x00,0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00
};
/* supported WAVE file extensions */
/* supported audio file extensions */
static const char extensions[SUPPORTED_EXT][16] =
{
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
@@ -198,23 +194,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 +222,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 +248,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 */
@@ -322,10 +315,14 @@ int cdd_load(char *filename, char *header)
/* open file */
fd = cdStreamOpen(filename);
if (!fd)
return (-1);
{
/* do not return an error as this could be a ROM loaded in memory */
/* which should be handled by load_archive function */
return (0);
}
#if defined(USE_LIBCHDR)
if (!memcmp(".chd", &filename[strlen(filename) - 4], 4) || !memcmp(".CHD", &filename[strlen(filename) - 4], 4))
if (!memcmp("chd", &filename[strlen(filename) - 3], 3) || !memcmp("CHD", &filename[strlen(filename) - 3], 3))
{
int sectors = 0;
char metadata[256];
@@ -403,19 +400,31 @@ int cdd_load(char *filename, char *header)
}
else
{
/* COOKED format (2048 bytes data blocks) */
if (!strcmp(type, "MODE1"))
cdd.sectorSize = 2048;
/* RAW format (2352 bytes data blocks) */
else if (!strcmp(type, "MODE1_RAW"))
if (!strcmp(type, "MODE1_RAW"))
{
/* Mode 1 RAW format (2352 bytes data blocks) */
cdd.sectorSize = 2352;
/* unsupported track format */
cdd.toc.tracks[0].type = TYPE_MODE1;
}
else if (!strcmp(type, "MODE1"))
{
/* Mode 1 COOKED format (2048 bytes data blocks) */
cdd.sectorSize = 2048;
cdd.toc.tracks[0].type = TYPE_MODE1;
}
else if (!strcmp(type, "MODE2_RAW"))
{
/* Mode 2 RAW format (2352 bytes data blocks) */
cdd.sectorSize = 2352;
cdd.toc.tracks[0].type = TYPE_MODE2;
}
else if (strcmp(type, "AUDIO"))
{
/* unsupported track format */
break;
/* Data track start LBA (2s pause assumed by default) */
}
/* First track start LBA (2s pause assumed by default) */
cdd.toc.tracks[0].start = 0;
}
@@ -451,9 +460,6 @@ int cdd_load(char *filename, char *header)
/* copy CD image header + security code (skip RAW sector 16-byte header) */
memcpy(header, cdd.chd.hunk + (cdd.toc.tracks[0].offset % cdd.chd.hunkbytes) + ((cdd.sectorSize == 2048) ? 0 : 16), 0x210);
/* there is a valid DATA track */
cdd.toc.tracks[0].type = TYPE_CDROM;
}
/* valid CD image ? */
@@ -478,44 +484,47 @@ int cdd_load(char *filename, char *header)
strncpy(fname, filename, 256);
/* check loaded file extension */
if (memcmp(".cue", &filename[strlen(filename) - 4], 4) && memcmp(".CUE", &filename[strlen(filename) - 4], 4))
if (memcmp("cue", &filename[strlen(filename) - 3], 3) && memcmp("CUE", &filename[strlen(filename) - 3], 3))
{
int len;
static const uint8 sync[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00};
/* read first 16 bytes */
cdStreamRead(header, 0x10, 1, fd);
/* look for valid CD image identifier */
/* auto-detect valid Sega CD image */
if (!memcmp("SEGADISCSYSTEM", header, 14))
{
/* COOKED format (2048 bytes data blocks) */
cdd.sectorSize = 2048;
}
else
{
/* read next 16 bytes */
cdStreamRead(header, 0x10, 1, fd);
/* look for valid CD image identifier */
if (!memcmp("SEGADISCSYSTEM", header, 14))
{
/* RAW format (2352 bytes data blocks) */
cdd.sectorSize = 2352;
}
}
/* valid CD image file ? */
if (cdd.sectorSize)
{
/* read CD image header + security code */
/* COOKED CD-ROM image (2048 bytes data blocks) */
cdd.sectorSize = 2048;
/* CD-ROM Mode 1 by default */
cdd.toc.tracks[0].type = TYPE_MODE1;
}
/* auto-detect CD-ROM synchro pattern */
else if (!memcmp(sync, header, 12))
{
/* RAW CD-ROM image (2352 bytes data blocks) */
cdd.sectorSize = 2352;
/* auto-detect CD-ROM mode from block header (byte 15) */
cdd.toc.tracks[0].type = header[15];
/* read next 16 bytes (start of user data) */
cdStreamRead(header, 0x10, 1, fd);
}
/* supported CD-ROM image file ? */
if ((cdd.toc.tracks[0].type == TYPE_MODE1) || (cdd.toc.tracks[0].type == TYPE_MODE2))
{
/* read Sega CD image header + security code */
cdStreamRead(header + 0x10, 0x200, 1, fd);
/* initialize first track file descriptor */
cdd.toc.tracks[0].fd = fd;
/* this is a valid DATA track */
cdd.toc.tracks[0].type = TYPE_CDROM;
/* DATA track end LBA (based on DATA file length) */
cdStreamSeek(fd, 0, SEEK_END);
cdd.toc.tracks[0].end = cdStreamTell(fd) / cdd.sectorSize;
@@ -536,7 +545,7 @@ int cdd_load(char *filename, char *header)
}
else
{
/* this is not a CD image file */
/* this is not a supported CD-ROM image file */
isCDfile = 0;
/* close file */
@@ -621,26 +630,26 @@ int cdd_load(char *filename, char *header)
if (!strstr(lptr,"BINARY") && !strstr(lptr,"MOTOROLA"))
{
/* read file header */
unsigned char head[28];
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET);
cdStreamRead(head, 28, 1, cdd.toc.tracks[cdd.toc.last].fd);
unsigned char head[12];
cdStreamRead(head, 12, 1, cdd.toc.tracks[cdd.toc.last].fd);
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
/* autodetect WAVE file header (44.1KHz 16-bit stereo format only) */
if (!memcmp(head, waveHeader, 28))
/* autodetect WAVE file */
if (!memcmp(head, "RIFF", 4) && !memcmp(head + 8, "WAVE", 4))
{
/* look for 'data' chunk id */
int dataOffset = 0;
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 36, SEEK_SET);
while (cdStreamRead(head, 4, 1, cdd.toc.tracks[cdd.toc.last].fd))
/* look for 'data' chunk */
int chunkSize, dataOffset = 0;
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 12, SEEK_SET);
while (cdStreamRead(head, 8, 1, cdd.toc.tracks[cdd.toc.last].fd))
{
if (!memcmp(head, "data", 4))
{
dataOffset = cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + 4;
dataOffset = cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd);
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
break;
}
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, -2, SEEK_CUR);
chunkSize = head[4] + (head[5] << 8) + (head[6] << 16) + (head[7] << 24);
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, chunkSize, SEEK_CUR);
}
/* check if 'data' chunk has not been found */
@@ -682,42 +691,35 @@ int cdd_load(char *filename, char *header)
/* decode TRACK commands */
else if ((sscanf(lptr, "TRACK %02d %*s", &bb)) || (sscanf(lptr, "TRACK %d %*s", &bb)))
{
/* check track number */
if (bb != (cdd.toc.last + 1))
{
/* close any opened file */
if (cdd.toc.tracks[cdd.toc.last].fd)
{
cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
}
/* missing tracks */
break;
}
/* autodetect DATA track (first track only) */
/* autodetect DATA track type (first track only) */
if (!cdd.toc.last)
{
/* CD-ROM Mode 1 support only */
if (strstr(lptr,"MODE1/2048"))
{
/* COOKED format (2048 bytes / block) */
/* Mode 1 COOKED format (2048 bytes / block) */
cdd.sectorSize = 2048;
cdd.toc.tracks[0].type = TYPE_MODE1;
}
else if (strstr(lptr,"MODE1/2352"))
{
/* RAW format (2352 bytes / block) */
/* Mode 1 RAW format (2352 bytes / block) */
cdd.sectorSize = 2352;
/* skip 16-byte header */
cdStreamSeek(cdd.toc.tracks[0].fd, 0x10, SEEK_SET);
cdd.toc.tracks[0].type = TYPE_MODE1;
}
else if (strstr(lptr,"MODE2/2352"))
{
/* Mode 2 RAW format (2352 bytes / block) */
cdd.sectorSize = 2352;
cdd.toc.tracks[0].type = TYPE_MODE2;
}
if (cdd.sectorSize)
{
/* this is a valid DATA track */
cdd.toc.tracks[0].type = TYPE_CDROM;
if (cdd.sectorSize == 2352)
{
/* skip 16-byte header */
cdStreamSeek(cdd.toc.tracks[0].fd, 0x10, SEEK_SET);
}
/* read CD image header + security code */
cdStreamRead(header, 0x210, 1, cdd.toc.tracks[0].fd);
@@ -760,16 +762,16 @@ int cdd_load(char *filename, char *header)
cdd.toc.tracks[cdd.toc.last].offset += pregap * 2352;
/* check if a single file is used for consecutive tracks */
if (!cdd.toc.tracks[cdd.toc.last].fd)
if (!cdd.toc.tracks[cdd.toc.last].fd && cdd.toc.last)
{
/* use common file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = cdd.toc.tracks[0].fd;
cdd.toc.tracks[cdd.toc.last].fd = cdd.toc.tracks[cdd.toc.last - 1].fd;
/* current track start time (based on current file absolute time + PREGAP length) */
cdd.toc.tracks[cdd.toc.last].start = bb + ss*75 + mm*60*75 + pregap;
/* check if previous track end time needs to be set */
if (cdd.toc.last && !cdd.toc.tracks[cdd.toc.last - 1].end)
if (!cdd.toc.tracks[cdd.toc.last - 1].end)
{
/* set previous track end time (based on current track start time, ignoring any "PREGAP"-type pause if no INDEX00) */
cdd.toc.tracks[cdd.toc.last - 1].end = cdd.toc.tracks[cdd.toc.last].start;
@@ -866,7 +868,7 @@ int cdd_load(char *filename, char *header)
/* close CUE file */
cdStreamClose(fd);
}
else
else if (cdd.toc.last)
{
int i, offset = 1;
@@ -893,26 +895,27 @@ int cdd_load(char *filename, char *header)
/* repeat until no more valid track files can be found */
while (fd)
{
/* read file HEADER */
unsigned char head[28];
cdStreamSeek(fd, 8, SEEK_SET);
cdStreamRead(head, 28, 1, fd);
/* read file header */
unsigned char head[12];
cdStreamRead(head, 12, 1, fd);
cdStreamSeek(fd, 0, SEEK_SET);
/* check if this is a valid WAVE file (44.1KHz 16-bit stereo format only) */
if (!memcmp(head, waveHeader, 28))
/* autodetect WAVE file */
if (!memcmp(head, "RIFF", 4) && !memcmp(head + 8, "WAVE", 4))
{
/* look for 'data' chunk id */
int dataOffset = 0;
cdStreamSeek(fd, 36, SEEK_SET);
while (cdStreamRead(head, 4, 1, fd))
/* look for 'data' chunk */
int chunkSize, dataOffset = 0;
cdStreamSeek(fd, 12, SEEK_SET);
while (cdStreamRead(head, 8, 1, fd))
{
if (!memcmp(head, "data", 4))
{
dataOffset = cdStreamTell(fd) + 4;
dataOffset = cdStreamTell(fd);
cdStreamSeek(fd, 0, SEEK_SET);
break;
}
cdStreamSeek(fd, -2, SEEK_CUR);
chunkSize = head[4] + (head[5] << 8) + (head[6] << 16) + (head[7] << 24);
cdStreamSeek(fd, chunkSize, SEEK_CUR);
}
/* check if 'data' chunk has not been found */
@@ -1036,19 +1039,9 @@ int cdd_load(char *filename, char *header)
sprintf(ptr, extensions[i], cdd.toc.last + offset);
fd = cdStreamOpen(fname);
}
}
/* CD tracks found ? */
if (cdd.toc.last)
{
/* Lead-out */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* CD mounted */
cdd.loaded = 1;
/* Valid DATA track found ? */
if (cdd.toc.tracks[0].type)
/* Valid CD-ROM Mode 1 track found ? */
if (cdd.toc.tracks[0].type == TYPE_MODE1)
{
/* simulate audio tracks if none found */
if (cdd.toc.last == 1)
@@ -1132,6 +1125,11 @@ int cdd_load(char *filename, char *header)
}
while (cdd.toc.last < 29);
}
else if (strstr(header + 0x180,"T-06201-01") != NULL)
{
/* Sewer Shark (USA) (REV1) */
/* no audio track */
}
else
{
/* default TOC (99 tracks & 2s per audio tracks) */
@@ -1147,8 +1145,19 @@ int cdd_load(char *filename, char *header)
}
}
}
/* CD tracks found ? */
if (cdd.toc.last)
{
/* Lead-out */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* CD mounted */
cdd.loaded = 1;
/* 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 +1178,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,12 +1217,17 @@ 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;
}
void cdd_read_data(uint8 *dst)
void cdd_read_data(uint8 *dst, uint8 *subheader)
{
/* only allow reading (first) CD-ROM track sectors */
if (cdd.toc.tracks[cdd.index].type && (cdd.lba >= 0))
@@ -1235,36 +1248,60 @@ void cdd_read_data(uint8 *dst)
cdd.chd.hunknum = hunknum;
}
/* copy Mode 1 sector data (2048 bytes only) */
/* check sector size */
if (cdd.sectorSize == 2048)
{
/* Mode 1 COOKED data (ISO) */
/* read Mode 1 user data (2048 bytes) */
memcpy(dst, cdd.chd.hunk + (offset % cdd.chd.hunkbytes), 2048);
}
else
{
/* Mode 1 RAW data (skip 16-byte header) */
memcpy(dst, cdd.chd.hunk + (offset % cdd.chd.hunkbytes) + 16, 2048);
/* check if sub-header is required (Mode 2 sector only) */
if (!subheader)
{
/* read Mode 1 user data (2048 bytes), skipping block sync pattern (12 bytes) + block header (4 bytes)*/
memcpy(dst, cdd.chd.hunk + (offset % cdd.chd.hunkbytes) + 12 + 4, 2048);
}
else
{
/* read Mode 2 sub-header (first 4 bytes), skipping block sync pattern (12 bytes) + block header (4 bytes)*/
memcpy(subheader, cdd.chd.hunk + (offset % cdd.chd.hunkbytes) + 12 + 4, 4);
/* read Mode 2 user data (max 2328 bytes), skipping Mode 2 sub-header (8 bytes) */
memcpy(dst, cdd.chd.hunk + (offset % cdd.chd.hunkbytes) + 12 + 4 + 8, 2328);
}
}
return;
}
#endif
/* seek current track sector */
/* check sector size */
if (cdd.sectorSize == 2048)
{
/* Mode 1 COOKED data (ISO) */
/* read Mode 1 user data (2048 bytes) */
cdStreamSeek(cdd.toc.tracks[0].fd, cdd.lba * 2048, SEEK_SET);
cdStreamRead(dst, 2048, 1, cdd.toc.tracks[0].fd);
}
else
{
/* Mode 1 RAW data (skip 16-byte header) */
cdStreamSeek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
}
/* check if sub-header is required (Mode 2 sector only) */
if (!subheader)
{
/* skip block sync pattern (12 bytes) + block header (4 bytes) then read Mode 1 user data (2048 bytes) */
cdStreamSeek(cdd.toc.tracks[0].fd, (cdd.lba * 2352) + 12 + 4, SEEK_SET);
cdStreamRead(dst, 2048, 1, cdd.toc.tracks[0].fd);
}
else
{
/* skip block sync pattern (12 bytes) + block header (4 bytes) + Mode 2 sub-header (first 4 bytes) then read Mode 2 sub-header (last 4 bytes) */
cdStreamSeek(cdd.toc.tracks[0].fd, (cdd.lba * 2352) + 12 + 4 + 4, SEEK_SET);
cdStreamRead(subheader, 4, 1, cdd.toc.tracks[0].fd);
/* read Mode 1 sector data (2048 bytes only) */
cdStreamRead(dst, 2048, 1, cdd.toc.tracks[0].fd);
/* read Mode 2 user data (max 2328 bytes) */
cdStreamRead(dst, 2328, 1, cdd.toc.tracks[0].fd);
}
}
}
}
@@ -1283,10 +1320,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 +1509,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;
@@ -1544,30 +1581,16 @@ void cdd_update(void)
error("LBA = %d (track %d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
#endif
/* seeking disc */
if (cdd.status == CD_SEEK)
/* drive latency */
if (cdd.latency > 0)
{
/* drive latency */
if (cdd.latency > 0)
{
cdd.latency--;
return;
}
/* drive is ready */
cdd.status = CD_PAUSE;
cdd.latency--;
return;
}
/* reading disc */
else if (cdd.status == CD_PLAY)
if (cdd.status == CD_PLAY)
{
/* drive latency */
if (cdd.latency > 0)
{
cdd.latency--;
return;
}
/* end of disc detection */
if (cdd.index >= cdd.toc.last)
{
@@ -1584,13 +1607,13 @@ void cdd_update(void)
/* track type */
if (cdd.toc.tracks[cdd.index].type)
{
/* CD-ROM (Mode 1) sector header */
/* CD-ROM sector header */
uint8 header[4];
uint32 msf = cdd.lba + 150;
header[0] = lut_BCD_8[(msf / 75) / 60];
header[1] = lut_BCD_8[(msf / 75) % 60];
header[2] = lut_BCD_8[(msf % 75)];
header[3] = 0x01;
header[3] = cdd.toc.tracks[cdd.index].type;
/* decode CD-ROM track sector */
cdc_decoder_update(*(uint32 *)(header));
@@ -1724,7 +1747,7 @@ void cdd_update(void)
}
/* AUDIO track playing ? */
scd.regs[0x36>>1].byte.h = cdd.toc.tracks[cdd.index].type;
scd.regs[0x36>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x01 : 0x00;
/* seek to current subcode position */
if (cdd.toc.sub)
@@ -1774,19 +1797,50 @@ void cdd_process(void)
/* Process CDD command */
switch (scd.regs[0x42>>1].byte.h & 0x0f)
{
case 0x00: /* Drive Status */
case 0x00: /* Get Drive Status */
{
/* RS1-RS8 normally unchanged */
scd.regs[0x38>>1].byte.h = cdd.status;
/* unless RS1 indicated invalid track infos */
if (scd.regs[0x38>>1].byte.l == 0x0f)
/* RS0-RS1 are normally unchanged unless reported drive status needs to be updated (i.e previous drive command has been processed) */
/* Note: this function is called one 75hz frame ahead of CDD update so latency counter is always one step ahead of upcoming status */
/* Radical Rex and Annet Futatabi both need at least respectively 2 and 3 interrupts with 'playing' status returned before sectors start getting incremented */
if (cdd.latency <= 3)
{
/* and drive is now ready */
if (!cdd.latency)
/* update reported drive status */
scd.regs[0x38>>1].byte.h = cdd.status;
/* check if RS1 indicated invalid track infos (during seeking) */
if (scd.regs[0x38>>1].byte.l == 0x0f)
{
/* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
scd.regs[0x38>>1].byte.l = 0x02;
/* seeking has ended so we return valid track infos, e.g current absolute time by default (fixes Lunar - The Silver Star) */
int lba = cdd.lba + 150;
scd.regs[0x38>>1].byte.l = 0x00;
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
}
/* otherwise, check if RS2-RS8 need to be updated */
else if (scd.regs[0x38>>1].byte.l == 0x00)
{
/* current absolute time */
int lba = cdd.lba + 150;
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
}
else if (scd.regs[0x38>>1].byte.l == 0x01)
{
/* current track relative time */
int lba = abs(cdd.lba - cdd.toc.tracks[cdd.index].start);
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
}
else if (scd.regs[0x38>>1].byte.l == 0x02)
{
/* current track number */
scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A;
}
}
@@ -1796,21 +1850,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) */
@@ -1823,7 +1877,7 @@ void cdd_process(void)
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type << 2; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
break;
}
@@ -1834,7 +1888,7 @@ void cdd_process(void)
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type << 2; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
break;
}
@@ -1877,15 +1931,25 @@ void cdd_process(void)
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x3e>>1].byte.h |= (cdd.toc.tracks[track-1].type << 3); /* RS6 bit 3 is set for CD-ROM track */
scd.regs[0x3e>>1].byte.h |= cdd.toc.tracks[track-1].type ? 0x08 : 0x00; /* RS6 bit 3 is set for CD-ROM track */
scd.regs[0x40>>1].byte.h = track % 10; /* Track Number (low digit) */
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;
}
@@ -1907,10 +1971,9 @@ void cdd_process(void)
if (!cdd.latency)
{
/* 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 (Annet 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 */
@@ -1967,14 +2030,14 @@ void cdd_process(void)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[cdd.index].offset + (lba * CD_FRAME_SIZE);
cdd.chd.hunkofs = cdd.toc.tracks[index].offset + (lba * CD_FRAME_SIZE);
}
else
#endif
if (cdd.toc.tracks[index].type)
{
/* DATA track */
cdStreamSeek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
cdStreamSeek(cdd.toc.tracks[index].fd, lba * cdd.sectorSize, SEEK_SET);
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (cdd.toc.tracks[index].vf.seekable)
@@ -1998,15 +2061,16 @@ void cdd_process(void)
/* no audio track playing (yet) */
scd.regs[0x36>>1].byte.h = 0x01;
/* update status */
/* update status (reported to host once seeking has ended) */
cdd.status = CD_PLAY;
/* RS0 should indicates seeking until drive is ready (fixes audio delay in Bari Arm) */
/* RS1=0xf to invalidate track infos in RS2-RS8 until drive is ready (fixes Snatcher Act 2 start cutscene) */
scd.regs[0x38>>1].w = (CD_PLAY << 8) | 0x0f;
scd.regs[0x38>>1].w = (CD_SEEK << 8) | 0x0f;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~(CD_PLAY + 0xf) & 0x0f;
scd.regs[0x40>>1].w = ~(CD_SEEK + 0xf) & 0x0f;
return;
}
@@ -2073,14 +2137,14 @@ void cdd_process(void)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[cdd.index].offset + (lba * CD_FRAME_SIZE);
cdd.chd.hunkofs = cdd.toc.tracks[index].offset + (lba * CD_FRAME_SIZE);
}
else
#endif
if (cdd.toc.tracks[index].type)
{
/* DATA track */
cdStreamSeek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
cdStreamSeek(cdd.toc.tracks[index].fd, lba * cdd.sectorSize, SEEK_SET);
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (cdd.toc.tracks[index].vf.seekable)
@@ -2104,8 +2168,8 @@ void cdd_process(void)
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
/* update status */
cdd.status = CD_SEEK;
/* update status (reported to host once seeking has ended) */
cdd.status = CD_PAUSE;
/* RS1=0xf to invalidate track infos in RS2-RS8 while seeking (fixes Final Fight CD intro when seek time is emulated) */
scd.regs[0x38>>1].w = (CD_SEEK << 8) | 0x0f;
@@ -2153,7 +2217,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 +2238,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 +2273,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;
+24 -12
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-2020 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;
@@ -124,7 +136,7 @@ extern int cdd_context_save(uint8 *state);
extern int cdd_context_load(uint8 *state);
extern int cdd_load(char *filename, char *header);
extern void cdd_unload(void);
extern void cdd_read_data(uint8 *dst);
extern void cdd_read_data(uint8 *dst, uint8 *subheader);
extern void cdd_read_audio(unsigned int samples);
extern void cdd_update(void);
extern void cdd_process(void);
+13 -28
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012 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:
@@ -47,10 +47,10 @@ void word_ram_0_dma_w(unsigned int words)
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* WORD-RAM destination address*/
uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x1fffe;
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 2);
@@ -60,13 +60,8 @@ void word_ram_0_dma_w(unsigned int words)
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* read 16-bit word from CDC RAM buffer (big-endian format) */
data = READ_WORD(cdc.ram, src_index);
/* write 16-bit word to WORD-RAM */
*(uint16 *)(scd.word_ram[0] + dst_index) = data ;
@@ -85,10 +80,10 @@ void word_ram_1_dma_w(unsigned int words)
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* WORD-RAM destination address*/
uint32 dst_index = ((scd.regs[0x0a>>1].w << 3) & 0x1fffe);
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 2);
@@ -98,13 +93,8 @@ void word_ram_1_dma_w(unsigned int words)
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* read 16-bit word from CDC RAM buffer (big-endian format) */
data = READ_WORD(cdc.ram, src_index);
/* write 16-bit word to WORD-RAM */
*(uint16 *)(scd.word_ram[1] + dst_index) = data ;
@@ -123,10 +113,10 @@ void word_ram_2M_dma_w(unsigned int words)
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* WORD-RAM destination address*/
uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x3fffe;
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 2);
@@ -136,13 +126,8 @@ void word_ram_2M_dma_w(unsigned int words)
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* read 16-bit word from CDC RAM buffer (big-endian format) */
data = READ_WORD(cdc.ram, src_index);
/* write 16-bit word to WORD-RAM */
*(uint16 *)(scd.word_ram_2M + dst_index) = data ;
+1 -1
View File
@@ -2,7 +2,7 @@
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012 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,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
+47 -18
View File
@@ -201,6 +201,7 @@ typedef struct _zlib_allocator zlib_allocator;
struct _zlib_allocator
{
UINT32 * allocptr[MAX_ZLIB_ALLOCS];
UINT32 * allocptr2[MAX_ZLIB_ALLOCS];
};
typedef struct _zlib_codec_data zlib_codec_data;
@@ -220,10 +221,11 @@ struct _lzma_allocator
void (*Free)(void *p, void *address); /* address can be 0 */
void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
uint32_t* allocptr[MAX_LZMA_ALLOCS];
uint32_t* allocptr2[MAX_LZMA_ALLOCS];
};
typedef struct _lzma_codec_data lzma_codec_data;
struct _lzma_codec_data
struct _lzma_codec_data
{
CLzmaDec decoder;
lzma_allocator allocator;
@@ -375,6 +377,7 @@ void lzma_allocator_init(void* p)
/* reset pointer list */
memset(codec->allocptr, 0, sizeof(codec->allocptr));
memset(codec->allocptr2, 0, sizeof(codec->allocptr2));
codec->Alloc = lzma_fast_alloc;
codec->Free = lzma_fast_free;
}
@@ -403,11 +406,16 @@ void lzma_allocator_free(void* p )
*-------------------------------------------------
*/
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define LZMA_MIN_ALIGNMENT_BITS 512
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
void *lzma_fast_alloc(void *p, size_t size)
{
int scan;
uint32_t *addr;
uint32_t *addr = NULL;
lzma_allocator *codec = (lzma_allocator *)(p);
uintptr_t vaddr = 0;
/* compute the size, rounding to the nearest 1k */
size = (size + 0x3ff) & ~0x3ff;
@@ -420,28 +428,37 @@ void *lzma_fast_alloc(void *p, size_t size)
{
/* set the low bit of the size so we don't match next time */
*ptr |= 1;
return ptr + 1;
/* return aligned address of the block */
return codec->allocptr2[scan];
}
}
/* alloc a new one and put it into the list */
addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t)));
addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
if (addr==NULL)
return NULL;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
if (codec->allocptr[scan] == NULL)
{
/* store block address */
codec->allocptr[scan] = addr;
/* compute aligned address, store it */
vaddr = (uintptr_t)addr;
vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
codec->allocptr2[scan] = (uint32_t*)vaddr;
break;
}
}
/* set the low bit of the size so we don't match next time */
*addr = size | 1;
return addr + 1;
}
/* return aligned address */
return (void*)vaddr;
}
/*-------------------------------------------------
* lzma_fast_free - fast free for lzma, which
@@ -452,21 +469,22 @@ void *lzma_fast_alloc(void *p, size_t size)
void lzma_fast_free(void *p, void *address)
{
int scan;
uint32_t *ptr;
lzma_allocator *codec;
uint32_t *ptr = NULL;
lzma_allocator *codec = NULL;
if (address == NULL)
return;
codec = (lzma_allocator *)(p);
/* find the hunk */
ptr = (uint32_t *)(address) - 1;
ptr = (uint32_t *)address;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
if (ptr == codec->allocptr[scan])
if (ptr == codec->allocptr2[scan])
{
/* clear the low bit of the size to allow matches */
*ptr &= ~1;
*codec->allocptr[scan] &= ~1;
return;
}
}
@@ -2458,9 +2476,14 @@ static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t
allocates and frees memory frequently
-------------------------------------------------*/
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define ZLIB_MIN_ALIGNMENT_BITS 512
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
zlib_allocator *alloc = (zlib_allocator *)opaque;
uintptr_t paddr = 0;
UINT32 *ptr;
int i;
@@ -2475,12 +2498,14 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
/* set the low bit of the size so we don't match next time */
*ptr |= 1;
return ptr + 1;
/* return aligned block address */
return (voidpf)(alloc->allocptr2[i]);
}
}
/* alloc a new one */
ptr = (UINT32 *)malloc(size + sizeof(UINT32));
ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
if (!ptr)
return NULL;
@@ -2489,12 +2514,16 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
if (!alloc->allocptr[i])
{
alloc->allocptr[i] = ptr;
paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
alloc->allocptr2[i] = (uint32_t*)paddr;
break;
}
/* set the low bit of the size so we don't match next time */
*ptr = size | 1;
return ptr + 1;
/* return aligned block address */
return (voidpf)paddr;
}
@@ -2506,15 +2535,15 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
static void zlib_fast_free(voidpf opaque, voidpf address)
{
zlib_allocator *alloc = (zlib_allocator *)opaque;
UINT32 *ptr = (UINT32 *)address - 1;
UINT32 *ptr = (UINT32 *)address;
int i;
/* find the hunk */
for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
if (ptr == alloc->allocptr[i])
if (ptr == alloc->allocptr2[i])
{
/* clear the low bit of the size to allow matches */
*ptr &= ~1;
*(alloc->allocptr[i]) &= ~1;
return;
}
}
+147 -92
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-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -101,13 +101,8 @@ void prg_ram_dma_w(unsigned int words)
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* read 16-bit word from CDC RAM buffer (big-endian format) */
data = READ_WORD(cdc.ram, src_index);
/* write 16-bit word to PRG-RAM */
*(uint16 *)(scd.prg_ram + dst_index) = data ;
@@ -255,7 +250,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 +288,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 +340,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 +440,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 +670,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 +788,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 */
@@ -985,28 +992,6 @@ static void scd_write_byte(unsigned int address, unsigned int data)
return;
}
case 0x37: /* CDD control (controlled by BIOS, byte access only ?) */
{
/* CDD communication started ? */
if ((data & 0x04) && !(scd.regs[0x37>>1].byte.l & 0x04))
{
/* reset CDD cycle counter */
cdd.cycles = (scd.cycles - s68k.cycles) * 3;
/* set pending interrupt level 4 */
scd.pending |= (1 << 4);
/* update IRQ level if interrupt is enabled */
if (scd.regs[0x32>>1].byte.l & 0x10)
{
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
scd.regs[0x37>>1].byte.l = data;
return;
}
default:
{
/* SUB-CPU communication words */
@@ -1059,7 +1044,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 +1266,53 @@ 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 0x36: /* CDD control */
{
/* only bit 2 is writable (bits [1:0] forced to 0 by default) */
scd.regs[0x37>>1].byte.l = data & 0x04;
return;
}
case 0x4a: /* CDD command 9 (controlled by BIOS, word access only ?) */
{
scd.regs[0x4a>>1].w = 0;
@@ -1532,7 +1564,6 @@ void scd_init(void)
void scd_reset(int hard)
{
/* TODO: figure what exactly is resetted when RESET bit is cleared by SUB-CPU */
if (hard)
{
/* Clear all ASIC registers by default */
@@ -1574,11 +1605,17 @@ void scd_reset(int hard)
s68k.cycles = 0;
s68k_pulse_reset();
s68k_pulse_halt();
/* Reset frame cycle counter */
scd.cycles = 0;
}
else
{
/* Clear only SUB-CPU side registers */
memset(&scd.regs[0x04>>1], 0, sizeof(scd.regs) - 4);
/* TODO: figure what exactly is reset when RESET bit is cleared by SUB-CPU */
/* Clear only SUB-CPU side registers (communication registers are not cleared, see msu-md-sample.bin) */
scd.regs[0x04>>1].w = 0x0000;
scd.regs[0x0c>>1].w = 0x0000;
memset(&scd.regs[0x30>>1], 0, sizeof(scd.regs) - 0x30);
}
/* SUB-CPU side default values */
@@ -1597,10 +1634,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 +1643,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();
@@ -1618,6 +1655,10 @@ void scd_reset(int hard)
void scd_update(unsigned int cycles)
{
int m68k_end_cycles;
int s68k_run_cycles;
int s68k_end_cycles = scd.cycles + SCYCLES_PER_LINE;
/* update CDC DMA transfer */
if (cdc.dma_w)
{
@@ -1627,63 +1668,77 @@ void scd_update(unsigned int cycles)
/* run both CPU in sync until end of line */
do
{
m68k_run(cycles);
s68k_run(scd.cycles + SCYCLES_PER_LINE);
}
while ((m68k.cycles < cycles) || (s68k.cycles < (scd.cycles + SCYCLES_PER_LINE)));
/* CD hardware remaining cycles until end of line */
s68k_run_cycles = s68k_end_cycles - scd.cycles;
/* increment CD hardware cycle counter */
scd.cycles += SCYCLES_PER_LINE;
/* CDD processing at 75Hz (one clock = 12500000/75 = 500000/3 CPU clocks) */
cdd.cycles += (SCYCLES_PER_LINE * 3);
if (cdd.cycles >= (500000 * 4))
{
/* reload CDD cycle counter */
cdd.cycles -= (500000 * 4);
/* update CDD sector */
cdd_update();
/* check if a new CDD command has been processed */
if (!(scd.regs[0x4a>>1].byte.l & 0xf0))
/* check Timer interrupt occurence */
if ((scd.timer > 0) && (scd.timer < s68k_run_cycles))
{
/* reset CDD command wait flag */
scd.regs[0x4a>>1].byte.l = 0xf0;
/* adjust Sub-CPU and Main-CPU end cycle counters up to Timer interrupt occurence */
s68k_run_cycles = scd.timer;
m68k_end_cycles = mcycles_vdp + ((s68k_run_cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE);
}
else
{
/* default Main-CPU end cycle counter (end of line) */
m68k_end_cycles = cycles;
}
/* pending level 4 interrupt */
scd.pending |= (1 << 4);
/* run both CPU in sync until required cycle counters */
m68k_run(m68k_end_cycles);
s68k_run(scd.cycles + s68k_run_cycles);
/* level 4 interrupt enabled */
if (scd.regs[0x32>>1].byte.l & 0x10)
/* increment CD hardware cycle counter */
scd.cycles += s68k_run_cycles;
/* CDD processing at 75Hz (one clock = 12500000/75 = 500000/3 CPU clocks) */
cdd.cycles += (s68k_run_cycles * 3);
if (cdd.cycles >= (500000 * 4))
{
/* reload CDD cycle counter */
cdd.cycles -= (500000 * 4);
/* update CDD sector */
cdd_update();
/* check if CDD communication is enabled */
if (scd.regs[0x37>>1].byte.l & 0x04)
{
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
}
/* Timer */
if (scd.timer)
{
/* decrement timer */
scd.timer -= SCYCLES_PER_LINE;
if (scd.timer <= 0)
{
/* reload timer (one timer clock = 384 CPU cycles) */
scd.timer += (scd.regs[0x30>>1].byte.l * TIMERS_SCYCLES_RATIO);
/* level 3 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x08)
{
/* trigger level 3 interrupt */
scd.pending |= (1 << 3);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
/* pending level 4 interrupt */
scd.pending |= (1 << 4);
/* level 4 interrupt enabled */
if (scd.regs[0x32>>1].byte.l & 0x10)
{
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
}
/* Timer */
if (scd.timer)
{
/* decrement timer */
scd.timer -= s68k_run_cycles;
if (scd.timer <= 0)
{
/* reload timer (one timer clock = 384 CPU cycles) */
scd.timer += (scd.regs[0x30>>1].byte.l * TIMERS_SCYCLES_RATIO);
/* level 3 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x08)
{
/* trigger level 3 interrupt */
scd.pending |= (1 << 3);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
}
}
while ((m68k.cycles < cycles) || (s68k.cycles < s68k_end_cycles));
/* GFX processing */
if (scd.regs[0x58>>1].byte.h & 0x80)
+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-2020 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_ */
+16 -8
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-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -279,10 +279,18 @@ void gen_reset(int hard_reset)
/* reset CD hardware */
scd_reset(1);
}
/* reset MD cartridge hardware (only when booting from cartridge) */
if (scd.cartridge.boot)
{
md_cart_reset(hard_reset);
}
}
else
{
/* reset MD cartridge hardware */
md_cart_reset(hard_reset);
}
/* reset MD cartridge hardware */
md_cart_reset(hard_reset);
/* Z80 bus is released & Z80 is reseted */
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
@@ -474,8 +482,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 +504,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-2020 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:
+24 -4
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-2020 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;
@@ -630,7 +647,9 @@ int load_rom(char *filename)
/* auto-detect byte-swapped dumps */
if (!memcmp((char *)(cart.rom + 0x100),"ESAGM GE ARDVI E", 16) ||
!memcmp((char *)(cart.rom + 0x100),"ESAGG NESESI", 12))
!memcmp((char *)(cart.rom + 0x100),"ESAGG NESESI", 12) ||
!memcmp((char *)(cart.rom + 0x80000 + 0x100),"ESAGM GE ARDVI E", 16) ||
!memcmp((char *)(cart.rom + 0x80000 + 0x100),"ESAGG NESESI", 12))
{
for(i = 0; i < size; i += 2)
{
@@ -1059,7 +1078,8 @@ void get_region(char *romheader)
(strstr(rominfo.product,"T-69046-50") != NULL) || /* Back to the Future III (Europe) */
(strstr(rominfo.product,"T-120106-00") != NULL) || /* Brian Lara Cricket (Europe) */
(strstr(rominfo.product,"T-97126 -50") != NULL) || /* Williams Arcade's Greatest Hits (Europe) */
(strstr(rominfo.product,"T-70096 -00") != NULL)) /* Muhammad Ali Heavyweight Boxing (Europe) */
(strstr(rominfo.product,"T-70096 -00") != NULL) || /* Muhammad Ali Heavyweight Boxing (Europe) */
((rominfo.checksum == 0x0000) && (rominfo.realchecksum == 0x1f7f))) /* Radica - Sensible Soccer Plus edition */
{
/* need PAL settings */
region_code = REGION_EUROPE;
+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-2020 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 ==================== */
+15 -8
View File
@@ -188,7 +188,8 @@ void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
}
#endif
#ifdef LOGVDP
#ifdef LOGERROR
extern void error(char *format, ...);
extern uint16 v_counter;
#endif
@@ -202,8 +203,8 @@ void m68k_update_irq(unsigned int mask)
/* Update IRQ level */
CPU_INT_LEVEL |= (mask << 8);
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#ifdef LOGERROR
error("[%d(%d)][%d(%d)] m68k IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
}
@@ -212,8 +213,8 @@ void m68k_set_irq(unsigned int int_level)
/* Set IRQ level */
CPU_INT_LEVEL = int_level << 8;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#ifdef LOGERROR
error("[%d(%d)][%d(%d)] m68k IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
}
@@ -245,8 +246,8 @@ void m68k_set_irq_delay(unsigned int int_level)
CPU_INT_LEVEL = int_level << 8;
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#ifdef LOGERROR
error("[%d(%d)][%d(%d)] m68k IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
/* Check interrupt mask to process IRQ */
@@ -277,7 +278,7 @@ void m68k_run(unsigned int cycles)
/* Return point for when we have an address error (TODO: use goto) */
m68ki_set_address_error_trap() /* auto-disable (see m68kcpu.h) */
#ifdef LOGVDP
#ifdef LOGERROR
error("[%d][%d] m68k run to %d cycles (%x), irq mask = %x (%x)\n", v_counter, m68k.cycles, cycles, m68k.pc,FLAG_INT_MASK, CPU_INT_LEVEL);
#endif
@@ -289,6 +290,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;
+20 -20
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,
@@ -40,7 +40,7 @@ static const unsigned char m68ki_cycles[0x10000] =
16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7,
22*7, 22*7, 22*7, 22*7, 22*7, 22*7, 22*7, 22*7, 20*7, 24*7, 0*7, 0*7, 20*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 16*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7, 28*7,
30*7, 30*7, 30*7, 30*7, 30*7, 30*7, 30*7, 30*7, 32*7, 32*7, 32*7, 32*7, 32*7, 32*7, 32*7, 32*7,
34*7, 34*7, 34*7, 34*7, 34*7, 34*7, 34*7, 34*7, 32*7, 36*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*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,
@@ -1197,9 +1197,9 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7,
20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 22*7, 22*7, 22*7, 22*7, 22*7, 22*7, 22*7, 22*7,
24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 24*7, 22*7, 26*7, 0*7, 0*7, 4*7, 0*7, 0*7, 0*7,
14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*7, 14*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, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7,
20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 20*7, 18*7, 22*7, 0*7, 0*7, 4*7, 0*7, 0*7, 0*7,
0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1284,7 +1284,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1316,7 +1316,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1348,7 +1348,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1380,7 +1380,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1412,7 +1412,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1444,7 +1444,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1476,7 +1476,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
@@ -1508,7 +1508,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7,
4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 4*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*7, 8*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,
18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 18*7, 16*7, 20*7, 0*7, 0*7, 0*7, 0*7, 0*7, 0*7,
+27 -24
View File
@@ -8117,7 +8117,7 @@ static void m68k_op_divu_16_d(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8148,7 +8148,7 @@ static void m68k_op_divu_16_ai(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8179,7 +8179,7 @@ static void m68k_op_divu_16_pi(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 *10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8210,7 +8210,7 @@ static void m68k_op_divu_16_pd(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8241,7 +8241,7 @@ static void m68k_op_divu_16_di(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8272,7 +8272,7 @@ static void m68k_op_divu_16_ix(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8303,7 +8303,7 @@ static void m68k_op_divu_16_aw(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8334,7 +8334,7 @@ static void m68k_op_divu_16_al(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8365,7 +8365,7 @@ static void m68k_op_divu_16_pcdi(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8396,7 +8396,7 @@ static void m68k_op_divu_16_pcix(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -8427,7 +8427,7 @@ static void m68k_op_divu_16_i(void)
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
return;
}
USE_CYCLES(7 * 10);
USE_CYCLES(MUL * 10);
FLAG_V = VFLAG_SET;
FLAG_N = NFLAG_SET; /* undocumented behavior (fixes Blood Shot on Genesis) */
FLAG_C = CFLAG_CLEAR;
@@ -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();
@@ -23885,7 +23888,7 @@ static const opcode_handler_struct m68k_opcode_handler_table[] =
{m68k_op_addq_8_di , 0xf1f8, 0x5028, 16},
{m68k_op_addq_8_ix , 0xf1f8, 0x5030, 18},
{m68k_op_addq_16_d , 0xf1f8, 0x5040, 4},
{m68k_op_addq_16_a , 0xf1f8, 0x5048, 4},
{m68k_op_addq_16_a , 0xf1f8, 0x5048, 8}, /* see Yacht.txt */
{m68k_op_addq_16_ai , 0xf1f8, 0x5050, 12},
{m68k_op_addq_16_pi , 0xf1f8, 0x5058, 12},
{m68k_op_addq_16_pd , 0xf1f8, 0x5060, 14},
@@ -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},
@@ -24595,7 +24598,7 @@ static const opcode_handler_struct m68k_opcode_handler_table[] =
{m68k_op_andi_16_pd , 0xfff8, 0x0260, 18},
{m68k_op_andi_16_di , 0xfff8, 0x0268, 20},
{m68k_op_andi_16_ix , 0xfff8, 0x0270, 22},
{m68k_op_andi_32_d , 0xfff8, 0x0280, 14},
{m68k_op_andi_32_d , 0xfff8, 0x0280, 16}, /* see Yacht.txt */
{m68k_op_andi_32_ai , 0xfff8, 0x0290, 28},
{m68k_op_andi_32_pi , 0xfff8, 0x0298, 28},
{m68k_op_andi_32_pd , 0xfff8, 0x02a0, 30},
@@ -24878,11 +24881,11 @@ static const opcode_handler_struct m68k_opcode_handler_table[] =
{m68k_op_tst_32_di , 0xfff8, 0x4aa8, 16},
{m68k_op_tst_32_ix , 0xfff8, 0x4ab0, 18},
{m68k_op_tas_8_d , 0xfff8, 0x4ac0, 4},
{m68k_op_tas_8_ai , 0xfff8, 0x4ad0, 18},
{m68k_op_tas_8_pi , 0xfff8, 0x4ad8, 18},
{m68k_op_tas_8_pd , 0xfff8, 0x4ae0, 20},
{m68k_op_tas_8_di , 0xfff8, 0x4ae8, 22},
{m68k_op_tas_8_ix , 0xfff8, 0x4af0, 24},
{m68k_op_tas_8_ai , 0xfff8, 0x4ad0, 14}, /* see Yacht.txt */
{m68k_op_tas_8_pi , 0xfff8, 0x4ad8, 14}, /* see Yacht.txt */
{m68k_op_tas_8_pd , 0xfff8, 0x4ae0, 16}, /* see Yacht.txt */
{m68k_op_tas_8_di , 0xfff8, 0x4ae8, 18}, /* see Yacht.txt */
{m68k_op_tas_8_ix , 0xfff8, 0x4af0, 20}, /* see Yacht.txt */
{m68k_op_movem_16_er_ai , 0xfff8, 0x4c90, 12},
{m68k_op_movem_16_er_pi , 0xfff8, 0x4c98, 12},
{m68k_op_movem_16_er_di , 0xfff8, 0x4ca8, 16},
@@ -25242,10 +25245,10 @@ static const opcode_handler_struct m68k_opcode_handler_table[] =
{m68k_op_tst_16_al , 0xffff, 0x4a79, 16},
{m68k_op_tst_32_aw , 0xffff, 0x4ab8, 16},
{m68k_op_tst_32_al , 0xffff, 0x4ab9, 20},
{m68k_op_tas_8_pi7 , 0xffff, 0x4adf, 18},
{m68k_op_tas_8_pd7 , 0xffff, 0x4ae7, 20},
{m68k_op_tas_8_aw , 0xffff, 0x4af8, 22},
{m68k_op_tas_8_al , 0xffff, 0x4af9, 26},
{m68k_op_tas_8_pi7 , 0xffff, 0x4adf, 14}, /* see Yacht.txt */
{m68k_op_tas_8_pd7 , 0xffff, 0x4ae7, 16}, /* see Yacht.txt */
{m68k_op_tas_8_aw , 0xffff, 0x4af8, 18}, /* see Yacht.txt */
{m68k_op_tas_8_al , 0xffff, 0x4af9, 22}, /* see Yacht.txt */
{m68k_op_illegal , 0xffff, 0x4afc, 4},
{m68k_op_movem_16_er_aw , 0xffff, 0x4cb8, 16},
{m68k_op_movem_16_er_al , 0xffff, 0x4cb9, 20},
+1 -1
View File
@@ -213,7 +213,7 @@ void s68k_update_irq(unsigned int mask)
CPU_INT_LEVEL = mask << 8;
#ifdef LOG_SCD
error("[%d][%d] IRQ Level = %d(0x%02x) (%x)\n", v_counter, s68k.cycles, CPU_INT_LEVEL>>8,FLAG_INT_MASK,s68k.pc);
error("[%d][%d] s68k IRQ Level = %d(0x%02x) (%x)\n", v_counter, s68k.cycles, CPU_INT_LEVEL>>8,FLAG_INT_MASK,s68k.pc);
#endif
}
+20 -20
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,
@@ -40,7 +40,7 @@ static const unsigned char m68ki_cycles[0x10000] =
16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4,
22*4, 22*4, 22*4, 22*4, 22*4, 22*4, 22*4, 22*4, 20*4, 24*4, 0*4, 0*4, 20*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 16*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4, 28*4,
30*4, 30*4, 30*4, 30*4, 30*4, 30*4, 30*4, 30*4, 32*4, 32*4, 32*4, 32*4, 32*4, 32*4, 32*4, 32*4,
34*4, 34*4, 34*4, 34*4, 34*4, 34*4, 34*4, 34*4, 32*4, 36*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*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, 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,
@@ -1197,9 +1197,9 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4,
20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 22*4, 22*4, 22*4, 22*4, 22*4, 22*4, 22*4, 22*4,
24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 24*4, 22*4, 26*4, 0*4, 0*4, 4*4, 0*4, 0*4, 0*4,
14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*4, 14*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, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4,
20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 20*4, 18*4, 22*4, 0*4, 0*4, 4*4, 0*4, 0*4, 0*4,
0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1284,7 +1284,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1316,7 +1316,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1348,7 +1348,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1380,7 +1380,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1412,7 +1412,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1444,7 +1444,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1476,7 +1476,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
@@ -1508,7 +1508,7 @@ static const unsigned char m68ki_cycles[0x10000] =
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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4,
4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 4*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*4, 8*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,
18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 18*4, 16*4, 20*4, 0*4, 0*4, 0*4, 0*4, 0*4, 0*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:
+4 -1
View File
@@ -3,7 +3,7 @@
* Z80 bank access to 68k bus
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -39,6 +39,9 @@
#include "shared.h"
t_zbank_memory_map zbank_memory_map[256];
/*
Handlers for access to unused addresses and those which make the
machine lock up.
+5 -3
View File
@@ -3,7 +3,7 @@
* Z80 bank access to 68k bus
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -49,10 +49,12 @@ extern void zbank_write_ctrl_io(unsigned int address, unsigned int data);
extern unsigned int zbank_read_vdp(unsigned int address);
extern void zbank_write_vdp(unsigned int address, unsigned int data);
struct _zbank_memory_map
typedef struct
{
unsigned int (*read)(unsigned int address);
void (*write)(unsigned int address, unsigned int data);
} zbank_memory_map[256];
} t_zbank_memory_map;
extern t_zbank_memory_map zbank_memory_map[256];
#endif /* _MEMBNK_H_ */
+14 -4
View File
@@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive ports access
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -111,6 +111,8 @@ unsigned char z80_memory_r(unsigned int address)
{
if ((address >> 8) == 0x7F)
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
return (*zbank_memory_map[0xc0].read)(address);
}
return z80_unused_r(address);
@@ -118,6 +120,9 @@ unsigned char z80_memory_r(unsigned int address)
default: /* $8000-$FFFF: 68k bank (32K) */
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
address = zbank | (address & 0x7FFF);
if (zbank_memory_map[address >> 16].read)
{
@@ -158,6 +163,8 @@ void z80_memory_w(unsigned int address, unsigned char data)
case 0x7F: /* $7F00-$7FFF: VDP */
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
(*zbank_memory_map[0xc0].write)(address, data);
return;
}
@@ -172,6 +179,9 @@ void z80_memory_w(unsigned int address, unsigned char data)
default: /* $8000-$FFFF: 68k bank (32K) */
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
address = zbank | (address & 0x7FFF);
if (zbank_memory_map[address >> 16].write)
{
@@ -300,7 +310,7 @@ unsigned char z80_md_port_r(unsigned int port)
/* read FM chip if enabled */
if ((port >= 0xF0) && (config.ym2413 & 1))
{
return YM2413Read();
return fm_read(Z80.cycles, port);
}
return z80_unused_port_r(port);
@@ -578,7 +588,7 @@ unsigned char z80_ms_port_r(unsigned int port)
/* read FM board if enabled */
if (!(port & 4) && (config.ym2413 & 1))
{
data = YM2413Read();
data = fm_read(Z80.cycles, port);
}
/* read I/O ports if enabled */
@@ -678,7 +688,7 @@ unsigned char z80_m3_port_r(unsigned int port)
if (!(port & 4) && (config.ym2413 & 1))
{
/* I/O ports are automatically disabled by hardware */
return YM2413Read();
return fm_read(Z80.cycles, port);
}
/* read I/O ports */
+1 -1
View File
@@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive ports access
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2020 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
@@ -28,6 +28,9 @@
#ifdef HAVE_YM3438_CORE
#include "ym3438.h"
#endif
#ifdef HAVE_OPLL_CORE
#include "opll.h"
#endif
#include "sram.h"
#include "ggenie.h"
#include "areplay.h"
File diff suppressed because it is too large Load Diff
+215
View File
@@ -0,0 +1,215 @@
/*
* Copyright (C) 2019 Nuke.YKT
*
* 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.
*
*
* Yamaha YM2413 emulator
* Thanks:
* siliconpr0n.org(digshadow, John McMaster):
* VRC VII decap and die shot.
*
* version: 1.0
*/
#ifndef OPLL_H
#define OPLL_H
#include <stdint.h>
enum {
opll_type_ym2413 = 0x00, /* Yamaha YM2413 */
opll_type_ds1001, /* Konami VRC VII */
opll_type_ym2413b /* Yamaha YM2413B */
};
enum {
opll_patch_1 = 0x00,
opll_patch_2,
opll_patch_3,
opll_patch_4,
opll_patch_5,
opll_patch_6,
opll_patch_7,
opll_patch_8,
opll_patch_9,
opll_patch_10,
opll_patch_11,
opll_patch_12,
opll_patch_13,
opll_patch_14,
opll_patch_15,
opll_patch_drum_0,
opll_patch_drum_1,
opll_patch_drum_2,
opll_patch_drum_3,
opll_patch_drum_4,
opll_patch_drum_5,
opll_patch_max
};
typedef struct {
uint8_t tl;
uint8_t dc;
uint8_t dm;
uint8_t fb;
uint8_t am[2];
uint8_t vib[2];
uint8_t et[2];
uint8_t ksr[2];
uint8_t multi[2];
uint8_t ksl[2];
uint8_t ar[2];
uint8_t dr[2];
uint8_t sl[2];
uint8_t rr[2];
} opll_patch_t;
typedef struct {
uint32_t chip_type;
uint32_t cycles;
uint32_t slot;
const opll_patch_t *patchrom;
/* IO */
uint8_t write_data;
uint8_t write_a;
uint8_t write_d;
uint8_t write_a_en;
uint8_t write_d_en;
uint8_t write_fm_address;
uint8_t write_fm_data;
uint8_t write_mode_address;
uint8_t address;
uint8_t data;
/* Envelope generator */
uint8_t eg_counter_state;
uint8_t eg_counter_state_prev;
uint32_t eg_timer;
uint8_t eg_timer_low_lock;
uint8_t eg_timer_carry;
uint8_t eg_timer_shift;
uint8_t eg_timer_shift_lock;
uint8_t eg_timer_shift_stop;
uint8_t eg_state[18];
uint8_t eg_level[18];
uint8_t eg_kon;
uint32_t eg_dokon;
uint8_t eg_off;
uint8_t eg_rate;
uint8_t eg_maxrate;
uint8_t eg_zerorate;
uint8_t eg_inc_lo;
uint8_t eg_inc_hi;
uint8_t eg_rate_hi;
uint16_t eg_sl;
uint16_t eg_ksltl;
uint8_t eg_out;
uint8_t eg_silent;
/* Phase generator */
uint16_t pg_fnum;
uint8_t pg_block;
uint16_t pg_out;
uint32_t pg_inc;
uint32_t pg_phase[18];
uint32_t pg_phase_next;
/* Operator */
int16_t op_fb1[9];
int16_t op_fb2[9];
int16_t op_fbsum;
int16_t op_mod;
uint8_t op_neg;
uint16_t op_logsin;
uint16_t op_exp_m;
uint16_t op_exp_s;
/* Channel */
int16_t ch_out;
int16_t ch_out_hh;
int16_t ch_out_tm;
int16_t ch_out_bd;
int16_t ch_out_sd;
int16_t ch_out_tc;
/* LFO */
uint16_t lfo_counter;
uint8_t lfo_vib_counter;
uint16_t lfo_am_counter;
uint8_t lfo_am_step;
uint8_t lfo_am_dir;
uint8_t lfo_am_car;
uint8_t lfo_am_out;
/* Register set */
uint16_t fnum[9];
uint8_t block[9];
uint8_t kon[9];
uint8_t son[9];
uint8_t vol[9];
uint8_t inst[9];
uint8_t rhythm;
uint8_t testmode;
opll_patch_t patch;
uint8_t c_instr;
uint8_t c_op;
uint8_t c_tl;
uint8_t c_dc;
uint8_t c_dm;
uint8_t c_fb;
uint8_t c_am;
uint8_t c_vib;
uint8_t c_et;
uint8_t c_ksr;
uint8_t c_ksr_freq;
uint8_t c_ksl_freq;
uint8_t c_ksl_block;
uint8_t c_multi;
uint8_t c_ksl;
uint8_t c_adrr[3];
uint8_t c_sl;
uint16_t c_fnum;
uint16_t c_block;
/* Rhythm mode */
int8_t rm_enable;
uint32_t rm_noise;
uint32_t rm_select;
uint8_t rm_hh_bit2;
uint8_t rm_hh_bit3;
uint8_t rm_hh_bit7;
uint8_t rm_hh_bit8;
uint8_t rm_tc_bit3;
uint8_t rm_tc_bit5;
int16_t output_m;
int16_t output_r;
} opll_t;
void OPLL_Reset(opll_t *chip, uint32_t chip_type);
void OPLL_Clock(opll_t *chip, int32_t *buffer);
void OPLL_Write(opll_t *chip, uint32_t port, uint8_t data);
#endif
+327 -136
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-2020 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,8 +40,11 @@
#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
#if defined(HAVE_YM3438_CORE) || defined(HAVE_OPLL_CORE)
static int fm_buffer[1080 * 2 * 24];
#else
static int fm_buffer[1080 * 2];
@@ -51,28 +54,134 @@ 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)
#ifdef HAVE_OPLL_CORE
static opll_t opll;
static int opll_accm[18][2];
static int opll_sample;
static int opll_cycles;
static int opll_status;
#endif
/* 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);
/* 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);
}
static unsigned int YM2413_Read(unsigned int cycles, unsigned int a)
{
return YM2413Read();
}
#ifdef HAVE_YM3438_CORE
static void YM3438_Update(int *buffer, int length)
{
int i, j;
for (i = 0; i < length; i++)
@@ -94,36 +203,87 @@ 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);
/* read FM status */
return OPN2_Read(&ym3438, a);
}
#endif
/* Run FM chip until required M-cycles */
INLINE void fm_update(unsigned int cycles)
#ifdef HAVE_OPLL_CORE
static void OPLL2413_Update(int* buffer, int length)
{
if (cycles > fm_cycles_count)
int i, j;
for (i = 0; i < length; i++)
{
/* 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;
OPLL_Clock(&opll, opll_accm[opll_cycles]);
opll_cycles = (opll_cycles + 1) % 18;
if (opll_cycles == 0)
{
opll_sample = 0;
for (j = 0; j < 18; j++)
{
opll_sample += opll_accm[j][0] + opll_accm[j][1];
}
}
*buffer++ = opll_sample * 16 * opll_status;
*buffer++ = opll_sample * 16 * opll_status;
}
}
static void OPLL2413_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
OPLL_Reset(&opll, opll_type_ym2413);
}
static void OPLL2413_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
if (!(a&2))
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* write FM register */
OPLL_Write(&opll, a, v);
}
else
{
opll_status = v&1;
}
}
static unsigned int OPLL2413_Read(unsigned int cycles, unsigned int a)
{
return 0xf8 | opll_status;
}
#endif
void sound_init( void )
{
/* Initialize FM chip */
@@ -137,40 +297,60 @@ 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;
#ifdef HAVE_OPLL_CORE
if (config.opll)
{
/* Nuked OPLL */
memset(&opll, 0, sizeof(opll));
memset(&opll_accm, 0, sizeof(opll_accm));
opll_sample = 0;
opll_status = 0;
YM_Update = (config.ym2413 & 1) ? OPLL2413_Update : NULL;
fm_reset = OPLL2413_Reset;
fm_write = OPLL2413_Write;
fm_read = OPLL2413_Read;
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
fm_cycles_ratio = 72 * 15;
/* chip is running at internal clock */
fm_cycles_ratio = 4 * 15;
}
else
#endif
{
YM2413Init();
YM_Update = (config.ym2413 & 1) ? YM2413Update : NULL;
fm_reset = YM2413_Reset;
fm_write = YM2413_Write;
fm_read = YM2413_Read;
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
fm_cycles_ratio = 72 * 15;
}
}
/* Initialize PSG chip */
@@ -180,7 +360,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 +376,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 +480,6 @@ int sound_context_save(uint8 *state)
else
{
bufferptr += YM2612SaveContext(state + sizeof(config.ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612SaveContext(state);
@@ -296,7 +487,21 @@ int sound_context_save(uint8 *state)
}
else
{
save_param(YM2413GetContextPtr(),YM2413GetContextSize());
#ifdef HAVE_OPLL_CORE
save_param(&config.opll, sizeof(config.opll));
if (config.opll)
{
save_param(&opll, sizeof(opll));
save_param(&opll_accm, sizeof(opll_accm));
save_param(&opll_sample, sizeof(opll_sample));
save_param(&opll_cycles, sizeof(opll_cycles));
save_param(&opll_status, sizeof(opll_status));
}
else
#endif
{
save_param(YM2413GetContextPtr(),YM2413GetContextSize());
}
}
bufferptr += psg_context_save(&state[bufferptr]);
@@ -325,16 +530,29 @@ 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
{
load_param(YM2413GetContextPtr(),YM2413GetContextSize());
#ifdef HAVE_OPLL_CORE
uint8 config_opll;
load_param(&config_opll, sizeof(config_opll));
if (config_opll)
{
load_param(&opll, sizeof(opll));
load_param(&opll_accm, sizeof(opll_accm));
load_param(&opll_sample, sizeof(opll_sample));
load_param(&opll_cycles, sizeof(opll_cycles));
load_param(&opll_status, sizeof(opll_status));
}
else
#endif
{
load_param(YM2413GetContextPtr(),YM2413GetContextSize());
}
}
bufferptr += psg_context_load(&state[bufferptr]);
@@ -344,30 +562,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-2020 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_ */
+241 -133
View File
@@ -25,7 +25,21 @@ to do:
*/
/** EkeEke (2011): removed multiple chips support, cleaned code & added FM board interface for Genesis Plus GX **/
/************************************************/
/** Modifications for Genesis Plus GX (EkeEke) **/
/************************************************/
/** 2011/xx/xx: removed multiple chips support, cleaned code & added FM board interface **/
/** 2021/04/23: fixed synchronization of carrier/modulator phase reset after channel Key ON (fixes Japanese Master System BIOS music) **/
/** 2021/04/24: fixed intruments ROM (verified on YM2413B die, cf. https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#ym2413_instrument_rom) **/
/** 2021/04/24: fixed EG resolution bits (verified on YM2413B die, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-03-20) **/
/** 2021/04/24: fixed EG dump rate (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-31) **/
/** 2021/04/25: fixed EG behavior for fastest attack rates (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) **/
/** 2021/04/25: fixed EG behavior when SL = 0 (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-24) **/
/** 2021/04/25: improved EG sustain phase transition comparator accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-31) **/
/** 2021/05/04: improved EG increment steps accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-03-20) **/
/** 2021/05/08: improved EG transitions accuracy (verified against https://github.com/nukeykt/Nuked-OPLL/blob/master/opll.c) **/
/** 2021/05/11: improved EG attack phase algorithm accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) **/
/************************************************/
#include "shared.h"
@@ -40,7 +54,7 @@ to do:
#define ENV_LEN (1<<ENV_BITS)
#define ENV_STEP (128.0/ENV_LEN)
#define MAX_ATT_INDEX ((1<<(ENV_BITS-2))-1) /*255*/
#define MAX_ATT_INDEX ((1<<(ENV_BITS-3))-1) /*127*/
#define MIN_ATT_INDEX (0)
/* sinwave entries */
@@ -219,67 +233,100 @@ static const UINT32 sl_tab[16]={
#undef SC
#define RATE_STEPS (8)
static const unsigned char eg_inc[15*RATE_STEPS]={
#define RATE_STEPS (16)
/*cycle:0 1 2 3 4 5 6 7*/
static const unsigned char eg_inc[14*RATE_STEPS]={
/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */
/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */
/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */
/*cycle:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */
/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */
/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */
/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */
/* 0 */ 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, /* infinity rates for decay(s) */
/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */
/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */
/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */
/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */
/* 1 */ 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, /* rates 01..12 0 for decay(s) (increment by 0 or 1) */
/* 2 */ 0,1, 1,1, 0,1, 0,1, 0,1, 1,1, 0,1, 0,1, /* rates 01..12 1 for decay(s) */
/* 3 */ 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, /* rates 01..12 2 for decay(s) */
/* 4 */ 0,1, 1,1, 1,1, 1,1, 0,1, 1,1, 1,1, 1,1, /* rates 01..12 3 for decay(s) */
/* 5 */ 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, /* rate 13 0 for decay(s) (increment by 0 or 1) */
/* 6 */ 0,1, 0,1, 1,1, 1,1, 0,1, 0,1, 0,1, 0,1, /* rate 13 1 for decay(s) */
/* 7 */ 0,1, 0,1, 1,1, 1,1, 0,1, 0,1, 1,1, 1,1, /* rate 13 2 for decay(s) */
/* 8 */ 0,1, 0,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, /* rate 13 3 for decay(s) */
/* 9 */ 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, /* rate 14 0 for decay(s) (increment by 1) */
/*10 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 1,1, 1,1, /* rate 14 1 for decay(s) */
/*11 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 2,2, 2,2, /* rate 14 2 for decay(s) */
/*12 */ 1,1, 1,1, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rate 14 3 for decay(s) */
/*13 */ 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rates 15 0, 15 1, 15 2, 15 3 for decay(s) (increment by 2) */
/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */
/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */
/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
};
static const unsigned char eg_mul[17*RATE_STEPS]={
/*cycle:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
/* 0 */ 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack */
/* 1 */ 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, /* rates 01..11 0 for attack */
/* 2 */ 0,1, 1,1, 0,1, 0,1, 0,1, 1,1, 0,1, 0,1, /* rates 01..11 1 for attack */
/* 3 */ 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, /* rates 01..11 2 for attack */
/* 4 */ 0,1, 1,1, 1,1, 1,1, 0,1, 1,1, 1,1, 1,1, /* rates 01..11 3 for attack */
/* 5 */ 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, /* rate 12 0 for attack */
/* 6 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 1,1, 1,1, /* rate 12 1 for attack */
/* 7 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 2,2, 2,2, /* rate 12 2 for attack */
/* 8 */ 1,1, 1,1, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rate 12 3 for attack */
/* 9 */ 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rate 13 0 for attack */
/*10 */ 2,2, 2,2, 4,4, 4,4, 2,2, 2,2, 2,2, 2,2, /* rate 13 1 for attack */
/*11 */ 2,2, 2,2, 4,4, 4,4, 2,2, 2,2, 4,4, 4,4, /* rate 13 2 for attack */
/*12 */ 2,2, 2,2, 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, /* rate 13 3 for attack */
/*13 */ 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, /* rate 14 0 for attack */
/*14 */ 4,4, 4,4, 8,8, 8,8, 4,4, 4,4, 4,4, 4,4, /* rate 14 1 for attack */
/*15 */ 4,4, 4,4, 8,8, 8,8, 4,4, 4,4, 8,8, 8,8, /* rate 14 2 for attack */
/*16 */ 4,4, 4,4, 8,8, 8,8, 8,8, 8,8, 8,8, 8,8, /* rate 14 3 for attack */
};
#define O(a) (a*RATE_STEPS)
/*note that there is no O(13) in this table - it's directly in the code */
static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
/* 16 infinite time rates */
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
/* rates 00-12 */
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
O( 0),O( 1),O( 2),O( 3),
/* rate 00 */
O( 0),O( 0),O( 0),O( 0), /* never used since infinite time rates are directly forced in the code for rate 00 */
/* rate 13 */
O( 4),O( 5),O( 6),O( 7),
/* rates 01-11 */
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
O( 1),O( 2),O( 3),O( 4),
/* rate 14 */
O( 8),O( 9),O(10),O(11),
/* rate 12 */ /* only used for decay(s), handled directly in the code for attack */
O( 1),O( 2),O( 3),O( 4),
/* rate 15 */
O(12),O(12),O(12),O(12),
/* rate 13 */ /* only used for decay(s), handled directly in the code for attack */
O( 5),O( 6),O( 7),O( 8),
/* rate 14 */ /* only used for decay(s), handled directly in the code for attack */
O( 9),O(10),O(11),O(12),
/* rate 15 */ /* only used for decay(s), handled directly in the code for attack */
O(13),O(13),O(13),O(13),
/* 16 dummy rates (same as 15 3) */
O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
};
#undef O
@@ -287,15 +334,19 @@ O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
/*shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 */
/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */
/*NB: for attack, above mask values lower 2 bits are cleared and rate 12 shift value is equal to 0 */
#define O(a) (a*1)
static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
/* 16 infinite time rates */
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
/* rates 00-12 */
O(13),O(13),O(13),O(13),
/* 16 infinite time rates */
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
/* rate 00 */
O(13),O(13),O(13),O(13), /* never used since infinite time rates are directly forced in the code for rate 00 */
/* rates 01-11 */
O(12),O(12),O(12),O(12),
O(11),O(11),O(11),O(11),
O(10),O(10),O(10),O(10),
@@ -307,15 +358,17 @@ O( 5),O( 5),O( 5),O( 5),
O( 4),O( 4),O( 4),O( 4),
O( 3),O( 3),O( 3),O( 3),
O( 2),O( 2),O( 2),O( 2),
/* rate 12 */ /* only used for decay(s), handled directly in the code for attack */
O( 1),O( 1),O( 1),O( 1),
/* rate 13 */
/* rate 13 */ /* only used for decay(s), handled directly in the code for attack */
O( 0),O( 0),O( 0),O( 0),
/* rate 14 */
/* rate 14 */ /* only used for decay(s), handled directly in the code for attack */
O( 0),O( 0),O( 0),O( 0),
/* rate 15 */
/* rate 15 */ /* only used for decay(s), handled directly in the code for attack */
O( 0),O( 0),O( 0),O( 0),
/* 16 dummy rates (same as 15 3) */
@@ -455,45 +508,71 @@ static const INT8 lfo_pm_table[8*8] = {
- LFO PM and AM enable are 100% correct
- waveform DC and DM select are 100% correct
*/
/* 2021/04/23: corrected with values extracted from YM2413 instrument ROM, cf. https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#ym2413_instrument_rom */
static unsigned char table[19][8] = {
/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */
/* 0 1 2 3 4 5 6 7 */
{0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, /* 0 */
/*{0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, */ /* 0 */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 0 */
{0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, /* 1 */
{0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, /* 2 */
{0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, /* 3 */
{0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, /* 4 */
/*{0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, */ /* 1 */
{0x71, 0x61, 0x1e, 0x17, 0xd0, 0x78, 0x00, 0x17 }, /* 1 */
/*{0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, */ /* 2 */
{0x13, 0x41, 0x1a, 0x0d, 0xd8, 0xf7, 0x23, 0x13 }, /* 2 */
/*{0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, */ /* 3 */
{0x13, 0x01, 0x99, 0x00, 0xf2, 0xc4, 0x11, 0x23 }, /* 3 */
/*{0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, */ /* 4 */
{0x31, 0x61, 0x0e, 0x07, 0xa8, 0x64, 0x70, 0x27 }, /* 4 */
/*{0x22, 0x21, 0x1e, 0x09, 0xf0, 0x76, 0x08, 0x28 }, */ /* 5 */
{0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, /* 5 */
/*{0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, */ /* 5 */
{0x32, 0x21, 0x1e, 0x06, 0xe0, 0x76, 0x00, 0x28 }, /* 5 */
/*{0x31, 0x22, 0x16, 0x09, 0x90, 0x7f, 0x00, 0x08 }, */ /* 6 */
{0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, /* 6 */
/*{0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, */ /* 6 */
{0x31, 0x22, 0x16, 0x05, 0xe0, 0x71, 0x00, 0x18 }, /* 6 */
{0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, /* 7 */
{0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, /* 8 */
{0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, /* 9 */
/*{0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, */ /* 7 */
{0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x10, 0x07 }, /* 7 */
/* {0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, */ /* A */
{0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, /* A */
/*{0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, */ /* 8 */
{0x23, 0x21, 0x2d, 0x14, 0xa2, 0x72, 0x00, 0x07 }, /* 8 */
{0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, /* B */
{0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, /* C */
{0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, /* 9 */
/* {0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, */ /* D */
{0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, /* D */
/*{0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, */ /* A */
/*{0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, */ /* A */
{0x41, 0x61, 0x0b, 0x18, 0x85, 0xf7, 0x71, 0x07 }, /* A */
{0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, /* E */
{0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, /* F */
/*{0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, */ /* B */
{0x13, 0x01, 0x83, 0x11, 0xfa, 0xe4, 0x10, 0x04 }, /* B */
/*{0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, */ /* C */
{0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12 }, /* C */
/*{0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, */ /* D */
/*{0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, */ /* D */
{0x61, 0x50, 0x0c, 0x05, 0xc2, 0xf5, 0x20, 0x42 }, /* D */
/*{0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, */ /* E */
{0x01, 0x01, 0x55, 0x03, 0xc9, 0x95, 0x03, 0x02 }, /* E */
/*{0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, */ /* F */
{0x61, 0x41, 0x89, 0x03, 0xf1, 0xe4, 0x40, 0x13 }, /* F */
/* drum instruments definitions */
/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */
/* 0 1 2 3 4 5 6 7 */
{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */
{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
/*{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },*/ /* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
/*{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },*/ /* HH(multi verified), SD(multi not used) */
/*{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },*/ /* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
{0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d }, /* BD */
{0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x48 }, /* HH, SD */
{0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55 } /* TOM, TOP CYM */
};
static signed int output[2];
@@ -542,47 +621,55 @@ INLINE void advance(void)
switch(op->state)
{
case EG_DMP: /* dump phase */
/*dump phase is performed by both operators in each channel*/
/*when CARRIER envelope gets down to zero level,
** phases in BOTH opearators are reset (at the same time ?)
*/
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dp)-1) ) )
case EG_DMP: /* dump phase */
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
{
op->volume += eg_inc[op->eg_sel_dp + ((ym2413.eg_cnt>>op->eg_sh_dp)&7)];
op->state = EG_ATT;
if ( op->volume >= MAX_ATT_INDEX )
/* force envelope to zero when attack rate is set to 15.0-15.3 */
if ((op->ar + op->ksr) >= 16+60)
{
op->volume = MAX_ATT_INDEX;
op->state = EG_ATT;
/* restart Phase Generator */
op->phase = 0;
op->volume = MIN_ATT_INDEX;
}
/*dump phase is performed by both operators in each channel*/
/*when CARRIER envelope gets down to zero level,
*phases in BOTH operators are reset (at the same time ?)
*/
if (i&1)
{
CH->SLOT[0].phase = CH->SLOT[1].phase = 0;
}
}
else if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dp)-1) ) )
{
op->volume += eg_inc[op->eg_sel_dp + ((ym2413.eg_cnt>>op->eg_sh_dp)&15)];
}
break;
case EG_ATT: /* attack phase */
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_ar)-1) ) )
case EG_ATT: /* attack phase */
if (op->volume == MIN_ATT_INDEX)
{
op->volume += (~op->volume *
(eg_inc[op->eg_sel_ar + ((ym2413.eg_cnt>>op->eg_sh_ar)&7)])
) >>2;
if (op->volume <= MIN_ATT_INDEX)
{
op->volume = MIN_ATT_INDEX;
op->state = EG_DEC;
}
op->state = EG_DEC;
}
else if ( !(ym2413.eg_cnt & (((1<<op->eg_sh_ar)-1) & ~3)) )
{
op->volume += (~op->volume * (eg_mul[op->eg_sel_ar + ((ym2413.eg_cnt>>op->eg_sh_ar)&15)]))>>4;
}
break;
case EG_DEC: /* decay phase */
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
if ( (op->volume & ~7) == op->sl ) /* envelope level lowest 3 bits are ignored by the comparator */
{
op->volume += eg_inc[op->eg_sel_dr + ((ym2413.eg_cnt>>op->eg_sh_dr)&7)];
if ( op->volume >= op->sl )
op->state = EG_SUS;
op->state = EG_SUS;
}
else if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
{
op->volume += eg_inc[op->eg_sel_dr + ((ym2413.eg_cnt>>op->eg_sh_dr)&15)];
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
{
op->state = EG_OFF;
}
}
break;
@@ -591,19 +678,20 @@ INLINE void advance(void)
one can change percusive/non-percussive modes on the fly and
the chip will remain in sustain phase - verified on real YM3812 */
if(op->eg_type) /* non-percussive mode (sustained tone) */
if (op->eg_type) /* non-percussive mode (sustained tone) */
{
/* do nothing */
}
else /* percussive mode */
else /* percussive mode */
{
/* during sustain phase chip adds Release Rate (in percussive mode) */
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
{
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&7)];
if ( op->volume >= MAX_ATT_INDEX )
op->volume = MAX_ATT_INDEX;
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&15)];
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
{
op->state = EG_OFF;
}
}
/* else do nothing in sustain phase */
}
@@ -629,7 +717,7 @@ INLINE void advance(void)
*/
if ( (i&1) || ((ym2413.rhythm&0x20) && (i>=12)) )/* exclude modulators */
{
if(op->eg_type) /* non-percussive mode (sustained tone) */
if (op->eg_type) /* non-percussive mode (sustained tone) */
/*this is correct: use RR when SUS = OFF*/
/*and use RS when SUS = ON*/
{
@@ -637,10 +725,9 @@ INLINE void advance(void)
{
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rs)-1) ) )
{
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&7)];
if ( op->volume >= MAX_ATT_INDEX )
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&15)];
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
{
op->volume = MAX_ATT_INDEX;
op->state = EG_OFF;
}
}
@@ -649,23 +736,21 @@ INLINE void advance(void)
{
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
{
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&7)];
if ( op->volume >= MAX_ATT_INDEX )
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&15)];
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
{
op->volume = MAX_ATT_INDEX;
op->state = EG_OFF;
}
}
}
}
else /* percussive mode */
else /* percussive mode */
{
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rs)-1) ) )
{
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&7)];
if ( op->volume >= MAX_ATT_INDEX )
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&15)];
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
{
op->volume = MAX_ATT_INDEX;
op->state = EG_OFF;
}
}
@@ -673,8 +758,12 @@ INLINE void advance(void)
}
break;
default:
break;
case EG_OFF: /* envelope off */
op->volume = MAX_ATT_INDEX;
break;
default:
break;
}
}
}
@@ -1142,21 +1231,30 @@ INLINE void CALC_FCSLOT(YM2413_OPLL_CH *CH,YM2413_OPLL_SLOT *SLOT)
SLOT->ksr = ksr;
/* calculate envelope generator rates */
if ((SLOT->ar + SLOT->ksr) < 16+62)
if ((SLOT->ar + SLOT->ksr) >= 16+60)
{
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
/* attack phase is skipped in case attack rate is set to 15.0-15.3 before attack phase is started */
/* during attack phase, in case attack rate is changed to 15.0-15.3, attack phase is blocked */
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
SLOT->eg_sh_ar = 13;
SLOT->eg_sel_ar = 0 * RATE_STEPS;
}
else
else if ((SLOT->ar + SLOT->ksr) >= 16+48)
{
/* attack rates 12.0 to 14.3 have similar specific behavior */
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
SLOT->eg_sh_ar = 0;
SLOT->eg_sel_ar = 13*RATE_STEPS;
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr] + (4 * RATE_STEPS);
}
else
{
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr];
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr];
}
SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
}
if (CH->sus)
@@ -1167,7 +1265,7 @@ INLINE void CALC_FCSLOT(YM2413_OPLL_CH *CH,YM2413_OPLL_SLOT *SLOT)
SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ];
SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ];
SLOT_dp = 16 + (13<<2);
SLOT_dp = 16 + (12<<2);
SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ];
SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ];
}
@@ -1225,15 +1323,25 @@ INLINE void set_ar_dr(int slot,int v)
SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0;
if ((SLOT->ar + SLOT->ksr) < 16+62)
if ((SLOT->ar + SLOT->ksr) >= 16+60)
{
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
/* attack phase is skipped in case attack rate is set to 15.0-15.3 before attack phase is started */
/* during attack phase, in case attack rate is changed to 15.0-15.3, attack phase is blocked */
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
SLOT->eg_sh_ar = 13;
SLOT->eg_sel_ar = 0 * RATE_STEPS;
}
else
else if ((SLOT->ar + SLOT->ksr) >= 16+48)
{
/* attack rates 12.0 to 14.3 have similar specific behavior */
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
SLOT->eg_sh_ar = 0;
SLOT->eg_sel_ar = 13*RATE_STEPS;
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr] + (4 * RATE_STEPS);
}
else
{
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr];
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr];
}
SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
+116 -49
View File
@@ -15,15 +15,19 @@
** 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:
**
** 11-05-2021 Eke-Eke (Genesis Plus GX):
** - fixed potential issue with SSG-EG inverted attenuation level on Key OFF
**
** 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 +630,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 )
@@ -680,7 +687,7 @@ INLINE void FM_KEYOFF(FM_CH *CH , int s )
{
/* convert EG attenuation level */
if (SLOT->ssgn ^ (SLOT->ssg&0x04))
SLOT->volume = (0x200 - SLOT->volume);
SLOT->volume = (0x200 - SLOT->volume) & MAX_ATT_INDEX;
/* force EG attenuation level */
if (SLOT->volume >= 0x200)
@@ -745,7 +752,7 @@ INLINE void FM_KEYOFF_CSM(FM_CH *CH , int s )
{
/* convert EG attenuation level */
if (SLOT->ssgn ^ (SLOT->ssg&0x04))
SLOT->volume = (0x200 - SLOT->volume);
SLOT->volume = (0x200 - SLOT->volume) & MAX_ATT_INDEX;
/* force EG attenuation level */
if (SLOT->volume >= 0x200)
@@ -1408,22 +1415,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 +1440,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 +1451,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 +1467,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 +1522,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 +1557,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 +1692,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 +1726,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 +1741,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 +1751,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 +1888,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 +1997,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 +2033,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 +2079,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 +2107,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 +2157,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);
+78 -62
View File
@@ -1,6 +1,6 @@
#ifdef HAVE_YM3438_CORE
/*
* Copyright (C) 2017 Alexey Khokholov (Nuke.YKT)
* Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -40,7 +40,7 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.7
* version: 1.0.10
*/
#include <string.h>
@@ -233,9 +233,9 @@ 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)
static void OPN2_DoIO(ym3438_t *chip)
{
/* Write signal check */
chip->write_a_en = (chip->write_a & 0x03) == 0x01;
@@ -249,10 +249,10 @@ void OPN2_DoIO(ym3438_t *chip)
chip->write_busy_cnt &= 0x1f;
}
void OPN2_DoRegWrite(ym3438_t *chip)
static void OPN2_DoRegWrite(ym3438_t *chip)
{
Bit32u i;
Bit32u slot = chip->slot % 12;
Bit32u slot = chip->cycles % 12;
Bit32u address;
Bit32u channel = chip->channel;
/* Update registers */
@@ -379,7 +379,7 @@ void OPN2_DoRegWrite(ym3438_t *chip)
/* Data */
if (chip->write_d_en && (chip->write_data & 0x100) == 0)
{
switch (chip->address)
switch (chip->write_fm_mode_a)
{
case 0x21: /* LSI test 1 */
for (i = 0; i < 8; i++)
@@ -458,7 +458,7 @@ void OPN2_DoRegWrite(ym3438_t *chip)
/* Address */
if (chip->write_a_en)
{
chip->write_fm_mode_a = chip->write_data & 0xff;
chip->write_fm_mode_a = chip->write_data & 0x1ff;
}
}
@@ -468,16 +468,18 @@ void OPN2_DoRegWrite(ym3438_t *chip)
}
}
void OPN2_PhaseCalcIncrement(ym3438_t *chip)
static void OPN2_PhaseCalcIncrement(ym3438_t *chip)
{
Bit32u chan = chip->channel;
Bit32u slot = chip->cycles;
Bit32u fnum = chip->pg_fnum;
Bit32u fnum_h = fnum >> 4;
Bit32u fm;
Bit32u basefreq;
Bit8u lfo = chip->lfo_pm;
Bit8u lfo_l = lfo & 0x0f;
Bit8u pms = chip->pms[chip->channel];
Bit8u dt = chip->dt[chip->slot];
Bit8u pms = chip->pms[chan];
Bit8u dt = chip->dt[slot];
Bit8u dt_l = dt & 0x03;
Bit8u detune = 0;
Bit8u block, note;
@@ -531,32 +533,32 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip)
basefreq += detune;
}
basefreq &= 0x1ffff;
chip->pg_inc[chip->slot] = (basefreq * chip->multi[chip->slot]) >> 1;
chip->pg_inc[chip->slot] &= 0xfffff;
chip->pg_inc[slot] = (basefreq * chip->multi[slot]) >> 1;
chip->pg_inc[slot] &= 0xfffff;
}
void OPN2_PhaseGenerate(ym3438_t *chip)
static void OPN2_PhaseGenerate(ym3438_t *chip)
{
Bit32u slot;
/* Mask increment */
slot = (chip->slot + 20) % 24;
slot = (chip->cycles + 20) % 24;
if (chip->pg_reset[slot])
{
chip->pg_inc[slot] = 0;
}
/* Phase step */
slot = (chip->slot + 19) % 24;
chip->pg_phase[slot] += chip->pg_inc[slot];
chip->pg_phase[slot] &= 0xfffff;
slot = (chip->cycles + 19) % 24;
if (chip->pg_reset[slot] || chip->mode_test_21[3])
{
chip->pg_phase[slot] = 0;
}
chip->pg_phase[slot] += chip->pg_inc[slot];
chip->pg_phase[slot] &= 0xfffff;
}
void OPN2_EnvelopeSSGEG(ym3438_t *chip)
static void OPN2_EnvelopeSSGEG(ym3438_t *chip)
{
Bit32u slot = chip->slot;
Bit32u slot = chip->cycles;
Bit8u direction = 0;
chip->eg_ssg_pgrst_latch[slot] = 0;
chip->eg_ssg_repeat_latch[slot] = 0;
@@ -601,9 +603,9 @@ void OPN2_EnvelopeSSGEG(ym3438_t *chip)
chip->eg_ssg_enable[slot] = (chip->ssg_eg[slot] >> 3) & 0x01;
}
void OPN2_EnvelopeADSR(ym3438_t *chip)
static void OPN2_EnvelopeADSR(ym3438_t *chip)
{
Bit32u slot = (chip->slot + 22) % 24;
Bit32u slot = (chip->cycles + 22) % 24;
Bit8u nkon = chip->eg_kon_latch[slot];
Bit8u okon = chip->eg_kon[slot];
@@ -725,12 +727,12 @@ void OPN2_EnvelopeADSR(ym3438_t *chip)
chip->eg_state[slot] = nextstate;
}
void OPN2_EnvelopePrepare(ym3438_t *chip)
static void OPN2_EnvelopePrepare(ym3438_t *chip)
{
Bit8u rate;
Bit8u sum;
Bit8u inc = 0;
Bit32u slot = chip->slot;
Bit32u slot = chip->cycles;
Bit8u rate_sel;
/* Prepare increment */
@@ -813,9 +815,9 @@ void OPN2_EnvelopePrepare(ym3438_t *chip)
chip->eg_sl[0] = chip->sl[slot];
}
void OPN2_EnvelopeGenerate(ym3438_t *chip)
static void OPN2_EnvelopeGenerate(ym3438_t *chip)
{
Bit32u slot = (chip->slot + 23) % 24;
Bit32u slot = (chip->cycles + 23) % 24;
Bit16u level;
level = chip->eg_level[slot];
@@ -846,7 +848,7 @@ void OPN2_EnvelopeGenerate(ym3438_t *chip)
chip->eg_out[slot] = level;
}
void OPN2_UpdateLFO(ym3438_t *chip)
static void OPN2_UpdateLFO(ym3438_t *chip)
{
if ((chip->lfo_quotient & lfo_cycles[chip->lfo_freq]) == lfo_cycles[chip->lfo_freq])
{
@@ -860,14 +862,14 @@ void OPN2_UpdateLFO(ym3438_t *chip)
chip->lfo_cnt &= chip->lfo_en;
}
void OPN2_FMPrepare(ym3438_t *chip)
static void OPN2_FMPrepare(ym3438_t *chip)
{
Bit32u slot = (chip->slot + 6) % 24;
Bit32u slot = (chip->cycles + 6) % 24;
Bit32u channel = chip->channel;
Bit16s mod, mod1, mod2;
Bit32u op = slot / 6;
Bit8u connect = chip->connect[channel];
Bit32u prevslot = (chip->slot + 18) % 24;
Bit32u prevslot = (chip->cycles + 18) % 24;
/* Calculate modulation */
mod1 = mod2 = 0;
@@ -908,7 +910,7 @@ void OPN2_FMPrepare(ym3438_t *chip)
}
chip->fm_mod[slot] = mod;
slot = (chip->slot + 18) % 24;
slot = (chip->cycles + 18) % 24;
/* OP1 */
if (slot / 6 == 0)
{
@@ -922,9 +924,9 @@ void OPN2_FMPrepare(ym3438_t *chip)
}
}
void OPN2_ChGenerate(ym3438_t *chip)
static void OPN2_ChGenerate(ym3438_t *chip)
{
Bit32u slot = (chip->slot + 18) % 24;
Bit32u slot = (chip->cycles + 18) % 24;
Bit32u channel = chip->channel;
Bit32u op = slot / 6;
Bit32u test_dac = chip->mode_test_2c[5];
@@ -957,16 +959,17 @@ void OPN2_ChGenerate(ym3438_t *chip)
chip->ch_acc[channel] = sum;
}
void OPN2_ChOutput(ym3438_t *chip)
static void OPN2_ChOutput(ym3438_t *chip)
{
Bit32u cycles = chip->cycles;
Bit32u slot = chip->cycles;
Bit32u channel = chip->channel;
Bit32u test_dac = chip->mode_test_2c[5];
Bit16s out;
Bit16s sign;
Bit32u out_en;
chip->ch_read = chip->ch_lock;
if (chip->slot < 12)
if (slot < 12)
{
/* Ch 4,5,6 */
channel++;
@@ -995,7 +998,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 +1031,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;
@@ -1044,9 +1042,9 @@ void OPN2_ChOutput(ym3438_t *chip)
}
}
void OPN2_FMGenerate(ym3438_t *chip)
static void OPN2_FMGenerate(ym3438_t *chip)
{
Bit32u slot = (chip->slot + 19) % 24;
Bit32u slot = (chip->cycles + 19) % 24;
/* Calculate phase */
Bit16u phase = (chip->fm_mod[slot] + (chip->pg_phase[slot] >> 10)) & 0x3ff;
Bit16u quarter;
@@ -1082,7 +1080,7 @@ void OPN2_FMGenerate(ym3438_t *chip)
chip->fm_out[slot] = output;
}
void OPN2_DoTimerA(ym3438_t *chip)
static void OPN2_DoTimerA(ym3438_t *chip)
{
Bit16u time;
Bit8u load;
@@ -1131,7 +1129,7 @@ void OPN2_DoTimerA(ym3438_t *chip)
chip->timer_a_cnt = time & 0x3ff;
}
void OPN2_DoTimerB(ym3438_t *chip)
static void OPN2_DoTimerB(ym3438_t *chip)
{
Bit16u time;
Bit8u load;
@@ -1176,27 +1174,29 @@ void OPN2_DoTimerB(ym3438_t *chip)
chip->timer_b_cnt = time & 0xff;
}
void OPN2_KeyOn(ym3438_t*chip)
static void OPN2_KeyOn(ym3438_t*chip)
{
Bit32u slot = chip->cycles;
Bit32u chan = chip->channel;
/* Key On */
chip->eg_kon_latch[chip->slot] = chip->mode_kon[chip->slot];
chip->eg_kon_csm[chip->slot] = 0;
chip->eg_kon_latch[slot] = chip->mode_kon[slot];
chip->eg_kon_csm[slot] = 0;
if (chip->channel == 2 && chip->mode_kon_csm)
{
/* CSM Key On */
chip->eg_kon_latch[chip->slot] = 1;
chip->eg_kon_csm[chip->slot] = 1;
chip->eg_kon_latch[slot] = 1;
chip->eg_kon_csm[slot] = 1;
}
if (chip->cycles == chip->mode_kon_channel)
{
/* OP1 */
chip->mode_kon[chip->channel] = chip->mode_kon_operator[0];
chip->mode_kon[chan] = chip->mode_kon_operator[0];
/* OP2 */
chip->mode_kon[chip->channel + 12] = chip->mode_kon_operator[1];
chip->mode_kon[chan + 12] = chip->mode_kon_operator[1];
/* OP3 */
chip->mode_kon[chip->channel + 6] = chip->mode_kon_operator[2];
chip->mode_kon[chan + 6] = chip->mode_kon_operator[2];
/* OP4 */
chip->mode_kon[chip->channel + 18] = chip->mode_kon_operator[3];
chip->mode_kon[chan + 18] = chip->mode_kon_operator[3];
}
}
@@ -1223,8 +1223,9 @@ void OPN2_SetChipType(Bit32u type)
chip_type = type;
}
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
{
Bit32u slot = chip->cycles;
chip->lfo_inc = chip->mode_test_21[1];
chip->pg_read >>= 1;
chip->eg_read[1] >>= 1;
@@ -1315,7 +1316,7 @@ void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
if (chip->mode_ch3)
{
/* Channel 3 special mode */
switch (chip->slot)
switch (slot)
{
case 1: /* OP1 */
chip->pg_fnum = chip->fnum_3ch[1];
@@ -1350,11 +1351,13 @@ void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
OPN2_UpdateLFO(chip);
OPN2_DoRegWrite(chip);
chip->cycles = (chip->cycles + 1) % 24;
chip->slot = chip->cycles;
chip->channel = chip->cycles % 6;
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,11 +1397,12 @@ 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])
{
/* Read test data */
Bit32u slot = (chip->cycles + 18) % 24;
Bit16u testdata = ((chip->pg_read & 0x01) << 15)
| ((chip->eg_read[chip->mode_test_21[0]] & 0x01) << 14);
if (chip->mode_test_2c[4])
@@ -1407,22 +1411,34 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
}
else
{
testdata |= chip->fm_out[(chip->slot + 18) % 24] & 0x3fff;
testdata |= chip->fm_out[slot] & 0x3fff;
}
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;
}
+21 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Alexey Khokholov (Nuke.YKT)
* Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -39,16 +39,19 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.7
* version: 1.0.9
*/
#ifndef YM3438_H
#define YM3438_H
#ifdef __cplusplus
extern "C" {
#endif
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>
@@ -67,7 +70,6 @@ typedef int8_t Bit8s;
typedef struct
{
Bit32u cycles;
Bit32u slot;
Bit32u channel;
Bit16s mol, mor;
/* IO */
@@ -80,7 +82,7 @@ typedef struct
Bit8u write_busy_cnt;
Bit8u write_fm_address;
Bit8u write_fm_data;
Bit8u write_fm_mode_a;
Bit16u write_fm_mode_a;
Bit16u address;
Bit8u data;
Bit8u pin_test_in;
@@ -156,7 +158,7 @@ typedef struct
Bit8u timer_a_load_latch;
Bit8u timer_a_overflow_flag;
Bit8u timer_a_overflow;
Bit16u timer_b_cnt;
Bit8u timer_b_subcnt;
Bit16u timer_b_reg;
@@ -167,7 +169,7 @@ typedef struct
Bit8u timer_b_load_latch;
Bit8u timer_b_overflow_flag;
Bit8u timer_b_overflow;
/* Register set */
Bit8u mode_test_21[8];
Bit8u mode_test_2c[8];
@@ -179,7 +181,7 @@ typedef struct
Bit8u mode_kon_csm;
Bit8u dacen;
Bit16s dacdata;
Bit8u ks[24];
Bit8u ar[24];
Bit8u sr[24];
@@ -191,7 +193,7 @@ typedef struct
Bit8u am[24];
Bit8u tl[24];
Bit8u ssg_eg[24];
Bit16u fnum[6];
Bit8u block[6];
Bit8u kcode[6];
@@ -205,14 +207,21 @@ 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);
Bit32u OPN2_ReadIRQPin(ym3438_t *chip);
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port);
#ifdef __cplusplus
}
#endif
#endif
+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 */
+8 -3
View File
@@ -28,14 +28,17 @@ typedef struct
uint8 padtype;
} t_input_config;
struct
typedef struct
{
char version[16];
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;
@@ -59,7 +62,7 @@ struct
uint8 lcd;
uint8 render;
t_input_config input[MAX_INPUTS];
} config;
} t_config;
extern char GG_ROM[256];
extern char AR_ROM[256];
@@ -73,6 +76,8 @@ extern char MS_BIOS_US[256];
extern char MS_BIOS_EU[256];
extern char MS_BIOS_JP[256];
extern t_config config;
void osd_input_update(void);
int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension);
extern void ROMCheatUpdate(void);
+2 -2
View File
@@ -1,7 +1,7 @@
#ifndef _S_CRC32_H
#define _S_CRC32_H
static const unsigned long crc_table[256] = {
static const unsigned int crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
@@ -61,7 +61,7 @@ static const unsigned long crc_table[256] = {
#define DO4_CRC32(buf) DO2_CRC32(buf); DO2_CRC32(buf);
#define DO8_CRC32(buf) DO4_CRC32(buf); DO4_CRC32(buf);
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len)
unsigned int crc32(unsigned int crc, const unsigned char *buf, unsigned int len)
{
if (buf == 0) return 0L;
crc = crc ^ 0xffffffffL;
+1 -1
View File
@@ -1,6 +1,6 @@
#ifndef _S_CRC32_H
#define _S_CRC32_H
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len);
unsigned int crc32(unsigned int crc, const unsigned char *buf, unsigned int len);
#endif