30 Commits

Author SHA1 Message Date
clobber 07de1ad746 Merge pull request #13 from ShutOstrich/master 2023-09-06 18:50:19 -06:00
ShutOstrich 23bc100386 Update to FCEUX 2.6.6 2023-08-27 23:45:32 +02:00
ShutOstrich f2c6ba0c43 Disable all messages 2023-08-27 23:45:26 +02:00
clobber 7e9cde361e Build fix
Now requires a minimum of C++11: Use of undeclared identifier 'nullptr'
2023-06-20 20:07:39 -06:00
clobber ee3ffeeacc Merge pull request #12 from ShutOstrich/master
Update to FCEUX 2.6.5
2023-04-29 20:40:56 -06:00
ShutOstrich 8a1427db5c Update to FCEUX 2.6.5 2023-04-30 00:37:54 +02:00
ShutOstrich 10724c5437 Disable "Reset" message 2023-04-30 00:32:10 +02:00
clobber 88b1044105 Fix -ringBufferAtIndex: deprecation warning. 2022-12-24 17:10:23 -07:00
clobber 1b76eae51e Update to FCEUX 2.6.3 2022-12-16 17:49:38 -07:00
clobber 4db4639569 Update to FCEUX 2.6.2 2022-12-16 17:34:24 -07:00
clobber 1e9dc7ee26 Update to FCEUX 2.6.1 2022-12-16 17:28:16 -07:00
clobber e62374c88d Update to FCEUX 2.6.0 2022-12-16 17:23:14 -07:00
clobber c4ea492891 Update to FCEUX 2.5.0 2022-12-16 16:58:06 -07:00
clobber 4b460d1cb8 Update to FCEUX 2.4.0 2022-12-16 16:44:41 -07:00
clobber 14cfd5c93c Update to FCEUX 2.3.0 2022-12-16 16:32:10 -07:00
C.W. Betts 14a65ab35d Minor Xcode maintenance.
Remove the ~attic directory.
2021-03-22 01:02:58 -06:00
C.W. Betts 46d186d251 Poke the plists: get the development language from Xcode build. 2020-10-01 01:51:37 -06:00
C.W. Betts b1a06da5ba Fix locations of the system plugin headers.
Minor Xcode maintenance.
2020-10-01 01:26:41 -06:00
C.W. Betts 7bd6e5ea8b Update language resources.
This quiets warnings in newer Xcode releases.

Also update framework locations.
2020-01-07 16:36:20 -07:00
clobber 9d79c1a4a5 Bump version for sparkle updater. Core is still 2.2.3 2018-12-08 23:22:48 -06:00
clobber c1271716eb Add support for Raw cheat formats 2018-12-08 23:22:32 -06:00
clobber cd166c0561 Bump version for sparkle updater. Core is still 2.2.3 2018-11-25 16:15:16 -06:00
clobber dd9e1c3cee Cleanup 2018-11-25 16:14:41 -06:00
clobber 28ae039566 Add display mode change support 2018-11-23 00:54:14 -06:00
clobber 33026a6424 Cleanup 2018-11-22 21:11:38 -06:00
clobber 10e4d8fd38 Build fix for latest Clang.
cheat.cpp:219:30: error: ordered comparison between pointer and zero ('char *' and 'int')
2018-04-05 02:11:16 -05:00
clobber 2758d42404 Use -fileSystemRepresentation instead of -UTF8String for file names 2017-08-16 23:42:32 -05:00
Rudy Richter 0fa341d5c1 these should be uint32_t not uint8_t 2017-07-20 20:54:58 -04:00
Rudy Richter 5bfdfc26d4 Use spaces 2017-07-20 08:50:47 -04:00
mrvacbob 22d81842fa Enable direct-rendering 2017-07-20 01:35:09 -07:00
624 changed files with 17263 additions and 142104 deletions
Binary file not shown.
File diff suppressed because it is too large Load Diff
+412 -76
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2015, OpenEmu Team
Copyright (c) 2018, OpenEmu Team
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -41,18 +41,37 @@
extern uint8 *XBuf;
static uint32_t palette[256];
#define OVERSCAN_VERTICAL 8
#define OVERSCAN_HORIZONTAL 8
#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 : @"",}
@interface FCEUGameCore () <OENESSystemResponderClient>
{
uint32_t *videoBuffer;
uint8_t *pXBuf;
int32_t *soundBuffer;
int32_t soundSize;
uint32_t pad;
uint32_t arkanoid[3];
uint32_t zapper[3];
uint32_t hypershot[4];
uint32_t *_videoBuffer;
int32_t *_soundBuffer;
int32_t _soundSize;
uint32_t _pad;
uint32_t _arkanoid[3];
uint32_t _zapper[3];
uint32_t _hypershot[4];
int _videoWidth, _videoHeight;
int _videoOffsetX, _videoOffsetY;
int _aspectWidth, _aspectHeight;
BOOL _isHorzOverscanCropped;
BOOL _isVertOverscanCropped;
NSMutableDictionary<NSString *, NSNumber *> *_cheatList;
NSMutableArray <NSMutableDictionary <NSString *, id> *> *_availableDisplayModes;
}
- (void)loadDisplayModeOptions;
@end
@implementation FCEUGameCore
@@ -63,7 +82,7 @@ static __weak FCEUGameCore *_current;
{
if((self = [super init]))
{
videoBuffer = (uint32_t *)malloc(256 * 240 * 4);
_cheatList = [NSMutableDictionary dictionary];
}
_current = self;
@@ -73,51 +92,51 @@ static __weak FCEUGameCore *_current;
- (void)dealloc
{
free(videoBuffer);
free(_videoBuffer);
}
# pragma mark - Execution
- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error
{
pad = 0;
memset(arkanoid, 0, sizeof(arkanoid));
memset(zapper, 0, sizeof(zapper));
memset(hypershot, 0, sizeof(hypershot));
_pad = 0;
memset(_arkanoid, 0, sizeof(_arkanoid));
memset(_zapper, 0, sizeof(_zapper));
memset(_hypershot, 0, sizeof(_hypershot));
//newppu = 0 default off, set 1 to enable
FCEUI_Initialize();
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
[[NSFileManager defaultManager] createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
//FCEUI_SetBaseDirectory([[self biosDirectoryPath] UTF8String]); unused for now
FCEUI_SetDirOverride(FCEUIOD_NV, strdup([[batterySavesDirectory path] UTF8String]));
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
[NSFileManager.defaultManager createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
//FCEUI_SetBaseDirectory([[self biosDirectoryPath] fileSystemRepresentation]); unused for now
FCEUI_SetDirOverride(FCEUIOD_NV, strdup(batterySavesDirectory.fileSystemRepresentation));
FCEUI_SetSoundVolume(256);
FCEUI_Sound(48000);
FCEUGI *FCEUGameInfo;
FCEUGameInfo = FCEUI_LoadGame([path UTF8String], 1, false);
FCEUGameInfo = FCEUI_LoadGame(path.fileSystemRepresentation, 1, false);
if(!FCEUGameInfo)
return NO;
//NSLog(@"FPS: %d", FCEUI_GetDesiredFPS() >> 24); // Hz
FCEUI_SetInput(0, SI_GAMEPAD, &pad, 0); // Controllers 1 and 3
FCEUI_SetInput(0, SI_GAMEPAD, &_pad, 0); // Controllers 1 and 3
if(FCEUGameInfo->input[1] == SI_ZAPPER)
FCEUI_SetInput(1, SI_ZAPPER, &zapper, 0);
FCEUI_SetInput(1, SI_ZAPPER, &_zapper, 0);
else if(FCEUGameInfo->input[1] == SI_ARKANOID)
FCEUI_SetInput(1, SI_ARKANOID, &arkanoid, 0);
FCEUI_SetInput(1, SI_ARKANOID, &_arkanoid, 0);
else
FCEUI_SetInput(1, SI_GAMEPAD, &pad, 0); // Controllers 2 and 4
FCEUI_SetInput(1, SI_GAMEPAD, &_pad, 0); // Controllers 2 and 4
if(FCEUGameInfo->inputfc == SIFC_SHADOW)
FCEUI_SetInputFC(SIFC_SHADOW, &hypershot, 0);
FCEUI_SetInputFC(SIFC_SHADOW, &_hypershot, 0);
else if(FCEUGameInfo->inputfc == SIFC_ARKANOID)
FCEUI_SetInputFC(SIFC_ARKANOID, &arkanoid, 0);
FCEUI_SetInputFC(SIFC_ARKANOID, &_arkanoid, 0);
extern uint32_t iNESGameCRC32;
NSString *cartCRC32 = [NSString stringWithFormat:@"%08x", iNESGameCRC32];
@@ -192,29 +211,29 @@ static __weak FCEUGameCore *_current;
FCEUI_SetInputFourscore(true);
if([famicom4Player containsObject:cartCRC32])
FCEUI_SetInputFC(SIFC_4PLAYER, &pad, 0);
FCEUI_SetInputFC(SIFC_4PLAYER, &_pad, 0);
FCEU_ResetPalette();
// Only temporary, so core doesn't crash on an older OpenEmu version
if ([self respondsToSelector:@selector(displayModeInfo)]) {
[self loadDisplayModeOptions];
}
return YES;
}
- (void)executeFrame
{
pXBuf = 0;
soundSize = 0;
uint8_t *pXBuf;
_soundSize = 0;
FCEUI_Emulate(&pXBuf, &soundBuffer, &soundSize, 0);
FCEUI_Emulate(&pXBuf, &_soundBuffer, &_soundSize, 0);
pXBuf = XBuf;
for (unsigned y = 0; y < 240; y++)
for (unsigned x = 0; x < 256; x++, pXBuf++)
videoBuffer[y * 256 + x] = palette[*pXBuf];
for (int i = 0; i < _soundSize; i++)
_soundBuffer[i] = (_soundBuffer[i] << 16) | (_soundBuffer[i] & 0xffff);
for (int i = 0; i < soundSize; i++)
soundBuffer[i] = (soundBuffer[i] << 16) | (soundBuffer[i] & 0xffff);
[[self ringBufferAtIndex:0] write:soundBuffer maxLength:soundSize << 2];
[[self audioBufferAtIndex:0] write:_soundBuffer maxLength:_soundSize << 2];
}
- (void)resetEmulation
@@ -237,19 +256,39 @@ static __weak FCEUGameCore *_current;
# pragma mark - Video
- (const void *)videoBuffer
- (const void *)getVideoBufferWithHint:(void *)hint
{
return videoBuffer;
if (!hint) {
if (!_videoBuffer) _videoBuffer = (uint32_t *)malloc(256 * 240 * sizeof(uint32_t));
hint = _videoBuffer;
}
// TODO: support paletted video in OE
uint8_t *pXBuf = XBuf;
uint32_t *pOBuf = (uint32_t *)hint;
for (unsigned y = 0; y < 240; y++)
for (unsigned x = 0; x < 256; x++, pXBuf++)
pOBuf[y * 256 + x] = palette[*pXBuf];
return hint;
}
- (OEIntRect)screenRect
{
return OEIntRectMake(0, 0, 256, 240);
_videoOffsetX = _isHorzOverscanCropped ? OVERSCAN_HORIZONTAL : 0;
_videoOffsetY = _isVertOverscanCropped ? OVERSCAN_VERTICAL : 0;
_videoWidth = _isHorzOverscanCropped ? 256 - (OVERSCAN_HORIZONTAL * 2) : 256;
_videoHeight = _isVertOverscanCropped ? 240 - (OVERSCAN_VERTICAL * 2) : 240;
return OEIntRectMake(_videoOffsetX, _videoOffsetY, _videoWidth, _videoHeight);
}
- (OEIntSize)aspectSize
{
return OEIntSizeMake(256 * (8.0/7.0), 240);
_aspectWidth = _isHorzOverscanCropped ? (256 - (OVERSCAN_HORIZONTAL * 2)) * (8.0/7.0) : 256 * (8.0/7.0);
_aspectHeight = _isVertOverscanCropped ? 240 - (OVERSCAN_VERTICAL * 2) : 240;
return OEIntSizeMake(_aspectWidth, _aspectHeight);
}
- (OEIntSize)bufferSize
@@ -267,11 +306,6 @@ static __weak FCEUGameCore *_current;
return GL_UNSIGNED_INT_8_8_8_8_REV;
}
- (GLenum)internalPixelFormat
{
return GL_RGB8;
}
# pragma mark - Audio
- (double)audioSampleRate
@@ -316,8 +350,8 @@ static __weak FCEUGameCore *_current;
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError
{
u8 *bytes = (u8 *)[state bytes];
size_t length = [state length];
u8 *bytes = (u8 *)state.bytes;
size_t length = state.length;
std::vector<u8> byteVector(bytes, bytes + length);
EMUFILE *emuFile = new EMUFILE_MEMORY(&byteVector);
@@ -349,7 +383,7 @@ const int NESMap[] = {JOY_UP, JOY_DOWN, JOY_LEFT, JOY_RIGHT, JOY_A, JOY_B, JOY_S
break;
}
pad |= NESMap[button] << playerShift;
_pad |= NESMap[button] << playerShift;
}
- (oneway void)didReleaseNESButton:(OENESButton)button forPlayer:(NSUInteger)player;
@@ -370,87 +404,384 @@ const int NESMap[] = {JOY_UP, JOY_DOWN, JOY_LEFT, JOY_RIGHT, JOY_A, JOY_B, JOY_S
break;
}
pad &= ~(NESMap[button] << playerShift);
_pad &= ~(NESMap[button] << playerShift);
}
- (oneway void)didTriggerGunAtPoint:(OEIntPoint)aPoint
{
[self mouseMovedAtPoint:aPoint];
arkanoid[2] = 1;
int xcoord = _isHorzOverscanCropped ? (aPoint.x + OVERSCAN_HORIZONTAL) * 0.876712 : aPoint.x * 0.876712;
int ycoord = _isVertOverscanCropped ? aPoint.y + OVERSCAN_VERTICAL : aPoint.y;
zapper[0] = aPoint.x * 0.876712;
zapper[1] = aPoint.y;
zapper[2] = 1;
_arkanoid[2] = 1;
hypershot[0] = aPoint.x * 0.876712;
hypershot[1] = aPoint.y;
hypershot[2] = 1;
_zapper[0] = xcoord;
_zapper[1] = ycoord;
_zapper[2] = 1;
_hypershot[0] = xcoord;
_hypershot[1] = ycoord;
_hypershot[2] = 1;
}
- (oneway void)didReleaseTrigger
{
arkanoid[2] = 0;
zapper[2] = 0;
hypershot[2] = 0;
_arkanoid[2] = 0;
_zapper[2] = 0;
_hypershot[2] = 0;
}
- (oneway void)mouseMovedAtPoint:(OEIntPoint)aPoint
{
arkanoid[0] = aPoint.x * 0.876712;
_arkanoid[0] = _isHorzOverscanCropped ? (aPoint.x + OVERSCAN_HORIZONTAL) * 0.876712 : aPoint.x * 0.876712;
}
- (oneway void)rightMouseDownAtPoint:(OEIntPoint)point
{
hypershot[3] = 1; // "move" button
_hypershot[3] = 1; // "move" button
}
- (oneway void)rightMouseUp;
{
hypershot[3] = 0;
_hypershot[3] = 0;
}
#pragma mark - Cheats
NSMutableDictionary *cheatList = [[NSMutableDictionary alloc] init];
- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled
{
// Sanitize
code = [code stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
code = [code stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
// Remove any spaces
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
if (enabled)
[cheatList setValue:@YES forKey:code];
_cheatList[code] = @YES;
else
[cheatList removeObjectForKey:code];
[_cheatList removeObjectForKey:code];
FCEU_FlushGameCheats(0, 1);
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:@"+"];
for (NSString *singleCode in multipleCodes) {
const char *cCode = [singleCode UTF8String];
const char *cCode = singleCode.UTF8String;
int address, value, compare;
int type = 1;
if (FCEUI_DecodeGG(cCode, &address, &value, &compare))
if (singleCode.length == 7 && [singleCode characterAtIndex:4] == ':')
{
address = (int)strtoul([singleCode substringToIndex:4].UTF8String, NULL, 16);
value = (int)strtoul([singleCode substringFromIndex:5].UTF8String, NULL, 16);
compare = -1;
FCEUI_AddCheat(cCode, address, value, compare, type);
}
else if (singleCode.length == 10 && [singleCode characterAtIndex:4] == '?' && [singleCode characterAtIndex:7] == ':')
{
address = (int)strtoul([singleCode substringToIndex:4].UTF8String, NULL, 16);
compare = (int)strtoul([singleCode substringWithRange:NSMakeRange(5, 2)].UTF8String, NULL, 16);
value = (int)strtoul([singleCode substringFromIndex:8].UTF8String, NULL, 16);
FCEUI_AddCheat(cCode, address, value, compare, type);
}
else if (FCEUI_DecodeGG(cCode, &address, &value, &compare))
FCEUI_AddCheat(cCode, address, value, compare, type);
// Does not work
// else if (FCEUI_DecodePAR(cCode, &address, &value, &compare, &type))
// FCEUI_AddCheat(cCode, address, value, compare, type);
}
}
}
}
# pragma mark - Display Mode
- (NSArray <NSDictionary <NSString *, id> *> *)displayModes
{
if (_availableDisplayModes.count == 0)
{
_availableDisplayModes = [NSMutableArray array];
NSArray <NSDictionary <NSString *, id> *> *availableModesWithDefault =
@[
OptionToggleableNoSave(@"No Sprite Limit", @"noSpriteLimit"),
SeparatorItem(),
Label(@"Overscan"),
OptionToggleable(@"Crop Horizontal", @"cropHorizontalOverscan"),
OptionToggleable(@"Crop Vertical", @"cropVerticalOverscan"),
SeparatorItem(),
Label(@"Palette"),
OptionDefault(@"Default — FCEUX", @"palette"),
Option(@"RGB (PlayChoice-10)", @"palette"),
Option(@"NESCAP", @"palette"),
Option(@"Sony CXA2025AS", @"palette"),
Option(@"Smooth (FBX)", @"palette"),
Option(@"Wavebeam", @"palette"),
];
// 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);
}
if ([displayMode isEqualToString:@"Crop Horizontal"])
{
_isHorzOverscanCropped = !_isHorzOverscanCropped;
}
else if ([displayMode isEqualToString:@"Crop Vertical"])
{
_isVertOverscanCropped = !_isVertOverscanCropped;
}
else if ([displayMode isEqualToString:@"No Sprite Limit"])
{
FCEUI_DisableSpriteLimitation(!displayModeState);
}
else if ([displayMode isEqualToString:@"Default — FCEUX"])
{
FCEU_ResetPalette();
}
else if ([displayMode isEqualToString:@"RGB (PlayChoice-10)"])
{
unsigned int pc10_palette[64] =
{
0x6D6D6D, 0x002492, 0x0000DB, 0x6D49DB,
0x92006D, 0xB6006D, 0xB62400, 0x924900,
0x6D4900, 0x244900, 0x006D24, 0x009200,
0x004949, 0x000000, 0x000000, 0x000000,
0xB6B6B6, 0x006DDB, 0x0049FF, 0x9200FF,
0xB600FF, 0xFF0092, 0xFF0000, 0xDB6D00,
0x926D00, 0x249200, 0x009200, 0x00B66D,
0x009292, 0x242424, 0x000000, 0x000000,
0xFFFFFF, 0x6DB6FF, 0x9292FF, 0xDB6DFF,
0xFF00FF, 0xFF6DFF, 0xFF9200, 0xFFB600,
0xDBDB00, 0x6DDB00, 0x00FF00, 0x49FFDB,
0x00FFFF, 0x494949, 0x000000, 0x000000,
0xFFFFFF, 0xB6DBFF, 0xDBB6FF, 0xFFB6FF,
0xFF92FF, 0xFFB6B6, 0xFFDB92, 0xFFFF49,
0xFFFF6D, 0xB6FF49, 0x92FF6D, 0x49FFDB,
0x92DBFF, 0x929292, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = pc10_palette[i] >> 16;
int g = (pc10_palette[i] & 0xff00) >> 8;
int b = pc10_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"NESCAP"])
{
unsigned int nescap_palette[64] =
{
0x646365, 0x001580, 0x1D0090, 0x380082,
0x56005D, 0x5A001A, 0x4F0900, 0x381B00,
0x1E3100, 0x003D00, 0x004100, 0x003A1B,
0x002F55, 0x000000, 0x000000, 0x000000,
0xAFADAF, 0x164BCA, 0x472AE7, 0x6B1BDB,
0x9617B0, 0x9F185B, 0x963001, 0x7B4800,
0x5A6600, 0x237800, 0x017F00, 0x00783D,
0x006C8C, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x60A6FF, 0x8F84FF, 0xB473FF,
0xE26CFF, 0xF268C3, 0xEF7E61, 0xD89527,
0xBAB307, 0x81C807, 0x57D43D, 0x47CF7E,
0x4BC5CD, 0x4C4B4D, 0x000000, 0x000000,
0xFFFFFF, 0xC2E0FF, 0xD5D2FF, 0xE3CBFF,
0xF7C8FF, 0xFEC6EE, 0xFECEC6, 0xF6D7AE,
0xE9E49F, 0xD3ED9D, 0xC0F2B2, 0xB9F1CC,
0xBAEDED, 0xBAB9BB, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = nescap_palette[i] >> 16;
int g = (nescap_palette[i] & 0xff00) >> 8;
int b = nescap_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"Sony CXA2025AS"])
{
unsigned int cxa2025as_palette[64] =
{
0x585858, 0x00238C, 0x00139B, 0x2D0585,
0x5D0052, 0x7A0017, 0x7A0800, 0x5F1800,
0x352A00, 0x093900, 0x003F00, 0x003C22,
0x00325D, 0x000000, 0x000000, 0x000000,
0xA1A1A1, 0x0053EE, 0x153CFE, 0x6028E4,
0xA91D98, 0xD41E41, 0xD22C00, 0xAA4400,
0x6C5E00, 0x2D7300, 0x007D06, 0x007852,
0x0069A9, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x1FA5FE, 0x5E89FE, 0xB572FE,
0xFE65F6, 0xFE6790, 0xFE773C, 0xFE9308,
0xC4B200, 0x79CA10, 0x3AD54A, 0x11D1A4,
0x06BFFE, 0x424242, 0x000000, 0x000000,
0xFFFFFF, 0xA0D9FE, 0xBDCCFE, 0xE1C2FE,
0xFEBCFB, 0xFEBDD0, 0xFEC5A9, 0xFED18E,
0xE9DE86, 0xC7E992, 0xA8EEB0, 0x95ECD9,
0x91E4FE, 0xACACAC, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = cxa2025as_palette[i] >> 16;
int g = (cxa2025as_palette[i] & 0xff00) >> 8;
int b = cxa2025as_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"Smooth (FBX)"])
{
unsigned int smoothfbx_palette[64] =
{
0x6A6D6A, 0x001380, 0x1E008A, 0x39007A,
0x550056, 0x5A0018, 0x4F1000, 0x3D1C00,
0x253200, 0x003D00, 0x004000, 0x003924,
0x002E55, 0x000000, 0x000000, 0x000000,
0xB9BCB9, 0x1850C7, 0x4B30E3, 0x7322D6,
0x951FA9, 0x9D285C, 0x983700, 0x7F4C00,
0x5E6400, 0x227700, 0x027E02, 0x007645,
0x006E8A, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x68A6FF, 0x8C9CFF, 0xB586FF,
0xD975FD, 0xE377B9, 0xE58D68, 0xD49D29,
0xB3AF0C, 0x7BC211, 0x55CA47, 0x46CB81,
0x47C1C5, 0x4A4D4A, 0x000000, 0x000000,
0xFFFFFF, 0xCCEAFF, 0xDDDEFF, 0xECDAFF,
0xF8D7FE, 0xFCD6F5, 0xFDDBCF, 0xF9E7B5,
0xF1F0AA, 0xDAFAA9, 0xC9FFBC, 0xC3FBD7,
0xC4F6F6, 0xBEC1BE, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = smoothfbx_palette[i] >> 16;
int g = (smoothfbx_palette[i] & 0xff00) >> 8;
int b = smoothfbx_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"Wavebeam"])
{
unsigned int wavebeam_palette[64] =
{
0x6B6B6B, 0x001B88, 0x21009A, 0x40008C,
0x600067, 0x64001E, 0x590800, 0x481600,
0x283600, 0x004500, 0x004908, 0x00421D,
0x003659, 0x000000, 0x000000, 0x000000,
0xB4B4B4, 0x1555D3, 0x4337EF, 0x7425DF,
0x9C19B9, 0xAC0F64, 0xAA2C00, 0x8A4B00,
0x666B00, 0x218300, 0x008A00, 0x008144,
0x007691, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x63B2FF, 0x7C9CFF, 0xC07DFE,
0xE977FF, 0xF572CD, 0xF4886B, 0xDDA029,
0xBDBD0A, 0x89D20E, 0x5CDE3E, 0x4BD886,
0x4DCFD2, 0x525252, 0x000000, 0x000000,
0xFFFFFF, 0xBCDFFF, 0xD2D2FF, 0xE1C8FF,
0xEFC7FF, 0xFFC3E1, 0xFFCAC6, 0xF2DAAD,
0xEBE3A0, 0xD2EDA2, 0xBCF4B4, 0xB5F1CE,
0xB6ECF1, 0xBFBFBF, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = wavebeam_palette[i] >> 16;
int g = (wavebeam_palette[i] & 0xff00) >> 8;
int b = wavebeam_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
}
- (void)loadDisplayModeOptions
{
// Restore palette
NSString *lastPalette = self.displayModeInfo[@"palette"];
if (lastPalette && ![lastPalette isEqualToString:@"Default — FCEUX"]) {
[self changeDisplayWithMode:lastPalette];
}
// Crop horizontal overscan
BOOL isHorizontalOverscanCropped = [self.displayModeInfo[@"cropHorizontalOverscan"] boolValue];
if (isHorizontalOverscanCropped) {
[self changeDisplayWithMode:@"Crop Horizontal"];
}
// Crop vertical overscan
BOOL isVerticalOverscanCropped = [self.displayModeInfo[@"cropVerticalOverscan"] boolValue];
if (isVerticalOverscanCropped) {
[self changeDisplayWithMode:@"Crop Vertical"];
}
}
// FCEUX internal functions and stubs
void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g, unsigned char b)
{
@@ -464,7 +795,9 @@ const char *GetKeyboard(void) {return "";}
bool turbo = false;
bool swapDuty = 0; // some Famicom and NES clones had duty cycle bits swapped
int dendy = 0;
int eoptions = 0;
int closeFinishedMovie = 0;
int KillFCEUXonFrame = 0;
int FCEUD_ShowStatusIcon(void) {return 0;}
int FCEUD_SendData(void *data, uint32 len) {return 1;}
int FCEUD_RecvData(void *data, uint32 len) {return 1;}
@@ -492,6 +825,7 @@ EMUFILE_FILE *FCEUD_UTF8_fstream(const char *fn, const char *m)
}
void FCEUD_NetplayText(uint8 *text) {};
void FCEUD_NetworkClose(void) {}
void FCEUD_FlushTrace(void) {}
void FCEUD_VideoChanged (void) {}
bool FCEUD_ShouldDrawInputAids() {return false;}
bool FCEUD_PauseAfterPlayback() {return false;}
@@ -501,15 +835,17 @@ bool FCEUI_AviIsRecording(void) {return false;}
bool FCEUI_AviDisableMovieMessages() {return true;}
FCEUFILE *FCEUD_OpenArchiveIndex(ArchiveScanRecord &asr, std::string &fname, int innerIndex) {return 0;}
FCEUFILE *FCEUD_OpenArchive(ArchiveScanRecord &asr, std::string &fname, std::string *innerFilename) {return 0;}
FCEUFILE *FCEUD_OpenArchiveIndex(ArchiveScanRecord &asr, std::string &fname, int innerIndex, int *userCancel) {return 0;}
FCEUFILE *FCEUD_OpenArchive(ArchiveScanRecord &asr, std::string &fname, std::string *innerFilename, int *userCancel) {return 0;}
ArchiveScanRecord FCEUD_ScanArchive(std::string fname) { return ArchiveScanRecord(); }
void GetMouseData(uint32 (&md)[3]) {}
void FCEUD_PrintError(const char *s)
{
NSLog(@"FCEUX error: %s", s);
NSLog(@"[FCEUX] error: %s", s);
}
void FCEUD_Message(const char *s)
{
NSLog(@"FCEUX message: %s", s);
NSLog(@"[FCEUX] message: %s", s);
}
@end
+5 -3
View File
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
@@ -17,7 +17,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.2.3</string>
<string>2.6.6</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
@@ -32,6 +32,8 @@
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsDisplayModeChange</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
</dict>
@@ -39,7 +41,7 @@
<key>OEGameCorePlayerCount</key>
<string>4</string>
<key>OEProjectURL</key>
<string>http://sourceforge.net/projects/fceultra/</string>
<string>https://github.com/TASEmulators/fceux</string>
<key>OESystemIdentifiers</key>
<array>
<string>openemu.system.nes</string>
+2
View File
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
+731
View File
@@ -0,0 +1,731 @@
include(GNUInstallDirs)
set( APP_NAME fceux)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if (${PUBLIC_RELEASE})
add_definitions( -DPUBLIC_RELEASE=1 )
endif()
if ( ${QT6} )
message( STATUS "GUI Frontend: Qt6")
set( Qt Qt6 )
else()
message( STATUS "GUI Frontend: Qt5")
set( Qt Qt5 )
endif()
if ( ${QHELP} )
set(QtHelpModule Help)
add_definitions( -D_USE_QHELP )
endif()
if ( ${FCEU_PROFILER_ENABLE} )
message( STATUS "FCEU Profiler Enabled")
add_definitions( -D__FCEU_PROFILER_ENABLE__ )
endif()
if ( ${QT6} )
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets ${QtHelpModule})
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
else()
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QtHelpModule})
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
endif()
if(WIN32)
find_package(OpenGL REQUIRED)
#find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED)
#add_definitions( ${Qt5Widgets_DEFINITIONS} )
#include_directories( ${Qt5Widgets_INCLUDE_DIRS} )
add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS )
add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
add_definitions( -DFCEUDEF_DEBUGGER )
add_definitions( -D_USE_LIBARCHIVE )
add_definitions( /wd4267 /wd4244 )
#add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings
include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include )
include_directories( ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/include )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
set( OPENGL_LDFLAGS OpenGL::GL )
set( SDL2_LDFLAGS ${SDL_INSTALL_PREFIX}/SDL2/lib/x64/SDL2.lib )
set( LIBARCHIVE_LDFLAGS ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/lib/archive.lib )
set( SYS_LIBS wsock32 ws2_32 vfw32 Htmlhelp )
set(APP_ICON_RESOURCES_WINDOWS ${CMAKE_SOURCE_DIR}/icons/fceux.rc )
if ( ${USE_LIBAV} )
add_definitions( -D_USE_LIBAV ${LIBAV_CFLAGS} )
include_directories( ${FFMPEG_INSTALL_PREFIX}/ffmpeg/include )
set( LIBAV_LDFLAGS ${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/avcodec.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/avformat.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/avutil.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/swscale.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/swresample.lib )
endif()
else(WIN32)
# Non Windows System
# UNIX (Linux or Mac OSX)
if ( ${GLVND} )
message( STATUS "OpenGL preference: GLVND")
set (OpenGL_GL_PREFERENCE GLVND)
else()
message( STATUS "OpenGL preference: LEGACY")
set (OpenGL_GL_PREFERENCE LEGACY)
endif()
# Use the built-in cmake find_package functions to find dependencies
# Use package PkgConfig to detect headers/library what find_package cannot find.
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
find_package(ZLIB REQUIRED)
add_definitions( -Wall -Wno-write-strings -Wno-parentheses -Wno-unused-local-typedefs -fPIC )
#add_definitions( -Wno-sign-compare ) # Integer comparison sign mismatch warnings
add_definitions( -DFCEUDEF_DEBUGGER )
#if ( ${QT6} )
# find_package( Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED)
# add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
# include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${QtOpenGLWidgets_INCLUDE_DIRS} )
#else()
# find_package( Qt5 COMPONENTS Widgets OpenGL REQUIRED)
# add_definitions( ${Qt5Widgets_DEFINITIONS} )
# include_directories( ${Qt5Widgets_INCLUDE_DIRS} )
#endif()
add_definitions( -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
if ( ${GPROF_ENABLE} )
add_definitions( -pg )
set( GPROF_LDFLAGS -pg )
message( STATUS "GNU Profiling Enabled" )
endif()
if ( ${ASAN_ENABLE} )
add_definitions( -fsanitize=address -fsanitize=bounds-strict )
add_definitions( -fsanitize=undefined -fno-sanitize=vptr )
set( ASAN_LDFLAGS -lasan -lubsan)
message( STATUS "Address Sanitizer Enabled" )
else()
message( STATUS "Address Sanitizer Disabled" )
endif()
# Check for libminizip
pkg_check_modules( MINIZIP REQUIRED minizip)
if ( ${MINIZIP_FOUND} )
message( STATUS "Using System minizip ${MINIZIP_VERSION}" )
add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} )
endif()
pkg_check_modules( LIBARCHIVE libarchive)
if ( ${LIBARCHIVE_FOUND} )
message( STATUS "Using System Libarchive Library ${LIBARCHIVE_VERSION}" )
add_definitions( -D_USE_LIBARCHIVE ${LIBARCHIVE_CFLAGS} )
endif()
pkg_check_modules( X264 x264)
if ( ${X264_FOUND} )
message( STATUS "Using System X264 Encoder Library ${X264_VERSION}" )
add_definitions( -D_USE_X264 ${X264_CFLAGS} )
endif()
pkg_check_modules( X265 x265)
if ( ${X265_FOUND} )
message( STATUS "Using System X265 Encoder Library ${X265_VERSION}" )
add_definitions( -D_USE_X265 ${X265_CFLAGS} )
endif()
pkg_check_modules( LIBAV libavcodec libavformat libavutil libswresample libswscale)
if ( ${LIBAV_FOUND} )
message( STATUS "Using System Libav Library ${LIBAV_VERSION}" )
add_definitions( -D_USE_LIBAV ${LIBAV_CFLAGS} )
endif()
#find_package(X11)
pkg_check_modules( X11 x11)
if ( ${X11_FOUND} )
message( STATUS "Has X11 Library ${X11_VERSION}" )
add_definitions( -D_HAS_X11 )
include_directories( ${X11_INCLUDE_DIR} )
endif()
pkg_check_modules( XKB xkbcommon)
if ( ${XKB_FOUND} )
message( STATUS "Has XKB Library ${XKB_VERSION}" )
add_definitions( -D_HAS_XKB ${XKB_CFLAGS} )
endif()
#pkg_check_modules( GL gl) # Use built in find package instead for OpenGL
# Check for OpenGL
if ( ${OPENGL_FOUND} )
include_directories( ${OPENGL_INCLUDE_DIR} )
endif()
# Check for SDL2
pkg_check_modules( SDL2 REQUIRED sdl2)
if ( ${SDL2_FOUND} )
add_definitions( ${SDL2_CFLAGS} -D__SDL__ )
endif()
# Check for LUA
pkg_search_module( LUA lua5.1 lua-5.1 )
add_definitions( -DHAVE_ASPRINTF ) # What system wouldn't have this?
add_definitions( -DLUA_USE_LINUX ) # This needs to be set when link LUA internally for linux and macosx
if(APPLE)
set( OPENGL_LDFLAGS "-framework OpenGL" )
else()
set( OPENGL_LDFLAGS ${OPENGL_LIBRARIES} )
# OpenBSD refuses to implement the POSIX realtime interface and
# refuses to provide a stub library for -ldl
if(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set( SYS_LIBS -lpthread)
else()
set( SYS_LIBS -lrt -lpthread -ldl)
endif()
endif()
endif(WIN32)
if ( ${LUA_FOUND} )
# Use System LUA
message( STATUS "Using System Lua ${LUA_VERSION}" )
add_definitions( -D_S9XLUA_H ${LUA_CFLAGS} )
set( LUA_ENGINE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp )
else ()
# Use Internal LUA
message( STATUS "Using Internal Lua" )
add_definitions( -D_S9XLUA_H -I${CMAKE_CURRENT_SOURCE_DIR}/lua/src )
set( LUA_ENGINE_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lapi.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lauxlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lbaselib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lcode.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldblib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldebug.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldo.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldump.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lfunc.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lgc.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/linit.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/liolib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/llex.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lmathlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lmem.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/loadlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lobject.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lopcodes.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/loslib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lparser.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstate.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstring.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstrlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltable.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltablib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltm.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lundump.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lvm.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lzio.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/print.c
${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp
)
endif()
if ( ${ZLIB_FOUND} )
message( STATUS "Using System zlib ${ZLIB_VERSION_STRING}" )
#add_definitions( ${ZLIB_CFLAGS} )
include_directories( ${ZLIB_INCLUDE_DIRS} )
else()
message( STATUS "Using Internal zlib" )
set( ZLIB_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/adler32.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/compress.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/crc32.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/deflate.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/gzio.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/infblock.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/infcodes.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/inffast.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/inflate.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/inftrees.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/infutil.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/trees.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/uncompr.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/unzip.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/zutil.c
)
endif()
include_directories( ${CMAKE_SOURCE_DIR}/src )
include_directories( ${CMAKE_SOURCE_DIR}/src/drivers )
if(APPLE)
add_definitions( -DPSS_STYLE=1 )
else(APPLE)
if(UNIX)
add_definitions( -DPSS_STYLE=1 )
endif(UNIX)
endif(APPLE)
set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/asm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cart.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cheat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/conddebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debugsymboltable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drawing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fceu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fds.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
${CMAKE_CURRENT_SOURCE_DIR}/emufile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/filter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ines.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ld65dbg.cpp
${CMAKE_CURRENT_SOURCE_DIR}/movie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/netplay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nsf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/oldmovie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/palette.cpp
${CMAKE_CURRENT_SOURCE_DIR}/profiler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ppu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sound.cpp
${CMAKE_CURRENT_SOURCE_DIR}/state.cpp
${CMAKE_CURRENT_SOURCE_DIR}/unif.cpp
${CMAKE_CURRENT_SOURCE_DIR}/video.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vsuni.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wave.cpp
${CMAKE_CURRENT_SOURCE_DIR}/x6502.cpp
${LUA_ENGINE_SOURCE}
${ZLIB_SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/boards/01-222.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/09-034a.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/103.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/106.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/108.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/112.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/116.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/117.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/120.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/121.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/12in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/151.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/156.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/158B.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/15.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/164.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/168.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/170.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/175.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/176.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/177.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/178.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/183.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/185.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/186.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/187.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/189.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/18.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/190.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/193.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/199.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/206.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/208.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/222.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/225.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/228.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/230.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/232.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/234.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/235.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/244.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/246.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/252.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/253.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/28.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/33.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/354.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/411120-c.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/41.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/42.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/43.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/46.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/50.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/51.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/57.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/603-5052.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/62.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/65.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/67.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/68.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/69.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/71.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/72.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/77.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/79.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/80013-B.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/80.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/8157.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/8237.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/82.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/830118C.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/88.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/8in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/90.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/91.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/96.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/99.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/a9746.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ac-08.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/addrlatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ax5705.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bandai.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc13in1jy110.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc42in1r.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc64in1nr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc70in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/BMW8544.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bonza.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bs-5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bs4xxxr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolgirl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/__dummy_mapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/edu2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/eh8813a.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/emu2413.c
${CMAKE_CURRENT_SOURCE_DIR}/boards/et-100.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/et-4320.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/F-15.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/famicombox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ffe.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/fk23c.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/fns.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ghostbusters63in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/gs-2004.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/gs-2013.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/h2288.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/hp10xx_hp20xx.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/hp898f.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/inlnsf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/karaoke.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/kof97.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7010.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7012.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7013.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7016.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7017.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7030.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7031.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7032.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7037.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7057.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/le05.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/lh32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/lh53.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/malee.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mihunche.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc2and4.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/n106.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/n625092.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/novel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/onebus.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/pec-586.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/rt-01.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sa-9602b.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sachen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sb-2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sc-127.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sheroes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sl1632.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/subor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/super24.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/supervision.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/t-227-1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/t-262.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/tengen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/tf-1201.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/transformer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/unrom512.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc2and4.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc6.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7p.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/yoko.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/inx007t.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/arkanoid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/bworld.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/cursor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/fkb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/fns.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/ftrainer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/hypershot.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/mahjong.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/mouse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/oekakids.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/pec586kb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/powerpad.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/quiz.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/shadow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/snesmouse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/suborkb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/toprider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/virtualboy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/lcdcompzapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/zapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/backward.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/xstring.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/crc32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/endian.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/general.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/guid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mutex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/timeStamp.cpp
)
set(SRC_DRIVERS_COMMON
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/args.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/cheat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/configSys.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq2x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq3x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale2x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale3x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scalebit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/vidblit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/os_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/nes_ntsc.c
)
set(SRC_DRIVERS_SDL
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerGL.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerSDL.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerQWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/InputConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FamilyKeyboard.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FrameTimingStats.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ColorMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HelpPages.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MovieRecord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MovieOptions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GameGenie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MsgLogViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CodeDataLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SymbolicDebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleDebugger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/StateRecorderConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/iNesHeaderEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SplashScreen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/fceuWrapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ppuViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/NameTableViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamWatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamSearch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/input.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/nes_shm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/keyscan.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-sound.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-video.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-joystick.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRecord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRiffViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/fileio.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/gwavi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/TasEditorWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/taseditor_project.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/taseditor_config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/taseditor_lua.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/markers_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/greenzone.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/selection.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/playback.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/recorder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/history.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/splicer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/inputlog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/laglog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/branches.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/bookmarks.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/bookmark.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/snapshot.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/markers.cpp
)
set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_SDL})
# Put build timestamp into BUILD_TS environment variable and from there into
# the FCEUX_BUILD_TIMESTAMP preprocessor definition.
# Note: with CMake >= 3.8.0, this will respect SOURCE_DATE_EPOCH. For more info,
# see <https://reproducible-builds.org/docs/source-date-epoch/>.
string(TIMESTAMP BUILD_TS "%H:%M:%S %b %d %Y" UTC)
add_definitions( -DFCEUX_BUILD_TIMESTAMP=\"${BUILD_TS}\" )
if (WIN32)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp
COMMAND ${CMAKE_SOURCE_DIR}/scripts/genGitHdr.bat ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM )
else()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp
COMMAND ${CMAKE_SOURCE_DIR}/scripts/genGitHdr.sh ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM )
endif()
set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp PROPERTY SKIP_AUTOGEN ON)
if (APPLE)
set(MACOSX_BUNDLE_ICON_FILE fceux.icns)
set(APP_ICON ${CMAKE_SOURCE_DIR}/fceux.icns )
set_source_files_properties( ${APP_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources" )
add_executable( ${APP_NAME} MACOSX_BUNDLE ${APP_ICON} ${SOURCES} ../resources.qrc
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp)
elseif (WIN32)
add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp
${APP_ICON_RESOURCES_WINDOWS} )
else()
add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp)
endif()
target_link_libraries( ${APP_NAME}
${ASAN_LDFLAGS} ${GPROF_LDFLAGS}
${${Qt}Widgets_LIBRARIES}
${${Qt}Help_LIBRARIES}
${${Qt}OpenGL_LIBRARIES}
${${Qt}OpenGLWidgets_LIBRARIES}
${OPENGL_LDFLAGS}
${SDL2_LDFLAGS}
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} ${LIBARCHIVE_LDFLAGS}
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
${SYS_LIBS}
)
if (WIN32)
# target_link_libraries( ${APP_NAME} wsock32 ws2_32 )
set_target_properties(${APP_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
if (APPLE)
install( TARGETS ${APP_NAME}
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION bin COMPONENT Runtime )
# Use \$ to defer expansion until install script is called; CPack will call it with its own CMAKE_INSTALL_PREFIX
set(APP \${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app)
install( DIRECTORY ${CMAKE_SOURCE_DIR}/output/.
DESTINATION ${APP_NAME}.app/Contents/Resources COMPONENT Extra )
set(CPACK_PACKAGE_ICON ${CMAKE_SOURCE_DIR}/fceux.icns )
set(CPACK_GENERATOR "DragNDrop")
include(CPACK)
# macdeployqt tool that comes with Qt: https://doc.qt.io/qt-5/macos-deployment.html#macdeploy
# Compared to fixup_bundle, correctly finds and installs Qt-specific resources as well as non-Qt dependencies
find_program(MACDEPLOYQT macdeployqt)
if(NOT MACDEPLOYQT)
message(FATAL_ERROR "Could not find macdeployqt executable")
endif()
find_package(Perl REQUIRED)
install( CODE "
message(STATUS \"Deploying and fixing up dependencies in app: ${APP}\")
execute_process(COMMAND \"${MACDEPLOYQT}\" \"${APP}\" -verbose=1)
execute_process(COMMAND \"${PERL_EXECUTABLE}\"
\"${CMAKE_SOURCE_DIR}/scripts/macOSX_BundleFix.pl\"
\"${CMAKE_BINARY_DIR}/_CPack_Packages\")
"
COMPONENT Runtime
)
else(APPLE)
install( TARGETS ${APP_NAME}
RUNTIME DESTINATION bin )
install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/auxlib.lua DESTINATION share/fceux/luaScripts )
install( DIRECTORY ${CMAKE_SOURCE_DIR}/output/. DESTINATION share/fceux )
install( FILES ${CMAKE_SOURCE_DIR}/fceux1.png DESTINATION share/pixmaps )
install( FILES ${CMAKE_SOURCE_DIR}/fceux.desktop DESTINATION share/applications )
install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6 )
install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux-net-server.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6 )
endif(APPLE)
-42
View File
@@ -1,42 +0,0 @@
import glob
file_list = glob.glob('*.cpp')
file_list.remove('lua-engine.cpp') # use logic below for this
subdirs = Split("""
boards
drivers/common
fir
input
utils
""")
#palettes
Import('env')
Export('env')
if env['LUA']:
file_list.append('lua-engine.cpp')
if env['SYSTEM_LUA'] == 0:
subdirs.append('lua')
if env['CREATE_AVI']:
subdirs.append('drivers/videolog')
for dir in subdirs:
subdir_files = SConscript('%s/SConscript' % dir)
file_list.append(subdir_files)
if env['PLATFORM'] == 'win32':
platform_files = SConscript('drivers/win/SConscript')
else:
platform_files = SConscript('drivers/sdl/SConscript')
file_list.append(platform_files)
print env['LINKFLAGS']
if env['PLATFORM'] == 'win32':
fceux = env.Program('fceux.exe', file_list)
else:
fceux = env.Program('fceux', file_list)
Return('fceux')
+7 -7
View File
@@ -16,7 +16,7 @@ int Assemble(unsigned char *output, int addr, char *str) {
output[0] = output[1] = output[2] = 0;
char astr[128],ins[4];
int len = strlen(str);
if ((!len) || (len > 0x127)) return 1;
if ((!len) || (len > 127)) return 1;
strcpy(astr,str);
str_ucase(astr);
@@ -272,7 +272,7 @@ char *Disassemble(int addr, uint8 *opcode) {
(a) = opcode[1] | opcode[2]<<8; \
}
#define zpIndex(a,i) { \
(a) = opcode[1]+(i); \
(a) = (opcode[1]+(i))&0xFF; \
}
#define indirectX(a) { \
(a) = (opcode[1]+RX)&0xFF; \
@@ -360,8 +360,8 @@ char *Disassemble(int addr, uint8 *opcode) {
case 0xE6: strcpy(chr,"INC"); goto _zeropage;
_zeropage:
// ################################## Start of SP CODE ###########################
// Change width to %04X
sprintf(str,"%s $%04X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
// Change width to %04X // don't!
sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
// ################################## End of SP CODE ###########################
break;
@@ -457,7 +457,7 @@ char *Disassemble(int addr, uint8 *opcode) {
_zeropagex:
zpIndex(tmp,RX);
// ################################## Start of SP CODE ###########################
// Change width to %04X
// Change width to %04X // don't!
sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
@@ -515,8 +515,8 @@ char *Disassemble(int addr, uint8 *opcode) {
_zeropagey:
zpIndex(tmp,RY);
// ################################## Start of SP CODE ###########################
// Change width to %04X
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// Change width to %04X // don't!
sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
+2
View File
@@ -19,6 +19,7 @@
*
* TXC mappers, originally much complex banksitching
*
* P/N PRG MAP, UNIF Name
* 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang
* 01-22110-000 (52S ) - MGC-002 2-in-1 Gun
* 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block
@@ -27,6 +28,7 @@
* 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman
* 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior
* 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1
* 01-22026-000 (05-04010-090) ( ) - MGC-026 4-in-1
* 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom
* 01-22200-400 (------------) (079 ) - ET.03 F-15 City War
* (172 ) - 1991 Du Ma Racing
+89 -89
View File
@@ -1,90 +1,90 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(8, 0x6000, WRAM);
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}
+1 -1
View File
@@ -48,7 +48,7 @@ static void M121CW(uint32 A, uint8 V) {
if (PRGsize[0] == CHRsize[0]) { // A9713 multigame extension hack!
setchr1(A, V | ((EXPREGS[3] & 0x80) << 1));
} else {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);
+20 -14
View File
@@ -24,7 +24,7 @@
static uint16 latchea;
static uint8 latched;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
{ &latchea, 2, "AREG" },
@@ -35,31 +35,39 @@ static SFORMAT StateRegs[] =
static void Sync(void) {
int i;
setmirror(((latched >> 6) & 1) ^ 1);
switch (latchea) {
case 0x8000:
switch (latchea & 3) {
case 0:
for (i = 0; i < 4; i++)
setprg8(0x8000 + (i << 13), (((latched & 0x7F) << 1) + i) ^ (latched >> 7));
setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + i);
break;
case 0x8002:
case 2:
for (i = 0; i < 4; i++)
setprg8(0x8000 + (i << 13), ((latched & 0x7F) << 1) + (latched >> 7));
setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + (latched >> 7));
break;
case 0x8001:
case 0x8003:
case 1:
case 3:
for (i = 0; i < 4; i++) {
unsigned int b;
b = latched & 0x7F;
b = latched & 0x3F;
if (i >= 2 && !(latchea & 0x2))
b = 0x7F;
setprg8(0x8000 + (i << 13), (i & 1) + ((b << 1) ^ (latched >> 7)));
b = b | 0x07;
setprg8(0x8000 + (i << 13), (i & 1) + (b << 1));
}
break;
}
setchr8(0);
}
static DECLFW(M15Write) {
latchea = A;
latched = V;
// cah4e3 02.10.19 once again, there may be either two similar mapper 15 exist. the one for 110in1 or 168in1 carts with complex multi game features.
// and another implified version for subor/waixing chinese originals and hacks with no different modes, working only in mode 0 and which does not
// expect there is any CHR write protection. protecting CHR writes only for mode 3 fixes the problem, all roms may be run on the same source again.
if((latchea & 3) == 3)
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
else
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
Sync();
}
@@ -70,7 +78,6 @@ static void StateRestore(int version) {
static void M15Power(void) {
latchea = 0x8000;
latched = 0;
setchr8(0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
@@ -101,8 +108,7 @@ void Mapper15_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
+226 -229
View File
@@ -1,232 +1,229 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE=0;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
+2 -3
View File
@@ -23,7 +23,7 @@
static uint8 reg;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -73,8 +73,7 @@ void Mapper177_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+4 -5
View File
@@ -27,7 +27,7 @@
static uint8 reg[4];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
// Tennis with VR sensor, very simple behaviour
extern void GetMouseData(uint32 (&md)[3]);
@@ -37,8 +37,8 @@ static int32 SensorDelay;
// highly experimental, not actually working, just curious if it hapen to work with some other decoder
// SND Registers
static uint8 pcm_enable = 0;
static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
static writefunc pcmwrite;
//static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
//static writefunc pcmwrite;
static SFORMAT StateRegs[] =
{
@@ -192,8 +192,7 @@ void Mapper178_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
+2 -3
View File
@@ -24,7 +24,7 @@ static uint8 preg[4], creg[8];
static uint8 IRQa, mirr;
static int32 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -125,8 +125,7 @@ void Mapper18_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+27
View File
@@ -18,6 +18,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Family Study Box by Fukutake Shoten
*
* REG[0] R dddddddd / W ww---sss
* ddd - TAPE DATA BYTE (ready when IRQ occurs)
* sss - BRAM hi-bank
* ww - PRAM bank
* REG[1] R 0123---- / W ----PPPP
* 0 - ?
* 1 - ?
* 2 - ?
* 3 - ?
* PPPP- PROM bank
* REG[2] R -?--R--- / W A-BC-DEF
* 4 - ?
* R - sb4x power supply status (active low)
* A - ?
* B - ?
* C - ?
* D - ?
* E - ?
* F - ?
*
* BRAM0 4400-4FFF, 3K bank 0 (32K SWRAM) [hardwired]
* BRAMB 5000-5FFF, 4K banks 1-7 (32K SWRAM) [REG[0] W -----sss]
* PRAMB 6000-7FFF, 8K banks 1-3 (32K PRAM) [REG[0] W ww------]
* PROMB 8000-BFFF, 16K banks 1-15 (256K PROM)[REG[1] W ----PPPP]
* PROM0 C000-FFFF, 16K bank 0 (256K PROM) [hardwired]
*
*/
#include "mapinc.h"
+1 -1
View File
@@ -22,7 +22,7 @@
#include "mmc3.h"
static void M187CW(uint32 A, uint8 V) {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);
+85
View File
@@ -0,0 +1,85 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright (C) 2017 FCEUX Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Magic Kid GooGoo
*/
#include "mapinc.h"
static uint8 prgr, chrr[4];
static uint8 *WRAM = NULL;
static void Mapper190_Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg16(0x8000, prgr);
setprg16(0xC000, 0);
setchr2(0x0000, chrr[0]);
setchr2(0x0800, chrr[1]);
setchr2(0x1000, chrr[2]);
setchr2(0x1800, chrr[3]);
}
static DECLFW(Mapper190_Write89) { prgr = V&7; Mapper190_Sync(); }
static DECLFW(Mapper190_WriteCD) { prgr = 8|(V&7); Mapper190_Sync(); }
static DECLFW(Mapper190_WriteAB) {
int bank = A&3;
chrr[bank] = V&63;
Mapper190_Sync();
}
static void Mapper190_Power(void) {
FCEU_CheatAddRAM(0x2000 >> 10, 0x6000, WRAM);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetWriteHandler(0x8000, 0x9FFF, Mapper190_Write89);
SetWriteHandler(0xA000, 0xBFFF, Mapper190_WriteAB);
SetWriteHandler(0xC000, 0xDFFF, Mapper190_WriteCD);
Mapper190_Sync();
setmirror(MI_V);
}
static void Mapper190_Close(void) {
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void Mapper190_Restore(int) {
Mapper190_Sync();
}
void Mapper190_Init(CartInfo *info) {
info->Power = Mapper190_Power;
info->Close = Mapper190_Close;
GameStateRestore = Mapper190_Restore;
WRAM = (uint8*)FCEU_gmalloc(0x2000);
SetupCartPRGMapping(0x10, WRAM, 0x2000, 1);
chrr[0] = chrr[1] = chrr[2] = chrr[3] = prgr = 0;
AddExState(&prgr, 1, 0, "PRGR");
AddExState(chrr, 4, 0, "CHRR");
AddExState(WRAM, 0x2000, 0, "WRAM");
}
+43 -25
View File
@@ -1,30 +1,40 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
* Copyright (C) 2019 Libretro Team
* Copyright (C) 2020
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* PCB-018 board, discrete multigame cart 110-in-1
*
* Mapper 225
* Mapper 255
*
*/
/* 2020-2-20 - merge mapper 255, re-implement extra RAM */
#include "mapinc.h"
static uint8 prot[4], prg, mode, chr, mirr;
static uint8 extraRAM[4], prg, mode, chr, mirr;
static SFORMAT StateRegs[] =
{
{ prot, 4, "PROT" },
{ extraRAM, 4, "PROT" },
{ &prg, 1, "PRG" },
{ &chr, 1, "CHR" },
{ &mode, 1, "MODE" },
@@ -36,14 +46,15 @@ static void Sync(void) {
if (mode) {
setprg16(0x8000, prg);
setprg16(0xC000, prg);
} else
}
else
setprg32(0x8000, prg >> 1);
setchr8(chr);
setmirror(mirr ^ 1);
}
static DECLFW(M225Write) {
uint32 bank = (A >> 14) & 1;
uint8 bank = (A >> 14) & 1;
mirr = (A >> 13) & 1;
mode = (A >> 12) & 1;
chr = (A & 0x3f) | (bank << 6);
@@ -52,18 +63,21 @@ static DECLFW(M225Write) {
}
static DECLFW(M225LoWrite) {
/* e.g. 115-in-1 [p1][!] CRC32 0xb39d30b4 */
if (A & 0x800) extraRAM[A & 3] = V & 0x0F;
}
static DECLFR(M225LoRead) {
return 0;
if (A & 0x800) return extraRAM[A & 3];
return X.DB;
}
static void M225Power(void) {
prg = 0;
mode = 0;
Sync();
SetReadHandler(0x5000, 0x5FFF, M225LoRead);
SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
SetReadHandler(0x5000, 0x5fff, M225LoRead);
SetWriteHandler(0x5000, 0x5fff, M225LoWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M225Write);
}
@@ -84,3 +98,7 @@ void Mapper225_Init(CartInfo *info) {
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper255_Init(CartInfo *info) {
Mapper225_Init(info);
}
+58 -11
View File
@@ -19,36 +19,79 @@
*/
#include "mapinc.h"
#include "ines.h"
static uint16 cmdreg = 0;
static uint8 openbus = 0;
// For carts with extra 128K prg rom (Contra)
static uint8 unrom = 0;
static uint8 unromData = 0;
static uint32 PRGROMSize = 0;
static uint16 cmdreg;
static SFORMAT StateRegs[] =
{
{ &cmdreg, 2, "CREG" },
{ &openbus, 1, "OB" },
{ &unrom, 1, "UROM" },
{ &unromData, 1, "UDTA" },
{ 0 }
};
static void Sync(void) {
if (cmdreg & 0x400)
setmirror(MI_0);
else
setmirror(((cmdreg >> 13) & 1) ^ 1);
if (cmdreg & 0x800) {
setprg16(0x8000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
setprg16(0xC000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
} else
setprg32(0x8000, ((cmdreg & 0x300) >> 4) | (cmdreg & 0x1F));
if (unrom) {
int PRGPageCount = PRGROMSize / (16 * 1024);
setprg16(0x8000, PRGPageCount & 0xC0 | (unromData & 7));
setprg16(0xC000, PRGPageCount & 0xC0 | 7);
setmirror(MI_V);
} else {
uint8 bank = ((cmdreg & 0x300) >> 3) | (cmdreg & 0x1F);
if (bank >= (PRGROMSize / (32 * 1024))) {
openbus = 1;
} else {
if (cmdreg & 0x400)
setmirror(MI_0);
else
setmirror(((cmdreg >> 13) & 1) ^ 1);
if (cmdreg & 0x800) {
setprg16(0x8000, (bank << 1) | ((cmdreg >> 12) & 1));
setprg16(0xC000, (bank << 1) | ((cmdreg >> 12) & 1));
} else
setprg32(0x8000, bank);
}
}
}
static DECLFR(M235Read) {
if (openbus) {
openbus = 0;
return X.DB;
}
return CartBR(A);
}
static DECLFW(M235Write) {
cmdreg = A;
unromData = V;
Sync();
}
static void M235Reset(void) {
cmdreg = 0;
unromData = 0;
if (PRGROMSize & 0x20000)
unrom = (unrom + 1) & 1;
Sync();
}
static void M235Power(void) {
setchr8(0);
SetWriteHandler(0x8000, 0xFFFF, M235Write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x8000, 0xFFFF, M235Read);
cmdreg = 0;
unromData = 0;
unrom = 0;
Sync();
}
@@ -57,7 +100,11 @@ static void M235Restore(int version) {
}
void Mapper235_Init(CartInfo *info) {
info->Reset = M235Reset;
info->Power = M235Power;
GameStateRestore = M235Restore;
AddExState(&StateRegs, ~0, 0, 0);
// needs raw, non-pow2 PRGROM size for comparison
PRGROMSize = head.ROM_size * 16384;
}
+2 -3
View File
@@ -22,7 +22,7 @@
static uint8 regs[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE = 0;
static SFORMAT StateRegs[] =
{
@@ -79,8 +79,7 @@ void Mapper246_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+3 -4
View File
@@ -23,9 +23,9 @@
static uint8 creg[8], preg[2];
static int32 IRQa, IRQCount, IRQClock, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
static uint32 CHRRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -127,8 +127,7 @@ void Mapper252_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
+3 -4
View File
@@ -23,9 +23,9 @@
static uint8 chrlo[8], chrhi[8], prg[2], mirr, vlock;
static int32 IRQa, IRQCount, IRQLatch, IRQClock;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
static uint32 CHRRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -144,8 +144,7 @@ void Mapper253_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+6 -5
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2012 FCEUX team
Copyright (C) 2012-2017 FCEUX team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -53,8 +53,8 @@ void Mirror(uint8 value)
static void Sync()
{
int prglo;
int prghi;
int prglo = 0;
int prghi = 0;
int outb = outer << 1;
//this can probably be rolled up, but i have no motivation to do so
@@ -127,20 +127,21 @@ static void Sync()
static DECLFW(WriteEXP)
{
uint32 addr = A;
//uint32 addr = A;
uint8 value = V;
reg = value & 0x81;
}
static DECLFW(WritePRG)
{
uint32 addr = A;
//uint32 addr = A;
uint8 value = V;
switch (reg)
{
case 0x00:
chr = value & 3;
Mirror(value);
Sync();
break;
case 0x01:
prg = value & 15;
+98
View File
@@ -0,0 +1,98 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
static uint16 latchAddr;
static uint8 latchData;
static uint8 submapper;
static SFORMAT StateRegs[] =
{
{ &latchAddr, 2, "ADDR" },
{ &latchData, 1, "DATA" },
{ 0 }
};
static void Mapper354_Sync(void)
{
int prg = latchData & 0x3F | latchAddr << 2 & 0x40 | latchAddr >> 5 & 0x80;
switch (latchAddr & 7)
{
case 0: case 4:
setprg32(0x8000, prg >> 1);
break;
case 1:
setprg16(0x8000, prg);
setprg16(0xC000, prg | 7);
break;
case 2: case 6:
setprg8(0x8000, prg << 1 | latchData >> 7);
setprg8(0xA000, prg << 1 | latchData >> 7);
setprg8(0xC000, prg << 1 | latchData >> 7);
setprg8(0xE000, prg << 1 | latchData >> 7);
break;
case 3: case 7:
setprg16(0x8000, prg);
setprg16(0xC000, prg);
break;
case 5:
setprg8(0x6000, prg << 1 | latchData >> 7);
setprg32(0x8000, prg >> 1 | 3);
break;
}
SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], (latchAddr & 8) ? 0 : 1);
setchr8(0);
setmirror(latchData & 0x40 ? MI_H : MI_V);
}
static DECLFW(Mapper354_WriteLatch)
{
latchData = V;
latchAddr = A & 0xFFFF;
Mapper354_Sync();
}
static void Mapper354_Reset(void)
{
latchAddr = latchData = 0;
Mapper354_Sync();
}
static void Mapper354_Power(void)
{
latchAddr = latchData = 0;
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(submapper == 1 ? 0xE000 : 0xF000, 0xFFFF, Mapper354_WriteLatch);
Mapper354_Sync();
}
static void StateRestore(int version) {
Mapper354_Sync();
}
void Mapper354_Init(CartInfo *info)
{
submapper = info->submapper;
info->Power = Mapper354_Power;
info->Reset = Mapper354_Reset;
GameStateRestore = StateRestore;
AddExState(StateRegs, ~0, 0, 0);
}
+7 -1
View File
@@ -22,11 +22,12 @@
#include "mapinc.h"
static uint8 latche;
static uint8 latche, mirr;
static SFORMAT StateRegs[] =
{
{ &latche, 1, "LATC" },
{ &mirr, 1, "MIRR" },
{ 0 }
};
@@ -36,6 +37,11 @@ static void Sync(void) {
}
static DECLFW(M36Write) {
switch((A>>12)&7) { // need to 4-in-1 MGC-26 BMC, doesnt break other games though
case 0: mirr = MI_V; setmirror(mirr); break;
case 4: mirr = MI_H; setmirror(mirr); break;
}
latche = V;
Sync();
}
+2 -3
View File
@@ -24,7 +24,7 @@ static uint8 chr_reg[4];
static uint8 kogame, prg_reg, nt1, nt2, mirr;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE, count;
static uint32 WRAMSIZE=0, count=0;
static SFORMAT StateRegs[] =
{
@@ -156,8 +156,7 @@ void Mapper68_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
+2 -3
View File
@@ -25,7 +25,7 @@ static uint8 cmdreg, preg[4], creg[8], mirr;
static uint8 IRQa;
static int32 IRQCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -266,8 +266,7 @@ void Mapper69_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
Mapper69_ESI();
+5
View File
@@ -21,6 +21,7 @@
#include "mapinc.h"
static uint8 preg, mirr;
static int hardmirr;
static SFORMAT StateRegs[] =
{
@@ -35,6 +36,8 @@ static void Sync(void) {
setchr8(0);
if(mirr)
setmirror(mirr);
else
setmirror(hardmirr); // restore hardwired mirroring
}
static DECLFW(M71Write) {
@@ -46,6 +49,7 @@ static DECLFW(M71Write) {
}
static void M71Power(void) {
preg = 0;
mirr = 0;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
@@ -57,6 +61,7 @@ static void StateRestore(int version) {
}
void Mapper71_Init(CartInfo *info) {
hardmirr = info->mirror;
info->Power = M71Power;
GameStateRestore = StateRestore;
+1 -2
View File
@@ -169,8 +169,7 @@ void Mapper80_Init(CartInfo *info) {
GameStateRestore = StateRestore;
if (info->battery) {
info->SaveGame[0] = wram;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( wram, sizeof(wram) );
}
AddExState(&StateRegs80, ~0, 0, 0);
+76
View File
@@ -0,0 +1,76 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2017 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
static uint8 bios_prg, rom_prg, rom_mode, mirror;
static SFORMAT StateRegs[] =
{
{ &bios_prg, 1, "BREG" },
{ &rom_prg, 1, "RREG" },
{ &rom_mode, 1, "RMODE" },
{ 0 }
};
static void Sync(void) {
setchr8(0);
if(rom_mode&2) {
setprg16r(0,0x8000,(bios_prg&0xF)|(rom_prg&0x70));
} else {
setprg16r(1,0x8000,bios_prg&3);
}
setprg16r(0,0xC000,rom_prg&0x7F);
setmirror(((bios_prg>>4)&1)^1);
}
static DECLFW(BMC80013BWrite) {
uint8 reg = (A>>13)&3;
if(reg == 0) {
bios_prg = V;
} else {
rom_prg = V;
rom_mode = reg;
}
Sync();
}
static void BMC80013BPower(void) {
bios_prg=rom_prg=rom_mode=mirror=0;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, BMC80013BWrite);
}
static void BMC80013BReset(void) {
bios_prg=rom_prg=rom_mode=mirror=0;
Sync();
}
static void StateRestore(int version) {
Sync();
}
void BMC80013B_Init(CartInfo *info) {
info->Reset = BMC80013BReset;
info->Power = BMC80013BPower;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
+2 -3
View File
@@ -25,7 +25,7 @@
static uint8 regs[9], ctrl;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -90,8 +90,7 @@ void Mapper82_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
+1 -2
View File
@@ -19,7 +19,6 @@
*
* Super Game (Sugar Softec) protected mapper
* Pocahontas 2 (Unl) [U][!], etc.
* TODO: 9in1 LION KING HANGS!
*/
#include "mapinc.h"
@@ -139,7 +138,7 @@ static DECLFW(UNL8237Write) {
}
static DECLFW(UNL8237ExWrite) {
switch (A) {
switch (A & 0xF007) {
case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break;
case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break;
case 0x5007: EXPREGS[2] = V; break;
-6
View File
@@ -1,6 +0,0 @@
import glob
source_list = glob.glob('*.cpp')+glob.glob('*.c')
for x in range(len(source_list)):
source_list[x] = 'boards/' + source_list[x]
Return('source_list')
+1 -2
View File
@@ -92,8 +92,7 @@ void MapperNNN_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
*/
AddExState(&StateRegs, ~0, 0, 0);
+40 -13
View File
@@ -26,7 +26,8 @@ static uint8 dipswitch;
static void (*WSync)(void);
static readfunc defread;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 hasBattery = 0;
static DECLFW(LatchWrite) {
latche = A;
@@ -77,8 +78,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint16
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@@ -122,7 +122,7 @@ static void UNL43272Sync(void) {
if ((latche & 0x81) == 0x81) {
setprg32(0x8000, (latche & 0x38) >> 3);
} else
FCEU_printf("unrecognized command %04!\n", latche);
FCEU_printf("unrecognized command %04x!\n", latche);
setchr8(0);
setmirror(0);
}
@@ -221,6 +221,23 @@ void Mapper92_Init(CartInfo *info) {
Latch_Init(info, M92Sync, NULL, 0x80B0, 0x8000, 0xFFFF, 0);
}
//------------------ Map 174 ---------------------------
static void M174Sync(void) {
if (latche & 0x80) {
setprg32(0x8000, (latche >> 5) & 3);
} else {
setprg16(0x8000, (latche >> 4) & 7);
setprg16(0xC000, (latche >> 4) & 7);
}
setchr8((latche >> 1) & 7);
setmirror((latche & 1) ^ 1);
}
void Mapper174_Init(CartInfo *info) {
Latch_Init(info, M174Sync, NULL, 0, 0x8000, 0xFFFF, 0);
}
//------------------ Map 200 ---------------------------
static void M200Sync(void) {
@@ -237,13 +254,8 @@ void Mapper200_Init(CartInfo *info) {
//------------------ Map 201 ---------------------------
static void M201Sync(void) {
if (latche & 8) {
setprg32(0x8000, latche & 3);
setchr8(latche & 3);
} else {
setprg32(0x8000, 0);
setchr8(0);
}
setprg32(0x8000, latche & 3);
setchr8(latche & 3);
}
void Mapper201_Init(CartInfo *info) {
@@ -309,8 +321,14 @@ void Mapper212_Init(CartInfo *info) {
//------------------ Map 213 ---------------------------
static void M213Sync(void) {
setprg32(0x8000, (latche >> 1) & 3);
if(latche & 0x40) {
setprg16(0x8000, (latche & 7));
setprg16(0xC000, (latche & 7));
} else {
setprg32(0x8000, (latche >> 1) & 3);
}
setchr8((latche >> 3) & 7);
setmirror(((latche & 1)^((latche >> 6) & 1)) ^ 1);
}
void Mapper213_Init(CartInfo *info) {
@@ -341,12 +359,20 @@ void Mapper217_Init(CartInfo *info) {
}
//------------------ Map 227 ---------------------------
static void M227Sync(void) {
uint32 S = latche & 1;
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
uint32 L = (latche >> 9) & 1;
// Only Waixing appear to have battery flag enabled, while multicarts don't.
// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect
// on non battery-enabled carts.
if (!hasBattery && (latche & 0x80) == 0x80)
/* CHR-RAM write protect hack, needed for some multicarts */
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
else
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
if ((latche >> 7) & 1) {
if (S) {
setprg32(0x8000, p >> 1);
@@ -381,6 +407,7 @@ static void M227Sync(void) {
void Mapper227_Init(CartInfo *info) {
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
hasBattery = info->battery;
}
//------------------ Map 229 ---------------------------
+276 -134
View File
@@ -29,7 +29,7 @@ static uint8 IRQa;
static int16 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -48,120 +48,205 @@ static SFORMAT StateRegs[] =
#define X24C0X_READ 3
#define X24C0X_WRITE 4
static uint8 x24c0x_data[256], x24c0x_state;
static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount;
static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe;
static uint8 x24c0x_data[512];
static SFORMAT x24c0xStateRegs[] =
static uint8 x24c01_state;
static uint8 x24c01_addr, x24c01_word, x24c01_latch, x24c01_bitcount;
static uint8 x24c01_sda, x24c01_scl, x24c01_out;
static uint8 x24c02_state;
static uint8 x24c02_addr, x24c02_word, x24c02_latch, x24c02_bitcount;
static uint8 x24c02_sda, x24c02_scl, x24c02_out;
static SFORMAT x24c01StateRegs[] =
{
{ &x24c0x_addr, 1, "ADDR" },
{ &x24c0x_word, 1, "WORD" },
{ &x24c0x_latch, 1, "LATC" },
{ &x24c0x_bitcount, 1, "BITC" },
{ &x24c0x_sda, 1, "SDA" },
{ &x24c0x_scl, 1, "SCL" },
{ &x24c0x_out, 1, "OUT" },
{ &x24c0x_oe, 1, "OE" },
{ &x24c0x_state, 1, "STAT" },
{ &x24c01_addr, 1, "ADDR" },
{ &x24c01_word, 1, "WORD" },
{ &x24c01_latch, 1, "LATC" },
{ &x24c01_bitcount, 1, "BITC" },
{ &x24c01_sda, 1, "SDA" },
{ &x24c01_scl, 1, "SCL" },
{ &x24c01_out, 1, "OUT" },
{ &x24c01_state, 1, "STAT" },
{ 0 }
};
static void x24c0x_init() {
x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0;
x24c0x_state = X24C0X_STANDBY;
static SFORMAT x24c02StateRegs[] =
{
{ &x24c02_addr, 1, "ADDR" },
{ &x24c02_word, 1, "WORD" },
{ &x24c02_latch, 1, "LATC" },
{ &x24c02_bitcount, 1, "BITC" },
{ &x24c02_sda, 1, "SDA" },
{ &x24c02_scl, 1, "SCL" },
{ &x24c02_out, 1, "OUT" },
{ &x24c02_state, 1, "STAT" },
{ 0 }
};
static void x24c01_init() {
x24c01_addr = x24c01_word = x24c01_latch = x24c01_bitcount = x24c01_sda = x24c01_scl = 0;
x24c01_state = X24C0X_STANDBY;
}
static void x24c0x_write(uint8 data) {
uint8 sda = (data >> 6) & 1;
uint8 scl = (data >> 5) & 1;
x24c0x_oe = (data >> 7);
static void x24c02_init() {
x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0;
x24c02_state = X24C0X_STANDBY;
}
if(x24c0x_scl && scl) {
if(x24c0x_sda && !sda) { // START
x24c0x_state = X24C0X_ADDRESS;
x24c0x_bitcount = 0;
x24c0x_addr = 0;
} else if(!x24c0x_sda && sda) { //STOP
x24c0x_state = X24C0X_STANDBY;
static void x24c01_write(uint8 data) {
uint8 scl = (data >> 5) & 1;
uint8 sda = (data >> 6) & 1;
if(x24c01_scl && scl) {
if(x24c01_sda && !sda) { // START
x24c01_state = X24C0X_ADDRESS;
x24c01_bitcount = 0;
x24c01_addr = 0;
} else if(!x24c01_sda && sda) { //STOP
x24c01_state = X24C0X_STANDBY;
}
} else if(!x24c0x_scl && scl) { // RISING EDGE
switch(x24c0x_state) {
} else if(!x24c01_scl && scl) { // RISING EDGE
switch(x24c01_state) {
case X24C0X_ADDRESS:
if(x24c0x_bitcount < 7) {
x24c0x_addr <<= 1;
x24c0x_addr |= sda;
if(x24c01_bitcount < 7) {
x24c01_addr <<= 1;
x24c01_addr |= sda;
} else {
if(!x24c02) // X24C01 mode
x24c0x_word = x24c0x_addr;
if(sda) { // READ COMMAND
x24c0x_state = X24C0X_READ;
} else { // WRITE COMMAND
if(x24c02) // X24C02 mode
x24c0x_state = X24C0X_WORD;
else
x24c0x_state = X24C0X_WRITE;
}
x24c01_word = x24c01_addr;
if(sda) // READ COMMAND
x24c01_state = X24C0X_READ;
else // WRITE COMMAND
x24c01_state = X24C0X_WRITE;
}
x24c0x_bitcount++;
break;
case X24C0X_WORD:
if(x24c0x_bitcount == 8) { // ACK
x24c0x_word = 0;
x24c0x_out = 0;
} else { // WORD ADDRESS INPUT
x24c0x_word <<= 1;
x24c0x_word |= sda;
if(x24c0x_bitcount == 16) { // END OF ADDRESS INPUT
x24c0x_bitcount = 7;
x24c0x_state = X24C0X_WRITE;
}
}
x24c0x_bitcount++;
x24c01_bitcount++;
break;
case X24C0X_READ:
if (x24c0x_bitcount == 8) { // ACK
x24c0x_out = 0;
x24c0x_latch = x24c0x_data[x24c0x_word];
x24c0x_bitcount = 0;
} else { // REAL OUTPUT
x24c0x_out = x24c0x_latch >> 7;
x24c0x_latch <<= 1;
x24c0x_bitcount++;
if(x24c0x_bitcount == 8) {
x24c0x_word++;
x24c0x_word &= 0xff;
if (x24c01_bitcount == 8) { // ACK
x24c01_out = 0;
x24c01_latch = x24c0x_data[x24c01_word];
x24c01_bitcount = 0;
} else { // REAL OUTPUT
x24c01_out = x24c01_latch >> 7;
x24c01_latch <<= 1;
x24c01_bitcount++;
if(x24c01_bitcount == 8) {
x24c01_word++;
x24c01_word &= 0xff;
}
}
break;
case X24C0X_WRITE:
if (x24c0x_bitcount == 8) { // ACK
x24c0x_out = 0;
x24c0x_latch = 0;
x24c0x_bitcount = 0;
} else { // REAL INPUT
x24c0x_latch <<= 1;
x24c0x_latch |= sda;
x24c0x_bitcount++;
if(x24c0x_bitcount == 8) {
x24c0x_data[x24c0x_word] = x24c0x_latch;
x24c0x_word++;
x24c0x_word &= 0xff;
if (x24c01_bitcount == 8) { // ACK
x24c01_out = 0;
x24c01_latch = 0;
x24c01_bitcount = 0;
} else { // REAL INPUT
x24c01_latch <<= 1;
x24c01_latch |= sda;
x24c01_bitcount++;
if(x24c01_bitcount == 8) {
x24c0x_data[x24c01_word] = x24c01_latch;
x24c01_word++;
x24c01_word &= 0xff;
}
}
break;
}
}
x24c0x_sda = sda;
x24c0x_scl = scl;
x24c01_sda = sda;
x24c01_scl = scl;
}
static uint8 x24c0x_read() {
return x24c0x_out << 4;
static void x24c02_write(uint8 data) {
uint8 scl = (data >> 5) & 1;
uint8 sda = (data >> 6) & 1;
if (x24c02_scl && scl) {
if (x24c02_sda && !sda) { // START
x24c02_state = X24C0X_ADDRESS;
x24c02_bitcount = 0;
x24c02_addr = 0;
} else if (!x24c02_sda && sda) { //STOP
x24c02_state = X24C0X_STANDBY;
}
} else if (!x24c02_scl && scl) { // RISING EDGE
switch (x24c02_state) {
case X24C0X_ADDRESS:
if (x24c02_bitcount < 7) {
x24c02_addr <<= 1;
x24c02_addr |= sda;
} else {
if (sda) // READ COMMAND
x24c02_state = X24C0X_READ;
else // WRITE COMMAND
x24c02_state = X24C0X_WORD;
}
x24c02_bitcount++;
break;
case X24C0X_WORD:
if (x24c02_bitcount == 8) { // ACK
x24c02_word = 0;
x24c02_out = 0;
} else { // WORD ADDRESS INPUT
x24c02_word <<= 1;
x24c02_word |= sda;
if (x24c02_bitcount == 16) {// END OF ADDRESS INPUT
x24c02_bitcount = 7;
x24c02_state = X24C0X_WRITE;
}
}
x24c02_bitcount++;
break;
case X24C0X_READ:
if (x24c02_bitcount == 8) { // ACK
x24c02_out = 0;
x24c02_latch = x24c0x_data[x24c02_word|0x100];
x24c02_bitcount = 0;
} else { // REAL OUTPUT
x24c02_out = x24c02_latch >> 7;
x24c02_latch <<= 1;
x24c02_bitcount++;
if (x24c02_bitcount == 8) {
x24c02_word++;
x24c02_word &= 0xff;
}
}
break;
case X24C0X_WRITE:
if (x24c02_bitcount == 8) { // ACK
x24c02_out = 0;
x24c02_latch = 0;
x24c02_bitcount = 0;
} else { // REAL INPUT
x24c02_latch <<= 1;
x24c02_latch |= sda;
x24c02_bitcount++;
if (x24c02_bitcount == 8) {
x24c0x_data[x24c02_word|0x100] = x24c02_latch;
x24c02_word++;
x24c02_word &= 0xff;
}
}
break;
}
}
x24c02_sda = sda;
x24c02_scl = scl;
}
//
static void SyncMirror(void) {
switch (reg[9] & 3) {
case 0: setmirror(MI_V); break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_0); break;
case 3: setmirror(MI_1); break;
}
}
static void Sync(void) {
if (is153) {
int base = (reg[0] & 1) << 4;
@@ -174,12 +259,7 @@ static void Sync(void) {
setprg16(0x8000, reg[8]);
setprg16(0xC000, ~0);
}
switch (reg[9] & 3) {
case 0: setmirror(MI_V); break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_0); break;
case 3: setmirror(MI_1); break;
}
SyncMirror();
}
static DECLFW(BandaiWrite) {
@@ -192,12 +272,15 @@ static DECLFW(BandaiWrite) {
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break;
case 0x0D: x24c0x_write(V); break;
case 0x0D: if(x24c02) x24c02_write(V); else x24c01_write(V); break;
}
}
static DECLFR(BandaiRead) {
return (X.DB & 0xEF) | x24c0x_read();
if(x24c02)
return (X.DB & 0xEF) | (x24c02_out << 4);
else
return (X.DB & 0xEF) | (x24c01_out << 4);
}
static void BandaiIRQHook(int a) {
@@ -213,7 +296,10 @@ static void BandaiIRQHook(int a) {
static void BandaiPower(void) {
IRQa = 0;
x24c0x_init();
if(x24c02)
x24c02_init();
else
x24c01_init();
Sync();
SetReadHandler(0x6000, 0x7FFF, BandaiRead);
SetReadHandler(0x8000, 0xFFFF, CartBR);
@@ -231,12 +317,11 @@ void Mapper16_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( x24c0x_data + 256, 256 );
AddExState(x24c0x_data, 256, 0, "DATA");
AddExState(&x24c02StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore;
AddExState(&x24c0xStateRegs, ~0, 0, 0);
AddExState(&StateRegs, ~0, 0, 0);
}
@@ -247,12 +332,11 @@ void Mapper159_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 128;
info->addSaveGameBuf( x24c0x_data, 128 );
AddExState(x24c0x_data, 128, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore;
AddExState(&x24c0xStateRegs, ~0, 0, 0);
AddExState(&StateRegs, ~0, 0, 0);
}
@@ -292,8 +376,7 @@ void Mapper153_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
@@ -307,7 +390,9 @@ static int BarcodeReadPos;
static int BarcodeCycleCount;
static uint32 BarcodeOut;
int FCEUI_DatachSet(const uint8 *rcode) {
// #define INTERL2OF5
int FCEUI_DatachSet(uint8 *rcode) {
int prefix_parity_type[10][6] = {
{ 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 },
@@ -330,6 +415,7 @@ int FCEUI_DatachSet(const uint8 *rcode) {
};
uint8 code[13 + 1];
uint32 tmp_p = 0;
uint32 csum = 0;
int i, j;
int len;
@@ -341,18 +427,46 @@ int FCEUI_DatachSet(const uint8 *rcode) {
}
if (len != 13 && len != 12 && len != 8 && len != 7) return(0);
#define BS(x) BarcodeData[tmp_p] = x; tmp_p++
#define BS(x) BarcodeData[tmp_p] = x; tmp_p++
for (j = 0; j < 32; j++) {
for (j = 0; j < 32; j++) { // delay before sending a code
BS(0x00);
}
/* Left guard bars */
#ifdef INTERL2OF5
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0 cs
BS(1); BS(1); BS(0); BS(0); // 1
#else
// Left guard bars
BS(1); BS(0); BS(1);
if (len == 13 || len == 12) {
uint32 csum;
for (i = 0; i < 6; i++)
if (prefix_parity_type[code[0]][i]) {
for (j = 0; j < 7; j++) {
@@ -362,53 +476,53 @@ int FCEUI_DatachSet(const uint8 *rcode) {
for (j = 0; j < 7; j++) {
BS(data_left_odd[code[i + 1]][j]);
}
/* Center guard bars */
// Center guard bars
BS(0); BS(1); BS(0); BS(1); BS(0);
for (i = 7; i < 12; i++)
for (j = 0; j < 7; j++) {
BS(data_right[code[i]][j]);
}
csum = 0;
for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1);
csum = (10 - (csum % 10)) % 10;
// Calc and write down the control code if not assigned, instead, send code as is
// Battle Rush uses modified type of codes with different control code calculation
if (len == 12) {
for (i = 0; i < 12; i++)
csum += code[i] * ((i & 1) ? 3 : 1);
csum = (10 - (csum % 10)) % 10;
rcode[12] = csum + 0x30; // update check code to the input string as well
rcode[13] = 0;
code[12] = csum;
}
for (j = 0; j < 7; j++) {
BS(data_right[csum][j]);
BS(data_right[code[12]][j]);
}
} else if (len == 8 || len == 7) {
uint32 csum = 0;
for (i = 0; i < 7; i++) csum += (i & 1) ? code[i] : (code[i] * 3);
csum = (10 - (csum % 10)) % 10;
for (i = 0; i < 4; i++)
for (j = 0; j < 7; j++) {
BS(data_left_odd[code[i]][j]);
}
/* Center guard bars */
// Center guard bars
BS(0); BS(1); BS(0); BS(1); BS(0);
for (i = 4; i < 7; i++)
for (j = 0; j < 7; j++) {
BS(data_right[code[i]][j]);
}
csum = 0;
for (i = 0; i < 7; i++)
csum += (i & 1) ? code[i] : (code[i] * 3);
csum = (10 - (csum % 10)) % 10;
rcode[7] = csum + 0x30; // update check code to the input string as well
rcode[8] = 0;
for (j = 0; j < 7; j++) {
BS(data_right[csum][j]);
}
}
/* Right guard bars */
// Right guard bars
BS(1); BS(0); BS(1);
#endif
for (j = 0; j < 32; j++) {
BS(0x00);
}
BS(0xFF);
#undef BS
@@ -419,6 +533,26 @@ int FCEUI_DatachSet(const uint8 *rcode) {
return(1);
}
static void BarcodeSync(void) {
setchr8(0);
setprg16(0x8000, (reg[8] & 0x0F));
setprg16(0xC000, 0x0F);
SyncMirror();
}
static DECLFW(BarcodeWrite) {
A &= 0x0F;
switch (A) {
case 0x00: reg[0] = (V & 8) << 2; x24c01_write(reg[0xD] | reg[0]); break; // extra EEPROM x24C01 used in Battle Rush mini-cart
case 0x08:
case 0x09: reg[A] = V; BarcodeSync(); break;
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break;
case 0x0D: reg[0xD] = V & (~0x20); x24c01_write(reg[0xD] | reg[0]); x24c02_write(V); break;
}
}
static void BarcodeIRQHook(int a) {
BandaiIRQHook(a);
@@ -436,7 +570,7 @@ static void BarcodeIRQHook(int a) {
}
static DECLFR(BarcodeRead) {
return BarcodeOut;
return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut;
}
static void M157Power(void) {
@@ -446,20 +580,28 @@ static void M157Power(void) {
BarcodeOut = 0;
BarcodeCycleCount = 0;
Sync();
x24c01_init();
x24c02_init();
BarcodeSync();
SetWriteHandler(0x6000, 0xFFFF, BandaiWrite);
SetReadHandler(0x6000, 0x7FFF, BarcodeRead);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite);
}
void Mapper157_Init(CartInfo *info) {
is153 = 1;
x24c02 = 1;
info->Power = M157Power;
MapIRQHook = BarcodeIRQHook;
GameInfo->cspecial = SIS_DATACH;
info->battery = 1;
info->addSaveGameBuf( x24c0x_data, 512 );
AddExState(x24c0x_data, 512, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
AddExState(&x24c02StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
+6 -6
View File
@@ -84,12 +84,12 @@ byte_8C29: .BYTE 0,$76, 0, 0, 8
byte_8CC6: .BYTE 0,$78, 0, 0,$12
*/
static uint8 sim0reset[0x1F] = {
0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
};
//static uint8 sim0reset[0x1F] = {
// 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
// 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
// 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
// 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
//};
static void Sync(void) {
setprg32(0x8000, prg_reg);
+164
View File
@@ -0,0 +1,164 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2020 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Double Dragon 310000-in-1 (4040R)
* 700000-in-1 (BS-400R)(Unl)
*/
#include "mapinc.h"
#include "mmc3.h"
static uint8 pointer;
static uint8 offset;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static int getPRGBankBS4XXXR(int bank)
{
if (((~bank) & 1) && (pointer & 0x40))
bank ^= 2;
return (bank & 2) ? (0xFE | (bank & 1)) : EXPREGS[4 | (bank & 1)];
}
static void BS4XXXRPW(uint32 A, uint8 V) {
if ((EXPREGS[3] >> 4) & 0x01)
{
int AND = ((EXPREGS[0] >> 1) & 1) ? 0x0F : 0x0F;
int OR = (EXPREGS[0] & 7) << 4;
int bank0 = getPRGBankBS4XXXR(0);
int bank1 = getPRGBankBS4XXXR(1);
if (!((EXPREGS[3] >> 1) & 1)) //16K Mode
{
setprg8(0x8000, ((bank0) & AND) | OR);
setprg8(0xA000, ((bank1) & AND) | OR);
setprg8(0xC000, ((bank0) & AND) | OR);
setprg8(0xE000, ((bank1) & AND) | OR);
}
else // 32K Mode
{
setprg8(0x8000, ((bank0) & AND) | OR);
setprg8(0xA000, ((bank1) & AND) | OR);
setprg8(0xC000, ((bank0 | 2) & AND) | OR);
setprg8(0xE000, ((bank1 | 2) & AND) | OR);
}
}
else // MMC3 Mode
{
int prgAND = ((EXPREGS[0] >> offset) & 1) ? 0x0F : 0x1F;
int prgOR = (EXPREGS[0] & 7) << 4;
setprg8(A, (V & prgAND) | (prgOR));
}
setprg8r(0x10, 0x6000, 0);
}
static void BS4XXXRCW(uint32 A, uint8 V) {
if ((EXPREGS[3] >> 4) & 1)
{
int AND = ((EXPREGS[0] >> 1) & 1) ? 0x0F : 0x0F;
int bank = EXPREGS[2] & AND;
int chrOR = ((EXPREGS[0] >> 3) & 7) << 4;
setchr8((bank) | (chrOR));
}
else
{
int chrAND = ((EXPREGS[0] >> 1) & 1) ? 0xFF : 0xFF;
int chrOR = ((EXPREGS[0] >> 3) & 7) << 7;
setchr1(A, (V & chrAND) | (chrOR));
}
}
static DECLFW(BS4XXXRHiWrite) {
// FCEU_printf("w: %04x-%02x\n",A,V)
if (A==0x8000)
{
pointer = MMC3_cmd ^ V;
}
else if (A == 0x8001)
{
if((MMC3_cmd & 7) > 5)
EXPREGS[4|(MMC3_cmd & 1)] = V;
}
MMC3_CMDWrite(A, V);
}
static DECLFW(BS4XXXRLoWrite) {
// FCEU_printf("w: %04x-%02x\n", A, V);
if (A & 0x800)
{
if (!(EXPREGS[3] & 0x80)) {
EXPREGS[A & 0x03] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else if (EXPREGS[3] & 0x10)
{
EXPREGS[A & 0x03] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else
WRAM[A - 0x6000] = V;
}
else
WRAM[A - 0x6000] = V;
}
static void BSXXXXRPower(void) {
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0;
GenMMC3Power();
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, BS4XXXRLoWrite);
SetWriteHandler(0x8000, 0x9FFF, BS4XXXRHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BS4XXXRClose(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void BSXXXXR_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap = BS4XXXRCW;
pwrap = BS4XXXRPW;
info->Power = BSXXXXRPower;
info->Close = BS4XXXRClose;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(EXPREGS, 8, 0, "EXPR");
}
void BS400R_Init(CartInfo *info) {
offset = 1;
BSXXXXR_Init(info);
}
void BS4040R_Init(CartInfo *info) {
offset = 6;
BSXXXXR_Init(info);
}
+269
View File
@@ -0,0 +1,269 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// mapper 111 - Cheapocabra board by Memblers
// http://forums.nesdev.com/viewtopic.php?p=146039
//
// 512k PRG-ROM in 32k pages (flashable if battery backed is specified)
// 32k CHR-RAM used as:
// 2 x 8k pattern pages
// 2 x 8k nametable pages
//
// Notes:
// - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k?
#include "mapinc.h"
#include "../ines.h"
static uint8 reg;
static uint8 *CHRRAM = NULL;
const uint32 CHRRAMSIZE = 1024 * 32;
static bool flash = false;
static uint8 flash_mode;
static uint8 flash_sequence;
static uint8 flash_id;
static uint8 *FLASHROM = NULL;
const uint32 FLASHROMSIZE = 1024 * 512;
static SFORMAT StateRegs[] =
{
{ &reg, 1, "REG" },
{ 0 }
};
static SFORMAT FlashRegs[] =
{
{ &flash_mode, 1, "FMOD" },
{ &flash_sequence, 1, "FSEQ" },
{ &flash_id, 1, "FMID" },
{ 0 }
};
static void Sync(void) {
// bit 7 controls green LED
// bit 6 controls red LED
int nt = (reg & 0x20) ? 8192 : 0; // bit 5 controls 8k nametable page
int chr = (reg & 0x10) ? 1 : 0; // bit 4 selects 8k CHR page
int prg = (reg & 0x0F); // bits 0-3 select 32k PRG page
nt += (16 * 1024);
for (int n=0; n<4; ++n)
{
setntamem(CHRRAM + nt + (1024 * n),1,n);
}
setchr8r(0x10, chr);
uint32 prg_chip = flash ? 0x10 : 0;
setprg32r(prg_chip,0x8000,prg);
}
static DECLFW(M111Write) {
if ((A >= 0x5000 && A <= 0x5FFF) || (A >= 0x7000 && A <= 0x7FFF))
{
reg = V;
Sync();
}
}
static DECLFR(M111FlashID)
{
// Software ID mode is undefined by the datasheet for all but the lowest 2 addressable bytes,
// but some tests of the chip currently being used found it repeats in 512-byte patterns.
// http://forums.nesdev.com/viewtopic.php?p=178728#p178728
uint32 aid = A & 0x1FF;
switch (aid)
{
case 0: return 0xBF;
case 1: return 0xB7;
default: return 0xFF;
}
}
void M111FlashIDEnter()
{
if (flash_id) return;
flash_id = 1;
SetReadHandler(0x8000,0xFFFF,M111FlashID);
}
void M111FlashIDExit()
{
if (!flash_id) return;
flash_id = 0;
SetReadHandler(0x8000,0xFFFF,CartBR);
}
static DECLFW(M111Flash) {
if (A < 0x8000 || A > 0xFFFF) return;
uint32 flash_addr = ((reg & 0x0F) << 15) | (A & 0x7FFF);
uint32 command_addr = flash_addr & 0x7FFF;
enum
{
FLASH_MODE_READY = 0,
FLASH_MODE_COMMAND,
FLASH_MODE_BYTE_WRITE,
FLASH_MODE_ERASE,
};
switch (flash_mode)
{
default:
case FLASH_MODE_READY:
if (command_addr == 0x5555 && V == 0xAA)
{
flash_mode = FLASH_MODE_COMMAND;
flash_sequence = 0;
}
else if (V == 0xF0)
{
M111FlashIDExit();
}
break;
case FLASH_MODE_COMMAND:
if (flash_sequence == 0)
{
if (command_addr == 0x2AAA && V == 0x55)
flash_sequence = 1;
else
flash_mode = FLASH_MODE_READY;
}
else if (flash_sequence == 1)
{
if (command_addr == 0x5555)
{
flash_sequence = 0;
switch (V)
{
default: flash_mode = FLASH_MODE_READY; break;
case 0xA0: flash_mode = FLASH_MODE_BYTE_WRITE; break;
case 0x80: flash_mode = FLASH_MODE_ERASE; break;
case 0x90: M111FlashIDEnter(); flash_mode = FLASH_MODE_READY; break;
case 0xF0: M111FlashIDExit(); flash_mode = FLASH_MODE_READY; break;
}
}
else
flash_mode = FLASH_MODE_READY;
}
else
flash_mode = FLASH_MODE_READY; // should be unreachable
break;
case FLASH_MODE_BYTE_WRITE:
FLASHROM[flash_addr] &= V;
flash_mode = FLASH_MODE_READY;
break;
case FLASH_MODE_ERASE:
if (flash_sequence == 0)
{
if (command_addr == 0x5555 && V == 0xAA)
flash_sequence = 1;
else
flash_mode = FLASH_MODE_READY;
}
else if (flash_sequence == 1)
{
if (command_addr == 0x2AAA && V == 0x55)
flash_sequence = 2;
else
flash_mode = FLASH_MODE_READY;
}
else if (flash_sequence == 2)
{
if (command_addr == 0x5555 && V == 0x10) // erase chip
{
memset(FLASHROM, 0xFF, FLASHROMSIZE);
}
else if (V == 0x30) // erase 4k sector
{
uint32 sector = flash_addr & 0x7F000;
memset(FLASHROM + sector, 0xFF, 1024 * 4);
}
flash_mode = FLASH_MODE_READY;
}
else
flash_mode = FLASH_MODE_READY; // should be unreachable
break;
}
}
static void M111Power(void) {
reg = 0xFF;
Sync();
SetReadHandler(0x8000, 0xffff, CartBR);
SetWriteHandler(0x5000, 0x5fff, M111Write);
SetWriteHandler(0x7000, 0x7fff, M111Write);
if (flash)
{
flash_mode = 0;
flash_sequence = 0;
flash_id = false;
SetWriteHandler(0x8000, 0xFFFF, M111Flash);
}
}
static void M111Close(void) {
if (CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM = NULL;
if (FLASHROM)
FCEU_gfree(FLASHROM);
FLASHROM = NULL;
}
static void StateRestore(int version) {
Sync();
}
void Mapper111_Init(CartInfo *info) {
info->Power = M111Power;
info->Close = M111Close;
CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1);
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM");
flash = (info->battery != 0);
if (flash)
{
FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE);
info->addSaveGameBuf( FLASHROM, FLASHROMSIZE );
AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM");
AddExState(&FlashRegs, ~0, 0, 0);
// copy PRG ROM into FLASHROM, use it instead of PRG ROM
const uint32 PRGSIZE = ROM_size * 16 * 1024;
for (uint32 w=0, r=0; w<FLASHROMSIZE; ++w)
{
FLASHROM[w] = ROM[r];
++r;
if (r >= PRGSIZE) r = 0;
}
SetupCartPRGMapping(0x10, FLASHROM, FLASHROMSIZE, 0);
}
}
+409 -71
View File
@@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2015 CaH4e3, ClusteR
* Copyright (C) 2018 CaH4e3, Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,38 +17,148 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM
* only MMC3 mode
* SMD132 and SMD133 ASICs, MMC3 clones that can address up to 32 MiB of PRG-ROM, 256 KiB of CHR-RAM, and 8 KiB of WRAM.
*
* 6000 (xx76x210) | 0xC0
* 6001 (xxx354x)
* 6002 = 0
* 6003 = 0
* COOLBOY cartridges use registers at address $6xxx
* MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
*
* $xxx0
* 7 bit 0
* ---- ----
* ABCC DEEE
* |||| ||||
* |||| |+++-- PRG offset (PRG A19, A18, A17)
* |||| +----- Alternate CHR A17
* ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18)
* |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
* +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*
* $xxx1
* 7 bit 0
* ---- ----
* GHIJ KKLx
* |||| |||
* |||| ||+--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
* |||+-++---- PRG offset (in order: PRG A20, A22, A21)
* ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
* |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
* +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*
* $xxx2
* 7 bit 0
* ---- ----
* xxxx MMMM
* ||||
* ++++-- CHR offset for GNROM mode (CHR A16, A15, A14, A13)
*
* $xxx3
* 7 bit 0
* ---- ----
* NPZP QQRx
* |||| |||
* |||| +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
* |||+------- 1: GNROM mode; 0: MMC3 mode
* |||| (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
* |||| 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
* ||+-------- 1: Also enable PRG RAM in $5000-$5FFF
* |+-+------- Banking mode
* |+--------- "Weird MMC3 mode"
* +---------- Lockout (prevent further writes to all registers but the one at $xxx2, only works in MMC3 mode)
*
* Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper,
* which allows you to rewrite flash memory without soldering.
* This also allows console to write data to the cartridge.
* This behavior is not emulated.
* No cart has been discovered so far that makes use of this feature, but this can be used for homebrew.
*
* hardware tested logic, don't try to understand lol
*/
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static void COOLBOYCW(uint32 A, uint8 V) {
uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80);
if (EXPREGS[3] & 0x10) {
if (EXPREGS[3] & 0x40) { // Weird mode
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x11;
const int FLASH_CHIP = 0x12;
const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
extern uint8* WRAM;
static uint8* CFI = NULL;
static uint8* Flash = NULL;
static uint8 flash_save = 0;
static uint8 flash_state = 0;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 cfi_mode = 0;
static uint16 regs_base = 0;
static uint8 flag23 = 0;
static uint8 flag45 = 0;
static uint8 flag67 = 0;
static uint8 flag89 = 0;
// Macronix 256-mbit memory CFI data
const uint8 cfi_data[] =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x03,
0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x19,
0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01,
0x00, 0x08, 0x00, 0x00, 0x02, 0x95, 0xA5, 0x05,
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static void AA6023CW(uint32 A, uint8 V) {
if (flag89) {
/*
$xxx0
7 bit 0
---- ----
AB.C DEEE
|| | ||||
|| | |+++-- PRG offset (PRG A19, A18, A17)
|| | +----- Alternate CHR A17
|| +------- 1=Write-protect CHR-RAM
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*/
if (EXPREGS[0] & 0b00010000)
SetupCartCHRMapping(0, VROM, CHRsize[0], 0); // write-protect CHR-RAM
else
SetupCartCHRMapping(0, VROM, CHRsize[0], 1); // allow CHR writes
}
uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000);
if (EXPREGS[3] & 0b00010000) {
if (EXPREGS[3] & 0b01000000) { // Weird mode
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0400:
case 0x0C00: V &= 0x7F; break;
}
}
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit
(V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit
| ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits
| ((A >> 10) & 7) // 2-0 bits
| ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM
);
} else {
if (EXPREGS[3] & 0x40) { // Weird mode, again
}
else {
if (EXPREGS[3] & 0b01000000) { // Weird mode, again
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0000: V = DRegBuf[0]; break;
@@ -58,89 +168,317 @@ static void COOLBOYCW(uint32 A, uint8 V) {
}
}
// Simple MMC3 mode
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask));
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & mask)
| (((EXPREGS[0] & 0x08) << 4) & ~mask)
| ((EXPREGS[0] & 0b00110000) << 4)); // There are some ROMs with 1 MiB CHR-ROM
}
}
static void COOLBOYPW(uint32 A, uint8 V) {
uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2);
uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2);
static void AA6023PW(uint32 A, uint8 V) {
uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]};
// Submappers has scrambled bits
if (flag23) {
/*
$xxx1
7 bit 0
---- ----
GHIL JKKx
|||| |||
|||| +++--- PRG offset (in order: PRG A20, A21, A22)
|||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100101)
| ((CREGS[1] & 0b00001000) << 1) // PRG A20
| ((CREGS[1] & 0b00000010) << 2) // PRG A22
| ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size
}
if (flag45) {
/*
$xxx0
7 bit 0
---- ----
ABCC DEEE
|||| ||||
|||| |+++-- PRG offset (PRG A19, A18, A17)
|||| +----- Alternate CHR A17
||++------- PRG offset (PRG A21, A20)
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
$xxx1
7 bit 0
---- ----
GHIx xxLx
||| |
||| +--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100011)
| ((CREGS[0] & 0b00100000) >> 3) // PRG A21
| (CREGS[0] & 0b00010000); // PRG A20
CREGS[0] &= 0b11001111;
}
uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2);
uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2);
if (flash_save && cfi_mode) {
setprg32r(CFI_CHIP, 0x8000, 0);
return;
}
int chip = !flash_save ? ROM_CHIP : FLASH_CHIP;
// There are ROMs with multiple PRG ROM chips
int chip_offset = 0;
if (flag67 && EXPREGS[0] & 0b00001000) {
chip_offset += ROM_size;
}
// Very weird mode
// Last banks are first in this mode, ignored when MMC3_cmd&0x40
if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
if ((CREGS[3] & 0b01000000) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
switch (A & 0xE000) {
case 0xA000:
if ((MMC3_cmd & 0x40)) V = 0;
break;
case 0xC000:
if (!(MMC3_cmd & 0x40)) V = 0;
break;
case 0xE000:
V = 0;
break;
}
}
// Regular MMC3 mode, internal ROM size can be up to 2048kb!
if (!(EXPREGS[3] & 0x10))
setprg8(A, (((base << 4) & ~mask)) | (V & mask));
else { // NROM mode
if (!(CREGS[3] & 0x10)) {
// Regular MMC3 mode but can be extended to 2MiB
setprg8r(chip, A, ((((base << 4) & ~mask)) | (V & mask)) + chip_offset);
}
else {
// NROM mode
mask &= 0xF0;
uint8 emask;
if ((((EXPREGS[1] & 2) != 0))) // 32kb mode
emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13);
if (CREGS[1] & 0b00000010) // 32kb mode
emask = (CREGS[3] & 0b00001100) | ((A & 0x4000) >> 13);
else // 16kb mode
emask = EXPREGS[3] & 0x0E;
setprg8(A, ((base << 4) & ~mask) // 7-4 bits are from base (see below)
| (V & mask) // ... or from MM3 internal regs, depends on mask
| emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
| ((A & 0x2000) >> 13)); // 0th just as is
emask = CREGS[3] & 0b00001110;
setprg8r(chip, A, (
((base << 4) & ~mask) // 7-4 bits are from base
| (V & mask) // ... or from MM3 internal regs, depends on mask
| emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
| ((A & 0x2000) >> 13) // 0th just as is
) + chip_offset); // For multi-chip ROMs
}
}
static DECLFW(COOLBOYWrite) {
if(A001B & 0x80)
CartBW(A,V);
static DECLFW(AA6023WramWrite) {
if (A001B & 0x80)
CartBW(A, V);
}
static DECLFW(AA6023Write) {
if (A >= 0x6000) {
AA6023WramWrite(A, V);
}
// Deny any further writes when 7th bit is 1 AND 4th is 0
if ((EXPREGS[3] & 0x90) != 0x80) {
EXPREGS[A & 3] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static DECLFW(AA6023FlashWrite) {
if (A < 0xC000)
MMC3_CMDWrite(A, V);
else
MMC3_IRQWrite(A, V);
if (!flash_save) return;
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = A & 0xFFF;
flash_buffer_v[flash_state] = V;
flash_state++;
// enter CFI mode
if ((flash_state == 1) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) {
cfi_mode = 1;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - Flash;
int sector = offset / FLASH_SECTOR_SIZE;
for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
Flash[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
flash_state = 0;
}
// erase chip, lol
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x10)) {
memset(Flash, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - Flash;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
cfi_mode = 0;
}
FixMMC3PRG(MMC3_cmd);
}
static void AA6023Reset(void) {
MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
flash_state = 0;
cfi_mode = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void AA6023Power(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
if (regs_base != 0x5000)
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x7fff, AA6023WramWrite);
SetWriteHandler(regs_base, regs_base + 0x0fff, AA6023Write);
SetWriteHandler(0x8000, 0xFFFF, AA6023FlashWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
}
static void AA6023Restore(int version) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void AA6023Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
if (Flash)
FCEU_gfree(Flash);
if (CFI)
FCEU_gfree(CFI);
WRAM = Flash = CFI = NULL;
}
void CommonInit(CartInfo* info, int submapper)
{
GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery);
pwrap = AA6023PW;
cwrap = AA6023CW;
switch (submapper)
{
case 2:
regs_base = 0x7000;
break;
case 0:
case 4:
case 6:
case 8:
regs_base = 0x6000;
break;
case 1:
case 3:
case 5:
case 7:
case 9:
regs_base = 0x5000;
break;
default:
FCEU_PrintError("Submapper #%d is not supported", submapper);
}
flag23 = (submapper == 2) || (submapper == 3);
flag45 = (submapper == 4) || (submapper == 5);
flag67 = (submapper == 6) || (submapper == 7);
flag89 = (submapper == 8) || (submapper == 9);
info->Power = AA6023Power;
info->Reset = AA6023Reset;
info->Close = AA6023Close;
GameStateRestore = AA6023Restore;
flash_save = info->battery;
if (flash_save) {
CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
for (size_t i = 0; i < sizeof(cfi_data); i++) {
CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i];
}
SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0);
Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]);
for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) {
Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]];
}
SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1);
info->addSaveGameBuf( Flash, PRGsize[ROM_CHIP] );
}
AddExState(EXPREGS, 4, 0, "EXPR");
if (flash_save)
{
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
AddExState(&cfi_mode, sizeof(cfi_mode), 0, "CFIM");
AddExState(Flash, PRGsize[ROM_CHIP], 0, "FLAS");
}
}
static void COOLBOYReset(void) {
MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
// Registers at $6xxx
void COOLBOY_Init(CartInfo* info) {
CommonInit(info, 0);
}
static void COOLBOYPower(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x7fff, COOLBOYWrite);
// Registers at $5xxx
void MINDKIDS_Init(CartInfo* info) {
CommonInit(info, 1);
}
void COOLBOY_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 8, 0);
pwrap = COOLBOYPW;
cwrap = COOLBOYCW;
info->Power = COOLBOYPower;
info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR");
}
// For NES 2.0 loader
void AA6023_Init(CartInfo* info) {
CommonInit(info, info->submapper);
}
File diff suppressed because it is too large Load Diff
+574 -498
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -70,8 +70,7 @@ void UNLEDU2000_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(32768);
SetupCartPRGMapping(0x10, WRAM, 32768, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 32768;
info->addSaveGameBuf( WRAM, 32768 );
}
AddExState(WRAM, 32768, 0, "WRAM");
AddExState(StateRegs, ~0, 0, 0);
+18 -18
View File
@@ -53,22 +53,22 @@
#include "emu2413.h"
static const unsigned char default_inst[15][8] = {
/* VRC7 instruments, January 17, 2004 update -Xodnizel */
{ 0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17 },
{ 0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12 },
{ 0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02 },
{ 0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27 },
{ 0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28 },
{ 0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95 },
{ 0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07 },
{ 0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15 },
{ 0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11 },
{ 0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12 },
{ 0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4 },
{ 0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16 },
{ 0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51 },
{ 0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05 },
{ 0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17 },
/* VRC7 instruments, March 15, 2019 dumped by Nuke.YKT */
{ 0x03, 0x21, 0x05, 0x06, 0xE8, 0x81, 0x42, 0x27 },
{ 0x13, 0x41, 0x14, 0x0D, 0xD8, 0xF6, 0x23, 0x12 },
{ 0x11, 0x11, 0x08, 0x08, 0xFA, 0xB2, 0x20, 0x12 },
{ 0x31, 0x61, 0x0C, 0x07, 0xA8, 0x64, 0x61, 0x27 },
{ 0x32, 0x21, 0x1E, 0x06, 0xE1, 0x76, 0x01, 0x28 },
{ 0x02, 0x01, 0x06, 0x00, 0xA3, 0xE2, 0xF4, 0xF4 },
{ 0x21, 0x61, 0x1D, 0x07, 0x82, 0x81, 0x11, 0x07 },
{ 0x23, 0x21, 0x22, 0x17, 0xA2, 0x72, 0x01, 0x17 },
{ 0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 },
{ 0xB5, 0x01, 0x0F, 0x0F, 0xA8, 0xA5, 0x51, 0x02 },
{ 0x17, 0xC1, 0x24, 0x07, 0xF8, 0xF8, 0x22, 0x12 },
{ 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 },
{ 0x01, 0x02, 0xD3, 0x05, 0xC9, 0x95, 0x03, 0x02 },
{ 0x61, 0x63, 0x0C, 0x00, 0x94, 0xC0, 0x33, 0xF6 },
{ 0x21, 0x72, 0x0D, 0x00, 0xC1, 0xD5, 0x56, 0x06 },
};
/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.)*/
@@ -604,8 +604,8 @@ void OPLL_reset(OPLL * opll) {
for (i = 0; i < 0x40; i++)
OPLL_writeReg(opll, i, 0);
opll->realstep = (uint32)((1 << 31) / rate);
opll->opllstep = (uint32)((1 << 31) / (clk / 72));
opll->realstep = (uint32)((1u << 31) / rate);
opll->opllstep = (uint32)((1u << 31) / (clk / 72));
opll->oplltime = 0;
}
+1 -1
View File
@@ -70,7 +70,7 @@ static void SSSNROMPower(void) {
regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = regs[6] = 0;
regs[7] = 0xff;
Sync();
memset(WRAM, 0x00, WRAMSIZE);
FCEU_MemoryRand(WRAM, WRAMSIZE, true);
// SetWriteHandler(0x0000,0x1FFF,SSSNROMRamWrite);
SetReadHandler(0x0800, 0x1FFF, CartBR);
SetWriteHandler(0x0800, 0x1FFF, CartBW);
+1 -2
View File
@@ -141,8 +141,7 @@ void Mapper6_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+130 -131
View File
@@ -30,26 +30,22 @@ static uint32 CHRRAMSize;
static void BMCFK23CCW(uint32 A, uint8 V)
{
if(EXPREGS[0]&0x40)
setchr8(EXPREGS[2]|unromchr);
else if(EXPREGS[0]&0x20) {
setchr1r(0x10, A, V);
}
else
{
uint16 base=(EXPREGS[2]&0x7F)<<3;
if(EXPREGS[3]&2)
{
int cbase=(MMC3_cmd&0x80)<<5;
setchr1(A,V|base);
setchr1(0x0000^cbase,DRegBuf[0]|base);
setchr1(0x0400^cbase,EXPREGS[6]|base);
setchr1(0x0800^cbase,DRegBuf[1]|base);
setchr1(0x0c00^cbase,EXPREGS[7]|base);
}
else
setchr1(A,V|base);
}
if(EXPREGS[0]&0x40)
setchr8(EXPREGS[2]|unromchr);
else if(EXPREGS[0]&0x20) {
setchr1r(0x10, A, V);
} else {
uint16 base=(EXPREGS[2]&0x7F)<<3;
if(EXPREGS[3]&2) {
int cbase=(MMC3_cmd&0x80)<<5;
setchr1(A,V|base);
setchr1(0x0000^cbase,DRegBuf[0]|base);
setchr1(0x0400^cbase,EXPREGS[6]|base);
setchr1(0x0800^cbase,DRegBuf[1]|base);
setchr1(0x0c00^cbase,EXPREGS[7]|base);
} else
setchr1(A,V|base);
}
}
//some games are wired differently, and this will need to be changed.
@@ -86,110 +82,110 @@ static int prg_mask;
//PRG wrapper
static void BMCFK23CPW(uint32 A, uint8 V)
{
uint32 bank = (EXPREGS[1] & 0x1F);
uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
uint32 block = (EXPREGS[1] & 0x60) | hiblock;
uint32 extra = (EXPREGS[3] & 2);
//uint32 bank = (EXPREGS[1] & 0x1F);
//uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
//uint32 block = (EXPREGS[1] & 0x60) | hiblock;
//uint32 extra = (EXPREGS[3] & 2);
// FCEU_printf("0:%04X:%02X\n",A,V);
if((EXPREGS[0]&7)==4)
setprg32(0x8000,EXPREGS[1]>>1);
else if ((EXPREGS[0]&7)==3)
{
setprg16(0x8000,EXPREGS[1]);
setprg16(0xC000,EXPREGS[1]);
}
else
{
if(EXPREGS[0]&3)
{
if((EXPREGS[0]&7)==4)
setprg32(0x8000,EXPREGS[1]>>1);
else if ((EXPREGS[0]&7)==3) {
setprg16(0x8000,EXPREGS[1]);
setprg16(0xC000,EXPREGS[1]);
} else {
if(EXPREGS[0]&3) {
uint32 blocksize = (6)-(EXPREGS[0]&3);
uint32 mask = (1<<blocksize)-1;
V &= mask;
//V &= 63; //? is this a good idea?
V |= (EXPREGS[1]<<1);
setprg8(A,V);
// FCEU_printf("1:%04X:%02X\n",A,V);
setprg8(A,V);
} else {
setprg8(A,V & prg_mask);
// FCEU_printf("2:%04X:%02X\n",A,V);
}
else
setprg8(A,V & prg_mask);
if(EXPREGS[3]&2)
{
setprg8(0xC000,EXPREGS[4]);
setprg8(0xE000,EXPREGS[5]);
}
}
if(EXPREGS[3]&2) {
setprg8(0xC000,EXPREGS[4]);
setprg8(0xE000,EXPREGS[5]);
}
}
setprg8r(0x10,0x6000,A001B&3);
}
//PRG handler ($8000-$FFFF)
static DECLFW(BMCFK23CHiWrite)
{
if(EXPREGS[0]&0x40)
{
// FCEU_printf("K4:(exp0=%02x)\n",EXPREGS[0]);
// FCEU_printf("W0:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if((EXPREGS[0]&0x60)==0x40) {
// FCEU_printf("W2:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if(EXPREGS[0]&0x30)
unromchr=0;
else
{
else {
unromchr=V&3;
FixMMC3CHR(MMC3_cmd);
}
}
else
{
if((A==0x8001)&&(EXPREGS[3]&2&&MMC3_cmd&8))
{
} else {
if((A==0x8001)&&(EXPREGS[3]&2)&&(MMC3_cmd&8)) {
// FCEU_printf("W3:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
EXPREGS[4|(MMC3_cmd&3)]=V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else
if(A<0xC000) {
if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions
// check if it not interfer with other dumps
if((A==0x8000)&&(V==0x46))
V=0x47;
else if((A==0x8000)&&(V==0x47))
V=0x46;
}
MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd);
}
else
MMC3_IRQWrite(A,V);
}
} else
if(A<0xC000) {
if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions
// check if it not interfer with other dumps
if((A==0x8000)&&(V==0x46))
V=0x47;
else if((A==0x8000)&&(V==0x47))
V=0x46;
}
// FCEU_printf("W1:%04X:%02X\n",A,V);
MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd);
} else {
MMC3_IRQWrite(A,V);
// FCEU_printf("W4:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
}
}
}
//EXP handler ($5000-$5FFF)
static DECLFW(BMCFK23CWrite)
{
if(A&(1<<(dipswitch+4)))
{
if(A&(1<<(dipswitch+4))) {
//printf("+ ");
EXPREGS[A&3]=V;
EXPREGS[A&3]=V;
bool remap = false;
// BUT WHY is there any rom that need it actually?
// bool remap = false;
// FCEU_printf("K3:(exp0=%02x)\n",EXPREGS[0]);
// FCEU_printf("WH0:%04X:%02X\n",A,V);
//sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this.
//sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this.
//if not, 0x24 is a value that is known to work
//however, the low 4 bits are known to control the mapping mode, so 0x20 is more likely to be the immediate remap flag
remap |= ((EXPREGS[0]&0xF0)==0x20);
// remap |= ((EXPREGS[0]&0xF0)==0x20);
//this is an actual mapping reg. i think reg0 controls what happens when reg1 is written. anyway, we have to immediately remap these
remap |= (A&3)==1;
// remap |= (A&3)==1;
//this too.
remap |= (A&3)==2;
// remap |= (A&3)==2;
if(remap)
{
// if(remap) {
// FCEU_printf("WH1:%04X:%02X\n",A,V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
}
// }
}
if(is_BMCFK23CA)
{
if(is_BMCFK23CA) {
if(EXPREGS[3]&2)
EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper)
// FCEU_printf("EXTRA!\n",A);
EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper)
}
//printf("%04X = $%02X\n",A,V);
@@ -199,62 +195,65 @@ static DECLFW(BMCFK23CWrite)
static void BMCFK23CReset(void)
{
//NOT NECESSARY ANYMORE
// BUT WHY?
//this little hack makes sure that we try all the dip switch settings eventually, if we reset enough
// dipswitch++;
// dipswitch&=7;
//printf("BMCFK23C dipswitch set to %d\n",dipswitch);
dipswitch++;
dipswitch&=7;
printf("BMCFK23C dipswitch set to %u\n",dipswitch);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K0:(exp0=%02x)\n",EXPREGS[0]);
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BMCFK23CPower(void)
{
GenMMC3Power();
dipswitch = 0;
GenMMC3Power();
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
GenMMC3Power();
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K1:(exp0=%02x)\n",EXPREGS[0]);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
}
static void BMCFK23CAPower(void)
{
GenMMC3Power();
dipswitch = 0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
GenMMC3Power();
dipswitch = 0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K2:(exp0=%02x)\n",EXPREGS[0]);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
}
static void BMCFK23CAClose(void)
{
if(CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM=NULL;
if(CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM=NULL;
}
void BMCFK23C_Init(CartInfo *info)
{
is_BMCFK23CA = false;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CPower;
info->Reset=BMCFK23CReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CPower;
info->Reset=BMCFK23CReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
prg_bonus = 1;
if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end())
@@ -267,21 +266,21 @@ void BMCFK23CA_Init(CartInfo *info)
{
is_BMCFK23CA = true;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CAPower;
info->Reset=BMCFK23CReset;
info->Close=BMCFK23CAClose;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CAPower;
info->Reset=BMCFK23CReset;
info->Close=BMCFK23CAClose;
CHRRAMSize=8192;
CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1);
AddExState(CHRRAM, CHRRAMSize, 0, "CRAM");
CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1);
AddExState(CHRRAM, CHRRAMSize, 0, "CRAM");
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
prg_bonus = 1;
if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end())
+265
View File
@@ -0,0 +1,265 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 1998 BERO
* Copyright (C) 2002 Xodnizel
* Copyright (C) 2020 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Famicom Network System Base Unit + MMC1 cartridge board
*
*/
#include "mapinc.h"
static uint8 DRegs[4];
static uint8 Buffer, BufferShift;
static uint32 WRAMSIZE=0;
static uint8 *WRAM = NULL;
static int kanji_pos, kanji_page, r40C0;
static int IRQa, IRQCount;
FCEU_MAYBE_UNUSED
static DECLFW(MBWRAM) {
if (!(DRegs[3] & 0x10))
Page[A >> 11][A] = V;
}
FCEU_MAYBE_UNUSED
static DECLFR(MAWRAM) {
if (DRegs[3] & 0x10)
return X.DB;
return(Page[A >> 11][A]);
}
static void MMC1CHR(void) {
setchr8((r40C0 >> 3) & 1);
}
static void MMC1PRG(void) {
uint8 offs_16banks = DRegs[1] & 0x10;
uint8 prg_reg = DRegs[3] & 0xF;
setprg8r(0x10, 0x6000, DRegs[1] & 3);
switch (DRegs[0] & 0xC) {
case 0xC:
setprg16(0x8000, (prg_reg + offs_16banks));
setprg16(0xC000, 0xF + offs_16banks);
break;
case 0x8:
setprg16(0xC000, (prg_reg + offs_16banks));
setprg16(0x8000, offs_16banks);
break;
case 0x0:
case 0x4:
setprg16(0x8000, ((prg_reg & ~1) + offs_16banks));
setprg16(0xc000, ((prg_reg & ~1) + offs_16banks + 1));
break;
}
}
static void MMC1MIRROR(void) {
switch (DRegs[0] & 3) {
case 2: setmirror(MI_V); break;
case 3: setmirror(MI_H); break;
case 0: setmirror(MI_0); break;
case 1: setmirror(MI_1); break;
}
}
static uint64 lreset;
static DECLFW(MMC1_write) {
int n = (A >> 13) - 4;
if ((timestampbase + timestamp) < (lreset + 2))
return;
if (V & 0x80) {
DRegs[0] |= 0xC;
BufferShift = Buffer = 0;
MMC1PRG();
lreset = timestampbase + timestamp;
return;
}
Buffer |= (V & 1) << (BufferShift++);
if (BufferShift == 5) {
FCEU_printf("MMC1 REG%d:%02x (PC %04x)\n", n, Buffer, X.PC);
DRegs[n] = Buffer;
BufferShift = Buffer = 0;
switch (n) {
case 0: MMC1MIRROR();
case 1:
case 2:
case 3: MMC1PRG(); break;
}
}
}
static void MMC1_Restore(int version) {
MMC1MIRROR();
MMC1CHR();
MMC1PRG();
lreset = 0;
}
static void MMC1CMReset(void) {
int i;
for (i = 0; i < 4; i++)
DRegs[i] = 0;
Buffer = BufferShift = 0;
DRegs[0] = 0x1F;
DRegs[1] = 0;
DRegs[2] = 0;
DRegs[3] = 0;
MMC1MIRROR();
MMC1CHR();
MMC1PRG();
}
static DECLFW(FNC_cmd_write) {
switch (A) {
case 0x40A6: {
IRQCount = (IRQCount & 0xFF00) | V;
break;
}
case 0x40A7: {
IRQCount = (IRQCount & 0x00FF) | (V << 8);
break;
}
case 0x40A8: {
IRQa = V;
break;
}
case 0x40B0: {
kanji_page = V & 1;
break;
}
case 0x40C0: {
FCEU_printf("FNS W %04x:%02x (PC %04x)\n", A, V, X.PC);
r40C0 = V;
MMC1CHR();
break;
}
default:
FCEU_printf("FNS W %04x:%02x (PC %04x)\n", A, V, X.PC);
}
}
static DECLFR(FNC_stat_read) {
switch (A) {
case 0x40A2: {
int ret = (IRQa >> 1);
X6502_IRQEnd(FCEU_IQEXT);
IRQa = 0;
return ret;
}
case 0x40AC: { // NMI/IRQ state reset (lookalike)
return 0;
}
case 0x40B0: {
kanji_pos = 0;
return 0;
}
case 0x40C0: {
FCEU_printf("FNS R %04x (PC %04x)\n", A, X.PC);
int ret = r40C0;
r40C0 &= 0;
return ret;
}
default: {
FCEU_printf("FNS R %04x (PC %04x)\n", A, X.PC);
return 0xff;
}
}
}
static DECLFR(FNC_cart_i2c_read) {
FCEU_printf("I2C R %04x (PC %04x)\n", A, X.PC);
return 0;
}
static DECLFR(FNC_kanji_read) {
int32 ofs = ((A & 0xFFF) << 5) + kanji_pos;
kanji_pos++;
kanji_pos &= 0x1F;
// if (PRGptr[1] != NULL) // iNES debug
return PRGptr[1][ofs];
// else
// return CHRptr[0][ofs];
}
void NFC_IRQ(int a) {
if (IRQa) {
IRQCount -= a;
if (IRQCount <= 0)
X6502_IRQBegin(FCEU_IQEXT);
}
}
static void FNS_Power(void) {
lreset = 0;
SetWriteHandler(0x8000, 0xFFFF, MMC1_write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
kanji_page = 0;
kanji_pos = 0;
r40C0 = 0xC0;
SetWriteHandler(0x4080, 0x40FF, FNC_cmd_write);
SetReadHandler(0x4080, 0x40FF, FNC_stat_read);
SetReadHandler(0x5000, 0x5FFF, FNC_kanji_read);
SetReadHandler(0x6000, 0x6000, FNC_cart_i2c_read);
SetReadHandler(0x6001, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(8, 0x6000, WRAM);
MMC1CMReset();
}
static void FNS_Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void FNS_Init(CartInfo *info) {
info->Close = FNS_Close;
info->Power = FNS_Power;
GameStateRestore = MMC1_Restore;
MapIRQHook = NFC_IRQ;
WRAMSIZE = (8 + 32) * 1024;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
info->addSaveGameBuf( WRAM, WRAMSIZE );
AddExState(DRegs, 4, 0, "DREG");
AddExState(&lreset, 8, 1, "LRST");
AddExState(&Buffer, 1, 1, "BFFR");
AddExState(&BufferShift, 1, 1, "BFRS");
}
+177
View File
@@ -0,0 +1,177 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2017 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* HP10xx/HP20xx - a simplified version of FK23C mapper with pretty strict and better
* organized banking behaviour. It seems that some 176 mapper assigned game may be
* actually this kind of board instead but in common they aren't compatible at all,
* the games on the regular FK23C boards couldn't run on this mapper and vice versa...
*
*/
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static uint8 unromchr, lock;
static uint32 dipswitch;
static void BMCHPxxCW(uint32 A, uint8 V)
{
if(EXPREGS[0]&4) { // custom banking
switch(EXPREGS[0]&3) {
case 0:
case 1:
setchr8(EXPREGS[2]&0x3F);
// FCEU_printf("\tCHR8 %02X\n",EXPREGS[2]&0x3F);
break;
case 2:
setchr8((EXPREGS[2]&0x3E)|(unromchr&1));
// FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3E)|(unromchr&1));
break;
case 3:
setchr8((EXPREGS[2]&0x3C)|(unromchr&3));
// FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3C)|(unromchr&3));
break;
}
} else { // mmc3 banking
int base, mask;
if(EXPREGS[0]&1) { // 128K mode
base=EXPREGS[2]&0x30;
mask=0x7F;
} else { // 256K mode
base=EXPREGS[2]&0x20;
mask=0xFF;
}
// FCEU_printf("\tCHR1 %04x:%02X\n",A,(V&mask)|(base<<3));
setchr1(A,(V&mask)|(base<<3));
}
}
//PRG wrapper
static void BMCHPxxPW(uint32 A, uint8 V)
{
if(EXPREGS[0]&4) { // custom banking
if((EXPREGS[0]&0xF)==4) { // 16K mode
// FCEU_printf("\tPRG16 %02X\n",EXPREGS[1]&0x1F);
setprg16(0x8000,EXPREGS[1]&0x1F);
setprg16(0xC000,EXPREGS[1]&0x1F);
} else { // 32K modes
// FCEU_printf("\tPRG32 %02X\n",(EXPREGS[1]&0x1F)>>1);
setprg32(0x8000,(EXPREGS[1]&0x1F)>>1);
}
} else { // mmc3 banking
int base, mask;
if(EXPREGS[0]&2) { // 128K mode
base=EXPREGS[1]&0x18;
mask=0x0F;
} else { // 256K mode
base=EXPREGS[1]&0x10;
mask=0x1F;
}
// FCEU_printf("\tPRG8 %02X\n",(V&mask)|(base<<1));
setprg8(A,(V&mask)|(base<<1));
setprg8r(0x10,0x6000,A001B&3);
}
}
//MIRROR wrapper
static void BMCHPxxMW(uint8 V) {
if(EXPREGS[0]&4) { // custom banking
// FCEU_printf("CUSTOM MIRR: %d\n",(unromchr>>2)&1);
setmirror(((unromchr>>2)&1)^1);
} else { // mmc3 banking
// FCEU_printf("MMC3 MIRR: %d\n",(V&1)^1);
A000B = V;
setmirror((A000B & 1) ^ 1);
}
}
//PRG handler ($8000-$FFFF)
static DECLFW(BMCHPxxHiWrite)
{
// FCEU_printf("HI WRITE %04X:%02X\n",A,V);
if(EXPREGS[0]&4) { // custom banking
// FCEU_printf("CUSTOM\n");
unromchr=V;
FixMMC3CHR(MMC3_cmd);
} else { // mmc3 banking
// FCEU_printf("MMC3\n");
if(A<0xC000) {
MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
} else {
MMC3_IRQWrite(A,V);
}
}
}
//EXP handler ($5000-$5FFF)
static DECLFW(BMCHPxxWrite)
{
if(!lock) {
// FCEU_printf("LO WRITE %04X:%02X\n",A,V);
EXPREGS[A&3]=V;
lock=V&0x80;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
}
static DECLFR(BMCHPxxRead) {
return dipswitch;
}
static void BMCHPxxReset(void)
{
dipswitch++;
dipswitch&=0xF;
lock=0;
// FCEU_printf("BMCHPxx dipswitch set to %d\n",dipswitch);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BMCHPxxPower(void)
{
GenMMC3Power();
dipswitch=lock=0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetReadHandler(0x5000,0x5fff,BMCHPxxRead);
SetWriteHandler(0x5000,0x5fff,BMCHPxxWrite);
SetWriteHandler(0x8000,0xffff,BMCHPxxHiWrite);
}
void BMCHPxx_Init(CartInfo *info)
{
GenMMC3_Init(info, 256, 256, 8, 0);
cwrap=BMCHPxxCW;
pwrap=BMCHPxxPW;
mwrap=BMCHPxxMW;
info->Power=BMCHPxxPower;
info->Reset=BMCHPxxReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
AddExState(&lock, 1, 0, "LOCK");
}
+88
View File
@@ -0,0 +1,88 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022 Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* NES 2.0 Mapper 470 denotes the INX_007T_V01 multicart circuit board,
* used for the Retro-Bit re-release of Battletoads and Double Dragon.
* It is basically AOROM with an additional outer bank register at $5000-$5FFF
* whose data selects the 256 KiB outer bank.
*
* $5000-$5FFF
* 7 bit 0
* ---- ----
* xxxx xxOO
* ||
* ++- Select outer 256 KB PRG ROM bank for CPU $8000-$FFFF
*
* $8000-$FFFF
* 7 bit 0
* ---- ----
* xxxM xPPP
* | |||
* | +++- Select inner 32 KB PRG ROM bank for CPU $8000-$FFFF
* +------ Select 1 KB VRAM page for all 4 nametables
*
*/
#include "mapinc.h"
static uint8 latch_out, latch_in;
static void INX_007T_Sync() {
setprg32(0x8000, (latch_in & 0b111) | (latch_out << 3));
setmirror(MI_0 + ((latch_in >> 4) & 1));
setchr8(0);
}
static void StateRestore(int version) {
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteLow)
{
latch_out = V;
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteHi)
{
latch_in = V;
INX_007T_Sync();
}
static void INX_007T_Power(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x5000,0x5FFF, INX_007T_WriteLow);
SetWriteHandler(0x8000, 0xFFFF, INX_007T_WriteHi);
}
static void INX_007T_Reset(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
}
void INX_007T_Init(CartInfo *info) {
info->Power = INX_007T_Power;
info->Reset = INX_007T_Reset;
GameStateRestore = StateRestore;
SetupCartMirroring(MI_0, 0, NULL);
AddExState(&latch_out, 1, 0, "LATO");
AddExState(&latch_in, 1, 0, "LATI");
}
+1
View File
@@ -35,6 +35,7 @@ static void MALEEPower(void) {
void MALEE_Init(CartInfo *info) {
info->Power = MALEEPower;
FCEU_MemoryRand(WRAM,sizeof(WRAM),true);
SetupCartPRGMapping(0x10, WRAM, 2048, 1);
AddExState(WRAM, 2048, 0, "WRAM");
}
+58 -48
View File
@@ -22,12 +22,13 @@
#include "mapinc.h"
static void GenMMC1Power(void);
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery);
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram);
static uint8 DRegs[4];
static uint8 Buffer, BufferShift;
static int mmc1opts;
static uint32 WRAMSIZE;
static uint32 NONBRAMSIZE; // size of non-battery-backed portion of WRAM
static void (*MMC1CHRHook4)(uint32 A, uint8 V);
static void (*MMC1PRGHook16)(uint32 A, uint8 V);
@@ -48,9 +49,9 @@ static DECLFR(MAWRAM) {
}
static void MMC1CHR(void) {
if (mmc1opts & 4) {
if (DRegs[0] & 0x10)
setprg8r(0x10, 0x6000, (DRegs[1] >> 4) & 1);
if (WRAMSIZE > 0x2000) {
if (WRAMSIZE > 0x4000)
setprg8r(0x10, 0x6000, (DRegs[1] >> 2) & 3);
else
setprg8r(0x10, 0x6000, (DRegs[1] >> 3) & 1);
}
@@ -179,20 +180,39 @@ static void MMC1CMReset(void) {
MMC1PRG();
}
static int DetectMMC1WRAMSize(uint32 crc32) {
switch (crc32) {
static int DetectMMC1WRAMSize(CartInfo *info, int *bs) {
int ws = 8;
switch (info->CRC32) {
case 0xc6182024: // Romance of the 3 Kingdoms
case 0xabbf7217: // "" "" (J) (PRG0)
case 0xccf35c02: // "" "" (J) (PRG1)
case 0x2225c20f: // Genghis Khan
case 0xfb69743a: // "" "" (J)
case 0x4642dda6: // Nobunaga's Ambition
case 0x29449ba9: // "" "" (J)
case 0x2b11e0b0: // "" "" (J)
case 0xb8747abf: // Best Play Pro Yakyuu Special (J)
case 0xc9556b36: // Final Fantasy I & II (J) [!]
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
return(16);
case 0x3f7ad415: // "" "" (J) (PRG0)
case 0x2b11e0b0: // "" "" (J) (PRG1)
*bs = 8;
ws = 16;
break;
default: return(8);
case 0xb8747abf: // Best Play Pro Yakyuu Special (J) (PRG0)
case 0xc3de7c69: // "" "" (J) (PRG1)
case 0xc9556b36: // Final Fantasy I & II (J) [!]
*bs = 32;
ws = 32;
break;
default:
if(info->ines2) {
ws = (info->wram_size + info->battery_wram_size) / 1024;
*bs = info->battery_wram_size / 1024;
// we only support sizes between 8K and 32K
if (ws > 0 && ws < 8) ws = 8;
if (ws > 32) ws = 32;
if (*bs > ws) *bs = ws;
}
}
if (ws > 8)
FCEU_printf(" >8KB external WRAM present. Use NES 2.0 if you hack the ROM image.\n");
return ws;
}
static uint32 NWCIRQCount;
@@ -244,17 +264,16 @@ void Mapper105_Init(CartInfo *info) {
static void GenMMC1Power(void) {
lreset = 0;
if (mmc1opts & 1) {
FCEU_CheatAddRAM(8, 0x6000, WRAM);
if (mmc1opts & 4)
FCEU_dwmemset(WRAM, 0, 8192)
else if (!(mmc1opts & 2))
FCEU_dwmemset(WRAM, 0, 8192); // wtf?
}
SetWriteHandler(0x8000, 0xFFFF, MMC1_write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
if (mmc1opts & 1) {
if (WRAMSIZE) {
FCEU_CheatAddRAM(8, 0x6000, WRAM);
// clear non-battery-backed portion of WRAM
if (NONBRAMSIZE)
FCEU_MemoryRand(WRAM, NONBRAMSIZE, true);
SetReadHandler(0x6000, 0x7FFF, MAWRAM);
SetWriteHandler(0x6000, 0x7FFF, MBWRAM);
setprg8r(0x10, 0x6000, 0);
@@ -271,31 +290,23 @@ static void GenMMC1Close(void) {
CHRRAM = WRAM = NULL;
}
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery) {
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram) {
is155 = 0;
info->Close = GenMMC1Close;
MMC1PRGHook16 = MMC1CHRHook4 = 0;
mmc1opts = 0;
WRAMSIZE = wram * 1024;
NONBRAMSIZE = (wram - bram) * 1024;
PRGmask16[0] &= (prg >> 14) - 1;
CHRmask4[0] &= (chr >> 12) - 1;
CHRmask8[0] &= (chr >> 13) - 1;
if (wram) {
WRAM = (uint8*)FCEU_gmalloc(wram * 1024);
//mbg 17-jun-08 - this shouldve been cleared to re-initialize save ram
//ch4 10-dec-08 - nope, this souldn't
//mbg 29-mar-09 - no time to debate this, we need to keep from breaking some old stuff.
//we really need to make up a policy for how compatibility and accuracy can be resolved.
memset(WRAM, 0, wram * 1024);
mmc1opts |= 1;
if (wram > 8) mmc1opts |= 4;
SetupCartPRGMapping(0x10, WRAM, wram * 1024, 1);
AddExState(WRAM, wram * 1024, 0, "WRAM");
if (battery) {
mmc1opts |= 2;
info->SaveGame[0] = WRAM + ((mmc1opts & 4) ? 8192 : 0);
info->SaveGameLen[0] = 8192;
if (WRAMSIZE) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (bram) {
info->addSaveGameBuf( WRAM + NONBRAMSIZE, bram * 1024 );
}
}
if (!chr) {
@@ -313,13 +324,14 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
}
void Mapper1_Init(CartInfo *info) {
int ws = DetectMMC1WRAMSize(info->CRC32);
GenMMC1Init(info, 512, 256, ws, info->battery);
int bs = info->battery ? 8 : 0;
int ws = DetectMMC1WRAMSize(info, &bs);
GenMMC1Init(info, 512, 256, ws, bs);
}
/* Same as mapper 1, without respect for WRAM enable bit. */
void Mapper155_Init(CartInfo *info) {
GenMMC1Init(info, 512, 256, 8, info->battery);
GenMMC1Init(info, 512, 256, 8, info->battery ? 8 : 0);
is155 = 1;
}
@@ -331,7 +343,7 @@ void Mapper171_Init(CartInfo *info) {
}
void SAROM_Init(CartInfo *info) {
GenMMC1Init(info, 128, 64, 8, info->battery);
GenMMC1Init(info, 128, 64, 8, info->battery ? 8 : 0);
}
void SBROM_Init(CartInfo *info) {
@@ -351,7 +363,7 @@ void SGROM_Init(CartInfo *info) {
}
void SKROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 64, 8, info->battery);
GenMMC1Init(info, 256, 64, 8, info->battery ? 8 : 0);
}
void SLROM_Init(CartInfo *info) {
@@ -383,11 +395,9 @@ void SHROM_Init(CartInfo *info) {
/* */
void SNROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 0, 8, info->battery);
GenMMC1Init(info, 256, 0, 8, info->battery ? 8 : 0);
}
void SOROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 0, 16, info->battery);
GenMMC1Init(info, 256, 0, 16, info->battery ? 8 : 0);
}
+2 -3
View File
@@ -25,7 +25,7 @@
static uint8 is10;
static uint8 creg[4], latch0, latch1, preg, mirr;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -130,8 +130,7 @@ void Mapper10_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
+111 -21
View File
@@ -113,6 +113,9 @@ void MMC3RegReset(void) {
DRegBuf[6] = 0;
DRegBuf[7] = 1;
// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support
kt_extra = 0;
FixMMC3PRG(0);
FixMMC3CHR(0);
}
@@ -187,7 +190,14 @@ DECLFW(MMC3_IRQWrite) {
DECLFW(KT008HackWrite) {
// FCEU_printf("%04x:%04x\n",A,V);
switch (A & 3) {
case 0: kt_extra = V; FixMMC3PRG(MMC3_cmd); break;
case 0: {
if (V == 0x27) // FF Xn hack! one more mapper in one
kt_extra = 0;
else
kt_extra = V;
FixMMC3PRG(MMC3_cmd);
break;
}
case 1: break; // unk
case 2: break; // unk
case 3: break; // unk
@@ -279,11 +289,11 @@ void GenMMC3Power(void) {
setprg8r(0x10, 0x6000, 0);
}
if (!(mmc3opts & 2))
FCEU_dwmemset(WRAM, 0, WRAMSIZE);
FCEU_MemoryRand(WRAM, WRAMSIZE, true);
}
MMC3RegReset();
if (CHRRAM)
FCEU_dwmemset(CHRRAM, 0, CHRRAMSIZE);
FCEU_MemoryRand(CHRRAM, CHRRAMSIZE, true);
}
static void GenMMC3Close(void) {
@@ -314,8 +324,7 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) {
if (battery) {
mmc3opts |= 2;
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support
@@ -1127,20 +1136,73 @@ void Mapper198_Init(CartInfo *info) {
info->Power = M195Power;
}
// ---------------------------- Mapper 205 ------------------------------
// GN-45 BOARD
/* ---------------------------- Mapper 205 ------------------------------ */
/* UNIF boardname BMC-JC-016-2
https://wiki.nesdev.com/w/index.php/INES_Mapper_205 */
/* 2023-02 : Update reg write logic and add solder pad */
static void M205PW(uint32 A, uint8 V) {
// GN-30A - íà÷àëüíàÿ ìàñêà äîëæíà áûòü 1F + àïïàðàòíûé ïåðåêëþ÷àòåëü íà øèíå àäðåñà
setprg8(A, (V & 0x0f) | EXPREGS[0]);
uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x0F : 0x1F);
if (PRGsize[1]) { // split-rom variant
setprg8r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank);
} else {
setprg8(A, EXPREGS[0] << 4 | bank);
}
}
static void M205CW(uint32 A, uint8 V) {
// GN-30A - íà÷àëüíàÿ ìàñêà äîëæíà áûòü FF
uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x7F : 0xFF);
if (CHRsize[1]) { // split-rom variant
setchr1r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank);
} else {
setchr1(A, (EXPREGS[0] << 7) | bank);
}
}
static DECLFW(M205Write) {
EXPREGS[0] = V & 3;
if (V & 1) {
EXPREGS[0] |= EXPREGS[1];
}
CartBW(A, V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void M205Reset(void) {
EXPREGS[0] = 0;
EXPREGS[1] ^= 2; /* solder pad */
MMC3RegReset();
}
static void M205Power(void) {
EXPREGS[0] = EXPREGS[1] = 0;
GenMMC3Power();
SetWriteHandler(0x6000, 0x7FFF, M205Write);
}
void Mapper205_Init(CartInfo *info) {
GenMMC3_Init(info, 256, 128, 0, 0);
pwrap = M205PW;
cwrap = M205CW;
info->Power = M205Power;
info->Reset = M205Reset;
AddExState(EXPREGS, 2, 0, "EXPR");
}
/* --------------------------- GN-45 BOARD ------------------------------ */
/* Mapper 361 and 366, previously assigned as Mapper 205 */
static void GN45PW(uint32 A, uint8 V) {
setprg8(A, (V & 0x0f) | EXPREGS[0]);
}
static void GN45CW(uint32 A, uint8 V) {
setchr1(A, (V & 0x7F) | (EXPREGS[0] << 3));
}
static DECLFW(M205Write0) {
static DECLFW(GN45Write0) {
if (EXPREGS[2] == 0) {
EXPREGS[0] = A & 0x30;
EXPREGS[2] = A & 0x80;
@@ -1150,7 +1212,7 @@ static DECLFW(M205Write0) {
CartBW(A, V);
}
static DECLFW(M205Write1) {
static DECLFW(GN45Write1) {
if (EXPREGS[2] == 0) {
EXPREGS[0] = V & 0x30;
FixMMC3PRG(MMC3_cmd);
@@ -1159,23 +1221,23 @@ static DECLFW(M205Write1) {
CartBW(A, V);
}
static void M205Reset(void) {
static void GN45Reset(void) {
EXPREGS[0] = EXPREGS[2] = 0;
MMC3RegReset();
}
static void M205Power(void) {
static void GN45Power(void) {
GenMMC3Power();
SetWriteHandler(0x6000, 0x6fff, M205Write0);
SetWriteHandler(0x7000, 0x7fff, M205Write1); // OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein
SetWriteHandler(0x6000, 0x6fff, GN45Write0);
SetWriteHandler(0x7000, 0x7fff, GN45Write1); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */
}
void Mapper205_Init(CartInfo *info) {
void GN45_Init(CartInfo *info) {
GenMMC3_Init(info, 128, 128, 8, 0);
pwrap = M205PW;
cwrap = M205CW;
info->Power = M205Power;
info->Reset = M205Reset;
pwrap = GN45PW;
cwrap = GN45CW;
info->Power = GN45Power;
info->Reset = GN45Reset;
AddExState(EXPREGS, 1, 0, "EXPR");
}
@@ -1353,3 +1415,31 @@ void TQROM_Init(CartInfo *info) {
void HKROM_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 512, 1, info->battery);
}
// -------------------------------- iNES 2.0 ----------------------------
// ---------------------------- Mapper 406 ------------------------------
static DECLFW(M406CMDWrite) {
MMC3_CMDWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
}
static DECLFW(M406IRQWrite) {
MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
}
FCEU_MAYBE_UNUSED
static DECLFW(M406Write) {
}
static void M406_Power(void) {
GenMMC3Power();
// TODO : FLASH
SetWriteHandler(0x8000, 0xBFFF, M406CMDWrite);
SetWriteHandler(0xC000, 0xFFFF, M406IRQWrite);
}
void Mapper406_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 0, 0);
info->Power = M406_Power;
}
+249 -66
View File
@@ -22,6 +22,15 @@
#include "mapinc.h"
#include <array>
#define ABANKS MMC5SPRVPage
#define BBANKS MMC5BGVPage
#define SpriteON (PPU[1] & 0x10) //Show Sprite
#define ScreenON (PPU[1] & 0x08) //Show screen
#define PPUON (PPU[1] & 0x18) //PPU should operate
#define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8
static void (*sfun)(int P);
static void (*psfun)(void);
@@ -74,10 +83,11 @@ static INLINE void MMC5BGVROM_BANK8(uint32 V) {
}
}
static uint8 PRGBanks[4];
static std::array<uint8,4> PRGBanks;
static uint8 WRAMPage;
static uint16 CHRBanksA[8], CHRBanksB[4];
static uint8 WRAMMaskEnable[2];
static std::array<uint16,8> CHRBanksA;
static std::array<uint16,4> CHRBanksB;
static std::array<uint8,2> WRAMMaskEnable;
uint8 mmc5ABMode; /* A=0, B=1 */
static uint8 IRQScanline, IRQEnable;
@@ -86,18 +96,20 @@ static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
static uint8 MMC5IRQR;
static uint8 MMC5LineCounter;
static uint8 mmc5psize, mmc5vsize;
static uint8 mul[2];
static std::array<uint8,2> mul;
static uint32 WRAMSIZE = 0;
static uint8 *WRAM = NULL;
static uint8 *MMC5fill = NULL;
static uint8 *ExRAM = NULL;
static uint8 MMC5battery = 0;
static uint8 MMC5WRAMsize; //configuration, not state
static uint8 MMC5WRAMIndex[8]; //configuration, not state
const int MMC5WRAMMAX = 1<<7; // 7 bits in register interface (real MMC5 has only 4 pins, however)
static uint8 MMC5WRAMsize=0; //configuration, not state
static uint8 MMC5WRAMIndex[MMC5WRAMMAX]; //configuration, not state
static uint8 MMC5ROMWrProtect[4];
static uint8 MMC5MemIn[5];
static std::array<uint8,4> MMC5ROMWrProtect;
static std::array<uint8,5> MMC5MemIn;
static void MMC5CHRA(void);
static void MMC5CHRB(void);
@@ -107,26 +119,50 @@ typedef struct __cartdata {
uint8 size;
} cartdata;
#define Sprite16 (PPU[0]& 0x20) //Sprites 8x16/8x8
//#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]
static inline uint8 * MMC5BGVRAMADR(uint32 A) {
#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)]
uint8* MMC5BGVRAMADR(uint32 A)
{
if(newppu)
{
if(Sprite16)
{
bool isPattern = PPUON != 0;
if (ppuphase == PPUPHASE_OBJ && isPattern)
return &ABANKS[(A) >> 10][(A)];
if (ppuphase == PPUPHASE_BG && isPattern)
return &BBANKS[(A) >> 10][(A)];
else if(mmc5ABMode == 0)
return &ABANKS[(A) >> 10][(A)];
else
return &BBANKS[(A) >> 10][(A)];
}
else return &ABANKS[(A) >> 10][(A)];;
}
if (!Sprite16) {
if (mmc5ABMode == 0)
return &MMC5SPRVPage[(A) >> 10][(A)];
return &ABANKS[(A) >> 10][(A)];
else
return &MMC5BGVPage[(A) >> 10][(A)];
} else return &MMC5BGVPage[(A) >> 10][(A)];
return &BBANKS[(A) >> 10][(A)];
} else return &BBANKS[(A) >> 10][(A)];
}
static void mmc5_PPUWrite(uint32 A, uint8 V) {
uint32 tmp = A;
extern uint8 PALRAM[0x20];
extern uint8 UPALRAM[0x03];
if (tmp >= 0x3F00) {
// hmmm....
if (!(tmp & 0xf))
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
else if (tmp & 3) PALRAM[(tmp & 0x1f)] = V & 0x3f;
if (!(tmp & 3)) {
if (!(tmp & 0xC)) {
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F;
}
else
UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F;
} else
PALRAM[tmp & 0x1F] = V & 0x3F;
} else if (tmp < 0x2000) {
if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V;
@@ -136,16 +172,105 @@ static void mmc5_PPUWrite(uint32 A, uint8 V) {
}
}
uint8 FASTCALL mmc5_PPURead(uint32 A) {
if (A < 0x2000) {
if (ppuphase == PPUPHASE_BG
//zero 03-aug-2014 - added this to fix Uchuu Keibitai SDF. The game reads NT entries from CHR rom while PPU is disabled.
//obviously we have enormous numbers of bugs springing from our terrible emulation of ppu-disabled states, but this does the job for fixing this one
&& (PPU[1] & 0x10)
)
return *MMC5BGVRAMADR(A);
else return MMC5SPRVPage[(A) >> 10][(A)];
} else {
extern uint32 NTRefreshAddr;
uint8 FASTCALL mmc5_PPURead(uint32 A)
{
bool split = false;
if(newppu)
{
if((MMC5HackSPMode&0x80) && !(MMC5HackCHRMode&2))
{
int target = MMC5HackSPMode&0x1f;
int side = MMC5HackSPMode&0x40;
int ht = NTRefreshAddr&31;
if(side==0)
{
if(ht<target) split = true;
}
else
{
if(ht>=target) split = true;
}
}
}
if (A < 0x2000)
{
if(Sprite16)
{
bool isPattern = !!PPUON;
if (ppuphase == PPUPHASE_OBJ && isPattern)
return ABANKS[(A) >> 10][(A)];
if (ppuphase == PPUPHASE_BG && isPattern)
{
if(split)
return MMC5HackVROMPTR[MMC5HackSPPage*0x1000 + (A&0xFFF)];
//uhhh call through to this more sophisticated function, only if it's really needed?
//we should probably reuse it completely, if we can
if (MMC5HackCHRMode == 1)
return *FCEUPPU_GetCHR(A,NTRefreshAddr);
return BBANKS[(A) >> 10][(A)];
}
else if(mmc5ABMode == 0)
return ABANKS[(A) >> 10][(A)];
else
return BBANKS[(A) >> 10][(A)];
}
else
{
if (ppuphase == PPUPHASE_BG && ScreenON)
{
if(split)
return MMC5HackVROMPTR[MMC5HackSPPage*0x1000 + (A&0xFFF)];
//uhhh call through to this more sophisticated function, only if it's really needed?
//we should probably reuse it completely, if we can
if (MMC5HackCHRMode == 1)
return *FCEUPPU_GetCHR(A,NTRefreshAddr);
}
return ABANKS[(A) >> 10][(A)];
}
}
else
{
if(split)
{
static const int kHack = -1; //dunno if theres science to this or if it just fixes SDF (cant be bothered to think about it)
int linetile = (newppu_get_scanline()+kHack)/8 + MMC5HackSPScroll;
//REF NT: return 0x2000 | (v << 0xB) | (h << 0xA) | (vt << 5) | ht;
//REF AT: return 0x2000 | (v << 0xB) | (h << 0xA) | 0x3C0 | ((vt & 0x1C) << 1) | ((ht & 0x1C) >> 2);
if((A&0x3FF)>=0x3C0)
{
A &= ~(0x1C<<1); //mask off VT
A |= (linetile&0x1C)<<1; //mask on adjusted VT
return ExRAM[A & 0x3FF];
}
else
{
A &= ~((0x1F<<5) | (1<<0xB)); //mask off VT and V
A |= (linetile&31)<<5; //mask on adjusted VT (V doesnt make any sense, I think)
return ExRAM[A & 0x3FF];
}
}
if (MMC5HackCHRMode == 1)
{
if((A&0x3FF)>=0x3C0)
{
uint8 byte = ExRAM[NTRefreshAddr & 0x3ff];
//get attribute part and paste it 4x across the byte
byte >>= 6;
byte *= 0x55;
return byte;
}
}
return vnapage[(A >> 10) & 0x3][A & 0x3FF];
}
}
@@ -182,8 +307,7 @@ cartdata MMC5CartList[] =
#define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0]))
int DetectMMC5WRAMSize(uint32 crc32) {
int x;
for (x = 0; x < MMC5_NOCARTS; x++) {
for (size_t x = 0; x < MMC5_NOCARTS; x++) {
if (crc32 == MMC5CartList[x].crc32) {
if(MMC5CartList[x].size > 1)
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
@@ -194,6 +318,8 @@ int DetectMMC5WRAMSize(uint32 crc32) {
}
static void BuildWRAMSizeTable(void) {
bool other = false; // non-standard configuration
// fill first 8 entries
int x;
for (x = 0; x < 8; x++) {
switch (MMC5WRAMsize) {
@@ -201,9 +327,22 @@ static void BuildWRAMSizeTable(void) {
case 1: MMC5WRAMIndex[x] = (x > 3) ? 255 : 0; break; //0,0,0,0,X,X,X,X
case 2: MMC5WRAMIndex[x] = (x & 4) >> 2; break; //0,0,0,0,1,1,1,1
case 4: MMC5WRAMIndex[x] = (x > 3) ? 255 : (x & 3); break; //0,1,2,3,X,X,X,X
case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7
case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7
default: MMC5WRAMIndex[x] = x; other = true; break; //0,1,2...
}
}
// extend to fill complete table
if (other)
{
for (x = 0; x < MMC5WRAMMAX && x < MMC5WRAMsize; ++x) MMC5WRAMIndex[x] = x; // linear mapping
for (x = MMC5WRAMsize; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x-MMC5WRAMsize]; // repeat to fill table
// theoretically the table fill should decompose into powers of two for possible mismatched SRAM combos,
// but I don't want to complicate the code with unnecessary hypotheticals
}
else
{
for (x = 8; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x & 7]; // fill table, repeating groups of 8
}
}
static void MMC5CHRA(void) {
@@ -271,7 +410,7 @@ static void MMC5CHRB(void) {
}
static void MMC5WRAM(uint32 A, uint32 V) {
V = MMC5WRAMIndex[V & 7];
V = MMC5WRAMIndex[V & (MMC5WRAMMAX-1)];
if (V != 255) {
setprg8r(0x10, A, V);
FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1))));
@@ -285,7 +424,7 @@ static void MMC5PRG(void) {
switch (mmc5psize & 3) {
case 0:
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
setprg32(0x8000, ((PRGBanks[1] & 0x7F) >> 2));
setprg32(0x8000, ((PRGBanks[3] & 0x7F) >> 2));
for (x = 0; x < 4; x++)
MMC5MemIn[1 + x] = 1;
break;
@@ -296,8 +435,8 @@ static void MMC5PRG(void) {
MMC5MemIn[1] = MMC5MemIn[2] = 1;
} else {
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1);
MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
}
MMC5MemIn[3] = MMC5MemIn[4] = 1;
MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
@@ -310,8 +449,8 @@ static void MMC5PRG(void) {
setprg16(0x8000, (PRGBanks[1] & 0x7F) >> 1);
} else {
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1);
MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
}
if (PRGBanks[2] & 0x80) {
MMC5ROMWrProtect[2] = 1;
@@ -319,7 +458,7 @@ static void MMC5PRG(void) {
setprg8(0xC000, PRGBanks[2] & 0x7F);
} else {
MMC5ROMWrProtect[2] = 0;
MMC5WRAM(0xC000, PRGBanks[2] & 7);
MMC5WRAM(0xC000, PRGBanks[2] & (MMC5WRAMMAX-1));
}
MMC5MemIn[4] = 1;
MMC5ROMWrProtect[3] = 1;
@@ -333,7 +472,7 @@ static void MMC5PRG(void) {
MMC5MemIn[1 + x] = 1;
} else {
MMC5ROMWrProtect[x] = 0;
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & 7);
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & (MMC5WRAMMAX-1));
}
MMC5MemIn[4] = 1;
MMC5ROMWrProtect[3] = 1;
@@ -396,7 +535,7 @@ static DECLFW(Mapper5_write) {
break;
case 0x5113:
WRAMPage = V;
MMC5WRAM(0x6000, V & 7);
MMC5WRAM(0x6000, V & (MMC5WRAMMAX-1));
break;
case 0x5114:
case 0x5115:
@@ -492,7 +631,7 @@ void MMC5Synco(void) {
case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break;
}
}
MMC5WRAM(0x6000, WRAMPage & 7);
MMC5WRAM(0x6000, WRAMPage & (MMC5WRAMMAX-1));
if (!mmc5ABMode) {
MMC5CHRB();
MMC5CHRA();
@@ -755,22 +894,42 @@ void NSFMMC5_Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
MMC5WRAMsize = 0;
FCEU_gfree(ExRAM);
ExRAM = NULL;
}
static void GenMMC5Reset(void) {
int x;
static void GenMMC5Power(void) {
for (x = 0; x < 4; x++) PRGBanks[x] = ~0;
for (x = 0; x < 8; x++) CHRBanksA[x] = ~0;
for (x = 0; x < 4; x++) CHRBanksB[x] = ~0;
WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0;
mmc5psize = mmc5vsize = 3;
PRGBanks.fill(0xFF);
WRAMPage = 0;
CHRBanksA.fill(0xFF);
CHRBanksB.fill(0xFF);
WRAMMaskEnable.fill(0xFF);
mmc5ABMode = 0;
IRQScanline = 0;
IRQEnable = 0;
CHRMode = 0;
NTAMirroring = NTFill = ATFill = 0xFF;
MMC5IRQR = 0;
MMC5LineCounter = 0;
mmc5psize = mmc5vsize = 3;
mul.fill(0);
MMC5ROMWrProtect.fill(0);
MMC5MemIn.fill(0);
// MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
u8 nval = MMC5fill[0x000];
u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6);
FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0);
FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040);
if(MMC5battery == 0) {
FCEU_MemoryRand(WRAM, MMC5WRAMsize * 8 * 1024);
FCEU_MemoryRand(MMC5fill,1024);
FCEU_MemoryRand(ExRAM,1024);
}
MMC5Synco();
@@ -793,11 +952,11 @@ static void GenMMC5Reset(void) {
}
static SFORMAT MMC5_StateRegs[] = {
{ PRGBanks, 4, "PRGB" },
{ CHRBanksA, 16, "CHRA" },
{ CHRBanksB, 8, "CHRB" },
{ &PRGBanks, 4, "PRGB" },
{ &CHRBanksA, 16, "CHRA" },
{ &CHRBanksB, 8, "CHRB" },
{ &WRAMPage, 1, "WRMP" },
{ WRAMMaskEnable, 2, "WRME" },
{ &WRAMMaskEnable, 2, "WRME" },
{ &mmc5ABMode, 1, "ABMD" },
{ &IRQScanline, 1, "IRQS" },
{ &IRQEnable, 1, "IRQE" },
@@ -811,9 +970,9 @@ static SFORMAT MMC5_StateRegs[] = {
{ &MMC5LineCounter, 1, "LCTR" },
{ &mmc5psize, 1, "PSIZ" },
{ &mmc5vsize, 1, "VSIZ" },
{ mul, 2, "MUL2" },
{ MMC5ROMWrProtect, 4, "WRPR" },
{ MMC5MemIn, 5, "MEMI" },
{ &mul, 2, "MUL2" },
{ &MMC5ROMWrProtect, 4, "WRPR" },
{ &MMC5MemIn, 5, "MEMI" },
{ &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" },
{ &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" },
@@ -836,13 +995,17 @@ static SFORMAT MMC5_StateRegs[] = {
static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
if (wsize) {
WRAM = (uint8*)FCEU_gmalloc(wsize * 1024);
WRAM = (uint8*)FCEU_malloc(wsize * 1024);
FCEU_MemoryRand(WRAM, wsize * 1024);
SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1);
AddExState(WRAM, wsize * 1024, 0, "WRAM");
}
MMC5fill = (uint8*)FCEU_gmalloc(1024);
ExRAM = (uint8*)FCEU_gmalloc(1024);
MMC5fill = (uint8*)FCEU_malloc(1024);
ExRAM = (uint8*)FCEU_malloc(1024);
FCEU_MemoryRand(MMC5fill,1024);
FCEU_MemoryRand(ExRAM,1024);
AddExState(ExRAM, 1024, 0, "ERAM");
AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
@@ -854,14 +1017,27 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
MMC5WRAMsize = wsize / 8;
BuildWRAMSizeTable();
GameStateRestore = MMC5_StateRestore;
info->Power = GenMMC5Reset;
info->Power = GenMMC5Power;
MMC5battery = battery;
if (battery) {
info->SaveGame[0] = WRAM;
if (wsize <= 16)
info->SaveGameLen[0] = 8192;
uint32 saveGameSize = 0;
if (info->ines2)
{
saveGameSize = info->battery_wram_size;
}
else
info->SaveGameLen[0] = 32768;
{
//this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you
//I added 64KB for the new 64KB homebrews
if (wsize <= 16)
saveGameSize = 8192;
else if(wsize == 64)
saveGameSize = 64*1024;
else
saveGameSize = 32768;
}
info->addSaveGameBuf( WRAM, saveGameSize );
}
MMC5HackVROMMask = CHRmask4[0];
@@ -877,7 +1053,14 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
}
void Mapper5_Init(CartInfo *info) {
WRAMSIZE = DetectMMC5WRAMSize(info->CRC32);
if (info->ines2)
{
WRAMSIZE = (info->wram_size + info->battery_wram_size) / 1024;
}
else
{
WRAMSIZE = DetectMMC5WRAMSize(info->CRC32);
}
GenMMC5_Init(info, WRAMSIZE, info->battery);
}
+30 -8
View File
@@ -57,9 +57,23 @@ static SFORMAT N106_StateRegs[] = {
{ PRG, 3, "PRG" },
{ CHR, 8, "CHR" },
{ NTAPage, 4, "NTA" },
{ &gorfus, 1, "GORF" },
{ &dopol, 1, "DOPO" },
{ &gorko, 1, "GORK" },
{ 0 }
};
static void SyncMirror()
{
switch(gorko) {
case 0: setmirror(MI_0); break;
case 1: setmirror(MI_V); break;
case 2: setmirror(MI_H); break;
case 3: setmirror(MI_0); break;
}
}
static void SyncPRG(void) {
setprg8(0x8000, PRG[0]);
setprg8(0xa000, PRG[1]);
@@ -143,7 +157,10 @@ static void FixCache(int a, int V) {
case 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break;
case 0x04:
FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16;
LengthCache[w] = (8 - ((V >> 2) & 7)) << 2;
// something wrong here http://www.romhacking.net/forum/index.php?topic=21907.msg306903#msg306903
// LengthCache[w] = (8 - ((V >> 2) & 7)) << 2;
// fix be like in https://github.com/SourMesen/Mesen/blob/cda0a0bdcb5525480784f4b8c71de6fc7273b570/Core/Namco163Audio.h#L61
LengthCache[w] = 256 - (V & 0xFC);
break;
case 0x07: EnvCache[w] = (double)(V & 0xF) * 576716; break;
}
@@ -179,8 +196,11 @@ static DECLFW(Mapper19_write) {
X6502_IRQEnd(FCEU_IQEXT);
break;
case 0xE000:
gorko = V & 0xC0;
PRG[0] = V & 0x3F;
if(is210) {
gorko = V>>6;
SyncMirror();
}
SyncPRG();
break;
case 0xE800:
@@ -331,6 +351,7 @@ static void DoNamcoSound(int32 *Wave, int Count) {
static void Mapper19_StateRestore(int version) {
SyncPRG();
SyncMirror();
FixNTAR();
FixCRR();
int x;
@@ -382,8 +403,8 @@ static void N106_Power(void) {
FixCRR();
if (!battery) {
FCEU_dwmemset(WRAM, 0, 8192);
FCEU_dwmemset(IRAM, 0, 128);
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
FCEU_MemoryRand(IRAM, sizeof(IRAM), true);
}
for (x = 0x40; x < 0x80; x++)
FixCache(x, IRAM[x]);
@@ -401,15 +422,15 @@ void Mapper19_Init(CartInfo *info) {
if (FSettings.SndRate)
Mapper19_ESI();
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
FCEU_MemoryRand(IRAM, sizeof(IRAM), true);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(IRAM, 128, 0, "IRAM");
AddExState(N106_StateRegs, ~0, 0, 0);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 8192;
info->SaveGame[1] = IRAM;
info->SaveGameLen[1] = 128;
info->addSaveGameBuf( WRAM, 8192 );
info->addSaveGameBuf( IRAM, 128 );
}
}
@@ -422,6 +443,7 @@ void Mapper210_Init(CartInfo *info) {
is210 = 1;
GameStateRestore = Mapper210_StateRestore;
info->Power = N106_Power;
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(N106_StateRegs, ~0, 0, 0);
}
+29
View File
@@ -47,6 +47,9 @@ static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xE1;
static writefunc defapuwrite[64];
static readfunc defapuread[64];
static uint32 WRAMSIZE;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ cpu410x, 16, "REGC" },
@@ -265,6 +268,13 @@ static void UNLOneBusPower(void) {
SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X);
SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3);
if (WRAMSIZE) {
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW);
SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR);
setprg8r(0x10, 0x6000, 0);
}
Sync();
}
@@ -282,9 +292,16 @@ static void StateRestore(int version) {
Sync();
}
void UNLOneBusClose(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void UNLOneBus_Init(CartInfo *info) {
info->Power = UNLOneBusPower;
info->Reset = UNLOneBusReset;
info->Close = UNLOneBusClose;
if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts
((*(uint32*)&(info->MD5)) == 0x6abfce8e))
@@ -294,4 +311,16 @@ void UNLOneBus_Init(CartInfo *info) {
MapIRQHook = UNLOneBusCpuHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
WRAMSIZE = 8 * 1024;
if (info->ines2)
WRAMSIZE = info->wram_size + info->battery_wram_size;
if (WRAMSIZE) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
}
}
+3
View File
@@ -16,6 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* PEC-586 FC based computer series by DUNDA
*
*/
#include "mapinc.h"
+3 -1
View File
@@ -26,6 +26,8 @@
#include "mapinc.h"
extern u64 xoroshiro128plus_next(); // deterministic random
static DECLFR(UNLRT01Read) {
// u16 i, prot_areas[2][2] = {
// { 0x8E80, 0x8EFF },
@@ -33,7 +35,7 @@ static DECLFR(UNLRT01Read) {
// };
if(((A >= 0xCE80) && (A < 0xCF00)) ||
((A >= 0xFE80) && (A < 0xFF00))) {
return 0xF2 | (rand() & 0x0D);
return 0xF2 | (xoroshiro128plus_next() & 0x0D);
} else
return CartBR(A);
}
+1 -2
View File
@@ -54,8 +54,7 @@ void SA9602B_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 0, 0, 0);
pwrap = SA9602BPW;
mmc3opts |= 2;
info->SaveGame[0] = UNIFchrrama;
info->SaveGameLen[0] = 32 * 1024;
info->addSaveGameBuf( UNIFchrrama, 32 * 1024 );
info->Power = SA9602BPower;
AddExState(EXPREGS, 2, 0, "EXPR");
}
+2 -3
View File
@@ -24,7 +24,7 @@ static uint8 preg[8];
static uint8 IRQa;
static int16 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
/*
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
@@ -187,8 +187,7 @@ void UNLSB2000_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+2 -3
View File
@@ -21,7 +21,7 @@
#include "mapinc.h"
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
unsigned int *GetKeyboard(void); // FIXME: 10/28 - now implemented in SDL as well. should we rename this to a FCEUI_* function?
@@ -90,8 +90,7 @@ void Transformer_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
+160 -194
View File
@@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2014 CaitSith2
* Copyright (C) 2014 CaitSith2, 2022 Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
*/
/*
* Roms still using NES 1.0 format should be loaded as 32K CHR RAM.
* Roms still using NES 1.0 format should be loaded as 8K CHR RAM.
* Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present.
* UNIF doesn't have this problem, because unique board names can define this information.
* The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K
@@ -28,6 +28,7 @@
* Known games to use this board are:
* Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled)
* Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled)
* Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled)
* Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space),
* it otherwise functions identically.
*/
@@ -35,235 +36,200 @@
#include "mapinc.h"
#include "../ines.h"
static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false;
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x10;
const int FLASH_CHIP = 0x11;
const int FLASH_SECTOR_SIZE = 4 * 1024;
static uint8 flash_save, flash_state, flash_id_mode, latche, bus_conflict;
static uint16 latcha;
static uint8 *flashdata;
static uint32 *flash_write_count;
static uint8 *FlashPage[32];
static uint32 *FlashWriteCountPage[32];
static uint8 flashloaded = false;
static uint8 *flash_data;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 flash_id[2];
static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
static void (*WLSync)(void);
static void (*WHSync)(void);
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11;
int x;
if (p)
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A;
}
else
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0;
}
}
void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) {
V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else {
uint32 VA = V << 3;
int x;
for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
}
}
void inc_flash_write_count(uint8 bank, uint32 A)
{
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)])
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
}
uint32 GetFlashWriteCount(uint8 bank, uint32 A)
{
return flash_write_count[(bank*4) + ((A&0x3000)>>12)];
static void UNROM512_Sync() {
int chip;
if (flash_save)
chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP;
else
chip = ROM_CHIP;
setprg16r(chip, 0x8000, latche & 0b11111);
setprg16r(chip, 0xc000, ~0);
setchr8((latche >> 5) & 0b11);
setmirror(MI_0 + ((latche >> 7) & 1));
}
static void StateRestore(int version) {
WHSync();
UNROM512_Sync();
}
static DECLFW(UNROM512LLatchWrite)
static DECLFW(UNROM512FlashWrite)
{
latche = V;
latcha = A;
WLSync();
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latche & 1) << 14);
flash_buffer_v[flash_state] = V;
flash_state++;
// enter flash ID mode
if ((flash_state == 2) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[1] == 0x5555) && (flash_buffer_v[1] == 0x90)) {
flash_id_mode = 0;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - flash_data;
int sector = offset / FLASH_SECTOR_SIZE;
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
}
// erase chip
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_a[4] == 0x5555) && (flash_buffer_v[4] == 0x10)) {
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - flash_data;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
flash_id_mode = 0;
}
UNROM512_Sync();
}
static DECLFW(UNROM512HLatchWrite)
{
if (bus_conflict)
latche = (V == CartBR(A)) ? V : 0;
latche = V & CartBR(A);
else
latche = V;
latcha = A;
WHSync();
}
static DECLFR(UNROM512LatchRead)
{
uint8 flash_id[3]={0xB5,0xB6,0xB7};
if(software_id)
{
if(A&1)
return flash_id[ROM_size>>4];
else
return 0xBF;
}
if(flash_save)
{
if(A < 0xC000)
{
if(GetFlashWriteCount(flash_bank,A))
return FlashPage[A >> 11][A];
}
else
{
if(GetFlashWriteCount(ROM_size-1,A))
return FlashPage[A >> 11][A];
}
}
return Page[A >> 11][A];
UNROM512_Sync();
}
static void UNROM512LatchPower(void) {
latche = latcheinit;
WHSync();
SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead);
latche = 0;
UNROM512_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
if(!flash_save)
SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite);
else
{
SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite);
SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite);
SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite);
}
}
static void UNROM512LatchClose(void) {
if(flash_write_count)
FCEU_gfree(flash_write_count);
if(flashdata)
FCEU_gfree(flashdata);
flash_write_count = NULL;
flashdata = NULL;
if(flash_data)
FCEU_gfree(flash_data);
flash_data = NULL;
}
static void UNROM512LSync() {
int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA};
int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55};
int erase_b[5]={1,0,1,1,0};
if(flash_mode==0)
{
if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state]))
{
flash_state++;
if(flash_state == 5)
{
flash_mode=1;
}
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1))
{
flash_state++;
flash_mode=2;
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1))
{
flash_state=0;
software_id=true;
}
else
{
if(latche==0xF0)
software_id=false;
flash_state=0;
}
}
else if(flash_mode==1) //Chip Erase or Sector Erase
{
if(latche==0x30)
{
inc_flash_write_count(flash_bank,latcha);
memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000);
}
else if (latche==0x10)
{
for(uint32 i=0;i<(ROM_size*4);i++)
inc_flash_write_count(i>>2,i<<12);
memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :)
}
flash_state=0;
flash_mode=0;
}
else if(flash_mode==2) //Byte Program
{
if(!GetFlashWriteCount(flash_bank,latcha))
{
inc_flash_write_count(flash_bank,latcha);
memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000);
}
FlashPage[latcha>>11][latcha]&=latche;
flash_state=0;
flash_mode=0;
}
}
static void UNROM512HSync()
static void UNROM512_FlashReset(void)
{
flash_bank=latche&(ROM_size-1);
setprg16(0x8000, flash_bank);
setprg16(0xc000, ~0);
setfprg16(0x8000, flash_bank);
setfprg16(0xC000, ~0);
setchr8r(0, (latche & chrram_mask) >> 5);
setmirror(MI_0+(latche>>7));
if (flash_data)
{
size_t flash_size = PRGsize[ROM_CHIP];
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
}
}
void UNROM512_Init(CartInfo *info) {
flash_state=0;
flash_bank=0;
flash_save=info->battery;
if(info->vram_size == 8192)
chrram_mask = 0;
else if (info->vram_size == 16384)
chrram_mask = 0x20;
else
chrram_mask = 0x60;
SetupCartMirroring(info->mirror,(info->mirror>=MI_0)?0:1,0);
bus_conflict = !info->battery;
latcheinit = 0;
WLSync = UNROM512LSync;
WHSync = UNROM512HSync;
info->Power = UNROM512LatchPower;
info->Close = UNROM512LatchClose;
GameStateRestore = StateRestore;
flash_state = 0;
flash_id_mode = 0;
flash_save = info->battery;
bus_conflict = !info->battery; // Is it required by any game?
int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2);
switch (mirror)
{
case 0: // hard horizontal, internal
SetupCartMirroring(MI_H, 1, NULL);
break;
case 1: // hard vertical, internal
SetupCartMirroring(MI_V, 1, NULL);
break;
case 2: // switchable 1-screen, internal (flags: 4-screen + horizontal)
SetupCartMirroring(MI_0, 0, NULL);
break;
case 3: // hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical)
SetupCartMirroring( 4, 1, VROM + (info->vram_size - 8192));
break;
}
if(flash_save)
{
flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000);
flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32));
info->SaveGame[0] = (uint8*)flash_write_count;
info->SaveGame[1] = flashdata;
info->SaveGameLen[0] = ROM_size*4*sizeof(uint32);
info->SaveGameLen[1] = ROM_size*0x4000;
AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT");
AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA");
AddExState(&flash_state,1,0,"FLASH_STATE");
AddExState(&flash_mode,1,0,"FLASH_MODE");
AddExState(&flash_bank,1,0,"FLASH_BANK");
AddExState(&latcha,2,0,"LATA");
// Allocate memory for flash
size_t flash_size = PRGsize[ROM_CHIP];
flash_data = (uint8*)FCEU_gmalloc(flash_size);
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1);
info->addSaveGameBuf( flash_data, flash_size, UNROM512_FlashReset );
flash_id[0] = 0xBF;
flash_id[1] = 0xB5 + (ROM_size >> 4);
SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
AddExState(flash_data, flash_size, 0, "FLSH");
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
}
AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC");
}
AddExState(&latcha, sizeof(latcha), 0, "LATA");
AddExState(&latche, sizeof(latche), 0, "LATC");
AddExState(&bus_conflict, sizeof(bus_conflict), 0, "BUSC");
}
+69 -100
View File
@@ -20,14 +20,14 @@
#include "mapinc.h"
static uint8 isPirate, is22;
static bool isPirate;
static uint8 is22, reg1mask, reg2mask;
static uint16 IRQCount;
static uint8 IRQLatch, IRQa;
static uint8 IRQLatch, IRQa, IRQMode;
static uint8 prgreg[2], chrreg[8];
static uint16 chrhi[8];
static uint8 regcmd, irqcmd, mirr, big_bank;
static uint16 acount = 0;
static uint16 weirdo = 0;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
@@ -37,6 +37,7 @@ static SFORMAT StateRegs[] =
{ prgreg, 2, "PREG" },
{ chrreg, 8, "CREG" },
{ chrhi, 16, "CRGH" },
{ &acount, 2, "ACNT" },
{ &regcmd, 1, "CMDR" },
{ &irqcmd, 1, "CMDI" },
{ &mirr, 1, "MIRR" },
@@ -44,6 +45,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 2, "IRQC" },
{ &IRQLatch, 1, "IRQL" },
{ &IRQa, 1, "IRQA" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@@ -61,15 +63,8 @@ static void Sync(void) {
setchr8(0);
else{
uint8 i;
if(!weirdo)
for (i = 0; i < 8; i++)
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
else {
setchr1(0x0000, 0xFC);
setchr1(0x0400, 0xFD);
setchr1(0x0800, 0xFF);
weirdo--;
}
for (i = 0; i < 8; i++)
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
}
switch (mirr & 0x3) {
case 0: setmirror(MI_V); break;
@@ -80,7 +75,7 @@ static void Sync(void) {
}
static DECLFW(VRC24Write) {
A &= 0xF003;
A = A & 0xF000 | !!(A & reg2mask) << 1 | !!(A & reg1mask);
if ((A >= 0xB000) && (A <= 0xE003)) {
if (UNIFchrrama)
big_bank = (V & 8) << 2; // my personally many-in-one feature ;) just for support pirate cart 2-in-1
@@ -121,81 +116,49 @@ static DECLFW(VRC24Write) {
case 0x9003: regcmd = V; Sync(); break;
case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break;
case 0xF001: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0x0F; IRQLatch |= V << 4; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQMode = V & 4; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF003: X6502_IRQEnd(FCEU_IQEXT); IRQa = irqcmd; break;
}
}
static DECLFW(M21Write) {
A = (A & 0xF000) | ((A >> 1) & 0x3); // Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] isn't mapper 21 actually,
// it's mapper 23 by wirings
VRC24Write(A, V);
}
static DECLFW(M22Write) {
if (A == 0xC007) { // Ganbare Goemon Gaiden does strange things!!! at the end credits
weirdo = 8; // quick dirty hack, seems there is no other games with such PCB, so
// we never know if it will not work for something else lol
static void VRC24Power(void) {
big_bank = 0x20;
Sync();
if (WRAM) {
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
}
A |= ((A >> 2) & 0x3); // It's just swapped lines from 21 mapper
//
VRC24Write((A & 0xF000) | ((A >> 1) & 1) | ((A << 1) & 2), V);
}
static DECLFW(M23Write) {
A |= ((A >> 2) & 0x3) | ((A >> 4) & 0x3) | ((A >> 6) & 0x3);// actually there is many-in-one mapper source, some pirate or
// licensed games use various address bits for registers
VRC24Write(A, V);
}
static void M21Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M21Write);
}
static void M22Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M22Write);
}
static void M23Power(void) {
big_bank = 0x20;
Sync();
setprg8r(0x10, 0x6000, 0); // Only two Goemon games are have battery backed RAM, three more shooters
// (Parodius Da!, Gradius 2 and Crisis Force uses 2k or SRAM at 6000-67FF only
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M23Write);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
}
static void M25Power(void) {
big_bank = 0x20;
Sync();
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M22Write);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
SetWriteHandler(0x8000, 0xFFFF, VRC24Write);
}
void VRC24IRQHook(int a) {
#define LCYCS 341
if (IRQa) {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
if (IRQMode) {
acount += a;
while (acount > 0) {
acount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
}
}
}
}
@@ -210,26 +173,8 @@ static void VRC24Close(void) {
WRAM = NULL;
}
void Mapper21_Init(CartInfo *info) {
isPirate = 0;
is22 = 0;
info->Power = M21Power;
MapIRQHook = VRC24IRQHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper22_Init(CartInfo *info) {
isPirate = 0;
is22 = 1;
info->Power = M22Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void VRC24_Init(CartInfo *info) {
static void VRC24_Init(CartInfo *info) {
info->Power = VRC24Power;
info->Close = VRC24Close;
MapIRQHook = VRC24IRQHook;
GameStateRestore = StateRestore;
@@ -240,30 +185,54 @@ void VRC24_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if(info->battery) {
info->SaveGame[0]=WRAM;
info->SaveGameLen[0]=WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper23_Init(CartInfo *info) {
isPirate = 0;
void Mapper21_Init(CartInfo *info) {
isPirate = false;
is22 = 0;
info->Power = M23Power;
reg1mask = 0x42;
reg2mask = 0x84;
VRC24_Init(info);
}
void Mapper22_Init(CartInfo *info) {
isPirate = false;
is22 = 1;
reg1mask = 2;
reg2mask = 1;
// no IRQ (all mapper 22 games are VRC2)
// no WRAM
info->Power = VRC24Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper23_Init(CartInfo *info) {
isPirate = false;
is22 = 0;
reg1mask = 0x15;
reg2mask = 0x2a;
VRC24_Init(info);
}
void Mapper25_Init(CartInfo *info) {
isPirate = 0;
isPirate = false;
is22 = 0;
info->Power = M25Power;
reg1mask = 0xa;
reg2mask = 0x5;
VRC24_Init(info);
}
void UNLT230_Init(CartInfo *info) {
isPirate = 1;
isPirate = true;
is22 = 0;
info->Power = M23Power;
reg1mask = 0x15;
reg2mask = 0x2a;
VRC24_Init(info);
}
+159 -121
View File
@@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
* Copyright (C) 2005-2019 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,25 +17,118 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* VRC-5 (CAI Shogakko no Sansu)
* VRC-V (CAI Shogakko no Sansu)
*
*/
#include "mapinc.h"
static uint8 QTAINTRAM[2048];
static writefunc old2007wrap;
//#define CAI_DEBUG
// main tiles RAM is 8K in size, but unless other non-CHR ROM type carts,
// this one accesses the $0000 and $1000 pages based on extra NT RAM on board
// which is similar to MMC5 but much simpler because there are no additional
// bankings here.
// extra NT RAM handling is in PPU code now.
static uint16 CHRSIZE = 8192;
static uint16 WRAMSIZE = 8192 + 4096;
// there are two separate WRAMs 8K each, on main system cartridge (not battery
// backed), and one on the daughter cart (with battery). both are accessed
// via the same registers with additional selector flags.
static uint16 WRAMSIZE = 8192 + 8192;
static uint8 *CHRRAM = NULL;
static uint8 *WRAM = NULL;
static uint8 IRQa, K4IRQ;
static uint32 IRQLatch, IRQCount;
// some kind of 16-bit text encoding (actually 14-bit) used in game resources
// may be converted by the hardware into the tile indexes for internal CHR ROM
// not sure whey they made it hardware, because most of calculations are just
// bit shifting. the main purpose of this table is to calculate actual CHR ROM
// bank for every character. there is a some kind of regularity, so this table
// may be calculated in software easily.
// table read out from hardware registers as is
///*
static uint8 conv_tbl[4][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x40, 0x10, 0x28, 0x00, 0x18, 0x30 },
{ 0x00, 0x00, 0x48, 0x18, 0x30, 0x08, 0x20, 0x38 },
{ 0x00, 0x00, 0x80, 0x20, 0x38, 0x10, 0x28, 0xB0 }
};
//*/
/*
static uint8 conv_tbl[64][4] = {
{ 0x40, 0x40, 0x40, 0x40 }, // 00 | A - 40 41 42 43 44 45 46 47
{ 0x41, 0x41, 0x41, 0x41 }, // 02 | B - 48 49 4A 4B 4C 4D 4E 4F
{ 0x42, 0x42, 0x42, 0x42 }, // 04 | C - 50 51 52 53 54 55 56 57
{ 0x43, 0x43, 0x43, 0x43 }, // 06 | D - 58 59 5A 5B 5C 5D 5E 5F
{ 0x44, 0x44, 0x44, 0x44 }, // 08 | E - 60 61 62 63 64 65 66 67
{ 0x45, 0x45, 0x45, 0x45 }, // 0A | F - 68 69 6A 6B 6C 6D 6E 6F
{ 0x46, 0x46, 0x46, 0x46 }, // 0C | G - 70 71 72 73 74 75 76 77
{ 0x47, 0x47, 0x47, 0x47 }, // 0E | H - 78 79 7A 7B 7C 7D 7E 7F
{ 0x40, 0x40, 0x40, 0x40 }, // 10 |
{ 0x41, 0x41, 0x41, 0x41 }, // 12 +----------------------------
{ 0x42, 0x42, 0x42, 0x42 }, // 14 | A A A A
{ 0x43, 0x43, 0x43, 0x43 }, // 16 | A A A A
{ 0x44, 0x44, 0x44, 0x44 }, // 18 | A A' B' A"
{ 0x45, 0x45, 0x45, 0x45 }, // 1A | A C D E
{ 0x46, 0x46, 0x46, 0x46 }, // 1C | A F G H
{ 0x47, 0x47, 0x47, 0x47 }, // 1E | A A B C
{ 0x40, 0x40, 0x48, 0x44 }, // 20 | A D E F
{ 0x41, 0x41, 0x49, 0x45 }, // 22 | A G H G"
{ 0x42, 0x42, 0x4A, 0x46 }, // 24 +----------------------------
{ 0x43, 0x43, 0x4B, 0x47 }, // 26 | A' - 40 41 42 43 40 41 42 43
{ 0x44, 0x40, 0x48, 0x44 }, // 28 | A" - 44 45 46 47 44 45 46 47
{ 0x45, 0x41, 0x49, 0x45 }, // 2A | B' - 48 49 4A 4B 48 49 4A 4B
{ 0x46, 0x42, 0x4A, 0x46 }, // 2C | G" - 74 75 76 77 74 75 76 77
{ 0x47, 0x43, 0x4B, 0x47 }, // 2E
{ 0x40, 0x50, 0x58, 0x60 }, // 30
{ 0x41, 0x51, 0x59, 0x61 }, // 32
{ 0x42, 0x52, 0x5A, 0x62 }, // 34
{ 0x43, 0x53, 0x5B, 0x63 }, // 36
{ 0x44, 0x54, 0x5C, 0x64 }, // 38
{ 0x45, 0x55, 0x5D, 0x65 }, // 3A
{ 0x46, 0x56, 0x5E, 0x66 }, // 3C
{ 0x47, 0x57, 0x5F, 0x67 }, // 3E
{ 0x40, 0x68, 0x70, 0x78 }, // 40
{ 0x41, 0x69, 0x71, 0x79 }, // 42
{ 0x42, 0x6A, 0x72, 0x7A }, // 44
{ 0x43, 0x6B, 0x73, 0x7B }, // 46
{ 0x44, 0x6C, 0x74, 0x7C }, // 48
{ 0x45, 0x6D, 0x75, 0x7D }, // 4A
{ 0x46, 0x6E, 0x76, 0x7E }, // 4C
{ 0x47, 0x6F, 0x77, 0x7F }, // 4E
{ 0x40, 0x40, 0x48, 0x50 }, // 50
{ 0x41, 0x41, 0x49, 0x51 }, // 52
{ 0x42, 0x42, 0x4A, 0x52 }, // 54
{ 0x43, 0x43, 0x4B, 0x53 }, // 56
{ 0x44, 0x44, 0x4C, 0x54 }, // 58
{ 0x45, 0x45, 0x4D, 0x55 }, // 5A
{ 0x46, 0x46, 0x4E, 0x56 }, // 5C
{ 0x47, 0x47, 0x4F, 0x57 }, // 5E
{ 0x40, 0x58, 0x60, 0x68 }, // 60
{ 0x41, 0x59, 0x61, 0x69 }, // 62
{ 0x42, 0x5A, 0x62, 0x6A }, // 64
{ 0x43, 0x5B, 0x63, 0x6B }, // 66
{ 0x44, 0x5C, 0x64, 0x6C }, // 68
{ 0x45, 0x5D, 0x65, 0x6D }, // 6A
{ 0x46, 0x5E, 0x66, 0x6E }, // 6C
{ 0x47, 0x5F, 0x67, 0x6F }, // 6E
{ 0x40, 0x70, 0x78, 0x74 }, // 70
{ 0x41, 0x71, 0x79, 0x75 }, // 72
{ 0x42, 0x72, 0x7A, 0x76 }, // 74
{ 0x43, 0x73, 0x7B, 0x77 }, // 76
{ 0x44, 0x74, 0x7C, 0x74 }, // 78
{ 0x45, 0x75, 0x7D, 0x75 }, // 7A
{ 0x46, 0x76, 0x7E, 0x76 }, // 7C
{ 0x47, 0x77, 0x7F, 0x77 }, // 7E
};
*/
static uint8 regs[16];
//static uint8 test[8];
static SFORMAT StateRegs[] =
{
{ &IRQCount, 1, "IRQC" },
@@ -48,93 +141,68 @@ static SFORMAT StateRegs[] =
static void chrSync(void) {
setchr4r(0x10, 0x0000, regs[5] & 1);
setchr4r(0x10, 0x1000, 0);
// 30.06.19 CaH4e3 there is much more complicated behaviour with second banking register, you may actually
// view the content of the internal character CHR rom via this window, but it is useless because hardware
// does not use this area to access the internal ROM. not sure why they did this, but I see no need to
// emulate this behaviour carefully, unless I find something that I missed...
setchr4r(0x10, 0x1000, 1);
}
static void Sync(void) {
chrSync();
// if(regs[0xA]&0x10)
// {
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0);
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1);
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2);
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3);
setchr1r(0x10,0x1000,0);
setchr1r(0x10,0x1400,1);
setchr1r(0x10,0x1800,2);
setchr1r(0x10,0x1c00,3);*/
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0);
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1);
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2);
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3);
setchr1r(0x10,0x1000,(((regs[5]&1)^1)<<2)+4);
setchr1r(0x10,0x1400,(((regs[5]&1)^1)<<2)+5);
setchr1r(0x10,0x1800,(((regs[5]&1)^1)<<2)+6);
setchr1r(0x10,0x1c00,(((regs[5]&1)^1)<<2)+7);
*/
// }
// else
// {
/*
setchr1r(0x10,0x0000,(((regs[5]&1)^1)<<2)+0);
setchr1r(0x10,0x0400,(((regs[5]&1)^1)<<2)+1);
setchr1r(0x10,0x0800,(((regs[5]&1)^1)<<2)+2);
setchr1r(0x10,0x0c00,(((regs[5]&1)^1)<<2)+3);
setchr1r(0x10,0x1000,(((regs[5]&1))<<2)+4);
setchr1r(0x10,0x1400,(((regs[5]&1))<<2)+5);
setchr1r(0x10,0x1800,(((regs[5]&1))<<2)+6);
setchr1r(0x10,0x1c00,(((regs[5]&1))<<2)+7);
// }
//*/
/* setchr1r(1,0x0000,test[0]);
setchr1r(1,0x0400,test[1]);
setchr1r(1,0x0800,test[2]);
setchr1r(1,0x0c00,test[3]);
setchr1r(1,0x1000,test[4]);
setchr1r(1,0x1400,test[5]);
setchr1r(1,0x1800,test[6]);
setchr1r(1,0x1c00,test[7]);
*/
setprg4r(0x10, 0x6000, regs[0] & 1);
if (regs[2] >= 0x40)
setprg8r(1, 0x8000, (regs[2] - 0x40));
else
setprg8r(0, 0x8000, (regs[2] & 0x3F));
if (regs[3] >= 0x40)
setprg8r(1, 0xA000, (regs[3] - 0x40));
else
setprg8r(0, 0xA000, (regs[3] & 0x3F));
if (regs[4] >= 0x40)
setprg8r(1, 0xC000, (regs[4] - 0x40));
else
setprg8r(0, 0xC000, (regs[4] & 0x3F));
setprg8r(1, 0xE000, ~0);
setmirror(MI_V);
setprg4r(0x10, 0x6000, (regs[0] & 1) | (regs[0] >> 2)); // two 4K banks are identical, either internal or excernal
setprg4r(0x10, 0x7000, (regs[1] & 1) | (regs[1] >> 2)); // SRAMs may be mapped in any bank independently
if (PRGptr[1] == NULL) { // for iNES 2.0 version it even more hacky lol
setprg8(0x8000, (regs[2] & 0x3F) + ((regs[2] & 0x40) >> 2));
setprg8(0xA000, (regs[3] & 0x3F) + ((regs[3] & 0x40) >> 2));
setprg8(0xC000, (regs[4] & 0x3F) + ((regs[4] & 0x40) >> 2));
setprg8(0xE000, 0x10 + 0x3F);
} else {
setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F));
setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F));
setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F));
setprg8r(1, 0xE000, ~0); // always sees the last bank of the external cart, so can't be booted without it.
}
setmirror(((regs[0xA]&2)>>1)^1);
}
/*static DECLFW(TestWrite)
{
test[A&7] = V;
Sync();
}*/
static DECLFW(M190Write) {
// FCEU_printf("write %04x:%04x %d, %d\n",A,V,scanline,timestamp);
regs[(A & 0x0F00) >> 8] = V;
static DECLFW(QTAiWrite) {
regs[(A & 0x0F00) >> 8] = V; // IRQ pretty the same as in other VRC mappers by Konami
switch (A) {
case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break;
case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xda00: qtaintramreg = regs[0xA] & 3; break; // register shadow to share it with ppu
}
Sync();
}
static DECLFR(M190Read) {
// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp);
return regs[(A & 0x0F00) >> 8] + regs[0x0B];
static DECLFR(QTAiRead) {
// uint8 res1 = conv_tbl[(regs[0xD] & 0x7F) >> 1][(regs[0xC] >> 5) & 3];
// uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
uint8 tabl = conv_tbl[(regs[0xC] >> 5) & 3][(regs[0xD] & 0x7F) >> 4];
uint8 res1 = 0x40 | (tabl & 0x3F) | ((regs[0xD] >> 1) & 7) | ((regs[0xB] & 4) << 5);
uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
if (tabl & 0x40)
res1 &= 0xFB;
else if (tabl & 0x80)
res1 |= 0x04;
if (A == 0xDD00) {
return res1;
} else if (A == 0xDC00) {
#ifdef CAI_DEBUG
FCEU_printf("%02x:%02x+%d -> %02x:%02x\n", regs[0xD], regs[0xC], regs[0xB], res1, res2);
#endif
return res2;
} else
return 0;
}
static void VRC5IRQ(int a) {
if (IRQa) {
IRQCount += a;
@@ -145,50 +213,17 @@ static void VRC5IRQ(int a) {
}
}
//static void Mapper190_PPU(uint32 A)
//{
// if(A<0x2000)
// setchr4r(0x10,0x1000,QTAINTRAM[A&0x1FFF]&1);
// else
// chrSync();
//}
static DECLFW(M1902007Wrap) {
if (A >= 0x2000) {
if (regs[0xA] & 1)
QTAINTRAM[A & 0x1FFF] = V;
else
old2007wrap(A, V);
}
}
static void M190Power(void) {
/* test[0]=0;
test[1]=1;
test[2]=2;
test[3]=3;
test[4]=4;
test[5]=5;
test[6]=6;
test[7]=7;
*/
setprg4r(0x10, 0x7000, 2);
old2007wrap = GetWriteHandler(0x2007);
SetWriteHandler(0x2007, 0x2007, M1902007Wrap);
static void QTAiPower(void) {
SetReadHandler(0x6000, 0xFFFF, CartBR);
// SetWriteHandler(0x5000,0x5007,TestWrite);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetWriteHandler(0x8000, 0xFFFF, M190Write);
SetReadHandler(0xDC00, 0xDC00, M190Read);
SetReadHandler(0xDD00, 0xDD00, M190Read);
SetWriteHandler(0x8000, 0xFFFF, QTAiWrite);
SetReadHandler(0xDC00, 0xDC00, QTAiRead);
SetReadHandler(0xDD00, 0xDD00, QTAiRead);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
Sync();
}
static void M190Close(void) {
static void QTAiClose(void) {
if (CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM = NULL;
@@ -201,13 +236,14 @@ static void StateRestore(int version) {
Sync();
}
void Mapper190_Init(CartInfo *info) {
info->Power = M190Power;
info->Close = M190Close;
void QTAi_Init(CartInfo *info) {
QTAIHack = 1;
info->Power = QTAiPower;
info->Close = QTAiClose;
GameStateRestore = StateRestore;
MapIRQHook = VRC5IRQ;
// PPU_hook=Mapper190_PPU;
CHRRAM = (uint8*)FCEU_gmalloc(CHRSIZE);
SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1);
@@ -218,8 +254,10 @@ void Mapper190_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE - 4096;
// note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just
// an additional work ram. so we may save only half here, but I forgot what part is saved lol, will
// find out later.
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+24 -11
View File
@@ -25,10 +25,10 @@
static uint8 is26;
static uint8 prg[2], chr[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -40,6 +40,7 @@ static SFORMAT StateRegs[] =
{ &IRQLatch, 1, "IRQL" },
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@@ -109,6 +110,7 @@ static DECLFW(VRC6Write) {
case 0xE003: chr[7] = V; Sync(); break;
case 0xF000: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF001:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@@ -132,13 +134,25 @@ static void VRC6Power(void) {
static void VRC6IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@@ -365,8 +379,7 @@ void Mapper26_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+25 -12
View File
@@ -21,10 +21,10 @@
#include "mapinc.h"
static uint8 vrc7idx, preg[3], creg[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
#include "emu2413.h"
@@ -44,6 +44,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" },
{ &IRQMode, 1, "IRQM" },
{0}
};
@@ -86,7 +87,7 @@ static void VRC7SKill(void) {
static void VRC7_ESI(void) {
GameExpSound.RChange = VRC7SC;
GameExpSound.Kill = VRC7SKill;
VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 44100);
VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 48000);
OPLL_reset(VRC7Sound);
OPLL_reset(VRC7Sound);
}
@@ -134,6 +135,7 @@ static DECLFW(VRC7Write) {
case 0xE000: mirr = V & 3; Sync(); break;
case 0xE010: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF000:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@@ -165,13 +167,25 @@ static void VRC7Close(void)
static void VRC7IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@@ -190,8 +204,7 @@ void Mapper85_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
VRC7_ESI();
+54 -19
View File
@@ -76,6 +76,8 @@ uint8 geniech[3];
uint32 genieaddr[3];
CartInfo *currCartInfo;
static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) {
uint32 AB = A >> 11;
int x;
@@ -130,6 +132,11 @@ void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram) {
CHRmask4[chip] = (size >> 12) - 1;
CHRmask8[chip] = (size >> 13) - 1;
if (CHRmask1[chip] >= (unsigned int)(-1)) CHRmask1[chip] = 0;
if (CHRmask2[chip] >= (unsigned int)(-1)) CHRmask2[chip] = 0;
if (CHRmask4[chip] >= (unsigned int)(-1)) CHRmask4[chip] = 0;
if (CHRmask8[chip] >= (unsigned int)(-1)) CHRmask8[chip] = 0;
CHRram[chip] = ram;
}
@@ -529,19 +536,27 @@ void FCEU_GeniePower(void) {
}
void FCEU_SaveGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) {
void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty())
{
FILE *sp;
std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL) {
if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL)
{
FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n", soot.c_str());
} else {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x]) {
fwrite(LocalHWInfo->SaveGame[x], 1,
LocalHWInfo->SaveGameLen[x], sp);
}
else
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
fwrite(LocalHWInfo->SaveGame[x].bufptr, 1,
LocalHWInfo->SaveGame[x].buflen, sp);
}
}
}
}
}
@@ -549,25 +564,45 @@ void FCEU_SaveGameSave(CartInfo *LocalHWInfo) {
// hack, movie.cpp has to communicate with this function somehow
int disableBatteryLoading = 0;
void FCEU_LoadGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading) {
void FCEU_LoadGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty() && !disableBatteryLoading)
{
FILE *sp;
std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
sp = FCEUD_UTF8fopen(soot, "rb");
if (sp != NULL) {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x])
fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp);
if (sp != NULL)
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
if ( fread(LocalHWInfo->SaveGame[x].bufptr, 1, LocalHWInfo->SaveGame[x].buflen, sp) != LocalHWInfo->SaveGame[x].buflen )
{
FCEU_printf("Warning save game data read came up short!\n");
}
}
}
}
}
}
//clears all save memory. call this if you want to pretend the saveram has been reset (it doesnt touch what is on disk though)
void FCEU_ClearGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x])
memset(LocalHWInfo->SaveGame[x], 0, LocalHWInfo->SaveGameLen[x]);
void FCEU_ClearGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty())
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
memset(LocalHWInfo->SaveGame[x].bufptr, 0, LocalHWInfo->SaveGame[x].buflen);
}
if (LocalHWInfo->SaveGame[x].resetFunc)
{
LocalHWInfo->SaveGame[x].resetFunc();
}
}
}
}
+67 -8
View File
@@ -1,17 +1,46 @@
typedef struct {
#ifndef CART_H
#define CART_H
#include <vector>
struct CartInfo
{
// Set by mapper/board code:
void (*Power)(void);
void (*Reset)(void);
void (*Close)(void);
uint8 *SaveGame[4]; // Pointers to memory to save/load.
uint32 SaveGameLen[4]; // How much memory to save/load.
struct SaveGame_t
{
uint8 *bufptr; // Pointer to memory to save/load.
uint32 buflen; // How much memory to save/load.
void (*resetFunc)(void); // Callback to reset save game memory
SaveGame_t(void)
: bufptr(nullptr), buflen(0), resetFunc(nullptr)
{
}
};
std::vector <SaveGame_t> SaveGame;
void addSaveGameBuf( uint8* bufptrIn, uint32 buflenIn, void (*resetFuncIn)(void) = nullptr )
{
SaveGame_t tmp;
tmp.bufptr = bufptrIn;
tmp.buflen = buflenIn;
tmp.resetFunc = resetFuncIn;
SaveGame.push_back( tmp );
}
// Set by iNES/UNIF loading code.
int mirror; // As set in the header or chunk.
// iNES/UNIF specific. Intended
// to help support games like "Karnov"
// that are not really MMC3 but are
// set to mapper 4.
// iNES/UNIF specific. Intended
// to help support games like "Karnov"
// that are not really MMC3 but are
// set to mapper 4.
int mirrorAs2Bits;
int battery; // Presence of an actual battery.
int ines2;
int submapper; // Submappers as defined by NES 2.0
@@ -23,7 +52,35 @@ typedef struct {
uint32 CRC32; // Should be set by the iNES/UNIF loading
// code, used by mapper/board code, maybe
// other code in the future.
} CartInfo;
CartInfo(void)
{
clear();
}
void clear(void)
{
Power = nullptr;
Reset = nullptr;
Close = nullptr;
SaveGame.clear();
mirror = 0;
mirrorAs2Bits = 0;
battery = 0;
ines2 = 0;
submapper = 0;
wram_size = 0;
battery_wram_size = 0;
vram_size = 0;
battery_vram_size = 0;
memset( MD5, 0, sizeof(MD5));
CRC32 = 0;
};
};
extern CartInfo *currCartInfo;
void FCEU_SaveGameSave(CartInfo *LocalHWInfo);
void FCEU_LoadGameSave(CartInfo *LocalHWInfo);
@@ -98,3 +155,5 @@ void FCEU_GeniePower(void);
bool FCEU_OpenGenie(void);
void FCEU_CloseGenie(void);
void FCEU_KillGenie(void);
#endif
+286 -315
View File
@@ -39,8 +39,7 @@ using namespace std;
static uint8 *CheatRPtrs[64];
vector<uint16> FrozenAddresses; //List of addresses that are currently frozen
void UpdateFrozenList(void); //Function that populates the list of frozen addresses
unsigned int FrozenAddressCount=0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor)
unsigned int FrozenAddressCount = 0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor)
void FCEU_CheatResetRAM(void)
{
@@ -60,27 +59,13 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
}
struct CHEATF {
struct CHEATF *next;
char *name;
uint16 addr;
uint8 val;
int compare; /* -1 for no compare. */
int type; /* 0 for replace, 1 for substitute(GG). */
int status;
};
typedef struct {
uint16 addr;
uint8 val;
int compare;
readfunc PrevRead;
} CHEATF_SUBFAST;
static CHEATF_SUBFAST SubCheats[256];
static int numsubcheats=0;
struct CHEATF *cheats=0,*cheatsl=0;
CHEATF_SUBFAST SubCheats[256];
uint32 numsubcheats = 0;
int globalCheatDisabled = 0;
int disableAutoLSCheats = 0;
bool disableShowGG = 0;
static _8BYTECHEATMAP* cheatMap = NULL;
struct CHEATF *cheats = 0, *cheatsl = 0;
#define CHEATC_NONE 0x8000
@@ -92,7 +77,7 @@ int savecheats = 0;
static DECLFR(SubCheatsRead)
{
CHEATF_SUBFAST *s=SubCheats;
CHEATF_SUBFAST *s = SubCheats;
int x=numsubcheats;
do
@@ -116,79 +101,91 @@ static DECLFR(SubCheatsRead)
void RebuildSubCheats(void)
{
int x;
struct CHEATF *c=cheats;
for(x=0;x<numsubcheats;x++)
SetReadHandler(SubCheats[x].addr,SubCheats[x].addr,SubCheats[x].PrevRead);
numsubcheats=0;
while(c)
uint32 x;
struct CHEATF *c = cheats;
for (x = 0; x < numsubcheats; x++)
{
if(c->type==1 && c->status)
SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[x].addr, false);
}
numsubcheats = 0;
if (!globalCheatDisabled)
{
while(c)
{
if(GetReadHandler(c->addr)==SubCheatsRead)
if(c->type == 1 && c->status && GetReadHandler(c->addr) != SubCheatsRead)
{
/* Prevent a catastrophe by this check. */
//FCEU_DispMessage("oops",0);
}
else
{
SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr);
SubCheats[numsubcheats].addr=c->addr;
SubCheats[numsubcheats].val=c->val;
SubCheats[numsubcheats].compare=c->compare;
SetReadHandler(c->addr,c->addr,SubCheatsRead);
SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr);
SubCheats[numsubcheats].addr = c->addr;
SubCheats[numsubcheats].val = c->val;
SubCheats[numsubcheats].compare = c->compare;
SetReadHandler(c->addr, c->addr, SubCheatsRead);
if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true);
numsubcheats++;
}
c = c->next;
}
c=c->next;
}
FrozenAddressCount = numsubcheats; //Update the frozen address list
UpdateFrozenList();
//FCEUI_DispMessage("Active Cheats: %d",0, FrozenAddresses.size()/*FrozenAddressCount*/); //Debug
}
void FCEU_PowerCheats()
{
numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */
numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */
if (cheatMap)
FCEUI_RefreshCheatMap();
RebuildSubCheats();
}
static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size) {
uint32 count = 0;
if (cheatMap)
for (uint32 i = 0; i < size; ++i)
if (FCEUI_FindCheatMapByte(address + i))
++count;
return count;
}
static void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type);
static void CheatMemErr(void)
{
FCEUD_PrintError("Error allocating memory for cheat data.");
}
/* This function doesn't allocate any memory for "name" */
static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type)
static void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
{
struct CHEATF *temp;
if(!(temp=(struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
{
CheatMemErr();
return(0);
}
temp->name=name;
temp->addr=addr;
temp->val=val;
temp->status=status;
temp->compare=compare;
temp->type=type;
temp->next=0;
CHEATF *temp = new CHEATF();
temp->name = name;
temp->addr = addr;
temp->val = val;
temp->status = status;
temp->compare = compare;
temp->type = type;
temp->next = nullptr;
if(cheats)
{
cheatsl->next=temp;
cheatsl=temp;
cheatsl->next = temp;
cheatsl = temp;
}
else
cheats=cheatsl=temp;
return(1);
cheats = cheatsl = temp;
}
void FCEU_LoadGameCheats(FILE *override)
/* The "override_existing" parameter is used only in cheat dialog import.
Since the default behaviour will reset numsubcheats to 0 everytime,
In game loading, this is absolutely right, but when importing in cheat window,
resetting numsubcheats to 0 will override existed cheat items to make them
invalid.
*/
void FCEU_LoadGameCheats(FILE *override, int override_existing)
{
FILE *fp;
unsigned int addr;
@@ -198,89 +195,120 @@ void FCEU_LoadGameCheats(FILE *override)
unsigned int compare;
int x;
char linebuf[2048];
char *namebuf;
int tc=0;
char linebuf[2048] = { 0 };
char namebuf[128] = { 0 };
int tc = 0;
char *fn;
numsubcheats=savecheats=0;
if (override_existing)
{
numsubcheats = 0;
if (cheatMap)
FCEUI_RefreshCheatMap();
}
if(override)
fp = override;
else
{
fn=strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
fp=FCEUD_UTF8fopen(fn,"rb");
fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0).c_str());
fp = FCEUD_UTF8fopen(fn, "rb");
free(fn);
if(!fp) return;
if (!fp) {
return;
}
}
FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded.
while(fgets(linebuf,2048,fp)>0)
while(fgets(linebuf, 2048, fp) != nullptr)
{
char *tbuf=linebuf;
int doc=0;
char *tbuf = linebuf;
int doc = 0;
addr=val=compare=status=type=0;
addr = val = compare = status = type = 0;
if(tbuf[0]=='S')
if(tbuf[0] == 'S')
{
tbuf++;
type=1;
type = 1;
}
else type=0;
else
type = 0;
if(tbuf[0]=='C')
if(tbuf[0] == 'C')
{
tbuf++;
doc=1;
doc = 1;
}
if(tbuf[0]==':')
if(tbuf[0] == ':')
{
tbuf++;
status=0;
status = 0;
}
else status=1;
else status = 1;
if(doc)
{
char *neo=&tbuf[4+2+2+1+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3)
char *neo = &tbuf[4+2+2+1+1+1];
if(sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3)
continue;
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1)))
return;
strcpy(namebuf,neo);
strcpy(namebuf, neo);
}
else
{
char *neo=&tbuf[4+2+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2)
char *neo = &tbuf[4+2+1+1];
if(sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2)
continue;
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1)))
return;
strcpy(namebuf,neo);
strcpy(namebuf, neo);
}
for(x=0;x<(int)strlen(namebuf);x++)
for(x = 0; x < (int)strlen(namebuf); x++)
{
if(namebuf[x]==10 || namebuf[x]==13)
if(namebuf[x] == 10 || namebuf[x] == 13)
{
namebuf[x]=0;
namebuf[x] = 0;
break;
}
else if(namebuf[x] > 0x00 && namebuf[x] < 0x20)
namebuf[x]=0x20;
namebuf[x] = 0x20;
}
AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type);
AddCheatEntry(namebuf, addr, val, doc ? compare : -1, status, type);
tc++;
}
RebuildSubCheats();
FCEU_DispMessage("Cheats file loaded.", 0); //Tells user a cheats file was loaded.
if(!override)
fclose(fp);
}
void FCEU_SaveGameCheats(FILE* fp, int release)
{
struct CHEATF *next = cheats;
while (next)
{
if (next->type)
fputc('S', fp);
if (next->compare >= 0)
fputc('C', fp);
if (!next->status)
fputc(':', fp);
if (next->compare >= 0)
fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name.c_str());
else
fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name.c_str());
struct CHEATF *t = next;
next = next->next;
if (release) delete t;
}
}
void FCEU_FlushGameCheats(FILE *override, int nosave)
{
if(CheatComp)
@@ -297,8 +325,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
{
struct CHEATF *last=next;
next=next->next;
free(last->name);
free(last);
delete last;
if(!next) break;
}
cheats=cheatsl=0;
@@ -313,7 +340,6 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
if(cheats)
{
struct CHEATF *next=cheats;
FILE *fp;
if(override)
@@ -323,28 +349,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
if(fp)
{
for(;;)
{
struct CHEATF *t;
if(next->type)
fputc('S',fp);
if(next->compare>=0)
fputc('C',fp);
if(!next->status)
fputc(':',fp);
if(next->compare>=0)
fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name);
else
fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
free(next->name);
t=next;
next=next->next;
free(t);
if(!next) break;
}
FCEU_SaveGameCheats(fp, 1);
if(!override)
fclose(fp);
}
@@ -365,23 +370,11 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
{
char *t;
if(!(t=(char *)FCEU_dmalloc(strlen(name)+1)))
{
CheatMemErr();
return(0);
}
strcpy(t,name);
if(!AddCheatEntry(t,addr,val,compare,1,type))
{
free(t);
return(0);
}
savecheats=1;
AddCheatEntry(name, addr, val, compare, 1, type);
savecheats = 1;
RebuildSubCheats();
return(1);
return 1;
}
int FCEUI_DelCheat(uint32 which)
@@ -411,8 +404,7 @@ int FCEUI_DelCheat(uint32 which)
else
cheats=cheatsl=0; // No (more) cheats.
}
free(cur->name); // Now that all references to this cheat are removed,
free(cur); // free the memory.
delete cur; // free the memory.
break;
} // *END REMOVE THIS CHEAT*
@@ -447,18 +439,18 @@ void FCEU_ApplyPeriodicCheats(void)
}
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
{
struct CHEATF *next=cheats;
while(next)
{
if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break;
if(!callb(next->name.c_str(),next->addr,next->val,next->compare,next->status,next->type,data)) break;
next=next->next;
}
}
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
{
struct CHEATF *next=cheats;
uint32 x=0;
@@ -566,7 +558,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c)
int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
{
int boo[4];
unsigned int boo[4];
if(strlen(str)!=8) return(0);
sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3);
@@ -596,45 +588,36 @@ int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
/* name can be NULL if the name isn't going to be changed. */
/* same goes for a, v, and s(except the values of each one must be <0) */
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type)
int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int c, int s, int type)
{
struct CHEATF *next=cheats;
uint32 x=0;
struct CHEATF *next = cheats;
uint32 x = 0;
while(next)
{
if(x==which)
if(x == which)
{
if(name)
{
char *t;
if((t=(char *)realloc(next->name, strlen(name)+1)))
{
next->name=t;
strcpy(next->name,name);
}
else
return(0);
}
if(a>=0)
next->addr=a;
if(v>=0)
next->val=v;
if(s>=0)
next->status=s;
if(c>=-1)
next->compare=c;
next->type=type;
next->name = *name;
if(a >= 0)
next->addr = a;
if(v >= 0)
next->val = v;
if(s >= 0)
next->status = s;
if(c >= -1)
next->compare = c;
next->type = type;
savecheats=1;
savecheats = 1;
RebuildSubCheats();
return(1);
return 1;
}
next=next->next;
next = next->next;
x++;
}
return(0);
return 0;
}
/* Convenience function. */
@@ -659,6 +642,14 @@ int FCEUI_ToggleCheat(uint32 which)
return(-1);
}
int FCEUI_GlobalToggleCheat(int global_enabled)
{
unsigned int _numsubcheats = numsubcheats;
globalCheatDisabled = !global_enabled;
RebuildSubCheats();
return _numsubcheats != numsubcheats;
}
static int InitCheatComp(void)
{
uint32 x;
@@ -741,7 +732,7 @@ void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
{
uint32 x;
uint32 in=0;
uint32 in = 0;
if(!CheatComp)
{
@@ -750,14 +741,15 @@ void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a,
return;
}
for(x=0;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
for(x = 0; x < 0x10000; x++)
if(!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
{
if(in>=first)
if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
if(in >= first)
if(!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x]))
break;
in++;
if(in>last) return;
if(in > last)
return;
}
}
@@ -803,130 +795,56 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
}
}
if(!type) // Change to a specific value.
switch (type)
{
for(x=0;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
default:
case FCEU_SEARCH_SPECIFIC_CHANGE: // Change to a specific value
for (x = 0; x < 0x10000; ++x)
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CheatRPtrs[x >> 10][x] != v2))
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_RELATIVE_CHANGE: // Search for relative change (between values).
for (x = 0; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2))
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_PUERLY_RELATIVE_CHANGE: // Purely relative change.
for (x = 0x000; x<0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_ANY_CHANGE: // Any change.
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] == CheatRPtrs[x >> 10][x])
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_KNOWN: // new value = known
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] != v1)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_GT: // new value greater than
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] >= CheatRPtrs[x >> 10][x])
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_LT: // new value less than
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] <= CheatRPtrs[x >> 10][x])
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_GT_KNOWN: // new value greater than by known value
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] - CheatComp[x] != v2)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_LT_KNOWN: // new value less than by known value
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
}
else if(type==1) // Search for relative change(between values).
{
for(x=0;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==2) // Purely relative change.
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==3) // Any change.
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]!=CheatRPtrs[x>>10][x])
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==4) // new value = known
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatRPtrs[x>>10][x]==v1)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==5) // new value greater than
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]<CheatRPtrs[x>>10][x])
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==6) // new value less than
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]>CheatRPtrs[x>>10][x])
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==7) // new value greater than by known value
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if((CheatRPtrs[x>>10][x]-CheatComp[x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==8) // new value less than by known value
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if((CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
}
int FCEU_CheatGetByte(uint32 A)
@@ -949,18 +867,71 @@ void FCEU_CheatSetByte(uint32 A, uint8 V)
BWrite[A](A, V);
}
void UpdateFrozenList(void)
// disable all cheats
int FCEU_DisableAllCheats(void)
{
//The purpose of this function is to keep an up to date list of addresses that are currently frozen
//and make these accessible to other dialogs that deal with memory addresses such as
//memwatch, hex editor, ramfilter, etc.
int x;
FrozenAddresses.clear(); //Clear vector and repopulate
for(x=0;x<numsubcheats;x++)
int count = 0;
struct CHEATF *next = cheats;
while(next)
{
FrozenAddresses.push_back(SubCheats[x].addr);
//FCEU_printf("Address %d: %d \n",x,FrozenAddresses[x]); //Debug
if(next->status){
count++;
}
next->status = 0;
next = next->next;
}
savecheats = 1;
RebuildSubCheats();
return count;
}
// delete all cheats
int FCEU_DeleteAllCheats(void)
{
struct CHEATF *cur = cheats;
struct CHEATF *next = NULL;
while (cur)
{
next = cur->next;
delete cur;
cur = next;
}
cheats = cheatsl = 0;
savecheats = 1;
RebuildSubCheats();
return 0;
}
int FCEUI_FindCheatMapByte(uint16 address)
{
return cheatMap[address / 8] >> (address % 8) & 1;
}
void FCEUI_SetCheatMapByte(uint16 address, bool cheat)
{
cheat ? cheatMap[address / 8] |= (1 << address % 8) : cheatMap[address / 8] ^= (1 << address % 8);
}
void FCEUI_CreateCheatMap(void)
{
if (!cheatMap)
cheatMap = (unsigned char*)malloc(CHEATMAP_SIZE);
FCEUI_RefreshCheatMap();
}
void FCEUI_RefreshCheatMap(void)
{
memset(cheatMap, 0, CHEATMAP_SIZE);
for (uint32 i = 0; i < numsubcheats; ++i)
FCEUI_SetCheatMapByte(SubCheats[i].addr, true);
}
void FCEUI_ReleaseCheatMap(void)
{
if (cheatMap)
{
free(cheatMap);
cheatMap = NULL;
}
//FCEUI_DispMessage("FrozenCount: %d",0,FrozenAddressCount);//Debug
}
+66 -2
View File
@@ -1,12 +1,76 @@
#ifndef CHEAT_H
#define CHEAT_H
void FCEU_CheatResetRAM(void);
void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p);
void FCEU_LoadGameCheats(FILE *override);
void FCEU_LoadGameCheats(FILE *override, int override_existing = 1);
void FCEU_FlushGameCheats(FILE *override, int nosave);
void FCEU_SaveGameCheats(FILE *fp, int release = 0);
int FCEUI_GlobalToggleCheat(int global_enabled);
void FCEU_ApplyPeriodicCheats(void);
void FCEU_PowerCheats(void);
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size);
// Trying to find a more efficient way for determining if an address has a cheat
// each bit of 1 byte represents to 8 bytes in NES
typedef unsigned char _8BYTECHEATMAP;
#define CHEATMAP_SIZE 0x10000 / 8
extern int FCEUI_FindCheatMapByte(uint16 address);
extern void FCEUI_SetCheatMapByte(uint16 address, bool cheat);
extern void FCEUI_CreateCheatMap(void);
extern void FCEUI_RefreshCheatMap(void);
extern void FCEUI_ReleaseCheatMap(void);
extern unsigned int FrozenAddressCount;
int FCEU_CheatGetByte(uint32 A);
void FCEU_CheatSetByte(uint32 A, uint8 V);
extern int savecheats;
extern int savecheats;
extern int globalCheatDisabled;
extern int disableAutoLSCheats;
int FCEU_DisableAllCheats(void);
int FCEU_DeleteAllCheats(void);
struct CHEATF_SUBFAST
{
uint16 addr;
uint8 val;
int compare;
readfunc PrevRead;
CHEATF_SUBFAST(void)
{
addr = 0; val = 0; compare = 0; PrevRead = nullptr;
}
};
struct CHEATF {
struct CHEATF *next;
std::string name;
uint16 addr;
uint8 val;
int compare; /* -1 for no compare. */
int type; /* 0 for replace, 1 for substitute(GG). */
int status;
};
struct SEARCHPOSSIBLE {
uint16 addr;
uint8 previous;
uint8 current;
bool update;
};
#define FCEU_SEARCH_SPECIFIC_CHANGE 0
#define FCEU_SEARCH_RELATIVE_CHANGE 1
#define FCEU_SEARCH_PUERLY_RELATIVE_CHANGE 2
#define FCEU_SEARCH_ANY_CHANGE 3
#define FCEU_SEARCH_NEWVAL_KNOWN 4
#define FCEU_SEARCH_NEWVAL_GT 5
#define FCEU_SEARCH_NEWVAL_LT 6
#define FCEU_SEARCH_NEWVAL_GT_KNOWN 7
#define FCEU_SEARCH_NEWVAL_LT_KNOWN 8
#endif
+114 -61
View File
@@ -34,10 +34,11 @@
* Primitive -> Number | Address | Register | Flag | PC Bank | '(' Connect ')'
* Number -> '#' [1-9A-F]*
* Address -> '$' [1-9A-F]* | '$' '[' Connect ']'
* Register -> 'A' | 'X' | 'Y' | 'P'
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V'
* Register -> 'A' | 'X' | 'Y' | 'P' | 'S'
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' | 'U' | 'D'
* PC Bank -> 'K'
* Data Bank -> 'T'
* Data Bank -> 'T'
* Value -> 'R' | 'W'
*/
#include "types.h"
@@ -50,17 +51,18 @@
#include <cassert>
#include <cctype>
// hack: this address is used by 'T' condition
uint16 addressOfTheLastAccessedData = 0;
// Next non-whitespace character in string
char next;
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
uint8 debugLastOpcode = 0; // used to evaluate 'W' condition
int ishex(char c)
// Next non-whitespace character in string
static char next = 0;
static int ishex(char c)
{
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
void scan(const char** str)
static void scan(const char** str)
{
do
{
@@ -69,40 +71,37 @@ void scan(const char** str)
} while (isspace(next));
}
// Frees a condition and all of it's sub conditions
void freeTree(Condition* c)
{
if (c->lhs) freeTree(c->lhs);
if (c->rhs) freeTree(c->rhs);
free(c);
}
// Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')'
Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
static Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
{
Condition* t = nextPart(str);
Condition* t1;
Condition* mid;
int op;
if (t == nullptr)
{
return nullptr;
}
while ((op = operators(str)))
{
scan(str);
t1 = nextPart(str);
if (t1 == 0)
if (t1 == nullptr)
{
if(t)
freeTree(t);
delete t;
return 0;
}
mid = (Condition*)FCEU_dmalloc(sizeof(Condition));
if (!mid)
return NULL;
memset(mid, 0, sizeof(Condition));
mid = new Condition();
if (mid == nullptr)
{
delete t;
delete t1;
return nullptr;
}
mid->lhs = t;
mid->rhs = t1;
@@ -115,7 +114,7 @@ Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), i
}
// Generic handler for two-character operators
int TwoCharOperator(const char** str, char c1, char c2, int op)
static int TwoCharOperator(const char** str, char c1, char c2, int op)
{
if (next == c1 && **str == c2)
{
@@ -129,31 +128,43 @@ int TwoCharOperator(const char** str, char c1, char c2, int op)
}
// Determines if a character is a flag
int isFlag(char c)
static int isFlag(char c)
{
return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D';
}
// Determines if a character is a register
int isRegister(char c)
static int isRegister(char c)
{
return c == 'A' || c == 'X' || c == 'Y' || c == 'P';
return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S';
}
// Determines if a character is for PC bank
int isPCBank(char c)
static int isPCBank(char c)
{
return c == 'K';
}
// Determines if a character is for Data bank
int isDataBank(char c)
static int isDataBank(char c)
{
return c == 'T';
}
// Determines if a character is for value read
static int isValueRead(char c)
{
return c == 'R';
}
// Determines if a character is for value write
static int isValueWrite(char c)
{
return c == 'W';
}
// Reads a hexadecimal number from str
int getNumber(unsigned int* number, const char** str)
static int getNumber(unsigned int* number, const char** str)
{
// char buffer[5];
@@ -171,19 +182,19 @@ int getNumber(unsigned int* number, const char** str)
return 1;
}
Condition* Connect(const char** str);
static Condition* Connect(const char** str);
// Handles the following part of the grammar: '(' E ')'
Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
static Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
{
if (next == openPar)
{
scan(str);
c->lhs = Connect(str);
if (!c) return 0;
c->lhs = Connect(str);
if (next == closePar)
{
scan(str);
@@ -202,7 +213,7 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP
* Check for primitives
* Flags, Registers, Numbers, Addresses and parentheses
*/
Condition* Primitive(const char** str, Condition* c)
static Condition* Primitive(const char** str, Condition* c)
{
if (isFlag(next)) /* Flags */
{
@@ -272,6 +283,40 @@ Condition* Primitive(const char** str, Condition* c)
return c;
}
else if (isValueRead(next))
{
if (c->type1 == TYPE_NO)
{
c->type1 = TYPE_VALUE_READ;
c->value1 = next;
}
else
{
c->type2 = TYPE_VALUE_READ;
c->value2 = next;
}
scan(str);
return c;
}
else if (isValueWrite(next))
{
if (c->type1 == TYPE_NO)
{
c->type1 = TYPE_VALUE_WRITE;
c->value1 = next;
}
else
{
c->type2 = TYPE_VALUE_WRITE;
c->value2 = next;
}
scan(str);
return c;
}
else if (next == '#') /* Numbers */
{
unsigned int number = 0;
@@ -346,21 +391,22 @@ Condition* Primitive(const char** str, Condition* c)
}
/* Handle * and / operators */
Condition* Term(const char** str)
static Condition* Term(const char** str)
{
Condition* t;
Condition* t1;
Condition* mid;
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
if (!t)
return NULL;
t = new Condition();
memset(t, 0, sizeof(Condition));
if (t == nullptr)
{
return NULL;
}
if (!Primitive(str, t))
{
freeTree(t);
delete t;
return 0;
}
@@ -370,22 +416,25 @@ Condition* Term(const char** str)
scan(str);
if (!(t1 = (Condition*)FCEU_dmalloc(sizeof(Condition))))
return NULL;
memset(t1, 0, sizeof(Condition));
if ((t1 = new Condition()) == nullptr)
{
delete t;
return nullptr;
}
if (!Primitive(str, t1))
{
freeTree(t);
freeTree(t1);
delete t;
delete t1;
return 0;
}
if (!(mid = (Condition*)FCEU_dmalloc(sizeof(Condition))))
return NULL;
memset(mid, 0, sizeof(Condition));
if ((mid = new Condition()) == nullptr)
{
delete t;
delete t1;
return nullptr;
}
mid->lhs = t;
mid->rhs = t1;
@@ -398,7 +447,7 @@ Condition* Term(const char** str)
}
/* Check for + and - operators */
int SumOperators(const char** str)
static int SumOperators(const char** str)
{
switch (next)
{
@@ -409,13 +458,13 @@ int SumOperators(const char** str)
}
/* Handle + and - operators */
Condition* Sum(const char** str)
static Condition* Sum(const char** str)
{
return InfixOperator(str, Term, SumOperators);
}
/* Check for <=, =>, ==, !=, > and < operators */
int CompareOperators(const char** str)
static int CompareOperators(const char** str)
{
int val = TwoCharOperator(str, '=', '=', OP_EQ);
if (val) return val;
@@ -439,13 +488,13 @@ int CompareOperators(const char** str)
}
/* Handle <=, =>, ==, !=, > and < operators */
Condition* Compare(const char** str)
static Condition* Compare(const char** str)
{
return InfixOperator(str, Sum, CompareOperators);
}
/* Check for || or && operators */
int ConnectOperators(const char** str)
static int ConnectOperators(const char** str)
{
int val = TwoCharOperator(str, '|', '|', OP_OR);
if(val) return val;
@@ -457,7 +506,7 @@ int ConnectOperators(const char** str)
}
/* Handle || and && operators */
Condition* Connect(const char** str)
static Condition* Connect(const char** str)
{
return InfixOperator(str, Compare, ConnectOperators);
}
@@ -470,6 +519,10 @@ Condition* generateCondition(const char* str)
scan(&str);
c = Connect(&str);
if (!c || next != 0) return 0;
if (!c || next != 0)
{
if (c) delete c;
return 0;
}
else return c;
}
+25 -2
View File
@@ -28,6 +28,8 @@
#define TYPE_ADDR 4
#define TYPE_PC_BANK 5
#define TYPE_DATA_BANK 6
#define TYPE_VALUE_READ 7
#define TYPE_VALUE_WRITE 8
#define OP_NO 0
#define OP_EQ 1
@@ -43,7 +45,9 @@
#define OP_OR 11
#define OP_AND 12
extern uint16 addressOfTheLastAccessedData;
extern uint16 debugLastAddress;
extern uint8 debugLastOpcode;
//mbg merge 7/18/06 turned into sane c++
struct Condition
{
@@ -57,9 +61,28 @@ struct Condition
unsigned int type2;
unsigned int value2;
Condition(void)
{
op = 0;
lhs = rhs = nullptr;
type1 = value1 = 0;
type2 = value2 = 0;
};
~Condition(void)
{
if (lhs)
{
delete lhs;
}
if (rhs)
{
delete rhs;
}
}
};
void freeTree(Condition* c);
Condition* generateCondition(const char* str);
#endif
+26 -12
View File
@@ -11,20 +11,27 @@
#include <cstdio>
#include <cstdlib>
static char *aboutString = 0;
static std::string aboutString;
#ifndef FCEUX_BUILD_TIMESTAMP
#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
#endif
//#pragma message( "Compiling using C++ Std: " __FCEU_STRINGIZE(__cplusplus) )
// returns a string suitable for use in an aboutbox
char *FCEUI_GetAboutString() {
const char *FCEUI_GetAboutString(void)
{
const char *aboutTemplate =
FCEU_NAME_AND_VERSION "\n\n"
"Administrators:\n"
"zeromus, punkrockguy318 (Lukas Sabota), feos\n"
"zeromus, feos\n"
"\n"
"Current Contributors:\n"
"CaH4e3, rainwarrior\n"
"CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n"
"\n"
"Past Contributors:\n"
"xhainingx, gocha, AnS\n"
"xhainingx, gocha, AnS, mjbudd77\n"
"\n"
"FCEUX 2.0:\n"
"mz, nitsujrehtona, SP, Ugly Joe,\n"
@@ -40,20 +47,27 @@ char *FCEUI_GetAboutString() {
"FCEU TAS - blip & nitsuja\n"
"FCEU TAS+ - Luke Gustafson\n"
"\n"
"Logo/icon:\n"
"Terwilf\n"
"\n"
"FCEUX is dedicated to the fallen heroes\n"
"of NES emulation. In Memoriam --\n"
"ugetab\n"
"\n"
__TIME__ " " __DATE__ "\n";
"\n"
FCEUX_BUILD_TIMESTAMP "\n";
if(aboutString) return aboutString;
if (aboutString.size() > 0) return aboutString.c_str();
const char *compilerString = FCEUD_GetCompilerString();
//allocate the string and concatenate the template with the compiler string
if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
return NULL;
char cppVersion[128];
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
return aboutString;
snprintf( cppVersion, sizeof(cppVersion), "\nCompiled using C++ Language Standard: %li\n", __cplusplus);
aboutString.assign( aboutTemplate );
aboutString.append( compilerString );
aboutString.append( cppVersion );
return aboutString.c_str();
}
View File
+286 -117
View File
@@ -6,6 +6,7 @@
#include "cart.h"
#include "ines.h"
#include "debug.h"
#include "debugsymboltable.h"
#include "driver.h"
#include "ppu.h"
@@ -18,45 +19,88 @@ unsigned int debuggerPageSize = 14;
int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank)
int vblankPixel = 0; //Used to calculate the pixels in vblank
int offsetStringToInt(unsigned int type, const char* offsetBuffer)
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk)
{
int offset = -1;
if (sscanf(offsetBuffer,"%4X",&offset) == EOF)
if (conversionOk)
{
*conversionOk = false;
}
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
{
return -1;
}
if (type & BT_P)
{
if (conversionOk)
{
*conversionOk = (offset >= 0) && (offset < 0x4000);
}
return offset & 0x3FFF;
}
else if (type & BT_S)
{
if (conversionOk)
{
*conversionOk = (offset >= 0) && (offset < 0x100);
}
return offset & 0x00FF;
}
else if (type & BT_R)
{
if (conversionOk)
{
*conversionOk = (offset >= 0);
}
return offset;
}
else // BT_C
{
if (GameInfo->type == GIT_NSF) { //NSF Breakpoint keywords
if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
auto sym = debugSymbolTable.getSymbolAtAnyBank(offsetBuffer);
if (sym)
{
if (conversionOk)
{
*conversionOk = true;
}
return sym->offset() & 0xFFFF;
}
else if (GameInfo->type == GIT_FDS) { //FDS Breakpoint keywords
if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
int type = GIT_CART;
if (GameInfo)
{
type = GameInfo->type;
}
if (type == GIT_NSF) { //NSF Breakpoint keywords
if (strcmp(offsetBuffer,"LOAD") == 0) offset = (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
else if (strcmp(offsetBuffer,"INIT") == 0) offset = (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
else if (strcmp(offsetBuffer,"PLAY") == 0) offset = (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
}
else if (type == GIT_FDS) { //FDS Breakpoint keywords
if (strcmp(offsetBuffer,"NMI1") == 0) offset = (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
else if (strcmp(offsetBuffer,"NMI2") == 0) offset = (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
else if (strcmp(offsetBuffer,"NMI3") == 0) offset = (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
}
else { //NES Breakpoint keywords
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) return (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) offset = (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
}
if (conversionOk)
{
*conversionOk = (offset >= 0) && (offset < 0x10000);
}
}
return offset;
return offset & 0xFFFF;
}
// Returns the value of a given type or register
@@ -77,6 +121,7 @@ int getValue(int type)
case 'Z': return _P & Z_FLAG ? 1 : 0;
case 'C': return _P & C_FLAG ? 1 : 0;
case 'P': return _PC;
case 'S': return _S;
}
return 0;
@@ -120,7 +165,7 @@ int checkCondition(const char* condition, int num)
// Remove the old breakpoint condition before adding a new condition.
if (watchpoint[num].cond)
{
freeTree(watchpoint[num].cond);
delete watchpoint[num].cond;
free(watchpoint[num].condText);
watchpoint[num].cond = 0;
watchpoint[num].condText = 0;
@@ -134,8 +179,8 @@ int checkCondition(const char* condition, int num)
{
watchpoint[num].cond = c;
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
if (!watchpoint[num].condText)
return 0;
if (!watchpoint[num].condText)
return 0;
strcpy(watchpoint[num].condText, condition);
}
else
@@ -150,7 +195,7 @@ int checkCondition(const char* condition, int num)
// Remove the old breakpoint condition
if (watchpoint[num].cond)
{
freeTree(watchpoint[num].cond);
delete watchpoint[num].cond;
free(watchpoint[num].condText);
watchpoint[num].cond = 0;
watchpoint[num].condText = 0;
@@ -193,6 +238,9 @@ unsigned int NewBreak(const char* name, int start, int end, unsigned int type, c
watchpoint[num].flags|=BT_S;
watchpoint[num].flags&=~WP_X; //disable execute flag!
}
if (type & BT_R) {
watchpoint[num].flags|=BT_R;
}
if (watchpoint[num].desc)
free(watchpoint[num].desc);
@@ -207,11 +255,27 @@ int GetPRGAddress(int A){
int result;
if(A > 0xFFFF)
return -1;
result = &Page[A>>11][A]-PRGptr[0];
if((result > (int)PRGsize[0]) || (result < 0))
return -1;
else
return result;
if (GameInfo->type == GIT_FDS) {
if (A < 0xE000) {
result = &Page[A >> 11][A] - PRGptr[1];
if ((result > (int)PRGsize[1]) || (result < 0))
return -1;
else
return result;
} else {
result = &Page[A >> 11][A] - PRGptr[0];
if ((result > (int)PRGsize[0]) || (result < 0))
return -1;
else
return result + PRGsize[1];
}
} else {
result = &Page[A >> 11][A] - PRGptr[0];
if ((result > (int)PRGsize[0]) || (result < 0))
return -1;
else
return result;
}
}
/**
@@ -228,7 +292,7 @@ int getBank(int offs)
//Anything over FFFFF will kill it.
//GetNesFileAddress doesn't work well with Unif files
int addr = GetNesFileAddress(offs)-16;
int addr = GetNesFileAddress(offs)-NES_HEADER_SIZE;
if (GameInfo && GameInfo->type==GIT_NSF)
return addr != -1 ? addr / 0x1000 : -1;
@@ -240,12 +304,12 @@ int GetNesFileAddress(int A){
if((A < 0x6000) || (A > 0xFFFF))return -1;
result = &Page[A>>11][A]-PRGptr[0];
if((result > (int)(PRGsize[0])) || (result < 0))return -1;
else return result+16; //16 bytes for the header remember
else return result+NES_HEADER_SIZE; //16 bytes for the header remember
}
int GetRomAddress(int A){
int i;
uint8 *p = GetNesPRGPointer(A-=16);
uint8 *p = GetNesPRGPointer(A-=NES_HEADER_SIZE);
for(i = 16;i < 32;i++){
if((&Page[i][i<<11] <= p) && (&Page[i][(i+1)<<11] > p))break;
}
@@ -309,6 +373,32 @@ uint8 GetPPUMem(uint8 A) {
//---------------------
uint8 evaluateWrite(uint8 opcode, uint16 address)
{
// predicts value written by this opcode
switch (opwrite[opcode])
{
default:
case 0: return 0; // no write
case 1: return _A; // STA, PHA
case 2: return _X; // STX
case 3: return _Y; // STY
case 4: return _P; // PHP
case 5: return GetMem(address) << 1; // ASL (SLO)
case 6: return GetMem(address) >> 1; // LSR (SRE)
case 7: return (GetMem(address) << 1) | (_P & 1); // ROL (RLA)
case 8: return (GetMem(address) >> 1) | ((_P & 1) << 7); // ROL (RRA)
case 9: return GetMem(address) + 1; // INC (ISC)
case 10: return GetMem(address) - 1; // DEC (DCP)
case 11: return _A & _X; // (SAX)
case 12: return _A&_X&(((address-_Y)>>8)+1); // (AHX)
case 13: return _Y&(((address-_X)>>8)+1); // (SHY)
case 14: return _X&(((address-_Y)>>8)+1); // (SHX)
case 15: return _S& (((address-_Y)>>8)+1); // (TAS)
}
return 0;
}
// Evaluates a condition
int evaluate(Condition* c)
{
@@ -334,7 +424,9 @@ int evaluate(Condition* c)
{
case TYPE_ADDR: value1 = GetMem(value1); break;
case TYPE_PC_BANK: value1 = getBank(_PC); break;
case TYPE_DATA_BANK: value1 = getBank(addressOfTheLastAccessedData); break;
case TYPE_DATA_BANK: value1 = getBank(debugLastAddress); break;
case TYPE_VALUE_READ: value1 = GetMem(debugLastAddress); break;
case TYPE_VALUE_WRITE: value1 = evaluateWrite(debugLastOpcode, debugLastAddress); break;
}
f = value1;
@@ -359,7 +451,9 @@ int evaluate(Condition* c)
{
case TYPE_ADDR: value2 = GetMem(value2); break;
case TYPE_PC_BANK: value2 = getBank(_PC); break;
case TYPE_DATA_BANK: value2 = getBank(addressOfTheLastAccessedData); break;
case TYPE_DATA_BANK: value2 = getBank(debugLastAddress); break;
case TYPE_VALUE_READ: value2 = GetMem(debugLastAddress); break;
case TYPE_VALUE_WRITE: value2 = evaluateWrite(debugLastOpcode, debugLastAddress); break;
}
switch (c->op)
@@ -371,7 +465,7 @@ int evaluate(Condition* c)
case OP_G: f = value1 > value2; break;
case OP_L: f = value1 < value2; break;
case OP_MULT: f = value1 * value2; break;
case OP_DIV: f = value1 / value2; break;
case OP_DIV: f = (value2==0) ? 0 : (value1 / value2); break;
case OP_PLUS: f = value1 + value2; break;
case OP_MINUS: f = value1 - value2; break;
case OP_OR: f = value1 || value2; break;
@@ -390,12 +484,12 @@ int condition(watchpointinfo* wp)
//---------------------
volatile int codecount, datacount, undefinedcount;
unsigned char *cdloggerdata;
volatile int codecount = 0, datacount = 0, undefinedcount = 0;
unsigned char *cdloggerdata = NULL;
unsigned int cdloggerdataSize = 0;
static int indirectnext;
static int indirectnext = 0;
int debug_loggingCD;
int debug_loggingCD = 0;
//called by the cpu to perform logging if CDLogging is enabled
void LogCDVectors(int which){
@@ -417,20 +511,29 @@ void LogCDVectors(int which){
}
}
void LogCDData(uint8 *opcode, uint16 A, int size) {
bool break_on_unlogged_code = false;
bool break_on_unlogged_data = false;
void LogCDData(uint8 *opcode, uint16 A, int size)
{
int i, j;
uint8 memop = 0;
bool newCodeHit = false, newDataHit = false;
if((j = GetPRGAddress(_PC)) != -1)
for (i = 0; i < size; i++) {
if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip
if ((j = GetPRGAddress(_PC)) != -1)
{
for (i = 0; i < size; i++)
{
if (cdloggerdata[j+i] & 1) continue; //this has been logged so skip
cdloggerdata[j+i] |= 1;
cdloggerdata[j+i] |= ((_PC + i) >> 11) & 0x0c;
cdloggerdata[j+i] |= ((_PC & 0x8000) >> 8) ^ 0x80; // 19/07/14 used last reserved bit, if bit 7 is 1, then code is running from lowe area (6000)
if(indirectnext)cdloggerdata[j+i] |= 0x10;
if (indirectnext)cdloggerdata[j+i] |= 0x10;
codecount++;
if(!(cdloggerdata[j+i] & 2))undefinedcount--;
if (!(cdloggerdata[j+i] & 2))undefinedcount--;
newCodeHit = true;
}
}
//log instruction jumped to in an indirect jump
if(opcode[0] == 0x6c)
@@ -443,14 +546,43 @@ void LogCDData(uint8 *opcode, uint16 A, int size) {
case 4: memop = 0x20; break;
}
if((j = GetPRGAddress(A)) != -1) {
if(!(cdloggerdata[j] & 2)) {
cdloggerdata[j] |= 2;
cdloggerdata[j] |=(A>>11)&0x0c;
cdloggerdata[j] |= memop;
datacount++;
if(!(cdloggerdata[j] & 1))undefinedcount--;
if ((j = GetPRGAddress(A)) != -1)
{
if (opwrite[opcode[0]] == 0)
{
if (!(cdloggerdata[j] & 2))
{
cdloggerdata[j] |= 2;
cdloggerdata[j] |= (A >> 11) & 0x0c;
cdloggerdata[j] |= memop;
cdloggerdata[j] |= ((A & 0x8000) >> 8) ^ 0x80;
datacount++;
if (!(cdloggerdata[j] & 1))undefinedcount--;
newDataHit = true;
}
}
else
{
if (cdloggerdata[j] & 1)
{
codecount--;
}
if (cdloggerdata[j] & 2)
{
datacount--;
}
if ((cdloggerdata[j] & 3) != 0) undefinedcount++;
cdloggerdata[j] = 0;
}
}
if ( break_on_unlogged_code && newCodeHit )
{
BreakHit( BREAK_TYPE_UNLOGGED_CODE );
}
else if ( break_on_unlogged_data && newDataHit )
{
BreakHit( BREAK_TYPE_UNLOGGED_DATA );
}
}
@@ -502,61 +634,71 @@ void IncrementInstructionsCounters()
delta_instructions++;
}
void BreakHit(int bp_num, bool force)
{
if(!force)
bool CondForbidTest(int bp_num) {
if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
{
//check to see whether we fall in any forbid zone
for (int i = 0; i < numWPs; i++)
{
watchpointinfo& wp = watchpoint[i];
if(!(wp.flags & WP_F) || !(wp.flags & WP_E))
continue;
return false; // condition rejected
}
if (condition(&wp))
{
if (wp.endaddress) {
if( (wp.address <= _PC) && (wp.endaddress >= _PC) )
return; //forbid
} else {
if(wp.address == _PC)
return; //forbid
}
//check to see whether we fall in any forbid zone
for (int i = 0; i < numWPs; i++)
{
watchpointinfo& wp = watchpoint[i];
if (!(wp.flags & WP_F) || !(wp.flags & WP_E))
continue;
if (condition(&wp))
{
if (wp.endaddress) {
if ((wp.address <= _PC) && (wp.endaddress >= _PC))
return false; // forbid
}
else {
if (wp.address == _PC)
return false; // forbid
}
}
}
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused()
#ifdef WIN32
FCEUD_DebugBreakpoint(bp_num);
#endif
return true;
}
uint8 StackAddrBackup = X.S;
void BreakHit(int bp_num)
{
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused()
//#ifdef WIN32
FCEUD_DebugBreakpoint(bp_num);
//#endif
}
int StackAddrBackup;
uint16 StackNextIgnorePC = 0xFFFF;
///fires a breakpoint
static void breakpoint(uint8 *opcode, uint16 A, int size) {
int i, j;
int i, romAddrPC;
unsigned int j;
uint8 brk_type;
uint8 stackop=0;
uint8 stackopstartaddr,stackopendaddr;
uint8 stackopstartaddr=0,stackopendaddr=0;
debugLastAddress = A;
debugLastOpcode = opcode[0];
if (break_asap)
{
break_asap = false;
BreakHit(BREAK_TYPE_LUA, true);
BreakHit(BREAK_TYPE_LUA);
}
if (break_on_cycles && ((timestampbase + (uint64)timestamp - total_cycles_base) > break_cycles_limit))
BreakHit(BREAK_TYPE_CYCLES_EXCEED, true);
BreakHit(BREAK_TYPE_CYCLES_EXCEED);
if (break_on_instructions && (total_instructions > break_instructions_limit))
BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED, true);
BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED);
//if the current instruction is bad, and we are breaking on bad opcodes, then hit the breakpoint
if(dbgstate.badopbreak && (size == 0))
BreakHit(BREAK_TYPE_BADOP, true);
BreakHit(BREAK_TYPE_BADOP);
//if we're stepping out, track the nest level
if (dbgstate.stepout) {
@@ -575,7 +717,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
//if we're stepping, then we'll always want to break
if (dbgstate.step) {
dbgstate.step = false;
BreakHit(BREAK_TYPE_STEP, true);
BreakHit(BREAK_TYPE_STEP);
return;
}
@@ -587,7 +729,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (diff<=0)
{
dbgstate.runline=false;
BreakHit(BREAK_TYPE_STEP, true);
BreakHit(BREAK_TYPE_STEP);
return;
}
}
@@ -596,33 +738,36 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) {
watchpoint[64].address = 0;
watchpoint[64].flags = 0;
BreakHit(BREAK_TYPE_STEP, true);
BreakHit(BREAK_TYPE_STEP);
return;
}
romAddrPC = GetNesFileAddress(_PC);
brk_type = opbrktype[opcode[0]] | WP_X;
switch (opcode[0]) {
//Push Ops
case 0x08: //Fall to next
case 0x48: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
case 0x48: debugLastAddress=stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
//Pull Ops
case 0x28: //Fall to next
case 0x68: stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
case 0x68: debugLastAddress=stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
//JSR (Includes return address - 1)
case 0x20: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=(opcode[1]|opcode[2]<<8); break;
//RTI (Includes processor status, and exact return address)
case 0x40: stackopstartaddr=X.S+1; stackopendaddr=X.S+3; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(X.S+2|0x0100)|GetMem(X.S+3|0x0100)<<8); break;
//RTS (Includes return address - 1)
case 0x60: stackopstartaddr=X.S+1; stackopendaddr=X.S+2; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(stackopstartaddr|0x0100)|GetMem(stackopendaddr|0x0100)<<8)+1; break;
default: break;
}
#define BREAKHIT(x) { if (CondForbidTest(x)) { breakHit = (x); goto STOPCHECKING; } }
int breakHit = -1;
for (i = 0; i < numWPs; i++)
{
// ################################## Start of SP CODE ###########################
if ((watchpoint[i].flags & WP_E) && condition(&watchpoint[i]))
if ((watchpoint[i].flags & WP_E))
{
// ################################## End of SP CODE ###########################
if (watchpoint[i].flags & BT_P)
{
// PPU Mem breaks
@@ -632,11 +777,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= PPUAddr) && (watchpoint[i].endaddress >= PPUAddr))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == PPUAddr)
BreakHit(i);
BREAKHIT(i);
}
}
} else if (watchpoint[i].flags & BT_S)
@@ -647,16 +792,16 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= PPU[3]) && (watchpoint[i].endaddress >= PPU[3]))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == PPU[3])
BreakHit(i);
BREAKHIT(i);
}
} else if ((watchpoint[i].flags & WP_W) && (A == 0x4014))
{
// Sprite DMA! :P
BreakHit(i);
BREAKHIT(i);
}
} else
{
@@ -667,12 +812,32 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
{
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address <= A) && (watchpoint[i].endaddress >= A)) ||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC)))
BreakHit(i);
} else
BREAKHIT(i);
}
else
{
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) ||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC)))
BreakHit(i);
if (watchpoint[i].flags & BT_R)
{
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == static_cast<unsigned int>(romAddrPC)) )
{
BREAKHIT(i);
}
//else if ( (watchpoint[i].flags & WP_R) && (watchpoint[i].address == A) )
//{
// BREAKHIT(i);
//}
}
else
{
if ( (watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A))
{
BREAKHIT(i);
}
else if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC) )
{
BREAKHIT(i);
}
}
}
} else
{
@@ -684,16 +849,16 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// TXS and TSX only deal with the pointer.
if (watchpoint[i].flags & stackop)
{
for (j = (stackopstartaddr|0x0100); j <= (stackopendaddr|0x0100); j++)
for (j = (stackopstartaddr|0x0100); j <= (static_cast<unsigned int>(stackopendaddr)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == j)
BreakHit(i);
BREAKHIT(i);
}
}
}
@@ -704,40 +869,40 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
StackNextIgnorePC = 0xFFFF;
} else
{
if ((X.S < StackAddrBackup) && (stackop==0))
if (StackAddrBackup != -1 && (X.S < StackAddrBackup) && (stackop==0))
{
// Unannounced stack mem breaks
// Pushes to stack
if (watchpoint[i].flags & WP_W)
{
for (j = (X.S|0x0100); j < (StackAddrBackup|0x0100); j++)
for (j = (X.S|0x0100); j < (static_cast<unsigned int>(StackAddrBackup)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == j)
BreakHit(i);
BREAKHIT(i);
}
}
}
} else if ((StackAddrBackup < X.S) && (stackop==0))
} else if (StackAddrBackup != -1 && (StackAddrBackup < X.S) && (stackop==0))
{
// Pulls from stack
if (watchpoint[i].flags & WP_R)
{
for (j = (StackAddrBackup|0x0100); j < (X.S|0x0100); j++)
for (j = (StackAddrBackup|0x0100); j < (static_cast<unsigned int>(X.S)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == j)
BreakHit(i);
BREAKHIT(i);
}
}
}
@@ -746,13 +911,20 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
}
}
// ################################## Start of SP CODE ###########################
}
// ################################## End of SP CODE ###########################
}
} //loop across all breakpoints
STOPCHECKING:
//Update the stack address with the current one, now that changes have registered.
//ZEROMUS THINKS IT MAKES MORE SENSE HERE
StackAddrBackup = X.S;
if(breakHit != -1)
BreakHit(i);
////Update the stack address with the current one, now that changes have registered.
//StackAddrBackup = X.S;
}
//bbit edited: this is the end of the inserted code
@@ -781,9 +953,12 @@ void DebugCycle()
size = opsize[opcode[0]];
switch (size)
{
default:
case 1: break;
case 2:
opcode[1] = GetMem(_PC + 1);
break;
case 0: // illegal instructions may have operands
case 3:
opcode[1] = GetMem(_PC + 1);
opcode[2] = GetMem(_PC + 2);
@@ -807,7 +982,6 @@ void DebugCycle()
case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break;
case 8: A = opcode[1] + _Y; break;
}
addressOfTheLastAccessedData = A;
if (numWPs || dbgstate.step || dbgstate.runline || dbgstate.stepout || watchpoint[64].flags || dbgstate.badopbreak || break_on_cycles || break_on_instructions || break_asap)
breakpoint(opcode, A, size);
@@ -815,10 +989,5 @@ void DebugCycle()
if(debug_loggingCD)
LogCDData(opcode, A, size);
#ifdef WIN32
//This needs to be windows only or else the linux build system will fail since logging is declared in a
//windows source file
FCEUD_TraceInstruction(opcode, size);
#endif
}
+14 -8
View File
@@ -15,12 +15,15 @@
#define BT_C 0x00 //break type, cpu mem
#define BT_P 0x20 //break type, ppu mem
#define BT_S 0x40 //break type, sprite mem
#define BT_R 0x80 //break type, rom mem
#define BREAK_TYPE_STEP -1
#define BREAK_TYPE_BADOP -2
#define BREAK_TYPE_CYCLES_EXCEED -3
#define BREAK_TYPE_INSTRUCTIONS_EXCEED -4
#define BREAK_TYPE_LUA -5
#define BREAK_TYPE_UNLOGGED_CODE -6
#define BREAK_TYPE_UNLOGGED_DATA -7
//opbrktype is used to grab the breakpoint type that each instruction will cause.
//WP_X is not used because ALL opcodes will have the execute bit set.
@@ -46,21 +49,20 @@ static const uint8 opbrktype[256] = {
typedef struct {
uint16 address;
uint16 endaddress;
uint8 flags;
// ################################## Start of SP CODE ###########################
uint32 address;
uint32 endaddress;
uint16 flags;
Condition* cond;
char* condText;
char* desc;
// ################################## End of SP CODE ###########################
} watchpointinfo;
//mbg merge 7/18/06 had to make this extern
extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over
extern unsigned int debuggerPageSize;
int getBank(int offs);
int GetNesFileAddress(int A);
int GetPRGAddress(int A);
@@ -95,9 +97,12 @@ static INLINE int FCEUI_GetLoggingCD() { return debug_loggingCD; }
extern int iaPC;
extern uint32 iapoffset; //mbg merge 7/18/06 changed from int
void DebugCycle();
void BreakHit(int bp_num, bool force = false);
bool CondForbidTest(int bp_num);
void BreakHit(int bp_num);
extern bool break_asap;
extern bool break_on_unlogged_code;
extern bool break_on_unlogged_data;
extern uint64 total_cycles_base;
extern uint64 delta_cycles_base;
extern bool break_on_cycles;
@@ -115,8 +120,9 @@ extern void IncrementInstructionsCounters();
//internal variables that debuggers will want access to
extern uint8 *vnapage[4],*VPage[8];
extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
extern uint8 PPU[4],PALRAM[0x20],UPALRAM[3],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
extern uint32 FCEUPPU_PeekAddress();
extern uint8 READPAL_MOTHEROFALL(uint32 A);
extern int numWPs;
///encapsulates the operational state of the debugger core
@@ -166,7 +172,7 @@ DebuggerState &FCEUI_Debugger();
//#define WRITE_BREAKPOINT 16
//#define EXECUTE_BREAKPOINT 32
int offsetStringToInt(unsigned int type, const char* offsetBuffer);
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk = nullptr);
unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable);
#endif
File diff suppressed because it is too large Load Diff
+170
View File
@@ -0,0 +1,170 @@
#ifndef _DEBUGSYMBOLTABLE_H_
#define _DEBUGSYMBOLTABLE_H_
#include <string>
#include <map>
#include "utils/mutex.h"
#include "ld65dbg.h"
class debugSymbolPage_t;
class debugSymbolTable_t;
class debugSymbol_t
{
public:
debugSymbol_t(void)
{
ofs = 0;
page = nullptr;
};
debugSymbol_t( int ofs, const char *name = nullptr, const char *comment = nullptr )
{
this->ofs = ofs;
if (name)
{
this->_name.assign(name);
}
if ( comment )
{
this->_comment.assign( comment );
}
page = nullptr;
}
const std::string &name(void)
{
return _name;
}
const std::string &comment(void)
{
return _comment;
}
void commentAssign( std::string str )
{
_comment.assign(str);
return;
}
void commentAssign( const char *str )
{
_comment.assign(str);
return;
}
int offset(void)
{
return ofs;
}
void setOffset( int o )
{
if (o != ofs)
{
ofs = o;
}
}
int updateName( const char *name, int arrayIndex = -1 );
void trimTrailingSpaces(void);
private:
int ofs;
std::string _name;
std::string _comment;
debugSymbolPage_t *page;
friend class debugSymbolPage_t;
friend class debugSymbolTable_t;
};
class debugSymbolPage_t
{
public:
debugSymbolPage_t(int page);
~debugSymbolPage_t(void);
int save(void);
void print(void);
int size(void){ return static_cast<int>(symMap.size()); }
int addSymbol( debugSymbol_t *sym );
int deleteSymbolAtOffset( int ofs );
int updateSymbol( debugSymbol_t *sym );
debugSymbol_t *getSymbolAtOffset( int ofs );
debugSymbol_t *getSymbol( const std::string &name );
int pageNum(void)
{
return _pageNum;
}
const char *pageName(void)
{
return _pageName;
}
private:
int _pageNum;
char _pageName[8];
std::map <int, debugSymbol_t*> symMap;
std::map <std::string, debugSymbol_t*> symNameMap;
friend class debugSymbolTable_t;
};
class debugSymbolTable_t
{
public:
debugSymbolTable_t(void);
~debugSymbolTable_t(void);
int loadFileNL( int addr );
int loadRegisterMap(void);
int loadGameSymbols(void);
int numPages(void){ return pageMap.size(); }
int numSymbols(void);
void save(void);
void clear(void);
void print(void);
debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs );
debugSymbol_t *getSymbol( int bank, const std::string& name);
debugSymbol_t *getSymbolAtAnyBank( const std::string& name);
int addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym );
int addSymbolAtBankOffset(int bank, int ofs, const char* name, const char* comment = nullptr);
int deleteSymbolAtBankOffset( int bank, int ofs );
int updateSymbol( debugSymbol_t *sym );
const char *errorMessage(void);
int ld65LoadDebugFile( const char *dbgFilePath );
void ld65_SymbolLoad( ld65::sym *s );
private:
std::map <int, debugSymbolPage_t*> pageMap;
FCEU::mutex *cs;
};
extern debugSymbolTable_t debugSymbolTable;
#endif
+5 -5
View File
@@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf)
hasPlayRecIcon = true;
}
if(FCEUI_EmulationPaused())
if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
}
}
@@ -395,10 +395,10 @@ static int FixJoedChar(uint8 ch)
int c = ch - 32;
return (c < 0 || c > 98) ? 0 : c;
}
static int JoedCharWidth(uint8 ch)
{
return Font6x7[FixJoedChar(ch)*8];
}
//static int JoedCharWidth(uint8 ch)
//{
// return Font6x7[FixJoedChar(ch)*8];
//}
char target[64][256];
+28 -8
View File
@@ -14,14 +14,16 @@ inline FILE *FCEUD_UTF8fopen(const std::string &n, const char *mode) { return FC
EMUFILE_FILE* FCEUD_UTF8_fstream(const char *n, const char *m);
inline EMUFILE_FILE* FCEUD_UTF8_fstream(const std::string &n, const char *m) { return FCEUD_UTF8_fstream(n.c_str(),m); }
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex);
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex, int* userCancel);
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename);
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel);
ArchiveScanRecord FCEUD_ScanArchive(std::string fname);
//mbg 7/23/06
const char *FCEUD_GetCompilerString();
//This makes me feel dirty for some reason.
void FCEU_printf(char *format, ...);
void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
#define FCEUI_printf FCEU_printf
//Video interface
@@ -122,7 +124,8 @@ void FCEUI_SetVidSystem(int a);
//Set variables for NTSC(0) / PAL(1) / Dendy(2)
//Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps
void FCEUI_SetRegion(int region);
void FCEUI_SetRegion(int region, int notify = 1);
int FCEUI_GetRegion(void);
//Convenience function; returns currently emulated video system(0=NTSC, 1=PAL).
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend);
@@ -140,7 +143,9 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall);
//Sets the base directory(save states, snapshots, etc. are saved in directories below this directory.
void FCEUI_SetBaseDirectory(std::string const & dir);
const char *FCEUI_GetBaseDirectory(void);
bool FCEUI_GetUserPaletteAvail(void);
void FCEUI_SetUserPalette(uint8 *pal, int nEntries);
//Sets up sound code to render sound at the specified rate, in samples
@@ -178,10 +183,16 @@ void FCEUD_MovieRecordTo(void);
void FCEUD_MovieReplayFrom(void);
void FCEUD_LuaRunFrom(void);
#ifdef _S9XLUA_H
// lua engine
void TaseditorAutoFunction(void);
void TaseditorManualFunction(void);
#endif
int32 FCEUI_GetDesiredFPS(void);
void FCEUI_SaveSnapshot(void);
void FCEUI_SaveSnapshotAs(void);
void FCEU_DispMessage(char *format, int disppos, ...);
void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
#define FCEUI_DispMessage FCEU_DispMessage
int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
@@ -189,16 +200,17 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
int FCEUI_DelCheat(uint32 which);
int FCEUI_ToggleCheat(uint32 which);
int FCEUI_GlobalToggleCheat(int global_enable);
int32 FCEUI_CheatSearchGetCount(void);
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current));
void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data);
void FCEUI_CheatSearchBegin(void);
void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2);
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type);
int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int compare,int s, int type);
void FCEUI_CheatSearchShowExcluded(void);
void FCEUI_CheatSearchSetCurrentAsOriginal(void);
@@ -242,12 +254,14 @@ void FCEUI_VSUniToggleDIP(int w);
uint8 FCEUI_VSUniGetDIPs(void);
void FCEUI_VSUniSetDIP(int w, int state);
void FCEUI_VSUniCoin(void);
void FCEUI_VSUniCoin2(void);
void FCEUI_VSUniService(void);
void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make it an EMUCMDFN
//int FCEUI_FDSEject(void);
void FCEUI_FDSSelect(void);
int FCEUI_DatachSet(const uint8 *rcode);
int FCEUI_DatachSet(uint8 *rcode);
///returns a flag indicating whether emulation is paused
int FCEUI_EmulationPaused();
@@ -259,6 +273,8 @@ void FCEUI_ClearEmulationFrameStepped();
void FCEUI_SetEmulationPaused(int val);
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
void FCEUI_ToggleEmulationPause();
void FCEUI_PauseForDuration(int secs);
int FCEUI_PauseFramesRemaining();
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
bool FCEUD_ShouldDrawInputAids();
@@ -318,6 +334,9 @@ void FCEUD_DebugBreakpoint(int bp_num);
///the driver should log the current instruction, if it wants (we should move the code in the win driver that does this to the shared area)
void FCEUD_TraceInstruction(uint8 *opcode, int size);
///the driver should flush its trace log
void FCEUD_FlushTrace();
///the driver might should update its NTView (only used if debugging support is compiled in)
void FCEUD_UpdateNTView(int scanline, bool drawall);
@@ -337,7 +356,8 @@ enum EFCEUI
FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE,
FCEUI_OPENGAME, FCEUI_CLOSEGAME,
FCEUI_TASEDITOR,
FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN
FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN, FCEUI_INPUT_BARCODE,
FCEUI_TOGGLERECORDINGMOVIE, FCEUI_TRUNCATEMOVIE, FCEUI_INSERT1FRAME, FCEUI_DELETE1FRAME
};
//checks whether an EFCEUI is valid right now
-6
View File
@@ -1,6 +0,0 @@
import glob
source_list = glob.glob('*.cpp') + glob.glob('*.c')
for x in range(len(source_list)):
source_list[x] = 'drivers/common/' + source_list[x]
Return('source_list')
+5 -5
View File
@@ -19,11 +19,11 @@
*/
/****************************************************************/
/* FCE Ultra */
/* */
/* This file contains code for parsing command-line */
/* options. */
/* */
/* FCE Ultra */
/* */
/* This file contains code for parsing command-line */
/* options. */
/* */
/****************************************************************/
#include <stdio.h>
+57 -25
View File
@@ -26,7 +26,11 @@
static void GetString(char *s, int max)
{
int x;
fgets(s,max,stdin);
if ( fgets(s,max,stdin) == nullptr )
{
s[0] = 0;
return;
}
for(x=0;x<max;x++)
if(s[x]=='\n')
@@ -41,7 +45,10 @@ static uint32 GetH16(unsigned int def)
{
char buf[32];
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='\n')
return(def);
if(buf[0]=='$')
@@ -56,7 +63,10 @@ static uint8 Get8(unsigned int def)
{
char buf[32];
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='\n')
return(def);
sscanf(buf,"%u",&def);
@@ -67,7 +77,10 @@ static int GetI(int def)
{
char buf[32];
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='\n')
return(def);
sscanf(buf,"%d",&def);
@@ -78,7 +91,10 @@ static int GetYN(int def)
{
char buf[32];
printf("(Y/N)[%s]: ",def?"Y":"N");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='y' || buf[0]=='Y')
return(1);
if(buf[0]=='n' || buf[0]=='N')
@@ -114,7 +130,10 @@ int ListChoice(int hmm)
tryagain:
printf(" <'Enter' to continue, (S)top, or enter a number.> ");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return -1;
}
if(buf[0]=='s' || buf[0]=='S') return(-1);
if(buf[0]=='\n') return(0);
if(!sscanf(buf,"%d",&num))
@@ -128,7 +147,10 @@ int ListChoice(int hmm)
tryagain2:
printf(" <'Enter' to make no selection or enter a number.> ");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return -1;
}
if(buf[0]=='\n') return(0);
if(!sscanf(buf,"%d",&num))
return(0);
@@ -176,7 +198,7 @@ int AddToList(char *text, uint32 id)
**/
typedef struct MENU {
char *text;
const char *text;
void *action;
int type; // 0 for menu, 1 for function.
} MENU;
@@ -199,7 +221,8 @@ static void ToggleCheat(int num)
static void ModifyCheat(int num)
{
char *name;
std::string name;
std::string *pName;
char buf[256];
uint32 A;
uint8 V;
@@ -211,7 +234,7 @@ static void ModifyCheat(int num)
FCEUI_GetCheat(num, &name, &A, &V, &compare, &s, &type);
printf("Name [%s]: ",name);
printf("Name [%s]: ",name.c_str());
GetString(buf,256);
/* This obviously doesn't allow for cheats with no names. Bah. Who wants
@@ -219,14 +242,14 @@ static void ModifyCheat(int num)
*/
if(buf[0])
name=buf; // Change name when FCEUI_SetCheat() is called.
pName=&name; // Change name when FCEUI_SetCheat() is called.
else
name=0; // Don't change name when FCEUI_SetCheat() is called.
pName=nullptr; // Don't change name when FCEUI_SetCheat() is called.
printf("Address [$%04x]: ",(unsigned int)A);
A=GetH16(A);
printf("Value [%03d]: ",(unsigned int)V);
printf("Value [%03u]: ",(unsigned int)V);
V=Get8(V);
printf("Compare [%3d]: ",compare);
@@ -240,7 +263,7 @@ static void ModifyCheat(int num)
if(t=='Y' || t=='y') s=1;
else if(t=='N' || t=='n') s=0;
FCEUI_SetCheat(num,name,A,V,compare,s,type);
FCEUI_SetCheat(num,pName,A,V,compare,s,type);
}
@@ -302,9 +325,9 @@ static void AddCheatParam(uint32 A, uint8 V)
GetString(name,256);
printf("Address [$%04x]: ",(unsigned int)A);
A=GetH16(A);
printf("Value [%03d]: ",(unsigned int)V);
printf("Value [%03u]: ",(unsigned int)V);
V=Get8(V);
printf("Add cheat \"%s\" for address $%04x with value %03d?",name,(unsigned int)A,(unsigned int)V);
printf("Add cheat \"%s\" for address $%04x with value %03u?",name,(unsigned int)A,(unsigned int)V);
if(GetYN(0))
{
if(FCEUI_AddCheat(name,A,V,-1,0))
@@ -320,15 +343,15 @@ static void AddCheat(void)
}
static int lid;
static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
static int clistcallb(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
{
char tmp[512];
int ret;
if(compare>=0)
sprintf(tmp,"%s $%04x:%03d:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name);
sprintf(tmp,"%s $%04x:%03u:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name);
else
sprintf(tmp,"%s $%04x:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
sprintf(tmp,"%s $%04x:%03u - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
if(type==1)
tmp[2]='S';
ret=AddToList(tmp,lid);
@@ -348,7 +371,10 @@ static void ListCheats(void)
{
char tmp[32];
printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
fgets(tmp,ARRAY_SIZE(tmp),stdin);
if ( fgets(tmp,ARRAY_SIZE(tmp),stdin) == nullptr )
{
tmp[0] = 0;
}
switch(tolower(tmp[0]))
{
case 't':ToggleCheat(which);
@@ -373,7 +399,7 @@ static void ResetSearch(void)
static int srescallb(uint32 a, uint8 last, uint8 current, void *data)
{
char tmp[14];
sprintf(tmp, "$%04x:%03d:%03d",(unsigned int)a,(unsigned int)last,(unsigned int)current);
sprintf(tmp, "$%04x:%03u:%03u",(unsigned int)a,(unsigned int)last,(unsigned int)current);
return(AddToList(tmp,a));
}
@@ -392,7 +418,7 @@ static void ShowRes(void)
}
}
static int ShowShortList(char *moe[], int n, int def)
static int ShowShortList(const char *moe[], int n, int def)
{
int x,c;
int baa; //mbg merge 7/17/06 made to normal int
@@ -405,7 +431,10 @@ static int ShowShortList(char *moe[], int n, int def)
clo:
printf("\nSelection [%d]> ",def+1);
fgets(tmp,ARRAY_SIZE(tmp),stdin);
if ( fgets(tmp,ARRAY_SIZE(tmp),stdin) == nullptr )
{
return def;
}
if(tmp[0]=='\n')
return def;
c=tolower(tmp[0]);
@@ -430,7 +459,7 @@ static void DoSearch(void)
{
static int v1=0,v2=0;
static int method=0;
char *m[9]={"O==V1 && C==V2",
const char *m[9]={"O==V1 && C==V2",
"O==V1 && |O-C|==V2",
"|O-C|==V2",
"O!=C",
@@ -504,7 +533,10 @@ static void DoMenu(MENU *men)
recommand:
printf("Command> ");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return;
}
c=tolower(buf[0]);
if(c=='\n')
goto recommand;
+3 -1
View File
@@ -17,5 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef COMMON_CHEAT_H
#define COMMON_CHEAT_H
void DoConsoleCheatConfig(void);
#endif
+7 -2
View File
@@ -125,7 +125,7 @@ static void cfg_Save(FILE *fp)
{
if(it->first.size()>30 || it->second.size()>30)
{
int zzz=9;
//int zzz=9;
}
fprintf(fp,"%s %s\n",it->first.c_str(),it->second.c_str());
}
@@ -145,6 +145,11 @@ static void GetValueR(FILE *fp, char *str, void *v, int c)
{
if(!c) // String, allocate some memory.
{
// Windows enforces a 32767 character limit for text boxes by default
// If a string exceeds this length, it's probably a corrupt file
if (s > 32768)
goto gogl;
if(!(*(char **)v=(char*)malloc(s)))
goto gogl;
@@ -208,7 +213,7 @@ void SaveParse(const CFGSTRUCT *cfgst, FILE *fp)
if(*(char **)cfgst[x].ptr)
{
// Only save it if there IS a string.
unsigned int len = strlen(*(char **)cfgst[x].ptr);
size_t len = strlen(*(char **)cfgst[x].ptr);
SetValueR(fp,cfgst[x].name,*(char **)cfgst[x].ptr, len + 1);
}
}
+7 -2
View File
@@ -23,16 +23,21 @@ void LoadFCEUConfig(const char *filename, CFGSTRUCT *cfgst);
// isn't really hurting much.
// Single piece of data(integer).
#define AC(x) { #x,&x,sizeof(x)}
#define NAC(w,x) { #w,&x,sizeof(x)}
#define AC(x) {#x,&x,sizeof(x)}
#define NAC(w,x) {#w,&x,sizeof(x)}
// VAC intruduced for backward compatibility with
// configuration files of previous versions
#define VAC(x,version) {#x "_V" #version,&x,sizeof(x)}
// Array.
#define ACA(x) {#x,x,sizeof(x)}
#define NACA(w,x) {#w,x,sizeof(x)}
#define VACA(x,version) {#x "_V" #version,x,sizeof(x)}
// String(pointer) with automatic memory allocation.
#define ACS(x) {#x,&x,0}
#define NACS(w,x) {#w,&x,0}
#define VACS(x,version) {#x "_V" #version,&x,0}
#define _DRIVERS_CONFIGH
#endif
+34 -11
View File
@@ -3,7 +3,10 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef WIN32
#include <dirent.h>
#endif
#include "../../types.h"
#include "configSys.h"
@@ -444,6 +447,23 @@ Config::getOption(const std::string &name,
return 0;
}
int
Config::getOption(const std::string &name,
bool *value) const
{
std::map<std::string, int>::const_iterator opt_i;
// confirm that the option exists
opt_i = _intOptMap.find(name);
if(opt_i == _intOptMap.end()) {
return -1;
}
// get the option
(*value) = opt_i->second ? true : false;
return 0;
}
int
Config::getOption(const std::string &name,
double *value) const
@@ -559,6 +579,7 @@ Config::parse(int argc,
return error;
}
#ifndef WIN32
// try to read cfg.d/*
std::string cfgd_dir_name = _dir + "/" + "cfg.d/";
DIR *d;
@@ -576,7 +597,7 @@ Config::parse(int argc,
// TODO 0 = good -1 = bad
std::string fname = cfgd_dir_name + dir->d_name;
printf("Loading auxilary configuration file at %s...\n", fname.c_str());
printf("Loading auxiliary configuration file at %s...\n", fname.c_str());
if (_loadFile(fname.c_str()) != 0)
{
printf("Failed to parse configuration at %s\n", fname.c_str());
@@ -585,7 +606,9 @@ Config::parse(int argc,
closedir(d);
}
#else
// FIXME TODO WIN32
#endif
// parse the arguments
return _parseArgs(argc, argv);
}
@@ -618,7 +641,7 @@ Config::_load()
int
Config::_loadFile(const char* fname)
{
signed int pos, eqPos;
size_t pos=0, eqPos=0;
std::fstream config;
std::map<std::string, int>::iterator int_i;
std::map<std::string, double>::iterator dbl_i;
@@ -633,7 +656,7 @@ Config::_loadFile(const char* fname)
configFile = fname;
}
std::string line, name, value;
char buf[1024];
char buf[4096];
// set the exception handling to catch i/o errors
config.exceptions(std::fstream::badbit);
@@ -648,7 +671,7 @@ Config::_loadFile(const char* fname)
while(!config.eof()) {
// read a line
config.getline(buf, 1024);
config.getline(buf, sizeof(buf));
line = buf;
// check line validity
@@ -681,7 +704,7 @@ Config::_loadFile(const char* fname)
// close the file
config.close();
} catch(std::fstream::failure e) {
} catch(std::fstream::failure &e) {
std::cerr << e.what() << std::endl;
return -1;
}
@@ -700,7 +723,7 @@ Config::save()
std::map<std::string, double>::iterator dbl_i;
std::map<std::string, std::string>::iterator str_i;
std::string configFile = _dir + "/" + cfgFile;
char buf[1024];
char buf[4096];
// set the exception handling to catch i/o errors
config.exceptions(std::ios::failbit | std::ios::badbit);
@@ -718,26 +741,26 @@ Config::save()
// write each configuration setting
for(int_i = _intOptMap.begin(); int_i != _intOptMap.end(); int_i++)
{
snprintf(buf, 1024, "%s = %d\n",
snprintf(buf, sizeof(buf), "%s = %d\n",
int_i->first.c_str(), int_i->second);
config.write(buf, strlen(buf));
}
for(dbl_i = _dblOptMap.begin(); dbl_i != _dblOptMap.end(); dbl_i++)
{
snprintf(buf, 1024, "%s = %f\n",
snprintf(buf, sizeof(buf), "%s = %f\n",
dbl_i->first.c_str(), dbl_i->second);
config.write(buf, strlen(buf));
}
for(str_i = _strOptMap.begin(); str_i != _strOptMap.end(); str_i++)
{
snprintf(buf, 1024, "%s = %s\n",
snprintf(buf, sizeof(buf), "%s = %s\n",
str_i->first.c_str(), str_i->second.c_str());
config.write(buf, strlen(buf));
}
// close the file
config.close();
} catch(std::fstream::failure e)
} catch(std::fstream::failure &e)
{
std::cerr << e.what() << std::endl;
return -1;
+1
View File
@@ -69,6 +69,7 @@ public:
int getOption(const std::string &, std::string *) const;
int getOption(const std::string &, const char **) const;
int getOption(const std::string &, int *) const;
int getOption(const std::string &, bool *) const;
int getOption(const std::string &, double *) const;
/**
+9 -6
View File
@@ -242,15 +242,16 @@ void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup, int bpp )
#ifndef NES_NTSC_NO_BLITTERS
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int emphasis, int in_width, int in_height, void* rgb_out, long out_pitch )
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, NES_NTSC_IN_T const* inputD, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / nes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
NES_NTSC_IN_T const* line_in = input;
NES_NTSC_BEGIN_ROW( ntsc, burst_phase, nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in ) );
NES_NTSC_IN_T const* line_inD = inputD;
NES_NTSC_BEGIN_ROW( ntsc, burst_phase, nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in, *line_inD ) );
nes_ntsc_out_t* restrict line_out = (nes_ntsc_out_t*) rgb_out;
int n;
++line_in;
@@ -259,20 +260,21 @@ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_
{
/* order of input and output pixels must not be altered */
NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0] ) );
NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0], line_inD [0] ) );
NES_NTSC_RGB_OUT( 0, line_out [0], OutputDepth );
NES_NTSC_RGB_OUT( 1, line_out [1], OutputDepth );
NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1] ) );
NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1], line_inD [1] ) );
NES_NTSC_RGB_OUT( 2, line_out [2], OutputDepth );
NES_NTSC_RGB_OUT( 3, line_out [3], OutputDepth );
NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2] ) );
NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2], line_inD [2] ) );
NES_NTSC_RGB_OUT( 4, line_out [4], OutputDepth );
NES_NTSC_RGB_OUT( 5, line_out [5], OutputDepth );
NES_NTSC_RGB_OUT( 6, line_out [6], OutputDepth );
line_in += 3;
line_inD += 3;
line_out += rescale_out;
}
@@ -293,6 +295,7 @@ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_
burst_phase = (burst_phase + 1) % nes_ntsc_burst_count;
input += in_row_width;
inputD += in_row_width;
}
}
+2 -2
View File
@@ -61,8 +61,8 @@ In_row_width is the number of pixels to get to the next input row. Emphasis is
the emphasis bits to bitwise-OR with all pixels in the input data. Out_pitch
is the number of *bytes* to get to the next output row. Output pixel format
is set by NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in,
long in_row_width, int burst_phase, int emphasis, int in_width,
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in, NES_NTSC_IN_T const* nes_inD,
long in_row_width, int burst_phase, int in_width,
int in_height, void* rgb_out, long out_pitch );
/* Number of output pixels written by blitter for given input width. Width might
+1 -1
View File
@@ -21,7 +21,7 @@ if you enable emphasis above. */
// CUSTOM: (XBuf uses bit 0x80, and has palettes above 0x3f for LUA)
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define NES_NTSC_ADJ_IN( in ) ((in & 0x3f) | emphasis)
#define NES_NTSC_ADJ_IN( in, inD ) ((in & 0x3F) | (inD << 6))
/* For each pixel, this is the basic operation:
output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */
+101
View File
@@ -0,0 +1,101 @@
// os_util.cpp
#include <stdio.h>
#include <stdlib.h>
#if defined(WIN32)
#include <windows.h>
#include <direct.h>
#include <io.h>
#else
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#endif
#include "common/os_utils.h"
//************************************************************
int fceu_mkdir( const char *path )
{
int retval;
#if defined(WIN32)
retval = _mkdir(path);
_chmod(path, 755);
#else
retval = mkdir(path, S_IRWXU);
if ( retval != 0 )
{
if ( errno == EEXIST )
{
//printf("Path Exists: '%s'\n", path);
retval = 0;
}
}
#endif
return retval;
}
//************************************************************
int fceu_mkpath( const char *path )
{
int i, retval = 0;
char p[512];
i=0;
while ( path[i] != 0 )
{
if ( path[i] == '/' )
{
if ( i > 0 )
{
p[i] = 0;
retval = fceu_mkdir( p );
if ( retval )
{
return retval;
}
}
}
p[i] = path[i]; i++;
}
p[i] = 0;
retval = fceu_mkdir( p );
return retval;
}
//************************************************************
bool fceu_file_exists( const char *filepath )
{
#ifdef WIN32
FILE *fp;
fp = ::fopen( filepath, "r" );
if ( fp != NULL )
{
::fclose(fp);
return true;
}
#else
struct stat sb;
if ( stat( filepath, &sb ) == 0 )
{
return true;
}
#endif
return false;
}
//************************************************************
int msleep( int ms )
{
int ret = 0;
#ifdef WIN32
Sleep(ms);
#else
ret = usleep(ms*1000);
#endif
return ret;
}
//************************************************************
+10
View File
@@ -0,0 +1,10 @@
// os_utils.h
//
int fceu_mkdir( const char *path );
int fceu_mkpath( const char *path );
bool fceu_file_exists( const char *filepath );
int msleep( int ms );
+78 -26
View File
@@ -65,9 +65,9 @@ static float *moire = NULL; // modulated signal
const float phasex = (float) 5/18*2;
const float phasey = (float) 1/ 6*2;
const float pi = 3.14f;
int palnotch = 90;
int palnotch = 100;
int palsaturation = 100;
int palsharpness = 50;
int palsharpness = 0;
int palcontrast = 100;
int palbrightness = 50;
bool palupdate = 1;
@@ -88,13 +88,13 @@ static int PAL_LUT(uint32 *buffer, int index, int x, int y)
static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl)
{
int a,x,z,y;
int a,x,z;
cshiftl[0]=cshiftl[1]=cshiftl[2]=-1;
for(a=0;a<3;a++)
{
for(x=0,y=-1,z=0;x<32;x++)
for(x=0,z=0;x<32;x++)
{
if(CBM[a]&(1<<x))
if(CBM[a]&(1u<<x))
{
if(cshiftl[a]==-1) cshiftl[a]=x;
z++;
@@ -107,8 +107,6 @@ static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl)
int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int specfilt, int specfilteropt)
{
//paldeemphswap = 0; // determine this in FCEUPPU_SetVideoSystem() instead
// -Video Modes Tag-
if(specfilt == 3) // NTSC 2x
{
@@ -208,6 +206,7 @@ int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int
palrgb = (uint32 *)FCEU_dmalloc((256+512)*PAL_PHASES*sizeof(uint32));
palrgb2 = (uint32 *)FCEU_dmalloc((256+512)*PAL_PHASES*sizeof(uint32));
moire = (float *)FCEU_dmalloc( PAL_PHASES*sizeof(float));
palupdate = 1;
}
silt = specfilt;
@@ -218,6 +217,11 @@ int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int
return(0);
//allocate adequate room for 32bpp palette
if ( palettetranslate )
{
free(palettetranslate);
palettetranslate=NULL;
}
palettetranslate=(uint32*)FCEU_dmalloc(256*4 + 512*4);
if(!palettetranslate)
@@ -234,18 +238,18 @@ void KillBlitToHigh(void)
{
if(palettetranslate)
{
free(palettetranslate);
FCEU_free(palettetranslate);
palettetranslate=NULL;
}
if(specbuf8bpp)
{
free(specbuf8bpp);
FCEU_free(specbuf8bpp);
specbuf8bpp = NULL;
}
if(specbuf32bpp)
{
free(specbuf32bpp);
FCEU_free(specbuf32bpp);
specbuf32bpp = NULL;
}
if(specbuf)
@@ -255,10 +259,11 @@ void KillBlitToHigh(void)
hq3x_Kill();
else
hq2x_Kill();
FCEU_free(specbuf);
specbuf=NULL;
}
if (nes_ntsc) {
free(nes_ntsc);
FCEU_free(nes_ntsc);
nes_ntsc = NULL;
}
if (ntscblit) {
@@ -461,7 +466,7 @@ void Blit8To8(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, in
/* Todo: Make sure 24bpp code works right with big-endian cpus */
//takes a pointer to XBuf and applies fully modern deemph palettizing
u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale)
template<int SCALE> static u32 _ModernDeemphColorMap(const u8* src, const u8* srcbuf)
{
u8 pixel = *src;
@@ -471,8 +476,8 @@ u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale)
int ofs = src-srcbuf;
int xofs = ofs&255;
int yofs = ofs>>8;
if(xscale!=1) xofs /= xscale; //untested optimization
if(yscale!=1) yofs /= yscale; //untested optimization
xofs /= SCALE;
yofs /= SCALE;
ofs = xofs+yofs*256;
//find out which deemph bitplane value we're on
@@ -480,11 +485,47 @@ u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale)
//if it was a deemph'd value, grab it from the deemph palette
if(deemph != 0)
color = palettetranslate[256+(pixel&0x3F)+deemph*64];
{
color = palettetranslate[256+(pixel&0x3F)+(deemph*64)];
}
return color;
}
u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale)
{
if(scale == 1) return _ModernDeemphColorMap<1>(src,srcbuf);
else if(scale == 2) return _ModernDeemphColorMap<2>(src,srcbuf);
else if(scale == 3) return _ModernDeemphColorMap<3>(src,srcbuf);
else if(scale == 4) return _ModernDeemphColorMap<4>(src,srcbuf);
else if(scale == 5) return _ModernDeemphColorMap<5>(src,srcbuf);
else if(scale == 6) return _ModernDeemphColorMap<6>(src,srcbuf);
else if(scale == 7) return _ModernDeemphColorMap<7>(src,srcbuf);
else if(scale == 8) return _ModernDeemphColorMap<8>(src,srcbuf);
else if(scale == 9) return _ModernDeemphColorMap<9>(src,srcbuf);
else { FCEU_abort("unhandled ModernDeemphColorMap scale"); return 0; }
}
typedef u32 (*ModernDeemphColorMapFuncPtr)( const u8*, const u8* );
static ModernDeemphColorMapFuncPtr getModernDeemphColorMapFunc(int scale)
{
ModernDeemphColorMapFuncPtr ptr;
if(scale == 1) ptr = &_ModernDeemphColorMap<1>;
else if(scale == 2) ptr = &_ModernDeemphColorMap<2>;
else if(scale == 3) ptr = &_ModernDeemphColorMap<3>;
else if(scale == 4) ptr = &_ModernDeemphColorMap<4>;
else if(scale == 5) ptr = &_ModernDeemphColorMap<5>;
else if(scale == 6) ptr = &_ModernDeemphColorMap<6>;
else if(scale == 7) ptr = &_ModernDeemphColorMap<7>;
else if(scale == 8) ptr = &_ModernDeemphColorMap<8>;
else if(scale == 9) ptr = &_ModernDeemphColorMap<9>;
else { FCEU_abort("unhandled ModernDeemphColorMap scale"); ptr = nullptr; }
return ptr;
}
void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale)
{
int x,y;
@@ -500,6 +541,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
int mult;
int base;
ModernDeemphColorMapFuncPtr ModernDeemphColorMapFunc = NULL;
// -Video Modes Tag-
if(silt == 2) mult = 2;
@@ -508,7 +550,12 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
Blit8To8(src, specbuf8bpp, xr, yr, 256*mult, xscale, yscale, 0, silt);
int mdcmxs = xscale*mult;
int mdcmys = yscale*mult;
if(mdcmxs != mdcmys)
abort();
ModernDeemphColorMapFunc = getModernDeemphColorMapFunc( mdcmxs );
xr *= mult;
yr *= mult;
xscale=yscale=1;
@@ -523,7 +570,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
*(uint32 *)dest=ModernDeemphColorMap(src,specbuf8bpp,mdcmxs, mdcmys);
*(uint32 *)dest=ModernDeemphColorMapFunc(src,specbuf8bpp);
dest+=4;
src++;
}
@@ -536,7 +583,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
uint32 tmp=ModernDeemphColorMap(src,specbuf8bpp,mdcmxs, mdcmys);
uint32 tmp=ModernDeemphColorMapFunc(src,specbuf8bpp);
*(uint8 *)dest=tmp;
*((uint8 *)dest+1)=tmp>>8;
*((uint8 *)dest+2)=tmp>>16;
@@ -576,7 +623,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr; x; x--)
{
*(uint32 *)dest = ModernDeemphColorMap(src,XBuf,1,1);
*(uint32 *)dest = _ModernDeemphColorMap<1>(src,XBuf);
dest += 4;
src++;
}
@@ -587,9 +634,11 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
uint32 *s = prescalebuf;
uint32 *d = (uint32 *)destbackup; // use 32-bit pointers ftw
int subpixel;
int subpixel,yend;
for (y=0; y<yr*yscale; y++)
yend = yr*yscale;
for (y=0; y<yend; y++)
{
int back = xr*(y%yscale>0); // bool as multiplier
for (x=0; x<xr; x++)
@@ -715,7 +764,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
newindex = (*src&63) | (deemph*64);
newindex += 256;
if(GameInfo->type==GIT_NSF)
if(GameInfo && GameInfo->type==GIT_NSF)
{
*d++ = palettetranslate[temp];
*d++ = palettetranslate[temp];
@@ -785,6 +834,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
lastindex = index;
}
}
src += (256-xr);
}
}
@@ -807,11 +857,13 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
switch(Bpp)
{
case 4:
if ( nes_ntsc && GameInfo->type!=GIT_NSF) {
if ( nes_ntsc && GameInfo && GameInfo->type!=GIT_NSF) {
int outxr = 301;
//if(xr == 282) outxr = 282; //hack for windows
burst_phase ^= 1;
nes_ntsc_blit( nes_ntsc, (unsigned char*)src, xr, burst_phase, (PPU[1] >> 5) << 6, xr, yr, ntscblit, (2*outxr) * Bpp );
u8* srcD = XDBuf + (src-XBuf); // get deemphasis buffer
nes_ntsc_blit( nes_ntsc, (unsigned char*)src, (unsigned char*)srcD, xr, burst_phase, xr, yr, ntscblit, (2*outxr) * Bpp );
const uint8 *in = ntscblit + (Bpp * xscale);
uint8 *out = dest;
@@ -912,7 +964,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
for(x=xr;x;x--)
{
//THE MAIN BLITTING CODEPATH (there may be others that are important)
*(uint32 *)dest = ModernDeemphColorMap(src,XBuf,1,1);
*(uint32 *)dest = _ModernDeemphColorMap<1>(src,XBuf);
dest+=4;
src++;
}
@@ -925,7 +977,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
uint32 tmp = ModernDeemphColorMap(src,XBuf,1,1);
uint32 tmp = _ModernDeemphColorMap<1>(src,XBuf);
*(uint8 *)dest=tmp;
*((uint8 *)dest+1)=tmp>>8;
*((uint8 *)dest+2)=tmp>>16;
@@ -941,7 +993,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
*(uint16 *)dest = ModernDeemphColorMap(src,XBuf,1,1);
*(uint16 *)dest = _ModernDeemphColorMap<1>(src,XBuf);
dest+=2;
src++;
}
+1 -1
View File
@@ -29,4 +29,4 @@ void Blit32to16(uint32 *src, uint16 *dest, int xr, int yr, int dpitch,
int shiftr[3], int shiftl[3]);
u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale);
u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale);
-28
View File
@@ -1,28 +0,0 @@
# Fix compliation error about 'XKeysymToString' by linking X11 explicitly
# Thanks Antonio Ospite!
Import('env')
config_string = 'pkg-config --cflags --libs x11'
env.ParseConfig(config_string)
Export('env')
source_list = Split(
"""
input.cpp
config.cpp
sdl.cpp
sdl-joystick.cpp
sdl-sound.cpp
sdl-throttle.cpp
sdl-video.cpp
unix-netplay.cpp
""")
Import('env')
if 'GL' in env['LIBS']:
source_list.append('sdl-opengl.cpp')
if env['GTK'] or env['GTK3']:
source_list.append('gui.cpp')
source_list = ['drivers/sdl/' + source for source in source_list]
Return('source_list')
-443
View File
@@ -1,443 +0,0 @@
#include "main.h"
#include "throttle.h"
#include "config.h"
#include "../common/cheat.h"
#include "input.h"
#include "dface.h"
#include "sdl.h"
#include "sdl-video.h"
#include "unix-netplay.h"
#ifdef WIN32
#include <windows.h>
#endif
#include <unistd.h>
#include <csignal>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
/**
* Read a custom pallete from a file and load it into the core.
*/
int
LoadCPalette(const std::string &file)
{
uint8 tmpp[192];
FILE *fp;
if(!(fp = FCEUD_UTF8fopen(file.c_str(), "rb"))) {
char errorMsg[256];
strcpy(errorMsg, "Error loading custom palette from file: ");
strcat(errorMsg, file.c_str());
FCEUD_PrintError(errorMsg);
return 0;
}
size_t result = fread(tmpp, 1, 192, fp);
if(result != 192) {
char errorMsg[256];
strcpy(errorMsg, "Error loading custom palette from file: ");
strcat(errorMsg, file.c_str());
FCEUD_PrintError(errorMsg);
return 0;
}
FCEUI_SetUserPalette(tmpp, result/3);
fclose(fp);
return 1;
}
/**
* Creates the subdirectories used for saving snapshots, movies, game
* saves, etc. Hopefully obsolete with new configuration system.
*/
static void
CreateDirs(const std::string &dir)
{
char *subs[8]={"fcs","snaps","gameinfo","sav","cheats","movies","cfg.d"};
std::string subdir;
int x;
#if defined(WIN32) || defined(NEED_MINGW_HACKS)
mkdir(dir.c_str());
chmod(dir.c_str(), 755);
for(x = 0; x < 6; x++) {
subdir = dir + PSS + subs[x];
mkdir(subdir.c_str());
}
#else
mkdir(dir.c_str(), S_IRWXU);
for(x = 0; x < 6; x++) {
subdir = dir + PSS + subs[x];
mkdir(subdir.c_str(), S_IRWXU);
}
#endif
}
/**
* Attempts to locate FCEU's application directory. This will
* hopefully become obsolete once the new configuration system is in
* place.
*/
static void
GetBaseDirectory(std::string &dir)
{
char *home = getenv("HOME");
if(home) {
dir = std::string(home) + "/.fceux";
} else {
#ifdef WIN32
home = new char[MAX_PATH + 1];
GetModuleFileName(NULL, home, MAX_PATH + 1);
char *lastBS = strrchr(home,'\\');
if(lastBS) {
*lastBS = 0;
}
dir = std::string(home);
delete[] home;
#else
dir = "";
#endif
}
}
// returns a config structure with default options
// also creates config base directory (ie: /home/user/.fceux as well as subdirs
Config *
InitConfig()
{
std::string dir, prefix;
Config *config;
GetBaseDirectory(dir);
FCEUI_SetBaseDirectory(dir.c_str());
CreateDirs(dir);
config = new Config(dir);
// sound options
config->addOption('s', "sound", "SDL.Sound", 1);
config->addOption("volume", "SDL.Sound.Volume", 150);
config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 256);
config->addOption("square1vol", "SDL.Sound.Square1Volume", 256);
config->addOption("square2vol", "SDL.Sound.Square2Volume", 256);
config->addOption("noisevol", "SDL.Sound.NoiseVolume", 256);
config->addOption("pcmvol", "SDL.Sound.PCMVolume", 256);
config->addOption("soundrate", "SDL.Sound.Rate", 44100);
config->addOption("soundq", "SDL.Sound.Quality", 1);
config->addOption("soundrecord", "SDL.Sound.RecordFile", "");
config->addOption("soundbufsize", "SDL.Sound.BufSize", 128);
config->addOption("lowpass", "SDL.Sound.LowPass", 0);
config->addOption('g', "gamegenie", "SDL.GameGenie", 0);
config->addOption("pal", "SDL.PAL", 0);
config->addOption("frameskip", "SDL.Frameskip", 0);
config->addOption("clipsides", "SDL.ClipSides", 0);
config->addOption("nospritelim", "SDL.DisableSpriteLimit", 1);
config->addOption("swapduty", "SDL.SwapDuty", 0);
// color control
config->addOption('p', "palette", "SDL.Palette", "");
config->addOption("tint", "SDL.Tint", 56);
config->addOption("hue", "SDL.Hue", 72);
config->addOption("ntsccolor", "SDL.NTSCpalette", 0);
// scanline settings
config->addOption("slstart", "SDL.ScanLineStart", 0);
config->addOption("slend", "SDL.ScanLineEnd", 239);
// video controls
config->addOption('f', "fullscreen", "SDL.Fullscreen", 0);
// set x/y res to 0 for automatic fullscreen resolution detection (no change)
config->addOption('x', "xres", "SDL.XResolution", 0);
config->addOption('y', "yres", "SDL.YResolution", 0);
config->addOption("SDL.LastXRes", 0);
config->addOption("SDL.LastYRes", 0);
config->addOption('b', "bpp", "SDL.BitsPerPixel", 32);
config->addOption("doublebuf", "SDL.DoubleBuffering", 0);
config->addOption("autoscale", "SDL.AutoScale", 1);
config->addOption("keepratio", "SDL.KeepRatio", 1);
config->addOption("xscale", "SDL.XScale", 1.0);
config->addOption("yscale", "SDL.YScale", 1.0);
config->addOption("xstretch", "SDL.XStretch", 0);
config->addOption("ystretch", "SDL.YStretch", 0);
config->addOption("noframe", "SDL.NoFrame", 0);
config->addOption("special", "SDL.SpecialFilter", 0);
config->addOption("showfps", "SDL.ShowFPS", 0);
config->addOption("togglemenu", "SDL.ToggleMenu", 0);
// OpenGL options
config->addOption("opengl", "SDL.OpenGL", 0);
config->addOption("openglip", "SDL.OpenGLip", 0);
config->addOption("SDL.SpecialFilter", 0);
config->addOption("SDL.SpecialFX", 0);
config->addOption("SDL.Vsync", 1);
// network play options - netplay is broken
config->addOption("server", "SDL.NetworkIsServer", 0);
config->addOption('n', "net", "SDL.NetworkIP", "");
config->addOption('u', "user", "SDL.NetworkUsername", "");
config->addOption('w', "pass", "SDL.NetworkPassword", "");
config->addOption('k', "netkey", "SDL.NetworkGameKey", "");
config->addOption("port", "SDL.NetworkPort", 4046);
config->addOption("players", "SDL.NetworkPlayers", 1);
// input configuration options
config->addOption("input1", "SDL.Input.0", "GamePad.0");
config->addOption("input2", "SDL.Input.1", "GamePad.1");
config->addOption("input3", "SDL.Input.2", "Gamepad.2");
config->addOption("input4", "SDL.Input.3", "Gamepad.3");
// allow for input configuration
config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg);
// display input
config->addOption("inputdisplay", "SDL.InputDisplay", 0);
// enable / disable opposite directionals (left + right or up + down simultaneously)
config->addOption("opposite-directionals", "SDL.Input.EnableOppositeDirectionals", 1);
// pause movie playback at frame x
config->addOption("pauseframe", "SDL.PauseFrame", 0);
config->addOption("recordhud", "SDL.RecordHUD", 1);
config->addOption("moviemsg", "SDL.MovieMsg", 1);
// overwrite the config file?
config->addOption("no-config", "SDL.NoConfig", 0);
config->addOption("autoresume", "SDL.AutoResume", 0);
// video playback
config->addOption("playmov", "SDL.Movie", "");
config->addOption("subtitles", "SDL.SubtitleDisplay", 1);
config->addOption("fourscore", "SDL.FourScore", 0);
config->addOption("nofscursor", "SDL.NoFullscreenCursor", 1);
#ifdef _S9XLUA_H
// load lua script
config->addOption("loadlua", "SDL.LuaScript", "");
#endif
#ifdef CREATE_AVI
config->addOption("videolog", "SDL.VideoLog", "");
config->addOption("mute", "SDL.MuteCapture", 0);
#endif
// auto load/save on gameload/close
config->addOption("loadstate", "SDL.AutoLoadState", INVALID_STATE);
config->addOption("savestate", "SDL.AutoSaveState", INVALID_STATE);
//TODO implement this
config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);
#ifdef _GTK
char* home_dir = getenv("HOME");
// prefixed with _ because they are internal (not cli options)
config->addOption("_lastopenfile", "SDL.LastOpenFile", home_dir);
config->addOption("_laststatefrom", "SDL.LastLoadStateFrom", home_dir);
config->addOption("_lastopennsf", "SDL.LastOpenNSF", home_dir);
config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", home_dir);
config->addOption("_lastloadlua", "SDL.LastLoadLua", "");
#endif
// fcm -> fm2 conversion
config->addOption("fcmconvert", "SDL.FCMConvert", "");
// fm2 -> srt conversion
config->addOption("ripsubs", "SDL.RipSubs", "");
// enable new PPU core
config->addOption("newppu", "SDL.NewPPU", 0);
// quit when a+b+select+start is pressed
config->addOption("4buttonexit", "SDL.ABStartSelectExit", 0);
// GamePad 0 - 3
for(unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) {
char buf[64];
snprintf(buf, 20, "SDL.Input.GamePad.%d.", i);
prefix = buf;
config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) {
config->addOption(prefix + GamePadNames[j], DefaultGamePad[i][j]);
}
}
// PowerPad 0 - 1
for(unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) {
char buf[64];
snprintf(buf, 20, "SDL.Input.PowerPad.%d.", i);
prefix = buf;
config->addOption(prefix + "DeviceType", DefaultPowerPadDevice[i]);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) {
config->addOption(prefix +PowerPadNames[j], DefaultPowerPad[i][j]);
}
}
// QuizKing
prefix = "SDL.Input.QuizKing.";
config->addOption(prefix + "DeviceType", DefaultQuizKingDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) {
config->addOption(prefix + QuizKingNames[j], DefaultQuizKing[j]);
}
// HyperShot
prefix = "SDL.Input.HyperShot.";
config->addOption(prefix + "DeviceType", DefaultHyperShotDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) {
config->addOption(prefix + HyperShotNames[j], DefaultHyperShot[j]);
}
// Mahjong
prefix = "SDL.Input.Mahjong.";
config->addOption(prefix + "DeviceType", DefaultMahjongDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) {
config->addOption(prefix + MahjongNames[j], DefaultMahjong[j]);
}
// TopRider
prefix = "SDL.Input.TopRider.";
config->addOption(prefix + "DeviceType", DefaultTopRiderDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) {
config->addOption(prefix + TopRiderNames[j], DefaultTopRider[j]);
}
// FTrainer
prefix = "SDL.Input.FTrainer.";
config->addOption(prefix + "DeviceType", DefaultFTrainerDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) {
config->addOption(prefix + FTrainerNames[j], DefaultFTrainer[j]);
}
// FamilyKeyBoard
prefix = "SDL.Input.FamilyKeyBoard.";
config->addOption(prefix + "DeviceType", DefaultFamilyKeyBoardDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) {
config->addOption(prefix + FamilyKeyBoardNames[j],
DefaultFamilyKeyBoard[j]);
}
// for FAMICOM microphone in pad 2 pad 1 didn't have it
// Takeshi no Chousenjou uses it for example.
prefix = "SDL.Input.FamicomPad2.";
config->addOption("rp2mic", prefix + "EnableMic", 0);
// TODO: use a better data structure to store the hotkeys or something
// improve this code overall in the future to make it
// easier to maintain
const int Hotkeys[HK_MAX] = {
SDLK_F1, // cheat menu
SDLK_F2, // bind state
SDLK_F3, // load lua
SDLK_F4, // toggleBG
SDLK_F5, // save state
SDLK_F6, // fds select
SDLK_F7, // load state
SDLK_F8, // fds eject
SDLK_F6, // VS insert coin
SDLK_F8, // VS toggle dipswitch
SDLK_PERIOD, // toggle frame display
SDLK_F10, // toggle subtitle
SDLK_F11, // reset
SDLK_F12, // screenshot
SDLK_PAUSE, // pause
SDLK_MINUS, // speed++
SDLK_EQUALS, // speed--
SDLK_BACKSLASH, //frame advnace
SDLK_TAB, // turbo
SDLK_COMMA, // toggle input display
SDLK_q, // toggle movie RW
SDLK_QUOTE, // toggle mute capture
0, // quit // edit 10/11/11 - don't map to escape, it causes ugly things to happen to sdl. can be manually appended to config
SDLK_DELETE, // frame advance lag skip
SDLK_SLASH, // lag counter display
SDLK_0, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5,
SDLK_6, SDLK_7, SDLK_8, SDLK_9,
SDLK_PAGEUP, // select state next
SDLK_PAGEDOWN}; // select state prev
prefix = "SDL.Hotkeys.";
for(int i=0; i < HK_MAX; i++)
config->addOption(prefix + HotkeyStrings[i], Hotkeys[i]);
// All mouse devices
config->addOption("SDL.OekaKids.0.DeviceType", "Mouse");
config->addOption("SDL.OekaKids.0.DeviceNum", 0);
config->addOption("SDL.Arkanoid.0.DeviceType", "Mouse");
config->addOption("SDL.Arkanoid.0.DeviceNum", 0);
config->addOption("SDL.Shadow.0.DeviceType", "Mouse");
config->addOption("SDL.Shadow.0.DeviceNum", 0);
config->addOption("SDL.Zapper.0.DeviceType", "Mouse");
config->addOption("SDL.Zapper.0.DeviceNum", 0);
return config;
}
void
UpdateEMUCore(Config *config)
{
int ntsccol, ntsctint, ntschue, flag, region, start, end;
std::string cpalette;
config->getOption("SDL.NTSCpalette", &ntsccol);
config->getOption("SDL.Tint", &ntsctint);
config->getOption("SDL.Hue", &ntschue);
FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
config->getOption("SDL.Palette", &cpalette);
if(cpalette.size()) {
LoadCPalette(cpalette);
}
config->getOption("SDL.PAL", &region);
FCEUI_SetRegion(region);
config->getOption("SDL.GameGenie", &flag);
FCEUI_SetGameGenie(flag ? 1 : 0);
config->getOption("SDL.Sound.LowPass", &flag);
FCEUI_SetLowPass(flag ? 1 : 0);
config->getOption("SDL.DisableSpriteLimit", &flag);
FCEUI_DisableSpriteLimitation(flag ? 1 : 0);
config->getOption("SDL.ScanLineStart", &start);
config->getOption("SDL.ScanLineEnd", &end);
#if DOING_SCANLINE_CHECKS
for(int i = 0; i < 2; x++) {
if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0;
if(erendlinev[x]<srendlinev[x] || erendlinev[x]>239) erendlinev[x]=239;
}
#endif
FCEUI_SetRenderedLines(start + 8, end - 8, start, end);
}

Some files were not shown because too many files have changed in this diff Show More