45 Commits

Author SHA1 Message Date
C.W. Betts 3fe5b1a41d Don't build fmemopen and open_memstream if targeting macOS versions 10.13 or above.
This is currently limited to 11.0 on Apple Silicon.
2021-01-16 15:27:31 -07:00
C.W. Betts da07e7e466 Xcode project maintenance. 2021-01-16 15:00:38 -07:00
C.W. Betts 0f0245743f Also use native open_memstream if available. 2021-01-15 14:52:30 -07:00
C.W. Betts 137232a50d Poke the plists: get the development language from Xcode build. 2020-10-01 01:51:38 -06:00
C.W. Betts d891dc75e4 Fix locations of the system plugin headers.
Minor Xcode maintenance.
2020-10-01 01:26:42 -06:00
C.W. Betts 89ac34677d Update language resources.
This quiets warnings in newer Xcode releases.

Also update framework locations.
2020-01-07 16:34:56 -07:00
clobber a25c7277cd Merge pull request #2 from MaddTheSane/updateFmem
Use Mac OS X's native fmemopen if present.
2018-03-26 12:38:28 -05:00
C.W. Betts 78cdb9a493 Use Mac OS X's native fmemopen if present. 2018-03-24 14:03:48 -06:00
clobber d47ffbc5ec Bump version for sparkle updater. Core is still r268 2017-12-17 21:51:48 -06:00
clobber 85a75b3ec7 Remove support for SMS, GG, SG-1000. This will be ColecoVision only. 2017-10-28 23:18:36 -05:00
clobber 97f3d66a9d Clean up input handling. 2017-10-20 21:21:58 -05:00
clobber dab27bf1d2 Update SG-1000 input for API change. 2017-10-20 20:53:53 -05:00
clobber 955658e547 Use -fileSystemRepresentation instead of -UTF8String for file names 2017-08-16 23:38:21 -05:00
clobber c614a91a1f Enable direct-rendering 2017-07-21 14:56:40 -05:00
clobber f6f74109be Clean up after commit a7ad4d21cf 2017-07-20 17:02:17 -05:00
clobber a7ad4d21cf Use proper API for video output 2017-07-20 16:35:35 -05:00
Rudy Richter 944d9954bb Use spaces 2017-07-20 08:50:18 -04:00
mrvacbob 4274fa8510 Remove internalPixelFormat 2017-07-20 01:12:25 -07:00
clobber f8c7919cdf Remove unneeded "deployment location" project file setting 2016-09-23 19:54:45 -05:00
clobber c3db984ef7 Update to CrabEmu r268 2016-09-06 01:15:04 -05:00
clobber f0ebea6655 Update to CrabEmu r265 2016-09-04 22:43:37 -05:00
clobber d1b1e673c0 Update to CrabEmu r261 2016-07-01 10:46:57 -05:00
clobber 83c3edc625 Limit rewind buffer to 60 seconds to reduce memory use 2016-06-30 01:31:12 -05:00
clobber 912191aa94 Try to work around weird SG-1000 state loading issue 2015-12-22 19:38:41 -07:00
clobber e7c8745b4e Clean up deprecated methods. 2015-12-12 17:03:49 -08:00
Alexander Strange 9ce27a4cd6 Update projects - fix debug builds, make deployment 10.11, enable objc-arc properly, build faster 2015-10-17 13:04:19 -07:00
clobber bea03d023c Turn off GCC_NO_COMMON_BLOCKS 2015-10-09 10:42:22 -05:00
Christoph Leimbrock 731eed88d8 Fix some warning and adjust project settings. 2015-10-06 22:04:32 +02:00
clobber e6ba3a7e80 Add Lander 2 (homebrew) to forced mappers list 2015-08-23 13:36:15 -05:00
Christoph Leimbrock 49d6e9721e Fix debug build. 2015-08-10 21:48:04 +02:00
clobber 66823f0f5a Update to CrabEmu r256 2015-07-31 20:10:56 -05:00
clobber a40d4f03d0 Fix PAR 2015-07-31 17:24:37 -05:00
clobber 114fcdd3fa Add region handling for SMS
Details: http://www.smspower.org/Development/ROMHeader
2015-07-31 17:24:10 -05:00
clobber c67d23d158 Update to CrabEmu r254 2015-07-31 14:17:39 -05:00
clobber d8ed15b6d0 Full enable/disable support for cheats 2015-07-29 03:50:54 -05:00
clobber 80f06c9e18 Update to CrabEmu r253 2015-07-29 02:43:57 -05:00
Kyle Lacy 674e6454bf Add plist keys to support rewinding 2015-07-26 11:41:38 -07:00
Kyle Lacy aa2bc8680f Add state serialization/deserialization 2015-07-26 11:41:23 -07:00
Kyle Lacy 062e83f7d7 Add fmemopen
From https://github.com/materialsvirtuallab/pyhull/tree/master/src/fmemopen
2015-07-26 09:40:57 -07:00
clobber a9e16763d2 Bump version in order for sparkle updater to work. Core is still 0.2.0 2014-05-30 15:34:57 -05:00
clobber 3fc41431fb Add OEGameCoreOptions for multi-system options and required bios/system files per core
Options:
OEGameCoreHasGlitches - Compatibility and graphics issues; core is WIP. Shows warning at core launch.
OEGameCoreRequiresFiles - Needs bios or system files. Use OERequiredFiles array of dictionaries.
OEGameCoreSaveStatesNotSupported - Save states are not supported. Disables save UI in HUD.
OEGameCoreSupportsCheatCode - Cheat codes are supported. Enables cheat UI in HUD.
2014-05-26 02:00:27 -05:00
clobber 718b2932a7 Add error: parameter to -loadFileAtPath: method. 2014-02-08 14:22:54 -08:00
Alexander Strange f77d286df6 Compilation speed: enable modules 2014-01-19 22:14:43 -08:00
clobber c45912f8b4 Upstream changes and fix for games that can change resolution to 256x224 2014-01-10 02:40:15 -06:00
clobber cd18b5e165 Update spakle update URL and remove DSA key 2013-12-21 21:29:54 -06:00
80 changed files with 9733 additions and 8365 deletions
+9 -3
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2009, 2012 Lawrence Sebald
Copyright (C) 2009, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -20,7 +20,7 @@
#ifndef CRABEMU_H
#define CRABEMU_H
#define VERSION "0.2.0"
#define VERSION "0.2.1"
#ifdef __cplusplus
#define CLINKAGE extern "C" {
@@ -35,6 +35,7 @@
#ifdef _arch_dreamcast
#include <arch/types.h>
#include <stdint.h>
#else
#include <stdint.h>
typedef uint8_t uint8;
@@ -127,6 +128,11 @@ typedef uint16 pixel_t;
CLINKAGE
extern void gui_set_aspect(float x, float y);
extern void gui_set_title(const char *str);
/* Forward declaration... */
struct crabemu_console;
extern void gui_set_console(struct crabemu_console *c);
ENDCLINK
#endif /* !CRABEMU_H */
+116 -56
View File
@@ -35,10 +35,15 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
1B46D09D14293CAD0025EF88 /* libz.1.2.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B46D09C14293CAD0025EF88 /* libz.1.2.5.dylib */; };
1B46D09D14293CAD0025EF88 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B46D09C14293CAD0025EF88 /* libz.tbd */; };
27E3D4E41B6543BC00D8D8B5 /* fmemopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 27E3D4E21B6543BC00D8D8B5 /* fmemopen.c */; };
27E3D4E71B6543D500D8D8B5 /* open_memstream.c in Sources */ = {isa = PBXBuildFile; fileRef = 27E3D4E51B6543D500D8D8B5 /* open_memstream.c */; };
3720DB4D0F19510D00744A9A /* CrabEmu.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3720DB4C0F19510D00744A9A /* CrabEmu.icns */; };
82CAFADA0FEDA5CA00CCDC7E /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 82CAFAD90FEDA5CA00CCDC7E /* dsa_pub.pem */; };
82CAFDB00FEDD88100CCDC7E /* config.yaml in CopyFiles */ = {isa = PBXBuildFile; fileRef = 82CAFADD0FEDA5EA00CCDC7E /* config.yaml */; };
834A0CAC1B79371A0073803A /* nesmapper2.c in Sources */ = {isa = PBXBuildFile; fileRef = 878700DF1B675EB4006841C9 /* nesmapper2.c */; };
834A0CAD1B79371A0073803A /* nesmapper3.c in Sources */ = {isa = PBXBuildFile; fileRef = 878700E01B675EB4006841C9 /* nesmapper3.c */; };
834A0CAE1B79371A0073803A /* nesmapper7.c in Sources */ = {isa = PBXBuildFile; fileRef = 878700E11B675EB4006841C9 /* nesmapper7.c */; };
834A0CAF1B79371A0073803A /* nesmapper9.c in Sources */ = {isa = PBXBuildFile; fileRef = 878700E21B675EB4006841C9 /* nesmapper9.c */; };
834A0CB01B79371A0073803A /* nesmapper66.c in Sources */ = {isa = PBXBuildFile; fileRef = 878700E31B675EB4006841C9 /* nesmapper66.c */; };
8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; settings = {ATTRIBUTES = (Required, ); }; };
9443D4411715F42200E452AC /* CrabZ80.c in Sources */ = {isa = PBXBuildFile; fileRef = 9443D3FC1715F31000E452AC /* CrabZ80.c */; };
@@ -80,7 +85,6 @@
9443D4671715F74100E452AC /* mmc5_snd.c in Sources */ = {isa = PBXBuildFile; fileRef = 9443D42B1715F33C00E452AC /* mmc5_snd.c */; };
9443D4681715F74F00E452AC /* nes_apu.c in Sources */ = {isa = PBXBuildFile; fileRef = 9443D42D1715F33C00E452AC /* nes_apu.c */; };
9443D4691715F75700E452AC /* vrcvisnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 9443D42F1715F33C00E452AC /* vrcvisnd.c */; };
9443D46D1715FFE600E452AC /* list.c in Sources */ = {isa = PBXBuildFile; fileRef = 9443D46B1715FFE600E452AC /* list.c */; };
94BE9E7A171695AE00AB08E6 /* OEColecoVisionSystemResponderClient.h in Resources */ = {isa = PBXBuildFile; fileRef = 94BE9E79171695AE00AB08E6 /* OEColecoVisionSystemResponderClient.h */; };
C66DFC1A0F51D82F0080AA28 /* SMSGameCore.m in Sources */ = {isa = PBXBuildFile; fileRef = C66DFC180F51D82F0080AA28 /* SMSGameCore.m */; };
C6D120E91711302600E868A8 /* OpenEmuBase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6D120E71711302600E868A8 /* OpenEmuBase.framework */; };
@@ -110,22 +114,38 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
82CAFDB00FEDD88100CCDC7E /* config.yaml in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
1B46D09C14293CAD0025EF88 /* libz.1.2.5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.2.5.dylib; path = usr/lib/libz.1.2.5.dylib; sourceTree = SDKROOT; };
089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
089C167EFE841241C02AAC07 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
1B46D09C14293CAD0025EF88 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
27E3D4E21B6543BC00D8D8B5 /* fmemopen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmemopen.c; sourceTree = "<group>"; };
27E3D4E31B6543BC00D8D8B5 /* fmemopen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmemopen.h; sourceTree = "<group>"; };
27E3D4E51B6543D500D8D8B5 /* open_memstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = open_memstream.c; sourceTree = "<group>"; };
27E3D4E61B6543D500D8D8B5 /* open_memstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = open_memstream.h; sourceTree = "<group>"; };
3720DB4C0F19510D00744A9A /* CrabEmu.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = CrabEmu.icns; sourceTree = "<group>"; };
8291C4E21489595000A72540 /* OEGGSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGGSystemResponderClient.h; path = ../OpenEmu/GameGear/OEGGSystemResponderClient.h; sourceTree = "<group>"; };
82CAFAD90FEDA5CA00CCDC7E /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsa_pub.pem; sourceTree = "<group>"; };
82CAFADD0FEDA5EA00CCDC7E /* config.yaml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = config.yaml; sourceTree = "<group>"; };
8291C4E21489595000A72540 /* OEGGSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGGSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/GameGear/OEGGSystemResponderClient.h; sourceTree = "<group>"; };
878700D11B674AB3006841C9 /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = queue.h; path = utils/queue.h; sourceTree = "<group>"; };
878700DA1B675E9C006841C9 /* chip8.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = chip8.c; path = chip8/chip8.c; sourceTree = "<group>"; };
878700DB1B675E9C006841C9 /* chip8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = chip8.h; path = chip8/chip8.h; sourceTree = "<group>"; };
878700DC1B675E9C006841C9 /* chip8cpu.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = chip8cpu.c; path = chip8/chip8cpu.c; sourceTree = "<group>"; };
878700DD1B675E9C006841C9 /* chip8cpu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = chip8cpu.h; path = chip8/chip8cpu.h; sourceTree = "<group>"; };
878700DE1B675E9C006841C9 /* chip8cpuops.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = chip8cpuops.h; path = chip8/chip8cpuops.h; sourceTree = "<group>"; };
878700DF1B675EB4006841C9 /* nesmapper2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nesmapper2.c; sourceTree = "<group>"; };
878700E01B675EB4006841C9 /* nesmapper3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nesmapper3.c; sourceTree = "<group>"; };
878700E11B675EB4006841C9 /* nesmapper7.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nesmapper7.c; sourceTree = "<group>"; };
878700E21B675EB4006841C9 /* nesmapper9.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nesmapper9.c; sourceTree = "<group>"; };
878700E31B675EB4006841C9 /* nesmapper66.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nesmapper66.c; sourceTree = "<group>"; };
878700E41B675EF0006841C9 /* console.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = console.h; sourceTree = "<group>"; };
87ACB6E41D26C1F600138B7E /* CrabZ80_gbmacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrabZ80_gbmacros.h; sourceTree = "<group>"; };
87ACB6E51D26C1F600138B7E /* CrabZ80gbops.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrabZ80gbops.h; sourceTree = "<group>"; };
87ACB6E61D26C1F700138B7E /* CrabZ80gbopsCB.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrabZ80gbopsCB.h; sourceTree = "<group>"; };
8D5B49B6048680CD000E48DA /* CrabEmu.oecoreplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CrabEmu.oecoreplugin; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9443D39B1715F2EB00E452AC /* colecomem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = colecomem.c; sourceTree = "<group>"; };
@@ -177,7 +197,6 @@
9443D3CC1715F2EB00E452AC /* smsvdp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smsvdp.c; sourceTree = "<group>"; };
9443D3CD1715F2EB00E452AC /* smsvdp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = smsvdp.h; sourceTree = "<group>"; };
9443D3CE1715F2EB00E452AC /* smsz80-cz80.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "smsz80-cz80.c"; sourceTree = "<group>"; };
9443D3CF1715F2EB00E452AC /* smsz80-debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "smsz80-debug.c"; sourceTree = "<group>"; };
9443D3D01715F2EB00E452AC /* smsz80.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smsz80.c; sourceTree = "<group>"; };
9443D3D11715F2EB00E452AC /* smsz80.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = smsz80.h; sourceTree = "<group>"; };
9443D3D21715F2EB00E452AC /* terebi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = terebi.c; sourceTree = "<group>"; };
@@ -213,8 +232,6 @@
9443D4101715F31000E452AC /* cz80exec.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = cz80exec.inc; sourceTree = "<group>"; };
9443D4111715F31000E452AC /* cz80jmp.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = cz80jmp.inc; sourceTree = "<group>"; };
9443D4121715F31000E452AC /* readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = readme.txt; sourceTree = "<group>"; };
9443D4141715F31000E452AC /* z80.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = z80.c; sourceTree = "<group>"; };
9443D4151715F31000E452AC /* z80.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = z80.h; sourceTree = "<group>"; };
9443D4261715F33C00E452AC /* sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sound.c; sourceTree = "<group>"; };
9443D4281715F33C00E452AC /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
9443D4291715F33C00E452AC /* fds_snd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fds_snd.c; sourceTree = "<group>"; };
@@ -234,16 +251,14 @@
9443D4371715F33C00E452AC /* ym2413.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ym2413.h; sourceTree = "<group>"; };
9443D45B1715F67D00E452AC /* rom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rom.c; sourceTree = "<group>"; };
9443D45C1715F67D00E452AC /* rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rom.h; sourceTree = "<group>"; };
9443D46B1715FFE600E452AC /* list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = list.c; path = utils/list.c; sourceTree = "<group>"; };
9443D46C1715FFE600E452AC /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = list.h; path = utils/list.h; sourceTree = "<group>"; };
946C18AF171491B300C64BF9 /* OESG1000SystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESG1000SystemResponderClient.h; path = "../OpenEmu/SG-1000/OESG1000SystemResponderClient.h"; sourceTree = "<group>"; };
94BE9E79171695AE00AB08E6 /* OEColecoVisionSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEColecoVisionSystemResponderClient.h; path = ../OpenEmu/ColecoVision/OEColecoVisionSystemResponderClient.h; sourceTree = "<group>"; };
946C18AF171491B300C64BF9 /* OESG1000SystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESG1000SystemResponderClient.h; path = "../OpenEmu/SystemPlugins/SG-1000/OESG1000SystemResponderClient.h"; sourceTree = "<group>"; };
94BE9E79171695AE00AB08E6 /* OEColecoVisionSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEColecoVisionSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/ColecoVision/OEColecoVisionSystemResponderClient.h; sourceTree = "<group>"; };
B5DA7D8C0F5B28940008F047 /* CrabEmu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrabEmu.h; sourceTree = "<group>"; };
C66DFC180F51D82F0080AA28 /* SMSGameCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMSGameCore.m; sourceTree = "<group>"; };
C66DFC190F51D82F0080AA28 /* SMSGameCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMSGameCore.h; sourceTree = "<group>"; };
C6B3E67C1365255700D34947 /* OESMSSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESMSSystemResponderClient.h; path = ../OpenEmu/SegaMasterSystem/OESMSSystemResponderClient.h; sourceTree = "<group>"; };
C6B3E67C1365255700D34947 /* OESMSSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OESMSSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/SegaMasterSystem/OESMSSystemResponderClient.h; sourceTree = "<group>"; };
C6D120E71711302600E868A8 /* OpenEmuBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OpenEmuBase.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -253,7 +268,7 @@
files = (
C6D120E91711302600E868A8 /* OpenEmuBase.framework in Frameworks */,
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */,
1B46D09D14293CAD0025EF88 /* libz.1.2.5.dylib in Frameworks */,
1B46D09D14293CAD0025EF88 /* libz.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -266,26 +281,26 @@
08FB77AFFE84173DC02AAC07 /* Classes */,
32C88E010371C26100C91783 /* Other Sources */,
089C167CFE841241C02AAC07 /* Resources */,
089C1671FE841209C02AAC07 /* Frameworks and Libraries */,
089C1671FE841209C02AAC07 /* Frameworks */,
19C28FB8FE9D52D311CA2CBB /* Products */,
);
name = CrabEmu;
sourceTree = "<group>";
usesTabs = 0;
};
089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = {
089C1671FE841209C02AAC07 /* Frameworks */ = {
isa = PBXGroup;
children = (
C6D120E71711302600E868A8 /* OpenEmuBase.framework */,
1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */,
1058C7AEFEA557BF11CA2CBB /* Other Frameworks */,
);
name = "Frameworks and Libraries";
name = Frameworks;
sourceTree = "<group>";
};
089C167CFE841241C02AAC07 /* Resources */ = {
isa = PBXGroup;
children = (
82CAFAD90FEDA5CA00CCDC7E /* dsa_pub.pem */,
8D5B49B7048680CD000E48DA /* Info.plist */,
089C167DFE841241C02AAC07 /* InfoPlist.strings */,
3720DB4C0F19510D00744A9A /* CrabEmu.icns */,
@@ -309,7 +324,7 @@
1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
1B46D09C14293CAD0025EF88 /* libz.1.2.5.dylib */,
1B46D09C14293CAD0025EF88 /* libz.tbd */,
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
);
name = "Linked Frameworks";
@@ -333,10 +348,22 @@
name = Products;
sourceTree = "<group>";
};
27E3D4E11B65439900D8D8B5 /* fmemopen */ = {
isa = PBXGroup;
children = (
27E3D4E21B6543BC00D8D8B5 /* fmemopen.c */,
27E3D4E31B6543BC00D8D8B5 /* fmemopen.h */,
27E3D4E51B6543D500D8D8B5 /* open_memstream.c */,
27E3D4E61B6543D500D8D8B5 /* open_memstream.h */,
);
path = fmemopen;
sourceTree = "<group>";
};
32C88E010371C26100C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
82CAFADD0FEDA5EA00CCDC7E /* config.yaml */,
27E3D4E11B65439900D8D8B5 /* fmemopen */,
878700E41B675EF0006841C9 /* console.h */,
B5DA7D8C0F5B28940008F047 /* CrabEmu.h */,
9443D45B1715F67D00E452AC /* rom.c */,
9443D45C1715F67D00E452AC /* rom.h */,
@@ -348,6 +375,18 @@
name = "Other Sources";
sourceTree = "<group>";
};
878700D21B675E74006841C9 /* chip8 */ = {
isa = PBXGroup;
children = (
878700DA1B675E9C006841C9 /* chip8.c */,
878700DB1B675E9C006841C9 /* chip8.h */,
878700DC1B675E9C006841C9 /* chip8cpu.c */,
878700DD1B675E9C006841C9 /* chip8cpu.h */,
878700DE1B675E9C006841C9 /* chip8cpuops.h */,
);
name = chip8;
sourceTree = "<group>";
};
9443D39A1715F2EB00E452AC /* colecovision */ = {
isa = PBXGroup;
children = (
@@ -379,6 +418,11 @@
children = (
9443D3A11715F2EB00E452AC /* nesmapper0.c */,
9443D3A21715F2EB00E452AC /* nesmapper1.c */,
878700DF1B675EB4006841C9 /* nesmapper2.c */,
878700E01B675EB4006841C9 /* nesmapper3.c */,
878700E11B675EB4006841C9 /* nesmapper7.c */,
878700E21B675EB4006841C9 /* nesmapper9.c */,
878700E31B675EB4006841C9 /* nesmapper66.c */,
);
path = mappers;
sourceTree = "<group>";
@@ -422,7 +466,6 @@
9443D3CC1715F2EB00E452AC /* smsvdp.c */,
9443D3CD1715F2EB00E452AC /* smsvdp.h */,
9443D3CE1715F2EB00E452AC /* smsz80-cz80.c */,
9443D3CF1715F2EB00E452AC /* smsz80-debug.c */,
9443D3D01715F2EB00E452AC /* smsz80.c */,
9443D3D11715F2EB00E452AC /* smsz80.h */,
9443D3D21715F2EB00E452AC /* terebi.c */,
@@ -456,6 +499,9 @@
9443D3FF1715F31000E452AC /* CrabZ80_tables.h */,
9443D4001715F31000E452AC /* CrabZ80d.c */,
9443D4011715F31000E452AC /* CrabZ80d.h */,
87ACB6E41D26C1F600138B7E /* CrabZ80_gbmacros.h */,
87ACB6E51D26C1F600138B7E /* CrabZ80gbops.h */,
87ACB6E61D26C1F700138B7E /* CrabZ80gbopsCB.h */,
9443D4021715F31000E452AC /* CrabZ80ops.h */,
9443D4031715F31000E452AC /* CrabZ80opsCB.h */,
9443D4041715F31000E452AC /* CrabZ80opsDD-FD.h */,
@@ -483,15 +529,6 @@
path = cz80;
sourceTree = "<group>";
};
9443D4131715F31000E452AC /* mamez80 */ = {
isa = PBXGroup;
children = (
9443D4141715F31000E452AC /* z80.c */,
9443D4151715F31000E452AC /* z80.h */,
);
path = mamez80;
sourceTree = "<group>";
};
9443D4251715F33C00E452AC /* coreaudio */ = {
isa = PBXGroup;
children = (
@@ -519,8 +556,7 @@
9443D46A1715FFA200E452AC /* utils */ = {
isa = PBXGroup;
children = (
9443D46B1715FFE600E452AC /* list.c */,
9443D46C1715FFE600E452AC /* list.h */,
878700D11B674AB3006841C9 /* queue.h */,
);
name = utils;
sourceTree = "<group>";
@@ -528,6 +564,7 @@
B50C176B0E936FD500A8FA7E /* consoles */ = {
isa = PBXGroup;
children = (
878700D21B675E74006841C9 /* chip8 */,
9443D39A1715F2EB00E452AC /* colecovision */,
9443D39F1715F2EB00E452AC /* nes */,
9443D3AA1715F2EB00E452AC /* sms */,
@@ -541,7 +578,6 @@
9443D3F31715F31000E452AC /* Crab6502 */,
9443D3FB1715F31000E452AC /* CrabZ80 */,
9443D4071715F31000E452AC /* cz80 */,
9443D4131715F31000E452AC /* mamez80 */,
);
path = cpu;
sourceTree = "<group>";
@@ -589,12 +625,11 @@
089C1669FE841209C02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 0460;
LastUpgradeCheck = 0700;
};
buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "CrabEmu" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
en,
@@ -617,7 +652,6 @@
files = (
8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */,
3720DB4D0F19510D00744A9A /* CrabEmu.icns in Resources */,
82CAFADA0FEDA5CA00CCDC7E /* dsa_pub.pem in Resources */,
94BE9E7A171695AE00AB08E6 /* OEColecoVisionSystemResponderClient.h in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -659,14 +693,21 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
834A0CAC1B79371A0073803A /* nesmapper2.c in Sources */,
834A0CAD1B79371A0073803A /* nesmapper3.c in Sources */,
834A0CAE1B79371A0073803A /* nesmapper7.c in Sources */,
834A0CAF1B79371A0073803A /* nesmapper9.c in Sources */,
834A0CB01B79371A0073803A /* nesmapper66.c in Sources */,
C66DFC1A0F51D82F0080AA28 /* SMSGameCore.m in Sources */,
9443D4411715F42200E452AC /* CrabZ80.c in Sources */,
9443D4421715F42500E452AC /* CrabZ80d.c in Sources */,
9443D4431715F44E00E452AC /* 93c46.c in Sources */,
9443D4441715F45C00E452AC /* mappers.c in Sources */,
9443D4451715F46100E452AC /* sms.c in Sources */,
27E3D4E71B6543D500D8D8B5 /* open_memstream.c in Sources */,
9443D4461715F46900E452AC /* smsmem.c in Sources */,
9443D4471715F47A00E452AC /* terebi.c in Sources */,
27E3D4E41B6543BC00D8D8B5 /* fmemopen.c in Sources */,
9443D4481715F48300E452AC /* tms9918a.c in Sources */,
9443D4491715F4AC00E452AC /* sn76489.c in Sources */,
9443D44A1715F4F100E452AC /* smsmem-gg.c in Sources */,
@@ -699,7 +740,6 @@
9443D4681715F74F00E452AC /* nes_apu.c in Sources */,
9443D4691715F75700E452AC /* vrcvisnd.c in Sources */,
9443D4601715F6EB00E452AC /* nesapu-nosefart.c in Sources */,
9443D46D1715FFE600E452AC /* list.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -722,7 +762,7 @@
089C167DFE841241C02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
089C167EFE841241C02AAC07 /* English */,
089C167EFE841241C02AAC07 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
@@ -744,6 +784,7 @@
"-DNO_BZ2",
"-DCRABEMU_32BIT_COLOR",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
PRODUCT_NAME = CrabEmu;
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = oecoreplugin;
@@ -764,6 +805,7 @@
"-DNO_BZ2",
"-DCRABEMU_32BIT_COLOR",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
PRODUCT_NAME = CrabEmu;
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = oecoreplugin;
@@ -774,24 +816,35 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEPLOYMENT_LOCATION = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "";
INSTALL_PATH = "$(HOME)/Library/Bundles";
MACOSX_DEPLOYMENT_TARGET = 10.7;
MACOSX_DEPLOYMENT_TARGET = 10.11;
"MACOSX_DEPLOYMENT_TARGET[arch=arm64]" = 11.0;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = (
"-DCRABZ80_NO_READMAP_FALLBACK",
"-DIN_CRABEMU",
@@ -804,25 +857,34 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEPLOYMENT_LOCATION = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "";
INSTALL_PATH = "$(HOME)/Library/Bundles";
MACOSX_DEPLOYMENT_TARGET = 10.7;
MACOSX_DEPLOYMENT_TARGET = 10.11;
"MACOSX_DEPLOYMENT_TARGET[arch=arm64]" = 11.0;
OTHER_CFLAGS = (
"-DCRABZ80_NO_READMAP_FALLBACK",
"-DIN_CRABEMU",
@@ -834,7 +896,6 @@
82CAFB620FEDA62500CCDC7E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
COMBINE_HIDPI_IMAGES = YES;
INSTALL_PATH = "\"$(USER_LIBRARY_DIR)/Application Support/OpenEmu/Cores\"";
PRODUCT_NAME = Distribution;
@@ -845,7 +906,6 @@
82CAFB630FEDA62500CCDC7E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
COMBINE_HIDPI_IMAGES = YES;
INSTALL_PATH = "\"$(USER_LIBRARY_DIR)/Application Support/OpenEmu/Cores\"";
PRODUCT_NAME = Distribution;
Binary file not shown.
+66 -13
View File
@@ -3,13 +3,13 @@
<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>
<string>CrabEmu</string>
<key>CFBundleIdentifier</key>
<string>org.openemu.${PRODUCT_NAME:identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
@@ -17,31 +17,84 @@
<key>CFBundleSignature</key>
<string>OpEm</string>
<key>CFBundleVersion</key>
<string>0.2.0</string>
<string>0.2.1.269</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
<string>SMSGameCore</string>
<key>OEGameCoreOptions</key>
<dict>
<key>openemu.system.colecovision</key>
<dict>
<key>OEGameCoreRequiresFiles</key>
<true/>
<key>OEGameCoreRewindBufferSeconds</key>
<integer>60</integer>
<key>OEGameCoreRewindInterval</key>
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
<key>OERequiredFiles</key>
<array>
<dict>
<key>Description</key>
<string>ColecoVision BIOS</string>
<key>MD5</key>
<string>2c66f5911e5b42b8ebe113403548eee7</string>
<key>Name</key>
<string>coleco.rom</string>
<key>Size</key>
<integer>8192</integer>
</dict>
</array>
</dict>
<key>openemu.system.gg</key>
<dict>
<key>OEGameCoreRewindBufferSeconds</key>
<integer>60</integer>
<key>OEGameCoreRewindInterval</key>
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
</dict>
<key>openemu.system.sg1000</key>
<dict>
<key>OEGameCoreRewindBufferSeconds</key>
<integer>60</integer>
<key>OEGameCoreRewindInterval</key>
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
</dict>
<key>openemu.system.sms</key>
<dict>
<key>OEGameCoreRewindBufferSeconds</key>
<integer>60</integer>
<key>OEGameCoreRewindInterval</key>
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
</dict>
</dict>
<key>OEGameCorePlayerCount</key>
<string>2</string>
<key>OEGameCoreRequiresFiles</key>
<true/>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEProjectURL</key>
<string>http://crabemu.sourceforge.net/</string>
<key>OESystemIdentifiers</key>
<array>
<string>openemu.system.sms</string>
<string>openemu.system.gg</string>
<string>openemu.system.sg1000</string>
<string>openemu.system.colecovision</string>
</array>
<key>SUEnableAutomaticChecks</key>
<string>1</string>
<key>SUFeedURL</key>
<string>http://openemu.org/updater/crabemu_appcast.xml</string>
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
<string>https://raw.github.com/OpenEmu/OpenEmu-Update/master/crabemu_appcast.xml</string>
</dict>
</plist>
-8
View File
@@ -49,12 +49,4 @@ typedef enum SMSButtons {
OE_EXPORTED_CLASS
@interface SMSGameCore : OEGameCore
{
unsigned char *tempBuffer;
NSLock *bufLock;
int oldrun;
int position;
BOOL paused;
}
@end
+237 -232
View File
@@ -25,7 +25,6 @@
*/
#import "SMSGameCore.h"
#import <IOKit/hid/IOHIDLib.h>
#import <OpenEmuBase/OERingBuffer.h>
#import <OpenGL/gl.h>
#import "OESMSSystemResponderClient.h"
@@ -33,8 +32,6 @@
#import "OESG1000SystemResponderClient.h"
#import "OEColecoVisionSystemResponderClient.h"
#define _UINT32
#include "sms.h"
#include "smsmem.h"
#include "sound.h"
@@ -44,29 +41,29 @@
#include "colecovision.h"
#include "colecomem.h"
#include "cheats.h"
#include "console.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13
#include "fmemopen/fmemopen.h"
#include "fmemopen/open_memstream.h"
#endif
#define SAMPLERATE 44100
@interface SMSGameCore () <OESMSSystemResponderClient, OEGGSystemResponderClient, OESG1000SystemResponderClient, OEColecoVisionSystemResponderClient>
{
NSString *romName;
NSLock *bufLock;
BOOL paused;
NSURL *romFile;
NSMutableDictionary *cheatList;
}
- (int)crabButtonForButton:(OESMSButton)button player:(NSUInteger)player;
- (int)crabButtonForSG1000Button:(OESG1000Button)button;
- (int)crabButtonForColecoVisionButton:(OEColecoVisionButton)button player:(NSUInteger)player;
@end
@implementation SMSGameCore
extern int sms_initialized;
extern int sms_console;
extern int coleco_initialized;
// Global variables because the callbacks need to access them...
static OERingBuffer *ringBuffer;
/*
OpenEmu Core internal functions
*/
console_t *cur_console;
- (id)init
{
@@ -74,9 +71,7 @@ static OERingBuffer *ringBuffer;
if(self != nil)
{
bufLock = [[NSLock alloc] init];
tempBuffer = malloc(256 * 256 * 4);
position = 0;
cheatList = [[NSMutableDictionary alloc] init];
ringBuffer = [self ringBufferAtIndex:0];
}
return self;
@@ -85,120 +80,141 @@ static OERingBuffer *ringBuffer;
- (void)dealloc
{
DLog(@"releasing/deallocating CrabEmu memory");
free(tempBuffer);
sms_initialized = 0;
coleco_initialized = 0;
cur_console->shutdown();
}
- (void)executeFrame
{
//DLog(@"Executing");
//Get a reference to the emulator
[bufLock lock];
if(sms_console == CONSOLE_COLECOVISION)
oldrun = coleco_frame(oldrun, 0);
else
oldrun = sms_frame(oldrun, 0);
[bufLock unlock];
}
# pragma mark - Execution
- (BOOL)loadFileAtPath:(NSString *)path
- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error
{
romName = [path copy];
int console = rom_detect_console([path UTF8String]);
romFile = [NSURL fileURLWithPath:path];
int console = rom_detect_console(path.fileSystemRepresentation);
DLog(@"Loaded File");
//TODO: add choice NTSC/PAL
if(console == CONSOLE_COLECOVISION)
{
NSString *biosPath = [NSString pathWithComponents:@[
[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject],
@"OpenEmu", @"BIOS", @"coleco.rom"]];
NSString *biosPath = [[self biosDirectoryPath] stringByAppendingPathComponent:@"coleco.rom"];
coleco_init(VIDEO_NTSC);
coleco_mem_load_bios([biosPath UTF8String]);
coleco_mem_load_rom([path UTF8String]);
coleco_mem_load_bios(biosPath.fileSystemRepresentation);
coleco_mem_load_rom(path.fileSystemRepresentation);
}
else
{
sms_init(SMS_VIDEO_NTSC, SMS_REGION_DOMESTIC);
sms_mem_load_rom([path UTF8String], console);
sms_frame(0, 1);
NSData *dataObj = [NSData dataWithContentsOfFile:[path stringByStandardizingPath]];
const void *data = [dataObj bytes];
uint16_t offset = 0;
int region = SMS_REGION_DOMESTIC;
// Detect SMS ROM header
if(memcmp(&data[0x1ff0], "TMR SEGA", 8) == 0)
offset = 0x1ff0;
else if (memcmp(&data[0x3ff0], "TMR SEGA", 8) == 0)
offset = 0x3ff0;
else if (memcmp(&data[0x7ff0], "TMR SEGA", 8) == 0)
offset = 0x7ff0;
if(offset)
{
// Set machine region
switch (((char *)data)[offset + 0x0f] >> 4)
{
case 3: // SMS Japan
region = SMS_REGION_DOMESTIC;
break;
case 4: // SMS Export
// Force system region to Japan if user locale is Japan and the cart is world/multi-region
region = [[self systemRegion] isEqualToString: @"Japan"] ? SMS_REGION_DOMESTIC : SMS_REGION_EXPORT;
break;
case 5: // GG Japan
case 6: // GG Export
case 7: // GG International
default:
region = SMS_REGION_DOMESTIC;
break;
}
}
else
// No header means Japan region
region = SMS_REGION_DOMESTIC;
sms_init(SMS_VIDEO_NTSC, region, 0); // 1 = VDP borders
sms_mem_load_rom(path.fileSystemRepresentation, console);
cur_console->frame(0);
}
NSString *extensionlessFilename = [[path lastPathComponent] stringByDeletingPathExtension];
NSString *batterySavesDirectory = [self batterySavesDirectoryPath];
if([batterySavesDirectory length] != 0)
if(cur_console->console_type != CONSOLE_COLECOVISION)
{
[[NSFileManager defaultManager] createDirectoryAtPath:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
NSString *filePath = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
if(console != CONSOLE_COLECOVISION)
sms_read_cartram_from_file([filePath UTF8String]);
NSString *extensionlessFilename = [[romFile lastPathComponent] stringByDeletingPathExtension];
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
[[NSFileManager defaultManager] createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
NSURL *saveFile = [batterySavesDirectory URLByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
if([saveFile checkResourceIsReachableAndReturnError:nil] && sms_read_cartram_from_file(saveFile.path.fileSystemRepresentation) == 0)
NSLog(@"CrabEmu: Loaded sram");
}
return YES;
}
- (void)executeFrame
{
[bufLock lock];
cur_console->frame(0);
[bufLock unlock];
}
- (void)resetEmulation
{
if(sms_console == CONSOLE_COLECOVISION)
coleco_soft_reset();
else
sms_soft_reset();
cur_console->soft_reset();
}
- (void)stopEmulation
{
NSString *path = romName;
NSString *extensionlessFilename = [[path lastPathComponent] stringByDeletingPathExtension];
NSString *batterySavesDirectory = [self batterySavesDirectoryPath];
if([batterySavesDirectory length] != 0)
if(cur_console->console_type != CONSOLE_COLECOVISION)
{
[[NSFileManager defaultManager] createDirectoryAtPath:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
NSLog(@"Trying to save SRAM");
NSString *filePath = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
if(sms_console != CONSOLE_COLECOVISION)
sms_write_cartram_to_file([filePath UTF8String]);
NSString *extensionlessFilename = [[romFile lastPathComponent] stringByDeletingPathExtension];
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
NSURL *saveFile = [batterySavesDirectory URLByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
cur_console->save_sram(saveFile.path.fileSystemRepresentation);
}
[super stopEmulation];
}
- (IBAction)pauseEmulation:(id)sender
- (NSTimeInterval)frameInterval
{
[bufLock lock];
sms_z80_nmi();
[bufLock unlock];
return 60;
}
# pragma mark - Video
- (OEIntSize)bufferSize
{
return OEIntSizeMake(sms_console == CONSOLE_GG ? 160 : 256, sms_console == CONSOLE_GG ? 144 : smsvdp.lines);
uint32_t f_x, f_y;
cur_console->frame_size(&f_x, &f_y);
return OEIntSizeMake(f_x, f_y);
}
- (OEIntRect)screenRect
{
uint32_t a_x, a_y, a_w, a_h;
cur_console->active_size(&a_x, &a_y, &a_w, &a_h);
return OEIntRectMake(a_x, a_y, a_w, a_h);
}
- (OEIntSize)aspectSize
{
return OEIntSizeMake(sms_console == CONSOLE_GG ? 160 : 256, sms_console == CONSOLE_GG ? 144 : smsvdp.lines);
return OEIntSizeMake(cur_console->console_type == CONSOLE_GG ? 160 : 256 * (8.0/7.0), cur_console->console_type == CONSOLE_GG ? 144 : 192);
}
- (const void *)videoBuffer
- (const void *)getVideoBufferWithHint:(void *)hint
{
if (sms_console != CONSOLE_GG)
return smsvdp.framebuffer;
else
for (int i = 0; i < 144; i++)
//jump 24 lines, skip 48 pixels and capture for each line of the buffer 160 pixels
// sizeof(unsigned char) is always equal to 1 by definition
memcpy(tempBuffer + i * 160 * 4, smsvdp.framebuffer + 24 * 256 * 1 + 48 * 1 + i * 256 * 1, 160 * 4);
return tempBuffer;
if (!hint) {
return cur_console->framebuffer();
}
return smsvdp.framebuffer = (uint32*)hint;
}
- (GLenum)pixelFormat
@@ -211,10 +227,7 @@ static OERingBuffer *ringBuffer;
return GL_UNSIGNED_INT_8_8_8_8_REV;
}
- (GLenum)internalPixelFormat
{
return GL_RGB8;
}
# pragma mark - Audio
- (double)audioSampleRate
{
@@ -226,20 +239,79 @@ static OERingBuffer *ringBuffer;
return 2;
}
- (BOOL)saveStateToFileAtPath:(NSString *)fileName
# pragma mark - Save States
- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
{
if(sms_console == CONSOLE_COLECOVISION)
return coleco_save_state([fileName fileSystemRepresentation]) == 0;
else
return sms_save_state([fileName fileSystemRepresentation]) == 0;
block(cur_console->save_state([fileName fileSystemRepresentation]) == 0, nil);
}
- (BOOL)loadStateFromFileAtPath:(NSString *)fileName
- (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
{
if(sms_console == CONSOLE_COLECOVISION)
return coleco_load_state([fileName fileSystemRepresentation]) == 0;
if([[self systemIdentifier] isEqualToString:@"openemu.system.sg1000"])
{
cur_console->load_state([fileName fileSystemRepresentation]);
block(YES, nil);
}
else
return sms_load_state([fileName fileSystemRepresentation]) == 0;
block(cur_console->load_state([fileName fileSystemRepresentation]) == 0, nil);
}
- (NSData *)serializeStateWithError:(NSError **)outError
{
void *bytes;
size_t length;
FILE *fp = open_memstream((char **)&bytes, &length);
int status;
if(cur_console->console_type == CONSOLE_COLECOVISION)
status = coleco_write_state(fp);
else
status = sms_write_state(fp);
if(status == 0) {
fclose(fp);
return [NSData dataWithBytesNoCopy:bytes length:length];
}
if(outError) {
*outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotSaveStateError userInfo:@{
NSLocalizedDescriptionKey : @"Save state data could not be written",
NSLocalizedRecoverySuggestionErrorKey : @"The emulator could not write the state data."
}];
}
fclose(fp);
free(bytes);
return nil;
}
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError
{
const void *bytes = [state bytes];
size_t length = [state length];
FILE *fp = fmemopen((void *)bytes, length, "rb");
int status;
if(cur_console->console_type == CONSOLE_COLECOVISION)
status = coleco_read_state(fp);
else
status = sms_read_state(fp);
fclose(fp);
if(status == 0)
return YES;
if(outError) {
*outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:@{
NSLocalizedDescriptionKey : @"The save state data could not be read",
NSLocalizedRecoverySuggestionErrorKey : @"Could not load data from the save state"
}];
}
return NO;
}
/*
@@ -259,12 +331,12 @@ int sound_init(int channels, int region)
void sound_shutdown(void)
{
}
void sound_reset_buffer(void)
{
}
void gui_set_viewport(int w, int h)
@@ -282,124 +354,44 @@ void gui_set_title(const char *str)
//NSLog(@"set_title%s", str);
}
- (int)crabButtonForButton:(OESMSButton)button player:(NSUInteger)player;
void gui_set_console(console_t *c)
{
int btn = -1;
switch(button)
{
case OESMSButtonUp : btn = SMS_UP; break;
case OESMSButtonDown : btn = SMS_DOWN; break;
case OESMSButtonLeft : btn = SMS_LEFT; break;
case OESMSButtonRight : btn = SMS_RIGHT; break;
case OESMSButtonA : btn = SMS_BUTTON_1; break;
case OESMSButtonB : btn = SMS_BUTTON_2; break;
default : break;
}
return btn;
cur_console = c;
}
- (int)crabButtonForButton:(OEGGButton)button;
{
int btn = -1;
switch(button)
{
case OEGGButtonUp: btn = SMS_UP; break;
case OEGGButtonDown: btn = SMS_DOWN; break;
case OEGGButtonLeft: btn = SMS_LEFT; break;
case OEGGButtonRight: btn = SMS_RIGHT; break;
case OEGGButtonA: btn = SMS_BUTTON_1; break;
case OEGGButtonB: btn = SMS_BUTTON_2; break;
case OEGGButtonStart: btn = GAMEGEAR_START; break;
default : break;
}
return btn;
}
# pragma mark - Input
- (int)crabButtonForSG1000Button:(OESG1000Button)button;
{
int btn = -1;
switch(button)
{
case OESG1000ButtonUp: btn = SMS_UP; break;
case OESG1000ButtonDown: btn = SMS_DOWN; break;
case OESG1000ButtonLeft: btn = SMS_LEFT; break;
case OESG1000ButtonRight: btn = SMS_RIGHT; break;
case OESG1000Button1: btn = SMS_BUTTON_1; break;
case OESG1000Button2: btn = SMS_BUTTON_2; break;
default : break;
}
return btn;
}
- (int)crabButtonForColecoVisionButton:(OEColecoVisionButton)button player:(NSUInteger)player;
{
int btn = -1;
switch(button)
{
case OEColecoVisionButtonUp : btn = COLECOVISION_UP; break;
case OEColecoVisionButtonDown : btn = COLECOVISION_DOWN; break;
case OEColecoVisionButtonLeft : btn = COLECOVISION_LEFT; break;
case OEColecoVisionButtonRight : btn = COLECOVISION_RIGHT; break;
case OEColecoVisionButtonLeftAction : btn = COLECOVISION_L_ACTION; break;
case OEColecoVisionButtonRightAction : btn = COLECOVISION_R_ACTION; break;
case OEColecoVisionButton1 : btn = COLECOVISION_1; break;
case OEColecoVisionButton2 : btn = COLECOVISION_2; break;
case OEColecoVisionButton3 : btn = COLECOVISION_3; break;
case OEColecoVisionButton4 : btn = COLECOVISION_4; break;
case OEColecoVisionButton5 : btn = COLECOVISION_5; break;
case OEColecoVisionButton6 : btn = COLECOVISION_6; break;
case OEColecoVisionButton7 : btn = COLECOVISION_7; break;
case OEColecoVisionButton8 : btn = COLECOVISION_8; break;
case OEColecoVisionButton9 : btn = COLECOVISION_9; break;
case OEColecoVisionButton0 : btn = COLECOVISION_0; break;
case OEColecoVisionButtonAsterisk : btn = COLECOVISION_STAR; break;
case OEColecoVisionButtonPound : btn = COLECOVISION_POUND; break;
default : break;
}
return btn;
}
const int MasterSystemMap[] = {SMS_UP, SMS_DOWN, SMS_LEFT, SMS_RIGHT, SMS_BUTTON_1, SMS_BUTTON_2, GAMEGEAR_START};
const int ColecoVisionMap[] = {COLECOVISION_UP, COLECOVISION_DOWN, COLECOVISION_LEFT, COLECOVISION_RIGHT, COLECOVISION_L_ACTION, COLECOVISION_R_ACTION, COLECOVISION_1, COLECOVISION_2, COLECOVISION_3, COLECOVISION_4, COLECOVISION_5, COLECOVISION_6, COLECOVISION_7, COLECOVISION_8, COLECOVISION_9, COLECOVISION_0, COLECOVISION_STAR, COLECOVISION_POUND};
- (oneway void)didPushGGButton:(OEGGButton)button;
{
int btn = [self crabButtonForButton:button];
if(btn > -1) sms_button_pressed(1, btn);
sms_button_pressed(1, MasterSystemMap[button]);
}
- (oneway void)didReleaseGGButton:(OEGGButton)button;
{
int btn = [self crabButtonForButton:button];
if(btn > -1) sms_button_released(1, btn);
sms_button_released(1, MasterSystemMap[button]);
}
- (oneway void)didPushSMSButton:(OESMSButton)button forPlayer:(NSUInteger)player;
{
int btn = [self crabButtonForButton:button player:player];
if(btn > -1) sms_button_pressed(player, btn);
sms_button_pressed((int)player, MasterSystemMap[button]);
}
- (oneway void)didReleaseSMSButton:(OESMSButton)button forPlayer:(NSUInteger)player;
{
int btn = [self crabButtonForButton:button player:player];
if(btn > -1) sms_button_released(player, btn);
sms_button_released((int)player, MasterSystemMap[button]);
}
- (oneway void)didPushSMSStartButton;
{
if(sms_console != CONSOLE_GG)
[self pauseEmulation:self];
else
sms_button_pressed(1, GAMEGEAR_START);
sms_button_pressed(1, GAMEGEAR_START);
}
- (oneway void)didReleaseSMSStartButton;
{
sms_button_released(1, GAMEGEAR_START);
}
- (oneway void)didPushSMSResetButton;
@@ -412,68 +404,81 @@ void gui_set_title(const char *str)
sms_button_released(1, SMS_CONSOLE_RESET);
}
- (oneway void)didPushSG1000Button:(OESG1000Button)button;
- (oneway void)didPushSG1000Button:(OESG1000Button)button forPlayer:(NSUInteger)player
{
int btn = [self crabButtonForSG1000Button:button];
if(btn > -1) sms_button_pressed(1, btn);
//console pause, sms_z80_nmi()
sms_button_pressed((int)player, MasterSystemMap[button]);
}
- (oneway void)didReleaseSG1000Button:(OESG1000Button)button;
- (oneway void)didReleaseSG1000Button:(OESG1000Button)button forPlayer:(NSUInteger)player
{
int btn = [self crabButtonForSG1000Button:button];
if(btn > -1) sms_button_released(1, btn);
sms_button_released((int)player, MasterSystemMap[button]);
}
- (oneway void)didPushColecoVisionButton:(OEColecoVisionButton)button forPlayer:(NSUInteger)player;
{
int btn = [self crabButtonForColecoVisionButton:button player:player];
if(btn > -1) coleco_button_pressed(player, btn);
coleco_button_pressed((int)player, ColecoVisionMap[button]);
}
- (oneway void)didReleaseColecoVisionButton:(OEColecoVisionButton)button forPlayer:(NSUInteger)player;
{
int btn = [self crabButtonForColecoVisionButton:button player:player];
if(btn > -1) coleco_button_released(player, btn);
coleco_button_released((int)player, ColecoVisionMap[button]);
}
#pragma mark - Cheats
- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled
{
// Sanitize
code = [code stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// Remove any spaces
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
// Remove address-value separator
code = [code stringByReplacingOccurrencesOfString:@"-" withString:@""];
if (enabled)
[cheatList setValue:@YES forKey:code];
else
[cheatList removeObjectForKey:code];
sms_cheat_reset();
NSArray *multipleCodes = [[NSArray alloc] init];
multipleCodes = [code componentsSeparatedByString:@"+"];
for (NSString *singleCode in multipleCodes)
// Apply enabled cheats found in dictionary
for (id key in cheatList)
{
if ([singleCode length] == 8)
if ([[cheatList valueForKey:key] isEqual:@YES])
{
// Action Replay GG/SMS format: XXXX-YYYY
NSString *address = [singleCode substringWithRange:NSMakeRange(0, 4)];
NSString *value = [singleCode substringWithRange:NSMakeRange(4, 4)];
// Convert AR hex to int
uint32_t outAddress, outValue;
NSScanner* scanAddress = [NSScanner scannerWithString:address];
NSScanner* scanValue = [NSScanner scannerWithString:value];
[scanAddress scanHexInt:&outAddress];
[scanValue scanHexInt:&outValue];
sms_cheat_t *arCode = (sms_cheat_t *)malloc(sizeof(sms_cheat_t));
arCode->ar_code = (outAddress << 16) | outValue;
strcpy(arCode->desc, [singleCode UTF8String]);
arCode->enabled = 1;
sms_cheat_enable();
sms_cheat_add(arCode);
// Handle multi-line cheats
multipleCodes = [key componentsSeparatedByString:@"+"];
for (NSString *singleCode in multipleCodes)
{
if ([singleCode length] == 8)
{
// Action Replay GG/SMS format: XXXX-YYYY
NSString *address = [singleCode substringWithRange:NSMakeRange(0, 4)];
NSString *value = [singleCode substringWithRange:NSMakeRange(4, 4)];
// Convert AR hex to int
uint32_t outAddress, outValue;
NSScanner *scanAddress = [NSScanner scannerWithString:address];
NSScanner *scanValue = [NSScanner scannerWithString:value];
[scanAddress scanHexInt:&outAddress];
[scanValue scanHexInt:&outValue];
sms_cheat_t *arCode = (sms_cheat_t *)malloc(sizeof(sms_cheat_t));
memset(arCode, 0, sizeof(sms_cheat_t));
arCode->ar_code = (outAddress << 16) | outValue;
strcpy(arCode->desc, [singleCode UTF8String]);
arCode->enabled = 1;
sms_cheat_add(arCode);
sms_cheat_enable();
}
}
}
}
}
-9
View File
@@ -1,9 +0,0 @@
build_now: 'YES'
create_core_path: 'YES'
download_base_url: http://github.com/downloads/openemu/openemu/
release_notes_base_url: http://openemu.org/category/releasenotes/crabemu/
appcast_basefolder: '/Users/jweinberg/Desktop/Appcast'
appcast_xml_name: 'crabemu_appcast.xml'
keychain_privkey_name: 'Sparkle Private Key'
css_file_name: 'rnotes.css'
bundle_extension: 'oecoreplugin'
+93
View File
@@ -0,0 +1,93 @@
/*
This file is part of CrabEmu.
Copyright (C) 2014, 2015, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CONSOLE_H
#define CONSOLE_H
#include "CrabEmu.h"
CLINKAGE
/* All of the consoles that are supported currently. These may eventually go
away if there is ever a push to abstract this even more... */
#define CONSOLE_NULL 0 /* No console */
#define CONSOLE_SMS 1 /* Sega Master System or Mark III */
#define CONSOLE_GG 2 /* Sega Game Gear */
#define CONSOLE_SG1000 3 /* Sega SG-1000 */
#define CONSOLE_SC3000 4 /* Sega SC-3000 */
#define CONSOLE_COLECOVISION 5 /* ColecoVision */
#define CONSOLE_NES 6 /* Nintendo Entertainment System */
/* 7 left blank for now... */
#define CONSOLE_CHIP8 8 /* Chip-8 "Console" */
/* Region codes. */
#define REGION_NONE 0x00
#define REGION_JAPAN 0x01
#define REGION_US 0x02
#define REGION_EUROPE 0x04
/* This structure is meant to provide an abstraction of a console, such that
there can be less console-specific code up at the GUI level. Rignt now, this
doesn't take care of everything, but that might eventually change... Each
console should create and initialize a "subclass" of one of these (provide
a structure such that a console_t is the first member thereof). */
typedef struct crabemu_console {
int console_family;
int console_type;
int initialized;
/* Initialization-related stuff */
int (*shutdown)(void);
int (*reset)(void);
int (*soft_reset)(void);
/* Run one frame of output. */
void (*frame)(int skip);
/* Save state management */
int (*load_state)(const char *fn);
int (*save_state)(const char *fn);
int (*save_sram)(const char *fn);
/* Input */
void (*button_pressed)(int player, int button);
void (*button_released)(int player, int button);
/* Video-related functionaity */
void *(*framebuffer)(void);
void (*frame_size)(uint32_t *x, uint32_t *y);
void (*active_size)(uint32_t *x, uint32_t *y, uint32_t *w, uint32_t *h);
/* Cheats */
int (*save_cheats)(const char *fn);
/* Debugging related functions. */
void (*scanline)(void);
void (*step)(void);
void (*finish_frame)(void);
void (*finish_line)(void);
int (*current_scanline)(void);
int (*current_cycles)(void);
void (*set_control)(int player, int control);
} console_t;
ENDCLINK
#endif /* !CONSOLE_H */
+622
View File
@@ -0,0 +1,622 @@
/*
This file is part of CrabEmu.
Copyright (C) 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#ifdef DEBUG
#include <inttypes.h>
#endif
#ifdef _arch_dreamcast
#include <zlib/zlib.h>
#include <bzlib/bzlib.h>
#else
#ifndef NO_ZLIB
#include <zlib.h>
#endif
#ifndef NO_BZ2
#include <bzlib.h>
#endif
#endif
#include "rom.h"
#include "chip8.h"
#include "chip8cpu.h"
#include "sound.h"
#ifndef NO_ZLIB
#include "unzip.h"
#endif
/* Forward declaration... */
chip8_t chip8_cons;
static uint8 *cart_rom;
static uint32 cart_len;
static uint8 memory[4096];
static uint32 rom_crc, rom_adler;
static pixel_t fb[64 * 32];
static Chip8CPU_t cpu;
static uint8 buttons[16];
static uint8 dt, st;
static const uint8 font[80] = {
0xF0, 0x90, 0x90, 0x90, 0xF0,
0x20, 0x60, 0x20, 0x20, 0x70,
0xF0, 0x10, 0xF0, 0x80, 0xF0,
0xF0, 0x10, 0xF0, 0x10, 0xF0,
0x90, 0x90, 0xF0, 0x10, 0x10,
0xF0, 0x80, 0xF0, 0x10, 0xF0,
0xF0, 0x80, 0xF0, 0x90, 0xF0,
0xF0, 0x10, 0x20, 0x40, 0x40,
0xF0, 0x90, 0xF0, 0x90, 0xF0,
0xF0, 0x90, 0xF0, 0x10, 0xF0,
0xF0, 0x90, 0xF0, 0x90, 0x90,
0xE0, 0x90, 0xE0, 0x90, 0xE0,
0xF0, 0x80, 0x80, 0x80, 0xF0,
0xE0, 0x90, 0x90, 0x90, 0xE0,
0xF0, 0x80, 0xF0, 0x80, 0xF0,
0xF0, 0x80, 0xF0, 0x80, 0x80
};
#define PIXEL_SET ((pixel_t)(0xFFFFFFFF))
static uint8 chip8_mem_read(void *cpu, uint16 addr) {
(void)cpu;
return memory[addr & 0xFFF];
}
static void chip8_mem_write(void *cpu, uint16 addr, uint8 val) {
(void)cpu;
memory[addr & 0xFFF] = val;
}
static uint16 chip8_mem_read16(void *cpu, uint16 addr) {
(void)cpu;
return (memory[addr & 0xFFF] << 8) | memory[(addr + 1) & 0xFFF];
}
static uint8 chip8_reg_read(void *cpu, uint8 reg) {
(void)cpu;
if(reg < CHIP8_REG_DT)
return buttons[reg];
else if(reg == CHIP8_REG_DT)
return dt;
else if(reg == CHIP8_REG_ST)
return st;
else
return 0;
}
static void chip8_reg_write(void *cpu, uint8 reg, uint8 val) {
(void)cpu;
if(reg == CHIP8_REG_DT)
dt = val;
else if(reg == CHIP8_REG_ST)
st = val;
}
static void chip8_mem_clear_fb(void *cpu) {
(void)cpu;
memset(fb, 0, 64 * 32 * sizeof(pixel_t));
}
static int chip8_mem_draw_spr(void *cpu, uint16 addr, uint8 x, uint8 y,
uint8 height) {
uint8 i, j, bp;
int rv = 0;
int ptr;
y &= 0x1F;
x &= 0x3F;
ptr = (y << 6) + x;
if(height + y > 32)
height = 32 - y;
for(i = 0; i < height; ++i, ptr += 64) {
bp = chip8_mem_read(cpu, addr + i);
for(j = 0; j < 8 && x + j < 64; ++j) {
if((bp & (0x80 >> j))) {
fb[ptr + j] ^= PIXEL_SET;
if(!fb[ptr + j])
rv = 1;
}
}
}
return rv;
}
static void finalize_load(const char *fn) {
char *name;
/* Calculate the checksums of the game */
rom_adler = rom_adler32(cart_rom, cart_len);
rom_crc = rom_crc32(cart_rom, cart_len);
#ifdef DEBUG
printf("Checksums: Adler-32: 0x%08" PRIX32 " CRC32: 0x%08" PRIX32 "\n",
(uint32_t)rom_adler, (uint32_t)rom_crc);
#endif
/* Copy the rom and font into the memory space. */
memcpy(memory + 0x200, cart_rom, cart_len);
memcpy(memory, font, 80);
chip8_mem_clear_fb(NULL);
name = strrchr(fn, '/');
if(name != NULL) {
/* we have a filename, but the first char is /, so skip that */
gui_set_title(name + 1);
}
else {
gui_set_title("CrabEmu");
}
}
#ifndef NO_ZLIB
static int load_gz_rom(const char *fn) {
int len;
gzFile fp;
void *tmp;
/* Open up the file in question. */
if(!(fp = gzopen(fn, "rb"))) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Could not open ROM: %s!\n", fn);
#endif
return ROM_LOAD_E_OPEN;
}
/* Read one chunk of the file at a time, until we have no more left. */
cart_rom = (uint8 *)malloc(0x100);
if(!cart_rom) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't allocate space!\n");
#endif
gzclose(fp);
return ROM_LOAD_E_ERRNO;
}
cart_len = 0;
len = gzread(fp, cart_rom, 0x100);
while(len != 0 && len != -1) {
cart_len += len;
tmp = realloc(cart_rom, cart_len + 0x100);
if(!tmp) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't allocate space!\n");
#endif
gzclose(fp);
free(cart_rom);
cart_rom = NULL;
return ROM_LOAD_E_ERRNO;
}
cart_rom = (uint8 *)tmp;
memset(cart_rom + cart_len, 0xFF, 0x100);
len = gzread(fp, cart_rom + cart_len, 0x100);
}
gzclose(fp);
finalize_load(fn);
return ROM_LOAD_SUCCESS;
}
#endif
#ifndef NO_BZ2
static int load_bz2_rom(const char *fn) {
int len;
BZFILE *fp;
void *tmp;
/* Open up the file in question. */
if(!(fp = BZ2_bzopen(fn, "rb"))) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Could not open ROM: %s!\n", fn);
#endif
return ROM_LOAD_E_OPEN;
}
/* Read one chunk of the file at a time, until we have no more left. */
if(!(cart_rom = (uint8 *)malloc(0x100))) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't allocate space!\n");
#endif
BZ2_bzclose(fp);
return ROM_LOAD_E_ERRNO;
}
cart_len = 0;
len = BZ2_bzread(fp, cart_rom, 0x100);
while(len != 0 && len != -1) {
cart_len += len;
tmp = realloc(cart_rom, cart_len + 0x100);
if(!tmp) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't allocate space!\n");
#endif
BZ2_bzclose(fp);
free(cart_rom);
cart_rom = NULL;
return ROM_LOAD_E_ERRNO;
}
cart_rom = (uint8 *)tmp;
memset(cart_rom + cart_len, 0xFF, 0x100);
len = BZ2_bzread(fp, cart_rom + cart_len, 0x100);
}
BZ2_bzclose(fp);
finalize_load(fn);
return ROM_LOAD_SUCCESS;
}
#endif
#ifndef NO_ZLIB
static int load_zip_rom(const char *fn) {
int found = 0;
unzFile fp;
unz_file_info inf;
char fn2[4096];
char *ext;
int size;
/* Open up the file in question. */
fp = unzOpen(fn);
if(!fp) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Could not open ROM: %s!\n", fn);
#endif
return ROM_LOAD_E_OPEN;
}
if(unzGoToFirstFile(fp) != UNZ_OK) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't find file in zip!\n");
#endif
unzClose(fp);
return ROM_LOAD_E_CORRUPT;
}
/* Keep looking at files until we find a rom. */
while(!found) {
if(unzGetCurrentFileInfo(fp, &inf, fn2, 4096, NULL, 0, NULL,
0) != UNZ_OK) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Error parsing Zip file!\n");
#endif
unzClose(fp);
return ROM_LOAD_E_CORRUPT;
}
/* Check if this file looks like a rom. */
ext = strrchr(fn2, '.');
if(ext) {
/* XXXX */
if(!strcmp(ext, ".ch8") || !strcmp(ext, ".c8")) {
found = 1;
}
}
/* If we haven't found a rom yet, move to the next file. */
if(!found) {
if(unzGoToNextFile(fp) != UNZ_OK) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: End of zip file!\n");
#endif
unzClose(fp);
return ROM_LOAD_E_NO_ROM;
}
}
}
/* If the size isn't a nice even amount, round it. */
size = inf.uncompressed_size;
if(!(cart_rom = (uint8 *)malloc(size))) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Could not load ROM: %s!\n", fn);
fprintf(stderr, "Reason: %s\n", strerror(errno));
#endif
unzClose(fp);
return ROM_LOAD_E_ERRNO;
}
/* Attempt to open the file we think is a rom. */
if(unzOpenCurrentFile(fp) != UNZ_OK) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't open rom from zip!\n");
#endif
unzClose(fp);
free(cart_rom);
cart_rom = NULL;
return ROM_LOAD_E_CORRUPT;
}
/* Attempt to read the file. */
if(unzReadCurrentFile(fp, cart_rom, size) < 0) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Couldn't read rom from zip!\n");
#endif
unzCloseCurrentFile(fp);
unzClose(fp);
free(cart_rom);
cart_rom = NULL;
return ROM_LOAD_E_CORRUPT;
}
/* We're done with the file, close everything. */
unzCloseCurrentFile(fp);
unzClose(fp);
cart_len = size;
finalize_load(fn);
return ROM_LOAD_SUCCESS;
}
#endif
int chip8_mem_load_rom(const char *fn) {
FILE *fp;
int size;
char *ext;
/* If its a compressed format, go onto the handler for it... */
ext = strrchr(fn, '.');
if(ext) {
#ifndef NO_ZLIB
if(!strcmp(ext, ".gz")) {
return load_gz_rom(fn);
}
else if(!strcmp(ext, ".zip")) {
return load_zip_rom(fn);
}
#endif
#ifndef NO_BZ2
if(!strcmp(ext, ".bz2")) {
return load_bz2_rom(fn);
}
#endif
}
if(!(fp = fopen(fn, "rb"))) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Could not open ROM: %s!\n", fn);
#endif
return ROM_LOAD_E_ERRNO;
}
/* Determine the size of the file */
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(!(cart_rom = (uint8 *)malloc(size))) {
#ifdef DEBUG
fprintf(stderr, "chip8_mem_load_rom: Could not load ROM: %s!\n", fn);
fprintf(stderr, "Reason: %s\n", strerror(errno));
#endif
return ROM_LOAD_E_ERRNO;
}
fread(cart_rom, size, 1, fp);
fclose(fp);
cart_len = size;
finalize_load(fn);
return ROM_LOAD_SUCCESS;
}
static int chip8_mem_init(void) {
memset(memory, 0, 0x1000);
chip8_mem_clear_fb(NULL);
return 0;
}
static int chip8_mem_shutdown(void) {
if(cart_rom)
free(cart_rom);
cart_rom = NULL;
cart_len = 0;
return 0;
}
static void chip8_mem_reset(void) {
memset(memory, 0, 0x1000);
memcpy(memory + 0x200, cart_rom, cart_len);
memcpy(memory, font, 80);
chip8_mem_clear_fb(NULL);
}
void chip8_get_checksums(uint32 *crc, uint32 *adler) {
*crc = rom_crc;
*adler = rom_adler;
}
/* Console interface for CrabEmu's core... */
int chip8_init(void) {
if(chip8_cons._base.initialized)
return -1;
gui_set_console((console_t *)&chip8_cons);
Chip8CPU_init(&cpu);
Chip8CPU_set_memread(&cpu, &chip8_mem_read);
Chip8CPU_set_memread16(&cpu, &chip8_mem_read16);
Chip8CPU_set_memwrite(&cpu, &chip8_mem_write);
Chip8CPU_set_regread(&cpu, &chip8_reg_read);
Chip8CPU_set_regwrite(&cpu, &chip8_reg_write);
Chip8CPU_set_clearfb(&cpu, &chip8_mem_clear_fb);
Chip8CPU_set_drawspr(&cpu, &chip8_mem_draw_spr);
chip8_mem_init();
sound_init(1, VIDEO_NTSC);
chip8_cons._base.initialized = 1;
return 0;
}
static int chip8_shutdown(void) {
if(!chip8_cons._base.initialized)
return -1;
chip8_mem_clear_fb(NULL);
Chip8CPU_reset(&cpu);
chip8_mem_shutdown();
sound_shutdown();
chip8_cons._base.initialized = 0;
return 0;
}
static int chip8_reset(void) {
if(!chip8_cons._base.initialized)
return -1;
sound_reset_buffer();
chip8_mem_shutdown();
chip8_mem_init();
Chip8CPU_reset(&cpu);
return 0;
}
static int chip8_soft_reset(void) {
if(!chip8_cons._base.initialized)
return 0;
sound_reset_buffer();
chip8_mem_reset();
Chip8CPU_reset(&cpu);
return 0;
}
static void chip8_frame(int skip) {
int i;
(void)skip;
/* XXXX: How many cycles to execute? We punt and do 15. */
for(i = 0; i < 15; ++i) {
Chip8CPU_execute(&cpu);
}
/* Update the timers, if they're running. */
if(dt)
--dt;
if(st) {
/* Need to deal with sound still... */
--st;
}
}
static void chip8_button_pressed(int player, int button) {
if(player != 1)
return;
if(button < 0 || button > 15)
return;
buttons[button] = 1;
}
static void chip8_button_released(int player, int button) {
if(player != 1)
return;
if(button < 0 || button > 15)
return;
buttons[button] = 0;
}
static void *chip8_framebuffer(void) {
return fb;
}
static void chip8_framesize(uint32_t *x, uint32_t *y) {
*x = 64;
*y = 32;
}
static void chip8_activeframe(uint32_t *x, uint32_t *y, uint32_t *w,
uint32_t *h) {
*x = *y = 0;
*w = 64;
*h = 32;
}
/* Console declaration... */
chip8_t chip8_cons = {
{
CONSOLE_CHIP8,
CONSOLE_CHIP8,
0,
&chip8_shutdown,
&chip8_reset,
&chip8_soft_reset,
&chip8_frame,
NULL,
NULL,
NULL,
&chip8_button_pressed,
&chip8_button_released,
&chip8_framebuffer,
&chip8_framesize,
&chip8_activeframe,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
}
};
+40
View File
@@ -0,0 +1,40 @@
/*
This file is part of CrabEmu.
Copyright (C) 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CHIP8_H
#define CHIP8_H
#include "CrabEmu.h"
#include "console.h"
CLINKAGE
extern int chip8_init(void);
extern int chip8_mem_load_rom(const char *fn);
/* Console definition. */
typedef struct crabemu_chip8 {
console_t _base;
} chip8_t;
extern chip8_t chip8_cons;
ENDCLINK
#endif /* !CHIP8_H */
+147
View File
@@ -0,0 +1,147 @@
/*
This file is part of CrabEmu.
Copyright (C) 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include "chip8cpu.h"
static uint8 Chip8CPU_dummy_read(void *cpu, uint16 addr) {
(void)cpu;
(void)addr;
return 0;
}
static uint16 Chip8CPU_dummy_read16(void *cpu, uint16 addr) {
Chip8CPU_t *c = (Chip8CPU_t *)cpu;
return (c->mread(cpu, addr) << 8) | c->mread(cpu, addr + 1);
}
static void Chip8CPU_dummy_write(void *cpu, uint16 addr, uint8 data) {
(void)cpu;
(void)addr;
(void)data;
}
static uint8 Chip8CPU_dummy_rread(void *cpu, uint8 reg) {
(void)cpu;
(void)reg;
return 0;
}
static void Chip8CPU_dummy_rwrite(void *cpu, uint8 reg, uint8 data) {
(void)cpu;
(void)reg;
(void)data;
}
static void Chip8CPU_dummy_clear(void *cpu) {
(void)cpu;
}
static int Chip8CPU_dummy_draw(void *cpu, uint16 a, uint8 x, uint8 y, uint8 h) {
(void)cpu;
(void)a;
(void)x;
(void)y;
(void)h;
return 0;
}
void Chip8CPU_set_memread(Chip8CPU_t *cpu, uint8 (*mread)(void *, uint16)) {
if(mread == NULL)
cpu->mread = &Chip8CPU_dummy_read;
else
cpu->mread = mread;
}
void Chip8CPU_set_memread16(Chip8CPU_t *cpu, uint16 (*mread)(void *, uint16)) {
if(mread == NULL)
cpu->mread16 = &Chip8CPU_dummy_read16;
else
cpu->mread16 = mread;
}
void Chip8CPU_set_memwrite(Chip8CPU_t *cpu,
void (*mwrite)(void *, uint16, uint8)) {
if(mwrite == NULL)
cpu->mwrite = &Chip8CPU_dummy_write;
else
cpu->mwrite = mwrite;
}
void Chip8CPU_set_regread(Chip8CPU_t *cpu, uint8 (*rread)(void *, uint8)) {
if(rread == NULL)
cpu->rread = &Chip8CPU_dummy_rread;
else
cpu->rread = rread;
}
void Chip8CPU_set_regwrite(Chip8CPU_t *cpu,
void (*rwrite)(void *, uint8, uint8)) {
if(rwrite == NULL)
cpu->rwrite = &Chip8CPU_dummy_rwrite;
else
cpu->rwrite = rwrite;
}
void Chip8CPU_set_clearfb(Chip8CPU_t *cpu,
void (*clearfb)(void *)) {
if(clearfb == NULL)
cpu->clear_fb = &Chip8CPU_dummy_clear;
else
cpu->clear_fb = clearfb;
}
void Chip8CPU_set_drawspr(Chip8CPU_t *cpu,
int (*drawspr)(void *, uint16, uint8, uint8, uint8)) {
if(drawspr == NULL)
cpu->draw_spr = &Chip8CPU_dummy_draw;
else
cpu->draw_spr = drawspr;
}
void Chip8CPU_init(Chip8CPU_t *cpu) {
cpu->mread = &Chip8CPU_dummy_read;
cpu->mwrite = &Chip8CPU_dummy_write;
cpu->mread16 = &Chip8CPU_dummy_read16;
cpu->rread = &Chip8CPU_dummy_rread;
cpu->rwrite = &Chip8CPU_dummy_rwrite;
cpu->clear_fb = &Chip8CPU_dummy_clear;
cpu->draw_spr = &Chip8CPU_dummy_draw;
}
void Chip8CPU_reset(Chip8CPU_t *cpu) {
cpu->pc = 0x200;
cpu->i = 0;
cpu->sp = 0;
memset(cpu->stack, 0, sizeof(uint16) * 16);
memset(cpu->v, 0, sizeof(uint8) * 16);
}
void Chip8CPU_execute(Chip8CPU_t *cpu) {
uint16 inst;
inst = cpu->mread16(cpu, cpu->pc);
cpu->pc += 2;
#define INSIDE_CHIP8CPU_EXECUTE
#include "chip8cpuops.h"
#undef INSIDE_CHIP8CPU_EXECUTE
}
+104
View File
@@ -0,0 +1,104 @@
/*
This file is part of CrabEmu.
Copyright (C) 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CHIP8CPU_H
#define CHIP8CPU_H
#ifdef IN_CRABEMU
#include "CrabEmu.h"
#else
#ifdef __cplusplus
#define CLINKAGE extern "C" {
#define ENDCLINK }
#else
#define CLINKAGE
#define ENDCLINK
#endif /* __cplusplus */
#ifndef CRABEMU_TYPEDEFS
#define CRABEMU_TYPEDEFS
#ifdef _arch_dreamcast
#include <arch/types.h>
#else
#include <stdint.h>
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef int8_t int8;
typedef int16_t int16;
typedef uint32_t int32;
#endif /* _arch_dreamcast */
#endif /* CRABEMU_TYPEDEFS */
#endif /* IN_CRABEMU */
CLINKAGE
typedef struct Chip8CPU_struct Chip8CPU_t;
struct Chip8CPU_struct {
uint16 pc;
uint16 i;
uint16 stack[16];
uint8 v[16];
uint8 sp;
uint8 (*mread)(void *, uint16);
void (*mwrite)(void *, uint16, uint8);
uint16 (*mread16)(void *, uint16);
uint8 (*rread)(void *, uint8);
void (*rwrite)(void *, uint8, uint8);
void (*clear_fb)(void *);
int (*draw_spr)(void *, uint16, uint8, uint8, uint8);
};
/* Key statuses are defined as registers 0x00-0x0F */
#define CHIP8_REG_DT 0x10
#define CHIP8_REG_ST 0x11
/* Function definitions */
void Chip8CPU_init(Chip8CPU_t *cpu);
void Chip8CPU_reset(Chip8CPU_t *cpu);
void Chip8CPU_execute(Chip8CPU_t *cpu);
void Chip8CPU_set_memread(Chip8CPU_t *cpu,
uint8 (*mread)(void *cpu, uint16 addr));
void Chip8CPU_set_memread16(Chip8CPU_t *cpu,
uint16 (*mread)(void *cpu, uint16 addr));
void Chip8CPU_set_memwrite(Chip8CPU_t *cpu,
void (*mwrite)(void *cpu, uint16 addr, uint8 data));
void Chip8CPU_set_regread(Chip8CPU_t *cpu,
uint8 (*rread)(void *cpu, uint8 reg));
void Chip8CPU_set_regwrite(Chip8CPU_t *cpu,
void (*rwrite)(void *cpu, uint8 reg, uint8 data));
void Chip8CPU_set_clearfb(Chip8CPU_t *cpu, void (*clearfb)(void*));
void Chip8CPU_set_drawspr(Chip8CPU_t *cpu,
int (*drawspr)(void *, uint16, uint8, uint8, uint8));
ENDCLINK
#endif /* !CHIP8CPU_H */
+266
View File
@@ -0,0 +1,266 @@
/*
This file is part of CrabEmu.
Copyright (C) 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INSIDE_CHIP8CPU_EXECUTE
#error This file can only be compiled inside of chip8cpu.c. Do not try to
#error include this file in other files.
#endif
uint8 _tmp, _tmp2;
int _tmp3;
switch(inst >> 12) {
case 0x0:
switch(inst) {
case 0xE0: /* CLS */
cpu->clear_fb(cpu);
goto out;
case 0xEE: /* RET */
--cpu->sp;
cpu->pc = cpu->stack[cpu->sp & 0xF];
goto out;
default:
/* XXXX */
goto out;
}
break;
case 0x1: /* JP #addr12 */
cpu->pc = inst & 0x0FFF;
goto out;
case 0x2: /* CALL #addr12 */
cpu->stack[cpu->sp & 0xF] = cpu->pc;
++cpu->sp;
cpu->pc = inst & 0x0FFF;
goto out;
case 0x3: /* SE Vx, #imm8 */
_tmp = cpu->v[(inst >> 8) & 0x0F];
_tmp2 = (uint8)inst;
if(_tmp == _tmp2)
cpu->pc += 2;
goto out;
case 0x4: /* SNE VX, #imm8 */
_tmp = cpu->v[(inst >> 8) & 0x0F];
_tmp2 = (uint8)inst;
if(_tmp != _tmp2)
cpu->pc += 2;
goto out;
case 0x5: /* SE Vx, Vy */
/* XXXX: What if the last nibble isn't 0? */
_tmp = cpu->v[(inst >> 8) & 0x0F];
_tmp2 = cpu->v[(inst >> 4) & 0x0F];
if(_tmp == _tmp2)
cpu->pc += 2;
goto out;
case 0x6: /* LD Vx, #imm8 */
cpu->v[(inst >> 8) & 0x0F] = (uint8)inst;
goto out;
case 0x7: /* ADD Vx, #imm8 */
cpu->v[(inst >> 8) & 0x0F] += (uint8)inst;
goto out;
case 0x8:
switch(inst & 0x000F) {
case 0x0: /* LD Vx, Vy */
cpu->v[(inst >> 8) & 0x0F] = cpu->v[(inst >> 4) & 0x0F];
goto out;
case 0x1: /* OR Vx, Vy */
cpu->v[(inst >> 8) & 0x0F] |= cpu->v[(inst >> 4) & 0x0F];
goto out;
case 0x2: /* AND Vx, Vy */
cpu->v[(inst >> 8) & 0x0F] &= cpu->v[(inst >> 4) & 0x0F];
goto out;
case 0x3: /* XOR Vx, Vy */
cpu->v[(inst >> 8) & 0x0F] ^= cpu->v[(inst >> 4) & 0x0F];
goto out;
case 0x4: /* ADD Vx, Vy */
_tmp = (inst >> 8) & 0x0F;
_tmp3 = cpu->v[_tmp] + cpu->v[(inst >> 4) & 0x0F];
cpu->v[_tmp] = (uint8)_tmp3;
cpu->v[0xF] = (uint8)(_tmp3 >> 8) & 0x01;
goto out;
case 0x5: /* SUB Vx, Vy */
_tmp = (inst >> 8) & 0xF;
_tmp2 = (inst >> 4) & 0xF;
_tmp3 = cpu->v[_tmp] - cpu->v[_tmp2];
cpu->v[0xF] = !!(cpu->v[_tmp] >= cpu->v[_tmp2]);
cpu->v[_tmp] = (uint8)_tmp3;
goto out;
case 0x6: /* SHR Vx {, Vy} */
_tmp = (inst >> 8) & 0x0F;
cpu->v[0xF] = cpu->v[_tmp] & 0x01;
cpu->v[_tmp] >>= 1;
goto out;
case 0x7: /* SUBN Vx, Vy */
_tmp = (inst >> 8) & 0xF;
_tmp2 = (inst >> 4) & 0xF;
_tmp3 = cpu->v[_tmp2] - cpu->v[_tmp];
cpu->v[0xF] = !!(cpu->v[_tmp2] >= cpu->v[_tmp]);
cpu->v[_tmp] = (uint8)_tmp3;
goto out;
case 0xE: /* SHL Vx {, Vy} */
_tmp = (inst >> 8) & 0x0F;
cpu->v[0xF] = (cpu->v[_tmp] >> 7) & 0x01;
cpu->v[_tmp] <<= 1;
goto out;
default:
/* XXXX */
goto out;
}
case 0x9: /* SNE Vx, Vy */
/* XXXX: What if the last nibble isn't 0? */
_tmp = cpu->v[(inst >> 8) & 0x0F];
_tmp2 = cpu->v[(inst >> 4) & 0x0F];
if(_tmp != _tmp2)
cpu->pc += 2;
goto out;
case 0xA: /* LD I, #addr12 */
cpu->i = inst & 0x0FFF;
goto out;
case 0xB: /* JP V0, #addr12 */
cpu->pc = (inst & 0x0FFF) + cpu->v[0];
goto out;
case 0xC: /* RND Vx, #imm8 */
_tmp = (uint8)inst;
cpu->v[(inst >> 8) & 0xF] = rand() & _tmp;
goto out;
case 0xD: /* DRW Vx, Vy, #imm4 */
cpu->v[0xF] = cpu->draw_spr(cpu, cpu->i, cpu->v[(inst >> 8) & 0xF],
cpu->v[(inst >> 4) & 0xF], inst & 0xF);
goto out;
case 0xE:
switch(inst & 0xFF) {
case 0x9E: /* SKP Vx */
_tmp = cpu->v[(inst >> 8) & 0xF] & 0xF;
if(cpu->rread(cpu, _tmp))
cpu->pc += 2;
goto out;
case 0xA1: /* SKNP Vx */
_tmp = cpu->v[(inst >> 8) & 0xF] & 0xF;
if(!cpu->rread(cpu, _tmp))
cpu->pc += 2;
goto out;
default:
/* XXXX */
goto out;
}
case 0xF:
switch(inst & 0xFF) {
case 0x07: /* LD Vx, DT */
cpu->v[(inst >> 8) & 0xF] = cpu->rread(cpu, CHIP8_REG_DT);
goto out;
case 0x0A: /* LD Vx, K */
for(_tmp = 0; _tmp < 15; ++_tmp) {
if(cpu->rread(cpu, _tmp)) {
cpu->v[(inst >> 8) & 0xF] = _tmp;
goto out;
}
}
/* Didn't find a key pressed, so repeat the instruction. */
cpu->pc -= 2;
goto out;
case 0x15: /* LD DT, Vx */
cpu->rwrite(cpu, CHIP8_REG_DT, cpu->v[(inst >> 8) & 0xF]);
goto out;
case 0x18: /* LD ST, Vx */
cpu->rwrite(cpu, CHIP8_REG_ST, cpu->v[(inst >> 8) & 0xF]);
goto out;
case 0x1E: /* ADD I, Vx */
cpu->i += cpu->v[(inst >> 8) & 0xF];
cpu->v[0xF] = !!(cpu->i >> 12);
goto out;
case 0x29: /* LD F, Vx */
/* The font is at 0x000, so this is easy. */
cpu->i = (cpu->v[(inst >> 8) & 0xF] & 0xF) * 5;
goto out;
case 0x33: /* LD B, Vx */
_tmp = cpu->v[(inst >> 8) & 0xF];
cpu->mwrite(cpu, cpu->i, _tmp / 100);
cpu->mwrite(cpu, cpu->i + 1, (_tmp % 100) / 10);
cpu->mwrite(cpu, cpu->i + 2, _tmp % 10);
goto out;
case 0x55: /* LD [I], Vx */
_tmp2 = (inst >> 8) & 0xF;
for(_tmp = 0; _tmp <= _tmp2; ++_tmp) {
cpu->mwrite(cpu, cpu->i + _tmp, cpu->v[_tmp]);
}
cpu->i += _tmp2 + 1;
goto out;
case 0x65: /* LD Vx, [I] */
_tmp2 = (inst >> 8) & 0xF;
for(_tmp = 0; _tmp <= _tmp2; ++_tmp) {
cpu->v[_tmp] = cpu->mread(cpu, cpu->i + _tmp);
}
cpu->i += _tmp2 + 1;
goto out;
default:
/* XXXX */
goto out;
}
}
out:
;
+124 -24
View File
@@ -1,7 +1,8 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2014, 2015, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -43,8 +44,8 @@
#include "colecovision.h"
#include "colecomem.h"
#include "sn76489.h"
#include "smsvdp.h"
#include "smsz80.h"
#include "tms9918a.h"
#include "sms.h"
#include "rom.h"
@@ -65,25 +66,30 @@ static uint32 cart_len = 0;
static uint8 cont_mode = 0;
static uint32 rom_crc, rom_adler;
static uint32 megacart_page = 0;
static uint32 megacart_pages = 0;
extern sn76489_t psg;
uint16 coleco_cont_bits[2];
uint8 coleco_port_read(uint16 port) {
uint8 tmp;
switch(port & 0xE0) {
case 0xA0:
if(port & 0x01)
return sms_vdp_status_read();
return tms9918a_vdp_status_read();
else
return sms_vdp_data_read();
return tms9918a_vdp_data_read();
case 0xE0:
if(cont_mode == 0) {
return ~((uint8)(coleco_cont_bits[port & 0x01] & 0xFF));
}
else {
return ~((uint8)(coleco_cont_bits[port & 0x01] >> 8));
}
if(cont_mode == 0)
tmp = ~((uint8)(coleco_cont_bits[(port & 0x02) >> 1] & 0xFF));
else
tmp = ~((uint8)(coleco_cont_bits[(port & 0x02) >> 1] >> 8));
return tmp & 0x7f;
default:
return 0xFF;
@@ -94,10 +100,9 @@ void coleco_port_write(uint16 port, uint8 data) {
switch(port & 0xE0) {
case 0xA0:
if(port & 0x01)
sms_vdp_ctl_write(data);
tms9918a_vdp_ctl_write(data);
else
sms_vdp_data_write(data);
tms9918a_vdp_data_write(data);
break;
case 0x80:
@@ -115,10 +120,36 @@ void coleco_port_write(uint16 port, uint8 data) {
}
uint8 coleco_mem_read(uint16 addr) {
if(megacart_pages && addr >= 0xFFC0) {
int i;
megacart_page = (addr & (megacart_pages - 1));
/* Fix the paging... */
for(i = 0; i < 0x40; ++i) {
read_map[i + 0xC0] = cart_rom + (megacart_page << 14) + (i << 8);
}
sms_z80_set_readmap(read_map);
}
return read_map[addr >> 8][addr & 0xFF];
}
void coleco_mem_write(uint16 addr, uint8 data) {
if(megacart_pages && addr >= 0xFFC0) {
int i;
megacart_page = (addr & (megacart_pages - 1));
/* Fix the paging... */
for(i = 0; i < 0x40; ++i) {
read_map[i + 0xC0] = cart_rom + (megacart_page << 14) + (i << 8);
}
sms_z80_set_readmap(read_map);
}
write_map[addr >> 8][addr & 0xFF] = data;
}
@@ -126,6 +157,20 @@ uint16 coleco_mem_read16(uint16 addr) {
uint16 rv = (uint16)read_map[addr >> 8][addr & 0xFF];
++addr;
/* Nobody'd be stupid enough to do this, would they?... */
if(megacart_pages && addr >= 0xFFC0) {
int i;
megacart_page = (addr & (megacart_pages - 1));
/* Fix the paging... */
for(i = 0; i < 0x40; ++i) {
read_map[i + 0xC0] = cart_rom + (megacart_page << 14) + (i << 8);
}
sms_z80_set_readmap(read_map);
}
rv |= ((uint16)read_map[addr >> 8][addr & 0xFF]) << 8;
return rv;
}
@@ -133,6 +178,22 @@ uint16 coleco_mem_read16(uint16 addr) {
void coleco_mem_write16(uint16 addr, uint16 data) {
write_map[addr >> 8][addr & 0xFF] = (uint8)data;
++addr;
/* Hopefully if nobody's stupid enough to trigger the one above, there
really won't be anyone triggering THIS one... */
if(megacart_pages && addr >= 0xFFC0) {
int i;
megacart_page = (addr & (megacart_pages - 1));
/* Fix the paging... */
for(i = 0; i < 0x40; ++i) {
read_map[i + 0xC0] = cart_rom + (megacart_page << 14) + (i << 8);
}
sms_z80_set_readmap(read_map);
}
write_map[addr >> 8][addr & 0xFF] = (uint8)(data >> 8);
}
@@ -167,13 +228,38 @@ static void finalize_load(const char *fn) {
}
/* ROM */
for(i = 0; i < 0x80; ++i) {
write_map[i + 0x80] = dummy_areaw;
if(cart_len > 0x8000) {
/* We have a MegaCart... */
megacart_page = 0;
megacart_pages = cart_len >> 14;
if(i < (cart_len >> 8))
read_map[i + 0x80] = cart_rom + (i << 8);
else
read_map[i + 0x80] = dummy_arear;
#ifdef DEBUG
printf("coleco_mem_load_rom: Detected MegaCart\n"
" %" PRIu32 " bytes long = %" PRIu32 " pages\n",
cart_len, megacart_pages);
#endif
/* Always map 0x8000-0xBFFF to the top 16k of the cart... The page
selected for 0xC000-0xFFFF starts out as page 0. */
for(i = 0; i < 0x40; ++i) {
write_map[i + 0x80] = dummy_areaw;
write_map[i + 0xC0] = dummy_areaw;
read_map[i + 0x80] = cart_rom + (cart_len - 0x4000) + (i << 8);
read_map[i + 0xC0] = cart_rom + (i << 8);
}
}
else {
megacart_pages = megacart_page = 0;
for(i = 0; i < 0x80; ++i) {
write_map[i + 0x80] = dummy_areaw;
if(i < (cart_len >> 8))
read_map[i + 0x80] = cart_rom + (i << 8);
else
read_map[i + 0x80] = dummy_arear;
}
}
sms_z80_set_readmap(read_map);
@@ -254,7 +340,7 @@ static int load_gz_rom(const char *fn) {
len = gzread(fp, cart_rom, 0x100);
while(len != 0 && len != -1) {
cart_len += len;
cart_len += 0x100;
tmp = realloc(cart_rom, cart_len + 0x100);
if(!tmp) {
@@ -306,7 +392,7 @@ static int load_bz2_rom(const char *fn) {
len = BZ2_bzread(fp, cart_rom, 0x100);
while(len != 0 && len != -1) {
cart_len += len;
cart_len += 0x100;
tmp = realloc(cart_rom, cart_len + 0x100);
if(!tmp) {
@@ -434,7 +520,7 @@ static int load_zip_rom(const char *fn) {
unzCloseCurrentFile(fp);
unzClose(fp);
cart_len = size;
cart_len = realsize;
finalize_load(fn);
return ROM_LOAD_SUCCESS;
@@ -493,7 +579,7 @@ int coleco_mem_load_rom(const char *fn) {
fread(cart_rom, size, 1, fp);
fclose(fp);
cart_len = size;
cart_len = realsize;
finalize_load(fn);
return ROM_LOAD_SUCCESS;
@@ -543,6 +629,18 @@ int coleco_regs_read_context(const uint8 *buf) {
/* Copy in the registers */
cont_mode = buf[16];
if(megacart_pages) {
int i;
megacart_page = buf[17];
/* Fix the paging... */
for(i = 0; i < 0x40; ++i) {
read_map[i + 0xC0] = cart_rom + (megacart_page << 14) + (i << 8);
sms_z80_set_readmap(read_map);
}
}
return 0;
}
@@ -586,7 +684,8 @@ int coleco_mem_write_context(FILE *fp) {
fwrite(data, 1, 4, fp); /* Child pointer */
data[0] = cont_mode;
data[1] = data[2] = data[3] = 0;
data[1] = megacart_page;
data[2] = data[3] = 0;
fwrite(data, 1, 4, fp);
return 0;
@@ -656,6 +755,7 @@ int coleco_mem_init(void) {
memset(bios_rom, 0, 8192);
bios_loaded = 0;
megacart_page = megacart_pages = 0;
coleco_cont_bits[0] = 0;
coleco_cont_bits[1] = 0;
+324 -39
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -36,6 +36,7 @@
#include "colecomem.h"
#include "sms.h"
#include "smsvdp.h"
#include "tms9918a.h"
#include "sn76489.h"
#include "smsz80.h"
#include "sound.h"
@@ -45,13 +46,10 @@
extern int sms_psg_enabled;
extern sn76489_t psg;
extern uint32 psg_samples[313];
extern int sms_console;
extern int sms_region;
extern int sms_cycles_run;
extern int sms_cycles_to_run;
int coleco_initialized = 0;
extern uint16 coleco_cont_bits[2];
static const float NTSC_Z80_CLOCK = 3579545.0f;
@@ -69,6 +67,58 @@ static const int cont_bit_map[12] = {
0x02, 0x08, 0x03, 0x0D, 0x0C, 0x01, 0x0A, 0x0E, 0x04, 0x06, 0x05, 0x09
};
static int cycles_run, cycles_to_run, scanline;
#ifndef _arch_dreamcast
static void coleco_frame(int);
static void coleco_scanline(void);
static void coleco_single_step(void);
static void coleco_finish_frame(void);
static void coleco_finish_scanline(void);
#endif
static int coleco_current_scanline(void);
static int coleco_cycles_left(void);
/* Console declaration... */
colecovision_t colecovision_cons = {
{
CONSOLE_COLECOVISION,
CONSOLE_COLECOVISION,
0,
&coleco_shutdown,
&coleco_reset,
&coleco_soft_reset,
#ifndef _arch_dreamcast
&coleco_frame,
#else
NULL,
#endif
&coleco_load_state,
&coleco_save_state,
NULL, /* save_sram */
&coleco_button_pressed,
&coleco_button_released,
&sms_vdp_framebuffer,
&sms_vdp_framesize,
&tms9918a_vdp_activeframe,
NULL, /* save_cheats */
#ifndef _arch_dreamcast
&coleco_scanline,
&coleco_single_step,
&coleco_finish_frame,
&coleco_finish_scanline,
#else
NULL,
NULL,
NULL,
NULL,
#endif
&coleco_current_scanline,
&coleco_cycles_left,
NULL /* set_control */
}
};
int coleco_init(int video_system) {
int i;
float tmp;
@@ -98,7 +148,7 @@ int coleco_init(int video_system) {
for(i = 0; i < PAL_LINES_PER_FRAME; ++i) {
psg_samples[i] = (uint32) (tmp * (i + 1)) -
(uint32) (tmp * i);
(uint32) (tmp * i);
}
/* We need 882 samples per frame @ 44100 Hz, 50fps. */
@@ -109,33 +159,34 @@ int coleco_init(int video_system) {
}
sms_region = region;
sms_console = CONSOLE_COLECOVISION;
gui_set_console((console_t *)&colecovision_cons);
coleco_mem_init();
sms_vdp_init(video_system);
sms_vdp_init(video_system, 0);
sms_z80_init();
sound_init(2, video_system);
sms_z80_set_pread(&coleco_port_read);
sms_z80_set_pwrite(&coleco_port_write);
cycles_run = cycles_to_run = scanline = 0;
colecovision_cons._base.initialized = 1;
coleco_initialized = 1;
return 0;
}
int coleco_reset(void) {
if(coleco_initialized == 0)
if(!colecovision_cons._base.initialized)
return 0;
if(sms_region & SMS_VIDEO_NTSC) {
if(sms_region & SMS_VIDEO_NTSC)
sn76489_reset(&psg, NTSC_Z80_CLOCK, 44100.0f,
SN76489_NOISE_BITS_NORMAL, SN76489_NOISE_TAPPED_NORMAL);
}
else {
else
sn76489_reset(&psg, PAL_Z80_CLOCK, 44100.0f,
SN76489_NOISE_BITS_NORMAL, SN76489_NOISE_TAPPED_NORMAL);
}
sound_reset_buffer();
@@ -144,18 +195,22 @@ int coleco_reset(void) {
sms_z80_reset();
sms_vdp_reset();
cycles_run = cycles_to_run = scanline = 0;
return 0;
}
void coleco_soft_reset(void) {
if(coleco_initialized == 0)
return;
int coleco_soft_reset(void) {
if(!colecovision_cons._base.initialized)
return 0;
coleco_mem_reset();
sms_z80_reset();
sms_vdp_reset();
cycles_run = cycles_to_run = scanline = 0;
return 0;
}
int coleco_shutdown(void) {
@@ -166,7 +221,7 @@ int coleco_shutdown(void) {
sound_shutdown();
/* Reset a few things in case we reinit later. */
coleco_initialized = 0;
colecovision_cons._base.initialized = 0;
return 0;
}
@@ -253,12 +308,18 @@ void coleco_button_released(int player, int button) {
}
#ifndef _arch_dreamcast
int coleco_frame(int run, int skip) {
int16 buf[882 << 1];
int line, total_lines, samples = 0;
static __INLINE__ int update_sound(int16 buf[], int start, int line) {
if(sms_psg_enabled)
sn76489_execute_samples(&psg, buf + start, psg_samples[line]);
else
memset(buf + start, 0, psg_samples[line] << 2);
sms_cycles_run = run;
sms_cycles_to_run = 0;
return start + (psg_samples[line] << 1);
}
static void coleco_frame(int skip) {
int16 buf[882 << 1];
int samples = 0, total_lines, line;
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
@@ -266,29 +327,151 @@ int coleco_frame(int run, int skip) {
total_lines = PAL_LINES_PER_FRAME;
for(line = 0; line < total_lines; ++line) {
sms_cycles_to_run += SMS_CYCLES_PER_LINE;
cycles_to_run += SMS_CYCLES_PER_LINE;
sms_cycles_run += tms9918a_vdp_execute(line, &sms_z80_nmi, skip);
sms_cycles_run += sms_z80_run(sms_cycles_to_run - sms_cycles_run);
cycles_run += tms9918a_vdp_execute(line, &sms_z80_nmi, skip);
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
if(sms_psg_enabled) {
sn76489_execute_samples(&psg, buf + samples, psg_samples[line]);
}
else {
memset(buf + samples, 0, psg_samples[line] << 2);
}
samples += psg_samples[line] << 1;
samples = update_sound(buf, samples, line);
}
#ifndef TIMING_TEST
sound_update_buffer(buf, samples << 1);
#endif
return sms_cycles_run - sms_cycles_to_run;
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
static void coleco_scanline(void) {
int16 buf[882 << 1];
int total_lines, samples = 0;
cycles_to_run += SMS_CYCLES_PER_LINE;
/* Run the VDP and Z80 for the whole line. */
cycles_run += sms_vdp_execute(scanline, 0);
cycles_run += tms9918a_vdp_execute(scanline, &sms_z80_nmi, 0);
samples = update_sound(buf, 0, scanline);
sound_update_buffer(buf, samples << 1);
/* See if we hit the end of a frame by running this scanline. */
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
if(++scanline == total_lines) {
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
static void coleco_single_step(void) {
int16 buf[882 << 1];
int total_lines, run;
/* If we're at the start of a frame, set things up for the first line. Also,
if we finished a line last time (or are starting a new frame), run the
VDP for the line. */
if(!cycles_to_run || cycles_run >= cycles_to_run) {
cycles_to_run += SMS_CYCLES_PER_LINE;
if((run = tms9918a_vdp_execute(scanline, &sms_z80_nmi, 0))) {
cycles_run += run;
return;
}
}
/* Run our one instruction. */
cycles_run += sms_z80_run(1);
/* Did we finish a line? */
if(cycles_run >= cycles_to_run) {
run = update_sound(buf, 0, scanline);
sound_update_buffer(buf, run << 1);
/* Was it the last line in the frame? */
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
if(++scanline == total_lines) {
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
}
static void coleco_finish_frame(void) {
int16 buf[882 << 1];
int samples = 0, total_lines, line;
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
for(line = scanline; line < total_lines; ++line) {
cycles_to_run += SMS_CYCLES_PER_LINE;
cycles_run += tms9918a_vdp_execute(scanline, &sms_z80_nmi, 0);
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
samples = update_sound(buf, samples, line);
}
sound_update_buffer(buf, samples << 1);
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
static void coleco_finish_scanline(void) {
int16 buf[882 << 1];
int total_lines, samples = 0;
/* Make sure we have something to do. */
if(cycles_run >= cycles_to_run)
return;
/* Run the Z80 for the rest of the line. The VDP should've already been
run. */
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
samples = update_sound(buf, 0, scanline);
sound_update_buffer(buf, samples << 1);
/* See if we hit the end of a frame by finishing this line. */
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
if(++scanline == total_lines) {
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
#endif
static int coleco_current_scanline(void) {
return scanline;
}
static int coleco_cycles_left(void) {
return cycles_to_run - cycles_run;
}
#ifdef _arch_dreamcast
static int coleco_save_state_int(const char *filename)
#else
@@ -298,7 +481,7 @@ int coleco_save_state(const char *filename)
FILE *fp;
uint8 data[4];
if(!coleco_initialized)
if(!colecovision_cons._base.initialized)
/* This shouldn't happen.... */
return -1;
@@ -641,7 +824,7 @@ int coleco_load_state(const char *filename)
char byte;
int rv;
if(!coleco_initialized) {
if(!colecovision_cons._base.initialized) {
/* This shouldn't happen.... */
return -1;
}
@@ -738,3 +921,105 @@ int coleco_load_state(const char *filename __UNUSED__) {
return rv;
}
#endif
int coleco_write_state(FILE *fp)
{
uint8 data[4];
if(!colecovision_cons._base.initialized)
/* This shouldn't happen.... */
return -1;
if(!fp)
return -1;
fprintf(fp, "CrabEmu Save State");
/* Write save state version */
data[0] = 0x00;
data[1] = 0x02;
fwrite(data, 1, 2, fp);
/* Write out the Console Metadata block */
data[0] = 'C';
data[1] = 'O';
data[2] = 'N';
data[3] = 'S';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(24, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
fwrite(data, 1, 2, fp); /* Flags (Importance = 1) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
UINT32_TO_BUF(1, data);
fwrite(data, 1, 4, fp); /* Console (1 = ColecoVision) */
data[0] = 0; /* Console sub-type */
data[1] = 0; /* Region code */
data[2] = sms_region >> 4; /* Video system */
data[3] = 0; /* Reserved */
fwrite(data, 1, 4, fp);
/* Write each block's state */
if(coleco_game_write_context(fp)) {
return -1;
}
else if(sms_z80_write_context(fp)) {
return -1;
}
else if(sms_psg_write_context(fp)) {
return -1;
}
else if(sms_vdp_write_context(fp)) {
return -1;
}
else if(coleco_mem_write_context(fp)) {
return -1;
}
return 0;
}
int coleco_read_state(FILE *fp)
{
char str[19];
char byte;
int rv;
if(!colecovision_cons._base.initialized) {
/* This shouldn't happen.... */
return -1;
}
if(!fp)
return -1;
fread(str, 18, 1, fp);
str[18] = 0;
if(strcmp("CrabEmu Save State", str)) {
return -2;
}
/* Read save state version */
fread(&byte, 1, 1, fp);
if(byte != 0x00) {
return -2;
}
fread(&byte, 1, 1, fp);
if(byte != 0x02) {
return -2;
}
rv = coleco_load_state_v2(fp);
sound_reset_buffer();
return rv;
}
+13 -6
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012 Lawrence Sebald
Copyright (C) 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -21,11 +21,10 @@
#define COLECOVISION_H
#include "CrabEmu.h"
#include "console.h"
CLINKAGE
#define CONSOLE_COLECOVISION 5
/* Button defines */
#define COLECOVISION_UP 0
#define COLECOVISION_DOWN 1
@@ -48,17 +47,25 @@ CLINKAGE
extern int coleco_init(int video_system);
extern int coleco_reset(void);
extern void coleco_soft_reset(void);
extern int coleco_soft_reset(void);
extern int coleco_shutdown(void);
extern int coleco_frame(int run, int skip);
extern void coleco_button_pressed(int player, int button);
extern void coleco_button_released(int player, int button);
extern int coleco_save_state(const char *fn);
extern int coleco_load_state(const char *fn);
extern int coleco_write_state(FILE *fp);
extern int coleco_read_state(FILE *fp);
/* Console definition. */
typedef struct crabemu_colecovision {
console_t _base;
} colecovision_t;
extern colecovision_t colecovision_cons;
ENDCLINK
#endif /* !COLECOVISION_H */
+10 -7
View File
@@ -32,8 +32,6 @@ static int chr_is_rom;
static int prg_banks;
static int chr_size;
#include <stdio.h>
static void fill_prg_map(void) {
int i, page;
@@ -44,14 +42,18 @@ static void fill_prg_map(void) {
/* Which page should be swapped? */
if(bank_regs[0] & 0x04) {
for(i = 0; i < 0x40; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i + page) << 8);
nes_read_map[i + 0xC0] = nes_prg_rom + ((i + 0x3C0) << 8);
nes_read_map[i + 0x80] = nes_prg_rom +
(((i + page) << 8) & (nes_prg_rom_size - 1));
nes_read_map[i + 0xC0] = nes_prg_rom +
(((i + 0x3C0) << 8) & (nes_prg_rom_size - 1));
}
}
else {
for(i = 0; i < 0x40; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + (i << 8);
nes_read_map[i + 0xC0] = nes_prg_rom + ((i + page) << 8);
nes_read_map[i + 0x80] = nes_prg_rom +
((i << 8) & (nes_prg_rom_size - 1));
nes_read_map[i + 0xC0] = nes_prg_rom +
(((i + page) << 8) & (nes_prg_rom_size - 1));
}
}
}
@@ -59,7 +61,8 @@ static void fill_prg_map(void) {
page = (bank_regs[3] & 0x0E) << 6;
for(i = 0; i < 0x80; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i + page) << 8);
nes_read_map[i + 0x80] = nes_prg_rom +
(((i + page) << 8) & (nes_prg_rom_size - 1));
}
}
+189
View File
@@ -0,0 +1,189 @@
/*
This file is part of CrabEmu.
Copyright (C) 2013 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nesmem.h"
#include "nesppu.h"
/* iNES Mapper 2: UxROM */
static uint8 bank_reg = 0;
static int prg_banks;
static void fill_prg_map(void) {
int i, page = bank_reg << 6;
for(i = 0; i < 0x40; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i + page) << 8);
}
nes_mem_update_map();
}
static void init(void) {
int is_rom = 1, i, b;
prg_banks = nes_prg_rom_size >> 8;
b = prg_banks - 0x40;
bank_reg = 0;
/* Fill in the read map */
for(i = 0; i < 0x40; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + (i << 8);
nes_read_map[i + 0xC0] = nes_prg_rom + ((i + b) << 8);
}
for(i = 0; i < 0x20; ++i) {
nes_read_map[i + 0x60] = nes_sram + (i << 8);
nes_write_map[i + 0x60] = nes_sram + (i << 8);
}
/* Set up the PPU */
if(!nes_chr_rom_size)
is_rom = 0;
nes_ppu_set_patterntbl(0, nes_chr_rom, is_rom);
nes_ppu_set_patterntbl(1, nes_chr_rom + 0x1000, is_rom);
if(nes_cur_hdr.flags[0] & 0x08)
nes_ppu_set_tblmirrors(0, 1, 2, 3);
else if(nes_cur_hdr.flags[0] & 0x01)
nes_ppu_set_tblmirrors(0, 1, 0, 1);
else
nes_ppu_set_tblmirrors(0, 0, 1, 1);
nes_mem_update_map();
}
static void reset(void) {
bank_reg = 0;
fill_prg_map();
}
static uint8 read_byte(void *cpu __UNUSED__, uint16 addr) {
switch(addr >> 12) {
case 2:
case 3:
return nes_ppu_readreg(addr & 0x0007);
case 4:
if(addr < 0x4020)
return nes_mem_readreg(addr);
break;
}
return nes_read_map[addr >> 8][(uint8)addr];
}
static void write_byte(void *cpu __UNUSED__, uint16 addr, uint8 val) {
/* Is the write bound anywhere interesting? */
switch(addr >> 12) {
case 2:
case 3:
nes_ppu_writereg(addr & 0x0007, val);
break;
case 4:
if(addr < 0x4020)
nes_mem_writereg(addr, val);
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
bank_reg = val;
fill_prg_map();
break;
}
nes_write_map[addr >> 8][(uint8)addr] = val;
}
static int write_cxt(FILE *fp) {
uint8 data[4];
data[0] = 'M';
data[1] = 'P';
data[2] = 'P';
data[3] = 'R';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(20, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
UINT16_TO_BUF(0, data);
fwrite(data, 1, 2, fp); /* Flags (Importance = 0) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
data[0] = bank_reg;
data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp);
return 0;
}
static int read_cxt(const uint8 *buf) {
uint16 ver;
uint32 len;
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len != 20)
return -1;
/* Check the version number */
BUF_TO_UINT16(buf + 8, ver);
if(ver != 1)
return -1;
/* Check the child pointer */
if(buf[12] != 0 || buf[13] != 0 || buf[14] != 0 || buf[15] != 0)
return -1;
/* Read in the registers */
bank_reg = buf[16];
fill_prg_map();
return 0;
}
static uint32 cxt_len(void) {
return 20;
}
/* Mapper definition. */
nes_mapper_t nes_mapper_2 = {
2,
&init,
&reset,
&read_byte,
&write_byte,
&write_cxt,
&read_cxt,
&cxt_len
};
+180
View File
@@ -0,0 +1,180 @@
/*
This file is part of CrabEmu.
Copyright (C) 2013 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nesmem.h"
#include "nesppu.h"
/* iNES Mapper 3: CNROM */
static uint8 bank_reg = 0;
static int chr_banks;
static void fill_chr_map(void) {
int b = bank_reg << 13;
nes_ppu_set_patterntbl(0, nes_chr_rom + b, 1);
nes_ppu_set_patterntbl(1, nes_chr_rom + b + 0x1000, 1);
}
static void init(void) {
int i, banks = nes_prg_rom_size >> 8;
chr_banks = nes_chr_rom_size >> 8;
bank_reg = 0;
/* Fill in the read map */
for(i = 0; i < 0x80; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i & (banks - 1)) << 8);
}
for(i = 0; i < 0x20; ++i) {
nes_read_map[i + 0x60] = nes_sram + (i << 8);
nes_write_map[i + 0x60] = nes_sram + (i << 8);
}
/* Set up the PPU */
nes_ppu_set_patterntbl(0, nes_chr_rom, 1);
nes_ppu_set_patterntbl(1, nes_chr_rom + 0x1000, 1);
if(nes_cur_hdr.flags[0] & 0x08)
nes_ppu_set_tblmirrors(0, 1, 2, 3);
else if(nes_cur_hdr.flags[0] & 0x01)
nes_ppu_set_tblmirrors(0, 1, 0, 1);
else
nes_ppu_set_tblmirrors(0, 0, 1, 1);
nes_mem_update_map();
}
static void reset(void) {
bank_reg = 0;
fill_chr_map();
}
static uint8 read_byte(void *cpu __UNUSED__, uint16 addr) {
switch(addr >> 12) {
case 2:
case 3:
return nes_ppu_readreg(addr & 0x0007);
case 4:
if(addr < 0x4020)
return nes_mem_readreg(addr);
break;
}
return nes_read_map[addr >> 8][(uint8)addr];
}
static void write_byte(void *cpu __UNUSED__, uint16 addr, uint8 val) {
/* Is the write bound anywhere interesting? */
switch(addr >> 12) {
case 2:
case 3:
nes_ppu_writereg(addr & 0x0007, val);
break;
case 4:
if(addr < 0x4020)
nes_mem_writereg(addr, val);
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
bank_reg = val & 0x03;
fill_chr_map();
break;
}
nes_write_map[addr >> 8][(uint8)addr] = val;
}
static int write_cxt(FILE *fp) {
uint8 data[4];
data[0] = 'M';
data[1] = 'P';
data[2] = 'P';
data[3] = 'R';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(20, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
UINT16_TO_BUF(0, data);
fwrite(data, 1, 2, fp); /* Flags (Importance = 0) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
data[0] = bank_reg;
data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp);
return 0;
}
static int read_cxt(const uint8 *buf) {
uint16 ver;
uint32 len;
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len != 20)
return -1;
/* Check the version number */
BUF_TO_UINT16(buf + 8, ver);
if(ver != 1)
return -1;
/* Check the child pointer */
if(buf[12] != 0 || buf[13] != 0 || buf[14] != 0 || buf[15] != 0)
return -1;
/* Read in the registers */
bank_reg = buf[16] & 0x03;
fill_chr_map();
return 0;
}
static uint32 cxt_len(void) {
return 20;
}
/* Mapper definition. */
nes_mapper_t nes_mapper_3 = {
3,
&init,
&reset,
&read_byte,
&write_byte,
&write_cxt,
&read_cxt,
&cxt_len
};
+193
View File
@@ -0,0 +1,193 @@
/*
This file is part of CrabEmu.
Copyright (C) 2013 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nesmem.h"
#include "nesppu.h"
/* iNES Mapper 66: GxROM */
static uint8 bank_reg = 0, chr_is_rom;
static int prg_banks;
static void fill_map(void) {
int i, page = (bank_reg & 0x30) << 3, cpage = (bank_reg & 0x03) << 13;
/* Deal with PRG first. */
for(i = 0; i < 0x80; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i + page) << 8);
}
/* Now deal with CHR. */
nes_ppu_set_patterntbl(0, nes_chr_rom + cpage, chr_is_rom);
nes_ppu_set_patterntbl(1, nes_chr_rom + cpage + 0x1000, chr_is_rom);
nes_mem_update_map();
}
static void init(void) {
int i;
prg_banks = nes_prg_rom_size >> 8;
bank_reg = 0;
chr_is_rom = 1;
/* Fill in the read map */
for(i = 0; i < 0x80; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i & (prg_banks - 1)) << 8);
}
for(i = 0; i < 0x20; ++i) {
nes_read_map[i + 0x60] = nes_sram + (i << 8);
nes_write_map[i + 0x60] = nes_sram + (i << 8);
}
/* Set up the PPU */
if(!nes_chr_rom_size)
chr_is_rom = 0;
nes_ppu_set_patterntbl(0, nes_chr_rom, chr_is_rom);
nes_ppu_set_patterntbl(1, nes_chr_rom + 0x1000, chr_is_rom);
if(nes_cur_hdr.flags[0] & 0x08)
nes_ppu_set_tblmirrors(0, 1, 2, 3);
else if(nes_cur_hdr.flags[0] & 0x01)
nes_ppu_set_tblmirrors(0, 1, 0, 1);
else
nes_ppu_set_tblmirrors(0, 0, 1, 1);
nes_mem_update_map();
}
static void reset(void) {
bank_reg = 0;
fill_map();
}
static uint8 read_byte(void *cpu __UNUSED__, uint16 addr) {
switch(addr >> 12) {
case 2:
case 3:
return nes_ppu_readreg(addr & 0x0007);
case 4:
if(addr < 0x4020)
return nes_mem_readreg(addr);
break;
}
return nes_read_map[addr >> 8][(uint8)addr];
}
static void write_byte(void *cpu __UNUSED__, uint16 addr, uint8 val) {
/* Is the write bound anywhere interesting? */
switch(addr >> 12) {
case 2:
case 3:
nes_ppu_writereg(addr & 0x0007, val);
break;
case 4:
if(addr < 0x4020)
nes_mem_writereg(addr, val);
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
bank_reg = val;
fill_map();
break;
}
nes_write_map[addr >> 8][(uint8)addr] = val;
}
static int write_cxt(FILE *fp) {
uint8 data[4];
data[0] = 'M';
data[1] = 'P';
data[2] = 'P';
data[3] = 'R';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(20, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
UINT16_TO_BUF(0, data);
fwrite(data, 1, 2, fp); /* Flags (Importance = 0) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
data[0] = bank_reg;
data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp);
return 0;
}
static int read_cxt(const uint8 *buf) {
uint16 ver;
uint32 len;
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len != 20)
return -1;
/* Check the version number */
BUF_TO_UINT16(buf + 8, ver);
if(ver != 1)
return -1;
/* Check the child pointer */
if(buf[12] != 0 || buf[13] != 0 || buf[14] != 0 || buf[15] != 0)
return -1;
/* Read in the registers */
bank_reg = buf[16];
fill_map();
return 0;
}
static uint32 cxt_len(void) {
return 20;
}
/* Mapper definition. */
nes_mapper_t nes_mapper_66 = {
66,
&init,
&reset,
&read_byte,
&write_byte,
&write_cxt,
&read_cxt,
&cxt_len
};
+186
View File
@@ -0,0 +1,186 @@
/*
This file is part of CrabEmu.
Copyright (C) 2013 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nesmem.h"
#include "nesppu.h"
/* iNES Mapper 7: AxROM */
static uint8 bank_reg = 0;
static int prg_banks;
static void fill_map(void) {
int i, page = (bank_reg & 0x07) << 7;
for(i = 0; i < 0x80; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i + page) << 8);
}
nes_mem_update_map();
if(bank_reg & 0x10)
nes_ppu_set_tblmirrors(1, 1, 1, 1);
else
nes_ppu_set_tblmirrors(0, 0, 0, 0);
}
static void init(void) {
int is_rom = 1, i;
prg_banks = nes_prg_rom_size >> 8;
bank_reg = 0;
/* Fill in the read map */
for(i = 0; i < 0x80; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i & (prg_banks - 1)) << 8);
}
for(i = 0; i < 0x20; ++i) {
nes_read_map[i + 0x60] = nes_sram + (i << 8);
nes_write_map[i + 0x60] = nes_sram + (i << 8);
}
/* Set up the PPU */
if(!nes_chr_rom_size)
is_rom = 0;
nes_ppu_set_patterntbl(0, nes_chr_rom, is_rom);
nes_ppu_set_patterntbl(1, nes_chr_rom + 0x1000, is_rom);
nes_ppu_set_tblmirrors(0, 0, 0, 0);
nes_mem_update_map();
}
static void reset(void) {
bank_reg = 0;
fill_map();
}
static uint8 read_byte(void *cpu __UNUSED__, uint16 addr) {
switch(addr >> 12) {
case 2:
case 3:
return nes_ppu_readreg(addr & 0x0007);
case 4:
if(addr < 0x4020)
return nes_mem_readreg(addr);
break;
}
return nes_read_map[addr >> 8][(uint8)addr];
}
static void write_byte(void *cpu __UNUSED__, uint16 addr, uint8 val) {
/* Is the write bound anywhere interesting? */
switch(addr >> 12) {
case 2:
case 3:
nes_ppu_writereg(addr & 0x0007, val);
break;
case 4:
if(addr < 0x4020)
nes_mem_writereg(addr, val);
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
bank_reg = val;
fill_map();
break;
}
nes_write_map[addr >> 8][(uint8)addr] = val;
}
static int write_cxt(FILE *fp) {
uint8 data[4];
data[0] = 'M';
data[1] = 'P';
data[2] = 'P';
data[3] = 'R';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(20, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
UINT16_TO_BUF(0, data);
fwrite(data, 1, 2, fp); /* Flags (Importance = 0) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
data[0] = bank_reg;
data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp);
return 0;
}
static int read_cxt(const uint8 *buf) {
uint16 ver;
uint32 len;
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len != 20)
return -1;
/* Check the version number */
BUF_TO_UINT16(buf + 8, ver);
if(ver != 1)
return -1;
/* Check the child pointer */
if(buf[12] != 0 || buf[13] != 0 || buf[14] != 0 || buf[15] != 0)
return -1;
/* Read in the registers */
bank_reg = buf[16];
fill_map();
return 0;
}
static uint32 cxt_len(void) {
return 20;
}
/* Mapper definition. */
nes_mapper_t nes_mapper_7 = {
7,
&init,
&reset,
&read_byte,
&write_byte,
&write_cxt,
&read_cxt,
&cxt_len
};
+244
View File
@@ -0,0 +1,244 @@
/*
This file is part of CrabEmu.
Copyright (C) 2013 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nesmem.h"
#include "nesppu.h"
/* iNES Mapper 9: MMC2/PxROM */
static uint8 prg_bank = 0;
static uint8 chr_bank[4] = { 0, 0, 0, 0 };
static int latches[2] = { 0, 0 }, mirror = 0;
static int prg_banks, chr_size;
static void fill_prg_map(void) {
int i, page = (prg_bank & 0x0F) << 5;
for(i = 0; i < 0x20; ++i) {
nes_read_map[i + 0x80] = nes_prg_rom + ((i + page) << 8);
}
nes_mem_update_map();
}
static void fill_chr_map(void) {
int page;
if(latches[0])
page = (chr_bank[1] << 12) & (chr_size - 1);
else
page = (chr_bank[0] << 12) & (chr_size - 1);
nes_ppu_set_patterntbl(0, nes_chr_rom + page, 1);
if(latches[1])
page = (chr_bank[3] << 12) & (chr_size - 1);
else
page = (chr_bank[2] << 12) & (chr_size - 1);
nes_ppu_set_patterntbl(1, nes_chr_rom + page, 1);
}
static void ppu_cb(uint16 pn) {
/* Set/clear the appropriate latch */
if((pn & 0x00FF) == 0xFD)
latches[(pn >> 8) & 1] = 0;
else
latches[(pn >> 8) & 1] = 1;
fill_chr_map();
}
static void init(void) {
int i, j;
prg_banks = j = nes_prg_rom_size >> 8;
chr_size = nes_chr_rom_size;
prg_bank = 0;
chr_bank[0] = chr_bank[1] = chr_bank[2] = chr_bank[3] = 0;
latches[0] = latches[1] = mirror = 0;
/* Fill in the read map */
for(i = 0xFF; i > 0x9F; --i) {
nes_read_map[i] = nes_prg_rom + (--j << 8);
}
for(i = 0; i < 0x20; ++i) {
nes_read_map[i + 0x60] = nes_sram + (i << 8);
nes_write_map[i + 0x60] = nes_sram + (i << 8);
}
fill_prg_map();
/* Set up the PPU */
nes_ppu_set_patterntbl(0, nes_chr_rom, 1);
nes_ppu_set_patterntbl(1, nes_chr_rom, 1);
nes_ppu_set_tblmirrors(0, 1, 0, 1);
nes_ppu_set_mmc2(&ppu_cb);
}
static void reset(void) {
/* Reset all the registers and the CPU's mapping */
prg_bank = 0;
chr_bank[0] = chr_bank[1] = chr_bank[2] = chr_bank[3] = 0;
latches[0] = latches[1] = mirror = 0;
fill_prg_map();
/* Reset the PPU */
nes_ppu_set_patterntbl(0, nes_chr_rom, 1);
nes_ppu_set_patterntbl(1, nes_chr_rom, 1);
nes_ppu_set_tblmirrors(0, 1, 0, 1);
nes_ppu_set_mmc2(&ppu_cb);
}
static uint8 read_byte(void *cpu __UNUSED__, uint16 addr) {
switch(addr >> 12) {
case 2:
case 3:
return nes_ppu_readreg(addr & 0x0007);
case 4:
if(addr < 0x4020)
return nes_mem_readreg(addr);
break;
}
return nes_read_map[addr >> 8][(uint8)addr];
}
static void write_byte(void *cpu __UNUSED__, uint16 addr, uint8 val) {
/* Is the write bound anywhere interesting? */
switch(addr >> 12) {
case 2:
case 3:
nes_ppu_writereg(addr & 0x0007, val);
break;
case 4:
if(addr < 0x4020)
nes_mem_writereg(addr, val);
break;
case 10:
prg_bank = val;
fill_prg_map();
break;
case 11:
case 12:
case 13:
case 14:
chr_bank[(addr >> 12) - 11] = val;
fill_chr_map();
break;
case 15:
if((mirror = val & 0x01))
nes_ppu_set_tblmirrors(0, 0, 1, 1);
else
nes_ppu_set_tblmirrors(0, 1, 0, 1);
}
nes_write_map[addr >> 8][(uint8)addr] = val;
}
static int write_cxt(FILE *fp) {
uint8 data[4];
data[0] = 'M';
data[1] = 'P';
data[2] = 'P';
data[3] = 'R';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(24, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
UINT16_TO_BUF(0, data);
fwrite(data, 1, 2, fp); /* Flags (Importance = 0) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
data[0] = prg_bank;
data[1] = (latches[0]) | (latches[1] << 1) | (mirror << 2);
data[2] = data[3] = 0;
fwrite(data, 1, 4, fp);
fwrite(chr_bank, 1, 4, fp);
return 0;
}
static int read_cxt(const uint8 *buf) {
uint16 ver;
uint32 len;
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len != 24)
return -1;
/* Check the version number */
BUF_TO_UINT16(buf + 8, ver);
if(ver != 1)
return -1;
/* Check the child pointer */
if(buf[12] != 0 || buf[13] != 0 || buf[14] != 0 || buf[15] != 0)
return -1;
/* Read in the registers */
prg_bank = buf[16];
latches[0] = buf[17] & 0x01;
latches[1] = (buf[17] & 0x02) >> 1;
mirror = (buf[17] & 0x04) >> 2;
chr_bank[0] = buf[20];
chr_bank[1] = buf[21];
chr_bank[2] = buf[22];
chr_bank[3] = buf[23];
fill_prg_map();
fill_chr_map();
if(mirror)
nes_ppu_set_tblmirrors(0, 0, 1, 1);
else
nes_ppu_set_tblmirrors(0, 1, 0, 1);
nes_ppu_set_mmc2(&ppu_cb);
return 0;
}
static uint32 cxt_len(void) {
return 24;
}
/* Mapper definition. */
nes_mapper_t nes_mapper_9 = {
9,
&init,
&reset,
&read_byte,
&write_byte,
&write_cxt,
&read_cxt,
&cxt_len
};
+255 -27
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012, 2013 Lawrence Sebald
Copyright (C) 2012, 2013, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -50,35 +50,68 @@ static const float PAL_FPS = 53.355f;
/* From nesmem.c */
extern uint16 nes_pad;
/* XXXX */
extern int sms_console;
int nes_initialized = 0;
Crab6502_t nescpu;
static int cycles_run, cycles_to_run;
static int cycles_run, cycles_to_run, scanline;
static void nes_scanline(void);
static void nes_single_step(void);
static void nes_finish_frame(void);
static void nes_finish_scanline(void);
static int nes_current_scanline(void);
static int nes_cycles_left(void);
/* Console declaration... */
nes_t nes_cons = {
{
CONSOLE_NES,
CONSOLE_NES,
0,
&nes_shutdown,
&nes_reset,
&nes_soft_reset,
&nes_frame,
&nes_load_state,
&nes_save_state,
&nes_mem_write_sram,
&nes_button_pressed,
&nes_button_released,
&nes_ppu_framebuffer,
&nes_ppu_framesize,
&nes_ppu_activeframe,
NULL,
&nes_scanline,
&nes_single_step,
&nes_finish_frame,
&nes_finish_scanline,
&nes_current_scanline,
&nes_cycles_left,
NULL
}
};
int nes_init(int video_system) {
(void)video_system;
if(nes_initialized)
if(nes_cons._base.initialized)
return -1;
sms_console = CONSOLE_NES;
gui_set_console((console_t *)&nes_cons);
Crab6502_init(&nescpu);
nes_mem_init();
nes_ppu_init();
nes_apu_init();
nes_initialized = 1;
sound_init(1, video_system);
cycles_run = cycles_to_run = scanline = 0;
nes_cons._base.initialized = 1;
return 0;
}
int nes_reset(void) {
if(!nes_initialized)
if(!nes_cons._base.initialized)
return -1;
sound_reset_buffer();
@@ -90,12 +123,14 @@ int nes_reset(void) {
nes_ppu_reset();
nes_apu_reset();
cycles_run = cycles_to_run = scanline = 0;
return 0;
}
void nes_soft_reset(void) {
if(!nes_initialized)
return;
int nes_soft_reset(void) {
if(!nes_cons._base.initialized)
return 0;
sound_reset_buffer();
@@ -103,10 +138,14 @@ void nes_soft_reset(void) {
Crab6502_reset(&nescpu);
nes_ppu_reset();
nes_apu_reset();
cycles_run = cycles_to_run = scanline = 0;
return 0;
}
int nes_shutdown(void) {
if(!nes_initialized)
if(!nes_cons._base.initialized)
return -1;
nes_ppu_shutdown();
@@ -114,16 +153,14 @@ int nes_shutdown(void) {
nes_apu_shutdown();
sound_shutdown();
nes_initialized = 0;
nes_cons._base.initialized = 0;
return 0;
}
int nes_frame(int run, int skip) {
void nes_frame(int skip) {
int i;
cycles_run = run;
cycles_to_run = 113;
/* Lines 0-239 */
for(i = 0; i < 240; ++i) {
cycles_to_run += 113;
@@ -157,7 +194,199 @@ int nes_frame(int run, int skip) {
nes_apu_execute(cycles_run);
return cycles_run - cycles_to_run;
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
static void nes_scanline(void) {
cycles_to_run += 113;
if(scanline < 240) {
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
nes_ppu_execute(scanline, 0);
}
else if(scanline == 240) {
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
}
else if(scanline == 241) {
nes_ppu_vblank_in();
if(cycles_to_run == cycles_run)
cycles_run += Crab6502_execute(&nescpu, 1);
if(nes_ppu_vblnmi_enabled())
Crab6502_pulse_nmi(&nescpu);
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
}
else if(scanline < 261) {
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
}
else if(scanline == 262) {
nes_ppu_vblank_out();
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
nes_apu_execute(cycles_run);
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
++scanline;
}
static void nes_finish_frame(void) {
int i = scanline;
if(scanline < 240)
goto line_0;
else if(scanline == 240)
goto line_240;
else if(scanline == 241)
goto line_241;
else if(scanline >= 242 && scanline < 261)
goto line_242;
else if(scanline == 261)
goto line_261;
line_0:
/* Lines 0-239 */
for(; i < 240; ++i) {
cycles_to_run += 113;
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
nes_ppu_execute(i, 0);
}
line_240:
/* Line 240 */
cycles_to_run += 113;
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
line_241:
/* Line 241 */
nes_ppu_vblank_in();
if(cycles_to_run == cycles_run)
cycles_run += Crab6502_execute(&nescpu, 1);
if(nes_ppu_vblnmi_enabled())
Crab6502_pulse_nmi(&nescpu);
cycles_to_run += 113;
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
line_242:
/* Lines 242-260 */
for(i = 242; i < 261; ++i) {
cycles_to_run += 113;
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
}
line_261:
/* Line 261 (aka, line -1) */
nes_ppu_vblank_out();
cycles_to_run += 113;
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
nes_apu_execute(cycles_run);
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
static void nes_single_step(void) {
/* If we're at the start of a frame, set things up for the first line. */
if(!cycles_to_run)
cycles_to_run += 113;
/* Run the one instruction we need to run. */
cycles_run += Crab6502_execute(&nescpu, 1);
/* See if we finished a scanline... */
if(cycles_run >= cycles_to_run) {
/* Which scanline did we just finish? */
if(scanline < 240) {
nes_ppu_execute(scanline, 0);
++scanline;
cycles_to_run += 113;
}
else if(scanline == 240) {
++scanline;
cycles_to_run += 113;
nes_ppu_vblank_in();
if(nes_ppu_vblnmi_enabled())
Crab6502_pulse_nmi(&nescpu);
}
else if(scanline < 260) {
++scanline;
cycles_to_run += 113;
}
else if(scanline == 260) {
++scanline;
cycles_to_run += 113;
nes_ppu_vblank_out();
}
else {
nes_apu_execute(cycles_run);
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
}
static void nes_finish_scanline(void) {
/* Make sure we have something to do... */
if(cycles_run >= cycles_to_run)
return;
/* Run instructions to the end of the line. */
cycles_run += Crab6502_execute(&nescpu, cycles_to_run - cycles_run);
/* We should have finished a scanline, so do whatever we need to for that
particular line. */
if(cycles_run >= cycles_to_run) {
/* Which scanline did we just finish? */
if(scanline < 240) {
nes_ppu_execute(scanline, 0);
++scanline;
cycles_to_run += 113;
}
else if(scanline == 240) {
++scanline;
cycles_to_run += 113;
nes_ppu_vblank_in();
if(nes_ppu_vblnmi_enabled())
Crab6502_pulse_nmi(&nescpu);
}
else if(scanline < 260) {
++scanline;
cycles_to_run += 113;
}
else if(scanline == 260) {
++scanline;
cycles_to_run += 113;
nes_ppu_vblank_out();
}
else {
nes_apu_execute(cycles_run);
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
}
static int nes_current_scanline(void) {
return scanline;
}
static int nes_cycles_left(void) {
return cycles_to_run - cycles_run;
}
int nes_cycles_elapsed(void) {
@@ -301,8 +530,8 @@ int nes_save_state(const char *filename)
FILE *fp;
uint8 data[4];
if(nes_initialized == 0)
/* This shouldn't happen.... */
if(!nes_cons._base.initialized)
/* This shouldn't happen.... */
return -1;
fp = fopen(filename, "wb");
@@ -408,10 +637,9 @@ int nes_load_state(const char *filename)
uint8 *ptr;
size_t read;
if(!nes_initialized) {
if(!nes_cons._base.initialized)
/* This shouldn't happen.... */
return -1;
}
fp = fopen(filename, "rb");
if(!fp)
+11 -5
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012, 2013 Lawrence Sebald
Copyright (C) 2012, 2013, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -21,16 +21,15 @@
#define NES_H
#include "CrabEmu.h"
#include "console.h"
CLINKAGE
#define CONSOLE_NES 6
extern int nes_init(int video_system);
extern int nes_reset(void);
extern void nes_soft_reset(void);
extern int nes_soft_reset(void);
extern int nes_shutdown(void);
extern int nes_frame(int run, int skip);
extern void nes_frame(int skip);
extern int nes_cycles_elapsed(void);
extern void nes_assert_irq(void);
@@ -56,6 +55,13 @@ extern void nes_button_released(int player, int button);
extern int nes_save_state(const char *filename);
extern int nes_load_state(const char *filename);
/* Console definition. */
typedef struct crabemu_nes {
console_t _base;
} nes_t;
extern nes_t nes_cons;
ENDCLINK
#endif /* !NES_H */
+4 -3
View File
@@ -77,11 +77,12 @@ static uint8 *rom_data = NULL;
extern Crab6502_t nescpu;
/* Various mappers */
extern nes_mapper_t nes_mapper_0;
extern nes_mapper_t nes_mapper_1;
extern nes_mapper_t nes_mapper_0, nes_mapper_1, nes_mapper_2, nes_mapper_3;
extern nes_mapper_t nes_mapper_7, nes_mapper_9, nes_mapper_66;
static nes_mapper_t *mappers[] = {
&nes_mapper_0, &nes_mapper_1,
&nes_mapper_0, &nes_mapper_1, &nes_mapper_2, &nes_mapper_3, &nes_mapper_7,
&nes_mapper_9, &nes_mapper_66,
NULL
};
+88 -16
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012, 2013 Lawrence Sebald
Copyright (C) 2012, 2013, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -50,6 +50,7 @@ static int ppu_patterns_rom = 0;
static nes_ppu_pattern_t ppu_patterns[512];
static pixel_t *ppu_framebuffer;
static void (*mmc2_cb)(uint16 pn);
struct ppu_spr {
int pattern;
@@ -147,6 +148,17 @@ void *nes_ppu_framebuffer(void) {
return ppu_framebuffer;
}
void nes_ppu_framesize(uint32_t *x, uint32_t *y) {
*x = 256;
*y = 256;
}
void nes_ppu_activeframe(uint32_t *x, uint32_t *y, uint32_t *w, uint32_t *h) {
*x = *y = 0;
*w = 256;
*h = 240;
}
void nes_ppu_writereg(int reg, uint8 val) {
uint16 addr;
@@ -255,7 +267,7 @@ void nes_ppu_writereg(int reg, uint8 val) {
uint8 nes_ppu_readreg(int reg) {
uint8 rv = ppu_regs[reg & 0x07];
uint16 addr;
uint16 addr, addr2;
switch(reg & 0x07) {
case 2:
@@ -267,7 +279,7 @@ uint8 nes_ppu_readreg(int reg) {
case 7:
/* Grab the address and update what we're looking at for next time
we try to read/write. */
addr = ppu_v & 0x3FFF;
addr = addr2 = ppu_v & 0x3FFF;
ppu_v += (ppu_regs[0] & 0x04) ? 32 : 1;
/* See where we're reading... */
@@ -282,18 +294,26 @@ uint8 nes_ppu_readreg(int reg) {
if(ppu_regs[1] & 0x01)
rv &= 0x30;
/* Mask the address for filling the buffer below. */
/* Mask the address and fill the buffer. */
addr &= 0x2FFF;
ppu_buffer = ppu_map[(addr >> 8)][(uint8)addr];
}
else {
/* Make sure we handle any sort of mirroring caused by accessing
0x3000-0x3EFF. */
if(addr >= 0x3000)
addr &= 0x2FFF;
rv = ppu_buffer;
}
addr2 &= 0x2FFF;
ppu_buffer = ppu_map[(addr >> 8)][(uint8)addr];
rv = ppu_buffer;
ppu_buffer = ppu_map[(addr2 >> 8)][(uint8)addr2];
/* Grumble... grumble... Stupid MMC2... */
if(mmc2_cb) {
if((addr >= 0x0FD0 && addr < 0x0FF0) ||
(addr >= 0x1FD0 && addr < 0x1FF0))
mmc2_cb(addr >> 4);
}
}
break;
}
@@ -400,7 +420,7 @@ static void ppu_calc_spr(void) {
pal = (attr & 0x03) << 2;
tex = 0;
bg = 0;
if(attr & 0x80)
tex = 2;
if(attr & 0x40)
@@ -515,6 +535,12 @@ static void ppu_bg_draw(int line __UNUSED__, uint8 *px,
RENDER_BG_PIXEL();
RENDER_BG_PIXEL();
/* If we've got an MMC2 or an MMC4 and we need to set the latches, do
so now. */
if(mmc2_cb &&
(pn == 0x0FD || pn == 0x0FE || pn == 0x1FD || pn == 0x1FE))
mmc2_cb(pn);
/* We're done with this tile, move onto the next one */
if(xc != 31) {
++nt;
@@ -596,6 +622,12 @@ static void ppu_bg_skip(int line, uint8 bg_pixels[256 + 16]) {
SKIP_BG_PIXEL();
SKIP_BG_PIXEL();
/* If we've got an MMC2 or an MMC4 and we need to set the latches, do
so now. */
if(mmc2_cb &&
(pn == 0x0FD || pn == 0x0FE || pn == 0x1FD || pn == 0x1FE))
mmc2_cb(pn);
/* We're done with this tile, move onto the next one */
if(xc != 31) {
++nt;
@@ -662,7 +694,7 @@ static void ppu_bg_skip(int line, uint8 bg_pixels[256 + 16]) {
static void ppu_spr_draw(int line, uint8 *px, uint8 bg_pixels[256 + 16]) {
static uint8 col_tab[256 + 16];
int i = 0, x, pal;
int i = 0, x, pal, pn;
nes_ppu_pattern_t *pat;
uint8 *pixels;
uint8 pixel;
@@ -674,11 +706,12 @@ static void ppu_spr_draw(int line, uint8 *px, uint8 bg_pixels[256 + 16]) {
in how we deal with it. */
if(sprs[line][0].spr_num == 0) {
i = 1;
pat = ppu_patterns + sprs[line][0].pattern;
pn = sprs[line][0].pattern;
pat = ppu_patterns + pn;
/* Update the cache if the pattern is marked as dirty */
if(pat->dirty)
nes_ppu_update_cache(sprs[line][0].pattern);
nes_ppu_update_cache(pn);
pixels = &pat->texture[sprs[line][0].tex][sprs[line][0].y << 3];
x = sprs[line][0].x + 8;
@@ -704,15 +737,22 @@ static void ppu_spr_draw(int line, uint8 *px, uint8 bg_pixels[256 + 16]) {
RENDER_SPR_PIXEL_FG_SPR0();
RENDER_SPR_PIXEL_FG_SPR0();
}
/* If we've got an MMC2 or an MMC4 and we need to set the latches, do
so now. */
if(mmc2_cb &&
(pn == 0x0FD || pn == 0x0FE || pn == 0x1FD || pn == 0x1FE))
mmc2_cb(pn);
}
/* Go through all the sprites on this line. */
for(; i < 8 && sprs[line][i].spr_num != 0xFF; ++i) {
pat = ppu_patterns + sprs[line][i].pattern;
pn = sprs[line][i].pattern;
pat = ppu_patterns + pn;
/* Update the cache if the pattern is marked as dirty */
if(pat->dirty)
nes_ppu_update_cache(sprs[line][i].pattern);
nes_ppu_update_cache(pn);
pixels = &pat->texture[sprs[line][i].tex][sprs[line][i].y << 3];
x = sprs[line][i].x + 8;
@@ -738,6 +778,12 @@ static void ppu_spr_draw(int line, uint8 *px, uint8 bg_pixels[256 + 16]) {
RENDER_SPR_PIXEL_FG();
RENDER_SPR_PIXEL_FG();
}
/* If we've got an MMC2 or an MMC4 and we need to set the latches, do
so now. */
if(mmc2_cb &&
(pn == 0x0FD || pn == 0x0FE || pn == 0x1FD || pn == 0x1FE))
mmc2_cb(pn);
}
/* Set the sprite overflow bit, if appropriate. */
@@ -755,15 +801,18 @@ static void ppu_spr_skip(int line, uint8 bg_pixels[256 + 16]) {
int x;
nes_ppu_pattern_t *pat;
uint8 *pixels;
int pn, i = 0;
/* See if sprite 0 is on this line, since its really the only sprite we care
about for now... */
if(sprs[line][0].spr_num == 0) {
pat = ppu_patterns + sprs[line][0].pattern;
i = 1;
pn = sprs[line][0].pattern;
pat = ppu_patterns + pn;
/* Update the cache if the pattern is marked as dirty */
if(pat->dirty)
nes_ppu_update_cache(sprs[line][0].pattern);
nes_ppu_update_cache(pn);
pixels = &pat->texture[sprs[line][0].tex][sprs[line][0].y << 3];
x = sprs[line][0].x + 8;
@@ -776,6 +825,23 @@ static void ppu_spr_skip(int line, uint8 bg_pixels[256 + 16]) {
SKIP_SPR_PIXEL_SPR0();
SKIP_SPR_PIXEL_SPR0();
SKIP_SPR_PIXEL_SPR0();
/* If we've got an MMC2 or an MMC4 and we need to set the latches, do
so now. */
if(mmc2_cb &&
(pn == 0x0FD || pn == 0x0FE || pn == 0x1FD || pn == 0x1FE))
mmc2_cb(pn);
}
/* We only have to look at the other sprites if we've got either an MMC2 or
an MMC4... */
if(mmc2_cb) {
for(; i < 8 && sprs[line][i].spr_num != 0xFF; ++i) {
pn = sprs[line][i].pattern;
if(pn == 0x0FD || pn == 0x0FE || pn == 0x1FD || pn == 0x1FE)
mmc2_cb(pn);
}
}
/* Set the sprite overflow bit, if appropriate. */
@@ -910,6 +976,7 @@ int nes_ppu_init(void) {
ppu_x = 0;
ppu_oam_addr = 0;
ppu_patterns_rom = 0;
mmc2_cb = NULL;
for(i = 0; i < 256; ++i) {
ppu_lut[i] = (i & 0x01) | ((i & 0x02) << 1) | ((i & 0x04) << 2) |
@@ -956,6 +1023,7 @@ int nes_ppu_reset(void) {
ppu_x = 0;
ppu_oam_addr = 0;
ppu_patterns_rom = 0;
mmc2_cb = NULL;
memset(ppu_framebuffer, 0, 256 * 256 * sizeof(pixel_t));
gui_set_aspect(16.0f, 15.0f);
@@ -963,6 +1031,10 @@ int nes_ppu_reset(void) {
return 0;
}
void nes_ppu_set_mmc2(void (*cb)(uint16 pn)) {
mmc2_cb = cb;
}
int nes_ppu_shutdown(void) {
#ifdef _arch_dreamcast
/* Put the framebuffer back into P1. */
+6 -1
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012, 2013 Lawrence Sebald
Copyright (C) 2012, 2013, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -37,7 +37,11 @@ extern void nes_ppu_update_cache(int pat);
extern const nes_ppu_pattern_t *nes_ppu_fetch_pattern(int pat);
extern void nes_ppu_fetch_bg_pal(uint8 pal[16]);
extern void nes_ppu_fetch_spr_pal(uint8 pal[16]);
extern void *nes_ppu_framebuffer(void);
extern void nes_ppu_framesize(uint32_t *x, uint32_t *y);
extern void nes_ppu_activeframe(uint32_t *x, uint32_t *y, uint32_t *w,
uint32_t *h);
extern void nes_ppu_writereg(int reg, uint8 value);
extern uint8 nes_ppu_readreg(int reg);
@@ -52,6 +56,7 @@ extern void nes_ppu_set_tblmirrors(int n1, int n2, int n3, int n4);
extern void nes_ppu_set_patterntbl(int tbl, uint8 *ptr, int rom);
extern void nes_ppu_execute(int line, int skip);
extern void nes_ppu_set_mmc2(void (*cb)(uint16 pn));
extern int nes_ppu_init(void);
extern int nes_ppu_reset(void);
+75 -55
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2009, 2012 Lawrence Sebald
Copyright (C) 2009, 2012, 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -22,66 +22,55 @@
#include <ctype.h>
#include "cheats.h"
#include "list.h"
#include "smsmem.h"
cc_dlist_t *sms_active_cheats = NULL;
int sms_cheats_enabled = 0;
static int sms_cheats_initted = 0;
static int count = 0;
TAILQ_HEAD(cheat_queue, smscheat_s) sms_cheats;
extern uint8 *sms_write_map[256];
extern int sms_bios_active;
int sms_cheat_init(void) {
if(sms_active_cheats)
if(sms_cheats_initted)
return 0;
sms_active_cheats = cc_dlist_create();
if(sms_active_cheats)
return 0;
return -1;
TAILQ_INIT(&sms_cheats);
sms_cheats_initted = 1;
return 0;
}
void sms_cheat_shutdown(void) {
cc_dlist_node_t *i;
if(!sms_active_cheats)
return;
CC_DLIST_FOREACH(sms_active_cheats, i) {
free(i->data);
}
cc_dlist_destroy(sms_active_cheats);
sms_cheats_enabled = 0;
sms_active_cheats = NULL;
sms_cheat_reset();
sms_cheats_initted = 0;
}
void sms_cheat_reset(void) {
cc_dlist_node_t *i;
sms_cheat_t *i, *next;
if(!sms_active_cheats)
if(!sms_cheats_initted)
return;
sms_cheats_enabled = 0;
while((i = sms_active_cheats->head)) {
free(i->data);
cc_dlist_remove(sms_active_cheats, i);
i = TAILQ_FIRST(&sms_cheats);
while(i) {
next = TAILQ_NEXT(i, qentry);
TAILQ_REMOVE(&sms_cheats, i, qentry);
free(i);
i = next;
}
sms_cheats_enabled = 0;
count = 0;
}
void sms_cheat_frame(void) {
cc_dlist_node_t *i;
sms_cheat_t *c;
sms_cheat_t *i;
uint16 addr;
uint8 data;
if(!sms_active_cheats)
return;
if(!sms_cheats_enabled)
return;
@@ -91,12 +80,10 @@ void sms_cheat_frame(void) {
if(sms_bios_active)
return;
CC_DLIST_FOREACH(sms_active_cheats, i) {
c = (sms_cheat_t *)i->data;
if(c->enabled) {
addr = (uint16)(c->ar_code >> 8);
data = (uint8)c->ar_code;
TAILQ_FOREACH(i, &sms_cheats, qentry) {
if(i->enabled){
addr = (uint16)(i->ar_code >> 8);
data = (uint8)i->ar_code;
sms_write_map[addr >> 8][(uint8)addr] = data;
}
@@ -104,10 +91,42 @@ void sms_cheat_frame(void) {
}
int sms_cheat_add(sms_cheat_t *c) {
return cc_dlist_insert_tail(sms_active_cheats, c);
TAILQ_INSERT_TAIL(&sms_cheats, c, qentry);
++count;
return 0;
}
void sms_cheat_read(const char *fn) {
int sms_cheat_remove(int index) {
sms_cheat_t *i;
TAILQ_FOREACH(i, &sms_cheats, qentry) {
if(!index--) {
TAILQ_REMOVE(&sms_cheats, i, qentry);
free(i);
--count;
return 0;
}
}
return -1;
}
int sms_cheat_count(void) {
return count;
}
sms_cheat_t *sms_cheat_get(int index) {
sms_cheat_t *i;
TAILQ_FOREACH(i, &sms_cheats, qentry) {
if(!index--)
return i;
}
return NULL;
}
int sms_cheat_read(const char *fn) {
FILE *fp;
char linebuf[256], str[64];
size_t len;
@@ -116,7 +135,7 @@ void sms_cheat_read(const char *fn) {
fp = fopen(fn, "r");
if(!fp)
return;
return -1;
while(fgets(linebuf, 256, fp)) {
/* Ignore shell-style comments. */
@@ -153,30 +172,31 @@ void sms_cheat_read(const char *fn) {
}
fclose(fp);
return 0;
}
void sms_cheat_write(const char *fn) {
int sms_cheat_write(const char *fn) {
FILE *fp;
sms_cheat_t *c;
cc_dlist_node_t *i;
sms_cheat_t *i;
if(!sms_active_cheats || !sms_active_cheats->count)
return;
if(!sms_cheats_initted || TAILQ_EMPTY(&sms_cheats))
return 0;
fp = fopen(fn, "w");
if(!fp)
return;
return -1;
fprintf(fp, "# Cheats file generated by CrabEmu\n");
CC_DLIST_FOREACH(sms_active_cheats, i) {
c = (sms_cheat_t *)i->data;
fprintf(fp, "%04X-%04X %s", (uint16)(c->ar_code >> 16),
(uint16)c->ar_code, c->desc);
TAILQ_FOREACH(i, &sms_cheats, qentry) {
fprintf(fp, "%04X-%04X %s\n", (uint16)(i->ar_code >> 16),
(uint16)i->ar_code, i->desc);
}
fclose(fp);
return 0;
}
void sms_cheat_enable(void) {
+8 -3
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2009 Lawrence Sebald
Copyright (C) 2009, 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -21,10 +21,12 @@
#define CHEATS_H
#include "CrabEmu.h"
#include "queue.h"
CLINKAGE
typedef struct smscheat_s {
TAILQ_ENTRY(smscheat_s) qentry;
uint32 ar_code;
char desc[64];
int enabled;
@@ -37,8 +39,11 @@ extern void sms_cheat_reset(void);
extern void sms_cheat_frame(void);
extern int sms_cheat_add(sms_cheat_t *c);
extern void sms_cheat_read(const char *fn);
extern void sms_cheat_write(const char *fn);
extern int sms_cheat_remove(int index);
extern int sms_cheat_count(void);
extern sms_cheat_t *sms_cheat_get(int index);
extern int sms_cheat_read(const char *fn);
extern int sms_cheat_write(const char *fn);
extern void sms_cheat_enable(void);
extern void sms_cheat_disable(void);
+1 -1
View File
@@ -18,7 +18,7 @@
*/
#ifndef MAPPER_NONE_H
#define MAPEPR_NONE_H
#define MAPPER_NONE_H
#include "CrabEmu.h"
+1 -1
View File
@@ -18,7 +18,7 @@
*/
#ifndef MAPPER_SEGA_H
#define MAPEPR_SEGA_H
#define MAPPER_SEGA_H
#include "CrabEmu.h"
+4 -3
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2008, 2012 Lawrence Sebald
Copyright (C) 2008, 2012, 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -40,7 +40,7 @@ typedef struct srom_s {
uint32 mapper;
} special_rom_t;
static const int rom_count = 26;
static const int rom_count = 27;
static special_rom_t romlist[] = {
{ 0xBF3A0EDC, 0x092F29D6, SMS_MAPPER_CASTLE }, /* The Castle - SG-1000 */
{ 0x86429577, 0x4ED45BDA, SMS_MAPPER_93C46 }, /* Nomo's World Series Baseball */
@@ -68,6 +68,7 @@ static special_rom_t romlist[] = {
{ 0x9CABE756, 0xAAAC12CF, SMS_MAPPER_TW_MSX_TYPE_B }, /* Rally-X */
{ 0x7C5AC4A0, 0xD2EDD329, SMS_MAPPER_TW_MSX_TYPE_B }, /* Road Fighter */
{ 0x6E11F0D2, 0x72542786, SMS_MAPPER_NONE }, /* Monaco GP */
{ 0x1282E24F, 0x704F6A61, SMS_MAPPER_NONE }, /* Lander 2 (homebrew) */
};
uint32 sms_find_mapper(const uint8 *rom, uint32 len, uint32 *rcrc,
+3 -4
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2009 Lawrence Sebald
Copyright (C) 2009, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -29,7 +29,6 @@
#ifdef ENABLE_SDSC_TERMINAL
extern int sms_console;
extern uint8 *sms_read_map[256];
static char console[25][80 * 2];
@@ -128,10 +127,10 @@ static void sdsc_write_format_num(void) {
if(cur_data_param1 < 0x10) {
num = smsvdp.regs[cur_data_param1];
}
else if(sms_console == CONSOLE_SMS) {
else if(sms_cons._base.console_type == CONSOLE_SMS) {
num = smsvdp.cram[cur_data_param1 - 0x10];
}
else if(sms_console == CONSOLE_GG) {
else if(sms_cons._base.console_type == CONSOLE_GG) {
addr = (cur_data_param1 - 0x10) << 1;
num = smsvdp.cram[addr] | (smsvdp.cram[addr + 1] << 8);
bits = 16;
+514 -122
View File
@@ -1,20 +1,21 @@
/*
This file is part of CrabEmu.
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2014,
2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
You should have received a copy of the GNU General Public License
along with CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
@@ -42,16 +43,14 @@
#include "sound.h"
#include "cheats.h"
#include "sdscterminal.h"
#include "console.h"
uint16 sms_pad = 0xFFFF;
int sms_psg_enabled = 1;
int sms_ym2413_enabled = 1;
int sms_initialized = 0;
sn76489_t psg;
int sms_console = CONSOLE_SMS;
int sms_region = SMS_REGION_EXPORT;
int sms_cycles_run;
int sms_cycles_to_run;
YM2413 *sms_fm = NULL;
uint32 psg_samples[313];
@@ -68,8 +67,63 @@ static const float PAL_CLOCKS_PER_SAMPLE = 5.02677579365f;
extern uint8 sms_gg_regs[7];
extern int sms_bios_active;
extern int sms_control_type[2];
extern uint32 sms_gfxbd_data[2];
int sms_init(int video_system, int region) {
static int cycles_run, cycles_to_run, scanline;
#ifndef _arch_dreamcast
static void sms_frame(int);
static void sms_scanline(void);
static void sms_single_step(void);
static void sms_finish_frame(void);
static void sms_finish_scanline(void);
#endif
static int sms_current_scanline(void);
static int sms_cycles_left(void);
static void sms_set_control(int player, int control);
/* Console declaration... */
sms_t sms_cons = {
{
CONSOLE_SMS,
CONSOLE_SMS,
0,
&sms_shutdown,
&sms_reset,
&sms_soft_reset,
#ifndef _arch_dreamcast
&sms_frame,
#else
NULL,
#endif
&sms_load_state,
&sms_save_state,
&sms_write_cartram_to_file,
&sms_button_pressed,
&sms_button_released,
&sms_vdp_framebuffer,
&sms_vdp_framesize,
&sms_vdp_activeframe,
&sms_cheat_write,
#ifndef _arch_dreamcast
&sms_scanline,
&sms_single_step,
&sms_finish_frame,
&sms_finish_scanline,
#else
NULL,
NULL,
NULL,
NULL,
#endif
&sms_current_scanline,
&sms_cycles_left,
&sms_set_control
}
};
int sms_init(int video_system, int region, int borders) {
int i;
float tmp;
@@ -90,7 +144,7 @@ int sms_init(int video_system, int region) {
sn76489_init(&psg, NTSC_Z80_CLOCK, 44100.0f,
SN76489_NOISE_BITS_SMS, SN76489_NOISE_TAPPED_SMS);
YM2413Init(1, NTSC_Z80_CLOCK, 44100);
sms_fm = ym2413_init(NTSC_Z80_CLOCK, 44100);
}
else {
tmp = PAL_Z80_CLOCK / PSG_DIVISOR / PAL_FPS / PAL_LINES_PER_FRAME /
@@ -98,7 +152,7 @@ int sms_init(int video_system, int region) {
for(i = 0; i < PAL_LINES_PER_FRAME; ++i) {
psg_samples[i] = (uint32) (tmp * (i + 1)) -
(uint32) (tmp * i);
(uint32) (tmp * i);
}
/* We need 882 samples per frame @ 44100 Hz, 50fps. */
@@ -106,29 +160,32 @@ int sms_init(int video_system, int region) {
sn76489_init(&psg, PAL_Z80_CLOCK, 44100.0f,
SN76489_NOISE_BITS_SMS, SN76489_NOISE_TAPPED_SMS);
YM2413Init(1, PAL_Z80_CLOCK, 44100);
sms_fm = ym2413_init(PAL_Z80_CLOCK, 44100);
}
sms_region = region;
gui_set_console((console_t *)&sms_cons);
sms_cheat_init();
sms_mem_init();
sms_vdp_init(video_system);
sms_vdp_init(video_system, borders);
sms_z80_init();
sound_init(2, video_system);
sms_sdsc_reset();
YM2413ResetChip(0);
ym2413_reset(sms_fm);
cycles_run = cycles_to_run = scanline = 0;
sms_initialized = 1;
sms_cons._base.initialized = 1;
return 0;
}
int sms_reset() {
if(sms_initialized == 0)
int sms_reset(void) {
if(sms_cons._base.initialized == 0)
return 0;
if(sms_region & SMS_VIDEO_NTSC) {
@@ -140,7 +197,7 @@ int sms_reset() {
SN76489_NOISE_BITS_SMS, SN76489_NOISE_TAPPED_SMS);
}
YM2413ResetChip(0);
ym2413_reset(sms_fm);
sound_reset_buffer();
@@ -154,14 +211,16 @@ int sms_reset() {
sms_sdsc_reset();
cycles_run = cycles_to_run = scanline = 0;
return 0;
}
void sms_soft_reset() {
if(sms_initialized == 0)
return;
int sms_soft_reset(void) {
if(sms_cons._base.initialized == 0)
return 0;
YM2413ResetChip(0);
ym2413_reset(sms_fm);
sound_reset_buffer();
@@ -170,31 +229,56 @@ void sms_soft_reset() {
sms_vdp_reset();
sms_sdsc_reset();
cycles_run = cycles_to_run = scanline = 0;
return 0;
}
int sms_shutdown() {
int sms_shutdown(void) {
sms_cheat_shutdown();
sms_mem_shutdown();
sms_vdp_shutdown();
sms_z80_shutdown();
YM2413Shutdown();
ym2413_shutdown(sms_fm);
sound_shutdown();
/* Reset a few things in case we reinit later. */
sms_pad = 0xFFFF;
sms_initialized = 0;
sms_cons._base.initialized = 0;
sms_cons._base.console_type = CONSOLE_SMS;
return 0;
}
#ifndef _arch_dreamcast
int sms_frame(int run, int skip) {
int16 buf[882 << 1], fmbuf[882 << 1];
int line, total_lines, tmp, samples = 0;
static __INLINE__ int update_sound(int16 buf[], int start, int line) {
int16 fmbuf[16]; /* More than we'll need, but meh. */
int16 tmp;
uint32 i;
sms_cycles_run = run;
sms_cycles_to_run = 0;
if(sms_psg_enabled)
sn76489_execute_samples(&psg, buf + start, psg_samples[line]);
else
memset(buf + start, 0, psg_samples[line] << 2);
if(sms_ym2413_enabled) {
ym2413_update(sms_fm, fmbuf, psg_samples[line]);
/* Mix in the FM unit's samples */
for(i = 0; i < psg_samples[line]; ++i) {
tmp = (fmbuf[i << 1] + fmbuf[(i << 1) + 1]);
buf[(i << 1) + start] += tmp;
buf[(i << 1) + 1 + start] += tmp;
}
}
return start + (psg_samples[line] << 1);
}
static void sms_frame(int skip) {
int16 buf[882 << 1];
int samples = 0, total_lines, line;
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
@@ -202,40 +286,159 @@ int sms_frame(int run, int skip) {
total_lines = PAL_LINES_PER_FRAME;
for(line = 0; line < total_lines; ++line) {
sms_cycles_to_run += SMS_CYCLES_PER_LINE;
cycles_to_run += SMS_CYCLES_PER_LINE;
sms_cheat_frame();
sms_cycles_run += sms_vdp_execute(line, skip);
sms_cycles_run += sms_z80_run(sms_cycles_to_run - sms_cycles_run);
cycles_run += sms_vdp_execute(line, skip);
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
if(sms_psg_enabled) {
sn76489_execute_samples(&psg, buf + samples, psg_samples[line]);
}
else {
memset(buf + samples, 0, psg_samples[line] << 2);
}
if(sms_ym2413_enabled) {
YM2413UpdateOne(0, fmbuf, psg_samples[line]);
/* Mix in the FM unit's samples */
for(i = 0; i < psg_samples[line]; ++i) {
tmp = (fmbuf[i << 1] + fmbuf[(i << 1) + 1]) / 2;
buf[(i << 1) + samples] += tmp;
buf[(i << 1) + 1 + samples] += tmp;
}
}
samples += psg_samples[line] << 1;
samples = update_sound(buf, samples, line);
}
#ifndef TIMING_TEST
sound_update_buffer(buf, samples << 1);
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
static void sms_scanline(void) {
int16 buf[882 << 1];
int total_lines, samples = 0;
cycles_to_run += SMS_CYCLES_PER_LINE;
sms_cheat_frame();
/* Run the VDP and Z80 for the whole line. */
cycles_run += sms_vdp_execute(scanline, 0);
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
samples = update_sound(buf, 0, scanline);
sound_update_buffer(buf, samples << 1);
/* See if we hit the end of a frame by running this scanline. */
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
if(++scanline == total_lines) {
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
static void sms_single_step(void) {
int16 buf[882 << 1];
int total_lines, run;
/* If we're at the start of a frame, set things up for the first line. Also,
if we finished a line last time (or are starting a new frame), run the
VDP for the line. */
if(!cycles_to_run || cycles_run >= cycles_to_run) {
cycles_to_run += SMS_CYCLES_PER_LINE;
sms_cheat_frame();
if((run = sms_vdp_execute(scanline, 0))) {
cycles_run += run;
return;
}
}
/* Run our one instruction. */
cycles_run += sms_z80_run(1);
/* Did we finish a line? */
if(cycles_run >= cycles_to_run) {
run = update_sound(buf, 0, scanline);
sound_update_buffer(buf, run << 1);
/* Was it the last line in the frame? */
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
if(++scanline == total_lines) {
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
}
static void sms_finish_frame(void) {
int16 buf[882 << 1];
int samples = 0, total_lines, line;
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
for(line = scanline; line < total_lines; ++line) {
cycles_to_run += SMS_CYCLES_PER_LINE;
sms_cheat_frame();
cycles_run += sms_vdp_execute(line, 0);
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
samples = update_sound(buf, samples, line);
}
sound_update_buffer(buf, samples << 1);
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
static void sms_finish_scanline(void) {
int16 buf[882 << 1];
int total_lines, samples = 0;
/* Make sure we have something to do. */
if(cycles_run >= cycles_to_run)
return;
/* Run the Z80 for the rest of the line. The VDP should've already been
run. */
cycles_run += sms_z80_run(cycles_to_run - cycles_run);
samples = update_sound(buf, 0, scanline);
sound_update_buffer(buf, samples << 1);
/* See if we hit the end of a frame by finishing this line. */
if(sms_region & SMS_VIDEO_NTSC)
total_lines = NTSC_LINES_PER_FRAME;
else
total_lines = PAL_LINES_PER_FRAME;
if(++scanline == total_lines) {
/* Reset the state for the next frame. */
cycles_run -= cycles_to_run;
cycles_to_run = 0;
scanline = 0;
}
}
#endif
return sms_cycles_run - sms_cycles_to_run;
static void sms_set_control(int player, int control) {
/* Verify what we got from the ui... */
if(player < 0 || player > 1)
return;
if(control < SMS_PADTYPE_NONE || control > SMS_PADTYPE_GFX_BOARD)
return;
/* Set the control type. */
sms_control_type[player] = control;
}
#endif
void sms_button_pressed(int player, int button) {
uint16 mask = 0;
@@ -243,35 +446,57 @@ void sms_button_pressed(int player, int button) {
if(player < 1 || player > 2)
return;
if(button < SMS_UP || button > SMS_CONSOLE_RESET || button == SMS_QUIT)
return;
switch(button) {
case SMS_UP:
case SMS_DOWN:
case SMS_LEFT:
case SMS_RIGHT:
case SMS_BUTTON_1:
case SMS_BUTTON_2:
mask = (player == 1) ? (1 << button) : (1 << (button + 6));
break;
case SMS_CONSOLE_RESET:
mask = SMS_RESET;
break;
case GAMEGEAR_START:
if(sms_console == CONSOLE_GG) {
sms_gg_regs[0] &= 0x7F;
}
else if(sms_console == CONSOLE_SMS) {
sms_z80_nmi();
}
if(sms_control_type[player - 1] == SMS_PADTYPE_CONTROL_PAD) {
if(button < SMS_UP || button > SMS_CONSOLE_RESET || button == SMS_QUIT)
return;
}
/* Update the pad */
sms_pad &= ~mask;
switch(button) {
case SMS_UP:
case SMS_DOWN:
case SMS_LEFT:
case SMS_RIGHT:
case SMS_BUTTON_1:
case SMS_BUTTON_2:
mask = (player == 1) ? (1 << button) : (1 << (button + 6));
break;
case SMS_CONSOLE_RESET:
mask = SMS_RESET;
break;
case GAMEGEAR_START:
if(sms_cons._base.console_type == CONSOLE_GG) {
sms_gg_regs[0] &= 0x7F;
}
else if(sms_cons._base.console_type == CONSOLE_SMS) {
sms_z80_nmi();
}
return;
}
/* Update the pad */
sms_pad &= ~mask;
}
else if(sms_control_type[player - 1] == SMS_PADTYPE_GFX_BOARD) {
switch(button) {
case SMS_GFXBD_1:
case SMS_GFXBD_2:
case SMS_GFXBD_3:
sms_gfxbd_data[player - 1] &= ~(1 << button);
break;
case SMS_CONSOLE_RESET:
sms_pad &= ~SMS_RESET;
break;
case GAMEGEAR_START:
if(sms_cons._base.console_type == CONSOLE_GG)
sms_gg_regs[0] &= 0x7F;
else if(sms_cons._base.console_type == CONSOLE_SMS)
sms_z80_nmi();
break;
}
}
}
void sms_button_released(int player, int button) {
@@ -280,32 +505,52 @@ void sms_button_released(int player, int button) {
if(player < 1 || player > 2)
return;
if(button < SMS_UP || button > SMS_CONSOLE_RESET || button == SMS_QUIT)
return;
switch(button) {
case SMS_UP:
case SMS_DOWN:
case SMS_LEFT:
case SMS_RIGHT:
case SMS_BUTTON_1:
case SMS_BUTTON_2:
mask = (player == 1) ? (1 << button) : (1 << (button + 6));
break;
case SMS_CONSOLE_RESET:
mask = SMS_RESET;
break;
case GAMEGEAR_START:
if(sms_console == CONSOLE_GG) {
sms_gg_regs[0] |= 0x80;
}
if(sms_control_type[player - 1] == SMS_PADTYPE_CONTROL_PAD) {
if(button < SMS_UP || button > SMS_CONSOLE_RESET || button == SMS_QUIT)
return;
}
/* Update the pad */
sms_pad |= mask;
switch(button) {
case SMS_UP:
case SMS_DOWN:
case SMS_LEFT:
case SMS_RIGHT:
case SMS_BUTTON_1:
case SMS_BUTTON_2:
mask = (player == 1) ? (1 << button) : (1 << (button + 6));
break;
case SMS_CONSOLE_RESET:
mask = SMS_RESET;
break;
case GAMEGEAR_START:
if(sms_cons._base.console_type == CONSOLE_GG) {
sms_gg_regs[0] |= 0x80;
}
return;
}
/* Update the pad */
sms_pad |= mask;
}
else if(sms_control_type[player - 1] == SMS_PADTYPE_GFX_BOARD) {
switch(button) {
case SMS_GFXBD_1:
case SMS_GFXBD_2:
case SMS_GFXBD_3:
sms_gfxbd_data[player - 1] |= (1 << button);
break;
case SMS_CONSOLE_RESET:
sms_pad |= SMS_RESET;
break;
case GAMEGEAR_START:
if(sms_cons._base.console_type == CONSOLE_GG)
sms_gg_regs[0] |= 0x80;
break;
}
}
}
void sms_set_console(int console) {
@@ -342,7 +587,19 @@ void sms_set_console(int console) {
return;
}
sms_console = console;
sms_cons._base.console_type = console;
}
static int sms_current_scanline(void) {
return scanline;
}
static int sms_cycles_left(void) {
return cycles_to_run - cycles_run;
}
int sms_cycles_elapsed(void) {
return cycles_run + sms_z80_get_cycles();
}
static void sms_psg_read_context_v1(FILE *fp) {
@@ -476,7 +733,7 @@ int sms_save_state(const char *filename)
FILE *fp;
uint8 data[4];
if(sms_initialized == 0)
if(sms_cons._base.initialized == 0)
/* This shouldn't happen.... */
return -1;
@@ -513,10 +770,10 @@ int sms_save_state(const char *filename)
fwrite(data, 1, 4, fp); /* Child pointer */
fwrite(data, 1, 4, fp); /* Console (0 = SMS) */
data[0] = sms_console; /* Console sub-type */
data[1] = sms_region & 0x0F; /* Region code */
data[2] = sms_region >> 4; /* Video system */
data[3] = 0; /* Reserved */
data[0] = sms_cons._base.console_type; /* Console sub-type */
data[1] = sms_region & 0x0F; /* Region code */
data[2] = sms_region >> 4; /* Video system */
data[3] = 0; /* Reserved */
fwrite(data, 1, 4, fp);
/* Write each block's state */
@@ -548,7 +805,7 @@ int sms_save_state(const char *filename)
fclose(fp);
return 0;
}
#ifdef _arch_dreamcast
int sms_save_state(const char *filename) {
char tmpfn[4096];
@@ -703,7 +960,7 @@ static int sms_cons_read_context(const uint8 *buf) {
if(cons != 0)
return -1;
if(buf[20] != sms_console)
if(buf[20] != sms_cons._base.console_type)
return -1;
region = buf[21] == 1 ? SMS_REGION_DOMESTIC : SMS_REGION_EXPORT;
@@ -837,7 +1094,7 @@ int sms_load_state(const char *filename)
FILE *fp;
char byte;
if(sms_initialized == 0) {
if(sms_cons._base.initialized == 0) {
/* This shouldn't happen.... */
return -1;
}
@@ -950,3 +1207,138 @@ int sms_load_state(const char *filename __UNUSED__) {
return rv;
}
#endif
int sms_write_state(FILE *fp)
{
uint8 data[4];
if(sms_cons._base.initialized == 0)
/* This shouldn't happen.... */
return -1;
/* Don't let users do this while the bios is running... */
if(sms_bios_active)
return -42;
if(!fp)
return -1;
fprintf(fp, "CrabEmu Save State");
/* Write save state version */
data[0] = 0x00;
data[1] = 0x02;
fwrite(data, 1, 2, fp);
/* Write out the Console Metadata block */
data[0] = 'C';
data[1] = 'O';
data[2] = 'N';
data[3] = 'S';
fwrite(data, 1, 4, fp); /* Block ID */
UINT32_TO_BUF(24, data);
fwrite(data, 1, 4, fp); /* Length */
UINT16_TO_BUF(1, data);
fwrite(data, 1, 2, fp); /* Version */
fwrite(data, 1, 2, fp); /* Flags (Importance = 1) */
data[0] = data[1] = data[2] = data[3] = 0;
fwrite(data, 1, 4, fp); /* Child pointer */
fwrite(data, 1, 4, fp); /* Console (0 = SMS) */
data[0] = sms_cons._base.console_type; /* Console sub-type */
data[1] = sms_region & 0x0F; /* Region code */
data[2] = sms_region >> 4; /* Video system */
data[3] = 0; /* Reserved */
fwrite(data, 1, 4, fp);
/* Write each block's state */
if(sms_game_write_context(fp)) {
fclose(fp);
return -1;
}
else if(sms_z80_write_context(fp)) {
fclose(fp);
return -1;
}
else if(sms_psg_write_context(fp)) {
fclose(fp);
return -1;
}
else if(sms_vdp_write_context(fp)) {
fclose(fp);
return -1;
}
else if(sms_mem_write_context(fp)) {
fclose(fp);
return -1;
}
else if(sms_ym2413_write_context(fp)) {
fclose(fp);
return -1;
}
fclose(fp);
return 0;
}
int sms_read_state(FILE *fp)
{
char str[19];
char byte;
if(sms_cons._base.initialized == 0) {
/* This shouldn't happen.... */
return -1;
}
if(!fp)
return -1;
fread(str, 18, 1, fp);
str[18] = 0;
if(strcmp("CrabEmu Save State", str)) {
fclose(fp);
return -2;
}
/* Read save state version */
fread(&byte, 1, 1, fp);
if(byte != 0x00) {
fclose(fp);
return -2;
}
fread(&byte, 1, 1, fp);
if(byte == 0x01) {
/* Read in the current Z80 context */
sms_z80_read_context_v1(fp);
/* Next, read the current VDP state */
sms_vdp_read_context_v1(fp);
/* Now, read the current PSG state */
sms_psg_read_context_v1(fp);
/* Finally, read the current memory contents from the file */
sms_mem_read_context_v1(fp);
}
else if(byte == 0x02) {
if(sms_load_state_v2(fp))
return -1;
}
else {
/* Unknown version... */
fclose(fp);
return -2;
}
fclose(fp);
sound_reset_buffer();
return 0;
}
+28 -14
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2007, 2009, 2012 Lawrence Sebald
Copyright (C) 2005, 2007, 2009, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -21,22 +21,22 @@
#define SMS_H
#include "CrabEmu.h"
#include "console.h"
CLINKAGE
#include <stdio.h>
extern int sms_init(int video_system, int region);
extern int sms_init(int video_system, int region, int borders);
extern int sms_reset(void);
extern void sms_soft_reset(void);
extern int sms_soft_reset(void);
extern int sms_shutdown(void);
extern int sms_frame(int run, int skip);
extern void sms_button_pressed(int player, int button);
extern void sms_button_released(int player, int button);
extern void sms_set_console(int console);
extern int sms_cycles_elapsed(void);
extern int sms_psg_write_context(FILE *fp);
extern int sms_psg_read_context(const uint8 *buf);
@@ -44,6 +44,9 @@ extern int sms_psg_read_context(const uint8 *buf);
extern int sms_save_state(const char *filename);
extern int sms_load_state(const char *filename);
extern int sms_write_state(FILE *fp);
extern int sms_read_state(FILE *fp);
/* Old button defines. These define the raw bits used for the data. */
#define SMS_PAD1_UP 0x0001
#define SMS_PAD1_DOWN 0x0002
@@ -72,6 +75,16 @@ extern int sms_load_state(const char *filename);
#define SMS_QUIT 7 /* This one is ignored... */
#define SMS_CONSOLE_RESET 8
/* Buttons for the Graphic Board */
#define SMS_GFXBD_1 0
#define SMS_GFXBD_2 1
#define SMS_GFXBD_3 2
/* Control pad types. */
#define SMS_PADTYPE_NONE 0
#define SMS_PADTYPE_CONTROL_PAD 1
#define SMS_PADTYPE_GFX_BOARD 2
#define SMS_PAD1_TL SMS_PAD1_A
#define SMS_PAD1_TR SMS_PAD1_B
#define SMS_PAD2_TL SMS_PAD2_A
@@ -81,15 +94,9 @@ extern int sms_load_state(const char *filename);
#define SMS_TH_MASK 0xC000
/* Console types */
#define CONSOLE_SMS 1
#define CONSOLE_GG 2
#define CONSOLE_SG1000 3
#define CONSOLE_SC3000 4
/* Region types */
#define SMS_REGION_DOMESTIC 0x01
#define SMS_REGION_EXPORT 0x02
#define SMS_REGION_DOMESTIC REGION_JAPAN
#define SMS_REGION_EXPORT REGION_US
/* Video Standards */
#define SMS_VIDEO_NTSC VIDEO_NTSC
@@ -97,6 +104,13 @@ extern int sms_load_state(const char *filename);
#define SMS_CYCLES_PER_LINE 228
/* Console definition. */
typedef struct crabemu_sms {
console_t _base;
} sms_t;
extern sms_t sms_cons;
ENDCLINK
#endif /* !SMS_H */
+32 -4
View File
@@ -96,10 +96,20 @@ void sms_gg_port_write(uint16 port, uint8 data) {
port &= 0xFF;
if(port < 0x07) {
sms_gg_regs[port] = data;
switch(port) {
case 1:
case 2:
case 3:
sms_gg_regs[port] = data;
break;
if(port == 0x06) {
sn76489_set_output_channels(&psg, data);
case 5:
sms_gg_regs[5] = data & 0xF8;
break;
case 6:
sn76489_set_output_channels(&psg, data);
break;
}
}
else if(port < 0x40) {
@@ -144,7 +154,25 @@ uint8 sms_gg_port_read(uint16 port) {
port &= 0xFF;
if(port < 0x07) {
return sms_gg_regs[port];
switch(port) {
case 0:
return sms_gg_regs[0] & 0xE0;
case 1:
return 0;
case 2:
case 3:
case 4:
case 5:
return sms_gg_regs[port];
case 6:
return 0xFF;
default:
return 0xFF;
}
}
else if(port < 0x40) {
return 0xFF;
+204 -71
View File
@@ -1,7 +1,8 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014,
2015, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -79,9 +80,9 @@ static uint32 mapper;
extern uint16 sms_pad;
extern int sms_region;
extern sn76489_t psg;
extern int sms_console;
extern eeprom93c46_t e93c46;
extern int sms_ym2413_enabled;
extern YM2413 *sms_fm;
uint8 sms_paging_regs[4];
uint8 *sms_rom_page0;
@@ -103,10 +104,13 @@ uint8 sms_dummy_arear[256];
uint8 sms_dummy_areaw[256];
uint8 sms_cart_ram[0x8000];
int sms_bios_active = 0;
int sms_control_type[2] = { SMS_PADTYPE_CONTROL_PAD, SMS_PADTYPE_CONTROL_PAD };
static uint8 sms_fm_detect = 0;
static uint8 sms_ym2413_regs[0x41] = { 0 };
static int sms_ym2413_in_use = 0;
static uint32 rom_crc, rom_adler;
static int gfx_board_nibble[2] = { 0, 0 };
uint32 sms_gfxbd_data[2] = { 0x0000000F, 0x0000000F };
typedef void (*remap_page_func)();
remap_page_func sms_mem_remap_page[4];
@@ -201,9 +205,17 @@ static void remap_page0_sms_bios() {
sms_write_map[2] = sms_dummy_areaw;
sms_write_map[3] = sms_dummy_areaw;
for(i = 0x04; i < 0x40; ++i) {
sms_read_map[i] = sms_rom_page0 + (i << 8);
sms_write_map[i] = sms_dummy_areaw;
if(sms_bios_len >= 0x4000) {
for(i = 0x04; i < 0x40; ++i) {
sms_read_map[i] = sms_rom_page0 + (i << 8);
sms_write_map[i] = sms_dummy_areaw;
}
}
else {
for(i = 0x04; i < 0x20; ++i) {
sms_read_map[i] = sms_read_map[i + 0x20] = sms_rom_page0 + (i << 8);
sms_write_map[i] = sms_write_map[i + 0x20] = sms_dummy_areaw;
}
}
sms_z80_set_readmap(sms_read_map);
@@ -255,9 +267,18 @@ static void remap_page1_sms_bios() {
sms_rom_page1 = sms_bios_rom;
}
for(i = 0x40; i < 0x80; ++i) {
sms_read_map[i] = sms_rom_page1 + ((i & 0x3F) << 8);
sms_write_map[i] = sms_dummy_areaw;
if(sms_bios_len >= 0x4000) {
for(i = 0x40; i < 0x80; ++i) {
sms_read_map[i] = sms_rom_page1 + ((i & 0x3F) << 8);
sms_write_map[i] = sms_dummy_areaw;
}
}
else {
for(i = 0x40; i < 0x60; ++i) {
sms_read_map[i] = sms_read_map[i + 0x20] =
sms_rom_page1 + ((i & 0x3F) << 8);
sms_write_map[i] = sms_write_map[i + 0x20] = sms_dummy_areaw;
}
}
sms_z80_set_readmap(sms_read_map);
@@ -330,9 +351,18 @@ static void remap_page2_sms_bios() {
sms_rom_page2 = sms_bios_rom;
}
for(i = 0x80; i < 0xC0; ++i) {
sms_read_map[i] = sms_rom_page2 + ((i & 0x3F) << 8);
sms_write_map[i] = sms_dummy_areaw;
if(sms_bios_len >= 0x4000) {
for(i = 0x80; i < 0xC0; ++i) {
sms_read_map[i] = sms_rom_page2 + ((i & 0x3F) << 8);
sms_write_map[i] = sms_dummy_areaw;
}
}
else {
for(i = 0x80; i < 0xA0; ++i) {
sms_read_map[i] = sms_read_map[i + 0x20] =
sms_rom_page2 + ((i & 0x3F) << 8);
sms_write_map[i] = sms_write_map[i + 0x20] = sms_dummy_areaw;
}
}
sms_z80_set_readmap(sms_read_map);
@@ -372,7 +402,7 @@ static void setup_mapper() {
int codemasters, sega, korean, korean_msx;
uint8 *ptr;
if(sms_cart_len < 0x8000) {
if(sms_cart_len <= 0x8000) {
/* The cartridge contains less than 32KB of data, so there probably
isn't even a mapper in it, but just to be safe, in case it has
SRAM for some reason, we'll just assume the Sega Mapper. */
@@ -398,7 +428,7 @@ static void setup_mapper() {
++codemasters;
else if(value == 0xA000)
++korean;
else if(value < 0x0004)
else if(value == 0x0002 || value == 0x0003 || value == 0x0004)
++korean_msx;
}
}
@@ -417,10 +447,12 @@ void sms_mem_handle_memctl(uint8 data) {
if(sms_memctl == data)
return;
if(sms_console != CONSOLE_SMS && sms_console != CONSOLE_GG)
if(sms_cons._base.console_type != CONSOLE_SMS &&
sms_cons._base.console_type != CONSOLE_GG)
return;
if(!(data & SMS_MEMCTL_BIOS) && sms_console == CONSOLE_SMS &&
if(!(data & SMS_MEMCTL_BIOS) &&
sms_cons._base.console_type == CONSOLE_SMS &&
sms_bios_rom != NULL) {
sms_mem_remap_page[0] = &remap_page2_sms_bios;
sms_mem_remap_page[1] = &remap_page0_sms_bios;
@@ -432,7 +464,8 @@ void sms_mem_handle_memctl(uint8 data) {
sms_z80_set_mwrite16(&sms_mem_sega_mwrite16);
sms_bios_active = 1;
}
else if(!(data & SMS_MEMCTL_CART) || sms_bios_rom == NULL) {
else if((!(data & SMS_MEMCTL_CART) || sms_bios_rom == NULL) &&
sms_cart_rom) {
sms_bios_active = 0;
switch(mapper) {
@@ -538,13 +571,16 @@ void sms_mem_handle_memctl(uint8 data) {
void sms_mem_handle_ioctl(uint8 data) {
int old, new;
uint8 tmp;
/* Make sure we're emulating an export SMS, the Japanese SMS (and earlier
hardware) did not have the I/O Control Register functionality. */
if((sms_console == CONSOLE_SMS && (sms_region & SMS_REGION_DOMESTIC)) ||
sms_console == CONSOLE_SG1000)
if((sms_cons._base.console_type == CONSOLE_SMS &&
(sms_region & SMS_REGION_DOMESTIC)) ||
sms_cons._base.console_type == CONSOLE_SG1000)
return;
tmp = sms_ioctl;
sms_ioctl = data;
old = ((sms_pad & sms_ioctl_input_mask) |
(sms_ioctl_output_bits & sms_ioctl_output_mask)) ^ SMS_TH_MASK;
@@ -567,9 +603,71 @@ void sms_mem_handle_ioctl(uint8 data) {
new = ((sms_pad & sms_ioctl_input_mask) |
(sms_ioctl_output_bits & sms_ioctl_output_mask)) & SMS_TH_MASK;
if(old & new) {
sms_vdp_hcnt_latch();
}
if(old & new)
sms_vdp_hcnt_latch(sms_cycles_elapsed() % SMS_CYCLES_PER_LINE);
/* Handle any graphics boards hooked up. Information from the SMS Power
forums provided by Maxim and Bock here:
http://www.smspower.org/forums/viewtopic.php?p=81920#81920 */
if(sms_control_type[0] == SMS_PADTYPE_GFX_BOARD) {
if((tmp ^ data) & SMS_IOCTL_TH_A_LEVEL)
gfx_board_nibble[0] = (gfx_board_nibble[0] + 1) & 7;
if(data & SMS_IOCTL_TR_A_LEVEL)
gfx_board_nibble[0] = 0;
}
if(sms_control_type[1] == SMS_PADTYPE_GFX_BOARD) {
if((tmp ^ data) & SMS_IOCTL_TH_B_LEVEL)
gfx_board_nibble[1] = (gfx_board_nibble[1] + 1) & 7;
if(data & SMS_IOCTL_TR_B_LEVEL)
gfx_board_nibble[1] = 0;
}
}
static uint8 sms_read_controls(uint16 port) {
uint16 output = sms_ioctl_output_bits & sms_ioctl_output_mask;
uint16 input = sms_pad;
/* The information here came from the forum thread linked to above... */
if(sms_control_type[0] == SMS_PADTYPE_GFX_BOARD) {
if(sms_ioctl & SMS_IOCTL_TR_A_LEVEL) {
input &= 0xFFE0;
}
else {
input = (input & 0xFFF0) |
((sms_gfxbd_data[0] >> (gfx_board_nibble[0] << 2)) & 0x0F);
if(gfx_board_nibble[0] == 0)
input &= ~SMS_PAD1_TL;
}
}
/* This is totally a guess until someone actually tests this out, but it
seems logical, at least. */
if(sms_control_type[1] == SMS_PADTYPE_GFX_BOARD) {
if(sms_ioctl & SMS_IOCTL_TR_B_LEVEL) {
input &= 0xF83F;
}
else {
input = (input & 0xFC3F) |
(((sms_gfxbd_data[1] >> (gfx_board_nibble[1] << 2)) &
0x0F) <<6);
if(gfx_board_nibble[1] == 0)
input &= ~SMS_PAD2_TL;
}
}
input &= sms_ioctl_input_mask;
if(port & 0x01) {
/* I/O port B/misc register */
return ((input | output) >> 8) & 0xFF;
}
else {
/* I/O port A/B register */
return (input | output) & 0xFF;
}
}
void sms_port_write(uint16 port, uint8 data) {
@@ -603,12 +701,14 @@ void sms_port_write(uint16 port, uint8 data) {
if(sms_ym2413_enabled) {
if(port == 0xF0) {
sms_ym2413_regs[0x40] = data;
YM2413Write(0, 0, data);
//YM2413Write(0, 0, data);
ym2413_write(sms_fm, 0, data);
sms_ym2413_in_use = 1;
}
else if(port == 0xF1) {
sms_ym2413_regs[sms_ym2413_regs[0x40]] = data;
YM2413Write(0, 1, data);
//YM2413Write(0, 1, data);
ym2413_write(sms_fm, 1, data);
sms_ym2413_in_use = 1;
}
else if(port == 0xF2) {
@@ -653,24 +753,17 @@ uint8 sms_port_read(uint16 port) {
}
}
else {
if(!(sms_memctl & SMS_MEMCTL_IO)) {
if(port & 0x01) {
/* I/O port B/misc register */
return (((sms_pad & sms_ioctl_input_mask) |
(sms_ioctl_output_bits &
sms_ioctl_output_mask)) >> 8) & 0xFF;
}
else {
/* I/O port A/B register */
return ((sms_pad & sms_ioctl_input_mask) |
(sms_ioctl_output_bits &
sms_ioctl_output_mask)) & 0xFF;
}
}
else if(sms_ym2413_enabled && port == 0xF2) {
/* Uguu~~ Some games apparently don't disable the I/O chip properly when
trying to detect the FM unit... In theory this would potentially give
some fun interference on the bus and allow for false positives, but
whatever. */
if(sms_ym2413_enabled && port == 0xF2) {
sms_ym2413_in_use = 1;
return sms_fm_detect;
}
else if(!(sms_memctl & SMS_MEMCTL_IO)) {
return sms_read_controls(port);
}
else {
return 0xFF;
}
@@ -947,7 +1040,7 @@ static void finalize_load(const char *fn) {
&rom_adler)) == (uint32)-1) {
mapper = SMS_MAPPER_SEGA;
if(sms_console != CONSOLE_SG1000) {
if(sms_cons._base.console_type != CONSOLE_SG1000) {
setup_mapper();
if(mapper == SMS_MAPPER_SEGA) {
@@ -979,7 +1072,12 @@ static void finalize_load(const char *fn) {
}
}
if((sms_console == CONSOLE_SG1000 || sms_console == CONSOLE_SC3000) &&
#ifdef DEBUG
printf("Detected Mapper %d\n", mapper);
#endif
if((sms_cons._base.console_type == CONSOLE_SG1000 ||
sms_cons._base.console_type == CONSOLE_SC3000) &&
mapper != SMS_MAPPER_TW_MSX_TYPE_B) {
for(i = 0; i < 0x08; ++i) {
sms_read_map[i + 0xC8] = ram + (i << 8);
@@ -1007,11 +1105,11 @@ static void finalize_load(const char *fn) {
}
}
if((sms_console != CONSOLE_SMS || sms_bios_rom == NULL) &&
(sms_console != CONSOLE_GG || gg_bios_rom == NULL)) {
if((sms_cons._base.console_type != CONSOLE_SMS || sms_bios_rom == NULL) &&
(sms_cons._base.console_type != CONSOLE_GG || gg_bios_rom == NULL)) {
switch(mapper) {
case SMS_MAPPER_SEGA:
if(sms_console != CONSOLE_SG1000) {
if(sms_cons._base.console_type != CONSOLE_SG1000) {
sms_z80_set_mread(&sms_mem_sega_mread);
sms_z80_set_mread16(&sms_mem_sega_mread16);
sms_z80_set_mwrite(&sms_mem_sega_mwrite);
@@ -1146,7 +1244,7 @@ static void finalize_load(const char *fn) {
/* Give a sane default for the SP since we don't have a BIOS. */
sms_z80_write_reg(SMS_Z80_REG_SP, 0xDFF0);
}
else if(sms_console == CONSOLE_SMS) {
else if(sms_cons._base.console_type == CONSOLE_SMS) {
sms_mem_remap_page[0] = &remap_page2_sms_bios;
sms_mem_remap_page[1] = &remap_page0_sms_bios;
sms_mem_remap_page[2] = &remap_page1_sms_bios;
@@ -1160,7 +1258,7 @@ static void finalize_load(const char *fn) {
sms_mem_janggun_init();
}
}
else if(sms_console == CONSOLE_GG) {
else if(sms_cons._base.console_type == CONSOLE_GG) {
sms_mem_remap_page[0] = &remap_page2;
sms_mem_remap_page[1] = &sms_mem_remap_page0_gg_bios;
sms_mem_remap_page[2] = &remap_page1;
@@ -1184,6 +1282,32 @@ static void finalize_load(const char *fn) {
}
}
int sms_mem_run_bios(int console) {
/* Clear cartram, although it shouldn't be relevant... */
memset(sms_cart_ram, 0, 0x8000);
cartram_enabled = 0;
sms_set_console(console);
sms_cart_rom = NULL;
sms_cart_len = 0;
/* Set up the mapping functions. */
sms_mem_remap_page[0] = &remap_page2_sms_bios;
sms_mem_remap_page[1] = &remap_page0_sms_bios;
sms_mem_remap_page[2] = &remap_page1_sms_bios;
sms_mem_remap_page[3] = &remap_page2_sms_bios;
sms_z80_set_mread(&sms_mem_sega_mread);
sms_z80_set_mread16(&sms_mem_sega_mread16);
sms_z80_set_mwrite(&sms_mem_sega_mwrite);
sms_z80_set_mwrite16(&sms_mem_sega_mwrite16);
reorganize_pages();
gui_set_title("CrabEmu");
return 0;
}
#ifndef NO_ZLIB
static int load_gz_rom(const char *fn) {
int len;
@@ -1502,7 +1626,7 @@ int sms_ym2413_write_context(FILE *fp) {
return 0;
/* Also, this isn't possible on Game Gear */
if(sms_console == CONSOLE_GG)
if(sms_cons._base.console_type == CONSOLE_GG)
return 0;
/* Finally, if its not being used, don't bother */
@@ -1555,30 +1679,30 @@ int sms_ym2413_read_context(const uint8 *buf) {
memcpy(sms_ym2413_regs, buf + 16, 65);
/* This is based on how SMS Plus handles things... */
YM2413Write(0, 0, 0x0E);
YM2413Write(0, 1, sms_ym2413_regs[0x0E]);
ym2413_write(sms_fm, 0, 0x0E);
ym2413_write(sms_fm, 1, sms_ym2413_regs[0x0E]);
for(i = 0x00; i <= 0x07; ++i) {
YM2413Write(0, 0, i);
YM2413Write(0, 1, sms_ym2413_regs[i]);
ym2413_write(sms_fm, 0, i);
ym2413_write(sms_fm, 1, sms_ym2413_regs[i]);
}
for(i = 0x10; i <= 0x18; ++i) {
YM2413Write(0, 0, i);
YM2413Write(0, 1, sms_ym2413_regs[i]);
ym2413_write(sms_fm, 0, i);
ym2413_write(sms_fm, 1, sms_ym2413_regs[i]);
}
for(i = 0x20; i <= 0x28; ++i) {
YM2413Write(0, 0, i);
YM2413Write(0, 1, sms_ym2413_regs[i]);
ym2413_write(sms_fm, 0, i);
ym2413_write(sms_fm, 1, sms_ym2413_regs[i]);
}
for(i = 0x30; i <= 0x38; ++i) {
YM2413Write(0, 0, i);
YM2413Write(0, 1, sms_ym2413_regs[i]);
ym2413_write(sms_fm, 0, i);
ym2413_write(sms_fm, 1, sms_ym2413_regs[i]);
}
YM2413Write(0, 0, sms_ym2413_regs[64]);
ym2413_write(sms_fm, 0, sms_ym2413_regs[64]);
return 0;
}
@@ -1664,7 +1788,7 @@ int sms_mem_write_context(FILE *fp) {
data[3] = 'M';
fwrite(data, 1, 4, fp); /* Block ID */
switch(sms_console) {
switch(sms_cons._base.console_type) {
case CONSOLE_SMS:
case CONSOLE_GG:
memlen = 0x2000;
@@ -1717,7 +1841,7 @@ int sms_mem_write_context(FILE *fp) {
fwrite(data, 1, 4, fp);
/* Write the GG Registers block, if appropriate */
if(sms_console == CONSOLE_GG) {
if(sms_cons._base.console_type == CONSOLE_GG) {
data[0] = 'G';
data[1] = 'G';
data[2] = 'R';
@@ -1807,7 +1931,7 @@ int sms_mem_read_context(const uint8 *buf) {
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
switch(sms_console) {
switch(sms_cons._base.console_type) {
case CONSOLE_SMS:
case CONSOLE_GG:
if(len != 0x2010)
@@ -1952,6 +2076,8 @@ int sms_mapper_read_context(const uint8 *buf) {
ptr += clen;
}
reorganize_pages();
return 0;
}
@@ -1990,6 +2116,7 @@ int sms_mem_init(void) {
sms_gg_regs[6] = 0xFF;
for(i = 0x00; i < 0xC0; ++i) {
sms_read_map[i] = sms_dummy_arear;
sms_write_map[i] = sms_dummy_areaw;
}
@@ -2011,16 +2138,19 @@ int sms_mem_init(void) {
sms_ioctl_output_mask = 0x0000;
sms_ioctl_output_bits = 0x0000;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_CART | SMS_MEMCTL_RAM) ^ 0xFF;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_CART | SMS_MEMCTL_RAM) ^ 0xFC;
sms_ioctl = SMS_IOCTL_TR_A_DIRECTION | SMS_IOCTL_TH_A_DIRECTION |
SMS_IOCTL_TR_B_DIRECTION | SMS_IOCTL_TH_B_DIRECTION;
gfx_board_nibble[0] = gfx_board_nibble[1] = 0;
sms_gfxbd_data[0] = sms_gfxbd_data[1] = 0x0000000F;
memset(ram, 0xF0, 8 * 1024);
/* Set the memctl value at address 0xC000 of the SMS' memory. */
ram[0] = sms_memctl;
sms_bios_active = 0;
memset(ram, 0xF0, 8 * 1024);
return 0;
}
@@ -2057,38 +2187,41 @@ void sms_mem_reset(void) {
sms_gg_regs[5] = 0x00;
sms_gg_regs[6] = 0xFF;
if(sms_console == CONSOLE_SMS && sms_bios_rom != NULL) {
if(sms_cons._base.console_type == CONSOLE_SMS && sms_bios_rom != NULL) {
sms_mem_remap_page[0] = &remap_page2_sms_bios;
sms_mem_remap_page[1] = &remap_page0_sms_bios;
sms_mem_remap_page[2] = &remap_page1_sms_bios;
sms_mem_remap_page[3] = &remap_page2_sms_bios;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_BIOS | SMS_MEMCTL_RAM) ^ 0xFF;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_BIOS | SMS_MEMCTL_RAM) ^ 0xFC;
sms_bios_active = 1;
}
else if(sms_console == CONSOLE_GG && gg_bios_rom != NULL) {
else if(sms_cons._base.console_type == CONSOLE_GG && gg_bios_rom != NULL) {
sms_mem_remap_page[0] = &remap_page2;
sms_mem_remap_page[1] = &sms_mem_remap_page0_gg_bios;
sms_mem_remap_page[2] = &remap_page1;
sms_mem_remap_page[3] = &remap_page2;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_BIOS | SMS_MEMCTL_RAM) ^ 0xFF;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_BIOS | SMS_MEMCTL_RAM) ^ 0xFC;
sms_bios_active = 1;
}
else {
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_CART | SMS_MEMCTL_RAM) ^ 0xFF;
sms_memctl = (SMS_MEMCTL_IO | SMS_MEMCTL_CART | SMS_MEMCTL_RAM) ^ 0xFC;
sms_bios_active = 0;
}
/* Set the memctl value at address 0xC000 in the SMS' memory. */
ram[0] = sms_memctl;
sms_ioctl_input_mask = 0xFFFF;
sms_ioctl_output_mask = 0x0000;
sms_ioctl_output_bits = 0x0000;
sms_ioctl = SMS_IOCTL_TR_A_DIRECTION | SMS_IOCTL_TH_A_DIRECTION |
SMS_IOCTL_TR_B_DIRECTION | SMS_IOCTL_TH_B_DIRECTION;
gfx_board_nibble[0] = gfx_board_nibble[1] = 0;
sms_gfxbd_data[0] = sms_gfxbd_data[1] = 0x0000000F;
memset(ram, 0xF0, 8 * 1024);
/* Set the memctl value at address 0xC000 in the SMS' memory. */
ram[0] = sms_memctl;
reorganize_pages();
sms_mem_janggun_reset();
}
+3 -1
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2007, 2008, 2009, 2012 Lawrence Sebald
Copyright (C) 2005, 2007, 2008, 2009, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -63,6 +63,8 @@ extern void sms_mem_handle_ioctl(uint8 data);
extern int sms_mem_load_bios(const char *fn);
extern int sms_mem_load_rom(const char *fn, int console);
extern int sms_mem_run_bios(int console);
extern int sms_mem_init(void);
extern int sms_mem_shutdown(void);
extern void sms_mem_reset(void);
+300 -47
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2012, 2013, 2014, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -30,9 +30,14 @@
#include <malloc.h>
#endif
extern int sms_console;
sms_vdp_t smsvdp;
uint32 lut[256];
static uint32 lut[256];
/* Size of the top border for each video mode, in scanlines. */
static const int top_border[6] = { 27, 11, 0, 54, 38, 30 };
static const int kyoukai1[] = { 216, 232, 240, 240, 256, 264 };
static const int kyoukai2[] = { 235, 251, 262, 259, 275, 283 };
#ifdef CRABEMU_32BIT_COLOR
static void update_local_pal_sms(int num) {
@@ -102,20 +107,19 @@ void sms_vdp_update_cache(int pat) {
if(pat >= 512 || !smsvdp.pattern[pat].dirty)
return;
/* Determine where we should start converting */
/* Determine where we should start converting from and to... */
bitplane = smsvdp.vram + (pat << 5);
tmp1 = *bitplane++;
tmp2 = *bitplane++;
tmp3 = *bitplane++;
tmp4 = *bitplane++;
tex1 = smsvdp.pattern[pat].texture[0] + 7;
tex2 = smsvdp.pattern[pat].texture[1];
tex3 = smsvdp.pattern[pat].texture[2] + 63;
tex4 = smsvdp.pattern[pat].texture[3] + 56;
for(i = 0; i < 8; ++i) {
tmp1 = *bitplane++;
tmp2 = *bitplane++;
tmp3 = *bitplane++;
tmp4 = *bitplane++;
/* lutval = 8x4bpp pixels */
lutval = (lut[tmp1]) | (lut[tmp2] << 1) | (lut[tmp3] << 2) |
(lut[tmp4] << 3);
@@ -134,11 +138,6 @@ void sms_vdp_update_cache(int pat) {
tex1 += 16;
tex4 -= 16;
tmp1 = *bitplane++;
tmp2 = *bitplane++;
tmp3 = *bitplane++;
tmp4 = *bitplane++;
}
smsvdp.pattern[pat].dirty = 0;
@@ -293,6 +292,10 @@ static void sms_vdp_m4_draw_spr(int line, pixel_t *px) {
y = sat[i] + 1;
/* sat[i] = 255 implies that the sprite should start on line 0. */
if(y == 256)
y = 0;
/* Check the position of this sprite */
if(line >= y && line <= y + height - 1) {
/* If its on this line, make sure that we haven't already rendered
@@ -495,7 +498,39 @@ uint32 sms_vdp_execute(int line, int skip) {
/* Draw only if the display is enabled */
if(smsvdp.regs[1] & 0x40 && line < smsvdp.lines) {
if(!skip) {
pixel_t *px = (smsvdp.framebuffer) + (line << 8);
pixel_t *px;
#ifndef _arch_dreamcast
if(smsvdp.borders)
px = (smsvdp.framebuffer_base) + (line << smsvdp.fb_x);
else
#endif /* !_arch_dreamcast */
px = (smsvdp.framebuffer) + (line << smsvdp.fb_x);
#ifndef _arch_dreamcast
/* Fill in the left border, if we're bothering to emulate them.
This will also, conveniently, reposition the px pointer to beyond
the border for us. */
if(smsvdp.borders) {
int tmp = (smsvdp.regs[7] & 0x0F) | 0x10;
pixel_t col = smsvdp.pal[tmp];
/* The left border is 13 pixels in size. */
*px++ = col; /* 1 */
*px++ = col; /* 2 */
*px++ = col; /* 3 */
*px++ = col; /* 4 */
*px++ = col; /* 5 */
*px++ = col; /* 6 */
*px++ = col; /* 7 */
*px++ = col; /* 8 */
*px++ = col; /* 9 */
*px++ = col; /* 10 */
*px++ = col; /* 11 */
*px++ = col; /* 12 */
*px++ = col; /* 13 */
}
#endif /* !_arch_dreamcast */
bg_draw(line, px);
spr_draw(line, px);
@@ -515,6 +550,33 @@ uint32 sms_vdp_execute(int line, int skip) {
*px++ = col; /* 7 */
*px++ = col; /* 8 */
}
#ifndef _arch_dreamcast
/* Fill in the right border, if we're bothering to emulate them. */
if(smsvdp.borders) {
int tmp = (smsvdp.regs[7] & 0x0F) | 0x10;
pixel_t col = smsvdp.pal[tmp];
px = (smsvdp.framebuffer_base) + (line << smsvdp.fb_x) + 256 +
13;
/* The right border is 15 pixels in size. */
*px++ = col; /* 1 */
*px++ = col; /* 2 */
*px++ = col; /* 3 */
*px++ = col; /* 4 */
*px++ = col; /* 5 */
*px++ = col; /* 6 */
*px++ = col; /* 7 */
*px++ = col; /* 8 */
*px++ = col; /* 9 */
*px++ = col; /* 10 */
*px++ = col; /* 11 */
*px++ = col; /* 12 */
*px++ = col; /* 13 */
*px++ = col; /* 14 */
*px++ = col; /* 15 */
}
#endif /* !_arch_dreamcast */
}
else {
/* Backgrounds can't actually affect anything status-wise, so there
@@ -524,7 +586,13 @@ uint32 sms_vdp_execute(int line, int skip) {
}
}
else if(line < smsvdp.lines && !skip) {
pixel_t *px = (smsvdp.framebuffer) + (line << 8);
pixel_t *px;
#ifndef _arch_dreamcast
if(smsvdp.borders)
px = (smsvdp.framebuffer_base) + (line << smsvdp.fb_x);
else
#endif /* !_arch_dreamcast */
px = (smsvdp.framebuffer) + (line << smsvdp.fb_x);
/* Blank the whole scanline. */
int tmp = (smsvdp.regs[7] & 0x0F) | 0x10;
@@ -533,7 +601,79 @@ uint32 sms_vdp_execute(int line, int skip) {
for(i = 0; i < 256; ++i) {
*px++ = col;
}
#ifndef _arch_dreamcast
/* Blank the rest of the scanline as well. */
if(smsvdp.borders) {
for(i = 0; i < 28; ++i) {
*px++ = col;
}
}
#endif /* !_arch_dreamcast */
}
#ifndef _arch_dreamcast
/* If we're emulating borders, then we might have work to do outside the
active display period. */
else if(smsvdp.borders) {
int bb = 0, tb = 512;
if(smsvdp.vidmode == SMS_VIDEO_NTSC) {
switch(smsvdp.lines) {
case 192:
bb = kyoukai1[0];
tb = kyoukai2[0];
break;
case 224:
bb = kyoukai1[1];
tb = kyoukai2[1];
break;
case 240:
bb = kyoukai1[2];
tb = kyoukai2[2];
break;
}
}
else {
switch(smsvdp.lines) {
case 192:
bb = kyoukai1[3];
tb = kyoukai2[3];
break;
case 224:
bb = kyoukai1[4];
tb = kyoukai2[4];
break;
case 240:
bb = kyoukai1[5];
tb = kyoukai2[5];
break;
}
}
if(line < bb) {
pixel_t *px = (smsvdp.framebuffer_base) + (line << smsvdp.fb_x);
int tmp = (smsvdp.regs[7] & 0x0F) | 0x10;
pixel_t col = smsvdp.pal[tmp];
for(i = 0; i < 284; ++i) {
*px++ = col;
}
}
else if(line >= tb) {
pixel_t *px = (smsvdp.framebuffer) + ((line - tb) << smsvdp.fb_x);
int tmp = (smsvdp.regs[7] & 0x0F) | 0x10;
pixel_t col = smsvdp.pal[tmp];
for(i = 0; i < 284; ++i) {
*px++ = col;
}
}
}
#endif /* !_arch_dreamcast */
if(line <= smsvdp.lines) {
if(smsvdp.linecnt == 0) {
@@ -587,7 +727,14 @@ uint32 tms9918a_vdp_execute(int line, void (*irqfunc)(), int skip) {
/* Draw only if the display is enabled */
if((smsvdp.regs[1] & 0x40) && line < 192) {
if(!skip) {
pixel_t *px = (smsvdp.framebuffer) + (line << 8);
pixel_t *px;
#ifndef _arch_dreamcast
if(smsvdp.borders)
px = (smsvdp.framebuffer_base) + (line << smsvdp.fb_x);
else
#endif /* !_arch_dreamcast */
px = (smsvdp.framebuffer) + (line << smsvdp.fb_x);
bg_draw(line, px);
spr_draw(line, px);
@@ -600,7 +747,7 @@ uint32 tms9918a_vdp_execute(int line, void (*irqfunc)(), int skip) {
}
}
else if(line < 192 && !skip) {
pixel_t *px = (smsvdp.framebuffer) + (line << 8);
pixel_t *px = (smsvdp.framebuffer_base) + (line << smsvdp.fb_x);
/* Blank the whole scanline. */
int tmp = (smsvdp.regs[7] & 0x0F);
@@ -643,7 +790,7 @@ void sms_vdp_data_write(uint8 data) {
}
break;
case 0x03:
if(sms_console != CONSOLE_GG) {
if(sms_cons._base.console_type != CONSOLE_GG) {
smsvdp.cram[smsvdp.addr & 0x1F] = data;
update_local_pal_sms(smsvdp.addr & 0x1F);
}
@@ -744,6 +891,40 @@ void sms_vdp_ctl_write(uint8 data) {
}
}
void *sms_vdp_framebuffer(void) {
return smsvdp.framebuffer;
}
void sms_vdp_framesize(uint32_t *x, uint32_t *y) {
*x = 1 << smsvdp.fb_x;
*y = 1 << smsvdp.fb_y;
}
void sms_vdp_activeframe(uint32_t *x, uint32_t *y, uint32_t *w, uint32_t *h) {
if(sms_cons._base.console_type == CONSOLE_GG) {
*x = 48;
*y = 24;
*w = 160;
*h = 144;
}
else {
if(!smsvdp.borders) {
*x = *y = 0;
*w = 256;
*h = smsvdp.lines;
}
else {
*x = *y = 0;
*w = 284;
if(smsvdp.vidmode == SMS_VIDEO_NTSC)
*h = 243;
else
*h = 288;
}
}
}
uint8 sms_vdp_vcnt_read(void) {
return vcnt_tab[smsvdp.line];
}
@@ -788,16 +969,17 @@ uint8 sms_vdp_status_read(void) {
return tmp;
}
void sms_vdp_hcnt_latch(void) {
extern int sms_cycles_run, sms_cycles_to_run;
smsvdp.hcnt = sms_hcnt[(sms_cycles_run + sms_z80_get_cycles()) -
(sms_cycles_to_run - SMS_CYCLES_PER_LINE)];
void sms_vdp_hcnt_latch(int cycles) {
smsvdp.hcnt = sms_hcnt[cycles];
}
int sms_vdp_init(int mode) {
int sms_vdp_init(int mode, int borders) {
int i, tmp;
#ifdef _arch_dreamcast
(void)borders;
#endif
/* Initialize the VDP emulation to a sane state */
smsvdp.code = 0;
smsvdp.addr = 0;
@@ -807,6 +989,7 @@ int sms_vdp_init(int mode) {
smsvdp.linecnt = 0xFF;
smsvdp.pal_latch = 0;
smsvdp.hcnt = 0;
smsvdp.borders = 0;
/* Set some sane register values */
smsvdp.regs[0x0] = 0x04;
@@ -865,9 +1048,24 @@ int sms_vdp_init(int mode) {
}
#ifndef _arch_dreamcast
smsvdp.framebuffer = (pixel_t *)malloc(256 * 256 * sizeof(pixel_t));
if(!borders) {
smsvdp.framebuffer = (pixel_t *)malloc(256 * 256 * sizeof(pixel_t));
#else
smsvdp.framebuffer = (pixel_t *)memalign(32, 256 * 256 * sizeof(pixel_t));
smsvdp.framebuffer =
(pixel_t *)memalign(32, 256 * 256 * sizeof(pixel_t));
#endif
smsvdp.fb_x = 8;
smsvdp.fb_y = 8;
smsvdp.borders = 0;
#ifndef _arch_dreamcast
}
else {
smsvdp.framebuffer = (pixel_t *)malloc(512 * 512 * sizeof(pixel_t));
smsvdp.fb_x = 9;
smsvdp.fb_y = 9;
smsvdp.borders = 1;
}
#endif
if(smsvdp.framebuffer == NULL) {
@@ -1002,9 +1200,18 @@ void sms_vdp_set_vidmode(int mode, int machine) {
case 0x0C:
case 0x0E:
case 0x0F:
bg_draw = &sms_vdp_m4_draw_bg;
spr_draw = &sms_vdp_m4_draw_spr;
spr_skip = &sms_vdp_m4_skip_spr;
if(machine != SMS_VDP_MACHINE_TMS9918A) {
bg_draw = &sms_vdp_m4_draw_bg;
spr_draw = &sms_vdp_m4_draw_spr;
spr_skip = &sms_vdp_m4_skip_spr;
}
else {
#ifdef DEBUG
fprintf(stderr, "sms_vdp_set_vidmode: Unsupported mode for "
"TMS9918A VDP: 0x%02x.\n", vdp_mode);
return;
#endif
}
break;
default:
@@ -1031,16 +1238,22 @@ void sms_vdp_set_vidmode(int mode, int machine) {
192 line mode */
vcnt_tab = vcnt_ntsc_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[0] << smsvdp.fb_x);
}
else if(smsvdp.regs[1] & 0x10) {
/* M1 is set: 224 line mode */
vcnt_tab = vcnt_ntsc_224;
smsvdp.lines = 224;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[1] << smsvdp.fb_x);
}
else if(smsvdp.regs[1] & 0x08) {
/* M3 is set: 240 line mode */
vcnt_tab = vcnt_ntsc_240;
smsvdp.lines = 240;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[2] << smsvdp.fb_x);
}
else {
/* Invalid text mode.... */
@@ -1055,15 +1268,19 @@ void sms_vdp_set_vidmode(int mode, int machine) {
/* M1 is not set: 192 line mode */
vcnt_tab = vcnt_ntsc_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[0] << smsvdp.fb_x);
}
}
else {
/* M4 is not set, use TMS9918 modes */
vcnt_tab = vcnt_ntsc_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[0] << smsvdp.fb_x);
}
if(sms_console != CONSOLE_GG) {
if(sms_cons._base.console_type != CONSOLE_GG) {
if(smsvdp.lines == 192) {
gui_set_aspect(4.0f, 3.0f);
}
@@ -1080,6 +1297,13 @@ void sms_vdp_set_vidmode(int mode, int machine) {
}
else if(machine == SMS_VDP_MACHINE_SMS1) {
}
else if(machine == SMS_VDP_MACHINE_TMS9918A) {
vcnt_tab = vcnt_ntsc_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[0] << smsvdp.fb_x);
gui_set_aspect(4.0f, 3.0f);
}
else {
#ifdef DEBUG
fprintf(stderr, "sms_vdp_set_vidmode: Invalid machine: %d\n",
@@ -1103,16 +1327,22 @@ void sms_vdp_set_vidmode(int mode, int machine) {
192 line mode */
vcnt_tab = vcnt_pal_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[3] << smsvdp.fb_x);
}
else if(smsvdp.regs[1] & 0x10) {
/* M1 is set: 224 line mode */
vcnt_tab = vcnt_pal_224;
smsvdp.lines = 224;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[4] << smsvdp.fb_x);
}
else if(smsvdp.regs[1] & 0x08) {
/* M3 is set: 240 line mode */
vcnt_tab = vcnt_pal_240;
smsvdp.lines = 240;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[5] << smsvdp.fb_x);
}
else {
/* Invalid text mode.... */
@@ -1127,15 +1357,19 @@ void sms_vdp_set_vidmode(int mode, int machine) {
/* M1 is not set: 192 line mode */
vcnt_tab = vcnt_pal_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[3] << smsvdp.fb_x);
}
}
else {
/* M4 is not set, use TMS9918 modes */
vcnt_tab = vcnt_pal_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[3] << smsvdp.fb_x);
}
if(sms_console != CONSOLE_GG) {
if(sms_cons._base.console_type != CONSOLE_GG) {
if(smsvdp.lines == 192) {
gui_set_aspect(4.0f, 3.0f);
}
@@ -1152,6 +1386,13 @@ void sms_vdp_set_vidmode(int mode, int machine) {
}
else if(machine == SMS_VDP_MACHINE_SMS1) {
}
else if(machine == SMS_VDP_MACHINE_TMS9918A) {
vcnt_tab = vcnt_pal_192;
smsvdp.lines = 192;
smsvdp.framebuffer_base =
smsvdp.framebuffer + (top_border[0] << smsvdp.fb_x);
gui_set_aspect(4.0f, 3.0f);
}
else {
#ifdef DEBUG
fprintf(stderr, "sms_vdp_set_vidmode: Invalid machine: %d\n",
@@ -1199,7 +1440,7 @@ static int sms_vdp_read_vram_context(const uint8 *buf) {
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len < 16 || len > 0x4010)
if(len != 0x4010)
return -1;
/* Check the version number */
@@ -1212,7 +1453,7 @@ static int sms_vdp_read_vram_context(const uint8 *buf) {
return -1;
memset(smsvdp.vram, 0, 0x4000);
memcpy(smsvdp.vram, buf + 16, len - 16);
memcpy(smsvdp.vram, buf + 16, 0x4000);
return 0;
}
@@ -1220,9 +1461,8 @@ static int sms_vdp_write_cram_context(FILE *fp) {
uint8 data[4];
/* Don't write anything for SG-1000, SC-3000, or ColecoVision. */
if(sms_console > CONSOLE_GG) {
if(sms_cons._base.console_type > CONSOLE_GG)
return 0;
}
data[0] = 'C';
data[1] = 'R';
@@ -1250,7 +1490,7 @@ static int sms_vdp_read_cram_context(const uint8 *buf) {
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
if(len < 16 || len > 80)
if(len != 80)
return -1;
/* Check the version number */
@@ -1263,7 +1503,7 @@ static int sms_vdp_read_cram_context(const uint8 *buf) {
return -1;
memset(smsvdp.cram, 0, 64);
memcpy(smsvdp.cram, buf + 16, len - 16);
memcpy(smsvdp.cram, buf + 16, 64);
return 0;
}
@@ -1277,12 +1517,10 @@ int sms_vdp_write_context(FILE *fp) {
data[3] = '8';
fwrite(data, 1, 4, fp); /* Block ID */
if(sms_console < CONSOLE_SG1000) {
if(sms_cons._base.console_type < CONSOLE_SG1000)
len = 0x4010 + 80 + 48; /* VRAM + CRAM + this block */
}
else {
else
len = 0x4010 + 48; /* VRAM + this block */
}
UINT32_TO_BUF(len, data);
fwrite(data, 1, 4, fp); /* Length */
@@ -1327,7 +1565,7 @@ int sms_vdp_read_context(const uint8 *buf) {
uint32 len, child, clen;
uint16 ver;
const uint8 *ptr;
int rv, i;
int rv, i, tmp;
/* Check the size */
BUF_TO_UINT32(buf + 4, len);
@@ -1346,7 +1584,7 @@ int sms_vdp_read_context(const uint8 *buf) {
/* Read the VDP state */
for(i = 0; i < 16; ++i) {
sms_vdp_reg_write(i, buf[16 + i]);
smsvdp.regs[i] = buf[16 + i];
}
BUF_TO_UINT16(buf + 32, smsvdp.addr);
@@ -1398,7 +1636,7 @@ int sms_vdp_read_context(const uint8 *buf) {
ptr += clen;
}
if(sms_console != CONSOLE_GG) {
if(sms_cons._base.console_type != CONSOLE_GG) {
for(i = 0; i < 0x20; ++i) {
update_local_pal_sms(i);
}
@@ -1409,6 +1647,21 @@ int sms_vdp_read_context(const uint8 *buf) {
}
}
/* Deal with the updated register values... */
sms_z80_clear_irq();
smsvdp.sat = smsvdp.vram + ((smsvdp.regs[5] & 0x7E) << 7);
tmp = (smsvdp.regs[8] & 0xF8) >> 3;
smsvdp.xscroll_coarse = (32 - tmp) & 0x1F;
smsvdp.xscroll_fine = smsvdp.regs[8] & 0x07;
smsvdp.yscroll_fine = smsvdp.regs[9] & 0x07;
sms_vdp_set_vidmode(smsvdp.vidmode, smsvdp.machine);
readjust_name_table();
/* Assert the irq line if we need to. */
if((smsvdp.status & 0x80) && (smsvdp.regs[1] & 0x20)) {
sms_z80_assert_irq();
}
/* Mark all patterns as dirty */
for(i = 0; i < 512; ++i) {
smsvdp.pattern[i].dirty = 1;
@@ -1448,7 +1701,7 @@ void sms_vdp_read_context_v1(FILE *fp) {
overwritten before they're used, anyway */
}
if(sms_console != CONSOLE_GG) {
if(sms_cons._base.console_type != CONSOLE_GG) {
for(i = 0; i < 0x20; ++i) {
update_local_pal_sms(i);
}
+18 -6
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -73,8 +73,9 @@ typedef struct smsvdp_s {
/* Background priority levels */
uint8 bg_prio[32];
/* Internal Framebuffer - 256x256 pixels 32bpp or 16bpp */
/* Internal Framebuffer - 256x256 or 512x512 pixels 32bpp or 16bpp */
pixel_t *framebuffer;
pixel_t *framebuffer_base;
/* Background alpha levels, used with the priority to determine if
a given pixel is invisible or not */
@@ -106,6 +107,11 @@ typedef struct smsvdp_s {
int xscroll_coarse;
int xscroll_fine;
int yscroll_fine;
/* Framebuffer size, in lg(pixels) */
int borders;
int fb_x;
int fb_y;
} sms_vdp_t;
#define SMS_VDP_FLAG_BYTES_WRITTEN 0x00000001
@@ -117,23 +123,29 @@ extern void sms_vdp_update_cache(int pat);
extern void sms_vdp_data_write(uint8 data);
extern void sms_vdp_ctl_write(uint8 data);
extern void *sms_vdp_framebuffer(void);
extern void sms_vdp_framesize(uint32_t *x, uint32_t *y);
extern void sms_vdp_activeframe(uint32_t *x, uint32_t *y, uint32_t *w,
uint32_t *h);
extern uint8 sms_vdp_vcnt_read(void);
extern uint8 sms_vdp_hcnt_read(void);
extern uint8 sms_vdp_data_read(void);
extern uint8 sms_vdp_status_read(void);
extern void sms_vdp_hcnt_latch(void);
extern void sms_vdp_hcnt_latch(int cycles);
extern uint32 sms_vdp_execute(int line, int skip);
extern uint32 tms9918a_vdp_execute(int line, void (*irqfunc)(), int skip);
extern void sms_vdp_dump_vram(const char *fn);
extern int sms_vdp_init(int mode);
extern int sms_vdp_init(int mode, int borders);
extern int sms_vdp_reset(void);
extern int sms_vdp_shutdown(void);
#define SMS_VDP_MACHINE_SMS1 1
#define SMS_VDP_MACHINE_SMS2 2
#define SMS_VDP_MACHINE_SMS1 1
#define SMS_VDP_MACHINE_SMS2 2
#define SMS_VDP_MACHINE_TMS9918A 3
extern void sms_vdp_set_vidmode(int mode, int machine);
extern int sms_vdp_write_context(FILE *fp);
+77 -1
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2009 Lawrence Sebald
Copyright (C) 2009, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -198,6 +198,77 @@ uint16 sms_z80_read_reg(int reg) {
}
}
void sms_z80_write_reg(int reg, uint16 value) {
switch(reg) {
case SMS_Z80_REG_B:
CZ80.BC.B.H = (uint8)value;
break;
case SMS_Z80_REG_C:
CZ80.BC.B.L = (uint8)value;
break;
case SMS_Z80_REG_D:
CZ80.DE.B.H = (uint8)value;
break;
case SMS_Z80_REG_E:
CZ80.DE.B.L = (uint8)value;
break;
case SMS_Z80_REG_H:
CZ80.HL.B.H = (uint8)value;
break;
case SMS_Z80_REG_L:
CZ80.HL.B.L = (uint8)value;
break;
case SMS_Z80_REG_F:
CZ80.FA.B.H = (uint8)value;
break;
case SMS_Z80_REG_A:
CZ80.FA.B.L = (uint8)value;
break;
case SMS_Z80_REG_PC:
Cz80_Set_PC(&CZ80, value);
break;
case SMS_Z80_REG_SP:
CZ80.SP.W = value;
break;
case SMS_Z80_REG_IX:
CZ80.IX.W = value;
break;
case SMS_Z80_REG_IY:
CZ80.IY.W = value;
break;
case SMS_Z80_REG_BC:
CZ80.BC.W = value;
break;
case SMS_Z80_REG_DE:
CZ80.DE.W = value;
break;
case SMS_Z80_REG_HL:
CZ80.HL.W = value;
break;
case SMS_Z80_REG_AF:
CZ80.FA.W = (value >> 8) | ((value & 0xFF) << 8);
break;
case SMS_Z80_REG_R:
CZ80.R.B.L = (uint8)value;
break;
case SMS_Z80_REG_I:
CZ80.I = (uint8)value;
break;
case SMS_Z80_REG_BCp:
CZ80.BC2.W = value;
break;
case SMS_Z80_REG_DEp:
CZ80.DE2.W = value;
break;
case SMS_Z80_REG_HLp:
CZ80.HL2.W = value;
break;
case SMS_Z80_REG_AFp:
CZ80.FA2.W = (value >> 8) | ((value & 0xFF) << 8);
break;
}
}
int sms_z80_write_context(FILE *fp __UNUSED__) {
/* XXXX */
return -1;
@@ -206,3 +277,8 @@ int sms_z80_write_context(FILE *fp __UNUSED__) {
void sms_z80_read_context_v1(FILE *fp __UNUSED__) {
/* XXXX */
}
int sms_z80_read_context(const uint8 *buf __UNUSED__) {
/* XXXX */
return -1;
}
-422
View File
@@ -1,422 +0,0 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2008 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* This file contains the z80 core debugger that I wrote
to compare how CrabZ80 worked versus the Z80 core from
MAME. The code isn't pretty, but its here, in case
anyone wants to compile their own binary with it.
(These binaries cannot be released due to licensing
restrictions on the MAME core that contradict the GPL).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "smsz80.h"
#include "CrabZ80d.h"
#include "../../cpu/mamez80/z80.h"
typedef struct {
uint16 addr;
uint8 val;
uint8 write;
} debug_memory_ent;
CrabZ80_t *cpuz80;
extern Z80_Regs Z80;
debug_memory_ent crabmem[10];
debug_memory_ent mz80mem[10];
debug_memory_ent crabport[10];
debug_memory_ent mz80port[10];
debug_memory_ent portread[10];
debug_memory_ent memread[200];
int debug_crab_ents = 0;
int debug_mz80_ents = 0;
int debug_crab_ports = 0;
int debug_mz80_ports = 0;
int debug_port_reads1 = 0;
int debug_port_reads2 = 0;
int debug_mem_reads1 = 0;
int debug_mem_reads2 = 0;
uint8 (*mread8)(uint16) = NULL;
void (*mwrite8)(uint16, uint8) = NULL;
static void sms_debug_memwrite(uint16 addr, uint8 val) {
crabmem[debug_crab_ents].addr = addr;
crabmem[debug_crab_ents].write = 1;
crabmem[debug_crab_ents++].val = val;
mwrite8(addr, val);
}
static uint8 sms_debug_portread(uint16 port) {
uint8 res = sms_port_read(port);
portread[debug_port_reads1].addr = port;
portread[debug_port_reads1].val = res;
portread[debug_port_reads1++].write = 0;
return res;
}
static void sms_debug_portwrite(uint16 port, uint8 data) {
crabport[debug_crab_ports].addr = port & 0xFF;
crabport[debug_crab_ports].write = 1;
crabport[debug_crab_ports++].val = data;
sms_port_write(port, data);
}
static uint8 sms_debug_memread(uint16 addr) {
uint8 res = mread8(addr);
memread[debug_mem_reads1].addr = addr;
memread[debug_mem_reads1].write = 0;
memread[debug_mem_reads1++].val = res;
return res;
}
/* Glue code for mz80 */
void program_write_byte_8(UINT32 addr, UINT8 val) {
mz80mem[debug_mz80_ents].addr = addr;
mz80mem[debug_mz80_ents].write = 1;
mz80mem[debug_mz80_ents++].val = val;
}
UINT8 program_read_byte_8(UINT32 addr) {
int i;
for(i = 0; i < debug_mem_reads1; ++i) {
if(memread[i].addr == (addr & 0xFFFF))
return memread[i].val;
}
printf("reading other addr: %04x %04X\n", addr & 0xFFFF, Z80.pc.w.l);
return mread8(addr);
}
#define UNUSED __attribute__((unused))
void io_write_byte_8(UINT32 port, UINT8 val) {
mz80port[debug_mz80_ports].addr = port & 0xFF;
mz80port[debug_mz80_ports].write = 1;
mz80port[debug_mz80_ports++].val = val;
}
UINT8 io_read_byte_8(UINT32 port) {
int i;
for(i = 0; i < debug_port_reads1; ++i) {
if(portread[i].addr == (port & 0xFF))
return portread[i].val;
}
printf("reading other port: %04x %04X\n", port & 0xFF, Z80.pc.w.l);
return sms_port_read(port & 0xFF);
}
static int _compare_registers() {
int f = 0;
if(cpuz80->af.b.h != Z80.af.b.h) {
printf("A does not match, %x v %x\n", cpuz80->af.b.h, Z80.af.b.h);
f++;
}
if(cpuz80->af.b.l != Z80.af.b.l) {
printf("F does not match, %02X v %02X\n", cpuz80->af.b.l, Z80.af.b.l);
f++;
}
if(cpuz80->bc.b.h != Z80.bc.b.h) {
printf("B does not match, %x v %x\n", cpuz80->bc.b.h, Z80.bc.b.h);
f++;
}
if(cpuz80->bc.b.l != Z80.bc.b.l) {
printf("C does not match, %x v %x\n", cpuz80->bc.b.l, Z80.bc.b.l);
f++;
}
if(cpuz80->de.b.h != Z80.de.b.h) {
printf("D does not match, %x v %x\n", cpuz80->de.b.h, Z80.de.b.h);
f++;
}
if(cpuz80->de.b.l != Z80.de.b.l) {
printf("E does not match, %x v %x\n", cpuz80->de.b.l, Z80.de.b.l);
f++;
}
if(cpuz80->hl.b.h != Z80.hl.b.h) {
printf("H does not match, %x v %x\n", cpuz80->hl.b.h, Z80.hl.b.h);
f++;
}
if(cpuz80->hl.b.l != Z80.hl.b.l) {
printf("L does not match, %x v %x\n", cpuz80->hl.b.l, Z80.hl.b.l);
f++;
}
if(cpuz80->afp.b.h != Z80.af2.b.h) {
printf("Ap does not match, %x v %x\n", cpuz80->afp.b.h, Z80.af2.b.h);
f++;
}
if(cpuz80->afp.b.l != Z80.af2.b.l) {
printf("Fp does not match, %x v %x\n", cpuz80->afp.b.l, Z80.af2.b.l);
f++;
}
if(cpuz80->bcp.b.h != Z80.bc2.b.h) {
printf("Bp does not match, %x v %x\n", cpuz80->bcp.b.h, Z80.bc2.b.h);
f++;
}
if(cpuz80->bcp.b.l != Z80.bc2.b.l) {
printf("Cp does not match, %x v %x\n", cpuz80->bcp.b.l, Z80.bc2.b.l);
f++;
}
if(cpuz80->dep.b.h != Z80.de2.b.h) {
printf("Dp does not match, %x v %x\n", cpuz80->dep.b.h, Z80.de2.b.h);
f++;
}
if(cpuz80->dep.b.l != Z80.de2.b.l) {
printf("Ep does not match, %x v %x\n", cpuz80->dep.b.l, Z80.de2.b.l);
f++;
}
if(cpuz80->hlp.b.h != Z80.hl2.b.h) {
printf("Hp does not match, %x v %x\n", cpuz80->hlp.b.h, Z80.hl2.b.h);
f++;
}
if(cpuz80->hlp.b.l != Z80.hl2.b.l) {
printf("Lp does not match, %x v %x\n", cpuz80->hlp.b.l, Z80.hl2.b.l);
f++;
}
if(cpuz80->pc.w != Z80.pc.w.l) {
printf("PC does not match, %x v %x\n", cpuz80->pc.w, Z80.pc.w.l);
f++;
}
if(cpuz80->ix.w != Z80.ix.w.l) {
printf("IX does not match %x v %x\n", cpuz80->ix.w, Z80.iy.w.l);
f++;
}
if(cpuz80->iy.w != Z80.iy.w.l) {
printf("IY does not match %x v %x\n", cpuz80->iy.w, Z80.ix.w.l);
f++;
}
if(cpuz80->sp.w != Z80.sp.w.l) {
printf("SP does not match %x v %x\n", cpuz80->sp.w, Z80.sp.w.l);
f++;
}
if(cpuz80->ir.b.h != Z80.i) {
printf("I does not match %x v %x\n", cpuz80->ir.b.h, Z80.i);
f++;
}
if(cpuz80->ir.b.l != Z80.r) {
printf("R does not match %x v %x\n", cpuz80->ir.b.l, Z80.r);
f++;
}
return f;
}
static int _compare_memory() {
int i;
int f = 0;
for(i = 0; i < debug_crab_ents; ++i) {
if(crabmem[i].addr != mz80mem[i].addr) {
printf("Mismatched addresses (write=%d)! %02x v %02x\n", crabmem[i].write, crabmem[i].addr, mz80mem[i].addr);
f++;
}
else if(crabmem[i].val != mz80mem[i].val) {
printf("mismatched bytes (write=%d)! %02x v %02x\n", crabmem[i].write, crabmem[i].val, mz80mem[i].val);
f++;
}
}
return f;
}
static int _compare_ports() {
int i;
int f = 0;
for(i = 0; i < debug_crab_ports; ++i) {
if(crabport[i].addr != mz80port[i].addr) {
printf("Mismatched ports (write=%d)! %02x v %02x\n", crabport[i].write, crabport[i].addr, mz80port[i].addr);
f++;
}
else if(crabport[i].val != mz80port[i].val) {
printf("mismatched pbytes (write=%d)! %02x v %02x\n", crabport[i].write, crabport[i].val, mz80port[i].val);
f++;
}
}
return f;
}
int sms_z80_init(void) {
cpuz80 = (CrabZ80_t *)malloc(sizeof(CrabZ80_t));
if(cpuz80 == NULL) {
fprintf(stderr, "Out of memory while initializing Z80 in debug mode\n");
return -1;
}
/* Initialize CrabZ80 */
CrabZ80_init(cpuz80);
CrabZ80_reset(cpuz80);
CrabZ80_set_memwrite(cpuz80, sms_debug_memwrite);
CrabZ80_set_memread(cpuz80, sms_debug_memread);
CrabZ80_set_portwrite(cpuz80, sms_debug_portwrite);
CrabZ80_set_portread(cpuz80, sms_debug_portread);
z80_init();
z80_reset();
return 0;
}
int sms_z80_shutdown(void) {
free(cpuz80);
z80_exit();
return 0;
}
void sms_z80_reset(void) {
CrabZ80_reset(cpuz80);
z80_reset();
}
#define INPUT_LINE_NMI 127
void sms_z80_assert_irq(void) {
CrabZ80_assert_irq(cpuz80, 0xFFFFFFFF);
z80_set_irq_line(1, 1);
}
void sms_z80_clear_irq(void) {
CrabZ80_clear_irq(cpuz80);
z80_set_irq_line(1, 0);
}
void sms_z80_nmi(void) {
CrabZ80_pulse_nmi(cpuz80);
z80_set_irq_line(INPUT_LINE_NMI, 1);
}
uint32 sms_z80_run(uint32 cycles) {
uint32 cyclesdone = 0;
uint32 opcode;
uint16 pc;
int tmp;
static char last_str[256];
char str[256];
static uint16 last_pc = 0;
uint32 c1, c2;
while(cyclesdone < cycles) {
debug_crab_ents = debug_mz80_ents = 0;
debug_port_reads1 = debug_port_reads2 = 0;
debug_mem_reads1 = debug_mem_reads2 = 0;
debug_crab_ports = debug_mz80_ports = 0;
pc = cpuz80->pc.w;
opcode = mread8(cpuz80->pc.w);
if(opcode == 0xED || opcode == 0xCB || opcode == 0xDD || opcode == 0xFD) {
opcode |= (mread8(cpuz80->pc.w + 1) << 8);
}
if((opcode & 0xFF00) == 0xCB00) {
opcode |= (mread8(cpuz80->pc.w + 2) << 16) | (mread8(cpuz80->pc.w + 3) << 24);
}
c1 = CrabZ80_execute(cpuz80, 1);
c2 = z80_execute(1);
cyclesdone += c1;
tmp = _compare_registers() + _compare_memory() + _compare_ports();
CrabZ80_disassemble(str, cpuz80, pc);
if(tmp) {
printf("Cycles done: %d %d\n", (int)c1, (int)c2);
printf("%d errors at: PC = 0x%04X, old_pc = 0x%04X Opcode = 0x%02X",
tmp, pc, last_pc, opcode & 0xFF);
switch(opcode & 0xFF) {
case 0xED:
case 0xCB:
printf("%02X (%s -- %s)\n", (opcode & 0xFF00) >> 8, str,
last_str);
break;
case 0xDD:
case 0xFD:
if((opcode & 0xFF00) == 0xCB00)
printf("%02X%02X%02X (%s -- %s)\n",
(opcode & 0xFF00) >> 8,
(opcode & 0xFF0000) >> 16,
(opcode & 0xFF000000) >> 24, str, last_str);
else
printf("%02X (%s -- %s)\n", (opcode & 0xFF00) >> 8, str,
last_str);
break;
default:
printf("(%s -- %s)\n", str, last_str);
}
}
strcpy(last_str, str);
last_pc = pc;
}
return cyclesdone;
}
uint16 sms_z80_get_pc(void) {
return cpuz80->pc.w;
}
void sms_z80_set_mread(uint8 (*mread)(uint16)) {
mread8 = mread;
}
void sms_z80_set_mwrite(void (*mwrite)(uint16, uint8)) {
mwrite8 = mwrite;
}
void sms_z80_set_mread16(uint16 (*mread)(uint16) UNUSED) {
/* Disabled for debugging */
}
void sms_z80_set_mwrite16(void (*mwrite)(uint16, uint16) UNUSED) {
/* Disabled for debugging */
}
void sms_z80_set_readmap(uint8 *readmap[256] UNUSED) {
/* Disabled for debugging */
}
int sms_z80_write_context(FILE *fp) {
/* XXXX */
return -1;
}
void sms_z80_read_context_v1(FILE *fp) {
/* XXXX */
}
+2 -2
View File
@@ -4,7 +4,7 @@
Copyright (C) 2005, 2006, 2007, 2008, 2009 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -34,7 +34,7 @@ int sms_z80_init(void) {
return -1;
}
CrabZ80_init(cpuz80);
CrabZ80_init(cpuz80, CRABZ80_CPU_Z80);
CrabZ80_reset(cpuz80);
CrabZ80_set_portwrite(cpuz80, sms_port_write);
+4 -9
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2008 Lawrence Sebald
Copyright (C) 2008, 2013 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -37,8 +37,8 @@ void terebi_update(int x, int y, int pressed) {
if(x < 0)
x = 0;
else if(x > 255)
x = 255;
else if(x > 251)
x = 251;
if(y < 0)
y = 0;
@@ -63,12 +63,7 @@ uint8 terebi_mread(uint16 addr) {
return (terebi_flags & TEREBI_OEKAKI_PRESSED) ? 0 : 1;
}
else if(addr == 0xA000) {
if((terebi_flags & TEREBI_OEKAKI_PRESSED)) {
return (terebi_flags & TEREBI_OEKAKI_AXIS_Y) ? terebi_x : terebi_y;
}
else {
return 0;
}
return (terebi_flags & TEREBI_OEKAKI_AXIS_Y) ? terebi_x : terebi_y;
}
return sms_read_map[addr >> 8][addr & 0xFF];
+117 -10
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -18,6 +18,7 @@
*/
#include "sms.h"
#include "smsz80.h"
#include "smsvdp.h"
#include "tms9918a.h"
@@ -364,19 +365,15 @@ void tms9918a_m023_draw_spr(int line, pixel_t *px) {
for(i = 0; i < 32 && count < 5; ++i) {
y = sat[i << 2] + 1;
if(y == 0xD1) {
if(y == 0xD1)
/* End of list marker */
break;
}
else if(line < y) {
else if(line < y)
continue;
}
else if(y + (pattern_size << size_shift) - 1 < line) {
else if(y + (pattern_size << size_shift) - 1 < line)
continue;
}
else if(++count == 5) {
else if(++count == 5)
break;
}
x = sat[(i << 2) + 1];
pattern = sat[(i << 2) + 2];
@@ -601,7 +598,7 @@ void tms9918a_m023_skip_spr(int line) {
if(y == 0xD1)
/* End of list marker */
return;
break;
else if(line < y)
continue;
else if(y + (pattern_size << size_shift) - 1 < line)
@@ -710,6 +707,7 @@ void tms9918a_m023_skip_spr(int line) {
}
else if(y == 0xD1) {
/* Set the fifth sprite bits to the last sprite displayed */
smsvdp.status &= 0xE0;
smsvdp.status |= (i & 0x1F);
}
else {
@@ -719,5 +717,114 @@ void tms9918a_m023_skip_spr(int line) {
}
}
void tms9918a_vdp_data_write(uint8 data) {
/* Clear the bytes written flag */
smsvdp.flags &= (~SMS_VDP_FLAG_BYTES_WRITTEN);
/* First, update the read buffer */
smsvdp.read_buf = data;
/* Write the byte to the RAM */
smsvdp.vram[smsvdp.addr] = data;
/* Update the address register, and wrap, if needed */
smsvdp.addr = (smsvdp.addr + 1) & 0x3FFF;
}
static void tms9918a_vdp_reg_write(int reg, uint8 data) {
if(reg > 7)
return;
switch(reg) {
case 0:
smsvdp.regs[0] = data & 0x03;
sms_vdp_set_vidmode(smsvdp.vidmode, SMS_VDP_MACHINE_TMS9918A);
break;
case 1:
smsvdp.regs[1] = data & 0xfb;
sms_vdp_set_vidmode(smsvdp.vidmode, SMS_VDP_MACHINE_TMS9918A);
if((smsvdp.status & 0x80) && (smsvdp.regs[1] & 0x20))
sms_z80_assert_irq();
break;
default:
smsvdp.regs[reg] = data;
break;
}
}
void tms9918a_vdp_ctl_write(uint8 data) {
/* First, update the code/address registers */
if(!(smsvdp.flags & SMS_VDP_FLAG_BYTES_WRITTEN)) {
/* A multiple of 2 bytes written */
smsvdp.addr = (smsvdp.addr & 0x3F00) | (data);
smsvdp.addr_latch = data;
smsvdp.flags |= SMS_VDP_FLAG_BYTES_WRITTEN;
return;
}
/* One byte written, write the last one */
smsvdp.addr = (data & 0x3F) << 8 | (smsvdp.addr_latch & 0xFF);
smsvdp.code = (data & 0xC0) >> 6;
smsvdp.flags &= (~SMS_VDP_FLAG_BYTES_WRITTEN);
/* Code 0 - Read a byte of vram, put it in the buffer, and increment
the address (that last part is important!) */
if(smsvdp.code == 0x00) {
smsvdp.read_buf = smsvdp.vram[smsvdp.addr];
smsvdp.addr = (smsvdp.addr + 1) & 0x3FFF;
}
/* Code 2 - Register Write */
else if(smsvdp.code == 0x02) {
int reg = data & 0x0F;
tms9918a_vdp_reg_write(reg, smsvdp.addr & 0xFF);
}
}
uint8 tms9918a_vdp_data_read(void) {
uint8 tmp;
/* Clear the bytes written flag */
smsvdp.flags &= (~SMS_VDP_FLAG_BYTES_WRITTEN);
/* Fetch what is already in the buffer */
tmp = smsvdp.read_buf;
/* Fetch a new byte for the buffer */
smsvdp.read_buf = smsvdp.vram[smsvdp.addr];
/* And finally, increment the address */
smsvdp.addr = (smsvdp.addr + 1) & 0x3FFF;
return tmp;
}
uint8 tms9918a_vdp_status_read(void) {
uint8 tmp;
/* Check the interrupt flags */
if((smsvdp.status & 0x80))
sms_z80_clear_irq();
/* Clear the bytes written flag and line interrupt pending flag */
smsvdp.flags &= ~SMS_VDP_FLAG_BYTES_WRITTEN;
/* Fetch our flags, so that we can clear stale ones */
tmp = smsvdp.status;
smsvdp.status &= (~0xE0);
return tmp;
}
#undef DRAW_PIXEL
#undef CHECK_PIXEL
void tms9918a_vdp_activeframe(uint32_t *x, uint32_t *y, uint32_t *w,
uint32_t *h) {
*x = *y = 0;
*w = 256;
*h = 192;
}
+10 -2
View File
@@ -1,7 +1,7 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
@@ -72,7 +72,15 @@ extern void tms9918a_m1_draw_bg(int line, pixel_t *px);
extern void tms9918a_m2_draw_bg(int line, pixel_t *px);
extern void tms9918a_m3_draw_bg(int line, pixel_t *px);
extern void tms9918a_m023_draw_spr(int line, pixel_t *px);
void tms9918a_m023_skip_spr(int line);
extern void tms9918a_m023_skip_spr(int line);
extern void tms9918a_vdp_data_write(uint8 data);
extern void tms9918a_vdp_ctl_write(uint8 data);
extern uint8 tms9918a_vdp_data_read(void);
extern uint8 tms9918a_vdp_status_read(void);
extern void tms9918a_vdp_activeframe(uint32_t *x, uint32_t *y, uint32_t *w,
uint32_t *h);
ENDCLINK
+78 -17
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012 Lawrence Sebald
Copyright (C) 2012, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -42,9 +42,34 @@ ADCMOP:
FETCH_BYTE(_addr, _tmp);
ADCOP:
#ifndef CRAB6502_NO_DECIMAL
/* Decimal mode is... ugly. But it should work. */
if(cpu->p & 0x08) {
/* XXXX: Support BCD mode */
assert(0);
/* Calculate the two halves as well as the Z flag. */
uint8 _al = (cpu->a & 0x0F) + (_tmp & 0x0F) + (cpu->p & 0x01);
_tmp32 = (cpu->a >> 4) + (_tmp >> 4);
cpu->p = (cpu->p & 0x3C) |
(ZNtable[(uint8)(cpu->a + _tmp + (cpu->p & 0x01))] & 0x02);
/* Adjust the lower half, if needed, adding the half carry to the
upper half. */
if(_al > 9) {
_al += 6;
++_tmp32;
}
/* Set the N flag if the top bit of the upper half is set, as well
as the V flag, if needed. */
cpu->p |= (_tmp32 & 0x08) << 4 |
(((_tmp ^ cpu->a ^ 0x80) & (_tmp ^ (_tmp32 << 4)) & 0x80) >> 1);
/* Adjust the upper half and set the C flag, if needed. */
if(_tmp32 > 9) {
_tmp32 += 6;
cpu->p |= 0x01;
}
/* Store the final result. */
cpu->a = (uint8)((_tmp32 << 4) | (_al & 0x0F));
break;
}
#endif
@@ -193,14 +218,35 @@ ANDOP:
case 0x6B: /* (U) ARR imm */
FETCH_ARG8(_tmp);
#ifndef CRAB6502_NO_DECIMAL
/* Yup... this makes about... zero sense. */
if(cpu->p & 0x08) {
/* XXXX: Support BCD mode */
assert(0);
uint8 _al, _ah;
_tmp32 = _tmp = cpu->a & _tmp;
_ah = _tmp >> 4;
_al = _tmp & 0x0F;
_tmp = (_tmp >> 1) | ((cpu->p & 0x01) << 7);
/* Set all the flags except for C. */
cpu->p = (cpu->p & 0x3C) | ZNtable[_tmp] | ((_tmp32 ^ _tmp) & 0x40);
/* BCD adjust (sorta) the low order bits. */
if(_al + (_al & 0x01) > 5)
_tmp = (_tmp & 0xf0) | ((_tmp + 6) & 0x0F);
/* BCD adjust (sorta) the high order bits, and set C if needed. */
if(_ah + (_ah & 0x01) > 5) {
cpu->p |= 0x01;
_tmp = (_tmp + 0x60);
}
cpu->a = _tmp;
cycles_done += 2;
break;
}
#endif
cpu->a = ((cpu->a & _tmp) >> 1) | (cpu->p << 7);
cpu->p = (cpu->p & 0x3C) | ((cpu->a >> 6) & 0x01) |
cpu->p = (cpu->p & 0x3C) | ((cpu->a >> 6) & 0x01) |
(((cpu->a << 1) ^ cpu->a) & 0x40) | ZNtable[cpu->a];
cycles_done += 2;
break;
@@ -443,13 +489,13 @@ CMPOP:
inst = cpu->y;
cycles_done += 2;
goto CMPOP;
case 0xC4: /* CPY zpg */
FETCH_ARG8(_addr);
inst = cpu->y;
cycles_done += 3;
goto CMPMOP;
case 0xCC: /* CPY abs */
FETCH_ARG16(_addr);
inst = cpu->y;
@@ -793,7 +839,7 @@ LDAMOP:
FETCH_BYTE(_addr, cpu->a);
LDAOP:
cpu->p = (cpu->p & 0x7D) | ZNtable[cpu->a];
break;
case 0xB5: /* LDA zpg, X */
@@ -1295,17 +1341,32 @@ SAXOP:
SBCMOP:
FETCH_BYTE(_addr, _tmp);
SBCOP:
#ifndef CRAB6502_NO_DECIMAL
if(cpu->p & 0x08) {
/* XXXX: Support BCD mode */
assert(0);
break;
}
#endif
/* Flag calculation is the same regardless of whether or not we are in
decimal mode. */
_tmp32 = cpu->a - _tmp - ((cpu->p & 0x01) ^ 0x01);
inst = cpu->p;
cpu->p = (cpu->p & 0x3C) | ZNtable[(uint8)_tmp32] |
(((~_tmp32) >> 8) & 0x01) |
(((_tmp ^ cpu->a) & (cpu->a ^ _tmp32) & 0x80) >> 1);
#ifndef CRAB6502_NO_DECIMAL
/* If we're in decimal mode, calculate the real value that we want in
the accumulator after all is said and done. */
if(cpu->p & 0x08) {
uint8 _al = (cpu->a & 0x0F) - (_tmp & 0x0F) -
((inst & 0x01) ^ 0x01);
if(_al & 0xF0)
_al = (_al - 6) | 0x10;
_tmp = (cpu->a >> 4) - (_tmp >> 4) - ((_al & 0x10) >> 4);
if(_tmp & 0xF0)
_tmp -= 6;
_tmp32 = (_tmp << 4) | (_al & 0x0F);
}
#endif
cpu->a = (uint8)_tmp32;
break;
+142 -32
View File
@@ -1,12 +1,13 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2011, 2012 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2011, 2012, 2015,
2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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
@@ -17,14 +18,16 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "CrabZ80.h"
#include "CrabZ80_tables.h"
#include "CrabZ80_macros.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
static CrabZ80_t *cpu = NULL;
#include "CrabZ80.h"
#include "CrabZ80_tables.h"
#include "CrabZ80_macros.h"
#include "CrabZ80_gbmacros.h"
static Z80 *cpu = NULL;
#ifndef CRABZ80_NO_READMAP_FALLBACK
@@ -38,9 +41,9 @@ static CrabZ80_t *cpu = NULL;
uint16 pc2 = cpu->pc.w + 1; \
uint8 pc_s = cpu->pc.w >> 8; \
uint8 pc2_s = pc2 >> 8; \
name = cpu->readmap[pc_s] ? \
name = (cpu->readmap[pc_s] ? \
cpu->readmap[pc_s][(uint8)cpu->pc.w] : \
cpu->mread(cpu->pc.w) | \
cpu->mread(cpu->pc.w)) | \
((cpu->readmap[pc2_s] ? \
cpu->readmap[pc2_s][(uint8)pc2] : \
cpu->mread(pc2)) << 8); \
@@ -62,6 +65,9 @@ static CrabZ80_t *cpu = NULL;
#endif
static uint32 CrabZ80_exec_z80(Z80 *cpuin, uint32 cycles);
static uint32 CrabZ80_exec_lr35902(Z80 *cpuin, uint32 cycles);
static uint8 CrabZ80_dummy_read(uint16 addr) {
(void)addr;
return 0;
@@ -95,57 +101,57 @@ static void CrabZ80_default_mwrite16(uint16 addr, uint16 data) {
cpu->mwrite(addr, data & 0xFF);
}
void CrabZ80_set_portread(CrabZ80_t *cpuz80, uint8 (*pread)(uint16 port)) {
void CRABZ80_FUNC(set_portread)(Z80 *cpuz80, uint8 (*pread)(uint16 port)) {
if(pread == NULL)
cpuz80->pread = CrabZ80_dummy_read;
else
cpuz80->pread = pread;
}
void CrabZ80_set_memread(CrabZ80_t *cpuz80, uint8 (*mread)(uint16 addr)) {
void CRABZ80_FUNC(set_memread)(Z80 *cpuz80, uint8 (*mread)(uint16 addr)) {
if(mread == NULL)
cpuz80->mread = CrabZ80_dummy_read;
else
cpuz80->mread = mread;
}
void CrabZ80_set_portwrite(CrabZ80_t *cpuz80,
void (*pwrite)(uint16 port, uint8 data)) {
void CRABZ80_FUNC(set_portwrite)(Z80 *cpuz80,
void (*pwrite)(uint16 port, uint8 data)) {
if(pwrite == NULL)
cpuz80->pwrite = CrabZ80_dummy_write;
else
cpuz80->pwrite = pwrite;
}
void CrabZ80_set_memwrite(CrabZ80_t *cpuz80,
void (*mwrite)(uint16 addr, uint8 data)) {
void CRABZ80_FUNC(set_memwrite)(Z80 *cpuz80,
void (*mwrite)(uint16 addr, uint8 data)) {
if(mwrite == NULL)
cpuz80->mwrite = CrabZ80_dummy_write;
else
cpuz80->mwrite = mwrite;
}
void CrabZ80_set_memread16(CrabZ80_t *cpuz80,
uint16 (*mread16)(uint16 addr)) {
void CRABZ80_FUNC(set_memread16)(Z80 *cpuz80,
uint16 (*mread16)(uint16 addr)) {
if(mread16 == NULL)
cpuz80->mread16 = CrabZ80_default_mread16;
else
cpuz80->mread16 = mread16;
}
void CrabZ80_set_memwrite16(CrabZ80_t *cpuz80,
void (*mwrite16)(uint16 addr, uint16 data)) {
void CRABZ80_FUNC(set_memwrite16)(Z80 *cpuz80,
void (*mwrite16)(uint16 addr, uint16 data)) {
if(mwrite16 == NULL)
cpuz80->mwrite16 = CrabZ80_default_mwrite16;
else
cpuz80->mwrite16 = mwrite16;
}
void CrabZ80_set_readmap(CrabZ80_t *cpuz80, uint8 *readmap[256]) {
void CRABZ80_FUNC(set_readmap)(Z80 *cpuz80, uint8 *readmap[256]) {
memcpy(cpuz80->readmap, readmap, 256 * sizeof(uint8 *));
}
void CrabZ80_init(CrabZ80_t *cpuz80) {
void CRABZ80_FUNC(init)(Z80 *cpuz80, int model) {
cpuz80->pread = CrabZ80_dummy_read;
cpuz80->mread = CrabZ80_dummy_read;
cpuz80->pwrite = CrabZ80_dummy_write;
@@ -154,9 +160,24 @@ void CrabZ80_init(CrabZ80_t *cpuz80) {
cpuz80->mwrite16 = CrabZ80_default_mwrite16;
memset(cpuz80->readmap, 0, 256 * sizeof(uint8 *));
switch(model) {
case CRABZ80_CPU_Z80:
cpuz80->exec = &CrabZ80_exec_z80;
break;
case CRABZ80_CPU_LR35902:
cpuz80->exec = &CrabZ80_exec_lr35902;
break;
default:
fprintf(stderr, "Unknown CPU type (%d), selecting Z80.\n", model);
cpuz80->exec = &CrabZ80_exec_z80;
break;
}
}
void CrabZ80_reset(CrabZ80_t *cpuz80) {
void CRABZ80_FUNC(reset)(Z80 *cpuz80) {
cpuz80->pc.w = 0x0000;
cpuz80->iff1 = 0;
cpuz80->iff2 = 0;
@@ -181,7 +202,7 @@ void CrabZ80_reset(CrabZ80_t *cpuz80) {
cpuz80->irq_pending = 0;
}
static uint32 CrabZ80_take_nmi(CrabZ80_t *cpuz80) {
static uint32 CrabZ80_take_nmi(Z80 *cpuz80) {
if(cpuz80->halt) {
cpuz80->pc.w++;
cpuz80->halt = 0;
@@ -201,7 +222,7 @@ static uint32 CrabZ80_take_nmi(CrabZ80_t *cpuz80) {
return 11;
}
static uint32 CrabZ80_take_irq(CrabZ80_t *cpuz80) {
static uint32 CrabZ80_take_irq(Z80 *cpuz80) {
if(cpuz80->halt) {
cpuz80->pc.w++;
cpuz80->halt = 0;
@@ -223,7 +244,7 @@ static uint32 CrabZ80_take_irq(CrabZ80_t *cpuz80) {
case 0:
case 1:
cpuz80->sp.w -= 2;
cpuz80->mwrite16(cpu->sp.w, cpu->pc.w);
cpuz80->mwrite16(cpuz80->sp.w, cpuz80->pc.w);
cpuz80->pc.w = 0x0038;
return 13;
@@ -231,8 +252,8 @@ static uint32 CrabZ80_take_irq(CrabZ80_t *cpuz80) {
{
uint16 tmp = (cpuz80->ir.b.h << 8) + (cpuz80->irq_vector & 0xFF);
cpuz80->sp.w -= 2;
cpuz80->mwrite16(cpu->sp.w, cpu->pc.w);
cpuz80->pc.w = cpu->mread16(tmp);
cpuz80->mwrite16(cpuz80->sp.w, cpuz80->pc.w);
cpuz80->pc.w = cpuz80->mread16(tmp);
return 19;
}
@@ -246,24 +267,37 @@ static uint32 CrabZ80_take_irq(CrabZ80_t *cpuz80) {
}
}
void CrabZ80_pulse_nmi(CrabZ80_t *cpuz80) {
void CRABZ80_FUNC(pulse_nmi)(Z80 *cpuz80) {
cpuz80->irq_pending |= 2;
}
void CrabZ80_assert_irq(CrabZ80_t *cpuz80, uint32 vector) {
void CRABZ80_FUNC(assert_irq)(Z80 *cpuz80, uint32 vector) {
cpuz80->irq_pending |= 1;
cpuz80->irq_vector = vector;
}
void CrabZ80_clear_irq(CrabZ80_t *cpuz80) {
void CRABZ80_FUNC(clear_irq)(Z80 *cpuz80) {
cpuz80->irq_pending &= 2;
}
void CrabZ80_release_cycles(CrabZ80_t *cpuz80) {
void CRABZ80_FUNC(set_irqflag_lr35902)(Z80 *cpuz80, uint8 irqs) {
cpuz80->irq_pending = irqs;
}
void CRABZ80_FUNC(set_irqen_lr35902)(Z80 *cpuz80, uint8 irqs) {
/* Reuse IFF2, since it doesn't exist on the LR35902. */
cpuz80->iff2 = irqs;
}
void CRABZ80_FUNC(release_cycles)(Z80 *cpuz80) {
cpuz80->cycles_in = 0;
}
uint32 CrabZ80_execute(CrabZ80_t *cpuin, uint32 cycles) {
uint32 CRABZ80_FUNC(execute)(Z80 *cpuin, uint32 cycles) {
return cpuin->exec(cpuin, cycles);
}
static uint32 CrabZ80_exec_z80(Z80 *cpuin, uint32 cycles) {
register uint32 cycles_done = 0;
CrabZ80_t *oldcpu = NULL;
uint32 oldcyclesin = 0, oldcycles = 0;
@@ -311,3 +345,79 @@ out:
return cycles_done;
}
static uint32 CrabZ80_exec_lr35902(Z80 *cpuin, uint32 cycles) {
register uint32 cycles_done = 0;
CrabZ80_t *oldcpu = NULL;
uint32 oldcyclesin = 0, oldcycles = 0;
if(cpu) {
oldcyclesin = cpu->cycles_in;
oldcycles = cpu->cycles;
oldcpu = cpu;
}
cpu = cpuin;
cycles_done = 0;
cpuin->cycles_in = cycles;
cpuin->cycles = 0;
while(cycles_done < cpuin->cycles_in) {
/* If interrupts are enabled, then check if we have any waiting. */
if(!cpuin->ei && cpuin->iff1) {
uint8 irqs;
/* Do we actually have any IRQs pending? */
irqs = cpuin->irq_pending & cpuin->iff2;
if(irqs) {
uint8 i;
/* Un-halt the CPU if it is halted. */
if(cpuin->halt) {
cpuin->pc.w++;
cpuin->halt = 0;
}
/* Look through all interrupts being asserted (that are enabled)
until we find the highest priority one being asserted. */
for(i = 0; i < 5; ++i) {
if((irqs & (1 << i))) {
/* Clear the IRQ pending flag and disable interrupts. */
cpuin->irq_pending &= ~(1 << i);
cpuin->iff1 = 0;
/* Push the PC onto the stack and set the new PC. */
cpuin->sp.w -= 2;
cpuin->mwrite16(cpuin->sp.w, cpuin->pc.w);
cpuin->pc.w = 0x40 + (i << 3);
cycles_done += 12;
goto out;
}
}
}
}
cpuin->ei = 0;
{
uint8 inst;
FETCH_ARG8(inst);
++cpuin->ir.b.l;
#define INSIDE_CRABZ80_GBEXECUTE
#include "CrabZ80gbops.h"
#undef INSIDE_CRABZ80_GBEXECUTE
}
out:
cpuin->cycles = cycles_done;
}
cpu = oldcpu;
if(cpu) {
cpu->cycles = oldcycles;
cpu->cycles_in = oldcyclesin;
}
return cycles_done;
}
+81 -37
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2009 Lawrence Sebald
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -52,8 +52,38 @@ typedef uint32_t int32;
#endif /* CRABEMU_TYPEDEFS */
#endif /* IN_CRABEMU */
/******************************************************************************
DANGER WILL ROBINSON!
No User-serviceable parts below this block.
DANGER WILL ROBINSON!
******************************************************************************/
CLINKAGE
#ifndef CRABZ80_PREFIX
#define CRABZ80_PREFIX CrabZ80
#endif
/* Because any of this makes sense... */
#define CRABZ80_SYM_3(x, y) x ## _ ## y
#define CRABZ80_SYM_2(x, y) CRABZ80_SYM_3(x, y)
#define CRABZ80_SYM(x) CRABZ80_SYM_2(CRABZ80_PREFIX, x)
#define CRABZ80_FUNC(fn) CRABZ80_SYM(fn)
#define CRABZ80_CPU CRABZ80_SYM(t)
#define Z80 CRABZ80_CPU
/* CPU Types.
These control various parts of the code to implement emulation for different
Z80-like CPUs. */
#define CRABZ80_CPU_Z80 0
#define CRABZ80_CPU_LR35902 1
#define CRABZ80_CPU_GB CRABZ80_CPU_LR35902
#define CRABZ80_CPU_MAX 1 /* Don't use this one... */
typedef union {
struct {
#ifdef __BIG_ENDIAN__
@@ -66,7 +96,7 @@ typedef union {
} b;
uint8 bytes[2];
uint16 w;
} CrabZ80_reg_t;
} CRABZ80_SYM(reg_t);
typedef union {
struct {
@@ -79,7 +109,7 @@ typedef union {
#endif
} b;
uint16 w;
} CrabZ80_regAF_t;
} CRABZ80_SYM(regAF_t);
#ifdef __BIG_ENDIAN__
#define REG8(x) cpu->regs8[(x) & 0x07]
@@ -91,28 +121,28 @@ typedef union {
#define REG16(x) cpu->regs16[(x) & 0x03]
typedef struct CrabZ80_struct {
typedef struct CRABZ80_SYM(struct) {
union {
uint8 regs8[8];
uint16 regs16[4];
struct {
CrabZ80_reg_t bc;
CrabZ80_reg_t de;
CrabZ80_reg_t hl;
CrabZ80_regAF_t af;
CRABZ80_SYM(reg_t) bc;
CRABZ80_SYM(reg_t) de;
CRABZ80_SYM(reg_t) hl;
CRABZ80_SYM(regAF_t) af;
};
};
CrabZ80_reg_t ix;
CrabZ80_reg_t iy;
CrabZ80_reg_t pc;
CrabZ80_reg_t sp;
CrabZ80_reg_t ir;
CrabZ80_regAF_t afp;
CrabZ80_reg_t bcp;
CrabZ80_reg_t dep;
CrabZ80_reg_t hlp;
CRABZ80_SYM(reg_t) ix;
CRABZ80_SYM(reg_t) iy;
CRABZ80_SYM(reg_t) pc;
CRABZ80_SYM(reg_t) sp;
CRABZ80_SYM(reg_t) ir;
CRABZ80_SYM(regAF_t) afp;
CRABZ80_SYM(reg_t) bcp;
CRABZ80_SYM(reg_t) dep;
CRABZ80_SYM(reg_t) hlp;
CrabZ80_reg_t *offset;
CRABZ80_SYM(reg_t) *offset;
uint8 iff1;
uint8 iff2;
@@ -137,8 +167,10 @@ typedef struct CrabZ80_struct {
uint16 (*mread16)(uint16 addr);
void (*mwrite16)(uint16 addr, uint16 data);
uint32 (*exec)(struct CRABZ80_SYM(struct) *, uint32);
uint8 *readmap[256];
} CrabZ80_t;
} CRABZ80_SYM(t);
/* Flag definitions */
#define CRABZ80_CF 0
@@ -150,35 +182,47 @@ typedef struct CrabZ80_struct {
#define CRABZ80_ZF 6
#define CRABZ80_SF 7
/* Flags when emulating an LR35902. Other flag bits are all 0. */
#define CRABZ80_LR35902_CF 4
#define CRABZ80_LR35902_HF 5
#define CRABZ80_LR35902_NF 6
#define CRABZ80_LR35902_ZF 7
/* Flag setting macros */
#define CRABZ80_SET_FLAG(z80, n) (z80)->af.b.l |= (1 << (n))
#define CRABZ80_CLEAR_FLAG(z80, n) (z80)->af.b.l &= (~(1 << (n)))
#define CRABZ80_GET_FLAG(z80, n) ((z80)->af.b.l >> (n)) & 1
/* Function definitions */
void CrabZ80_init(CrabZ80_t *cpu);
void CrabZ80_reset(CrabZ80_t *cpu);
void CRABZ80_FUNC(init)(Z80 *cpu, int model);
void CRABZ80_FUNC(reset)(Z80 *cpu);
void CrabZ80_pulse_nmi(CrabZ80_t *cpu);
void CrabZ80_assert_irq(CrabZ80_t *cpu, uint32 vector);
void CrabZ80_clear_irq(CrabZ80_t *cpu);
/* Z80 IRQs. */
void CRABZ80_FUNC(pulse_nmi)(Z80 *cpu);
void CRABZ80_FUNC(assert_irq)(Z80 *cpu, uint32 vector);
void CRABZ80_FUNC(clear_irq)(Z80 *cpu);
uint32 CrabZ80_execute(CrabZ80_t *cpu, uint32 cycles);
/* LR35902 IRQs. */
void CRABZ80_FUNC(set_irqflag_lr35902)(Z80 *cpuz80, uint8 irqs);
void CRABZ80_FUNC(set_irqen_lr35902)(Z80 *cpuz80, uint8 irqs);
void CrabZ80_release_cycles();
uint32 CRABZ80_FUNC(execute)(Z80 *cpu, uint32 cycles);
void CrabZ80_set_portread(CrabZ80_t *cpu, uint8 (*pread)(uint16 port));
void CrabZ80_set_memread(CrabZ80_t *cpu, uint8 (*mread)(uint16 addr));
void CrabZ80_set_portwrite(CrabZ80_t *cpu,
void (*pwrite)(uint16 port, uint8 data));
void CrabZ80_set_memwrite(CrabZ80_t *cpu,
void (*mwrite)(uint16 addr, uint8 data));
void CRABZ80_FUNC(release_cycles)(Z80 *cpu);
void CrabZ80_set_memread16(CrabZ80_t *cpu, uint16 (*mread16)(uint16 addr));
void CrabZ80_set_memwrite16(CrabZ80_t *cpu,
void (*mwrite16)(uint16 addr, uint16 data));
void CRABZ80_FUNC(set_portread)(Z80 *cpu, uint8 (*pread)(uint16 port));
void CRABZ80_FUNC(set_memread)(Z80 *cpu, uint8 (*mread)(uint16 addr));
void CRABZ80_FUNC(set_portwrite)(Z80 *cpu,
void (*pwrite)(uint16 port, uint8 data));
void CRABZ80_FUNC(set_memwrite)(Z80 *cpu,
void (*mwrite)(uint16 addr, uint8 data));
void CrabZ80_set_readmap(CrabZ80_t *cpuz80, uint8 *readmap[256]);
void CRABZ80_FUNC(set_memread16)(Z80 *cpu,
uint16 (*mread16)(uint16 addr));
void CRABZ80_FUNC(set_memwrite16)(Z80 *cpu,
void (*mwrite16)(uint16 addr, uint16 data));
void CRABZ80_FUNC(set_readmap)(Z80 *cpu, uint8 *readmap[256]);
ENDCLINK
+133
View File
@@ -0,0 +1,133 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2015, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define GB_INC8(val) { \
uint32 _tmp = (val) + 1; \
cpu->af.b.l = ((!_tmp) << 7) | \
((_tmp & 0x0F) ? 0x00 : 0x20) | \
(cpu->af.b.l & 0x10); \
(val) = _tmp; \
}
#define GB_DEC8(val) { \
uint32 _tmp = (val) - 1; \
cpu->af.b.l = ((!_tmp) << 7) | \
(cpu->af.b.l & 0x01) | \
((((val) ^ _tmp) & 0x10) << 1) | \
0x40; \
(val) = _tmp; \
}
#define GB_RLCA() { \
cpu->af.b.h = (cpu->af.b.h << 1) | (cpu->af.b.h >> 7); \
cpu->af.b.l = (cpu->af.b.l & 0xEF) | ((cpu->af.b.h & 0x01) << 4); \
}
#define GB_RRCA() { \
cpu->af.b.l = (cpu->af.b.l & 0xEF) | ((cpu->af.b.h & 0x01) << 4); \
cpu->af.b.h = (cpu->af.b.h >> 1) | (cpu->af.b.h << 7); \
}
#define GB_RLA() { \
cpu->af.b.l = (cpu->af.b.l & 0xEF) | ((cpu->af.b.h >> 3) & 0x10); \
cpu->af.b.h = (cpu->af.b.h << 1) | (cpu->af.b.l & 0x01); \
}
#define GB_RRA() { \
cpu->af.b.l = (cpu->af.b.l & 0xEF) | ((cpu->af.b.h & 0x01) << 4); \
cpu->af.b.h = (cpu->af.b.h >> 1) | (cpu->af.b.l << 7); \
}
#define GB_CPL() { \
cpu->af.b.h ^= 0xFF; \
cpu->af.b.l = (cpu->af.b.l & 0x9F) | 0x60; \
}
#define GB_SCF() { \
cpu->af.b.l = (cpu->af.b.l & 0x80) | 0x10; \
}
#define GB_CCF() { \
cpu->af.b.l = (cpu->af.b.l & 0x80) | ((cpu->af.b.l ^ 0x10) & 0x10); \
}
#define GB_ADD() { \
uint32 _tmp = cpu->af.b.h + _value; \
cpu->af.b.l = ((!((uint8)_tmp)) << 7) | \
(((cpu->af.b.h ^ _tmp ^ _value) & 0x10) << 1) | \
((_tmp >> 4) & 0x10); \
cpu->af.b.h = _tmp; \
}
#define GB_ADC() { \
uint32 _tmp = cpu->af.b.h + _value + (cpu->af.b.l & 0x01); \
cpu->af.b.l = ((!((uint8)_tmp)) << 7) | \
(((cpu->af.b.h ^ _tmp ^ _value) & 0x10) << 1) | \
((_tmp >> 4) & 0x10); \
cpu->af.b.h = _tmp; \
}
#define GB_SUB() { \
uint32 _tmp = cpu->af.b.h - _value; \
cpu->af.b.l = ((!((uint8)_tmp)) << 7) | \
(((cpu->af.b.h ^ _tmp ^ _value) & 0x10) << 1) | \
0x40 | ((_tmp >> 4) & 0x10); \
cpu->af.b.h = _tmp; \
}
#define GB_SBC() { \
uint32 _tmp = cpu->af.b.h - (cpu->af.b.l & 0x01) - _value; \
cpu->af.b.l = ((!((uint8)_tmp)) << 7) | \
(((cpu->af.b.h ^ _tmp ^ _value) & 0x10) << 1) | \
0x40 | ((_tmp >> 4) & 0x10); \
cpu->af.b.h = _tmp; \
}
#define GB_AND() { \
uint32 _tmp = cpu->af.b.h & _value; \
cpu->af.b.l = ((!_tmp) << 7) | 0x10; \
cpu->af.b.h = _tmp; \
}
#define GB_XOR() { \
uint32 _tmp = cpu->af.b.h ^ _value; \
cpu->af.b.l = ((!_tmp) << 7); \
cpu->af.b.h = _tmp; \
}
#define GB_OR() { \
uint32 _tmp = cpu->af.b.h | _value; \
cpu->af.b.l = ((!_tmp) << 7); \
cpu->af.b.h = _tmp; \
}
#define GB_CP() { \
uint32 _tmp = cpu->af.b.h - _value; \
cpu->af.b.l = ((!((uint8)_tmp)) << 7) | \
(((cpu->af.b.h ^ _tmp ^ _value) & 0x10) << 1) | \
0x40 | ((_tmp >> 4) & 0x10); \
}
#define GB_ADDHL() { \
uint32 _tmp = cpu->hl.w + _value; \
cpu->af.b.l = (cpu->af.b.l & 0x8F) | \
(((cpu->hl.w ^ _tmp ^ _value) >> 7) & 0x20) | \
((_tmp >> 12) & 0x10); \
cpu->hl.w = _tmp; \
}
+2 -2
View File
@@ -4,7 +4,7 @@
Copyright (C) 2005, 2006, 2007, 2008 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -350,7 +350,7 @@
#define OP_ADDIx() { \
uint32 _tmp = cpu->offset->w + _value; \
cpu->af.b.l = (cpu->af.b.l & 0xC4) | \
cpu->af.b.l = (cpu->af.b.l & 0xC4) | \
(((cpu->offset->w ^ _tmp ^ _value) >> 8) & 0x10) | \
((_tmp >> 8) & 0x28) | \
((_tmp >> 16) & 0x01); \
+1 -1
View File
@@ -4,7 +4,7 @@
Copyright (C) 2005, 2006 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
+877
View File
@@ -0,0 +1,877 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2015, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INSIDE_CRABZ80_GBEXECUTE
#error This file can only be compiled inside of CrabZ80.c. Do not try to include
#error this file in other files.
#endif
{
uint32 _value;
uint32 _tmp;
switch(inst) {
case 0x00: /* NOP */ //d
case 0x40: /* LD B, B */ //d
case 0x49: /* LD C, C */ //d
case 0x52: /* LD D, D */ //d
case 0x5B: /* LD E, E */ //d
case 0x64: /* LD H, H */ //d
case 0x6D: /* LD L, L */ //d
case 0x7F: /* LD A, A */ //d
cycles_done += 4;
goto out;
case 0x01: /* LD BC, nn */ //d
case 0x11: /* LD DE, nn */ //d
case 0x21: /* LD HL, nn */ //d
FETCH_ARG16(_value);
REG16(inst >> 4) = _value;
cycles_done += 12;
goto out;
case 0x31: /* LD SP, nn */ //d
FETCH_ARG16(_value);
cpu->sp.w = _value;
cycles_done += 12;
goto out;
case 0x02: /* LD (BC), A */ //d
case 0x12: /* LD (DE), A */ //d
cpu->mwrite(REG16(inst >> 4), cpu->af.b.h);
cycles_done += 8;
goto out;
case 0x03: /* INC BC */ //d
++cpu->bc.w;
cycles_done += 8;
goto out;
case 0x13: /* INC DE */ //d
++cpu->de.w;
cycles_done += 8;
goto out;
case 0x23: /* INC HL */ //d
++cpu->hl.w;
cycles_done += 8;
goto out;
case 0x33: /* INC SP */ //d
++cpu->sp.w;
cycles_done += 8;
goto out;
case 0x04: /* INC B */ //d
case 0x0C: /* INC C */ //d
case 0x14: /* INC D */ //d
case 0x1C: /* INC E */ //d
case 0x24: /* INC H */ //d
case 0x2C: /* INC L */ //d
case 0x3C: /* INC A */ //d
_value = REG8(inst >> 3);
GB_INC8(_value);
REG8(inst >> 3) = _value;
cycles_done += 4;
goto out;
case 0x34: /* INC (HL) */ //d
_value = cpu->mread(cpu->hl.w);
GB_INC8(_value);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 12;
goto out;
case 0x05: /* DEC B */ //d
case 0x0D: /* DEC C */ //d
case 0x15: /* DEC D */ //d
case 0x1D: /* DEC E */ //d
case 0x25: /* DEC H */ //d
case 0x2D: /* DEC L */ //d
case 0x3D: /* DEC A */ //d
_value = REG8(inst >> 3);
GB_DEC8(_value);
REG8(inst >> 3) = _value;
cycles_done += 4;
goto out;
case 0x35: /* DEC (HL) */ //d
_value = cpu->mread(cpu->hl.w);
GB_DEC8(_value);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 12;
goto out;
case 0x06: /* LD B, n */ //d
case 0x0E: /* LD C, n */ //d
case 0x16: /* LD D, n */ //d
case 0x1E: /* LD E, n */ //d
case 0x26: /* LD H, n */ //d
case 0x2E: /* LD L, n */ //d
case 0x3E: /* LD A, n */ //d
FETCH_ARG8(_value);
REG8(inst >> 3) = _value;
cycles_done += 8;
goto out;
case 0x36: /* LD (HL), n */ //d
FETCH_ARG8(_value);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 12;
goto out;
case 0x07: /* RLCA */ //d
GB_RLCA();
cycles_done += 4;
goto out;
case 0x09: /* ADD HL, BC */ //d
case 0x19: /* ADD HL, DE */ //d
case 0x29: /* ADD HL, HL */ //d
_value = REG16(inst >> 4);
ADDHLOP:
cpu->internal_reg = cpu->hl.b.h;
GB_ADDHL();
cycles_done += 8;
goto out;
case 0x39: /* ADD HL, SP */ //d
_value = cpu->sp.w;
goto ADDHLOP;
case 0x0A: /* LD A, (BC) */ //d
case 0x1A: /* LD A, (DE) */ //d
cpu->af.b.h = cpu->mread(REG16(inst >> 4));
cycles_done += 8;
goto out;
case 0x0B: /* DEC BC */ //d
--cpu->bc.w;
cycles_done += 8;
goto out;
case 0x1B: /* DEC DE */ //d
--cpu->de.w;
cycles_done += 8;
goto out;
case 0x2B: /* DEC HL */ //d
--cpu->hl.w;
cycles_done += 8;
goto out;
case 0x3B: /* DEC SP */ //d
--cpu->sp.w;
cycles_done += 8;
goto out;
case 0x0F: /* RRCA */ //d
GB_RRCA();
cycles_done += 4;
goto out;
case 0x18: /* JR e */ //d
JROP:
FETCH_ARG8(_value);
cpu->pc.w += (int8)_value;
cycles_done += 12;
cpu->internal_reg = cpu->pc.b.h;
goto out;
case 0x20: /* JR NZ, e */ //d
if(!(cpu->af.b.l & 0x80)) {
goto JROP;
}
++cpu->pc.w;
cycles_done += 8;
goto out;
case 0x28: /* JR Z, e */ //d
if(cpu->af.b.l & 0x80) {
goto JROP;
}
++cpu->pc.w;
cycles_done += 8;
goto out;
case 0x30: /* JR NC, e */ //d
if(!(cpu->af.b.l & 0x10)) {
goto JROP;
}
++cpu->pc.w;
cycles_done += 8;
goto out;
case 0x38: /* JR C, e */ //d
if(cpu->af.b.l & 0x10) {
goto JROP;
}
++cpu->pc.w;
cycles_done += 8;
goto out;
case 0x17: /* RLA */ //d
GB_RLA();
cycles_done += 4;
goto out;
case 0x1F: /* RRA */ //d
GB_RRA();
cycles_done += 4;
goto out;
case 0x27: /* DAA */ //d
{
int low = cpu->af.b.h & 0x0F;
int high = cpu->af.b.h >> 4;
int cf = cpu->af.b.l & 0x10;
int hf = cpu->af.b.l & 0x20;
int nf = cpu->af.b.l & 0x40;
if(cf) {
_value = (low < 0x0A && !hf) ? 0x60 : 0x66;
}
else {
if(low < 0x0A) {
if(high < 0x0A) {
_value = (hf) ? 0x06 : 0x00;
}
else {
_value = (hf) ? 0x66 : 0x60;
}
}
else {
_value = (high < 0x09) ? 0x06 : 0x66;
}
}
if(nf) {
cpu->af.b.h -= _value;
}
else {
cpu->af.b.h += _value;
}
cpu->af.b.l = ((!cpu->af.b.h) << 7) | (nf);
if(_value >= 0x60)
cpu->af.b.l |= 0x01;
if(nf) {
if(hf && low < 0x06) {
cpu->af.b.l |= 0x10;
}
}
else if(low >= 10) {
cpu->af.b.l |= 0x10;
}
cycles_done += 4;
goto out;
}
case 0x2F: /* CPL */ //d
GB_CPL();
cycles_done += 4;
goto out;
case 0x37: /* SCF */ //d
GB_SCF();
cycles_done += 4;
goto out;
case 0x3F: /* CCF */ //d
GB_CCF();
cycles_done += 4;
goto out;
case 0x41: /* LD B, C */ //d
case 0x42: /* LD B, D */ //d
case 0x43: /* LD B, E */ //d
case 0x44: /* LD B, H */ //d
case 0x45: /* LD B, L */ //d
case 0x47: /* LD B, A */ //d
case 0x48: /* LD C, B */ //d
case 0x4A: /* LD C, D */ //d
case 0x4B: /* LD C, E */ //d
case 0x4C: /* LD C, H */ //d
case 0x4D: /* LD C, L */ //d
case 0x4F: /* LD C, A */ //d
case 0x50: /* LD D, B */ //d
case 0x51: /* LD D, C */ //d
case 0x53: /* LD D, E */ //d
case 0x54: /* LD D, H */ //d
case 0x55: /* LD D, L */ //d
case 0x57: /* LD D, A */ //d
case 0x58: /* LD E, B */ //d
case 0x59: /* LD E, C */ //d
case 0x5A: /* LD E, D */ //d
case 0x5C: /* LD E, H */ //d
case 0x5D: /* LD E, L */ //d
case 0x5F: /* LD E, A */ //d
case 0x60: /* LD H, B */ //d
case 0x61: /* LD H, C */ //d
case 0x62: /* LD H, D */ //d
case 0x63: /* LD H, E */ //d
case 0x65: /* LD H, L */ //d
case 0x67: /* LD H, A */ //d
case 0x68: /* LD L, B */ //d
case 0x69: /* LD L, C */ //d
case 0x6A: /* LD L, D */ //d
case 0x6B: /* LD L, E */ //d
case 0x6C: /* LD L, H */ //d
case 0x6F: /* LD L, A */ //d
case 0x78: /* LD A, B */ //d
case 0x79: /* LD A, C */ //d
case 0x7A: /* LD A, D */ //d
case 0x7B: /* LD A, E */ //d
case 0x7C: /* LD A, H */ //d
case 0x7D: /* LD A, L */ //d
REG8(inst >> 3) = REG8(inst);
cycles_done += 4;
goto out;
case 0x46: /* LD B, (HL) */ //d
case 0x4E: /* LD C, (HL) */ //d
case 0x56: /* LD D, (HL) */ //d
case 0x5E: /* LD E, (HL) */ //d
case 0x66: /* LD H, (HL) */ //d
case 0x6E: /* LD L, (HL) */ //d
case 0x7E: /* LD A, (HL) */ //d
REG8(inst >> 3) = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto out;
case 0x70: /* LD (HL), B */ //d
case 0x71: /* LD (HL), C */ //d
case 0x72: /* LD (HL), D */ //d
case 0x73: /* LD (HL), E */ //d
case 0x74: /* LD (HL), H */ //d
case 0x75: /* LD (HL), L */ //d
case 0x77: /* LD (HL), A */ //d
cpu->mwrite(cpu->hl.w, REG8(inst));
cycles_done += 8;
goto out;
case 0x76: /* HALT */ //d
--cpu->pc.w;
cpu->halt = 1;
cycles_done += 4;
goto out;
case 0x80: /* ADD A, B */ //d
case 0x81: /* ADD A, C */ //d
case 0x82: /* ADD A, D */ //d
case 0x83: /* ADD A, E */ //d
case 0x84: /* ADD A, H */ //d
case 0x85: /* ADD A, L */ //d
case 0x87: /* ADD A, A */ //d
_value = REG8(inst);
cycles_done += 4;
ADDOP:
GB_ADD();
goto out;
case 0x86: /* ADD A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto ADDOP;
case 0xC6: /* ADD A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto ADDOP;
case 0x88: /* ADC A, B */ //d
case 0x89: /* ADC A, C */ //d
case 0x8A: /* ADC A, D */ //d
case 0x8B: /* ADC A, E */ //d
case 0x8C: /* ADC A, H */ //d
case 0x8D: /* ADC A, L */ //d
case 0x8F: /* ADC A, A */ //d
_value = REG8(inst);
cycles_done += 4;
ADCOP:
GB_ADC();
goto out;
case 0x8E: /* ADC A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto ADCOP;
case 0xCE: /* ADC A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto ADCOP;
case 0x90: /* SUB A, B */ //d
case 0x91: /* SUB A, C */ //d
case 0x92: /* SUB A, D */ //d
case 0x93: /* SUB A, E */ //d
case 0x94: /* SUB A, H */ //d
case 0x95: /* SUB A, L */ //d
case 0x97: /* SUB A, A */ //d
_value = REG8(inst);
cycles_done += 4;
SUBOP:
GB_SUB();
goto out;
case 0x96: /* SUB A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto SUBOP;
case 0xD6: /* SUB A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto SUBOP;
case 0x98: /* SBC A, B */ //d
case 0x99: /* SBC A, C */ //d
case 0x9A: /* SBC A, D */ //d
case 0x9B: /* SBC A, E */ //d
case 0x9C: /* SBC A, H */ //d
case 0x9D: /* SBC A, L */ //d
case 0x9F: /* SBC A, A */ //d
_value = REG8(inst);
cycles_done += 4;
SBCOP:
GB_SBC();
goto out;
case 0x9E: /* SBC A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto SBCOP;
case 0xDE: /* SBC A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto SBCOP;
case 0xA0: /* AND A, B */ //d
case 0xA1: /* AND A, C */ //d
case 0xA2: /* AND A, D */ //d
case 0xA3: /* AND A, E */ //d
case 0xA4: /* AND A, H */ //d
case 0xA5: /* AND A, L */ //d
case 0xA7: /* AND A, A */ //d
_value = REG8(inst);
cycles_done += 4;
ANDOP:
GB_AND();
goto out;
case 0xA6: /* AND A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto ANDOP;
case 0xE6: /* AND A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto ANDOP;
case 0xA8: /* XOR A, B */ //d
case 0xA9: /* XOR A, C */ //d
case 0xAA: /* XOR A, D */ //d
case 0xAB: /* XOR A, E */ //d
case 0xAC: /* XOR A, H */ //d
case 0xAD: /* XOR A, L */ //d
case 0xAF: /* XOR A, A */ //d
_value = REG8(inst);
cycles_done += 4;
XOROP:
GB_XOR();
goto out;
case 0xAE: /* XOR A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto XOROP;
case 0xEE: /* XOR A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto XOROP;
case 0xB0: /* OR A, B */ //d
case 0xB1: /* OR A, C */ //d
case 0xB2: /* OR A, D */ //d
case 0xB3: /* OR A, E */ //d
case 0xB4: /* OR A, H */ //d
case 0xB5: /* OR A, L */ //d
case 0xB7: /* OR A, A */ //d
_value = REG8(inst);
cycles_done += 4;
OROP:
GB_OR();
goto out;
case 0xB6: /* OR A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto OROP;
case 0xF6: /* OR A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto OROP;
case 0xB8: /* CP A, B */ //d
case 0xB9: /* CP A, C */ //d
case 0xBA: /* CP A, D */ //d
case 0xBB: /* CP A, E */ //d
case 0xBC: /* CP A, H */ //d
case 0xBD: /* CP A, L */ //d
case 0xBF: /* CP A, A */ //d
_value = REG8(inst);
cycles_done += 4;
CPOP:
GB_CP();
goto out;
case 0xBE: /* CP A, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cycles_done += 8;
goto CPOP;
case 0xFE: /* CP A, n */ //d
FETCH_ARG8(_value);
cycles_done += 8;
goto CPOP;
case 0xC0: /* RET NZ */ //d
if(!(cpu->af.b.l & 0x80)) {
cycles_done += 4;
goto RETOP;
}
cycles_done += 8;
goto out;
case 0xC8: /* RET Z */ //d
if(!(cpu->af.b.l & 0x80)) {
cycles_done += 8;
goto out;
}
cycles_done += 4;
/* Fall through... */
case 0xC9: /* RET */ //d
RETOP:
cpu->pc.w = cpu->mread16(cpu->sp.w);
cpu->sp.w += 2;
cycles_done += 16;
goto out;
case 0xD0: /* RET NC */ //d
if(!(cpu->af.b.l & 0x10)) {
cycles_done += 4;
goto RETOP;
}
cycles_done += 8;
goto out;
case 0xD8: /* RET C */ //d
if(cpu->af.b.l & 0x10) {
cycles_done += 4;
goto RETOP;
}
cycles_done += 8;
goto out;
case 0xC1: /* POP BC */ //d
case 0xD1: /* POP DE */ //d
case 0xE1: /* POP HL */ //d
REG16(inst >> 4) = cpu->mread16(cpu->sp.w);
cpu->sp.w += 2;
cycles_done += 12;
goto out;
case 0xF1: /* POP AF */ //d
cpu->af.b.l = cpu->mread(cpu->sp.w++);
cpu->af.b.h = cpu->mread(cpu->sp.w++);
cycles_done += 12;
goto out;
case 0xC2: /* JP NZ, ee */ //d
if(cpu->af.b.l & 0x80)
goto out_nocondjump;
cycles_done += 4;
/* Fall through... */
case 0xC3: /* JP ee */ //d
JPOP:
FETCH_ARG16(_value);
cpu->pc.w = _value;
cycles_done += 16;
goto out;
case 0xCA: /* JP Z, ee */ //d
if(cpu->af.b.l & 0x80) {
cycles_done += 4;
goto JPOP;
}
goto out_nocondjump;
case 0xD2: /* JP NC, ee */ //d
if(!(cpu->af.b.l & 0x10)) {
cycles_done += 4;
goto JPOP;
}
goto out_nocondjump;
case 0xDA: /* JP C, ee */ //d
if(cpu->af.b.l & 0x10) {
cycles_done += 4;
goto JPOP;
}
goto out_nocondjump;
case 0xC4: /* CALL NZ, ee */ //d
if(!(cpu->af.b.l & 0x80))
goto CALLOP;
goto out_nocondjump;
case 0xCC: /* CALL Z, ee */ //d
if(!(cpu->af.b.l & 0x80))
goto out_nocondjump;
/* Fall through... */
case 0xCD: /* CALL ee */ //d
CALLOP:
FETCH_ARG16(_value);
cpu->sp.w -= 2;
cpu->mwrite16(cpu->sp.w, cpu->pc.w);
cpu->pc.w = _value;
cycles_done += 24;
goto out;
case 0xD4: /* CALL NC, ee */ //d
if(!(cpu->af.b.l & 0x10))
goto CALLOP;
goto out_nocondjump;
case 0xDC: /* CALL C, ee */ //d
if(cpu->af.b.l & 0x10)
goto CALLOP;
goto out_nocondjump;
case 0xC5: /* PUSH BC */ //d
case 0xD5: /* PUSH DE */ //d
case 0xE5: /* PUSH HL */ //d
cpu->sp.w -= 2;
cpu->mwrite16(cpu->sp.w, REG16(inst >> 4));
cycles_done += 16;
goto out;
case 0xF5: /* PUSH AF */ //d
cpu->mwrite(--cpu->sp.w, cpu->af.b.h);
cpu->mwrite(--cpu->sp.w, cpu->af.b.l);
cycles_done += 16;
goto out;
case 0xC7: /* RST 0h */ //d
case 0xCF: /* RST 8h */ //d
case 0xD7: /* RST 10h */ //d
case 0xDF: /* RST 18h */ //d
case 0xE7: /* RST 20h */ //d
case 0xEF: /* RST 28h */ //d
case 0xF7: /* RST 30h */ //d
case 0xFF: /* RST 38h */ //d
cpu->sp.w -= 2;
cpu->mwrite16(cpu->sp.w, cpu->pc.w);
cpu->pc.w = inst & 0x38;
cycles_done += 16;
goto out;
case 0xE9: /* JP (HL) */ //d
cpu->pc.w = cpu->hl.w;
cycles_done += 4;
goto out;
case 0xF3: /* DI */ //d
cpu->iff1 = 0;
cycles_done += 4;
goto out;
case 0xF9: /* LD SP, HL */ //d
cpu->sp.w = cpu->hl.w;
cycles_done += 8;
goto out;
case 0xFB: /* EI */ //d
cpu->iff1 = cpu->ei = 1;
cycles_done += 4;
goto out;
/* Weird instructions that don't match Z80. */
case 0x08: /* LD (nn), SP */ //d
FETCH_ARG16(_value)
cpu->mwrite16(_value, cpu->sp.w);
cycles_done += 20;
goto out;
case 0x10: /* STOP */ //d, sorta.
// XXXX
--cpu->pc.w;
cpu->halt = 1;
cycles_done += 4;
goto out;
case 0x22: /* LD (HL+), A */ //d
cpu->mwrite(cpu->hl.w++, cpu->af.b.h);
cycles_done += 8;
goto out;
case 0x2A: /* LD A, (HL+) */ //d
cpu->af.b.l = cpu->mread(cpu->hl.w++);
cycles_done += 8;
goto out;
case 0x32: /* LD (HL-), A */ //d
cpu->mwrite(cpu->hl.w--, cpu->af.b.h);
cycles_done += 8;
goto out;
case 0x3A: /* LD A, (HL-) */ //d
cpu->af.b.l = cpu->mread(cpu->hl.w--);
cycles_done += 8;
goto out;
case 0xD9: /* RETI */ //d
cpu->pc.w = cpu->mread16(cpu->sp.w);
cpu->sp.w += 2;
cpu->iff1 = 1;
cycles_done += 16;
goto out;
case 0xE0: /* LD (0xFF00 + n), A */ //d
FETCH_ARG8(_value);
cpu->mwrite(0xFF00 + _value, cpu->af.b.h);
cycles_done += 12;
goto out;
case 0xE2: /* LD (0xFF00 + C), A */ //d
cpu->mwrite(0xFF00 + cpu->bc.b.l, cpu->af.b.h);
cycles_done += 8;
goto out;
case 0xE8: /* ADD SP, n */ //d
FETCH_ARG8(_value);
_tmp = cpu->sp.b.l + ((int8)_value);
/* ... Why? ... */
cpu->af.b.l = (((cpu->sp.b.l ^ _tmp ^ _value) & 0x10) << 1) |
((_tmp >> 4) & 0x10);
cpu->sp.w += (int8)_value;
cycles_done += 16;
goto out;
case 0xEA: /* LD (nn), A */ //d
FETCH_ARG16(_value);
cpu->mwrite(_value, cpu->af.b.h);
cycles_done += 16;
goto out;
case 0xF0: /* LD A, (0xFF00 + n) */ //d
FETCH_ARG8(_value);
cpu->af.b.h = cpu->mread(0xFF00 + _value);
cycles_done += 12;
goto out;
case 0xF2: /* LD A, (0xFF00 + C) */ //d
cpu->af.b.h = cpu->mread(0xFF00 + cpu->bc.b.l);
cycles_done += 8;
goto out;
case 0xF8: /* LD HL, SP + nn */ //d
FETCH_ARG8(_value);
_tmp = cpu->sp.b.l + ((int8)_value);
/* ... Why? ... */
cpu->af.b.l = (((cpu->sp.b.l ^ _tmp ^ _value) & 0x10) << 1) |
((_tmp >> 4) & 0x10);
cpu->hl.w = cpu->sp.w + ((int8)_value);
cycles_done += 12;
goto out;
case 0xFA: /* LD A, (nn) */ //d
FETCH_ARG16(_value);
cpu->af.b.h = cpu->mread(_value);
cycles_done += 16;
goto out;
/* Illegal opcodes.... */
case 0xD3:
case 0xDB:
case 0xDD:
case 0xE3:
case 0xE4:
case 0xEB:
case 0xEC:
case 0xED:
case 0xF4:
case 0xFC:
case 0xFD:
/* XXXX */
goto out;
case 0xCB: /* CB-prefix */
goto execCB;
}
execCB:
#include "CrabZ80gbopsCB.h"
/* We shouldn't get here. */
/* Conditional JP and CALL instructions that don't end up jumping end up
coming here instead. This falls through back to CrabZ80.c (essentially to the
same place that goto out would put us). */
out_nocondjump: //d
cycles_done += 12;
cpu->pc.w += 2;
/* Fall through... */
}
+420
View File
@@ -0,0 +1,420 @@
/*
This file is part of CrabEmu.
Copyright (C) 2005, 2006, 2007, 2008, 2016 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu 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 CrabEmu; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INSIDE_CRABZ80_GBEXECUTE
#error This file can only be compiled inside of CrabZ80.c. Do not try to include
#error this file in other files.
#endif
++cpu->ir.b.l;
FETCH_ARG8(inst);
switch(inst) {
case 0x00: /* RLC B */ //d
case 0x01: /* RLC C */ //d
case 0x02: /* RLC D */ //d
case 0x03: /* RLC E */ //d
case 0x04: /* RLC H */ //d
case 0x05: /* RLC L */ //d
case 0x07: /* RLC A */ //d
_value = REG8(inst) = (uint8)((REG8(inst) << 1) | (REG8(inst) >> 7));
cpu->af.b.l = ((!_value) << 7) | ((_value & 0x01) << 4);
cycles_done += 8;
goto out;
case 0x06: /* RLC (HL) */ //d
_value = cpu->mread(cpu->hl.w);
_value = (uint8)((_value << 1) | (_value >> 7));
cpu->af.b.l = ((!_value) << 7) | ((_value & 0x01) << 4);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
case 0x08: /* RRC B */ //d
case 0x09: /* RRC C */ //d
case 0x0A: /* RRC D */ //d
case 0x0B: /* RRC E */ //d
case 0x0C: /* RRC H */ //d
case 0x0D: /* RRC L */ //d
case 0x0F: /* RRC A */ //d
_value = (uint8)((REG8(inst) >> 1) | (REG8(inst) << 7));
cpu->af.b.l = ((!_value) << 7) | ((REG8(inst) & 0x01) << 4);
REG8(inst) = _value;
cycles_done += 8;
goto out;
case 0x0E: /* RRC (HL) */ //d
_tmp = cpu->mread(cpu->hl.w);
_value = (uint8)((_tmp >> 1) | (_tmp << 7));
cpu->af.b.l = ((!_value) << 7) | ((_tmp & 0x01) << 4);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
case 0x10: /* RL B */ //d
case 0x11: /* RL C */ //d
case 0x12: /* RL D */ //d
case 0x13: /* RL E */ //d
case 0x14: /* RL H */ //d
case 0x15: /* RL L */ //d
case 0x17: /* RL A */ //d
_value = (uint8)((REG8(inst) << 1) | ((cpu->af.b.l & 0x10) >> 4));
cpu->af.b.l = ((!_value) << 7) | ((REG8(inst) & 0x80) >> 3);
REG8(inst) = _value;
cycles_done += 8;
goto out;
case 0x16: /* RL (HL) */ //d
_tmp = cpu->mread(cpu->hl.w);
_value = (uint8)(_tmp << 1) | ((cpu->af.b.l & 0x10) >> 4);
cpu->af.b.l = ((!_value) << 7) | ((_tmp & 0x80) >> 3);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
case 0x18: /* RR B */ //d
case 0x19: /* RR C */ //d
case 0x1A: /* RR D */ //d
case 0x1B: /* RR E */ //d
case 0x1C: /* RR H */ //d
case 0x1D: /* RR L */ //d
case 0x1F: /* RR A */ //d
_value = (uint8)((REG8(inst) >> 1) | ((cpu->af.b.l & 0x10) << 3));
cpu->af.b.l = ((!_value) << 7) | ((REG8(inst) & 0x01) << 4);
REG8(inst) = _value;
cycles_done += 8;
goto out;
case 0x1E: /* RR (HL) */ //d
_tmp = cpu->mread(cpu->hl.w);
_value = (uint8)(_tmp >> 1) | ((cpu->af.b.l & 0x10) << 3);
cpu->af.b.l = ((!_value) << 7) | ((_tmp & 0x01) << 4);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
case 0x20: /* SLA B */ //d
case 0x21: /* SLA C */ //d
case 0x22: /* SLA D */ //d
case 0x23: /* SLA E */ //d
case 0x24: /* SLA H */ //d
case 0x25: /* SLA L */ //d
case 0x27: /* SLA A */ //d
_value = (uint8)(REG8(inst) << 1);
cpu->af.b.l = ((!_value) << 7) | ((REG8(inst) & 0x80) >> 3);
REG8(inst) = _value;
cycles_done += 8;
goto out;
case 0x26: /* SLA (HL) */ //d
_tmp = cpu->mread(cpu->hl.w);
_value = (uint8)(_tmp << 1);
cpu->af.b.l = ((!_value) << 7) | ((_tmp & 0x80) >> 3);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
case 0x28: /* SRA B */ //d
case 0x29: /* SRA C */ //d
case 0x2A: /* SRA D */ //d
case 0x2B: /* SRA E */ //d
case 0x2C: /* SRA H */ //d
case 0x2D: /* SRA L */ //d
case 0x2F: /* SRA A */ //d
_value = (uint8)((REG8(inst) >> 1) | (REG8(inst) & 0x80));
cpu->af.b.l = ((!_value) << 7) | ((REG8(inst) & 0x01) << 4);
REG8(inst) = _value;
cycles_done += 8;
goto out;
case 0x2E: /* SRA (HL) */ //d
_tmp = cpu->mread(cpu->hl.w);
_value = (uint8)((_tmp >> 1) | (_tmp & 0x80));
cpu->af.b.l = ((!_value) << 7) | ((_tmp & 0x01) << 4);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
/* The SWAP instructions are unique to the LR35902. On the Z80, these are
the undocumented SLL instructions. */
case 0x30: /* SWAP B */ //d
case 0x31: /* SWAP C */ //d
case 0x32: /* SWAP D */ //d
case 0x33: /* SWAP E */ //d
case 0x34: /* SWAP H */ //d
case 0x35: /* SWAP L */ //d
case 0x37: /* SWAP A */ //d
_value = REG8(inst);
/* Doesn't matter if we swap yet, because if it is zero after swapping,
it was zero before too (and that's the only bit that matters). */
cpu->af.b.l = (!_value) << 7;
REG8(inst) = (_value >> 4) | (_value << 4);
cycles_done += 8;
goto out;
case 0x36: /* SWAP (HL) */ //d
_value = cpu->mread(cpu->hl.w);
/* Doesn't matter if we swap yet, because if it is zero after swapping,
it was zero before too (and that's the only bit that matters). */
cpu->af.b.l = (!_value) << 7;
cpu->mwrite(cpu->hl.w, (_value >> 4) | (_value << 4));
cycles_done += 16;
goto out;
case 0x38: /* SRL B */ //d
case 0x39: /* SRL C */ //d
case 0x3A: /* SRL D */ //d
case 0x3B: /* SRL E */ //d
case 0x3C: /* SRL H */ //d
case 0x3D: /* SRL L */ //d
case 0x3F: /* SRL A */ //d
_value = (uint8)(REG8(inst) >> 1);
cpu->af.b.l = ((!_value) << 7) | ((REG8(inst) & 0x01) << 4);
REG8(inst) = _value;
cycles_done += 8;
goto out;
case 0x3E: /* SRL (HL) */ //d
_tmp = cpu->mread(cpu->hl.w);
_value = (uint8)(_tmp >> 1);
cpu->af.b.l = ((!_value) << 7) | ((_tmp & 0x01) << 4);
cpu->mwrite(cpu->hl.w, _value);
cycles_done += 16;
goto out;
case 0x40: /* BIT 0, B */ //d
case 0x41: /* BIT 0, C */ //d
case 0x42: /* BIT 0, D */ //d
case 0x43: /* BIT 0, E */ //d
case 0x44: /* BIT 0, H */ //d
case 0x45: /* BIT 0, L */ //d
case 0x47: /* BIT 0, A */ //d
case 0x48: /* BIT 1, B */ //d
case 0x49: /* BIT 1, C */ //d
case 0x4A: /* BIT 1, D */ //d
case 0x4B: /* BIT 1, E */ //d
case 0x4C: /* BIT 1, H */ //d
case 0x4D: /* BIT 1, L */ //d
case 0x4F: /* BIT 1, A */ //d
case 0x50: /* BIT 2, B */ //d
case 0x51: /* BIT 2, C */ //d
case 0x52: /* BIT 2, D */ //d
case 0x53: /* BIT 2, E */ //d
case 0x54: /* BIT 2, H */ //d
case 0x55: /* BIT 2, L */ //d
case 0x57: /* BIT 2, A */ //d
case 0x58: /* BIT 3, B */ //d
case 0x59: /* BIT 3, C */ //d
case 0x5A: /* BIT 3, D */ //d
case 0x5B: /* BIT 3, E */ //d
case 0x5C: /* BIT 3, H */ //d
case 0x5D: /* BIT 3, L */ //d
case 0x5F: /* BIT 3, A */ //d
case 0x60: /* BIT 4, B */ //d
case 0x61: /* BIT 4, C */ //d
case 0x62: /* BIT 4, D */ //d
case 0x63: /* BIT 4, E */ //d
case 0x64: /* BIT 4, H */ //d
case 0x65: /* BIT 4, L */ //d
case 0x67: /* BIT 4, A */ //d
case 0x68: /* BIT 5, B */ //d
case 0x69: /* BIT 5, C */ //d
case 0x6A: /* BIT 5, D */ //d
case 0x6B: /* BIT 5, E */ //d
case 0x6C: /* BIT 5, H */ //d
case 0x6D: /* BIT 5, L */ //d
case 0x6F: /* BIT 5, A */ //d
case 0x70: /* BIT 6, B */ //d
case 0x71: /* BIT 6, C */ //d
case 0x72: /* BIT 6, D */ //d
case 0x73: /* BIT 6, E */ //d
case 0x74: /* BIT 6, H */ //d
case 0x75: /* BIT 6, L */ //d
case 0x77: /* BIT 6, A */ //d
case 0x78: /* BIT 7, B */ //d
case 0x79: /* BIT 7, C */ //d
case 0x7A: /* BIT 7, D */ //d
case 0x7B: /* BIT 7, E */ //d
case 0x7C: /* BIT 7, H */ //d
case 0x7D: /* BIT 7, L */ //d
case 0x7F: /* BIT 7, A */ //d
_tmp = REG8(inst) & (1 << ((inst >> 3) & 0x07));
cpu->af.b.l = ((!_tmp) << 7) | 0x20 | (cpu->af.b.l & 0x10);
cycles_done += 8;
goto out;
case 0x46: /* BIT 0, (HL) */ //d
case 0x4E: /* BIT 1, (HL) */ //d
case 0x56: /* BIT 2, (HL) */ //d
case 0x5E: /* BIT 3, (HL) */ //d
case 0x66: /* BIT 4, (HL) */ //d
case 0x6E: /* BIT 5, (HL) */ //d
case 0x76: /* BIT 6, (HL) */ //d
case 0x7E: /* BIT 7, (HL) */ //d
_tmp = cpu->mread(cpu->hl.w) & (1 << ((inst >> 3) & 0x07));
cpu->af.b.l = ((!_tmp) << 7) | 0x20 | (cpu->af.b.l & 0x10);
cycles_done += 16;
goto out;
case 0x80: /* RES 0, B */ //d
case 0x81: /* RES 0, C */ //d
case 0x82: /* RES 0, D */ //d
case 0x83: /* RES 0, E */ //d
case 0x84: /* RES 0, H */ //d
case 0x85: /* RES 0, L */ //d
case 0x87: /* RES 0, A */ //d
case 0x88: /* RES 1, B */ //d
case 0x89: /* RES 1, C */ //d
case 0x8A: /* RES 1, D */ //d
case 0x8B: /* RES 1, E */ //d
case 0x8C: /* RES 1, H */ //d
case 0x8D: /* RES 1, L */ //d
case 0x8F: /* RES 1, A */ //d
case 0x90: /* RES 2, B */ //d
case 0x91: /* RES 2, C */ //d
case 0x92: /* RES 2, D */ //d
case 0x93: /* RES 2, E */ //d
case 0x94: /* RES 2, H */ //d
case 0x95: /* RES 2, L */ //d
case 0x97: /* RES 2, A */ //d
case 0x98: /* RES 3, B */ //d
case 0x99: /* RES 3, C */ //d
case 0x9A: /* RES 3, D */ //d
case 0x9B: /* RES 3, E */ //d
case 0x9C: /* RES 3, H */ //d
case 0x9D: /* RES 3, L */ //d
case 0x9F: /* RES 3, A */ //d
case 0xA0: /* RES 4, B */ //d
case 0xA1: /* RES 4, C */ //d
case 0xA2: /* RES 4, D */ //d
case 0xA3: /* RES 4, E */ //d
case 0xA4: /* RES 4, H */ //d
case 0xA5: /* RES 4, L */ //d
case 0xA7: /* RES 4, A */ //d
case 0xA8: /* RES 5, B */ //d
case 0xA9: /* RES 5, C */ //d
case 0xAA: /* RES 5, D */ //d
case 0xAB: /* RES 5, E */ //d
case 0xAC: /* RES 5, H */ //d
case 0xAD: /* RES 5, L */ //d
case 0xAF: /* RES 5, A */ //d
case 0xB0: /* RES 6, B */ //d
case 0xB1: /* RES 6, C */ //d
case 0xB2: /* RES 6, D */ //d
case 0xB3: /* RES 6, E */ //d
case 0xB4: /* RES 6, H */ //d
case 0xB5: /* RES 6, L */ //d
case 0xB7: /* RES 6, A */ //d
case 0xB8: /* RES 7, B */ //d
case 0xB9: /* RES 7, C */ //d
case 0xBA: /* RES 7, D */ //d
case 0xBB: /* RES 7, E */ //d
case 0xBC: /* RES 7, H */ //d
case 0xBD: /* RES 7, L */ //d
case 0xBF: /* RES 7, A */ //d
REG8(inst) &= ~(1 << ((inst >> 3) & 0x07));
cycles_done += 8;
goto out;
case 0x86: /* RES 0, (HL) */ //d
case 0x8E: /* RES 1, (HL) */ //d
case 0x96: /* RES 2, (HL) */ //d
case 0x9E: /* RES 3, (HL) */ //d
case 0xA6: /* RES 4, (HL) */ //d
case 0xAE: /* RES 5, (HL) */ //d
case 0xB6: /* RES 6, (HL) */ //d
case 0xBE: /* RES 7, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cpu->mwrite(cpu->hl.w, _value & ~(1 << ((inst >> 3) & 0x07)));
cycles_done += 16;
goto out;
case 0xC0: /* SET 0, B */ //d
case 0xC1: /* SET 0, C */ //d
case 0xC2: /* SET 0, D */ //d
case 0xC3: /* SET 0, E */ //d
case 0xC4: /* SET 0, H */ //d
case 0xC5: /* SET 0, L */ //d
case 0xC7: /* SET 0, A */ //d
case 0xC8: /* SET 1, B */ //d
case 0xC9: /* SET 1, C */ //d
case 0xCA: /* SET 1, D */ //d
case 0xCB: /* SET 1, E */ //d
case 0xCC: /* SET 1, H */ //d
case 0xCD: /* SET 1, L */ //d
case 0xCF: /* SET 1, A */ //d
case 0xD0: /* SET 2, B */ //d
case 0xD1: /* SET 2, C */ //d
case 0xD2: /* SET 2, D */ //d
case 0xD3: /* SET 2, E */ //d
case 0xD4: /* SET 2, H */ //d
case 0xD5: /* SET 2, L */ //d
case 0xD7: /* SET 2, A */ //d
case 0xD8: /* SET 3, B */ //d
case 0xD9: /* SET 3, C */ //d
case 0xDA: /* SET 3, D */ //d
case 0xDB: /* SET 3, E */ //d
case 0xDC: /* SET 3, H */ //d
case 0xDD: /* SET 3, L */ //d
case 0xDF: /* SET 3, A */ //d
case 0xE0: /* SET 4, B */ //d
case 0xE1: /* SET 4, C */ //d
case 0xE2: /* SET 4, D */ //d
case 0xE3: /* SET 4, E */ //d
case 0xE4: /* SET 4, H */ //d
case 0xE5: /* SET 4, L */ //d
case 0xE7: /* SET 4, A */ //d
case 0xE8: /* SET 5, B */ //d
case 0xE9: /* SET 5, C */ //d
case 0xEA: /* SET 5, D */ //d
case 0xEB: /* SET 5, E */ //d
case 0xEC: /* SET 5, H */ //d
case 0xED: /* SET 5, L */ //d
case 0xEF: /* SET 5, A */ //d
case 0xF0: /* SET 6, B */ //d
case 0xF1: /* SET 6, C */ //d
case 0xF2: /* SET 6, D */ //d
case 0xF3: /* SET 6, E */ //d
case 0xF4: /* SET 6, H */ //d
case 0xF5: /* SET 6, L */ //d
case 0xF7: /* SET 6, A */ //d
case 0xF8: /* SET 7, B */ //d
case 0xF9: /* SET 7, C */ //d
case 0xFA: /* SET 7, D */ //d
case 0xFB: /* SET 7, E */ //d
case 0xFC: /* SET 7, H */ //d
case 0xFD: /* SET 7, L */ //d
case 0xFF: /* SET 7, A */ //d
REG8(inst) |= (1 << ((inst >> 3) & 0x07));
cycles_done += 8;
goto out;
case 0xC6: /* SET 0, (HL) */ //d
case 0xCE: /* SET 1, (HL) */ //d
case 0xD6: /* SET 2, (HL) */ //d
case 0xDE: /* SET 3, (HL) */ //d
case 0xE6: /* SET 4, (HL) */ //d
case 0xEE: /* SET 5, (HL) */ //d
case 0xF6: /* SET 6, (HL) */ //d
case 0xFE: /* SET 7, (HL) */ //d
_value = cpu->mread(cpu->hl.w);
cpu->mwrite(cpu->hl.w, _value | (1 << ((inst >> 3) & 0x07)));
cycles_done += 16;
goto out;
}
-3557
View File
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
#ifndef _Z80_H_
#define _Z80_H_
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
#define TRUE (1 == 1)
#define FALSE (1 == 0)
#include <stdio.h>
#define INPUT_LINE_NMI 127
#define CLEAR_LINE 0
#define INLINE inline
enum {
Z80_PC=1, Z80_SP,
Z80_A, Z80_B, Z80_C, Z80_D, Z80_E, Z80_H, Z80_L,
Z80_AF, Z80_BC, Z80_DE, Z80_HL,
Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2,
Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT,
Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3
};
enum {
Z80_TABLE_op,
Z80_TABLE_cb,
Z80_TABLE_ed,
Z80_TABLE_xy,
Z80_TABLE_xycb,
Z80_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
};
#define LSB_FIRST
typedef union {
#ifdef LSB_FIRST
struct { UINT8 l,h,h2,h3; } b;
struct { UINT16 l,h; } w;
#else
struct { UINT8 h3,h2,h,l; } b;
struct { UINT16 h,l; } w;
#endif
UINT32 d;
} PAIR;
/****************************************************************************/
/* The Z80 registers. HALT is set to 1 when the CPU is halted, the refresh */
/* register is calculated as follows: refresh=(Z80.r&127)|(Z80.r2&128) */
/****************************************************************************/
typedef struct
{
PAIR prvpc,pc,sp,af,bc,de,hl,ix,iy;
PAIR af2,bc2,de2,hl2;
UINT8 r,r2,iff1,iff2,halt,im,i;
UINT8 nmi_state; /* nmi line state */
UINT8 nmi_pending; /* nmi pending */
UINT8 irq_state; /* irq line state */
UINT8 after_ei; /* are we in the EI shadow? */
const struct z80_irq_daisy_chain *daisy;
int (*irq_callback)(int irqline);
} Z80_Regs;
void z80_init();
void z80_exit(void);
void z80_set_irq_line(int irqline, int state);
int z80_execute(int cycles);
void z80_reset(void);
#endif
-20
View File
@@ -1,20 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIDOjCCAi0GByqGSM44BAEwggIgAoIBAQD/nSuLzikeU6MrymSPr34AiU2RDJz6
0pm/3PPs27f6QTtbUAvGC13q6XWrE3HJU8Gz7RM0EJZGpiwb86LgqOJhjfQ7WKse
uaGdbHnvJEFsGqpKX7rnUWaWO3HAsKzDx4HzJqKupFEbTbzXl/GT3JMm+a3PXA3S
kyATydRPrX583Ih8iHO1zQs1pwp2AnUvaQXvp4QOLFWheH5napkDZBjc9B7H38dg
f4c0QqEXJw0lJbG26FxhpOWMiXwpWpOHSfb+XtmzpeTDIHxKPLMEdf2wc+xNC/M9
GdVBfM7+hCEhl1JGqNWPpT7ZzciX8Cxg+5/MIfx+BQ7xQ4wo1SN7y1bZAhUAuBcT
+ZsHbLXlR3uGHLIMg8boUKcCggEAGKgD56/tB6siFr5zEY+RTozPLmbBEcvhz5/p
hAQo7z7ODimZAA1MN1J7Hv7o1S5D9dpZuOnGhiXaN3Z50WdePb9LVH7twrB8v3Xn
ZOEHpumYNcYhvXrIx8LbhnMZmU27xSnrOQF9UfokRxGnXkNmlIwjT0NWqZCqQZwM
wVj1Bgld3YV7CpGTF3aGM6a0pk9LBB71PoczXAx0Cum87ouXXy3c8F/82RF9tgXE
ZBQ+7K2QXYPv9smbYDB+ZlsQ4VTOi3AReG5AeHTVWha3uaSFxY5vKpfau31iMRuT
b1VQ2HVynBpemwhAw4FFvj5dm94aN0Rrvq9BKM09DL4zoOlLogOCAQUAAoIBAE8B
I8z38GdbtswSoSV5JZ9z9cBMj/7x/sHi5ED9v1M8MD6AcxJSbo2cbK98xA3A9U22
6XFHthGReVLa0dyN3Ov+GhBdf8b4CBuebAAS4z8du2EvUFtwDUHorLIo2Qtq2SYR
wpznpB9+3g+z+8GZbzZkdm2mFBKa6GItj82qfEHwxB40aEBx7uQXzM3TH0rV8sMq
u91aAVUQuoiG2/IYWc5O34kKMlHUTt6+uuJiSG0ax8ysWE5XltCfSh/VJcGrzKU6
ZjGBzh8j5+KSXgoe9TuKlsnN5HDCZKaFTCvrxq889HJj0/ks4UrIF+meEyJvDt4P
O4HHoKRtUdLEBMcY0JA=
-----END PUBLIC KEY-----
+2
View File
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
+96
View File
@@ -0,0 +1,96 @@
/*
* fmem.c : fmemopen() on top of BSD's funopen()
* 20081017 AF
*/
#include <AvailabilityMacros.h>
/* Don't build if the deployment target is 10.13 or above. */
#if MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fmemopen.h"
#undef fmemopen
#ifndef __has_builtin // Optional of course.
#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef linux
struct fmem {
size_t pos;
size_t size;
char *buffer;
};
typedef struct fmem fmem_t;
static int readfn(void *handler, char *buf, int size)
{
int count = 0;
fmem_t *mem = handler;
size_t available = mem->size - mem->pos;
if(size > available) size = available;
for(count=0; count < size; mem->pos++, count++)
buf[count] = mem->buffer[mem->pos];
return count;
}
static int writefn(void *handler, const char *buf, int size)
{
int count = 0;
fmem_t *mem = handler;
size_t available = mem->size - mem->pos;
if(size > available) size = available;
for(count=0; count < size; mem->pos++, count++)
mem->buffer[mem->pos] = buf[count];
return count; // ? count : size;
}
static fpos_t seekfn(void *handler, fpos_t offset, int whence)
{
size_t pos;
fmem_t *mem = handler;
switch(whence) {
case SEEK_SET: pos = offset; break;
case SEEK_CUR: pos = mem->pos + offset; break;
case SEEK_END: pos = mem->size + offset; break;
default: return -1;
}
if(pos < 0 || pos > mem->size) return -1;
mem->pos = pos;
return (fpos_t) pos;
}
static int closefn(void *handler)
{
free(handler);
return 0;
}
/* simple, but portable version of fmemopen for OS X / BSD */
FILE *fmemopen_(void *buf, size_t size, const char *mode)
{
#if __has_builtin(__builtin_available)
if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
return fmemopen(buf, size, mode);
}
#endif
fmem_t *mem = (fmem_t *) malloc(sizeof(fmem_t));
memset(mem, 0, sizeof(fmem_t));
mem->size = size, mem->buffer = buf;
return funopen(mem, readfn, writefn, seekfn, closefn);
}
#endif
#endif
+53
View File
@@ -0,0 +1,53 @@
//
// Copyright 2012 Jeff Verkoeyen
// Originally ported from https://github.com/ingenuitas/python-tesseract/blob/master/fmemopen.c
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef FMEMOPEN_H_
#define FMEMOPEN_H_
#ifdef __cplusplus
extern "C"
{
#endif
/**
* A BSD port of the fmemopen Linux method using funopen.
*
* man docs for fmemopen:
* http://linux.die.net/man/3/fmemopen
*
* man docs for funopen:
* https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/funopen.3.html
*
* This method is ported from ingenuitas' python-tesseract project.
*
* You must call fclose on the returned file pointer or memory will be leaked.
*
* @param buf The data that will be used to back the FILE* methods. Must be at least
* @c size bytes.
* @param size The size of the @c buf data.
* @param mode The permitted stream operation modes.
* @returns A pointer that can be used in the fread/fwrite/fseek/fclose family of methods.
* If a failure occurred NULL will be returned.
*/
FILE *fmemopen_(void *buf, size_t size, const char *mode);
#define fmemopen fmemopen_
#ifdef __cplusplus
}
#endif
#endif // #ifndef FMEMOPEN_H_
+144
View File
@@ -0,0 +1,144 @@
/* Use funopen(3) to provide open_memstream(3) like functionality. */
#include <AvailabilityMacros.h>
/* But only if the deployment target is below 10.13 */
#if MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "open_memstream.h"
#undef open_memstream
struct memstream {
char **cp;
size_t *lenp;
size_t offset;
};
static void
memstream_grow(struct memstream *ms, size_t newsize)
{
char *buf;
if (newsize > *ms->lenp) {
buf = realloc(*ms->cp, newsize + 1);
if (buf != NULL) {
#ifdef DEBUG
fprintf(stderr, "MS: %p growing from %zd to %zd\n",
ms, *ms->lenp, newsize);
#endif
memset(buf + *ms->lenp + 1, 0, newsize - *ms->lenp);
*ms->cp = buf;
*ms->lenp = newsize;
}
}
}
static int
memstream_read(void *cookie, char *buf, int len)
{
struct memstream *ms;
int tocopy;
ms = cookie;
memstream_grow(ms, ms->offset + len);
tocopy = *ms->lenp - ms->offset;
if (len < tocopy)
tocopy = len;
memcpy(buf, *ms->cp + ms->offset, tocopy);
ms->offset += tocopy;
#ifdef DEBUG
fprintf(stderr, "MS: read(%p, %d) = %d\n", ms, len, tocopy);
#endif
return (tocopy);
}
static int
memstream_write(void *cookie, const char *buf, int len)
{
struct memstream *ms;
int tocopy;
ms = cookie;
memstream_grow(ms, ms->offset + len);
tocopy = *ms->lenp - ms->offset;
if (len < tocopy)
tocopy = len;
memcpy(*ms->cp + ms->offset, buf, tocopy);
ms->offset += tocopy;
#ifdef DEBUG
fprintf(stderr, "MS: write(%p, %d) = %d\n", ms, len, tocopy);
#endif
return (tocopy);
}
static fpos_t
memstream_seek(void *cookie, fpos_t pos, int whence)
{
struct memstream *ms;
#ifdef DEBUG
size_t old;
#endif
ms = cookie;
#ifdef DEBUG
old = ms->offset;
#endif
switch (whence) {
case SEEK_SET:
ms->offset = pos;
break;
case SEEK_CUR:
ms->offset += pos;
break;
case SEEK_END:
ms->offset = *ms->lenp + pos;
break;
}
#ifdef DEBUG
fprintf(stderr, "MS: seek(%p, %zd, %d) %zd -> %zd\n", ms, pos, whence,
old, ms->offset);
#endif
return (ms->offset);
}
static int
memstream_close(void *cookie)
{
free(cookie);
return (0);
}
FILE *
open_memstream_(char **cp, size_t *lenp)
{
#if __has_builtin(__builtin_available)
if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
return open_memstream(cp, lenp);
}
#endif
struct memstream *ms;
int save_errno;
FILE *fp;
*cp = NULL;
*lenp = 0;
ms = malloc(sizeof(*ms));
ms->cp = cp;
ms->lenp = lenp;
ms->offset = 0;
fp = funopen(ms, memstream_read, memstream_write, memstream_seek,
memstream_close);
if (fp == NULL) {
save_errno = errno;
free(ms);
errno = save_errno;
}
return (fp);
}
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef OPEN_MEMSTREAM_H_
#define OPEN_MEMSTREAM_H_
#ifdef __cplusplus
extern "C"
{
#endif
FILE *open_memstream_(char **cp, size_t *lenp);
#define open_memstream open_memstream_
#ifdef __cplusplus
}
#endif
#endif // #ifndef FMEMOPEN_H_
+4 -2
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2012, 2013 Lawrence Sebald
Copyright (C) 2012, 2013, 2015 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -86,6 +86,8 @@ static int guess_on_ext(const char *fn, int chop) {
return CONSOLE_COLECOVISION;
else if(!strcasecmp(ext, ".nes"))
return CONSOLE_NES;
else if(!strcasecmp(ext, ".ch8") || !strcasecmp(ext, ".c8"))
return CONSOLE_CHIP8;
#ifndef NO_ZLIB
else if(!strcasecmp(ext, ".gz"))
return TYPE_GZIP;
+2 -13
View File
@@ -23,6 +23,7 @@
#include <string.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/semaphore.h>
#include "CrabEmu.h"
@@ -138,8 +139,7 @@ int sound_init(int channels, int region) {
AudioStreamBasicDescription basic_desc;
Component comp;
AURenderCallbackStruct callback;
UInt32 bufsz, size;
AudioDeviceID dev;
UInt32 bufsz;
int rv = 0;
if(initted)
@@ -214,17 +214,6 @@ int sound_init(int channels, int region) {
goto err2;
}
size = sizeof(dev);
error = AudioUnitGetProperty(outputAU,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global, 0, &dev, &size);
if(error != noErr) {
rv = -5;
goto err3;
}
bufsz = 512;
error = AudioUnitSetProperty(outputAU,
kAudioUnitProperty_MaximumFramesPerSlice,
+2
View File
@@ -41,6 +41,8 @@ static int32 fds_process(void)
/* write to registers */
static void fds_write(uint32 address, uint8 value)
{
(void)address;
(void)value;
}
/* reset state of vrcvi sound channels */
+1
View File
@@ -1080,6 +1080,7 @@ apu_t *apu_create(int sample_rate, int refresh_rate, int sample_bits, boolean st
{
apu_t *temp_apu;
/* int channel; */
(void)stereo;
temp_apu = malloc(sizeof(apu_t));
if (NULL == temp_apu)
+1757 -2240
View File
File diff suppressed because it is too large Load Diff
+171 -41
View File
@@ -1,41 +1,171 @@
#ifndef _H_YM2413_
#define _H_YM2413_
/* select output bits size of output : 8 or 16 */
#define SAMPLE_BITS 16
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if (SAMPLE_BITS==16)
typedef INT16 SAMP;
#endif
#if (SAMPLE_BITS==8)
typedef INT8 SAMP;
#endif
int YM2413Init(int num, int clock, int rate);
void YM2413Shutdown(void);
void YM2413ResetChip(int which);
void YM2413Write(int which, int a, int v);
unsigned char YM2413Read(int which, int a);
void YM2413UpdateOne(int which, INT16 *buffers, int length);
void YM2413UpdateOneMono(int which, INT16 *buffers, int length);
typedef void (*OPLL_UPDATEHANDLER)(int param,int min_interval_us);
void YM2413SetUpdateHandler(int which, OPLL_UPDATEHANDLER UpdateHandler, int param);
#endif /*_H_YM2413_*/
/*
CrabEmu Modifications to this code:
- Added typedefs and such to unglue the code from MAME's core.
- Added mono update function for the Dreamcast port.
- Updated to mamedev current as of September 4, 2016, backporting to C
from C++.
Copyright (C) 2011, 2012, 2016 Lawrence Sebald
Modifications distributed under the same license as the rest of the code in
this file (GPLv2 or newer).
*/
// license:GPL-2.0+
// copyright-holders:Jarek Burczynski,Ernesto Corvi
#ifndef __YM2413_H__
#define __YM2413_H__
/* MAME glue... */
#if __STDC_VERSION__ >= 199901L
#include <stdint.h>
typedef uint8_t UINT8;
typedef uint32_t UINT32;
typedef int8_t INT8;
typedef int16_t INT16;
typedef int32_t INT32;
#else
#warning Check integer types, they may not be correct!
typedef unsigned char UINT8;
typedef unsigned int UINT32;
typedef signed char INT8;
typedef signed int INT32;
#endif
/* End MAME glue... */
struct OPLL_SLOT
{
UINT32 ar; /* attack rate: AR<<2 */
UINT32 dr; /* decay rate: DR<<2 */
UINT32 rr; /* release rate:RR<<2 */
UINT8 KSR; /* key scale rate */
UINT8 ksl; /* keyscale level */
UINT8 ksr; /* key scale rate: kcode>>KSR */
UINT8 mul; /* multiple: mul_tab[ML] */
/* Phase Generator */
UINT32 phase; /* frequency counter */
UINT32 freq; /* frequency counter step */
UINT8 fb_shift; /* feedback shift value */
INT32 op1_out[2]; /* slot1 output for feedback */
/* Envelope Generator */
UINT8 eg_type; /* percussive/nonpercussive mode*/
UINT8 state; /* phase type */
UINT32 TL; /* total level: TL << 2 */
INT32 TLL; /* adjusted now TL */
INT32 volume; /* envelope counter */
UINT32 sl; /* sustain level: sl_tab[SL] */
UINT8 eg_sh_dp; /* (dump state) */
UINT8 eg_sel_dp; /* (dump state) */
UINT8 eg_sh_ar; /* (attack state) */
UINT8 eg_sel_ar; /* (attack state) */
UINT8 eg_sh_dr; /* (decay state) */
UINT8 eg_sel_dr; /* (decay state) */
UINT8 eg_sh_rr; /* (release state for non-perc.)*/
UINT8 eg_sel_rr; /* (release state for non-perc.)*/
UINT8 eg_sh_rs; /* (release state for perc.mode)*/
UINT8 eg_sel_rs; /* (release state for perc.mode)*/
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
/* LFO */
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
/* waveform select */
unsigned int wavetable;
};
struct OPLL_CH
{
struct OPLL_SLOT SLOT[2];
/* phase generator state */
UINT32 block_fnum; /* block+fnum */
UINT32 fc; /* Freq. freqement base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 kcode; /* key code (for key scaling) */
UINT8 sus; /* sus on/off (release speed in percussive mode)*/
};
enum {
RATE_STEPS = (8),
/* sinwave entries */
SIN_BITS = 10,
SIN_LEN = (1<<SIN_BITS),
SIN_MASK = (SIN_LEN-1),
TL_RES_LEN = (256), /* 8 bits addressing (real chip) */
/* TL_TAB_LEN is calculated as:
* 11 - sinus amplitude bits (Y axis)
* 2 - sinus sign bit (Y axis)
* TL_RES_LEN - sinus resolution (X axis)
*/
TL_TAB_LEN = (11*2*TL_RES_LEN),
LFO_AM_TAB_ELEMENTS = 210
};
typedef struct ym2413_s {
int tl_tab[TL_TAB_LEN];
/* sin waveform table in 'decibel' scale */
/* two waveforms on OPLL type chips */
unsigned int sin_tab[SIN_LEN * 2];
struct OPLL_CH P_CH[9]; /* OPLL chips have 9 channels*/
UINT8 instvol_r[9]; /* instrument/volume (or volume/volume in percussive mode)*/
UINT32 eg_cnt; /* global envelope generator counter */
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
UINT32 eg_timer_add; /* step of eg_timer */
UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */
UINT8 rhythm; /* Rhythm mode */
/* LFO */
UINT32 LFO_AM;
INT32 LFO_PM;
UINT32 lfo_am_cnt;
UINT32 lfo_am_inc;
UINT32 lfo_pm_cnt;
UINT32 lfo_pm_inc;
UINT32 noise_rng; /* 23 bit noise shift register */
UINT32 noise_p; /* current noise 'phase' */
UINT32 noise_f; /* current noise period */
/* instrument settings */
/*
0-user instrument
1-15 - fixed instruments
16 -bass drum settings
17,18 - other percussion instruments
*/
UINT8 inst_tab[19][8];
UINT32 fn_tab[1024]; /* fnumber->increment counter */
UINT8 address; /* address register */
signed int output[2];
} YM2413;
/* CrabEmu's public interface... */
YM2413 *ym2413_init(int clock, int rate);
void ym2413_shutdown(YM2413 *fm);
void ym2413_reset(YM2413 *fm);
void ym2413_write(YM2413 *fm, int a, int v);
void ym2413_update(YM2413 *fm, int16_t *buf, int samples);
void ym2413_update_mono(YM2413 *fm, int16_t buf, int samples);
unsigned char ym2413_read(YM2413 *fm, int a);
#endif /*__YM2413_H__*/
-201
View File
@@ -1,201 +0,0 @@
/*
This file is part of CrabClaw.
Copyright (C) 2008, 2009 Lawrence Sebald
CrabClaw is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabClaw 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 CrabClaw; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "list.h"
#include <stdlib.h>
cc_dlist_t *cc_dlist_create(void) {
cc_dlist_t *rv = (cc_dlist_t *)malloc(sizeof(cc_dlist_t));
if(!rv) {
return NULL;
}
rv->head = rv->tail = NULL;
rv->count = 0;
return rv;
}
void cc_dlist_destroy(cc_dlist_t *list) {
/* Remove any nodes still in the list. The user is responsible for freeing
any data associated with the nodes. */
while(list->head) {
cc_dlist_remove(list, list->head);
}
free(list);
}
int cc_dlist_remove(cc_dlist_t *list, cc_dlist_node_t *node) {
/* Make sure the node and list are valid. */
if(!list || !node) {
return -1;
}
if(list->head == node) {
/* Case 1: The node is the head node, advance the head to the next
node in the list. */
list->head = node->next;
}
if(list->tail == node) {
/* Case 2: The node is the tail node, point the tail pointer at the
previous node in the list. If this is the only item in the list, this
can happen at the same time as case 1 above. */
list->tail = node->prev;
}
else {
/* Case 3: The node is in the middle of the list. Remove the node from
the chain and readjust some pointers. */
node->prev->next = node->next;
node->next->prev = node->prev;
free(node);
}
free(node);
--list->count;
return 0;
}
int cc_dlist_remove_at(cc_dlist_t *list, uint32 pos) {
cc_dlist_node_t *node = list->head;
/* Make sure the user has passed us a valid position to remove. */
if(!list || list->count <= pos) {
return -1;
}
/* Grab the node that the user has requested removed. */
while(pos-- && node != NULL) {
node = node->next;
}
/* We're guaranteed to have a node at this point, assuming the user hasn't
screwed around with the internals of the list. The check at the beginning
of cc_dlist_remove will take care of the case if the user has screwed
with the innards. */
return cc_dlist_remove(list, node);
}
int cc_dlist_insert_head(cc_dlist_t *list, void *data) {
cc_dlist_node_t *node;
if(!list) {
return -1;
}
/* Make sure we allocate memory properly. */
if(!(node = (cc_dlist_node_t *)malloc(sizeof(cc_dlist_node_t)))) {
return -1;
}
/* Fill in the node structure. */
node->data = data;
node->prev = NULL;
node->next = list->head;
/* Update the head of the list and increment the list count. */
if(list->head) {
list->head->prev = node;
}
list->head = node;
if(!list->tail) {
list->tail = node;
}
++list->count;
return 0;
}
int cc_dlist_insert_tail(cc_dlist_t *list, void *data) {
cc_dlist_node_t *node;
if(!list) {
return -1;
}
/* Make sure we allocate memory properly. */
if(!(node = (cc_dlist_node_t *)malloc(sizeof(cc_dlist_node_t)))) {
return -1;
}
/* Fill in the node structure. */
node->data = data;
node->prev = list->tail;
node->next = NULL;
/* Update the tail of the list and increment the list count. */
if(list->tail) {
list->tail->next = node;
}
list->tail = node;
if(!list->head) {
list->head = node;
}
++list->count;
return 0;
}
int cc_dlist_insert_after(cc_dlist_t *list, cc_dlist_node_t *node,
void *data) {
cc_dlist_node_t *n;
if(!list || !node) {
return -1;
}
/* Make sure we allocate memory properly. */
if(!(n = (cc_dlist_node_t *)malloc(sizeof(cc_dlist_node_t)))) {
return -1;
}
/* Fill in the node structure. */
n->data = data;
n->prev = node;
n->next = node->next;
/* Update the node passed in and increment the list count. */
node->next->prev = n;
node->next = n;
++list->count;
return 0;
}
void *cc_dlist_get_data_at(cc_dlist_t *list, int idx) {
cc_dlist_node_t *tmp;
CC_DLIST_FOREACH(list, tmp) {
if(!(idx--))
return tmp->data;
}
return NULL;
}
-170
View File
@@ -1,170 +0,0 @@
/*
This file is part of CrabClaw.
Copyright (C) 2008, 2009 Lawrence Sebald
CrabClaw is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabClaw 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 CrabClaw; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* This linked list code was "ported" from CrabClaw. */
#ifndef CRABCLAW__LIST_H
#define CRABCLAW__LIST_H
#include "CrabEmu.h"
/**
* A node in a doubly-linked list.
* This object is used in a doubly-linked list to hold one data item.
* @since 1.0.0
*/
typedef struct cc_dlist_node {
/**
* The previous node in the list.
* @since 1.0.0
*/
struct cc_dlist_node *prev;
/**
* The next node in the list.
* @since 1.0.0
*/
struct cc_dlist_node *next;
/**
* The data stored by this node.
* @since 1.0.0
*/
void *data;
} cc_dlist_node_t;
/**
* A doubly-linked list.
* This object is used to hold a doubly-linked list of free-form data items.
* All fields in this structure should be considered to be read-only from
* outside of CrabClaw.
* @since 1.0.0
*/
typedef struct cc_dlist {
/**
* The head of this list.
* @since 1.0.0
*/
struct cc_dlist_node *head;
/**
* The tail of this list.
* @since 1.0.0
*/
struct cc_dlist_node *tail;
/**
* The number of elements in this list.
* @since 1.0.0
*/
uint32 count;
} cc_dlist_t;
/**
* Create a new doubly-linked list.
* Create and initialize a empty doubly-linked list.
* @since 1.0.0
* @return A new <code>cc_dlist_t</code> object on success, NULL on
* failure.
*/
extern cc_dlist_t *cc_dlist_create(void);
/**
* Destroy a doubly-linked list.
* Destroy an existing doubly-linked list. You are responsible for freeing any
* memory used by the data in the list. This function will free only the nodes
* used and the list object itself.
* @since 1.0.0
* @param list The list to destroy.
*/
extern void cc_dlist_destroy(cc_dlist_t *list);
/**
* Insert a new item at the head of the list.
* This function inserts a new node with the given data at the head of the
* given list.
* @since 1.0.0
* @param list The list to insert into.
* @param data The data to add to the list.
* @return 0 on success, non-zero on failure.
*/
extern int cc_dlist_insert_head(cc_dlist_t *list, void *data);
/**
* Insert a new item at the tail of the list.
* This function inserts a new node with the given data at the tail of the
* given list.
* @since 1.0.0
* @param list The list to insert into.
* @param data The data to add to the list.
* @return 0 on success, non-zero on failure.
*/
extern int cc_dlist_insert_tail(cc_dlist_t *list, void *data);
/**
* Insert a new item after a given node.
* This function inserts a new node with the given data after the node passed
* into the function.
* @since 1.0.0
* @param list The list to insert into.
* @param node The node to insert after.
* @param data The data to add to the list.
* @return 0 on success, non-zero on failure.
*/
extern int cc_dlist_insert_after(cc_dlist_t *list, cc_dlist_node_t *node,
void *data);
/**
* Remove a given node from a list.
* This function removes the given node from the list. You are responsible for
* cleaning up any resources used by the data, this function only frees the
* memory used by the node itself.
* @since 1.0.0
* @param list The list to remove from.
* @param node The node to remove.
* @return 0 on success, non-zero on failure.
*/
extern int cc_dlist_remove(cc_dlist_t *list, cc_dlist_node_t *node);
/**
* Remove the element at a given position in a list.
* This function removes the element at a given position in the list passed in.
* You are responsible for cleaning up any resources used by the data in the
* node, this function only frees the memory used by the node itself.
* @since 1.0.0
* @param list The list to remove from.
* @param pos The element to remove (zero-based).
* @return 0 on success, non-zero on failure.
*/
extern int cc_dlist_remove_at(cc_dlist_t *list, uint32 pos);
void *cc_dlist_get_data_at(cc_dlist_t *list, int idx);
/**
* Loop through each element in a given list.
* This macro defines a "foreach" style loop for the given list.
* @since 1.0.0
* @param list The list to traverse.
* @param tmp The name of the temporary <code>cc_dlist_node_t</code>
* pointer to use while traversing the list.
*/
#define CC_DLIST_FOREACH(list, tmp) \
for(tmp = list->head; tmp != NULL; tmp = tmp->next)
#endif /* !CRABCLAW__LIST_H */
+14 -14
View File
@@ -34,40 +34,40 @@
#define SEEK_SET 0
#endif
voidpf ZCALLBACK fopen_file_func OF((
voidpf ZCALLBACK fopen_file_func (
voidpf opaque,
const char* filename,
int mode));
int mode);
uLong ZCALLBACK fread_file_func OF((
uLong ZCALLBACK fread_file_func (
voidpf opaque,
voidpf stream,
void* buf,
uLong size));
uLong size);
uLong ZCALLBACK fwrite_file_func OF((
uLong ZCALLBACK fwrite_file_func (
voidpf opaque,
voidpf stream,
const void* buf,
uLong size));
uLong size);
long ZCALLBACK ftell_file_func OF((
long ZCALLBACK ftell_file_func (
voidpf opaque,
voidpf stream));
voidpf stream);
long ZCALLBACK fseek_file_func OF((
long ZCALLBACK fseek_file_func (
voidpf opaque,
voidpf stream,
uLong offset,
int origin));
int origin);
int ZCALLBACK fclose_file_func OF((
int ZCALLBACK fclose_file_func (
voidpf opaque,
voidpf stream));
voidpf stream);
int ZCALLBACK ferror_file_func OF((
int ZCALLBACK ferror_file_func (
voidpf opaque,
voidpf stream));
voidpf stream);
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
+8 -8
View File
@@ -35,13 +35,13 @@
extern "C" {
#endif
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode);
typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size);
typedef uLong (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size);
typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin);
typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream);
typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream);
typedef struct zlib_filefunc_def_s
{
@@ -57,7 +57,7 @@ typedef struct zlib_filefunc_def_s
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def);
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
+10 -10
View File
@@ -175,10 +175,10 @@ typedef struct
*/
local int unzlocal_getByte OF((
local int unzlocal_getByte (
const zlib_filefunc_def* pzlib_filefunc_def,
voidpf filestream,
int *pi));
int *pi);
local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi)
const zlib_filefunc_def* pzlib_filefunc_def;
@@ -205,10 +205,10 @@ local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi)
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
local int unzlocal_getShort OF((
local int unzlocal_getShort (
const zlib_filefunc_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX));
uLong *pX);
local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
const zlib_filefunc_def* pzlib_filefunc_def;
@@ -233,10 +233,10 @@ local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
return err;
}
local int unzlocal_getLong OF((
local int unzlocal_getLong (
const zlib_filefunc_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX));
uLong *pX);
local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)
const zlib_filefunc_def* pzlib_filefunc_def;
@@ -336,9 +336,9 @@ extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivit
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local uLong unzlocal_SearchCentralDir OF((
local uLong unzlocal_SearchCentralDir (
const zlib_filefunc_def* pzlib_filefunc_def,
voidpf filestream));
voidpf filestream);
local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream)
const zlib_filefunc_def* pzlib_filefunc_def;
@@ -575,7 +575,7 @@ local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
/*
Get Info about the current file in the zipfile, with internal only info
*/
local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
unz_file_info *pfile_info,
unz_file_info_internal
*pfile_info_internal,
@@ -584,7 +584,7 @@ local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
uLong commentBufferSize);
local int unzlocal_GetCurrentFileInfoInternal (file,
pfile_info,
+30 -30
View File
@@ -123,9 +123,9 @@ typedef struct unz_file_info_s
tm_unz tmu_date;
} unz_file_info;
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
const char* fileName2,
int iCaseSensitivity));
int iCaseSensitivity);
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
@@ -136,7 +136,7 @@ extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
*/
extern unzFile ZEXPORT unzOpen OF((const char *path));
extern unzFile ZEXPORT unzOpen (const char *path);
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
@@ -147,31 +147,31 @@ extern unzFile ZEXPORT unzOpen OF((const char *path));
of this unzip package.
*/
extern unzFile ZEXPORT unzOpen2 OF((const char *path,
zlib_filefunc_def* pzlib_filefunc_def));
extern unzFile ZEXPORT unzOpen2 (const char *path,
zlib_filefunc_def* pzlib_filefunc_def);
/*
Open a Zip file, like unzOpen, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
extern int ZEXPORT unzClose OF((unzFile file));
extern int ZEXPORT unzClose (unzFile file);
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
unz_global_info *pglobal_info));
extern int ZEXPORT unzGetGlobalInfo (unzFile file,
unz_global_info *pglobal_info);
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
extern int ZEXPORT unzGetGlobalComment (unzFile file,
char *szComment,
uLong uSizeBuf));
uLong uSizeBuf);
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
@@ -182,22 +182,22 @@ extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
/***************************************************************************/
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
extern int ZEXPORT unzGoToFirstFile (unzFile file);
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
extern int ZEXPORT unzGoToNextFile (unzFile file);
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzLocateFile OF((unzFile file,
extern int ZEXPORT unzLocateFile (unzFile file,
const char *szFileName,
int iCaseSensitivity));
int iCaseSensitivity);
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
@@ -227,14 +227,14 @@ extern int ZEXPORT unzGoToFilePos(
/* ****************************************** */
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
uLong commentBufferSize);
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
@@ -253,24 +253,24 @@ extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
extern int ZEXPORT unzOpenCurrentFile (unzFile file);
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
const char* password));
extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file,
const char* password);
/*
Open for reading data the current file in the zipfile.
password is a crypting password
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
extern int ZEXPORT unzOpenCurrentFile2 (unzFile file,
int* method,
int* level,
int raw));
int raw);
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
@@ -280,11 +280,11 @@ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
extern int ZEXPORT unzOpenCurrentFile3 (unzFile file,
int* method,
int* level,
int raw,
const char* password));
const char* password);
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
@@ -295,15 +295,15 @@ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
*/
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
extern int ZEXPORT unzCloseCurrentFile (unzFile file);
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
extern int ZEXPORT unzReadCurrentFile (unzFile file,
voidp buf,
unsigned len));
unsigned len);
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
@@ -315,19 +315,19 @@ extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell OF((unzFile file));
extern z_off_t ZEXPORT unztell (unzFile file);
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof OF((unzFile file));
extern int ZEXPORT unzeof (unzFile file);
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
extern int ZEXPORT unzGetLocalExtrafield (unzFile file,
voidp buf,
unsigned len));
unsigned len);
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
-13
View File
@@ -1,13 +0,0 @@
Copyright (c) 2006-2009, WolfWings
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-558
View File
@@ -1,558 +0,0 @@
/* This source code is Copyright (C) 2006-2009 by WolfWings. */
/* It is, however, released under the ISC license. */
/* en.wikipedia.org/wiki/ISC_Licence */
/* --------------------------------------------------------- */
/* It is a formula-level rederiviation of the HQ2x technique */
/* and is, thus, not a derivative work of the original code, */
/* only the original equations behind the code. */
#include <string.h>
#include "pastlib.h"
#ifdef _MSC_VER
#define bzero(x, y) memset(x, 0, y)
#endif
static const uint8_t blends_2x[14*4] = {
/* 5 2 4 1 */
8, 4, 4, 0,
8, 4, 0, 4,
8, 0, 4, 4,
16, 0, 0, 0,
12, 4, 0, 0,
12, 0, 4, 0,
12, 0, 0, 4,
4, 6, 6, 0, /* Interp9 */
12, 2, 2, 0, /* Interp7 */
14, 1, 1, 0, /* Interp10*/
10, 4, 2, 0, /* Interp6 */
10, 2, 4, 0, /* Interp6 */
4, 6, 6, 0, /* Added for secondary blending used in HQ4x */
8, 4, 4, 0, /* Added for secondary blending used in HQ4x */
};
static const uint8_t blends_4x[14*16] = {
/* 5 2 4 1 5 2 4 1 5 2 4 1 5 2 4 1 */
8, 4, 4, 0, 10, 4, 2, 0, 10, 2, 4, 0, 12, 2, 2, 0, /* Needs to be split. B */
10, 0, 0, 6, 10, 4, 0, 2, 12, 0, 0, 4, 14, 0, 0, 2,
10, 0, 0, 6, 10, 0, 4, 2, 12, 0, 0, 4, 14, 0, 0, 2,
16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, /* Solid colors */
10, 6, 0, 0, 10, 6, 0, 0, 14, 2, 0, 0, 14, 2, 0, 0,
10, 0, 6, 0, 14, 0, 2, 0, 10, 0, 6, 0, 14, 0, 2, 0,
10, 0, 0, 6, 12, 0, 0, 4, 12, 0, 0, 4, 14, 0, 0, 2,
0, 8, 8, 0, 4, 8, 4, 0, 0, 6,10, 0, 12, 2, 2, 0, /* Needs to be split. A */
8, 4, 4, 0, 12, 4, 0, 0, 12, 0, 4, 0, 16, 0, 0, 0,
8, 4, 4, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0,
12, 4, 0, 0, 4,12, 0, 0, 10, 0, 4, 0, 14, 0, 2, 0,
12, 0, 4, 0, 10, 4, 0, 0, 4, 0,12, 0, 14, 2, 0, 0,
0, 8, 8, 0, 0,10, 6, 0, 4, 4, 8, 0, 12, 2, 2, 0, /* Needs to be split. A */
0, 8, 8, 0, 8, 8, 0, 0, 8, 0, 8, 0, 16, 0, 0, 0, /* Needs to be split. B */
};
static const uint8_t tree_hq[0x800] = {
/* 6 6 6 6 6 6 6 6
* 2 2 2 2 2 2 2 2
* 4 4 4 4 4 4 4 4
* 8 8 8 8 8 8 8 8
*/
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8, /* */
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8, /* 3 */
0, 0, 5,10, 4, 4,13,13, 0, 0, 5, 5,11, 4,13,13, /* 1 */
0, 0, 5,10, 4, 4,12,13, 0, 0, 5, 5,11, 4,13,13, /* 31 */
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8, /* 7 */
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6, /* 3 7 */
0, 0, 5,10, 4, 4, 7,13, 0, 0, 5, 5,11, 4,13,13, /* 17 */
0, 0, 5,10, 4, 4, 9, 9, 0, 0, 5,10,11,11, 9, 9, /* 317 */
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8, /* 9 */
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6, /* 3 9 */
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13, /* 1 9 */
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13, /* 31 9 */
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6, /* 79 */
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6, /* 3 79 */
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13, /* 179 */
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9, /* 3179 */
/* DIFF26 */
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8,
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5,11, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5,11, 4,13,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7,13, 0, 0, 5, 5,11, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5,11,11, 9, 9,
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
/* DIFF24 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5,10,11,11, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
/* DIFF26 DIFF24 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11,11, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
/* DIFF84 */
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8,
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 5,10, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5,10, 4, 4,12,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 7,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5,10, 4, 4, 9, 9, 0, 0, 5,10, 4, 4, 9, 9,
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
/* DIFF26 DIFF84 */
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8,
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
/* DIFF24 DIFF84 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5,10, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
/* DIFF26 DIFF24 DIFF84 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3};
#define RB(y,u,v) (((y)&0x3FF)<<22)|(((u)&0x3FF)<<11)|((v)&0x3FF)
#define GO(y,v) ((((y)+64)&0x3FF)<<22)|(16<<11)|(((v)+16)&0x3FF)
static const uint32_t DiffTable[128] = {
RB(-85, 160, 80), RB(-83, 155, 77), RB(-80, 150, 75), RB(-77, 145, 72),
RB(-75, 140, 70), RB(-72, 135, 67), RB(-69, 130, 65), RB(-67, 125, 62),
RB(-64, 120, 60), RB(-61, 115, 57), RB(-59, 110, 55), RB(-56, 105, 52),
RB(-53, 100, 50), RB(-51, 95, 47), RB(-48, 90, 45), RB(-45, 85, 42),
RB(-43, 80, 40), RB(-40, 75, 37), RB(-37, 70, 35), RB(-35, 65, 32),
RB(-32, 60, 30), RB(-29, 55, 27), RB(-27, 50, 25), RB(-24, 45, 22),
RB(-21, 40, 20), RB(-19, 35, 17), RB(-16, 30, 15), RB(-13, 25, 12),
RB(-11, 20, 10), RB( -8, 15, 7), RB( -5, 10, 5), RB( -3, 5, 2),
RB( 0, 0, 0), RB( 2, -5, -2), RB( 5, -10, -5), RB( 7, -15, -7),
RB( 10, -20, -10), RB( 13, -25, -12), RB( 15, -30, -15), RB( 18, -35, -17),
RB( 21, -40, -20), RB( 23, -45, -22), RB( 26, -50, -25), RB( 29, -55, -27),
RB( 31, -60, -30), RB( 34, -65, -32), RB( 37, -70, -35), RB( 39, -75, -37),
RB( 42, -80, -40), RB( 45, -85, -42), RB( 47, -90, -45), RB( 50, -95, -47),
RB( 53,-100, -50), RB( 55,-105, -52), RB( 58,-110, -55), RB( 61,-115, -57),
RB( 63,-120, -60), RB( 66,-125, -62), RB( 69,-130, -65), RB( 71,-135, -67),
RB( 74,-140, -70), RB( 77,-145, -72), RB( 79,-150, -75), RB( 82,-155, -77),
GO(-84, -160), GO(-81, -155), GO(-78, -150), GO(-76, -145),
GO(-73, -140), GO(-70, -135), GO(-68, -130), GO(-65, -125),
GO(-63, -120), GO(-60, -115), GO(-57, -110), GO(-55, -105),
GO(-52, -100), GO(-49, -95), GO(-47, -90), GO(-44, -85),
GO(-42, -80), GO(-39, -75), GO(-36, -70), GO(-34, -65),
GO(-31, -60), GO(-28, -55), GO(-26, -50), GO(-23, -45),
GO(-21, -40), GO(-18, -35), GO(-15, -30), GO(-13, -25),
GO(-10, -20), GO( -7, -15), GO( -5, -10), GO( -2, -5),
GO( 0, 0), GO( 2, 4), GO( 5, 9), GO( 7, 14),
GO( 10, 19), GO( 13, 24), GO( 15, 29), GO( 18, 34),
GO( 21, 39), GO( 23, 44), GO( 26, 49), GO( 28, 54),
GO( 31, 59), GO( 34, 64), GO( 36, 69), GO( 39, 74),
GO( 42, 79), GO( 44, 84), GO( 47, 89), GO( 49, 94),
GO( 52, 99), GO( 55, 104), GO( 57, 109), GO( 60, 114),
GO( 63, 119), GO( 65, 124), GO( 68, 129), GO( 70, 134),
GO( 73, 139), GO( 76, 144), GO( 78, 149), GO( 81, 154)};
__inline__ static int ExpandedDiff (uint32_t c0, uint32_t c1) {
uint32_t r, g;
g = c0;
g += 0x4008020;
g -= c1;
r = DiffTable[(int)((unsigned char)g) + 0];
r ^= (0x3FF << 11);
g >>= 10;
r += DiffTable[(int)((unsigned char)g) + 0];
g >>= 11;
r += DiffTable[(int)((unsigned char)g) + 64];
r &= 0xE01F03E0;
return r;
}
#define DIFF56 0x001
#define DIFF52 0x002
#define DIFF54 0x004
#define DIFF58 0x008
#define DIFF53 0x010
#define DIFF51 0x020
#define DIFF57 0x040
#define DIFF59 0x080
#define DIFF26 0x100
#define DIFF24 0x200
#define DIFF84 0x400
#define DIFF86 0x800
/* lastLineDiffs is previous line's 52, 53, 26, all >> 1 */
uint8_t lastLineDiffs[__PAST_LIBRARY_WIDTH];
#define RotatePattern(x) ((((x) & 0x777) << 1) | (((x) & 0x888) >> 3))
void ProcessHQ2x(const pixel *in, pixel *out, signed int height) {
signed int y, x;
unsigned int pattern, newpattern;
uint32_t pixels[9];
int prevline, nextline;
bzero(lastLineDiffs, sizeof(lastLineDiffs));
prevline = 1;
nextline = 1 + __PAST_LIBRARY_WIDTH;
y = height - 1;
do {
pixels[1-1] =
pixels[2-1] = RGBUnpack(in[prevline-1]); /* Pixel 2 */
pixels[3-1] = RGBUnpack(in[prevline ]); /* Pixel 3 */
pixels[4-1] =
pixels[5-1] = RGBUnpack(in[ 0]); /* Pixel 5 */
pixels[6-1] = RGBUnpack(in[ 1]); /* Pixel 6 */
pixels[7-1] =
pixels[8-1] = RGBUnpack(in[nextline-1]); /* Pixel 8 */
pixels[9-1] = RGBUnpack(in[nextline ]); /* Pixel 9 */
pattern = 0;
x = __PAST_LIBRARY_WIDTH - 1;
do {
newpattern = 0;
if (pattern & DIFF26) newpattern |= DIFF51;
if (pattern & DIFF56) newpattern |= DIFF54;
if (pattern & DIFF86) newpattern |= DIFF57;
if (pattern & DIFF53) newpattern |= DIFF24;
if (pattern & DIFF59) newpattern |= DIFF84;
if (lastLineDiffs[x] & (DIFF52 >> 1)) newpattern |= DIFF58;
if (lastLineDiffs[x] & (DIFF26 >> 1)) newpattern |= DIFF59;
if (lastLineDiffs[x] & (DIFF53 >> 1)) newpattern |= DIFF86;
pattern = newpattern;
if (ExpandedDiff(pixels[5-1], pixels[2-1])) pattern |= DIFF52;
if (ExpandedDiff(pixels[5-1], pixels[3-1])) pattern |= DIFF53;
if (ExpandedDiff(pixels[5-1], pixels[6-1])) pattern |= DIFF56;
if (ExpandedDiff(pixels[2-1], pixels[6-1])) pattern |= DIFF26;
lastLineDiffs[x] = pattern >> 1;
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 0] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[2-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[4-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[1-1] * blends_2x[(newpattern * 4) + 3])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 1] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[6-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[2-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[3-1] * blends_2x[(newpattern * 4) + 3])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*2)+1] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[8-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[6-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[9-1] * blends_2x[(newpattern * 4) + 3])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*2) ] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[4-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[8-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[7-1] * blends_2x[(newpattern * 4) + 3])) / 16);
out += 2;
in++;
x--;
if (x == 0) {
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
continue;
}
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[3-1] = RGBUnpack(in[prevline]); /* Pixel 3 */
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[6-1] = RGBUnpack(in[1 ]); /* Pixel 6 */
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
pixels[9-1] = RGBUnpack(in[nextline]); /* Pixel 9 */
} while (x >= 0);
prevline = 1 - __PAST_LIBRARY_WIDTH;
out += (__PAST_LIBRARY_WIDTH * 2);
y--;
if (y > 0) {
continue;
}
nextline = 0;
} while (y >= 0);
}
void ProcessHQ4x(const pixel *in, pixel *out, signed int height) {
signed int y, x;
unsigned int pattern, newpattern;
uint32_t pixels[9];
int prevline, nextline;
bzero(lastLineDiffs, sizeof(lastLineDiffs));
prevline = 1;
nextline = 1 + __PAST_LIBRARY_WIDTH;
y = height - 1;
do {
pixels[1-1] =
pixels[2-1] = RGBUnpack(in[prevline-1]); /* Pixel 2 */
pixels[3-1] = RGBUnpack(in[prevline ]); /* Pixel 3 */
pixels[4-1] =
pixels[5-1] = RGBUnpack(in[ 0]); /* Pixel 5 */
pixels[6-1] = RGBUnpack(in[ 1]); /* Pixel 6 */
pixels[7-1] =
pixels[8-1] = RGBUnpack(in[nextline-1]); /* Pixel 8 */
pixels[9-1] = RGBUnpack(in[nextline ]); /* Pixel 9 */
pattern = 0;
x = __PAST_LIBRARY_WIDTH - 1;
do {
newpattern = 0;
if (pattern & DIFF26) newpattern |= DIFF51;
if (pattern & DIFF56) newpattern |= DIFF54;
if (pattern & DIFF86) newpattern |= DIFF57;
if (pattern & DIFF53) newpattern |= DIFF24;
if (pattern & DIFF59) newpattern |= DIFF84;
if (lastLineDiffs[x] & (DIFF52 >> 1)) newpattern |= DIFF58;
if (lastLineDiffs[x] & (DIFF26 >> 1)) newpattern |= DIFF59;
if (lastLineDiffs[x] & (DIFF53 >> 1)) newpattern |= DIFF86;
pattern = newpattern;
if (ExpandedDiff(pixels[5-1], pixels[2-1])) pattern |= DIFF52;
if (ExpandedDiff(pixels[5-1], pixels[3-1])) pattern |= DIFF53;
if (ExpandedDiff(pixels[5-1], pixels[6-1])) pattern |= DIFF56;
if (ExpandedDiff(pixels[2-1], pixels[6-1])) pattern |= DIFF26;
lastLineDiffs[x] = pattern >> 1;
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 0] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[ 1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4) ] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4)+1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4)+3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[ 2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4)+2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*0xC)+3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[(__PAST_LIBRARY_WIDTH*0xC)+2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8)+3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8)+2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*0xC) ] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8) ] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[(__PAST_LIBRARY_WIDTH*0xC)+1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8)+1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
out += 4;
in++;
x--;
if (x == 0) {
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
continue;
}
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[3-1] = RGBUnpack(in[prevline]); /* Pixel 3 */
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[6-1] = RGBUnpack(in[1 ]); /* Pixel 6 */
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
pixels[9-1] = RGBUnpack(in[nextline]); /* Pixel 9 */
} while (x >= 0);
prevline = 1 - __PAST_LIBRARY_WIDTH;
out += (__PAST_LIBRARY_WIDTH * 0xC);
y--;
if (y > 0) {
continue;
}
nextline = 0;
} while (y >= 0);
}
-64
View File
@@ -1,64 +0,0 @@
/* This source code is Copyright (C) 2006-2009 by WolfWings. */
/* It is, however, released under the ISC license. */
/* en.wikipedia.org/wiki/ISC_Licence */
/* --------------------------------------------------------- */
/* It is a formula-level rederiviation of the HQ2x technique */
/* and is, thus, not a derivative work of the original code, */
/* only the original equations behind the code. */
#ifndef __PAST_LIBRARY_H
#define __PAST_LIBRARY_H
#include <stdint.h>
#ifndef __PAST_LIBRARY_WIDTH
#define __PAST_LIBRARY_WIDTH 256
#endif
#ifndef __PAST_LIBRARY_HEIGHT
#define __PAST_LIBRARY_HEIGHT 224
#endif
#ifdef _MSC_VER
#define __inline__
#endif
#include "CrabEmu.h"
CLINKAGE
typedef uint16_t pixel;
/* These two functions are what need to be modified to interface other
* pixel formats with the library. They need to return values inside a
* format like this: (Red/Blue can be reversed.)
*
* 0000-00GG-GGG0-0000-0RRR-RR00-000B-BBBB
*
* This is VERY fast to create from 15-bit (NOT 16-bit) RGB/BGR, as
* below.
*
* If you can't return data in this format, you'll have to rebuild the
* ExpandedDiff function and DiffTable array to compensate, and possibly
* change the blending functions in the Process* functions to handle any
* guard-bits and masking.
*/
static __inline__ uint32_t RGBUnpack(pixel i) {
uint32_t o = i;
o = (o * 0x10001);
o = o & 0x03E07C1F;
return o;
}
static __inline__ pixel RGBPack(uint32_t x) {
x &= 0x03E07C1F;
x |= (x >> 16);
return x;
}
void ProcessHQ2x(const pixel *inbuffer, pixel *outbuffer, signed int height);
void ProcessHQ4x(const pixel *inbuffer, pixel *outbuffer, signed int height);
ENDCLINK
#endif /* __PAST_LIBRARY_H */
-28
View File
@@ -1,28 +0,0 @@
-=[ Pixel Art Scaling Toolkit - v0.2 by WolfWings ]=-
This is a low-level graphics-scaling library intented primarilly for use with
low-resolution 'pixel art' such as that found in emulation. It will implement
most scaling methods with a relatively fixed time, though it may require more
work than some other choices to add to your software. On a Core 2 Duo it will
render HQ2x (one of the most demanding algo's currently) in around 21.5 clock
cycles per output pixel without any MMX/SSE code, while HQ4x costs half that,
approximately 10.75 clock cycles per output pixel. So quadruple the scale, at
only double the cost.
Please examine and understand the pastlib.h file, it is how you'd modify the
library to support other resolutions and/or pixel formats. And please do not
try to make the library accomidate dynamic horizontal resolutions, it's just
not possible without suffering a very measurable 20-25% speed loss on x86-64
or even worse on plain x86 with even fewer registers available.
Also, note that this code is developed under GCC 4.3, and takes advantage of
the profile optimized compiling technique. For example, the 'unguided' build
of the algo is almost a third slower than the profiled version. There's some
work to be done yet to integrate MMX code and the like, but for now enjoy.
And yes, I will be creating tables for HQ3x, 2xSai, Scale2x, etc, etc. While
most of these will likely be redundant, and perhaps inefficient, they'll all
be entirely ISC Licensed implementations at that point, allowing use in many
situations where their current licenses would prevent that.
- WolfWings, who is way too good at making full-justified text.
+753
View File
@@ -0,0 +1,753 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD$
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#include <sys/cdefs.h>
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may be traversed in either direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _CLASS_HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _CLASS_ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - + - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_FROM + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_FROM_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_FROM - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _FOREACH_REVERSE_FROM_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
* _SWAP + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
unsigned long lastline;
unsigned long prevline;
const char *lastfile;
const char *prevfile;
};
#define TRACEBUF struct qm_trace trace;
#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRACEBUF_INITIALIZER
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
#ifdef __cplusplus
/*
* In C++ there can be structure lists and class lists:
*/
#define QUEUE_TYPEOF(type) type
#else
#define QUEUE_TYPEOF(type) struct type
#endif
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_CLASS_HEAD(name, type) \
struct name { \
class type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
#define SLIST_CLASS_ENTRY(type) \
struct { \
class type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_SWAP(head1, head2, type) do { \
QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *stqh_first; /* first element */ \
class type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
#define STAILQ_CLASS_ENTRY(type) \
struct { \
class type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, \
QUEUE_TYPEOF(type), field.stqe_next))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_SWAP(head1, head2, type) do { \
QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \
QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_CLASS_HEAD(name, type) \
struct name { \
class type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
#define LIST_CLASS_ENTRY(type) \
struct { \
class type *le_next; /* next element */ \
class type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, \
QUEUE_TYPEOF(type), field.le_next))
#define LIST_REMOVE(elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *tqh_first; /* first element */ \
class type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
#define TAILQ_CLASS_ENTRY(type) \
struct { \
class type *tqe_next; /* next element */ \
class type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
&((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&(listelm)->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&(listelm)->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \
QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */
+8 -3
View File
@@ -1,10 +1,10 @@
/*
This file is part of CrabEmu.
Copyright (C) 2009 Lawrence Sebald
Copyright (C) 2009, 2014 Lawrence Sebald
CrabEmu is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
CrabEmu is distributed in the hope that it will be useful,
@@ -29,7 +29,7 @@
void scale2x_scale(const pixel_t *inbuf, pixel_t *outbuf, int width,
int height) {
int i;
int a, b, c, d, p;
pixel_t a, b, c, d, p;
int neww = (width << 1) - 2;
/* Top row comes first. */
@@ -146,3 +146,8 @@ void scale2x_scale(const pixel_t *inbuf, pixel_t *outbuf, int width,
*(outbuf + neww + 1) = PIXEL3(a, 0, c, 0, p); /* Duplicate. */
*(outbuf + neww) = PIXEL3(a, 0, c, 0, p);
}
#undef PIXEL1
#undef PIXEL2
#undef PIXEL3
#undef PIXEL4