Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ebf7e57eb | |||
| 576e14d64c | |||
| 95b9099b3e | |||
| 90c519eb1e | |||
| 779baa7fca | |||
| 4f13fea4e2 | |||
| 17f423cfbd | |||
| 975a3e3266 | |||
| 17788c3ddd | |||
| 15af996d79 | |||
| 2c0279c0ac | |||
| 6863200707 | |||
| 35889724f4 | |||
| 41577e1fa5 | |||
| 02499a735b | |||
| 2875815a60 | |||
| f1828430d3 | |||
| 682625653b | |||
| 38c438243e | |||
| 25933fefad | |||
| 20a3b05782 | |||
| c5df0565e6 | |||
| c06e10d458 | |||
| 0419c81f9e |
Binary file not shown.
+175
-64
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 */
|
||||
@@ -0,0 +1,91 @@
|
||||
/***************************************************************************************
|
||||
* Genesis Plus GX
|
||||
* CPU hooking support
|
||||
*
|
||||
* HOOK_CPU should be defined in a makefile or MSVC project to enable this functionality
|
||||
*
|
||||
* Copyright DrMefistO (2018-2019)
|
||||
*
|
||||
* Copyright feos (2019)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions may not be sold, nor may they be used in a commercial
|
||||
* product or activity.
|
||||
*
|
||||
* - Redistributions that are modified from the original source must include the
|
||||
* complete source code, including the source code for all components used by a
|
||||
* binary built from the modified sources. However, as a special exception, the
|
||||
* source code distributed need not include anything that is normally distributed
|
||||
* (in either source or binary form) with the major components (compiler, kernel,
|
||||
* and so on) of the operating system on which the executable runs, unless that
|
||||
* component itself accompanies the executable.
|
||||
*
|
||||
* - Redistributions must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef _CPUHOOK_H_
|
||||
#define _CPUHOOK_H_
|
||||
|
||||
|
||||
typedef enum {
|
||||
HOOK_ANY = (0 << 0),
|
||||
|
||||
// M68K
|
||||
HOOK_M68K_E = (1 << 0),
|
||||
HOOK_M68K_R = (1 << 1),
|
||||
HOOK_M68K_W = (1 << 2),
|
||||
HOOK_M68K_RW = HOOK_M68K_R | HOOK_M68K_W,
|
||||
|
||||
// VDP
|
||||
HOOK_VRAM_R = (1 << 3),
|
||||
HOOK_VRAM_W = (1 << 4),
|
||||
HOOK_VRAM_RW = HOOK_VRAM_R | HOOK_VRAM_W,
|
||||
|
||||
HOOK_CRAM_R = (1 << 5),
|
||||
HOOK_CRAM_W = (1 << 6),
|
||||
HOOK_CRAM_RW = HOOK_CRAM_R | HOOK_CRAM_W,
|
||||
|
||||
HOOK_VSRAM_R = (1 << 7),
|
||||
HOOK_VSRAM_W = (1 << 8),
|
||||
HOOK_VSRAM_RW = HOOK_VSRAM_R | HOOK_VSRAM_W,
|
||||
|
||||
// Z80
|
||||
HOOK_Z80_E = (1 << 9),
|
||||
HOOK_Z80_R = (1 << 10),
|
||||
HOOK_Z80_W = (1 << 11),
|
||||
HOOK_Z80_RW = HOOK_Z80_R | HOOK_Z80_W,
|
||||
|
||||
// REGS
|
||||
HOOK_VDP_REG = (1 << 12),
|
||||
HOOK_M68K_REG = (1 << 13),
|
||||
} hook_type_t;
|
||||
|
||||
|
||||
/* CPU hook is called on read, write, and execute.
|
||||
*/
|
||||
void (*cpu_hook)(hook_type_t type, int width, unsigned int address, unsigned int value);
|
||||
|
||||
/* Use set_cpu_hook() to assign a callback that can process the data provided
|
||||
* by cpu_hook().
|
||||
*/
|
||||
void set_cpu_hook(void(*hook)(hook_type_t type, int width, unsigned int address, unsigned int value));
|
||||
|
||||
|
||||
#endif /* _CPUHOOK_H_ */
|
||||
@@ -5,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();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
|
||||
#include <setjmp.h>
|
||||
#include "macros.h"
|
||||
#ifdef HOOK_CPU
|
||||
#include "cpuhook.h"
|
||||
#endif
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user