PicoDrive (WIP)

This commit is contained in:
nattthebear 2017-07-02 13:47:43 -04:00
parent bc9726f687
commit 47535f8158
87 changed files with 79134 additions and 0 deletions

View File

@ -1117,6 +1117,8 @@
</Compile>
<Compile Include="Consoles\Sega\gpgx64\GPGXControlConverter.cs" />
<Compile Include="Consoles\Sega\gpgx64\LibGPGX.cs" />
<Compile Include="Consoles\Sega\PicoDrive\LibPicoDrive.cs" />
<Compile Include="Consoles\Sega\PicoDrive\PicoDrive.cs" />
<Compile Include="Consoles\Sega\Saturn\FilePiping.cs" />
<Compile Include="Consoles\Sega\Saturn\LibSaturnus.cs" />
<Compile Include="Consoles\Sega\Saturn\Saturnus.cs" />

View File

@ -0,0 +1,16 @@
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
{
public abstract class LibPicoDrive : LibWaterboxCore
{
[BizImport(CC)]
public abstract bool Init();
}
}

View File

@ -0,0 +1,51 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
{
[CoreAttributes("PicoDrive", "notaz", true, false,
"0e352905c7aa80b166933970abbcecfce96ad64e", "https://github.com/notaz/picodrive", false)]
public class PicoDrive : WaterboxCore
{
private LibPicoDrive _core;
[CoreConstructor("GEN")]
public PicoDrive(CoreComm comm, byte[] rom)
: base(comm, new Configuration
{
MaxSamples = 2048,
DefaultWidth = 320,
DefaultHeight = 224,
MaxWidth = 320,
MaxHeight = 480,
SystemId = "GEN"
})
{
_core = PreInit<LibPicoDrive>(new PeRunnerOptions
{
Filename = "picodrive.wbx",
SbrkHeapSizeKB = 4096,
SealedHeapSizeKB = 4096,
InvisibleHeapSizeKB = 4096,
MmapHeapSizeKB = 65536,
PlainHeapSizeKB = 4096,
});
_exe.AddReadonlyFile(rom, "romfile.md");
if (!_core.Init())
throw new InvalidOperationException("Core rejected the rom!");
_exe.RemoveReadonlyFile("romfile.md");
PostInit();
}
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
return new LibWaterboxCore.FrameInfo();
}
}
}

6
waterbox/gpgx/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
// Place your settings in this file to overwrite default and user settings.
{
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.detectIndentation": false
}

View File

@ -0,0 +1,6 @@
// Place your settings in this file to overwrite default and user settings.
{
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.detectIndentation": false
}

View File

@ -0,0 +1,56 @@
notaz
core, 32X emulation, CD code, ARM asm renderers, dynamic recompilers,
Pandora, GPH device, PSP, Gizmondo ports, CPU core hacks
lots of additional coding (see changeLog).
Homepage: http://notaz.gp2x.de/
fDave
project starter
Cyclone 68000 core and PicoDrive core itself
Chui
FAME/C 68k interpreter core
(based on C68K by Stephane Dallongeville)
Stephane Dallongeville (written), NJ (optimized)
CZ80 Z80 interpreter core
Reesy & FluBBa
DrZ80, the Z80 interpreter written in ARM assembly.
Homepage: http://reesy.gp32x.de/ (defunct)
Tatsuyuki Satoh, Jarek Burczynski, MAME development
software implementation of Yamaha FM sound generator
MAME development
Texas Instruments SN76489 / SN76496 programmable tone/noise generator
Homepage: http://www.mame.net/
Eke-Eke
CD graphics processor and CD controller implementation (from Genesis Plus GX)
Additional thanks
-----------------
* Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful
info about genesis hardware.
* Steve Snake for all that he has done for Genesis emulation scene.
* Stephane Dallongeville for writing Gens and making it open source.
* Tasco Deluxe for his reverse engineering work on SVP and some mappers.
* Bart Trzynadlowski for his SSFII and 68000 docs.
* Haze for his research (http://mamedev.emulab.it/haze/).
* Lordus, Exophase and Rokas for various ideas.
* Nemesis for his YM2612, VDP research and docs.
* Eke-Eke for sharing the knowledge and his work on Genesis Plus GX.
* Many posters at spritesmind.net forums for valuable information.
* Mark and Jean-loup for zlib library.
* ketchupgun for the skin.
* GP2X specific help: rlyeh, Squidge, Dzz, A_SN, Alex and GP32X posters.
* Gizmondo code: Kingcdr, Reesy, jens.l (for the device itself)
* Hardware: craigix (GP2X), EvilDragon (Wiz, Caanoo, Pandora, ...)
and jens.l (Gizmondo)
* Paul Cercueil for OpenDingux port.
* Inder for some graphics.
* squarepusher for some libretro fixes
* Anyone else I forgot. Let me know if it's you.

View File

@ -0,0 +1,30 @@
Redistribution and use of this code or any derivative works are permitted
provided that the following conditions are met:
* Redistributions may not be sold, nor may they be used in a commercial
product or activity.
* Redistributions that are modified from the original source must include the
complete source code, including the source code for all components used by a
binary built from the modified sources. However, as a special exception, the
source code distributed need not include anything that is normally distributed
(in either source or binary form) with the major components (compiler, kernel,
and so on) of the operating system on which the executable runs, unless that
component itself accompanies the executable.
* Redistributions must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,487 @@
1.91 (2013-10-12)
+ Added OpenDingux support (Paul Cercueil).
* Save directory changed to ~/.picodrive/ for generic platform build
(Paul Cercueil).
+ Revived GP2X/Caanoo/Wiz support.
+ Switched to cleaner CD controller code from Eke-Eke's Genesis Plus GX.
* Fixed overflow issue where cd emulation would break after
~10 minutes of gameplay.
* Fixed synchronization issue where model1 CD BIOS would randomly hang.
1.90 (2013-09-24)
+ 32X+CD emulation has been implemented.
+ CD graphics processor code has been replaced with much cleaner Eke-Eke's
implementation from Genesis Plus GX.
+ CD PCM code has been completely rewritten.
* Various CD compatibility issues have been solved. Hopefully no more
regressions this time.
* pandora: fixed tv-out (again), added automatic layer switching
* libretro: fixed crackling sound for some games, added some core options
* sdl: multiple joystick support has been fixed (Victor Luchits)
1.85 (2013-08-31)
* Lots of 32X compatibility and accuracy improvements. All commercial games
are booting now, but some still have issues.
* Fixed some regressions in MegaCD code, like hang in jap BIOS.
* Implemented pause for SMS.
* Updated UI with improvements from PCSX ReARMed.
* Frontend timing has been rewritten, should no longer slowly desync from
LCD on pandora.
* Added libretro and SDL 32/64bit ports, fixed compatibility issues with
Android, iOS.
* Various other things I forgot (it has been a while since last release..)
1.80 (2010-09-19)
+ Added Caanoo support. Now the GP2X binary supports GP2X F100/F200, Wiz
and Caanoo. Lots of internal refactoring to support this.
+ Enabled 32X and SMS code. It's still unfinished but better release something
now than wait even more (it has been in development for more then a year now
due to various other projects or simply lack of time).
+ Pandora: added hardware scaler support, including ability to resize the
layer and control filtering.
+ GP2X: Added basic line-doubling vertical scaling option.
* Changed the way keys are bound, no need to unbind old one any more.
* Handle MP3s with ID3 tags better (some MP3s with ID3 did not play).
* Improved shadow/hilight color levels.
* Fixed broken cheat support.
1.80beta2
* Pandora: updated documentation.
1.80beta1 (2010-06-02)
+ Added pandora port.
* Internal refactoring for 32x/SMS support.
* Move mapper database to external file.
+ Added preliminary SMS emulation.
+ Added emulation of 32x peripherals including VDP. More work is needed here.
+ ARM: Added new SH2 recompiler for 32x. Some unification with SVP one.
- Disabled most of the above bacause I'm not yet happy with the results.
1.56 (2009-09-19)
* Changed sync in Sega CD emulation again. Should fix games that
broke after changes in 1.51a.
* Fixed default keys rebinding when they shouldn't.
* Fixed sram being loaded from wrong game.
* Emu should no longer hang shortly after using fast-forward.
* Fixed save states sometimes no longer showing up in save state menu.
* ARM: some asm code refactoring for slight speed improvement.
1.55
+ Added Wiz support. Now the same GP2X binary supports F100/F200 and Wiz.
* Changed shadow/hilight handling a bit, fixes some effects in Pirates! Gold.
* Complete input code rewrite. This fixes some limitations like not allowing
to control both players using single input device. It also allows to use
more devices (like keyboards) on Linux based devices.
* Options menu has been reordered, "restore defaults" option added.
1.51b
* Fixed a crash when uncompressed savestate is loaded.
* Fixed an idle loop detection related hanging problem.
* PSP: fixed another palette related regression.
* UIQ3: updated frontend for the latest emu core.
1.51a
* Fixed a sync problem between main and sub 68k. Should fix the hanging
problem for some games.
* ARM: fixed a crash when CD savestate is loaded just after loading ROM.
1.51
* Improved bin_to_cso_mp3 tool, it should no longer complain about
missing lame.exe even if it's in working dir.
* Fixed a regression from 1.50, which caused slowdowns in Final Fight.
* Fixed some regressions from 1.50 related to sprite limit and palette
handling (caused graphical glitches in some games).
+ Added ABC turbo actions to key config.
* Some other minor adjustments.
1.50
+ Added some basic support for Sega Pico, a MegaDrive-based toy.
+ Added proper support for cue/bin images, including cdda playback.
.cue sheets with iso/cso/mp3/wav files listed in them are now
supported too (but 44kHz restriction still applies).
+ Added bin_to_cso_mp3 tool, based on Exophase's bin_to_iso_ogg.
The tool can convert .cue/.bin Sega CD images to .cso/.mp3.
* Greatly improved Sega CD load times.
* Changed how scheduling between 68k and z80 is handled. Improves
performance for some games. Credits to Lordus for the idea.
* YM2612 state was not 100% saved, this should be better now.
* Improved renderer performance for shadow/hilight mode.
* Added a hack for YM2612 frequency overflow issue (bleep noises
in Shaq Fu, Spider-Man - The Animated Series (intro music), etc.)
Credits to Nemesis @ spritesmind forum. Works only if sound rate
is set to 44kHz.
+ Implemented some sprite rendering improvements, as suggested by
Exophase. Games with lots of sprites now perform better.
+ Added better idle loop detection, based on Lordus' idea again.
- "accurate timing" option removed, as disabling it no longer
improves performance.
- "accurate sprites" was removed too, the new sprite code can
properly handle sprite priorities in all cases.
* Timers adjusted again.
* Improved .smd detection code.
* ARM: fixed a bug in DrZ80 core, which could cause problems in
some rare cases.
* ARM: fixed a problem of occasional clicks on MP3 music start.
* Minor general optimizations and menu improvements.
* Fixed a bug in Sega CD savestate loader, where the game would
sometimes crash after load.
* Fixed a crash of games using eeprom (introduced in 1.40b).
* PSP: fixed suspend/resume (hopefully for real).
1.40c
* Fixed a problem with sound in Marble Madness.
* GP2X: Fixed minor problem with key config.
1.40b
* Fixed sprite masking code. Thanks to Lordus for explaining how it works.
+ Added "disable sprite limit" option.
+ PSP: added black level adjustment to display options.
* Changed reset to act as 'soft' reset.
+ Added detection for Puggsy (it doesn't really have sram).
* Some small timing adjustments.
1.40a
* GP2X: Fixed a binding problem with up and down keys.
* Default game config no longer overrides global user config.
1.40
+ Added support for SVP (Sega Virtua Processor) to emulate Virtua Racing,
wrote ARM recompiler and some HLE code for VR. Credits to Exophase and
Rokas for various ideas.
* Changed config file format, files are now human-readable. Game specific
configs are now held in single file (but old game config files are still
read when new one is missing).
* Fixed a bug where some key combos didn't work as expected.
* Fixed a regression in renderer (ARM ports only, some graphic glitches in
rare cases).
* Adjusted fast renderer to work with more games, including VR.
* Fixed a problem where SegaCD RAM cart data was getting lost on reset.
* GP2X: Greatly reduced SegaCD FMV game slowdowns by disabling read-ahead
in the Linux kernel and C library (thanks to Rokas and Exophase for ideas
again). Be sure to keep "ReadAhead buffer" OFF to avoid slowdowns.
+ PicoDrive now comes with a game config file for some games which need
special settings, so they should now work out-of-the-box. More games will
be added with later updates.
+ GP2X: Files now can be deleted by pressing A+SELECT in the file browser.
1.35b
* PSP: mp3 code should no longer fail on 1.5 firmware.
+ PSP: added gamma adjustment option.
+ Added .cso ISO format support. Useful for non-FMV games.
* It is now possile to force a region after the ROM is loaded.
* Fixed a sram bug in memhandlers (fixes Shining in the Darkness saves).
* PSP: fixed another bug in memhanlers, which crashed the emu for some games
(like NBA Jam and NHL 9x).
+ PSP: added suspend/resume handling for Sega CD games.
+ GP2X: added additional low volume levels for my late-night gaming sessions
(in stereo mode only).
+ GP2X: added "fast forward" action in key config. Not recommended to use for
Sega CD, may case problems there.
* Some other small tweaks I forgot about.
1.35a
* PSP: fixed a bug which prevented to load any ROMs after testing the BIOS.
* PSP: fixed incorrect CZ80 memory map setup, which caused Z80 crashes and
graphics corruption in EU Mega CD model1 BIOS menus.
+ PSP: added additional "set to 4:3 scaled" display option for convenience.
+ PSP: Added an option to disable frame limitter (works only with non-auto frameskip).
1.35
+ PSP port added. Lots of new code for it. Integrated modified FAME/C, CZ80 cores.
+ Some minor generic optimizations.
* Patched some code which was crashing under PSP, but was working in GP2X/Giz
(although it should have crashed there too).
* Readme updated.
1.34
+ Gizmondo port added.
+ Some new optimizations in memory handlers, and for shadow/hilight mode.
+ Added some hacks to make more games work without enabling "accurate timing".
* Adjusted timing for "accurate timing" mode and added preliminary VDP FIFO
emulation. Fixes Double Dragon 2, tearing in Chaos Engine and some other games.
* Fixed a few games not having sound at startup.
* Updated serial EEPROM code to support more games. Thanks to EkeEke for
providing info about additional EEPROM types and game mappers.
* The above change fixed hang of NBA Jam.
* Minor adjustments to control configurator.
1.33
* Updated Cyclone core to 0.0088.
+ Added A r k's usbjoy fix.
+ Added "perfect vsync" option, which adjusts GP2X LCD refresh rate and syncs
emulation to it to eliminate tearing and ensure smoothest scrolling possible.
+ Added an option to use A_SN's gamma curve for gamma correction (improves dark
and bright color display for mk2s).
* Sometimes stray sounds were played after loading a savestate. Fixed.
* Fixed a problem where >6MB mp3s were corrupted in memory (sound glitches in
Snatcher).
* PD no longer overwrites video player code in memory, video player now can be
used after exiting PicoDrive.
* Fixed a bug which was causing Sonic 3 code to deadlock in some rare conditions
if "accurate timing" was not enabled.
* Fixed support for large hacked ROMs like "Ultimate Mortal Kombat Trilogy".
Upto 10MB hacked ROMs are supported now.
+ Config profiles added (press left/right when saving config).
* Changed key configuration behavior to the one from gpfce (should be more
intuitive).
+ Added some skinning capabilities to the menu system with default skin by
ketchupgun. Delete skin directory if you want old behaviour.
* Some other little tweaks I forgot about.
1.32
+ Added some new scaling options.
+ Added ability to reload CD images while game is running (needed for games
with multiple CDs, like Night Trap).
+ Added RAM cart emulation.
* Fixed DMA timing emulation (caused lock-ups for some genesis games).
* Idle loop detection was picking up wrong code and causing glitches, fixed.
* The ym2612 code on 940 now can handle multiple updates per frame
(fixes Thunger Force III "seiren" level drums for example).
* Memory handlers were ignoring some writes to PSG chip, fixed (missing sounds in
Popful Mail, Silpheed).
* Improved z80 timing, should fix some sound problems.
* Fixed a bug with sram register (fixes Phantasy Star 4).
* ROM loader was incorrectly identifying some ROMs as invalid. Fixed.
* Added code for PRG ram write protection register (Dungeon Explorer).
* The memory mode register change in 1.31 was unsafe and caused some glitches in
AH-3 Thunderstrike. Fixed.
* Fixed a file descriptor leak.
* Updated documentation, added Gmenu2x manual.
1.31
* Changed the way memory mode register is read (fixes Lunar 2, broken in 1.30).
* Fixed TAS opcode on sub-68k side (fixes Batman games).
* File browser now filters out mp3s, saves and some other files, which are not ROMS.
1.30
+ ISO files now can be zipped. Note that this causes VERY long loading times.
+ Added data pre-buffering support, this allows to reduce frequency of short pauses
in FMV games (caused by SD access), but makes those pauses longer.
* Fixed PCM DMA transfers (intro FMV in Popful Mail).
+ Properly implemented "decode" data transformation (Jaguar XJ220).
* Integrated "better sync" code into cyclone code, what made this mode much faster.
* Fixed a bug related to game specific config saving.
* Frameskipper was skipping sound processing, what caused some audio desyncs. Fixed.
* Fixed reset not working for some games.
+ New assembly optimized memory handlers for CD (gives at least a few fps).
Also re-enabled all optimizations from 0.964 release.
+ New idle-loop detection code for sub-68k. Speeds up at least a few games.
1.201
+ Added basic cheat support (GameGenie and Genecyst patches).
1.20
* Fixed a long-standing problem in audio mixing code which caused slight distortions
at lower sample rates.
* Changed the way 920 and 940 communicates (again), should be more reliable and give
slight performance increase.
* Some optimizations in audio mixing code.
* Some menu changes (background added, smaller font in ROM browser, savestate loader
now can select slots).
+ 1M mode DMA transfers implemented (used by FMV games like Night Trap and Sewer Shark).
+ Games now can run code from WORD RAM in 1M mode (fixes Adventures of Willy Beamish).
+ "Cell arrange" address mapping is now emulated (Heart of the alien).
+ "Color numeric operation" is now emulated (text in Lunar 2, Silpheed intro graphics).
+ "Better sync" option added (prevents some games from hanging).
1.14
+ Region autodetection now can be customized.
* When CDDA music tracks changed, old buffer contents were incorrectly played. Fixed.
* BRAM is now automatically formatted (no need to enter BIOS menu and format any more).
* Games now can be reset, CDDA music no longer breaks after loading another ISO.
* Fixed a race condition between 920 and 940 which sometimes caused CDDA music not to play.
+ Savestates implemented for Sega/Mega CD.
+ PCM sound added.
* Some mixer code rewritten in asm. 22kHz and 11kHz sound rates are now supported in
Mega CD mode (but mp3s must still be 44kHz stereo).
+ Timer emulation added.
* CDC DMA tansfers fixed. Snatcher and probably some more games now boot.
* 2M word RAM -> VDP transfers fixed, no more corruption in Ecco and some other games.
1.10
+ GP2X: Added experimental Sega CD support.
+ GP2X: Added partial gmv movie playback support.
0.964 (2006-12-03)
* GP2X: Fixed a sound buffer underflow issue on lower sample rate modes, which was
happening for NTSC games and causing sound clicks.
* GP2X: Redone key config to better support USB joysticks (now multiple joysticks
should be useable and configurable).
+ GP2X: Added save confirmation option.
+ GP2X: Added 940 CPU crash detection.
+ ALL: UIQ3 port added.
0.963
* GP2X: Gamma-reset-on-entering-menu bug fixed.
* GP2X: Recompiled PicoDrive with gcc profiling option set as described here:
http://www.gp32x.com/board/index.php?showtopic=28490
0.962
* GP2X: Fixed an issue with incorrect sounds in some games when dualcore operation
was enabled (for example punch sound in SOR).
* GP2X: Limited max volume to 90, because higher values often cause distortions.
* GP2X: Fixed a bug with lower res scaling.
* GP2X: Gamma is now reset on exit.
0.96
* ALL: Severely optimized MAME's YM2612 core, part of it is now rewritten in asm.
+ GP2X: The YM2612's code now can be run in GP2X's ARM940T CPU, what causes large
performance increase.
* ALL: Accurate renderers are slightly faster now.
+ GP2X: Using quadruple buffering instead of doublebuffer now, also updated
framelimitter, this should eliminate some scrolling and tearing problems.
* GP2X: Fixed some flickering issues of 8bit accurate renderer.
+ GP2X: craigix's RAM timings now can be enabled in the menu (see advanced options).
+ GP2X: Added ability to save config for specific games only.
+ GP2X: Gamma control added (using GP2X's hardware capabilities for this).
* GP2X: Volume keys are now configurable.
+ GP2X: GnoStiC added USB joystick support, I made it possible to use it for
player 2 control (currently untested).
* GP2X: squidgehack is now applied through kernel module (cleaner way).
0.95
* ALL: Fixed a bug in sprite renderer which was causing slowdowns for some games.
+ GP2X: Added command line support
+ GP2X: Added optional hardware scaling for lower-res games like Shining Force.
* ALL: Sound chips are now sampled 2 times per frame. This fixed some games which
had missing sounds (Vectorman 2 1st level, Thunder Force 3 water level,
etc.).
+ ALL: Added another accurate 8-bit renderer which is slightly faster and made it
default.
0.945
+ GP2X: Added frame limiter for frameskipped modes.
* GP2X: Increased brightness a bit (unused pixel bits now also contain data).
* GP2X: Suidgehack was not applied correctly (was applied before allocating some
high memory and had no effect).
0.94
+ Added GP2X port.
* Improved interrupt timing, Mazin Saga and Burning Force now works.
* Rewritten renderer code to better suit GP2X, should be faster on other
ports too.
+ Added support for banking used by 12-in-1 and 4-in-1 ROMs (thanks Haze).
+ Added some protection device faking, used by some unlicensed games like
Super Bubble Bobble, King of Fighters, Elf Wor, ... (thanks to Haze again)
+ Added primitive Virtua Racing SVP faking, so menus can be seen now.
0.93
* Fixed a problem with P900/P910 key configuration in FC mode.
* Improved shadow/hilight mode emulation. Still not perfect, but should be
enough for most games.
+ Save state slots added.
+ Region selector added.
0.92
VDP changes:
* VDP emulation is now more accurate (fixes flickering in Chase HQ II,
Super Hang-On and some other problems in other games).
* HV counter emulation is now much more accurate. Fixes the Asterix games,
line in Road Rash 3, etc.
* Minor sprite and layer scroll masking bugs fixed.
+ Added partial interlace mode renderer (Sonic 2 vs mode)
* Fixed a crash in both renderers when certain size window layers were used.
+ Added emulation of shadow/hilight operator sprites. Other shadow/hilight
effects are still unemulated.
+ Sprite emulation is more accurate, sprite limit is emulated.
+ Added "accurate sprites" option, which always draws sprites in correct
order and emulates sprite collision bit, but is significantly slower.
Emulation changes:
* Improved interrupt handling, added deferred interrupt emulation
(Lemmings, etc).
+ Added serial EEPROM SRAM support (Wonder Boy in Monster World,
Megaman - The Wily Wars and many EA sports games like NBA Jam).
+ Implemented ROM banking for Super Street Fighter II - The New Challengers
* Updated to the latest version of DrZ80 core, integrated memory handlers
in it for better performance. A noticeable performance increase, but save
states may not work from the previous version (you can only use them with
sound disabled in that case).
+ SRAM word read handler was using incorrect byte order, fixed.
Changes in Cyclone 0.0086:
+ Added missing CHK opcode handler (used by SeaQuest DSV).
+ Added missing TAS opcode handler (Gargoyles,Bubba N Stix,...). As in real genesis,
memory write-back phase is ignored (but can be enabled in config.h if needed).
+ Added missing NBCD and TRAPV opcode handlers.
+ Added missing addressing mode for CMP/EOR.
+ Added some minor optimizations.
- Removed 216 handlers for 2927 opcodes which were generated for invalid addressing modes.
+ Fixed flags for ASL, NEG, NEGX, DIVU, ADDX, SUBX, ROXR.
+ Bugs fixed in MOVEP, LINK, ADDQ, DIVS handlers.
* Undocumented flags for CHK, ABCD, SBCD and NBCD are now emulated the same way as in Musashi.
+ Added Uninitialized Interrupt emulation.
+ Altered timing for about half of opcodes to match Musashi's.
0.80
* Nearly all VDP code was rewritten in ARM asm. Gives ~10-25% performance
increase (depends on game).
* Optimized 32-column renderer not to render tiles offscreen, games which
use 32-column display (like Shining Force) run ~50% faster.
+ Added new "Alternative renderer", which gives another ~30-45% performance
increase (in addition to mentioned above), but works only with some games,
because it is missing some features (it uses tile-based rendering
instead of default line-based and disables H-ints).
+ Added "fit2" display mode for all FC gamers. It always uses 208x146 for
P800 and 208x208 for all other phones.
+ Added volume control for Motorolas (experimental).
VDP changes:
+ Added support for vertical window (used by Vapor Trail, Mercs, GRIND
Stormer and others).
+ Added sprite masking (hiding), adds some speed.
+ Added preliminary H counter emulation. Comix Zone and Sonic 3D Blast
special stage are now playable.
+ Added column based vertical scrolling (Gunstar Heroes battleship level,
Sonic and Knuckles lava boss, etc).
Emulation changes:
+ Re-added and improved Z80 faking when Z80 is disabled. Many games now can
be played without enabling Z80 (Lost Vikings, Syndicate, etc), but some
still need it (International Superstar Soccer Deluxe).
* Improved ym2612 timers, Outrun music plays at correct speed, voices in
Earthworm Jim play better, more games play sound.
* I/O registers now remember their values (needed for Pirates! Gold)
+ Added support for 6 button pad.
Changes in Cyclone 0.0083wip:
+ Added missing CHK opcode (used by SeaQuest DSV).
+ Added missing TAS opcode (Gargoyles). As in real genesis, write-back phase
is ignored (but is enabled for other systems).
Backported stuff from Snes9x:
* Fixed Pxxx jog up/down which were not working in game.
+ Added an option to gzip save states to save space.
+ The emulator now pauses whenever it is loosing focus, so it will now pause
when alarm/ponecall/battery low/... windows come up.
- Removed 'pause on phonecall' feature, as it is no longer needed.
+ Video fix for asian A1000s.
0.70
* Started using tools from "Symbian GCC Improvement Project", which give
considerable speed increase (~4fps in "center 90" mode).
* Rewrote some drawing routines in ARM assembly (gives ~6 more fps in
"center 90" mode).
* Minor improvement to 0 and 180 "fit" modes. Now they look slightly better
and are faster.
* Minor stability improvements (emulator is less likely to crash).
+ Added some background for OSD text for better readability.
+ Added Pal/NTSC detection. This is needed for proper sound speed.
+ Implemented Reesy's DrZ80 Z80 emu. Made some changes to it with hope to make
it faster.
+ Implemented ym2612 emu from the MAME project. Runs well but sometimes sounds
a bit weird. Could be a little faster, so made some changes too.
+ Implemented SN76489 emu from the MAME project.
+ Added two separate sound output methods (mediaserver and cmaudiofb) with
autodetection (needs testing).
* Fixed VDP DMA fill emulation (as described in Charles MacDonald's docs),
fixes Contra and some other games.
0.301
Launcher:
* Launcher now starts emulation process from current directory,
not from hardcoded paths.
* Improved 'pause on call' feature, should hopefully work with Motorola phones.
0.30 (2006-01-07)
Initial release based on fDave's code.

View File

@ -0,0 +1,43 @@
CC = x86_64-nt64-midipix-gcc
CCFLAGS:=-I. \
-I../emulibc \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-std=c99 -fomit-frame-pointer -fvisibility=hidden \
-falign-functions=16 \
-DLSB_FIRST -DNDEBUG -DEMU_F68K -D_USE_CZ80 \
-O0 -g
TARGET = picodrive.wbx
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c')
OBJ_DIR:=$(ROOT_DIR)/obj
_OBJS:=$(SRCS:.c=.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS)
all: $(TARGET)
.PHONY: clean all
$(TARGET).in: $(OBJS)
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so
$(TARGET): $(TARGET).in
# strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
cp $< $@
clean:
rm -rf $(OBJ_DIR)
rm -f $(TARGET).in
rm -f $(TARGET)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

View File

@ -0,0 +1,154 @@
# Makefile for PicoDrive (libretro)
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
platform = osx
else ifneq ($(findstring win,$(shell uname -a)),)
platform = win
endif
endif
CC ?= gcc
CXX ?= g++
AS ?= as
CC_AS ?= $(CC)
CFLAGS ?=
TARGET_NAME := picodrive
asm_memory = 0
asm_render = 0
asm_ym2612 = 0
asm_misc = 0
asm_cdpico = 0
asm_cdmemory = 0
asm_mix = 0
ifeq ($(platform), unix)
TARGET := $(TARGET_NAME)_libretro.so
SHARED := -shared
else ifeq ($(platform), osx)
TARGET := $(TARGET_NAME)_libretro.dylib
SHARED := -dynamiclib
else ifeq ($(platform), ios)
TARGET := $(TARGET_NAME)_libretro_ios.dylib
SHARED := -dynamiclib
CC = clang -arch armv7 -isysroot $(IOSSDK) -miphoneos-version-min=5.0
CXX = clang++ -arch armv7 -isysroot $(IOSSDK) -miphoneos-version-min=5.0
CC_AS = perl ./tools/gas-preprocessor.pl $(CC) -miphoneos-version-min=5.0
CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -marm
ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
CFLAGS += -DIOS -miphoneos-version-min=5.0
ARCH := arm
use_cyclone = 0
use_fame = 1
use_drz80 = 0
use_cz80 = 1
use_sh2drc = 1
use_svpdrc = 1
else ifeq ($(platform), ps3)
TARGET := $(TARGET_NAME)_libretro_ps3.a
CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__
else ifeq ($(platform), sncps3)
TARGET := $(TARGET_NAME)_libretro_ps3.a
CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__
else ifeq ($(platform), psl1ght)
TARGET := $(TARGET_NAME)_libretro_psl1ght.a
CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT)
AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT)
CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__
else ifeq ($(platform), psp1)
TARGET := $(TARGET_NAME)_libretro_psp1.a
CC = psp-gcc$(EXE_EXT)
AR = psp-ar$(EXE_EXT)
CFLAGS += -DPSP -G0
else ifeq ($(platform), xenon)
TARGET := $(TARGET_NAME)_libretro_xenon360.a
CC = xenon-gcc$(EXE_EXT)
AR = xenon-ar$(EXE_EXT)
CFLAGS += -D__LIBXENON__ -m32 -D__ppc__
else ifeq ($(platform), ngc)
TARGET := $(TARGET_NAME)_libretro_ngc.a
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__
else ifeq ($(platform), wii)
TARGET := libretro_$(TARGET_NAME)_wii.a
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__
else ifeq ($(platform), qnx)
TARGET := $(TARGET_NAME)_libretro_qnx.so
CC = qcc -Vgcc_ntoarmv7le
CC_AS = $(CC)
CFLAGS += -DBASE_ADDR_FIXED=0 -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp
ASFLAGS += -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
ARCH = arm
ARM_ASM = 1
else ifneq (,$(findstring armv,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
SHARED := -shared -Wl,--no-undefined
ifneq (,$(findstring cortexa8,$(platform)))
CFLAGS += -marm -mcpu=cortex-a8
ASFLAGS += -mcpu=cortex-a8
else ifneq (,$(findstring cortexa9,$(platform)))
CFLAGS += -marm -mcpu=cortex-a9
ASFLAGS += -mcpu=cortex-a9
endif
CFLAGS += -marm
ifneq (,$(findstring neon,$(platform)))
CFLAGS += -mfpu=neon
ASFLAGS += -mfpu=neon
endif
ifneq (,$(findstring softfloat,$(platform)))
CFLAGS += -mfloat-abi=softfp
ASFLAGS += -mfloat-abi=softfp
else ifneq (,$(findstring hardfloat,$(platform)))
CFLAGS += -mfloat-abi=hard
ASFLAGS += -mfloat-abi=hard
endif
ifneq (,$(findstring armasm,$(platform)))
ARM_ASM = 1
endif
ARCH = arm
else
TARGET := $(TARGET_NAME)_libretro.dll
CC = gcc
LD_FLAGS := -fPIC
SHARED := -shared -static-libgcc -static-libstdc++
CFLAGS += -D__WIN32__ -D__WIN32_LIBRETRO__
endif
ifeq ($(ARM_ASM),1)
asm_memory = 1
asm_render = 1
asm_ym2612 = 1
asm_misc = 1
asm_cdpico = 1
asm_cdmemory = 1
asm_mix = 1
endif
CFLAGS += -fPIC
LDLIBS += -lm
SHARED ?= -shared
LDFLAGS += $(SHARED)
PLATFORM = libretro
NO_CONFIG_MAK = yes
include Makefile

View File

@ -0,0 +1,227 @@
TARGET ?= PicoDrive
CFLAGS += -Wall -ggdb -falign-functions=2
CFLAGS += -I.
ifndef DEBUG
CFLAGS += -O3 -DNDEBUG -ffunction-sections
ifeq ($(findstring clang,$(CC)),)
LDFLAGS += -Wl,--gc-sections
endif
endif
#CFLAGS += -DEVT_LOG
#CFLAGS += -DDRC_CMP
#cpu_cmp = 1
#drc_debug = 7
#profile = 1
all: config.mak target_
ifndef NO_CONFIG_MAK
ifneq ($(wildcard config.mak),)
config.mak: ./configure
@echo $@ is out-of-date, running configure
@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
include config.mak
else
config.mak:
@echo "Please run ./configure before running make!"
@exit 1
endif
else # NO_CONFIG_MAK
config.mak:
endif
# default settings
ifeq "$(ARCH)" "arm"
use_cyclone ?= 1
use_drz80 ?= 1
use_sh2drc ?= 1
use_svpdrc ?= 1
asm_memory ?= 1
asm_render ?= 1
asm_ym2612 ?= 1
asm_misc ?= 1
asm_cdpico ?= 1
asm_cdmemory ?= 1
asm_mix ?= 1
else # if not arm
use_fame ?= 1
use_cz80 ?= 1
endif
-include Makefile.local
ifneq "$(use_cyclone)" "1"
# due to CPU stop flag access
asm_cdpico = 0
asm_cdmemory = 0
endif
ifeq "$(PLATFORM)" "opendingux"
opk: $(TARGET).opk
$(TARGET).opk: $(TARGET)
$(RM) -rf .opk_data
cp -r platform/opendingux/data .opk_data
cp $< .opk_data/PicoDrive
$(STRIP) .opk_data/PicoDrive
mksquashfs .opk_data $@ -all-root -noappend -no-exports -no-xattrs
OBJS += platform/opendingux/inputmap.o
# OpenDingux is a generic platform, really.
PLATFORM := generic
endif
ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","rpi1" "rpi2"))
CFLAGS += -DHAVE_GLES -DRASPBERRY
CFLAGS += -I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads/ -I/opt/vc/include/interface/vmcs_host/linux/
LDFLAGS += -ldl -lbcm_host -L/opt/vc/lib -lEGL -lGLESv2
OBJS += platform/linux/emu.o platform/linux/blit.o # FIXME
OBJS += platform/common/plat_sdl.o
OBJS += platform/libpicofe/plat_sdl.o platform/libpicofe/in_sdl.o
OBJS += platform/libpicofe/plat_dummy.o
OBJS += platform/libpicofe/gl.o
OBJS += platform/libpicofe/gl_platform.o
USE_FRONTEND = 1
endif
ifeq "$(PLATFORM)" "generic"
OBJS += platform/linux/emu.o platform/linux/blit.o # FIXME
OBJS += platform/common/plat_sdl.o
OBJS += platform/libpicofe/plat_sdl.o platform/libpicofe/in_sdl.o
OBJS += platform/libpicofe/plat_dummy.o
USE_FRONTEND = 1
endif
ifeq "$(PLATFORM)" "pandora"
platform/common/menu_pico.o: CFLAGS += -DPANDORA
platform/libpicofe/linux/plat.o: CFLAGS += -DPANDORA
OBJS += platform/pandora/plat.o
OBJS += platform/pandora/asm_utils.o
OBJS += platform/common/arm_utils.o
OBJS += platform/libpicofe/linux/fbdev.o
OBJS += platform/libpicofe/linux/xenv.o
OBJS += platform/libpicofe/pandora/plat.o
USE_FRONTEND = 1
endif
ifeq "$(PLATFORM)" "gp2x"
OBJS += platform/common/arm_utils.o
OBJS += platform/libpicofe/gp2x/in_gp2x.o
OBJS += platform/libpicofe/gp2x/soc.o
OBJS += platform/libpicofe/gp2x/soc_mmsp2.o
OBJS += platform/libpicofe/gp2x/soc_pollux.o
OBJS += platform/libpicofe/gp2x/plat.o
OBJS += platform/libpicofe/gp2x/pollux_set.o
OBJS += platform/gp2x/940ctl.o
OBJS += platform/gp2x/plat.o
OBJS += platform/gp2x/emu.o
OBJS += platform/gp2x/vid_mmsp2.o
OBJS += platform/gp2x/vid_pollux.o
OBJS += platform/gp2x/warm.o
USE_FRONTEND = 1
PLATFORM_MP3 = 1
endif
ifeq "$(PLATFORM)" "libretro"
OBJS += platform/libretro.o
endif
ifeq "$(USE_FRONTEND)" "1"
# common
OBJS += platform/common/main.o platform/common/emu.o \
platform/common/menu_pico.o platform/common/config_file.o
# libpicofe
OBJS += platform/libpicofe/input.o platform/libpicofe/readpng.o \
platform/libpicofe/fonts.o platform/libpicofe/linux/in_evdev.o \
platform/libpicofe/linux/plat.o
# libpicofe - sound
OBJS += platform/libpicofe/sndout.o
ifneq ($(findstring oss,$(SOUND_DRIVERS)),)
platform/libpicofe/sndout.o: CFLAGS += -DHAVE_OSS
OBJS += platform/libpicofe/linux/sndout_oss.o
endif
ifneq ($(findstring alsa,$(SOUND_DRIVERS)),)
platform/libpicofe/sndout.o: CFLAGS += -DHAVE_ALSA
OBJS += platform/libpicofe/linux/sndout_alsa.o
endif
ifneq ($(findstring sdl,$(SOUND_DRIVERS)),)
platform/libpicofe/sndout.o: CFLAGS += -DHAVE_SDL
OBJS += platform/libpicofe/sndout_sdl.o
endif
ifeq "$(ARCH)" "arm"
OBJS += platform/libpicofe/arm_linux.o
endif
endif # USE_FRONTEND
OBJS += platform/common/mp3.o
ifeq "$(PLATFORM_MP3)" "1"
else ifeq "$(HAVE_LIBAVCODEC)" "1"
OBJS += platform/common/mp3_libavcodec.o
else
OBJS += platform/common/mp3_dummy.o
endif
ifeq "$(PLATFORM)" "libretro"
# zlib
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o zlib/uncompr.o
CFLAGS += -Izlib
endif
# unzip
OBJS += unzip/unzip.o
include platform/common/common.mak
OBJS += $(OBJS_COMMON)
CFLAGS += $(addprefix -D,$(DEFINES))
ifneq ($(findstring gcc,$(CC)),)
LDFLAGS += -Wl,-Map=$(TARGET).map
endif
target_: $(TARGET)
clean:
$(RM) $(TARGET) $(OBJS)
$(RM) -r .opk_data
$(TARGET): $(OBJS)
$(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS) $(LDLIBS)
pprof: platform/linux/pprof.c
$(CC) -O2 -ggdb -DPPROF -DPPROF_TOOL -I../../ -I. $^ -o $@
tools/textfilter: tools/textfilter.c
make -C tools/ textfilter
.s.o:
$(CC) $(CFLAGS) -c $< -o $@
# special flags - perhaps fix this someday instead?
pico/draw.o: CFLAGS += -fno-strict-aliasing
pico/draw2.o: CFLAGS += -fno-strict-aliasing
pico/mode4.o: CFLAGS += -fno-strict-aliasing
pico/cd/memory.o: CFLAGS += -fno-strict-aliasing
pico/cd/cd_file.o: CFLAGS += -fno-strict-aliasing
pico/cd/pcm.o: CFLAGS += -fno-strict-aliasing
pico/cd/LC89510.o: CFLAGS += -fno-strict-aliasing
pico/cd/gfx_cd.o: CFLAGS += -fno-strict-aliasing
# fame needs ~2GB of RAM to compile on gcc 4.8
# on x86, this is reduced by ~300MB when debug info is off (but not on ARM)
# not using O3 and -fno-expensive-optimizations seems to also help, but you may
# want to remove this stuff for better performance if your compiler can handle it
cpu/fame/famec.o: CFLAGS += -g0 -O2 -fno-expensive-optimizations
# random deps
pico/carthw/svp/compiler.o : cpu/drc/emit_$(ARCH).c
cpu/sh2/compiler.o : cpu/drc/emit_$(ARCH).c
cpu/sh2/mame/sh2pico.o : cpu/sh2/mame/sh2.c
pico/pico.o pico/cd/mcd.o pico/32x/32x.o : pico/pico_cmn.c pico/pico_int.h
pico/memory.o pico/cd/memory.o pico/32x/memory.o : pico/pico_int.h pico/memory.h
cpu/fame/famec.o: cpu/fame/famec.c cpu/fame/famec_opcodes.h

21
waterbox/picodrive/README Normal file
View File

@ -0,0 +1,21 @@
This is yet another Megadrive / Genesis / Sega CD / Mega CD / 32X / SMS
emulator, which was written having ARM-based handheld devices in mind
(such as smartphones and handheld consoles like GP2X and Pandora),
but also runs on non-ARM little-endian hardware too.
The emulator is heavily optimized for ARM, features assembly cores for
68k, Z80 and VDP chip emulation, also has dynamic recompilers for SH2 and
SSP16 (for 32X and SVP emulation). It was started by Dave (aka fdave,
finalburn author) as basic Genesis/Megadrive emulator for Pocket PC,
then taken over and expanded by notaz.
PicoDrive was the first emulator ever to properly emulate Virtua Racing and
it's SVP chip.
How to compile on Raspbian Wheezy:
export CC=gcc-4.8
export CXX=g++-4.8
./configure --platform=rpi2
make

View File

@ -0,0 +1,153 @@
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include "../emulibc/emulibc.h"
#include "../emulibc/waterboxcore.h"
#include "pico/pico.h"
#include "pico/cd/cue.h"
void lprintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
int PicoCartResize(int newsize)
{
// TODO: change boards that use this to store their extra data elsewhere
return -1;
}
int PicoCdCheck(const char *fname_in, int *pregion)
{
return CIT_NOT_CD;
}
cue_data_t *cue_parse(const char *fname)
{
return NULL;
}
pm_file *pm_open(const char *path)
{
FILE *f = fopen(path, "rb");
if (!f)
return NULL;
fseek(f, 0, SEEK_END);
pm_file *ret = calloc(1, sizeof(*ret));
ret->file = f;
ret->size = ftell(f);
fseek(f, 0, SEEK_SET);
ret->type = PMT_UNCOMPRESSED;
return ret;
}
size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
{
return fread(ptr, 1, bytes, (FILE *)stream->file);
}
int pm_seek(pm_file *stream, long offset, int whence)
{
return fseek((FILE *)stream->file, offset, whence);
}
int pm_close(pm_file *fp)
{
int ret = fclose((FILE *)fp->file);
fp->file = NULL;
free(fp);
return ret;
}
static int video_start_line;
static int video_line_count;
static int video_width;
static uint16_t* video_buffer;
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
{
video_start_line = start_line;
video_line_count = line_count;
video_width = is_32cols ? 256 : 320;
}
// "switch to 16bpp mode?"
void emu_32x_startup(void)
{
}
int mp3_get_bitrate(void *f, int size) { return 0; }
void mp3_start_play(void *f, int pos) {}
void mp3_update(int *buffer, int length, int stereo) {}
ECL_EXPORT int Init(void)
{
video_buffer = alloc_invisible(512 * 512 * sizeof(uint16_t));
PicoInit();
PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN);
PicoSetInputDevice(1, PICO_INPUT_PAD_6BTN);
PicoDrawSetOutBuf(video_buffer, 512 * sizeof(uint16_t));
if (PicoLoadMedia("romfile.md", NULL, NULL, NULL, PM_MD_CART) != PM_MD_CART)
return 0;
PicoDrawSetOutFormat(PDF_RGB555, 0); // TODO: what is "use_32x_line_mode"?
PicoPower();
return 1;
}
typedef struct
{
FrameInfo b;
} MyFrameInfo;
static void Blit(const uint16_t *src, FrameInfo *f)
{
f->Width = video_width;
f->Height = video_line_count;
uint8_t *dst = (uint8_t *)f->VideoBuffer;
src += 512 * video_start_line;
if (video_width == 256)
src += 32;
for (int j = 0; j < video_line_count; j++)
{
for (int i = 0; i < video_width; i++)
{
uint16_t c = src[i];
*dst++ = c << 3 & 0xf8 | c >> 2 & 7;
*dst++ = c >> 3 & 0xfa | c >> 9 & 3;
*dst++ = c >> 8 & 0xf8 | c >> 13 & 7;
*dst++ = 0xff;
}
src += 512;
}
}
ECL_EXPORT void FrameAdvance(MyFrameInfo *f)
{
PicoLoopPrepare();
PicoFrame();
Blit(video_buffer, &f->b);
f->b.Samples = 735; // TODO
}
static uint8_t dumbo[16];
ECL_EXPORT void GetMemoryAreas(MemoryArea *m)
{
m[0].Data = dumbo;
m[0].Name = "TODO";
m[0].Size = 16;
m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_PRIMARY;
}
ECL_EXPORT void SetInputCallback(void (*callback)(void))
{
}
int main(void)
{
return 0;
}

View File

@ -0,0 +1,488 @@
/******************************************************************************
*
* CZ80 (Z80 CPU emulator) version 0.9
* Compiled with Dev-C++
* Copyright 2004-2005 St<EFBFBD>phane Dallongeville
*
* (Modified by NJ)
*
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cz80.h"
#if PICODRIVE_HACKS
#include <pico/memory.h>
#endif
#ifndef ALIGN_DATA
#ifdef _MSC_VER
#define ALIGN_DATA
#define inline
#undef CZ80_USE_JUMPTABLE
#define CZ80_USE_JUMPTABLE 0
#else
#define ALIGN_DATA __attribute__((aligned(4)))
#endif
#endif
#define CF 0x01
#define NF 0x02
#define PF 0x04
#define VF PF
#define XF 0x08
#define HF 0x10
#define YF 0x20
#define ZF 0x40
#define SF 0x80
/******************************************************************************
<EFBFBD>}<EFBFBD>N<EFBFBD><EFBFBD>
******************************************************************************/
#include "cz80macro.h"
/******************************************************************************
<EFBFBD>O<EFBFBD><EFBFBD><EFBFBD>[<EFBFBD>o<EFBFBD><EFBFBD><EFBFBD>\<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
******************************************************************************/
cz80_struc ALIGN_DATA CZ80;
/******************************************************************************
<EFBFBD><EFBFBD><EFBFBD>[<EFBFBD>J<EFBFBD><EFBFBD><EFBFBD>ϐ<EFBFBD>
******************************************************************************/
static UINT8 ALIGN_DATA cz80_bad_address[1 << CZ80_FETCH_SFT];
static UINT8 ALIGN_DATA SZ[256];
static UINT8 ALIGN_DATA SZP[256];
static UINT8 ALIGN_DATA SZ_BIT[256];
static UINT8 ALIGN_DATA SZHV_inc[256];
static UINT8 ALIGN_DATA SZHV_dec[256];
#if CZ80_BIG_FLAGS_ARRAY
static UINT8 ALIGN_DATA SZHVC_add[2*256*256];
static UINT8 ALIGN_DATA SZHVC_sub[2*256*256];
#endif
/******************************************************************************
<EFBFBD><EFBFBD><EFBFBD>[<EFBFBD>J<EFBFBD><EFBFBD><EFBFBD>֐<EFBFBD>
******************************************************************************/
/*--------------------------------------------------------
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>݃R<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD>o<EFBFBD>b<EFBFBD>N
--------------------------------------------------------*/
static INT32 Cz80_Interrupt_Callback(INT32 line)
{
return 0xff;
}
/******************************************************************************
CZ80<EFBFBD>C<EFBFBD><EFBFBD><EFBFBD>^<EFBFBD>t<EFBFBD>F<EFBFBD>[<EFBFBD>X<EFBFBD>֐<EFBFBD>
******************************************************************************/
/*--------------------------------------------------------
CPU<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
--------------------------------------------------------*/
void Cz80_Init(cz80_struc *CPU)
{
UINT32 i, j, p;
#if CZ80_BIG_FLAGS_ARRAY
int oldval, newval, val;
UINT8 *padd, *padc, *psub, *psbc;
#endif
memset(CPU, 0, sizeof(cz80_struc));
memset(cz80_bad_address, 0xff, sizeof(cz80_bad_address));
for (i = 0; i < CZ80_FETCH_BANK; i++)
{
CPU->Fetch[i] = (FPTR)cz80_bad_address;
#if CZ80_ENCRYPTED_ROM
CPU->OPFetch[i] = 0;
#endif
}
// flags tables initialisation
for (i = 0; i < 256; i++)
{
SZ[i] = i & (SF | YF | XF);
if (!i) SZ[i] |= ZF;
SZ_BIT[i] = i & (SF | YF | XF);
if (!i) SZ_BIT[i] |= ZF | PF;
for (j = 0, p = 0; j < 8; j++) if (i & (1 << j)) p++;
SZP[i] = SZ[i];
if (!(p & 1)) SZP[i] |= PF;
SZHV_inc[i] = SZ[i];
if(i == 0x80) SZHV_inc[i] |= VF;
if((i & 0x0f) == 0x00) SZHV_inc[i] |= HF;
SZHV_dec[i] = SZ[i] | NF;
if (i == 0x7f) SZHV_dec[i] |= VF;
if ((i & 0x0f) == 0x0f) SZHV_dec[i] |= HF;
}
#if CZ80_BIG_FLAGS_ARRAY
padd = &SZHVC_add[ 0*256];
padc = &SZHVC_add[256*256];
psub = &SZHVC_sub[ 0*256];
psbc = &SZHVC_sub[256*256];
for (oldval = 0; oldval < 256; oldval++)
{
for (newval = 0; newval < 256; newval++)
{
/* add or adc w/o carry set */
val = newval - oldval;
*padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
*padd |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
if ((newval & 0x0f) < (oldval & 0x0f)) *padd |= HF;
if (newval < oldval ) *padd |= CF;
if ((val ^ oldval ^ 0x80) & (val ^ newval) & 0x80) *padd |= VF;
padd++;
/* adc with carry set */
val = newval - oldval - 1;
*padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
*padc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
if ((newval & 0x0f) <= (oldval & 0x0f)) *padc |= HF;
if (newval <= oldval) *padc |= CF;
if ((val ^ oldval ^ 0x80) & (val ^ newval) & 0x80) *padc |= VF;
padc++;
/* cp, sub or sbc w/o carry set */
val = oldval - newval;
*psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
*psub |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
if ((newval & 0x0f) > (oldval & 0x0f)) *psub |= HF;
if (newval > oldval) *psub |= CF;
if ((val^oldval) & (oldval^newval) & 0x80) *psub |= VF;
psub++;
/* sbc with carry set */
val = oldval - newval - 1;
*psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
*psbc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
if ((newval & 0x0f) >= (oldval & 0x0f)) *psbc |= HF;
if (newval >= oldval) *psbc |= CF;
if ((val ^ oldval) & (oldval^newval) & 0x80) *psbc |= VF;
psbc++;
}
}
#endif
CPU->pzR8[0] = &zB;
CPU->pzR8[1] = &zC;
CPU->pzR8[2] = &zD;
CPU->pzR8[3] = &zE;
CPU->pzR8[4] = &zH;
CPU->pzR8[5] = &zL;
CPU->pzR8[6] = &zF; // <20><><EFBFBD><EFBFBD><EFBFBD>̓s<CC93><73><EFBFBD><EFBFBD>AA<41>Ɠ<EFBFBD><C693><EFBFBD>ւ<EFBFBD>
CPU->pzR8[7] = &zA; // <20><><EFBFBD><EFBFBD><EFBFBD>̓s<CC93><73><EFBFBD><EFBFBD>AF<41>Ɠ<EFBFBD><C693><EFBFBD>ւ<EFBFBD>
CPU->pzR16[0] = pzBC;
CPU->pzR16[1] = pzDE;
CPU->pzR16[2] = pzHL;
CPU->pzR16[3] = pzAF;
zIX = zIY = 0xffff;
zF = ZF;
CPU->Interrupt_Callback = Cz80_Interrupt_Callback;
}
/*--------------------------------------------------------
CPU<EFBFBD><EFBFBD><EFBFBD>Z<EFBFBD>b<EFBFBD>g
--------------------------------------------------------*/
void Cz80_Reset(cz80_struc *CPU)
{
memset(CPU, 0, (FPTR)&CPU->BasePC - (FPTR)CPU);
Cz80_Set_Reg(CPU, CZ80_PC, 0);
}
/* */
#if PICODRIVE_HACKS
static inline unsigned char picodrive_read(unsigned short a)
{
uptr v = z80_read_map[a >> Z80_MEM_SHIFT];
if (map_flag_set(v))
return ((z80_read_f *)(v << 1))(a);
return *(unsigned char *)((v << 1) + a);
}
#endif
/*--------------------------------------------------------
CPU<EFBFBD><EFBFBD><EFBFBD>s
--------------------------------------------------------*/
INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles)
{
#if CZ80_USE_JUMPTABLE
#include "cz80jmp.inc"
#endif
FPTR PC;
#if CZ80_ENCRYPTED_ROM
FPTR OPBase;
#endif
UINT32 Opcode;
UINT32 adr = 0;
UINT32 res;
UINT32 val;
int afterEI = 0;
union16 *data;
PC = CPU->PC;
#if CZ80_ENCRYPTED_ROM
OPBase = CPU->OPBase;
#endif
CPU->ICount = cycles - CPU->ExtraCycles;
CPU->ExtraCycles = 0;
if (!CPU->HaltState)
{
Cz80_Exec:
if (CPU->ICount > 0)
{
Cz80_Exec_nocheck:
data = pzHL;
Opcode = READ_OP();
#if CZ80_EMULATE_R_EXACTLY
zR++;
#endif
#include "cz80_op.inc"
}
if (afterEI)
{
afterEI = 0;
Cz80_Check_Interrupt:
if (CPU->IRQState != CLEAR_LINE)
{
CHECK_INT
CPU->ICount -= CPU->ExtraCycles;
CPU->ExtraCycles = 0;
}
goto Cz80_Exec;
}
}
else CPU->ICount = 0;
Cz80_Exec_End:
CPU->PC = PC;
#if CZ80_ENCRYPTED_ROM
CPU->OPBase = OPBase;
#endif
cycles -= CPU->ICount;
#if !CZ80_EMULATE_R_EXACTLY
zR = (zR + (cycles >> 2)) & 0x7f;
#endif
return cycles;
}
/*--------------------------------------------------------
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݏ<EFBFBD><EFBFBD><EFBFBD>
--------------------------------------------------------*/
void Cz80_Set_IRQ(cz80_struc *CPU, INT32 line, INT32 state)
{
if (line == IRQ_LINE_NMI)
{
zIFF1 = 0;
CPU->ExtraCycles += 11;
CPU->HaltState = 0;
PUSH_16(CPU->PC - CPU->BasePC)
Cz80_Set_Reg(CPU, CZ80_PC, 0x66);
}
else
{
CPU->IRQState = state;
if (state != CLEAR_LINE)
{
FPTR PC = CPU->PC;
#if CZ80_ENCRYPTED_ROM
FPTR OPBase = CPU->OPBase;
#endif
CPU->IRQLine = line;
CHECK_INT
CPU->PC = PC;
#if CZ80_ENCRYPTED_ROM
CPU->OPBase = OPBase;
#endif
}
}
}
/*--------------------------------------------------------
<EFBFBD><EFBFBD><EFBFBD>W<EFBFBD>X<EFBFBD>^<EFBFBD>
--------------------------------------------------------*/
UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum)
{
switch (regnum)
{
case CZ80_PC: return (CPU->PC - CPU->BasePC);
case CZ80_SP: return zSP;
case CZ80_AF: return zAF;
case CZ80_BC: return zBC;
case CZ80_DE: return zDE;
case CZ80_HL: return zHL;
case CZ80_IX: return zIX;
case CZ80_IY: return zIY;
case CZ80_AF2: return zAF2;
case CZ80_BC2: return zBC2;
case CZ80_DE2: return zDE2;
case CZ80_HL2: return zHL2;
case CZ80_R: return zR;
case CZ80_I: return zI;
case CZ80_IM: return zIM;
case CZ80_IFF1: return zIFF1;
case CZ80_IFF2: return zIFF2;
case CZ80_HALT: return CPU->HaltState;
case CZ80_IRQ: return CPU->IRQState;
default: return 0;
}
}
/*--------------------------------------------------------
<EFBFBD><EFBFBD><EFBFBD>W<EFBFBD>X<EFBFBD>^<EFBFBD>ݒ<EFBFBD>
--------------------------------------------------------*/
void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val)
{
switch (regnum)
{
case CZ80_PC:
CPU->BasePC = CPU->Fetch[val >> CZ80_FETCH_SFT];
#if CZ80_ENCRYPTED_ROM
CPU->OPBase = CPU->OPFetch[val >> CZ80_FETCH_SFT];
#endif
CPU->PC = val + CPU->BasePC;
break;
case CZ80_SP: zSP = val; break;
case CZ80_AF: zAF = val; break;
case CZ80_BC: zBC = val; break;
case CZ80_DE: zDE = val; break;
case CZ80_HL: zHL = val; break;
case CZ80_IX: zIX = val; break;
case CZ80_IY: zIY = val; break;
case CZ80_AF2: zAF2 = val; break;
case CZ80_BC2: zBC2 = val; break;
case CZ80_DE2: zDE2 = val; break;
case CZ80_HL2: zHL2 = val; break;
case CZ80_R: zR = val; break;
case CZ80_I: zI = val; break;
case CZ80_IM: zIM = val; break;
case CZ80_IFF1: zIFF1 = val ? (1 << 2) : 0; break;
case CZ80_IFF2: zIFF2 = val ? (1 << 2) : 0; break;
case CZ80_HALT: CPU->HaltState = val; break;
case CZ80_IRQ: CPU->IRQState = val; break;
default: break;
}
}
/*--------------------------------------------------------
<EFBFBD>t<EFBFBD>F<EFBFBD>b<EFBFBD>`<EFBFBD>A<EFBFBD>h<EFBFBD><EFBFBD><EFBFBD>X<EFBFBD>ݒ<EFBFBD>
--------------------------------------------------------*/
void Cz80_Set_Fetch(cz80_struc *CPU, UINT32 low_adr, UINT32 high_adr, FPTR fetch_adr)
{
int i, j;
i = low_adr >> CZ80_FETCH_SFT;
j = high_adr >> CZ80_FETCH_SFT;
fetch_adr -= i << CZ80_FETCH_SFT;
while (i <= j)
{
CPU->Fetch[i] = fetch_adr;
#if CZ80_ENCRYPTED_ROM
CPU->OPFetch[i] = 0;
#endif
i++;
}
}
/*--------------------------------------------------------
<EFBFBD>t<EFBFBD>F<EFBFBD>b<EFBFBD>`<EFBFBD>A<EFBFBD>h<EFBFBD><EFBFBD><EFBFBD>X<EFBFBD>ݒ<EFBFBD> (<EFBFBD>Í<EFBFBD><EFBFBD><EFBFBD>ROM<EFBFBD>Ή<EFBFBD>)
--------------------------------------------------------*/
#if CZ80_ENCRYPTED_ROM
void Cz80_Set_Encrypt_Range(cz80_struc *CPU, UINT32 low_adr, UINT32 high_adr, UINT32 decrypted_rom)
{
int i, j;
i = low_adr >> CZ80_FETCH_SFT;
j = high_adr >> CZ80_FETCH_SFT;
decrypted_rom -= i << CZ80_FETCH_SFT;
while (i <= j)
{
CPU->OPFetch[i] = (INT32)decrypted_rom - (INT32)CPU->Fetch[i];
i++;
}
}
#endif
/*--------------------------------------------------------
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[<EFBFBD>h/<EFBFBD><EFBFBD><EFBFBD>C<EFBFBD>g<EFBFBD>֐<EFBFBD><EFBFBD>ݒ<EFBFBD>
--------------------------------------------------------*/
void Cz80_Set_ReadB(cz80_struc *CPU, UINT8 (*Func)(UINT32 address))
{
CPU->Read_Byte = Func;
}
void Cz80_Set_WriteB(cz80_struc *CPU, void (*Func)(UINT32 address, UINT8 data))
{
CPU->Write_Byte = Func;
}
/*--------------------------------------------------------
<EFBFBD>|<EFBFBD>[<EFBFBD>g<EFBFBD><EFBFBD><EFBFBD>[<EFBFBD>h/<EFBFBD><EFBFBD><EFBFBD>C<EFBFBD>g<EFBFBD>֐<EFBFBD><EFBFBD>ݒ<EFBFBD>
--------------------------------------------------------*/
void Cz80_Set_INPort(cz80_struc *CPU, UINT8 (*Func)(UINT16 port))
{
CPU->IN_Port = Func;
}
void Cz80_Set_OUTPort(cz80_struc *CPU, void (*Func)(UINT16 port, UINT8 value))
{
CPU->OUT_Port = Func;
}
/*--------------------------------------------------------
<EFBFBD>R<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD>o<EFBFBD>b<EFBFBD>N<EFBFBD>֐<EFBFBD><EFBFBD>ݒ<EFBFBD>
--------------------------------------------------------*/
void Cz80_Set_IRQ_Callback(cz80_struc *CPU, INT32 (*Func)(INT32 irqline))
{
CPU->Interrupt_Callback = Func;
}

View File

@ -0,0 +1,309 @@
/******************************************************************************
*
* CZ80 (Z80 CPU emulator) version 0.9
* Compiled with Dev-C++
* Copyright 2004-2005 Stéphane Dallongeville
*
* (Modified by NJ)
*
*****************************************************************************/
#ifndef CZ80_H
#define CZ80_H
#ifdef __cplusplus
extern "C" {
#endif
/******************************/
/* Compiler dependant defines */
/******************************/
#ifndef UINT8
#define UINT8 unsigned char
#endif
#ifndef INT8
#define INT8 signed char
#endif
#ifndef UINT16
#define UINT16 unsigned short
#endif
#ifndef INT16
#define INT16 signed short
#endif
#ifndef UINT32
#define UINT32 unsigned int
#endif
#ifndef INT32
#define INT32 signed int
#endif
#ifndef FPTR
#define FPTR unsigned long
#endif
/*************************************/
/* Z80 core Structures & definitions */
/*************************************/
#define CZ80_FETCH_BITS 4 // [4-12] default = 8
#define CZ80_FETCH_SFT (16 - CZ80_FETCH_BITS)
#define CZ80_FETCH_BANK (1 << CZ80_FETCH_BITS)
#define PICODRIVE_HACKS 1
#define CZ80_LITTLE_ENDIAN 1
#define CZ80_USE_JUMPTABLE 1
#define CZ80_BIG_FLAGS_ARRAY 1
//#ifdef BUILD_CPS1PSP
//#define CZ80_ENCRYPTED_ROM 1
//#else
#define CZ80_ENCRYPTED_ROM 0
//#endif
#define CZ80_EMULATE_R_EXACTLY 1
#define zR8(A) (*CPU->pzR8[A])
#define zR16(A) (CPU->pzR16[A]->W)
#define pzAF &(CPU->AF)
#define zAF CPU->AF.W
#define zlAF CPU->AF.B.L
#define zhAF CPU->AF.B.H
#define zA zhAF
#define zF zlAF
#define pzBC &(CPU->BC)
#define zBC CPU->BC.W
#define zlBC CPU->BC.B.L
#define zhBC CPU->BC.B.H
#define zB zhBC
#define zC zlBC
#define pzDE &(CPU->DE)
#define zDE CPU->DE.W
#define zlDE CPU->DE.B.L
#define zhDE CPU->DE.B.H
#define zD zhDE
#define zE zlDE
#define pzHL &(CPU->HL)
#define zHL CPU->HL.W
#define zlHL CPU->HL.B.L
#define zhHL CPU->HL.B.H
#define zH zhHL
#define zL zlHL
#define zAF2 CPU->AF2.W
#define zlAF2 CPU->AF2.B.L
#define zhAF2 CPU->AF2.B.H
#define zA2 zhAF2
#define zF2 zlAF2
#define zBC2 CPU->BC2.W
#define zDE2 CPU->DE2.W
#define zHL2 CPU->HL2.W
#define pzIX &(CPU->IX)
#define zIX CPU->IX.W
#define zlIX CPU->IX.B.L
#define zhIX CPU->IX.B.H
#define pzIY &(CPU->IY)
#define zIY CPU->IY.W
#define zlIY CPU->IY.B.L
#define zhIY CPU->IY.B.H
#define pzSP &(CPU->SP)
#define zSP CPU->SP.W
#define zlSP CPU->SP.B.L
#define zhSP CPU->SP.B.H
#define zRealPC (PC - CPU->BasePC)
#define zPC PC
#define zI CPU->I
#define zIM CPU->IM
#define zwR CPU->R.W
#define zR1 CPU->R.B.L
#define zR2 CPU->R.B.H
#define zR zR1
#define zIFF CPU->IFF.W
#define zIFF1 CPU->IFF.B.L
#define zIFF2 CPU->IFF.B.H
#define CZ80_SF_SFT 7
#define CZ80_ZF_SFT 6
#define CZ80_YF_SFT 5
#define CZ80_HF_SFT 4
#define CZ80_XF_SFT 3
#define CZ80_PF_SFT 2
#define CZ80_VF_SFT 2
#define CZ80_NF_SFT 1
#define CZ80_CF_SFT 0
#define CZ80_SF (1 << CZ80_SF_SFT)
#define CZ80_ZF (1 << CZ80_ZF_SFT)
#define CZ80_YF (1 << CZ80_YF_SFT)
#define CZ80_HF (1 << CZ80_HF_SFT)
#define CZ80_XF (1 << CZ80_XF_SFT)
#define CZ80_PF (1 << CZ80_PF_SFT)
#define CZ80_VF (1 << CZ80_VF_SFT)
#define CZ80_NF (1 << CZ80_NF_SFT)
#define CZ80_CF (1 << CZ80_CF_SFT)
#define CZ80_IFF_SFT CZ80_PF_SFT
#define CZ80_IFF CZ80_PF
#ifndef IRQ_LINE_STATE
#define IRQ_LINE_STATE
#define CLEAR_LINE 0 /* clear (a fired, held or pulsed) line */
#define ASSERT_LINE 1 /* assert an interrupt immediately */
#define HOLD_LINE 2 /* hold interrupt line until acknowledged */
#define PULSE_LINE 3 /* pulse interrupt line for one instruction */
#define IRQ_LINE_NMI 127 /* IRQ line for NMIs */
#endif
enum
{
CZ80_PC = 1,
CZ80_SP,
CZ80_AF,
CZ80_BC,
CZ80_DE,
CZ80_HL,
CZ80_IX,
CZ80_IY,
CZ80_AF2,
CZ80_BC2,
CZ80_DE2,
CZ80_HL2,
CZ80_R,
CZ80_I,
CZ80_IM,
CZ80_IFF1,
CZ80_IFF2,
CZ80_HALT,
CZ80_IRQ
};
typedef union
{
struct
{
#if CZ80_LITTLE_ENDIAN
UINT8 L;
UINT8 H;
#else
UINT8 H;
UINT8 L;
#endif
} B;
UINT16 W;
} union16;
typedef struct cz80_t
{
union
{
UINT8 r8[8];
union16 r16[4];
struct
{
union16 BC;
union16 DE;
union16 HL;
union16 AF;
};
};
union16 IX;
union16 IY;
union16 SP;
UINT32 unusedPC; /* left for binary compat */
union16 BC2;
union16 DE2;
union16 HL2;
union16 AF2;
union16 R;
union16 IFF;
UINT8 I;
UINT8 IM;
UINT8 HaltState;
UINT8 dummy;
INT32 IRQLine;
INT32 IRQState;
INT32 ICount;
INT32 ExtraCycles;
FPTR BasePC;
FPTR PC;
FPTR Fetch[CZ80_FETCH_BANK];
#if CZ80_ENCRYPTED_ROM
FPTR OPBase;
FPTR OPFetch[CZ80_FETCH_BANK];
#endif
UINT8 *pzR8[8];
union16 *pzR16[4];
UINT8 (*Read_Byte)(UINT32 address);
void (*Write_Byte)(UINT32 address, UINT8 data);
UINT8 (*IN_Port)(UINT16 port);
void (*OUT_Port)(UINT16 port, UINT8 value);
INT32 (*Interrupt_Callback)(INT32 irqline);
} cz80_struc;
/*************************/
/* Publics Z80 variables */
/*************************/
extern cz80_struc CZ80;
/*************************/
/* Publics Z80 functions */
/*************************/
void Cz80_Init(cz80_struc *CPU);
void Cz80_Reset(cz80_struc *CPU);
INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles);
void Cz80_Set_IRQ(cz80_struc *CPU, INT32 line, INT32 state);
UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum);
void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 value);
void Cz80_Set_Fetch(cz80_struc *CPU, UINT32 low_adr, UINT32 high_adr, FPTR fetch_adr);
#if CZ80_ENCRYPTED_ROM
void Cz80_Set_Encrypt_Range(cz80_struc *CPU, UINT32 low_adr, UINT32 high_adr, UINT32 decrypted_rom);
#endif
void Cz80_Set_ReadB(cz80_struc *CPU, UINT8 (*Func)(UINT32 address));
void Cz80_Set_WriteB(cz80_struc *CPU, void (*Func)(UINT32 address, UINT8 data));
void Cz80_Set_INPort(cz80_struc *CPU, UINT8 (*Func)(UINT16 port));
void Cz80_Set_OUTPort(cz80_struc *CPU, void (*Func)(UINT16 port, UINT8 value));
void Cz80_Set_IRQ_Callback(cz80_struc *CPU, INT32 (*Func)(INT32 irqline));
#ifdef __cplusplus
};
#endif
#endif /* CZ80_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,470 @@
/******************************************************************************
*
* CZ80 CB opcode include source file
* CZ80 emulator version 0.9
* Copyright 2004-2005 Stéphane Dallongeville
*
* (Modified by NJ)
*
*****************************************************************************/
#if CZ80_USE_JUMPTABLE
goto *JumpTableCB[Opcode];
#else
switch (Opcode)
{
#endif
/*-----------------------------------------
RLC
-----------------------------------------*/
OPCB(0x00): // RLC B
OPCB(0x01): // RLC C
OPCB(0x02): // RLC D
OPCB(0x03): // RLC E
OPCB(0x04): // RLC H
OPCB(0x05): // RLC L
OPCB(0x07): // RLC A
src = zR8(Opcode);
res = (src << 1) | (src >> 7);
zF = SZP[res] | (src >> 7);
zR8(Opcode) = res;
RET(8)
OPCB(0x06): // RLC (HL)
adr = zHL;
src = READ_MEM8(adr);
res = (src << 1) | (src >> 7);
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
RRC
-----------------------------------------*/
OPCB(0x08): // RRC B
OPCB(0x09): // RRC C
OPCB(0x0a): // RRC D
OPCB(0x0b): // RRC E
OPCB(0x0c): // RRC H
OPCB(0x0d): // RRC L
OPCB(0x0f): // RRC A
src = zR8(Opcode & 7);
res = (src >> 1) | (src << 7);
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x0e): // RRC (HL)
adr = zHL;
src = READ_MEM8(adr);
res = (src >> 1) | (src << 7);
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
RL
-----------------------------------------*/
OPCB(0x10): // RL B
OPCB(0x11): // RL C
OPCB(0x12): // RL D
OPCB(0x13): // RL E
OPCB(0x14): // RL H
OPCB(0x15): // RL L
OPCB(0x17): // RL A
src = zR8(Opcode & 7);
res = (src << 1) | (zF & CF);
zF = SZP[res] | (src >> 7);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x16): // RL (HL)
adr = zHL;
src = READ_MEM8(adr);
res = (src << 1) | (zF & CF);
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
RR
-----------------------------------------*/
OPCB(0x18): // RR B
OPCB(0x19): // RR C
OPCB(0x1a): // RR D
OPCB(0x1b): // RR E
OPCB(0x1c): // RR H
OPCB(0x1d): // RR L
OPCB(0x1f): // RR A
src = zR8(Opcode & 7);
res = (src >> 1) | (zF << 7);
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x1e): // RR (HL)
adr = zHL;
src = READ_MEM8(adr);
res = (src >> 1) | (zF << 7);
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
SLA
-----------------------------------------*/
OPCB(0x20): // SLA B
OPCB(0x21): // SLA C
OPCB(0x22): // SLA D
OPCB(0x23): // SLA E
OPCB(0x24): // SLA H
OPCB(0x25): // SLA L
OPCB(0x27): // SLA A
src = zR8(Opcode & 7);
res = src << 1;
zF = SZP[res] | (src >> 7);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x26): // SLA (HL)
adr = zHL;
src = READ_MEM8(adr);
res = src << 1;
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
SRA
-----------------------------------------*/
OPCB(0x28): // SRA B
OPCB(0x29): // SRA C
OPCB(0x2a): // SRA D
OPCB(0x2b): // SRA E
OPCB(0x2c): // SRA H
OPCB(0x2d): // SRA L
OPCB(0x2f): // SRA A
src = zR8(Opcode & 7);
res = (src >> 1) | (src & 0x80);
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x2e): // SRA (HL)
adr = zHL;
src = READ_MEM8(adr);
res = (src >> 1) | (src & 0x80);
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
SLL
-----------------------------------------*/
OPCB(0x30): // SLL B
OPCB(0x31): // SLL C
OPCB(0x32): // SLL D
OPCB(0x33): // SLL E
OPCB(0x34): // SLL H
OPCB(0x35): // SLL L
OPCB(0x37): // SLL A
src = zR8(Opcode & 7);
res = (src << 1) | 0x01;
zF = SZP[res] | (src >> 7);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x36): // SLL (HL)
adr = zHL;
src = READ_MEM8(adr);
res = (src << 1) | 0x01;
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
SRL
-----------------------------------------*/
OPCB(0x38): // SRL B
OPCB(0x39): // SRL C
OPCB(0x3a): // SRL D
OPCB(0x3b): // SRL E
OPCB(0x3c): // SRL H
OPCB(0x3d): // SRL L
OPCB(0x3f): // SRL A
src = zR8(Opcode & 7);
res = src >> 1;
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
RET(8)
OPCB(0x3e): // SRL (HL)
adr = zHL;
src = READ_MEM8(adr);
res = src >> 1;
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
BIT
-----------------------------------------*/
OPCB(0x40): // BIT 0,B
OPCB(0x41): // BIT 0,C
OPCB(0x42): // BIT 0,D
OPCB(0x43): // BIT 0,E
OPCB(0x44): // BIT 0,H
OPCB(0x45): // BIT 0,L
OPCB(0x47): // BIT 0,A
OPCB(0x48): // BIT 1,B
OPCB(0x49): // BIT 1,C
OPCB(0x4a): // BIT 1,D
OPCB(0x4b): // BIT 1,E
OPCB(0x4c): // BIT 1,H
OPCB(0x4d): // BIT 1,L
OPCB(0x4f): // BIT 1,A
OPCB(0x50): // BIT 2,B
OPCB(0x51): // BIT 2,C
OPCB(0x52): // BIT 2,D
OPCB(0x53): // BIT 2,E
OPCB(0x54): // BIT 2,H
OPCB(0x55): // BIT 2,L
OPCB(0x57): // BIT 2,A
OPCB(0x58): // BIT 3,B
OPCB(0x59): // BIT 3,C
OPCB(0x5a): // BIT 3,D
OPCB(0x5b): // BIT 3,E
OPCB(0x5c): // BIT 3,H
OPCB(0x5d): // BIT 3,L
OPCB(0x5f): // BIT 3,A
OPCB(0x60): // BIT 4,B
OPCB(0x61): // BIT 4,C
OPCB(0x62): // BIT 4,D
OPCB(0x63): // BIT 4,E
OPCB(0x64): // BIT 4,H
OPCB(0x65): // BIT 4,L
OPCB(0x67): // BIT 4,A
OPCB(0x68): // BIT 5,B
OPCB(0x69): // BIT 5,C
OPCB(0x6a): // BIT 5,D
OPCB(0x6b): // BIT 5,E
OPCB(0x6c): // BIT 5,H
OPCB(0x6d): // BIT 5,L
OPCB(0x6f): // BIT 5,A
OPCB(0x70): // BIT 6,B
OPCB(0x71): // BIT 6,C
OPCB(0x72): // BIT 6,D
OPCB(0x73): // BIT 6,E
OPCB(0x74): // BIT 6,H
OPCB(0x75): // BIT 6,L
OPCB(0x77): // BIT 6,A
OPCB(0x78): // BIT 7,B
OPCB(0x79): // BIT 7,C
OPCB(0x7a): // BIT 7,D
OPCB(0x7b): // BIT 7,E
OPCB(0x7c): // BIT 7,H
OPCB(0x7d): // BIT 7,L
OPCB(0x7f): // BIT 7,A
zF = (zF & CF) | HF | SZ_BIT[zR8(Opcode & 7) & (1 << ((Opcode >> 3) & 7))];
RET(8)
OPCB(0x46): // BIT 0,(HL)
OPCB(0x4e): // BIT 1,(HL)
OPCB(0x56): // BIT 2,(HL)
OPCB(0x5e): // BIT 3,(HL)
OPCB(0x66): // BIT 4,(HL)
OPCB(0x6e): // BIT 5,(HL)
OPCB(0x76): // BIT 6,(HL)
OPCB(0x7e): // BIT 7,(HL)
src = READ_MEM8(zHL);
zF = (zF & CF) | HF | SZ_BIT[src & (1 << ((Opcode >> 3) & 7))];
RET(12)
/*-----------------------------------------
RES
-----------------------------------------*/
OPCB(0x80): // RES 0,B
OPCB(0x81): // RES 0,C
OPCB(0x82): // RES 0,D
OPCB(0x83): // RES 0,E
OPCB(0x84): // RES 0,H
OPCB(0x85): // RES 0,L
OPCB(0x87): // RES 0,A
OPCB(0x88): // RES 1,B
OPCB(0x89): // RES 1,C
OPCB(0x8a): // RES 1,D
OPCB(0x8b): // RES 1,E
OPCB(0x8c): // RES 1,H
OPCB(0x8d): // RES 1,L
OPCB(0x8f): // RES 1,A
OPCB(0x90): // RES 2,B
OPCB(0x91): // RES 2,C
OPCB(0x92): // RES 2,D
OPCB(0x93): // RES 2,E
OPCB(0x94): // RES 2,H
OPCB(0x95): // RES 2,L
OPCB(0x97): // RES 2,A
OPCB(0x98): // RES 3,B
OPCB(0x99): // RES 3,C
OPCB(0x9a): // RES 3,D
OPCB(0x9b): // RES 3,E
OPCB(0x9c): // RES 3,H
OPCB(0x9d): // RES 3,L
OPCB(0x9f): // RES 3,A
OPCB(0xa0): // RES 4,B
OPCB(0xa1): // RES 4,C
OPCB(0xa2): // RES 4,D
OPCB(0xa3): // RES 4,E
OPCB(0xa4): // RES 4,H
OPCB(0xa5): // RES 4,L
OPCB(0xa7): // RES 4,A
OPCB(0xa8): // RES 5,B
OPCB(0xa9): // RES 5,C
OPCB(0xaa): // RES 5,D
OPCB(0xab): // RES 5,E
OPCB(0xac): // RES 5,H
OPCB(0xad): // RES 5,L
OPCB(0xaf): // RES 5,A
OPCB(0xb0): // RES 6,B
OPCB(0xb1): // RES 6,C
OPCB(0xb2): // RES 6,D
OPCB(0xb3): // RES 6,E
OPCB(0xb4): // RES 6,H
OPCB(0xb5): // RES 6,L
OPCB(0xb7): // RES 6,A
OPCB(0xb8): // RES 7,B
OPCB(0xb9): // RES 7,C
OPCB(0xba): // RES 7,D
OPCB(0xbb): // RES 7,E
OPCB(0xbc): // RES 7,H
OPCB(0xbd): // RES 7,L
OPCB(0xbf): // RES 7,A
zR8(Opcode & 7) &= ~(1 << ((Opcode >> 3) & 7));
RET(8)
OPCB(0x86): // RES 0,(HL)
OPCB(0x8e): // RES 1,(HL)
OPCB(0x96): // RES 2,(HL)
OPCB(0x9e): // RES 3,(HL)
OPCB(0xa6): // RES 4,(HL)
OPCB(0xae): // RES 5,(HL)
OPCB(0xb6): // RES 6,(HL)
OPCB(0xbe): // RES 7,(HL)
adr = zHL;
res = READ_MEM8(adr);
res &= ~(1 << ((Opcode >> 3) & 7));
WRITE_MEM8(adr, res);
RET(15)
/*-----------------------------------------
SET
-----------------------------------------*/
OPCB(0xc0): // SET 0,B
OPCB(0xc1): // SET 0,C
OPCB(0xc2): // SET 0,D
OPCB(0xc3): // SET 0,E
OPCB(0xc4): // SET 0,H
OPCB(0xc5): // SET 0,L
OPCB(0xc7): // SET 0,A
OPCB(0xc8): // SET 1,B
OPCB(0xc9): // SET 1,C
OPCB(0xca): // SET 1,D
OPCB(0xcb): // SET 1,E
OPCB(0xcc): // SET 1,H
OPCB(0xcd): // SET 1,L
OPCB(0xcf): // SET 1,A
OPCB(0xd0): // SET 2,B
OPCB(0xd1): // SET 2,C
OPCB(0xd2): // SET 2,D
OPCB(0xd3): // SET 2,E
OPCB(0xd4): // SET 2,H
OPCB(0xd5): // SET 2,L
OPCB(0xd7): // SET 2,A
OPCB(0xd8): // SET 3,B
OPCB(0xd9): // SET 3,C
OPCB(0xda): // SET 3,D
OPCB(0xdb): // SET 3,E
OPCB(0xdc): // SET 3,H
OPCB(0xdd): // SET 3,L
OPCB(0xdf): // SET 3,A
OPCB(0xe0): // SET 4,B
OPCB(0xe1): // SET 4,C
OPCB(0xe2): // SET 4,D
OPCB(0xe3): // SET 4,E
OPCB(0xe4): // SET 4,H
OPCB(0xe5): // SET 4,L
OPCB(0xe7): // SET 4,A
OPCB(0xe8): // SET 5,B
OPCB(0xe9): // SET 5,C
OPCB(0xea): // SET 5,D
OPCB(0xeb): // SET 5,E
OPCB(0xec): // SET 5,H
OPCB(0xed): // SET 5,L
OPCB(0xef): // SET 5,A
OPCB(0xf0): // SET 6,B
OPCB(0xf1): // SET 6,C
OPCB(0xf2): // SET 6,D
OPCB(0xf3): // SET 6,E
OPCB(0xf4): // SET 6,H
OPCB(0xf5): // SET 6,L
OPCB(0xf7): // SET 6,A
OPCB(0xf8): // SET 7,B
OPCB(0xf9): // SET 7,C
OPCB(0xfa): // SET 7,D
OPCB(0xfb): // SET 7,E
OPCB(0xfc): // SET 7,H
OPCB(0xfd): // SET 7,L
OPCB(0xff): // SET 7,A
zR8(Opcode & 7) |= 1 << ((Opcode >> 3) & 7);
RET(8)
OPCB(0xc6): // SET 0,(HL)
OPCB(0xce): // SET 1,(HL)
OPCB(0xd6): // SET 2,(HL)
OPCB(0xde): // SET 3,(HL)
OPCB(0xe6): // SET 4,(HL)
OPCB(0xee): // SET 5,(HL)
OPCB(0xf6): // SET 6,(HL)
OPCB(0xfe): // SET 7,(HL)
adr = zHL;
res = READ_MEM8(adr);
res |= 1 << ((Opcode >> 3) & 7);
WRITE_MEM8(adr, res);
RET(15)
#if !CZ80_USE_JUMPTABLE
}
#endif

View File

@ -0,0 +1,731 @@
/******************************************************************************
*
* CZ80 ED opcode include source file
* CZ80 emulator version 0.9
* Copyright 2004-2005 Stéphane Dallongeville
*
* (Modified by NJ)
*
*****************************************************************************/
#if CZ80_USE_JUMPTABLE
goto *JumpTableED[Opcode];
#else
switch (Opcode)
{
#endif
/*-----------------------------------------
ILLEGAL
-----------------------------------------*/
OPED(0x00):
OPED(0x01):
OPED(0x02):
OPED(0x03):
OPED(0x04):
OPED(0x05):
OPED(0x06):
OPED(0x07):
OPED(0x08):
OPED(0x09):
OPED(0x0a):
OPED(0x0b):
OPED(0x0c):
OPED(0x0d):
OPED(0x0e):
OPED(0x0f):
OPED(0x10):
OPED(0x11):
OPED(0x12):
OPED(0x13):
OPED(0x14):
OPED(0x15):
OPED(0x16):
OPED(0x17):
OPED(0x18):
OPED(0x19):
OPED(0x1a):
OPED(0x1b):
OPED(0x1c):
OPED(0x1d):
OPED(0x1e):
OPED(0x1f):
OPED(0x20):
OPED(0x21):
OPED(0x22):
OPED(0x23):
OPED(0x24):
OPED(0x25):
OPED(0x26):
OPED(0x27):
OPED(0x28):
OPED(0x29):
OPED(0x2a):
OPED(0x2b):
OPED(0x2c):
OPED(0x2d):
OPED(0x2e):
OPED(0x2f):
OPED(0x30):
OPED(0x31):
OPED(0x32):
OPED(0x33):
OPED(0x34):
OPED(0x35):
OPED(0x36):
OPED(0x37):
OPED(0x38):
OPED(0x39):
OPED(0x3a):
OPED(0x3b):
OPED(0x3c):
OPED(0x3d):
OPED(0x3e):
OPED(0x3f):
OPED(0x77):
OPED(0x7f):
OPED(0x80):
OPED(0x81):
OPED(0x82):
OPED(0x83):
OPED(0x84):
OPED(0x85):
OPED(0x86):
OPED(0x87):
OPED(0x88):
OPED(0x89):
OPED(0x8a):
OPED(0x8b):
OPED(0x8c):
OPED(0x8d):
OPED(0x8e):
OPED(0x8f):
OPED(0x90):
OPED(0x91):
OPED(0x92):
OPED(0x93):
OPED(0x94):
OPED(0x95):
OPED(0x96):
OPED(0x97):
OPED(0x98):
OPED(0x99):
OPED(0x9a):
OPED(0x9b):
OPED(0x9c):
OPED(0x9d):
OPED(0x9e):
OPED(0x9f):
OPED(0xa4):
OPED(0xa5):
OPED(0xa6):
OPED(0xa7):
OPED(0xac):
OPED(0xad):
OPED(0xae):
OPED(0xaf):
OPED(0xb4):
OPED(0xb5):
OPED(0xb6):
OPED(0xb7):
OPED(0xbc):
OPED(0xbd):
OPED(0xbe):
OPED(0xbf):
OPED(0xc0):
OPED(0xc1):
OPED(0xc2):
OPED(0xc3):
OPED(0xc4):
OPED(0xc5):
OPED(0xc6):
OPED(0xc7):
OPED(0xc8):
OPED(0xc9):
OPED(0xca):
OPED(0xcb):
OPED(0xcc):
OPED(0xcd):
OPED(0xce):
OPED(0xcf):
OPED(0xd0):
OPED(0xd1):
OPED(0xd2):
OPED(0xd3):
OPED(0xd4):
OPED(0xd5):
OPED(0xd6):
OPED(0xd7):
OPED(0xd8):
OPED(0xd9):
OPED(0xda):
OPED(0xdb):
OPED(0xdc):
OPED(0xdd):
OPED(0xde):
OPED(0xdf):
OPED(0xe0):
OPED(0xe1):
OPED(0xe2):
OPED(0xe3):
OPED(0xe4):
OPED(0xe5):
OPED(0xe6):
OPED(0xe7):
OPED(0xe8):
OPED(0xe9):
OPED(0xea):
OPED(0xeb):
OPED(0xec):
OPED(0xed):
OPED(0xee):
OPED(0xef):
OPED(0xf0):
OPED(0xf1):
OPED(0xf2):
OPED(0xf3):
OPED(0xf4):
OPED(0xf5):
OPED(0xf6):
OPED(0xf7):
OPED(0xf8):
OPED(0xf9):
OPED(0xfa):
OPED(0xfb):
OPED(0xfc):
OPED(0xfd):
OPED(0xfe):
OPED(0xff):
RET(4)
/*-----------------------------------------
LD r8
-----------------------------------------*/
OPED(0x47): // LD I,A
zI = zA;
RET(5)
OPED(0x4f): // LD R,A
#if CZ80_EMULATE_R_EXACTLY
zR = zA;
#else
zR = zA - ((cycles - CPU->ICount) >> 2);
#endif
zR2 = zA & 0x80;
RET(5)
OPED(0x57): // LD A,I
zA = zI;
zF = (zF & CF) | SZ[zA] | zIFF2;
RET(5)
OPED(0x5f): // LD A,R
#if CZ80_EMULATE_R_EXACTLY
zA = (zR & 0x7f) | zR2;
#else
zA = ((zR + ((cycles - CPU->ICount) >> 2)) & 0x7f) | zR2;
#endif
zF = (zF & CF) | SZ[zA] | zIFF2;
RET(5)
/*-----------------------------------------
LD r16
-----------------------------------------*/
OPED(0x43): // LD (w),BC
data = pzBC;
goto OP_LD_mNN_xx;
OPED(0x53): // LD (w),DE
data = pzDE;
goto OP_LD_mNN_xx;
OPED(0x63): // LD (w),HL
data = pzHL;
goto OP_LD_mNN_xx;
OPED(0x73): // LD (w),SP
data = pzSP;
goto OP_LD_mNN_xx;
OPED(0x4b): // LD BC,(w)
data = pzBC;
goto OP_LD_xx_mNN;
OPED(0x5b): // LD DE,(w)
data = pzDE;
goto OP_LD_xx_mNN;
OPED(0x6b): // LD HL,(w)
data = pzHL;
goto OP_LD_xx_mNN;
OPED(0x7b): // LD SP,(w)
data = pzSP;
goto OP_LD_xx_mNN;
/*-----------------------------------------
NEG
-----------------------------------------*/
OPED(0x44): // NEG
OPED(0x4c): // NEG
OPED(0x54): // NEG
OPED(0x5c): // NEG
OPED(0x64): // NEG
OPED(0x6c): // NEG
OPED(0x74): // NEG
OPED(0x7c): // NEG
val = zA;
zA = 0;
goto OP_SUB;
/*-----------------------------------------
RRD
-----------------------------------------*/
OPED(0x67): // RRD (HL)
adr = zHL;
val = READ_MEM8(adr);
WRITE_MEM8(adr, (val >> 4) | (zA << 4));
zA = (zA & 0xf0) | (val & 0x0f);
zF = (zF & CF) | SZP[zA];
RET(14)
/*-----------------------------------------
RLD
-----------------------------------------*/
OPED(0x6f): // RLD (HL)
adr = zHL;
val = READ_MEM8(adr);
WRITE_MEM8(adr, (val << 4) | (zA & 0x0f));
zA = (zA & 0xf0) | (val >> 4);
zF = (zF & CF) | SZP[zA];
RET(14)
/*-----------------------------------------
ADC 16
-----------------------------------------*/
OPED(0x7a): // ADC HL,SP
val = zSP;
goto OP_ADC16;
OPED(0x4a): // ADC HL,BC
OPED(0x5a): // ADC HL,DE
OPED(0x6a): // ADC HL,HL
val = zR16((Opcode >> 4) & 3);
OP_ADC16:
res = zHL + val + (zF & CF);
zF = (((zHL ^ res ^ val) >> 8) & HF) |
((res >> 16) & CF) |
((res >> 8) & (SF | YF | XF)) |
((res & 0xffff) ? 0 : ZF) |
(((val ^ zHL ^ 0x8000) & (val ^ res) & 0x8000) >> 13);
zHL = (UINT16)res;
RET(11)
/*-----------------------------------------
SBC 16
-----------------------------------------*/
OPED(0x72): // SBC HL,SP
val = zSP;
goto OP_SBC16;
OPED(0x42): // SBC HL,BC
OPED(0x52): // SBC HL,DE
OPED(0x62): // SBC HL,HL
val = zR16((Opcode >> 4) & 3);
OP_SBC16:
res = zHL - val - (zF & CF);
zF = (((zHL ^ res ^ val) >> 8) & HF) | NF |
((res >> 16) & CF) |
((res >> 8) & (SF | YF | XF)) |
((res & 0xffff) ? 0 : ZF) |
(((val ^ zHL) & (zHL ^ res) & 0x8000) >> 13);
zHL = (UINT16)res;
RET(11)
/*-----------------------------------------
IN
-----------------------------------------*/
OPED(0x40): // IN B,(C)
OPED(0x48): // IN C,(C)
OPED(0x50): // IN D,(C)
OPED(0x58): // IN E,(C)
OPED(0x60): // IN H,(C)
OPED(0x68): // IN L,(C)
OPED(0x78): // IN E,(C)
res = IN(zBC);
zR8((Opcode >> 3) & 7) = res;
zF = (zF & CF) | SZP[res];
RET(8)
OPED(0x70): // IN 0,(C)
res = IN(zBC);
zF = (zF & CF) | SZP[res];
RET(8)
/*-----------------------------------------
OUT
-----------------------------------------*/
OPED(0x51): // OUT (C),D
OPED(0x41): // OUT (C),B
OPED(0x49): // OUT (C),C
OPED(0x59): // OUT (C),E
OPED(0x61): // OUT (C),H
OPED(0x69): // OUT (C),L
OPED(0x79): // OUT (C),E
res = zR8((Opcode >> 3) & 7);
OUT(zBC, res);
RET(8)
OPED(0x71): // OUT (C),0
OUT(zBC, 0);
RET(8)
/*-----------------------------------------
RETN
-----------------------------------------*/
OPED(0x45): // RETN;
OPED(0x55): // RETN;
OPED(0x65): // RETN;
OPED(0x75): // RETN;
POP_16(res);
SET_PC(res);
if (!zIFF1 && zIFF2)
{
zIFF1 = (1 << 2);
if (CPU->IRQState)
{
USE_CYCLES(10)
goto Cz80_Check_Interrupt;
}
}
else zIFF1 = zIFF2;
RET(10)
/*-----------------------------------------
RETI
-----------------------------------------*/
OPED(0x4d): // RETI
OPED(0x5d): // RETI
OPED(0x6d): // RETI
OPED(0x7d): // RETI
POP_16(res);
SET_PC(res);
RET(10)
/*-----------------------------------------
IM
-----------------------------------------*/
OPED(0x46): // IM 0
OPED(0x4e): // IM 0
OPED(0x66): // IM 0
OPED(0x6e): // IM 0
zIM = 0;
RET(4)
OPED(0x56): // IM 1
OPED(0x76): // IM 1
zIM = 1;
RET(4)
OPED(0x5e): // IM 2
OPED(0x7e): // IM 2
zIM = 2;
RET(4)
{
UINT8 val;
UINT8 res;
UINT8 F;
/*-----------------------------------------
LDI/LDD
-----------------------------------------*/
OPED(0xa0): // LDI
val = READ_MEM8(zHL++);
WRITE_MEM8(zDE++, val);
goto OP_LDX;
OPED(0xa8): // LDD
val = READ_MEM8(zHL--);
WRITE_MEM8(zDE--, val);
OP_LDX:
F = zF & (SF | ZF | CF);
if ((zA + val) & 0x02) F |= YF;
if ((zA + val) & 0x08) F |= XF;
if (--zBC) F |= VF;
zF = F;
RET(12)
/*-----------------------------------------
LDIR/LDDR
-----------------------------------------*/
OPED(0xb0): // LDIR
do
{
val = READ_MEM8(zHL++);
WRITE_MEM8(zDE++, val);
zBC--;
USE_CYCLES(17)
} while (zBC && (CPU->ICount > 0));
goto OP_LDXR;
OPED(0xb8): // LDDR
do
{
val = READ_MEM8(zHL--);
WRITE_MEM8(zDE--, val);
zBC--;
USE_CYCLES(17)
} while (zBC && (CPU->ICount > 0));
OP_LDXR:
F = zF & (SF | ZF | CF);
if ((zA + val) & 0x02) F |= YF;
if ((zA + val) & 0x08) F |= XF;
if (zBC)
{
zF = F | VF;
PC -= 2;
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
goto Cz80_Exec_End;
}
zF = F;
ADD_CYCLES(5)
goto Cz80_Exec;
/*-----------------------------------------
CPI/CPD
-----------------------------------------*/
OPED(0xa1): // CPI
val = READ_MEM8(zHL++);
goto OP_CPX;
OPED(0xa9): // CPD
val = READ_MEM8(zHL--);
OP_CPX:
res = zA - val;
F = (zF & CF) | (SZ[res] & ~(YF | XF)) | ((zA ^ val ^ res) & HF) | NF;
if (F & HF) res--;
if (res & 0x02) F |= YF;
if (res & 0x08) F |= XF;
if (--zBC) F |= VF;
zF = F;
RET(12)
/*-----------------------------------------
CPIR/CPDR
-----------------------------------------*/
OPED(0xb1): // CPIR
do
{
val = READ_MEM8(zHL++);
res = zA - val;
zBC--;
F = (zF & CF) | (SZ[res] & ~(YF | XF)) | ((zA ^ val ^ res) & HF) | NF;
if (F & HF) res--;
if (res & 0x02) F |= YF;
if (res & 0x08) F |= XF;
if (zBC) F |= VF;
zF = F;
USE_CYCLES(17)
} while (zBC && !(F & ZF) && (CPU->ICount > 0));
goto OP_CPXR;
OPED(0xb9): // CPDR
do
{
val = READ_MEM8(zHL--);
res = zA - val;
zBC--;
F = (zF & CF) | (SZ[res] & ~(YF | XF)) | ((zA ^ val ^ res) & HF) | NF;
if (F & HF) res--;
if (res & 0x02) F |= YF;
if (res & 0x08) F |= XF;
if (zBC) F |= VF;
zF = F;
USE_CYCLES(17)
} while (zBC && !(F & ZF) && (CPU->ICount > 0));
OP_CPXR:
if (zBC && !(F & ZF))
{
PC -= 2;
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
goto Cz80_Exec_End;
}
ADD_CYCLES(5)
goto Cz80_Exec;
/*-----------------------------------------
INI/IND
-----------------------------------------*/
OPED(0xa2): // INI
val = IN(zBC);
zB--;
WRITE_MEM8(zHL++, val);
goto OP_INX;
OPED(0xaa): // IND
val = IN(zBC);
zB--;
WRITE_MEM8(zHL--, val);
OP_INX:
F = SZ[zB];
res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val;
if (val & SF) F |= NF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;
zF = F;
RET(12)
/*-----------------------------------------
INIR/INDR
-----------------------------------------*/
OPED(0xb2): // INIR
do
{
val = IN(zBC);
zB--;
WRITE_MEM8(zHL++, val);
USE_CYCLES(17)
} while (zB && (CPU->ICount > 0));
goto OP_INXR;
OPED(0xba): // INDR
do
{
val = IN(zBC);
zB--;
WRITE_MEM8(zHL--, val);
USE_CYCLES(17)
} while (zB && (CPU->ICount > 0));
OP_INXR:
F = SZ[zB];
res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val;
if (val & SF) F |= NF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;
zF = F;
if (zB)
{
PC -= 2;
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
goto Cz80_Exec_End;
}
ADD_CYCLES(5);
goto Cz80_Exec;
/*-----------------------------------------
OUTI/OUTD
-----------------------------------------*/
OPED(0xa3): // OUTI
val = READ_MEM8(zHL++);
zB--;
OUT(zBC, val);
goto OP_OUTX;
OPED(0xab): // OUTD
val = READ_MEM8(zHL--);
zB--;
OUT(zBC, val);
OP_OUTX:
F = SZ[zB];
res = (UINT32)zL + (UINT32)val;
if (val & SF) F |= NF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) - zB] & PF;
zF = F;
RET(12)
/*-----------------------------------------
OTIR/OTDR
-----------------------------------------*/
OPED(0xb3): // OTIR
do
{
val = READ_MEM8(zHL++);
zB--;
OUT(zBC, val);
USE_CYCLES(17)
} while (zB && (CPU->ICount > 0));
goto OP_OTXR;
OPED(0xbb): // OTDR
do
{
val = READ_MEM8(zHL--);
zB--;
OUT(zBC, val);
USE_CYCLES(17)
} while (zB && (CPU->ICount > 0));
OP_OTXR:
F = SZ[zB];
res = (UINT32)zL + (UINT32)val;
if (val & SF) F |= NF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) - zB] & PF;
zF = F;
if (zB)
{
PC -= 2;
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
goto Cz80_Exec_End;
}
ADD_CYCLES(5)
goto Cz80_Exec;
}
#if !CZ80_USE_JUMPTABLE
}
#endif

View File

@ -0,0 +1,786 @@
/******************************************************************************
*
* CZ80 XY opcode include source file
* CZ80 emulator version 0.9
* Copyright 2004-2005 St<EFBFBD>phane Dallongeville
*
* (Modified by NJ)
*
*****************************************************************************/
#if CZ80_USE_JUMPTABLE
goto *JumpTableXY[Opcode];
#else
switch (Opcode)
{
#endif
/*-----------------------------------------
NOP
-----------------------------------------*/
OPXY(0x00): // NOP
/*-----------------------------------------
LD r8 (same register)
-----------------------------------------*/
OPXY(0x40): // LD B,B
OPXY(0x49): // LD C,C
OPXY(0x52): // LD D,D
OPXY(0x5b): // LD E,E
OPXY(0x64): // LD H,H
OPXY(0x6d): // LD L,L
OPXY(0x7f): // LD A,A
RET(4)
/*-----------------------------------------
LD r8
-----------------------------------------*/
OPXY(0x41): // LD B,C
OPXY(0x42): // LD B,D
OPXY(0x43): // LD B,E
OPXY(0x47): // LD B,A
OPXY(0x48): // LD C,B
OPXY(0x4a): // LD C,D
OPXY(0x4b): // LD C,E
OPXY(0x4f): // LD C,A
OPXY(0x50): // LD D,B
OPXY(0x51): // LD D,C
OPXY(0x53): // LD D,E
OPXY(0x57): // LD D,A
OPXY(0x58): // LD E,B
OPXY(0x59): // LD E,C
OPXY(0x5a): // LD E,D
OPXY(0x5f): // LD E,A
OPXY(0x78): // LD A,B
OPXY(0x79): // LD A,C
OPXY(0x7a): // LD A,D
OPXY(0x7b): // LD A,E
goto OP_LD_R_R;
OPXY(0x44): // LD B,HX
OPXY(0x4c): // LD C,HX
OPXY(0x54): // LD D,HX
OPXY(0x5c): // LD E,HX
OPXY(0x7c): // LD A,HX
zR8((Opcode >> 3) & 7) = data->B.H;
RET(5)
OPXY(0x45): // LD B,LX
OPXY(0x4d): // LD C,LX
OPXY(0x55): // LD D,LX
OPXY(0x5d): // LD E,LX
OPXY(0x7d): // LD A,LX
zR8((Opcode >> 3) & 7) = data->B.L;
RET(5)
OPXY(0x60): // LD HX,B
OPXY(0x61): // LD HX,C
OPXY(0x62): // LD HX,D
OPXY(0x63): // LD HX,E
OPXY(0x67): // LD HX,A
data->B.H = zR8(Opcode & 7);
RET(5)
OPXY(0x68): // LD LX,B
OPXY(0x69): // LD LX,C
OPXY(0x6a): // LD LX,D
OPXY(0x6b): // LD LX,E
OPXY(0x6f): // LD LX,A
data->B.L = zR8(Opcode & 7);
RET(5)
OPXY(0x65): // LD HX,LX
data->B.H = data->B.L;
RET(5)
OPXY(0x6c): // LD LX,HX
data->B.L = data->B.H;
RET(5)
OPXY(0x06): // LD B,#imm
OPXY(0x0e): // LD C,#imm
OPXY(0x16): // LD D,#imm
OPXY(0x1e): // LD E,#imm
OPXY(0x3e): // LD A,#imm
goto OP_LD_R_imm;
OPXY(0x26): // LD HX,#imm
data->B.H = READ_ARG();
RET(5)
OPXY(0x2e): // LD LX,#imm
data->B.L = READ_ARG();
RET(5)
OPXY(0x0a): // LD A,(BC)
goto OP_LOAD_A_mBC;
OPXY(0x1a): // LD A,(DE)
goto OP_LOAD_A_mDE;
OPXY(0x3a): // LD A,(nn)
goto OP_LOAD_A_mNN;
OPXY(0x02): // LD (BC),A
goto OP_LOAD_mBC_A;
OPXY(0x12): // LD (DE),A
goto OP_LOAD_mDE_A;
OPXY(0x32): // LD (nn),A
goto OP_LOAD_mNN_A;
OPXY(0x46): // LD B,(IX+o)
OPXY(0x4e): // LD C,(IX+o)
OPXY(0x56): // LD D,(IX+o)
OPXY(0x5e): // LD E,(IX+o)
OPXY(0x66): // LD H,(IX+o)
OPXY(0x6e): // LD L,(IX+o)
OPXY(0x7e): // LD A,(IX+o)
adr = data->W + (INT8)READ_ARG();
zR8((Opcode >> 3) & 7) = READ_MEM8(adr);
RET(15)
OPXY(0x70): // LD (IX+o),B
OPXY(0x71): // LD (IX+o),C
OPXY(0x72): // LD (IX+o),D
OPXY(0x73): // LD (IX+o),E
OPXY(0x74): // LD (IX+o),H
OPXY(0x75): // LD (IX+o),L
OPXY(0x77): // LD (IX+o),A
adr = data->W + (INT8)READ_ARG();
WRITE_MEM8(adr, zR8(Opcode & 7));
RET(15)
OPXY(0x36): // LD (IX+o),#imm
adr = data->W + (INT8)READ_ARG();
WRITE_MEM8(adr, READ_ARG());
RET(15)
/*-----------------------------------------
LD r16
-----------------------------------------*/
OPXY(0x01): // LD BC,nn
OPXY(0x11): // LD DE,nn
goto OP_LOAD_RR_imm16;
OPXY(0x21): // LD IX,nn
data->W = READ_ARG16();
RET(10)
OPXY(0x31): // LD SP,nn
goto OP_LOAD_SP_imm16;
OPXY(0x2a): // LD IX,(w)
goto OP_LD_xx_mNN;
OPXY(0x22): // LD (w),IX
goto OP_LD_mNN_xx;
OPXY(0xf9): // LD SP,IX
goto OP_LD_SP_xx;
/*-----------------------------------------
POP
-----------------------------------------*/
OPXY(0xc1): // POP BC
OPXY(0xd1): // POP DE
OPXY(0xf1): // POP AF
goto OP_POP_RR;
OPXY(0xe1): // POP IX
goto OP_POP;
/*-----------------------------------------
PUSH
-----------------------------------------*/
OPXY(0xc5): // PUSH BC
OPXY(0xd5): // PUSH DE
OPXY(0xf5): // PUSH AF
goto OP_PUSH_RR;
OPXY(0xe5): // PUSH IX
goto OP_PUSH;
/*-----------------------------------------
EX
-----------------------------------------*/
OPXY(0x08): // EX AF,AF'
goto OP_EX_AF_AF2;
OPXY(0xeb): // EX DE,HL
goto OP_EX_DE_HL;
OPXY(0xd9): // EXX
goto OP_EXX;
OPXY(0xe3): // EX (SP),IX
goto OP_EX_xx_mSP;
/*-----------------------------------------
INC r8
-----------------------------------------*/
OPXY(0x04): // INC B
OPXY(0x0c): // INC C
OPXY(0x14): // INC D
OPXY(0x1c): // INC E
OPXY(0x3c): // INC A
goto OP_INC_R;
OPXY(0x24): // INC HX
data->B.H++;
zF = (zF & CF) | SZHV_inc[data->B.H];
RET(5)
OPXY(0x2c): // INC LX
data->B.L++;
zF = (zF & CF) | SZHV_inc[data->B.L];
RET(5)
OPXY(0x34): // INC (IX+o)
adr = data->W + (INT8)READ_ARG();
USE_CYCLES(8)
goto OP_INC_m;
/*-----------------------------------------
DEC r8
-----------------------------------------*/
OPXY(0x05): // DEC B
OPXY(0x0d): // DEC C
OPXY(0x15): // DEC D
OPXY(0x1d): // DEC E
OPXY(0x3d): // DEC A
goto OP_DEC_R;
OPXY(0x25): // DEC HX
data->B.H--;
zF = (zF & CF) | SZHV_dec[data->B.H];
RET(5)
OPXY(0x2d): // DEC LX
data->B.L--;
zF = (zF & CF) | SZHV_dec[data->B.L];
RET(5)
OPXY(0x35): // DEC (IX+o)
adr = data->W + (INT8)READ_ARG();
USE_CYCLES(8)
goto OP_DEC_m;
/*-----------------------------------------
ADD r8
-----------------------------------------*/
OPXY(0x80): // ADD A,B
OPXY(0x81): // ADD A,C
OPXY(0x82): // ADD A,D
OPXY(0x83): // ADD A,E
OPXY(0x87): // ADD A,A
goto OP_ADD_R;
OPXY(0xc6): // ADD A,n
goto OP_ADD_imm;
OPXY(0x84): // ADD A,HX
val = data->B.H;
USE_CYCLES(1)
goto OP_ADD;
OPXY(0x85): // ADD A,LX
val = data->B.L;
USE_CYCLES(1)
goto OP_ADD;
OPXY(0x86): // ADD A,(IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_ADD;
/*-----------------------------------------
ADC r8
-----------------------------------------*/
OPXY(0x88): // ADC A,B
OPXY(0x89): // ADC A,C
OPXY(0x8a): // ADC A,D
OPXY(0x8b): // ADC A,E
OPXY(0x8f): // ADC A,A
goto OP_ADC_R;
OPXY(0xce): // ADC A,n
goto OP_ADC_imm;
OPXY(0x8c): // ADC A,HX
val = data->B.H;
USE_CYCLES(1)
goto OP_ADC;
OPXY(0x8d): // ADC A,LX
val = data->B.L;
USE_CYCLES(1)
goto OP_ADC;
OPXY(0x8e): // ADC A,(IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_ADC;
/*-----------------------------------------
SUB r8
-----------------------------------------*/
OPXY(0x90): // SUB B
OPXY(0x91): // SUB C
OPXY(0x92): // SUB D
OPXY(0x93): // SUB E
OPXY(0x97): // SUB A
goto OP_SUB_R;
OPXY(0xd6): // SUB A,n
goto OP_SUB_imm;
OPXY(0x94): // SUB HX
val = data->B.H;
USE_CYCLES(1)
goto OP_SUB;
OPXY(0x95): // SUB LX
val = data->B.L;
USE_CYCLES(1)
goto OP_SUB;
OPXY(0x96): // SUB (IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_SUB;
/*-----------------------------------------
SBC r8
-----------------------------------------*/
OPXY(0x98): // SBC A,B
OPXY(0x99): // SBC A,C
OPXY(0x9a): // SBC A,D
OPXY(0x9b): // SBC A,E
OPXY(0x9f): // SBC A,A
goto OP_SBC_R;
OPXY(0xde): // SBC A,n
goto OP_SBC_imm;
OPXY(0x9c): // SBC A,HX
val = data->B.H;
USE_CYCLES(1)
goto OP_SBC;
OPXY(0x9d): // SBC A,LX
val = data->B.L;
USE_CYCLES(1)
goto OP_SBC;
OPXY(0x9e): // SBC A,(IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_SBC;
/*-----------------------------------------
CP r8
-----------------------------------------*/
OPXY(0xb8): // CP B
OPXY(0xb9): // CP C
OPXY(0xba): // CP D
OPXY(0xbb): // CP E
OPXY(0xbf): // CP A
goto OP_CP_R;
OPXY(0xfe): // CP n
goto OP_CP_imm;
OPXY(0xbc): // CP HX
val = data->B.H;
USE_CYCLES(1)
goto OP_CP;
OPXY(0xbd): // CP LX
val = data->B.L;
USE_CYCLES(1)
goto OP_CP;
OPXY(0xbe): // CP (IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_CP;
/*-----------------------------------------
AND r8
-----------------------------------------*/
OPXY(0xa0): // AND B
OPXY(0xa1): // AND C
OPXY(0xa2): // AND D
OPXY(0xa3): // AND E
OPXY(0xa7): // AND A
goto OP_AND_R;
OPXY(0xe6): // AND A,n
goto OP_AND_imm;
OPXY(0xa4): // AND HX
val = data->B.H;
USE_CYCLES(1)
goto OP_AND;
OPXY(0xa5): // AND LX
val = data->B.L;
USE_CYCLES(1)
goto OP_AND;
OPXY(0xa6): // AND (IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_AND;
/*-----------------------------------------
XOR r8
-----------------------------------------*/
OPXY(0xa8): // XOR B
OPXY(0xa9): // XOR C
OPXY(0xaa): // XOR D
OPXY(0xab): // XOR E
OPXY(0xaf): // XOR A
goto OP_XOR_R;
OPXY(0xee): // XOR A,n
goto OP_XOR_imm;
OPXY(0xac): // XOR HX
val = data->B.H;
USE_CYCLES(1)
goto OP_XOR;
OPXY(0xad): // XOR LX
val = data->B.L;
USE_CYCLES(1)
goto OP_XOR;
OPXY(0xae): // XOR (IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_XOR;
/*-----------------------------------------
OR r8
-----------------------------------------*/
OPXY(0xb0): // OR B
OPXY(0xb1): // OR C
OPXY(0xb2): // OR D
OPXY(0xb3): // OR E
OPXY(0xb7): // OR A
goto OP_OR_R;
OPXY(0xf6): // OR A,n
goto OP_OR_imm;
OPXY(0xb4): // OR HX
val = data->B.H;
USE_CYCLES(1)
goto OP_OR;
OPXY(0xb5): // OR LX
val = data->B.L;
USE_CYCLES(1)
goto OP_OR;
OPXY(0xb6): // OR (IX+o)
adr = data->W + (INT8)READ_ARG();
val = READ_MEM8(adr);
USE_CYCLES(11)
goto OP_OR;
/*-----------------------------------------
MISC ARITHMETIC & CPU CONTROL
-----------------------------------------*/
OPXY(0x27): // DAA
goto OP_DAA;
OPXY(0x2f): // CPL
goto OP_CPL;
OPXY(0x37): // SCF
goto OP_SCF;
OPXY(0x3f): // CCF
goto OP_CCF;
OPXY(0x76): // HALT
goto OP_HALT;
OPXY(0xf3): // DI
goto OP_DI;
OPXY(0xfb): // EI
goto OP_EI;
/*-----------------------------------------
INC r16
-----------------------------------------*/
OPXY(0x03): // INC BC
goto OP_INC_BC;
OPXY(0x13): // INC DE
goto OP_INC_DE;
OPXY(0x23): // INC IX
goto OP_INC_xx;
OPXY(0x33): // INC SP
goto OP_INC_SP;
/*-----------------------------------------
DEC r16
-----------------------------------------*/
OPXY(0x0b): // DEC BC
goto OP_DEC_BC;
OPXY(0x1b): // DEC DE
goto OP_DEC_DE;
OPXY(0x2b): // DEC IX
goto OP_DEC_xx;
OPXY(0x3b): // DEC SP
goto OP_DEC_SP;
/*-----------------------------------------
ADD r16
-----------------------------------------*/
OPXY(0x09): // ADD IX,BC
goto OP_ADD16_xx_BC;
OPXY(0x19): // ADD IX,DE
goto OP_ADD16_xx_DE;
OPXY(0x29): // ADD IX,IX
goto OP_ADD16_xx_xx;
OPXY(0x39): // ADD IX,SP
goto OP_ADD16_xx_SP;
/*-----------------------------------------
ROTATE
-----------------------------------------*/
OPXY(0x07): // RLCA
goto OP_RLCA;
OPXY(0x0f): // RRCA
goto OP_RRCA;
OPXY(0x17): // RLA
goto OP_RLA;
OPXY(0x1f): // RRA
goto OP_RRA;
/*-----------------------------------------
JP
-----------------------------------------*/
OPXY(0xc3): // JP nn
goto OP_JP;
OPXY(0xe9): // JP (IX)
goto OP_JP_xx;
OPXY(0xc2): // JP NZ,nn
goto OP_JP_NZ;
OPXY(0xca): // JP Z,nn
goto OP_JP_Z;
OPXY(0xd2): // JP NC,nn
goto OP_JP_NC;
OPXY(0xda): // JP C,nn
goto OP_JP_C;
OPXY(0xe2): // JP PO,nn
goto OP_JP_PO;
OPXY(0xea): // JP PE,nn
goto OP_JP_PE;
OPXY(0xf2): // JP P,nn
goto OP_JP_P;
OPXY(0xfa): // JP M,nn
goto OP_JP_M;
/*-----------------------------------------
JR
-----------------------------------------*/
OPXY(0x10): // DJNZ n
goto OP_DJNZ;
OPXY(0x18): // JR n
goto OP_JR;
OPXY(0x20): // JR NZ,n
goto OP_JR_NZ;
OPXY(0x28): // JR Z,n
goto OP_JR_Z;
OPXY(0x30): // JR NC,n
goto OP_JR_NC;
OPXY(0x38): // JR C,n
goto OP_JR_C;
/*-----------------------------------------
CALL
-----------------------------------------*/
OPXY(0xcd): // CALL nn
goto OP_CALL;
OPXY(0xc4): // CALL NZ,nn
goto OP_CALL_NZ;
OPXY(0xcc): // CALL Z,nn
goto OP_CALL_Z;
OPXY(0xd4): // CALL NC,nn
goto OP_CALL_NC;
OPXY(0xdc): // CALL C,nn
goto OP_CALL_C;
OPXY(0xe4): // CALL PO,nn
goto OP_CALL_PO;
OPXY(0xec): // CALL PE,nn
goto OP_CALL_PE;
OPXY(0xf4): // CALL P,nn
goto OP_CALL_P;
OPXY(0xfc): // CALL M,nn
goto OP_CALL_M;
/*-----------------------------------------
RET
-----------------------------------------*/
OPXY(0xc9): // RET
goto OP_RET;
OPXY(0xc0): // RET NZ
goto OP_RET_NZ;
OPXY(0xc8): // RET Z
goto OP_RET_Z;
OPXY(0xd0): // RET NC
goto OP_RET_NC;
OPXY(0xd8): // RET C
goto OP_RET_C;
OPXY(0xe0): // RET PO
goto OP_RET_PO;
OPXY(0xe8): // RET PE
goto OP_RET_PE;
OPXY(0xf0): // RET P
goto OP_RET_P;
OPXY(0xf8): // RET M
goto OP_RET_M;
/*-----------------------------------------
RST
-----------------------------------------*/
OPXY(0xc7): // RST 0
OPXY(0xcf): // RST 1
OPXY(0xd7): // RST 2
OPXY(0xdf): // RST 3
OPXY(0xe7): // RST 4
OPXY(0xef): // RST 5
OPXY(0xf7): // RST 6
OPXY(0xff): // RST 7
goto OP_RST;
/*-----------------------------------------
OUT
-----------------------------------------*/
OPXY(0xd3): // OUT (n),A
goto OP_OUT_mN_A;
/*-----------------------------------------
IN
-----------------------------------------*/
OPXY(0xdb): // IN A,(n)
goto OP_IN_A_mN;
/*-----------------------------------------
PREFIX
-----------------------------------------*/
OPXY(0xcb): // XYCB prefix (BIT & SHIFT INSTRUCTIONS)
{
UINT8 src;
UINT8 res;
adr = data->W + (INT8)READ_ARG();
Opcode = READ_ARG();
#if CZ80_EMULATE_R_EXACTLY
zR++;
#endif
#include "cz80_opXYCB.inc"
}
OPXY(0xed): // ED prefix
goto ED_PREFIX;
OPXY(0xdd): // DD prefix (IX)
goto DD_PREFIX;
OPXY(0xfd): // FD prefix (IY)
goto FD_PREFIX;
#if !CZ80_USE_JUMPTABLE
}
#endif

View File

@ -0,0 +1,474 @@
/******************************************************************************
*
* CZ80 XYCB opcode include source file
* CZ80 emulator version 0.9
* Copyright 2004-2005 Stéphane Dallongeville
*
* (Modified by NJ)
*
*****************************************************************************/
#if CZ80_USE_JUMPTABLE
goto *JumpTableXYCB[Opcode];
#else
switch (Opcode)
{
#endif
/*-----------------------------------------
RLC
-----------------------------------------*/
OPXYCB(0x00): // RLC (Ix+d), B
OPXYCB(0x01): // RLC (Ix+d), C
OPXYCB(0x02): // RLC (Ix+d), D
OPXYCB(0x03): // RLC (Ix+d), E
OPXYCB(0x04): // RLC (Ix+d), H
OPXYCB(0x05): // RLC (Ix+d), L
OPXYCB(0x07): // RLC (Ix+d), A
src = READ_MEM8(adr);
res = ((src << 1) | (src >> 7)) & 0xff;
zF = SZP[res] | (src >> 7);
zR8(Opcode) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x06): // RLC (Ix+d)
src = READ_MEM8(adr);
res = ((src << 1) | (src >> 7)) & 0xff;
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
RRC
-----------------------------------------*/
OPXYCB(0x08): // RRC (Ix+d), B
OPXYCB(0x09): // RRC (Ix+d), C
OPXYCB(0x0a): // RRC (Ix+d), D
OPXYCB(0x0b): // RRC (Ix+d), E
OPXYCB(0x0c): // RRC (Ix+d), H
OPXYCB(0x0d): // RRC (Ix+d), L
OPXYCB(0x0f): // RRC (Ix+d), A
src = READ_MEM8(adr);
res = ((src >> 1) | (src << 7)) & 0xff;
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x0e): // RRC (Ix+d)
src = READ_MEM8(adr);
res = ((src >> 1) | (src << 7)) & 0xff;
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
RL
-----------------------------------------*/
OPXYCB(0x10): // RL (Ix+d), B
OPXYCB(0x11): // RL (Ix+d), C
OPXYCB(0x12): // RL (Ix+d), D
OPXYCB(0x13): // RL (Ix+d), E
OPXYCB(0x14): // RL (Ix+d), H
OPXYCB(0x15): // RL (Ix+d), L
OPXYCB(0x17): // RL (Ix+d), A
src = READ_MEM8(adr);
res = ((src << 1) | (zF & CF)) & 0xff;
zF = SZP[res] | (src >> 7);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x16): // RL (Ix+d)
src = READ_MEM8(adr);
res = ((src << 1) | (zF & CF)) & 0xff;
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
RR
-----------------------------------------*/
OPXYCB(0x18): // RR (Ix+d), B
OPXYCB(0x19): // RR (Ix+d), C
OPXYCB(0x1a): // RR (Ix+d), D
OPXYCB(0x1b): // RR (Ix+d), E
OPXYCB(0x1c): // RR (Ix+d), H
OPXYCB(0x1d): // RR (Ix+d), L
OPXYCB(0x1f): // RR (Ix+d), A
src = READ_MEM8(adr);
res = ((src >> 1) | (zF << 7)) & 0xff;
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x1e): // RR (Ix+d)
src = READ_MEM8(adr);
res = ((src >> 1) | (zF << 7)) & 0xff;
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
SLA
-----------------------------------------*/
OPXYCB(0x20): // SLA (Ix+d), B
OPXYCB(0x21): // SLA (Ix+d), C
OPXYCB(0x22): // SLA (Ix+d), D
OPXYCB(0x23): // SLA (Ix+d), E
OPXYCB(0x24): // SLA (Ix+d), H
OPXYCB(0x25): // SLA (Ix+d), L
OPXYCB(0x27): // SLA (Ix+d), A
src = READ_MEM8(adr);
res = (src << 1) & 0xff;
zF = SZP[res] | (src >> 7);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x26): // SLA (Ix+d)
src = READ_MEM8(adr);
res = (src << 1) & 0xff;
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
SRA
-----------------------------------------*/
OPXYCB(0x28): // SRA (Ix+d), B
OPXYCB(0x29): // SRA (Ix+d), C
OPXYCB(0x2a): // SRA (Ix+d), D
OPXYCB(0x2b): // SRA (Ix+d), E
OPXYCB(0x2c): // SRA (Ix+d), H
OPXYCB(0x2d): // SRA (Ix+d), L
OPXYCB(0x2f): // SRA (Ix+d), A
src = READ_MEM8(adr);
res = ((src >> 1) | (src & 0x80)) & 0xff;
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x2e): // SRA (Ix+d)
src = READ_MEM8(adr);
res = ((src >> 1) | (src & 0x80)) & 0xff;
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
SLL
-----------------------------------------*/
OPXYCB(0x30): // SLL (Ix+d), B
OPXYCB(0x31): // SLL (Ix+d), C
OPXYCB(0x32): // SLL (Ix+d), D
OPXYCB(0x33): // SLL (Ix+d), E
OPXYCB(0x34): // SLL (Ix+d), H
OPXYCB(0x35): // SLL (Ix+d), L
OPXYCB(0x37): // SLL (Ix+d), A
src = READ_MEM8(adr);
res = ((src << 1) | 0x01) & 0xff;
zF = SZP[res] | (src >> 7);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x36): // SLL (Ix+d)
src = READ_MEM8(adr);
res = ((src << 1) | 0x01) & 0xff;
zF = SZP[res] | (src >> 7);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
SRL
-----------------------------------------*/
OPXYCB(0x38): // SRL (Ix+d), B
OPXYCB(0x39): // SRL (Ix+d), C
OPXYCB(0x3a): // SRL (Ix+d), D
OPXYCB(0x3b): // SRL (Ix+d), E
OPXYCB(0x3c): // SRL (Ix+d), H
OPXYCB(0x3d): // SRL (Ix+d), L
OPXYCB(0x3f): // SRL (Ix+d), A
src = READ_MEM8(adr);
res = (src >> 1) & 0xff;
zF = SZP[res] | (src & CF);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x3e): // SRL (Ix+d)
src = READ_MEM8(adr);
res = (src >> 1) & 0xff;
zF = SZP[res] | (src & CF);
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
BIT
-----------------------------------------*/
OPXYCB(0x40): // BIT 0,(Ix+d)
OPXYCB(0x41): // BIT 0,(Ix+d)
OPXYCB(0x42): // BIT 0,(Ix+d)
OPXYCB(0x43): // BIT 0,(Ix+d)
OPXYCB(0x44): // BIT 0,(Ix+d)
OPXYCB(0x45): // BIT 0,(Ix+d)
OPXYCB(0x47): // BIT 0,(Ix+d)
OPXYCB(0x48): // BIT 1,(Ix+d)
OPXYCB(0x49): // BIT 1,(Ix+d)
OPXYCB(0x4a): // BIT 1,(Ix+d)
OPXYCB(0x4b): // BIT 1,(Ix+d)
OPXYCB(0x4c): // BIT 1,(Ix+d)
OPXYCB(0x4d): // BIT 1,(Ix+d)
OPXYCB(0x4f): // BIT 1,(Ix+d)
OPXYCB(0x50): // BIT 2,(Ix+d)
OPXYCB(0x51): // BIT 2,(Ix+d)
OPXYCB(0x52): // BIT 2,(Ix+d)
OPXYCB(0x53): // BIT 2,(Ix+d)
OPXYCB(0x54): // BIT 2,(Ix+d)
OPXYCB(0x55): // BIT 2,(Ix+d)
OPXYCB(0x57): // BIT 2,(Ix+d)
OPXYCB(0x58): // BIT 3,(Ix+d)
OPXYCB(0x59): // BIT 3,(Ix+d)
OPXYCB(0x5a): // BIT 3,(Ix+d)
OPXYCB(0x5b): // BIT 3,(Ix+d)
OPXYCB(0x5c): // BIT 3,(Ix+d)
OPXYCB(0x5d): // BIT 3,(Ix+d)
OPXYCB(0x5f): // BIT 3,(Ix+d)
OPXYCB(0x60): // BIT 4,(Ix+d)
OPXYCB(0x61): // BIT 4,(Ix+d)
OPXYCB(0x62): // BIT 4,(Ix+d)
OPXYCB(0x63): // BIT 4,(Ix+d)
OPXYCB(0x64): // BIT 4,(Ix+d)
OPXYCB(0x65): // BIT 4,(Ix+d)
OPXYCB(0x67): // BIT 4,(Ix+d)
OPXYCB(0x68): // BIT 5,(Ix+d)
OPXYCB(0x69): // BIT 5,(Ix+d)
OPXYCB(0x6a): // BIT 5,(Ix+d)
OPXYCB(0x6b): // BIT 5,(Ix+d)
OPXYCB(0x6c): // BIT 5,(Ix+d)
OPXYCB(0x6d): // BIT 5,(Ix+d)
OPXYCB(0x6f): // BIT 5,(Ix+d)
OPXYCB(0x70): // BIT 6,(Ix+d)
OPXYCB(0x71): // BIT 6,(Ix+d)
OPXYCB(0x72): // BIT 6,(Ix+d)
OPXYCB(0x73): // BIT 6,(Ix+d)
OPXYCB(0x74): // BIT 6,(Ix+d)
OPXYCB(0x75): // BIT 6,(Ix+d)
OPXYCB(0x77): // BIT 6,(Ix+d)
OPXYCB(0x78): // BIT 7,(Ix+d)
OPXYCB(0x79): // BIT 7,(Ix+d)
OPXYCB(0x7a): // BIT 7,(Ix+d)
OPXYCB(0x7b): // BIT 7,(Ix+d)
OPXYCB(0x7c): // BIT 7,(Ix+d)
OPXYCB(0x7d): // BIT 7,(Ix+d)
OPXYCB(0x7f): // BIT 7,(Ix+d)
OPXYCB(0x46): // BIT 0,(Ix+d)
OPXYCB(0x4e): // BIT 1,(Ix+d)
OPXYCB(0x56): // BIT 2,(Ix+d)
OPXYCB(0x5e): // BIT 3,(Ix+d)
OPXYCB(0x66): // BIT 4,(Ix+d)
OPXYCB(0x6e): // BIT 5,(Ix+d)
OPXYCB(0x76): // BIT 6,(Ix+d)
OPXYCB(0x7e): // BIT 7,(Ix+d)
src = READ_MEM8(adr);
zF = (zF & CF) | HF |
(SZ_BIT[src & (1 << ((Opcode >> 3) & 7))] & ~(YF | XF)) |
((adr >> 8) & (YF | XF));
RET(16)
/*-----------------------------------------
RES
-----------------------------------------*/
OPXYCB(0x80): // RES 0,(Ix+d),B
OPXYCB(0x81): // RES 0,(Ix+d),C
OPXYCB(0x82): // RES 0,(Ix+d),D
OPXYCB(0x83): // RES 0,(Ix+d),E
OPXYCB(0x84): // RES 0,(Ix+d),H
OPXYCB(0x85): // RES 0,(Ix+d),L
OPXYCB(0x87): // RES 0,(Ix+d),A
OPXYCB(0x88): // RES 1,(Ix+d),B
OPXYCB(0x89): // RES 1,(Ix+d),C
OPXYCB(0x8a): // RES 1,(Ix+d),D
OPXYCB(0x8b): // RES 1,(Ix+d),E
OPXYCB(0x8c): // RES 1,(Ix+d),H
OPXYCB(0x8d): // RES 1,(Ix+d),L
OPXYCB(0x8f): // RES 1,(Ix+d),A
OPXYCB(0x90): // RES 2,(Ix+d),B
OPXYCB(0x91): // RES 2,(Ix+d),C
OPXYCB(0x92): // RES 2,(Ix+d),D
OPXYCB(0x93): // RES 2,(Ix+d),E
OPXYCB(0x94): // RES 2,(Ix+d),H
OPXYCB(0x95): // RES 2,(Ix+d),L
OPXYCB(0x97): // RES 2,(Ix+d),A
OPXYCB(0x98): // RES 3,(Ix+d),B
OPXYCB(0x99): // RES 3,(Ix+d),C
OPXYCB(0x9a): // RES 3,(Ix+d),D
OPXYCB(0x9b): // RES 3,(Ix+d),E
OPXYCB(0x9c): // RES 3,(Ix+d),H
OPXYCB(0x9d): // RES 3,(Ix+d),L
OPXYCB(0x9f): // RES 3,(Ix+d),A
OPXYCB(0xa0): // RES 4,(Ix+d),B
OPXYCB(0xa1): // RES 4,(Ix+d),C
OPXYCB(0xa2): // RES 4,(Ix+d),D
OPXYCB(0xa3): // RES 4,(Ix+d),E
OPXYCB(0xa4): // RES 4,(Ix+d),H
OPXYCB(0xa5): // RES 4,(Ix+d),L
OPXYCB(0xa7): // RES 4,(Ix+d),A
OPXYCB(0xa8): // RES 5,(Ix+d),B
OPXYCB(0xa9): // RES 5,(Ix+d),C
OPXYCB(0xaa): // RES 5,(Ix+d),D
OPXYCB(0xab): // RES 5,(Ix+d),E
OPXYCB(0xac): // RES 5,(Ix+d),H
OPXYCB(0xad): // RES 5,(Ix+d),L
OPXYCB(0xaf): // RES 5,(Ix+d),A
OPXYCB(0xb0): // RES 6,(Ix+d),B
OPXYCB(0xb1): // RES 6,(Ix+d),C
OPXYCB(0xb2): // RES 6,(Ix+d),D
OPXYCB(0xb3): // RES 6,(Ix+d),E
OPXYCB(0xb4): // RES 6,(Ix+d),H
OPXYCB(0xb5): // RES 6,(Ix+d),L
OPXYCB(0xb7): // RES 6,(Ix+d),A
OPXYCB(0xb8): // RES 7,(Ix+d),B
OPXYCB(0xb9): // RES 7,(Ix+d),C
OPXYCB(0xba): // RES 7,(Ix+d),D
OPXYCB(0xbb): // RES 7,(Ix+d),E
OPXYCB(0xbc): // RES 7,(Ix+d),H
OPXYCB(0xbd): // RES 7,(Ix+d),L
OPXYCB(0xbf): // RES 7,(Ix+d),A
res = READ_MEM8(adr);
res &= ~(1 << ((Opcode >> 3) & 7));
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0x86): // RES 0,(Ix+d)
OPXYCB(0x8e): // RES 1,(Ix+d)
OPXYCB(0x96): // RES 2,(Ix+d)
OPXYCB(0x9e): // RES 3,(Ix+d)
OPXYCB(0xa6): // RES 4,(Ix+d)
OPXYCB(0xae): // RES 5,(Ix+d)
OPXYCB(0xb6): // RES 6,(Ix+d)
OPXYCB(0xbe): // RES 7,(Ix+d)
res = READ_MEM8(adr);
res &= ~(1 << ((Opcode >> 3) & 7));
WRITE_MEM8(adr, res);
RET(19)
/*-----------------------------------------
SET
-----------------------------------------*/
OPXYCB(0xc0): // SET 0,(Ix+d),B
OPXYCB(0xc1): // SET 0,(Ix+d),C
OPXYCB(0xc2): // SET 0,(Ix+d),D
OPXYCB(0xc3): // SET 0,(Ix+d),E
OPXYCB(0xc4): // SET 0,(Ix+d),H
OPXYCB(0xc5): // SET 0,(Ix+d),L
OPXYCB(0xc7): // SET 0,(Ix+d),A
OPXYCB(0xc8): // SET 1,(Ix+d),B
OPXYCB(0xc9): // SET 1,(Ix+d),C
OPXYCB(0xca): // SET 1,(Ix+d),D
OPXYCB(0xcb): // SET 1,(Ix+d),E
OPXYCB(0xcc): // SET 1,(Ix+d),H
OPXYCB(0xcd): // SET 1,(Ix+d),L
OPXYCB(0xcf): // SET 1,(Ix+d),A
OPXYCB(0xd0): // SET 2,(Ix+d),B
OPXYCB(0xd1): // SET 2,(Ix+d),C
OPXYCB(0xd2): // SET 2,(Ix+d),D
OPXYCB(0xd3): // SET 2,(Ix+d),E
OPXYCB(0xd4): // SET 2,(Ix+d),H
OPXYCB(0xd5): // SET 2,(Ix+d),L
OPXYCB(0xd7): // SET 2,(Ix+d),A
OPXYCB(0xd8): // SET 3,(Ix+d),B
OPXYCB(0xd9): // SET 3,(Ix+d),C
OPXYCB(0xda): // SET 3,(Ix+d),D
OPXYCB(0xdb): // SET 3,(Ix+d),E
OPXYCB(0xdc): // SET 3,(Ix+d),H
OPXYCB(0xdd): // SET 3,(Ix+d),L
OPXYCB(0xdf): // SET 3,(Ix+d),A
OPXYCB(0xe0): // SET 4,(Ix+d),B
OPXYCB(0xe1): // SET 4,(Ix+d),C
OPXYCB(0xe2): // SET 4,(Ix+d),D
OPXYCB(0xe3): // SET 4,(Ix+d),E
OPXYCB(0xe4): // SET 4,(Ix+d),H
OPXYCB(0xe5): // SET 4,(Ix+d),L
OPXYCB(0xe7): // SET 4,(Ix+d),A
OPXYCB(0xe8): // SET 5,(Ix+d),B
OPXYCB(0xe9): // SET 5,(Ix+d),C
OPXYCB(0xea): // SET 5,(Ix+d),D
OPXYCB(0xeb): // SET 5,(Ix+d),E
OPXYCB(0xec): // SET 5,(Ix+d),H
OPXYCB(0xed): // SET 5,(Ix+d),L
OPXYCB(0xef): // SET 5,(Ix+d),A
OPXYCB(0xf0): // SET 6,(Ix+d),B
OPXYCB(0xf1): // SET 6,(Ix+d),C
OPXYCB(0xf2): // SET 6,(Ix+d),D
OPXYCB(0xf3): // SET 6,(Ix+d),E
OPXYCB(0xf4): // SET 6,(Ix+d),H
OPXYCB(0xf5): // SET 6,(Ix+d),L
OPXYCB(0xf7): // SET 6,(Ix+d),A
OPXYCB(0xf8): // SET 7,(Ix+d),B
OPXYCB(0xf9): // SET 7,(Ix+d),C
OPXYCB(0xfa): // SET 7,(Ix+d),D
OPXYCB(0xfb): // SET 7,(Ix+d),E
OPXYCB(0xfc): // SET 7,(Ix+d),H
OPXYCB(0xfd): // SET 7,(Ix+d),L
OPXYCB(0xff): // SET 7,(Ix+d),A
res = READ_MEM8(adr);
res |= 1 << ((Opcode >> 3) & 7);
zR8(Opcode & 7) = res;
WRITE_MEM8(adr, res);
RET(19)
OPXYCB(0xc6): // SET 0,(Ix+d)
OPXYCB(0xce): // SET 1,(Ix+d)
OPXYCB(0xd6): // SET 2,(Ix+d)
OPXYCB(0xde): // SET 3,(Ix+d)
OPXYCB(0xe6): // SET 4,(Ix+d)
OPXYCB(0xee): // SET 5,(Ix+d)
OPXYCB(0xf6): // SET 6,(Ix+d)
OPXYCB(0xfe): // SET 7,(Ix+d)
res = READ_MEM8(adr);
res |= 1 << ((Opcode >> 3) & 7);
WRITE_MEM8(adr, res);
RET(19)
#if !CZ80_USE_JUMPTABLE
}
#endif

View File

@ -0,0 +1,422 @@
/******************************************************************************
cz80jmp.c
CZ80 opcodeƒWƒƒƒ“ƒvƒe<EFBFBD>[ƒuƒ
******************************************************************************/
static const void ALIGN_DATA *JumpTable[0x100] =
{
&&OP0x00, &&OP0x01, &&OP0x02, &&OP0x03,
&&OP0x04, &&OP0x05, &&OP0x06, &&OP0x07,
&&OP0x08, &&OP0x09, &&OP0x0a, &&OP0x0b,
&&OP0x0c, &&OP0x0d, &&OP0x0e, &&OP0x0f,
&&OP0x10, &&OP0x11, &&OP0x12, &&OP0x13,
&&OP0x14, &&OP0x15, &&OP0x16, &&OP0x17,
&&OP0x18, &&OP0x19, &&OP0x1a, &&OP0x1b,
&&OP0x1c, &&OP0x1d, &&OP0x1e, &&OP0x1f,
&&OP0x20, &&OP0x21, &&OP0x22, &&OP0x23,
&&OP0x24, &&OP0x25, &&OP0x26, &&OP0x27,
&&OP0x28, &&OP0x29, &&OP0x2a, &&OP0x2b,
&&OP0x2c, &&OP0x2d, &&OP0x2e, &&OP0x2f,
&&OP0x30, &&OP0x31, &&OP0x32, &&OP0x33,
&&OP0x34, &&OP0x35, &&OP0x36, &&OP0x37,
&&OP0x38, &&OP0x39, &&OP0x3a, &&OP0x3b,
&&OP0x3c, &&OP0x3d, &&OP0x3e, &&OP0x3f,
&&OP0x40, &&OP0x41, &&OP0x42, &&OP0x43,
&&OP0x44, &&OP0x45, &&OP0x46, &&OP0x47,
&&OP0x48, &&OP0x49, &&OP0x4a, &&OP0x4b,
&&OP0x4c, &&OP0x4d, &&OP0x4e, &&OP0x4f,
&&OP0x50, &&OP0x51, &&OP0x52, &&OP0x53,
&&OP0x54, &&OP0x55, &&OP0x56, &&OP0x57,
&&OP0x58, &&OP0x59, &&OP0x5a, &&OP0x5b,
&&OP0x5c, &&OP0x5d, &&OP0x5e, &&OP0x5f,
&&OP0x60, &&OP0x61, &&OP0x62, &&OP0x63,
&&OP0x64, &&OP0x65, &&OP0x66, &&OP0x67,
&&OP0x68, &&OP0x69, &&OP0x6a, &&OP0x6b,
&&OP0x6c, &&OP0x6d, &&OP0x6e, &&OP0x6f,
&&OP0x70, &&OP0x71, &&OP0x72, &&OP0x73,
&&OP0x74, &&OP0x75, &&OP0x76, &&OP0x77,
&&OP0x78, &&OP0x79, &&OP0x7a, &&OP0x7b,
&&OP0x7c, &&OP0x7d, &&OP0x7e, &&OP0x7f,
&&OP0x80, &&OP0x81, &&OP0x82, &&OP0x83,
&&OP0x84, &&OP0x85, &&OP0x86, &&OP0x87,
&&OP0x88, &&OP0x89, &&OP0x8a, &&OP0x8b,
&&OP0x8c, &&OP0x8d, &&OP0x8e, &&OP0x8f,
&&OP0x90, &&OP0x91, &&OP0x92, &&OP0x93,
&&OP0x94, &&OP0x95, &&OP0x96, &&OP0x97,
&&OP0x98, &&OP0x99, &&OP0x9a, &&OP0x9b,
&&OP0x9c, &&OP0x9d, &&OP0x9e, &&OP0x9f,
&&OP0xa0, &&OP0xa1, &&OP0xa2, &&OP0xa3,
&&OP0xa4, &&OP0xa5, &&OP0xa6, &&OP0xa7,
&&OP0xa8, &&OP0xa9, &&OP0xaa, &&OP0xab,
&&OP0xac, &&OP0xad, &&OP0xae, &&OP0xaf,
&&OP0xb0, &&OP0xb1, &&OP0xb2, &&OP0xb3,
&&OP0xb4, &&OP0xb5, &&OP0xb6, &&OP0xb7,
&&OP0xb8, &&OP0xb9, &&OP0xba, &&OP0xbb,
&&OP0xbc, &&OP0xbd, &&OP0xbe, &&OP0xbf,
&&OP0xc0, &&OP0xc1, &&OP0xc2, &&OP0xc3,
&&OP0xc4, &&OP0xc5, &&OP0xc6, &&OP0xc7,
&&OP0xc8, &&OP0xc9, &&OP0xca, &&OP0xcb,
&&OP0xcc, &&OP0xcd, &&OP0xce, &&OP0xcf,
&&OP0xd0, &&OP0xd1, &&OP0xd2, &&OP0xd3,
&&OP0xd4, &&OP0xd5, &&OP0xd6, &&OP0xd7,
&&OP0xd8, &&OP0xd9, &&OP0xda, &&OP0xdb,
&&OP0xdc, &&OP0xdd, &&OP0xde, &&OP0xdf,
&&OP0xe0, &&OP0xe1, &&OP0xe2, &&OP0xe3,
&&OP0xe4, &&OP0xe5, &&OP0xe6, &&OP0xe7,
&&OP0xe8, &&OP0xe9, &&OP0xea, &&OP0xeb,
&&OP0xec, &&OP0xed, &&OP0xee, &&OP0xef,
&&OP0xf0, &&OP0xf1, &&OP0xf2, &&OP0xf3,
&&OP0xf4, &&OP0xf5, &&OP0xf6, &&OP0xf7,
&&OP0xf8, &&OP0xf9, &&OP0xfa, &&OP0xfb,
&&OP0xfc, &&OP0xfd, &&OP0xfe, &&OP0xff
};
static const void ALIGN_DATA *JumpTableCB[0x100] =
{
&&OPCB0x00, &&OPCB0x01, &&OPCB0x02, &&OPCB0x03,
&&OPCB0x04, &&OPCB0x05, &&OPCB0x06, &&OPCB0x07,
&&OPCB0x08, &&OPCB0x09, &&OPCB0x0a, &&OPCB0x0b,
&&OPCB0x0c, &&OPCB0x0d, &&OPCB0x0e, &&OPCB0x0f,
&&OPCB0x10, &&OPCB0x11, &&OPCB0x12, &&OPCB0x13,
&&OPCB0x14, &&OPCB0x15, &&OPCB0x16, &&OPCB0x17,
&&OPCB0x18, &&OPCB0x19, &&OPCB0x1a, &&OPCB0x1b,
&&OPCB0x1c, &&OPCB0x1d, &&OPCB0x1e, &&OPCB0x1f,
&&OPCB0x20, &&OPCB0x21, &&OPCB0x22, &&OPCB0x23,
&&OPCB0x24, &&OPCB0x25, &&OPCB0x26, &&OPCB0x27,
&&OPCB0x28, &&OPCB0x29, &&OPCB0x2a, &&OPCB0x2b,
&&OPCB0x2c, &&OPCB0x2d, &&OPCB0x2e, &&OPCB0x2f,
&&OPCB0x30, &&OPCB0x31, &&OPCB0x32, &&OPCB0x33,
&&OPCB0x34, &&OPCB0x35, &&OPCB0x36, &&OPCB0x37,
&&OPCB0x38, &&OPCB0x39, &&OPCB0x3a, &&OPCB0x3b,
&&OPCB0x3c, &&OPCB0x3d, &&OPCB0x3e, &&OPCB0x3f,
&&OPCB0x40, &&OPCB0x41, &&OPCB0x42, &&OPCB0x43,
&&OPCB0x44, &&OPCB0x45, &&OPCB0x46, &&OPCB0x47,
&&OPCB0x48, &&OPCB0x49, &&OPCB0x4a, &&OPCB0x4b,
&&OPCB0x4c, &&OPCB0x4d, &&OPCB0x4e, &&OPCB0x4f,
&&OPCB0x50, &&OPCB0x51, &&OPCB0x52, &&OPCB0x53,
&&OPCB0x54, &&OPCB0x55, &&OPCB0x56, &&OPCB0x57,
&&OPCB0x58, &&OPCB0x59, &&OPCB0x5a, &&OPCB0x5b,
&&OPCB0x5c, &&OPCB0x5d, &&OPCB0x5e, &&OPCB0x5f,
&&OPCB0x60, &&OPCB0x61, &&OPCB0x62, &&OPCB0x63,
&&OPCB0x64, &&OPCB0x65, &&OPCB0x66, &&OPCB0x67,
&&OPCB0x68, &&OPCB0x69, &&OPCB0x6a, &&OPCB0x6b,
&&OPCB0x6c, &&OPCB0x6d, &&OPCB0x6e, &&OPCB0x6f,
&&OPCB0x70, &&OPCB0x71, &&OPCB0x72, &&OPCB0x73,
&&OPCB0x74, &&OPCB0x75, &&OPCB0x76, &&OPCB0x77,
&&OPCB0x78, &&OPCB0x79, &&OPCB0x7a, &&OPCB0x7b,
&&OPCB0x7c, &&OPCB0x7d, &&OPCB0x7e, &&OPCB0x7f,
&&OPCB0x80, &&OPCB0x81, &&OPCB0x82, &&OPCB0x83,
&&OPCB0x84, &&OPCB0x85, &&OPCB0x86, &&OPCB0x87,
&&OPCB0x88, &&OPCB0x89, &&OPCB0x8a, &&OPCB0x8b,
&&OPCB0x8c, &&OPCB0x8d, &&OPCB0x8e, &&OPCB0x8f,
&&OPCB0x90, &&OPCB0x91, &&OPCB0x92, &&OPCB0x93,
&&OPCB0x94, &&OPCB0x95, &&OPCB0x96, &&OPCB0x97,
&&OPCB0x98, &&OPCB0x99, &&OPCB0x9a, &&OPCB0x9b,
&&OPCB0x9c, &&OPCB0x9d, &&OPCB0x9e, &&OPCB0x9f,
&&OPCB0xa0, &&OPCB0xa1, &&OPCB0xa2, &&OPCB0xa3,
&&OPCB0xa4, &&OPCB0xa5, &&OPCB0xa6, &&OPCB0xa7,
&&OPCB0xa8, &&OPCB0xa9, &&OPCB0xaa, &&OPCB0xab,
&&OPCB0xac, &&OPCB0xad, &&OPCB0xae, &&OPCB0xaf,
&&OPCB0xb0, &&OPCB0xb1, &&OPCB0xb2, &&OPCB0xb3,
&&OPCB0xb4, &&OPCB0xb5, &&OPCB0xb6, &&OPCB0xb7,
&&OPCB0xb8, &&OPCB0xb9, &&OPCB0xba, &&OPCB0xbb,
&&OPCB0xbc, &&OPCB0xbd, &&OPCB0xbe, &&OPCB0xbf,
&&OPCB0xc0, &&OPCB0xc1, &&OPCB0xc2, &&OPCB0xc3,
&&OPCB0xc4, &&OPCB0xc5, &&OPCB0xc6, &&OPCB0xc7,
&&OPCB0xc8, &&OPCB0xc9, &&OPCB0xca, &&OPCB0xcb,
&&OPCB0xcc, &&OPCB0xcd, &&OPCB0xce, &&OPCB0xcf,
&&OPCB0xd0, &&OPCB0xd1, &&OPCB0xd2, &&OPCB0xd3,
&&OPCB0xd4, &&OPCB0xd5, &&OPCB0xd6, &&OPCB0xd7,
&&OPCB0xd8, &&OPCB0xd9, &&OPCB0xda, &&OPCB0xdb,
&&OPCB0xdc, &&OPCB0xdd, &&OPCB0xde, &&OPCB0xdf,
&&OPCB0xe0, &&OPCB0xe1, &&OPCB0xe2, &&OPCB0xe3,
&&OPCB0xe4, &&OPCB0xe5, &&OPCB0xe6, &&OPCB0xe7,
&&OPCB0xe8, &&OPCB0xe9, &&OPCB0xea, &&OPCB0xeb,
&&OPCB0xec, &&OPCB0xed, &&OPCB0xee, &&OPCB0xef,
&&OPCB0xf0, &&OPCB0xf1, &&OPCB0xf2, &&OPCB0xf3,
&&OPCB0xf4, &&OPCB0xf5, &&OPCB0xf6, &&OPCB0xf7,
&&OPCB0xf8, &&OPCB0xf9, &&OPCB0xfa, &&OPCB0xfb,
&&OPCB0xfc, &&OPCB0xfd, &&OPCB0xfe, &&OPCB0xff
};
static const void ALIGN_DATA *JumpTableED[0x100] =
{
&&OPED0x00, &&OPED0x01, &&OPED0x02, &&OPED0x03,
&&OPED0x04, &&OPED0x05, &&OPED0x06, &&OPED0x07,
&&OPED0x08, &&OPED0x09, &&OPED0x0a, &&OPED0x0b,
&&OPED0x0c, &&OPED0x0d, &&OPED0x0e, &&OPED0x0f,
&&OPED0x10, &&OPED0x11, &&OPED0x12, &&OPED0x13,
&&OPED0x14, &&OPED0x15, &&OPED0x16, &&OPED0x17,
&&OPED0x18, &&OPED0x19, &&OPED0x1a, &&OPED0x1b,
&&OPED0x1c, &&OPED0x1d, &&OPED0x1e, &&OPED0x1f,
&&OPED0x20, &&OPED0x21, &&OPED0x22, &&OPED0x23,
&&OPED0x24, &&OPED0x25, &&OPED0x26, &&OPED0x27,
&&OPED0x28, &&OPED0x29, &&OPED0x2a, &&OPED0x2b,
&&OPED0x2c, &&OPED0x2d, &&OPED0x2e, &&OPED0x2f,
&&OPED0x30, &&OPED0x31, &&OPED0x32, &&OPED0x33,
&&OPED0x34, &&OPED0x35, &&OPED0x36, &&OPED0x37,
&&OPED0x38, &&OPED0x39, &&OPED0x3a, &&OPED0x3b,
&&OPED0x3c, &&OPED0x3d, &&OPED0x3e, &&OPED0x3f,
&&OPED0x40, &&OPED0x41, &&OPED0x42, &&OPED0x43,
&&OPED0x44, &&OPED0x45, &&OPED0x46, &&OPED0x47,
&&OPED0x48, &&OPED0x49, &&OPED0x4a, &&OPED0x4b,
&&OPED0x4c, &&OPED0x4d, &&OPED0x4e, &&OPED0x4f,
&&OPED0x50, &&OPED0x51, &&OPED0x52, &&OPED0x53,
&&OPED0x54, &&OPED0x55, &&OPED0x56, &&OPED0x57,
&&OPED0x58, &&OPED0x59, &&OPED0x5a, &&OPED0x5b,
&&OPED0x5c, &&OPED0x5d, &&OPED0x5e, &&OPED0x5f,
&&OPED0x60, &&OPED0x61, &&OPED0x62, &&OPED0x63,
&&OPED0x64, &&OPED0x65, &&OPED0x66, &&OPED0x67,
&&OPED0x68, &&OPED0x69, &&OPED0x6a, &&OPED0x6b,
&&OPED0x6c, &&OPED0x6d, &&OPED0x6e, &&OPED0x6f,
&&OPED0x70, &&OPED0x71, &&OPED0x72, &&OPED0x73,
&&OPED0x74, &&OPED0x75, &&OPED0x76, &&OPED0x77,
&&OPED0x78, &&OPED0x79, &&OPED0x7a, &&OPED0x7b,
&&OPED0x7c, &&OPED0x7d, &&OPED0x7e, &&OPED0x7f,
&&OPED0x80, &&OPED0x81, &&OPED0x82, &&OPED0x83,
&&OPED0x84, &&OPED0x85, &&OPED0x86, &&OPED0x87,
&&OPED0x88, &&OPED0x89, &&OPED0x8a, &&OPED0x8b,
&&OPED0x8c, &&OPED0x8d, &&OPED0x8e, &&OPED0x8f,
&&OPED0x90, &&OPED0x91, &&OPED0x92, &&OPED0x93,
&&OPED0x94, &&OPED0x95, &&OPED0x96, &&OPED0x97,
&&OPED0x98, &&OPED0x99, &&OPED0x9a, &&OPED0x9b,
&&OPED0x9c, &&OPED0x9d, &&OPED0x9e, &&OPED0x9f,
&&OPED0xa0, &&OPED0xa1, &&OPED0xa2, &&OPED0xa3,
&&OPED0xa4, &&OPED0xa5, &&OPED0xa6, &&OPED0xa7,
&&OPED0xa8, &&OPED0xa9, &&OPED0xaa, &&OPED0xab,
&&OPED0xac, &&OPED0xad, &&OPED0xae, &&OPED0xaf,
&&OPED0xb0, &&OPED0xb1, &&OPED0xb2, &&OPED0xb3,
&&OPED0xb4, &&OPED0xb5, &&OPED0xb6, &&OPED0xb7,
&&OPED0xb8, &&OPED0xb9, &&OPED0xba, &&OPED0xbb,
&&OPED0xbc, &&OPED0xbd, &&OPED0xbe, &&OPED0xbf,
&&OPED0xc0, &&OPED0xc1, &&OPED0xc2, &&OPED0xc3,
&&OPED0xc4, &&OPED0xc5, &&OPED0xc6, &&OPED0xc7,
&&OPED0xc8, &&OPED0xc9, &&OPED0xca, &&OPED0xcb,
&&OPED0xcc, &&OPED0xcd, &&OPED0xce, &&OPED0xcf,
&&OPED0xd0, &&OPED0xd1, &&OPED0xd2, &&OPED0xd3,
&&OPED0xd4, &&OPED0xd5, &&OPED0xd6, &&OPED0xd7,
&&OPED0xd8, &&OPED0xd9, &&OPED0xda, &&OPED0xdb,
&&OPED0xdc, &&OPED0xdd, &&OPED0xde, &&OPED0xdf,
&&OPED0xe0, &&OPED0xe1, &&OPED0xe2, &&OPED0xe3,
&&OPED0xe4, &&OPED0xe5, &&OPED0xe6, &&OPED0xe7,
&&OPED0xe8, &&OPED0xe9, &&OPED0xea, &&OPED0xeb,
&&OPED0xec, &&OPED0xed, &&OPED0xee, &&OPED0xef,
&&OPED0xf0, &&OPED0xf1, &&OPED0xf2, &&OPED0xf3,
&&OPED0xf4, &&OPED0xf5, &&OPED0xf6, &&OPED0xf7,
&&OPED0xf8, &&OPED0xf9, &&OPED0xfa, &&OPED0xfb,
&&OPED0xfc, &&OPED0xfd, &&OPED0xfe, &&OPED0xff
};
static const void ALIGN_DATA *JumpTableXY[0x100] =
{
&&OPXY0x00, &&OPXY0x01, &&OPXY0x02, &&OPXY0x03,
&&OPXY0x04, &&OPXY0x05, &&OPXY0x06, &&OPXY0x07,
&&OPXY0x08, &&OPXY0x09, &&OPXY0x0a, &&OPXY0x0b,
&&OPXY0x0c, &&OPXY0x0d, &&OPXY0x0e, &&OPXY0x0f,
&&OPXY0x10, &&OPXY0x11, &&OPXY0x12, &&OPXY0x13,
&&OPXY0x14, &&OPXY0x15, &&OPXY0x16, &&OPXY0x17,
&&OPXY0x18, &&OPXY0x19, &&OPXY0x1a, &&OPXY0x1b,
&&OPXY0x1c, &&OPXY0x1d, &&OPXY0x1e, &&OPXY0x1f,
&&OPXY0x20, &&OPXY0x21, &&OPXY0x22, &&OPXY0x23,
&&OPXY0x24, &&OPXY0x25, &&OPXY0x26, &&OPXY0x27,
&&OPXY0x28, &&OPXY0x29, &&OPXY0x2a, &&OPXY0x2b,
&&OPXY0x2c, &&OPXY0x2d, &&OPXY0x2e, &&OPXY0x2f,
&&OPXY0x30, &&OPXY0x31, &&OPXY0x32, &&OPXY0x33,
&&OPXY0x34, &&OPXY0x35, &&OPXY0x36, &&OPXY0x37,
&&OPXY0x38, &&OPXY0x39, &&OPXY0x3a, &&OPXY0x3b,
&&OPXY0x3c, &&OPXY0x3d, &&OPXY0x3e, &&OPXY0x3f,
&&OPXY0x40, &&OPXY0x41, &&OPXY0x42, &&OPXY0x43,
&&OPXY0x44, &&OPXY0x45, &&OPXY0x46, &&OPXY0x47,
&&OPXY0x48, &&OPXY0x49, &&OPXY0x4a, &&OPXY0x4b,
&&OPXY0x4c, &&OPXY0x4d, &&OPXY0x4e, &&OPXY0x4f,
&&OPXY0x50, &&OPXY0x51, &&OPXY0x52, &&OPXY0x53,
&&OPXY0x54, &&OPXY0x55, &&OPXY0x56, &&OPXY0x57,
&&OPXY0x58, &&OPXY0x59, &&OPXY0x5a, &&OPXY0x5b,
&&OPXY0x5c, &&OPXY0x5d, &&OPXY0x5e, &&OPXY0x5f,
&&OPXY0x60, &&OPXY0x61, &&OPXY0x62, &&OPXY0x63,
&&OPXY0x64, &&OPXY0x65, &&OPXY0x66, &&OPXY0x67,
&&OPXY0x68, &&OPXY0x69, &&OPXY0x6a, &&OPXY0x6b,
&&OPXY0x6c, &&OPXY0x6d, &&OPXY0x6e, &&OPXY0x6f,
&&OPXY0x70, &&OPXY0x71, &&OPXY0x72, &&OPXY0x73,
&&OPXY0x74, &&OPXY0x75, &&OPXY0x76, &&OPXY0x77,
&&OPXY0x78, &&OPXY0x79, &&OPXY0x7a, &&OPXY0x7b,
&&OPXY0x7c, &&OPXY0x7d, &&OPXY0x7e, &&OPXY0x7f,
&&OPXY0x80, &&OPXY0x81, &&OPXY0x82, &&OPXY0x83,
&&OPXY0x84, &&OPXY0x85, &&OPXY0x86, &&OPXY0x87,
&&OPXY0x88, &&OPXY0x89, &&OPXY0x8a, &&OPXY0x8b,
&&OPXY0x8c, &&OPXY0x8d, &&OPXY0x8e, &&OPXY0x8f,
&&OPXY0x90, &&OPXY0x91, &&OPXY0x92, &&OPXY0x93,
&&OPXY0x94, &&OPXY0x95, &&OPXY0x96, &&OPXY0x97,
&&OPXY0x98, &&OPXY0x99, &&OPXY0x9a, &&OPXY0x9b,
&&OPXY0x9c, &&OPXY0x9d, &&OPXY0x9e, &&OPXY0x9f,
&&OPXY0xa0, &&OPXY0xa1, &&OPXY0xa2, &&OPXY0xa3,
&&OPXY0xa4, &&OPXY0xa5, &&OPXY0xa6, &&OPXY0xa7,
&&OPXY0xa8, &&OPXY0xa9, &&OPXY0xaa, &&OPXY0xab,
&&OPXY0xac, &&OPXY0xad, &&OPXY0xae, &&OPXY0xaf,
&&OPXY0xb0, &&OPXY0xb1, &&OPXY0xb2, &&OPXY0xb3,
&&OPXY0xb4, &&OPXY0xb5, &&OPXY0xb6, &&OPXY0xb7,
&&OPXY0xb8, &&OPXY0xb9, &&OPXY0xba, &&OPXY0xbb,
&&OPXY0xbc, &&OPXY0xbd, &&OPXY0xbe, &&OPXY0xbf,
&&OPXY0xc0, &&OPXY0xc1, &&OPXY0xc2, &&OPXY0xc3,
&&OPXY0xc4, &&OPXY0xc5, &&OPXY0xc6, &&OPXY0xc7,
&&OPXY0xc8, &&OPXY0xc9, &&OPXY0xca, &&OPXY0xcb,
&&OPXY0xcc, &&OPXY0xcd, &&OPXY0xce, &&OPXY0xcf,
&&OPXY0xd0, &&OPXY0xd1, &&OPXY0xd2, &&OPXY0xd3,
&&OPXY0xd4, &&OPXY0xd5, &&OPXY0xd6, &&OPXY0xd7,
&&OPXY0xd8, &&OPXY0xd9, &&OPXY0xda, &&OPXY0xdb,
&&OPXY0xdc, &&OPXY0xdd, &&OPXY0xde, &&OPXY0xdf,
&&OPXY0xe0, &&OPXY0xe1, &&OPXY0xe2, &&OPXY0xe3,
&&OPXY0xe4, &&OPXY0xe5, &&OPXY0xe6, &&OPXY0xe7,
&&OPXY0xe8, &&OPXY0xe9, &&OPXY0xea, &&OPXY0xeb,
&&OPXY0xec, &&OPXY0xed, &&OPXY0xee, &&OPXY0xef,
&&OPXY0xf0, &&OPXY0xf1, &&OPXY0xf2, &&OPXY0xf3,
&&OPXY0xf4, &&OPXY0xf5, &&OPXY0xf6, &&OPXY0xf7,
&&OPXY0xf8, &&OPXY0xf9, &&OPXY0xfa, &&OPXY0xfb,
&&OPXY0xfc, &&OPXY0xfd, &&OPXY0xfe, &&OPXY0xff
};
static const void ALIGN_DATA *JumpTableXYCB[0x100] =
{
&&OPXYCB0x00, &&OPXYCB0x01, &&OPXYCB0x02, &&OPXYCB0x03,
&&OPXYCB0x04, &&OPXYCB0x05, &&OPXYCB0x06, &&OPXYCB0x07,
&&OPXYCB0x08, &&OPXYCB0x09, &&OPXYCB0x0a, &&OPXYCB0x0b,
&&OPXYCB0x0c, &&OPXYCB0x0d, &&OPXYCB0x0e, &&OPXYCB0x0f,
&&OPXYCB0x10, &&OPXYCB0x11, &&OPXYCB0x12, &&OPXYCB0x13,
&&OPXYCB0x14, &&OPXYCB0x15, &&OPXYCB0x16, &&OPXYCB0x17,
&&OPXYCB0x18, &&OPXYCB0x19, &&OPXYCB0x1a, &&OPXYCB0x1b,
&&OPXYCB0x1c, &&OPXYCB0x1d, &&OPXYCB0x1e, &&OPXYCB0x1f,
&&OPXYCB0x20, &&OPXYCB0x21, &&OPXYCB0x22, &&OPXYCB0x23,
&&OPXYCB0x24, &&OPXYCB0x25, &&OPXYCB0x26, &&OPXYCB0x27,
&&OPXYCB0x28, &&OPXYCB0x29, &&OPXYCB0x2a, &&OPXYCB0x2b,
&&OPXYCB0x2c, &&OPXYCB0x2d, &&OPXYCB0x2e, &&OPXYCB0x2f,
&&OPXYCB0x30, &&OPXYCB0x31, &&OPXYCB0x32, &&OPXYCB0x33,
&&OPXYCB0x34, &&OPXYCB0x35, &&OPXYCB0x36, &&OPXYCB0x37,
&&OPXYCB0x38, &&OPXYCB0x39, &&OPXYCB0x3a, &&OPXYCB0x3b,
&&OPXYCB0x3c, &&OPXYCB0x3d, &&OPXYCB0x3e, &&OPXYCB0x3f,
&&OPXYCB0x40, &&OPXYCB0x41, &&OPXYCB0x42, &&OPXYCB0x43,
&&OPXYCB0x44, &&OPXYCB0x45, &&OPXYCB0x46, &&OPXYCB0x47,
&&OPXYCB0x48, &&OPXYCB0x49, &&OPXYCB0x4a, &&OPXYCB0x4b,
&&OPXYCB0x4c, &&OPXYCB0x4d, &&OPXYCB0x4e, &&OPXYCB0x4f,
&&OPXYCB0x50, &&OPXYCB0x51, &&OPXYCB0x52, &&OPXYCB0x53,
&&OPXYCB0x54, &&OPXYCB0x55, &&OPXYCB0x56, &&OPXYCB0x57,
&&OPXYCB0x58, &&OPXYCB0x59, &&OPXYCB0x5a, &&OPXYCB0x5b,
&&OPXYCB0x5c, &&OPXYCB0x5d, &&OPXYCB0x5e, &&OPXYCB0x5f,
&&OPXYCB0x60, &&OPXYCB0x61, &&OPXYCB0x62, &&OPXYCB0x63,
&&OPXYCB0x64, &&OPXYCB0x65, &&OPXYCB0x66, &&OPXYCB0x67,
&&OPXYCB0x68, &&OPXYCB0x69, &&OPXYCB0x6a, &&OPXYCB0x6b,
&&OPXYCB0x6c, &&OPXYCB0x6d, &&OPXYCB0x6e, &&OPXYCB0x6f,
&&OPXYCB0x70, &&OPXYCB0x71, &&OPXYCB0x72, &&OPXYCB0x73,
&&OPXYCB0x74, &&OPXYCB0x75, &&OPXYCB0x76, &&OPXYCB0x77,
&&OPXYCB0x78, &&OPXYCB0x79, &&OPXYCB0x7a, &&OPXYCB0x7b,
&&OPXYCB0x7c, &&OPXYCB0x7d, &&OPXYCB0x7e, &&OPXYCB0x7f,
&&OPXYCB0x80, &&OPXYCB0x81, &&OPXYCB0x82, &&OPXYCB0x83,
&&OPXYCB0x84, &&OPXYCB0x85, &&OPXYCB0x86, &&OPXYCB0x87,
&&OPXYCB0x88, &&OPXYCB0x89, &&OPXYCB0x8a, &&OPXYCB0x8b,
&&OPXYCB0x8c, &&OPXYCB0x8d, &&OPXYCB0x8e, &&OPXYCB0x8f,
&&OPXYCB0x90, &&OPXYCB0x91, &&OPXYCB0x92, &&OPXYCB0x93,
&&OPXYCB0x94, &&OPXYCB0x95, &&OPXYCB0x96, &&OPXYCB0x97,
&&OPXYCB0x98, &&OPXYCB0x99, &&OPXYCB0x9a, &&OPXYCB0x9b,
&&OPXYCB0x9c, &&OPXYCB0x9d, &&OPXYCB0x9e, &&OPXYCB0x9f,
&&OPXYCB0xa0, &&OPXYCB0xa1, &&OPXYCB0xa2, &&OPXYCB0xa3,
&&OPXYCB0xa4, &&OPXYCB0xa5, &&OPXYCB0xa6, &&OPXYCB0xa7,
&&OPXYCB0xa8, &&OPXYCB0xa9, &&OPXYCB0xaa, &&OPXYCB0xab,
&&OPXYCB0xac, &&OPXYCB0xad, &&OPXYCB0xae, &&OPXYCB0xaf,
&&OPXYCB0xb0, &&OPXYCB0xb1, &&OPXYCB0xb2, &&OPXYCB0xb3,
&&OPXYCB0xb4, &&OPXYCB0xb5, &&OPXYCB0xb6, &&OPXYCB0xb7,
&&OPXYCB0xb8, &&OPXYCB0xb9, &&OPXYCB0xba, &&OPXYCB0xbb,
&&OPXYCB0xbc, &&OPXYCB0xbd, &&OPXYCB0xbe, &&OPXYCB0xbf,
&&OPXYCB0xc0, &&OPXYCB0xc1, &&OPXYCB0xc2, &&OPXYCB0xc3,
&&OPXYCB0xc4, &&OPXYCB0xc5, &&OPXYCB0xc6, &&OPXYCB0xc7,
&&OPXYCB0xc8, &&OPXYCB0xc9, &&OPXYCB0xca, &&OPXYCB0xcb,
&&OPXYCB0xcc, &&OPXYCB0xcd, &&OPXYCB0xce, &&OPXYCB0xcf,
&&OPXYCB0xd0, &&OPXYCB0xd1, &&OPXYCB0xd2, &&OPXYCB0xd3,
&&OPXYCB0xd4, &&OPXYCB0xd5, &&OPXYCB0xd6, &&OPXYCB0xd7,
&&OPXYCB0xd8, &&OPXYCB0xd9, &&OPXYCB0xda, &&OPXYCB0xdb,
&&OPXYCB0xdc, &&OPXYCB0xdd, &&OPXYCB0xde, &&OPXYCB0xdf,
&&OPXYCB0xe0, &&OPXYCB0xe1, &&OPXYCB0xe2, &&OPXYCB0xe3,
&&OPXYCB0xe4, &&OPXYCB0xe5, &&OPXYCB0xe6, &&OPXYCB0xe7,
&&OPXYCB0xe8, &&OPXYCB0xe9, &&OPXYCB0xea, &&OPXYCB0xeb,
&&OPXYCB0xec, &&OPXYCB0xed, &&OPXYCB0xee, &&OPXYCB0xef,
&&OPXYCB0xf0, &&OPXYCB0xf1, &&OPXYCB0xf2, &&OPXYCB0xf3,
&&OPXYCB0xf4, &&OPXYCB0xf5, &&OPXYCB0xf6, &&OPXYCB0xf7,
&&OPXYCB0xf8, &&OPXYCB0xf9, &&OPXYCB0xfa, &&OPXYCB0xfb,
&&OPXYCB0xfc, &&OPXYCB0xfd, &&OPXYCB0xfe, &&OPXYCB0xff
};

View File

@ -0,0 +1,129 @@
/******************************************************************************
cz80macro.h
CZ80 ŠeŽíƒ}ƒ<EFBFBD>
******************************************************************************/
#if CZ80_USE_JUMPTABLE
#define _SSOP(A,B) A##B
#define OP(A) _SSOP(OP,A)
#define OPCB(A) _SSOP(OPCB,A)
#define OPED(A) _SSOP(OPED,A)
#define OPXY(A) _SSOP(OPXY,A)
#define OPXYCB(A) _SSOP(OPXYCB,A)
#else
#define OP(A) case A
#define OPCB(A) case A
#define OPED(A) case A
#define OPXY(A) case A
#define OPXYCB(A) case A
#endif
#define USE_CYCLES(A) CPU->ICount -= (A);
#define ADD_CYCLES(A) CPU->ICount += (A);
#define RET(A) { USE_CYCLES(A) goto Cz80_Exec; }
#if CZ80_ENCRYPTED_ROM
#define SET_PC(A) \
CPU->BasePC = CPU->Fetch[(A) >> CZ80_FETCH_SFT]; \
OPBase = CPU->OPFetch[(A) >> CZ80_FETCH_SFT]; \
PC = (A) + CPU->BasePC;
#define GET_OP() (*(UINT8 *)(OPBase + PC))
#else
#define SET_PC(A) \
CPU->BasePC = CPU->Fetch[(A) >> CZ80_FETCH_SFT]; \
PC = (A) + CPU->BasePC;
#define GET_OP() (*(UINT8 *)PC)
#endif
#define READ_OP() GET_OP(); PC++
#define READ_ARG() (*(UINT8 *)PC++)
#if CZ80_LITTLE_ENDIAN
#define READ_ARG16() (*(UINT8 *)PC | (*(UINT8 *)(PC + 1) << 8)); PC += 2
#else
#define READ_ARG16() (*(UINT8 *)(PC + 1) | (*(UINT8 *)PC << 8)); PC += 2
#endif
//#ifndef BUILD_CPS1PSP
//#define READ_MEM8(A) memory_region_cpu2[(A)]
//#else
#if PICODRIVE_HACKS
#define READ_MEM8(A) picodrive_read(A)
#else
#define READ_MEM8(A) CPU->Read_Byte(A)
#endif
//#endif
#if CZ80_LITTLE_ENDIAN
#define READ_MEM16(A) (READ_MEM8(A) | (READ_MEM8((A) + 1) << 8))
#else
#define READ_MEM16(A) ((READ_MEM8(A) << 8) | READ_MEM8((A) + 1))
#endif
#if PICODRIVE_HACKS
#define WRITE_MEM8(A, D) { \
unsigned short a = A; \
unsigned char d = D; \
unsigned long v = z80_write_map[a >> Z80_MEM_SHIFT]; \
if (map_flag_set(v)) \
((z80_write_f *)(v << 1))(a, d); \
else \
*(unsigned char *)((v << 1) + a) = d; \
}
#else
#define WRITE_MEM8(A, D) CPU->Write_Byte(A, D);
#endif
#if CZ80_LITTLE_ENDIAN
#define WRITE_MEM16(A, D) { WRITE_MEM8(A, D); WRITE_MEM8((A) + 1, (D) >> 8); }
#else
#define WRITE_MEM16(A, D) { WRITE_MEM8((A) + 1, D); WRITE_MEM8(A, (D) >> 8); }
#endif
#define PUSH_16(A) { UINT32 sp; zSP -= 2; sp = zSP; WRITE_MEM16(sp, A); }
#define POP_16(A) { UINT32 sp; sp = zSP; A = READ_MEM16(sp); zSP = sp + 2; }
#define IN(A) CPU->IN_Port(A)
#define OUT(A, D) CPU->OUT_Port(A, D)
#define CHECK_INT \
if (zIFF1) \
{ \
UINT32 IntVect; \
\
if (CPU->IRQState == HOLD_LINE) \
CPU->IRQState = CLEAR_LINE; \
\
CPU->HaltState = 0; \
zIFF1 = zIFF2 = 0; \
IntVect = CPU->Interrupt_Callback(CPU->IRQLine); \
\
PUSH_16(zRealPC) \
\
if (zIM == 2) \
{ \
IntVect = (IntVect & 0xff) | (zI << 8); \
PC = READ_MEM16(IntVect); \
CPU->ExtraCycles += 17; \
} \
else if (zIM == 1) \
{ \
PC = 0x38; \
CPU->ExtraCycles += 13; \
} \
else \
{ \
PC = IntVect & 0x38; \
CPU->ExtraCycles += 13; \
} \
\
SET_PC(PC) \
}

View File

@ -0,0 +1,165 @@
/*****************************************************************************/
/* FAME Fast and Accurate Motorola 68000 Emulation Core */
/* (c) 2005 Oscar Orallo Pelaez */
/* Version: 1.24 */
/* Date: 08-20-2005 */
/* See FAME.HTML for documentation and license information */
/*****************************************************************************/
#ifndef __FAME_H__
#define __FAME_H__
#ifdef __cplusplus
extern "C" {
#endif
// PicoDrive hacks
#define FAMEC_FETCHBITS 8
#define M68K_FETCHBANK1 (1 << FAMEC_FETCHBITS)
//#define M68K_RUNNING 0x01
#define FM68K_HALTED 0x80
//#define M68K_WAITING 0x04
//#define M68K_DISABLE 0x20
//#define M68K_FAULTED 0x40
#define FM68K_EMULATE_GROUP_0 0x02
#define FM68K_EMULATE_TRACE 0x08
#define FM68K_DO_TRACE 0x10
/************************************/
/* General library defines */
/************************************/
#ifndef M68K_OK
#define M68K_OK 0
#endif
#ifndef M68K_RUNNING
#define M68K_RUNNING 1
#endif
#ifndef M68K_NO_SUP_ADDR_SPACE
#define M68K_NO_SUP_ADDR_SPACE 2
#endif
#ifndef M68K_DOUBLE_BUS_FAULT
#define M68K_DOUBLE_BUS_FAULT -1
#endif
#ifndef M68K_INV_REG
#define M68K_INV_REG -1
#endif
/* Hardware interrupt state */
#ifndef M68K_IRQ_LEVEL_ERROR
#define M68K_IRQ_LEVEL_ERROR -1
#endif
#ifndef M68K_IRQ_INV_PARAMS
#define M68K_IRQ_INV_PARAMS -2
#endif
/* Defines to specify hardware interrupt type */
#ifndef M68K_AUTOVECTORED_IRQ
#define M68K_AUTOVECTORED_IRQ -1
#endif
#ifndef M68K_SPURIOUS_IRQ
#define M68K_SPURIOUS_IRQ -2
#endif
#ifndef M68K_AUTO_LOWER_IRQ
#define M68K_AUTO_LOWER_IRQ 1
#endif
#ifndef M68K_MANUAL_LOWER_IRQ
#define M68K_MANUAL_LOWER_IRQ 0
#endif
/* Defines to specify address space */
#ifndef M68K_SUP_ADDR_SPACE
#define M68K_SUP_ADDR_SPACE 0
#endif
#ifndef M68K_USER_ADDR_SPACE
#define M68K_USER_ADDR_SPACE 2
#endif
#ifndef M68K_PROG_ADDR_SPACE
#define M68K_PROG_ADDR_SPACE 0
#endif
#ifndef M68K_DATA_ADDR_SPACE
#define M68K_DATA_ADDR_SPACE 1
#endif
/*******************/
/* Data definition */
/*******************/
typedef union
{
unsigned char B;
signed char SB;
unsigned short W;
signed short SW;
unsigned int D;
signed int SD;
} famec_union32;
/* M68K CPU CONTEXT */
typedef struct
{
unsigned int (*read_byte )(unsigned int a);
unsigned int (*read_word )(unsigned int a);
unsigned int (*read_long )(unsigned int a);
void (*write_byte)(unsigned int a,unsigned char d);
void (*write_word)(unsigned int a,unsigned short d);
void (*write_long)(unsigned int a,unsigned int d);
void (*reset_handler)(void);
void (*iack_handler)(unsigned level);
famec_union32 dreg[8];
famec_union32 areg[8];
unsigned asp;
unsigned pc;
unsigned char interrupts[8];
unsigned short sr;
unsigned short execinfo;
// PD extension
int io_cycle_counter; // cycles left
unsigned int Opcode;
signed int cycles_needed;
unsigned short *PC;
unsigned long BasePC;
unsigned int flag_C;
unsigned int flag_V;
unsigned int flag_NotZ;
unsigned int flag_N;
unsigned int flag_X;
unsigned int flag_T;
unsigned int flag_S;
unsigned int flag_I;
unsigned char not_polling;
unsigned char pad[3];
unsigned long Fetch[M68K_FETCHBANK1];
} M68K_CONTEXT;
extern M68K_CONTEXT *g_m68kcontext;
/************************/
/* Function definition */
/************************/
/* General purpose functions */
void fm68k_init(void);
int fm68k_reset(void);
int fm68k_emulate(int n, int idle_mode);
int fm68k_would_interrupt(void); // to be called from fm68k_emulate()
unsigned fm68k_get_pc(M68K_CONTEXT *context);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,326 @@
#include "../sh2.h"
#ifdef DRC_CMP
#include "../compiler.c"
#define BUSY_LOOP_HACKS 0
#else
#define BUSY_LOOP_HACKS 1
#endif
// MAME types
#ifndef INT8
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
#endif
#ifdef DRC_SH2
// this nasty conversion is needed for drc-expecting memhandlers
#define MAKE_READFUNC(name, cname) \
static inline unsigned int name(SH2 *sh2, unsigned int a) \
{ \
unsigned int ret; \
sh2->sr |= sh2->icount << 12; \
ret = cname(a, sh2); \
sh2->icount = (signed int)sh2->sr >> 12; \
sh2->sr &= 0x3f3; \
return ret; \
}
#define MAKE_WRITEFUNC(name, cname) \
static inline void name(SH2 *sh2, unsigned int a, unsigned int d) \
{ \
sh2->sr |= sh2->icount << 12; \
cname(a, d, sh2); \
sh2->icount = (signed int)sh2->sr >> 12; \
sh2->sr &= 0x3f3; \
}
MAKE_READFUNC(RB, p32x_sh2_read8)
MAKE_READFUNC(RW, p32x_sh2_read16)
MAKE_READFUNC(RL, p32x_sh2_read32)
MAKE_WRITEFUNC(WB, p32x_sh2_write8)
MAKE_WRITEFUNC(WW, p32x_sh2_write16)
MAKE_WRITEFUNC(WL, p32x_sh2_write32)
#else
#define RB(sh2, a) p32x_sh2_read8(a, sh2)
#define RW(sh2, a) p32x_sh2_read16(a, sh2)
#define RL(sh2, a) p32x_sh2_read32(a, sh2)
#define WB(sh2, a, d) p32x_sh2_write8(a, d, sh2)
#define WW(sh2, a, d) p32x_sh2_write16(a, d, sh2)
#define WL(sh2, a, d) p32x_sh2_write32(a, d, sh2)
#endif
// some stuff from sh2comn.h
#define T 0x00000001
#define S 0x00000002
#define I 0x000000f0
#define Q 0x00000100
#define M 0x00000200
#define AM 0xc7ffffff
#define FLAGS (M|Q|I|S|T)
#define Rn ((opcode>>8)&15)
#define Rm ((opcode>>4)&15)
#define sh2_state SH2
extern void lprintf(const char *fmt, ...);
#define logerror lprintf
#ifdef SH2_STATS
static SH2 sh2_stats;
static unsigned int op_refs[0x10000];
# define LRN 1
# define LRM 2
# define LRNM (LRN|LRM)
# define rlog(rnm) { \
int op = opcode; \
if ((rnm) & LRN) { \
op &= ~0x0f00; \
sh2_stats.r[Rn]++; \
} \
if ((rnm) & LRM) { \
op &= ~0x00f0; \
sh2_stats.r[Rm]++; \
} \
op_refs[op]++; \
}
# define rlog1(x) sh2_stats.r[x]++
# define rlog2(x1,x2) sh2_stats.r[x1]++; sh2_stats.r[x2]++
#else
# define rlog(x)
# define rlog1(...)
# define rlog2(...)
#endif
#include "sh2.inc"
#ifndef DRC_CMP
int sh2_execute_interpreter(SH2 *sh2, int cycles)
{
UINT32 opcode;
sh2->icount = cycles;
if (sh2->icount <= 0)
goto out;
do
{
if (sh2->delay)
{
sh2->ppc = sh2->delay;
opcode = RW(sh2, sh2->delay);
sh2->pc -= 2;
}
else
{
sh2->ppc = sh2->pc;
opcode = RW(sh2, sh2->pc);
}
sh2->delay = 0;
sh2->pc += 2;
switch (opcode & ( 15 << 12))
{
case 0<<12: op0000(sh2, opcode); break;
case 1<<12: op0001(sh2, opcode); break;
case 2<<12: op0010(sh2, opcode); break;
case 3<<12: op0011(sh2, opcode); break;
case 4<<12: op0100(sh2, opcode); break;
case 5<<12: op0101(sh2, opcode); break;
case 6<<12: op0110(sh2, opcode); break;
case 7<<12: op0111(sh2, opcode); break;
case 8<<12: op1000(sh2, opcode); break;
case 9<<12: op1001(sh2, opcode); break;
case 10<<12: op1010(sh2, opcode); break;
case 11<<12: op1011(sh2, opcode); break;
case 12<<12: op1100(sh2, opcode); break;
case 13<<12: op1101(sh2, opcode); break;
case 14<<12: op1110(sh2, opcode); break;
default: op1111(sh2, opcode); break;
}
sh2->icount--;
if (sh2->test_irq && !sh2->delay && sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
{
int level = sh2->pending_level;
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
sh2->test_irq = 0;
}
}
while (sh2->icount > 0 || sh2->delay); /* can't interrupt before delay */
out:
return sh2->icount;
}
#else // if DRC_CMP
int sh2_execute_interpreter(SH2 *sh2, int cycles)
{
static unsigned int base_pc_[2] = { 0, 0 };
static unsigned int end_pc_[2] = { 0, 0 };
static unsigned char op_flags_[2][BLOCK_INSN_LIMIT];
unsigned int *base_pc = &base_pc_[sh2->is_slave];
unsigned int *end_pc = &end_pc_[sh2->is_slave];
unsigned char *op_flags = op_flags_[sh2->is_slave];
unsigned int pc_expect;
UINT32 opcode;
sh2->icount = sh2->cycles_timeslice = cycles;
if (sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
{
int level = sh2->pending_level;
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
}
pc_expect = sh2->pc;
if (sh2->icount <= 0)
goto out;
do
{
if (!sh2->delay) {
if (sh2->pc < *base_pc || sh2->pc >= *end_pc) {
*base_pc = sh2->pc;
scan_block(*base_pc, sh2->is_slave,
op_flags, end_pc, NULL);
}
if ((op_flags[(sh2->pc - *base_pc) / 2]
& OF_BTARGET) || sh2->pc == *base_pc
|| pc_expect != sh2->pc) // branched
{
pc_expect = sh2->pc;
if (sh2->icount < 0)
break;
}
do_sh2_trace(sh2, sh2->icount);
}
pc_expect += 2;
if (sh2->delay)
{
sh2->ppc = sh2->delay;
opcode = RW(sh2, sh2->delay);
sh2->pc -= 2;
}
else
{
sh2->ppc = sh2->pc;
opcode = RW(sh2, sh2->pc);
}
sh2->delay = 0;
sh2->pc += 2;
switch (opcode & ( 15 << 12))
{
case 0<<12: op0000(sh2, opcode); break;
case 1<<12: op0001(sh2, opcode); break;
case 2<<12: op0010(sh2, opcode); break;
case 3<<12: op0011(sh2, opcode); break;
case 4<<12: op0100(sh2, opcode); break;
case 5<<12: op0101(sh2, opcode); break;
case 6<<12: op0110(sh2, opcode); break;
case 7<<12: op0111(sh2, opcode); break;
case 8<<12: op1000(sh2, opcode); break;
case 9<<12: op1001(sh2, opcode); break;
case 10<<12: op1010(sh2, opcode); break;
case 11<<12: op1011(sh2, opcode); break;
case 12<<12: op1100(sh2, opcode); break;
case 13<<12: op1101(sh2, opcode); break;
case 14<<12: op1110(sh2, opcode); break;
default: op1111(sh2, opcode); break;
}
sh2->icount--;
if (sh2->test_irq && !sh2->delay && sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
{
int level = sh2->pending_level;
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
sh2->test_irq = 0;
}
}
while (1);
out:
return sh2->icount;
}
#endif // DRC_CMP
#ifdef SH2_STATS
#include <stdio.h>
#include <string.h>
#include "sh2dasm.h"
void sh2_dump_stats(void)
{
static const char *rnames[] = {
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "SP",
"PC", "", "PR", "SR", "GBR", "VBR", "MACH", "MACL"
};
long long total;
char buff[64];
int u, i;
// dump reg usage
total = 0;
for (i = 0; i < 24; i++)
total += sh2_stats.r[i];
for (i = 0; i < 24; i++) {
if (i == 16 || i == 17 || i == 19)
continue;
printf("r %6.3f%% %-4s %9d\n", (double)sh2_stats.r[i] * 100.0 / total,
rnames[i], sh2_stats.r[i]);
}
memset(&sh2_stats, 0, sizeof(sh2_stats));
// dump ops
printf("\n");
total = 0;
for (i = 0; i < 0x10000; i++)
total += op_refs[i];
for (u = 0; u < 16; u++) {
int max = 0, op = 0;
for (i = 0; i < 0x10000; i++) {
if (op_refs[i] > max) {
max = op_refs[i];
op = i;
}
}
DasmSH2(buff, 0, op);
printf("i %6.3f%% %9d %s\n", (double)op_refs[op] * 100.0 / total,
op_refs[op], buff);
op_refs[op] = 0;
}
memset(op_refs, 0, sizeof(op_refs));
}
#endif

View File

@ -0,0 +1,346 @@
/*
* PicoDrive
* (C) notaz, 2009,2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <string.h>
#include <stddef.h>
#include "sh2.h"
#define I 0xf0
int sh2_init(SH2 *sh2, int is_slave, SH2 *other_sh2)
{
int ret = 0;
unsigned int mult_m68k_to_sh2 = sh2->mult_m68k_to_sh2;
unsigned int mult_sh2_to_m68k = sh2->mult_sh2_to_m68k;
memset(sh2, 0, sizeof(*sh2));
sh2->is_slave = is_slave;
sh2->other_sh2 = other_sh2;
sh2->mult_m68k_to_sh2 = mult_m68k_to_sh2;
sh2->mult_sh2_to_m68k = mult_sh2_to_m68k;
return ret;
}
void sh2_finish(SH2 *sh2)
{
#ifdef DRC_SH2
sh2_drc_finish(sh2);
#endif
}
void sh2_reset(SH2 *sh2)
{
sh2->pc = p32x_sh2_read32(0, sh2);
sh2->r[15] = p32x_sh2_read32(4, sh2);
sh2->sr = I;
sh2->vbr = 0;
sh2->pending_int_irq = 0;
}
void sh2_do_irq(SH2 *sh2, int level, int vector)
{
sh2->sr &= 0x3f3;
sh2->r[15] -= 4;
p32x_sh2_write32(sh2->r[15], sh2->sr, sh2); /* push SR onto stack */
sh2->r[15] -= 4;
p32x_sh2_write32(sh2->r[15], sh2->pc, sh2); /* push PC onto stack */
/* set I flags in SR */
sh2->sr = (sh2->sr & ~I) | (level << 4);
/* fetch PC */
sh2->pc = p32x_sh2_read32(sh2->vbr + vector * 4, sh2);
/* 13 cycles at best */
sh2->icount -= 13;
}
int sh2_irl_irq(SH2 *sh2, int level, int nested_call)
{
int taken;
sh2->pending_irl = level;
if (level < sh2->pending_int_irq)
level = sh2->pending_int_irq;
sh2->pending_level = level;
taken = (level > ((sh2->sr >> 4) & 0x0f));
if (taken) {
if (!nested_call) {
// not in memhandler, so handle this now (recompiler friendly)
// do this to avoid missing irqs that other SH2 might clear
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, 13);
}
else
sh2->test_irq = 1;
}
return taken;
}
void sh2_internal_irq(SH2 *sh2, int level, int vector)
{
// FIXME: multiple internal irqs not handled..
// assuming internal irqs never clear until accepted
sh2->pending_int_irq = level;
sh2->pending_int_vector = vector;
if (level > sh2->pending_level)
sh2->pending_level = level;
sh2->test_irq = 1;
}
#define SH2_REG_SIZE (offsetof(SH2, macl) + sizeof(sh2->macl))
void sh2_pack(const SH2 *sh2, unsigned char *buff)
{
unsigned int *p;
memcpy(buff, sh2, SH2_REG_SIZE);
p = (void *)(buff + SH2_REG_SIZE);
p[0] = sh2->pending_int_irq;
p[1] = sh2->pending_int_vector;
}
void sh2_unpack(SH2 *sh2, const unsigned char *buff)
{
unsigned int *p;
memcpy(sh2, buff, SH2_REG_SIZE);
p = (void *)(buff + SH2_REG_SIZE);
sh2->pending_int_irq = p[0];
sh2->pending_int_vector = p[1];
sh2->test_irq = 1;
}
#ifdef DRC_CMP
/* trace/compare */
#include <stdio.h>
#include <stdlib.h>
#include <pico/memory.h>
#undef _USE_CZ80 // HACK
#include <pico/pico_int.h>
#include <pico/debug.h>
static SH2 sh2ref[2];
static unsigned int mem_val;
static unsigned int local_read32(SH2 *sh2, u32 a)
{
const sh2_memmap *sh2_map = sh2->read16_map;
u16 *pd;
uptr p;
sh2_map += (a >> 25);
p = sh2_map->addr;
if (!map_flag_set(p)) {
pd = (u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
return (pd[0] << 16) | pd[1];
}
if ((a & 0xfffff000) == 0xc0000000) {
// data array
pd = (u16 *)sh2->data_array + (a & 0xfff) / 2;
return (pd[0] << 16) | pd[1];
}
if ((a & 0xdfffffc0) == 0x4000) {
pd = &Pico32x.regs[(a & 0x3f) / 2];
return (pd[0] << 16) | pd[1];
}
if ((a & 0xdffffe00) == 0x4200) {
pd = &Pico32xMem->pal[(a & 0x1ff) / 2];
return (pd[0] << 16) | pd[1];
}
return 0;
}
void do_sh2_trace(SH2 *current, int cycles)
{
static int current_slave = -1;
static u32 current_m68k_pc;
SH2 *sh2o = &sh2ref[current->is_slave];
u32 *regs_a = (void *)current;
u32 *regs_o = (void *)sh2o;
unsigned char v;
u32 val;
int i;
if (SekPc != current_m68k_pc) {
current_m68k_pc = SekPc;
tl_write_uint(CTL_M68KPC, current_m68k_pc);
}
if (current->is_slave != current_slave) {
current_slave = current->is_slave;
v = CTL_MASTERSLAVE | current->is_slave;
tl_write(&v, sizeof(v));
}
for (i = 0; i < offsetof(SH2, read8_map) / 4; i++) {
if (i == 17) // ppc
continue;
if (regs_a[i] != regs_o[i]) {
tl_write_uint(CTL_SH2_R + i, regs_a[i]);
regs_o[i] = regs_a[i];
}
}
if (current->ea != sh2o->ea) {
tl_write_uint(CTL_EA, current->ea);
sh2o->ea = current->ea;
}
val = local_read32(current, current->ea);
if (mem_val != val) {
tl_write_uint(CTL_EAVAL, val);
mem_val = val;
}
tl_write_uint(CTL_CYCLES, cycles);
}
static const char *regnames[] = {
"r0", "r1", "r2", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15",
"pc", "ppc", "pr", "sr",
"gbr", "vbr", "mach","macl",
};
static void dump_regs(SH2 *sh2)
{
char csh2;
int i;
csh2 = sh2->is_slave ? 's' : 'm';
for (i = 0; i < 16/2; i++)
printf("%csh2 r%d: %08x r%02d: %08x\n", csh2,
i, sh2->r[i], i+8, sh2->r[i+8]);
printf("%csh2 PC: %08x , %08x\n", csh2, sh2->pc, sh2->ppc);
printf("%csh2 SR: %03x PR: %08x\n", csh2, sh2->sr, sh2->pr);
}
void do_sh2_cmp(SH2 *current)
{
static int current_slave;
static u32 current_val;
SH2 *sh2o = &sh2ref[current->is_slave];
u32 *regs_a = (void *)current;
u32 *regs_o = (void *)sh2o;
unsigned char code;
int cycles_o = 666;
u32 sr, val;
int bad = 0;
int cycles;
int i, ret;
sh2ref[1].is_slave = 1;
while (1) {
ret = tl_read(&code, 1);
if (ret <= 0)
break;
if (code == CTL_CYCLES) {
tl_read(&cycles_o, 4);
break;
}
switch (code) {
case CTL_MASTERSLAVE:
case CTL_MASTERSLAVE + 1:
current_slave = code & 1;
break;
case CTL_EA:
tl_read_uint(&sh2o->ea);
break;
case CTL_EAVAL:
tl_read_uint(&current_val);
break;
case CTL_M68KPC:
tl_read_uint(&val);
if (SekPc != val) {
printf("m68k: %08x %08x\n", SekPc, val);
bad = 1;
}
break;
default:
if (CTL_SH2_R <= code && code < CTL_SH2_R +
offsetof(SH2, read8_map) / 4)
{
tl_read_uint(regs_o + code - CTL_SH2_R);
}
else
{
printf("wrong code: %02x\n", code);
goto end;
}
break;
}
}
if (ret <= 0) {
printf("EOF?\n");
goto end;
}
if (current->is_slave != current_slave) {
printf("bad slave: %d %d\n", current->is_slave,
current_slave);
bad = 1;
}
for (i = 0; i < offsetof(SH2, read8_map) / 4; i++) {
if (i == 17 || i == 19) // ppc, sr
continue;
if (regs_a[i] != regs_o[i]) {
printf("bad %4s: %08x %08x\n",
regnames[i], regs_a[i], regs_o[i]);
bad = 1;
}
}
sr = current->sr & 0x3f3;
cycles = (signed int)current->sr >> 12;
if (sr != sh2o->sr) {
printf("bad SR: %03x %03x\n", sr, sh2o->sr);
bad = 1;
}
if (cycles != cycles_o) {
printf("bad cycles: %d %d\n", cycles, cycles_o);
bad = 1;
}
val = local_read32(current, sh2o->ea);
if (val != current_val) {
printf("bad val @%08x: %08x %08x\n", sh2o->ea, val, current_val);
bad = 1;
}
if (!bad) {
sh2o->ppc = current->pc;
return;
}
end:
printf("--\n");
dump_regs(sh2o);
if (current->is_slave != current_slave)
dump_regs(&sh2ref[current->is_slave ^ 1]);
PDebugDumpMem();
exit(1);
}
#endif // DRC_CMP

View File

@ -0,0 +1,119 @@
#ifndef __SH2_H__
#define __SH2_H__
#if !defined(REGPARM) && defined(__i386__)
#define REGPARM(x) __attribute__((regparm(x)))
#else
#define REGPARM(x)
#endif
// registers - matches structure order
typedef enum {
SHR_R0 = 0, SHR_SP = 15,
SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
} sh2_reg_e;
typedef struct SH2_
{
unsigned int r[16]; // 00
unsigned int pc; // 40
unsigned int ppc;
unsigned int pr;
unsigned int sr;
unsigned int gbr, vbr; // 50
unsigned int mach, macl; // 58
// common
const void *read8_map; // 60
const void *read16_map;
const void **write8_tab;
const void **write16_tab;
#define SH2_STATE_RUN (1 << 0) // to prevent recursion
#define SH2_STATE_SLEEP (1 << 1)
#define SH2_STATE_CPOLL (1 << 2) // polling comm regs
#define SH2_STATE_VPOLL (1 << 3) // polling VDP
unsigned int state;
unsigned int poll_addr;
int poll_cycles;
int poll_cnt;
// interpreter stuff
int icount; // cycles left in current timeslice
unsigned int ea;
unsigned int delay;
unsigned int test_irq;
int pending_level; // MAX(pending_irl, pending_int_irq)
int pending_irl;
int pending_int_irq; // internal irq
int pending_int_vector;
int REGPARM(2) (*irq_callback)(struct SH2_ *sh2, int level);
int is_slave;
unsigned int cycles_timeslice;
struct SH2_ *other_sh2;
// we use 68k reference cycles for easier sync
unsigned int m68krcycles_done;
unsigned int mult_m68k_to_sh2;
unsigned int mult_sh2_to_m68k;
unsigned char data_array[0x1000]; // cache (can be used as RAM)
unsigned int peri_regs[0x200/4]; // periphereal regs
} SH2;
#define CYCLE_MULT_SHIFT 10
#define C_M68K_TO_SH2(xsh2, c) \
((int)((c) * (xsh2).mult_m68k_to_sh2) >> CYCLE_MULT_SHIFT)
#define C_SH2_TO_M68K(xsh2, c) \
((int)((c + 3) * (xsh2).mult_sh2_to_m68k) >> CYCLE_MULT_SHIFT)
int sh2_init(SH2 *sh2, int is_slave, SH2 *other_sh2);
void sh2_finish(SH2 *sh2);
void sh2_reset(SH2 *sh2);
int sh2_irl_irq(SH2 *sh2, int level, int nested_call);
void sh2_internal_irq(SH2 *sh2, int level, int vector);
void sh2_do_irq(SH2 *sh2, int level, int vector);
void sh2_pack(const SH2 *sh2, unsigned char *buff);
void sh2_unpack(SH2 *sh2, const unsigned char *buff);
int sh2_execute_drc(SH2 *sh2c, int cycles);
int sh2_execute_interpreter(SH2 *sh2c, int cycles);
static inline int sh2_execute(SH2 *sh2, int cycles, int use_drc)
{
int ret;
sh2->cycles_timeslice = cycles;
#ifdef DRC_SH2
if (use_drc)
ret = sh2_execute_drc(sh2, cycles);
else
#endif
ret = sh2_execute_interpreter(sh2, cycles);
return sh2->cycles_timeslice - ret;
}
// regs, pending_int*, cycles, reserved
#define SH2_STATE_SIZE ((24 + 2 + 2 + 12) * 4)
// pico memhandlers
// XXX: move somewhere else
unsigned int REGPARM(2) p32x_sh2_read8(unsigned int a, SH2 *sh2);
unsigned int REGPARM(2) p32x_sh2_read16(unsigned int a, SH2 *sh2);
unsigned int REGPARM(2) p32x_sh2_read32(unsigned int a, SH2 *sh2);
void REGPARM(3) p32x_sh2_write8 (unsigned int a, unsigned int d, SH2 *sh2);
void REGPARM(3) p32x_sh2_write16(unsigned int a, unsigned int d, SH2 *sh2);
void REGPARM(3) p32x_sh2_write32(unsigned int a, unsigned int d, SH2 *sh2);
// debug
#ifdef DRC_CMP
void do_sh2_trace(SH2 *current, int cycles);
void do_sh2_cmp(SH2 *current);
#endif
#endif /* __SH2_H__ */

View File

@ -0,0 +1,562 @@
/*
* PicoDrive
* (C) notaz, 2009,2010,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "../sound/ym2612.h"
struct Pico32x Pico32x;
SH2 sh2s[2];
#define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_SLEEP)
static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
{
if (sh2->pending_irl > sh2->pending_int_irq) {
elprintf_sh2(sh2, EL_32X, "ack/irl %d @ %08x",
level, sh2_pc(sh2));
return 64 + sh2->pending_irl / 2;
} else {
elprintf_sh2(sh2, EL_32X, "ack/int %d/%d @ %08x",
level, sh2->pending_int_vector, sh2_pc(sh2));
sh2->pending_int_irq = 0; // auto-clear
sh2->pending_level = sh2->pending_irl;
return sh2->pending_int_vector;
}
}
// MUST specify active_sh2 when called from sh2 memhandlers
void p32x_update_irls(SH2 *active_sh2, int m68k_cycles)
{
int irqs, mlvl = 0, slvl = 0;
int mrun, srun;
if (active_sh2 != NULL)
m68k_cycles = sh2_cycles_done_m68k(active_sh2);
// msh2
irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[0];
while ((irqs >>= 1))
mlvl++;
mlvl *= 2;
// ssh2
irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[1];
while ((irqs >>= 1))
slvl++;
slvl *= 2;
mrun = sh2_irl_irq(&msh2, mlvl, active_sh2 == &msh2);
if (mrun) {
p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, m68k_cycles);
if (active_sh2 == &msh2)
sh2_end_run(active_sh2, 1);
}
srun = sh2_irl_irq(&ssh2, slvl, active_sh2 == &ssh2);
if (srun) {
p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, m68k_cycles);
if (active_sh2 == &ssh2)
sh2_end_run(active_sh2, 1);
}
elprintf(EL_32X, "update_irls: m %d/%d, s %d/%d", mlvl, mrun, slvl, srun);
}
// the mask register is inconsistent, CMD is supposed to be a mask,
// while others are actually irq trigger enables?
// TODO: test on hw..
void p32x_trigger_irq(SH2 *sh2, int m68k_cycles, unsigned int mask)
{
Pico32x.sh2irqs |= mask & P32XI_VRES;
Pico32x.sh2irqi[0] |= mask & (Pico32x.sh2irq_mask[0] << 3);
Pico32x.sh2irqi[1] |= mask & (Pico32x.sh2irq_mask[1] << 3);
p32x_update_irls(sh2, m68k_cycles);
}
void p32x_update_cmd_irq(SH2 *sh2, int m68k_cycles)
{
if ((Pico32x.sh2irq_mask[0] & 2) && (Pico32x.regs[2 / 2] & 1))
Pico32x.sh2irqi[0] |= P32XI_CMD;
else
Pico32x.sh2irqi[0] &= ~P32XI_CMD;
if ((Pico32x.sh2irq_mask[1] & 2) && (Pico32x.regs[2 / 2] & 2))
Pico32x.sh2irqi[1] |= P32XI_CMD;
else
Pico32x.sh2irqi[1] &= ~P32XI_CMD;
p32x_update_irls(sh2, m68k_cycles);
}
void Pico32xStartup(void)
{
elprintf(EL_STATUS|EL_32X, "32X startup");
// TODO: OOM handling
PicoAHW |= PAHW_32X;
sh2_init(&msh2, 0, &ssh2);
msh2.irq_callback = sh2_irq_cb;
sh2_init(&ssh2, 1, &msh2);
ssh2.irq_callback = sh2_irq_cb;
PicoMemSetup32x();
p32x_pwm_ctl_changed();
p32x_timers_recalc();
Pico32x.sh2_regs[0] = P32XS2_ADEN;
if (Pico.m.ncart_in)
Pico32x.sh2_regs[0] |= P32XS_nCART;
if (!Pico.m.pal)
Pico32x.vdp_regs[0] |= P32XV_nPAL;
rendstatus_old = -1;
emu_32x_startup();
}
#define HWSWAP(x) (((x) << 16) | ((x) >> 16))
void p32x_reset_sh2s(void)
{
elprintf(EL_32X, "sh2 reset");
sh2_reset(&msh2);
sh2_reset(&ssh2);
sh2_peripheral_reset(&msh2);
sh2_peripheral_reset(&ssh2);
// if we don't have BIOS set, perform it's work here.
// MSH2
if (p32x_bios_m == NULL) {
unsigned int idl_src, idl_dst, idl_size; // initial data load
unsigned int vbr;
// initial data
idl_src = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000;
idl_dst = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000;
idl_size= HWSWAP(*(unsigned int *)(Pico.rom + 0x3dc));
if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize ||
idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) {
elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x",
idl_src, idl_dst, idl_size);
}
else
memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size);
// GBR/VBR
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3e8));
sh2_set_gbr(0, 0x20004000);
sh2_set_vbr(0, vbr);
// checksum and M_OK
Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e);
// program will set M_OK
}
// SSH2
if (p32x_bios_s == NULL) {
unsigned int vbr;
// GBR/VBR
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3ec));
sh2_set_gbr(1, 0x20004000);
sh2_set_vbr(1, vbr);
// program will set S_OK
}
msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDone();
}
void Pico32xInit(void)
{
if (msh2.mult_m68k_to_sh2 == 0 || msh2.mult_sh2_to_m68k == 0)
Pico32xSetClocks(PICO_MSH2_HZ, 0);
if (ssh2.mult_m68k_to_sh2 == 0 || ssh2.mult_sh2_to_m68k == 0)
Pico32xSetClocks(0, PICO_MSH2_HZ);
}
void PicoPower32x(void)
{
memset(&Pico32x, 0, sizeof(Pico32x));
Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified
Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_PEN;
}
void PicoReset32x(void)
{
if (PicoAHW & PAHW_32X) {
p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VRES);
p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, 0);
p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, 0);
p32x_pwm_ctl_changed();
p32x_timers_recalc();
}
}
static void p32x_start_blank(void)
{
if (Pico32xDrawMode != PDM32X_OFF && !PicoSkipFrame) {
int offs, lines;
pprof_start(draw);
offs = 8; lines = 224;
if ((Pico.video.reg[1] & 8) && !(PicoOpt & POPT_ALT_RENDERER)) {
offs = 0;
lines = 240;
}
// XXX: no proper handling of 32col mode..
if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0 && // 32x not blanking
(Pico.video.reg[12] & 1) && // 40col mode
(PicoDrawMask & PDRAW_32X_ON))
{
int md_bg = Pico.video.reg[7] & 0x3f;
// we draw full layer (not line-by-line)
PicoDraw32xLayer(offs, lines, md_bg);
}
else if (Pico32xDrawMode != PDM32X_32X_ONLY)
PicoDraw32xLayerMdOnly(offs, lines);
pprof_end(draw);
}
// enter vblank
Pico32x.vdp_regs[0x0a/2] |= P32XV_VBLK|P32XV_PEN;
// FB swap waits until vblank
if ((Pico32x.vdp_regs[0x0a/2] ^ Pico32x.pending_fb) & P32XV_FS) {
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_FS;
Pico32x.vdp_regs[0x0a/2] |= Pico32x.pending_fb;
Pico32xSwapDRAM(Pico32x.pending_fb ^ 1);
}
p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VINT);
p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0);
p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0);
}
void p32x_schedule_hint(SH2 *sh2, int m68k_cycles)
{
// rather rough, 32x hint is useless in practice
int after;
if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 4))
return; // nobody cares
// note: when Pico.m.scanline is 224, SH2s might
// still be at scanline 93 (or so)
if (!(Pico32x.sh2_regs[0] & 0x80) && Pico.m.scanline > 224)
return;
after = (Pico32x.sh2_regs[4 / 2] + 1) * 488;
if (sh2 != NULL)
p32x_event_schedule_sh2(sh2, P32X_EVENT_HINT, after);
else
p32x_event_schedule(m68k_cycles, P32X_EVENT_HINT, after);
}
/* events */
static void fillend_event(unsigned int now)
{
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_nFEN;
p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, now);
p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, now);
}
static void hint_event(unsigned int now)
{
p32x_trigger_irq(NULL, now, P32XI_HINT);
p32x_schedule_hint(NULL, now);
}
typedef void (event_cb)(unsigned int now);
/* times are in m68k (7.6MHz) cycles */
unsigned int p32x_event_times[P32X_EVENT_COUNT];
static unsigned int event_time_next;
static event_cb *p32x_event_cbs[P32X_EVENT_COUNT] = {
[P32X_EVENT_PWM] = p32x_pwm_irq_event,
[P32X_EVENT_FILLEND] = fillend_event,
[P32X_EVENT_HINT] = hint_event,
};
// schedule event at some time 'after', in m68k clocks
void p32x_event_schedule(unsigned int now, enum p32x_event event, int after)
{
unsigned int when;
when = (now + after) | 1;
elprintf(EL_32X, "32x: new event #%u %u->%u", event, now, when);
p32x_event_times[event] = when;
if (event_time_next == 0 || CYCLES_GT(event_time_next, when))
event_time_next = when;
}
void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after)
{
unsigned int now = sh2_cycles_done_m68k(sh2);
int left_to_next;
p32x_event_schedule(now, event, after);
left_to_next = (event_time_next - now) * 3;
sh2_end_run(sh2, left_to_next);
}
static void p32x_run_events(unsigned int until)
{
int oldest, oldest_diff, time;
int i, diff;
while (1) {
oldest = -1, oldest_diff = 0x7fffffff;
for (i = 0; i < P32X_EVENT_COUNT; i++) {
if (p32x_event_times[i]) {
diff = p32x_event_times[i] - until;
if (diff < oldest_diff) {
oldest_diff = diff;
oldest = i;
}
}
}
if (oldest_diff <= 0) {
time = p32x_event_times[oldest];
p32x_event_times[oldest] = 0;
elprintf(EL_32X, "32x: run event #%d %u", oldest, time);
p32x_event_cbs[oldest](time);
}
else if (oldest_diff < 0x7fffffff) {
event_time_next = p32x_event_times[oldest];
break;
}
else {
event_time_next = 0;
break;
}
}
if (oldest != -1)
elprintf(EL_32X, "32x: next event #%d at %u",
oldest, event_time_next);
}
static inline void run_sh2(SH2 *sh2, int m68k_cycles)
{
int cycles, done;
pevt_log_sh2_o(sh2, EVT_RUN_START);
sh2->state |= SH2_STATE_RUN;
cycles = C_M68K_TO_SH2(*sh2, m68k_cycles);
elprintf_sh2(sh2, EL_32X, "+run %u %d @%08x",
sh2->m68krcycles_done, cycles, sh2->pc);
done = sh2_execute(sh2, cycles, PicoOpt & POPT_EN_DRC);
sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, done);
sh2->state &= ~SH2_STATE_RUN;
pevt_log_sh2_o(sh2, EVT_RUN_END);
elprintf_sh2(sh2, EL_32X, "-run %u %d",
sh2->m68krcycles_done, done);
}
// sync other sh2 to this one
// note: recursive call
void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
{
SH2 *osh2 = sh2->other_sh2;
int left_to_event;
int m68k_cycles;
if (osh2->state & SH2_STATE_RUN)
return;
m68k_cycles = m68k_target - osh2->m68krcycles_done;
if (m68k_cycles < 200)
return;
if (osh2->state & SH2_IDLE_STATES) {
osh2->m68krcycles_done = m68k_target;
return;
}
elprintf_sh2(osh2, EL_32X, "sync to %u %d",
m68k_target, m68k_cycles);
run_sh2(osh2, m68k_cycles);
// there might be new event to schedule current sh2 to
if (event_time_next) {
left_to_event = event_time_next - m68k_target;
left_to_event *= 3;
if (sh2_cycles_left(sh2) > left_to_event) {
if (left_to_event < 1)
left_to_event = 1;
sh2_end_run(sh2, left_to_event);
}
}
}
#define sync_sh2s_normal p32x_sync_sh2s
//#define sync_sh2s_lockstep p32x_sync_sh2s
/* most timing is in 68k clock */
void sync_sh2s_normal(unsigned int m68k_target)
{
unsigned int now, target, timer_cycles;
int cycles;
elprintf(EL_32X, "sh2 sync to %u", m68k_target);
if (!(Pico32x.regs[0] & P32XS_nRES)) {
msh2.m68krcycles_done = ssh2.m68krcycles_done = m68k_target;
return; // rare
}
now = msh2.m68krcycles_done;
if (CYCLES_GT(now, ssh2.m68krcycles_done))
now = ssh2.m68krcycles_done;
timer_cycles = now;
while (CYCLES_GT(m68k_target, now))
{
if (event_time_next && CYCLES_GE(now, event_time_next))
p32x_run_events(now);
target = m68k_target;
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
while (CYCLES_GT(target, now))
{
elprintf(EL_32X, "sh2 exec to %u %d,%d/%d, flags %x", target,
target - msh2.m68krcycles_done, target - ssh2.m68krcycles_done,
m68k_target - now, Pico32x.emu_flags);
if (!(ssh2.state & SH2_IDLE_STATES)) {
cycles = target - ssh2.m68krcycles_done;
if (cycles > 0) {
run_sh2(&ssh2, cycles);
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
}
}
if (!(msh2.state & SH2_IDLE_STATES)) {
cycles = target - msh2.m68krcycles_done;
if (cycles > 0) {
run_sh2(&msh2, cycles);
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
}
}
now = target;
if (!(msh2.state & SH2_IDLE_STATES)) {
if (CYCLES_GT(now, msh2.m68krcycles_done))
now = msh2.m68krcycles_done;
}
if (!(ssh2.state & SH2_IDLE_STATES)) {
if (CYCLES_GT(now, ssh2.m68krcycles_done))
now = ssh2.m68krcycles_done;
}
}
p32x_timers_do(now - timer_cycles);
timer_cycles = now;
}
// advance idle CPUs
if (msh2.state & SH2_IDLE_STATES) {
if (CYCLES_GT(m68k_target, msh2.m68krcycles_done))
msh2.m68krcycles_done = m68k_target;
}
if (ssh2.state & SH2_IDLE_STATES) {
if (CYCLES_GT(m68k_target, ssh2.m68krcycles_done))
ssh2.m68krcycles_done = m68k_target;
}
}
#define STEP_68K 24
void sync_sh2s_lockstep(unsigned int m68k_target)
{
unsigned int mcycles;
mcycles = msh2.m68krcycles_done;
if (ssh2.m68krcycles_done < mcycles)
mcycles = ssh2.m68krcycles_done;
while (mcycles < m68k_target) {
mcycles += STEP_68K;
sync_sh2s_normal(mcycles);
}
}
#define CPUS_RUN(m68k_cycles) do { \
if (PicoAHW & PAHW_MCD) \
pcd_run_cpus(m68k_cycles); \
else \
SekRunM68k(m68k_cycles); \
\
if ((Pico32x.emu_flags & P32XF_Z80_32X_IO) && Pico.m.z80Run \
&& !Pico.m.z80_reset && (PicoOpt & POPT_EN_Z80)) \
PicoSyncZ80(SekCyclesDone()); \
if (Pico32x.emu_flags & (P32XF_68KCPOLL|P32XF_68KVPOLL)) \
p32x_sync_sh2s(SekCyclesDone()); \
} while (0)
#define PICO_32X
#define PICO_CD
#include "../pico_cmn.inc"
void PicoFrame32x(void)
{
Pico.m.scanline = 0;
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_VBLK; // get out of vblank
if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access
if (!(Pico32x.sh2_regs[0] & 0x80))
p32x_schedule_hint(NULL, SekCyclesDone());
p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0);
p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0);
if (PicoAHW & PAHW_MCD)
pcd_prepare_frame();
PicoFrameStart();
PicoFrameHints();
elprintf(EL_32X, "poll: %02x %02x %02x",
Pico32x.emu_flags & 3, msh2.state, ssh2.state);
}
// calculate multipliers against 68k clock (7670442)
// normally * 3, but effectively slower due to high latencies everywhere
// however using something lower breaks MK2 animations
void Pico32xSetClocks(int msh2_hz, int ssh2_hz)
{
float m68k_clk = (float)(OSC_NTSC / 7);
if (msh2_hz > 0) {
msh2.mult_m68k_to_sh2 = (int)((float)msh2_hz * (1 << CYCLE_MULT_SHIFT) / m68k_clk);
msh2.mult_sh2_to_m68k = (int)(m68k_clk * (1 << CYCLE_MULT_SHIFT) / (float)msh2_hz);
}
if (ssh2_hz > 0) {
ssh2.mult_m68k_to_sh2 = (int)((float)ssh2_hz * (1 << CYCLE_MULT_SHIFT) / m68k_clk);
ssh2.mult_sh2_to_m68k = (int)(m68k_clk * (1 << CYCLE_MULT_SHIFT) / (float)ssh2_hz);
}
}

View File

@ -0,0 +1,329 @@
/*
* PicoDrive
* (C) notaz, 2009,2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
int (*PicoScan32xBegin)(unsigned int num);
int (*PicoScan32xEnd)(unsigned int num);
int Pico32xDrawMode;
static void convert_pal555(int invert_prio)
{
unsigned int *ps = (void *)Pico32xMem->pal;
unsigned int *pd = (void *)Pico32xMem->pal_native;
unsigned int m1 = 0x001f001f;
unsigned int m2 = 0x03e003e0;
unsigned int m3 = 0xfc00fc00;
unsigned int inv = 0;
int i;
if (invert_prio)
inv = 0x00200020;
// place prio to LS green bit
for (i = 0x100/2; i > 0; i--, ps++, pd++) {
unsigned int t = *ps;
*pd = (((t & m1) << 11) | ((t & m2) << 1) | ((t & m3) >> 10)) ^ inv;
}
Pico32x.dirty_pal = 0;
}
// direct color mode
#define do_line_dc(pd, p32x, pmd, inv, pmd_draw_code) \
{ \
const unsigned int m1 = 0x001f; \
const unsigned int m2 = 0x03e0; \
const unsigned int m3 = 0x7c00; \
int i; \
\
for (i = 320; i > 0; i--, pd++, p32x++, pmd++) { \
unsigned short t = *p32x; \
if ((*pmd & 0x3f) != mdbg && !((t ^ inv) & 0x8000)) { \
pmd_draw_code; \
continue; \
} \
\
*pd = ((t & m1) << 11) | ((t & m2) << 1) | ((t & m3) >> 10); \
} \
}
// packed pixel mode
#define do_line_pp(pd, p32x, pmd, pmd_draw_code) \
{ \
unsigned short t; \
int i; \
for (i = 320; i > 0; i--, pd++, p32x++, pmd++) { \
t = pal[*(unsigned char *)((long)p32x ^ 1)]; \
if ((t & 0x20) || (*pmd & 0x3f) == mdbg) \
*pd = t; \
else \
pmd_draw_code; \
} \
}
// run length mode
#define do_line_rl(pd, p32x, pmd, pmd_draw_code) \
{ \
unsigned short len, t; \
int i; \
for (i = 320; i > 0; p32x++) { \
t = pal[*p32x & 0xff]; \
for (len = (*p32x >> 8) + 1; len > 0 && i > 0; len--, i--, pd++, pmd++) { \
if ((*pmd & 0x3f) == mdbg || (t & 0x20)) \
*pd = t; \
else \
pmd_draw_code; \
} \
} \
}
// this is almost never used (Wiz and menu bg gen only)
void FinalizeLine32xRGB555(int sh, int line)
{
unsigned short *pd = DrawLineDest;
unsigned short *pal = Pico32xMem->pal_native;
unsigned char *pmd = HighCol + 8;
unsigned short *dram, *p32x;
unsigned char mdbg;
FinalizeLine555(sh, line);
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 0 || // 32x blanking
// XXX: how is 32col mode hadled by real hardware?
!(Pico.video.reg[12] & 1) || // 32col mode
!(PicoDrawMask & PDRAW_32X_ON))
{
return;
}
dram = (void *)Pico32xMem->dram[Pico32x.vdp_regs[0x0a/2] & P32XV_FS];
p32x = dram + dram[line];
mdbg = Pico.video.reg[7] & 0x3f;
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 2) { // Direct Color Mode
int inv_bit = (Pico32x.vdp_regs[0] & P32XV_PRI) ? 0x8000 : 0;
do_line_dc(pd, p32x, pmd, inv_bit,);
return;
}
if (Pico32x.dirty_pal)
convert_pal555(Pico32x.vdp_regs[0] & P32XV_PRI);
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 1) { // Packed Pixel Mode
unsigned char *p32xb = (void *)p32x;
if (Pico32x.vdp_regs[2 / 2] & P32XV_SFT)
p32xb++;
do_line_pp(pd, p32xb, pmd,);
}
else { // Run Length Mode
do_line_rl(pd, p32x, pmd,);
}
}
#define MD_LAYER_CODE \
*dst = palmd[*pmd]
#define PICOSCAN_PRE \
PicoScan32xBegin(l + (lines_sft_offs & 0xff)); \
dst = DrawLineDest; \
#define PICOSCAN_POST \
PicoScan32xEnd(l + (lines_sft_offs & 0xff)); \
#define make_do_loop(name, pre_code, post_code, md_code) \
/* Direct Color Mode */ \
static void do_loop_dc##name(unsigned short *dst, \
unsigned short *dram, int lines_sft_offs, int mdbg) \
{ \
int inv_bit = (Pico32x.vdp_regs[0] & P32XV_PRI) ? 0x8000 : 0; \
unsigned char *pmd = PicoDraw2FB + \
328 * (lines_sft_offs & 0xff) + 8; \
unsigned short *palmd = HighPal; \
unsigned short *p32x; \
int lines = lines_sft_offs >> 16; \
int l; \
(void)palmd; \
for (l = 0; l < lines; l++, pmd += 8) { \
pre_code; \
p32x = dram + dram[l]; \
do_line_dc(dst, p32x, pmd, inv_bit, md_code); \
post_code; \
} \
} \
\
/* Packed Pixel Mode */ \
static void do_loop_pp##name(unsigned short *dst, \
unsigned short *dram, int lines_sft_offs, int mdbg) \
{ \
unsigned short *pal = Pico32xMem->pal_native; \
unsigned char *pmd = PicoDraw2FB + \
328 * (lines_sft_offs & 0xff) + 8; \
unsigned short *palmd = HighPal; \
unsigned char *p32x; \
int lines = lines_sft_offs >> 16; \
int l; \
(void)palmd; \
for (l = 0; l < lines; l++, pmd += 8) { \
pre_code; \
p32x = (void *)(dram + dram[l]); \
p32x += (lines_sft_offs >> 8) & 1; \
do_line_pp(dst, p32x, pmd, md_code); \
post_code; \
} \
} \
\
/* Run Length Mode */ \
static void do_loop_rl##name(unsigned short *dst, \
unsigned short *dram, int lines_sft_offs, int mdbg) \
{ \
unsigned short *pal = Pico32xMem->pal_native; \
unsigned char *pmd = PicoDraw2FB + \
328 * (lines_sft_offs & 0xff) + 8; \
unsigned short *palmd = HighPal; \
unsigned short *p32x; \
int lines = lines_sft_offs >> 16; \
int l; \
(void)palmd; \
for (l = 0; l < lines; l++, pmd += 8) { \
pre_code; \
p32x = dram + dram[l]; \
do_line_rl(dst, p32x, pmd, md_code); \
post_code; \
} \
}
#ifdef _ASM_32X_DRAW
#undef make_do_loop
#define make_do_loop(name, pre_code, post_code, md_code) \
extern void do_loop_dc##name(unsigned short *dst, \
unsigned short *dram, int lines_offs, int mdbg); \
extern void do_loop_pp##name(unsigned short *dst, \
unsigned short *dram, int lines_offs, int mdbg); \
extern void do_loop_rl##name(unsigned short *dst, \
unsigned short *dram, int lines_offs, int mdbg);
#endif
make_do_loop(,,,)
make_do_loop(_md, , , MD_LAYER_CODE)
make_do_loop(_scan, PICOSCAN_PRE, PICOSCAN_POST, )
make_do_loop(_scan_md, PICOSCAN_PRE, PICOSCAN_POST, MD_LAYER_CODE)
typedef void (*do_loop_func)(unsigned short *dst, unsigned short *dram, int lines, int mdbg);
enum { DO_LOOP, DO_LOOP_MD, DO_LOOP_SCAN, DO_LOOP_MD_SCAN };
static const do_loop_func do_loop_dc_f[] = { do_loop_dc, do_loop_dc_md, do_loop_dc_scan, do_loop_dc_scan_md };
static const do_loop_func do_loop_pp_f[] = { do_loop_pp, do_loop_pp_md, do_loop_pp_scan, do_loop_pp_scan_md };
static const do_loop_func do_loop_rl_f[] = { do_loop_rl, do_loop_rl_md, do_loop_rl_scan, do_loop_rl_scan_md };
void PicoDraw32xLayer(int offs, int lines, int md_bg)
{
int have_scan = PicoScan32xBegin != NULL && PicoScan32xEnd != NULL;
const do_loop_func *do_loop;
unsigned short *dram;
int lines_sft_offs;
int which_func;
DrawLineDest = (char *)DrawLineDestBase + offs * DrawLineDestIncrement;
dram = Pico32xMem->dram[Pico32x.vdp_regs[0x0a/2] & P32XV_FS];
if (Pico32xDrawMode == PDM32X_BOTH) {
if (Pico.m.dirtyPal)
PicoDrawUpdateHighPal();
}
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 2)
{
// Direct Color Mode
do_loop = do_loop_dc_f;
goto do_it;
}
if (Pico32x.dirty_pal)
convert_pal555(Pico32x.vdp_regs[0] & P32XV_PRI);
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 1)
{
// Packed Pixel Mode
do_loop = do_loop_pp_f;
}
else
{
// Run Length Mode
do_loop = do_loop_rl_f;
}
do_it:
if (Pico32xDrawMode == PDM32X_BOTH)
which_func = have_scan ? DO_LOOP_MD_SCAN : DO_LOOP_MD;
else
which_func = have_scan ? DO_LOOP_SCAN : DO_LOOP;
lines_sft_offs = (lines << 16) | offs;
if (Pico32x.vdp_regs[2 / 2] & P32XV_SFT)
lines_sft_offs |= 1 << 8;
do_loop[which_func](DrawLineDest, dram, lines_sft_offs, md_bg);
}
// mostly unused, games tend to keep 32X layer on
void PicoDraw32xLayerMdOnly(int offs, int lines)
{
int have_scan = PicoScan32xBegin != NULL && PicoScan32xEnd != NULL;
unsigned short *dst = (void *)((char *)DrawLineDestBase + offs * DrawLineDestIncrement);
unsigned char *pmd = PicoDraw2FB + 328 * offs + 8;
unsigned short *pal = HighPal;
int poffs = 0, plen = 320;
int l, p;
if (!(Pico.video.reg[12] & 1)) {
// 32col mode
poffs = 32;
plen = 256;
}
if (Pico.m.dirtyPal)
PicoDrawUpdateHighPal();
dst += poffs;
for (l = 0; l < lines; l++) {
if (have_scan) {
PicoScan32xBegin(l + offs);
dst = DrawLineDest + poffs;
}
for (p = 0; p < plen; p += 4) {
dst[p + 0] = pal[*pmd++];
dst[p + 1] = pal[*pmd++];
dst[p + 2] = pal[*pmd++];
dst[p + 3] = pal[*pmd++];
}
dst = (void *)((char *)dst + DrawLineDestIncrement);
pmd += 328 - plen;
if (have_scan)
PicoScan32xEnd(l + offs);
}
}
void PicoDrawSetOutFormat32x(pdso_t which, int use_32x_line_mode)
{
#ifdef _ASM_32X_DRAW
extern void *Pico32xNativePal;
Pico32xNativePal = Pico32xMem->pal_native;
#endif
if (which == PDF_RGB555 && use_32x_line_mode) {
// we'll draw via FinalizeLine32xRGB555 (rare)
PicoDrawSetInternalBuf(NULL, 0);
Pico32xDrawMode = PDM32X_OFF;
return;
}
// use the same layout as alt renderer
PicoDrawSetInternalBuf(PicoDraw2FB, 328);
Pico32xDrawMode = (which == PDF_RGB555) ? PDM32X_32X_ONLY : PDM32X_BOTH;
}
// vim:shiftwidth=2:ts=2:expandtab

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,337 @@
/*
* PicoDrive
* (C) notaz, 2009,2010,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
static int pwm_cycles;
static int pwm_mult;
static int pwm_ptr;
static int pwm_irq_reload;
static int pwm_doing_fifo;
static int pwm_silent;
void p32x_pwm_ctl_changed(void)
{
int control = Pico32x.regs[0x30 / 2];
int cycles = Pico32x.regs[0x32 / 2];
cycles = (cycles - 1) & 0x0fff;
pwm_cycles = cycles;
// supposedly we should stop FIFO when xMd is 0,
// but mars test disagrees
pwm_mult = 0;
if ((control & 0x0f) != 0)
pwm_mult = 0x10000 / cycles;
pwm_irq_reload = (control & 0x0f00) >> 8;
pwm_irq_reload = ((pwm_irq_reload - 1) & 0x0f) + 1;
if (Pico32x.pwm_irq_cnt == 0)
Pico32x.pwm_irq_cnt = pwm_irq_reload;
}
static void do_pwm_irq(SH2 *sh2, unsigned int m68k_cycles)
{
p32x_trigger_irq(sh2, m68k_cycles, P32XI_PWM);
if (Pico32x.regs[0x30 / 2] & P32XP_RTP) {
p32x_event_schedule(m68k_cycles, P32X_EVENT_PWM, pwm_cycles / 3 + 1);
// note: might recurse
p32x_dreq1_trigger();
}
}
static int convert_sample(unsigned int v)
{
if (v == 0)
return 0;
if (v > pwm_cycles)
v = pwm_cycles;
return ((int)v - pwm_cycles / 2) * pwm_mult;
}
#define consume_fifo(sh2, m68k_cycles) { \
int cycles_diff = ((m68k_cycles) * 3) - Pico32x.pwm_cycle_p; \
if (cycles_diff >= pwm_cycles) \
consume_fifo_do(sh2, m68k_cycles, cycles_diff); \
}
static void consume_fifo_do(SH2 *sh2, unsigned int m68k_cycles,
int sh2_cycles_diff)
{
struct Pico32xMem *mem = Pico32xMem;
unsigned short *fifo_l = mem->pwm_fifo[0];
unsigned short *fifo_r = mem->pwm_fifo[1];
int sum = 0;
if (pwm_cycles == 0 || pwm_doing_fifo)
return;
elprintf(EL_PWM, "pwm: %u: consume %d/%d, %d,%d ptr %d",
m68k_cycles, sh2_cycles_diff, sh2_cycles_diff / pwm_cycles,
Pico32x.pwm_p[0], Pico32x.pwm_p[1], pwm_ptr);
// this is for recursion from dreq1 writes
pwm_doing_fifo = 1;
for (; sh2_cycles_diff >= pwm_cycles; sh2_cycles_diff -= pwm_cycles)
{
if (Pico32x.pwm_p[0] > 0) {
fifo_l[0] = fifo_l[1];
fifo_l[1] = fifo_l[2];
fifo_l[2] = fifo_l[3];
Pico32x.pwm_p[0]--;
mem->pwm_current[0] = convert_sample(fifo_l[0]);
sum += mem->pwm_current[0];
}
if (Pico32x.pwm_p[1] > 0) {
fifo_r[0] = fifo_r[1];
fifo_r[1] = fifo_r[2];
fifo_r[2] = fifo_r[3];
Pico32x.pwm_p[1]--;
mem->pwm_current[1] = convert_sample(fifo_r[0]);
sum += mem->pwm_current[1];
}
mem->pwm[pwm_ptr * 2 ] = mem->pwm_current[0];
mem->pwm[pwm_ptr * 2 + 1] = mem->pwm_current[1];
pwm_ptr = (pwm_ptr + 1) & (PWM_BUFF_LEN - 1);
if (--Pico32x.pwm_irq_cnt == 0) {
Pico32x.pwm_irq_cnt = pwm_irq_reload;
do_pwm_irq(sh2, m68k_cycles);
}
}
Pico32x.pwm_cycle_p = m68k_cycles * 3 - sh2_cycles_diff;
pwm_doing_fifo = 0;
if (sum != 0)
pwm_silent = 0;
}
static int p32x_pwm_schedule_(SH2 *sh2, unsigned int m68k_now)
{
unsigned int sh2_now = m68k_now * 3;
int cycles_diff_sh2;
if (pwm_cycles == 0)
return 0;
cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p;
if (cycles_diff_sh2 >= pwm_cycles)
consume_fifo_do(sh2, m68k_now, cycles_diff_sh2);
if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 1))
return 0; // masked by everyone
cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p;
return (Pico32x.pwm_irq_cnt * pwm_cycles
- cycles_diff_sh2) / 3 + 1;
}
void p32x_pwm_schedule(unsigned int m68k_now)
{
int after = p32x_pwm_schedule_(NULL, m68k_now);
if (after != 0)
p32x_event_schedule(m68k_now, P32X_EVENT_PWM, after);
}
void p32x_pwm_schedule_sh2(SH2 *sh2)
{
int after = p32x_pwm_schedule_(sh2, sh2_cycles_done_m68k(sh2));
if (after != 0)
p32x_event_schedule_sh2(sh2, P32X_EVENT_PWM, after);
}
void p32x_pwm_sync_to_sh2(SH2 *sh2)
{
int m68k_cycles = sh2_cycles_done_m68k(sh2);
consume_fifo(sh2, m68k_cycles);
}
void p32x_pwm_irq_event(unsigned int m68k_now)
{
p32x_pwm_schedule(m68k_now);
}
unsigned int p32x_pwm_read16(unsigned int a, SH2 *sh2,
unsigned int m68k_cycles)
{
unsigned int d = 0;
consume_fifo(sh2, m68k_cycles);
a &= 0x0e;
switch (a) {
case 0: // control
case 2: // cycle
d = Pico32x.regs[(0x30 + a) / 2];
break;
case 4: // L ch
if (Pico32x.pwm_p[0] == 3)
d |= P32XP_FULL;
else if (Pico32x.pwm_p[0] == 0)
d |= P32XP_EMPTY;
break;
case 6: // R ch
case 8: // MONO
if (Pico32x.pwm_p[1] == 3)
d |= P32XP_FULL;
else if (Pico32x.pwm_p[1] == 0)
d |= P32XP_EMPTY;
break;
}
elprintf(EL_PWM, "pwm: %u: r16 %02x %04x (p %d %d)",
m68k_cycles, a, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1]);
return d;
}
void p32x_pwm_write16(unsigned int a, unsigned int d,
SH2 *sh2, unsigned int m68k_cycles)
{
elprintf(EL_PWM, "pwm: %u: w16 %02x %04x (p %d %d)",
m68k_cycles, a & 0x0e, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1]);
consume_fifo(sh2, m68k_cycles);
a &= 0x0e;
if (a == 0) { // control
// avoiding pops..
if ((Pico32x.regs[0x30 / 2] & 0x0f) == 0)
Pico32xMem->pwm_fifo[0][0] = Pico32xMem->pwm_fifo[1][0] = 0;
Pico32x.regs[0x30 / 2] = d;
p32x_pwm_ctl_changed();
Pico32x.pwm_irq_cnt = pwm_irq_reload; // ?
}
else if (a == 2) { // cycle
Pico32x.regs[0x32 / 2] = d & 0x0fff;
p32x_pwm_ctl_changed();
}
else if (a <= 8) {
d = (d - 1) & 0x0fff;
if (a == 4 || a == 8) { // L ch or MONO
unsigned short *fifo = Pico32xMem->pwm_fifo[0];
if (Pico32x.pwm_p[0] < 3)
Pico32x.pwm_p[0]++;
else {
fifo[1] = fifo[2];
fifo[2] = fifo[3];
}
fifo[Pico32x.pwm_p[0]] = d;
}
if (a == 6 || a == 8) { // R ch or MONO
unsigned short *fifo = Pico32xMem->pwm_fifo[1];
if (Pico32x.pwm_p[1] < 3)
Pico32x.pwm_p[1]++;
else {
fifo[1] = fifo[2];
fifo[2] = fifo[3];
}
fifo[Pico32x.pwm_p[1]] = d;
}
}
}
void p32x_pwm_update(int *buf32, int length, int stereo)
{
short *pwmb;
int step;
int p = 0;
int xmd;
consume_fifo(NULL, SekCyclesDone());
xmd = Pico32x.regs[0x30 / 2] & 0x0f;
if (xmd == 0 || xmd == 0x06 || xmd == 0x09 || xmd == 0x0f)
goto out; // invalid?
if (pwm_silent)
return;
step = (pwm_ptr << 16) / length;
pwmb = Pico32xMem->pwm;
if (stereo)
{
if (xmd == 0x05) {
// normal
while (length-- > 0) {
*buf32++ += pwmb[0];
*buf32++ += pwmb[1];
p += step;
pwmb += (p >> 16) * 2;
p &= 0xffff;
}
}
else if (xmd == 0x0a) {
// channel swap
while (length-- > 0) {
*buf32++ += pwmb[1];
*buf32++ += pwmb[0];
p += step;
pwmb += (p >> 16) * 2;
p &= 0xffff;
}
}
else {
// mono - LMD, RMD specify dst
if (xmd & 0x06) // src is R
pwmb++;
if (xmd & 0x0c) // dst is R
buf32++;
while (length-- > 0) {
*buf32 += *pwmb;
p += step;
pwmb += (p >> 16) * 2;
p &= 0xffff;
buf32 += 2;
}
}
}
else
{
// mostly unused
while (length-- > 0) {
*buf32++ += pwmb[0];
p += step;
pwmb += (p >> 16) * 2;
p &= 0xffff;
}
}
elprintf(EL_PWM, "pwm_update: pwm_ptr %d, len %d, step %04x, done %d",
pwm_ptr, length, step, (pwmb - Pico32xMem->pwm) / 2);
out:
pwm_ptr = 0;
pwm_silent = Pico32xMem->pwm_current[0] == 0
&& Pico32xMem->pwm_current[1] == 0;
}
void p32x_pwm_state_loaded(void)
{
int cycles_diff_sh2;
p32x_pwm_ctl_changed();
// for old savestates
cycles_diff_sh2 = SekCycleCnt * 3 - Pico32x.pwm_cycle_p;
if (cycles_diff_sh2 >= pwm_cycles || cycles_diff_sh2 < 0) {
Pico32x.pwm_irq_cnt = pwm_irq_reload;
Pico32x.pwm_cycle_p = SekCycleCnt * 3;
p32x_pwm_schedule(SekCycleCnt);
}
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,519 @@
/*
* SH2 peripherals/"system on chip"
* (C) notaz, 2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*
* rough fffffe00-ffffffff map:
* e00-e05 SCI serial communication interface
* e10-e1a FRT free-running timer
* e60-e68 VCRx irq vectors
* e71-e72 DRCR dma selection
* e80-e83 WDT watchdog timer
* e91 SBYCR standby control
* e92 CCR cache control
* ee0 ICR irq control
* ee2 IPRA irq priorities
* ee4 VCRWDT WDT irq vectors
* f00-f17 DIVU
* f40-f7b UBC user break controller
* f80-fb3 DMAC
* fe0-ffb BSC bus state controller
*/
#include "../pico_int.h"
#include "../memory.h"
// DMAC handling
struct dma_chan {
unsigned int sar, dar; // src, dst addr
unsigned int tcr; // transfer count
unsigned int chcr; // chan ctl
// -- dm dm sm sm ts ts ar am al ds dl tb ta ie te de
// ts - transfer size: 1, 2, 4, 16 bytes
// ar - auto request if 1, else dreq signal
// ie - irq enable
// te - transfer end
// de - dma enable
#define DMA_AR (1 << 9)
#define DMA_IE (1 << 2)
#define DMA_TE (1 << 1)
#define DMA_DE (1 << 0)
};
struct dmac {
struct dma_chan chan[2];
unsigned int vcrdma0;
unsigned int unknown0;
unsigned int vcrdma1;
unsigned int unknown1;
unsigned int dmaor;
// -- pr ae nmif dme
// pr - priority: chan0 > chan1 or round-robin
// ae - address error
// nmif - nmi occurred
// dme - DMA master enable
#define DMA_DME (1 << 0)
};
static void dmac_te_irq(SH2 *sh2, struct dma_chan *chan)
{
char *regs = (void *)sh2->peri_regs;
struct dmac *dmac = (void *)(regs + 0x180);
int level = PREG8(regs, 0xe2) & 0x0f; // IPRA
int vector = (chan == &dmac->chan[0]) ?
dmac->vcrdma0 : dmac->vcrdma1;
elprintf(EL_32XP, "dmac irq %d %d", level, vector);
sh2_internal_irq(sh2, level, vector & 0x7f);
}
static void dmac_transfer_complete(SH2 *sh2, struct dma_chan *chan)
{
chan->chcr |= DMA_TE; // DMA has ended normally
p32x_sh2_poll_event(sh2, SH2_STATE_SLEEP, SekCyclesDone());
if (chan->chcr & DMA_IE)
dmac_te_irq(sh2, chan);
}
static void dmac_transfer_one(SH2 *sh2, struct dma_chan *chan)
{
u32 size, d;
size = (chan->chcr >> 10) & 3;
switch (size) {
case 0:
d = p32x_sh2_read8(chan->sar, sh2);
p32x_sh2_write8(chan->dar, d, sh2);
case 1:
d = p32x_sh2_read16(chan->sar, sh2);
p32x_sh2_write16(chan->dar, d, sh2);
break;
case 2:
d = p32x_sh2_read32(chan->sar, sh2);
p32x_sh2_write32(chan->dar, d, sh2);
break;
case 3:
d = p32x_sh2_read32(chan->sar + 0x00, sh2);
p32x_sh2_write32(chan->dar + 0x00, d, sh2);
d = p32x_sh2_read32(chan->sar + 0x04, sh2);
p32x_sh2_write32(chan->dar + 0x04, d, sh2);
d = p32x_sh2_read32(chan->sar + 0x08, sh2);
p32x_sh2_write32(chan->dar + 0x08, d, sh2);
d = p32x_sh2_read32(chan->sar + 0x0c, sh2);
p32x_sh2_write32(chan->dar + 0x0c, d, sh2);
chan->sar += 16; // always?
if (chan->chcr & (1 << 15))
chan->dar -= 16;
if (chan->chcr & (1 << 14))
chan->dar += 16;
chan->tcr -= 4;
return;
}
chan->tcr--;
size = 1 << size;
if (chan->chcr & (1 << 15))
chan->dar -= size;
if (chan->chcr & (1 << 14))
chan->dar += size;
if (chan->chcr & (1 << 13))
chan->sar -= size;
if (chan->chcr & (1 << 12))
chan->sar += size;
}
// DMA trigger by SH2 register write
static void dmac_trigger(SH2 *sh2, struct dma_chan *chan)
{
elprintf_sh2(sh2, EL_32XP, "DMA %08x->%08x, cnt %d, chcr %04x @%06x",
chan->sar, chan->dar, chan->tcr, chan->chcr, sh2->pc);
chan->tcr &= 0xffffff;
if (chan->chcr & DMA_AR) {
// auto-request transfer
while ((int)chan->tcr > 0)
dmac_transfer_one(sh2, chan);
dmac_transfer_complete(sh2, chan);
return;
}
// DREQ0 is only sent after first 4 words are written.
// we do multiple of 4 words to avoid messing up alignment
if ((chan->sar & ~0x20000000) == 0x00004012) {
if (Pico32x.dmac0_fifo_ptr && (Pico32x.dmac0_fifo_ptr & 3) == 0) {
elprintf(EL_32XP, "68k -> sh2 DMA");
p32x_dreq0_trigger();
}
return;
}
// DREQ1
if ((chan->dar & 0xc7fffff0) == 0x00004030)
return;
elprintf(EL_32XP|EL_ANOMALY, "unhandled DMA: "
"%08x->%08x, cnt %d, chcr %04x @%06x",
chan->sar, chan->dar, chan->tcr, chan->chcr, sh2->pc);
}
// timer state - FIXME
static int timer_cycles[2];
static int timer_tick_cycles[2];
// timers
void p32x_timers_recalc(void)
{
int cycles;
int tmp, i;
// SH2 timer step
for (i = 0; i < 2; i++) {
tmp = PREG8(sh2s[i].peri_regs, 0x80) & 7;
// Sclk cycles per timer tick
if (tmp)
cycles = 0x20 << tmp;
else
cycles = 2;
timer_tick_cycles[i] = cycles;
timer_cycles[i] = 0;
elprintf(EL_32XP, "WDT cycles[%d] = %d", i, cycles);
}
}
void p32x_timers_do(unsigned int m68k_slice)
{
unsigned int cycles = m68k_slice * 3;
int cnt, i;
// WDT timers
for (i = 0; i < 2; i++) {
void *pregs = sh2s[i].peri_regs;
if (PREG8(pregs, 0x80) & 0x20) { // TME
timer_cycles[i] += cycles;
cnt = PREG8(pregs, 0x81);
while (timer_cycles[i] >= timer_tick_cycles[i]) {
timer_cycles[i] -= timer_tick_cycles[i];
cnt++;
}
if (cnt >= 0x100) {
int level = PREG8(pregs, 0xe3) >> 4;
int vector = PREG8(pregs, 0xe4) & 0x7f;
elprintf(EL_32XP, "%csh2 WDT irq (%d, %d)",
i ? 's' : 'm', level, vector);
sh2_internal_irq(&sh2s[i], level, vector);
cnt &= 0xff;
}
PREG8(pregs, 0x81) = cnt;
}
}
}
void sh2_peripheral_reset(SH2 *sh2)
{
memset(sh2->peri_regs, 0, sizeof(sh2->peri_regs)); // ?
PREG8(sh2->peri_regs, 0x001) = 0xff; // SCI BRR
PREG8(sh2->peri_regs, 0x003) = 0xff; // SCI TDR
PREG8(sh2->peri_regs, 0x004) = 0x84; // SCI SSR
PREG8(sh2->peri_regs, 0x011) = 0x01; // TIER
PREG8(sh2->peri_regs, 0x017) = 0xe0; // TOCR
}
// ------------------------------------------------------------------
// SH2 internal peripheral memhandlers
// we keep them in little endian format
u32 sh2_peripheral_read8(u32 a, SH2 *sh2)
{
u8 *r = (void *)sh2->peri_regs;
u32 d;
a &= 0x1ff;
d = PREG8(r, a);
elprintf_sh2(sh2, EL_32XP, "peri r8 [%08x] %02x @%06x",
a | ~0x1ff, d, sh2_pc(sh2));
return d;
}
u32 sh2_peripheral_read16(u32 a, SH2 *sh2)
{
u16 *r = (void *)sh2->peri_regs;
u32 d;
a &= 0x1ff;
d = r[(a / 2) ^ 1];
elprintf_sh2(sh2, EL_32XP, "peri r16 [%08x] %04x @%06x",
a | ~0x1ff, d, sh2_pc(sh2));
return d;
}
u32 sh2_peripheral_read32(u32 a, SH2 *sh2)
{
u32 d;
a &= 0x1fc;
d = sh2->peri_regs[a / 4];
elprintf_sh2(sh2, EL_32XP, "peri r32 [%08x] %08x @%06x",
a | ~0x1ff, d, sh2_pc(sh2));
return d;
}
static void sci_trigger(SH2 *sh2, u8 *r)
{
u8 *oregs;
if (!(PREG8(r, 2) & 0x20))
return; // transmitter not enabled
if ((PREG8(r, 4) & 0x80)) // TDRE - TransmitDataR Empty
return;
oregs = (u8 *)sh2->other_sh2->peri_regs;
if (!(PREG8(oregs, 2) & 0x10))
return; // receiver not enabled
PREG8(oregs, 5) = PREG8(r, 3); // other.RDR = this.TDR
PREG8(r, 4) |= 0x80; // TDRE - TDR empty
PREG8(oregs, 4) |= 0x40; // RDRF - RDR Full
// might need to delay these a bit..
if (PREG8(r, 2) & 0x80) { // TIE - tx irq enabled
int level = PREG8(oregs, 0x60) >> 4;
int vector = PREG8(oregs, 0x64) & 0x7f;
elprintf_sh2(sh2, EL_32XP, "SCI tx irq (%d, %d)",
level, vector);
sh2_internal_irq(sh2, level, vector);
}
// TODO: TEIE
if (PREG8(oregs, 2) & 0x40) { // RIE - rx irq enabled
int level = PREG8(oregs, 0x60) >> 4;
int vector = PREG8(oregs, 0x63) & 0x7f;
elprintf_sh2(sh2->other_sh2, EL_32XP, "SCI rx irq (%d, %d)",
level, vector);
sh2_internal_irq(sh2->other_sh2, level, vector);
}
}
void REGPARM(3) sh2_peripheral_write8(u32 a, u32 d, SH2 *sh2)
{
u8 *r = (void *)sh2->peri_regs;
u8 old;
elprintf_sh2(sh2, EL_32XP, "peri w8 [%08x] %02x @%06x",
a, d, sh2_pc(sh2));
a &= 0x1ff;
old = PREG8(r, a);
switch (a) {
case 0x002: // SCR - serial control
if (!(PREG8(r, a) & 0x20) && (d & 0x20)) { // TE being set
PREG8(r, a) = d;
sci_trigger(sh2, r);
}
break;
case 0x003: // TDR - transmit data
break;
case 0x004: // SSR - serial status
d = (old & (d | 0x06)) | (d & 1);
PREG8(r, a) = d;
sci_trigger(sh2, r);
return;
case 0x005: // RDR - receive data
break;
case 0x010: // TIER
if (d & 0x8e)
elprintf(EL_32XP|EL_ANOMALY, "TIER: %02x", d);
d = (d & 0x8e) | 1;
break;
case 0x017: // TOCR
d |= 0xe0;
break;
}
PREG8(r, a) = d;
}
void REGPARM(3) sh2_peripheral_write16(u32 a, u32 d, SH2 *sh2)
{
u16 *r = (void *)sh2->peri_regs;
elprintf_sh2(sh2, EL_32XP, "peri w16 [%08x] %04x @%06x",
a, d, sh2_pc(sh2));
a &= 0x1ff;
// evil WDT
if (a == 0x80) {
if ((d & 0xff00) == 0xa500) { // WTCSR
PREG8(r, 0x80) = d;
p32x_timers_recalc();
}
if ((d & 0xff00) == 0x5a00) // WTCNT
PREG8(r, 0x81) = d;
return;
}
r[(a / 2) ^ 1] = d;
}
void REGPARM(3) sh2_peripheral_write32(u32 a, u32 d, SH2 *sh2)
{
u32 *r = sh2->peri_regs;
u32 old;
elprintf_sh2(sh2, EL_32XP, "peri w32 [%08x] %08x @%06x",
a, d, sh2_pc(sh2));
a &= 0x1fc;
old = r[a / 4];
r[a / 4] = d;
switch (a) {
// division unit (TODO: verify):
case 0x104: // DVDNT: divident L, starts divide
elprintf_sh2(sh2, EL_32XP, "divide %08x / %08x",
d, r[0x100 / 4]);
if (r[0x100 / 4]) {
signed int divisor = r[0x100 / 4];
r[0x118 / 4] = r[0x110 / 4] = (signed int)d % divisor;
r[0x104 / 4] = r[0x11c / 4] = r[0x114 / 4] = (signed int)d / divisor;
}
else
r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
break;
case 0x114:
elprintf_sh2(sh2, EL_32XP, "divide %08x%08x / %08x @%08x",
r[0x110 / 4], d, r[0x100 / 4], sh2_pc(sh2));
if (r[0x100 / 4]) {
signed long long divident = (signed long long)r[0x110 / 4] << 32 | d;
signed int divisor = r[0x100 / 4];
// XXX: undocumented mirroring to 0x118,0x11c?
r[0x118 / 4] = r[0x110 / 4] = divident % divisor;
divident /= divisor;
r[0x11c / 4] = r[0x114 / 4] = divident;
divident >>= 31;
if ((unsigned long long)divident + 1 > 1) {
//elprintf_sh2(sh2, EL_32XP, "divide overflow! @%08x", sh2_pc(sh2));
r[0x11c / 4] = r[0x114 / 4] = divident > 0 ? 0x7fffffff : 0x80000000; // overflow
}
}
else
r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
break;
}
// perhaps starting a DMA?
if (a == 0x1b0 || a == 0x18c || a == 0x19c) {
struct dmac *dmac = (void *)&sh2->peri_regs[0x180 / 4];
if (a == 0x1b0 && !((old ^ d) & d & DMA_DME))
return;
if (!(dmac->dmaor & DMA_DME))
return;
if ((dmac->chan[0].chcr & (DMA_TE|DMA_DE)) == DMA_DE)
dmac_trigger(sh2, &dmac->chan[0]);
if ((dmac->chan[1].chcr & (DMA_TE|DMA_DE)) == DMA_DE)
dmac_trigger(sh2, &dmac->chan[1]);
}
}
/* 32X specific */
static void dreq0_do(SH2 *sh2, struct dma_chan *chan)
{
unsigned short dreqlen = Pico32x.regs[0x10 / 2];
int i;
// debug/sanity checks
if (chan->tcr < dreqlen || chan->tcr > dreqlen + 4)
elprintf(EL_32XP|EL_ANOMALY, "dreq0: tcr0/len inconsistent: %d/%d",
chan->tcr, dreqlen);
// note: DACK is not connected, single addr mode should not be used
if ((chan->chcr & 0x3f08) != 0x0400)
elprintf(EL_32XP|EL_ANOMALY, "dreq0: bad control: %04x", chan->chcr);
if ((chan->sar & ~0x20000000) != 0x00004012)
elprintf(EL_32XP|EL_ANOMALY, "dreq0: bad sar?: %08x", chan->sar);
// HACK: assume bus is busy and SH2 is halted
sh2->state |= SH2_STATE_SLEEP;
for (i = 0; i < Pico32x.dmac0_fifo_ptr && chan->tcr > 0; i++) {
elprintf_sh2(sh2, EL_32XP, "dreq0 [%08x] %04x, dreq_len %d",
chan->dar, Pico32x.dmac_fifo[i], dreqlen);
p32x_sh2_write16(chan->dar, Pico32x.dmac_fifo[i], sh2);
chan->dar += 2;
chan->tcr--;
}
if (Pico32x.dmac0_fifo_ptr != i)
memmove(Pico32x.dmac_fifo, &Pico32x.dmac_fifo[i],
(Pico32x.dmac0_fifo_ptr - i) * 2);
Pico32x.dmac0_fifo_ptr -= i;
Pico32x.regs[6 / 2] &= ~P32XS_FULL;
if (chan->tcr == 0)
dmac_transfer_complete(sh2, chan);
else
sh2_end_run(sh2, 16);
}
static void dreq1_do(SH2 *sh2, struct dma_chan *chan)
{
// debug/sanity checks
if ((chan->chcr & 0xc308) != 0x0000)
elprintf(EL_32XP|EL_ANOMALY, "dreq1: bad control: %04x", chan->chcr);
if ((chan->dar & ~0xf) != 0x20004030)
elprintf(EL_32XP|EL_ANOMALY, "dreq1: bad dar?: %08x\n", chan->dar);
dmac_transfer_one(sh2, chan);
if (chan->tcr == 0)
dmac_transfer_complete(sh2, chan);
}
void p32x_dreq0_trigger(void)
{
struct dmac *mdmac = (void *)&msh2.peri_regs[0x180 / 4];
struct dmac *sdmac = (void *)&ssh2.peri_regs[0x180 / 4];
elprintf(EL_32XP, "dreq0_trigger");
if ((mdmac->dmaor & DMA_DME) && (mdmac->chan[0].chcr & 3) == DMA_DE) {
dreq0_do(&msh2, &mdmac->chan[0]);
}
if ((sdmac->dmaor & DMA_DME) && (sdmac->chan[0].chcr & 3) == DMA_DE) {
dreq0_do(&ssh2, &sdmac->chan[0]);
}
}
void p32x_dreq1_trigger(void)
{
struct dmac *mdmac = (void *)&msh2.peri_regs[0x180 / 4];
struct dmac *sdmac = (void *)&ssh2.peri_regs[0x180 / 4];
int hit = 0;
elprintf(EL_32XP, "dreq1_trigger");
if ((mdmac->dmaor & DMA_DME) && (mdmac->chan[1].chcr & 3) == DMA_DE) {
dreq1_do(&msh2, &mdmac->chan[1]);
hit = 1;
}
if ((sdmac->dmaor & DMA_DME) && (sdmac->chan[1].chcr & 3) == DMA_DE) {
dreq1_do(&ssh2, &sdmac->chan[1]);
hit = 1;
}
// debug
#if (EL_LOGMASK & (EL_32XP|EL_ANOMALY))
{
static int miss_count;
if (!hit) {
if (++miss_count == 4)
elprintf(EL_32XP|EL_ANOMALY, "dreq1: nobody cared");
}
else
miss_count = 0;
}
#endif
(void)hit;
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,703 @@
/*
* PicoDrive
* (c) Copyright Dave, 2004
* (C) notaz, 2006-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "pico_int.h"
#include <stdint.h>
static const uint32_t crc32tab[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
uint32_t crc32(const uint8_t *p, size_t size)
{
uint32_t crc = ~0;
while (size--)
crc = (crc >> 8) ^ crc32tab[(crc ^ (*p++)) & 0xFF];
return ~crc;
}
static int rom_alloc_size;
static const char *rom_exts[] = { "bin", "gen", "smd", "iso", "sms", "gg", "sg" };
void (*PicoCartMemSetup)(void);
void (*PicoCDLoadProgressCB)(const char *fname, int percent) = NULL; // handled in Pico/cd/cd_file.c
int PicoGameLoaded;
static void PicoCartDetect(const char *carthw_cfg);
static const char *get_ext(const char *path)
{
const char *ext;
if (strlen(path) < 4)
return ""; // no ext
// allow 2 or 3 char extensions for now
ext = path + strlen(path) - 2;
if (ext[-1] != '.') ext--;
if (ext[-1] != '.')
return "";
return ext;
}
// byteswap, data needs to be int aligned, src can match dst
void Byteswap(void *dst, const void *src, int len)
{
const unsigned int *ps = src;
unsigned int *pd = dst;
int i, m;
if (len < 2)
return;
m = 0x00ff00ff;
for (i = 0; i < len / 4; i++) {
unsigned int t = ps[i];
pd[i] = ((t & m) << 8) | ((t & ~m) >> 8);
}
}
// Interleve a 16k block and byteswap
static int InterleveBlock(unsigned char *dest,unsigned char *src)
{
int i=0;
for (i=0;i<0x2000;i++) dest[(i<<1) ]=src[ i]; // Odd
for (i=0;i<0x2000;i++) dest[(i<<1)+1]=src[0x2000+i]; // Even
return 0;
}
// Decode a SMD file
static int DecodeSmd(unsigned char *data,int len)
{
unsigned char *temp=NULL;
int i=0;
temp=(unsigned char *)malloc(0x4000);
if (temp==NULL) return 1;
memset(temp,0,0x4000);
// Interleve each 16k block and shift down by 0x200:
for (i=0; i+0x4200<=len; i+=0x4000)
{
InterleveBlock(temp,data+0x200+i); // Interleve 16k to temporary buffer
memcpy(data+i,temp,0x4000); // Copy back in
}
free(temp);
return 0;
}
static unsigned char *PicoCartAlloc(int filesize, int is_sms)
{
unsigned char *rom;
if (is_sms) {
// make size power of 2 for easier banking handling
int s = 0, tmp = filesize;
while ((tmp >>= 1) != 0)
s++;
if (filesize > (1 << s))
s++;
rom_alloc_size = 1 << s;
// be sure we can cover all address space
if (rom_alloc_size < 0x10000)
rom_alloc_size = 0x10000;
}
else {
// make alloc size at least sizeof(mcd_state),
// in case we want to switch to CD mode
if (filesize < sizeof(mcd_state))
filesize = sizeof(mcd_state);
// align to 512K for memhandlers
rom_alloc_size = (filesize + 0x7ffff) & ~0x7ffff;
}
if (rom_alloc_size - filesize < 4)
rom_alloc_size += 4; // padding for out-of-bound exec protection
// Allocate space for the rom plus padding
rom = malloc(rom_alloc_size);
return rom;
}
int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms)
{
unsigned char *rom;
int size, bytes_read;
if (f == NULL)
return 1;
size = f->size;
if (size <= 0) return 1;
size = (size+3)&~3; // Round up to a multiple of 4
// Allocate space for the rom plus padding
rom = PicoCartAlloc(size, is_sms);
if (rom == NULL) {
elprintf(EL_STATUS, "out of memory (wanted %i)", size);
return 2;
}
bytes_read = pm_read(rom,size,f); // Load up the rom
if (bytes_read <= 0) {
elprintf(EL_STATUS, "read failed");
return 3;
}
if (!is_sms)
{
// maybe we are loading MegaCD BIOS?
if (!(PicoAHW & PAHW_MCD) && size == 0x20000 && (!strncmp((char *)rom+0x124, "BOOT", 4) ||
!strncmp((char *)rom+0x128, "BOOT", 4))) {
PicoAHW |= PAHW_MCD;
}
// Check for SMD:
if (size >= 0x4200 && (size&0x3fff) == 0x200 &&
((rom[0x2280] == 'S' && rom[0x280] == 'E') || (rom[0x280] == 'S' && rom[0x2281] == 'E'))) {
elprintf(EL_STATUS, "SMD format detected.");
DecodeSmd(rom,size); size-=0x200; // Decode and byteswap SMD
}
else Byteswap(rom, rom, size); // Just byteswap
}
else
{
if (size >= 0x4200 && (size&0x3fff) == 0x200) {
elprintf(EL_STATUS, "SMD format detected.");
// at least here it's not interleaved
size -= 0x200;
memmove(rom, rom + 0x200, size);
}
}
if (prom) *prom = rom;
if (psize) *psize = size;
return 0;
}
// Insert a cartridge:
int PicoCartInsert(unsigned char *rom, unsigned int romsize, const char *carthw_cfg)
{
// notaz: add a 68k "jump one op back" opcode to the end of ROM.
// This will hang the emu, but will prevent nasty crashes.
// note: 4 bytes are padded to every ROM
if (rom != NULL)
*(unsigned long *)(rom+romsize) = 0xFFFE4EFA; // 4EFA FFFE byteswapped
Pico.rom=rom;
Pico.romsize=romsize;
if (SRam.data) {
free(SRam.data);
SRam.data = NULL;
}
PicoAHW &= PAHW_MCD|PAHW_SMS;
PicoCartMemSetup = NULL;
PicoDmaHook = NULL;
PicoResetHook = NULL;
PicoLineHook = NULL;
if (!(PicoAHW & (PAHW_MCD|PAHW_SMS)))
PicoCartDetect(carthw_cfg);
// setup correct memory map for loaded ROM
switch (PicoAHW) {
default:
elprintf(EL_STATUS|EL_ANOMALY, "starting in unknown hw configuration: %x", PicoAHW);
case 0:
case PAHW_SVP: PicoMemSetup(); break;
case PAHW_MCD: PicoMemSetupCD(); break;
case PAHW_PICO: PicoMemSetupPico(); break;
case PAHW_SMS: PicoMemSetupMS(); break;
}
if (PicoCartMemSetup != NULL)
PicoCartMemSetup();
if (PicoAHW & PAHW_SMS)
PicoPowerMS();
else
PicoPower();
PicoGameLoaded = 1;
return 0;
}
static unsigned int rom_crc32(void)
{
unsigned int crc;
elprintf(EL_STATUS, "caclulating CRC32..");
// have to unbyteswap for calculation..
Byteswap(Pico.rom, Pico.rom, Pico.romsize);
crc = crc32(Pico.rom, Pico.romsize);
Byteswap(Pico.rom, Pico.rom, Pico.romsize);
return crc;
}
static int rom_strcmp(int rom_offset, const char *s1)
{
int i, len = strlen(s1);
const char *s_rom = (const char *)Pico.rom;
if (rom_offset + len > Pico.romsize)
return 0;
for (i = 0; i < len; i++)
if (s1[i] != s_rom[(i + rom_offset) ^ 1])
return 1;
return 0;
}
static unsigned int rom_read32(int addr)
{
unsigned short *m = (unsigned short *)(Pico.rom + addr);
return (m[0] << 16) | m[1];
}
static char *sskip(char *s)
{
while (*s && isspace_(*s))
s++;
return s;
}
static void rstrip(char *s)
{
char *p;
for (p = s + strlen(s) - 1; p >= s; p--)
if (isspace_(*p))
*p = 0;
}
static int parse_3_vals(char *p, int *val0, int *val1, int *val2)
{
char *r;
*val0 = strtoul(p, &r, 0);
if (r == p)
goto bad;
p = sskip(r);
if (*p++ != ',')
goto bad;
*val1 = strtoul(p, &r, 0);
if (r == p)
goto bad;
p = sskip(r);
if (*p++ != ',')
goto bad;
*val2 = strtoul(p, &r, 0);
if (r == p)
goto bad;
return 1;
bad:
return 0;
}
static int is_expr(const char *expr, char **pr)
{
int len = strlen(expr);
char *p = *pr;
if (strncmp(expr, p, len) != 0)
return 0;
p = sskip(p + len);
if (*p != '=')
return 0; // wrong or malformed
*pr = sskip(p + 1);
return 1;
}
#include "carthw_cfg.c"
static void parse_carthw(const char *carthw_cfg, int *fill_sram)
{
int line = 0, any_checks_passed = 0, skip_sect = 0;
const char *s, *builtin = builtin_carthw_cfg;
int tmp, rom_crc = 0;
char buff[256], *p, *r;
FILE *f;
f = fopen(carthw_cfg, "r");
if (f == NULL)
f = fopen("pico/carthw.cfg", "r");
if (f == NULL)
elprintf(EL_STATUS, "couldn't open carthw.cfg!");
for (;;)
{
if (f != NULL) {
p = fgets(buff, sizeof(buff), f);
if (p == NULL)
break;
}
else {
if (*builtin == 0)
break;
for (s = builtin; *s != 0 && *s != '\n'; s++)
;
while (*s == '\n')
s++;
tmp = s - builtin;
if (tmp > sizeof(buff) - 1)
tmp = sizeof(buff) - 1;
memcpy(buff, builtin, tmp);
buff[tmp] = 0;
p = buff;
builtin = s;
}
line++;
p = sskip(p);
if (*p == 0 || *p == '#')
continue;
if (*p == '[') {
any_checks_passed = 0;
skip_sect = 0;
continue;
}
if (skip_sect)
continue;
/* look for checks */
if (is_expr("check_str", &p))
{
int offs;
offs = strtoul(p, &r, 0);
if (offs < 0 || offs > Pico.romsize) {
elprintf(EL_STATUS, "carthw:%d: check_str offs out of range: %d\n", line, offs);
goto bad;
}
p = sskip(r);
if (*p != ',')
goto bad;
p = sskip(p + 1);
if (*p != '"')
goto bad;
p++;
r = strchr(p, '"');
if (r == NULL)
goto bad;
*r = 0;
if (rom_strcmp(offs, p) == 0)
any_checks_passed = 1;
else
skip_sect = 1;
continue;
}
else if (is_expr("check_size_gt", &p))
{
int size;
size = strtoul(p, &r, 0);
if (r == p || size < 0)
goto bad;
if (Pico.romsize > size)
any_checks_passed = 1;
else
skip_sect = 1;
continue;
}
else if (is_expr("check_csum", &p))
{
int csum;
csum = strtoul(p, &r, 0);
if (r == p || (csum & 0xffff0000))
goto bad;
if (csum == (rom_read32(0x18c) & 0xffff))
any_checks_passed = 1;
else
skip_sect = 1;
continue;
}
else if (is_expr("check_crc32", &p))
{
unsigned int crc;
crc = strtoul(p, &r, 0);
if (r == p)
goto bad;
if (rom_crc == 0)
rom_crc = rom_crc32();
if (crc == rom_crc)
any_checks_passed = 1;
else
skip_sect = 1;
continue;
}
/* now time for actions */
if (is_expr("hw", &p)) {
if (!any_checks_passed)
goto no_checks;
rstrip(p);
if (strcmp(p, "svp") == 0)
PicoSVPStartup();
else if (strcmp(p, "pico") == 0)
PicoInitPico();
else if (strcmp(p, "prot") == 0)
carthw_sprot_startup();
else if (strcmp(p, "ssf2_mapper") == 0)
carthw_ssf2_startup();
else if (strcmp(p, "x_in_1_mapper") == 0)
carthw_Xin1_startup();
else if (strcmp(p, "realtec_mapper") == 0)
carthw_realtec_startup();
else if (strcmp(p, "radica_mapper") == 0)
carthw_radica_startup();
else if (strcmp(p, "piersolar_mapper") == 0)
carthw_pier_startup();
else if (strcmp(p, "prot_lk3") == 0)
carthw_prot_lk3_startup();
else {
elprintf(EL_STATUS, "carthw:%d: unsupported mapper: %s", line, p);
skip_sect = 1;
}
continue;
}
if (is_expr("sram_range", &p)) {
int start, end;
if (!any_checks_passed)
goto no_checks;
rstrip(p);
start = strtoul(p, &r, 0);
if (r == p)
goto bad;
p = sskip(r);
if (*p != ',')
goto bad;
p = sskip(p + 1);
end = strtoul(p, &r, 0);
if (r == p)
goto bad;
if (((start | end) & 0xff000000) || start > end) {
elprintf(EL_STATUS, "carthw:%d: bad sram_range: %08x - %08x", line, start, end);
goto bad_nomsg;
}
SRam.start = start;
SRam.end = end;
continue;
}
else if (is_expr("prop", &p)) {
if (!any_checks_passed)
goto no_checks;
rstrip(p);
if (strcmp(p, "no_sram") == 0)
SRam.flags &= ~SRF_ENABLED;
else if (strcmp(p, "no_eeprom") == 0)
SRam.flags &= ~SRF_EEPROM;
else if (strcmp(p, "filled_sram") == 0)
*fill_sram = 1;
else if (strcmp(p, "force_6btn") == 0)
PicoQuirks |= PQUIRK_FORCE_6BTN;
else {
elprintf(EL_STATUS, "carthw:%d: unsupported prop: %s", line, p);
goto bad_nomsg;
}
elprintf(EL_STATUS, "game prop: %s", p);
continue;
}
else if (is_expr("eeprom_type", &p)) {
int type;
if (!any_checks_passed)
goto no_checks;
rstrip(p);
type = strtoul(p, &r, 0);
if (r == p || type < 0)
goto bad;
SRam.eeprom_type = type;
SRam.flags |= SRF_EEPROM;
continue;
}
else if (is_expr("eeprom_lines", &p)) {
int scl, sda_in, sda_out;
if (!any_checks_passed)
goto no_checks;
rstrip(p);
if (!parse_3_vals(p, &scl, &sda_in, &sda_out))
goto bad;
if (scl < 0 || scl > 15 || sda_in < 0 || sda_in > 15 ||
sda_out < 0 || sda_out > 15)
goto bad;
SRam.eeprom_bit_cl = scl;
SRam.eeprom_bit_in = sda_in;
SRam.eeprom_bit_out= sda_out;
continue;
}
else if ((tmp = is_expr("prot_ro_value16", &p)) || is_expr("prot_rw_value16", &p)) {
int addr, mask, val;
if (!any_checks_passed)
goto no_checks;
rstrip(p);
if (!parse_3_vals(p, &addr, &mask, &val))
goto bad;
carthw_sprot_new_location(addr, mask, val, tmp ? 1 : 0);
continue;
}
bad:
elprintf(EL_STATUS, "carthw:%d: unrecognized expression: %s", line, buff);
bad_nomsg:
skip_sect = 1;
continue;
no_checks:
elprintf(EL_STATUS, "carthw:%d: command without any checks before it: %s", line, buff);
skip_sect = 1;
continue;
}
if (f != NULL)
fclose(f);
}
/*
* various cart-specific things, which can't be handled by generic code
*/
static void PicoCartDetect(const char *carthw_cfg)
{
int fill_sram = 0;
memset(&SRam, 0, sizeof(SRam));
if (Pico.rom[0x1B1] == 'R' && Pico.rom[0x1B0] == 'A')
{
SRam.start = rom_read32(0x1B4) & ~0xff000001; // align
SRam.end = (rom_read32(0x1B8) & ~0xff000000) | 1;
if (Pico.rom[0x1B2] & 0x40)
// EEPROM
SRam.flags |= SRF_EEPROM;
SRam.flags |= SRF_ENABLED;
}
if (SRam.end == 0 || SRam.start > SRam.end)
{
// some games may have bad headers, like S&K and Sonic3
// note: majority games use 0x200000 as starting address, but there are some which
// use something else (0x300000 by HardBall '95). Luckily they have good headers.
SRam.start = 0x200000;
SRam.end = 0x203FFF;
SRam.flags |= SRF_ENABLED;
}
// set EEPROM defaults, in case it gets detected
SRam.eeprom_type = 0; // 7bit (24C01)
SRam.eeprom_bit_cl = 1;
SRam.eeprom_bit_in = 0;
SRam.eeprom_bit_out= 0;
if (carthw_cfg != NULL)
parse_carthw(carthw_cfg, &fill_sram);
if (SRam.flags & SRF_ENABLED)
{
if (SRam.flags & SRF_EEPROM)
SRam.size = 0x2000;
else
SRam.size = SRam.end - SRam.start + 1;
SRam.data = calloc(SRam.size, 1);
if (SRam.data == NULL)
SRam.flags &= ~SRF_ENABLED;
if (SRam.eeprom_type == 1) // 1 == 0 in PD EEPROM code
SRam.eeprom_type = 0;
}
if ((SRam.flags & SRF_ENABLED) && fill_sram)
{
elprintf(EL_STATUS, "SRAM fill");
memset(SRam.data, 0xff, SRam.size);
}
// Unusual region 'code'
if (rom_strcmp(0x1f0, "EUROPE") == 0 || rom_strcmp(0x1f0, "Europe") == 0)
*(int *) (Pico.rom + 0x1f0) = 0x20204520;
}

View File

@ -0,0 +1,320 @@
# hardware (hw = ...):
# svp - Sega Virtua Processor
# pico - Sega Pico (not really cart hw, but convenient to support here)
# prot - siple copy protection devices in unlicensed cartridges (see prot. below)
# prot_lk3 - Lion King 3 / Super King Kong 99 protection.
#
# cartridge properties (prop = ...):
# no_sram - don't emulate sram/EEPROM even if ROM headers tell it's there
# no_eeprom - save storage is not EEPROM, even if ROM headers tell it is
# filled_sram - save storage needs to be initialized with FFh instead of 00h
# force_6btn - game only supports 6 button pad (32X X-men proto)
#
# mappers (hw = ...):
# ssf2_mapper - used in Super Street Fighter2
# x_in_1_mapper - used in many *-in-1 pirate carts
# realtec_mapper
# radica_mapper - similar to x_in_1_mapper
# piersolar_mapper - used in Pier Solar
#
# save storage memory range (inclusive, overrides ROM header):
# sram_range = <start, end>
#
# EEPROM:
# eeprom_type = <1|2|3> - enable EEPROM, use type X (7bit, 2 addr words, 3 addr words).
# See EkeEke's gen_eeprom.pdf "mode" descriptions for 24Cxx EEPROMs.
# eeprom_lines = <SCL,SDA_IN,SDA_OUT>
# - select data bus pins that are connected to EEPROM
# SCL, SDA_IN and SDA_OUT pins (0-15 for D0-D15).
# hw = prot:
# prot_ro_value16 = <addr, mask, val> - return constant <val> on reads at location
# (<addr> & <mask>), ignore writes.
# prot_rw_value16 = <addr, mask, val> - same as above, but writeable
[Virtua Racing - SVP]
check_str = 0x150, "Virtua Racing"
check_str = 0x810, "OHMP"
hw = svp
[Virtua Racing - SVP]
check_str = 0x150, "VIRTUA RACING"
check_str = 0x810, "OHMP"
hw = svp
[Pico]
check_str = 0x100, "SEGA PICO"
hw = pico
[Pico]
check_str = 0x100, "IMA IKUNOUJYUKU"
hw = pico
# sram emulation triggers some protection for this one
[Puggsy]
check_str = 0x120, "PUGGSY"
prop = no_sram
# game has problems if it's save RAM is not initialized with FFh:
[Dino Dini's Soccer]
check_str = 0x150, "DINO DINI'S SOCCER"
prop = filled_sram
[Micro Machines 2 - Turbo Tournament]
check_str = 0x150, "MICRO MACHINES II"
prop = filled_sram
# X-Men proto
[X-Men (prototype)]
check_str = 0x150, "32X SAMPLE PROGRAM"
check_str = 0x32b74c, "Bishop Level"
prop = force_6btn
# The SSF2 mapper
[Super Street Fighter II - The New Challengers (U)]
check_str = 0x150, "SUPER STREET FIGHTER2 The New Challengers"
hw = ssf2_mapper
prop = no_sram
# The Pier Solar mapper, custom eeprom location
[Pier Solar and the Great Architects]
check_str = 0x150, "PIER"
check_str = 0x610, "Respect"
hw = piersolar_mapper
# detect *_in_1 based on first game and if it's larger than it should be,
# as some dumps look like to be incomplete.
# This will also pick overdumps, but those should still work with the mapper applied.
[12-in-1 (Unl)]
check_str = 0x120, "FLICKY"
check_size_gt = 0x020000
hw = x_in_1_mapper
[4-in-1]
check_str = 0x150, "ROBOCOP 3"
check_size_gt = 0x080000
hw = x_in_1_mapper
[4-in-1 a1]
check_str = 0x150, "ALIEN 3"
check_size_gt = 0x080000
hw = x_in_1_mapper
[Super 15-in-1]
check_str = 0x150, " SHOVE IT!"
check_size_gt = 0x020000
hw = x_in_1_mapper
[Super 19-in-1]
check_str = 0x150, "MS PACMAN"
check_size_gt = 0x020000
hw = x_in_1_mapper
# radica
[radica_v1]
check_str = 0x150, "KID CHAMELEON"
check_size_gt = 0x100000
hw = radica_mapper
# realtec
[Earth Defend, The (Unl)]
check_str = 0x94, "THE EARTH DEFEND"
hw = realtec_mapper
[Funny World & Balloon Boy (Unl)]
check_str = 0xfe, "WISEGAME 11-03-1993"
hw = realtec_mapper
[Whac-A-Critter (Unl)]
check_str = 0x95, "MALLET LEGEND"
hw = realtec_mapper
# EEPROM games - thanks to EkeEke for most of this info
[College Slam]
check_str = 0x150, "COLLEGE SLAM"
eeprom_type = 3
eeprom_lines = 8,0,0
[Frank Thomas Big Hurt Baseball]
check_str = 0x150, "FRANK THOMAS BIGHURT BASEBAL"
eeprom_type = 3
eeprom_lines = 8,0,0
[MICRO MACHINES II]
check_str = 0x150, "MICRO MACHINES II"
sram_range = 0x300000,0x380001
eeprom_type = 2
eeprom_lines = 9,8,7
[Micro Machines - Turbo Tournament '96]
check_str = 0x150, " "
check_csum = 0x165e
sram_range = 0x300000,0x380001
eeprom_type = 2
eeprom_lines = 9,8,7
[Micro Machines - Turbo Tournament '96]
check_str = 0x150, " "
check_csum = 0x2c41
sram_range = 0x300000,0x380001
eeprom_type = 2
eeprom_lines = 9,8,7
[Micro Machines Military]
check_str = 0x150, " "
check_csum = 0x168b
sram_range = 0x300000,0x380001
eeprom_type = 2
eeprom_lines = 9,8,7
[Micro Machines Military]
check_str = 0x150, " "
check_csum = 0xcee0
sram_range = 0x300000,0x380001
eeprom_type = 2
eeprom_lines = 9,8,7
[NBA Jam]
check_str = 0x150, "NBA JAM "
eeprom_type = 2
eeprom_lines = 1,0,1
[NBA Jam Tournament Edition]
check_str = 0x150, "NBA JAM TOURNAMENT EDITION"
sram_range = 0x200000,0x200001
eeprom_type = 2
eeprom_lines = 8,0,0
[NFL Quarterback Club]
check_str = 0x150, "NFL QUARTERBACK CLUB"
eeprom_type = 2
eeprom_lines = 8,0,0
[NHLPA Hockey '93]
check_str = 0x150, "NHLPA Hockey '93"
sram_range = 0x200000,0x200001
eeprom_type = 1
eeprom_lines = 6,7,7
[NHLPA Hockey '93]
check_str = 0x150, "NHLPA HOCKEY '93"
sram_range = 0x200000,0x200001
eeprom_type = 1
eeprom_lines = 6,7,7
[Rings of Power]
check_str = 0x150, "RINGS OF POWER"
sram_range = 0x200000,0x200001
eeprom_type = 1
eeprom_lines = 6,7,7
# Unlicensed games with simple protections
# some of these come from Haze, some from myself (notaz).
[Bug's Life, A (Unl)]
check_str = 0x104, " "
check_crc32 = 0x10458e09
hw = prot
prot_ro_value16 = 0xa13000,0xffff00,0x28
[Elf Wor (Unl)]
check_str = 0x172, "GAME : ELF WOR"
hw = prot
prot_ro_value16 = 0x400000,-2,0x5500
prot_ro_value16 = 0x400002,-2,0xc900 # check is done if the above one fails
prot_ro_value16 = 0x400004,-2,0x0f00
prot_ro_value16 = 0x400006,-2,0x1800 # similar to above
[King of Fighters '98, The (Unl)]
check_str = 0x104, " "
check_crc32 = 0xcbc38eea
hw = prot
prot_ro_value16 = 0x480000,0xff0000,0xaa00
prot_ro_value16 = 0x4a0000,0xff0000,0x0a00
prot_ro_value16 = 0x4c0000,0xff0000,0xf000
prot_ro_value16 = 0x400000,0xc00000,0x0000 # default for 400000-7f0000
[Lion King 3 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xc004219d
hw = prot_lk3
[Lion King II, The (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xaff46765
hw = prot
prot_rw_value16 = 0x400000,0xc00004,0
prot_rw_value16 = 0x400004,0xc00004,0
[Mahjong Lover (Unl)]
check_str = 0x118, "CREATON. "
check_crc32 = 0xddd02ba4
hw = prot
prot_ro_value16 = 0x400000,-2,0x9000
prot_ro_value16 = 0x401000,-2,0xd300
[Pocket Monsters (Unl)]
check_str = 0x104, " "
check_crc32 = 0xf68f6367
hw = prot
prot_ro_value16 = 0xa13002,-2,0x01
prot_ro_value16 = 0xa1303e,-2,0x1f
[Pocket Monsters (Unl) [a1]]
check_str = 0x104, " "
check_crc32 = 0xfb176667
hw = prot
prot_ro_value16 = 0xa13000,-2,0x14
prot_ro_value16 = 0xa13002,-2,0x01
prot_ro_value16 = 0xa1303e,-2,0x1f
[Rockman X3 (Unl)]
check_csum = 0
check_crc32 = 0x3ee639f0
hw = prot
prot_ro_value16 = 0xa13000,-2,0x0c
[Smart Mouse (Unl)]
check_csum = 0
check_crc32 = 0xdecdf740
hw = prot
prot_ro_value16 = 0x400000,-2,0x5500
prot_ro_value16 = 0x400002,-2,0x0f00
prot_ro_value16 = 0x400004,-2,0xaa00
prot_ro_value16 = 0x400006,-2,0xf000
[Soul Blade (Unl)]
check_str = 0x104, " "
check_crc32 = 0xf26f88d1
hw = prot
prot_ro_value16 = 0x400002,-2,0x9800
prot_ro_value16 = 0x400004,-2,0xaa00 # or 0xc900
prot_ro_value16 = 0x400006,-2,0xf000
[Super Bubble Bobble (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x4820a161
hw = prot
prot_ro_value16 = 0x400000,-2,0x5500
prot_ro_value16 = 0x400002,-2,0x0f00
[Super King Kong 99 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x413dfee2
hw = prot_lk3
[Super Mario Bros. (Unl)]
check_str = 0x140, "SUPER MARIO BROS "
hw = prot
prot_ro_value16 = 0xa13000,-2,0x0c
[Super Mario 2 1998 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xf7e1b3e1
hw = prot
prot_ro_value16 = 0xa13000,-2,0x0a
[Squirrel King (R)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xb8261ff5
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0

View File

@ -0,0 +1,629 @@
/*
* Support for a few cart mappers and some protection.
* (C) notaz, 2008-2011
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "../memory.h"
/* The SSFII mapper */
static unsigned char ssf2_banks[8];
static void carthw_ssf2_write8(u32 a, u32 d)
{
u32 target, base;
if ((a & 0xfffff0) != 0xa130f0) {
PicoWrite8_io(a, d);
return;
}
a &= 0x0e;
if (a == 0)
return;
ssf2_banks[a >> 1] = d;
base = d << 19;
target = a << 18;
if (base + 0x80000 > Pico.romsize) {
elprintf(EL_ANOMALY|EL_STATUS, "ssf2: missing bank @ %06x", base);
return;
}
cpu68k_map_set(m68k_read8_map, target, target + 0x80000 - 1, Pico.rom + base, 0);
cpu68k_map_set(m68k_read16_map, target, target + 0x80000 - 1, Pico.rom + base, 0);
}
static void carthw_ssf2_mem_setup(void)
{
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_ssf2_write8, 1);
}
void carthw_ssf2_startup(void)
{
int i;
elprintf(EL_STATUS, "SSF2 mapper startup");
// default map
for (i = 0; i < 8; i++)
ssf2_banks[i] = i;
PicoCartMemSetup = carthw_ssf2_mem_setup;
}
/* Common *-in-1 pirate mapper.
* Switches banks based on addr lines when /TIME is set.
* TODO: verify
*/
static unsigned int carthw_Xin1_baddr = 0;
static void carthw_Xin1_do(u32 a, int mask, int shift)
{
int len;
carthw_Xin1_baddr = a;
a &= mask;
a <<= shift;
len = Pico.romsize - a;
if (len <= 0) {
elprintf(EL_ANOMALY|EL_STATUS, "X-in-1: missing bank @ %06x", a);
return;
}
len = (len + M68K_BANK_MASK) & ~M68K_BANK_MASK;
cpu68k_map_set(m68k_read8_map, 0x000000, len - 1, Pico.rom + a, 0);
cpu68k_map_set(m68k_read16_map, 0x000000, len - 1, Pico.rom + a, 0);
}
// TODO: test a0, reads, w16
static void carthw_Xin1_write8(u32 a, u32 d)
{
if ((a & 0xffff00) != 0xa13000) {
PicoWrite8_io(a, d);
return;
}
carthw_Xin1_do(a, 0x3f, 16);
}
static void carthw_Xin1_mem_setup(void)
{
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_Xin1_write8, 1);
}
static void carthw_Xin1_reset(void)
{
carthw_Xin1_write8(0xa13000, 0);
}
void carthw_Xin1_startup(void)
{
elprintf(EL_STATUS, "X-in-1 mapper startup");
PicoCartMemSetup = carthw_Xin1_mem_setup;
PicoResetHook = carthw_Xin1_reset;
}
/* Realtec, based on TascoDLX doc
* http://www.sharemation.com/TascoDLX/REALTEC%20Cart%20Mapper%20-%20description%20v1.txt
*/
static int realtec_bank = 0x80000000, realtec_size = 0x80000000;
static void carthw_realtec_write8(u32 a, u32 d)
{
int i, bank_old = realtec_bank, size_old = realtec_size;
if (a == 0x400000)
{
realtec_bank &= 0x0e0000;
realtec_bank |= 0x300000 & (d << 19);
if (realtec_bank != bank_old)
elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc);
}
else if (a == 0x402000)
{
realtec_size = (d << 17) & 0x3e0000;
if (realtec_size != size_old)
elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc);
}
else if (a == 0x404000)
{
realtec_bank &= 0x300000;
realtec_bank |= 0x0e0000 & (d << 17);
if (realtec_bank != bank_old)
elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc);
}
else
elprintf(EL_ANOMALY, "realtec: unexpected write [%06x] %02x @ %06x", a, d, SekPc);
if (realtec_bank >= 0 && realtec_size >= 0 &&
(realtec_bank != bank_old || realtec_size != size_old))
{
elprintf(EL_ANOMALY, "realtec: new bank %06x, size %06x", realtec_bank, realtec_size, SekPc);
if (realtec_size > Pico.romsize - realtec_bank)
{
elprintf(EL_ANOMALY, "realtec: bank too large / out of range?");
return;
}
for (i = 0; i < 0x400000; i += realtec_size) {
cpu68k_map_set(m68k_read8_map, i, realtec_size - 1, Pico.rom + realtec_bank, 0);
cpu68k_map_set(m68k_read16_map, i, realtec_size - 1, Pico.rom + realtec_bank, 0);
}
}
}
static void carthw_realtec_reset(void)
{
int i;
/* map boot code */
for (i = 0; i < 0x400000; i += M68K_BANK_SIZE) {
cpu68k_map_set(m68k_read8_map, i, i + M68K_BANK_SIZE - 1, Pico.rom + Pico.romsize, 0);
cpu68k_map_set(m68k_read16_map, i, i + M68K_BANK_SIZE - 1, Pico.rom + Pico.romsize, 0);
}
cpu68k_map_set(m68k_write8_map, 0x400000, 0x400000 + M68K_BANK_SIZE - 1, carthw_realtec_write8, 1);
realtec_bank = realtec_size = 0x80000000;
}
void carthw_realtec_startup(void)
{
int i;
elprintf(EL_STATUS, "Realtec mapper startup");
// allocate additional bank for boot code
// (we know those ROMs have aligned size)
i = PicoCartResize(Pico.romsize + M68K_BANK_SIZE);
if (i != 0) {
elprintf(EL_STATUS, "OOM");
return;
}
// create bank for boot code
for (i = 0; i < M68K_BANK_SIZE; i += 0x2000)
memcpy(Pico.rom + Pico.romsize + i, Pico.rom + Pico.romsize - 0x2000, 0x2000);
PicoResetHook = carthw_realtec_reset;
}
/* Radica mapper, based on DevSter's info
* http://devster.monkeeh.com/sega/radica/
* XXX: mostly the same as X-in-1, merge?
*/
static u32 carthw_radica_read16(u32 a)
{
if ((a & 0xffff00) != 0xa13000)
return PicoRead16_io(a);
carthw_Xin1_do(a, 0x7e, 15);
return 0;
}
static void carthw_radica_mem_setup(void)
{
cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, carthw_radica_read16, 1);
}
static void carthw_radica_reset(void)
{
carthw_radica_read16(0xa13000);
}
void carthw_radica_startup(void)
{
elprintf(EL_STATUS, "Radica mapper startup");
PicoCartMemSetup = carthw_radica_mem_setup;
PicoResetHook = carthw_radica_reset;
}
/* Pier Solar. Based on my own research */
static unsigned char pier_regs[8];
static unsigned char pier_dump_prot;
static void carthw_pier_write8(u32 a, u32 d)
{
u32 a8, target, base;
if ((a & 0xffff00) != 0xa13000) {
PicoWrite8_io(a, d);
return;
}
a8 = a & 0x0f;
pier_regs[a8 / 2] = d;
elprintf(EL_UIO, "pier w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc);
switch (a8) {
case 0x01:
break;
case 0x03:
if (!(pier_regs[0] & 2))
goto unmapped;
target = 0x280000;
base = d << 19;
goto do_map;
case 0x05:
if (!(pier_regs[0] & 2))
goto unmapped;
target = 0x300000;
base = d << 19;
goto do_map;
case 0x07:
if (!(pier_regs[0] & 2))
goto unmapped;
target = 0x380000;
base = d << 19;
goto do_map;
case 0x09:
// TODO
break;
case 0x0b:
// eeprom read
default:
unmapped:
//elprintf(EL_UIO, "pier w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc);
elprintf(EL_STATUS, "-- unmapped w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc);
break;
}
return;
do_map:
if (base + 0x80000 > Pico.romsize) {
elprintf(EL_ANOMALY|EL_STATUS, "pier: missing bank @ %06x", base);
return;
}
cpu68k_map_set(m68k_read8_map, target, target + 0x80000 - 1, Pico.rom + base, 0);
cpu68k_map_set(m68k_read16_map, target, target + 0x80000 - 1, Pico.rom + base, 0);
}
static void carthw_pier_write16(u32 a, u32 d)
{
if ((a & 0xffff00) != 0xa13000) {
PicoWrite16_io(a, d);
return;
}
elprintf(EL_UIO, "pier w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
carthw_pier_write8(a + 1, d);
}
static u32 carthw_pier_read8(u32 a)
{
if ((a & 0xffff00) != 0xa13000)
return PicoRead8_io(a);
if (a == 0xa1300b)
return 0; // TODO
elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc);
return 0;
}
static void carthw_pier_statef(void);
static u32 carthw_pier_prot_read8(u32 a)
{
/* it takes more than just these reads here to disable ROM protection,
* but for game emulation purposes this is enough. */
if (pier_dump_prot > 0)
pier_dump_prot--;
if (pier_dump_prot == 0) {
carthw_pier_statef();
elprintf(EL_STATUS, "prot off on r8 @%06x", SekPc);
}
elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc);
return Pico.rom[(a & 0x7fff) ^ 1];
}
static void carthw_pier_mem_setup(void)
{
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_pier_write8, 1);
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_pier_write16, 1);
cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, carthw_pier_read8, 1);
}
static void carthw_pier_prot_mem_setup(int prot_enable)
{
if (prot_enable) {
/* the dump protection.. */
int a;
for (a = 0x000000; a < 0x400000; a += M68K_BANK_SIZE) {
cpu68k_map_set(m68k_read8_map, a, a + 0xffff, Pico.rom + Pico.romsize, 0);
cpu68k_map_set(m68k_read16_map, a, a + 0xffff, Pico.rom + Pico.romsize, 0);
}
cpu68k_map_set(m68k_read8_map, M68K_BANK_SIZE, M68K_BANK_SIZE * 2 - 1,
carthw_pier_prot_read8, 1);
}
else {
cpu68k_map_set(m68k_read8_map, 0, 0x27ffff, Pico.rom, 0);
cpu68k_map_set(m68k_read16_map, 0, 0x27ffff, Pico.rom, 0);
}
}
static void carthw_pier_statef(void)
{
carthw_pier_prot_mem_setup(pier_dump_prot);
if (!pier_dump_prot) {
/* setup all banks */
u32 r0 = pier_regs[0];
carthw_pier_write8(0xa13001, 3);
carthw_pier_write8(0xa13003, pier_regs[1]);
carthw_pier_write8(0xa13005, pier_regs[2]);
carthw_pier_write8(0xa13007, pier_regs[3]);
carthw_pier_write8(0xa13001, r0);
}
}
static void carthw_pier_reset(void)
{
pier_regs[0] = 1;
pier_regs[1] = pier_regs[2] = pier_regs[3] = 0;
pier_dump_prot = 3;
carthw_pier_statef();
}
void carthw_pier_startup(void)
{
int i;
elprintf(EL_STATUS, "Pier Solar mapper startup");
// mostly same as for realtec..
i = PicoCartResize(Pico.romsize + M68K_BANK_SIZE);
if (i != 0) {
elprintf(EL_STATUS, "OOM");
return;
}
// create dump protection bank
for (i = 0; i < M68K_BANK_SIZE; i += 0x8000)
memcpy(Pico.rom + Pico.romsize + i, Pico.rom, 0x8000);
PicoCartMemSetup = carthw_pier_mem_setup;
PicoResetHook = carthw_pier_reset;
}
/* Simple unlicensed ROM protection emulation */
static struct {
u32 addr;
u32 mask;
u16 val;
u16 readonly;
} *sprot_items;
static int sprot_item_alloc;
static int sprot_item_count;
static u16 *carthw_sprot_get_val(u32 a, int rw_only)
{
int i;
for (i = 0; i < sprot_item_count; i++)
if ((a & sprot_items[i].mask) == sprot_items[i].addr)
if (!rw_only || !sprot_items[i].readonly)
return &sprot_items[i].val;
return NULL;
}
static u32 PicoRead8_sprot(u32 a)
{
u16 *val;
u32 d;
if (0xa10000 <= a && a < 0xa12000)
return PicoRead8_io(a);
val = carthw_sprot_get_val(a, 0);
if (val != NULL) {
d = *val;
if (!(a & 1))
d >>= 8;
elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc);
return d;
}
else {
elprintf(EL_UIO, "prot r8 [%06x] MISS @%06x", a, SekPc);
return 0;
}
}
static u32 PicoRead16_sprot(u32 a)
{
u16 *val;
if (0xa10000 <= a && a < 0xa12000)
return PicoRead16_io(a);
val = carthw_sprot_get_val(a, 0);
if (val != NULL) {
elprintf(EL_UIO, "prot r16 [%06x] %04x @%06x", a, *val, SekPc);
return *val;
}
else {
elprintf(EL_UIO, "prot r16 [%06x] MISS @%06x", a, SekPc);
return 0;
}
}
static void PicoWrite8_sprot(u32 a, u32 d)
{
u16 *val;
if (0xa10000 <= a && a < 0xa12000) {
PicoWrite8_io(a, d);
return;
}
val = carthw_sprot_get_val(a, 1);
if (val != NULL) {
if (a & 1)
*val = (*val & 0xff00) | (d | 0xff);
else
*val = (*val & 0x00ff) | (d << 8);
elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
}
else
elprintf(EL_UIO, "prot w8 [%06x] %02x MISS @%06x", a, d & 0xff, SekPc);
}
static void PicoWrite16_sprot(u32 a, u32 d)
{
u16 *val;
if (0xa10000 <= a && a < 0xa12000) {
PicoWrite16_io(a, d);
return;
}
val = carthw_sprot_get_val(a, 1);
if (val != NULL) {
*val = d;
elprintf(EL_UIO, "prot w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
}
else
elprintf(EL_UIO, "prot w16 [%06x] %04x MISS @%06x", a, d & 0xffff, SekPc);
}
void carthw_sprot_new_location(unsigned int a, unsigned int mask, unsigned short val, int is_ro)
{
if (sprot_items == NULL) {
sprot_items = calloc(8, sizeof(sprot_items[0]));
sprot_item_alloc = 8;
sprot_item_count = 0;
}
if (sprot_item_count == sprot_item_alloc) {
void *tmp;
sprot_item_alloc *= 2;
tmp = realloc(sprot_items, sprot_item_alloc);
if (tmp == NULL) {
elprintf(EL_STATUS, "OOM");
return;
}
sprot_items = tmp;
}
sprot_items[sprot_item_count].addr = a;
sprot_items[sprot_item_count].mask = mask;
sprot_items[sprot_item_count].val = val;
sprot_items[sprot_item_count].readonly = is_ro;
sprot_item_count++;
}
static void carthw_sprot_mem_setup(void)
{
int start;
// map ROM - 0x7fffff, /TIME areas (which are tipically used)
start = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
cpu68k_map_set(m68k_read8_map, start, 0x7fffff, PicoRead8_sprot, 1);
cpu68k_map_set(m68k_read16_map, start, 0x7fffff, PicoRead16_sprot, 1);
cpu68k_map_set(m68k_write8_map, start, 0x7fffff, PicoWrite8_sprot, 1);
cpu68k_map_set(m68k_write16_map, start, 0x7fffff, PicoWrite16_sprot, 1);
cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_sprot, 1);
cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_sprot, 1);
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_sprot, 1);
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_sprot, 1);
}
void carthw_sprot_startup(void)
{
elprintf(EL_STATUS, "Prot emu startup");
PicoCartMemSetup = carthw_sprot_mem_setup;
}
/* Protection emulation for Lion King 3. Credits go to Haze */
static u8 prot_lk3_cmd, prot_lk3_data;
static u32 PicoRead8_plk3(u32 a)
{
u32 d = 0;
switch (prot_lk3_cmd) {
case 1: d = prot_lk3_data >> 1; break;
case 2: // nibble rotate
d = ((prot_lk3_data >> 4) | (prot_lk3_data << 4)) & 0xff;
break;
case 3: // bit rotate
d = prot_lk3_data;
d = (d >> 4) | (d << 4);
d = ((d & 0xcc) >> 2) | ((d & 0x33) << 2);
d = ((d & 0xaa) >> 1) | ((d & 0x55) << 1);
break;
/* Top Fighter 2000 MK VIII (Unl)
case 0x98: d = 0x50; break; // prot_lk3_data == a8 here
case 0x67: d = 0xde; break; // prot_lk3_data == 7b here (rot!)
case 0xb5: d = 0x9f; break; // prot_lk3_data == 4a
*/
default:
elprintf(EL_UIO, "unhandled prot cmd %02x @%06x", prot_lk3_cmd, SekPc);
break;
}
elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc);
return d;
}
static void PicoWrite8_plk3p(u32 a, u32 d)
{
elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
if (a & 2)
prot_lk3_cmd = d;
else
prot_lk3_data = d;
}
static void PicoWrite8_plk3b(u32 a, u32 d)
{
int addr;
elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
addr = d << 15;
if (addr + 0x8000 > Pico.romsize) {
elprintf(EL_UIO|EL_ANOMALY, "prot_lk3: bank too large: %02x", d);
return;
}
if (addr == 0)
memcpy(Pico.rom, Pico.rom + Pico.romsize, 0x8000);
else
memcpy(Pico.rom, Pico.rom + addr, 0x8000);
}
static void carthw_prot_lk3_mem_setup(void)
{
cpu68k_map_set(m68k_read8_map, 0x600000, 0x7fffff, PicoRead8_plk3, 1);
cpu68k_map_set(m68k_write8_map, 0x600000, 0x6fffff, PicoWrite8_plk3p, 1);
cpu68k_map_set(m68k_write8_map, 0x700000, 0x7fffff, PicoWrite8_plk3b, 1);
}
void carthw_prot_lk3_startup(void)
{
int ret;
elprintf(EL_STATUS, "lk3 prot emu startup");
// allocate space for bank0 backup
ret = PicoCartResize(Pico.romsize + 0x8000);
if (ret != 0) {
elprintf(EL_STATUS, "OOM");
return;
}
memcpy(Pico.rom + Pico.romsize, Pico.rom, 0x8000);
PicoCartMemSetup = carthw_prot_lk3_mem_setup;
}

View File

@ -0,0 +1,28 @@
/* svp */
#include "svp/ssp16.h"
typedef struct {
unsigned char iram_rom[0x20000]; // IRAM (0-0x7ff) and program ROM (0x800-0x1ffff)
unsigned char dram[0x20000];
ssp1601_t ssp1601;
} svp_t;
extern svp_t *svp;
void PicoSVPInit(void);
void PicoSVPStartup(void);
void PicoSVPMemSetup(void);
/* misc */
void carthw_ssf2_startup(void);
void carthw_Xin1_startup(void);
void carthw_realtec_startup(void);
void carthw_radica_startup(void);
void carthw_pier_startup(void);
void carthw_sprot_startup(void);
void carthw_sprot_new_location(unsigned int a,
unsigned int mask, unsigned short val, int is_ro);
void carthw_prot_lk3_startup(void);

View File

@ -0,0 +1,67 @@
vscroll: 1 (0); 209 (26) - alternates every 4 frames
vram range for patterns: 0000-999f (low scr 0000-395f,72e0-999f; high 3980-999f)
name table address: c000
seen DMAs (in order): [300002-3026c3]->[0020-26e1] len 4961
[3026c2-303943]->[26e0-3961] len 2369
[303942-306003]->[72e0-99a1] len 4961
---
[306002-3086c3]->[3980-6041] len 4961
[3086c2-309943]->[6040-72c1] len 2369
[309942-30c003]->[72e0-99a2] len 4961
tile arrangement:
000: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
001: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
002: 001 003 005 007 009 00b 00d 00f 011 013 015 017 019 01b 01d 01f 021 023 025 027 029 02b 02d 02f 031 033 035 037 039 03b 03d 03f
003: 002 004 006 008 00a 00c 00e 010 012 014 016 018 01a 01c 01e 020 022 024 026 028 02a 02c 02e 030 032 034 036 038 03a 03c 03e 040
004: 041 043 045 047 049 04b 04d 04f 051 053 055 057 059 05b 05d 05f 061 063 065 067 069 06b 06d 06f 071 073 075 077 079 07b 07d 07f
005: 042 044 046 048 04a 04c 04e 050 052 054 056 058 05a 05c 05e 060 062 064 066 068 06a 06c 06e 070 072 074 076 078 07a 07c 07e 080
006: 081 083 085 087 089 08b 08d 08f 091 093 095 097 099 09b 09d 09f 0a1 0a3 0a5 0a7 0a9 0ab 0ad 0af 0b1 0b3 0b5 0b7 0b9 0bb 0bd 0bf
007: 082 084 086 088 08a 08c 08e 090 092 094 096 098 09a 09c 09e 0a0 0a2 0a4 0a6 0a8 0aa 0ac 0ae 0b0 0b2 0b4 0b6 0b8 0ba 0bc 0be 0c0
008: 0c1 0c3 0c5 0c7 0c9 0cb 0cd 0cf 0d1 0d3 0d5 0d7 0d9 0db 0dd 0df 0e1 0e3 0e5 0e7 0e9 0eb 0ed 0ef 0f1 0f3 0f5 0f7 0f9 0fb 0fd 0ff
009: 0c2 0c4 0c6 0c8 0ca 0cc 0ce 0d0 0d2 0d4 0d6 0d8 0da 0dc 0de 0e0 0e2 0e4 0e6 0e8 0ea 0ec 0ee 0f0 0f2 0f4 0f6 0f8 0fa 0fc 0fe 100
010: 101 103 105 107 109 10b 10d 10f 111 113 115 117 119 11b 11d 11f 121 123 125 127 129 12b 12d 12f 131 133 135 137 139 13b 13d 13f
011: 102 104 106 108 10a 10c 10e 110 112 114 116 118 11a 11c 11e 120 122 124 126 128 12a 12c 12e 130 132 134 136 138 13a 13c 13e 140
012: 141 143 145 147 149 14b 14d 14f 151 153 155 157 159 15b 15d 15f 161 163 165 167 169 16b 16d 16f 171 173 175 177 179 17b 17d 17f
013: 142 144 146 148 14a 14c 14e 150 152 154 156 158 15a 15c 15e 160 162 164 166 168 16a 16c 16e 170 172 174 176 178 17a 17c 17e 180
014: 181 183 185 187 189 18b 18d 18f 191 193 195 197 199 19b 19d 19f 1a1 1a3 1a5 1a7 1a9 1ab 1ad 1af 1b1 1b3 1b5 1b7 1b9 1bb 1bd 1bf
015: 182 184 186 188 18a 18c 18e 190 192 194 196 198 19a 19c 19e 1a0 1a2 1a4 1a6 1a8 1aa 1ac 1ae 1b0 1b2 1b4 1b6 1b8 1ba 1bc 1be 1c0
016: 1c1 1c3 1c5 1c7 1c9 397 399 39b 39d 39f 3a1 3a3 3a5 3a7 3a9 3ab 3ad 3af 3b1 3b3 3b5 3b7 3b9 3bb 3bd 3bf 3c1 3c3 3c5 3c7 3c9 3cb
017: 1c2 1c4 1c6 1c8 1ca 398 39a 39c 39e 3a0 3a2 3a4 3a6 3a8 3aa 3ac 3ae 3b0 3b2 3b4 3b6 3b8 3ba 3bc 3be 3c0 3c2 3c4 3c6 3c8 3ca 3cc
018: 3cd 3cf 3d1 3d3 3d5 3d7 3d9 3db 3dd 3df 3e1 3e3 3e5 3e7 3e9 3eb 3ed 3ef 3f1 3f3 3f5 3f7 3f9 3fb 3fd 3ff 401 403 405 407 409 40b
019: 3ce 3d0 3d2 3d4 3d6 3d8 3da 3dc 3de 3e0 3e2 3e4 3e6 3e8 3ea 3ec 3ee 3f0 3f2 3f4 3f6 3f8 3fa 3fc 3fe 400 402 404 406 408 40a 40c
020: 40d 40f 411 413 415 417 419 41b 41d 41f 421 423 425 427 429 42b 42d 42f 431 433 435 437 439 43b 43d 43f 441 443 445 447 449 44b
021: 40e 410 412 414 416 418 41a 41c 41e 420 422 424 426 428 42a 42c 42e 430 432 434 436 438 43a 43c 43e 440 442 444 446 448 44a 44c
022: 44d 44f 451 453 455 457 459 45b 45d 45f 461 463 465 467 469 46b 46d 46f 471 473 475 477 479 47b 47d 47f 481 483 485 487 489 48b
023: 44e 450 452 454 456 458 45a 45c 45e 460 462 464 466 468 46a 46c 46e 470 472 474 476 478 47a 47c 47e 480 482 484 486 488 48a 48c
024: 48d 48f 491 493 495 497 499 49b 49d 49f 4a1 4a3 4a5 4a7 4a9 4ab 4ad 4af 4b1 4b3 4b5 4b7 4b9 4bb 4bd 4bf 4c1 4c3 4c5 4c7 4c9 4cb
025: 48e 490 492 494 496 498 49a 49c 49e 4a0 4a2 4a4 4a6 4a8 4aa 4ac 4ae 4b0 4b2 4b4 4b6 4b8 4ba 4bc 4be 4c0 4c2 4c4 4c6 4c8 4ca 4cc
026: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
027: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
028: 1cc 1ce 1d0 1d2 1d4 1d6 1d8 1da 1dc 1de 1e0 1e2 1e4 1e6 1e8 1ea 1ec 1ee 1f0 1f2 1f4 1f6 1f8 1fa 1fc 1fe 200 202 204 206 208 20a
029: 1cd 1cf 1d1 1d3 1d5 1d7 1d9 1db 1dd 1df 1e1 1e3 1e5 1e7 1e9 1eb 1ed 1ef 1f1 1f3 1f5 1f7 1f9 1fb 1fd 1ff 201 203 205 207 209 20b
030: 20c 20e 210 212 214 216 218 21a 21c 21e 220 222 224 226 228 22a 22c 22e 230 232 234 236 238 23a 23c 23e 240 242 244 246 248 24a
031: 20d 20f 211 213 215 217 219 21b 21d 21f 221 223 225 227 229 22b 22d 22f 231 233 235 237 239 23b 23d 23f 241 243 245 247 249 24b
032: 24c 24e 250 252 254 256 258 25a 25c 25e 260 262 264 266 268 26a 26c 26e 270 272 274 276 278 27a 27c 27e 280 282 284 286 288 28a
033: 24d 24f 251 253 255 257 259 25b 25d 25f 261 263 265 267 269 26b 26d 26f 271 273 275 277 279 27b 27d 27f 281 283 285 287 289 28b
034: 28c 28e 290 292 294 296 298 29a 29c 29e 2a0 2a2 2a4 2a6 2a8 2aa 2ac 2ae 2b0 2b2 2b4 2b6 2b8 2ba 2bc 2be 2c0 2c2 2c4 2c6 2c8 2ca
035: 28d 28f 291 293 295 297 299 29b 29d 29f 2a1 2a3 2a5 2a7 2a9 2ab 2ad 2af 2b1 2b3 2b5 2b7 2b9 2bb 2bd 2bf 2c1 2c3 2c5 2c7 2c9 2cb
036: 2cc 2ce 2d0 2d2 2d4 2d6 2d8 2da 2dc 2de 2e0 2e2 2e4 2e6 2e8 2ea 2ec 2ee 2f0 2f2 2f4 2f6 2f8 2fa 2fc 2fe 300 302 304 306 308 30a
037: 2cd 2cf 2d1 2d3 2d5 2d7 2d9 2db 2dd 2df 2e1 2e3 2e5 2e7 2e9 2eb 2ed 2ef 2f1 2f3 2f5 2f7 2f9 2fb 2fd 2ff 301 303 305 307 309 30b
038: 30c 30e 310 312 314 316 318 31a 31c 31e 320 322 324 326 328 32a 32c 32e 330 332 334 336 338 33a 33c 33e 340 342 344 346 348 34a
039: 30d 30f 311 313 315 317 319 31b 31d 31f 321 323 325 327 329 32b 32d 32f 331 333 335 337 339 33b 33d 33f 341 343 345 347 349 34b
040: 34c 34e 350 352 354 356 358 35a 35c 35e 360 362 364 366 368 36a 36c 36e 370 372 374 376 378 37a 37c 37e 380 382 384 386 388 38a
041: 34d 34f 351 353 355 357 359 35b 35d 35f 361 363 365 367 369 36b 36d 36f 371 373 375 377 379 37b 37d 37f 381 383 385 387 389 38b
042: 38c 38e 390 392 394 397 399 39b 39d 39f 3a1 3a3 3a5 3a7 3a9 3ab 3ad 3af 3b1 3b3 3b5 3b7 3b9 3bb 3bd 3bf 3c1 3c3 3c5 3c7 3c9 3cb
043: 38d 38f 391 393 395 398 39a 39c 39e 3a0 3a2 3a4 3a6 3a8 3aa 3ac 3ae 3b0 3b2 3b4 3b6 3b8 3ba 3bc 3be 3c0 3c2 3c4 3c6 3c8 3ca 3cc
044: 3cd 3cf 3d1 3d3 3d5 3d7 3d9 3db 3dd 3df 3e1 3e3 3e5 3e7 3e9 3eb 3ed 3ef 3f1 3f3 3f5 3f7 3f9 3fb 3fd 3ff 401 403 405 407 409 40b
045: 3ce 3d0 3d2 3d4 3d6 3d8 3da 3dc 3de 3e0 3e2 3e4 3e6 3e8 3ea 3ec 3ee 3f0 3f2 3f4 3f6 3f8 3fa 3fc 3fe 400 402 404 406 408 40a 40c
046: 40d 40f 411 413 415 417 419 41b 41d 41f 421 423 425 427 429 42b 42d 42f 431 433 435 437 439 43b 43d 43f 441 443 445 447 449 44b
047: 40e 410 412 414 416 418 41a 41c 41e 420 422 424 426 428 42a 42c 42e 430 432 434 436 438 43a 43c 43e 440 442 444 446 448 44a 44c
048: 44d 44f 451 453 455 457 459 45b 45d 45f 461 463 465 467 469 46b 46d 46f 471 473 475 477 479 47b 47d 47f 481 483 485 487 489 48b
049: 44e 450 452 454 456 458 45a 45c 45e 460 462 464 466 468 46a 46c 46e 470 472 474 476 478 47a 47c 47e 480 482 484 486 488 48a 48c
050: 48d 48f 491 493 495 497 499 49b 49d 49f 4a1 4a3 4a5 4a7 4a9 4ab 4ad 4af 4b1 4b3 4b5 4b7 4b9 4bb 4bd 4bf 4c1 4c3 4c5 4c7 4c9 4cb
051: 48e 490 492 494 496 498 49a 49c 49e 4a0 4a2 4a4 4a6 4a8 4aa 4ac 4ae 4b0 4b2 4b4 4b6 4b8 4ba 4bc 4be 4c0 4c2 4c4 4c6 4c8 4ca 4cc
052: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
053: 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

View File

@ -0,0 +1,163 @@
/*
* The SVP chip emulator, mem I/O stuff
*
* Copyright (c) Gražvydas "notaz" Ignotas, 2008
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the organization 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 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.
*/
#include "../../pico_int.h"
#include "../../memory.h"
// for wait loop det
static void PicoWrite16_dram(u32 a, u32 d)
{
a &= ~0xfe0000;
if (d != 0) {
if (a == 0xfe06) // 30fe06
svp->ssp1601.emu_status &= ~SSP_WAIT_30FE06;
else if (a == 0xfe08)
svp->ssp1601.emu_status &= ~SSP_WAIT_30FE08;
}
((u16 *)svp->dram)[a / 2] = d;
}
// "cell arrange" 1: 390000-39ffff
static u32 PicoRead16_svpca1(u32 a)
{
// this is 68k code rewritten
u32 a1 = a >> 1;
a1 = (a1 & 0x7001) | ((a1 & 0x3e) << 6) | ((a1 & 0xfc0) >> 5);
return ((u16 *)svp->dram)[a1];
}
// "cell arrange" 2: 3a0000-3affff
static u32 PicoRead16_svpca2(u32 a)
{
u32 a1 = a >> 1;
a1 = (a1 & 0x7801) | ((a1 & 0x1e) << 6) | ((a1 & 0x7e0) >> 4);
return ((u16 *)svp->dram)[a1];
}
// IO/control area (0xa10000 - 0xa1ffff)
static u32 PicoRead16_svpr(u32 a)
{
u32 d = 0;
// regs
if ((a & ~0x0f) == 0xa15000) {
switch (a & 0xf) {
case 0:
case 2:
d = svp->ssp1601.gr[SSP_XST].h;
break;
case 4:
d = svp->ssp1601.gr[SSP_PM0].h;
svp->ssp1601.gr[SSP_PM0].h &= ~1;
break;
}
#if EL_LOGMASK & EL_SVP
{
static int a15004_looping = 0;
if (a == 0xa15004 && (d & 1))
a15004_looping = 0;
if (!a15004_looping)
elprintf(EL_SVP, "SVP r%i: [%06x] %04x @%06x", realsize, a, d, SekPc);
if (a == 0xa15004 && !(d&1)) {
if (!a15004_looping)
elprintf(EL_SVP, "SVP det TIGHT loop: a15004");
a15004_looping = 1;
}
else
a15004_looping = 0;
}
#endif
return d;
}
//if (a == 0x30fe02 && d == 0)
// elprintf(EL_ANOMALY, "SVP lag?");
return PicoRead16_io(a);
}
// used in VR test mode
static u32 PicoRead8_svpr(u32 a)
{
u32 d;
if ((a & ~0x0f) != 0xa15000)
return PicoRead8_io(a);
d = PicoRead16_svpr(a & ~1);
if (!(a & 1))
d >>= 8;
return d;
}
static void PicoWrite16_svpr(u32 a, u32 d)
{
elprintf(EL_SVP, "SVP w16: [%06x] %04x @%06x", a, d, SekPc);
if ((a & ~0x0f) == 0xa15000) {
if (a == 0xa15000 || a == 0xa15002) {
// just guessing here
svp->ssp1601.gr[SSP_XST].h = d;
svp->ssp1601.gr[SSP_PM0].h |= 2;
svp->ssp1601.emu_status &= ~SSP_WAIT_PM0;
}
//else if (a == 0xa15006) svp->ssp1601.gr[SSP_PM0].h = d | (d << 1);
// 0xa15006 probably has 'halt'
return;
}
PicoWrite16_io(a, d);
}
void PicoSVPMemSetup(void)
{
// 68k memmap:
// DRAM
cpu68k_map_set(m68k_read8_map, 0x300000, 0x31ffff, svp->dram, 0);
cpu68k_map_set(m68k_read16_map, 0x300000, 0x31ffff, svp->dram, 0);
cpu68k_map_set(m68k_write8_map, 0x300000, 0x31ffff, svp->dram, 0);
cpu68k_map_set(m68k_write16_map, 0x300000, 0x31ffff, svp->dram, 0);
cpu68k_map_set(m68k_write16_map, 0x300000, 0x30ffff, PicoWrite16_dram, 1);
// DRAM (cell arrange)
cpu68k_map_set(m68k_read16_map, 0x390000, 0x39ffff, PicoRead16_svpca1, 1);
cpu68k_map_set(m68k_read16_map, 0x3a0000, 0x3affff, PicoRead16_svpca2, 1);
// regs
cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_svpr, 1);
cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_svpr, 1);
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_io, 1); // PicoWrite8_svpr
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_svpr, 1);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,92 @@
/*
* basic, incomplete SSP160x (SSP1601?) interpreter
*
* Copyright (c) Gražvydas "notaz" Ignotas, 2008
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the organization 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 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.
*/
// register names
enum {
SSP_GR0, SSP_X, SSP_Y, SSP_A,
SSP_ST, SSP_STACK, SSP_PC, SSP_P,
SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
};
typedef union
{
unsigned int v;
struct {
unsigned short l;
unsigned short h;
};
} ssp_reg_t;
typedef struct
{
union {
unsigned short RAM[256*2]; // 000 2 internal RAM banks
struct {
unsigned short RAM0[256];
unsigned short RAM1[256];
};
};
ssp_reg_t gr[16]; // 400 general registers
union {
unsigned char r[8]; // 440 BANK pointers
struct {
unsigned char r0[4];
unsigned char r1[4];
};
};
unsigned short stack[6]; // 448
unsigned int pmac_read[6]; // 454 read modes/addrs for PM0-PM5
unsigned int pmac_write[6]; // 46c write ...
//
#define SSP_PMC_HAVE_ADDR 0x0001 // address written to PMAC, waiting for mode
#define SSP_PMC_SET 0x0002 // PMAC is set
#define SSP_WAIT_PM0 0x2000 // bit1 in PM0
#define SSP_WAIT_30FE06 0x4000 // ssp tight loops on 30FE06 to become non-zero
#define SSP_WAIT_30FE08 0x8000 // same for 30FE06
#define SSP_WAIT_MASK 0xe000
unsigned int emu_status; // 484
/* used by recompiler only: */
struct {
unsigned int ptr_rom; // 488
unsigned int ptr_iram_rom; // 48c
unsigned int ptr_dram; // 490
unsigned int iram_dirty; // 494
unsigned int iram_context; // 498
unsigned int ptr_btable; // 49c
unsigned int ptr_btable_iram; // 4a0
unsigned int tmp0; // 4a4
unsigned int tmp1; // 4a8
unsigned int tmp2; // 4ac
} drc;
} ssp1601_t;
void ssp1601_reset(ssp1601_t *ssp);
void ssp1601_run(int cycles);

View File

@ -0,0 +1,150 @@
/*
* The SVP chip emulator
*
* Copyright (c) Gražvydas "notaz" Ignotas, 2008
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the organization 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 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.
*/
#include <pico/pico_int.h>
svp_t *svp = NULL;
int PicoSVPCycles = 850; // cycles/line, just a guess
static int svp_dyn_ready = 0;
static void PicoSVPReset(void)
{
elprintf(EL_SVP, "SVP reset");
memcpy(svp->iram_rom + 0x800, Pico.rom + 0x800, 0x20000 - 0x800);
ssp1601_reset(&svp->ssp1601);
#ifdef _SVP_DRC
if ((PicoOpt & POPT_EN_DRC) && svp_dyn_ready)
ssp1601_dyn_reset(&svp->ssp1601);
#endif
}
static void PicoSVPLine(void)
{
int count = 1;
#if defined(__arm__) || defined(PSP)
// performance hack
static int delay_lines = 0;
delay_lines++;
if ((Pico.m.scanline&0xf) != 0xf && Pico.m.scanline != 261 && Pico.m.scanline != 311)
return;
count = delay_lines;
delay_lines = 0;
#endif
#ifdef _SVP_DRC
if ((PicoOpt & POPT_EN_DRC) && svp_dyn_ready)
ssp1601_dyn_run(PicoSVPCycles * count);
else
#endif
{
ssp1601_run(PicoSVPCycles * count);
svp_dyn_ready = 0; // just in case
}
// test mode
//if (Pico.m.frame_count == 13) PicoPad[0] |= 0xff;
}
static int PicoSVPDma(unsigned int source, int len, unsigned short **srcp, unsigned short **limitp)
{
if (source < Pico.romsize) // Rom
{
source -= 2;
*srcp = (unsigned short *)(Pico.rom + (source&~1));
*limitp = (unsigned short *)(Pico.rom + Pico.romsize);
return 1;
}
else if ((source & 0xfe0000) == 0x300000)
{
elprintf(EL_VDPDMA|EL_SVP, "SVP DmaSlow from %06x, len=%i", source, len);
source &= 0x1fffe;
source -= 2;
*srcp = (unsigned short *)(svp->dram + source);
*limitp = (unsigned short *)(svp->dram + sizeof(svp->dram));
return 1;
}
else
elprintf(EL_VDPDMA|EL_SVP|EL_ANOMALY, "SVP FIXME unhandled DmaSlow from %06x, len=%i", source, len);
return 0;
}
void PicoSVPInit(void)
{
#ifdef _SVP_DRC
// this is to unmap tcache and make
// mem available for large ROMs, MCD, etc.
drc_cmn_cleanup();
#endif
}
static void PicoSVPExit(void)
{
#ifdef _SVP_DRC
ssp1601_dyn_exit();
#endif
}
void PicoSVPStartup(void)
{
int ret;
elprintf(EL_STATUS, "SVP startup");
ret = PicoCartResize(Pico.romsize + sizeof(*svp));
if (ret != 0) {
elprintf(EL_STATUS|EL_SVP, "OOM for SVP data");
return;
}
svp = (void *) ((char *)Pico.rom + Pico.romsize);
memset(svp, 0, sizeof(*svp));
// init SVP compiler
svp_dyn_ready = 0;
#ifdef _SVP_DRC
if (PicoOpt & POPT_EN_DRC) {
if (ssp1601_dyn_startup())
return;
svp_dyn_ready = 1;
}
#endif
// init ok, setup hooks..
PicoCartMemSetup = PicoSVPMemSetup;
PicoDmaHook = PicoSVPDma;
PicoResetHook = PicoSVPReset;
PicoLineHook = PicoSVPLine;
PicoAHW |= PAHW_SVP;
}

View File

@ -0,0 +1,229 @@
/* generated by ./tools/make_carthw_c, do not modify */
static const char builtin_carthw_cfg[] =
"[]\n"
"check_str=0x150,\"Virtua Racing\"\n"
"check_str=0x810,\"OHMP\"\n"
"hw=svp\n"
"[]\n"
"check_str=0x150,\"VIRTUA RACING\"\n"
"check_str=0x810,\"OHMP\"\n"
"hw=svp\n"
"[]\n"
"check_str=0x100,\"SEGA PICO\"\n"
"hw=pico\n"
"[]\n"
"check_str=0x100,\"IMA IKUNOUJYUKU\"\n"
"hw=pico\n"
"[]\n"
"check_str=0x120,\"PUGGSY\"\n"
"prop=no_sram\n"
"[]\n"
"check_str=0x150,\"DINO DINI'S SOCCER\"\n"
"prop=filled_sram\n"
"[]\n"
"check_str=0x150,\"MICRO MACHINES II\"\n"
"prop=filled_sram\n"
"[]\n"
"check_str=0x150,\"32X SAMPLE PROGRAM\"\n"
"check_str=0x32b74c,\"Bishop Level\"\n"
"prop=force_6btn\n"
"[]\n"
"check_str=0x150,\"SUPER STREET FIGHTER2 The New Challengers\"\n"
"hw=ssf2_mapper\n"
"prop=no_sram\n"
"[]\n"
"check_str=0x150,\"PIER\"\n"
"check_str=0x610,\"Respect\"\n"
"hw=piersolar_mapper\n"
"[]\n"
"check_str=0x120,\"FLICKY\"\n"
"check_size_gt=0x020000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x150,\"ROBOCOP 3\"\n"
"check_size_gt=0x080000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x150,\"ALIEN 3\"\n"
"check_size_gt=0x080000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x150,\" SHOVE IT!\"\n"
"check_size_gt=0x020000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x150,\"MS PACMAN\"\n"
"check_size_gt=0x020000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x150,\"KID CHAMELEON\"\n"
"check_size_gt=0x100000\n"
"hw=radica_mapper\n"
"[]\n"
"check_str=0x94,\"THE EARTH DEFEND\"\n"
"hw=realtec_mapper\n"
"[]\n"
"check_str=0xfe,\"WISEGAME 11-03-1993\"\n"
"hw=realtec_mapper\n"
"[]\n"
"check_str=0x95,\"MALLET LEGEND\"\n"
"hw=realtec_mapper\n"
"[]\n"
"check_str=0x150,\"COLLEGE SLAM\"\n"
"eeprom_type=3\n"
"eeprom_lines=8,0,0\n"
"[]\n"
"check_str=0x150,\"FRANK THOMAS BIGHURT BASEBAL\"\n"
"eeprom_type=3\n"
"eeprom_lines=8,0,0\n"
"[]\n"
"check_str=0x150,\"MICRO MACHINES II\"\n"
"sram_range=0x300000,0x380001\n"
"eeprom_type=2\n"
"eeprom_lines=9,8,7\n"
"[]\n"
"check_str=0x150,\" \"\n"
"check_csum=0x165e\n"
"sram_range=0x300000,0x380001\n"
"eeprom_type=2\n"
"eeprom_lines=9,8,7\n"
"[]\n"
"check_str=0x150,\" \"\n"
"check_csum=0x2c41\n"
"sram_range=0x300000,0x380001\n"
"eeprom_type=2\n"
"eeprom_lines=9,8,7\n"
"[]\n"
"check_str=0x150,\" \"\n"
"check_csum=0x168b\n"
"sram_range=0x300000,0x380001\n"
"eeprom_type=2\n"
"eeprom_lines=9,8,7\n"
"[]\n"
"check_str=0x150,\" \"\n"
"check_csum=0xcee0\n"
"sram_range=0x300000,0x380001\n"
"eeprom_type=2\n"
"eeprom_lines=9,8,7\n"
"[]\n"
"check_str=0x150,\"NBA JAM \"\n"
"eeprom_type=2\n"
"eeprom_lines=1,0,1\n"
"[]\n"
"check_str=0x150,\"NBA JAM TOURNAMENT EDITION\"\n"
"sram_range=0x200000,0x200001\n"
"eeprom_type=2\n"
"eeprom_lines=8,0,0\n"
"[]\n"
"check_str=0x150,\"NFL QUARTERBACK CLUB\"\n"
"eeprom_type=2\n"
"eeprom_lines=8,0,0\n"
"[]\n"
"check_str=0x150,\"NHLPA Hockey '93\"\n"
"sram_range=0x200000,0x200001\n"
"eeprom_type=1\n"
"eeprom_lines=6,7,7\n"
"[]\n"
"check_str=0x150,\"NHLPA HOCKEY '93\"\n"
"sram_range=0x200000,0x200001\n"
"eeprom_type=1\n"
"eeprom_lines=6,7,7\n"
"[]\n"
"check_str=0x150,\"RINGS OF POWER\"\n"
"sram_range=0x200000,0x200001\n"
"eeprom_type=1\n"
"eeprom_lines=6,7,7\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x10458e09\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,0xffff00,0x28\n"
"[]\n"
"check_str=0x172,\"GAME : ELF WOR\"\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x5500\n"
"prot_ro_value16=0x400002,-2,0xc900#checkisdoneiftheaboveonefails\n"
"prot_ro_value16=0x400004,-2,0x0f00\n"
"prot_ro_value16=0x400006,-2,0x1800#similartoabove\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xcbc38eea\n"
"hw=prot\n"
"prot_ro_value16=0x480000,0xff0000,0xaa00\n"
"prot_ro_value16=0x4a0000,0xff0000,0x0a00\n"
"prot_ro_value16=0x4c0000,0xff0000,0xf000\n"
"prot_ro_value16=0x400000,0xc00000,0x0000#defaultfor400000-7f0000\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xc004219d\n"
"hw=prot_lk3\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xaff46765\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00004,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_str=0x118,\"CREATON. \"\n"
"check_crc32=0xddd02ba4\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x9000\n"
"prot_ro_value16=0x401000,-2,0xd300\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xf68f6367\n"
"hw=prot\n"
"prot_ro_value16=0xa13002,-2,0x01\n"
"prot_ro_value16=0xa1303e,-2,0x1f\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xfb176667\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x14\n"
"prot_ro_value16=0xa13002,-2,0x01\n"
"prot_ro_value16=0xa1303e,-2,0x1f\n"
"[]\n"
"check_csum=0\n"
"check_crc32=0x3ee639f0\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x0c\n"
"[]\n"
"check_csum=0\n"
"check_crc32=0xdecdf740\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x5500\n"
"prot_ro_value16=0x400002,-2,0x0f00\n"
"prot_ro_value16=0x400004,-2,0xaa00\n"
"prot_ro_value16=0x400006,-2,0xf000\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xf26f88d1\n"
"hw=prot\n"
"prot_ro_value16=0x400002,-2,0x9800\n"
"prot_ro_value16=0x400004,-2,0xaa00#or0xc900\n"
"prot_ro_value16=0x400006,-2,0xf000\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x4820a161\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x5500\n"
"prot_ro_value16=0x400002,-2,0x0f00\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x413dfee2\n"
"hw=prot_lk3\n"
"[]\n"
"check_str=0x140,\"SUPER MARIO BROS \"\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x0c\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xf7e1b3e1\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x0a\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xb8261ff5\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
;

View File

@ -0,0 +1,268 @@
/*
* CD image handler
* (C) notaz, 2007,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "genplus_macros.h"
#include "cdd.h"
#include "cue.h"
static int handle_mp3(const char *fname, int index)
{
track_t *track = &cdd.toc.tracks[index];
FILE *tmp_file;
int kBps;
int fs, ret;
tmp_file = fopen(fname, "rb");
if (tmp_file == NULL)
return -1;
ret = fseek(tmp_file, 0, SEEK_END);
fs = ftell(tmp_file);
fseek(tmp_file, 0, SEEK_SET);
#ifdef _PSP_FW_VERSION
// some systems (like PSP) can't have many open files at a time,
// so we work with their names instead.
fclose(tmp_file);
tmp_file = (void *) strdup(fname);
#endif
kBps = mp3_get_bitrate(tmp_file, fs) / 8;
if (ret != 0 || kBps <= 0)
{
elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, kBps);
#ifdef _PSP_FW_VERSION
free(tmp_file);
#else
fclose(tmp_file);
#endif
return -1;
}
track->fd = tmp_file;
track->offset = 0;
fs *= 75;
fs /= kBps * 1000;
return fs;
}
static void to_upper(char *d, const char *s)
{
for (; *s != 0; d++, s++) {
if ('a' <= *s && *s <= 'z')
*d = *s - 'a' + 'A';
else
*d = *s;
}
}
// cdd.c uses lba - 150
static void sprintf_lba(char *buf, size_t size, int lba)
{
lba += 150;
snprintf(buf, size, "%02d:%02d:%02d", lba / 60 / 75,
(lba / 75) % 60, lba % 75);
}
int load_cd_image(const char *cd_img_name, int *type)
{
static const char *exts[] = {
"%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
"%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
};
int i, j, n, lba, index, length, ret;
int iso_name_len, missed, cd_img_sectors;
char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
track_t *tracks = cdd.toc.tracks;
cue_data_t *cue_data = NULL;
pm_file *pmf;
if (PicoCDLoadProgressCB != NULL)
PicoCDLoadProgressCB(cd_img_name, 1);
Pico_mcd->cdda_type = CT_UNKNOWN;
/* is this a .cue? */
cue_data = cue_parse(cd_img_name);
if (cue_data != NULL) {
cd_img_name = cue_data->tracks[1].fname;
*type = cue_data->tracks[1].type;
}
pmf = pm_open(cd_img_name);
if (pmf == NULL)
{
if (cue_data != NULL)
cue_destroy(cue_data);
return -1;
}
tracks[0].fd = pmf;
if (*type == CT_ISO)
cd_img_sectors = pmf->size >>= 11; // size in sectors
else cd_img_sectors = pmf->size /= 2352;
// cdd.c operates with lba - 150
tracks[0].start = 0;
tracks[0].end = cd_img_sectors;
tracks[0].offset = 0;
sprintf_lba(tmp_ext, sizeof(tmp_ext), 0);
elprintf(EL_STATUS, "Track 1: %s %9i DATA %s",
tmp_ext, tracks[0].end, cd_img_name);
lba = cd_img_sectors;
if (cue_data != NULL)
{
if (cue_data->tracks[2].fname == NULL) {
// NULL fname means track2 is in same file as track1
lba = tracks[0].end = cue_data->tracks[2].sector_offset;
}
i = 100 / cue_data->track_count + 1; // progress display
for (n = 2; n <= cue_data->track_count; n++)
{
if (PicoCDLoadProgressCB != NULL)
PicoCDLoadProgressCB(cd_img_name, i * n);
index = n - 1;
lba += cue_data->tracks[n].pregap;
if (cue_data->tracks[n].type == CT_MP3) {
ret = handle_mp3(cue_data->tracks[n].fname, index);
if (ret < 0)
break;
length = ret;
}
else if (cue_data->tracks[n].fname != NULL)
{
pm_file *f = pm_open(cue_data->tracks[n].fname);
if (f != NULL)
{
// assume raw, ignore header for wav..
tracks[index].fd = f;
tracks[index].offset = cue_data->tracks[n].sector_offset;
length = f->size / 2352;
}
else
{
elprintf(EL_STATUS, "track %2i (%s): can't determine length",
n, cue_data->tracks[n].fname);
tracks[index].offset = 0;
length = 2*75;
}
}
else
{
if (n < cue_data->track_count)
length = cue_data->tracks[n+1].sector_offset -
cue_data->tracks[n].sector_offset;
else
length = cd_img_sectors - cue_data->tracks[n].sector_offset;
tracks[index].offset = cue_data->tracks[n].sector_offset;
}
if (cue_data->tracks[n].sector_xlength != 0)
// overriden by custom cue command
length = cue_data->tracks[n].sector_xlength;
Pico_mcd->cdda_type = cue_data->tracks[n].type;
tracks[index].start = lba;
lba += length;
tracks[index].end = lba;
sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s",
n, tmp_ext, length, cue_data->tracks[n].fname);
}
goto finish;
}
/* mp3 track autosearch, Gens-like */
iso_name_len = strlen(cd_img_name);
if (iso_name_len >= sizeof(tmp_name))
iso_name_len = sizeof(tmp_name) - 1;
for (n = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
{
if (PicoCDLoadProgressCB != NULL && i > 1)
PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4);
for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
{
int ext_len;
char *p;
index = n - 1;
snprintf(tmp_ext, sizeof(tmp_ext), exts[j], i);
ext_len = strlen(tmp_ext);
to_upper(tmp_ext_u, tmp_ext);
memcpy(tmp_name, cd_img_name, iso_name_len + 1);
p = tmp_name + iso_name_len - 4;
strcpy(p, tmp_ext);
ret = handle_mp3(tmp_name, index);
if (ret <= 0) {
strcpy(p, tmp_ext_u);
ret = handle_mp3(tmp_name, index);
}
if (ret <= 0 && i > 1 && iso_name_len > ext_len) {
p = tmp_name + iso_name_len - ext_len;
strcpy(p, tmp_ext);
ret = handle_mp3(tmp_name, index);
if (ret <= 0) {
strcpy(p, tmp_ext_u);
ret = handle_mp3(tmp_name, index);
}
}
if (ret > 0)
{
length = ret;
tracks[index].start = lba;
lba += length;
tracks[index].end = lba;
Pico_mcd->cdda_type = CT_MP3;
sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO - %s",
n, tmp_ext, length, tmp_name);
n++;
missed = 0;
break;
}
}
if (ret <= 0 && i > 1)
missed++;
}
finish:
cdd.toc.last = n - 1;
cdd.toc.end = lba;
sprintf_lba(tmp_ext, sizeof(tmp_ext), cdd.toc.end);
elprintf(EL_STATUS, "End CD - %s\n", tmp_ext);
if (PicoCDLoadProgressCB != NULL)
PicoCDLoadProgressCB(cd_img_name, 100);
if (cue_data != NULL)
cue_destroy(cue_data);
return 0;
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,846 @@
/***************************************************************************************
* Genesis Plus
* CD data controller (LC89510 compatible)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "../pico_int.h"
#include "genplus_macros.h"
/* IFSTAT register bitmasks */
#define BIT_DTEI 0x40
#define BIT_DECI 0x20
#define BIT_DTBSY 0x08
#define BIT_DTEN 0x02
/* IFCTRL register bitmasks */
#define BIT_DTEIEN 0x40
#define BIT_DECIEN 0x20
#define BIT_DOUTEN 0x02
/* CTRL0 register bitmasks */
#define BIT_DECEN 0x80
#define BIT_E01RQ 0x20
#define BIT_AUTORQ 0x10
#define BIT_WRRQ 0x04
/* CTRL1 register bitmasks */
#define BIT_MODRQ 0x08
#define BIT_FORMRQ 0x04
#define BIT_SHDREN 0x01
/* CTRL2 register bitmask */
#define BIT_VALST 0x80
/* PicoDrive: doing DMA at once, not using callbacks */
//#define DMA_BYTES_PER_LINE 512
enum dma_type {
word_ram_0_dma_w = 1,
word_ram_1_dma_w = 2,
word_ram_2M_dma_w = 3,
pcm_ram_dma_w = 4,
prg_ram_dma_w = 5,
};
/* CDC hardware */
typedef struct
{
uint8 ifstat;
uint8 ifctrl;
uint16 dbc;
uint16 dac;
uint16 pt;
uint16 wa;
uint8 ctrl[2];
uint8 head[2][4];
uint8 stat[4];
int cycles;
//void (*dma_w)(unsigned int words);
int dma_w;
uint8 ram[0x4000 + 2352]; /* 16K external RAM (with one block overhead to handle buffer overrun) */
} cdc_t;
static cdc_t cdc;
void cdc_init(void)
{
memset(&cdc, 0, sizeof(cdc_t));
}
void cdc_reset(void)
{
/* reset CDC register index */
Pico_mcd->s68k_regs[0x04+1] = 0x00;
/* reset CDC registers */
cdc.ifstat = 0xff;
cdc.ifctrl = 0x00;
cdc.ctrl[0] = 0x00;
cdc.ctrl[1] = 0x00;
cdc.stat[0] = 0x00;
cdc.stat[1] = 0x00;
cdc.stat[2] = 0x00;
cdc.stat[3] = 0x80;
cdc.head[0][0] = 0x00;
cdc.head[0][1] = 0x00;
cdc.head[0][2] = 0x00;
cdc.head[0][3] = 0x01;
cdc.head[1][0] = 0x00;
cdc.head[1][1] = 0x00;
cdc.head[1][2] = 0x00;
cdc.head[1][3] = 0x00;
/* reset CDC cycle counter */
cdc.cycles = 0;
/* DMA transfer disabled */
cdc.dma_w = 0;
}
int cdc_context_save(uint8 *state)
{
uint8 tmp8;
int bufferptr = 0;
if (cdc.dma_w == pcm_ram_dma_w)
{
tmp8 = 1;
}
else if (cdc.dma_w == prg_ram_dma_w)
{
tmp8 = 2;
}
else if (cdc.dma_w == word_ram_0_dma_w)
{
tmp8 = 3;
}
else if (cdc.dma_w == word_ram_1_dma_w)
{
tmp8 = 4;
}
else if (cdc.dma_w == word_ram_2M_dma_w)
{
tmp8 = 5;
}
else
{
tmp8 = 0;
}
save_param(&cdc, sizeof(cdc));
save_param(&tmp8, 1);
return bufferptr;
}
int cdc_context_load(uint8 *state)
{
uint8 tmp8;
int bufferptr = 0;
load_param(&cdc, sizeof(cdc));
load_param(&tmp8, 1);
switch (tmp8)
{
case 1:
cdc.dma_w = pcm_ram_dma_w;
break;
case 2:
cdc.dma_w = prg_ram_dma_w;
break;
case 3:
cdc.dma_w = word_ram_0_dma_w;
break;
case 4:
cdc.dma_w = word_ram_1_dma_w;
break;
case 5:
cdc.dma_w = word_ram_2M_dma_w;
break;
default:
cdc.dma_w = 0;
break;
}
return bufferptr;
}
int cdc_context_load_old(uint8 *state)
{
#define old_load(v, ofs) \
memcpy(&cdc.v, state + ofs, sizeof(cdc.v))
memcpy(cdc.ram, state, 0x4000);
old_load(ifstat, 67892);
old_load(ifctrl, 67924);
old_load(dbc, 67896);
old_load(dac, 67900);
old_load(pt, 67908);
old_load(wa, 67912);
old_load(ctrl, 67928);
old_load(head[0], 67904);
old_load(stat, 67916);
cdc.dma_w = 0;
switch (Pico_mcd->s68k_regs[0x04+0] & 0x07)
{
case 4: /* PCM RAM DMA */
cdc.dma_w = pcm_ram_dma_w;
break;
case 5: /* PRG-RAM DMA */
cdc.dma_w = prg_ram_dma_w;
break;
case 7: /* WORD-RAM DMA */
if (Pico_mcd->s68k_regs[0x02+1] & 0x04)
{
if (Pico_mcd->s68k_regs[0x02+1] & 0x01)
cdc.dma_w = word_ram_0_dma_w;
else
cdc.dma_w = word_ram_1_dma_w;
}
else
{
if (Pico_mcd->s68k_regs[0x02+1] & 0x02)
cdc.dma_w = word_ram_2M_dma_w;
}
break;
}
return 0x10960; // sizeof(old_cdc)
#undef old_load
}
static void do_dma(enum dma_type type, int words_in)
{
int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b];
int src_addr = cdc.dac & 0x3ffe;
int dst_addr = dma_addr;
int words = words_in;
int dst_limit = 0;
uint8 *dst;
int len;
elprintf(EL_CD, "dma %d %04x->%04x %x",
type, cdc.dac, dst_addr, words_in);
switch (type)
{
case pcm_ram_dma_w:
dst_addr = (dst_addr << 2) & 0xffc;
if (dst_addr + words * 2 > 0x1000) {
elprintf(EL_ANOMALY, "pcm dma oflow: %x %x", dst_addr, words);
words = (0x1000 - dst_addr) / 2;
}
dst = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank];
dst = dst + dst_addr;
while (words > 0)
{
if (src_addr + words * 2 > 0x4000) {
len = 0x4000 - src_addr;
memcpy(dst, cdc.ram + src_addr, len);
dst += len;
src_addr = 0;
words -= len / 2;
continue;
}
memcpy(dst, cdc.ram + src_addr, words * 2);
break;
}
goto update_dma;
case prg_ram_dma_w:
dst_addr <<= 3;
dst = Pico_mcd->prg_ram + dst_addr;
dst_limit = 0x80000;
break;
case word_ram_0_dma_w:
dst_addr = (dst_addr << 3) & 0x1fffe;
dst = Pico_mcd->word_ram1M[0] + dst_addr;
dst_limit = 0x20000;
break;
case word_ram_1_dma_w:
dst_addr = (dst_addr << 3) & 0x1fffe;
dst = Pico_mcd->word_ram1M[1] + dst_addr;
dst_limit = 0x20000;
break;
case word_ram_2M_dma_w:
dst_addr = (dst_addr << 3) & 0x3fffe;
dst = Pico_mcd->word_ram2M + dst_addr;
dst_limit = 0x40000;
break;
default:
elprintf(EL_ANOMALY, "invalid dma: %d", type);
goto update_dma;
}
if (dst_addr + words * 2 > dst_limit) {
elprintf(EL_ANOMALY, "cd dma %d oflow: %x %x", type, dst_addr, words);
words = (dst_limit - dst_addr) / 2;
}
while (words > 0)
{
if (src_addr + words * 2 > 0x4000) {
len = 0x4000 - src_addr;
memcpy16bswap((void *)dst, cdc.ram + src_addr, len / 2);
dst += len;
src_addr = 0;
words -= len / 2;
continue;
}
memcpy16bswap((void *)dst, cdc.ram + src_addr, words);
break;
}
update_dma:
/* update DMA addresses */
cdc.dac += words_in * 2;
if (type == pcm_ram_dma_w)
dma_addr += words_in >> 1;
else
dma_addr += words_in >> 2;
Pico_mcd->s68k_regs[0x0a] = dma_addr >> 8;
Pico_mcd->s68k_regs[0x0b] = dma_addr;
}
void cdc_dma_update(void)
{
/* end of DMA transfer ? */
//if (cdc.dbc < DMA_BYTES_PER_LINE)
{
/* transfer remaining words using 16-bit DMA */
//cdc.dma_w((cdc.dbc + 1) >> 1);
do_dma(cdc.dma_w, (cdc.dbc + 1) >> 1);
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc = 0xf000;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DTE irq 5");
SekInterruptS68k(5);
}
}
/* clear DSR bit & set EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
/* disable DMA transfer */
cdc.dma_w = 0;
}
#if 0
else
{
/* transfer all words using 16-bit DMA */
cdc.dma_w(DMA_BYTES_PER_LINE >> 1);
/* decrement data byte counter */
cdc.dbc -= length;
}
#endif
}
int cdc_decoder_update(uint8 header[4])
{
/* data decoding enabled ? */
if (cdc.ctrl[0] & BIT_DECEN)
{
/* update HEAD registers */
memcpy(cdc.head[0], header, sizeof(cdc.head[0]));
/* set !VALST */
cdc.stat[3] = 0x00;
/* pending decoder interrupt */
cdc.ifstat &= ~BIT_DECI;
/* decoder interrupt enabled ? */
if (cdc.ifctrl & BIT_DECIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DEC irq 5");
SekInterruptS68k(5);
}
}
/* buffer RAM write enabled ? */
if (cdc.ctrl[0] & BIT_WRRQ)
{
uint16 offset;
/* increment block pointer */
cdc.pt += 2352;
/* increment write address */
cdc.wa += 2352;
/* CDC buffer address */
offset = cdc.pt & 0x3fff;
/* write CDD block header (4 bytes) */
memcpy(cdc.ram + offset, header, 4);
/* write CDD block data (2048 bytes) */
cdd_read_data(cdc.ram + 4 + offset);
/* take care of buffer overrun */
if (offset > (0x4000 - 2048 - 4))
{
/* data should be written at the start of buffer */
memcpy(cdc.ram, cdc.ram + 0x4000, offset + 2048 + 4 - 0x4000);
}
/* read next data block */
return 1;
}
}
/* keep decoding same data block if Buffer Write is disabled */
return 0;
}
void cdc_reg_w(unsigned char data)
{
#ifdef LOG_CDC
elprintf(EL_STATUS, "CDC register %X write 0x%04x", Pico_mcd->s68k_regs[0x04+1] & 0x0F, data);
#endif
switch (Pico_mcd->s68k_regs[0x04+1] & 0x0F)
{
case 0x01: /* IFCTRL */
{
/* pending interrupts ? */
if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||
((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc pending irq 5");
SekInterruptS68k(5);
}
}
else // if (scd.pending & (1 << 5))
{
/* clear pending level 5 interrupts */
SekInterruptClearS68k(5);
}
/* abort any data transfer if data output is disabled */
if (!(data & BIT_DOUTEN))
{
/* clear !DTBSY and !DTEN */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
}
cdc.ifctrl = data;
Pico_mcd->s68k_regs[0x04+1] = 0x02;
break;
}
case 0x02: /* DBCL */
cdc.dbc &= 0xff00;
cdc.dbc |= data;
Pico_mcd->s68k_regs[0x04+1] = 0x03;
break;
case 0x03: /* DBCH */
cdc.dbc &= 0x00ff;
cdc.dbc |= data << 8;
Pico_mcd->s68k_regs[0x04+1] = 0x04;
break;
case 0x04: /* DACL */
cdc.dac &= 0xff00;
cdc.dac |= data;
Pico_mcd->s68k_regs[0x04+1] = 0x05;
break;
case 0x05: /* DACH */
cdc.dac &= 0x00ff;
cdc.dac |= data << 8;
Pico_mcd->s68k_regs[0x04+1] = 0x06;
break;
case 0x06: /* DTRG */
{
/* start data transfer if data output is enabled */
if (cdc.ifctrl & BIT_DOUTEN)
{
/* set !DTBSY */
cdc.ifstat &= ~BIT_DTBSY;
/* clear DBCH bits 4-7 */
cdc.dbc &= 0x0fff;
/* clear EDT & DSR bits (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] &= 0x07;
cdc.dma_w = 0;
/* setup data transfer destination */
switch (Pico_mcd->s68k_regs[0x04+0] & 0x07)
{
case 2: /* MAIN-CPU host read */
case 3: /* SUB-CPU host read */
{
/* set !DTEN */
cdc.ifstat &= ~BIT_DTEN;
/* set DSR bit (register $04) */
Pico_mcd->s68k_regs[0x04+0] |= 0x40;
break;
}
case 4: /* PCM RAM DMA */
{
cdc.dma_w = pcm_ram_dma_w;
break;
}
case 5: /* PRG-RAM DMA */
{
cdc.dma_w = prg_ram_dma_w;
break;
}
case 7: /* WORD-RAM DMA */
{
/* check memory mode */
if (Pico_mcd->s68k_regs[0x02+1] & 0x04)
{
/* 1M mode */
if (Pico_mcd->s68k_regs[0x02+1] & 0x01)
{
/* Word-RAM bank 0 is assigned to SUB-CPU */
cdc.dma_w = word_ram_0_dma_w;
}
else
{
/* Word-RAM bank 1 is assigned to SUB-CPU */
cdc.dma_w = word_ram_1_dma_w;
}
}
else
{
/* 2M mode */
if (Pico_mcd->s68k_regs[0x02+1] & 0x02)
{
/* only process DMA if Word-RAM is assigned to SUB-CPU */
cdc.dma_w = word_ram_2M_dma_w;
}
}
break;
}
default: /* invalid */
{
elprintf(EL_ANOMALY, "invalid CDC tranfer destination (%d)",
Pico_mcd->s68k_regs[0x04+0] & 0x07);
break;
}
}
if (cdc.dma_w)
pcd_event_schedule_s68k(PCD_EVENT_DMA, cdc.dbc / 2);
}
Pico_mcd->s68k_regs[0x04+1] = 0x07;
break;
}
case 0x07: /* DTACK */
{
/* clear pending data transfer end interrupt */
cdc.ifstat |= BIT_DTEI;
/* clear DBCH bits 4-7 */
cdc.dbc &= 0x0fff;
#if 0
/* no pending decoder interrupt ? */
if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
{
/* clear pending level 5 interrupt */
SekInterruptClearS68k(5);
}
#endif
Pico_mcd->s68k_regs[0x04+1] = 0x08;
break;
}
case 0x08: /* WAL */
cdc.wa &= 0xff00;
cdc.wa |= data;
Pico_mcd->s68k_regs[0x04+1] = 0x09;
break;
case 0x09: /* WAH */
cdc.wa &= 0x00ff;
cdc.wa |= data << 8;
Pico_mcd->s68k_regs[0x04+1] = 0x0a;
break;
case 0x0a: /* CTRL0 */
{
/* set CRCOK bit only if decoding is enabled */
cdc.stat[0] = data & BIT_DECEN;
/* update decoding mode */
if (data & BIT_AUTORQ)
{
/* set MODE bit according to CTRL1 register & clear FORM bit */
cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ;
}
else
{
/* set MODE & FORM bits according to CTRL1 register */
cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
}
cdc.ctrl[0] = data;
Pico_mcd->s68k_regs[0x04+1] = 0x0b;
break;
}
case 0x0b: /* CTRL1 */
{
/* update decoding mode */
if (cdc.ctrl[0] & BIT_AUTORQ)
{
/* set MODE bit according to CTRL1 register & clear FORM bit */
cdc.stat[2] = data & BIT_MODRQ;
}
else
{
/* set MODE & FORM bits according to CTRL1 register */
cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
}
cdc.ctrl[1] = data;
Pico_mcd->s68k_regs[0x04+1] = 0x0c;
break;
}
case 0x0c: /* PTL */
cdc.pt &= 0xff00;
cdc.pt |= data;
Pico_mcd->s68k_regs[0x04+1] = 0x0d;
break;
case 0x0d: /* PTH */
cdc.pt &= 0x00ff;
cdc.pt |= data << 8;
Pico_mcd->s68k_regs[0x04+1] = 0x0e;
break;
case 0x0e: /* CTRL2 (unused) */
Pico_mcd->s68k_regs[0x04+1] = 0x0f;
break;
case 0x0f: /* RESET */
cdc_reset();
break;
default: /* by default, SBOUT is not used */
break;
}
}
unsigned char cdc_reg_r(void)
{
switch (Pico_mcd->s68k_regs[0x04+1] & 0x0F)
{
case 0x01: /* IFSTAT */
Pico_mcd->s68k_regs[0x04+1] = 0x02;
return cdc.ifstat;
case 0x02: /* DBCL */
Pico_mcd->s68k_regs[0x04+1] = 0x03;
return cdc.dbc & 0xff;
case 0x03: /* DBCH */
Pico_mcd->s68k_regs[0x04+1] = 0x04;
return (cdc.dbc >> 8) & 0xff;
case 0x04: /* HEAD0 */
Pico_mcd->s68k_regs[0x04+1] = 0x05;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];
case 0x05: /* HEAD1 */
Pico_mcd->s68k_regs[0x04+1] = 0x06;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];
case 0x06: /* HEAD2 */
Pico_mcd->s68k_regs[0x04+1] = 0x07;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];
case 0x07: /* HEAD3 */
Pico_mcd->s68k_regs[0x04+1] = 0x08;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];
case 0x08: /* PTL */
Pico_mcd->s68k_regs[0x04+1] = 0x09;
return cdc.pt & 0xff;
case 0x09: /* PTH */
Pico_mcd->s68k_regs[0x04+1] = 0x0a;
return (cdc.pt >> 8) & 0xff;
case 0x0a: /* WAL */
Pico_mcd->s68k_regs[0x04+1] = 0x0b;
return cdc.wa & 0xff;
case 0x0b: /* WAH */
Pico_mcd->s68k_regs[0x04+1] = 0x0c;
return (cdc.wa >> 8) & 0xff;
case 0x0c: /* STAT0 */
Pico_mcd->s68k_regs[0x04+1] = 0x0d;
return cdc.stat[0];
case 0x0d: /* STAT1 (always return 0) */
Pico_mcd->s68k_regs[0x04+1] = 0x0e;
return 0x00;
case 0x0e: /* STAT2 */
Pico_mcd->s68k_regs[0x04+1] = 0x0f;
return cdc.stat[2];
case 0x0f: /* STAT3 */
{
uint8 data = cdc.stat[3];
/* clear !VALST (note: this is not 100% correct but BIOS do not seem to care) */
cdc.stat[3] = BIT_VALST;
/* clear pending decoder interrupt */
cdc.ifstat |= BIT_DECI;
#if 0
/* no pending data transfer end interrupt */
if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
{
/* clear pending level 5 interrupt */
SekInterruptClearS68k(5);
}
#endif
Pico_mcd->s68k_regs[0x04+1] = 0x00;
return data;
}
default: /* by default, COMIN is always empty */
return 0xff;
}
}
unsigned short cdc_host_r(void)
{
/* check if data is available */
if (!(cdc.ifstat & BIT_DTEN))
{
/* read data word from CDC RAM buffer */
uint8 *datap = cdc.ram + (cdc.dac & 0x3ffe);
uint16 data = (datap[0] << 8) | datap[1];
#ifdef LOG_CDC
error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac, data, cdc.dbc, s68k.pc);
#endif
/* increment data address counter */
cdc.dac += 2;
/* decrement data byte counter */
cdc.dbc -= 2;
/* end of transfer ? */
if ((int16)cdc.dbc <= 0)
{
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc = 0xf000;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DTE irq 5");
SekInterruptS68k(5);
}
}
/* clear DSR bit & set EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
}
return data;
}
#ifdef LOG_CDC
error("error reading CDC host (data transfer disabled)\n");
#endif
return 0xffff;
}
// vim:shiftwidth=2:ts=2:expandtab

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/***************************************************************************************
* Genesis Plus
* CD drive processor & CD-DA fader
*
* Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _HW_CDD_
#define _HW_CDD_
#ifdef USE_LIBTREMOR
#include "tremor/ivorbisfile.h"
#endif
/* CDD status */
#define NO_DISC 0x00
#define CD_PLAY 0x01
#define CD_SEEK 0x02
#define CD_SCAN 0x03
#define CD_READY 0x04
#define CD_OPEN 0x05 /* similar to 0x0E ? */
#define CD_STOP 0x09
#define CD_END 0x0C
/* CD blocks scanning speed */
#define CD_SCAN_SPEED 30
#define CD_MAX_TRACKS 100
/* CD track */
typedef struct
{
void *fd;
#ifdef USE_LIBTREMOR
OggVorbis_File vf;
#endif
int offset;
int start;
int end;
} track_t;
/* CD TOC */
typedef struct
{
int end;
int last;
track_t tracks[CD_MAX_TRACKS];
} toc_t;
/* CDD hardware */
typedef struct
{
uint32 cycles;
uint32 latency;
int loaded;
int index;
int lba;
int scanOffset;
int volume;
uint8 status;
uint16 sectorSize;
toc_t toc;
int16 audio[2];
} cdd_t;
extern cdd_t cdd;
#endif

View File

@ -0,0 +1,45 @@
/*
* Convert "cell arrange" address to normal address.
* (C) notaz, 2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
// 64 x32 x16 x8 x4 x4
static unsigned int cell_map(int celln)
{
int col, row;
switch ((celln >> 12) & 7) { // 0-0x8000
case 0: // x32 cells
case 1:
case 2:
case 3:
col = celln >> 8;
row = celln & 0xff;
break;
case 4: // x16
case 5:
col = celln >> 7;
row = celln & 0x7f;
row |= 0x10000 >> 8;
break;
case 6: // x8
col = celln >> 6;
row = celln & 0x3f;
row |= 0x18000 >> 8;
break;
case 7: // x4
col = celln >> 5;
row = celln & 0x1f;
row |= (celln & 0x7800) >> 6;
break;
default: // never happens, only here to make compiler happy
col = row = 0;
break;
}
return (col & 0x3f) + row*64;
}

View File

@ -0,0 +1,35 @@
/*
* cuefile handling
* (C) notaz, 2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cue.h"
#include "../pico_int.h"
// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
#ifdef __EPOC32__
#define snprintf(b,s,...) sprintf(b,##__VA_ARGS__)
#endif
#define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
void cue_destroy(cue_data_t *data)
{
int c;
if (data == NULL) return;
for (c = data->track_count; c > 0; c--)
if (data->tracks[c].fname != NULL)
free(data->tracks[c].fname);
free(data);
}

View File

@ -0,0 +1,29 @@
typedef enum
{
CT_UNKNOWN = 0,
CT_ISO = 1, /* 2048 B/sector */
CT_BIN = 2, /* 2352 B/sector */
CT_MP3 = 3,
CT_WAV = 4
} cue_track_type;
typedef struct
{
char *fname;
int pregap; /* pregap for current track */
int sector_offset; /* in current file */
int sector_xlength;
cue_track_type type;
} cue_track;
typedef struct
{
int track_count;
cue_track tracks[0];
} cue_data_t;
cue_data_t *cue_parse(const char *fname);
void cue_destroy(cue_data_t *data);

View File

@ -0,0 +1,24 @@
#undef uint8
#undef uint16
#undef uint32
#undef int8
#undef int16
#undef int32
#define uint8 unsigned char
#define uint16 unsigned short
#define uint32 unsigned int
#define int8 signed char
#define int16 signed short
#define int32 signed int
#define READ_BYTE(BASE, ADDR) (BASE)[(ADDR)^1]
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL)
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \
bufferptr += size;
#define save_param(param, size) \
memcpy(&state[bufferptr], param, size); \
bufferptr += size;

View File

@ -0,0 +1,451 @@
/***************************************************************************************
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "../pico_int.h"
#include "genplus_macros.h"
typedef struct
{
//uint32 cycles; /* current cycles count for graphics operation */
//uint32 cyclesPerLine; /* current graphics operation timings */
uint32 dotMask; /* stamp map size mask */
uint16 *tracePtr; /* trace vector pointer */
uint16 *mapPtr; /* stamp map table base address */
uint8 stampShift; /* stamp pixel shift value (related to stamp size) */
uint8 mapShift; /* stamp map table shift value (related to stamp map size) */
uint16 bufferOffset; /* image buffer column offset */
uint32 bufferStart; /* image buffer start index */
uint32 y_step; /* pico: render line step */
uint8 lut_prio[4][0x10][0x10]; /* WORD-RAM data writes priority lookup table */
uint8 lut_pixel[0x200]; /* Graphics operation dot offset lookup table */
uint8 lut_cell[0x100]; /* Graphics operation stamp offset lookup table */
} gfx_t;
static gfx_t gfx;
static void gfx_schedule(void);
/***************************************************************/
/* Rotation / Scaling operation (2M Mode) */
/***************************************************************/
void gfx_init(void)
{
int i, j;
uint8 mask, row, col, temp;
memset(&gfx, 0, sizeof(gfx));
/* Initialize priority modes lookup table */
for (i = 0; i < 0x10; i++)
{
for (j = 0; j < 0x10; j++)
{
/* normal */
gfx.lut_prio[0][i][j] = j;
/* underwrite */
gfx.lut_prio[1][i][j] = i ? i : j;
/* overwrite */
gfx.lut_prio[2][i][j] = j ? j : i;
/* invalid */
gfx.lut_prio[3][i][j] = i;
}
}
/* Initialize cell lookup table */
/* table entry = yyxxshrr (8 bits) */
/* with: yy = cell row (0-3) */
/* xx = cell column (0-3) */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
for (i=0; i<0x100; i++)
{
/* one stamp = 2x2 cells (16x16) or 4x4 cells (32x32) */
mask = (i & 8) ? 3 : 1;
row = (i >> 6) & mask;
col = (i >> 4) & mask;
if (i & 4) { col = col ^ mask; } /* HFLIP (always first) */
if (i & 2) { col = col ^ mask; row = row ^ mask; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ mask; row = temp; } /* ROLL0 */
/* cell offset (0-3 or 0-15) */
gfx.lut_cell[i] = row + col * (mask + 1);
}
/* Initialize pixel lookup table */
/* table entry = yyyxxxhrr (9 bits) */
/* with: yyy = pixel row (0-7) */
/* xxx = pixel column (0-7) */
/* hrr = HFLIP & ROTATION bits */
for (i=0; i<0x200; i++)
{
/* one cell = 8x8 pixels */
row = (i >> 6) & 7;
col = (i >> 3) & 7;
if (i & 4) { col = col ^ 7; } /* HFLIP (always first) */
if (i & 2) { col = col ^ 7; row = row ^ 7; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ 7; row = temp; } /* ROLL0 */
/* pixel offset (0-63) */
gfx.lut_pixel[i] = col + row * 8;
}
}
int gfx_context_save(uint8 *state)
{
uint32 tmp32;
int bufferptr = 0;
//save_param(&gfx.cycles, sizeof(gfx.cycles));
//save_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
save_param(&gfx.dotMask, sizeof(gfx.dotMask));
save_param(&gfx.stampShift, sizeof(gfx.stampShift));
save_param(&gfx.mapShift, sizeof(gfx.mapShift));
save_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
save_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
tmp32 = (uint8 *)(gfx.tracePtr) - Pico_mcd->word_ram2M;
save_param(&tmp32, 4);
tmp32 = (uint8 *)(gfx.mapPtr) - Pico_mcd->word_ram2M;
save_param(&tmp32, 4);
save_param(&gfx.y_step, sizeof(gfx.y_step));
return bufferptr;
}
int gfx_context_load(const uint8 *state)
{
uint32 tmp32;
int bufferptr = 0;
//load_param(&gfx.cycles, sizeof(gfx.cycles));
//load_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
load_param(&gfx.dotMask, sizeof(gfx.dotMask));
load_param(&gfx.stampShift, sizeof(gfx.stampShift));
load_param(&gfx.mapShift, sizeof(gfx.mapShift));
load_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
load_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
load_param(&tmp32, 4);
gfx.tracePtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32);
load_param(&tmp32, 4);
gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32);
load_param(&gfx.y_step, sizeof(gfx.y_step));
return bufferptr;
}
static void gfx_render(uint32 bufferIndex, uint32 width)
{
uint8 pixel_in, pixel_out;
uint16 stamp_data;
uint32 stamp_index;
uint32 priority;
/* pixel map start position for current line (13.3 format converted to 13.11) */
uint32 xpos = *gfx.tracePtr++ << 8;
uint32 ypos = *gfx.tracePtr++ << 8;
/* pixel map offset values for current line (5.11 format) */
uint32 xoffset = (int16) *gfx.tracePtr++;
uint32 yoffset = (int16) *gfx.tracePtr++;
priority = (Pico_mcd->s68k_regs[2] << 8) | Pico_mcd->s68k_regs[3];
priority = (priority >> 3) & 0x03;
/* process all dots */
while (width--)
{
/* check if stamp map is repeated */
if (Pico_mcd->s68k_regs[0x58+1] & 0x01)
{
/* stamp map range */
xpos &= gfx.dotMask;
ypos &= gfx.dotMask;
}
else
{
/* 24-bit range */
xpos &= 0xffffff;
ypos &= 0xffffff;
}
/* check if pixel is outside stamp map */
if ((xpos | ypos) & ~gfx.dotMask)
{
/* force pixel output to 0 */
pixel_out = 0x00;
}
else
{
/* read stamp map table data */
stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
/* stamp generator base index */
/* sss ssssssss ccyyyxxx (16x16) or sss sssssscc ccyyyxxx (32x32) */
/* with: s = stamp number (1 stamp = 16x16 or 32x32 pixels) */
/* c = cell offset (0-3 for 16x16, 0-15 for 32x32) */
/* yyy = line offset (0-7) */
/* xxx = pixel offset (0-7) */
stamp_index = (stamp_data & 0x7ff) << 8;
if (stamp_index)
{
/* extract HFLIP & ROTATION bits */
stamp_data = (stamp_data >> 13) & 7;
/* cell offset (0-3 or 0-15) */
/* table entry = yyxxshrr (8 bits) */
/* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
/* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_cell[
stamp_data | ((Pico_mcd->s68k_regs[0x58+1] & 0x02) << 2 )
| ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
/* pixel offset (0-63) */
/* table entry = yyyxxxhrr (9 bits) */
/* with: yyy = pixel row (0-7) = (ypos >> 11) & 7 */
/* xxx = pixel column (0-7) = (xpos >> 11) & 7 */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
/* read pixel pair (2 pixels/byte) */
pixel_out = READ_BYTE(Pico_mcd->word_ram2M, stamp_index >> 1);
/* extract left or rigth pixel */
if (stamp_index & 1)
{
pixel_out &= 0x0f;
}
else
{
pixel_out >>= 4;
}
}
else
{
/* stamp 0 is not used: force pixel output to 0 */
pixel_out = 0x00;
}
}
/* read out paired pixel data */
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1);
/* update left or rigth pixel */
if (bufferIndex & 1)
{
/* priority mode write */
pixel_out = gfx.lut_prio[priority][pixel_in & 0x0f][pixel_out];
pixel_out |= (pixel_in & 0xf0);
}
else
{
/* priority mode write */
pixel_out = gfx.lut_prio[priority][pixel_in >> 4][pixel_out];
pixel_out = (pixel_out << 4) | (pixel_in & 0x0f);
}
/* write data to image buffer */
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_out);
/* check current pixel position */
if ((bufferIndex & 7) != 7)
{
/* next pixel */
bufferIndex++;
}
else
{
/* next cell: increment image buffer offset by one column (minus 7 pixels) */
bufferIndex += gfx.bufferOffset;
}
/* increment pixel position */
xpos += xoffset;
ypos += yoffset;
}
}
void gfx_start(unsigned int base)
{
/* make sure 2M mode is enabled */
if (!(Pico_mcd->s68k_regs[3] & 0x04))
{
uint32 mask = 0;
uint32 reg;
/* trace vector pointer */
gfx.tracePtr = (uint16 *)(Pico_mcd->word_ram2M + ((base << 2) & 0x3fff8));
/* stamps & stamp map size */
switch ((Pico_mcd->s68k_regs[0x58+1] >> 1) & 0x03)
{
case 0:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 4; /* 16x16 stamps/map */
mask = 0x3fe00; /* 512 bytes/table */
break;
case 1:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 3; /* 8x8 stamps/map */
mask = 0x3ff80; /* 128 bytes/table */
break;
case 2:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 8; /* 256x256 stamps/map */
mask = 0x20000; /* 131072 bytes/table */
break;
case 3:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 7; /* 128x128 stamps/map */
mask = 0x38000; /* 32768 bytes/table */
break;
}
/* stamp map table base address */
reg = (Pico_mcd->s68k_regs[0x5a] << 8) | Pico_mcd->s68k_regs[0x5b];
gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + ((reg << 2) & mask));
/* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
gfx.bufferOffset = (((Pico_mcd->s68k_regs[0x5c+1] & 0x1f) + 1) << 6) - 7;
/* image buffer start index in dot units (2 pixels/byte) */
reg = (Pico_mcd->s68k_regs[0x5e] << 8) | Pico_mcd->s68k_regs[0x5f];
gfx.bufferStart = (reg << 3) & 0x7ffc0;
/* add image buffer horizontal dot offset */
gfx.bufferStart += (Pico_mcd->s68k_regs[0x60+1] & 0x3f);
/* reset GFX chip cycle counter */
//gfx.cycles = cycles;
/* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
//gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
/* start graphics operation */
Pico_mcd->s68k_regs[0x58] = 0x80;
gfx_schedule();
}
}
/* PicoDrive specific */
#define UPDATE_CYCLES 20000
static void gfx_schedule(void)
{
int w, h, cycles;
int y_step;
w = (Pico_mcd->s68k_regs[0x62] << 8) | Pico_mcd->s68k_regs[0x63];
h = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
cycles = 5 * w * h;
if (cycles > UPDATE_CYCLES)
y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
else
y_step = h;
gfx.y_step = y_step;
pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * y_step);
}
void gfx_update(unsigned int cycles)
{
int lines, lines_reg;
int w;
if (!(Pico_mcd->s68k_regs[0x58] & 0x80))
return;
w = (Pico_mcd->s68k_regs[0x62] << 8) | Pico_mcd->s68k_regs[0x63];
lines = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
lines_reg = lines - gfx.y_step;
if (lines_reg <= 0) {
Pico_mcd->s68k_regs[0x58] = 0;
Pico_mcd->s68k_regs[0x64] =
Pico_mcd->s68k_regs[0x65] = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
elprintf(EL_INTS|EL_CD, "s68k: gfx_cd irq 1");
SekInterruptS68k(1);
}
}
else {
Pico_mcd->s68k_regs[0x64] = lines_reg >> 8;
Pico_mcd->s68k_regs[0x65] = lines_reg;
if (lines > gfx.y_step)
lines = gfx.y_step;
pcd_event_schedule(cycles, PCD_EVENT_GFX, 5 * w * lines);
}
if (PicoOpt & POPT_EN_MCD_GFX)
{
/* render lines */
while (lines--)
{
/* process dots to image buffer */
gfx_render(gfx.bufferStart, w);
/* increment image buffer start index for next line (8 pixels/line) */
gfx.bufferStart += 8;
}
}
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,79 @@
/*
* PicoDrive
* (C) notaz, 2007
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "cell_map.c"
#ifndef UTYPES_DEFINED
typedef unsigned short u16;
#endif
// check: Heart of the alien, jaguar xj 220
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
{
unsigned char *base;
unsigned int asrc, a2;
u16 *r;
base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
switch (Pico.video.type)
{
case 1: // vram
r = Pico.vram;
for(; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
// if(a&1) d=(d<<8)|(d>>8); // ??
r[a>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a=(u16)(a+inc);
}
rendstatus |= PDRAW_SPRITES_MOVED;
break;
case 3: // cram
Pico.m.dirtyPal = 1;
r = Pico.cram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
r[a2>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a2+=inc;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
case 5: // vsram[a&0x003f]=d;
r = Pico.vsram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
r[a2>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a2+=inc;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
}
// remember addr
Pico.video.addr=(u16)a;
}

View File

@ -0,0 +1,415 @@
/*
* PicoDrive
* (C) notaz, 2007,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "../sound/ym2612.h"
extern unsigned char formatted_bram[4*0x10];
static unsigned int mcd_m68k_cycle_mult;
static unsigned int mcd_m68k_cycle_base;
static unsigned int mcd_s68k_cycle_base;
void (*PicoMCDopenTray)(void) = NULL;
void (*PicoMCDcloseTray)(void) = NULL;
PICO_INTERNAL void PicoInitMCD(void)
{
SekInitS68k();
}
PICO_INTERNAL void PicoExitMCD(void)
{
}
PICO_INTERNAL void PicoPowerMCD(void)
{
SekCycleCntS68k = SekCycleAimS68k = 0;
int fmt_size = sizeof(formatted_bram);
memset(Pico_mcd->prg_ram, 0, sizeof(Pico_mcd->prg_ram));
memset(Pico_mcd->word_ram2M, 0, sizeof(Pico_mcd->word_ram2M));
memset(Pico_mcd->pcm_ram, 0, sizeof(Pico_mcd->pcm_ram));
memset(Pico_mcd->bram, 0, sizeof(Pico_mcd->bram));
memcpy(Pico_mcd->bram + sizeof(Pico_mcd->bram) - fmt_size,
formatted_bram, fmt_size);
memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
cdc_init();
gfx_init();
// cold reset state (tested)
Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
Pico_mcd->m.busreq = 2; // busreq on, s68k in reset
Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode, m68k access
memset(Pico_mcd->bios + 0x70, 0xff, 4);
}
void pcd_soft_reset(void)
{
elprintf(EL_CD, "cd: soft reset");
Pico_mcd->m.s68k_pend_ints = 0;
cdc_reset();
cdd_reset();
#ifdef _ASM_CD_MEMORY_C
//PicoMemResetCDdecode(1); // don't have to call this in 2M mode
#endif
memset(&Pico_mcd->s68k_regs[0x38], 0, 9);
Pico_mcd->s68k_regs[0x38+9] = 0x0f; // default checksum
pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);
// TODO: test if register state/timers change
}
PICO_INTERNAL int PicoResetMCD(void)
{
// reset button doesn't affect MCD hardware
// use SRam.data for RAM cart
if (PicoOpt & POPT_EN_MCD_RAMCART) {
if (SRam.data == NULL)
SRam.data = calloc(1, 0x12000);
}
else if (SRam.data != NULL) {
free(SRam.data);
SRam.data = NULL;
}
SRam.start = SRam.end = 0; // unused
return 0;
}
static void SekRunM68kOnce(void)
{
int cyc_do;
pevt_log_m68k_o(EVT_RUN_START);
if ((cyc_do = SekCycleAim - SekCycleCnt) > 0) {
SekCycleCnt += cyc_do;
#if defined(EMU_C68K)
PicoCpuCM68k.cycles = cyc_do;
CycloneRun(&PicoCpuCM68k);
SekCycleCnt -= PicoCpuCM68k.cycles;
#elif defined(EMU_M68K)
SekCycleCnt += m68k_execute(cyc_do) - cyc_do;
#elif defined(EMU_F68K)
SekCycleCnt += fm68k_emulate(cyc_do, 0) - cyc_do;
#endif
}
SekCyclesLeft = 0;
SekTrace(0);
pevt_log_m68k_o(EVT_RUN_END);
}
static void SekRunS68k(unsigned int to)
{
int cyc_do;
SekCycleAimS68k = to;
if ((cyc_do = SekCycleAimS68k - SekCycleCntS68k) <= 0)
return;
if (SekShouldInterrupt())
Pico_mcd->m.s68k_poll_a = 0;
SekCycleCntS68k += cyc_do;
#if defined(EMU_C68K)
PicoCpuCS68k.cycles = cyc_do;
CycloneRun(&PicoCpuCS68k);
SekCycleCntS68k -= PicoCpuCS68k.cycles;
#elif defined(EMU_M68K)
m68k_set_context(&PicoCpuMS68k);
SekCycleCntS68k += m68k_execute(cyc_do) - cyc_do;
m68k_set_context(&PicoCpuMM68k);
#elif defined(EMU_F68K)
g_m68kcontext = &PicoCpuFS68k;
SekCycleCntS68k += fm68k_emulate(cyc_do, 0) - cyc_do;
g_m68kcontext = &PicoCpuFM68k;
#endif
}
static void pcd_set_cycle_mult(void)
{
// ~1.63 for NTSC, ~1.645 for PAL
if (Pico.m.pal)
mcd_m68k_cycle_mult = ((12500000ull << 16) / (50*312*488));
else
mcd_m68k_cycle_mult = ((12500000ull << 16) / (60*262*488)) + 1;
}
unsigned int pcd_cycles_m68k_to_s68k(unsigned int c)
{
return (long long)c * mcd_m68k_cycle_mult >> 16;
}
/* events */
static void pcd_cdc_event(unsigned int now)
{
// 75Hz CDC update
cdd_update();
/* check if a new CDD command has been processed */
if (!(Pico_mcd->s68k_regs[0x4b] & 0xf0))
{
/* reset CDD command wait flag */
Pico_mcd->s68k_regs[0x4b] = 0xf0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
SekInterruptS68k(4);
}
}
pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
}
static void pcd_int3_timer_event(unsigned int now)
{
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN3) {
elprintf(EL_INTS|EL_CD, "s68k: timer irq 3");
SekInterruptS68k(3);
}
if (Pico_mcd->s68k_regs[0x31] != 0)
pcd_event_schedule(now, PCD_EVENT_TIMER3,
Pico_mcd->s68k_regs[0x31] * 384);
}
static void pcd_dma_event(unsigned int now)
{
cdc_dma_update();
}
typedef void (event_cb)(unsigned int now);
/* times are in s68k (12.5MHz) cycles */
unsigned int pcd_event_times[PCD_EVENT_COUNT];
static unsigned int event_time_next;
static event_cb *pcd_event_cbs[PCD_EVENT_COUNT] = {
[PCD_EVENT_CDC] = pcd_cdc_event,
[PCD_EVENT_TIMER3] = pcd_int3_timer_event,
[PCD_EVENT_GFX] = gfx_update,
[PCD_EVENT_DMA] = pcd_dma_event,
};
void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
{
unsigned int when;
when = now + after;
if (when == 0) {
// event cancelled
pcd_event_times[event] = 0;
return;
}
when |= 1;
elprintf(EL_CD, "cd: new event #%u %u->%u", event, now, when);
pcd_event_times[event] = when;
if (event_time_next == 0 || CYCLES_GT(event_time_next, when))
event_time_next = when;
}
void pcd_event_schedule_s68k(enum pcd_event event, int after)
{
if (SekCyclesLeftS68k > after)
SekEndRunS68k(after);
pcd_event_schedule(SekCyclesDoneS68k(), event, after);
}
static void pcd_run_events(unsigned int until)
{
int oldest, oldest_diff, time;
int i, diff;
while (1) {
oldest = -1, oldest_diff = 0x7fffffff;
for (i = 0; i < PCD_EVENT_COUNT; i++) {
if (pcd_event_times[i]) {
diff = pcd_event_times[i] - until;
if (diff < oldest_diff) {
oldest_diff = diff;
oldest = i;
}
}
}
if (oldest_diff <= 0) {
time = pcd_event_times[oldest];
pcd_event_times[oldest] = 0;
elprintf(EL_CD, "cd: run event #%d %u", oldest, time);
pcd_event_cbs[oldest](time);
}
else if (oldest_diff < 0x7fffffff) {
event_time_next = pcd_event_times[oldest];
break;
}
else {
event_time_next = 0;
break;
}
}
if (oldest != -1)
elprintf(EL_CD, "cd: next event #%d at %u",
oldest, event_time_next);
}
int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
{
#define now SekCycleCntS68k
unsigned int s68k_target;
unsigned int target;
target = m68k_target - mcd_m68k_cycle_base;
s68k_target = mcd_s68k_cycle_base +
((unsigned long long)target * mcd_m68k_cycle_mult >> 16);
elprintf(EL_CD, "s68k sync to %u, %u->%u",
m68k_target, now, s68k_target);
if (Pico_mcd->m.busreq != 1) { /* busreq/reset */
SekCycleCntS68k = SekCycleAimS68k = s68k_target;
pcd_run_events(m68k_target);
return 0;
}
while (CYCLES_GT(s68k_target, now)) {
if (event_time_next && CYCLES_GE(now, event_time_next))
pcd_run_events(now);
target = s68k_target;
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
SekRunS68k(target);
if (m68k_poll_sync && Pico_mcd->m.m68k_poll_cnt == 0)
break;
}
return s68k_target - now;
#undef now
}
#define pcd_run_cpus_normal pcd_run_cpus
//#define pcd_run_cpus_lockstep pcd_run_cpus
static void SekSyncM68k(void);
void pcd_run_cpus_normal(int m68k_cycles)
{
SekCycleAim += m68k_cycles;
if (SekShouldInterrupt() || Pico_mcd->m.m68k_poll_cnt < 12)
Pico_mcd->m.m68k_poll_cnt = 0;
else if (Pico_mcd->m.m68k_poll_cnt >= 16) {
int s68k_left = pcd_sync_s68k(SekCycleAim, 1);
if (s68k_left <= 0) {
elprintf(EL_CDPOLL, "m68k poll [%02x] x%d @%06x",
Pico_mcd->m.m68k_poll_a, Pico_mcd->m.m68k_poll_cnt, SekPc);
SekCycleCnt = SekCycleAim;
return;
}
SekCycleCnt = SekCycleAim - (s68k_left * 40220 >> 16);
}
while (CYCLES_GT(SekCycleAim, SekCycleCnt)) {
SekRunM68kOnce();
if (Pico_mcd->m.need_sync) {
Pico_mcd->m.need_sync = 0;
pcd_sync_s68k(SekCycleCnt, 0);
}
}
}
void pcd_run_cpus_lockstep(int m68k_cycles)
{
unsigned int target = SekCycleAim + m68k_cycles;
do {
SekCycleAim += 8;
SekSyncM68k();
pcd_sync_s68k(SekCycleAim, 0);
} while (CYCLES_GT(target, SekCycleAim));
SekCycleAim = target;
}
#define PICO_CD
#define CPUS_RUN(m68k_cycles) \
pcd_run_cpus(m68k_cycles)
#include "../pico_cmn.inc"
void pcd_prepare_frame(void)
{
pcd_set_cycle_mult();
// need this because we can't have direct mapping between
// master<->slave cycle counters because of overflows
mcd_m68k_cycle_base = SekCycleAim;
mcd_s68k_cycle_base = SekCycleAimS68k;
}
PICO_INTERNAL void PicoFrameMCD(void)
{
PicoFrameStart();
pcd_prepare_frame();
PicoFrameHints();
}
void pcd_state_loaded(void)
{
unsigned int cycles;
int diff;
pcd_set_cycle_mult();
pcd_state_loaded_mem();
memset(Pico_mcd->pcm_mixbuf, 0, sizeof(Pico_mcd->pcm_mixbuf));
Pico_mcd->pcm_mixbuf_dirty = 0;
Pico_mcd->pcm_mixpos = 0;
Pico_mcd->pcm_regs_dirty = 1;
// old savestates..
cycles = pcd_cycles_m68k_to_s68k(SekCycleAim);
diff = cycles - SekCycleAimS68k;
if (diff < -1000 || diff > 1000) {
SekCycleCntS68k = SekCycleAimS68k = cycles;
}
if (pcd_event_times[PCD_EVENT_CDC] == 0) {
pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_CDC, 12500000/75);
if (Pico_mcd->s68k_regs[0x31])
pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_TIMER3,
Pico_mcd->s68k_regs[0x31] * 384);
}
diff = cycles - Pico_mcd->pcm.update_cycles;
if ((unsigned int)diff > 12500000/50)
Pico_mcd->pcm.update_cycles = cycles;
// reschedule
event_time_next = 0;
pcd_run_events(SekCycleCntS68k);
}
// vim:shiftwidth=2:ts=2:expandtab

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
/*
* PicoDrive
* (C) notaz, 2007
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
unsigned char formatted_bram[4*0x10] =
{
#if 0
0x00, 0xd4, 0x63, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x53, 0xd2, 0xf5, 0x3a, 0x48, 0x50, 0x35, 0x0f,
0x47, 0x14, 0xf5, 0x7e, 0x5c, 0xd4, 0xf3, 0x03, 0x00, 0x03, 0x12, 0x00, 0x0a, 0xff, 0xca, 0xa6,
0xf5, 0x27, 0xed, 0x22, 0x47, 0xfa, 0x22, 0x96, 0x6c, 0xa5, 0x88, 0x14, 0x48, 0x48, 0x0a, 0xbb,
#endif
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x40,
0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x53, 0x45, 0x47, 0x41, 0x5f, 0x43, 0x44, 0x5f, 0x52, 0x4f, 0x4d, 0x00, 0x01, 0x00, 0x00, 0x00,
0x52, 0x41, 0x4d, 0x5f, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x5f, 0x5f, 0x5f,
// SEGA_CD_ROM.....RAM_CARTRIDGE___
};
// offs | 2Mbit | 1Mbit |
// 0 | [ 2M | unused |
// 128K | bit ] | bank0 |
// 256K | unused | bank1 |
#ifndef _ASM_MISC_C
PICO_INTERNAL_ASM void wram_2M_to_1M(unsigned char *m)
{
unsigned short *m1M_b0, *m1M_b1;
unsigned int i, tmp, *m2M;
m2M = (unsigned int *) (m + 0x40000);
m1M_b0 = (unsigned short *) m2M;
m1M_b1 = (unsigned short *) (m + 0x60000);
for (i = 0x40000/4; i; i--)
{
tmp = *(--m2M);
*(--m1M_b0) = tmp;
*(--m1M_b1) = tmp >> 16;
}
}
PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m)
{
unsigned short *m1M_b0, *m1M_b1;
unsigned int i, tmp, *m2M;
m2M = (unsigned int *) m;
m1M_b0 = (unsigned short *) (m + 0x20000);
m1M_b1 = (unsigned short *) (m + 0x40000);
for (i = 0x40000/4; i; i--)
{
tmp = *m1M_b0++ | (*m1M_b1++ << 16);
*m2M++ = tmp;
}
}
#endif

View File

@ -0,0 +1,165 @@
/*
* Emulation routines for the RF5C164 PCM chip
* (C) notaz, 2007, 2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#define PCM_STEP_SHIFT 11
void pcd_pcm_write(unsigned int a, unsigned int d)
{
unsigned int cycles = SekCyclesDoneS68k();
if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
pcd_pcm_sync(cycles);
if (a < 7)
{
Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
}
else if (a == 7) // control register
{
if (d & 0x40)
Pico_mcd->pcm.cur_ch = d & 7;
else
Pico_mcd->pcm.bank = d & 0xf;
Pico_mcd->pcm.control = d;
elprintf(EL_CD, "pcm control %02x", Pico_mcd->pcm.control);
}
else if (a == 8)
{
Pico_mcd->pcm.enabled = ~d;
}
Pico_mcd->pcm_regs_dirty = 1;
}
unsigned int pcd_pcm_read(unsigned int a)
{
unsigned int d, cycles = SekCyclesDoneS68k();
if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
pcd_pcm_sync(cycles);
d = Pico_mcd->pcm.ch[(a >> 1) & 7].addr >> PCM_STEP_SHIFT;
if (a & 1)
d >>= 8;
return d & 0xff;
}
void pcd_pcm_sync(unsigned int to)
{
unsigned int cycles = Pico_mcd->pcm.update_cycles;
int mul_l, mul_r, inc, smp;
struct pcm_chan *ch;
unsigned int addr;
int c, s, steps;
int enabled;
int *out;
if ((int)(to - cycles) < 384)
return;
steps = (to - cycles) / 384;
if (Pico_mcd->pcm_mixpos + steps > PCM_MIXBUF_LEN)
// shouldn't happen, but occasionally does
steps = PCM_MIXBUF_LEN - Pico_mcd->pcm_mixpos;
// PCM disabled or all channels off
enabled = Pico_mcd->pcm.enabled;
if (!(Pico_mcd->pcm.control & 0x80))
enabled = 0;
if (!enabled && !Pico_mcd->pcm_regs_dirty)
goto end;
out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2;
Pico_mcd->pcm_mixbuf_dirty = 1;
Pico_mcd->pcm_regs_dirty = 0;
for (c = 0; c < 8; c++)
{
ch = &Pico_mcd->pcm.ch[c];
if (!(enabled & (1 << c))) {
ch->addr = ch->regs[6] << (PCM_STEP_SHIFT + 8);
continue; // channel disabled
}
addr = ch->addr;
inc = *(unsigned short *)&ch->regs[2];
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1);
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
for (s = 0; s < steps; s++, addr = (addr + inc) & 0x7FFFFFF)
{
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
// test for loop signal
if (smp == 0xff)
{
addr = *(unsigned short *)&ch->regs[4]; // loop_addr
smp = Pico_mcd->pcm_ram[addr];
addr <<= PCM_STEP_SHIFT;
if (smp == 0xff)
break;
}
if (smp & 0x80)
smp = -(smp & 0x7f);
out[s*2 ] += smp * mul_l; // max 128 * 119 = 15232
out[s*2+1] += smp * mul_r;
}
ch->addr = addr;
}
end:
Pico_mcd->pcm.update_cycles = cycles + steps * 384;
Pico_mcd->pcm_mixpos += steps;
}
void pcd_pcm_update(int *buf32, int length, int stereo)
{
int step, *pcm;
int p = 0;
pcd_pcm_sync(SekCyclesDoneS68k());
if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoOpt & POPT_EN_MCD_PCM))
goto out;
step = (Pico_mcd->pcm_mixpos << 16) / length;
pcm = Pico_mcd->pcm_mixbuf;
if (stereo) {
while (length-- > 0) {
*buf32++ += pcm[0];
*buf32++ += pcm[1];
p += step;
pcm += (p >> 16) * 2;
p &= 0xffff;
}
}
else {
while (length-- > 0) {
// mostly unused
*buf32++ += pcm[0];
p += step;
pcm += (p >> 16) * 2;
p &= 0xffff;
}
}
memset(Pico_mcd->pcm_mixbuf, 0,
Pico_mcd->pcm_mixpos * 2 * sizeof(Pico_mcd->pcm_mixbuf[0]));
out:
Pico_mcd->pcm_mixbuf_dirty = 0;
Pico_mcd->pcm_mixpos = 0;
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,205 @@
/*
* PicoDrive
* (C) notaz, 2007
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
unsigned int SekCycleCntS68k;
unsigned int SekCycleAimS68k;
/* context */
// Cyclone 68000
#ifdef EMU_C68K
struct Cyclone PicoCpuCS68k;
#endif
// MUSASHI 68000
#ifdef EMU_M68K
m68ki_cpu_core PicoCpuMS68k;
#endif
// FAME 68000
#ifdef EMU_F68K
M68K_CONTEXT PicoCpuFS68k;
#endif
static int new_irq_level(int level)
{
int level_new = 0, irqs;
Pico_mcd->m.s68k_pend_ints &= ~(1 << level);
irqs = Pico_mcd->m.s68k_pend_ints;
irqs &= Pico_mcd->s68k_regs[0x33];
while ((irqs >>= 1)) level_new++;
return level_new;
}
#ifdef EMU_C68K
// interrupt acknowledgement
static int SekIntAckS68k(int level)
{
int level_new = new_irq_level(level);
elprintf(EL_INTS, "s68kACK %i -> %i", level, level_new);
PicoCpuCS68k.irq = level_new;
return CYCLONE_INT_ACK_AUTOVECTOR;
}
static void SekResetAckS68k(void)
{
elprintf(EL_ANOMALY, "s68k: Reset encountered @ %06x", SekPcS68k);
}
static int SekUnrecognizedOpcodeS68k(void)
{
elprintf(EL_ANOMALY, "Unrecognized Opcode @ %06x", SekPcS68k);
//exit(1);
return 0;
}
#endif
#ifdef EMU_M68K
static int SekIntAckMS68k(int level)
{
#ifndef EMU_CORE_DEBUG
int level_new = new_irq_level(level);
elprintf(EL_INTS, "s68kACK %i -> %i", level, level_new);
CPU_INT_LEVEL = level_new << 8;
#else
CPU_INT_LEVEL = 0;
#endif
return M68K_INT_ACK_AUTOVECTOR;
}
#endif
#ifdef EMU_F68K
static void SekIntAckFS68k(unsigned level)
{
int level_new = new_irq_level(level);
elprintf(EL_INTS, "s68kACK %i -> %i", level, level_new);
#ifndef EMU_CORE_DEBUG
PicoCpuFS68k.interrupts[0] = level_new;
#else
{
extern int dbg_irq_level_sub;
dbg_irq_level_sub = level_new;
PicoCpuFS68k.interrupts[0] = 0;
}
#endif
}
#endif
PICO_INTERNAL void SekInitS68k(void)
{
#ifdef EMU_C68K
// CycloneInit();
memset(&PicoCpuCS68k,0,sizeof(PicoCpuCS68k));
PicoCpuCS68k.IrqCallback=SekIntAckS68k;
PicoCpuCS68k.ResetCallback=SekResetAckS68k;
PicoCpuCS68k.UnrecognizedCallback=SekUnrecognizedOpcodeS68k;
#endif
#ifdef EMU_M68K
{
// Musashi is not very context friendly..
void *oldcontext = m68ki_cpu_p;
m68k_set_context(&PicoCpuMS68k);
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_init();
m68k_set_int_ack_callback(SekIntAckMS68k);
// m68k_pulse_reset(); // not yet, memmap is not set up
m68k_set_context(oldcontext);
}
#endif
#ifdef EMU_F68K
{
void *oldcontext = g_m68kcontext;
g_m68kcontext = &PicoCpuFS68k;
memset(&PicoCpuFS68k, 0, sizeof(PicoCpuFS68k));
fm68k_init();
PicoCpuFS68k.iack_handler = SekIntAckFS68k;
PicoCpuFS68k.sr = 0x2704; // Z flag
g_m68kcontext = oldcontext;
}
#endif
}
// Reset the 68000:
PICO_INTERNAL int SekResetS68k(void)
{
if (Pico.rom==NULL) return 1;
#ifdef EMU_C68K
CycloneReset(&PicoCpuCS68k);
#endif
#ifdef EMU_M68K
{
void *oldcontext = m68ki_cpu_p;
m68k_set_context(&PicoCpuMS68k);
m68ki_cpu.sp[0]=0;
m68k_set_irq(0);
m68k_pulse_reset();
m68k_set_context(oldcontext);
}
#endif
#ifdef EMU_F68K
{
void *oldcontext = g_m68kcontext;
g_m68kcontext = &PicoCpuFS68k;
fm68k_reset();
g_m68kcontext = oldcontext;
}
#endif
return 0;
}
PICO_INTERNAL int SekInterruptS68k(int irq)
{
int irqs, real_irq = 1;
Pico_mcd->m.s68k_pend_ints |= 1 << irq;
irqs = Pico_mcd->m.s68k_pend_ints >> 1;
while ((irqs >>= 1)) real_irq++;
#ifdef EMU_CORE_DEBUG
{
extern int dbg_irq_level_sub;
dbg_irq_level_sub=real_irq;
return 0;
}
#endif
#ifdef EMU_C68K
PicoCpuCS68k.irq=real_irq;
#endif
#ifdef EMU_M68K
void *oldcontext = m68ki_cpu_p;
m68k_set_context(&PicoCpuMS68k);
m68k_set_irq(real_irq);
m68k_set_context(oldcontext);
#endif
#ifdef EMU_F68K
PicoCpuFS68k.interrupts[0]=real_irq;
#endif
return 0;
}
void SekInterruptClearS68k(int irq)
{
int level_new = new_irq_level(irq);
#ifdef EMU_C68K
PicoCpuCS68k.irq = level_new;
#endif
#ifdef EMU_M68K
CPU_INT_LEVEL = level_new << 8;
#endif
#ifdef EMU_F68K
PicoCpuFS68k.interrupts[0] = level_new;
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,624 @@
/*
* tile renderer
* (C) notaz, 2006-2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "pico_int.h"
#define START_ROW 0 // which row of tiles to start rendering at?
#define END_ROW 28 // ..end
#define TILE_ROWS END_ROW-START_ROW
// note: this is not implemented in ARM asm
#if defined(DRAW2_OVERRIDE_LINE_WIDTH)
#define LINE_WIDTH DRAW2_OVERRIDE_LINE_WIDTH
#else
#define LINE_WIDTH 328
#endif
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
unsigned char *PicoDraw2FB = PicoDraw2FB_;
static int HighCache2A[41*(TILE_ROWS+1)+1+1]; // caches for high layers
static int HighCache2B[41*(TILE_ROWS+1)+1+1];
unsigned short *PicoCramHigh=Pico.cram; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)
void (*PicoPrepareCram)()=0; // prepares PicoCramHigh for renderer to use
// stuff available in asm:
#ifdef _ASM_DRAW_C
void BackFillFull(int reg7);
void DrawLayerFull(int plane, int *hcache, int planestart, int planeend);
void DrawTilesFromCacheF(int *hc);
void DrawWindowFull(int start, int end, int prio);
void DrawSpriteFull(unsigned int *sprite);
#else
static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
for(i=8; i; i--, addr+=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);
t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal);
t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal);
t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t )|pal);
t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal);
t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal);
t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal);
t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal);
blank = 0;
}
return blank; // Tile blank?
}
static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
for(i=8; i; i--, addr+=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);
t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal);
t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal);
t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal);
t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t )|pal);
t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal);
t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal);
t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal);
blank = 0;
}
return blank; // Tile blank?
}
static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
addr+=14;
for(i=8; i; i--, addr-=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);
t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal);
t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal);
t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t )|pal);
t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal);
t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal);
t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal);
t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal);
blank = 0;
}
return blank; // Tile blank?
}
static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
addr+=14;
for(i=8; i; i--, addr-=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);
t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal);
t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal);
t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal);
t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t )|pal);
t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal);
t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal);
t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal);
blank = 0;
}
return blank; // Tile blank?
}
// start: (tile_start<<16)|row_start, end: [same]
static void DrawWindowFull(int start, int end, int prio)
{
struct PicoVideo *pvid=&Pico.video;
int nametab, nametab_step, trow, tilex, blank=-1, code;
unsigned char *scrpos = PicoDraw2FB;
int tile_start, tile_end; // in cells
// parse ranges
tile_start = start>>16;
tile_end = end>>16;
start = start<<16>>16;
end = end<<16>>16;
// Find name table line:
if (pvid->reg[12]&1)
{
nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode
nametab_step = 1<<6;
}
else
{
nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode
nametab_step = 1<<5;
}
nametab += nametab_step*start;
// check priority
code=Pico.vram[nametab+tile_start];
if ((code>>15) != prio) return; // hack: just assume that whole window uses same priority
scrpos+=8*LINE_WIDTH+8;
scrpos+=8*LINE_WIDTH*(start-START_ROW);
// do a window until we reach planestart row
for(trow = start; trow < end; trow++, nametab+=nametab_step) { // current tile row
for (tilex=tile_start; tilex<tile_end; tilex++)
{
int code,addr,zero=0;
// unsigned short *pal=NULL;
unsigned char pal;
code=Pico.vram[nametab+tilex];
if (code==blank) continue;
// Get tile address/2:
addr=(code&0x7ff)<<4;
// pal=PicoCramHigh+((code>>9)&0x30);
pal=(unsigned char)((code>>9)&0x30);
switch((code>>11)&3) {
case 0: zero=TileXnormYnorm(scrpos+(tilex<<3),addr,pal); break;
case 1: zero=TileXflipYnorm(scrpos+(tilex<<3),addr,pal); break;
case 2: zero=TileXnormYflip(scrpos+(tilex<<3),addr,pal); break;
case 3: zero=TileXflipYflip(scrpos+(tilex<<3),addr,pal); break;
}
if(zero) blank=code; // We know this tile is blank now
}
scrpos += LINE_WIDTH*8;
}
}
static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
{
struct PicoVideo *pvid=&Pico.video;
static char shift[4]={5,6,6,7}; // 32,64 or 128 sized tilemaps
int width, height, ymask, htab;
int nametab, hscroll=0, vscroll, cells;
unsigned char *scrpos;
int blank=-1, xmask, nametab_row, trow;
// parse ranges
cells = (planeend>>16)-(planestart>>16);
planestart = planestart<<16>>16;
planeend = planeend<<16>>16;
// Work out the Tiles to draw
htab=pvid->reg[13]<<9; // Horizontal scroll table address
// if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line
// if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile
htab+=plane; // A or B
if(!(pvid->reg[11]&3)) { // full screen scroll
// Get horizontal scroll value
hscroll=Pico.vram[htab&0x7fff];
htab = 0; // this marks that we don't have to update scroll value
}
// Work out the name table size: 32 64 or 128 tiles (0-3)
width=pvid->reg[16];
height=(width>>4)&3; width&=3;
xmask=(1<<shift[width ])-1; // X Mask in tiles
ymask=(height<<5)|0x1f; // Y Mask in tiles
if(width == 1) ymask&=0x3f;
else if(width>1) ymask =0x1f;
// Find name table:
if (plane==0) nametab=(pvid->reg[2]&0x38)<< 9; // A
else nametab=(pvid->reg[4]&0x07)<<12; // B
scrpos = PicoDraw2FB;
scrpos+=8*LINE_WIDTH*(planestart-START_ROW);
// Get vertical scroll value:
vscroll=Pico.vsram[plane]&0x1ff;
scrpos+=(8-(vscroll&7))*LINE_WIDTH;
if(vscroll&7) planeend++; // we have vertically clipped tiles due to vscroll, so we need 1 more row
*hcache++ = 8-(vscroll&7); // push y-offset to tilecache
for(trow = planestart; trow < planeend; trow++) { // current tile row
int cellc=cells,tilex,dx;
// Find the tile row in the name table
//ts.line=(vscroll+Scanline)&ymask;
//ts.nametab+=(ts.line>>3)<<shift[width];
nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]); // pointer to nametable entries for this row
// update hscroll if needed
if(htab) {
int htaddr=htab+(trow<<4);
if(trow) htaddr-=(vscroll&7)<<1;
hscroll=Pico.vram[htaddr&0x7fff];
}
// Draw tiles across screen:
tilex=(-hscroll)>>3;
dx=((hscroll-1)&7)+1;
if(dx != 8) cellc++; // have hscroll, do more cells
for (; cellc; dx+=8,tilex++,cellc--)
{
int code=0,addr=0,zero=0;
// unsigned short *pal=NULL;
unsigned char pal;
code=Pico.vram[nametab_row+(tilex&xmask)];
if (code==blank) continue;
if (code>>15) { // high priority tile
*hcache++ = code|(dx<<16)|(trow<<27); // cache it
continue;
}
// Get tile address/2:
addr=(code&0x7ff)<<4;
// pal=PicoCramHigh+((code>>9)&0x30);
pal=(unsigned char)((code>>9)&0x30);
switch((code>>11)&3) {
case 0: zero=TileXnormYnorm(scrpos+dx,addr,pal); break;
case 1: zero=TileXflipYnorm(scrpos+dx,addr,pal); break;
case 2: zero=TileXnormYflip(scrpos+dx,addr,pal); break;
case 3: zero=TileXflipYflip(scrpos+dx,addr,pal); break;
}
if(zero) blank=code; // We know this tile is blank now
}
scrpos += LINE_WIDTH*8;
}
*hcache = 0; // terminate cache
}
static void DrawTilesFromCacheF(int *hc)
{
int code, addr, zero = 0;
unsigned int prevy=0xFFFFFFFF;
// unsigned short *pal;
unsigned char pal;
short blank=-1; // The tile we know is blank
unsigned char *scrpos = PicoDraw2FB, *pd = 0;
// *hcache++ = code|(dx<<16)|(trow<<27); // cache it
scrpos+=(*hc++)*LINE_WIDTH - START_ROW*LINE_WIDTH*8;
while((code=*hc++)) {
if((short)code == blank) continue;
// y pos
if(((unsigned)code>>27) != prevy) {
prevy = (unsigned)code>>27;
pd = scrpos + prevy*LINE_WIDTH*8;
}
// Get tile address/2:
addr=(code&0x7ff)<<4;
// pal=PicoCramHigh+((code>>9)&0x30);
pal=(unsigned char)((code>>9)&0x30);
switch((code>>11)&3) {
case 0: zero=TileXnormYnorm(pd+((code>>16)&0x1ff),addr,pal); break;
case 1: zero=TileXflipYnorm(pd+((code>>16)&0x1ff),addr,pal); break;
case 2: zero=TileXnormYflip(pd+((code>>16)&0x1ff),addr,pal); break;
case 3: zero=TileXflipYflip(pd+((code>>16)&0x1ff),addr,pal); break;
}
if(zero) blank=(short)code;
}
}
// sx and sy are coords of virtual screen with 8pix borders on top and on left
static void DrawSpriteFull(unsigned int *sprite)
{
int width=0,height=0;
// unsigned short *pal=NULL;
unsigned char pal;
int tile,code,tdeltax,tdeltay;
unsigned char *scrpos;
int sx, sy;
sy=sprite[0];
height=sy>>24;
sy=(sy&0x1ff)-0x78; // Y
width=(height>>2)&3; height&=3;
width++; height++; // Width and height in tiles
code=sprite[1];
sx=((code>>16)&0x1ff)-0x78; // X
tile=code&0x7ff; // Tile number
tdeltax=height; // Delta to increase tile by going right
tdeltay=1; // Delta to increase tile by going down
if (code&0x0800) { tdeltax=-tdeltax; tile+=height*(width-1); } // Flip X
if (code&0x1000) { tdeltay=-tdeltay; tile+=height-1; } // Flip Y
//delta<<=4; // Delta of address
// pal=PicoCramHigh+((code>>9)&0x30); // Get palette pointer
pal=(unsigned char)((code>>9)&0x30);
// goto first vertically visible tile
while(sy <= START_ROW*8) { sy+=8; tile+=tdeltay; height--; }
scrpos = PicoDraw2FB;
scrpos+=(sy-START_ROW*8)*LINE_WIDTH;
for (; height > 0; height--, sy+=8, tile+=tdeltay)
{
int w = width, x=sx, t=tile;
if(sy >= END_ROW*8+8) return; // offscreen
for (; w; w--,x+=8,t+=tdeltax)
{
if(x<=0) continue;
if(x>=328) break; // Offscreen
t&=0x7fff; // Clip tile address
switch((code>>11)&3) {
case 0: TileXnormYnorm(scrpos+x,t<<4,pal); break;
case 1: TileXflipYnorm(scrpos+x,t<<4,pal); break;
case 2: TileXnormYflip(scrpos+x,t<<4,pal); break;
case 3: TileXflipYflip(scrpos+x,t<<4,pal); break;
}
}
scrpos+=8*LINE_WIDTH;
}
}
#endif
static void DrawAllSpritesFull(int prio, int maxwidth)
{
struct PicoVideo *pvid=&Pico.video;
int table=0,maskrange=0;
int i,u,link=0;
unsigned int *sprites[80]; // Sprites
int y_min=START_ROW*8, y_max=END_ROW*8; // for a simple sprite masking
table=pvid->reg[5]&0x7f;
if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
table<<=8; // Get sprite table address/2
for (i=u=0; u < 80; u++)
{
unsigned int *sprite=NULL;
int code, code2, sx, sy, height;
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
// get sprite info
code = sprite[0];
// check if it is not hidden vertically
sy = (code&0x1ff)-0x80;
height = (((code>>24)&3)+1)<<3;
if(sy+height <= y_min || sy > y_max) goto nextsprite;
// masking sprite?
code2=sprite[1];
sx = (code2>>16)&0x1ff;
if(!sx) {
int to = sy+height; // sy ~ from
if(maskrange) {
// try to merge with previous range
if((maskrange>>16)+1 >= sy && (maskrange>>16) <= to && (maskrange&0xffff) < sy) sy = (maskrange&0xffff);
else if((maskrange&0xffff)-1 <= to && (maskrange&0xffff) >= sy && (maskrange>>16) > to) to = (maskrange>>16);
}
// support only very simple masking (top and bottom of screen)
if(sy <= y_min && to+1 > y_min) y_min = to+1;
else if(to >= y_max && sy-1 < y_max) y_max = sy-1;
else maskrange=sy|(to<<16);
goto nextsprite;
}
// priority
if(((code2>>15)&1) != prio) goto nextsprite; // wrong priority
// check if sprite is not hidden horizontally
sx -= 0x78; // Get X coordinate + 8
if(sx <= -8*3 || sx >= maxwidth) goto nextsprite;
// sprite is good, save it's index
sprites[i++]=sprite;
nextsprite:
// Find next sprite
link=(code>>16)&0x7f;
if(!link) break; // End of sprites
}
// Go through sprites backwards:
for (i-- ;i>=0; i--)
{
DrawSpriteFull(sprites[i]);
}
}
#ifndef _ASM_DRAW_C
static void BackFillFull(int reg7)
{
unsigned int back;
// Start with a background color:
// back=PicoCramHigh[reg7&0x3f];
back=reg7&0x3f;
back|=back<<8;
back|=back<<16;
memset32((int *)PicoDraw2FB, back, LINE_WIDTH*(8+(END_ROW-START_ROW)*8)/4);
}
#endif
static void DrawDisplayFull(void)
{
struct PicoVideo *pvid=&Pico.video;
int win, edge=0, hvwin=0; // LSb->MSb: hwin&plane, vwin&plane, full
int planestart=START_ROW, planeend=END_ROW; // plane A start/end when window shares display with plane A (in tile rows or columns)
int winstart=START_ROW, winend=END_ROW; // same for window
int maxw, maxcolc; // max width and col cells
if(pvid->reg[12]&1) {
maxw = 328; maxcolc = 40;
} else {
maxw = 264; maxcolc = 32;
}
// horizontal window?
if ((win=pvid->reg[0x12]))
{
hvwin=1; // hwindow shares display with plane A
edge=win&0x1f;
if(win == 0x80) {
// fullscreen window
hvwin=4;
} else if(win < 0x80) {
// window on the top
if(edge <= START_ROW) hvwin=0; // window not visible in our drawing region
else if(edge >= END_ROW) hvwin=4;
else planestart = winend = edge;
} else if(win > 0x80) {
// window at the bottom
if(edge >= END_ROW) hvwin=0;
else planeend = winstart = edge;
}
}
// check for vertical window, but only if win is not fullscreen
if (hvwin != 4)
{
win=pvid->reg[0x11];
edge=win&0x1f;
if (win&0x80) {
if(!edge) hvwin=4;
else if(edge < (maxcolc>>1)) {
// window is on the right
hvwin|=2;
planeend|=edge<<17;
winstart|=edge<<17;
winend|=maxcolc<<16;
}
} else {
if(edge >= (maxcolc>>1)) hvwin=4;
else if(edge) {
// window is on the left
hvwin|=2;
winend|=edge<<17;
planestart|=edge<<17;
planeend|=maxcolc<<16;
}
}
}
if (hvwin==1) { winend|=maxcolc<<16; planeend|=maxcolc<<16; }
HighCache2A[1] = HighCache2B[1] = 0;
if (PicoDrawMask & PDRAW_LAYERB_ON)
DrawLayerFull(1, HighCache2B, START_ROW, (maxcolc<<16)|END_ROW);
if (PicoDrawMask & PDRAW_LAYERA_ON) switch (hvwin)
{
case 4:
// fullscreen window
DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 0);
break;
case 3:
// we have plane A and both v and h windows
DrawLayerFull(0, HighCache2A, planestart, planeend);
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 0); // h
DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 0); // v
break;
case 2:
case 1:
// both window and plane A visible, window is vertical XOR horizontal
DrawLayerFull(0, HighCache2A, planestart, planeend);
DrawWindowFull(winstart, winend, 0);
break;
default:
// fullscreen plane A
DrawLayerFull(0, HighCache2A, START_ROW, (maxcolc<<16)|END_ROW);
break;
}
if (PicoDrawMask & PDRAW_SPRITES_LOW_ON)
DrawAllSpritesFull(0, maxw);
if (HighCache2B[1]) DrawTilesFromCacheF(HighCache2B);
if (HighCache2A[1]) DrawTilesFromCacheF(HighCache2A);
if (PicoDrawMask & PDRAW_LAYERA_ON) switch (hvwin)
{
case 4:
// fullscreen window
DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 1);
break;
case 3:
// we have plane A and both v and h windows
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 1); // h
DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 1); // v
break;
case 2:
case 1:
// both window and plane A visible, window is vertical XOR horizontal
DrawWindowFull(winstart, winend, 1);
break;
}
if (PicoDrawMask & PDRAW_SPRITES_HI_ON)
DrawAllSpritesFull(1, maxw);
}
PICO_INTERNAL void PicoFrameFull()
{
pprof_start(draw);
// prepare cram?
if (PicoPrepareCram) PicoPrepareCram();
// Draw screen:
BackFillFull(Pico.video.reg[7]);
if (Pico.video.reg[1] & 0x40)
DrawDisplayFull();
pprof_end(draw);
}

View File

@ -0,0 +1,212 @@
/*
* rarely used EEPROM code
* (C) notaz, 2007-2009
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*
* (see Genesis Plus for Wii/GC code and docs for info,
* full game list and better code).
*/
#include "pico_int.h"
static unsigned int last_write = 0xffff0000;
// eeprom_status: LA.. s.la (L=pending SCL, A=pending SDA,
// s=started, l=old SCL, a=old SDA)
static void EEPROM_write_do(unsigned int d) // ???? ??la (l=SCL, a=SDA)
{
unsigned int sreg = Pico.m.eeprom_status, saddr = Pico.m.eeprom_addr;
unsigned int scyc = Pico.m.eeprom_cycle, ssa = Pico.m.eeprom_slave;
elprintf(EL_EEPROM, "eeprom: scl/sda: %i/%i -> %i/%i, newtime=%i", (sreg&2)>>1, sreg&1,
(d&2)>>1, d&1, SekCyclesDone() - last_write);
saddr &= 0x1fff;
if(sreg & d & 2) {
// SCL was and is still high..
if((sreg & 1) && !(d&1)) {
// ..and SDA went low, means it's a start command, so clear internal addr reg and clock counter
elprintf(EL_EEPROM, "eeprom: -start-");
//saddr = 0;
scyc = 0;
sreg |= 8;
} else if(!(sreg & 1) && (d&1)) {
// SDA went high == stop command
elprintf(EL_EEPROM, "eeprom: -stop-");
sreg &= ~8;
}
}
else if((sreg & 8) && !(sreg & 2) && (d&2))
{
// we are started and SCL went high - next cycle
scyc++; // pre-increment
if(SRam.eeprom_type) {
// X24C02+
if((ssa&1) && scyc == 18) {
scyc = 9;
saddr++; // next address in read mode
/*if(SRam.eeprom_type==2) saddr&=0xff; else*/ saddr&=0x1fff; // mask
}
else if(SRam.eeprom_type == 2 && scyc == 27) scyc = 18;
else if(scyc == 36) scyc = 27;
} else {
// X24C01
if(scyc == 18) {
scyc = 9; // wrap
if(saddr&1) { saddr+=2; saddr&=0xff; } // next addr in read mode
}
}
elprintf(EL_EEPROM, "eeprom: scyc: %i", scyc);
}
else if((sreg & 8) && (sreg & 2) && !(d&2))
{
// we are started and SCL went low (falling edge)
if(SRam.eeprom_type) {
// X24C02+
if(scyc == 9 || scyc == 18 || scyc == 27); // ACK cycles
else if( (SRam.eeprom_type == 3 && scyc > 27) || (SRam.eeprom_type == 2 && scyc > 18) ) {
if(!(ssa&1)) {
// data write
unsigned char *pm=SRam.data+saddr;
*pm <<= 1; *pm |= d&1;
if(scyc == 26 || scyc == 35) {
saddr=(saddr&~0xf)|((saddr+1)&0xf); // only 4 (?) lowest bits are incremented
elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr, *pm);
}
SRam.changed = 1;
}
} else if(scyc > 9) {
if(!(ssa&1)) {
// we latch another addr bit
saddr<<=1;
if(SRam.eeprom_type == 2) saddr&=0xff; else saddr&=0x1fff; // mask
saddr|=d&1;
if(scyc==17||scyc==26) {
elprintf(EL_EEPROM, "eeprom: addr reg done: %x", saddr);
if(scyc==17&&SRam.eeprom_type==2) { saddr&=0xff; saddr|=(ssa<<7)&0x700; } // add device bits too
}
}
} else {
// slave address
ssa<<=1; ssa|=d&1;
if(scyc==8) elprintf(EL_EEPROM, "eeprom: slave done: %x", ssa);
}
} else {
// X24C01
if(scyc == 9); // ACK cycle, do nothing
else if(scyc > 9) {
if(!(saddr&1)) {
// data write
unsigned char *pm=SRam.data+(saddr>>1);
*pm <<= 1; *pm |= d&1;
if(scyc == 17) {
saddr=(saddr&0xf9)|((saddr+2)&6); // only 2 lowest bits are incremented
elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr>>1, *pm);
}
SRam.changed = 1;
}
} else {
// we latch another addr bit
saddr<<=1; saddr|=d&1; saddr&=0xff;
if(scyc==8) elprintf(EL_EEPROM, "eeprom: addr done: %x", saddr>>1);
}
}
}
sreg &= ~3; sreg |= d&3; // remember SCL and SDA
Pico.m.eeprom_status = (unsigned char) sreg;
Pico.m.eeprom_cycle = (unsigned char) scyc;
Pico.m.eeprom_slave = (unsigned char) ssa;
Pico.m.eeprom_addr = (unsigned short)saddr;
}
static void EEPROM_upd_pending(unsigned int d)
{
unsigned int d1, sreg = Pico.m.eeprom_status;
sreg &= ~0xc0;
// SCL
d1 = (d >> SRam.eeprom_bit_cl) & 1;
sreg |= d1 << 7;
// SDA in
d1 = (d >> SRam.eeprom_bit_in) & 1;
sreg |= d1 << 6;
Pico.m.eeprom_status = (unsigned char) sreg;
}
void EEPROM_write16(unsigned int d)
{
// this diff must be at most 16 for NBA Jam to work
if (SekCyclesDone() - last_write < 16) {
// just update pending state
elprintf(EL_EEPROM, "eeprom: skip because cycles=%i",
SekCyclesDone() - last_write);
EEPROM_upd_pending(d);
} else {
int srs = Pico.m.eeprom_status;
EEPROM_write_do(srs >> 6); // execute pending
EEPROM_upd_pending(d);
if ((srs ^ Pico.m.eeprom_status) & 0xc0) // update time only if SDA/SCL changed
last_write = SekCyclesDone();
}
}
void EEPROM_write8(unsigned int a, unsigned int d)
{
unsigned char *wb = Pico.m.eeprom_wb;
wb[a & 1] = d;
EEPROM_write16((wb[0] << 8) | wb[1]);
}
unsigned int EEPROM_read(void)
{
unsigned int shift, d;
unsigned int sreg, saddr, scyc, ssa, interval;
// flush last pending write
EEPROM_write_do(Pico.m.eeprom_status>>6);
sreg = Pico.m.eeprom_status; saddr = Pico.m.eeprom_addr&0x1fff; scyc = Pico.m.eeprom_cycle; ssa = Pico.m.eeprom_slave;
interval = SekCyclesDone() - last_write;
d = (sreg>>6)&1; // use SDA as "open bus"
// NBA Jam is nasty enough to read <before> raising the SCL and starting the new cycle.
// this is probably valid because data changes occur while SCL is low and data can be read
// before it's actual cycle begins.
if (!(sreg&0x80) && interval >= 24) {
elprintf(EL_EEPROM, "eeprom: early read, cycles=%i", interval);
scyc++;
}
if (!(sreg & 8)); // not started, use open bus
else if (scyc == 9 || scyc == 18 || scyc == 27) {
elprintf(EL_EEPROM, "eeprom: r ack");
d = 0;
} else if (scyc > 9 && scyc < 18) {
// started and first command word received
shift = 17-scyc;
if (SRam.eeprom_type) {
// X24C02+
if (ssa&1) {
elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg);
if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr]);
d = (SRam.data[saddr]>>shift)&1;
}
} else {
// X24C01
if (saddr&1) {
elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr>>1, scyc, sreg);
if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr>>1]);
d = (SRam.data[saddr>>1]>>shift)&1;
}
}
}
return (d << SRam.eeprom_bit_out);
}

View File

@ -0,0 +1,161 @@
/*
* PicoDrive
* (C) notaz, 2006-2010,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <string.h>
#include "pico_int.h"
#include "cd/cue.h"
unsigned char media_id_header[0x100];
static void strlwr_(char *string)
{
char *p;
for (p = string; *p; p++)
if ('A' <= *p && *p <= 'Z')
*p += 'a' - 'A';
}
static void get_ext(const char *file, char *ext)
{
const char *p;
p = file + strlen(file) - 4;
if (p < file)
p = file;
strncpy(ext, p, 4);
ext[4] = 0;
strlwr_(ext);
}
enum media_type_e PicoLoadMedia(
const char *filename,
const char *carthw_cfg_fname,
const char *(*get_bios_filename)(int *region, const char *cd_fname),
void (*do_region_override)(const char *media_filename), enum media_type_e media_type)
{
const char *rom_fname = filename;
enum cd_img_type cd_img_type = CIT_NOT_CD;
unsigned char *rom_data = NULL;
unsigned int rom_size = 0;
pm_file *rom = NULL;
int cd_region = 0;
int ret;
if (media_type == PM_BAD_DETECT)
goto out;
PicoAHW = 0;
PicoQuirks = 0;
if (media_type == PM_CD)
{
// check for MegaCD image
cd_img_type = PicoCdCheck(filename, &cd_region);
if ((int)cd_img_type >= 0 && cd_img_type != CIT_NOT_CD)
{
// valid CD image, ask frontend for BIOS..
rom_fname = NULL;
if (get_bios_filename != NULL)
rom_fname = get_bios_filename(&cd_region, filename);
if (rom_fname == NULL)
{
media_type = PM_BAD_CD_NO_BIOS;
goto out;
}
PicoAHW |= PAHW_MCD;
}
else
{
media_type = PM_BAD_CD;
goto out;
}
}
else if (media_type == PM_MARK3)
{
lprintf("detected SMS ROM\n");
PicoAHW = PAHW_SMS;
}
rom = pm_open(rom_fname);
if (rom == NULL)
{
lprintf("Failed to open ROM");
media_type = PM_ERROR;
goto out;
}
ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0);
pm_close(rom);
if (ret != 0)
{
if (ret == 2)
lprintf("Out of memory");
else if (ret == 3)
lprintf("Read failed");
else
lprintf("PicoCartLoad() failed.");
media_type = PM_ERROR;
goto out;
}
// detect wrong files
if (strncmp((char *)rom_data, "Pico", 4) == 0)
{
lprintf("savestate selected?\n");
media_type = PM_BAD_DETECT;
goto out;
}
if (!(PicoAHW & PAHW_SMS))
{
unsigned short *d = (unsigned short *)(rom_data + 4);
if ((((d[0] << 16) | d[1]) & 0xffffff) >= (int)rom_size)
{
lprintf("bad reset vector\n");
media_type = PM_BAD_DETECT;
goto out;
}
}
// load config for this ROM (do this before insert to get correct region)
if (!(PicoAHW & PAHW_MCD))
{
memcpy(media_id_header, rom_data + 0x100, sizeof(media_id_header));
if (do_region_override != NULL)
do_region_override(filename);
}
if (PicoCartInsert(rom_data, rom_size, carthw_cfg_fname))
{
media_type = PM_ERROR;
goto out;
}
rom_data = NULL; // now belongs to PicoCart
Pico.m.ncart_in = 0;
// insert CD if it was detected
if (cd_img_type != CIT_NOT_CD)
{
ret = cdd_load(filename, cd_img_type);
if (ret != 0)
{
media_type = PM_BAD_CD;
goto out;
}
Pico.m.ncart_in = 1;
}
if (PicoQuirks & PQUIRK_FORCE_6BTN)
PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN);
out:
if (rom_data)
free(rom_data);
return media_type;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
// memory map related stuff
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long uptr; // unsigned pointer-sized int
#define M68K_MEM_SHIFT 16
// minimum size we can map
#define M68K_BANK_SIZE (1 << M68K_MEM_SHIFT)
#define M68K_BANK_MASK (M68K_BANK_SIZE - 1)
extern uptr m68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];
extern uptr m68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
extern uptr m68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];
extern uptr m68k_write16_map[0x1000000 >> M68K_MEM_SHIFT];
extern uptr s68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];
extern uptr s68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
extern uptr s68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];
extern uptr s68k_write16_map[0x1000000 >> M68K_MEM_SHIFT];
// top-level handlers that cores can use
// (or alternatively build them into themselves)
// XXX: unhandled: *16 and *32 might cross the bank boundaries
typedef u32 (cpu68k_read_f)(u32 a);
typedef void (cpu68k_write_f)(u32 a, u32 d);
extern u32 m68k_read8(u32 a);
extern u32 m68k_read16(u32 a);
extern void m68k_write8(u32 a, u8 d);
extern void m68k_write16(u32 a, u16 d);
// z80
#define Z80_MEM_SHIFT 13
extern uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
extern uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT];
typedef unsigned char (z80_read_f)(unsigned short a);
typedef void (z80_write_f)(unsigned int a, unsigned char data);
void z80_map_set(uptr *map, int start_addr, int end_addr,
const void *func_or_mh, int is_func);
void cpu68k_map_set(uptr *map, int start_addr, int end_addr,
const void *func_or_mh, int is_func);
void cpu68k_map_all_ram(int start_addr, int end_addr, void *ptr, int is_sub);
void m68k_map_unmap(int start_addr, int end_addr);
#define MAP_FLAG ((uptr)1 << (sizeof(uptr) * 8 - 1))
#define map_flag_set(x) ((x) & MAP_FLAG)
#define MAKE_68K_READ8(name, map) \
u32 name(u32 a) \
{ \
uptr v; \
a &= 0x00ffffff; \
v = map[a >> M68K_MEM_SHIFT]; \
if (map_flag_set(v)) \
return ((cpu68k_read_f *)(v << 1))(a); \
else \
return *(u8 *)((v << 1) + (a ^ 1)); \
}
#define MAKE_68K_READ16(name, map) \
u32 name(u32 a) \
{ \
uptr v; \
a &= 0x00fffffe; \
v = map[a >> M68K_MEM_SHIFT]; \
if (map_flag_set(v)) \
return ((cpu68k_read_f *)(v << 1))(a); \
else \
return *(u16 *)((v << 1) + a); \
}
#define MAKE_68K_READ32(name, map) \
u32 name(u32 a) \
{ \
uptr v, vs; \
u32 d; \
a &= 0x00fffffe; \
v = map[a >> M68K_MEM_SHIFT]; \
vs = v << 1; \
if (map_flag_set(v)) { \
d = ((cpu68k_read_f *)vs)(a) << 16; \
d |= ((cpu68k_read_f *)vs)(a + 2); \
} \
else { \
u16 *m = (u16 *)(vs + a); \
d = (m[0] << 16) | m[1]; \
} \
return d; \
}
#define MAKE_68K_WRITE8(name, map) \
void name(u32 a, u8 d) \
{ \
uptr v; \
a &= 0x00ffffff; \
v = map[a >> M68K_MEM_SHIFT]; \
if (map_flag_set(v)) \
((cpu68k_write_f *)(v << 1))(a, d); \
else \
*(u8 *)((v << 1) + (a ^ 1)) = d; \
}
#define MAKE_68K_WRITE16(name, map) \
void name(u32 a, u16 d) \
{ \
uptr v; \
a &= 0x00fffffe; \
v = map[a >> M68K_MEM_SHIFT]; \
if (map_flag_set(v)) \
((cpu68k_write_f *)(v << 1))(a, d); \
else \
*(u16 *)((v << 1) + a) = d; \
}
#define MAKE_68K_WRITE32(name, map) \
void name(u32 a, u32 d) \
{ \
uptr v, vs; \
a &= 0x00fffffe; \
v = map[a >> M68K_MEM_SHIFT]; \
vs = v << 1; \
if (map_flag_set(v)) { \
((cpu68k_write_f *)vs)(a, d >> 16); \
((cpu68k_write_f *)vs)(a + 2, d); \
} \
else { \
u16 *m = (u16 *)(vs + a); \
m[0] = d >> 16; \
m[1] = d; \
} \
}
// 32x
typedef struct {
uptr addr; // stores (membase >> 1) or ((handler >> 1) | (1<<31))
u32 mask;
} sh2_memmap;

View File

@ -0,0 +1,158 @@
/*
* rarely used EEPROM code
* (C) notaz, 2006-2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "pico_int.h"
// H-counter table for hvcounter reads in 40col mode
// based on Gens code
const unsigned char hcounts_40[] = {
0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,
0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,
0x14,0x15,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,
0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21,
0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28,
0x28,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f,
0x2f,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x35,
0x36,0x36,0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3c,0x3c,
0x3d,0x3d,0x3d,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x41,0x41,0x42,0x42,0x42,0x43,
0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x47,0x47,0x47,0x48,0x48,0x49,0x49,0x4a,
0x4a,0x4a,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,
0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x57,0x57,
0x57,0x58,0x58,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5e,
0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x64,0x64,0x64,
0x65,0x65,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,
0x6c,0x6c,0x6c,0x6d,0x6d,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x71,0x71,0x71,0x72,
0x72,0x73,0x73,0x74,0x74,0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x79,
0x79,0x79,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,
0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x84,0x84,0x84,0x85,0x85,0x86,0x86,
0x86,0x87,0x87,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,
0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92,0x92,0x93,0x93,0x94,
0x94,0x94,0x95,0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a,
0x9b,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa1,0xa1,
0xa1,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,0xa8,
0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xab,0xab,0xab,0xac,0xac,0xad,0xad,0xae,0xae,0xae,
0xaf,0xaf,0xb0,0xb0,
0xe4,0xe4,0xe4,0xe5,0xe5,0xe6,0xe6,0xe6,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,
0xea,0xeb,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,
0xf1,0xf1,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,
0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfe,0xfe,
0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x05,
0x05,0x06,0x06,0x06,
0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,
0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,
};
// H-counter table for hvcounter reads in 32col mode
const unsigned char hcounts_32[] = {
0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,
0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x0f,0x10,
0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x15,
0x15,0x16,0x16,0x17,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b,
0x1b,0x1b,0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x1f,0x20,0x20,0x20,
0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x26,0x26,
0x26,0x27,0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,
0x2c,0x2c,0x2c,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x30,0x31,0x31,
0x31,0x32,0x32,0x32,0x33,0x33,0x33,0x34,0x34,0x34,0x35,0x35,0x36,0x36,0x36,0x37,
0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3b,0x3c,0x3c,
0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,0x41,0x41,0x41,0x42,
0x42,0x42,0x43,0x43,0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x46,0x47,0x47,0x47,
0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,
0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,0x50,0x51,0x51,0x51,0x52,0x52,0x52,
0x53,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,0x57,0x58,0x58,
0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e,
0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x60,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,
0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69,
0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,
0x6f,0x6f,0x6f,0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x74,0x74,
0x74,0x75,0x75,0x75,0x76,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x79,
0x7a,0x7a,0x7b,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,
0x7f,0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x83,0x84,0x84,0x84,0x85,
0x85,0x85,0x86,0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,
0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x90,
0x90,0x90,0x91,0x91,
0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,0xeb,0xec,0xec,0xec,0xed,
0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf2,0xf2,0xf2,
0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf8,0xf8,
0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,
0xfe,0xfe,0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,
0x03,0x04,0x04,0x04,
0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,
0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,
};
#ifndef _ASM_MISC_C
typedef struct
{
int b0;
int b1;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
} intblock;
PICO_INTERNAL_ASM void memcpy16(unsigned short *dest, unsigned short *src, int count)
{
if ((((long)dest | (long)src) & 3) == 0)
{
if (count >= 32) {
memcpy32((int *)dest, (int *)src, count/2);
count&=1;
} else {
for (; count >= 2; count -= 2, dest+=2, src+=2)
*(int *)dest = *(int *)src;
}
}
while (count--)
*dest++ = *src++;
}
PICO_INTERNAL_ASM void memcpy16bswap(unsigned short *dest, void *src, int count)
{
unsigned char *src_ = src;
for (; count; count--, src_ += 2)
*dest++ = (src_[0] << 8) | src_[1];
}
#ifndef _ASM_MISC_C_AMIPS
PICO_INTERNAL_ASM void memcpy32(void *dest_in, const void *src_in, int count)
{
const intblock *bs = (intblock *) src_in;
intblock *bd = (intblock *) dest_in;
const int *src;
int *dest;
for (; count >= sizeof(*bd)/4; count -= sizeof(*bd)/4)
*bd++ = *bs++;
dest = (int *)bd; src = (const int *)bs;
while (count--)
*dest++ = *src++;
}
PICO_INTERNAL_ASM void memset32(void *dest_in, int c, int count)
{
int *dest = dest_in;
for (; count >= 8; count -= 8, dest += 8)
dest[0] = dest[1] = dest[2] = dest[3] =
dest[4] = dest[5] = dest[6] = dest[7] = c;
while (count--)
*dest++ = c;
}
void memset32_uncached(int *dest, int c, int count) { memset32(dest, c, count); }
#endif
#endif

View File

@ -0,0 +1,302 @@
/*
* mode4/SMS renderer
* (C) notaz, 2009-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
/*
* TODO:
* - TMS9918 modes?
* - gg mode?
* - column scroll (reg 0 bit7)
* - 224/240 line modes
* - doubled sprites
*/
#include "pico_int.h"
static void (*FinalizeLineM4)(int line);
static int skip_next_line;
static int screen_offset;
#define PLANAR_PIXEL(x,p) \
t = pack & (0x80808080 >> p); \
if (t) { \
t = ((t >> (7-p)) | (t >> (14-p)) | (t >> (21-p)) | (t >> (28-p))) & 0x0f; \
pd[x] = pal|t; \
}
static int TileNormM4(int sx, int addr, int pal)
{
unsigned char *pd = HighCol + sx;
unsigned int pack, t;
pack = *(unsigned int *)(Pico.vram + addr); /* Get 4 bitplanes / 8 pixels */
if (pack)
{
PLANAR_PIXEL(0, 0)
PLANAR_PIXEL(1, 1)
PLANAR_PIXEL(2, 2)
PLANAR_PIXEL(3, 3)
PLANAR_PIXEL(4, 4)
PLANAR_PIXEL(5, 5)
PLANAR_PIXEL(6, 6)
PLANAR_PIXEL(7, 7)
return 0;
}
return 1; /* Tile blank */
}
static int TileFlipM4(int sx,int addr,int pal)
{
unsigned char *pd = HighCol + sx;
unsigned int pack, t;
pack = *(unsigned int *)(Pico.vram + addr); /* Get 4 bitplanes / 8 pixels */
if (pack)
{
PLANAR_PIXEL(0, 7)
PLANAR_PIXEL(1, 6)
PLANAR_PIXEL(2, 5)
PLANAR_PIXEL(3, 4)
PLANAR_PIXEL(4, 3)
PLANAR_PIXEL(5, 2)
PLANAR_PIXEL(6, 1)
PLANAR_PIXEL(7, 0)
return 0;
}
return 1; /* Tile blank */
}
static void draw_sprites(int scanline)
{
struct PicoVideo *pv = &Pico.video;
unsigned int sprites_addr[8];
unsigned int sprites_x[8];
unsigned char *sat;
int xoff = 8; // relative to HighCol, which is (screen - 8)
int sprite_base, addr_mask;
int i, s, h;
if (pv->reg[0] & 8)
xoff = 0;
sat = (unsigned char *)Pico.vram + ((pv->reg[5] & 0x7e) << 7);
if (pv->reg[1] & 2) {
addr_mask = 0xfe; h = 16;
} else {
addr_mask = 0xff; h = 8;
}
sprite_base = (pv->reg[6] & 4) << (13-2-1);
for (i = s = 0; i < 64 && s < 8; i++)
{
int y;
y = sat[i] + 1;
if (y == 0xd1)
break;
if (y + h <= scanline || scanline < y)
continue; // not on this line
sprites_x[s] = xoff + sat[0x80 + i*2];
sprites_addr[s] = sprite_base + ((sat[0x80 + i*2 + 1] & addr_mask) << (5-1)) +
((scanline - y) << (2-1));
s++;
}
// now draw all sprites backwards
for (--s; s >= 0; s--)
TileNormM4(sprites_x[s], sprites_addr[s], 0x10);
}
// tilex_ty_prio merged to reduce register pressure
static void draw_strip(const unsigned short *nametab, int dx, int cells, int tilex_ty_prio)
{
int oldcode = -1, blank = -1; // The tile we know is blank
int addr = 0, pal = 0;
// Draw tiles across screen:
for (; cells > 0; dx += 8, tilex_ty_prio++, cells--)
{
int code, zero;
code = nametab[tilex_ty_prio & 0x1f];
if (code == blank)
continue;
if ((code ^ tilex_ty_prio) & 0x1000) // priority differs?
continue;
if (code != oldcode) {
oldcode = code;
// Get tile address/2:
addr = (code & 0x1ff) << 4;
addr += tilex_ty_prio >> 16;
if (code & 0x0400)
addr ^= 0xe; // Y-flip
pal = (code>>7) & 0x10;
}
if (code&0x0200) zero = TileFlipM4(dx, addr, pal);
else zero = TileNormM4(dx, addr, pal);
if (zero)
blank = code; // We know this tile is blank now
}
}
static void DrawDisplayM4(int scanline)
{
struct PicoVideo *pv = &Pico.video;
unsigned short *nametab;
int line, tilex, dx, ty, cells;
int cellskip = 0; // XXX
int maxcells = 32;
// Find the line in the name table
line = pv->reg[9] + scanline; // vscroll + scanline
if (line >= 224)
line -= 224;
// Find name table:
nametab = Pico.vram;
nametab += (pv->reg[2] & 0x0e) << (10-1);
nametab += (line>>3) << (6-1);
dx = pv->reg[8]; // hscroll
if (scanline < 16 && (pv->reg[0] & 0x40))
dx = 0; // hscroll disabled for top 2 rows
tilex = ((-dx >> 3) + cellskip) & 0x1f;
ty = (line & 7) << 1; // Y-Offset into tile
cells = maxcells - cellskip;
dx = ((dx - 1) & 7) + 1;
if (dx != 8)
cells++; // have hscroll, need to draw 1 cell more
dx += cellskip << 3;
// low priority tiles
if (PicoDrawMask & PDRAW_LAYERB_ON)
draw_strip(nametab, dx, cells, tilex | 0x0000 | (ty << 16));
// sprites
if (PicoDrawMask & PDRAW_SPRITES_LOW_ON)
draw_sprites(scanline);
// high priority tiles (use virtual layer switch just for fun)
if (PicoDrawMask & PDRAW_LAYERA_ON)
draw_strip(nametab, dx, cells, tilex | 0x1000 | (ty << 16));
if (pv->reg[0] & 0x20)
// first column masked
((int *)HighCol)[2] = ((int *)HighCol)[3] = 0xe0e0e0e0;
}
void PicoFrameStartMode4(void)
{
int lines = 192;
skip_next_line = 0;
screen_offset = 24;
rendstatus = PDRAW_32_COLS;
if ((Pico.video.reg[0] & 6) == 6 && (Pico.video.reg[1] & 0x18)) {
if (Pico.video.reg[1] & 0x08) {
screen_offset = 0;
lines = 240;
}
else {
screen_offset = 8;
lines = 224;
}
}
if (rendstatus != rendstatus_old || lines != rendlines) {
emu_video_mode_change(screen_offset, lines, 1);
rendstatus_old = rendstatus;
rendlines = lines;
}
DrawLineDest = (char *)DrawLineDestBase + screen_offset * DrawLineDestIncrement;
}
void PicoLineMode4(int line)
{
if (skip_next_line > 0) {
skip_next_line--;
return;
}
if (PicoScanBegin != NULL)
skip_next_line = PicoScanBegin(line + screen_offset);
// Draw screen:
BackFill(Pico.video.reg[7] & 0x0f, 0);
if (Pico.video.reg[1] & 0x40)
DrawDisplayM4(line);
if (FinalizeLineM4 != NULL)
FinalizeLineM4(line);
if (PicoScanEnd != NULL)
skip_next_line = PicoScanEnd(line + screen_offset);
DrawLineDest = (char *)DrawLineDest + DrawLineDestIncrement;
}
void PicoDoHighPal555M4(void)
{
unsigned int *spal=(void *)Pico.cram;
unsigned int *dpal=(void *)HighPal;
unsigned int t;
int i;
Pico.m.dirtyPal = 0;
/* cram is always stored as shorts, even though real hardware probably uses bytes */
for (i = 0x20/2; i > 0; i--, spal++, dpal++) {
t = *spal;
#ifdef USE_BGR555
t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)<<10);
#else
t = ((t & 0x00030003)<<14) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)>>1);
#endif
t |= t >> 2;
t |= (t >> 4) & 0x08610861;
*dpal = t;
}
HighPal[0xe0] = 0;
}
static void FinalizeLineRGB555M4(int line)
{
if (Pico.m.dirtyPal)
PicoDoHighPal555M4();
// standard FinalizeLine can finish it for us,
// with features like scaling and such
FinalizeLine555(0, line);
}
static void FinalizeLine8bitM4(int line)
{
unsigned char *pd = DrawLineDest;
if (!(PicoOpt & POPT_DIS_32C_BORDER))
pd += 32;
memcpy32((int *)pd, (int *)(HighCol+8), 256/4);
}
void PicoDrawSetOutputMode4(pdso_t which)
{
switch (which)
{
case PDF_8BIT: FinalizeLineM4 = FinalizeLine8bitM4; break;
case PDF_RGB555: FinalizeLineM4 = FinalizeLineRGB555M4; break;
default: FinalizeLineM4 = NULL; break;
}
}

View File

@ -0,0 +1,345 @@
/*
* PicoDrive
* (c) Copyright Dave, 2004
* (C) notaz, 2006-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "pico_int.h"
#include "sound/ym2612.h"
struct Pico Pico;
int PicoOpt;
int PicoSkipFrame; // skip rendering frame?
int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU
int PicoPadInt[2]; // internal copy
int PicoAHW; // active addon hardware: PAHW_*
int PicoQuirks; // game-specific quirks
int PicoRegionOverride; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
int PicoAutoRgnOrder;
struct PicoSRAM SRam;
int emustatus; // rapid_ym2612, multi_ym_updates
int scanlines_total;
void (*PicoWriteSound)(int len) = NULL; // called at the best time to send sound buffer (PsndOut) to hardware
void (*PicoResetHook)(void) = NULL;
void (*PicoLineHook)(void) = NULL;
// to be called once on emu init
void PicoInit(void)
{
// Blank space for state:
memset(&Pico,0,sizeof(Pico));
memset(&PicoPad,0,sizeof(PicoPad));
memset(&PicoPadInt,0,sizeof(PicoPadInt));
// Init CPUs:
SekInit();
z80_init(); // init even if we aren't going to use it
PicoInitMCD();
PicoSVPInit();
Pico32xInit();
}
void PicoPower(void)
{
Pico.m.frame_count = 0;
SekCycleCnt = SekCycleAim = 0;
// clear all memory of the emulated machine
memset(&Pico.ram,0,(unsigned char *)&Pico.rom - Pico.ram);
memset(&Pico.video,0,sizeof(Pico.video));
memset(&Pico.m,0,sizeof(Pico.m));
Pico.video.pending_ints=0;
z80_reset();
// my MD1 VA6 console has this in IO
Pico.ioports[1] = Pico.ioports[2] = Pico.ioports[3] = 0xff;
// default VDP register values (based on Fusion)
Pico.video.reg[0] = Pico.video.reg[1] = 0x04;
Pico.video.reg[0xc] = 0x81;
Pico.video.reg[0xf] = 0x02;
if (PicoAHW & PAHW_MCD)
PicoPowerMCD();
if (PicoOpt & POPT_EN_32X)
PicoPower32x();
PicoReset();
}
PICO_INTERNAL void PicoDetectRegion(void)
{
int support=0, hw=0, i;
unsigned char pal=0;
if (PicoRegionOverride)
{
support = PicoRegionOverride;
}
else
{
// Read cartridge region data:
unsigned short *rd = (unsigned short *)(Pico.rom + 0x1f0);
int region = (rd[0] << 16) | rd[1];
for (i = 0; i < 4; i++)
{
int c;
c = region >> (i<<3);
c &= 0xff;
if (c <= ' ') continue;
if (c=='J') support|=1;
else if (c=='U') support|=4;
else if (c=='E') support|=8;
else if (c=='j') {support|=1; break; }
else if (c=='u') {support|=4; break; }
else if (c=='e') {support|=8; break; }
else
{
// New style code:
char s[2]={0,0};
s[0]=(char)c;
support|=strtol(s,NULL,16);
}
}
}
// auto detection order override
if (PicoAutoRgnOrder) {
if (((PicoAutoRgnOrder>>0)&0xf) & support) support = (PicoAutoRgnOrder>>0)&0xf;
else if (((PicoAutoRgnOrder>>4)&0xf) & support) support = (PicoAutoRgnOrder>>4)&0xf;
else if (((PicoAutoRgnOrder>>8)&0xf) & support) support = (PicoAutoRgnOrder>>8)&0xf;
}
// Try to pick the best hardware value for English/50hz:
if (support&8) { hw=0xc0; pal=1; } // Europe
else if (support&4) hw=0x80; // USA
else if (support&2) { hw=0x40; pal=1; } // Japan PAL
else if (support&1) hw=0x00; // Japan NTSC
else hw=0x80; // USA
Pico.m.hardware=(unsigned char)(hw|0x20); // No disk attached
Pico.m.pal=pal;
}
int PicoReset(void)
{
if (Pico.romsize <= 0)
return 1;
#if defined(CPU_CMP_R) || defined(CPU_CMP_W) || defined(DRC_CMP)
PicoOpt |= POPT_DIS_VDP_FIFO|POPT_DIS_IDLE_DET;
#endif
/* must call now, so that banking is reset, and correct vectors get fetched */
if (PicoResetHook)
PicoResetHook();
memset(&PicoPadInt,0,sizeof(PicoPadInt));
emustatus = 0;
if (PicoAHW & PAHW_SMS) {
PicoResetMS();
return 0;
}
SekReset();
// ..but do not reset SekCycle* to not desync with addons
// s68k doesn't have the TAS quirk, so we just globally set normal TAS handler in MCD mode (used by Batman games).
SekSetRealTAS(PicoAHW & PAHW_MCD);
Pico.m.dirtyPal = 1;
Pico.m.z80_bank68k = 0;
Pico.m.z80_reset = 1;
PicoDetectRegion();
Pico.video.status = 0x3428 | Pico.m.pal; // 'always set' bits | vblank | collision | pal
PsndReset(); // pal must be known here
// create an empty "dma" to cause 68k exec start at random frame location
if (Pico.m.dma_xfers == 0 && !(PicoOpt & POPT_DIS_VDP_FIFO))
Pico.m.dma_xfers = rand() & 0x1fff;
SekFinishIdleDet();
if (PicoAHW & PAHW_MCD) {
PicoResetMCD();
return 0;
}
// reinit, so that checksum checks pass
if (!(PicoOpt & POPT_DIS_IDLE_DET))
SekInitIdleDet();
if (PicoOpt & POPT_EN_32X)
PicoReset32x();
// reset sram state; enable sram access by default if it doesn't overlap with ROM
Pico.m.sram_reg = 0;
if ((SRam.flags & SRF_EEPROM) || Pico.romsize <= SRam.start)
Pico.m.sram_reg |= SRR_MAPPED;
if (SRam.flags & SRF_ENABLED)
elprintf(EL_STATUS, "sram: %06x - %06x; eeprom: %i", SRam.start, SRam.end,
!!(SRam.flags & SRF_EEPROM));
return 0;
}
// flush config changes before emu loop starts
void PicoLoopPrepare(void)
{
if (PicoRegionOverride)
// force setting possibly changed..
Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;
// FIXME: PAL has 313 scanlines..
scanlines_total = Pico.m.pal ? 312 : 262;
Pico.m.dirtyPal = 1;
rendstatus_old = -1;
}
// dma2vram settings are just hacks to unglitch Legend of Galahad (needs <= 104 to work)
// same for Outrunners (92-121, when active is set to 24)
// 96 is VR hack
static const int dma_timings[] = {
167, 167, 166, 83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy
102, 205, 204, 102, // vblank: 40cell:
16, 16, 15, 8, // active: 32cell:
24, 18, 17, 9 // ...
};
static const int dma_bsycles[] = {
(488<<8)/167, (488<<8)/167, (488<<8)/166, (488<<8)/83,
(488<<8)/102, (488<<8)/233, (488<<8)/204, (488<<8)/102,
(488<<8)/16, (488<<8)/16, (488<<8)/15, (488<<8)/8,
(488<<8)/24, (488<<8)/18, (488<<8)/17, (488<<8)/9
};
// grossly inaccurate.. FIXME FIXXXMEE
PICO_INTERNAL int CheckDMA(void)
{
int burn = 0, xfers_can, dma_op = Pico.video.reg[0x17]>>6; // see gens for 00 and 01 modes
int xfers = Pico.m.dma_xfers;
int dma_op1;
if(!(dma_op&2)) dma_op = (Pico.video.type==1) ? 0 : 1; // setting dma_timings offset here according to Gens
dma_op1 = dma_op;
if(Pico.video.reg[12] & 1) dma_op |= 4; // 40 cell mode?
if(!(Pico.video.status&8)&&(Pico.video.reg[1]&0x40)) dma_op|=8; // active display?
xfers_can = dma_timings[dma_op];
if(xfers <= xfers_can)
{
if(dma_op&2) Pico.video.status&=~2; // dma no longer busy
else {
burn = xfers * dma_bsycles[dma_op] >> 8; // have to be approximate because can't afford division..
}
Pico.m.dma_xfers = 0;
} else {
if(!(dma_op&2)) burn = 488;
Pico.m.dma_xfers -= xfers_can;
}
elprintf(EL_VDPDMA, "~Dma %i op=%i can=%i burn=%i [%i]", Pico.m.dma_xfers, dma_op1, xfers_can, burn, SekCyclesDone());
//dprintf("~aim: %i, cnt: %i", SekCycleAim, SekCycleCnt);
return burn;
}
#include "pico_cmn.inc"
unsigned int last_z80_sync; /* in 68k cycles */
int z80_cycle_cnt;
int z80_cycle_aim;
int z80_scanline;
int z80_scanline_cycles; /* cycles done until z80_scanline */
/* sync z80 to 68k */
PICO_INTERNAL void PicoSyncZ80(unsigned int m68k_cycles_done)
{
int m68k_cnt;
int cnt;
m68k_cnt = m68k_cycles_done - last_z80_sync;
z80_cycle_aim += cycles_68k_to_z80(m68k_cnt);
cnt = z80_cycle_aim - z80_cycle_cnt;
last_z80_sync = m68k_cycles_done;
pprof_start(z80);
elprintf(EL_BUSREQ, "z80 sync %i (%u|%u -> %u|%u)", cnt,
z80_cycle_cnt, z80_cycle_cnt / 288,
z80_cycle_aim, z80_cycle_aim / 288);
if (cnt > 0)
z80_cycle_cnt += z80_run(cnt);
pprof_end(z80);
}
void PicoFrame(void)
{
pprof_start(frame);
Pico.m.frame_count++;
if (PicoAHW & PAHW_SMS) {
PicoFrameMS();
goto end;
}
if (PicoAHW & PAHW_32X) {
PicoFrame32x(); // also does MCD+32X
goto end;
}
if (PicoAHW & PAHW_MCD) {
PicoFrameMCD();
goto end;
}
//if(Pico.video.reg[12]&0x2) Pico.video.status ^= 0x10; // change odd bit in interlace mode
PicoFrameStart();
PicoFrameHints();
end:
pprof_end(frame);
}
void PicoFrameDrawOnly(void)
{
if (!(PicoAHW & PAHW_SMS)) {
PicoFrameStart();
PicoDrawSync(223, 0);
} else {
PicoFrameDrawOnlyMS();
}
}
void PicoGetInternal(pint_t which, pint_ret_t *r)
{
switch (which)
{
case PI_ROM: r->vptr = Pico.rom; break;
case PI_ISPAL: r->vint = Pico.m.pal; break;
case PI_IS40_CELL: r->vint = Pico.video.reg[12]&1; break;
case PI_IS240_LINES: r->vint = Pico.m.pal && (Pico.video.reg[1]&8); break;
}
}

View File

@ -0,0 +1,246 @@
/*
* PicoDrive
* (c) Copyright Dave, 2004
* (C) notaz, 2006-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#ifndef PICO_H
#define PICO_H
#include <stdlib.h> // size_t
#ifdef __cplusplus
extern "C" {
#endif
// message log
extern void lprintf(const char *fmt, ...);
// external funcs for Sega/Mega CD
extern int mp3_get_bitrate(void *f, int size);
extern void mp3_start_play(void *f, int pos);
extern void mp3_update(int *buffer, int length, int stereo);
// this one should handle display mode changes
extern void emu_video_mode_change(int start_line, int line_count, int is_32cols);
// this must switch to 16bpp mode
extern void emu_32x_startup(void);
// optional 32X BIOS, should be left NULL if not used
// must be 256, 2048, 1024 bytes
extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
// Pico.c
#define POPT_EN_FM (1<< 0) // 00 000x
#define POPT_EN_PSG (1<< 1)
#define POPT_EN_Z80 (1<< 2)
#define POPT_EN_STEREO (1<< 3)
#define POPT_ALT_RENDERER (1<< 4) // 00 00x0
// unused (1<< 5)
// unused (1<< 6)
#define POPT_ACC_SPRITES (1<< 7)
#define POPT_DIS_32C_BORDER (1<< 8) // 00 0x00
#define POPT_EXT_FM (1<< 9)
#define POPT_EN_MCD_PCM (1<<10)
#define POPT_EN_MCD_CDDA (1<<11)
#define POPT_EN_MCD_GFX (1<<12) // 00 x000
// unused (1<<13)
#define POPT_EN_SOFTSCALE (1<<14)
#define POPT_EN_MCD_RAMCART (1<<15)
#define POPT_DIS_VDP_FIFO (1<<16) // 0x 0000
#define POPT_EN_DRC (1<<17)
#define POPT_DIS_SPRITE_LIM (1<<18)
#define POPT_DIS_IDLE_DET (1<<19)
#define POPT_EN_32X (1<<20)
#define POPT_EN_PWM (1<<21)
extern int PicoOpt; // bitfield
#define PAHW_MCD (1<<0)
#define PAHW_32X (1<<1)
#define PAHW_SVP (1<<2)
#define PAHW_PICO (1<<3)
#define PAHW_SMS (1<<4)
extern int PicoAHW; // Pico active hw
#define PQUIRK_FORCE_6BTN (1<<0)
extern int PicoQuirks;
extern int PicoSkipFrame; // skip rendering frame, but still do sound (if enabled) and emulation stuff
extern int PicoRegionOverride; // override the region detection 0: auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
extern int PicoAutoRgnOrder; // packed priority list of regions, for example 0x148 means this detection order: EUR, USA, JAP
extern int PicoSVPCycles;
void PicoInit(void);
void PicoPower(void);
int PicoReset(void);
void PicoLoopPrepare(void);
void PicoFrame(void);
void PicoFrameDrawOnly(void);
extern int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU
extern void (*PicoWriteSound)(int bytes); // called once per frame at the best time to send sound buffer (PsndOut) to hardware
typedef enum { PI_ROM, PI_ISPAL, PI_IS40_CELL, PI_IS240_LINES } pint_t;
typedef union { int vint; void *vptr; } pint_ret_t;
void PicoGetInternal(pint_t which, pint_ret_t *ret);
// cd/mcd.c
extern void (*PicoMCDopenTray)(void);
extern void (*PicoMCDcloseTray)(void);
// pico.c
#define XPCM_BUFFER_SIZE (320+160)
typedef struct
{
int pen_pos[2];
int page;
// internal
int fifo_bytes; // bytes in FIFO
int fifo_bytes_prev;
int fifo_line_bytes; // float part, << 16
int line_counter;
unsigned short r1, r12;
unsigned char xpcm_buffer[XPCM_BUFFER_SIZE+4];
unsigned char *xpcm_ptr;
} picohw_state;
extern picohw_state PicoPicohw;
// cd/cdd.c
int cdd_load(const char *filename, int type);
// Cart.c
typedef enum
{
PMT_UNCOMPRESSED = 0,
PMT_ZIP,
PMT_CSO
} pm_type;
typedef struct
{
void *file; /* file handle */
void *param; /* additional file related field */
unsigned int size; /* size */
pm_type type;
char ext[4];
} pm_file;
pm_file *pm_open(const char *path);
size_t pm_read(void *ptr, size_t bytes, pm_file *stream);
int pm_seek(pm_file *stream, long offset, int whence);
int pm_close(pm_file *fp);
int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms);
int PicoCartInsert(unsigned char *rom, unsigned int romsize, const char *carthw_cfg);
extern void (*PicoCDLoadProgressCB)(const char *fname, int percent);
extern int PicoGameLoaded;
// Draw.c
// for line-based renderer, set conversion
// from internal 8 bit representation in 'HighCol' to:
typedef enum
{
PDF_NONE = 0, // no conversion
PDF_RGB555, // RGB/BGR output, depends on compile options
PDF_8BIT, // 8-bit out (handles shadow/hilight mode, sonic water)
} pdso_t;
void PicoDrawSetOutFormat(pdso_t which, int use_32x_line_mode);
void PicoDrawSetOutBuf(void *dest, int increment);
void PicoDrawSetCallbacks(int (*begin)(unsigned int num), int (*end)(unsigned int num));
extern void *DrawLineDest;
extern unsigned char *HighCol;
// utility
#ifdef _ASM_DRAW_C
void vidConvCpyRGB565(void *to, void *from, int pixels);
#endif
void PicoDoHighPal555(int sh);
extern int PicoDrawMask;
#define PDRAW_LAYERB_ON (1<<2)
#define PDRAW_LAYERA_ON (1<<3)
#define PDRAW_SPRITES_LOW_ON (1<<4)
#define PDRAW_SPRITES_HI_ON (1<<7)
#define PDRAW_32X_ON (1<<8)
// internals
#define PDRAW_SPRITES_MOVED (1<<0) // (asm)
#define PDRAW_WND_DIFF_PRIO (1<<1) // not all window tiles use same priority
#define PDRAW_SPR_LO_ON_HI (1<<2) // seen sprites without layer pri bit ontop spr. with that bit
#define PDRAW_INTERLACE (1<<3)
#define PDRAW_DIRTY_SPRITES (1<<4) // (asm)
#define PDRAW_SONIC_MODE (1<<5) // mid-frame palette changes for 8bit renderer
#define PDRAW_PLANE_HI_PRIO (1<<6) // have layer with all hi prio tiles (mk3)
#define PDRAW_SHHI_DONE (1<<7) // layer sh/hi already processed
#define PDRAW_32_COLS (1<<8) // 32 column mode
extern int rendstatus, rendstatus_old;
extern int rendlines;
extern unsigned short HighPal[0x100];
// draw.c
void PicoDrawUpdateHighPal(void);
void PicoDrawSetInternalBuf(void *dest, int line_increment);
// draw2.c
// stuff below is optional
extern unsigned char *PicoDraw2FB; // buffer for fast renderer in format (8+320)x(8+224+8) (eights for borders)
extern unsigned short *PicoCramHigh; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)
extern void (*PicoPrepareCram)(); // prepares PicoCramHigh for renderer to use
// pico.c (32x)
#ifndef NO_32X
void Pico32xSetClocks(int msh2_hz, int ssh2_hz);
#else
#define Pico32xSetClocks(msh2_khz, ssh2_khz)
#endif
// normally 68k clock (7670442) * 3, in reality but much lower
// because of high memory latencies
#define PICO_MSH2_HZ ((int)(7670442.0 * 2.4))
#define PICO_SSH2_HZ ((int)(7670442.0 * 2.4))
// sound.c
extern int PsndRate,PsndLen;
extern short *PsndOut;
extern void (*PsndMix_32_to_16l)(short *dest, int *src, int count);
void PsndRerate(int preserve_state);
// media.c
enum media_type_e {
PM_BAD_DETECT = -1,
PM_ERROR = -2,
PM_BAD_CD = -3,
PM_BAD_CD_NO_BIOS = -4,
PM_MD_CART = 1, /* also 32x */
PM_MARK3,
PM_CD,
};
enum cd_img_type
{
CIT_NOT_CD = 0,
CIT_ISO,
CIT_BIN,
CIT_CUE
};
enum media_type_e PicoLoadMedia(const char *filename,
const char *carthw_cfg_fname,
const char *(*get_bios_filename)(int *region, const char *cd_fname),
void (*do_region_override)(const char *media_filename), enum media_type_e media_type);
int PicoCdCheck(const char *fname_in, int *pregion);
extern unsigned char media_id_header[0x100];
// memory.c
enum input_device {
PICO_INPUT_NOTHING,
PICO_INPUT_PAD_3BTN,
PICO_INPUT_PAD_6BTN,
};
void PicoSetInputDevice(int port, enum input_device device);
#ifdef __cplusplus
} // End of extern "C"
#endif
#endif // PICO_H

View File

@ -0,0 +1,124 @@
/*
* PicoDrive
* (C) notaz, 2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "../memory.h"
#include "../sound/sn76496.h"
/*
void dump(u16 w)
{
static FILE *f[0x10] = { NULL, };
char fname[32];
int num = PicoPicohw.r12 & 0xf;
w = (w << 8) | (w >> 8);
sprintf(fname, "ldump%i.bin", num);
if (f[num] == NULL)
f[num] = fopen(fname, "wb");
fwrite(&w, 1, 2, f[num]);
//fclose(f);
}
*/
static u32 PicoRead8_pico(u32 a)
{
u32 d = 0;
if ((a & 0xffffe0) == 0x800000) // Pico I/O
{
switch (a & 0x1f)
{
case 0x01: d = PicoPicohw.r1; break;
case 0x03:
d = PicoPad[0]&0x1f; // d-pad
d |= (PicoPad[0]&0x20) << 2; // pen push -> C
d = ~d;
break;
case 0x05: d = (PicoPicohw.pen_pos[0] >> 8); break; // what is MS bit for? Games read it..
case 0x07: d = PicoPicohw.pen_pos[0] & 0xff; break;
case 0x09: d = (PicoPicohw.pen_pos[1] >> 8); break;
case 0x0b: d = PicoPicohw.pen_pos[1] & 0xff; break;
case 0x0d: d = (1 << (PicoPicohw.page & 7)) - 1; break;
case 0x12: d = PicoPicohw.fifo_bytes == 0 ? 0x80 : 0; break; // guess
default:
goto unhandled;
}
return d;
}
unhandled:
elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
return d;
}
static u32 PicoRead16_pico(u32 a)
{
u32 d = 0;
if (a == 0x800010)
d = (PicoPicohw.fifo_bytes > 0x3f) ? 0 : (0x3f - PicoPicohw.fifo_bytes);
else if (a == 0x800012)
d = PicoPicohw.fifo_bytes == 0 ? 0x8000 : 0; // guess
else
elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
return d;
}
static void PicoWrite8_pico(u32 a, u32 d)
{
switch (a & ~0x800000) {
case 0x19: case 0x1b: case 0x1d: case 0x1f: break; // 'S' 'E' 'G' 'A'
default:
elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
break;
}
}
static void PicoWrite16_pico(u32 a, u32 d)
{
//if (a == 0x800010) dump(d);
if (a == 0x800010)
{
PicoPicohw.fifo_bytes += 2;
if (PicoPicohw.xpcm_ptr < PicoPicohw.xpcm_buffer + XPCM_BUFFER_SIZE) {
*PicoPicohw.xpcm_ptr++ = d >> 8;
*PicoPicohw.xpcm_ptr++ = d;
}
else if (PicoPicohw.xpcm_ptr == PicoPicohw.xpcm_buffer + XPCM_BUFFER_SIZE) {
elprintf(EL_ANOMALY|EL_PICOHW, "xpcm_buffer overflow!");
PicoPicohw.xpcm_ptr++;
}
}
else if (a == 0x800012) {
int r12_old = PicoPicohw.r12;
PicoPicohw.r12 = d;
if (r12_old != d)
PicoReratePico();
}
else
elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
}
PICO_INTERNAL void PicoMemSetupPico(void)
{
PicoMemSetup();
// no MD IO or Z80 on Pico
m68k_map_unmap(0x400000, 0xbfffff);
// map Pico I/O
cpu68k_map_set(m68k_read8_map, 0x800000, 0x80ffff, PicoRead8_pico, 1);
cpu68k_map_set(m68k_read16_map, 0x800000, 0x80ffff, PicoRead16_pico, 1);
cpu68k_map_set(m68k_write8_map, 0x800000, 0x80ffff, PicoWrite8_pico, 1);
cpu68k_map_set(m68k_write16_map, 0x800000, 0x80ffff, PicoWrite16_pico, 1);
}

View File

@ -0,0 +1,104 @@
/*
* PicoDrive
* (C) notaz, 2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
// x: 0x03c - 0x19d
// y: 0x1fc - 0x2f7
// 0x2f8 - 0x3f3
picohw_state PicoPicohw;
static int prev_line_cnt_irq3 = 0, prev_line_cnt_irq5 = 0;
static int fifo_bytes_line = (16000<<16)/60/262/2;
static const int guessed_rates[] = { 8000, 14000, 12000, 14000, 16000, 18000, 16000, 16000 }; // ?
#define PICOHW_FIFO_IRQ_THRESHOLD 12
PICO_INTERNAL void PicoReratePico(void)
{
int rate = guessed_rates[PicoPicohw.r12 & 7];
if (Pico.m.pal)
fifo_bytes_line = (rate<<16)/50/312/2;
else fifo_bytes_line = (rate<<16)/60/262/2;
PicoPicoPCMRerate(rate);
}
static void PicoLinePico(void)
{
PicoPicohw.line_counter++;
#if 1
if ((PicoPicohw.r12 & 0x4003) && PicoPicohw.line_counter - prev_line_cnt_irq3 > 200) {
prev_line_cnt_irq3 = PicoPicohw.line_counter;
// just a guess/hack, allows 101 Dalmantians to boot
elprintf(EL_PICOHW, "irq3");
SekInterrupt(3);
return;
}
#endif
if (PicoPicohw.fifo_bytes > 0)
{
PicoPicohw.fifo_line_bytes += fifo_bytes_line;
if (PicoPicohw.fifo_line_bytes >= (1<<16)) {
PicoPicohw.fifo_bytes -= PicoPicohw.fifo_line_bytes >> 16;
PicoPicohw.fifo_line_bytes &= 0xffff;
if (PicoPicohw.fifo_bytes < 0)
PicoPicohw.fifo_bytes = 0;
}
}
else
PicoPicohw.fifo_line_bytes = 0;
#if 1
if (PicoPicohw.fifo_bytes_prev >= PICOHW_FIFO_IRQ_THRESHOLD &&
PicoPicohw.fifo_bytes < PICOHW_FIFO_IRQ_THRESHOLD) {
prev_line_cnt_irq3 = PicoPicohw.line_counter; // ?
elprintf(EL_PICOHW, "irq3, fb=%i", PicoPicohw.fifo_bytes);
SekInterrupt(3);
}
PicoPicohw.fifo_bytes_prev = PicoPicohw.fifo_bytes;
#endif
#if 0
if (PicoPicohw.line_counter - prev_line_cnt_irq5 > 512) {
prev_line_cnt_irq5 = PicoPicohw.line_counter;
elprintf(EL_PICOHW, "irq5");
SekInterrupt(5);
}
#endif
}
static void PicoResetPico(void)
{
PicoPicoPCMReset();
PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer;
}
PICO_INTERNAL void PicoInitPico(void)
{
elprintf(EL_STATUS, "Pico startup");
PicoLineHook = PicoLinePico;
PicoResetHook = PicoResetPico;
PicoAHW = PAHW_PICO;
memset(&PicoPicohw, 0, sizeof(PicoPicohw));
PicoPicohw.pen_pos[0] = 0x03c + 320/2;
PicoPicohw.pen_pos[1] = 0x200 + 240/2;
prev_line_cnt_irq3 = prev_line_cnt_irq5 = 0;
// map version register
PicoDetectRegion();
switch (Pico.m.hardware >> 6) {
case 0: PicoPicohw.r1 = 0x00; break;
case 1: PicoPicohw.r1 = 0x00; break;
case 2: PicoPicohw.r1 = 0x40; break;
case 3: PicoPicohw.r1 = 0x20; break;
}
}

View File

@ -0,0 +1,120 @@
/*
* PicoDrive
* (C) notaz, 2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*
* The following ADPCM algorithm was stolen from MAME aica driver.
* I'm quite sure it's not the right one, but it's the
* best sounding of the ones that I tried.
*/
#include "../pico_int.h"
#define ADPCMSHIFT 8
#define ADFIX(f) (int) ((double)f * (double)(1<<ADPCMSHIFT))
/* limitter */
#define Limit(val, max, min) { \
if ( val > max ) val = max; \
else if ( val < min ) val = min; \
}
static const int TableQuant[8] =
{
ADFIX(0.8984375),
ADFIX(0.8984375),
ADFIX(0.8984375),
ADFIX(0.8984375),
ADFIX(1.19921875),
ADFIX(1.59765625),
ADFIX(2.0),
ADFIX(2.3984375)
};
// changed using trial and error..
//static const int quant_mul[16] = { 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15 };
static const int quant_mul[16] = { 1, 3, 5, 7, 9, 11, 13, -1, -1, -3, -5, -7, -9, -11, -13, -15 };
static int sample = 0, quant = 0, sgn = 0;
static int stepsamples = (44100<<10)/16000;
PICO_INTERNAL void PicoPicoPCMReset(void)
{
sample = sgn = 0;
quant = 0x7f;
memset(PicoPicohw.xpcm_buffer, 0, sizeof(PicoPicohw.xpcm_buffer));
}
PICO_INTERNAL void PicoPicoPCMRerate(int xpcm_rate)
{
stepsamples = (PsndRate<<10)/xpcm_rate;
}
#define XSHIFT 6
#define do_sample() \
{ \
int delta = quant * quant_mul[srcval] >> XSHIFT; \
sample += delta - (delta >> 2); /* 3/4 */ \
quant = (quant * TableQuant[srcval&7]) >> ADPCMSHIFT; \
Limit(quant, 0x6000, 0x7f); \
Limit(sample, 32767*3/4, -32768*3/4); \
}
PICO_INTERNAL void PicoPicoPCMUpdate(short *buffer, int length, int stereo)
{
unsigned char *src = PicoPicohw.xpcm_buffer;
unsigned char *lim = PicoPicohw.xpcm_ptr;
int srcval, needsamples = 0;
if (src == lim) goto end;
for (; length > 0 && src < lim; src++)
{
srcval = *src >> 4;
do_sample();
for (needsamples += stepsamples; needsamples > (1<<10) && length > 0; needsamples -= (1<<10), length--) {
*buffer++ += sample;
if (stereo) { buffer[0] = buffer[-1]; buffer++; }
}
srcval = *src & 0xf;
do_sample();
for (needsamples += stepsamples; needsamples > (1<<10) && length > 0; needsamples -= (1<<10), length--) {
*buffer++ += sample;
if (stereo) { buffer[0] = buffer[-1]; buffer++; }
}
// lame normalization stuff, needed due to wrong adpcm algo
sgn += (sample < 0) ? -1 : 1;
if (sgn < -16 || sgn > 16) sample -= sample >> 5;
}
if (src < lim) {
int di = lim - src;
memmove(PicoPicohw.xpcm_buffer, src, di);
PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer + di;
elprintf(EL_PICOHW, "xpcm update: over %i", di);
// adjust fifo
PicoPicohw.fifo_bytes = di;
return;
}
elprintf(EL_PICOHW, "xpcm update: under %i", length);
PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer;
end:
if (stereo)
// still must expand SN76496 to stereo
for (; length > 0; buffer+=2, length--)
buffer[1] = buffer[0];
sample = sgn = 0;
quant = 0x7f;
}

View File

@ -0,0 +1,290 @@
/*
* common code for base/cd/32x
* (C) notaz, 2007-2009,2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#define CYCLES_M68K_LINE 488 // suitable for both PAL/NTSC
#define CYCLES_M68K_VINT_LAG 68
#define CYCLES_M68K_ASD 148
// pad delay (for 6 button pads)
#define PAD_DELAY() { \
if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0; \
if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
}
// CPUS_RUN
#ifndef CPUS_RUN
#define CPUS_RUN(m68k_cycles) \
SekRunM68k(m68k_cycles)
#endif
// sync m68k to SekCycleAim
static void SekSyncM68k(void)
{
int cyc_do;
pprof_start(m68k);
pevt_log_m68k_o(EVT_RUN_START);
while ((cyc_do = SekCycleAim - SekCycleCnt) > 0) {
SekCycleCnt += cyc_do;
#if defined(EMU_C68K)
PicoCpuCM68k.cycles = cyc_do;
CycloneRun(&PicoCpuCM68k);
SekCycleCnt -= PicoCpuCM68k.cycles;
#elif defined(EMU_M68K)
SekCycleCnt += m68k_execute(cyc_do) - cyc_do;
#elif defined(EMU_F68K)
SekCycleCnt += fm68k_emulate(cyc_do, 0) - cyc_do;
#endif
}
SekCyclesLeft = 0;
SekTrace(0);
pevt_log_m68k_o(EVT_RUN_END);
pprof_end(m68k);
}
static inline void SekRunM68k(int cyc)
{
SekCycleAim += cyc;
SekSyncM68k();
}
static int PicoFrameHints(void)
{
struct PicoVideo *pv=&Pico.video;
int lines, y, lines_vis = 224, line_sample, skip, vcnt_wrap;
unsigned int cycles;
int hint; // Hint counter
pevt_log_m68k_o(EVT_FRAME_START);
pv->v_counter = Pico.m.scanline = 0;
if ((PicoOpt&POPT_ALT_RENDERER) && !PicoSkipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
// draw a frame just after vblank in alternative render mode
// yes, this will cause 1 frame lag, but this is inaccurate mode anyway.
PicoFrameFull();
#ifdef DRAW_FINISH_FUNC
DRAW_FINISH_FUNC();
#endif
skip = 1;
}
else skip=PicoSkipFrame;
if (Pico.m.pal) {
line_sample = 68;
if (pv->reg[1]&8) lines_vis = 240;
} else {
line_sample = 93;
}
z80_resetCycles();
PsndDacLine = 0;
emustatus &= ~1;
pv->status&=~0x88; // clear V-Int, come out of vblank
hint=pv->reg[10]; // Load H-Int counter
//dprintf("-hint: %i", hint);
// This is to make active scan longer (needed for Double Dragon 2, mainly)
CPUS_RUN(CYCLES_M68K_ASD);
for (y = 0; y < lines_vis; y++)
{
pv->v_counter = Pico.m.scanline = y;
if ((pv->reg[12]&6) == 6) { // interlace mode 2
pv->v_counter <<= 1;
pv->v_counter |= pv->v_counter >> 8;
pv->v_counter &= 0xff;
}
// VDP FIFO
pv->lwrite_cnt -= 12;
if (pv->lwrite_cnt <= 0) {
pv->lwrite_cnt=0;
Pico.video.status|=0x200;
}
PAD_DELAY();
// H-Interrupts:
if (--hint < 0) // y <= lines_vis: Comix Zone, Golden Axe
{
hint=pv->reg[10]; // Reload H-Int counter
pv->pending_ints|=0x10;
if (pv->reg[0]&0x10) {
elprintf(EL_INTS, "hint: @ %06x [%i]", SekPc, SekCyclesDone());
SekInterrupt(4);
}
}
// decide if we draw this line
if (!skip && (PicoOpt & POPT_ALT_RENDERER))
{
// find the right moment for frame renderer, when display is no longer blanked
if ((pv->reg[1]&0x40) || y > 100) {
PicoFrameFull();
#ifdef DRAW_FINISH_FUNC
DRAW_FINISH_FUNC();
#endif
skip = 1;
}
}
// get samples from sound chips
if ((y == 224 || y == line_sample) && PsndOut)
{
cycles = SekCyclesDone();
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
PicoSyncZ80(cycles);
if (ym2612.dacen && PsndDacLine <= y)
PsndDoDAC(y);
#ifdef PICO_CD
if (PicoAHW & PAHW_MCD)
pcd_sync_s68k(cycles, 0);
#endif
#ifdef PICO_32X
p32x_sync_sh2s(cycles);
#endif
PsndGetSamples(y);
}
// Run scanline:
line_base_cycles = SekCyclesDone();
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
CPUS_RUN(CYCLES_M68K_LINE);
if (PicoLineHook) PicoLineHook();
pevt_log_m68k_o(EVT_NEXT_LINE);
}
if (!skip)
{
if (DrawScanline < y)
PicoDrawSync(y - 1, 0);
#ifdef DRAW_FINISH_FUNC
DRAW_FINISH_FUNC();
#endif
}
// V-int line (224 or 240)
Pico.m.scanline = y;
pv->v_counter = 0xe0; // bad for 240 mode
if ((pv->reg[12]&6) == 6) pv->v_counter = 0xc1;
// VDP FIFO
pv->lwrite_cnt=0;
Pico.video.status|=0x200;
memcpy(PicoPadInt, PicoPad, sizeof(PicoPadInt));
PAD_DELAY();
// Last H-Int:
if (--hint < 0)
{
hint=pv->reg[10]; // Reload H-Int counter
pv->pending_ints|=0x10;
//printf("rhint: %i @ %06x [%i|%i]\n", hint, SekPc, y, SekCyclesDone());
if (pv->reg[0]&0x10) SekInterrupt(4);
}
pv->status|=0x08; // go into vblank
pv->pending_ints|=0x20;
// the following SekRun is there for several reasons:
// there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
// also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
// also delay between last H-int and V-int (Golden Axe 3)
line_base_cycles = SekCyclesDone();
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
CPUS_RUN(CYCLES_M68K_VINT_LAG);
if (pv->reg[1]&0x20) {
elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCyclesDone());
SekInterrupt(6);
}
cycles = SekCyclesDone();
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80)) {
PicoSyncZ80(cycles);
elprintf(EL_INTS, "zint");
z80_int();
}
#ifdef PICO_CD
if (PicoAHW & PAHW_MCD)
pcd_sync_s68k(cycles, 0);
#endif
#ifdef PICO_32X
p32x_sync_sh2s(cycles);
p32x_start_blank();
#endif
// get samples from sound chips
if (y == 224 && PsndOut)
{
if (ym2612.dacen && PsndDacLine <= y)
PsndDoDAC(y);
PsndGetSamples(y);
}
// Run scanline:
CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG - CYCLES_M68K_ASD);
if (PicoLineHook) PicoLineHook();
pevt_log_m68k_o(EVT_NEXT_LINE);
lines = scanlines_total;
vcnt_wrap = Pico.m.pal ? 0x103 : 0xEB; // based on Gens, TODO: verify
for (y++; y < lines; y++)
{
pv->v_counter = Pico.m.scanline = y;
if (y >= vcnt_wrap)
pv->v_counter -= Pico.m.pal ? 56 : 6;
if ((pv->reg[12]&6) == 6)
pv->v_counter = (pv->v_counter << 1) | 1;
pv->v_counter &= 0xff;
PAD_DELAY();
// Run scanline:
line_base_cycles = SekCyclesDone();
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
CPUS_RUN(CYCLES_M68K_LINE);
if (PicoLineHook) PicoLineHook();
pevt_log_m68k_o(EVT_NEXT_LINE);
}
// sync cpus
cycles = SekCyclesDone();
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
PicoSyncZ80(cycles);
if (PsndOut && ym2612.dacen && PsndDacLine <= lines-1)
PsndDoDAC(lines-1);
#ifdef PICO_CD
if (PicoAHW & PAHW_MCD)
pcd_sync_s68k(cycles, 0);
#endif
#ifdef PICO_32X
p32x_sync_sh2s(cycles);
#endif
timers_cycle();
return 0;
}
#undef PAD_DELAY
#undef CPUS_RUN
// vim:shiftwidth=2:ts=2:expandtab

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,589 @@
/*
* PicoDrive
* (c) Copyright Dave, 2004
* (C) notaz, 2006-2009
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "pico_int.h"
#include "memory.h"
unsigned int SekCycleCnt;
unsigned int SekCycleAim;
/* context */
// Cyclone 68000
#ifdef EMU_C68K
struct Cyclone PicoCpuCM68k;
#endif
// MUSASHI 68000
#ifdef EMU_M68K
m68ki_cpu_core PicoCpuMM68k;
#endif
// FAME 68000
#ifdef EMU_F68K
M68K_CONTEXT PicoCpuFM68k;
#endif
/* callbacks */
#ifdef EMU_C68K
// interrupt acknowledgment
static int SekIntAck(int level)
{
// try to emulate VDP's reaction to 68000 int ack
if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); }
else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); }
PicoCpuCM68k.irq = 0;
return CYCLONE_INT_ACK_AUTOVECTOR;
}
static void SekResetAck(void)
{
elprintf(EL_ANOMALY, "Reset encountered @ %06x", SekPc);
}
static int SekUnrecognizedOpcode()
{
unsigned int pc;
pc = SekPc;
elprintf(EL_ANOMALY, "Unrecognized Opcode @ %06x", pc);
// see if we are still in a mapped region
pc &= 0x00ffffff;
if (map_flag_set(m68k_read16_map[pc >> M68K_MEM_SHIFT])) {
elprintf(EL_STATUS|EL_ANOMALY, "m68k crash @%06x", pc);
PicoCpuCM68k.cycles = 0;
PicoCpuCM68k.state_flags |= 1;
return 1;
}
#ifdef EMU_M68K // debugging cyclone
{
extern int have_illegal;
have_illegal = 1;
}
#endif
return 0;
}
#endif
#ifdef EMU_M68K
static int SekIntAckM68K(int level)
{
if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); }
else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); }
CPU_INT_LEVEL = 0;
return M68K_INT_ACK_AUTOVECTOR;
}
static int SekTasCallback(void)
{
return 0; // no writeback
}
#endif
#ifdef EMU_F68K
static void SekIntAckF68K(unsigned level)
{
if (level == 4) {
Pico.video.pending_ints = 0;
elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCyclesDone());
}
else if(level == 6) {
Pico.video.pending_ints &= ~0x20;
elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCyclesDone());
}
PicoCpuFM68k.interrupts[0] = 0;
}
#endif
PICO_INTERNAL void SekInit(void)
{
#ifdef EMU_C68K
CycloneInit();
memset(&PicoCpuCM68k,0,sizeof(PicoCpuCM68k));
PicoCpuCM68k.IrqCallback=SekIntAck;
PicoCpuCM68k.ResetCallback=SekResetAck;
PicoCpuCM68k.UnrecognizedCallback=SekUnrecognizedOpcode;
PicoCpuCM68k.flags=4; // Z set
#endif
#ifdef EMU_M68K
{
void *oldcontext = m68ki_cpu_p;
m68k_set_context(&PicoCpuMM68k);
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_init();
m68k_set_int_ack_callback(SekIntAckM68K);
m68k_set_tas_instr_callback(SekTasCallback);
//m68k_pulse_reset();
m68k_set_context(oldcontext);
}
#endif
#ifdef EMU_F68K
{
void *oldcontext = g_m68kcontext;
g_m68kcontext = &PicoCpuFM68k;
memset(&PicoCpuFM68k, 0, sizeof(PicoCpuFM68k));
fm68k_init();
PicoCpuFM68k.iack_handler = SekIntAckF68K;
PicoCpuFM68k.sr = 0x2704; // Z flag
g_m68kcontext = oldcontext;
}
#endif
}
// Reset the 68000:
PICO_INTERNAL int SekReset(void)
{
if (Pico.rom==NULL) return 1;
#ifdef EMU_C68K
CycloneReset(&PicoCpuCM68k);
#endif
#ifdef EMU_M68K
m68k_set_context(&PicoCpuMM68k); // if we ever reset m68k, we always need it's context to be set
m68ki_cpu.sp[0]=0;
m68k_set_irq(0);
m68k_pulse_reset();
REG_USP = 0; // ?
#endif
#ifdef EMU_F68K
{
g_m68kcontext = &PicoCpuFM68k;
fm68k_reset();
}
#endif
return 0;
}
void SekStepM68k(void)
{
SekCycleAim=SekCycleCnt+1;
#if defined(EMU_CORE_DEBUG)
SekCycleCnt+=CM_compareRun(1, 0);
#elif defined(EMU_C68K)
PicoCpuCM68k.cycles=1;
CycloneRun(&PicoCpuCM68k);
SekCycleCnt+=1-PicoCpuCM68k.cycles;
#elif defined(EMU_M68K)
SekCycleCnt+=m68k_execute(1);
#elif defined(EMU_F68K)
SekCycleCnt+=fm68k_emulate(1, 0);
#endif
}
PICO_INTERNAL void SekSetRealTAS(int use_real)
{
#ifdef EMU_C68K
CycloneSetRealTAS(use_real);
#endif
#ifdef EMU_F68K
// TODO
#endif
}
// Pack the cpu into a common format:
// XXX: rename
PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub)
{
unsigned int pc=0;
#if defined(EMU_C68K)
struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
memcpy(cpu,context->d,0x40);
pc=context->pc-context->membase;
*(unsigned int *)(cpu+0x44)=CycloneGetSr(context);
*(unsigned int *)(cpu+0x48)=context->osp;
cpu[0x4c] = context->irq;
cpu[0x4d] = context->state_flags & 1;
#elif defined(EMU_M68K)
void *oldcontext = m68ki_cpu_p;
m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
memcpy(cpu,m68ki_cpu_p->dar,0x40);
pc=m68ki_cpu_p->pc;
*(unsigned int *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
*(unsigned int *)(cpu+0x48)=m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET];
cpu[0x4c] = CPU_INT_LEVEL>>8;
cpu[0x4d] = CPU_STOPPED;
m68k_set_context(oldcontext);
#elif defined(EMU_F68K)
M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
memcpy(cpu,context->dreg,0x40);
pc=context->pc;
*(unsigned int *)(cpu+0x44)=context->sr;
*(unsigned int *)(cpu+0x48)=context->asp;
cpu[0x4c] = context->interrupts[0];
cpu[0x4d] = (context->execinfo & FM68K_HALTED) ? 1 : 0;
#endif
*(unsigned int *)(cpu+0x40) = pc;
*(unsigned int *)(cpu+0x50) =
is_sub ? SekCycleCntS68k : SekCycleCnt;
}
PICO_INTERNAL void SekUnpackCpu(const unsigned char *cpu, int is_sub)
{
#if defined(EMU_C68K)
struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
CycloneSetSr(context, *(unsigned int *)(cpu+0x44));
context->osp=*(unsigned int *)(cpu+0x48);
memcpy(context->d,cpu,0x40);
context->membase = 0;
context->pc = *(unsigned int *)(cpu+0x40);
CycloneUnpack(context, NULL); // rebase PC
context->irq = cpu[0x4c];
context->state_flags = 0;
if (cpu[0x4d])
context->state_flags |= 1;
#elif defined(EMU_M68K)
void *oldcontext = m68ki_cpu_p;
m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44));
memcpy(m68ki_cpu_p->dar,cpu,0x40);
m68ki_cpu_p->pc=*(unsigned int *)(cpu+0x40);
m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET]=*(unsigned int *)(cpu+0x48);
CPU_INT_LEVEL = cpu[0x4c] << 8;
CPU_STOPPED = cpu[0x4d];
m68k_set_context(oldcontext);
#elif defined(EMU_F68K)
M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
memcpy(context->dreg,cpu,0x40);
context->pc =*(unsigned int *)(cpu+0x40);
context->sr =*(unsigned int *)(cpu+0x44);
context->asp=*(unsigned int *)(cpu+0x48);
context->interrupts[0] = cpu[0x4c];
context->execinfo &= ~FM68K_HALTED;
if (cpu[0x4d]&1) context->execinfo |= FM68K_HALTED;
#endif
if (is_sub)
SekCycleCntS68k = *(unsigned int *)(cpu+0x50);
else
SekCycleCnt = *(unsigned int *)(cpu+0x50);
}
/* idle loop detection, not to be used in CD mode */
#ifdef EMU_C68K
#include "cpu/cyclone/tools/idle.h"
#endif
static unsigned short **idledet_ptrs = NULL;
static int idledet_count = 0, idledet_bads = 0;
static int idledet_start_frame = 0;
#if 0
#define IDLE_STATS 1
unsigned int idlehit_addrs[128], idlehit_counts[128];
void SekRegisterIdleHit(unsigned int pc)
{
int i;
for (i = 0; i < 127 && idlehit_addrs[i]; i++) {
if (idlehit_addrs[i] == pc) {
idlehit_counts[i]++;
return;
}
}
idlehit_addrs[i] = pc;
idlehit_counts[i] = 1;
idlehit_addrs[i+1] = 0;
}
#endif
void SekInitIdleDet(void)
{
unsigned short **tmp = realloc(idledet_ptrs, 0x200*4);
if (tmp == NULL) {
free(idledet_ptrs);
idledet_ptrs = NULL;
}
else
idledet_ptrs = tmp;
idledet_count = idledet_bads = 0;
idledet_start_frame = Pico.m.frame_count + 360;
#ifdef IDLE_STATS
idlehit_addrs[0] = 0;
#endif
#ifdef EMU_C68K
CycloneInitIdle();
#endif
#ifdef EMU_F68K
fm68k_emulate(0, 1);
#endif
}
int SekIsIdleReady(void)
{
return (Pico.m.frame_count >= idledet_start_frame);
}
int SekIsIdleCode(unsigned short *dst, int bytes)
{
// printf("SekIsIdleCode %04x %i\n", *dst, bytes);
switch (bytes)
{
case 2:
if ((*dst & 0xf000) != 0x6000) // not another branch
return 1;
break;
case 4:
if ( (*dst & 0xff3f) == 0x4a38 || // tst.x ($xxxx.w); tas ($xxxx.w)
(*dst & 0xc1ff) == 0x0038 || // move.x ($xxxx.w), dX
(*dst & 0xf13f) == 0xb038) // cmp.x ($xxxx.w), dX
return 1;
if (PicoAHW & (PAHW_MCD|PAHW_32X))
break;
// with no addons, there should be no need to wait
// for byte change anywhere
if ( (*dst & 0xfff8) == 0x4a10 || // tst.b ($aX)
(*dst & 0xfff8) == 0x4a28) // tst.b ($xxxx,a0)
return 1;
break;
case 6:
if ( ((dst[1] & 0xe0) == 0xe0 && ( // RAM and
*dst == 0x4a39 || // tst.b ($xxxxxxxx)
*dst == 0x4a79 || // tst.w ($xxxxxxxx)
*dst == 0x4ab9 || // tst.l ($xxxxxxxx)
(*dst & 0xc1ff) == 0x0039 || // move.x ($xxxxxxxx), dX
(*dst & 0xf13f) == 0xb039))||// cmp.x ($xxxxxxxx), dX
*dst == 0x0838 || // btst $X, ($xxxx.w) [6 byte op]
(*dst & 0xffbf) == 0x0c38) // cmpi.{b,w} $X, ($xxxx.w)
return 1;
break;
case 8:
if ( ((dst[2] & 0xe0) == 0xe0 && ( // RAM and
*dst == 0x0839 || // btst $X, ($xxxxxxxx.w) [8 byte op]
(*dst & 0xffbf) == 0x0c39))||// cmpi.{b,w} $X, ($xxxxxxxx)
*dst == 0x0cb8) // cmpi.l $X, ($xxxx.w)
return 1;
break;
case 12:
if (PicoAHW & (PAHW_MCD|PAHW_32X))
break;
if ( (*dst & 0xf1f8) == 0x3010 && // move.w (aX), dX
(dst[1]&0xf100) == 0x0000 && // arithmetic
(dst[3]&0xf100) == 0x0000) // arithmetic
return 1;
break;
}
return 0;
}
int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop, void *ctx)
{
int is_main68k = 1;
u16 *target;
uptr v;
#if defined(EMU_C68K)
struct Cyclone *cyc = ctx;
is_main68k = cyc == &PicoCpuCM68k;
pc -= cyc->membase;
#elif defined(EMU_F68K)
is_main68k = ctx == &PicoCpuFM68k;
#endif
pc &= ~0xff000000;
if (!(newop&0x200))
elprintf(EL_IDLE, "idle: patch %06x %04x %04x %c %c #%i", pc, oldop, newop,
(newop&0x200)?'n':'y', is_main68k?'m':'s', idledet_count);
// XXX: probably shouldn't patch RAM too
v = m68k_read16_map[pc >> M68K_MEM_SHIFT];
if (!(v & 0x80000000))
target = (u16 *)((v << 1) + pc);
else {
if (++idledet_bads > 128)
return 2; // remove detector
return 1; // don't patch
}
if (idledet_count >= 0x200 && (idledet_count & 0x1ff) == 0) {
unsigned short **tmp = realloc(idledet_ptrs, (idledet_count+0x200)*4);
if (tmp == NULL)
return 1;
idledet_ptrs = tmp;
}
idledet_ptrs[idledet_count++] = target;
return 0;
}
void SekFinishIdleDet(void)
{
#ifdef EMU_C68K
CycloneFinishIdle();
#endif
#ifdef EMU_F68K
fm68k_emulate(0, 2);
#endif
while (idledet_count > 0)
{
unsigned short *op = idledet_ptrs[--idledet_count];
if ((*op & 0xfd00) == 0x7100)
*op &= 0xff, *op |= 0x6600;
else if ((*op & 0xfd00) == 0x7500)
*op &= 0xff, *op |= 0x6700;
else if ((*op & 0xfd00) == 0x7d00)
*op &= 0xff, *op |= 0x6000;
else
elprintf(EL_STATUS|EL_IDLE, "idle: don't know how to restore %04x", *op);
}
}
#if defined(CPU_CMP_R) || defined(CPU_CMP_W)
#include "debug.h"
struct ref_68k {
u32 dar[16];
u32 pc;
u32 sr;
u32 cycles;
u32 pc_prev;
};
struct ref_68k ref_68ks[2];
static int current_68k;
void SekTrace(int is_s68k)
{
struct ref_68k *x68k = &ref_68ks[is_s68k];
u32 pc = is_s68k ? SekPcS68k : SekPc;
u32 sr = is_s68k ? SekSrS68k : SekSr;
u32 cycles = is_s68k ? SekCycleCntS68k : SekCycleCnt;
u32 r;
u8 cmd;
#ifdef CPU_CMP_W
int i;
if (is_s68k != current_68k) {
current_68k = is_s68k;
cmd = CTL_68K_SLAVE | current_68k;
tl_write(&cmd, sizeof(cmd));
}
if (pc != x68k->pc) {
x68k->pc = pc;
tl_write_uint(CTL_68K_PC, x68k->pc);
}
if (sr != x68k->sr) {
x68k->sr = sr;
tl_write_uint(CTL_68K_SR, x68k->sr);
}
for (i = 0; i < 16; i++) {
r = is_s68k ? SekDarS68k(i) : SekDar(i);
if (r != x68k->dar[i]) {
x68k->dar[i] = r;
tl_write_uint(CTL_68K_R + i, r);
}
}
tl_write_uint(CTL_68K_CYCLES, cycles);
#else
int i, bad = 0;
while (1)
{
int ret = tl_read(&cmd, sizeof(cmd));
if (ret == 0) {
elprintf(EL_STATUS, "EOF");
exit(1);
}
switch (cmd) {
case CTL_68K_SLAVE:
case CTL_68K_SLAVE + 1:
current_68k = cmd & 1;
break;
case CTL_68K_PC:
tl_read_uint(&x68k->pc);
break;
case CTL_68K_SR:
tl_read_uint(&x68k->sr);
break;
case CTL_68K_CYCLES:
tl_read_uint(&x68k->cycles);
goto breakloop;
default:
if (CTL_68K_R <= cmd && cmd < CTL_68K_R + 0x10)
tl_read_uint(&x68k->dar[cmd - CTL_68K_R]);
else
elprintf(EL_STATUS, "invalid cmd: %02x", cmd);
}
}
breakloop:
if (is_s68k != current_68k) {
printf("bad 68k: %d %d\n", is_s68k, current_68k);
bad = 1;
}
if (cycles != x68k->cycles) {
printf("bad cycles: %u %u\n", cycles, x68k->cycles);
bad = 1;
}
if ((pc ^ x68k->pc) & 0xffffff) {
printf("bad PC: %08x %08x\n", pc, x68k->pc);
bad = 1;
}
if (sr != x68k->sr) {
printf("bad SR: %03x %03x\n", sr, x68k->sr);
bad = 1;
}
for (i = 0; i < 16; i++) {
r = is_s68k ? SekDarS68k(i) : SekDar(i);
if (r != x68k->dar[i]) {
printf("bad %c%d: %08x %08x\n", i < 8 ? 'D' : 'A', i & 7,
r, x68k->dar[i]);
bad = 1;
}
}
if (bad) {
for (i = 0; i < 8; i++)
printf("D%d: %08x A%d: %08x\n", i, x68k->dar[i],
i, x68k->dar[i + 8]);
printf("PC: %08x, %08x\n", x68k->pc, x68k->pc_prev);
PDebugDumpMem();
exit(1);
}
x68k->pc_prev = x68k->pc;
#endif
}
#endif // CPU_CMP_*
#if defined(EMU_M68K) && M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER
static unsigned char op_flags[0x400000/2] = { 0, };
static int atexit_set = 0;
static void make_idc(void)
{
FILE *f = fopen("idc.idc", "w");
int i;
if (!f) return;
fprintf(f, "#include <idc.idc>\nstatic main() {\n");
for (i = 0; i < 0x400000/2; i++)
if (op_flags[i] != 0)
fprintf(f, " MakeCode(0x%06x);\n", i*2);
fprintf(f, "}\n");
fclose(f);
}
void instruction_hook(void)
{
if (!atexit_set) {
atexit(make_idc);
atexit_set = 1;
}
if (REG_PC < 0x400000)
op_flags[REG_PC/2] = 1;
}
#endif
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,316 @@
/*
* SMS emulation
* (C) notaz, 2009-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
/*
* TODO:
* - start in a state as if BIOS ran
* - remaining status flags (OVR/COL)
* - RAM support in mapper
* - region support
* - SN76496 DAC-like usage
* - H counter
*/
#include "pico_int.h"
#include "memory.h"
#include "sound/sn76496.h"
static unsigned char vdp_data_read(void)
{
struct PicoVideo *pv = &Pico.video;
unsigned char d;
d = Pico.vramb[pv->addr];
pv->addr = (pv->addr + 1) & 0x3fff;
pv->pending = 0;
return d;
}
static unsigned char vdp_ctl_read(void)
{
unsigned char d = Pico.video.pending_ints << 7;
Pico.video.pending = 0;
Pico.video.pending_ints = 0;
elprintf(EL_SR, "VDP sr: %02x", d);
return d;
}
static void vdp_data_write(unsigned char d)
{
struct PicoVideo *pv = &Pico.video;
if (pv->type == 3) {
Pico.cram[pv->addr & 0x1f] = d;
Pico.m.dirtyPal = 1;
} else {
Pico.vramb[pv->addr] = d;
}
pv->addr = (pv->addr + 1) & 0x3fff;
pv->pending = 0;
}
static void vdp_ctl_write(unsigned char d)
{
struct PicoVideo *pv = &Pico.video;
if (pv->pending) {
if ((d >> 6) == 2) {
pv->reg[d & 0x0f] = pv->addr;
elprintf(EL_IO, " VDP r%02x=%02x", d & 0x0f, pv->addr & 0xff);
}
pv->type = d >> 6;
pv->addr &= 0x00ff;
pv->addr |= (d & 0x3f) << 8;
} else {
pv->addr &= 0x3f00;
pv->addr |= d;
}
pv->pending ^= 1;
}
static unsigned char z80_sms_in(unsigned short a)
{
unsigned char d = 0;
elprintf(EL_IO, "z80 port %04x read", a);
a &= 0xc1;
switch (a)
{
case 0x00:
case 0x01:
d = 0xff;
break;
case 0x40: /* V counter */
d = Pico.video.v_counter;
elprintf(EL_HVCNT, "V counter read: %02x", d);
break;
case 0x41: /* H counter */
d = Pico.m.rotate++;
elprintf(EL_HVCNT, "H counter read: %02x", d);
break;
case 0x80:
d = vdp_data_read();
break;
case 0x81:
d = vdp_ctl_read();
break;
case 0xc0: /* I/O port A and B */
d = ~((PicoPad[0] & 0x3f) | (PicoPad[1] << 6));
break;
case 0xc1: /* I/O port B and miscellaneous */
d = (Pico.ms.io_ctl & 0x80) | ((Pico.ms.io_ctl << 1) & 0x40) | 0x30;
d |= ~(PicoPad[1] >> 2) & 0x0f;
break;
}
elprintf(EL_IO, "ret = %02x", d);
return d;
}
static void z80_sms_out(unsigned short a, unsigned char d)
{
elprintf(EL_IO, "z80 port %04x write %02x", a, d);
a &= 0xc1;
switch (a)
{
case 0x01:
Pico.ms.io_ctl = d;
break;
case 0x40:
case 0x41:
if (PicoOpt & POPT_EN_PSG)
SN76496Write(d);
break;
case 0x80:
vdp_data_write(d);
break;
case 0x81:
vdp_ctl_write(d);
break;
}
}
static int bank_mask;
static void write_bank(unsigned short a, unsigned char d)
{
elprintf(EL_Z80BNK, "bank %04x %02x @ %04x", a, d, z80_pc());
switch (a & 0x0f)
{
case 0x0c:
elprintf(EL_STATUS|EL_ANOMALY, "%02x written to control reg!", d);
break;
case 0x0d:
if (d != 0)
elprintf(EL_STATUS|EL_ANOMALY, "bank0 changed to %d!", d);
break;
case 0x0e:
d &= bank_mask;
z80_map_set(z80_read_map, 0x4000, 0x7fff, Pico.rom + (d << 14), 0);
#ifdef _USE_CZ80
Cz80_Set_Fetch(&CZ80, 0x4000, 0x7fff, (FPTR)Pico.rom + (d << 14));
#endif
break;
case 0x0f:
d &= bank_mask;
z80_map_set(z80_read_map, 0x8000, 0xbfff, Pico.rom + (d << 14), 0);
#ifdef _USE_CZ80
Cz80_Set_Fetch(&CZ80, 0x8000, 0xbfff, (FPTR)Pico.rom + (d << 14));
#endif
break;
}
Pico.ms.carthw[a & 0x0f] = d;
}
static void xwrite(unsigned int a, unsigned char d)
{
elprintf(EL_IO, "z80 write [%04x] %02x", a, d);
if (a >= 0xc000)
Pico.zram[a & 0x1fff] = d;
if (a >= 0xfff8)
write_bank(a, d);
}
void PicoResetMS(void)
{
z80_reset();
PsndReset(); // pal must be known here
}
void PicoPowerMS(void)
{
int s, tmp;
memset(&Pico.ram,0,(unsigned char *)&Pico.rom - Pico.ram);
memset(&Pico.video,0,sizeof(Pico.video));
memset(&Pico.m,0,sizeof(Pico.m));
Pico.m.pal = 0;
// calculate a mask for bank writes.
// ROM loader has aligned the size for us, so this is safe.
s = 0; tmp = Pico.romsize;
while ((tmp >>= 1) != 0)
s++;
if (Pico.romsize > (1 << s))
s++;
tmp = 1 << s;
bank_mask = (tmp - 1) >> 14;
Pico.ms.carthw[0x0e] = 1;
Pico.ms.carthw[0x0f] = 2;
PicoReset();
}
void PicoMemSetupMS(void)
{
z80_map_set(z80_read_map, 0x0000, 0xbfff, Pico.rom, 0);
z80_map_set(z80_read_map, 0xc000, 0xdfff, Pico.zram, 0);
z80_map_set(z80_read_map, 0xe000, 0xffff, Pico.zram, 0);
z80_map_set(z80_write_map, 0x0000, 0xbfff, xwrite, 1);
z80_map_set(z80_write_map, 0xc000, 0xdfff, Pico.zram, 0);
z80_map_set(z80_write_map, 0xe000, 0xffff, xwrite, 1);
#ifdef _USE_DRZ80
drZ80.z80_in = z80_sms_in;
drZ80.z80_out = z80_sms_out;
#endif
#ifdef _USE_CZ80
Cz80_Set_Fetch(&CZ80, 0x0000, 0xbfff, (FPTR)Pico.rom);
Cz80_Set_Fetch(&CZ80, 0xc000, 0xdfff, (FPTR)Pico.zram);
Cz80_Set_Fetch(&CZ80, 0xe000, 0xffff, (FPTR)Pico.zram);
Cz80_Set_INPort(&CZ80, z80_sms_in);
Cz80_Set_OUTPort(&CZ80, z80_sms_out);
#endif
}
void PicoStateLoadedMS(void)
{
write_bank(0xfffe, Pico.ms.carthw[0x0e]);
write_bank(0xffff, Pico.ms.carthw[0x0f]);
}
void PicoFrameMS(void)
{
struct PicoVideo *pv = &Pico.video;
int is_pal = Pico.m.pal;
int lines = is_pal ? 313 : 262;
int cycles_line = is_pal ? 58020 : 58293; /* (226.6 : 227.7) * 256 */
int cycles_done = 0, cycles_aim = 0;
int skip = PicoSkipFrame;
int lines_vis = 192;
int hint; // Hint counter
int nmi;
int y;
nmi = (PicoPad[0] >> 7) & 1;
if (!Pico.ms.nmi_state && nmi)
z80_nmi();
Pico.ms.nmi_state = nmi;
PicoFrameStartMode4();
hint = pv->reg[0x0a];
for (y = 0; y < lines; y++)
{
pv->v_counter = Pico.m.scanline = y;
if (y > 218)
pv->v_counter = y - 6;
if (y < lines_vis && !skip)
PicoLineMode4(y);
if (y <= lines_vis)
{
if (--hint < 0)
{
hint = pv->reg[0x0a];
pv->pending_ints |= 2;
if (pv->reg[0] & 0x10) {
elprintf(EL_INTS, "hint");
z80_int();
}
}
}
else if (y == lines_vis + 1) {
pv->pending_ints |= 1;
if (pv->reg[1] & 0x20) {
elprintf(EL_INTS, "vint");
z80_int();
}
}
cycles_aim += cycles_line;
cycles_done += z80_run((cycles_aim - cycles_done) >> 8) << 8;
}
if (PsndOut)
PsndGetSamplesMS();
}
void PicoFrameDrawOnlyMS(void)
{
int lines_vis = 192;
int y;
PicoFrameStartMode4();
for (y = 0; y < lines_vis; y++)
PicoLineMode4(y);
}

View File

@ -0,0 +1,79 @@
/*
* some code for sample mixing
* (C) notaz, 2006,2007
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#define MAXOUT (+32767)
#define MINOUT (-32768)
/* limitter */
#define Limit(val, max,min) { \
if ( val > max ) val = max; \
else if ( val < min ) val = min; \
}
void mix_32_to_16l_stereo(short *dest, int *src, int count)
{
int l, r;
for (; count > 0; count--)
{
l = r = *dest;
l += *src++;
r += *src++;
Limit( l, MAXOUT, MINOUT );
Limit( r, MAXOUT, MINOUT );
*dest++ = l;
*dest++ = r;
}
}
void mix_32_to_16_mono(short *dest, int *src, int count)
{
int l;
for (; count > 0; count--)
{
l = *dest;
l += *src++;
Limit( l, MAXOUT, MINOUT );
*dest++ = l;
}
}
void mix_16h_to_32(int *dest_buf, short *mp3_buf, int count)
{
while (count--)
{
*dest_buf++ += *mp3_buf++ >> 1;
}
}
void mix_16h_to_32_s1(int *dest_buf, short *mp3_buf, int count)
{
count >>= 1;
while (count--)
{
*dest_buf++ += *mp3_buf++ >> 1;
*dest_buf++ += *mp3_buf++ >> 1;
mp3_buf += 1*2;
}
}
void mix_16h_to_32_s2(int *dest_buf, short *mp3_buf, int count)
{
count >>= 1;
while (count--)
{
*dest_buf++ += *mp3_buf++ >> 1;
*dest_buf++ += *mp3_buf++ >> 1;
mp3_buf += 3*2;
}
}

View File

@ -0,0 +1,10 @@
//void mix_32_to_32(int *dest, int *src, int count);
void mix_16h_to_32(int *dest, short *src, int count);
void mix_16h_to_32_s1(int *dest, short *src, int count);
void mix_16h_to_32_s2(int *dest, short *src, int count);
void mix_32_to_16l_stereo(short *dest, int *src, int count);
void mix_32_to_16_mono(short *dest, int *src, int count);
extern int mix_32_to_16l_level;
void mix_32_to_16l_stereo_lvl(short *dest, int *src, int count);

View File

@ -0,0 +1,344 @@
/***************************************************************************
sn76496.c
Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
tone /noise generator. Also known as (or at least compatible with) TMS9919.
Noise emulation is not accurate due to lack of documentation. The noise
generator uses a shift register with a XOR-feedback network, but the exact
layout is unknown. It can be set for either period or white noise; again,
the details are unknown.
28/03/2005 : Sebastien Chevalier
Update th SN76496Write func, according to SN76489 doc found on SMSPower.
- On write with 0x80 set to 0, when LastRegister is other then TONE,
the function is similar than update with 0x80 set to 1
***************************************************************************/
#ifndef __GNUC__
#pragma warning (disable:4244)
#endif
#include "sn76496.h"
#define MAX_OUTPUT 0x47ff // was 0x7fff
#define STEP 0x10000
/* Formulas for noise generator */
/* bit0 = output */
/* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */
#define FB_WNOISE 0x14002 /* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */
/* noise feedback for periodic noise mode */
//#define FB_PNOISE 0x10000 /* 16bit rorate */
#define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */
/*
0x08000 is definitely wrong. The Master System conversion of Marble Madness
uses periodic noise as a baseline. With a 15-bit rotate, the bassline is
out of tune.
The 16-bit rotate has been confirmed against a real PAL Sega Master System 2.
Hope that helps the System E stuff, more news on the PSG as and when!
*/
/* noise generator start preset (for periodic noise) */
#define NG_PRESET 0x0f35
struct SN76496
{
//sound_stream * Channel;
int SampleRate;
unsigned int UpdateStep;
int VolTable[16]; /* volume table */
int Register[8]; /* registers */
int LastRegister; /* last register written */
int Volume[4]; /* volume of voice 0-2 and noise */
unsigned int RNG; /* noise generator */
int NoiseFB; /* noise feedback mask */
int Period[4];
int Count[4];
int Output[4];
int pad[1];
};
static struct SN76496 ono_sn; // one and only SN76496
int *sn76496_regs;
//static
void SN76496Write(int data)
{
struct SN76496 *R = &ono_sn;
int n;
/* update the output buffer before changing the registers */
//stream_update(R->Channel,0);
if (data & 0x80)
{
int r = (data & 0x70) >> 4;
int c = r/2;
R->LastRegister = r;
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
switch (r)
{
case 0: /* tone 0 : frequency */
case 2: /* tone 1 : frequency */
case 4: /* tone 2 : frequency */
R->Period[c] = R->UpdateStep * R->Register[r];
if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
if (r == 4)
{
/* update noise shift frequency */
if ((R->Register[6] & 0x03) == 0x03)
R->Period[3] = 2 * R->Period[2];
}
break;
case 1: /* tone 0 : volume */
case 3: /* tone 1 : volume */
case 5: /* tone 2 : volume */
case 7: /* noise : volume */
R->Volume[c] = R->VolTable[data & 0x0f];
break;
case 6: /* noise : frequency, mode */
{
int n = R->Register[6];
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
n &= 3;
/* N/512,N/1024,N/2048,Tone #3 output */
R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3)));
/* reset noise shifter */
R->RNG = NG_PRESET;
R->Output[3] = R->RNG & 1;
}
break;
}
}
else
{
int r = R->LastRegister;
int c = r/2;
switch (r)
{
case 0: /* tone 0 : frequency */
case 2: /* tone 1 : frequency */
case 4: /* tone 2 : frequency */
R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
R->Period[c] = R->UpdateStep * R->Register[r];
if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
if (r == 4)
{
/* update noise shift frequency */
if ((R->Register[6] & 0x03) == 0x03)
R->Period[3] = 2 * R->Period[2];
}
break;
case 1: /* tone 0 : volume */
case 3: /* tone 1 : volume */
case 5: /* tone 2 : volume */
case 7: /* noise : volume */
R->Volume[c] = R->VolTable[data & 0x0f];
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
break;
case 6: /* noise : frequency, mode */
{
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
n = R->Register[6];
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
n &= 3;
/* N/512,N/1024,N/2048,Tone #3 output */
R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3)));
/* reset noise shifter */
R->RNG = NG_PRESET;
R->Output[3] = R->RNG & 1;
}
break;
}
}
}
/*
WRITE8_HANDLER( SN76496_0_w ) { SN76496Write(0,data); }
WRITE8_HANDLER( SN76496_1_w ) { SN76496Write(1,data); }
WRITE8_HANDLER( SN76496_2_w ) { SN76496Write(2,data); }
WRITE8_HANDLER( SN76496_3_w ) { SN76496Write(3,data); }
WRITE8_HANDLER( SN76496_4_w ) { SN76496Write(4,data); }
*/
//static
void SN76496Update(short *buffer, int length, int stereo)
{
int i;
struct SN76496 *R = &ono_sn;
/* If the volume is 0, increase the counter */
for (i = 0;i < 4;i++)
{
if (R->Volume[i] == 0)
{
/* note that I do count += length, NOT count = length + 1. You might think */
/* it's the same since the volume is 0, but doing the latter could cause */
/* interferencies when the program is rapidly modulating the volume. */
if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
}
}
while (length > 0)
{
int vol[4];
unsigned int out;
int left;
/* vol[] keeps track of how long each square wave stays */
/* in the 1 position during the sample period. */
vol[0] = vol[1] = vol[2] = vol[3] = 0;
for (i = 0;i < 3;i++)
{
if (R->Output[i]) vol[i] += R->Count[i];
R->Count[i] -= STEP;
/* Period[i] is the half period of the square wave. Here, in each */
/* loop I add Period[i] twice, so that at the end of the loop the */
/* square wave is in the same status (0 or 1) it was at the start. */
/* vol[i] is also incremented by Period[i], since the wave has been 1 */
/* exactly half of the time, regardless of the initial position. */
/* If we exit the loop in the middle, Output[i] has to be inverted */
/* and vol[i] incremented only if the exit status of the square */
/* wave is 1. */
while (R->Count[i] <= 0)
{
R->Count[i] += R->Period[i];
if (R->Count[i] > 0)
{
R->Output[i] ^= 1;
if (R->Output[i]) vol[i] += R->Period[i];
break;
}
R->Count[i] += R->Period[i];
vol[i] += R->Period[i];
}
if (R->Output[i]) vol[i] -= R->Count[i];
}
left = STEP;
do
{
int nextevent;
if (R->Count[3] < left) nextevent = R->Count[3];
else nextevent = left;
if (R->Output[3]) vol[3] += R->Count[3];
R->Count[3] -= nextevent;
if (R->Count[3] <= 0)
{
if (R->RNG & 1) R->RNG ^= R->NoiseFB;
R->RNG >>= 1;
R->Output[3] = R->RNG & 1;
R->Count[3] += R->Period[3];
if (R->Output[3]) vol[3] += R->Period[3];
}
if (R->Output[3]) vol[3] -= R->Count[3];
left -= nextevent;
} while (left > 0);
out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;
if ((out /= STEP)) // will be optimized to shift; max 0x47ff = 18431
*buffer += out;
if(stereo) buffer+=2; // only left for stereo, to be mixed to right later
else buffer++;
length--;
}
}
static void SN76496_set_clock(struct SN76496 *R,int clock)
{
/* the base clock for the tone generators is the chip clock divided by 16; */
/* for the noise generator, it is clock / 256. */
/* Here we calculate the number of steps which happen during one sample */
/* at the given sample rate. No. of events = sample rate / (clock/16). */
/* STEP is a multiplier used to turn the fraction into a fixed point */
/* number. */
R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
}
static void SN76496_set_gain(struct SN76496 *R,int gain)
{
int i;
double out;
gain &= 0xff;
/* increase max output basing on gain (0.2 dB per step) */
out = MAX_OUTPUT / 3;
while (gain-- > 0)
out *= 1.023292992; /* = (10 ^ (0.2/20)) */
/* build volume table (2dB per step) */
for (i = 0;i < 15;i++)
{
/* limit volume to avoid clipping */
if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
else R->VolTable[i] = out;
out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */
}
R->VolTable[15] = 0;
}
//static
int SN76496_init(int clock,int sample_rate)
{
struct SN76496 *R = &ono_sn;
int i;
//R->Channel = stream_create(0,1, sample_rate,R,SN76496Update);
sn76496_regs = R->Register;
R->SampleRate = sample_rate;
SN76496_set_clock(R,clock);
for (i = 0;i < 4;i++) R->Volume[i] = 0;
R->LastRegister = 0;
for (i = 0;i < 8;i+=2)
{
R->Register[i] = 0;
R->Register[i + 1] = 0x0f; /* volume = 0 */
}
for (i = 0;i < 4;i++)
{
R->Output[i] = 0;
R->Period[i] = R->Count[i] = R->UpdateStep;
}
R->RNG = NG_PRESET;
R->Output[3] = R->RNG & 1;
// added
SN76496_set_gain(R, 0);
return 0;
}

View File

@ -0,0 +1,8 @@
#ifndef SN76496_H
#define SN76496_H
void SN76496Write(int data);
void SN76496Update(short *buffer,int length,int stereo);
int SN76496_init(int clock,int sample_rate);
#endif

View File

@ -0,0 +1,384 @@
/*
* PicoDrive
* (c) Copyright Dave, 2004
* (C) notaz, 2006-2009
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <string.h>
#include "ym2612.h"
#include "sn76496.h"
#include "../pico_int.h"
#include "../cd/cue.h"
#include "mix.h"
#define SIMPLE_WRITE_SOUND 0
void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_stereo;
// master int buffer to mix to
static int PsndBuffer[2*(44100+100)/50];
// dac
static unsigned short dac_info[312+4]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample
// cdda output buffer
short cdda_out_buffer[2*1152];
// for Pico
int PsndRate=0;
int PsndLen=0; // number of mono samples, multiply by 2 for stereo
int PsndLen_exc_add=0; // this is for non-integer sample counts per line, eg. 22050/60
int PsndLen_exc_cnt=0;
int PsndDacLine=0;
short *PsndOut=NULL; // PCM data buffer
// timers
int timer_a_next_oflow, timer_a_step; // in z80 cycles
int timer_b_next_oflow, timer_b_step;
// sn76496
extern int *sn76496_regs;
static void dac_recalculate(void)
{
int i, dac_cnt, pos, len, lines = Pico.m.pal ? 312 : 262, mid = Pico.m.pal ? 68 : 93;
if (PsndLen <= lines)
{
// shrinking algo
dac_cnt = -PsndLen;
len=1; pos=0;
dac_info[225] = 1;
for(i=226; i != 225; i++)
{
if (i >= lines) i = 0;
len = 0;
if(dac_cnt < 0) {
len=1;
pos++;
dac_cnt += lines;
}
dac_cnt -= PsndLen;
dac_info[i] = (pos<<4)|len;
}
}
else
{
// stretching
dac_cnt = PsndLen;
pos=0;
for(i = 225; i != 224; i++)
{
if (i >= lines) i = 0;
len=0;
while(dac_cnt >= 0) {
dac_cnt -= lines;
len++;
}
if (i == mid) // midpoint
while(pos+len < PsndLen/2) {
dac_cnt -= lines;
len++;
}
dac_cnt += PsndLen;
dac_info[i] = (pos<<4)|len;
pos+=len;
}
// last sample
for(len = 0, i = pos; i < PsndLen; i++) len++;
if (PsndLen_exc_add) len++;
dac_info[224] = (pos<<4)|len;
}
mid = (dac_info[lines-1] & 0xfff0) + ((dac_info[lines-1] & 0xf) << 4);
for (i = lines; i < sizeof(dac_info) / sizeof(dac_info[0]); i++)
dac_info[i] = mid;
//for(i=len=0; i < lines; i++) {
// printf("%03i : %03i : %i\n", i, dac_info[i]>>4, dac_info[i]&0xf);
// len+=dac_info[i]&0xf;
//}
//printf("rate is %i, len %f\n", PsndRate, (double)PsndRate/(Pico.m.pal ? 50.0 : 60.0));
//printf("len total: %i, last pos: %i\n", len, pos);
//exit(8);
}
PICO_INTERNAL void PsndReset(void)
{
// PsndRerate calls YM2612Init, which also resets
PsndRerate(0);
timers_reset();
}
// to be called after changing sound rate or chips
void PsndRerate(int preserve_state)
{
void *state = NULL;
int target_fps = Pico.m.pal ? 50 : 60;
if (preserve_state) {
state = malloc(0x204);
if (state == NULL) return;
ym2612_pack_state();
memcpy(state, YM2612GetRegs(), 0x204);
}
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate);
if (preserve_state) {
// feed it back it's own registers, just like after loading state
memcpy(YM2612GetRegs(), state, 0x204);
ym2612_unpack_state();
}
if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state
SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate);
if (preserve_state) memcpy(sn76496_regs, state, 28*4); // restore old state
if (state)
free(state);
// calculate PsndLen
PsndLen=PsndRate / target_fps;
PsndLen_exc_add=((PsndRate - PsndLen*target_fps)<<16) / target_fps;
PsndLen_exc_cnt=0;
// recalculate dac info
dac_recalculate();
// clear all buffers
memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4);
memset(cdda_out_buffer, 0, sizeof(cdda_out_buffer));
if (PsndOut)
PsndClear();
// set mixer
PsndMix_32_to_16l = (PicoOpt & POPT_EN_STEREO) ? mix_32_to_16l_stereo : mix_32_to_16_mono;
if (PicoAHW & PAHW_PICO)
PicoReratePico();
}
PICO_INTERNAL void PsndDoDAC(int line_to)
{
int pos, pos1, len;
int dout = ym2612.dacout;
int line_from = PsndDacLine;
if (line_to >= 312)
line_to = 311;
PsndDacLine = line_to + 1;
pos =dac_info[line_from]>>4;
pos1=dac_info[line_to];
len = ((pos1>>4)-pos) + (pos1&0xf);
if (!len) return;
if (PicoOpt & POPT_EN_STEREO) {
short *d = PsndOut + pos*2;
for (; len > 0; len--, d+=2) *d = dout;
} else {
short *d = PsndOut + pos;
for (; len > 0; len--, d++) *d = dout;
}
}
// cdda
static void cdda_raw_update(int *buffer, int length)
{
int ret, cdda_bytes, mult = 1;
cdda_bytes = length*4;
if (PsndRate <= 22050 + 100) mult = 2;
if (PsndRate < 22050 - 100) mult = 4;
cdda_bytes *= mult;
ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);
if (ret < cdda_bytes) {
memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);
Pico_mcd->cdda_stream = NULL;
return;
}
// now mix
switch (mult) {
case 1: mix_16h_to_32(buffer, cdda_out_buffer, length*2); break;
case 2: mix_16h_to_32_s1(buffer, cdda_out_buffer, length*2); break;
case 4: mix_16h_to_32_s2(buffer, cdda_out_buffer, length*2); break;
}
}
void cdda_start_play(int lba_base, int lba_offset, int lb_len)
{
if (Pico_mcd->cdda_type == CT_MP3)
{
int pos1024 = 0;
if (lba_offset)
pos1024 = lba_offset * 1024 / lb_len;
mp3_start_play(Pico_mcd->cdda_stream, pos1024);
return;
}
pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET);
if (Pico_mcd->cdda_type == CT_WAV)
{
// skip headers, assume it's 44kHz stereo uncompressed
pm_seek(Pico_mcd->cdda_stream, 44, SEEK_CUR);
}
}
PICO_INTERNAL void PsndClear(void)
{
int len = PsndLen;
if (PsndLen_exc_add) len++;
if (PicoOpt & POPT_EN_STEREO)
memset32((int *) PsndOut, 0, len); // assume PsndOut to be aligned
else {
short *out = PsndOut;
if ((long)out & 2) { *out++ = 0; len--; }
memset32((int *) out, 0, len/2);
if (len & 1) out[len-1] = 0;
}
}
static int PsndRender(int offset, int length)
{
int buf32_updated = 0;
int *buf32 = PsndBuffer+offset;
int stereo = (PicoOpt & 8) >> 3;
offset <<= stereo;
pprof_start(sound);
#if !SIMPLE_WRITE_SOUND
if (offset == 0) { // should happen once per frame
// compensate for float part of PsndLen
PsndLen_exc_cnt += PsndLen_exc_add;
if (PsndLen_exc_cnt >= 0x10000) {
PsndLen_exc_cnt -= 0x10000;
length++;
}
}
#endif
// PSG
if (PicoOpt & POPT_EN_PSG)
SN76496Update(PsndOut+offset, length, stereo);
if (PicoAHW & PAHW_PICO) {
PicoPicoPCMUpdate(PsndOut+offset, length, stereo);
return length;
}
// Add in the stereo FM buffer
if (PicoOpt & POPT_EN_FM) {
buf32_updated = YM2612UpdateOne(buf32, length, stereo, 1);
} else
memset32(buf32, 0, length<<stereo);
//printf("active_chs: %02x\n", buf32_updated);
(void)buf32_updated;
// CD: PCM sound
if (PicoAHW & PAHW_MCD) {
pcd_pcm_update(buf32, length, stereo);
//buf32_updated = 1;
}
// CD: CDDA audio
// CD mode, cdda enabled, not data track, CDC is reading
if ((PicoAHW & PAHW_MCD) && (PicoOpt & POPT_EN_MCD_CDDA)
&& Pico_mcd->cdda_stream != NULL
&& !(Pico_mcd->s68k_regs[0x36] & 1))
{
// note: only 44, 22 and 11 kHz supported, with forced stereo
if (Pico_mcd->cdda_type == CT_MP3)
mp3_update(buf32, length, stereo);
else
cdda_raw_update(buf32, length);
}
if ((PicoAHW & PAHW_32X) && (PicoOpt & POPT_EN_PWM))
p32x_pwm_update(buf32, length, stereo);
// convert + limit to normal 16bit output
PsndMix_32_to_16l(PsndOut+offset, buf32, length);
pprof_end(sound);
return length;
}
// to be called on 224 or line_sample scanlines only
PICO_INTERNAL void PsndGetSamples(int y)
{
#if SIMPLE_WRITE_SOUND
if (y != 224) return;
PsndRender(0, PsndLen);
if (PicoWriteSound)
PicoWriteSound(PsndLen * ((PicoOpt & POPT_EN_STEREO) ? 4 : 2));
PsndClear();
#else
static int curr_pos = 0;
if (y == 224)
{
if (emustatus & 2)
curr_pos += PsndRender(curr_pos, PsndLen-PsndLen/2);
else curr_pos = PsndRender(0, PsndLen);
if (emustatus & 1)
emustatus |= 2;
else emustatus &= ~2;
if (PicoWriteSound)
PicoWriteSound(curr_pos * ((PicoOpt & POPT_EN_STEREO) ? 4 : 2));
// clear sound buffer
PsndClear();
}
else if (emustatus & 3) {
emustatus|= 2;
emustatus&=~1;
curr_pos = PsndRender(0, PsndLen/2);
}
#endif
}
PICO_INTERNAL void PsndGetSamplesMS(void)
{
int stereo = (PicoOpt & 8) >> 3;
int length = PsndLen;
#if !SIMPLE_WRITE_SOUND
// compensate for float part of PsndLen
PsndLen_exc_cnt += PsndLen_exc_add;
if (PsndLen_exc_cnt >= 0x10000) {
PsndLen_exc_cnt -= 0x10000;
length++;
}
#endif
// PSG
if (PicoOpt & POPT_EN_PSG)
SN76496Update(PsndOut, length, stereo);
// upmix to "stereo" if needed
if (stereo) {
int i, *p;
for (i = length, p = (void *)PsndOut; i > 0; i--, p++)
*p |= *p << 16;
}
if (PicoWriteSound != NULL)
PicoWriteSound(length * ((PicoOpt & POPT_EN_STEREO) ? 4 : 2));
PsndClear();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,192 @@
/*
header file for software emulation for FM sound generator
*/
#ifndef _H_FM_FM_
#define _H_FM_FM_
/* compiler dependence */
#ifndef UINT8
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
#endif
#ifndef INT8
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if 1
/* struct describing a single operator (SLOT) */
typedef struct
{
INT32 *DT; /* #0x00 detune :dt_tab[DT] */
UINT8 ar; /* #0x04 attack rate */
UINT8 d1r; /* #0x05 decay rate */
UINT8 d2r; /* #0x06 sustain rate */
UINT8 rr; /* #0x07 release rate */
UINT32 mul; /* #0x08 multiple :ML_TABLE[ML] */
/* Phase Generator */
UINT32 phase; /* #0x0c phase counter | need_save */
UINT32 Incr; /* #0x10 phase step */
UINT8 KSR; /* #0x14 key scale rate :3-KSR */
UINT8 ksr; /* #0x15 key scale rate :kcode>>(3-KSR) */
UINT8 key; /* #0x16 0=last key was KEY OFF, 1=KEY ON */
/* Envelope Generator */
UINT8 state; /* #0x17 phase type: EG_OFF=0, EG_REL, EG_SUS, EG_DEC, EG_ATT | need_save */
UINT16 tl; /* #0x18 total level: TL << 3 */
INT16 volume; /* #0x1a envelope counter | need_save */
UINT32 sl; /* #0x1c sustain level:sl_table[SL] */
UINT32 eg_pack_ar; /* #0x20 (attack state) */
UINT32 eg_pack_d1r; /* #0x24 (decay state) */
UINT32 eg_pack_d2r; /* #0x28 (sustain state) */
UINT32 eg_pack_rr; /* #0x2c (release state) */
} FM_SLOT;
typedef struct
{
FM_SLOT SLOT[4]; /* four SLOTs (operators) */
UINT8 ALGO; /* +00 algorithm */
UINT8 FB; /* feedback shift */
UINT8 pad[2];
INT32 op1_out; /* op1 output for feedback */
INT32 mem_value; /* +08 delayed sample (MEM) value */
INT32 pms; /* channel PMS */
UINT8 ams; /* channel AMS */
UINT8 kcode; /* +11 key code: */
UINT8 fn_h; /* freq latch */
UINT8 pad2;
UINT32 fc; /* fnum,blk:adjusted to sample rate */
UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
/* LFO */
UINT8 AMmasks; /* AM enable flag */
UINT8 pad3[3];
} FM_CH;
typedef struct
{
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* 08 frequency base */
UINT8 address; /* 10 address register | need_save */
UINT8 status; /* 11 status flag | need_save */
UINT8 mode; /* mode CSM / 3SLOT */
UINT8 pad;
int TA; /* timer a */
int TAC; /* timer a maxval */
int TAT; /* timer a ticker | need_save */
UINT8 TB; /* timer b */
UINT8 pad2[3];
int TBC; /* timer b maxval */
int TBT; /* timer b ticker | need_save */
/* local time tables */
INT32 dt_tab[8][32];/* DeTune table */
} FM_ST;
/***********************************************************/
/* OPN unit */
/***********************************************************/
/* OPN 3slot struct */
typedef struct
{
UINT32 fc[3]; /* fnum3,blk3: calculated */
UINT8 fn_h; /* freq3 latch */
UINT8 kcode[3]; /* key code */
UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
} FM_3SLOT;
/* OPN/A/B common state */
typedef struct
{
FM_ST ST; /* general state */
FM_3SLOT SL3; /* 3 slot mode state */
UINT32 pan; /* fm channels output mask (bit 1 = enable) */
UINT32 eg_cnt; /* global envelope generator counter | need_save */
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 | need_save */
UINT32 eg_timer_add; /* step of eg_timer */
/* LFO */
UINT32 lfo_cnt; /* need_save */
UINT32 lfo_inc;
UINT32 lfo_freq[8]; /* LFO FREQ table */
} FM_OPN;
/* here's the virtual YM2612 */
typedef struct
{
UINT8 REGS[0x200]; /* registers (for save states) */
INT32 addr_A1; /* address line A1 | need_save */
FM_CH CH[6]; /* channel state */
/* dac output (YM2612) */
int dacen;
INT32 dacout;
FM_OPN OPN; /* OPN state */
UINT32 slot_mask; /* active slot mask (performance hack) */
} YM2612;
#endif
#ifndef EXTERNAL_YM2612
extern YM2612 ym2612;
#endif
void YM2612Init_(int baseclock, int rate);
void YM2612ResetChip_(void);
int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty);
int YM2612Write_(unsigned int a, unsigned int v);
//unsigned char YM2612Read_(void);
int YM2612PicoTick_(int n);
void YM2612PicoStateLoad_(void);
void *YM2612GetRegs(void);
void YM2612PicoStateSave2(int tat, int tbt);
int YM2612PicoStateLoad2(int *tat, int *tbt);
#ifndef __GP2X__
#define YM2612Init YM2612Init_
#define YM2612ResetChip YM2612ResetChip_
#define YM2612UpdateOne YM2612UpdateOne_
#define YM2612PicoStateLoad YM2612PicoStateLoad_
#else
/* GP2X specific */
#include "../../platform/gp2x/940ctl.h"
extern int PicoOpt;
#define YM2612Init(baseclock,rate) { \
if (PicoOpt&0x200) YM2612Init_940(baseclock, rate); \
else YM2612Init_(baseclock, rate); \
}
#define YM2612ResetChip() { \
if (PicoOpt&0x200) YM2612ResetChip_940(); \
else YM2612ResetChip_(); \
}
#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) \
(PicoOpt&0x200) ? YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty) : \
YM2612UpdateOne_(buffer, length, stereo, is_buf_empty);
#define YM2612PicoStateLoad() { \
if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \
else YM2612PicoStateLoad_(); \
}
#endif /* __GP2X__ */
#endif /* _H_FM_FM_ */

View File

@ -0,0 +1,549 @@
/*
* PicoDrive
* (c) Copyright Dave, 2004
* (C) notaz, 2006-2009
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "pico_int.h"
int line_base_cycles;
extern const unsigned char hcounts_32[];
extern const unsigned char hcounts_40[];
#ifndef UTYPES_DEFINED
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#define UTYPES_DEFINED
#endif
int (*PicoDmaHook)(unsigned int source, int len, unsigned short **srcp, unsigned short **limitp) = NULL;
static __inline void AutoIncrement(void)
{
Pico.video.addr=(unsigned short)(Pico.video.addr+Pico.video.reg[0xf]);
}
static void VideoWrite(u16 d)
{
unsigned int a=Pico.video.addr;
switch (Pico.video.type)
{
case 1: if(a&1) d=(u16)((d<<8)|(d>>8)); // If address is odd, bytes are swapped (which game needs this?)
Pico.vram [(a>>1)&0x7fff]=d;
if (a - ((unsigned)(Pico.video.reg[5]&0x7f) << 9) < 0x400)
rendstatus |= PDRAW_DIRTY_SPRITES;
break;
case 3: Pico.m.dirtyPal = 1;
Pico.cram [(a>>1)&0x003f]=d; break; // wraps (Desert Strike)
case 5: Pico.vsram[(a>>1)&0x003f]=d; break;
//default:elprintf(EL_ANOMALY, "VDP write %04x with bad type %i", d, Pico.video.type); break;
}
AutoIncrement();
}
static unsigned int VideoRead(void)
{
unsigned int a=0,d=0;
a=Pico.video.addr; a>>=1;
switch (Pico.video.type)
{
case 0: d=Pico.vram [a&0x7fff]; break;
case 8: d=Pico.cram [a&0x003f]; break;
case 4: d=Pico.vsram[a&0x003f]; break;
default:elprintf(EL_ANOMALY, "VDP read with bad type %i", Pico.video.type); break;
}
AutoIncrement();
return d;
}
static int GetDmaLength(void)
{
struct PicoVideo *pvid=&Pico.video;
int len=0;
// 16-bit words to transfer:
len =pvid->reg[0x13];
len|=pvid->reg[0x14]<<8;
// Charles MacDonald:
if(!len) len = 0xffff;
return len;
}
static void DmaSlow(int len)
{
u16 *pd=0, *pdend, *r;
unsigned int a=Pico.video.addr, a2, d;
unsigned char inc=Pico.video.reg[0xf];
unsigned int source;
source =Pico.video.reg[0x15]<<1;
source|=Pico.video.reg[0x16]<<9;
source|=Pico.video.reg[0x17]<<17;
elprintf(EL_VDPDMA, "DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i] @ %06x",
Pico.video.type, source, a, len, inc, (Pico.video.status&8)||!(Pico.video.reg[1]&0x40),
SekCyclesDone(), SekPc);
Pico.m.dma_xfers += len;
SekCyclesBurnRun(CheckDMA());
if ((source&0xe00000)==0xe00000) { // Ram
pd=(u16 *)(Pico.ram+(source&0xfffe));
pdend=(u16 *)(Pico.ram+0x10000);
}
else if (PicoAHW & PAHW_MCD)
{
elprintf(EL_VDPDMA, "DmaSlow CD, r3=%02x", Pico_mcd->s68k_regs[3]);
if(source<0x20000) { // Bios area
pd=(u16 *)(Pico_mcd->bios+(source&~1));
pdend=(u16 *)(Pico_mcd->bios+0x20000);
} else if ((source&0xfc0000)==0x200000) { // Word Ram
source -= 2;
if (!(Pico_mcd->s68k_regs[3]&4)) { // 2M mode
pd=(u16 *)(Pico_mcd->word_ram2M+(source&0x3fffe));
pdend=(u16 *)(Pico_mcd->word_ram2M+0x40000);
} else {
if (source < 0x220000) { // 1M mode
int bank = Pico_mcd->s68k_regs[3]&1;
pd=(u16 *)(Pico_mcd->word_ram1M[bank]+(source&0x1fffe));
pdend=(u16 *)(Pico_mcd->word_ram1M[bank]+0x20000);
} else {
DmaSlowCell(source, a, len, inc);
return;
}
}
} else if ((source&0xfe0000)==0x020000) { // Prg Ram
u8 *prg_ram = Pico_mcd->prg_ram_b[Pico_mcd->s68k_regs[3]>>6];
pd=(u16 *)(prg_ram+(source&0x1fffe));
pdend=(u16 *)(prg_ram+0x20000);
} else {
elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow[%i] %06x->%04x: FIXME: unsupported src", Pico.video.type, source, a);
return;
}
}
else
{
// if we have DmaHook, let it handle ROM because of possible DMA delay
if (PicoDmaHook && PicoDmaHook(source, len, &pd, &pdend));
else if (source<Pico.romsize) { // Rom
pd=(u16 *)(Pico.rom+(source&~1));
pdend=(u16 *)(Pico.rom+Pico.romsize);
}
else {
elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow[%i] %06x->%04x: invalid src", Pico.video.type, source, a);
return;
}
}
// overflow protection, might break something..
if (len > pdend - pd) {
len = pdend - pd;
elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow overflow");
}
switch (Pico.video.type)
{
case 1: // vram
r = Pico.vram;
if (inc == 2 && !(a&1) && a+len*2 < 0x10000)
{
// most used DMA mode
memcpy16(r + (a>>1), pd, len);
a += len*2;
}
else
{
for(; len; len--)
{
d=*pd++;
if(a&1) d=(d<<8)|(d>>8);
r[a>>1] = (u16)d; // will drop the upper bits
// AutoIncrement
a=(u16)(a+inc);
// didn't src overlap?
//if(pd >= pdend) pd-=0x8000; // should be good for RAM, bad for ROM
}
}
rendstatus |= PDRAW_DIRTY_SPRITES;
break;
case 3: // cram
Pico.m.dirtyPal = 1;
r = Pico.cram;
for(a2=a&0x7f; len; len--)
{
r[a2>>1] = (u16)*pd++; // bit 0 is ignored
// AutoIncrement
a2+=inc;
// didn't src overlap?
//if(pd >= pdend) pd-=0x8000;
// good dest?
if(a2 >= 0x80) break; // Todds Adventures in Slime World / Andre Agassi tennis
}
a=(a&0xff00)|a2;
break;
case 5: // vsram[a&0x003f]=d;
r = Pico.vsram;
for(a2=a&0x7f; len; len--)
{
r[a2>>1] = (u16)*pd++;
// AutoIncrement
a2+=inc;
// didn't src overlap?
//if(pd >= pdend) pd-=0x8000;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
default:
if (Pico.video.type != 0 || (EL_LOGMASK & EL_VDPDMA))
elprintf(EL_VDPDMA|EL_ANOMALY, "DMA with bad type %i", Pico.video.type);
break;
}
// remember addr
Pico.video.addr=(u16)a;
}
static void DmaCopy(int len)
{
u16 a=Pico.video.addr;
unsigned char *vr = (unsigned char *) Pico.vram;
unsigned char *vrs;
unsigned char inc=Pico.video.reg[0xf];
int source;
elprintf(EL_VDPDMA, "DmaCopy len %i [%i]", len, SekCyclesDone());
Pico.m.dma_xfers += len;
Pico.video.status |= 2; // dma busy
source =Pico.video.reg[0x15];
source|=Pico.video.reg[0x16]<<8;
vrs=vr+source;
if (source+len > 0x10000) len=0x10000-source; // clip??
for (; len; len--)
{
vr[a] = *vrs++;
// AutoIncrement
a=(u16)(a+inc);
}
// remember addr
Pico.video.addr=a;
rendstatus |= PDRAW_DIRTY_SPRITES;
}
// check: Contra, Megaman
// note: this is still inaccurate
static void DmaFill(int data)
{
int len;
unsigned short a=Pico.video.addr;
unsigned char *vr=(unsigned char *) Pico.vram;
unsigned char high = (unsigned char) (data >> 8);
unsigned char inc=Pico.video.reg[0xf];
len=GetDmaLength();
elprintf(EL_VDPDMA, "DmaFill len %i inc %i [%i]", len, inc, SekCyclesDone());
Pico.m.dma_xfers += len;
Pico.video.status |= 2; // dma busy
// from Charles MacDonald's genvdp.txt:
// Write lower byte to address specified
vr[a] = (unsigned char) data;
a=(u16)(a+inc);
if (!inc) len=1;
for (; len; len--) {
// Write upper byte to adjacent address
// (here we are byteswapped, so address is already 'adjacent')
vr[a] = high;
// Increment address register
a=(u16)(a+inc);
}
// remember addr
Pico.video.addr=a;
// update length
Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0; // Dino Dini's Soccer (E) (by Haze)
rendstatus |= PDRAW_DIRTY_SPRITES;
}
static void CommandDma(void)
{
struct PicoVideo *pvid=&Pico.video;
int len=0,method=0;
if ((pvid->reg[1]&0x10)==0) return; // DMA not enabled
len=GetDmaLength();
method=pvid->reg[0x17]>>6;
if (method< 2) DmaSlow(len); // 68000 to VDP
if (method==3) DmaCopy(len); // VRAM Copy
}
static void CommandChange(void)
{
struct PicoVideo *pvid=&Pico.video;
unsigned int cmd=0,addr=0;
cmd=pvid->command;
// Get type of transfer 0xc0000030 (v/c/vsram read/write)
pvid->type=(unsigned char)(((cmd>>2)&0xc)|(cmd>>30));
// Get address 0x3fff0003
addr =(cmd>>16)&0x3fff;
addr|=(cmd<<14)&0xc000;
pvid->addr=(unsigned short)addr;
// Check for dma:
if (cmd&0x80) CommandDma();
}
static void DrawSync(int blank_on)
{
if (Pico.m.scanline < 224 && !(PicoOpt & POPT_ALT_RENDERER) &&
!PicoSkipFrame && DrawScanline <= Pico.m.scanline) {
//elprintf(EL_ANOMALY, "sync");
PicoDrawSync(Pico.m.scanline, blank_on);
}
}
PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
{
struct PicoVideo *pvid=&Pico.video;
//if (Pico.m.scanline < 224)
// elprintf(EL_STATUS, "PicoVideoWrite [%06x] %04x", a, d);
a&=0x1c;
if (a==0x00) // Data port 0 or 2
{
// try avoiding the sync..
if (Pico.m.scanline < 224 && (pvid->reg[1]&0x40) &&
!(!pvid->pending &&
((pvid->command & 0xc00000f0) == 0x40000010 && Pico.vsram[pvid->addr>>1] == d))
)
DrawSync(0);
if (pvid->pending) {
CommandChange();
pvid->pending=0;
}
// If a DMA fill has been set up, do it
if ((pvid->command&0x80) && (pvid->reg[1]&0x10) && (pvid->reg[0x17]>>6)==2)
{
DmaFill(d);
}
else
{
// preliminary FIFO emulation for Chaos Engine, The (E)
if (!(pvid->status&8) && (pvid->reg[1]&0x40) && !(PicoOpt&POPT_DIS_VDP_FIFO)) // active display?
{
pvid->status&=~0x200; // FIFO no longer empty
pvid->lwrite_cnt++;
if (pvid->lwrite_cnt >= 4) pvid->status|=0x100; // FIFO full
if (pvid->lwrite_cnt > 4) {
SekCyclesBurnRun(32); // penalty // 488/12-8
}
elprintf(EL_ASVDP, "VDP data write: %04x [%06x] {%i} #%i @ %06x", d, Pico.video.addr,
Pico.video.type, pvid->lwrite_cnt, SekPc);
}
VideoWrite(d);
}
return;
}
if (a==0x04) // Control (command) port 4 or 6
{
if (pvid->pending)
{
if (d & 0x80) DrawSync(0); // only need sync for DMA
// Low word of command:
pvid->command&=0xffff0000;
pvid->command|=d;
pvid->pending=0;
CommandChange();
}
else
{
if ((d&0xc000)==0x8000)
{
// Register write:
int num=(d>>8)&0x1f;
int dold=pvid->reg[num];
int blank_on = 0;
pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II)
if (num > 0x0a && !(pvid->reg[1]&4)) {
elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc);
return;
}
if (num == 1 && !(d&0x40) && SekCyclesDone() - line_base_cycles <= 488-390)
blank_on = 1;
DrawSync(blank_on);
pvid->reg[num]=(unsigned char)d;
switch (num)
{
case 0x00:
elprintf(EL_INTSW, "hint_onoff: %i->%i [%i] pend=%i @ %06x", (dold&0x10)>>4,
(d&0x10)>>4, SekCyclesDone(), (pvid->pending_ints&0x10)>>4, SekPc);
goto update_irq;
case 0x01:
elprintf(EL_INTSW, "vint_onoff: %i->%i [%i] pend=%i @ %06x", (dold&0x20)>>5,
(d&0x20)>>5, SekCyclesDone(), (pvid->pending_ints&0x20)>>5, SekPc);
goto update_irq;
case 0x05:
//elprintf(EL_STATUS, "spritep moved to %04x", (unsigned)(Pico.video.reg[5]&0x7f) << 9);
if (d^dold) rendstatus |= PDRAW_SPRITES_MOVED;
break;
case 0x0c:
// renderers should update their palettes if sh/hi mode is changed
if ((d^dold)&8) Pico.m.dirtyPal = 2;
break;
}
return;
update_irq:
#ifndef EMU_CORE_DEBUG
// update IRQ level
if (!SekShouldInterrupt()) // hack
{
int lines, pints, irq=0;
lines = (pvid->reg[1] & 0x20) | (pvid->reg[0] & 0x10);
pints = (pvid->pending_ints&lines);
if (pints & 0x20) irq = 6;
else if (pints & 0x10) irq = 4;
SekInterrupt(irq); // update line
if (irq) SekEndRun(24); // make it delayed
}
#endif
}
else
{
// High word of command:
pvid->command&=0x0000ffff;
pvid->command|=d<<16;
pvid->pending=1;
}
}
}
}
PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a)
{
a&=0x1c;
if (a==0x04) // control port
{
struct PicoVideo *pv=&Pico.video;
unsigned int d;
d=pv->status;
//if (PicoOpt&POPT_ALT_RENDERER) d|=0x0020; // sprite collision (Shadow of the Beast)
if (SekCyclesDone() - line_base_cycles >= 488-88)
d|=0x0004; // H-Blank (Sonic3 vs)
d |= ((pv->reg[1]&0x40)^0x40) >> 3; // set V-Blank if display is disabled
d |= (pv->pending_ints&0x20)<<2; // V-int pending?
if (d&0x100) pv->status&=~0x100; // FIFO no longer full
pv->pending = 0; // ctrl port reads clear write-pending flag (Charles MacDonald)
elprintf(EL_SR, "SR read: %04x @ %06x", d, SekPc);
return d;
}
// H-counter info (based on Generator):
// frame:
// | <- hblank? -> |
// start <416> hint <36> hdisplay <38> end // CPU cycles
// |---------...---------|------------|-------------|
// 0 B6 E4 FF // 40 cells
// 0 93 E8 FF // 32 cells
// Gens (?) v-render
// start <hblank=84> hint hdisplay <404> |
// |---------------------|--------------------------|
// E4 (hc[0x43]==0) 07 B1 // 40
// E8 (hc[0x45]==0) 05 91 // 32
// check: Sonic 3D Blast bonus, Cannon Fodder, Chase HQ II, 3 Ninjas kick back, Road Rash 3, Skitchin', Wheel of Fortune
if ((a&0x1c)==0x08)
{
unsigned int d;
d = (SekCyclesDone() - line_base_cycles) & 0x1ff; // FIXME
if (Pico.video.reg[12]&1)
d = hcounts_40[d];
else d = hcounts_32[d];
elprintf(EL_HVCNT, "hv: %02x %02x (%i) @ %06x", d, Pico.video.v_counter, SekCyclesDone(), SekPc);
return d | (Pico.video.v_counter << 8);
}
if (a==0x00) // data port
{
return VideoRead();
}
return 0;
}
unsigned int PicoVideoRead8(unsigned int a)
{
unsigned int d;
a&=0x1d;
switch (a)
{
case 0: return VideoRead() >> 8;
case 1: return VideoRead() & 0xff;
case 4: // control port/status reg
d = Pico.video.status >> 8;
if (d&1) Pico.video.status&=~0x100; // FIFO no longer full
Pico.video.pending = 0;
elprintf(EL_SR, "SR read (h): %02x @ %06x", d, SekPc);
return d;
case 5:
d = Pico.video.status & 0xff;
//if (PicoOpt&POPT_ALT_RENDERER) d|=0x0020; // sprite collision (Shadow of the Beast)
d |= ((Pico.video.reg[1]&0x40)^0x40) >> 3; // set V-Blank if display is disabled
d |= (Pico.video.pending_ints&0x20)<<2; // V-int pending?
if (SekCyclesDone() - line_base_cycles >= 488-88) d |= 4; // H-Blank
Pico.video.pending = 0;
elprintf(EL_SR, "SR read (l): %02x @ %06x", d, SekPc);
return d;
case 8: // hv counter
elprintf(EL_HVCNT, "vcounter: %02x (%i) @ %06x", Pico.video.v_counter, SekCyclesDone(), SekPc);
return Pico.video.v_counter;
case 9:
d = (SekCyclesDone() - line_base_cycles) & 0x1ff; // FIXME
if (Pico.video.reg[12]&1)
d = hcounts_40[d];
else d = hcounts_32[d];
elprintf(EL_HVCNT, "hcounter: %02x (%i) @ %06x", d, SekCyclesDone(), SekPc);
return d;
}
return 0;
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -0,0 +1,288 @@
/*
* PicoDrive
* (C) notaz, 2007-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <stddef.h>
#include "pico_int.h"
#include "memory.h"
uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT];
#ifdef _USE_DRZ80
struct DrZ80 drZ80;
static u32 drz80_sp_base;
static void drz80_load_pcsp(u32 pc, u32 sp)
{
drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
if (drZ80.Z80PC_BASE & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad PC: %04x", pc);
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0];
} else {
drZ80.Z80PC_BASE <<= 1;
drZ80.Z80PC = drZ80.Z80PC_BASE + pc;
}
drZ80.Z80SP_BASE = z80_read_map[sp >> Z80_MEM_SHIFT];
if (drZ80.Z80SP_BASE & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad SP: %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[0];
drZ80.Z80SP = drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT);
} else {
drZ80.Z80SP_BASE <<= 1;
drZ80.Z80SP = drZ80.Z80SP_BASE + sp;
}
}
// called only if internal xmap rebase fails
static unsigned int dz80_rebase_pc(unsigned short pc)
{
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_pc: fail on %04x", pc);
drZ80.Z80PC_BASE = z80_read_map[0] << 1;
return drZ80.Z80PC_BASE;
}
static unsigned int dz80_rebase_sp(unsigned short sp)
{
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_sp: fail on %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
return drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT) - 0x100;
}
#endif
void z80_init(void)
{
#ifdef _USE_DRZ80
memset(&drZ80, 0, sizeof(drZ80));
drZ80.z80_rebasePC = dz80_rebase_pc;
drZ80.z80_rebaseSP = dz80_rebase_sp;
drZ80.z80_read8 = (void *)z80_read_map;
drZ80.z80_read16 = NULL;
drZ80.z80_write8 = (void *)z80_write_map;
drZ80.z80_write16 = NULL;
drZ80.z80_irq_callback = NULL;
#endif
#ifdef _USE_CZ80
memset(&CZ80, 0, sizeof(CZ80));
Cz80_Init(&CZ80);
Cz80_Set_ReadB(&CZ80, NULL); // unused (hacked in)
Cz80_Set_WriteB(&CZ80, NULL);
#endif
}
void z80_reset(void)
{
#ifdef _USE_DRZ80
drZ80.Z80I = 0;
drZ80.Z80IM = 0;
drZ80.Z80IF = 0;
drZ80.z80irqvector = 0xff0000; // RST 38h
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
// others not changed, undefined on cold boot
/*
drZ80.Z80F = (1<<2); // set ZFlag
drZ80.Z80F2 = (1<<2); // set ZFlag
drZ80.Z80IX = 0xFFFF << 16;
drZ80.Z80IY = 0xFFFF << 16;
*/
// drZ80 is locked in single bank
drz80_sp_base = (PicoAHW & PAHW_SMS) ? 0xc000 : 0x0000;
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
if (PicoAHW & PAHW_SMS)
drZ80.Z80SP = drZ80.Z80SP_BASE + 0xdff0; // simulate BIOS
// XXX: since we use direct SP pointer, it might make sense to force it to RAM,
// but we'll rely on built-in stack protection for now
#endif
#ifdef _USE_CZ80
Cz80_Reset(&CZ80);
if (PicoAHW & PAHW_SMS)
Cz80_Set_Reg(&CZ80, CZ80_SP, 0xdff0);
#endif
}
/* save state stuff */
static int z80_unpack_legacy(const void *data)
{
#if defined(_USE_DRZ80)
if (*(int *)data == 0x015A7244) { // "DrZ" v1 save?
u32 pc, sp;
memcpy(&drZ80, data+4, 0x54);
pc = (drZ80.Z80PC - drZ80.Z80PC_BASE) & 0xffff;
sp = (drZ80.Z80SP - drZ80.Z80SP_BASE) & 0xffff;
// update bases
drz80_load_pcsp(pc, sp);
return 0;
}
#elif defined(_USE_CZ80)
if (*(int *)data == 0x00007a43) { // "Cz" save?
memcpy(&CZ80, data+8, offsetof(cz80_struc, BasePC));
Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4));
return 0;
}
#endif
return -1;
}
struct z80sr_main {
u8 a, f;
u8 b, c;
u8 d, e;
u8 h, l;
};
struct z80_state {
char magic[4];
// regs
struct z80sr_main m; // main regs
struct z80sr_main a; // alt (') regs
u8 i, r;
u16 ix, iy;
u16 sp;
u16 pc;
// other
u8 halted;
u8 iff1, iff2;
u8 im; // irq mode
u8 irq_pending; // irq line level, 1 if active
u8 irq_vector[3]; // up to 3 byte vector for irq mode0 handling
u8 reserved[8];
};
void z80_pack(void *data)
{
struct z80_state *s = data;
memset(data, 0, Z80_STATE_SIZE);
strcpy(s->magic, "Z80");
#if defined(_USE_DRZ80)
#define DRR8(n) (drZ80.Z80##n >> 24)
#define DRR16(n) (drZ80.Z80##n >> 16)
#define DRR16H(n) (drZ80.Z80##n >> 24)
#define DRR16L(n) ((drZ80.Z80##n >> 16) & 0xff)
s->m.a = DRR8(A); s->m.f = drZ80.Z80F;
s->m.b = DRR16H(BC); s->m.c = DRR16L(BC);
s->m.d = DRR16H(DE); s->m.e = DRR16L(DE);
s->m.h = DRR16H(HL); s->m.l = DRR16L(HL);
s->a.a = DRR8(A2); s->a.f = drZ80.Z80F2;
s->a.b = DRR16H(BC2); s->a.c = DRR16L(BC2);
s->a.d = DRR16H(DE2); s->a.e = DRR16L(DE2);
s->a.h = DRR16H(HL2); s->a.l = DRR16L(HL2);
s->i = DRR8(I); s->r = drZ80.spare;
s->ix = DRR16(IX); s->iy = DRR16(IY);
s->sp = drZ80.Z80SP - drZ80.Z80SP_BASE;
s->pc = drZ80.Z80PC - drZ80.Z80PC_BASE;
s->halted = !!(drZ80.Z80IF & 4);
s->iff1 = !!(drZ80.Z80IF & 1);
s->iff2 = !!(drZ80.Z80IF & 2);
s->im = drZ80.Z80IM;
s->irq_pending = !!drZ80.Z80_IRQ;
s->irq_vector[0] = drZ80.z80irqvector >> 16;
s->irq_vector[1] = drZ80.z80irqvector >> 8;
s->irq_vector[2] = drZ80.z80irqvector;
#elif defined(_USE_CZ80)
{
const cz80_struc *CPU = &CZ80;
s->m.a = zA; s->m.f = zF;
s->m.b = zB; s->m.c = zC;
s->m.d = zD; s->m.e = zE;
s->m.h = zH; s->m.l = zL;
s->a.a = zA2; s->a.f = zF2;
s->a.b = CZ80.BC2.B.H; s->a.c = CZ80.BC2.B.L;
s->a.d = CZ80.DE2.B.H; s->a.e = CZ80.DE2.B.L;
s->a.h = CZ80.HL2.B.H; s->a.l = CZ80.HL2.B.L;
s->i = zI; s->r = zR;
s->ix = zIX; s->iy = zIY;
s->sp = Cz80_Get_Reg(&CZ80, CZ80_SP);
s->pc = Cz80_Get_Reg(&CZ80, CZ80_PC);
s->halted = !!Cz80_Get_Reg(&CZ80, CZ80_HALT);
s->iff1 = !!zIFF1;
s->iff2 = !!zIFF2;
s->im = zIM;
s->irq_pending = (Cz80_Get_Reg(&CZ80, CZ80_IRQ) == HOLD_LINE);
s->irq_vector[0] = 0xff;
}
#endif
}
int z80_unpack(const void *data)
{
const struct z80_state *s = data;
if (strcmp(s->magic, "Z80") != 0) {
if (z80_unpack_legacy(data) != 0)
goto fail;
elprintf(EL_STATUS, "legacy z80 state");
return 0;
}
#if defined(_USE_DRZ80)
#define DRW8(n, v) drZ80.Z80##n = (u32)(v) << 24
#define DRW16(n, v) drZ80.Z80##n = (u32)(v) << 16
#define DRW16HL(n, h, l) drZ80.Z80##n = ((u32)(h) << 24) | ((u32)(l) << 16)
DRW8(A, s->m.a); drZ80.Z80F = s->m.f;
DRW16HL(BC, s->m.b, s->m.c);
DRW16HL(DE, s->m.d, s->m.e);
DRW16HL(HL, s->m.h, s->m.l);
DRW8(A2, s->a.a); drZ80.Z80F2 = s->a.f;
DRW16HL(BC2, s->a.b, s->a.c);
DRW16HL(DE2, s->a.d, s->a.e);
DRW16HL(HL2, s->a.h, s->a.l);
DRW8(I, s->i); drZ80.spare = s->r;
DRW16(IX, s->ix); DRW16(IY, s->iy);
drz80_load_pcsp(s->pc, s->sp);
drZ80.Z80IF = 0;
if (s->halted) drZ80.Z80IF |= 4;
if (s->iff1) drZ80.Z80IF |= 1;
if (s->iff2) drZ80.Z80IF |= 2;
drZ80.Z80IM = s->im;
drZ80.Z80_IRQ = s->irq_pending;
drZ80.z80irqvector = ((u32)s->irq_vector[0] << 16) |
((u32)s->irq_vector[1] << 8) | s->irq_vector[2];
return 0;
#elif defined(_USE_CZ80)
{
cz80_struc *CPU = &CZ80;
zA = s->m.a; zF = s->m.f;
zB = s->m.b; zC = s->m.c;
zD = s->m.d; zE = s->m.e;
zH = s->m.h; zL = s->m.l;
zA2 = s->a.a; zF2 = s->a.f;
CZ80.BC2.B.H = s->a.b; CZ80.BC2.B.L = s->a.c;
CZ80.DE2.B.H = s->a.d; CZ80.DE2.B.L = s->a.e;
CZ80.HL2.B.H = s->a.h; CZ80.HL2.B.L = s->a.l;
zI = s->i; zR = s->r;
zIX = s->ix; zIY = s->iy;
Cz80_Set_Reg(&CZ80, CZ80_SP, s->sp);
Cz80_Set_Reg(&CZ80, CZ80_PC, s->pc);
Cz80_Set_Reg(&CZ80, CZ80_HALT, s->halted);
Cz80_Set_Reg(&CZ80, CZ80_IFF1, s->iff1);
Cz80_Set_Reg(&CZ80, CZ80_IFF2, s->iff2);
zIM = s->im;
Cz80_Set_Reg(&CZ80, CZ80_IRQ, s->irq_pending ? HOLD_LINE : CLEAR_LINE);
return 0;
}
#endif
fail:
elprintf(EL_STATUS|EL_ANOMALY, "z80_unpack failed");
z80_reset();
z80_int();
return -1;
}
void z80_exit(void)
{
}
void z80_debug(char *dstr)
{
#if defined(_USE_DRZ80)
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
#elif defined(_USE_CZ80)
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", (unsigned int)(CZ80.PC - CZ80.BasePC), CZ80.SP.W);
#endif
}

View File

@ -0,0 +1,491 @@
#
PicoDrive 1.xx
About
-----
#include "../README"
How to make it run
------------------
#ifdef GP2X
Extract all files to some directory on your SD and run PicoDrive.gpe from your
GP2X/Wiz/Caanoo menu. The same .gpe supports GP2X F100/F200, Wiz and Caanoo,
there is no need to use separate versions.
Then load a ROM and enjoy! ROMs can be in .smd or .bin format and can be zipped.
Sega/Mega CD images can be in ISO/CSO+MP3/WAV or CUE+BIN formats (read below
for more details).
#endif
#ifdef GIZ
First make sure you have homebrew-enabled Service Pack installed. Then copy
PicoDrive.exe and KGSDK.dll to any place in your filesystem (both files must
be in the same directory) and run PicoDrive.exe using the launcher of your choice
(some of them might require renaming PicoDrive.exe to Autorun.exe, placing it in
the root of SD, etc). Then load a ROM and enjoy! ROMs can be placed anywhere, can
be in .smd or .bin format and can be zipped (one ROM per zip).
#endif
#ifdef PSP
If you are running a custom firmware, just copy the whole PicoDrive directory to
/PSP/GAME or /PSP/GAMEXXX directory in your memory stick (it shouldn't matter
which one GAME* directory to use).
If you are on 1.5, there is a separate KXploited version for it.
#endif
#ifdef PANDORA
Just copy the .pnd to <sd card>/pandora/menu or <sd card>/pandora/desktop.
#endif
This emulator has lots of options with various tweaks (for improved speed mostly),
but it should have best compatibility in it's default config. If suddenly you
start getting glitches or change something and forget what, use "Restore defaults"
option.
How to run Sega/Mega CD games
-----------------------------
To play any CD game, you need BIOS files. These files must be copied to
#ifdef PANDORA
<sd card>/pandora/appdata/picodrive/ directory
(if you run PicoDrive once it will create that directory for you).
#else
the same directory as PicoDrive files.
#endif
Files can be named as follows:
US: us_scd1_9210.bin us_scd2_9306.bin SegaCDBIOS9303.bin
EU: eu_mcd1_9210.bin eu_mcd2_9303.bin eu_mcd2_9306.bin
JP: jp_mcd1_9112.bin jp_mcd1_9111.bin
these files can also be zipped.
The game must be dumped to CUE+BIN or CUE+ISO format.
ISO/CSO+MP3/WAV is also supported, but may cause problems.
When using CUE/BIN, you must load .cue file from the menu, or else
the emu will not find audio tracks.
Other important stuff
---------------------
* Sega/Mega CD: If the background music is missing, the CD image format may be
wrong. Currently .cue/bin is recommended. Be aware that there are lots of bad
dumps on the web, and some use mp3 format for audio, which often causes
problems (see below).
* While iso/mp3 format is supported, it's not recommended to use.
Some of many problems with mp3 are listed below:
* MP3s may be named incorrectly and will not play.
* The game music may play too fast/too slow/out of sync, which means they
are encoded incorrectly. PicoDrive is not a mp3 player, so all mp3s MUST
be encoded at 44.1kHz stereo.
* Sega/Mega CD: If your games hang at the BIOS screen (with planets shown),
you may be using a bad BIOS dump. Try another from a different source,
like dumping it from your own console.
#ifdef GP2X
* What using mp3s, use lower bitrate for better performance (96 or 128kbps
CBRs recommended).
* GP2X F100/F200: When you use both GP2X CPUs, keep in mind that you can't
overclock as high as when using ARM920 only. For example my GP2X when run
singlecore can reach 280MHz, but with both cores it's about 250MHz. When
overclocked too much, it may start hanging and producing random noise, or
causing ARM940 crashes ("940 crashed" message displayed).
* GP2X F100/F200: Due to internal implementation mp3s must not be larger that
12MB (12582912 bytes). Larger mp3s will not be fully loaded.
#endif
Configuration
-------------
@@0. "Save slot"
This is a slot number to use for savestates, when done by a button press outside
menu. This can also be configured to be changed with a button
(see "key configuration").
@@0. "Frameskip"
How many frames to skip rendering before displaying another.
"Auto" is recommended.
@@0. "Region"
This option lets you force the game to think it is running on machine from the
specified region, or just to set autodetection order. Also affects Sega/Mega CD.
@@0. "Show FPS"
Self-explanatory. Format is XX/YY, where XX is the number of rendered frames and
YY is the number of emulated frames per second.
@@0. "Enable sound"
Does what it says. You must enable at least YM2612 or SN76496 (in advanced options,
see below) for this to make sense (already done by default).
@@0. "Sound Quality"
#ifdef PSP
Sound sample rate, affects sound quality and emulation performance.
22050Hz setting is the recommended one.
#else
Sound sample rate and stereo mode. Mono is not available in Sega/Mega CD mode.
#endif
@@0. "Confirm savestate"
Allows to enable confirmation on savestate saving (to prevent savestate overwrites),
on loading (to prevent destroying current game progress), and on both or none, when
using shortcut buttons (not menu) for saving/loading.
@@0. "[Display options]"
Enters Display options menu (see below).
@@0. "[Sega/Mega CD options]"
Enters Sega/Mega CD options menu (see below).
@@0. "[32X options]"
Enters 32X options menu (see below).
@@0. "[Advanced options]"
Enters advanced options menu (see below).
@@0. "Save cfg as default"
If you save your config here it will be loaded on next ROM load, but only if there
is no game specific config saved (which will be loaded in that case).
You can press left/right to switch to a different config profile.
@@0. "Save cfg for current game only"
Whenever you load current ROM again these settings will be loaded.
@@0. "Restore defaults"
Restores all options (except controls) to defaults.
Display options
---------------
#ifndef PANDORA
@@1. "Renderer"
#ifdef GP2X
8bit fast:
This enables alternative heavily optimized tile-based renderer, which renders
pixels not line-by-line (this is what accurate renderers do), but in 8x8 tiles,
which is much faster. But because of the way it works it can't render any
mid-frame image changes (raster effects), so it is useful only with some games.
Other two are accurate line-based renderers. The 8bit is faster but does not
run well with some games like Street Racer.
#endif
#ifdef GIZ
This option allows to switch between 16bit and 8bit renderers. The 8bit one is
a bit faster for some games, but not much, because colors still need to be
converted to 16bit, as this is what Gizmondo requires. It also introduces
graphics problems for some games, so it's best to use 16bit one.
#endif
#ifdef PSP
This option allows to switch between fast and accurate renderers. The fast one
is much faster, because it draws the whole frame at a time, instead of doing it
line by line, like the accurate one does. But because of the way it works it
can't render any mid-frame image changes (raster effects), so it is useful only
for some games.
#endif
#endif
#ifdef GP2X
@@1. "Tearing Fix"
Wiz only: works around the tearing problem by using portrait mode. Causes ~5-10%
performance hit, but eliminates the tearing effect.
@@1. "Gamma correction"
F100/F200 only: Alters image gamma through GP2X hardware. Larger values make
image to look brighter, lower - darker (default is 1.0).
@@1. "Vsync"
This one adjusts the LCD refresh rate to better match game's refresh rate and
starts synchronizing rendering with it. Should make scrolling smoother and
eliminate tearing on F100/F200.
#endif
#ifdef GIZ
@@1. "Scanline mode"
This option was designed to work around slow framebuffer access (the Gizmondo's
main bottleneck) by drawing every other line (even numbered lines only).
This improves performance greatly, but looses detail.
@@1. "Scale low res mode"
The Genesis/Megadrive had several graphics modes, some of which were only 256
pixels wide. This option scales their width to 320 by using simple
pixel averaging scaling. Works only when 16bit renderer is enabled.
@@1. "Double buffering"
Draws the display to offscreen buffer, and flips it with visible one when done.
Unfortunately this causes serious tearing, unless v-sync is used (next option).
@@1. "Wait for V-sync"
Waits for vertical sync before drawing (or flipping buffers, if previous option
is enabled). Emulation is stopped while waiting, so this causes large performance
hit.
#endif
#ifdef PSP
@@1. "Scale factor"
This allows to resize the displayed image by using the PSP's hardware. The number is
used to multiply width and height of the game image to get the size of image to be
displayed. If you just want to make it fullscreen, just use "Set to fullscreen"
setting below.
@@1. "Hor. scale (for low res. games)"
This one works similarly as the previous setting, but can be used to apply additional
scaling horizontally, and is used for games which use lower (256 pixel wide) Gen/MD
resolution.
@@1. "Hor. scale (for hi res. games)"
Same as above, only for higher (320 pixel wide) resolution using games.
@@1. "Bilinear filtering"
If this is enabled, PSP hardware will apply bilinear filtering on the resulting image,
making it smoother, but blurry.
@@1. "Gamma adjustment"
Color gamma can be adjusted with this.
@@1. "Black level"
This can be used to reduce unwanted "ghosting" effect for dark games, by making
black pixels brighter. Use in conjunction with "gamma adjustment" for more effect.
@@1. "Wait for v-sync"
Wait for the screen to finish updating before switching to next frame, to avoid tearing.
There are 3 options:
* never: don't wait for vsync.
* sometimes: wait only if emulator is running fast enough.
* always: always wait (causes emulation slowdown).
@@1. "Set to unscaled centered"
Adjust the resizing options to set game image to it's original size.
@@1. "Set to 4:3 scaled"
Scale the image up, but keep 4:3 aspect, by adding black borders.
@@1. "Set to fullscreen"
Adjust the resizing options to make the game image fullscreen.
#endif
#ifdef PANDORA
Allows to set up scaling, filtering and vertical sync.
#endif
Sega/Mega CD options
--------------------
@@2. "CD LEDs"
The Sega/Mega CD unit had two blinking LEDs (red and green) on it. This option
will display them on top-left corner of the screen.
@@2. "CDDA audio"
This option enables CD audio playback.
@@2. "PCM audio"
This enables 8 channel PCM sound source. It is required for some games to run,
because they monitor state of this audio chip.
@@2. "Save RAM cart"
Here you can enable 64K RAM cart. Format it in BIOS if you do.
@@2. "Scale/Rot. fx"
The Sega/Mega CD had scaling/rotation chip, which allows effects similar to
"Mode 7" effects in SNES. On slow systems like GP2X, disabling may improve
performance but cause graphical glitches.
32X options
-----------
@@3. "32X enabled"
Enables emulation of addon. Option only takes effect when ROM is reloaded.
#ifdef GP2X
@@3. "32X renderer"
This currently only affects how the Genesis/MD layers are rendered, which is
same as "Renderer" in display options.
#endif
@@3. "PWM sound"
Emulates PWM sound portion of 32X hardware. Disabling this may greatly improve
performance for games that dedicate one of SD2s for sound, but will cause
missing sound effects and instruments.
@@3. "Master SH2 cycles" / "Slave SH2 cycles"
This allows underclocking the 32X CPUs for better emulation performance. The
number has the same meaning as cycles in DOSBox, which is cycles per millisecond.
Underclocking too much may cause various in-game glitches.
Advanced configuration
----------------------
@@4. "Use SRAM/BRAM savestates"
This will automatically read/write SRAM (or BRAM for Sega/Mega CD) savestates for
games which are using them. SRAM is saved whenever you enter the menu or exit the
emulator.
@@4. "Disable sprite limit"
The MegaDrive/Genesis had a limit on how many sprites (usually smaller moving
objects) can be displayed on single line. This option allows to disable that
limit. Note that some games used this to hide unwanted things, so it is not
always good to enable this option.
@@4. "Emulate Z80"
Enables emulation of Z80 chip, which was mostly used to drive the other sound chips.
Some games do complex sync with it, so you must enable it even if you don't use
sound to be able to play them.
@@4. "Emulate YM2612 (FM)"
This enables emulation of six-channel FM sound synthesizer chip, which was used to
produce sound effects and music.
@@4. "Emulate SN76496 (PSG)"
This enables emulation of PSG (programmable sound generation) sound chip for
additional effects.
Note: if you change sound settings AFTER loading a ROM, you may need to reset
game to get sound. This is because most games initialize sound chips on
startup, and this data is lost when sound chips are being enabled/disabled.
@@4. "gzip savestates"
This will always apply gzip compression on your savestates, allowing you to
save some space and load/save time.
@@4. "Don't save last used ROM"
This will disable writing last used ROM to config on exit (what might cause SD
card corruption according to DaveC).
@@4. "Disable idle loop patching"
Idle loop patching is used to improve performance, but may cause compatibility
problems in some rare cases. Try disabling this if your game has problems.
@@4. "Disable frame limiter"
This allows games to run faster then 50/60fps, useful for benchmarking.
#ifdef GP2X
@@4. "Use ARM940 core for sound"
F100/F200: This option causes PicoDrive to use ARM940T core (GP2X's second CPU)
for sound (i.e. to generate YM2612 samples) to improve performance noticeably.
It also decodes MP3s in Sega/Mega CD mode.
#endif
@@4. "Enable dynarecs"
This enables dynamic recompilation for SH2 and SVP CPU code,
what improves emulation performance greatly.
Key configuration
-----------------
Select "Configure controls" from the main menu. Then select "Player 1" and you will
see two columns. The left column lists names of Genesis/MD controller buttons, and
the right column your handheld ones, which are assigned.
There is also option to enable 6 button pad (will allow you to configure XYZ
buttons), and an option to set turbo rate (in Hz) for turbo buttons.
Cheat support
-------------
To use GG/patch codes, you must type them into your favorite text editor, one
per line. Comments may follow code after a whitespace. Only GameGenie and
Genecyst patch formats are supported.
Examples:
Genecyst patch (this example is for Sonic):
00334A:0005 Start with five lives
012D24:0001 Keep invincibility until end of stage
009C76:5478 each ring worth 2
009C76:5678 each ring worth 3
...
Game Genie patch (for Sonic 2):
ACLA-ATD4 Hidden palace instead of death egg in level select
...
Both GG and patch codes can be mixed in one file.
When the file is ready, name it just like your ROM file, but with additional
.pat extension, making sure that case matches.
Examples:
ROM: Sonic.zip
PATCH FILE: Sonic.zip.pat
ROM: Sonic 2.bin
PATCH FILE: Sonic 2.bin.pat
Put the file into your ROMs directory. Then load the .pat file as you would
a ROM. Then Cheat Menu Option should appear in main menu.
What is emulated?
-----------------
Genesis/MegaDrive:
#ifdef PSP
main 68k @ 7.6MHz: yes, FAME/C core
z80 @ 3.6MHz: yes, CZ80 core
#else
main 68k @ 7.6MHz: yes, Cyclone core
z80 @ 3.6MHz: yes, DrZ80 core
#endif
VDP: yes, except some quirks and modes not used by games
YM2612 FM: yes, optimized MAME core
SN76489 PSG: yes, MAME core
SVP chip: yes! This is first emu to ever do this.
Some in-cart mappers are also supported.
Sega/Mega CD:
#ifdef PSP
another 68k @ 12.5MHz: yes, FAME/C too
#else
another 68k @ 12.5MHz: yes, Cyclone too
#endif
gfx scaling/rotation chip (custom ASIC): yes
PCM sound source: yes
CD-ROM controller: yes (mostly)
bram (internal backup RAM): yes
32X:
2x SH2 @ 23MHz: yes, custom recompiler
Super VDP: yes
PWM: yes
Problems / limitations
----------------------
#ifdef PSP
* SVP emulation is terribly slow.
#endif
* Various VDP modes and quirks (window bug, scroll size 2, etc.) are not
emulated, as very few games use this (if any at all).
* The emulator is not 100% accurate, so some things may not work as expected.
* The FM sound core doesn't support all features and has some accuracy issues.
Changelog
-------
#include "../ChangeLog"
Credits
-------
This emulator is made of the code from following people/projects:
#include "../AUTHORS"
License
-------
This program and it's code is released under the terms of MAME license:
#include "../COPYING"
SEGA/Genesis/MegaDrive/SEGA-CD/Mega-CD/32X are trademarks of
Sega Enterprises Ltd.

View File

@ -0,0 +1,166 @@
#
# Sega/Mega CD games
#
[CD|GM MK-4432 -00|U|ADVENTURES OF BA]
Scale/Rot. fx (slow) = 1
Better sync (slow) = 1
[CD|GM T-60055-00|U|AH3-THUNDERSTRIKE]
Scale/Rot. fx (slow) = 1
[CD|GM MK-4401 -00|U|BATMAN RETURNS]
Scale/Rot. fx (slow) = 1
[CD|GM T-115075-00|U|BCRACERS]
Scale/Rot. fx (slow) = 1
[CD|GM MK-4402|U|COBRA COMMAND]
Better sync (slow) = 1
[CD|GM T-121015-00|U|DRAGONS LAIR]
Renderer = 16bit accurate
[CD|GM T-60094|J|JAGUAR XJ220]
Renderer = 16bit accurate
[CD|GM T-127015-00|U|LUNAR]
Scale/Rot. fx (slow) = 1
[CD|GM T-111065 -0|U|MAD DOG II THE LOST GOLD]
Renderer = 16bit accurate
[CD|GM T-11105 -00|U|MAD DOG MCCREE]
Renderer = 16bit accurate
[CD|GM T-81025-00|U|MORTAL KOMBAT]
Renderer = 16bit accurate
Better sync (slow) = 1
[CD|GM T-04903-01|U|NIGHT TRAP]
Renderer = 16bit accurate
[CD|GM T-113025-00|U|NOVASTORM]
Better sync (slow) = 1
[CD|GM T-127035-00|U|Popful MAIL]
Better sync (slow) = 1
[CD|MK 4603-50|JUE|ROAD AVENGER]
Renderer = 16bit accurate
Better sync (slow) = 1
[CD|GM T-50085|U|ROAD RASH]
Renderer = 16bit accurate
Better sync (slow) = 1
[CD|GM MK-4416 -00|E|ROBO ALESTE]
Renderer = 16bit accurate
[CD|GM T-06201-03|U|SEWER SHARK]
Renderer = 16bit accurate
[CD|GM T-113045-00|E|SHADOW OF THE BEAST TWO]
Renderer = 16bit accurate
[CD|GM MK-4404|U|SOL-FEACE]
Better sync (slow) = 1
[CD|GM MK-4407-00|E|SONIC THE HEDGEHOG-CD]
Scale/Rot. fx (slow) = 1
[CD|GM MK-4407 -00|U|SONIC THE HEDGEHOG-CD]
Scale/Rot. fx (slow) = 1
[CD|GM T-22025-00|U|THE 3RD WORLD WAR]
Better sync (slow) = 1
[CD|GM MK- 4430 -|E|YUMEMI MISTERY MANSION]
Renderer = 16bit accurate
#
# Virtua Racing
#
[MD|GM MK-1229 -00|U|Virtua Racing]
Renderer = 8bit fast
Show FPS = 1
GP2X CPU clocks = 235
[MD|GM G-7001 -00|J|Virtua Racing]
Renderer = 8bit fast
Show FPS = 1
GP2X CPU clocks = 235
[MD|GM MK-1229 -00|E|Virtua Racing]
Renderer = 8bit fast
Show FPS = 1
GP2X CPU clocks = 235
[MD|GM MK-1229 -00|E|VIRTUA RACING \00\00\00\00\00\00\00\00\00]
Renderer = 8bit fast
Show FPS = 1
GP2X CPU clocks = 235
#
# Genesis/MegaDrive games
#
[MD|GM MK-1029-00|E| BURNING FORCE]
Renderer = 16bit accurate
[MD|GM T-14023 -00|J| BURNING FORCE]
Renderer = 16bit accurate
[MD|GM T-14026 -00|U| BURNING FORCE]
Renderer = 16bit accurate
[MD|GM T-95076-00|U|CASTLEVANIA BLOODLINES]
Renderer = 16bit accurate
[MD|GM T-95076-00|E|CASTLEVANIA THE NEW GENERATION]
Renderer = 16bit accurate
[MD|GM MK-1569 -50|A|COMIX ZONE]
Renderer = 16bit accurate
[MD|GM G-4132 -00|1|]
Renderer = 16bit accurate
[MD|GM MK-1569 -00|4|COMIX ZONE]
Renderer = 16bit accurate
[MD|GM T-097116 00|4|MORTAL KOMBAT 3]
Renderer = 16bit accurate
[MD|GM G-4119-00|J| OUT_RUNNERS 1994/03/03 Ver.FINAL!!]
Renderer = 16bit accurate
[MD|GM T-13096-00|U| OUT_RUNNERS]
Renderer = 16bit accurate
[MD|GM T-48376 00|JUE|RED-ZONE]
Renderer = 16bit accurate
[MD|GM T-177016-00|F|STREET RACER]
Renderer = 16bit accurate
[MD|GM T-95043-00|J|]
Renderer = 16bit accurate
[MD|GM T-25036 -00|U| SHOVE IT!]
Renderer = 16bit accurate
[MD|GM MK-1104 -00|U|AFTER BURNERII]
Renderer = 16bit accurate
[MD|GM T-32053 -00|U|ARCUS ODYSSEY]
Renderer = 16bit accurate
[MD|GM 00054010-00|JUE|RAMBO \87V]
Renderer = 16bit accurate
[MD|GM 00054010-01|JUE|RAMBO \87V]
Renderer = 16bit accurate
[MD|GM T-50406 -01|U|GALAHAD]
Renderer = 16bit accurate